a8/a8/pyengine.cc
2021-04-14 17:08:02 +08:00

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