Orocos Real-Time Toolkit  2.9.0
FunctionGraphBuilder.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: Peter Soetens Wed Jan 18 14:11:40 CET 2006 FunctionGraphBuilder.cxx
3 
4  FunctionGraphBuilder.cxx - description
5  -------------------
6  begin : Wed January 18 2006
7  copyright : (C) 2006 Peter Soetens
8  email : peter.soetens@mech.kuleuven.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  * Lesser 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 
39 
40 #include "FunctionGraphBuilder.hpp"
41 #include "CommandComposite.hpp"
42 #include "../base/AttributeBase.hpp"
43 #include "../internal/DataSource.hpp"
44 //#include "parse_exception.hpp"
45 #include "../FactoryExceptions.hpp"
46 #include "GraphCopier.hpp"
47 
48 #include "CommandNOP.hpp"
49 #include "ConditionFalse.hpp"
50 #include "ConditionTrue.hpp"
51 #include "ConditionTrue.hpp"
52 #include <boost/graph/copy.hpp>
53 #include <utility>
54 
55 #include <iostream>
56 
57 namespace RTT {
58  using namespace detail;
59  using namespace boost;
60  using namespace std;
61 
62 
63 
64 
66  : graph( 0 )
67  {
68  }
69 
71  {
72  }
73 
75  {
76  // next node should be 'empty'/ not used here.
77  // a function is to be constructed, it will unload when it stops/errors
78  func.reset( new FunctionGraph( fname, true ) );
79  graph = &func->getGraph();
80  build = func->startNode();
81  next = add_vertex( *graph );
82  put( vertex_exec, *graph, next, VertexNode::normal_node );
83  return func;
84  }
85 
87  {
88  // connect the build node to the exitNode under a condition,
89  // for example, the build implicit term condition.
90  add_edge(build, func->exitNode(), EdgeCondition(cond), *graph);
91  }
92 
94  {
95  return func;
96  }
97 
99  {
100  // the map contains _references_ to all vertex_command properties
101  boost::property_map<Graph, vertex_command_t>::type
102  cmap = get(vertex_command, *graph);
103  cmap[func->exitNode()].setLineNumber( endline );
104 
105  // A return statement is obligatory, so the returnFunction has
106  // already connected the build node to exitNode of the function.
107  // the end of the statement will proceedToNext
108  // remove the empty next nodes.
109  remove_vertex( build, *graph );
110  remove_vertex( next, *graph );
111 
112  func->finish();
113  func->reset();
114 
115  FunctionGraphPtr tfunc = func;
116  func.reset();
117  return tfunc;
118  }
119 
121  {
122  add_edge(build, next, EdgeCondition(cond), *graph);
123  build = next;
124  setCommand(com);
125  next = add_vertex( *graph );
126  put( vertex_exec, *graph, next, VertexNode::normal_node );
127  return next;
128  }
129 
131  {
132  add_edge(build, vert, EdgeCondition(cond), *graph);
133  }
134 
136  {
137  add_edge(vert, build, EdgeCondition(cond), *graph);
138  }
139 
141  {
142  this->setLineNumber( linenumber );
143  CommandNode old = build;
144  build = _build;
145  next = _next;
146  return old;
147  }
148 
150  {
151  // the map contains _references_ to all vertex_command properties
152  boost::property_map<Graph, vertex_command_t>::type
153  cmap = get(vertex_command, *graph);
154  // access the one of build
155  return cmap[cn].getCommand();
156  }
157 
159  {
160  this->setCommand(build, comm);
161  }
162 
164  {
165  // the map contains _references_ to all vertex_command properties
166  boost::property_map<Graph, vertex_command_t>::type
167  cmap = get(vertex_command, *graph);
168  // access the one of build
169  delete cmap[cn].setCommand( comm );
170  }
171 
172  void FunctionGraphBuilder::setName(const std::string& pname) {
173  func->setName(pname);
174  }
175 
177  {
178  add_edge(build, next, EdgeCondition(cond), *graph);
179  return proceedToNext( this_line );
180  }
181 
183  {
184  if ( this_line )
185  this->setLineNumber( this_line );
186  build = next;
187  next = add_vertex( *graph );
188  put(vertex_exec, *graph, next, VertexNode::normal_node );
189  return build;
190  }
191 
193  {
194  add_edge( v, next, EdgeCondition(cond), *graph);
195  }
196 
198  {
199  return build;
200  }
201 
203  {
204  return out_degree( build, *graph );
205  }
206 
208  {
209  return next;
210  }
211 
213  {
214  boost::property_map<Graph, vertex_command_t>::type
215  cmap = get(vertex_command, *graph);
216  cmap[build].setLineNumber( line );
217  }
218 
219 
220  template< class _Map >
221  struct finder {
223  typedef std::pair<_Map, int> second_argument_type ;
224  typedef bool result_type;
226  const std::pair<_Map, int>& to_find ) const
227  {
228  // return : Is this the node with the given property ?
229  return to_find.first[v] == to_find.second;
230  }
231  };
232 
234  std::vector<DataSourceBase::shared_ptr> fnargs )
235  {
239  // Do not move build inhere !
240  // copy FunctionGraph's graph into the current *graph, add an edge with
241  // the condition. Connect the exitNode() of the function with
242  // the next node.
243 
244  // The reason to reindex the vertexes of source graph is
245  // to silence valgrinds warnings about uninitialised values
246  // in the following piece of code. Technically, copy_graph
247  // does not need it.
248  boost::property_map<Graph, vertex_index_t>::type indexmap =
249  get( vertex_index, *graph );
250  boost::graph_traits<Graph>::vertex_iterator v, vend;
251  int index = 0;
252  for ( tie( v, vend ) = vertices( *graph ); v != vend; ++v )
253  indexmap[*v] = index++;
254 
255  // check nb of arguments:
256  std::vector<AttributeBase*> origlist = fn->getArguments();
257  if ( fnargs.size() != origlist.size() ) {
258 #ifndef ORO_EMBEDDED
259  throw wrong_number_of_args_exception( origlist.size(), fnargs.size() );
260 #else
261  return buildNode();
262 #endif
263  }
264 
265  // make a deep copy of the function :
266  std::map<const DataSourceBase*, DataSourceBase*> replacementdss;
267  std::vector<AttributeBase*> newlist;
268  for (unsigned int i=0; i < origlist.size(); ++i)
269  newlist.push_back( origlist[i]->copy( replacementdss, false ) ); // args are not instantiated.
270  // newlist contains the DS which need initialisations :
271 
272  // create commands that init all the args :
273  CommandComposite* icom= new CommandComposite();
274  std::vector<DataSourceBase::shared_ptr>::const_iterator dit = fnargs.begin();
275  std::vector<AttributeBase*>::const_iterator tit = newlist.begin();
276 #ifndef ORO_EMBEDDED
277  try {
278  for (; dit != fnargs.end(); ++dit, ++tit)
279  icom->add( (*tit)->getDataSource()->updateAction( dit->get() ) );
280  }
281  catch( const bad_assignment& ) {
282  // cleanup allocated memory
283  for (unsigned int i=0; i < newlist.size(); ++i)
284  delete newlist[i];
285  delete icom;
286  int parnb = (dit - fnargs.begin());
287  throw wrong_types_of_args_exception(parnb, (*tit)->getDataSource()->getType() ,(*dit)->getType() );
288  }
289 #else
290  for (; dit != fnargs.end(); ++dit, ++tit) {
291  ActionInterface* ret = (*tit)->getDataSource()->updateAction( dit->get() );
292  if (ret)
293  icom->add( ret );
294  else {
295  // cleanup allocated memory
296  for (unsigned int i=0; i < newlist.size(); ++i)
297  delete newlist[i];
298  delete icom;
299  return buildNode();
300  }
301  }
302 #endif
303  // set the init command on the build node
304  //assert( build not used by other than NOP )
305  assert( dynamic_cast<CommandNOP*>( this->getCommand(build) ));
306  this->setCommand( icom );
307 
308  GraphVertexCopier gvc( fn->getGraph(), *graph, replacementdss );
309  GraphEdgeCopier gec( fn->getGraph(), *graph, replacementdss );
310 
311  // This gives a compiler warning with GCC:
312  boost::copy_graph( fn->getGraph(), *graph, boost::vertex_copy( gvc ).edge_copy( gec ) );
313  // It's a bug in boost::copy_graph with 3 arguments. We'd have to implement the copy ourselves
314  // in order to get rid of this warning/bug.
315 
316  // cleanup newlist, the (var)DS's are stored in the assignCommand
317  for (unsigned int i=0; i < newlist.size(); ++i)
318  delete newlist[i];
319 
320  // the subgraph has been copied but is now 'floating' in the current graph.
321  // we search func start and exit points and connect them to
322  // the current graph.
323 
324  // domi: it would be cleaner if a function would keep a
325  // reference to its enter and exit point, and we would use the
326  // copy_graph orig_to_copy map to find the corresponding nodes
327  // in the copy...
328  graph_traits<Graph>::vertex_iterator v1,v2, vc;
329  tie(v1,v2) = vertices(*graph);
330  boost::property_map<Graph, vertex_exec_t>::type
331  vmap = get(vertex_exec, *graph);
332 
333 // // test not initialised value.
334 // vc = v1;
335 // while (vc != v2) {
336 // std::cerr << int( vmap[*vc] )<<std::endl;
337 // ++vc;
338 // }
339 // std::cerr<<std::endl;
340 // // test foo :
341 // tie(v1,v2) = vertices(fn->getGraph());
342 // vmap = get(vertex_exec, fn->getGraph());
343 // vc = v1;
344 // while (vc != v2) {
345 // std::cerr << int( vmap[*vc] )<<std::endl;
346 // ++vc;
347 // }
348 
349 
350  Vertex funcStart=*
351  find_if(v1, v2,
352  bind2nd( finder<boost::property_map<Graph, vertex_exec_t>::type>() ,
353  std::make_pair( vmap, int(VertexNode::func_start_node)) ) );
354  Vertex funcExit=*
355  find_if(v1, v2,
356  bind2nd( finder<boost::property_map<Graph, vertex_exec_t>::type>() ,
357  std::make_pair( vmap, int(VertexNode::func_exit_node)) ) );
358 
359  // reset their special meanings.
360  vmap[funcStart] = VertexNode::normal_node;
361  vmap[funcExit] = VertexNode::normal_node;
362  // connect the graph.
363  addConditionEdge( cond, funcStart );
364  connectToNext( funcExit, new ConditionTrue );
365 
366  return funcExit;
367 // // try to solve call in function bug with arguments
368 // boost::property_map<Graph, vertex_command_t>::type
369 // cmap = get(vertex_command, *graph);
370 // return proceedToNext( cmap[funcExit].getLineNumber() );
371  }
372 
374  std::vector<DataSourceBase::shared_ptr> fnargs )
375  {
384  return appendFunction( new ConditionTrue, fn, fnargs) ;
385  }
386 
388  {
389  // push all relevant nodes on the branch_stack.
390  // endIf and endElse will pop them
391 
392  // * next will become the first node of the succeeding if statement
393  // * after_else_node will become the node after the if block is finished
394  // and the else block is finished.
395  // * else_node is the first node of a failing if statement (this may be _any_statement, thus also an if)
396  CommandNode else_node = add_vertex( *graph );
397  put(vertex_exec, *graph, else_node, VertexNode::normal_node );
398  branch_stack.push( else_node );
399  CommandNode after_else_node = add_vertex( *graph );
400  put(vertex_exec, *graph, after_else_node, VertexNode::normal_node );
401  branch_stack.push( after_else_node );
402  //branch_stack.push( build );
403 
404  // add edge from build to next
405  addConditionEdge( cond, next );
406  // add edge from build to 'after_else_node'
407  addConditionEdge( new ConditionTrue(), else_node );
408  proceedToNext(linenumber);
409  }
410 
411  void FunctionGraphBuilder::endIfBlock(int linenumber){
412  // this is called after a proceedToNext of the last statement of
413  // the if block.
414  // Connect end of if block with after_else_node
415  CommandNode after_else_node = branch_stack.top();
416  addConditionEdge( new ConditionTrue(), after_else_node );
417  branch_stack.pop();
418  // make else_node build, next remains.
419  moveTo( branch_stack.top(), next, linenumber );
420  branch_stack.pop();
421  // store again !
422  branch_stack.push( after_else_node );
423  }
424 
425  // Else : can be empty and is then a plain proceed to next.
426  void FunctionGraphBuilder::endElseBlock(int linenumber) {
427  // after_else_node is on top of stack
428  CommandNode after_else_node = branch_stack.top();
429  branch_stack.pop();
430  addConditionEdge( new ConditionTrue(), after_else_node );
431  // make after_else_node build
432  moveTo( after_else_node, next, linenumber );
433  }
434 
436  {
437  // very analogous to the if statement, but there is no else part
438  // and we stack the first commandnode to be able to close the loop.
439  CommandNode after_while_node = add_vertex( *graph );
440  put(vertex_exec, *graph, after_while_node, VertexNode::normal_node );
441  branch_stack.push( after_while_node );
442  break_stack.push( after_while_node );
443  branch_stack.push( build );
444  // add edge from build to next if condition == true
445  addConditionEdge( cond, next );
446  // if condition fails, go from build to 'after_while_node'
447  addConditionEdge( new ConditionTrue(), after_while_node );
448  proceedToNext(linenumber);
449  }
450 
452  {
453  CommandNode start_of_while = branch_stack.top();
454  branch_stack.pop();
455  // go from build back to start (and check there the condition).
456  addConditionEdge( new ConditionTrue(), start_of_while );
457  CommandNode after_while_node = branch_stack.top();
458  branch_stack.pop();
459  break_stack.pop();
460  moveTo( after_while_node, next, linenumber );
461  }
462 
464  {
465  return break_stack.size() != 0;
466  }
467 
469  {
470  if ( !inLoop() )
471  return false;
472 
473  // go from build to last nested exit point.
474  addConditionEdge( new ConditionTrue(), break_stack.top() );
475  return true;
476  }
477 
478 #if 0
479  void FunctionGraphBuilder::prependCommand( ActionInterface* command, int line_nr )
480  {
481  CommandNode previousstart = start;
482  start = add_vertex( program );
483  boost::property_map<Graph, vertex_exec_t>::type
484  vmap = get(vertex_exec, program);
485  put( vmap, start, get( vmap, previousstart ) );
486  put( vmap, previousstart, VertexNode::normal_node );
487  boost::property_map<Graph, vertex_command_t>::type
488  cmap = get( vertex_command, program );
489  VertexNode vnode( command );
490  vnode.setLineNumber( line_nr );
491  put( cmap, start, vnode );
492  add_edge(start, previousstart, EdgeCondition(new ConditionTrue), program);
493  if ( build == previousstart )
494  build = start;
495 
496  // now let's reindex the vertices...
497  boost::property_map<Graph, vertex_index_t>::type indexmap =
498  get( vertex_index, *graph );
499  boost::graph_traits<Graph>::vertex_iterator v, vend;
500  int index = 0;
501  for ( tie( v, vend ) = vertices( *graph ); v != vend; ++v )
502  indexmap[*v] = index++;
503  }
504 #endif
505 
506 }
507 
std::pair< _Map, int > second_argument_type
boost::shared_ptr< FunctionGraph > FunctionGraphPtr
CommandNode next
The node which will be built next.
CommandNode nextNode() const
Return the next CommandNode.
This class represents elements in a program tree.
Definition: VertexNode.hpp:76
This interface represents the concept of a condition which can be evaluated and return true or false...
STL namespace.
A conditional that evaluates true.
base::ActionInterface * getCommand(CommandNode cn)
Get the Command on a given CommandNode.
CommandNode setFunction(FunctionGraphPtr fn, std::vector< base::DataSourceBase::shared_ptr > fnargs)
Put a function in the build CommandNode.
void startIfStatement(ConditionInterface *cond, int linenumber)
void closeConditionEdge(CommandNode vert, ConditionInterface *cond)
Add an edge between the given CommandNode and the build CommandNode.
void returnFunction(ConditionInterface *cond, int line)
Function return is detected inside the function.
void connectToNext(CommandNode v, ConditionInterface *cond)
Connect the given CommandNode to the &#39;next&#39; CommandNode.
This exception is thrown if the target and source type of an assignment of a DataSource with a base::...
Definition: DataSource.hpp:62
void startWhileStatement(ConditionInterface *cond, int linenumber)
void setLineNumber(int ln)
Set the line number of the build command node.
FunctionGraphPtr getFunction()
Return a pointer to the function being built, zero if none.
CommandNode build
The node which will be built next.
CommandNode moveTo(CommandNode _build, CommandNode _next, int linenr)
Select an already added CommandNode.
Based on the software pattern &#39;command&#39;, this interface allows execution of action objects...
FunctionGraphPtr endFunction(int line=0)
Finish building the function and return the result.
size_t buildEdges() const
Return the number of edges of the build CommandNode.
boost::graph_traits< Graph >::vertex_descriptor Vertex
void setName(const std::string &_name)
FunctionGraphBuilder::Vertex first_argument_type
void setCommand(base::ActionInterface *comm)
Sets a new Command on the build CommandNode.
void setLineNumber(int ln)
Set line number of this program node to given line number.
Definition: VertexNode.cpp:95
virtual void add(base::ActionInterface *com)
add a command to the vect
CommandNode buildNode() const
Return the build CommandNode.
Exception thrown when a factory is requested to create an object, but a wrong argument type was given...
Exception thrown when a factory is requested to create an object but the wrong number of arguments wa...
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:52
This class represents a function.
This class represents a conditional branch in a program tree.
FunctionGraphBuilder()
Constructs a Function graph builder.
bool operator()(const FunctionGraphBuilder::Vertex &v, const std::pair< _Map, int > &to_find) const
void addConditionEdge(ConditionInterface *cond, CommandNode vert)
Add an edge from the build CommandNode to the given CommandNode without changing the build CommandNod...
Based on the software pattern &#39;composite&#39;, this class RTT_SCRIPTING_API allows composing command obje...
FunctionGraph::Vertex CommandNode
A CommandNode serves as a token to construct a vertex or node, containing a command.
CommandNode appendFunction(ConditionInterface *cond, FunctionGraphPtr fn, std::vector< base::DataSourceBase::shared_ptr > fnargs)
Append a function to the build CommandNode.
CommandNode proceedToNext(int line_nr=0)
Proceed to the &#39;next&#39; CommandNode.
CommandNode addCommand(ConditionInterface *cond, base::ActionInterface *com)
Add a new command from the build CommandNode under a condition.
FunctionGraphPtr startFunction(const std::string &fname)
Start building a new function.