#include <ParametersPlugin_PyInterp.h>
#include <string>
+#include <stdexcept>
ParametersPlugin_PyInterp::ParametersPlugin_PyInterp()
: PyInterp_Interp()
{
}
-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.
}
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++) {
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) {
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;
}
}
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();
+}