1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
#include "pyinterp.h"
#include <boost/python/module_init.hpp>
namespace ledger {
using namespace boost::python;
struct python_run
{
object result;
python_run(python_interpreter_t * intepreter,
const 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;
}
};
extern void initialize_for_python();
python_interpreter_t::python_interpreter_t(xml::xpath_t::scope_t * parent)
: xml::xpath_t::scope_t(parent),
mmodule(borrowed(PyImport_AddModule("__main__"))),
nspace(handle<>(borrowed(PyModule_GetDict(mmodule.get()))))
{
Py_Initialize();
boost::python::detail::init_module("ledger", &initialize_for_python);
}
object python_interpreter_t::import(const string& str)
{
assert(Py_IsInitialized());
try {
PyObject * mod = PyImport_Import(PyString_FromString(str.c_str()));
if (! mod)
throw_(std::logic_error, "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[string(PyModule_GetName(mod))] = newmod;
#endif
return newmod;
}
catch (const error_already_set&) {
PyErr_Print();
throw_(std::logic_error, "Importing Python module " << str);
}
}
object python_interpreter_t::eval(std::istream& in, py_eval_mode_t mode)
{
bool first = true;
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_(std::logic_error, "Evaluating Python code");
}
}
object python_interpreter_t::eval(const 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_(std::logic_error, "Evaluating Python code");
}
}
void python_interpreter_t::functor_t::operator()(value_t& result,
xml::xpath_t::scope_t * locals)
{
try {
if (! PyCallable_Check(func.ptr())) {
result = static_cast<const value_t&>(extract<value_t>(func.ptr()));
} else {
assert(locals->args.type == value_t::SEQUENCE);
if (locals->args.to_sequence()->size() > 0) {
list arglist;
for (value_t::sequence_t::iterator
i = locals->args.to_sequence()->begin();
i != locals->args.to_sequence()->end();
i++)
arglist.append(*i);
if (PyObject * val =
PyObject_CallObject(func.ptr(),
boost::python::tuple(arglist).ptr())) {
result = extract<value_t>(val)();
Py_DECREF(val);
}
else if (PyObject * err = PyErr_Occurred()) {
PyErr_Print();
throw_(xml::xpath_t::calc_error,
"While calling Python function '" << name() << "'");
} else {
assert(0);
}
} else {
result = call<value_t>(func.ptr());
}
}
}
catch (const error_already_set&) {
PyErr_Print();
throw_(xml::xpath_t::calc_error,
"While calling Python function '" << name() << "'");
}
}
void python_interpreter_t::lambda_t::operator()(value_t& result,
xml::xpath_t::scope_t * locals)
{
try {
assert(locals->args.type == value_t::SEQUENCE);
assert(locals->args.to_sequence()->size() == 1);
value_t item = locals->args[0];
assert(item.type == value_t::POINTER);
result = call<value_t>(func.ptr(), item.to_xml_node());
}
catch (const error_already_set&) {
PyErr_Print();
throw_(xml::xpath_t::calc_error,
"While evaluating Python lambda expression");
}
}
} // namespace ledger
|