From 736d7b993d0506a4291c48bd513e48233284a7c7 Mon Sep 17 00:00:00 2001
From: Markus Frank <Markus.Frank@cern.ch>
Date: Thu, 9 Aug 2018 16:26:46 +0200
Subject: [PATCH] Make the expression evaluator understand variable names with
 namespaces

---
 DDCore/src/plugins/Compact2Objects.cpp        |  6 ++
 DDParsers/src/Evaluator/Evaluator.cpp         |  4 +-
 examples/ClientTests/CMakeLists.txt           | 10 +++
 .../compact/NamespaceConstants.xml            | 28 +++++++
 .../src/TestConstantMultiplier.cpp            | 76 +++++++++++++++++++
 5 files changed, 122 insertions(+), 2 deletions(-)
 create mode 100644 examples/ClientTests/compact/NamespaceConstants.xml
 create mode 100644 examples/ClientTests/src/TestConstantMultiplier.cpp

diff --git a/DDCore/src/plugins/Compact2Objects.cpp b/DDCore/src/plugins/Compact2Objects.cpp
index b83422f20..b4f862a1a 100644
--- a/DDCore/src/plugins/Compact2Objects.cpp
+++ b/DDCore/src/plugins/Compact2Objects.cpp
@@ -96,6 +96,7 @@ namespace {
   bool s_debug_elements     = false;
   bool s_debug_materials    = false;
   bool s_debug_segmentation = false;
+  bool s_debug_constants    = false;
 }
 
 static Ref_t create_ConstantField(Detector& /* description */, xml_h e) {
@@ -249,6 +250,7 @@ template <> void Converter<Debug>::operator()(xml_h e) const {
     else if ( nam.substr(0,6) == "readou" ) s_debug_readout      = (0 != val);
     else if ( nam.substr(0,6) == "limits" ) s_debug_limits       = (0 != val);
     else if ( nam.substr(0,6) == "segmen" ) s_debug_segmentation = (0 != val);
+    else if ( nam.substr(0,6) == "consta" ) s_debug_constants    = (0 != val);
   }
 }
   
@@ -287,6 +289,10 @@ template <> void Converter<Constant>::operator()(xml_h e) const {
     Constant c(nam, val, typ);
     _toDictionary(nam, val, typ);
     description.addConstant(c);
+    if ( s_debug_constants )   {
+      printout(ALWAYS, "Compact",
+               "++ Converting constant %-16s = %-32s [%s]", nam.c_str(), val.c_str(), typ.c_str());
+    }
     return;
   }
   xml::DocumentHolder doc(xml::DocumentHandler().load(e, e.attr_value(_U(ref))));
diff --git a/DDParsers/src/Evaluator/Evaluator.cpp b/DDParsers/src/Evaluator/Evaluator.cpp
index 3e00155d1..9a38df587 100644
--- a/DDParsers/src/Evaluator/Evaluator.cpp
+++ b/DDParsers/src/Evaluator/Evaluator.cpp
@@ -232,7 +232,7 @@ static int operand(pchar begin, pchar end, double & result,
 
   while(pointer <= end) {
     c = *pointer;
-    if (c != '_' && !isalnum(c)) break;
+    if ( !(c == '_' || c == ':') && !isalnum(c)) break;
     pointer++;
   }
   c = *pointer;
@@ -572,7 +572,7 @@ static void setItem(const char * prefix, const char * name,
   }
   for(int i=0; i<n; i++) {
     char c = *(pointer+i);
-    if (c != '_' && !isalnum(c)) {
+    if ( !(c == '_' || c== ':') && !isalnum(c)) {
       s->theStatus = EVAL::ERROR_NOT_A_NAME;
       return;
     }
diff --git a/examples/ClientTests/CMakeLists.txt b/examples/ClientTests/CMakeLists.txt
index 845b9a7ef..d6f124cc7 100644
--- a/examples/ClientTests/CMakeLists.txt
+++ b/examples/ClientTests/CMakeLists.txt
@@ -31,6 +31,16 @@ dd4hep_install_dir( compact scripts ref DESTINATION ${ClientTestsEx_INSTALL} )
 dd4hep_configure_scripts( ClientTests DEFAULT_SETUP WITH_TESTS)
 #---  Testing  ------------------------------------------------------------
 #
+#  Test namespaces for constants 
+dd4hep_add_test_reg( ClientTests_namespace_constants
+  COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_ClientTests.sh"
+  EXEC_ARGS  geoPluginRun -input ${ClientTestsEx_INSTALL}/compact/NamespaceConstants.xml
+  -destroy -plugin DD4hep_VolumeDump -plugin DD4hep_TestConstantsMultiplier
+  REGEX_PASS "Constant: world_z          = world::Z         \\[number\\]  -> 10\\*world_z          =     1e\\+03"
+  REGEX_FAIL "Exception"
+  REGEX_FAIL "FAILED"
+  )
+#
 #  Test JSON based parser
 dd4hep_add_test_reg( ClientTests_MiniTel_JSON_Dump
   COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_ClientTests.sh"
diff --git a/examples/ClientTests/compact/NamespaceConstants.xml b/examples/ClientTests/compact/NamespaceConstants.xml
new file mode 100644
index 000000000..61a87f033
--- /dev/null
+++ b/examples/ClientTests/compact/NamespaceConstants.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<lccdd xmlns:compact="http://www.lcsim.org/schemas/compact/1.0"
+       xmlns:xs="http://www.w3.org/2001/XMLSchema"
+       xs:noNamespaceSchemaLocation="http://www.lcsim.org/schemas/compact/1.0/compact.xsd">
+
+  <define>
+    <constant name="world_side"             value="2*m"/>
+    <constant name="world:X"                value="world_side/2"/>
+    <constant name="world:Y"                value="world:X"/>
+    <constant name="world:Z"                value="world:Y"/>
+    <constant name="world::Z"               value="world:Y"/>
+    <constant name="world_x"                value="world:X"/>
+    <constant name="world_y"                value="world:Y"/>
+    <constant name="world_z"                value="world::Z"/>
+  </define>
+  <debug>
+    <type name="constants" value="1"/>
+  </debug>
+  <includes>
+    <gdmlFile  ref="${DD4hepINSTALL}/DDDetectors/compact/elements.xml"/>
+    <gdmlFile  ref="${DD4hepINSTALL}/DDDetectors/compact/materials.xml"/>
+  </includes>
+  <!--
+  <plugins>
+    <plugin name="DD4hep_TestConstantsMultiplier"/>
+  </plugins>
+  -->
+</lccdd>
diff --git a/examples/ClientTests/src/TestConstantMultiplier.cpp b/examples/ClientTests/src/TestConstantMultiplier.cpp
new file mode 100644
index 000000000..b2e86f94a
--- /dev/null
+++ b/examples/ClientTests/src/TestConstantMultiplier.cpp
@@ -0,0 +1,76 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+/* 
+ Plugin invocation:
+ ==================
+ This plugin behaves like a main program.
+ Invoke the plugin with something like this:
+
+ geoPluginRun -destroy -plugin DD4hep_XML-In-Memory -input <file name>
+
+*/
+// Framework include files
+#include "DD4hep/Printout.h"
+#include "DD4hep/Factories.h"
+#include "DD4hep/Detector.h"
+#include "DD4hep/detail/ObjectsInterna.h"
+#include <fstream>
+#include <cerrno>
+
+using namespace std;
+using namespace dd4hep;
+
+/// Plugin function: Test in memory XML parsing of a simple sub detector
+/**
+ *  Factory: DD4hep_XML-In-Memory
+ *
+ *  Though there is a file name given, it is read FIRST and then parsed.
+ *  Similar to a in memory XML string.
+ *
+ *  \author  M.Frank
+ *  \version 1.0
+ *  \date    20/01/2018
+ */
+static int multiply_constants (Detector& detector, int argc, char** argv)  {
+  bool help = false;
+  for(int i=0; i<argc && argv[i]; ++i)  {
+    if ( 0 == ::strncmp("-help",argv[i],4) )
+      help = true;
+    else
+      help = true;
+  }
+  if ( help )   {
+    /// Help printout describing the basic command line interface
+    cout <<
+      "Usage: -plugin <name> -arg [-arg]                              \n"
+      "     name:   factory name     DD4hep_TestConstantsMultiplier   \n"
+      "\tArguments given: " << arguments(argc,argv) << endl << flush;
+    ::exit(EINVAL);
+  }
+  const auto& constants = detector.constants();
+  for(const auto e : constants)  {
+    Constant c = e.second;
+    if ( c.dataType() == "number" )   {
+      try {
+        double res = _multiply(c.name(),10.0);
+        printout(INFO,"TestConstantsMultiplier","+++ Constant: %-16s = %-16s [%s]  -> 10*%-16s = %9.3g",
+                 c.name(), c->GetTitle(), c.dataType().c_str(), c.name(), res);
+      }
+      catch(...)   {
+      }
+    }
+  }
+  return 1;
+}
+
+DECLARE_APPLY(DD4hep_TestConstantsMultiplier,multiply_constants)
-- 
GitLab