ExpressionParser.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: Peter Soetens Mon May 10 19:10:37 CEST 2004 ExpressionParser.cxx
3 
4  ExpressionParser.cxx - description
5  -------------------
6  begin : Mon May 10 2004
7  copyright : (C) 2004 Peter Soetens
8  email : peter.soetens@mech.kuleuven.ac.be
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU General Public *
13  * License as published by the Free Software Foundation; *
14  * version 2 of the License. *
15  * *
16  * As a special exception, you may use this file as part of a free *
17  * software library without restriction. Specifically, if other files *
18  * instantiate templates or use macros or inline functions from this *
19  * file, or you compile this file and link it with other files to *
20  * produce an executable, this file does not by itself cause the *
21  * resulting executable to be covered by the GNU General Public *
22  * License. This exception does not however invalidate any other *
23  * reasons why the executable file might be covered by the GNU General *
24  * Public License. *
25  * *
26  * This library is distributed in the hope that it will be useful, *
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
29  * General Public License for more details. *
30  * *
31  * You should have received a copy of the GNU General Public *
32  * License along with this library; if not, write to the Free Software *
33  * Foundation, Inc., 59 Temple Place, *
34  * Suite 330, Boston, MA 02111-1307 USA *
35  * *
36  ***************************************************************************/
37 
38 #include "parser-debug.hpp"
39 #include "parse_exception.hpp"
40 
41 #ifdef ORO_PRAGMA_INTERFACE
42 #pragma implementation
43 #endif
44 #include "ExpressionParser.hpp"
45 //#include "DumpObject.hpp"
46 
47 #include "ArgumentsParser.hpp"
48 #include "../types/Operators.hpp"
49 #include "DataSourceCondition.hpp"
50 #include "../internal/DataSourceCommand.hpp"
51 #include "CmdFunction.hpp"
52 #include "../internal/GlobalService.hpp"
53 #include "CommandDataSource.hpp"
54 
55 #include "DataSourceTime.hpp"
56 #include "../TaskContext.hpp"
57 #include "PeerParser.hpp"
58 #include "../types/Types.hpp"
59 #include "SendHandleAlias.hpp"
60 
61 #include <boost/lambda/lambda.hpp>
62 
63 #include <boost/bind.hpp>
64 #include <boost/ref.hpp>
65 #include "rtt-scripting-config.h"
66 #include <iostream>
67 
68 namespace RTT
69 {
70  using boost::bind;
71  using boost::ref;
72 
73  using namespace detail;
74  using namespace std;
75 
76  namespace {
77  boost::spirit::classic::assertion<std::string> expect_open("Open brace expected.");
78  boost::spirit::classic::assertion<std::string> expect_close("Closing brace expected ( or could not find out what this line means ).");
79  boost::spirit::classic::assertion<std::string> expect_type("Unknown type. Please specify a type.");
80  boost::spirit::classic::assertion<std::string> expect_expr("Expected a valid expression.");
81  boost::spirit::classic::assertion<std::string> expect_ident("Expected a valid identifier.");
82  boost::spirit::classic::assertion<std::string> expect_init("Expected an initialisation value of the value.");
83  boost::spirit::classic::assertion<std::string> expect_comma("Expected the ',' separator after expression.");
84  boost::spirit::classic::assertion<std::string> expect_timespec("Expected a time specification (e.g. > 10s or > varname ) after 'time' .");
85 
86  guard<std::string> my_guard;
87  }
88 
89 
90 
92  : ret(), mhandle(), mcmdcnd(0), mobject(), mmethod(),
93  mcaller( caller ? caller : c->engine()), mcalltype(DEFAULT_CALLTYPE), commonparser(cp), expressionparser( p ),
94  peerparser( c, cp, false ) // accept partial paths
95  {
96  BOOST_SPIRIT_DEBUG_RULE( datacall );
97  BOOST_SPIRIT_DEBUG_RULE( arguments );
98  BOOST_SPIRIT_DEBUG_RULE( peerpath );
99  BOOST_SPIRIT_DEBUG_RULE( object );
100  BOOST_SPIRIT_DEBUG_RULE( method );
101 
102  // this parser uses a neat boost.spirit trick to avoid keeping
103  // loads of stacks for all parsing data ( this parser needs to be
104  // reentrant because it can be called while parsing an argument of
105  // a datacall, which has itself been called while parsing an
106  // argument of a datacall... ). Boost.Spirit allows you to change
107  // the parser that a rule points to at runtime, so we only create
108  // the parser just before it's going to be used, when we know what
109  // arguments we want.. See the ArgumentsParser doc for more
110  // details..
112  object= (commonparser.identifier >> ".")[boost::bind(&DataCallParser::seenobjectname, this, _1, _2)];
113  method= ( commonparser.keyword | expect_ident(commonparser.tidentifier))[boost::bind( &DataCallParser::seenmethodname, this, _1, _2 ) ]; // may be send, call or method name.
114  datacall =
115  ( peerpath >> !object >> method[ boost::bind( &DataCallParser::seendataname, this ) ] >> !arguments)[ boost::bind( &DataCallParser::seendatacall, this ) ];
116  }
117 
119  {
120  std::string name( begin, end );
121  mobject = name.substr(0, name.length() - 1);
122  }
123 
125  {
126  std::string name( begin, end );
127  if ( name == "send" ) {
129  mmethod = mobject;
130  mobject.clear();
131  } else if (name == "cmd" ) {
133  mmethod = mobject;
134  mobject.clear();
135  } else if (name == "call" ) {
137  mmethod = mobject;
138  mobject.clear();
139  } else {
141  mmethod = name;
142  }
143 // cout << "seenmethodname "<< mobject << "." << mmethod<<endl;
144  }
145 
147  {
148  // re-init mobject, might have been cleared during parsing of send(), cmd() or call().
150  TaskContext* peer = peerparser.peer();
152  peerparser.reset();
153 // cout << "seendataname "<< mobject << "." << mmethod<<endl;
154  if (true) {
155  // it ain't...
156  // set the proper object name again in case of a send()
157  if ( (mcalltype != DEFAULT_CALLTYPE) && ops)
158  mobject = ops->getName();
159 // cout << "DCP saw method "<< mmethod <<" of object "<<mobject<<" of peer "<<peer->getName()<<endl;
160  // Check sanity of what we parsed:
161  if (mmethod != "collect" && mmethod != "collectIfDone" ) {
162  if ( ops == 0 || (mobject != "this" && ops->getName() != mobject ) ) {
164  }
165  // Check if method exists on current object:
166  if ( ops->hasMember(mmethod) == false ) {
167  // Check if it is a method of the global service:
168  if ( ops == peerparser.taskObject() && GlobalService::Instance()->hasMember(mmethod) ) {
169  mobject = "GlobalService";
170  ops = GlobalService::Instance();
171  } else {
172  if ( ops == peerparser.taskObject() && ops->hasService("scripting") && ops->provides("scripting")->hasMember(mmethod) ) {
173  mobject = "scripting";
174  ops = ops->provides("scripting");
175  } else {
176  //DumpObject( peer );
177  if ( mobject != "this" )
179  else
181  }
182  }
183  }
184  }
185  }
186 
187  // create an argument parser for the call..
188  // Store everything in the ArgumentsParser ! This DataCallParser instance is recursively called !
189  ArgumentsParser* argspar =
190  new ArgumentsParser( expressionparser, peer, ops,
191  mobject, mmethod );
192  // we no longer need these two..
193  mobject.clear();
194  mmethod.clear();
195  mcmdcnd = 0;
196 
197  // keep hold of the argspar, we're still going to need it after
198  // it's done its work.. ( in seendatacall(), that is.. )
199  argparsers.push( argspar );
200 
201  // set the arguments parser to the parser provided by the
202  // ArgumentsParser we just created..
203  arguments = argspar->parser();
204  }
205 
207  {
208  ArgumentsParser* argspar = argparsers.top();
209  argparsers.pop();
210  std::string obj = argspar->objectname();
211  std::string meth = argspar->methodname();
212  std::vector<DataSourceBase::shared_ptr> args = argspar->result();
213  Service::shared_ptr peer = argspar->object();
214  delete argspar;
215  assert(peer && "peer may never be null.");
216 // cout << "seendatacall "<< mobject << "." << mmethod<<endl;
217 
218  if ( true ) {
219  // plain method or collect/collectIfDone
220 
221  Service::shared_ptr ops = peer;
222  // we already checked for the existence of this object and method
223  // in seendataname()..
224  peerparser.reset();
225 
226  try {
227  if ( (meth == "collect" || meth == "collectIfDone") && !ops->hasMember(mmethod) ) {
228  if ( ops->hasAttribute(obj) ) {
229  SendHandleAlias* sha = dynamic_cast<SendHandleAlias*>( peer->getValue(obj) );
230  if (sha) {
231  // add SendHandle DS for Collect:
232  args.insert( args.begin(), sha->getDataSource() );
233  if (meth == "collect")
234  ret = sha->getFactory()->produceCollect(args, new ValueDataSource<bool>(true) );// blocking
235  else // (meth == "collectIfDone")
236  ret = sha->getFactory()->produceCollect(args, new ValueDataSource<bool>(false) );// non-blocking
237  return;
238  }
239  }
240  throw parse_exception_fatal_semantic_error( obj + "."+meth +": "+ obj +" is not a valid SendHandle object.");
241  }
242 
243  unsigned int arity = ops->getCollectArity(meth);
244  switch(mcalltype) {
245  case DEFAULT_CALLTYPE:
246  case CALLTYPE_CALL:
247  ret = ops->produce( meth, args, mcaller );
248  mhandle.reset();
249  break;
250  case CALLTYPE_SEND:
251  ret = ops->produceSend( meth, args, mcaller );
252  mhandle.reset( new SendHandleAlias( meth, ops->produceHandle(meth), ops->getPart(meth)) );
253  break;
254  case CALLTYPE_CMD:
255  DataSourceBase::shared_ptr sendds = ops->produceSend( meth, args, mcaller );
256  args.clear();
257  args.push_back( sendds ); // store the produceSend DS for collecting:
258  for ( unsigned int i =0; i != arity; ++i) {
259  args.push_back( ops->getOperation(meth)->getCollectType( i + 1 )->buildValue() ); // this is only to satisfy produceCollect. We ignore the results...
260  }
261 
263  = boost::dynamic_pointer_cast<DataSource<SendStatus> >(
264  ops->produceCollect( meth, args, new ValueDataSource<bool>(false) )
265  ); // non-blocking, need extra condition
266  assert(collectds);
267 
268  ret = new ActionAliasDataSource<SendStatus>(new CommandDataSource( sendds ), collectds.get() );
269  mcmdcnd = new CmdCollectCondition( collectds ); // Replaces RTT 1.x completion condition.
270  break;
271  }
272  }
273  catch( const wrong_number_of_args_exception& e )
274  {
276  (obj, meth, e.wanted, e.received );
277  }
278  catch( const wrong_types_of_args_exception& e )
279  {
281  (obj, meth, e.whicharg, e.expected_, e.received_ );
282  }
283  catch( const std::exception& e)
284  {
285  throw parse_exception_fatal_semantic_error("While calling "+obj+"."+meth+": "+e.what());
286  }
287  }
288  assert( ret.get() );
289  }
290 
292  {
293  // if argparsers is not empty, then something went wrong during
294  // the parsing ( someone threw an exception ), and we're
295  // responsible for cleaning up the argparsers we created..
296  while ( ! argparsers.empty() )
297  {
298  delete argparsers.top();
299  argparsers.pop();
300  }
301  }
302 
304  : commonparser(cp), expressionparser( p )
305  {
306  BOOST_SPIRIT_DEBUG_RULE( type_name );
307  BOOST_SPIRIT_DEBUG_RULE( arguments );
308 
309  type_name =
310  ( commonparser.type_name[ boost::bind( &ConstructorParser::seen_type_name, this, _1, _2 ) ] >> !arguments)[ boost::bind( &ConstructorParser::seen_constructor, this ) ];
311  }
312 
314  {
315  // if argparsers is not empty, then something went wrong during
316  // the parsing ( someone threw an exception ), and we're
317  // responsible for cleaning up the argparsers we created..
318  while ( ! argparsers.empty() )
319  {
320  delete argparsers.top();
321  argparsers.pop();
322  }
323  }
324 
325 
327  {
328  std::string name( begin, end );
329  TypeInfo* type = Types()->type( name );
330  if ( type == 0 )
331  throw_(iter_t(), "\"" + name + "\" is an unknown type...");
332 
333  ArgumentsParser* argspar =
335 
336  // keep hold of the argspar, we're still going to need it after
337  // it's done its work.. ( in seen_constructor(), that is.. )
338  argparsers.push( argspar );
339 
340  // set the arguments parser to the parser provided by the
341  // ArgumentsParser we just created..
342  arguments = argspar->parser();
343 
344  }
345 
347  {
348  ArgumentsParser* argspar = argparsers.top();
349  argparsers.pop();
350  std::string obj = argspar->objectname();
351  std::vector<DataSourceBase::shared_ptr> args = argspar->result();
352  delete argspar;
353 
354  ret = TypeInfoRepository::Instance()->type( obj )->construct( args );
355 
356  if (!ret) {
357  throw parse_exception_no_such_constructor( obj, args );
358  }
359 
360  }
361 
363  static void abort_rule(const string& reason) {
364  throw_(iter_t(), reason);
365  }
366 
367  static error_status<> fail_rule(scanner_t const& scan, parser_error<std::string, iter_t>&e )
368  {
369  return error_status<>( error_status<>::fail );
370  }
374  : mcmdcnd(0),
375  datacallparser( *this, cp, pc, caller ),
376  constrparser(*this, cp),
377  commonparser( cp ),
378  valueparser( pc, cp ),
379  _invert_time(false),
380  opreg( OperatorRepository::Instance() ),
381  context(pc)
382  {
383  BOOST_SPIRIT_DEBUG_RULE( expression );
384  BOOST_SPIRIT_DEBUG_RULE( unarynotexp );
385  BOOST_SPIRIT_DEBUG_RULE( unaryminusexp );
386  BOOST_SPIRIT_DEBUG_RULE( unaryplusexp );
387  BOOST_SPIRIT_DEBUG_RULE( div_or_mul );
388  BOOST_SPIRIT_DEBUG_RULE( modexp );
389  BOOST_SPIRIT_DEBUG_RULE( plus_or_min );
390  BOOST_SPIRIT_DEBUG_RULE( smallereqexp );
391  BOOST_SPIRIT_DEBUG_RULE( smallerexp );
392  BOOST_SPIRIT_DEBUG_RULE( greatereqexp );
393  BOOST_SPIRIT_DEBUG_RULE( greaterexp );
394  BOOST_SPIRIT_DEBUG_RULE( equalexp );
395  BOOST_SPIRIT_DEBUG_RULE( notequalexp );
396  BOOST_SPIRIT_DEBUG_RULE( orexp );
397  BOOST_SPIRIT_DEBUG_RULE( andexp );
398  BOOST_SPIRIT_DEBUG_RULE( ifthenelseexp );
399  BOOST_SPIRIT_DEBUG_RULE( groupexp );
400  BOOST_SPIRIT_DEBUG_RULE( dotexp );
401  BOOST_SPIRIT_DEBUG_RULE( atomicexpression );
402  BOOST_SPIRIT_DEBUG_RULE( time_expression );
403  BOOST_SPIRIT_DEBUG_RULE( time_spec );
404  BOOST_SPIRIT_DEBUG_RULE( indexexp );
405  BOOST_SPIRIT_DEBUG_RULE( comma );
406  BOOST_SPIRIT_DEBUG_RULE( close_brace );
407  BOOST_SPIRIT_DEBUG_RULE( value_expression );
408  BOOST_SPIRIT_DEBUG_RULE( call_expression );
409  BOOST_SPIRIT_DEBUG_RULE( constructor_expression );
410 
411  comma = expect_comma( ch_p(',') );
412  close_brace = expect_close( ch_p(')') );
414 
415  // We parse expressions without regard of the types. First we
416  // parse the expressions, then we worry about whether what the
417  // user says is actually valid. You can try to add up two
418  // booleans, and the parser will parse it, but it will notice
419  // you're writing bogus when it tries to pass it to an operator
420  // structure from Operators.hpp
421 
422  // TODO: implement the ifthenelse operator ?
423  assignexp = andexp >> *( ch_p( '=' ) >> eps_p(~ch_p( '=' )) // prevent parsing first '=' of "=="
424  >> assignexp)[ bind( &ExpressionParser::seen_assign, this)];
425  andexp =
426  orexp >> *( ( str_p( "&&" ) ) >> orexp[
427  boost::bind( &ExpressionParser::seen_binary, this, "&&" ) ] );
428  orexp =
429  notequalexp >> *( ( str_p( "||" ) ) >> notequalexp[
430  boost::bind( &ExpressionParser::seen_binary, this, "||" ) ] );
431  notequalexp =
432  equalexp >> *( "!=" >> equalexp[
433  boost::bind( &ExpressionParser::seen_binary, this, "!=" ) ] );
434  equalexp =
436  >> *( "==" >> greatereqexp[
437  boost::bind( &ExpressionParser::seen_binary, this, "==" ) ] );
438  greatereqexp =
439  greaterexp
440  >> *( ">=" >> greaterexp[
441  boost::bind( &ExpressionParser::seen_binary, this, ">=" ) ] );
442  greaterexp =
444  >> *( '>' >> smallereqexp[
445  boost::bind( &ExpressionParser::seen_binary, this, ">" ) ] );
446  smallereqexp =
447  smallerexp
448  >> *( "<=" >> smallerexp[
449  boost::bind( &ExpressionParser::seen_binary, this, "<=" ) ] );
450  smallerexp =
451  plus_or_min >> *( '<' >> plus_or_min[
452  boost::bind( &ExpressionParser::seen_binary, this, "<" ) ] );
453 
454  plus_or_min =
455  modexp >> *( ('-' >> modexp[
456  boost::bind( &ExpressionParser::seen_binary, this, "-" ) ] )
457  | ('+' >> modexp[
458  boost::bind( &ExpressionParser::seen_binary, this, "+" ) ] ) );
459 
460  modexp =
461  div_or_mul >> *( '%' >> div_or_mul[
462  boost::bind( &ExpressionParser::seen_binary, this, "%" ) ] );
463  div_or_mul =
464  unaryplusexp >> *( ('/' >> unaryplusexp[
465  boost::bind( &ExpressionParser::seen_binary, this, "/" ) ] )
466  | ('*' >> unaryplusexp[
467  boost::bind( &ExpressionParser::seen_binary, this, "*" ) ] ) );
468 
469  unaryplusexp =
470  '+' >> unaryminusexp[
471  boost::bind( &ExpressionParser::seen_unary, this, "+" ) ]
472  | unaryminusexp;
473  unaryminusexp =
474  '-' >> unarynotexp[
475  boost::bind( &ExpressionParser::seen_unary, this, "-" ) ]
476  | unarynotexp;
477  unarynotexp =
478  ch_p('!') >> atomicexpression[
479  boost::bind( &ExpressionParser::seen_unary, this, "!" ) ]
481 
482  // note the order is important: commonparser.identifier throws a
483  // useful "cannot use x as identifier" error if it fails, so we
484  // must first show all non-identifier rules.
485  atomicexpression = (
486  // A parenthesis group.
487  groupexp
488  // or a time expression
490  // or a constant or user-defined value..
494  // or an index or dot expression
495  ) >> *( dotexp | indexexp);
496 
497  constructor_expression = my_guard( constrparser.parser()[ boost::bind(&ExpressionParser::seenconstructor, this)])[&fail_rule];
498 
499  // if it's value.keyword then pass it on to the call_expression.
500  value_expression = my_guard( valueparser.parser() >> !('.' >> commonparser.keyword[boost::bind(&abort_rule,"Rule must be handled by datacallparser.")]))[ &fail_rule ]
501  [ bind( &ExpressionParser::seenvalue, this ) ];
502  call_expression = my_guard( datacallparser.parser() )[&fail_rule]
503  [bind( &ExpressionParser::seendatacall, this ) ];
504  // take index of an atomicexpression
505  indexexp =
506  (ch_p('[') >> expression[bind(&ExpressionParser::seen_index, this)] >> expect_close( ch_p( ']') ) );
507 
508  dotexp =
509  ( ch_p('.') >> commonparser.identifier[ boost::bind(&ExpressionParser::seen_dotmember, this, _1, _2)]);
510 
511  // needs no semantic action, its result is already on top of
512  // the stack, where it should be..
513  groupexp = '(' >> expression >> close_brace;
514 
515  // the day i find a clean way to temporarily disable 'eol' skipping, a lot of
516  // grammar will look better...
518  (str_p("time")>>eps_p(~commonparser.identchar | eol_p | end_p ))[bind(&ExpressionParser::seentimeexpr, this)]
519  |
520  ( (eps_p[boost::lambda::var(commonparser.skipeol) = false] >> uint_p[ bind( &ExpressionParser::seentimespec, this, _1 ) ]
521  >> (str_p( "s" ) | "ms" | "us" | "ns" )[boost::lambda::var(commonparser.skipeol) = true][boost::bind( &ExpressionParser::seentimeunit, this, _1, _2 ) ])
522  | (eps_p[boost::lambda::var(commonparser.skipeol) = true] >> nothing_p) // eps_p succeeds always, then fail.
523  )
524  ; // enable skipeol.
525 
526 // >> expect_timespec( (( str_p( ">=" ) | ">" )
527 // |
528 // (str_p("<=") | "<")[bind( &ExpressionParser::inverttime, this)])
529 // >> time_spec);
530 
531 // time_spec =
532 // ( uint_p[ bind( &ExpressionParser::seentimespec, this, _1 ) ]
533 // >>
534 // ( str_p( "s" ) | "ms" | "us" | "ns" )[
535 // bind( &ExpressionParser::seentimeunit, this, _1, _2 ) ] ) | expression[bind(&ExpressionParser::seentimeexpr, this)];
536 
537  }
538 
540  {
541  _invert_time = true;
542  }
543 
545  {
546  parsestack.push( new DataSourceTime() );
547 
548 // DataSourceBase::shared_ptr res = parsestack.top();
549 // parsestack.pop();
550 // DataSource<double>::shared_ptr dres = dynamic_cast<DataSource<double>*>( res.get() );
551 // if ( !dres )
552 // throw parse_exception_semantic_error("Expected time in seconds but expression is not a floating point number.");
553 // DataSourceBase::shared_ptr dsb( new DataSourceCondition( new ConditionDSDuration( dres, _invert_time ) ) );
554 // _invert_time = false;
555 // parsestack.push( dsb );
556  }
557 
559  {
560  // the string starting at begin, ending at end is either ms, us,
561  // ns or s, so we only need to check the first letter...
562  // Convert to seconds...
563  TimeService::Seconds total = 0;
564  switch( *begin )
565  {
566  case 's': total = TimeService::Seconds(tsecs);
567  break;
568  case 'm': total = tsecs / 1000.0;
569  break;
570  case 'u': total = tsecs / 1000000.0;
571  break;
572  case 'n': total = tsecs / 1000000000.0;
573  break;
574  default:
575  std::string arg(begin, end);
576  throw parse_exception_semantic_error("Expected time expression 's', 'ms', 'us' or 'ns' after integer value, got "+arg);
577  }
578 
579  parsestack.push( new ConstantDataSource<double>( total ) );
580 
581 // DataSourceBase::shared_ptr dsb( new DataSourceCondition(
582 // new ConditionDuration( total, _invert_time ) ) );
583 // _invert_time = false;
584 // parsestack.push( dsb );
585  }
586 
588  {
589  tsecs = n;
590  }
591 
593  {
595  parsestack.push( ds );
596  }
597 
599  {
601  parsestack.push( n );
604  }
605 
607  {
609  parsestack.push( n );
610  }
611 
613  {
614  // if parsestack is not empty, then something went wrong, someone
615  // threw an exception, so we clean up..
616  while ( !parsestack.empty() )
617  parsestack.pop();
618  }
619 
621  {
622  return expression;
623  }
624 
626  {
627  assert( !parsestack.empty() );
628  return parsestack.top();
629  }
630 
632  {
633  assert( !parsestack.empty() );
634  return mcmdcnd;
635  }
636 
637  boost::shared_ptr<AttributeBase> ExpressionParser::getHandle()
638  {
639  assert( !parsestack.empty() );
640  return mhandle;
641  }
642 
643  void ExpressionParser::seen_unary( const std::string& op )
644  {
646  if ( ! arg)
647  throw parse_exception_fatal_semantic_error( "Root element not found\"." );
648  parsestack.pop();
650  opreg->applyUnary( op, arg.get() );
651  if ( ! ret )
652  throw parse_exception_fatal_semantic_error( "Cannot apply unary operator \"" + op +
653  "\" to " + arg->getType() +"." );
654  parsestack.push( ret );
655  }
656 
658  {
659  std::string member(s,f);
660  // inspirired on seen_unary
662  parsestack.pop();
663  DataSourceBase::shared_ptr ret = arg->getMember(member);
664  if ( ! ret )
665  throw parse_exception_fatal_semantic_error( arg->getType() + " does not have member \"" + member +
666  "\"." );
667  parsestack.push( ret );
668  }
669 
670  void ExpressionParser::seen_binary( const std::string& op )
671  {
673  parsestack.pop();
675  parsestack.pop();
676 
677  // Arg2 is the first (!) argument, as it was pushed on the stack
678  // first.
680  opreg->applyBinary( op, arg2.get(), arg1.get() );
681  if ( ! ret )
682  throw parse_exception_fatal_semantic_error( "Cannot apply binary operation "+ arg2->getType() +" " + op +
683  " "+arg1->getType() +"." );
684  parsestack.push( ret );
685  }
686 
688  {
690  parsestack.pop(); // right hand side
692  parsestack.pop(); // left hand side
693 
694  // hack to drop-in a new instance of SendHandle:
695  if (arg2->getTypeName() == "SendHandle" && mhandle) {
696 // cout << "Trying to replace SendHandle/..."<<endl;
698  for( ConfigurationInterface::AttributeObjects::iterator it = attrs.begin(); it != attrs.end(); ++it) {
699  if ( (*it)->getDataSource() == arg2 ) { // since the parsestack only saves the DSB, we need to do lookup by DSB and not by name :-(
700 // cout << "Found !"<<endl;
701  string name = (*it)->getName();
703  // This aliasing may happen only once for each var SendHandle. Since 'arg1' is not assignable, a next assigning will fail.
704  if ( dynamic_cast<ValueDataSource<SendStatus>*>(mhandle->getDataSource().get() ) ) {
705  // This goes quite far: we also wrap the SH DataSource in a collect such that evaluating it does not cause a reset()+send(), but merely returns the SendStatus:
707  mhandle->getFactory()->produceCollect(std::vector<DataSourceBase::shared_ptr>(1,arg1), new ValueDataSource<bool>(false)),
708  mhandle->getFactory() ) );
709  parsestack.push( arg1 ); // effectively aliases RHS to lhs. Don't use the SendHandleAlias since it would not do the reset()+send().
710  return;
711  }
712  AttributeBase* var = mhandle->clone();
713  var->setName( name ); // fill in the final handle name.
714  context->attributes()->setValue( var );
715  arg2 = var->getDataSource(); // frees up dummy and puts real one in place.
716  break;
717  }
718  }
719  }
720 
722  ActionInterface* act = 0;
723  try {
724  act = arg2->updateAction( arg1.get() );
725  } catch(...) { // bad assignment
726  throw parse_exception_fatal_semantic_error( "Incompatible types. Cannot assign: "+ arg2->getType() +" = " +
727  " "+arg1->getType() +"." );
728  }
729  if (!act)
730  throw parse_exception_fatal_semantic_error( "2:Cannot assign constant (or returned) variable of types: "+ arg2->getType() +" = " +
731  " "+arg1->getType() );
732  // only try this if not unknown_t.
733  if (arg2->getTypeInfo()->getTypeName() != "unknown_t")
734  ret = arg2->getTypeInfo()->buildActionAlias(act, arg2);
735  if (!ret) { // no type info !
736  ret = new DataSourceCommand( act ); // fall back into the old behavior of returning a boolean.
737  }
738  parsestack.push( ret );
739  }
740 
742  {
744  parsestack.pop();
746  parsestack.pop();
747 
748  // Arg2 is the first (!) argument, as it was pushed on the stack
749  // first.
750  DataSourceBase::shared_ptr ret = arg2->getMember( arg1, 0 );
751  if ( ! ret )
752  throw parse_exception_fatal_semantic_error( "Illegal use of []: "+ arg2->getType() +"[ "
753  +arg1->getType() +" ]." );
754  parsestack.push( ret );
755  }
756 
758  {
759  mcmdcnd = 0;
760  parsestack.pop();
761  }
762 }
bool setValue(base::AttributeBase *ab)
std::vector< base::DataSourceBase::shared_ptr > result()
base::DataSourceBase::shared_ptr ret
virtual result_t get() const =0
rule_t tidentifier
recursive template def.
DataCallParser(ExpressionParser &p, CommonParser &cp, TaskContext *pc, ExecutionEngine *caller)
ConfigurationInterface * attributes()
std::stack< base::DataSourceBase::shared_ptr > parsestack
This interface represents the concept of a condition which can be evaluated and return true or false...
void seen_binary(const std::string &op)
void seenmethodname(iter_t begin, iter_t end)
boost::shared_ptr< SendHandleAlias > mhandle
boost::shared_ptr< SendHandleAlias > mhandle
Definition: mystd.hpp:163
bool skipeol
Saves eol skipping state.
types::OperatorRepository::shared_ptr opreg
virtual DataSourceBase::shared_ptr getDataSource() const =0
base::DataSourceBase::shared_ptr getDataSource() const
ConditionInterface * getCmdResult()
base::DataSourceBase * getParseResult()
void removeAttribute(const std::string &name)
This class contains some very common parser definitions.
base::DataSourceBase::shared_ptr ret
boost::shared_ptr< Service > shared_ptr
Definition: Service.hpp:101
void seen_type_name(iter_t begin, iter_t end)
void seen_dotmember(iter_t begin, iter_t end)
scanner< iter_t, scanner_pol_t > scanner_t
OperationInterfacePart * getFactory() const
boost::shared_ptr< base::AttributeBase > getHandle()
AttributeObjects const & getValues() const
rule_t type_name
See notassertingidentifier, but in lexeme parsing mode.
Based on the software pattern &#39;command&#39;, this interface allows execution of action objects...
base::DataSourceBase::shared_ptr getResult()
rule< scanner_t > rule_t
void seen_unary(const std::string &op)
ConditionInterface * getParseCmdResult()
void seentimeunit(iter_t begin, iter_t end)
TypeInfoRepository::shared_ptr Types()
Definition: Types.cpp:48
enum RTT::scripting::DataCallParser::CallType mcalltype
base::DataSourceBase * getParseResult()
virtual base::DataSourceBase::shared_ptr produceCollect(const std::vector< base::DataSourceBase::shared_ptr > &args, internal::DataSource< bool >::shared_ptr blocking) const =0
ExpressionParser(TaskContext *pc, ExecutionEngine *caller, CommonParser &common_parser)
std::stack< ArgumentsParser * > argparsers
std::stack< ArgumentsParser * > argparsers
std::vector< base::AttributeBase * > AttributeObjects
ConstructorParser(ExpressionParser &p, CommonParser &cp)
boost::intrusive_ptr< DataSourceBase > shared_ptr
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:53
void seenobjectname(iter_t begin, iter_t end)
our_pos_iter_t iter_t
const base::DataSourceBase::shared_ptr lastParsed() const
boost::shared_ptr< SendHandleAlias > getParseHandle()
static RTT_API Service::shared_ptr Instance()
virtual const std::string & getName() const
void setName(std::string const &new_name)
Definition: Attribute.cpp:64


rtt
Author(s): RTT Developers
autogenerated on Fri Oct 25 2019 03:59:33