| The Gaudi Framework v32r1 (f65d50dc)

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 // ============================================================================
22 #include "GaudiKernel/Environment.h"
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 ) {
64 std::unique_ptr<gp::PropertyValue> value;
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: {
92 std::stringstream ss;
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: {
104 std::vector<std::string> result;
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: {
113 std::map<std::string, std::string> result;
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 // ----------------------------------------------------------------------------
177 std::unique_ptr<gp::PropertyValue> value;
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 // ============================================================================
IncludedFiles.h
Analyzer.h
PragmaOptions.h
std::copy
T copy(T... args)
Gaudi::Parsers::PragmaOptions
Definition: PragmaOptions.h:23
format
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:109
Parser.h
System::resolveEnv
GAUDI_API StatusCode resolveEnv(const std::string &var, std::string &res, int recusions=124)
Definition: Environment.cpp:47
gaudiComponentHelp.name
name
Definition: gaudiComponentHelp.py:41
Gaudi::Parsers::ParseUnits
bool ParseUnits(const Position &from, const std::string &filename, const std::string &search_path, IncludedFiles *included, Messages *messages, Node *root)
Definition: Parser.cpp:126
Messages.h
std::stod
T stod(T... args)
std::to_string
T to_string(T... args)
std::left
T left(T... args)
std::end
T end(T... args)
graphanalysis.filename
string filename
Definition: graphanalysis.py:119
Gaudi::Parsers::ReadOptions
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
Property
Gaudi::Details::PropertyBase Property
\fixme backward compatibility hack for old Property base class
Definition: PropertyFwd.h:25
std::map< std::string, std::string >
std::stringstream
STL class.
Catalog.h
std::string
STL class.
Gaudi::Parsers::Units
Definition: Units.h:18
std::vector::push_back
T push_back(T... args)
std::next
T next(T... args)
Gaudi::Parsers::Parse
bool Parse(const std::string &filename, const std::string &search_path, IncludedFiles *included, Messages *messages, Node *root)
Definition: Parser.cpp:114
gaudirun.type
type
Definition: gaudirun.py:142
Node.h
std::stringstream::str
T str(T... args)
Gaudi::Parsers::Messages
Definition: Messages.h:21
std::move
T move(T... args)
PropertyName.h
std::vector< std::string >
std::unique_ptr
STL class.
Units.h
Gaudi::Parsers::Catalog
Definition: Catalog.h:29
std::begin
T begin(T... args)
std::back_inserter
T back_inserter(T... args)
Gaudi::Parsers
Definition: DODBasicMapper.cpp:7
std::map::emplace
T emplace(T... args)
Gaudi::Parsers::Node
Definition: Node.h:25
Environment.h
PropertyValue.h
gaudiComponentHelp.root
root
Definition: gaudiComponentHelp.py:27
std::transform
T transform(T... args)
Gaudi::Parsers::IncludedFiles
Definition: IncludedFiles.h:16
Unreference
bool Unreference(gp::Catalog &catalog, gp::Messages *messages)
Definition: Analyzer.cpp:356
std::vector::reserve
T reserve(T... args)