#define BOOST_PYTHON_MAX_ARITY 4
#include "python_plugin.hh"
#include "interp_python.hh"
#include <boost/python/extract.hpp>
#include <boost/python/import.hpp>
#include <boost/python/str.hpp>
namespace bp = boost::python;
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <exception>
#include "rs274ngc.hh"
#include "interp_return.hh"
#include "interp_internal.hh"
#include "rs274ngc_interp.hh"
#include "units.h"
extern PythonPlugin *python_plugin;
#define PYCHK(bad, fmt, ...) \
do { \
if (bad) { \
logPy(fmt, ## __VA_ARGS__); \
ERM(fmt, ## __VA_ARGS__); \
goto error; \
} \
} while(0)
#define IS_STRING(x) (PyObject_IsInstance(x.ptr(), (PyObject*)&PyString_Type))
#define IS_INT(x) (PyObject_IsInstance(x.ptr(), (PyObject*)&PyInt_Type))
std::string handle_pyerror()
{
using namespace boost::python;
using namespace boost;
PyObject *exc,*val,*tb;
object formatted_list, formatted;
PyErr_Fetch(&exc,&val,&tb);
handle<> hexc(exc),hval(allow_null(val)),htb(allow_null(tb));
object traceback(import("traceback"));
if (!tb) {
object format_exception_only(traceback.attr("format_exception_only"));
formatted_list = format_exception_only(hexc,hval);
} else {
object format_exception(traceback.attr("format_exception"));
formatted_list = format_exception(hexc,hval,htb);
}
formatted = str("\n").join(formatted_list);
return extract<std::string>(formatted);
}
int Interp::py_reload()
{
if (PYUSABLE) {
CHKS((python_plugin->initialize() == PLUGIN_EXCEPTION),
"py_reload:\n%s", python_plugin->last_exception().c_str());
}
return INTERP_OK;
}
bool Interp::is_pycallable(setup_pointer settings,
const char *module,
const char *funcname)
{
if (!PYUSABLE)
return false;
return python_plugin->is_callable(module,funcname);
}
int Interp::pycall(setup_pointer settings,
context_pointer frame,
const char *module,
const char *funcname,
int calltype)
{
bp::object retval, function;
std::string msg;
bool py_exception = false;
int status = INTERP_OK;
PyObject *res_str;
if (_setup.loggingLevel > 4)
logPy("pycall(%s.%s) \n", module ? module : "", funcname);
CHKS(!PYUSABLE, "pycall(%s): Pyhton plugin not initialized",funcname);
frame->pystuff.impl->py_return_type = 0;
switch (calltype) {
case PY_EXECUTE: python_plugin->run_string(funcname, retval);
CHKS(python_plugin->plugin_status() == PLUGIN_EXCEPTION,
"run_string(%s):\n%s", funcname,
python_plugin->last_exception().c_str());
break;
case PY_FINISH_OWORDCALL:
case PY_FINISH_PROLOG:
case PY_FINISH_BODY:
case PY_FINISH_EPILOG:
logPy("pycall: call generator.next()" );
read_inputs(&_setup);
try {
retval = frame->pystuff.impl->generator_next();
}
catch (bp::error_already_set) {
if (PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
frame->pystuff.impl->py_return_type = RET_STOPITERATION;
bp::handle_exception();
PyErr_Clear();
logPy("pycall: call generator - StopIteration exception");
return INTERP_OK;
} else {
msg = handle_pyerror();
bp::handle_exception();
PyErr_Clear();
logPy("pycall: call generator - exception: %s",msg.c_str());
ERS("exception during generator call: %s", msg.c_str());
}
} else
Error("calling generator: duh");
}
break;
default:
python_plugin->call(module,funcname, frame->pystuff.impl->tupleargs,frame->pystuff.impl->kwargs,retval);
CHKS(python_plugin->plugin_status() == PLUGIN_EXCEPTION,
"pycall(%s):\n%s", funcname,
python_plugin->last_exception().c_str());
}
try {
status = INTERP_OK;
switch (calltype) {
case PY_OWORDCALL:
case PY_PROLOG:
case PY_BODY:
case PY_EPILOG:
case PY_FINISH_OWORDCALL:
case PY_FINISH_PROLOG:
case PY_FINISH_BODY:
case PY_FINISH_EPILOG:
if (retval.ptr() != Py_None) {
if (PyGen_Check(retval.ptr())) {
frame->pystuff.impl->generator_next = bp::getattr(retval, "next");
frame->pystuff.impl->py_returned_int = bp::extract<int>(frame->pystuff.impl->generator_next());
frame->pystuff.impl->py_return_type = RET_YIELD;
} else if (PyString_Check(retval.ptr())) {
char *msg = bp::extract<char *>(retval);
ERM("%s", msg);
frame->pystuff.impl->py_return_type = RET_ERRORMSG;
status = INTERP_ERROR;
} else if (PyInt_Check(retval.ptr())) {
frame->pystuff.impl->py_returned_int = bp::extract<int>(retval);
frame->pystuff.impl->py_return_type = RET_INT;
logPy("Python call %s.%s returned int: %d", module, funcname, frame->pystuff.impl->py_returned_int);
} else if (PyFloat_Check(retval.ptr())) {
frame->pystuff.impl->py_returned_double = bp::extract<double>(retval);
frame->pystuff.impl->py_return_type = RET_DOUBLE;
logPy("Python call %s.%s returned float: %f", module, funcname, frame->pystuff.impl->py_returned_double);
} else {
PyObject *res_str = PyObject_Str(retval.ptr());
Py_XDECREF(res_str);
ERM("Python call %s.%s returned '%s' - expected generator, int, or float value, got %s",
module, funcname,
PyString_AsString(res_str),
retval.ptr()->ob_type->tp_name);
status = INTERP_ERROR;
}
} else {
logPy("call: O <%s> call returned None",funcname);
frame->pystuff.impl->py_return_type = RET_NONE;
}
break;
case PY_INTERNAL:
case PY_PLUGIN_CALL:
if ((retval.ptr() != Py_None) &&
(PyInt_Check(retval.ptr()))) {
status = frame->pystuff.impl->py_returned_int = bp::extract<int>(retval);
frame->pystuff.impl->py_return_type = RET_INT;
logPy("pycall(%s): PY_INTERNAL/PY_PLUGIN_CALL: return code=%d", funcname,status);
} else {
logPy("pycall(%s): PY_INTERNAL: expected an int return code", funcname);
res_str = PyObject_Str(retval.ptr());
ERM("Python internal function '%s' expected tuple or int return value, got '%s' (%s)",
funcname,
PyString_AsString(res_str),
retval.ptr()->ob_type->tp_name);
Py_XDECREF(res_str);
status = INTERP_ERROR;
}
break;
case PY_EXECUTE:
break;
default: ;
}
}
catch (bp::error_already_set) {
if (PyErr_Occurred()) {
msg = handle_pyerror();
}
py_exception = true;
bp::handle_exception();
PyErr_Clear();
}
if (py_exception) {
ERM("pycall: %s.%s:\n%s", module ? module:"", funcname, msg.c_str());
status = INTERP_ERROR;
}
return status;
}
int Interp::py_execute(const char *cmd, bool as_file)
{
bp::object retval;
logPy("py_execute(%s)",cmd);
CHKS(!PYUSABLE, "py_execute(%s): Python plugin not initialized",cmd);
python_plugin->run_string(cmd, retval, as_file);
CHKS((python_plugin->plugin_status() == PLUGIN_EXCEPTION),
"py_execute(%s)%s:\n%s", cmd,
as_file ? " as file" : "", python_plugin->last_exception().c_str());
return INTERP_OK;
}
pycontext::pycontext() : impl(new pycontext_impl) {}
pycontext::~pycontext() { delete impl; }
pycontext::pycontext(const pycontext &other)
: impl(new pycontext_impl(*other.impl)) {}
pycontext &pycontext::operator=(const pycontext &other) {
delete impl;
impl = new pycontext_impl(*other.impl);
return *this;
}