1 #include "Interpreter.h"
2 #include <iostream>
3 #include <map>
4 #include <memory>
5
6 PyThreadState* Interpreter::MainThreadState = NULL;
7
Interpreter()8 Interpreter::Interpreter( )
9 {
10 PyEval_AcquireThread( MainThreadState );
11 m_threadState = Py_NewInterpreter( );
12
13 PyObject *module = PyImport_ImportModule("__main__");
14 loc = glb = PyModule_GetDict(module);
15
16 PyRun_SimpleString("import sys\n"
17 "import redirector\n"
18 "sys.path.insert(0, \".\")\n" // add current path
19 "sys.stdout = redirector.redirector()\n"
20 "sys.stderr = sys.stdout\n"
21 "import rlcompleter\n"
22 "sys.completer = rlcompleter.Completer()\n"
23 );
24
25 PyEval_ReleaseThread( m_threadState );
26 }
27
~Interpreter()28 Interpreter::~Interpreter( )
29 {
30 PyEval_AcquireThread( m_threadState );
31 Py_EndInterpreter( m_threadState );
32 PyEval_ReleaseLock( );
33 }
34
35 void
test()36 Interpreter::test( )
37 {
38 PyEval_AcquireThread( m_threadState );
39
40 PyObject* py_result;
41 PyObject* dum;
42 std::string command = "print 'Hello world'\n";
43 py_result = Py_CompileString(command.c_str(), "<stdin>", Py_single_input);
44 if ( py_result == 0 )
45 {
46 std::cout << "Huh?\n";
47 PyEval_ReleaseThread( m_threadState );
48 return;
49 }
50 dum = PyEval_EvalCode (py_result, glb, loc);
51 Py_XDECREF (dum);
52 Py_XDECREF (py_result);
53
54 std::cout << GetResultString( m_threadState );
55 GetResultString( m_threadState ) = "";
56
57 PyEval_ReleaseThread( m_threadState );
58 }
59
60 template<typename ... Args>
string_format(const std::string & format,Args...args)61 std::string string_format( const std::string& format, Args ... args )
62 {
63 size_t size = std::snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0'
64 std::unique_ptr<char[]> buf( new char[ size ] );
65 std::snprintf( buf.get(), size, format.c_str(), args ... );
66 return std::string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
67 }
68
69 std::string
interpret(const std::string & command,int * errorCode)70 Interpreter::interpret( const std::string& command, int* errorCode )
71 {
72 PyEval_AcquireThread( m_threadState );
73 *errorCode = 0;
74
75 PyObject* py_result;
76 PyObject* dum;
77 std::string res;
78 py_result = Py_CompileString(command.c_str(), "<stdin>", Py_single_input);
79 if ( py_result == 0 )
80 {
81 if ( PyErr_Occurred( ) )
82 {
83 *errorCode = 1;
84 PyErr_Print( );
85 res = GetResultString( m_threadState );
86 GetResultString( m_threadState ) = "";
87 }
88
89 PyEval_ReleaseThread( m_threadState );
90 return res;
91 }
92 dum = PyEval_EvalCode (py_result, glb, loc);
93 Py_XDECREF (dum);
94 Py_XDECREF (py_result);
95 if ( PyErr_Occurred( ) )
96 {
97 *errorCode = 1;
98 PyErr_Print( );
99 }
100
101 res = GetResultString( m_threadState );
102 GetResultString( m_threadState ) = "";
103
104 PyEval_ReleaseThread( m_threadState );
105 return res;
106 }
107
suggest(const std::string & hint)108 const std::list<std::string>& Interpreter::suggest( const std::string& hint )
109 {
110 PyEval_AcquireThread( m_threadState );
111 m_suggestions.clear();
112 int i = 0;
113 std::string command = string_format("sys.completer.complete('%s', %d)\n", hint.c_str(),i);
114 std::string res;
115 do
116 {
117 PyObject* py_result;
118 PyObject* dum;
119 py_result = Py_CompileString(command.c_str(), "<stdin>", Py_single_input);
120 dum = PyEval_EvalCode (py_result, glb, loc);
121 Py_XDECREF (dum);
122 Py_XDECREF (py_result);
123 res = GetResultString( m_threadState );
124 GetResultString( m_threadState ) = "";
125 ++i;
126 command = string_format("sys.completer.complete('%s', %d)\n", hint.c_str(),i);
127 if (res.size())
128 {
129 // throw away the newline
130 res = res.substr(1, res.size() - 3);
131 m_suggestions.push_back(res);
132 }
133 }
134 while (res.size());
135
136 PyEval_ReleaseThread( m_threadState );
137 return m_suggestions;
138 }
139
140 void
Initialize()141 Interpreter::Initialize( )
142 {
143 PyImport_AppendInittab("redirector", Interpreter::PyInit_redirector);
144 Py_Initialize( );
145 PyEval_InitThreads( );
146 MainThreadState = PyEval_SaveThread( );
147 }
148
149 void
Finalize()150 Interpreter::Finalize( )
151 {
152 PyEval_RestoreThread( MainThreadState );
153 Py_Finalize( );
154 }
155
GetResultString(PyThreadState * threadState)156 std::string& Interpreter::GetResultString( PyThreadState* threadState )
157 {
158 static std::map< PyThreadState*, std::string > ResultStrings;
159 if ( !ResultStrings.count( threadState ) )
160 {
161 ResultStrings[ threadState ] = "";
162 }
163 return ResultStrings[ threadState ];
164 }
165
RedirectorInit(PyObject *,PyObject *)166 PyObject* Interpreter::RedirectorInit(PyObject *, PyObject *)
167 {
168 Py_INCREF(Py_None);
169 return Py_None;
170 }
171
RedirectorWrite(PyObject *,PyObject * args)172 PyObject* Interpreter::RedirectorWrite(PyObject *, PyObject *args)
173 {
174 char* output;
175 PyObject *selfi;
176
177 if (!PyArg_ParseTuple(args,"Os",&selfi,&output))
178 {
179 return NULL;
180 }
181
182 std::string outputString( output );
183 PyThreadState* currentThread = PyThreadState_Get( );
184 std::string& resultString = GetResultString( currentThread );
185 resultString = resultString + outputString;
186 Py_INCREF(Py_None);
187 return Py_None;
188 }
189
190 PyMethodDef Interpreter::RedirectorMethods[] =
191 {
192 {"__init__", Interpreter::RedirectorInit, METH_VARARGS,
193 "initialize the stdout/err redirector"},
194 {"write", Interpreter::RedirectorWrite, METH_VARARGS,
195 "implement the write method to redirect stdout/err"},
196 {NULL,NULL,0,NULL},
197 };
198
199
createClassObject(const char * name,PyMethodDef methods[])200 PyObject *createClassObject(const char *name, PyMethodDef methods[])
201 {
202 PyObject *pClassName = PyUnicode_FromString(name);
203 PyObject *pClassBases = PyTuple_New(0); // An empty tuple for bases is equivalent to `(object,)`
204 PyObject *pClassDic = PyDict_New();
205
206
207 PyMethodDef *def;
208 // add methods to class
209 for (def = methods; def->ml_name != NULL; def++)
210 {
211 PyObject *func = PyCFunction_New(def, NULL);
212 PyObject *method = PyInstanceMethod_New(func);
213 PyDict_SetItemString(pClassDic, def->ml_name, method);
214 Py_DECREF(func);
215 Py_DECREF(method);
216 }
217
218 // pClass = type(pClassName, pClassBases, pClassDic)
219 PyObject *pClass = PyObject_CallFunctionObjArgs((PyObject *)&PyType_Type, pClassName, pClassBases, pClassDic, NULL);
220
221 Py_DECREF(pClassName);
222 Py_DECREF(pClassBases);
223 Py_DECREF(pClassDic);
224
225
226 return pClass;
227 }
228
PyInit_redirector(void)229 PyMODINIT_FUNC Interpreter::PyInit_redirector(void)
230 {
231 static struct PyModuleDef moduledef = {
232 PyModuleDef_HEAD_INIT,
233 "redirector",
234 0,
235 -1,
236 0
237 };
238
239 PyObject *m = PyModule_Create(&moduledef);
240 if (m) {
241 PyObject *fooClass = createClassObject("redirector", RedirectorMethods);
242 PyModule_AddObject(m, "redirector", fooClass);
243 Py_DECREF(fooClass);
244 }
245 return m;
246 }
247