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