move Gosu backend into its own directory
[Tsunagari.git] / src / scriptinst.cpp
blob8074aec58e15b4bf55a3e69bf5ae55296f8b4db6
1 /***************************************
2 ** Tsunagari Tile Engine **
3 ** scriptinst.cpp **
4 ** Copyright 2011-2013 PariahSoft LLC **
5 ***************************************/
7 // **********
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
24 // IN THE SOFTWARE.
25 // **********
27 #ifdef __APPLE__
28 # include <stdio.h> // Mac needs ssize_t defined for pyport.h
29 #endif
31 // from Python
32 #ifdef __APPLE__
33 # include <pyport.h>
34 # include <object.h>
35 #endif
36 #include <import.h>
38 #include "log.h"
39 #include "python.h"
40 #include "reader.h"
41 #include "scriptinst.h"
44 struct validate_visitor : public boost::static_visitor<bool>
46 bool operator()(BytecodeRef bc) const
48 if (!bc) {
49 Log::err("ScriptInst", "<null script>: script not valid");
50 return false;
52 if (!bc->valid()) {
53 Log::err("ScriptInst", bc->filename() +
54 ": script not valid");
55 return false;
57 return true;
60 bool operator()(boost::python::object) const
62 return true;
67 struct invoke_visitor : public boost::static_visitor<bool>
69 bool operator()(BytecodeRef bc) const
71 return (bc && bc->valid()) ? bc->execute() : false;
74 bool operator()(boost::python::object callable) const
76 try {
77 inPythonScript++;
78 callable();
79 inPythonScript--;
80 return true;
81 } catch (boost::python::error_already_set) {
82 inPythonScript--;
83 // XXX: How does this interact with a C++/Python callstack?
84 //Log::err("Python", "Originating from " + source + ":");
85 pythonErr();
86 return false;
93 ScriptInst::ScriptInst(const std::string& source)
94 : data(Reader::getBytecode(source))
96 if (!validate()) {
97 Log::err("ScriptInst", "Error loading " + source);
102 ScriptInst::ScriptInst(boost::python::object callable)
103 : data(callable)
108 bool ScriptInst::validate()
110 return boost::apply_visitor(validate_visitor(), data);
114 bool ScriptInst::invoke()
116 return boost::apply_visitor(invoke_visitor(), data);
120 struct topython_visitor : public boost::static_visitor<PyObject*>
122 PyObject* operator()(BytecodeRef bc) const
124 boost::python::object str;
125 if (bc)
126 str = boost::python::object(bc->filename());
127 else
128 str = boost::python::object("");
129 return boost::python::incref(str.ptr());
132 PyObject* operator()(boost::python::object callable) const
134 return boost::python::incref(callable.ptr());
139 struct scriptinst_to_python
141 static PyObject* convert(ScriptInst script)
143 return boost::apply_visitor(topython_visitor(), script.data);
148 struct scriptinst_from_python
150 scriptinst_from_python()
152 boost::python::converter::registry::push_back(
153 &convertible,
154 &construct,
155 boost::python::type_id<ScriptInst>());
158 // Can this be converted to a ScriptInst?
159 static void* convertible(PyObject* obj)
161 //bool callable = obj->ob_type->tp_call != NULL;
162 //const char* tp_name = obj->ob_type->tp_name;
163 // XXX: Return non-NULL only if string or
164 // callable (fn or lambda?).
165 return obj;
168 // Convert. boost::python provides us with a chunch of memory that we
169 // have to construct in-place.
170 static void construct(
171 PyObject* obj,
172 boost::python::converter::rvalue_from_python_stage1_data* data)
174 // Prevent compilation name collisions with "object" by making
175 // it "bp::object".
176 namespace bp = boost::python;
178 void* storage =
179 ((bp::converter::rvalue_from_python_storage<ScriptInst>*)data)
180 ->storage.bytes;
182 if (PyString_Check(obj)) {
183 const char* value = PyString_AsString(obj);
184 new (storage) ScriptInst(value);
186 else {
187 // By default, the PyObject is a borrowed reference,
188 // which means it hasn't been incref'd.
189 bp::handle<> hndl(bp::borrowed(obj));
190 new (storage) ScriptInst(bp::object(hndl));
193 data->convertible = storage;
198 void exportScriptInst()
200 using namespace boost::python;
202 to_python_converter<ScriptInst, scriptinst_to_python>();
203 scriptinst_from_python();