diff options
Diffstat (limited to 'py_eval.cc')
-rw-r--r-- | py_eval.cc | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/py_eval.cc b/py_eval.cc new file mode 100644 index 00000000..ec656035 --- /dev/null +++ b/py_eval.cc @@ -0,0 +1,205 @@ +#ifdef USE_PCH +#include "pch.h" +#else +#include "py_eval.h" +#include "error.h" +#include "acconf.h" + +#include <istream> +#endif + +void export_amount(); +void export_balance(); +void export_value(); +void export_datetime(); + +void export_journal(); +void export_parser(); +void export_option(); +void export_walk(); +void export_report(); +void export_format(); +void export_valexpr(); + +void shutdown_option(); + +namespace ledger { + +namespace { + void initialize_ledger_for_python() + { + export_amount(); + export_balance(); + export_value(); + export_datetime(); + + export_journal(); + export_parser(); + export_option(); + export_walk(); + export_format(); + export_report(); + export_valexpr(); + } +} + +void shutdown_ledger_for_python() +{ + shutdown_option(); +} + +struct python_run +{ + object result; + python_run(python_interpreter_t * intepreter, + const std::string& str, int input_mode) + : result(handle<>(borrowed(PyRun_String(str.c_str(), input_mode, + intepreter->nspace.ptr(), + intepreter->nspace.ptr())))) {} + operator object() { + return result; + } +}; + +python_interpreter_t::python_interpreter_t(valexpr_t::scope_t * parent) + : valexpr_t::scope_t(parent), + mmodule(borrowed(PyImport_AddModule("__main__"))), + nspace(handle<>(borrowed(PyModule_GetDict(mmodule.get())))) +{ + Py_Initialize(); + detail::init_module("ledger", &initialize_ledger_for_python); +} + +object python_interpreter_t::import(const std::string& str) +{ + assert(Py_IsInitialized()); + + try { + PyObject * mod = PyImport_Import(PyString_FromString(str.c_str())); + if (! mod) + throw error(std::string("Failed to import Python module ") + str); + + object newmod(handle<>(borrowed(mod))); + +#if 1 + // Import all top-level entries directly into the main namespace + dict m_nspace(handle<>(borrowed(PyModule_GetDict(mod)))); + nspace.update(m_nspace); +#else + nspace[std::string(PyModule_GetName(mod))] = newmod; +#endif + return newmod; + } + catch (const error_already_set&) { + PyErr_Print(); + throw error(std::string("Importing Python module ") + str); + } +} + +object python_interpreter_t::eval(std::istream& in, py_eval_mode_t mode) +{ + bool first = true; + std::string buffer; + buffer.reserve(4096); + + while (! in.eof()) { + char buf[256]; + in.getline(buf, 255); + if (buf[0] == '!') + break; + if (first) + first = false; + else + buffer += "\n"; + buffer += buf; + } + + try { + int input_mode; + switch (mode) { + case PY_EVAL_EXPR: input_mode = Py_eval_input; break; + case PY_EVAL_STMT: input_mode = Py_single_input; break; + case PY_EVAL_MULTI: input_mode = Py_file_input; break; + } + assert(Py_IsInitialized()); + return python_run(this, buffer, input_mode); + } + catch (const error_already_set&) { + PyErr_Print(); + throw error("Evaluating Python code"); + } +} + +object python_interpreter_t::eval(const std::string& str, py_eval_mode_t mode) +{ + try { + int input_mode; + switch (mode) { + case PY_EVAL_EXPR: input_mode = Py_eval_input; break; + case PY_EVAL_STMT: input_mode = Py_single_input; break; + case PY_EVAL_MULTI: input_mode = Py_file_input; break; + } + assert(Py_IsInitialized()); + return python_run(this, str, input_mode); + } + catch (const error_already_set&) { + PyErr_Print(); + throw error("Evaluating Python code"); + } +} + +void python_interpreter_t::functor_t::operator()(value_t& result, + valexpr_t::scope_t * locals) +{ + try { + if (! PyCallable_Check(func.ptr())) { + result = extract<value_t>(func.ptr()); + } else { + if (locals->arg_scope && locals->args.size() > 0) { + list arglist; + for (valexpr_t::scope_t::args_list::iterator i = locals->args.begin(); + i != locals->args.end(); + i++) + arglist.append(*i); + + if (PyObject * val = + PyObject_CallObject(func.ptr(), tuple(arglist).ptr())) { + result = extract<value_t>(val)(); + Py_DECREF(val); + } + else if (PyObject * err = PyErr_Occurred()) { + PyErr_Print(); + throw new valexpr_t::calc_error + (std::string("While calling Python function '") + name() + "'"); + } else { + assert(0); + } + } else { + result = call<value_t>(func.ptr()); + } + } + } + catch (const error_already_set&) { + PyErr_Print(); + throw new valexpr_t::calc_error + (std::string("While calling Python function '") + name() + "'"); + } +} + +void python_interpreter_t::lambda_t::operator()(value_t& result, + valexpr_t::scope_t * locals) +{ + try { + assert(locals->arg_scope && locals->args.size() == 1); + value_t item = locals->args[0]; + assert(item.type == value_t::POINTER); + result = call<value_t>(func.ptr(), (repitem_t *)*(void **)item.data); + } + catch (const error_already_set&) { + PyErr_Print(); + throw new valexpr_t::calc_error + ("While evaluating Python lambda expression"); + } +} + +} // namespace ledger |