1 /***************************************
2 ** Tsunagari Tile Engine **
3 ** script-python.cpp **
4 ** Copyright 2011-2013 PariahSoft LLC **
5 ***************************************/
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to
10 // deal in the Software without restriction, including without limitation the
11 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 // sell copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
32 #include "script-python.h"
36 ScriptRef
Script::create(std::string source
)
38 std::string s_file
, s_func
;
40 PyObject
* module
= NULL
;
43 colon
= source
.find(':');
44 if (colon
!= std::string::npos
) {
45 s_file
= source
.substr(0, colon
);
46 s_func
= source
.substr(colon
+ 1);
52 if ((module
= PyImport_ImportModule(s_file
.c_str())) == NULL
) {
53 Log::err("Script", s_file
+ ": import failed");
57 script
= new PythonScript
;
58 script
->module
= module
;
59 script
->function
= s_func
;
60 return ScriptRef(script
);
71 ScriptRef
Script::create(const char* source
)
73 return Script::create(std::string(source
));
77 PythonScript::PythonScript()
83 PythonScript::~PythonScript()
89 bool PythonScript::validate()
96 bool PythonScript::invoke()
98 assert(function
.size());
100 PyObject
* result
= NULL
;
102 result
= PyObject_CallMethod(module
, (char*)function
.c_str(), (char*)"()");
103 if (result
== NULL
) {
112 /* The code below has support for being bound from inside of Python
115 ScriptInst::ScriptInst(const std::string& source)
116 : dataType(BYTECODE_REF), data(Reader::getBytecode(source))
119 Log::err("ScriptInst", "Error loading " + source);
124 ScriptInst::ScriptInst(boost::python::object& callable)
125 : dataType(BOOST_PY_OBJ), data(callable)
130 ScriptInst::ScriptInst(const ScriptInst& s)
131 : dataType(s.dataType)
144 ScriptInst::~ScriptInst()
157 bool ScriptInst::validate()
159 BytecodeRef& bc = *(BytecodeRef*)data;
164 Log::err("ScriptInst", "<null script>: script not valid");
168 Log::err("ScriptInst", bc->filename() +
169 ": script not valid");
176 Log::fatal("ScriptInstInternal", "validate(): unknown data type");
182 bool ScriptInst::invoke()
184 BytecodeRef& bc = *(BytecodeRef*)data;
185 boost::python::object& callable = *(boost::python::object*)data;
189 return (bc && bc->valid()) ? bc->execute() : false;
196 } catch (boost::python::error_already_set) {
198 // XXX: How does this interact with a C++/Python callstack?
199 //Log::err("Python", "Originating from " + source + ":");
204 Log::fatal("ScriptInstInternal", "invoke(): unknown data type");
210 struct scriptinst_to_python
212 static PyObject* convert(ScriptInst script)
214 BytecodeRef& bc = *(BytecodeRef*)data;
215 boost::python::object& callable = *(boost::python::object*)data;
219 boost::python::object str;
221 str = boost::python::object(bc->filename());
223 str = boost::python::object("");
224 return boost::python::incref(str.ptr());
226 return boost::python::incref(callable.ptr());
228 Log::fatal("ScriptInstInternal", "to_python: convert(): unknown data type");
235 struct scriptinst_from_python
237 scriptinst_from_python()
239 boost::python::converter::registry::push_back(
242 boost::python::type_id<ScriptInst>());
245 // Can this be converted to a ScriptInst?
246 static void* convertible(PyObject* obj)
248 //bool callable = obj->ob_type->tp_call != NULL;
249 //const char* tp_name = obj->ob_type->tp_name;
250 // XXX: Return non-NULL only if string or
251 // callable (fn or lambda?).
255 // Convert. boost::python provides us with a chunch of memory that we
256 // have to construct in-place.
257 static void construct(
259 boost::python::converter::rvalue_from_python_stage1_data* data)
261 // Prevent compilation name collisions with "object" by making
263 namespace bp = boost::python;
266 ((bp::converter::rvalue_from_python_storage<ScriptInst>*)data)
269 if (PyString_Check(obj)) {
270 const char* value = PyString_AsString(obj);
271 new (storage) ScriptInst(value);
274 // By default, the PyObject is a borrowed reference,
275 // which means it hasn't been incref'd.
276 bp::handle<> hndl(bp::borrowed(obj));
277 new (storage) ScriptInst(bp::object(hndl));
280 data->convertible = storage;
285 void exportScriptInst()
287 using namespace boost::python;
289 to_python_converter<ScriptInst, scriptinst_to_python>();
290 scriptinst_from_python();