Salome HOME
#1112 tab key doesn't work on the last field of left panels
[modules/shaper.git] / src / ParametersPlugin / ParametersPlugin_PyInterp.cpp
index 92812f50a4c1b9ec1921d3676f61f58953e9bb48..054c8c3e2bdbe1b209c381d7f10551f928dd5c6d 100644 (file)
@@ -8,6 +8,7 @@
 #include <ParametersPlugin_PyInterp.h>
 
 #include <string>
+#include <stdexcept>
 
 ParametersPlugin_PyInterp::ParametersPlugin_PyInterp()
 : PyInterp_Interp()
@@ -18,34 +19,60 @@ ParametersPlugin_PyInterp::~ParametersPlugin_PyInterp()
 {
 }
 
-std::list<std::string> ParametersPlugin_PyInterp::compile(const std::string& theExpression)
+const char* aSearchCode =
+  "import ast\n"
+  "class FindName(ast.NodeVisitor):\n"
+  "    def __init__(self, name):\n"
+  "        self.name = name\n"
+  "    def visit_Name(self, node):\n"
+  "        if node.id == self.name:\n"
+  "            positions.append((node.lineno, node.col_offset))\n"
+  "FindName(name).visit(ast.parse(expression))";
+
+std::list<std::pair<int, int> >
+ParametersPlugin_PyInterp::positions(const std::string& theExpression,
+                                     const std::string& theName)
 {
-  PyGILState_STATE aGilState = PyGILState_Ensure();
-  std::list<std::string>  res = this->_compile(theExpression);
-  PyGILState_Release(aGilState);
-  return res;
-}
+  PyLockWrapper lck; // Acquire GIL until the end of the method
+
+  std::list<std::pair<int, int> > aResult;
+
+  // prepare a context
+  PyObject* aContext = PyDict_New();
+  PyObject* aBuiltinModule = PyImport_AddModule("__builtin__");
+  PyDict_SetItemString(aContext, "__builtins__", aBuiltinModule);
+
+  // extend aContext with variables 
+  PyDict_SetItemString(aContext, "expression", PyString_FromString(theExpression.c_str()));
+  PyDict_SetItemString(aContext, "name", PyString_FromString(theName.c_str()));
+  PyDict_SetItemString(aContext, "positions", Py_BuildValue("[]"));
+
+  // run the search code
+  PyObject* aExecResult = PyRun_String(aSearchCode, Py_file_input, aContext, aContext);
+  Py_XDECREF(aExecResult);
+
+  // receive results from context
+  PyObject* aPositions = PyDict_GetItemString(aContext, "positions");
+  for (int anIndex = 0; anIndex < PyList_Size(aPositions); ++anIndex) {
+    PyObject* aPosition = PyList_GetItem(aPositions, anIndex);
+    PyObject* aLineNo = PyTuple_GetItem(aPosition, 0);
+    PyObject* aColOffset = PyTuple_GetItem(aPosition, 1);
+
+    aResult.push_back(
+        std::pair<int, int>((int)PyInt_AsLong(aLineNo),
+                            (int)PyInt_AsLong(aColOffset)));
+  }
 
-void ParametersPlugin_PyInterp::extendLocalContext(const std::list<std::string>& theParameters)
-{
-  PyGILState_STATE aGilState = PyGILState_Ensure();
-  this->_extendLocalContext(theParameters);
-  PyGILState_Release(aGilState);
-}
+  // TODO(spo): after this refCount of the variable is not 0. Is there memory leak?
+  Py_DECREF(aContext);
 
-double ParametersPlugin_PyInterp::evaluate(const std::string& theExpression,
-                                           std::string& theError)
-{
-  PyGILState_STATE aGilState = PyGILState_Ensure();
-  double res = this->_evaluate(theExpression, theError);
-  PyGILState_Release(aGilState);
-  return res;
+  return aResult;
 }
 
 
-std::list<std::string> ParametersPlugin_PyInterp::_compile(const std::string& theExpression)
+std::list<std::string> ParametersPlugin_PyInterp::compile(const std::string& theExpression)
 {
-
+  PyLockWrapper lck; // Acquire GIL until the end of the method
   std::list<std::string> aResult;
   PyObject *aCodeopModule = PyImport_AddModule("codeop");
   if(!aCodeopModule) { // Fatal error. No way to go on.
@@ -54,7 +81,7 @@ std::list<std::string> ParametersPlugin_PyInterp::_compile(const std::string& th
   }
 
   PyObject *aCodePyObj =
-      PyObject_CallMethod(aCodeopModule, "compile_command", "(s)", theExpression.c_str());
+      PyObject_CallMethod(aCodeopModule, (char*)"compile_command", (char*)"(s)", theExpression.c_str());
 
   if(!aCodePyObj || aCodePyObj == Py_None || !PyCode_Check(aCodePyObj)) {
     Py_XDECREF(aCodePyObj);
@@ -62,10 +89,11 @@ std::list<std::string> ParametersPlugin_PyInterp::_compile(const std::string& th
   }
 
   PyCodeObject* aCodeObj = (PyCodeObject*) aCodePyObj;
+  std::string aCodeName(PyString_AsString(aCodeObj->co_code));
   // co_names should be tuple, but can be changed in modern versions of python (>2.7.3)
   if(!PyTuple_Check(aCodeObj->co_names))
     return aResult;
-  
+
   int params_size = PyTuple_Size(aCodeObj->co_names);
   if (params_size > 0) {
     for (int i = 0; i < params_size; i++) {
@@ -80,15 +108,28 @@ std::list<std::string> ParametersPlugin_PyInterp::_compile(const std::string& th
   return aResult;
 }
 
-void ParametersPlugin_PyInterp::_extendLocalContext(const std::list<std::string>& theParameters)
+void ParametersPlugin_PyInterp::extendLocalContext(const std::list<std::string>& theParameters)
 {
+  PyLockWrapper lck; // Acquire GIL until the end of the method
   if (theParameters.empty())
     return;
+  std::list<std::string>::const_iterator it = theParameters.begin();
+  for ( ; it != theParameters.cend(); it++) {
+    std::string aParamValue = *it;
+    simpleRun(aParamValue.c_str(), false);
+  }
+}
+
+void ParametersPlugin_PyInterp::clearLocalContext()
+{
+  PyLockWrapper lck;
+  PyDict_Clear(_local_context);
 }
 
 
-double ParametersPlugin_PyInterp::_evaluate(const std::string& theExpression, std::string& theError)
+double ParametersPlugin_PyInterp::evaluate(const std::string& theExpression, std::string& theError)
 {
+  PyLockWrapper lck; // Acquire GIL until the end of the method
   PyCodeObject* anExprCode = (PyCodeObject *) Py_CompileString(theExpression.c_str(),
                                                                "<string>", Py_eval_input);
   if(!anExprCode) {
@@ -107,8 +148,16 @@ double ParametersPlugin_PyInterp::_evaluate(const std::string& theExpression, st
 
   PyObject* anEvalStrObj = PyObject_Str(anEvalResult);
   std::string anEvalStr(PyString_AsString(anEvalStrObj));
-  double result = std::stod(anEvalStr);
-
+  Py_XDECREF(anExprCode);
+  Py_XDECREF(anEvalResult);
+  Py_XDECREF(anEvalStrObj);
+  double result = 0.;
+  try {
+    result = std::stod(anEvalStr);
+  } catch (const std::invalid_argument&) {
+    theError = "Unable to eval " + anEvalStr;
+  }
+  
   return result;
 }
 
@@ -128,3 +177,24 @@ std::string ParametersPlugin_PyInterp::errorMessage()
   }
   return aPyError;
 }
+
+bool ParametersPlugin_PyInterp::initContext()
+{
+  PyObject *m = PyImport_AddModule("__main__");  // interpreter main module (module context)
+  if(!m){
+    PyErr_Print();
+    return false;
+  }
+  _global_context = PyModule_GetDict(m);          // get interpreter global variable context
+  Py_INCREF(_global_context);
+  _local_context = PyDict_New();
+  Py_INCREF(_local_context);
+
+  return PyRun_SimpleString("from math import *") == 0;
+}
+
+void ParametersPlugin_PyInterp::closeContext()
+{
+  Py_XDECREF(_local_context);
+  PyInterp_Interp::closeContext();
+}