| /* |
| Copyright 2019 Alain Dargelas |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| /* |
| * File: PythonAPI.cpp |
| * Author: alain |
| * |
| * Created on May 13, 2017, 4:42 PM |
| */ |
| |
| #include "../SourceCompile/SymbolTable.h" |
| #include "../Utils/StringUtils.h" |
| #include "../Utils/FileUtils.h" |
| #include "../CommandLine/CommandLineParser.hpp" |
| #include "../ErrorReporting/ErrorContainer.h" |
| #include "../SourceCompile/CompilationUnit.h" |
| #include "../SourceCompile/PreprocessFile.h" |
| #include "../SourceCompile/CompileSourceFile.h" |
| #include "../SourceCompile/Compiler.h" |
| #include "../SourceCompile/ParseFile.h" |
| #include "antlr4-runtime.h" |
| using namespace std; |
| using namespace antlr4; |
| |
| #include "../parser/SV3_1aParserBaseListener.h" |
| |
| #include "SV3_1aPythonListener.h" |
| |
| using namespace SURELOG; |
| |
| #include <sstream> |
| #include <string> |
| #include <fstream> |
| #include <iostream> |
| #include <cstdio> |
| #include "Python.h" |
| #include "PythonAPI.h" |
| #include "SLAPI.h" |
| #include "slapi_wrap.cxx" |
| #include "slapi.h" |
| #include "vobjecttypes_py.h" |
| #include <cstdlib> |
| #include "../SourceCompile/PythonListen.h" |
| |
| |
| std::string PythonAPI::m_invalidScriptResult = "INVALID_PYTHON_SCRIPT_RESULT"; |
| |
| PyThreadState * PythonAPI::m_mainThreadState = NULL; |
| |
| std::string PythonAPI::m_programPath = ""; |
| |
| bool PythonAPI::m_listenerLoaded = false; |
| |
| std::string PythonAPI::m_listenerScript; |
| |
| bool PythonAPI::m_strictMode = false; |
| |
| PythonAPI::PythonAPI () { } |
| |
| PythonAPI::PythonAPI (const PythonAPI& orig) { } |
| |
| PythonAPI::~PythonAPI () { } |
| |
| static struct PyModuleDef SLAPI_module = { |
| PyModuleDef_HEAD_INIT, |
| "slapi", |
| NULL, |
| -1, |
| SwigMethods, |
| NULL, |
| NULL, |
| NULL, |
| NULL |
| }; |
| |
| static PyObject* |
| PyInit_slapi (void) |
| { |
| return PyModule_Create (&SLAPI_module); |
| } |
| |
| void |
| PythonAPI::shutdown () |
| { |
| PyEval_RestoreThread(m_mainThreadState); |
| Py_Finalize (); |
| } |
| |
| bool |
| PythonAPI::loadScript (std::string name, bool check) |
| { |
| PyEval_AcquireThread(m_mainThreadState); |
| bool status = loadScript_(name, check); |
| PyEval_ReleaseThread(m_mainThreadState); |
| return status; |
| } |
| |
| |
| bool |
| PythonAPI::loadScript_ (std::string name, bool check) |
| { |
| if (FileUtils::fileExists (name)) |
| { |
| FILE* fp = fopen (name.c_str (), "r"); |
| PyRun_SimpleFile (fp, name.c_str ()); |
| PyErr_Print (); |
| fclose (fp); |
| return true; |
| } |
| else |
| { |
| if (check) |
| std::cout << "PYTHON API ERROR: Script \"" << name << "\" does not exist.\n"; |
| } |
| return false; |
| } |
| |
| |
| PyThreadState* PythonAPI::initNewInterp() { |
| PyEval_AcquireThread(m_mainThreadState); |
| PyThreadState* interpState = Py_NewInterpreter(); |
| |
| loadScriptsInInterp_(); |
| //PyEval_ReleaseThread(m_mainThreadState); |
| |
| PyEval_ReleaseThread(interpState); |
| return interpState; |
| } |
| |
| void PythonAPI::shutdown(PyThreadState* interp) { |
| if (interp != m_mainThreadState) |
| { |
| PyEval_AcquireThread(interp); |
| Py_EndInterpreter(interp); |
| PyEval_ReleaseLock(); |
| } |
| } |
| |
| void PythonAPI::loadScriptsInInterp_() { |
| // Loads the python SWIG generated defs |
| std::string script; |
| for (auto s : slapi_scripts) |
| { |
| script += s; |
| } |
| for (auto s : slapi_types) |
| { |
| script += s; |
| } |
| PyRun_SimpleString (script.c_str ()); |
| |
| PyRun_SimpleString ("import sys"); |
| PyRun_SimpleString ("sys.path.append(\".\")"); |
| PyRun_SimpleString (std::string("sys.path.append(\"" + m_programPath + "\")").c_str()); |
| |
| std::string waivers = m_programPath + "/../python/slwaivers.py"; |
| bool waiverLoaded = loadScript_ (waivers); |
| |
| const char* home = getenv("HOME"); |
| if (home) |
| { |
| waivers = std::string(home) + "/slwaivers.py"; |
| waiverLoaded = loadScript_ (waivers) || waiverLoaded; |
| } |
| |
| waivers = "./slwaivers.py"; |
| waiverLoaded = loadScript_ (waivers) || waiverLoaded; |
| |
| std::string format = m_programPath + "/../python/slformatmsg.py"; |
| bool messageFormatLoaded = loadScript_ (format); |
| |
| if (home) |
| { |
| format = std::string(home) + "/slformatmsg.py"; |
| messageFormatLoaded = loadScript_ (format) || messageFormatLoaded ; |
| } |
| |
| format = "./slformatmsg.py"; |
| messageFormatLoaded = loadScript_ (format) || messageFormatLoaded ; |
| |
| if (m_listenerScript != "") |
| { |
| if (FileUtils::fileExists (m_listenerScript)) |
| { |
| m_listenerLoaded = loadScript_ (m_listenerScript); |
| } |
| } |
| |
| if (!m_listenerLoaded) |
| { |
| std::string listener = m_programPath + "/../python/slSV3_1aPythonListener.py"; |
| if (FileUtils::fileExists (listener)) |
| m_listenerScript = listener; |
| m_listenerLoaded = loadScript_ (listener); |
| |
| if (home) |
| { |
| listener = std::string (home) + "/slSV3_1aPythonListener.py"; |
| if (FileUtils::fileExists (listener)) |
| m_listenerScript = listener; |
| m_listenerLoaded = loadScript_ (listener) || m_listenerLoaded; |
| } |
| |
| listener = "./slSV3_1aPythonListener.py"; |
| if (FileUtils::fileExists (listener)) |
| m_listenerScript = listener; |
| m_listenerLoaded = loadScript_ (listener) || m_listenerLoaded; |
| } |
| } |
| |
| void |
| PythonAPI::init (const char ** argv) |
| { |
| |
| m_programPath = argv[0]; |
| m_programPath = StringUtils::rtrim (m_programPath, '/'); |
| |
| Py_SetProgramName ((wchar_t*) argv[0]); /* optional but recommended */ |
| |
| PyImport_AppendInittab ("slapi", &PyInit_slapi); |
| |
| Py_Initialize (); |
| PyEval_InitThreads(); |
| m_mainThreadState = PyEval_SaveThread(); |
| PyEval_AcquireThread(m_mainThreadState); |
| |
| loadScriptsInInterp_(); |
| |
| PyEval_ReleaseThread(m_mainThreadState); |
| } |
| |
| void PythonAPI::evalScript(std::string function, SV3_1aPythonListener* listener, ParserRuleContext* ctx) { |
| PyEval_AcquireThread(listener->getPyThreadState()); |
| PyObject * pModuleName, *pModule, *pFunc; |
| PyObject *pArgs, *pValue; |
| pModuleName = PyString_FromString("__main__"); |
| pModule = PyImport_Import(pModuleName); |
| Py_DECREF(pModuleName); |
| pFunc = PyObject_GetAttrString(pModule, function.c_str()); |
| if (!pFunc || !PyCallable_Check(pFunc)) { |
| if (m_strictMode) |
| std::cout << "PYTHON API ERROR: Function \"" << function << "\" does not exist.\n"; |
| PyEval_ReleaseThread(listener->getPyThreadState()); |
| return; |
| } |
| pArgs = PyTuple_New(2); |
| pValue = SWIG_NewPointerObj(SWIG_as_voidptr(listener), SWIGTYPE_p_SURELOG__SV3_1aPythonListener, 0 | 0 ); |
| PyTuple_SetItem(pArgs, 0, pValue); |
| pValue = SWIG_NewPointerObj(SWIG_as_voidptr(ctx), SWIGTYPE_p_ParserRuleContext, 0 | 0 ); |
| PyTuple_SetItem(pArgs, 1, pValue); |
| PyObject_CallObject(pFunc, pArgs); |
| PyErr_Print (); |
| Py_DECREF(pArgs); |
| Py_XDECREF(pFunc); |
| Py_DECREF(pModule); |
| PyEval_ReleaseThread(listener->getPyThreadState()); |
| } |
| |
| std::string |
| PythonAPI::evalScript (std::string module, std::string function, std::vector<std::string> args, PyThreadState* interp) |
| { |
| PyEval_AcquireThread(interp); |
| |
| std::string result; |
| PyObject *pModuleName, *pModule, *pFunc; |
| PyObject *pArgs, *pValue; |
| |
| pModuleName = PyString_FromString (module.c_str ()); |
| pModule = PyImport_Import (pModuleName); |
| |
| |
| Py_DECREF (pModuleName); |
| if (pModule != NULL) |
| { |
| pFunc = PyObject_GetAttrString (pModule, function.c_str ()); |
| /* pFunc is a new reference */ |
| |
| if (pFunc && PyCallable_Check (pFunc)) |
| { |
| pArgs = PyTuple_New (args.size ()); |
| for (unsigned int i = 0; i < args.size (); ++i) |
| { |
| pValue = PyString_FromString (args[i].c_str ()); |
| /* pValue reference stolen here: */ |
| PyTuple_SetItem (pArgs, i, pValue); |
| } |
| pValue = PyObject_CallObject (pFunc, pArgs); |
| Py_DECREF (pArgs); |
| if (pValue != NULL) |
| { |
| |
| long int size; |
| char * compName = PyUnicode_AsUTF8AndSize(pValue, &size); |
| if (compName == NULL) |
| { |
| std::cout << "PYTHON API ERROR: Incorrect function return type, expecting a string: " << function << std::endl; |
| Py_DECREF (pValue); |
| |
| PyEval_ReleaseThread(interp); |
| return m_invalidScriptResult; |
| } |
| result = compName; |
| Py_DECREF (pValue); |
| } |
| else |
| { |
| Py_DECREF (pFunc); |
| Py_DECREF (pModule); |
| PyErr_Print (); |
| std::cout << "PYTHON API ERROR: Incorrect function evaluation: " << function << std::endl; |
| PyEval_ReleaseThread(interp); |
| return m_invalidScriptResult; |
| } |
| } |
| else |
| { |
| if (PyErr_Occurred ()) |
| PyErr_Print (); |
| std::cout << "PYTHON API ERROR: Cannot find function " << function << std::endl; |
| |
| PyEval_ReleaseThread(interp); |
| return m_invalidScriptResult; |
| } |
| Py_XDECREF (pFunc); |
| Py_DECREF (pModule); |
| } |
| else |
| { |
| PyErr_Print (); |
| std::cout << "PYTHON API ERROR: Cannot load module " << module << std::endl; |
| return m_invalidScriptResult; |
| } |
| |
| |
| PyEval_ReleaseThread(interp); |
| return result; |
| } |
| |
| bool PythonAPI::evalScriptPerFile(std::string script, ErrorContainer* errors, FileContent* fC, PyThreadState* interp) |
| { |
| PyEval_AcquireThread (interp); |
| loadScript_(script); |
| std::string function = "slUserCallbackPerFile"; |
| PyObject * pModuleName, *pModule, *pFunc; |
| PyObject *pArgs, *pValue; |
| pModuleName = PyString_FromString ("__main__"); |
| pModule = PyImport_Import (pModuleName); |
| Py_DECREF (pModuleName); |
| pFunc = PyObject_GetAttrString (pModule, function.c_str()); |
| if (!pFunc || !PyCallable_Check (pFunc)) |
| { |
| std::cout << "PYTHON API ERROR: Function \"" << function << "\" does not exist.\n"; |
| PyEval_ReleaseThread (interp); |
| return false; |
| } |
| pArgs = PyTuple_New (2); |
| pValue = SWIG_NewPointerObj (SWIG_as_voidptr (errors), SWIGTYPE_p_SURELOG__ErrorContainer, 0 | 0); |
| PyTuple_SetItem (pArgs, 0, pValue); |
| pValue = SWIG_NewPointerObj (SWIG_as_voidptr (fC), SWIGTYPE_p_SURELOG__FileContent, 0 | 0); |
| PyTuple_SetItem (pArgs, 1, pValue); |
| |
| PyObject_CallObject (pFunc, pArgs); |
| PyErr_Print (); |
| Py_DECREF (pArgs); |
| Py_XDECREF (pFunc); |
| Py_DECREF (pModule); |
| |
| PyEval_ReleaseThread (interp); |
| return true; |
| } |
| |
| bool PythonAPI::evalScript(std::string script, Design* design) { |
| PyEval_AcquireThread (m_mainThreadState); |
| loadScript_(script); |
| std::string function = "slUserCallbackPerDesign"; |
| PyObject * pModuleName, *pModule, *pFunc; |
| PyObject *pArgs, *pValue; |
| pModuleName = PyString_FromString ("__main__"); |
| pModule = PyImport_Import (pModuleName); |
| Py_DECREF (pModuleName); |
| pFunc = PyObject_GetAttrString (pModule, function.c_str()); |
| if (!pFunc || !PyCallable_Check (pFunc)) |
| { |
| std::cout << "PYTHON API ERROR: Function \"" << function << "\" does not exist.\n"; |
| PyEval_ReleaseThread (m_mainThreadState); |
| return false; |
| } |
| pArgs = PyTuple_New (2); |
| pValue = SWIG_NewPointerObj (SWIG_as_voidptr (design->getCompiler()->getErrorContainer ()), SWIGTYPE_p_SURELOG__ErrorContainer, 0 | 0); |
| PyTuple_SetItem (pArgs, 0, pValue); |
| pValue = SWIG_NewPointerObj (SWIG_as_voidptr (design), SWIGTYPE_p_SURELOG__Design, 0 | 0); |
| PyTuple_SetItem (pArgs, 1, pValue); |
| PyObject_CallObject (pFunc, pArgs); |
| PyErr_Print (); |
| Py_DECREF (pArgs); |
| Py_XDECREF (pFunc); |
| Py_DECREF (pModule); |
| |
| PyEval_ReleaseThread (m_mainThreadState); |
| return true; |
| } |