Orocos Real-Time Toolkit  2.6.0
PeerParser.cpp
00001 /***************************************************************************
00002   tag: Peter Soetens  Tue Dec 21 22:43:07 CET 2004  PeerParser.cxx
00003 
00004                         PeerParser.cxx -  description
00005                            -------------------
00006     begin                : Tue December 21 2004
00007     copyright            : (C) 2004 Peter Soetens
00008     email                : peter.soetens@mech.kuleuven.ac.be
00009 
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU General Public                   *
00013  *   License as published by the Free Software Foundation;                 *
00014  *   version 2 of the License.                                             *
00015  *                                                                         *
00016  *   As a special exception, you may use this file as part of a free       *
00017  *   software library without restriction.  Specifically, if other files   *
00018  *   instantiate templates or use macros or inline functions from this     *
00019  *   file, or you compile this file and link it with other files to        *
00020  *   produce an executable, this file does not by itself cause the         *
00021  *   resulting executable to be covered by the GNU General Public          *
00022  *   License.  This exception does not however invalidate any other        *
00023  *   reasons why the executable file might be covered by the GNU General   *
00024  *   Public License.                                                       *
00025  *                                                                         *
00026  *   This library is distributed in the hope that it will be useful,       *
00027  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00028  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00029  *   Lesser General Public License for more details.                       *
00030  *                                                                         *
00031  *   You should have received a copy of the GNU General Public             *
00032  *   License along with this library; if not, write to the Free Software   *
00033  *   Foundation, Inc., 59 Temple Place,                                    *
00034  *   Suite 330, Boston, MA  02111-1307  USA                                *
00035  *                                                                         *
00036  ***************************************************************************/
00037 
00038 
00039 
00040 #include "PeerParser.hpp"
00041 #include "parser-debug.hpp"
00042 #include "parse_exception.hpp"
00043 #include "../TaskContext.hpp"
00044 #include "parser-types.hpp"
00045 #include "../internal/GlobalService.hpp"
00046 
00047 #include <boost/bind.hpp>
00048 #include <boost/iterator/iterator_traits.hpp>
00049 
00050 namespace RTT
00051 {
00052     using boost::bind;
00053     using namespace detail;
00054     using namespace std;
00055     using namespace boost;
00056 
00057     error_status<> PeerParser::handle_no_peer(scanner_t const& scan, parser_error<PeerErrors, iter_t>&e )
00058     {
00059         int length = advance_on_error;
00060         // before, this was not necessary !
00061         while (advance_on_error != 0) {
00062             ++scan;
00063             --advance_on_error;
00064         }
00065         // ok, got as far as possible, _peer contains the furthest we got.
00066         //std::cerr<<"Returning accept, advance "<< length <<std::endl;
00067         return error_status<>( error_status<>::accept, length );
00068     }
00069 
00070         void PeerParser::done()
00071         {
00072             //std::cerr<<"Peerparser operating in "<<  context->getName()<<std::endl;
00073             mlastobject = "this";
00074 
00075             // if size() > 1, it must be a peer or service
00076             // first browse the peers
00077             while ( callqueue.size() > 0 && _peer->hasPeer( callqueue.front() ) ) {
00078                 //std::cerr<< _peer->getName() <<" has peer " << callqueue.front()<<std::endl;
00079                 _peer = _peer->getPeer( callqueue.front() );
00080 
00081                 if ( _peer->ready() == false ) {
00082                     throw parse_exception_semantic_error
00083                                     ("Attempt to use TaskContext "+ callqueue.front() +" which is not ready to use." );
00084                 }
00085 
00086                 callqueue.pop();
00087             }
00088 
00089             // BC: user uses 'states.' or 'programs'.
00090             if ( !callqueue.empty() ) {
00091                 std::string name = callqueue.front();
00092                 if ( (name == "states" || name == "programs") && _peer->provides()->hasService(name) == 0) {
00093                     log(Warning) << "'"<<name<<"' peer not found. The use of '"<<name<<"' has been deprecated."<<endlog();
00094                     log(Warning) << "Modify your script to use the program's or state machine's name directly."<<endlog();
00095                     callqueue.pop();
00096                 }
00097             }
00098 
00099             mcurobject = _peer->provides();
00100 
00101             // all peers done, now traverse services:
00102             while ( callqueue.size() > 0 && mcurobject->hasService( callqueue.front() ) ) {
00103                 //std::cerr<< mcurobject->getName() <<" has object " << callqueue.front()<<std::endl;
00104                 mcurobject = mcurobject->provides( callqueue.front() );
00105                 mlastobject = callqueue.front();
00106                 callqueue.pop();
00107             }
00108 
00109             // last resort: browse the global service if not a single match and items in queue
00110             if (mcurobject == context->provides() && callqueue.size() != 0 ) {
00111                 mcurobject = GlobalService::Instance();
00112                 while ( callqueue.size() && mcurobject->hasService( callqueue.front() ) ) {
00113                     mcurobject = mcurobject->provides( callqueue.front() );
00114                     mlastobject = callqueue.front();
00115                     callqueue.pop();
00116                 }
00117             }
00118 
00119             // Something went wrong, a peer or object was not found:
00120             if ( mfullpath && callqueue.size() != 0 ) {
00121                 // print to user the mismatch :
00122                 string object = callqueue.front();
00123                 while ( !callqueue.empty() )
00124                     callqueue.pop();
00125                 iter_t begin;
00126                 if ( _peer->provides() == mcurobject )
00127                     throw_(begin, "From TaskContext '"+context->getName()+"': Task '"+ _peer->getName()+"' has no child Service '"+object+"'." );
00128                 else
00129                     throw_(begin, "From TaskContext '"+context->getName()+"': Service '"+ mcurobject->getName()+"' has no child Service '"+object+"'." );
00130             }
00131 
00132         }
00133 
00134         PeerParser::PeerParser(TaskContext* c, CommonParser& cp, bool fullpath)
00135             : commonparser(cp), mcurobject(c->provides()), mlastobject("this"), context(c), _peer(context), mfullpath(fullpath), advance_on_error(0)
00136         {
00137             BOOST_SPIRIT_DEBUG_RULE( my_guard );
00138             BOOST_SPIRIT_DEBUG_RULE( peerpath );
00139             BOOST_SPIRIT_DEBUG_RULE( peerlocator );
00140             peerpath =
00141                 ( +(commonparser.notassertingidentifier >> ".")[boost::bind( &PeerParser::seenobjectname, this, _1, _2 ) ] )[boost::bind(&PeerParser::done, this)];
00142 
00143             // find as far as possible a peer without throwing an exception
00144             // outside our interface
00145             peerlocator =
00146                 my_guard( *((commonparser.notassertingidentifier >> ".")[boost::bind( &PeerParser::locatepeer, this, _1, _2 ) ]))
00147                         [ boost::bind(&PeerParser::handle_no_peer, this, _1, _2) ]
00148                 ;
00149         }
00150 
00151     void PeerParser::reset()
00152     {
00153         _peer = context;
00154         mcurobject = context->provides();
00155         mlastobject = "this";
00156         advance_on_error = 0;
00157         while( !callqueue.empty() )
00158             callqueue.pop();
00159     }
00160 
00161     void PeerParser::seenobjectname( iter_t begin, iter_t end )
00162     {
00163         std::string name( begin, end );
00164         name.erase( name.length() -1  ); // compensate for extra "."
00165         callqueue.push( name );
00166 //         std::cerr << "seen " << name <<std::endl;
00167     }
00168 
00169     void PeerParser::locatepeer( iter_t begin, iter_t end )
00170     {
00171         std::string name( begin, end );
00172         name.erase( name.length() -1  ); // compensate for extra "."
00173 
00174         if ( mcurobject == _peer->provides() && _peer->hasPeer( name ) ) {
00175             _peer = _peer->getPeer( name );
00176             if ( _peer->ready() == false ) {
00177                 throw parse_exception_semantic_error
00178                                 ("Attempt to use TaskContext "+name+" which is not ready to use." );
00179             }
00180             mcurobject = _peer->provides();
00181             advance_on_error += end.base() - begin.base();
00182 
00183 //            cout << "PP located "<<name <<endl;
00184         }
00185         else if ( mcurobject->hasService(name) ) {
00186             mcurobject = mcurobject->provides(name);
00187             advance_on_error += end.base() - begin.base();
00188         }
00189         // check global service if we're still on the top-level:
00190         else if (mcurobject == _peer->provides() && GlobalService::Instance()->hasService(name) ) {
00191             mcurobject = GlobalService::Instance()->provides(name);
00192             advance_on_error += end.base() - begin.base();
00193         } else {
00194             if ( name == "states" || name == "programs") {
00195                 log(Warning) << "'"<<name<<"' peer not found. The use of '"<<name<<"' has been deprecated."<<endlog();
00196                 log(Warning) << "Modify your script to use the program's or state machine's name directly."<<endlog();
00197                 advance_on_error += end.base() - begin.base();
00198                 return;
00199             }
00200 //            cout << "PP failed "<<name <<endl;
00201             // store object name for higher level access.
00202             // do not consume it though.
00203 //            cout << std::string(begin, end)<<endl;
00204             mlastobject = name;
00205             if (mfullpath)
00206                 mcurobject.reset(); //when partial paths are OK, leave curobject pointing to last valid object.
00207             throw_(begin, peer_not_found );
00208         }
00209     }
00210 
00211     rule_t& PeerParser::parser()
00212     {
00213         return peerpath;
00214     }
00215 
00216     rule_t& PeerParser::locator()
00217     {
00218         return peerlocator;
00219     }
00220 
00221     TaskContext* PeerParser::peer()
00222     {
00223         return _peer;
00224     }
00225 
00226     Service::shared_ptr PeerParser::taskObject()
00227     {
00228         return mcurobject;
00229     }
00230 
00231     std::string PeerParser::object()
00232     {
00233         return mlastobject;
00234     }
00235 
00236 }
00237