285 lines
8.0 KiB
C++
285 lines
8.0 KiB
C++
#include <stdio.h>
|
|
|
|
#include <a8/a8.h>
|
|
#include <a8/pyengine.h>
|
|
|
|
#ifdef A8_USE_PYTHON
|
|
|
|
#include <Python.h>
|
|
|
|
static bool CallPyFunc(PyObject* py_module,
|
|
const char* func_name,
|
|
std::initializer_list<a8::XValue>& args,
|
|
a8::XValue& result)
|
|
{
|
|
PyObject *py_func = PyObject_GetAttrString(py_module, func_name);
|
|
if (!py_func) {
|
|
return false;
|
|
}
|
|
PyObject* py_args = PyTuple_New(args.size());
|
|
int i = 0;
|
|
for (auto &arg : args) {
|
|
switch(arg.Type()){
|
|
case a8::XVT_INT:
|
|
PyTuple_SetItem(py_args, i, Py_BuildValue("i", arg.GetInt()));
|
|
break;
|
|
case a8::XVT_UINT:
|
|
PyTuple_SetItem(py_args, i, Py_BuildValue("i", arg.GetUInt()));
|
|
break;
|
|
case a8::XVT_FLOAT:
|
|
PyTuple_SetItem(py_args, i, Py_BuildValue("d", arg.GetDouble()));
|
|
break;
|
|
case a8::XVT_INT64:
|
|
PyTuple_SetItem(py_args, i, Py_BuildValue("i", arg.GetInt64()));
|
|
break;
|
|
case a8::XVT_UINT64:
|
|
PyTuple_SetItem(py_args, i, Py_BuildValue("i", arg.GetUInt64()));
|
|
break;
|
|
case a8::XVT_STRING:
|
|
PyTuple_SetItem(py_args, i, Py_BuildValue("s", arg.GetString().c_str()));
|
|
break;
|
|
default:
|
|
{
|
|
return false;
|
|
}
|
|
break;
|
|
}//end switch
|
|
i++;
|
|
}
|
|
|
|
PyObject* py_result = PyEval_CallObject(py_func, py_args);
|
|
if (py_result) {
|
|
if (PyLong_Check(py_result)) {
|
|
result = PyLong_AsLong(py_result);
|
|
} else if (PyFloat_Check(py_result)) {
|
|
result = PyFloat_AsDouble(py_result);
|
|
} else if (PyUnicode_Check(py_result)) {
|
|
int data_size = PyUnicode_GET_DATA_SIZE(py_result);
|
|
const char* data = PyUnicode_AS_DATA(py_result);
|
|
result.SetDynData(data, data_size);
|
|
} else {
|
|
assert(false);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void FetchError()
|
|
{
|
|
#if 0
|
|
if (!traceback_obj) {
|
|
strErrorMsg += "traceback:";;
|
|
|
|
PyObject *pModuleName = PyUnicode_FromString("traceback");
|
|
PyObject * pTraceModule = PyImport_Import(pModuleName);
|
|
Py_XDECREF(pModuleName);
|
|
if (pTraceModule != NULL) {
|
|
PyObject * pModuleDict = PyModule_GetDict(pTraceModule);
|
|
if (pModuleDict != NULL) {
|
|
PyObject * pFunc = PyDict_GetItemString(pModuleDict,"format_exception");
|
|
if (pFunc != NULL) {
|
|
PyObject * errList = PyObject_CallFunctionObjArgs(pFunc,type_obj,value_obj, traceback_obj,NULL);
|
|
if (errList != NULL) {
|
|
int listSize = PyList_Size(errList);
|
|
for (int i=0;i < listSize; ++i) {
|
|
strErrorMsg += PyUnicode_AS_DATA(PyList_GetItem(errList,i));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Py_XDECREF(pTraceModule);
|
|
}
|
|
}//end if
|
|
#endif
|
|
}
|
|
|
|
namespace a8
|
|
{
|
|
|
|
struct PyEngineImpl
|
|
{
|
|
PyObject* main_module = nullptr;
|
|
PyObject* global_funcs = nullptr;
|
|
PyObject* module_funcs = nullptr;
|
|
};
|
|
|
|
PyEngine::PyEngine()
|
|
{
|
|
impl_ = new PyEngineImpl();
|
|
}
|
|
|
|
PyEngine::~PyEngine()
|
|
{
|
|
delete impl_;
|
|
impl_ = nullptr;
|
|
}
|
|
|
|
void PyEngine::Init()
|
|
{
|
|
Py_Initialize();
|
|
PyRun_SimpleString(
|
|
R"(
|
|
import sys
|
|
sys.path.append('./')
|
|
|
|
global_funcs = {}
|
|
module_funcs = {}
|
|
module_hash = {}
|
|
loading_module_name = ''
|
|
|
|
def export(funcs):
|
|
global module_funcs
|
|
global loading_module_name
|
|
global module_hash
|
|
for func in funcs:
|
|
module_hash[loading_module_name][func[0]] = func[1]
|
|
module_func[loading_module_name + '.' + func[0]] = func[1]
|
|
|
|
def export_global(funcs):
|
|
global global_funcs
|
|
for func in funcs:
|
|
global_func[func[0]] = func[1]
|
|
__builtins__.__dict__[func[0]] = func[1]
|
|
|
|
def call_global_func(func_name, *args):
|
|
global global_funcs
|
|
func = global_funcs[func_name]
|
|
func(args)
|
|
|
|
def call_module_func(module_name, func_name, *args):
|
|
global module_hash
|
|
internal_func_name = module_name + '.' + func_name
|
|
func = module_func[internal_func_name]
|
|
func(args)
|
|
|
|
def _clear_module_info(module_name):
|
|
global module_funcs
|
|
global loading_module_name
|
|
global module_hash
|
|
if module_name in module_hash:
|
|
for func in module_hash[module_name].keys():
|
|
del module_func[func]
|
|
#end for
|
|
del module_hash[module_name]
|
|
|
|
def onload_module(module_name):
|
|
global loading_module_name
|
|
global module_hash
|
|
loading_module_name = module_name
|
|
_clear_module_info(module_name)
|
|
module_hash[module_name] = {}
|
|
return loading_module_name
|
|
|
|
__builtins__.export = export
|
|
__builtins__.export_global = export_global
|
|
)"
|
|
);
|
|
impl_->main_module = PyImport_ImportModule("__main__" );
|
|
PyObject* dict = PyModule_GetDict(impl_->main_module);
|
|
impl_->global_funcs = PyRun_String("global_funcs" , Py_eval_input, dict, dict);
|
|
impl_->module_funcs = PyRun_String("module_funcs" , Py_eval_input, dict, dict);
|
|
}
|
|
|
|
void PyEngine::UnInit()
|
|
{
|
|
Py_Finalize();
|
|
}
|
|
|
|
bool PyEngine::IsInitialized()
|
|
{
|
|
return Py_IsInitialized();
|
|
}
|
|
|
|
bool PyEngine::LoadModule(const char* module_name)
|
|
{
|
|
std::string module_name_str = module_name;
|
|
a8::ReplaceString(module_name_str, ".", "/");
|
|
|
|
std::string real_filename = work_path + module_name_str;
|
|
real_filename = real_filename + ".py";
|
|
|
|
FILE* fp = fopen(real_filename.c_str(), "r");
|
|
if (fp) {
|
|
std::string script = std::string("onload_module('") + module_name + "')";
|
|
if (PyRun_SimpleString(script.c_str()) != 0) {
|
|
fclose(fp);
|
|
return false;
|
|
} else {
|
|
int ret = PyRun_AnyFile(fp, real_filename.c_str());
|
|
fclose(fp);
|
|
return ret == 0;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool PyEngine::ExecString(const char* script_str)
|
|
{
|
|
return PyRun_SimpleString(script_str) == 0;
|
|
}
|
|
|
|
std::tuple<bool, a8::XValue> PyEngine::CallGlobalFunc(const char* func_name,
|
|
std::initializer_list<a8::XValue> args)
|
|
{
|
|
a8::XValue result;
|
|
bool ret = CallPyFunc(impl_->global_funcs, func_name, args, result);
|
|
return std::make_tuple(ret, result);
|
|
}
|
|
|
|
std::tuple<bool, a8::XValue> PyEngine::CallModuleFunc(const char* module_name,
|
|
const char* func_name,
|
|
std::initializer_list<a8::XValue> args)
|
|
{
|
|
char internal_func_name[512];
|
|
{
|
|
int ret = snprintf(internal_func_name, a8::ArraySize(internal_func_name), "%s.%s", module_name, func_name);
|
|
if (ret < 0) {
|
|
abort();
|
|
}
|
|
}
|
|
|
|
a8::XValue result;
|
|
bool ret = CallPyFunc(impl_->module_funcs, internal_func_name, args, result);
|
|
return std::make_tuple(ret, result);
|
|
}
|
|
|
|
std::string PyEngine::GetLastError()
|
|
{
|
|
std::string strErrorMsg;
|
|
if (!PyErr_Occurred()) {
|
|
return strErrorMsg;
|
|
}
|
|
|
|
PyObject* type_obj = nullptr;
|
|
PyObject* value_obj = nullptr;
|
|
PyObject* traceback_obj = nullptr;
|
|
PyErr_Fetch(&type_obj, &value_obj, &traceback_obj);
|
|
if (value_obj == nullptr) {
|
|
return strErrorMsg;
|
|
}
|
|
#if 1
|
|
PyErr_NormalizeException(&type_obj, &value_obj, 0);
|
|
#if 0
|
|
if (PyString_Check(PyObject_Str(value_obj))) {
|
|
strErrorMsg = PyString_AsString(PyObject_Str(value_obj));
|
|
}
|
|
#endif
|
|
|
|
if (type_obj) {
|
|
Py_XDECREF(type_obj);
|
|
}
|
|
if (value_obj) {
|
|
Py_XDECREF(value_obj);
|
|
}
|
|
if (traceback_obj) {
|
|
Py_XDECREF(traceback_obj);
|
|
}
|
|
#endif
|
|
return strErrorMsg;
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|