The Gaudi Framework  v32r2 (46d42edc)
Analyzer.cpp
Go to the documentation of this file.
1 // ============================================================================
2 // STD:
3 // ============================================================================
4 #include <iostream>
5 #include <memory>
6 // ============================================================================
7 // BOOST:
8 // ============================================================================
9 #include <boost/format.hpp>
10 // ============================================================================
11 #include "Analyzer.h"
12 #include "Catalog.h"
13 #include "IncludedFiles.h"
14 #include "Messages.h"
15 #include "Node.h"
16 #include "Parser.h"
17 #include "PragmaOptions.h"
18 #include "PropertyName.h"
19 #include "PropertyValue.h"
20 #include "Units.h"
21 // ============================================================================
23 // ============================================================================
24 namespace gp = Gaudi::Parsers;
25 // ============================================================================
26 static bool IncludeNode( gp::Node* node, const std::string& search_path, gp::IncludedFiles* included,
27  gp::Messages* messages ) {
28  gp::Node include_root;
29  bool status = gp::Parse( node->position, node->value, search_path, included, messages, &include_root );
30  if ( !status ) return false;
31  node->value = include_root.value; // Save absolute file path
32  node->children.reserve( node->children.size() + include_root.children.size() );
33  std::copy( std::begin( include_root.children ), std::end( include_root.children ),
34  std::back_inserter( node->children ) );
35  return true;
36 }
37 // ============================================================================
38 static bool UnitsNode( gp::Node* node, const std::string& search_path, gp::IncludedFiles* included,
39  gp::Messages* messages ) {
40  gp::Node units_root;
41  bool status = gp::ParseUnits( node->position, node->value, search_path, included, messages, &units_root );
42  if ( !status ) return false;
43  node->value = units_root.value; // Save absolute file path
44  node->children.reserve( node->children.size() + units_root.children.size() );
45  std::copy( std::begin( units_root.children ), std::end( units_root.children ), std::back_inserter( node->children ) );
46  return true;
47 }
48 // ============================================================================
49 static std::unique_ptr<gp::PropertyName> GetPropertyName( const gp::Node* node ) {
50  if ( node->children.size() == 1 ) {
51  return std::make_unique<gp::PropertyName>( node->children[0].value, node->position );
52  }
53  std::string delim;
54  std::string client;
55  for ( unsigned int i = 0; i < ( node->children.size() - 1 ); ++i ) {
56  client += delim + node->children[i].value;
57  delim = '.';
58  }
59  return std::make_unique<gp::PropertyName>( client, node->children[node->children.size() - 1].value, node->position );
60 }
61 // ============================================================================
62 static std::unique_ptr<gp::PropertyValue> GetPropertyValue( const gp::Node* node, gp::Catalog* catalog,
63  gp::Units* units ) {
65  switch ( node->type ) {
66  // ------------------------------------------------------------------------
67  case gp::Node::kReal: {
68  // Example:
69  // <real value="10" line="3" column="7">
70  // <identifier value="m" line="3" column="10"/>
71  // </real>
72  //
73  if ( node->children.size() == 1 ) {
74  // Unit is presented
75  std::string unit_name = node->children[0].value;
76  double unit_value = 0;
77  if ( units->Find( unit_name, unit_value ) ) {
78  // We have found a unit
79  double val = std::stod( node->value );
80  value = std::make_unique<gp::PropertyValue>( std::to_string( val * unit_value ) );
81  } else {
82  // Unit not found
83  throw gp::PositionalPropertyValueException::CouldNotFindUnit( node->children[0].position, unit_name );
84  }
85  } else {
86  value = std::make_unique<gp::PropertyValue>( node->value );
87  }
88  break;
89  }
90  // ------------------------------------------------------------------------
91  case gp::Node::kString: {
93  ss << std::quoted( node->value );
94  value = std::make_unique<gp::PropertyValue>( ss.str() );
95  break;
96  }
97  // ------------------------------------------------------------------------
98  case gp::Node::kBool: {
99  value = std::make_unique<gp::PropertyValue>( node->value );
100  break;
101  }
102  // ------------------------------------------------------------------------
103  case gp::Node::kVector: {
105  result.reserve( node->children.size() );
106  std::transform( std::begin( node->children ), std::end( node->children ), std::back_inserter( result ),
107  [&]( const gp::Node& child ) { return GetPropertyValue( &child, catalog, units )->ToString(); } );
108  value = std::make_unique<gp::PropertyValue>( std::move( result ) );
109  break;
110  }
111  // ------------------------------------------------------------------------
112  case gp::Node::kMap: {
114  for ( const auto& child : node->children ) {
115  auto kvalue = GetPropertyValue( &child.children[0], catalog, units );
116  auto vvalue = GetPropertyValue( &child.children[1], catalog, units );
117  result.emplace( kvalue->ToString(), vvalue->ToString() );
118  }
119  value = std::make_unique<gp::PropertyValue>( std::move( result ) );
120  break;
121  }
122  // ------------------------------------------------------------------------
123  case gp::Node::kProperty: {
124  auto property = GetPropertyName( node );
125  gp::Property* exists = catalog->Find( property->client(), property->property() );
126  if ( exists ) {
127  value = std::make_unique<gp::PropertyValue>( exists->property_value() );
128  } else {
129  throw gp::PositionalPropertyValueException::CouldNotFindProperty( node->position, property->ToString() );
130  }
131  break;
132  }
133  case gp::Node::kPropertyRef: {
134  auto property = GetPropertyName( node );
135  // Save a property reference as vector [clientname, property]
136  std::vector<std::string> reference;
137  reference.push_back( property->client() );
138  reference.push_back( property->property() );
139 
140  value = std::make_unique<gp::PropertyValue>( std::move( reference ), property->position(), true );
141  break;
142  }
143  // ------------------------------------------------------------------------
144  default: {
145  assert( false );
146  break;
147  }
148  }
149  return value;
150 }
151 
152 // ============================================================================
153 static std::string SignString( gp::Node::NodeType type ) {
154  switch ( type ) {
155  case gp::Node::kEqual: {
156  return "=";
157  }
158 
159  case gp::Node::kPlusEqual: {
160  return "+=";
161  }
162 
163  case gp::Node::kMinusEqual: {
164  return "-=";
165  }
166  default: {
167  assert( false );
168  break;
169  }
170  }
171  return "unknown";
172 }
173 // ============================================================================
174 static bool AssignNode( const gp::Node* node, gp::Messages* messages, gp::Catalog* catalog, gp::Units* units,
175  bool is_print ) {
176  // ----------------------------------------------------------------------------
178  // ----------------------------------------------------------------------------
179  auto property = GetPropertyName( &node->children[0] );
180  try {
181  value = GetPropertyValue( &node->children[2], catalog, units );
182  } catch ( const gp::PositionalPropertyValueException& ex ) {
183  messages->AddError( ex.position(), ex.what() );
184  return false;
185  }
186  // ------------------------------------------------------------------------
187  bool reassign = false;
188  gp::Property* exists = catalog->Find( property->client(), property->property() );
189  // ----------------------------------------------------------------------------
190  if ( exists ) {
191  // ----------------------------------------------------------------------
192  // If property already exists:
193  // ----------------------------------------------------------------------
194  try {
195  if ( node->children[1].type == gp::Node::kEqual ) {
196  std::string message = str( boost::format( "Reassignment of option '%1%' ." ) % property->FullName() );
197  if ( exists->HasDefinedPosition() ) {
198  message += " Previously defined at " + exists->DefinedPosition().ToString() + ".";
199  }
200  reassign = true;
201  // INFO: we don't need this warning
202  // messages->AddWarning(node->position, message);
203  } else if ( node->children[1].type == gp::Node::kPlusEqual ) {
204  *exists += *value;
205  } else if ( node->children[1].type == gp::Node::kMinusEqual ) {
206  *exists -= *value;
207  }
208  } catch ( const gp::PropertyValueException& ex ) {
209  std::string message = ex.what();
210  if ( exists->HasDefinedPosition() ) {
211  message += " Previously defined at " + exists->DefinedPosition().ToString() + ".";
212  }
213  messages->AddError( node->position, message );
214  return false;
215  }
216  }
217  // ----------------------------------------------------------------------------
218  bool result = true;
219  if ( !exists || reassign ) { result = catalog->Add( new gp::Property( *property, *value ) ); }
220 
221  if ( result && is_print ) { /*;%|72t|%2% %3%*/
222  std::string message = str( boost::format( "%1% %2% %3%" ) % property->FullName() %
223  SignString( node->children[1].type ) % value->ToString() );
224  messages->AddInfo( node->position, message );
225  }
226  return result;
227 }
228 // ============================================================================
229 static bool UnitNode( const gp::Node* node, gp::Messages* messages, gp::Units* units, bool is_print ) {
230  // --------------------------------------------------------------------------
231  double left = std::stod( node->children[0].value );
232  std::string name = node->children[1].value;
233  double right = std::stod( node->children[2].value );
234  // --------------------------------------------------------------------------
235  gp::Units::Container::mapped_type exists;
236  if ( units->Find( name, exists ) ) {
237  std::string message = str( boost::format( "Unit '%1%' already defined" ) % name );
238  if ( exists.second.Exists() ) { message += " at " + exists.second.ToString(); }
239  messages->AddError( node->children[1].position, message );
240  return false;
241  }
242  // --------------------------------------------------------------------------
243  bool result = units->Add( name, right / left, node->children[1].position );
244  if ( result && is_print ) {
245  std::string message = str( boost::format( "%1% %2% = %3%" ) % left % name % right );
246  messages->AddInfo( node->position, message );
247  }
248  return result;
249 }
250 // ============================================================================
251 static bool ConditionNode( gp::Node* node, gp::Catalog* catalog, gp::Node** next ) {
252  // ----------------------------------------------------------------------------
253  auto property_name = GetPropertyName( &node->children[0] );
254  // --------------------------------------------------------------------------
255  bool is_defined = ( nullptr != catalog->Find( property_name->client(), property_name->property() ) );
256  // --------------------------------------------------------------------------
257  if ( ( is_defined && ( node->children[1].type == gp::Node::kIfdef ) ) ||
258  ( !is_defined && ( node->children[1].type == gp::Node::kIfndef ) ) ) {
259  *next = &node->children[1];
260  } else if ( node->children.size() > 2 ) {
261  *next = &node->children[2];
262  } else {
263  *next = nullptr;
264  }
265  return true;
266 }
267 // ============================================================================
268 static bool Analyze( gp::Node* node, const std::string& search_path, gp::IncludedFiles* included,
269  gp::Messages* messages, gp::Catalog* catalog, gp::Units* units, gp::PragmaOptions* pragma ) {
270  // ----------------------------------------------------------------------------
271  bool result = true;
272  bool local_result = true;
273  bool skip_childs = true;
274  gp::Node* next_root = node;
275  // ------------------------------------------------------------------------
276  switch ( node->type ) {
277  // ------------------------------------------------------------------------
278  case gp::Node::kRoot: {
279  skip_childs = false;
280  break;
281  }
282  // ----------------------------------------------------------------------
283  case gp::Node::kInclude: {
284  local_result = IncludeNode( node, search_path, included, messages );
285  skip_childs = false;
286  break;
287  }
288  // ----------------------------------------------------------------------
289  case gp::Node::kUnits: {
290  local_result = UnitsNode( node, search_path, included, messages );
291  skip_childs = false;
292  break;
293  }
294  // ----------------------------------------------------------------------
295  case gp::Node::kAssign: {
296  local_result = AssignNode( node, messages, catalog, units, pragma->is_print() );
297  break;
298  }
299  // ----------------------------------------------------------------------
300  case gp::Node::kUnit: {
301  local_result = UnitNode( node, messages, units, pragma->is_print() );
302  break;
303  }
304  // ----------------------------------------------------------------------
305  case gp::Node::kCondition: {
306  local_result = ConditionNode( node, catalog, &next_root );
307  skip_childs = false;
308  break;
309  }
310 
311  case gp::Node::kPrintOptions: {
312  pragma->setIsPrintOptions( true );
313  break;
314  }
315 
316  case gp::Node::kPrintOn: {
317  pragma->setIsPrint( true );
318  break;
319  }
320 
321  case gp::Node::kPrintOff: {
322  pragma->setIsPrint( false );
323  break;
324  }
325 
326  case gp::Node::kPrintTree: {
327  pragma->setIsPrintTree( true );
328  break;
329  }
330 
331  case gp::Node::kDumpFile: {
332  std::string file = "";
333  if ( System::resolveEnv( node->value, file ) ) {
334  pragma->setDumpFile( file );
335  } else {
336  pragma->setDumpFile( node->value );
337  }
338  break;
339  }
340  // ----------------------------------------------------------------------
341  default: {
342  break;
343  }
344  }
345  if ( result ) result = local_result;
346 
347  if ( !skip_childs && next_root ) {
348  for ( auto& child : next_root->children ) {
349  local_result = Analyze( &child, search_path, included, messages, catalog, units, pragma );
350  if ( result ) result = local_result;
351  }
352  }
353  return result;
354 }
355 
356 bool Unreference( gp::Catalog& catalog, gp::Messages* messages ) {
357  bool unreference_result = true;
358  for ( auto& client : catalog ) {
359  for ( auto& current : client.second ) {
360  if ( current.IsReference() ) {
361  gp::PropertyValue& value = current.property_value();
362  const std::vector<std::string>& names = value.Vector();
363  gp::Property* property = catalog.Find( names[0], names[1] );
364  if ( !property ) {
365  messages->AddError( value.position(), "Could not unreference " + current.ValueAsString() );
366  unreference_result = false;
367  } else {
368  value = property->property_value();
369  }
370  }
371  }
372  }
373  return unreference_result;
374 }
375 
376 // ============================================================================
377 bool gp::ReadOptions( const std::string& filename, const std::string& search_path, Messages* messages, Catalog* catalog,
378  Units* units, PragmaOptions* pragma, Node* root ) {
379  // Extract Path
380  IncludedFiles included;
381  bool result = Parse( filename, search_path, &included, messages, root );
382  if ( !result ) return false;
383 
384  bool result1 = Analyze( root, search_path, &included, messages, catalog, units, pragma );
385  bool result2 = Unreference( *catalog, messages );
386  return result1 && result2;
387 }
388 
389 // ============================================================================
T copy(T... args)
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:109
GAUDI_API StatusCode resolveEnv(const std::string &var, std::string &res, int recusions=124)
Definition: Environment.cpp:47
bool ParseUnits(const Position &from, const std::string &filename, const std::string &search_path, IncludedFiles *included, Messages *messages, Node *root)
Definition: Parser.cpp:126
T stod(T... args)
T to_string(T... args)
T left(T... args)
T end(T... args)
bool ReadOptions(const std::string &filename, const std::string &search_path, Messages *messages, Catalog *catalog, Units *units, PragmaOptions *pragma, Node *root)
Parse and analyze filename, save all messages and properties.
Definition: Analyzer.cpp:377
Gaudi::Details::PropertyBase Property
\fixme backward compatibility hack for old Property base class
Definition: PropertyFwd.h:25
STL class.
T push_back(T... args)
T next(T... args)
bool Parse(const std::string &filename, const std::string &search_path, IncludedFiles *included, Messages *messages, Node *root)
Definition: Parser.cpp:114
T str(T... args)
T move(T... args)
STL class.
T begin(T... args)
T back_inserter(T... args)
T emplace(T... args)
T transform(T... args)
bool Unreference(gp::Catalog &catalog, gp::Messages *messages)
Definition: Analyzer.cpp:356
T reserve(T... args)