The Gaudi Framework  master (37c0b60a)
Analyzer.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2024 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"
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"
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 #if __GNUC__ >= 12
121 # pragma GCC diagnostic push
122 // hide gcc 12 warning (false positive? see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107138)
123 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
124 #endif
125  value = std::make_unique<gp::PropertyValue>( std::move( result ) );
126 #if __GNUC__ >= 12
127 # pragma GCC diagnostic pop
128 #endif
129  break;
130  }
131  // ------------------------------------------------------------------------
132  case gp::Node::kProperty: {
133  auto property = GetPropertyName( node );
134  gp::Property* exists = catalog->Find( property->client(), property->property() );
135  if ( exists ) {
136  value = std::make_unique<gp::PropertyValue>( exists->property_value() );
137  } else {
139  }
140  break;
141  }
142  case gp::Node::kPropertyRef: {
143  auto property = GetPropertyName( node );
144  // Save a property reference as vector [clientname, property]
146  reference.push_back( property->client() );
147  reference.push_back( property->property() );
148 
149  value = std::make_unique<gp::PropertyValue>( std::move( reference ), property->position(), true );
150  break;
151  }
152  // ------------------------------------------------------------------------
153  default: {
154  assert( false );
155  break;
156  }
157  }
158  return value;
159 }
160 
161 // ============================================================================
162 static std::string SignString( gp::Node::NodeType type ) {
163  switch ( type ) {
164  case gp::Node::kEqual: {
165  return "=";
166  }
167 
168  case gp::Node::kPlusEqual: {
169  return "+=";
170  }
171 
172  case gp::Node::kMinusEqual: {
173  return "-=";
174  }
175  default: {
176  assert( false );
177  break;
178  }
179  }
180  return "unknown";
181 }
182 // ============================================================================
183 static bool AssignNode( const gp::Node* node, gp::Messages* messages, gp::Catalog* catalog, gp::Units* units,
184  bool is_print ) {
185  // ----------------------------------------------------------------------------
187  // ----------------------------------------------------------------------------
188  auto property = GetPropertyName( &node->children[0] );
189  try {
190  value = GetPropertyValue( &node->children[2], catalog, units );
191  } catch ( const gp::PositionalPropertyValueException& ex ) {
192  messages->AddError( ex.position(), ex.what() );
193  return false;
194  }
195  // ------------------------------------------------------------------------
196  bool reassign = false;
197  gp::Property* exists = catalog->Find( property->client(), property->property() );
198  // ----------------------------------------------------------------------------
199  if ( exists ) {
200  // ----------------------------------------------------------------------
201  // If property already exists:
202  // ----------------------------------------------------------------------
203  try {
204  if ( node->children[1].type == gp::Node::kEqual ) {
205  std::string message = fmt::format( "Reassignment of option '{}'.", property->FullName() );
206 
207  if ( exists->HasDefinedPosition() ) {
208  message += fmt::format( " Previously defined at {}.", exists->DefinedPosition().ToString() );
209  }
210  reassign = true;
211  // INFO: we don't need this warning
212  // messages->AddWarning(node->position, message);
213  } else if ( node->children[1].type == gp::Node::kPlusEqual ) {
214  *exists += *value;
215  } else if ( node->children[1].type == gp::Node::kMinusEqual ) {
216  *exists -= *value;
217  }
218  } catch ( const gp::PropertyValueException& ex ) {
219  std::string message = ex.what();
220  if ( exists->HasDefinedPosition() ) {
221  message += fmt::format( " Previously defined at {}.", exists->DefinedPosition().ToString() );
222  }
223  messages->AddError( node->position, message );
224  return false;
225  }
226  }
227  // ----------------------------------------------------------------------------
228  bool result = true;
229  if ( !exists || reassign ) { result = catalog->Add( new gp::Property( *property, *value ) ); }
230 
231  if ( result && is_print ) {
233  fmt::format( "{} {} {}", property->FullName(), SignString( node->children[1].type ), value->ToString() );
234  messages->AddInfo( node->position, message );
235  }
236  return result;
237 }
238 // ============================================================================
239 static bool UnitNode( const gp::Node* node, gp::Messages* messages, gp::Units* units, bool is_print ) {
240  // --------------------------------------------------------------------------
241  double left = std::stod( node->children[0].value );
242  std::string name = node->children[1].value;
243  double right = std::stod( node->children[2].value );
244  // --------------------------------------------------------------------------
245  gp::Units::Container::mapped_type exists;
246  if ( units->Find( name, exists ) ) {
247  std::string message = fmt::format( "Unit '{}' already defined", name );
248  if ( exists.second.Exists() ) { message += " at " + exists.second.ToString(); }
249  messages->AddError( node->children[1].position, message );
250  return false;
251  }
252  // --------------------------------------------------------------------------
253  bool result = units->Add( name, right / left, node->children[1].position );
254  if ( result && is_print ) {
255  std::string message = fmt::format( "{} {} = {}", left, name, right );
256  messages->AddInfo( node->position, message );
257  }
258  return result;
259 }
260 // ============================================================================
261 static bool ConditionNode( gp::Node* node, gp::Catalog* catalog, gp::Node** next ) {
262  // ----------------------------------------------------------------------------
263  auto property_name = GetPropertyName( &node->children[0] );
264  // --------------------------------------------------------------------------
265  bool is_defined = ( nullptr != catalog->Find( property_name->client(), property_name->property() ) );
266  // --------------------------------------------------------------------------
267  if ( ( is_defined && ( node->children[1].type == gp::Node::kIfdef ) ) ||
268  ( !is_defined && ( node->children[1].type == gp::Node::kIfndef ) ) ) {
269  *next = &node->children[1];
270  } else if ( node->children.size() > 2 ) {
271  *next = &node->children[2];
272  } else {
273  *next = nullptr;
274  }
275  return true;
276 }
277 // ============================================================================
278 static bool Analyze( gp::Node* node, std::string_view search_path, gp::IncludedFiles* included, gp::Messages* messages,
279  gp::Catalog* catalog, gp::Units* units, gp::PragmaOptions* pragma ) {
280  // ----------------------------------------------------------------------------
281  bool result = true;
282  bool local_result = true;
283  bool skip_childs = true;
284  gp::Node* next_root = node;
285  // ------------------------------------------------------------------------
286  switch ( node->type ) {
287  // ------------------------------------------------------------------------
288  case gp::Node::kRoot: {
289  skip_childs = false;
290  break;
291  }
292  // ----------------------------------------------------------------------
293  case gp::Node::kInclude: {
294  local_result = IncludeNode( node, search_path, included, messages );
295  skip_childs = false;
296  break;
297  }
298  // ----------------------------------------------------------------------
299  case gp::Node::kUnits: {
300  local_result = UnitsNode( node, search_path, included, messages );
301  skip_childs = false;
302  break;
303  }
304  // ----------------------------------------------------------------------
305  case gp::Node::kAssign: {
306  local_result = AssignNode( node, messages, catalog, units, pragma->is_print() );
307  break;
308  }
309  // ----------------------------------------------------------------------
310  case gp::Node::kUnit: {
311  local_result = UnitNode( node, messages, units, pragma->is_print() );
312  break;
313  }
314  // ----------------------------------------------------------------------
315  case gp::Node::kCondition: {
316  local_result = ConditionNode( node, catalog, &next_root );
317  skip_childs = false;
318  break;
319  }
320 
322  pragma->setIsPrintOptions( true );
323  break;
324  }
325 
326  case gp::Node::kPrintOn: {
327  pragma->setIsPrint( true );
328  break;
329  }
330 
331  case gp::Node::kPrintOff: {
332  pragma->setIsPrint( false );
333  break;
334  }
335 
336  case gp::Node::kPrintTree: {
337  pragma->setIsPrintTree( true );
338  break;
339  }
340 
341  case gp::Node::kDumpFile: {
342  std::string file = "";
343  if ( System::resolveEnv( node->value, file ) ) {
344  pragma->setDumpFile( file );
345  } else {
346  pragma->setDumpFile( node->value );
347  }
348  break;
349  }
350  // ----------------------------------------------------------------------
351  default: {
352  break;
353  }
354  }
355  if ( result ) result = local_result;
356 
357  if ( !skip_childs && next_root ) {
358  for ( auto& child : next_root->children ) {
359  local_result = Analyze( &child, search_path, included, messages, catalog, units, pragma );
360  if ( result ) result = local_result;
361  }
362  }
363  return result;
364 }
365 
366 bool Unreference( gp::Catalog& catalog, gp::Messages* messages ) {
367  bool unreference_result = true;
368  for ( auto& client : catalog ) {
369  for ( auto& current : client.second ) {
370  if ( current.IsReference() ) {
371  gp::PropertyValue& value = current.property_value();
372  const std::vector<std::string>& names = value.Vector();
373  gp::Property* property = catalog.Find( names[0], names[1] );
374  if ( !property ) {
375  messages->AddError( value.position(), "Could not unreference " + current.ValueAsString() );
376  unreference_result = false;
377  } else {
378  value = property->property_value();
379  }
380  }
381  }
382  }
383  return unreference_result;
384 }
385 
386 // ============================================================================
387 bool gp::ReadOptions( std::string_view filename, std::string_view search_path, Messages* messages, Catalog* catalog,
388  Units* units, PragmaOptions* pragma, Node* root ) {
389  // Extract Path
390  IncludedFiles included;
391  bool result = Parse( filename, search_path, &included, messages, root );
392  if ( !result ) return false;
393 
394  bool result1 = Analyze( root, search_path, &included, messages, catalog, units, pragma );
395  bool result2 = Unreference( *catalog, messages );
396  return result1 && result2;
397 }
398 
399 // ============================================================================
Gaudi::Parsers::Node::value
std::string value
Definition: Node.h:70
Gaudi::Parsers::Node::kPrintOptions
@ kPrintOptions
Definition: Node.h:60
precedence.message
message
Definition: precedence.py:19
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:42
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
Gaudi::Parsers::PositionalPropertyValueException::CouldNotFindUnit
static PositionalPropertyValueException CouldNotFindUnit(const Position &position, const std::string &name)
Definition: PropertyValue.h:102
PropertyValue.h
IncludedFiles.h
Gaudi::Parsers::PragmaOptions
Definition: PragmaOptions.h:33
Gaudi::Parsers::Node::kPlusEqual
@ kPlusEqual
Definition: Node.h:45
Gaudi::Utils::begin
AttribStringParser::Iterator begin(const AttribStringParser &parser)
Definition: AttribStringParser.h:136
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:110
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)
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:387
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
ConditionsStallTest.name
name
Definition: ConditionsStallTest.py:77
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)
fixtures.reference
Generator[dict, None, None] reference(request, Optional[Path] reference_path)
Definition: fixtures.py:211
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)
IOTest.end
end
Definition: IOTest.py:125
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:122
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:366
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.
graphanalysis.filename
filename
Definition: graphanalysis.py:130
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