40 #ifdef EST_SIOD_ENABLE_PYTHON
41 #include "slib_python.h"
49 static int tc_pyobject = -1;
52 int pyobject_p(LISP x) {
53 if (TYPEP(x, tc_pyobject))
58 LISP pyobjectp(LISP x) {
67 static PyObject *get_c_pyobject(LISP x) {
68 if (TYPEP(x, tc_pyobject)) {
69 PyObject *p =
reinterpret_cast<PyObject *
>(USERVAL(x));
78 return PyFloat_FromDouble(get_c_double(x));
80 if (TYPEP(x, tc_string))
81 return PyUnicode_FromString(get_c_string(x));
84 int num_items = siod_llength(x);
85 PyObject *pList = PyList_New(num_items);
90 ptr = cdr(ptr), i++) {
91 PyList_SetItem(pList, i, get_c_pyobject(car(ptr)));
96 err(
"wrong type of argument to get_c_pyobject", x);
100 static LISP siod_make_pyobject(PyObject *pyobj) {
101 if (pyobj == NULL || pyobj == Py_None)
104 if (PyLong_Check(pyobj) || PyFloat_Check(pyobj))
105 return flocons(PyFloat_AsDouble(pyobj));
107 if (PyBool_Check(pyobj))
108 return PyObject_IsTrue(pyobj)? truth : NIL;
110 if (PyUnicode_Check(pyobj)) {
113 pBytes = PyUnicode_AsUTF8String(pyobj);
117 ret = strcons(PyBytes_Size(pBytes),
118 PyBytes_AsString(pBytes));
123 if (PyTuple_Check(pyobj) || PyList_Check(pyobj)) {
125 int size = PySequence_Size(pyobj);
128 for (
int i = size - 1; i >= 0; i--)
129 ret = cons(siod_make_pyobject(PySequence_GetItem(pyobj, i)),
136 return siod_make_typed_cell(tc_pyobject, pyobj);
139 static void pyobject_free(LISP x) {
141 if (TYPEP(x, tc_pyobject)) {
142 PyObject *p =
reinterpret_cast<PyObject *
>(USERVAL(x));
147 static void pyobject_prin1(LISP v, FILE *fp) {
148 if (TYPEP(v, tc_pyobject)) {
149 PyObject *p =
reinterpret_cast<PyObject *
>(USERVAL(v));
150 PyObject_Print(p, fp, Py_PRINT_RAW);
154 static void pyobject_print_string(LISP v,
char *tkbuffer) {
155 if (TYPEP(v, tc_pyobject)) {
156 PyObject *p =
reinterpret_cast<PyObject *
>(USERVAL(v));
157 PyObject *pRepr = PyObject_Str(p);
159 snprintf(tkbuffer, 1024,
"#<UnknownPythonObject %p>", p);
163 LISP repr = siod_make_pyobject(pRepr);
164 snprintf(tkbuffer, 1024,
"PyObject %s", get_c_string(repr));
168 snprintf(tkbuffer, 1024,
"#<UnknownObject>");
171 static LISP python_syspath_append(LISP path) {
172 if (!TYPEP(path, tc_string)) {
173 err(
"Invalid Path", path);
177 PyObject* sysPath = PySys_GetObject(
"path");
178 int ret = PyList_Append(sysPath, PyUnicode_FromString(get_c_string(path)));
186 static LISP python_import(LISP modulename) {
187 PyObject *pName, *pModule;
190 if (!TYPEP(modulename, tc_string)) {
191 err(
"Invalid module name (expecting string)", modulename);
195 pName = PyUnicode_FromString(get_c_string(modulename));
196 pModule = PyImport_Import(pName);
199 if (pModule == NULL) {
200 if (PyErr_Occurred()) {
204 err(
"Failed to load module", modulename);
207 ret = siod_make_pyobject(pModule);
212 static LISP python_attr_get(LISP lpobj, LISP attrname) {
213 if (!TYPEP(lpobj, tc_pyobject)) {
214 err(
"Invalid Object for python_attr_get", lpobj);
218 PyObject *p =
reinterpret_cast<PyObject *
>(USERVAL(lpobj));
220 if (!TYPEP(attrname, tc_string)) {
221 err(
"Invalid Attribute Name (expecting string)", attrname);
225 PyObject *pAttr = PyObject_GetAttrString(p, get_c_string(attrname));
227 if (PyErr_Occurred()) {
232 LISP ret = siod_make_pyobject(pAttr);
237 static LISP python_attr_set(LISP lpobj, LISP attrname, LISP value) {
238 if (!TYPEP(lpobj, tc_pyobject)) {
239 err(
"Invalid Object for python_attr_set", lpobj);
243 PyObject *p =
reinterpret_cast<PyObject *
>(USERVAL(lpobj));
245 if (!TYPEP(attrname, tc_string)) {
246 err(
"Invalid Attribute Name (expecting string)", attrname);
250 PyObject *pValue = get_c_pyobject(value);
251 if (pValue == NULL) {
252 if (PyErr_Occurred()) {
256 err(
"Invalid Value for python_attr_set", value);
260 int result = PyObject_SetAttrString(p, get_c_string(attrname), pValue);
264 err(
"Failed to set value", value);
270 static LISP python_call_object(LISP fpobj, LISP args) {
271 if (!TYPEP(fpobj, tc_pyobject)) {
272 err(
"Invalid Object for python_callfunction", fpobj);
276 PyObject *p =
reinterpret_cast<PyObject *
>(USERVAL(fpobj));
278 if (p == NULL || !PyCallable_Check(p)) {
279 err(
"Not a callable object", fpobj);
288 err(
"Invalid argument (expecting list)", args);
292 pArgs = get_c_pyobject(args);
294 err(
"Could not convert arguments", args);
299 PyObject *pArgsTuple = NULL;
301 pArgsTuple = PyList_AsTuple(pArgs);
305 PyObject *pValue = PyObject_CallObject(p, pArgsTuple);
306 Py_XDECREF(pArgsTuple);
308 if (pValue == NULL) {
309 if (PyErr_Occurred()) {
313 err(
"Could not call object", fpobj);
316 LISP ret = siod_make_pyobject(pValue);
321 static LISP python_call_method(LISP lpobj, LISP methodname, LISP args) {
322 LISP callable = python_attr_get(lpobj, methodname);
323 return python_call_object(callable, args);
326 void init_subrs_python(
void) {
331 tc_pyobject = siod_register_user_type(
"PyObject");
332 set_gc_hooks(tc_pyobject, 0, NULL, NULL, NULL, pyobject_free, NULL, &kind);
333 set_print_hooks(tc_pyobject, pyobject_prin1, pyobject_print_string);
336 PyObject* sysPath = PySys_GetObject(
"path");
337 PyList_Append(sysPath, PyUnicode_FromString(
"."));
339 init_subr_1(
"pyobjectp", pyobjectp,
341 "Checks if obj is a Python Object");
344 init_subr_1(
"python_syspath_append", python_syspath_append,
345 "(python_addpath path)\n"
346 "Appends path (string) to sys.path");
348 init_subr_1(
"python_import", python_import,
349 "(python_import modulename)\n"
350 "Imports specified module and returns it");
352 init_subr_2(
"python_attr_get", python_attr_get,
353 "(python_attr_get object attrname)\n"
354 "Returns the specified attribute of the given PyObject");
356 init_subr_3(
"python_attr_set", python_attr_set,
357 "(python_attr_set object attrname value)\n"
358 "Set value of the given attribute of the given PyObject");
360 init_subr_3(
"python_call_method", python_call_method,
361 "(python_call_method object methodname args)\n"
362 "Calls object.methodname(args)\n"
363 "object is a PyObject, methodname is string. args is a list.");
365 init_subr_2(
"python_call_object", python_call_object,
366 "(python_call_object object args)\n"
367 "Calls object(args)\n"
368 "object is a callable PyObject, args is a list");
371 void python_tidy_up(
void) {
374 #else // No python support
377 static int est_no_python_support = 1;
379 #endif // EST_SIOD_ENABLE_PYTHON