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