mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-21 12:00:18 +00:00
Merge branch 'dev'
This commit is contained in:
commit
1bd443107b
1
.gitignore
vendored
1
.gitignore
vendored
@ -30,3 +30,4 @@ APPS
|
|||||||
build
|
build
|
||||||
|
|
||||||
pocketpy.dSYM
|
pocketpy.dSYM
|
||||||
|
main
|
||||||
|
@ -26,31 +26,25 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(PK_EXPORT_C_API "Export C API" ON)
|
option(PK_EXPORT_CXX_API "Export C++ API" OFF)
|
||||||
|
|
||||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
|
include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
|
||||||
|
|
||||||
if(PK_EXPORT_C_API)
|
|
||||||
message(STATUS "Exporting C API")
|
|
||||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/c_bindings)
|
|
||||||
set(PK_LIB_CPP ${CMAKE_CURRENT_LIST_DIR}/c_bindings/pocketpy_c.cpp)
|
|
||||||
else()
|
|
||||||
set(PK_LIB_CPP ${CMAKE_CURRENT_LIST_DIR}/src2/lib.cpp)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src POCKETPY_SRC)
|
aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src POCKETPY_SRC)
|
||||||
|
|
||||||
option(PK_BUILD_SHARED_LIB "Build shared library" OFF)
|
option(PK_BUILD_SHARED_LIB "Build shared library" OFF)
|
||||||
option(PK_BUILD_STATIC_LIB "Build static library" OFF)
|
option(PK_BUILD_STATIC_LIB "Build static library" OFF)
|
||||||
|
|
||||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
if (PK_EXPORT_CXX_API)
|
||||||
|
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(PK_BUILD_SHARED_LIB)
|
if(PK_BUILD_SHARED_LIB)
|
||||||
add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC} ${PK_LIB_CPP})
|
add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC})
|
||||||
elseif(PK_BUILD_STATIC_LIB)
|
elseif(PK_BUILD_STATIC_LIB)
|
||||||
add_library(${PROJECT_NAME} STATIC ${POCKETPY_SRC} ${PK_LIB_CPP})
|
add_library(${PROJECT_NAME} STATIC ${POCKETPY_SRC})
|
||||||
else()
|
else()
|
||||||
add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC} ${PK_LIB_CPP})
|
add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC})
|
||||||
set(PROJECT_EXE_NAME main)
|
set(PROJECT_EXE_NAME main)
|
||||||
add_executable(${PROJECT_EXE_NAME} src2/main.cpp)
|
add_executable(${PROJECT_EXE_NAME} src2/main.cpp)
|
||||||
target_link_libraries(${PROJECT_EXE_NAME} ${PROJECT_NAME})
|
target_link_libraries(${PROJECT_EXE_NAME} ${PROJECT_NAME})
|
||||||
|
@ -88,28 +88,12 @@ if sys.platform in ['linux', 'darwin']:
|
|||||||
|
|
||||||
print("amalgamated/pocketpy.h")
|
print("amalgamated/pocketpy.h")
|
||||||
|
|
||||||
content = []
|
|
||||||
for i in ["include/pocketpy/export.h", "c_bindings/pocketpy_c.h", "c_bindings/pocketpy_c.cpp"]:
|
|
||||||
with open(i, "rt", encoding='utf-8') as g:
|
|
||||||
content.append(g.read())
|
|
||||||
|
|
||||||
with open("amalgamated/pocketpy.cpp", "wt", encoding='utf-8') as f:
|
|
||||||
content = '\n\n'.join(content)
|
|
||||||
content = content.replace('#include "pocketpy/export.h"', '')
|
|
||||||
content = content.replace('#include "pocketpy_c.h"', '')
|
|
||||||
f.write(content)
|
|
||||||
|
|
||||||
|
|
||||||
shutil.copy("amalgamated/pocketpy.h", "plugins/flutter/src/pocketpy.h")
|
shutil.copy("amalgamated/pocketpy.h", "plugins/flutter/src/pocketpy.h")
|
||||||
shutil.copy("amalgamated/pocketpy.cpp", "plugins/flutter/src/pocketpy.cpp")
|
|
||||||
|
|
||||||
shutil.copy("amalgamated/pocketpy.h", "plugins/macos/pocketpy/pocketpy.h")
|
shutil.copy("amalgamated/pocketpy.h", "plugins/macos/pocketpy/pocketpy.h")
|
||||||
shutil.copy("amalgamated/pocketpy.cpp", "plugins/macos/pocketpy/pocketpy.cpp")
|
|
||||||
|
|
||||||
# unity plugin
|
# unity plugin
|
||||||
unity_ios_root = 'plugins/unity/PocketPyUnityPlugin/Assets/PocketPython/Plugins/iOS'
|
unity_ios_root = 'plugins/unity/PocketPyUnityPlugin/Assets/PocketPython/Plugins/iOS'
|
||||||
if os.path.exists(unity_ios_root):
|
if os.path.exists(unity_ios_root):
|
||||||
shutil.copy("amalgamated/pocketpy.h", unity_ios_root)
|
shutil.copy("amalgamated/pocketpy.h", unity_ios_root)
|
||||||
shutil.copy("amalgamated/pocketpy.cpp", unity_ios_root)
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,554 +0,0 @@
|
|||||||
#include "pocketpy.h"
|
|
||||||
#include "pocketpy_c.h"
|
|
||||||
|
|
||||||
using namespace pkpy;
|
|
||||||
|
|
||||||
typedef int (*LuaStyleFuncC)(VM*);
|
|
||||||
|
|
||||||
struct LuaStack: public ValueStackImpl<32>{
|
|
||||||
PyObject*& at(int i) {
|
|
||||||
if(i < 0 || i >= size()){
|
|
||||||
throw std::runtime_error("lua stack index out of range");
|
|
||||||
}
|
|
||||||
return _begin[i];
|
|
||||||
}
|
|
||||||
PyObject* const& at(int i) const {
|
|
||||||
if(i < 0 || i >= size()){
|
|
||||||
throw std::runtime_error("lua stack index out of range");
|
|
||||||
}
|
|
||||||
return _begin[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
void safe_push(PyObject* obj){
|
|
||||||
if(size() >= max_size()) throw std::runtime_error("lua stack overflow");
|
|
||||||
push(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
void safe_pop(){
|
|
||||||
if(size() == 0) throw std::runtime_error("lua stack is empty");
|
|
||||||
pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject*& safe_top(){
|
|
||||||
if(size() == 0) throw std::runtime_error("lua stack is empty");
|
|
||||||
return top();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define ERRHANDLER_OPEN \
|
|
||||||
if (vm->error != nullptr) \
|
|
||||||
return false; \
|
|
||||||
try {
|
|
||||||
|
|
||||||
#define ERRHANDLER_CLOSE \
|
|
||||||
} catch(Exception& e ) { \
|
|
||||||
vm->error = py_var(vm, e); \
|
|
||||||
return false; \
|
|
||||||
} catch(const std::exception& re){ \
|
|
||||||
auto e = Exception("std::exception", re.what()); \
|
|
||||||
vm->error = py_var(vm, e); \
|
|
||||||
return false; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class CVM : public VM {
|
|
||||||
public :
|
|
||||||
|
|
||||||
LuaStack* c_data;
|
|
||||||
PyObject* error;
|
|
||||||
|
|
||||||
CVM(bool enable_os=true) : VM(enable_os) {
|
|
||||||
c_data = new LuaStack();
|
|
||||||
error = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
~CVM() {
|
|
||||||
c_data->clear();
|
|
||||||
delete c_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TempStack{
|
|
||||||
CVM* cvm;
|
|
||||||
LuaStack* prev;
|
|
||||||
TempStack(CVM* cvm, LuaStack* new_data) : cvm(cvm) {
|
|
||||||
prev = cvm->c_data;
|
|
||||||
cvm->c_data = new_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
~TempStack() { restore(); }
|
|
||||||
|
|
||||||
void restore(){
|
|
||||||
if(prev == nullptr) return;
|
|
||||||
cvm->c_data = prev;
|
|
||||||
prev = nullptr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//for now I will unpack a tuple automatically, we may not want to handle
|
|
||||||
//it this way, not sure
|
|
||||||
//it is more lua like, but maybe not python like
|
|
||||||
static void unpack_return(CVM* vm, PyObject* ret) {
|
|
||||||
if (is_type(ret, vm->tp_tuple)) {
|
|
||||||
Tuple& t = _py_cast<Tuple&>(vm, ret);
|
|
||||||
for (int i = 0; i < t.size(); i++)
|
|
||||||
vm->c_data->push(t[i]);
|
|
||||||
} else if (ret == vm->None) {
|
|
||||||
//do nothing here
|
|
||||||
//having to pop the stack after every call that returns none is annoying
|
|
||||||
//lua does not do this
|
|
||||||
//
|
|
||||||
//so for now we will not push none on the stack when it is the sole thing returned
|
|
||||||
//if this becomes a problem we can change it
|
|
||||||
//
|
|
||||||
//you can still check if it returned none by comparing stack size before
|
|
||||||
//and after if you have to
|
|
||||||
} else
|
|
||||||
vm->c_data->push(ret);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
// no error
|
|
||||||
if (vm->error == nullptr) return false;
|
|
||||||
Exception& e = _py_cast<Exception&>(vm, vm->error);
|
|
||||||
if (message != nullptr)
|
|
||||||
*message = e.summary().c_str_dup();
|
|
||||||
else
|
|
||||||
std::cerr << "ERROR: " << e.summary() << "\n";
|
|
||||||
vm->error = nullptr;
|
|
||||||
vm->c_data->clear();
|
|
||||||
vm->callstack.clear();
|
|
||||||
vm->s_data.clear();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gc_marker_ex(CVM* vm) {
|
|
||||||
for(PyObject* obj: *vm->c_data) if(obj!=nullptr) PK_OBJ_MARK(obj);
|
|
||||||
if(vm->error != nullptr) PK_OBJ_MARK(vm->error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static OutputHandler stdout_handler = nullptr;
|
|
||||||
static OutputHandler stderr_handler = nullptr;
|
|
||||||
|
|
||||||
void pkpy_set_output_handlers(pkpy_vm*, OutputHandler stdout_handler, OutputHandler stderr_handler){
|
|
||||||
::stdout_handler = stdout_handler;
|
|
||||||
::stderr_handler = stderr_handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
pkpy_vm* pkpy_vm_create(bool use_stdio, bool enable_os) {
|
|
||||||
CVM* vm = new CVM(enable_os);
|
|
||||||
vm->c_data = new LuaStack();
|
|
||||||
vm->heap._gc_marker_ex = (void (*)(VM*)) gc_marker_ex;
|
|
||||||
|
|
||||||
if (!use_stdio) {
|
|
||||||
vm->_stdout = [](VM* vm, const Str& s){
|
|
||||||
std::string str = s.str();
|
|
||||||
if (stdout_handler != nullptr) stdout_handler((pkpy_vm*)vm, str.c_str());
|
|
||||||
};
|
|
||||||
vm->_stderr = [](VM* vm, const Str& s){
|
|
||||||
std::string str = s.str();
|
|
||||||
if (stderr_handler != nullptr) stderr_handler((pkpy_vm*)vm, str.c_str());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return (pkpy_vm*) vm;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_vm_run(pkpy_vm* vm_handle, const char* source) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
CodeObject_ code = vm->compile(source, "<c-bound>", EXEC_MODE);
|
|
||||||
vm->_exec(code, vm->_main);
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
|
|
||||||
//unpack_return(w, result);
|
|
||||||
//NOTE: it seems like vm->_exec should return whatever the last command it
|
|
||||||
//ran returned but instead it seems to pretty much always return None
|
|
||||||
//so I guess uncomment this line if that every changes
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pkpy_vm_destroy(pkpy_vm* vm_handle) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
delete vm;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* c_function_wrapper(VM* vm, ArgsView args) {
|
|
||||||
LuaStyleFuncC f = lambda_get_userdata<LuaStyleFuncC>(args.begin());
|
|
||||||
CVM* cvm = (CVM*) vm;
|
|
||||||
|
|
||||||
//setup c stack
|
|
||||||
LuaStack local_stack;
|
|
||||||
|
|
||||||
for (int i = 0; i < args.size(); i++)
|
|
||||||
local_stack.safe_push(args[i]);
|
|
||||||
|
|
||||||
// tmp is controlled by RAII
|
|
||||||
auto tmp = CVM::TempStack(cvm, &local_stack);
|
|
||||||
int retc = f(cvm);
|
|
||||||
|
|
||||||
// propagate_if_errored
|
|
||||||
if (cvm->error != nullptr){
|
|
||||||
Exception e = _py_cast<Exception&>(vm, cvm->error);
|
|
||||||
cvm->error = nullptr;
|
|
||||||
tmp.restore();
|
|
||||||
vm->_error(e);
|
|
||||||
}
|
|
||||||
tmp.restore();
|
|
||||||
|
|
||||||
PyObject* ret = cvm->None;
|
|
||||||
|
|
||||||
if (retc == 1)
|
|
||||||
ret = local_stack.safe_top();
|
|
||||||
else if (retc > 1) {
|
|
||||||
Tuple t(retc);
|
|
||||||
|
|
||||||
for (int i = 0; i < retc; i++) {
|
|
||||||
int stack_index = (local_stack.size() - retc) + i;
|
|
||||||
t[i] = local_stack.at(stack_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = py_var(cvm, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_push_function(pkpy_vm* vm_handle, pkpy_function f, int argc) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
NativeFunc nf = NativeFunc(c_function_wrapper, argc, false);
|
|
||||||
nf.set_userdata(f);
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
vm->c_data->safe_push(py_var(vm, nf));
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_push_int(pkpy_vm* vm_handle, int value) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
vm->c_data->safe_push(py_var(vm, value));
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_push_float(pkpy_vm* vm_handle, double value) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
vm->c_data->safe_push(py_var(vm, value));
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_push_bool(pkpy_vm* vm_handle, bool value) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
vm->c_data->safe_push(py_var(vm, value));
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_push_string(pkpy_vm* vm_handle, const char* value) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
vm->c_data->safe_push(py_var(vm, value));
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_push_stringn(pkpy_vm* vm_handle, const char* value, int length) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
vm->c_data->safe_push(py_var(vm, Str(value, length)));
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_push_voidp(pkpy_vm* vm_handle, void* value) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
vm->c_data->safe_push(py_var(vm, value));
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_push_none(pkpy_vm* vm_handle) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
vm->c_data->safe_push(vm->None);
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool pkpy_set_global(pkpy_vm* vm_handle, const char* name) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
vm->_main->attr().set(name, vm->c_data->safe_top());
|
|
||||||
vm->c_data->safe_pop();
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//get global will also get bulitins
|
|
||||||
bool pkpy_get_global(pkpy_vm* vm_handle, const char* name) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
PyObject* o = vm->_main->attr().try_get(name);
|
|
||||||
if (o == nullptr) {
|
|
||||||
o = vm->builtins->attr().try_get(name);
|
|
||||||
if (o == nullptr)
|
|
||||||
throw Exception("NameError", name);
|
|
||||||
}
|
|
||||||
vm->c_data->safe_push(o);
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool pkpy_call(pkpy_vm* vm_handle, int argc) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
int callable_index = vm->c_data->size() - argc - 1;
|
|
||||||
PyObject* callable = vm->c_data->at(callable_index);
|
|
||||||
vm->s_data.push(callable);
|
|
||||||
vm->s_data.push(PY_NULL);
|
|
||||||
|
|
||||||
for (int i = 0; i < argc; i++)
|
|
||||||
vm->s_data.push(vm->c_data->at(callable_index + i + 1));
|
|
||||||
|
|
||||||
PyObject* o = vm->vectorcall(argc);
|
|
||||||
|
|
||||||
vm->c_data->shrink(argc + 1);
|
|
||||||
|
|
||||||
unpack_return(vm, o);
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_call_method(pkpy_vm* vm_handle, const char* name, int argc) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
|
|
||||||
int self_index = vm->c_data->size() - argc - 1;
|
|
||||||
PyObject* self = vm->c_data->at(self_index);
|
|
||||||
|
|
||||||
PyObject* callable = vm->get_unbound_method(self, name, &self);
|
|
||||||
|
|
||||||
vm->s_data.push(callable);
|
|
||||||
vm->s_data.push(self);
|
|
||||||
|
|
||||||
for (int i = 0; i < argc; i++)
|
|
||||||
vm->s_data.push(vm->c_data->at(self_index + i + 1));
|
|
||||||
|
|
||||||
PyObject* o = vm->vectorcall(argc);
|
|
||||||
vm->c_data->shrink(argc + 1);
|
|
||||||
unpack_return(vm, o);
|
|
||||||
return true;
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lua_to_cstack_index(int index, int size) {
|
|
||||||
if (index < 0) index = size + index;
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_to_int(pkpy_vm* vm_handle, int index, int* ret) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
|
|
||||||
index = lua_to_cstack_index(index, vm->c_data->size());
|
|
||||||
|
|
||||||
PyObject* o = vm->c_data->at(index);
|
|
||||||
if (ret != nullptr) *ret = py_cast<int>(vm, o);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_to_float(pkpy_vm* vm_handle, int index, double* ret) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
index = lua_to_cstack_index(index, vm->c_data->size());
|
|
||||||
PyObject* o = vm->c_data->at(index);
|
|
||||||
if (ret != nullptr) *ret = py_cast<double>(vm, o);
|
|
||||||
return true;
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_to_bool(pkpy_vm* vm_handle, int index, bool* ret) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
index = lua_to_cstack_index(index, vm->c_data->size());
|
|
||||||
PyObject* o = vm->c_data->at(index);
|
|
||||||
if (ret != nullptr) *ret = py_cast<bool>(vm, o);
|
|
||||||
return true;
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_to_voidp(pkpy_vm* vm_handle, int index, void** ret) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
index = lua_to_cstack_index(index, vm->c_data->size());
|
|
||||||
PyObject* o = vm->c_data->at(index);
|
|
||||||
if (ret != nullptr) *ret = py_cast<void*>(vm, o);
|
|
||||||
return true;
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_to_string(pkpy_vm* vm_handle, int index, char** ret) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
index = lua_to_cstack_index(index, vm->c_data->size());
|
|
||||||
PyObject* o = vm->c_data->at(index);
|
|
||||||
if (ret != nullptr) {
|
|
||||||
*ret = py_cast<Str&>(vm, o).c_str_dup();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_to_stringn(pkpy_vm* vm_handle, int index, const char** ret, int* size) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
index = lua_to_cstack_index(index, vm->c_data->size());
|
|
||||||
PyObject* o = vm->c_data->at(index);
|
|
||||||
if (ret != nullptr) {
|
|
||||||
std::string_view sv = py_cast<Str&>(vm, o).sv();
|
|
||||||
*ret = sv.data();
|
|
||||||
*size = sv.size();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool pkpy_is_int(pkpy_vm* vm_handle, int index) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
index = lua_to_cstack_index(index, vm->c_data->size());
|
|
||||||
PyObject* o = vm->c_data->at(index);
|
|
||||||
return is_type(o, vm->tp_int);
|
|
||||||
}
|
|
||||||
bool pkpy_is_float(pkpy_vm* vm_handle, int index) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
index = lua_to_cstack_index(index, vm->c_data->size());
|
|
||||||
PyObject* o = vm->c_data->at(index);
|
|
||||||
return is_type(o, vm->tp_float);
|
|
||||||
}
|
|
||||||
bool pkpy_is_bool(pkpy_vm* vm_handle, int index) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
index = lua_to_cstack_index(index, vm->c_data->size());
|
|
||||||
PyObject* o = vm->c_data->at(index);
|
|
||||||
return is_type(o, vm->tp_bool);
|
|
||||||
}
|
|
||||||
bool pkpy_is_string(pkpy_vm* vm_handle, int index) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
index = lua_to_cstack_index(index, vm->c_data->size());
|
|
||||||
PyObject* o = vm->c_data->at(index);
|
|
||||||
return is_type(o, vm->tp_str);
|
|
||||||
}
|
|
||||||
bool pkpy_is_voidp(pkpy_vm* vm_handle, int index) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
index = lua_to_cstack_index(index, vm->c_data->size());
|
|
||||||
PyObject* o = vm->c_data->at(index);
|
|
||||||
return is_type(o, VoidP::_type(vm));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_is_none(pkpy_vm* vm_handle, int index) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
index = lua_to_cstack_index(index, vm->c_data->size());
|
|
||||||
PyObject* o = vm->c_data->at(index);
|
|
||||||
return o == vm->None;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_check_global(pkpy_vm* vm_handle, const char* name) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
PyObject* o = vm->_main->attr().try_get(name);
|
|
||||||
if (o == nullptr) {
|
|
||||||
o = vm->builtins->attr().try_get(name);
|
|
||||||
if (o == nullptr)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_check_error(pkpy_vm* vm_handle) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
return vm->error != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool pkpy_check_stack(pkpy_vm* vm_handle, int free) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
return free + vm->c_data->size() <= LuaStack::max_size();
|
|
||||||
}
|
|
||||||
|
|
||||||
int pkpy_stack_size(pkpy_vm* vm_handle) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
return vm->c_data->size();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_pop(pkpy_vm* vm_handle, int n) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
vm->c_data->shrink(n);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool pkpy_push(pkpy_vm* vm_handle, int index) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
index = lua_to_cstack_index(index, vm->c_data->size());
|
|
||||||
vm->c_data->safe_push(vm->c_data->at(index));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool pkpy_error(pkpy_vm* vm_handle, const char* name, const char* message) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
// already in error state
|
|
||||||
if (vm->error != nullptr) return false;
|
|
||||||
vm->error = py_var(vm, Exception(name, message));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_getattr(pkpy_vm* vm_handle, const char* name) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
PyObject* o = vm->c_data->safe_top();
|
|
||||||
PyObject* ret = vm->getattr(o, name, false);
|
|
||||||
if(ret == nullptr) return false;
|
|
||||||
vm->c_data->top() = ret;
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_setattr(pkpy_vm* vm_handle, const char* name) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
if(vm->c_data->size() < 2){
|
|
||||||
throw std::runtime_error("not enough arguments");
|
|
||||||
}
|
|
||||||
PyObject* a = vm->c_data->top();
|
|
||||||
PyObject* val = vm->c_data->second();
|
|
||||||
vm->setattr(a, name, val);
|
|
||||||
vm->c_data->shrink(2);
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_eval(pkpy_vm* vm_handle, const char* code) {
|
|
||||||
CVM* vm = (CVM*) vm_handle;
|
|
||||||
ERRHANDLER_OPEN
|
|
||||||
CodeObject_ co = vm->compile(code, "<eval>", EVAL_MODE);
|
|
||||||
PyObject* ret = vm->_exec(co, vm->_main);
|
|
||||||
vm->c_data->safe_push(ret);
|
|
||||||
ERRHANDLER_CLOSE
|
|
||||||
return true;
|
|
||||||
}
|
|
@ -1,122 +0,0 @@
|
|||||||
#ifndef POCKETPY_C_H
|
|
||||||
#define POCKETPY_C_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "pocketpy/export.h"
|
|
||||||
|
|
||||||
typedef struct pkpy_vm_handle pkpy_vm;
|
|
||||||
|
|
||||||
//we we take a lot of inspiration from the lua api for these bindings
|
|
||||||
//the key difference being most methods return a bool,
|
|
||||||
//true if it succeeded false if it did not
|
|
||||||
|
|
||||||
//if a method returns false call the pkpy_clear_error method to check the error and clear it
|
|
||||||
//if pkpy_clear_error returns false it means that no error was set, and it takes no action
|
|
||||||
//if pkpy_clear_error returns true it means there was an error and it was cleared,
|
|
||||||
//it will provide a string summary of the error in the message parameter (if it is not NULL)
|
|
||||||
//if null is passed in as message, and it will just print the message to stderr
|
|
||||||
PK_EXPORT bool pkpy_clear_error(pkpy_vm*, char** message);
|
|
||||||
//NOTE you are responsible for freeing message
|
|
||||||
|
|
||||||
//this will cause the vm to enter an error state and report the given message
|
|
||||||
//when queried
|
|
||||||
//note that at the moment this is more like a panic than throwing an error
|
|
||||||
//the user will not be able to catch it with python code
|
|
||||||
PK_EXPORT bool pkpy_error(pkpy_vm*, const char* name, const char* message);
|
|
||||||
|
|
||||||
PK_EXPORT pkpy_vm* pkpy_vm_create(bool use_stdio, bool enable_os);
|
|
||||||
PK_EXPORT bool pkpy_vm_run(pkpy_vm*, const char* source);
|
|
||||||
PK_EXPORT void pkpy_vm_destroy(pkpy_vm*);
|
|
||||||
|
|
||||||
typedef int (*pkpy_function)(pkpy_vm*);
|
|
||||||
|
|
||||||
PK_EXPORT bool pkpy_pop(pkpy_vm*, int n);
|
|
||||||
|
|
||||||
//push the item at index onto the top of the stack (as well as leaving it where
|
|
||||||
//it is on the stack)
|
|
||||||
PK_EXPORT bool pkpy_push(pkpy_vm*, int index);
|
|
||||||
|
|
||||||
PK_EXPORT bool pkpy_push_function(pkpy_vm*, pkpy_function, int);
|
|
||||||
PK_EXPORT bool pkpy_push_int(pkpy_vm*, int);
|
|
||||||
PK_EXPORT bool pkpy_push_float(pkpy_vm*, double);
|
|
||||||
PK_EXPORT bool pkpy_push_bool(pkpy_vm*, bool);
|
|
||||||
PK_EXPORT bool pkpy_push_string(pkpy_vm*, const char*);
|
|
||||||
PK_EXPORT bool pkpy_push_stringn(pkpy_vm*, const char*, int length);
|
|
||||||
PK_EXPORT bool pkpy_push_voidp(pkpy_vm*, void*);
|
|
||||||
PK_EXPORT bool pkpy_push_none(pkpy_vm*);
|
|
||||||
|
|
||||||
PK_EXPORT bool pkpy_set_global(pkpy_vm*, const char* name);
|
|
||||||
PK_EXPORT bool pkpy_get_global(pkpy_vm*, const char* name);
|
|
||||||
|
|
||||||
//first push callable you want to call
|
|
||||||
//then push the arguments to send
|
|
||||||
//argc is the number of arguments that was pushed (not counting the callable)
|
|
||||||
PK_EXPORT bool pkpy_call(pkpy_vm*, int argc);
|
|
||||||
|
|
||||||
//first push the object the method belongs to (self)
|
|
||||||
//then push the the argments
|
|
||||||
//argc is the number of arguments that was pushed (not counting the callable or self)
|
|
||||||
//name is the name of the method to call on the object
|
|
||||||
PK_EXPORT bool pkpy_call_method(pkpy_vm*, const char* name, int argc);
|
|
||||||
|
|
||||||
|
|
||||||
//we will break with the lua api here
|
|
||||||
//lua uses 1 as the index to the first pushed element for all of these functions
|
|
||||||
//but we will start counting at zero to match python
|
|
||||||
//we will allow negative numbers to count backwards from the top
|
|
||||||
PK_EXPORT bool pkpy_to_int(pkpy_vm*, int index, int* ret);
|
|
||||||
PK_EXPORT bool pkpy_to_float(pkpy_vm*, int index, double* ret);
|
|
||||||
PK_EXPORT bool pkpy_to_bool(pkpy_vm*, int index, bool* ret);
|
|
||||||
PK_EXPORT bool pkpy_to_voidp(pkpy_vm*, int index, void** ret);
|
|
||||||
|
|
||||||
//this method provides a strong reference, you are responsible for freeing the
|
|
||||||
//string when you are done with it
|
|
||||||
PK_EXPORT bool pkpy_to_string(pkpy_vm*, int index, char** ret);
|
|
||||||
|
|
||||||
//this method provides a weak reference, it is only valid until the
|
|
||||||
//next api call
|
|
||||||
//it is not null terminated
|
|
||||||
PK_EXPORT bool pkpy_to_stringn(pkpy_vm*, int index, const char** ret, int* size);
|
|
||||||
|
|
||||||
|
|
||||||
//these do not follow the same error semantics as above, their return values
|
|
||||||
//just say whether the check succeeded or not, or else return the value asked for
|
|
||||||
|
|
||||||
PK_EXPORT bool pkpy_is_int(pkpy_vm*, int index);
|
|
||||||
PK_EXPORT bool pkpy_is_float(pkpy_vm*, int index);
|
|
||||||
PK_EXPORT bool pkpy_is_bool(pkpy_vm*, int index);
|
|
||||||
PK_EXPORT bool pkpy_is_string(pkpy_vm*, int index);
|
|
||||||
PK_EXPORT bool pkpy_is_voidp(pkpy_vm*, int index);
|
|
||||||
PK_EXPORT bool pkpy_is_none(pkpy_vm*, int index);
|
|
||||||
|
|
||||||
|
|
||||||
//will return true if global exists
|
|
||||||
PK_EXPORT bool pkpy_check_global(pkpy_vm*, const char* name);
|
|
||||||
|
|
||||||
//will return true if the vm is currently in an error state
|
|
||||||
PK_EXPORT bool pkpy_check_error(pkpy_vm*);
|
|
||||||
|
|
||||||
//will return true if at least free empty slots remain on the stack
|
|
||||||
PK_EXPORT bool pkpy_check_stack(pkpy_vm*, int free);
|
|
||||||
|
|
||||||
//returns the number of elements on the stack
|
|
||||||
PK_EXPORT int pkpy_stack_size(pkpy_vm*);
|
|
||||||
|
|
||||||
typedef void (*OutputHandler)(pkpy_vm*, const char*);
|
|
||||||
PK_EXPORT void pkpy_set_output_handlers(pkpy_vm*, OutputHandler stdout_handler, OutputHandler stderr_handler);
|
|
||||||
|
|
||||||
PK_EXPORT bool pkpy_getattr(pkpy_vm*, const char* name);
|
|
||||||
PK_EXPORT bool pkpy_setattr(pkpy_vm*, const char* name);
|
|
||||||
PK_EXPORT bool pkpy_eval(pkpy_vm*, const char* source);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
@ -14,20 +14,26 @@ Special thanks for [@koltenpearson](https://github.com/koltenpearson) for bringi
|
|||||||
|
|
||||||
## Basic Functions
|
## Basic Functions
|
||||||
|
|
||||||
#### `pkpy_vm* pkpy_vm_create(bool use_stdio, bool enable_os)`
|
#### `pkpy_vm* pkpy_new_vm(bool enable_os)`
|
||||||
|
|
||||||
Creates a new Lua Style VM.
|
Create a new VM.
|
||||||
|
|
||||||
+ `use_stdio`: if true, the VM will use stdout and stderr
|
|
||||||
+ `enable_os`: if true, the VM will have access to the os library
|
+ `enable_os`: if true, the VM will have access to the os library
|
||||||
|
|
||||||
#### `bool pkpy_vm_run(pkpy_vm*, const char* source)`
|
#### `bool pkpy_vm_run(pkpy_vm* vm_handle, const char* source)`
|
||||||
|
|
||||||
Runs the given source code in the VM.
|
Run the given source code in the VM.
|
||||||
|
|
||||||
+ `source`: the source code to run
|
+ `source`: the source code to run
|
||||||
|
|
||||||
#### `void pkpy_vm_destroy(pkpy_vm*)`
|
#### `void pkpy_delete_vm(pkpy_vm* vm_handle)`
|
||||||
|
|
||||||
Destroys the VM.
|
Dispose the VM.
|
||||||
|
|
||||||
|
#### `bool pkpy_vm_exec(pkpy_vm* vm_handle, const char* source)`
|
||||||
|
|
||||||
|
A wrapper of `vm->exec(...)`.
|
||||||
|
|
||||||
|
#### `bool pkpy_vm_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, int mode, const char* module)`
|
||||||
|
|
||||||
|
A wrapper of `vm->exec_2(...)`.
|
@ -128,6 +128,29 @@ struct FuncDecl {
|
|||||||
void _gc_mark() const;
|
void _gc_mark() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct UserData{
|
||||||
|
char data[16];
|
||||||
|
bool empty;
|
||||||
|
|
||||||
|
UserData(): empty(true) {}
|
||||||
|
template<typename T>
|
||||||
|
UserData(T t): empty(false){
|
||||||
|
static_assert(std::is_trivially_copyable_v<T>);
|
||||||
|
static_assert(sizeof(T) <= sizeof(data));
|
||||||
|
memcpy(data, &t, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T get() const{
|
||||||
|
static_assert(std::is_trivially_copyable_v<T>);
|
||||||
|
static_assert(sizeof(T) <= sizeof(data));
|
||||||
|
#if PK_DEBUG_EXTRA_CHECK
|
||||||
|
PK_ASSERT(!empty);
|
||||||
|
#endif
|
||||||
|
return reinterpret_cast<const T&>(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct NativeFunc {
|
struct NativeFunc {
|
||||||
NativeFuncC f;
|
NativeFuncC f;
|
||||||
|
|
||||||
@ -137,27 +160,14 @@ struct NativeFunc {
|
|||||||
// new style decl-based call
|
// new style decl-based call
|
||||||
FuncDecl_ decl;
|
FuncDecl_ decl;
|
||||||
|
|
||||||
using UserData = char[32];
|
|
||||||
UserData _userdata;
|
UserData _userdata;
|
||||||
bool _has_userdata;
|
|
||||||
|
|
||||||
template <typename T>
|
void set_userdata(UserData data) {
|
||||||
void set_userdata(T data) {
|
if(!_userdata.empty && !data.empty){
|
||||||
static_assert(std::is_trivially_copyable_v<T>);
|
// override is not supported
|
||||||
static_assert(sizeof(T) <= sizeof(UserData));
|
throw std::runtime_error("userdata already set");
|
||||||
if(_has_userdata) throw std::runtime_error("userdata already set");
|
}
|
||||||
_has_userdata = true;
|
_userdata = data;
|
||||||
memcpy(_userdata, &data, sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T get_userdata() const {
|
|
||||||
static_assert(std::is_trivially_copyable_v<T>);
|
|
||||||
static_assert(sizeof(T) <= sizeof(UserData));
|
|
||||||
#if PK_DEBUG_EXTRA_CHECK
|
|
||||||
if(!_has_userdata) throw std::runtime_error("userdata not set");
|
|
||||||
#endif
|
|
||||||
return reinterpret_cast<const T&>(_userdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeFunc(NativeFuncC f, int argc, bool method);
|
NativeFunc(NativeFuncC f, int argc, bool method);
|
||||||
@ -201,8 +211,8 @@ struct Py_<NativeFunc> final: PyObject {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T lambda_get_userdata(PyObject** p){
|
T lambda_get_userdata(PyObject** p){
|
||||||
if(p[-1] != PY_NULL) return PK_OBJ_GET(NativeFunc, p[-1]).get_userdata<T>();
|
if(p[-1] != PY_NULL) return PK_OBJ_GET(NativeFunc, p[-1])._userdata.get<T>();
|
||||||
else return PK_OBJ_GET(NativeFunc, p[-2]).get_userdata<T>();
|
else return PK_OBJ_GET(NativeFunc, p[-2])._userdata.get<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
@ -20,7 +20,7 @@
|
|||||||
#include <variant>
|
#include <variant>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#define PK_VERSION "1.0.9"
|
#define PK_VERSION "1.1.0"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "export.h"
|
#include "export.h"
|
||||||
@ -150,25 +150,3 @@ inline PyObject* const PY_OP_YIELD = (PyObject*)0b110011;
|
|||||||
#define ADD_MODULE_PLACEHOLDER(name) namespace pkpy { inline void add_module_##name(void* vm) { (void)vm; } }
|
#define ADD_MODULE_PLACEHOLDER(name) namespace pkpy { inline void add_module_##name(void* vm) { (void)vm; } }
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef NOMINMAX
|
|
||||||
#define NOMINMAX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <Windows.h>
|
|
||||||
|
|
||||||
#elif __EMSCRIPTEN__
|
|
||||||
|
|
||||||
#include <emscripten.h>
|
|
||||||
|
|
||||||
#elif __unix__
|
|
||||||
|
|
||||||
#include <dlfcn.h>
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,19 +1,44 @@
|
|||||||
#ifndef PK_EXPORT
|
#pragma once
|
||||||
|
|
||||||
#ifdef _WIN32
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
||||||
#define PK_EXPORT __declspec(dllexport)
|
//define something for Windows (32-bit and 64-bit, this part is common)
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
#define NOMINMAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#define PK_EXPORT __declspec(dllexport)
|
||||||
|
#define PK_SUPPORT_DYLIB 1
|
||||||
#elif __EMSCRIPTEN__
|
#elif __EMSCRIPTEN__
|
||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
#define PK_EXPORT EMSCRIPTEN_KEEPALIVE
|
#define PK_EXPORT EMSCRIPTEN_KEEPALIVE
|
||||||
|
#define PK_SUPPORT_DYLIB 0
|
||||||
|
#elif __APPLE__
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#define PK_SUPPORT_DYLIB 2
|
||||||
|
#if TARGET_IPHONE_SIMULATOR
|
||||||
|
// iOS, tvOS, or watchOS Simulator
|
||||||
|
#elif TARGET_OS_MACCATALYST
|
||||||
|
// Mac's Catalyst (ports iOS API into Mac, like UIKit).
|
||||||
|
#elif TARGET_OS_IPHONE
|
||||||
|
// iOS, tvOS, or watchOS device
|
||||||
|
#elif TARGET_OS_MAC
|
||||||
|
// Other kinds of Apple platforms
|
||||||
|
#else
|
||||||
|
# error "Unknown Apple platform"
|
||||||
|
#endif
|
||||||
|
#define PK_EXPORT __attribute__((visibility("default")))
|
||||||
|
#elif __linux__
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#define PK_SUPPORT_DYLIB 2
|
||||||
|
#define PK_EXPORT __attribute__((visibility("default")))
|
||||||
#else
|
#else
|
||||||
#define PK_EXPORT __attribute__((visibility("default")))
|
#define PK_EXPORT
|
||||||
#endif
|
#define PK_SUPPORT_DYLIB 0
|
||||||
|
|
||||||
#define PK_INLINE_EXPORT PK_EXPORT inline
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PK_SHARED_MODULE
|
|
||||||
#undef PK_INLINE_EXPORT
|
|
||||||
#define PK_INLINE_EXPORT inline
|
|
||||||
#endif
|
#endif
|
@ -24,6 +24,9 @@ struct FastLocals{
|
|||||||
|
|
||||||
PyObject** try_get_name(StrName name);
|
PyObject** try_get_name(StrName name);
|
||||||
NameDict_ to_namedict();
|
NameDict_ to_namedict();
|
||||||
|
|
||||||
|
PyObject** begin() const { return a; }
|
||||||
|
PyObject** end() const { return a + size(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<size_t MAX_SIZE>
|
template<size_t MAX_SIZE>
|
||||||
@ -63,6 +66,9 @@ struct ValueStackImpl {
|
|||||||
void clear() { _sp = _begin; }
|
void clear() { _sp = _begin; }
|
||||||
bool is_overflow() const { return _sp >= _max_end; }
|
bool is_overflow() const { return _sp >= _max_end; }
|
||||||
|
|
||||||
|
PyObject* operator[](int i) const { return _begin[i]; }
|
||||||
|
PyObject*& operator[](int i) { return _begin[i]; }
|
||||||
|
|
||||||
ValueStackImpl(const ValueStackImpl&) = delete;
|
ValueStackImpl(const ValueStackImpl&) = delete;
|
||||||
ValueStackImpl(ValueStackImpl&&) = delete;
|
ValueStackImpl(ValueStackImpl&&) = delete;
|
||||||
ValueStackImpl& operator=(const ValueStackImpl&) = delete;
|
ValueStackImpl& operator=(const ValueStackImpl&) = delete;
|
||||||
|
@ -246,8 +246,8 @@ struct MemoryPool{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PK_EXPORT inline MemoryPool<64> pool64;
|
inline MemoryPool<64> pool64;
|
||||||
PK_EXPORT inline MemoryPool<128> pool128;
|
inline MemoryPool<128> pool128;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct shared_ptr {
|
struct shared_ptr {
|
||||||
|
@ -95,82 +95,3 @@ void add_module_traceback(VM* vm);
|
|||||||
void add_module_gc(VM* vm);
|
void add_module_gc(VM* vm);
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|
||||||
/*************************GLOBAL NAMESPACE*************************/
|
|
||||||
extern "C" {
|
|
||||||
PK_INLINE_EXPORT
|
|
||||||
void pkpy_free(void* p){
|
|
||||||
free(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
PK_INLINE_EXPORT
|
|
||||||
void pkpy_vm_exec(pkpy::VM* vm, const char* source){
|
|
||||||
vm->exec(source, "main.py", pkpy::EXEC_MODE);
|
|
||||||
}
|
|
||||||
|
|
||||||
PK_INLINE_EXPORT
|
|
||||||
void pkpy_vm_exec_2(pkpy::VM* vm, const char* source, const char* filename, int mode, const char* module){
|
|
||||||
pkpy::PyObject* mod;
|
|
||||||
if(module == nullptr) mod = vm->_main;
|
|
||||||
else{
|
|
||||||
mod = vm->_modules.try_get(module);
|
|
||||||
if(mod == nullptr) return;
|
|
||||||
}
|
|
||||||
vm->exec(source, filename, (pkpy::CompileMode)mode, mod);
|
|
||||||
}
|
|
||||||
|
|
||||||
PK_INLINE_EXPORT
|
|
||||||
void pkpy_vm_compile(pkpy::VM* vm, const char* source, const char* filename, int mode, bool* ok, char** res){
|
|
||||||
try{
|
|
||||||
pkpy::CodeObject_ code = vm->compile(source, filename, (pkpy::CompileMode)mode);
|
|
||||||
*res = code->serialize(vm).c_str_dup();
|
|
||||||
*ok = true;
|
|
||||||
}catch(pkpy::Exception& e){
|
|
||||||
*ok = false;
|
|
||||||
*res = e.summary().c_str_dup();
|
|
||||||
}catch(std::exception& e){
|
|
||||||
*ok = false;
|
|
||||||
*res = strdup(e.what());
|
|
||||||
}catch(...){
|
|
||||||
*ok = false;
|
|
||||||
*res = strdup("unknown error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PK_INLINE_EXPORT
|
|
||||||
pkpy::REPL* pkpy_new_repl(pkpy::VM* vm){
|
|
||||||
pkpy::REPL* p = new pkpy::REPL(vm);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
PK_INLINE_EXPORT
|
|
||||||
bool pkpy_repl_input(pkpy::REPL* r, const char* line){
|
|
||||||
return r->input(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
PK_INLINE_EXPORT
|
|
||||||
void pkpy_vm_add_module(pkpy::VM* vm, const char* name, const char* source){
|
|
||||||
vm->_lazy_modules[name] = source;
|
|
||||||
}
|
|
||||||
|
|
||||||
PK_INLINE_EXPORT
|
|
||||||
pkpy::VM* pkpy_new_vm(bool enable_os=true){
|
|
||||||
pkpy::VM* p = new pkpy::VM(enable_os);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
PK_INLINE_EXPORT
|
|
||||||
void pkpy_delete_vm(pkpy::VM* vm){
|
|
||||||
delete vm;
|
|
||||||
}
|
|
||||||
|
|
||||||
PK_INLINE_EXPORT
|
|
||||||
void pkpy_delete_repl(pkpy::REPL* repl){
|
|
||||||
delete repl;
|
|
||||||
}
|
|
||||||
|
|
||||||
PK_INLINE_EXPORT
|
|
||||||
void pkpy_vm_gc_on_delete(pkpy::VM* vm, void (*f)(pkpy::VM *, pkpy::PyObject *)){
|
|
||||||
vm->heap._gc_on_delete = f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
103
include/pocketpy/pocketpy_c.h
Normal file
103
include/pocketpy/pocketpy_c.h
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#ifndef POCKETPY_C_H
|
||||||
|
#define POCKETPY_C_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "export.h"
|
||||||
|
|
||||||
|
typedef struct pkpy_vm_handle pkpy_vm;
|
||||||
|
typedef int (*pkpy_CFunction)(pkpy_vm*);
|
||||||
|
typedef int pkpy_CName;
|
||||||
|
typedef int pkpy_CType;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
const char* data;
|
||||||
|
int size;
|
||||||
|
}pkpy_CString;
|
||||||
|
|
||||||
|
/* Basic Functions */
|
||||||
|
PK_EXPORT pkpy_vm* pkpy_new_vm(bool enable_os);
|
||||||
|
PK_EXPORT void pkpy_delete_vm(pkpy_vm*);
|
||||||
|
PK_EXPORT bool pkpy_exec(pkpy_vm*, const char* source);
|
||||||
|
PK_EXPORT bool pkpy_exec_2(pkpy_vm*, const char* source, const char* filename, int mode, const char* module);
|
||||||
|
|
||||||
|
/* Stack Manipulation */
|
||||||
|
PK_EXPORT bool pkpy_pop(pkpy_vm*, int);
|
||||||
|
PK_EXPORT bool pkpy_pop_top(pkpy_vm*);
|
||||||
|
PK_EXPORT bool pkpy_dup_top(pkpy_vm*);
|
||||||
|
PK_EXPORT bool pkpy_rot_two(pkpy_vm*);
|
||||||
|
PK_EXPORT int pkpy_stack_size(pkpy_vm*);
|
||||||
|
|
||||||
|
// int
|
||||||
|
PK_EXPORT bool pkpy_push_int(pkpy_vm*, int);
|
||||||
|
PK_EXPORT bool pkpy_is_int(pkpy_vm*, int i);
|
||||||
|
PK_EXPORT bool pkpy_to_int(pkpy_vm*, int i, int* out);
|
||||||
|
|
||||||
|
// float
|
||||||
|
PK_EXPORT bool pkpy_push_float(pkpy_vm*, float);
|
||||||
|
PK_EXPORT bool pkpy_is_float(pkpy_vm*, int i);
|
||||||
|
PK_EXPORT bool pkpy_to_float(pkpy_vm*, int i, float* out);
|
||||||
|
|
||||||
|
// bool
|
||||||
|
PK_EXPORT bool pkpy_push_bool(pkpy_vm*, bool);
|
||||||
|
PK_EXPORT bool pkpy_is_bool(pkpy_vm*, int i);
|
||||||
|
PK_EXPORT bool pkpy_to_bool(pkpy_vm*, int i, bool* out);
|
||||||
|
|
||||||
|
// string
|
||||||
|
PK_EXPORT bool pkpy_push_string(pkpy_vm*, const char*);
|
||||||
|
PK_EXPORT bool pkpy_is_string(pkpy_vm*, int i);
|
||||||
|
PK_EXPORT bool pkpy_to_string(pkpy_vm*, int i, pkpy_CString* out);
|
||||||
|
|
||||||
|
// void_p
|
||||||
|
PK_EXPORT bool pkpy_push_voidp(pkpy_vm*, void*);
|
||||||
|
PK_EXPORT bool pkpy_is_voidp(pkpy_vm*, int i);
|
||||||
|
PK_EXPORT bool pkpy_to_voidp(pkpy_vm*, int i, void** out);
|
||||||
|
|
||||||
|
// none
|
||||||
|
PK_EXPORT bool pkpy_push_none(pkpy_vm*);
|
||||||
|
PK_EXPORT bool pkpy_is_none(pkpy_vm*, int i);
|
||||||
|
|
||||||
|
// null
|
||||||
|
PK_EXPORT bool pkpy_push_null(pkpy_vm*);
|
||||||
|
|
||||||
|
// special push
|
||||||
|
PK_EXPORT bool pkpy_push_function(pkpy_vm*, const char*, pkpy_CFunction);
|
||||||
|
PK_EXPORT bool pkpy_push_module(pkpy_vm*, const char*);
|
||||||
|
|
||||||
|
// some opt
|
||||||
|
PK_EXPORT bool pkpy_load_attr(pkpy_vm*, pkpy_CName);
|
||||||
|
PK_EXPORT bool pkpy_store_attr(pkpy_vm*, pkpy_CName);
|
||||||
|
PK_EXPORT bool pkpy_load_global(pkpy_vm*, pkpy_CName);
|
||||||
|
PK_EXPORT bool pkpy_store_global(pkpy_vm*, pkpy_CName);
|
||||||
|
PK_EXPORT bool pkpy_eval(pkpy_vm*, const char* source);
|
||||||
|
PK_EXPORT bool pkpy_unpack_sequence(pkpy_vm*, int size);
|
||||||
|
PK_EXPORT bool pkpy_get_unbound_method(pkpy_vm*, pkpy_CName);
|
||||||
|
|
||||||
|
/* Error Handling */
|
||||||
|
PK_EXPORT bool pkpy_error(pkpy_vm*, const char* name, const char* message);
|
||||||
|
PK_EXPORT bool pkpy_check_error(pkpy_vm*);
|
||||||
|
PK_EXPORT bool pkpy_clear_error(pkpy_vm*, char** message);
|
||||||
|
|
||||||
|
/* Callables */
|
||||||
|
PK_EXPORT bool pkpy_vectorcall(pkpy_vm*, int argc);
|
||||||
|
|
||||||
|
/* Special APIs */
|
||||||
|
PK_EXPORT void pkpy_free(void* p);
|
||||||
|
PK_EXPORT pkpy_CName pkpy_name(const char*);
|
||||||
|
PK_EXPORT void pkpy_compile_to_string(pkpy_vm*, const char* source, const char* filename, int mode, bool* ok, char** out);
|
||||||
|
|
||||||
|
/* REPL */
|
||||||
|
PK_EXPORT void* pkpy_new_repl(pkpy_vm* vm);
|
||||||
|
PK_EXPORT bool pkpy_repl_input(void* r, const char* line);
|
||||||
|
PK_EXPORT void pkpy_delete_repl(void* repl);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
std::string platform_getline(bool* eof=nullptr);
|
|
||||||
|
|
||||||
class REPL {
|
class REPL {
|
||||||
protected:
|
protected:
|
||||||
int need_more_lines = 0;
|
int need_more_lines = 0;
|
||||||
|
@ -117,6 +117,10 @@ public:
|
|||||||
NameDict _modules; // loaded modules
|
NameDict _modules; // loaded modules
|
||||||
std::map<StrName, Str> _lazy_modules; // lazy loaded modules
|
std::map<StrName, Str> _lazy_modules; // lazy loaded modules
|
||||||
|
|
||||||
|
struct{
|
||||||
|
PyObject* error;
|
||||||
|
} _c;
|
||||||
|
|
||||||
PyObject* None;
|
PyObject* None;
|
||||||
PyObject* True;
|
PyObject* True;
|
||||||
PyObject* False;
|
PyObject* False;
|
||||||
@ -453,8 +457,8 @@ public:
|
|||||||
PyObject* _py_generator(Frame&& frame, ArgsView buffer);
|
PyObject* _py_generator(Frame&& frame, ArgsView buffer);
|
||||||
void _prepare_py_call(PyObject**, ArgsView, ArgsView, const FuncDecl_&);
|
void _prepare_py_call(PyObject**, ArgsView, ArgsView, const FuncDecl_&);
|
||||||
// new style binding api
|
// new style binding api
|
||||||
PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, void* userdata=nullptr);
|
PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, UserData userdata={});
|
||||||
PyObject* bind(PyObject*, const char*, NativeFuncC, void* userdata=nullptr);
|
PyObject* bind(PyObject*, const char*, NativeFuncC, UserData userdata={});
|
||||||
};
|
};
|
||||||
|
|
||||||
DEF_NATIVE_2(Str, tp_str)
|
DEF_NATIVE_2(Str, tp_str)
|
||||||
|
3
include/pocketpy_c.h
Normal file
3
include/pocketpy_c.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pocketpy/pocketpy_c.h"
|
@ -108,7 +108,7 @@ __NEXT_STEP:;
|
|||||||
TARGET(LOAD_FAST) {
|
TARGET(LOAD_FAST) {
|
||||||
heap._auto_collect();
|
heap._auto_collect();
|
||||||
_0 = frame->_locals[byte.arg];
|
_0 = frame->_locals[byte.arg];
|
||||||
if(_0 == PY_NULL) vm->NameError(co->varnames[byte.arg]);
|
if(_0 == PY_NULL) vm->UnboundLocalError(co->varnames[byte.arg]);
|
||||||
PUSH(_0);
|
PUSH(_0);
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
TARGET(LOAD_NAME) {
|
TARGET(LOAD_NAME) {
|
||||||
@ -201,7 +201,7 @@ __NEXT_STEP:;
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
TARGET(DELETE_FAST)
|
TARGET(DELETE_FAST)
|
||||||
_0 = frame->_locals[byte.arg];
|
_0 = frame->_locals[byte.arg];
|
||||||
if(_0 == PY_NULL) vm->NameError(co->varnames[byte.arg]);
|
if(_0 == PY_NULL) vm->UnboundLocalError(co->varnames[byte.arg]);
|
||||||
frame->_locals[byte.arg] = PY_NULL;
|
frame->_locals[byte.arg] = PY_NULL;
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
TARGET(DELETE_NAME)
|
TARGET(DELETE_NAME)
|
||||||
|
@ -158,14 +158,12 @@ void CodeObjectSerializer::write_code(VM* vm, const CodeObject* co){
|
|||||||
this->f = f;
|
this->f = f;
|
||||||
this->argc = argc;
|
this->argc = argc;
|
||||||
if(argc != -1) this->argc += (int)method;
|
if(argc != -1) this->argc += (int)method;
|
||||||
_has_userdata = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeFunc::NativeFunc(NativeFuncC f, FuncDecl_ decl){
|
NativeFunc::NativeFunc(NativeFuncC f, FuncDecl_ decl){
|
||||||
this->f = f;
|
this->f = f;
|
||||||
this->argc = -1;
|
this->argc = -1;
|
||||||
this->decl = decl;
|
this->decl = decl;
|
||||||
_has_userdata = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
@ -58,7 +58,7 @@ namespace pkpy{
|
|||||||
if(_next_ip >= co->codes.size()){
|
if(_next_ip >= co->codes.size()){
|
||||||
while(i>=0) i = _exit_block(i);
|
while(i>=0) i = _exit_block(i);
|
||||||
}else{
|
}else{
|
||||||
// BUG!!!
|
// BUG (solved)
|
||||||
// for i in range(4):
|
// for i in range(4):
|
||||||
// _ = 0
|
// _ = 0
|
||||||
// # if there is no op here, the block check will fail
|
// # if there is no op here, the block check will fail
|
||||||
|
@ -6,22 +6,38 @@ using dylib_entry_t = PyObject*(*)(VM*, const char*);
|
|||||||
|
|
||||||
#if PK_ENABLE_OS
|
#if PK_ENABLE_OS
|
||||||
|
|
||||||
#if _WIN32
|
#if PK_SUPPORT_DYLIB == 1
|
||||||
static dylib_entry_t load_dylib(const char* path){
|
static dylib_entry_t load_dylib(const char* path){
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
auto p = std::filesystem::absolute(path, ec);
|
auto p = std::filesystem::absolute(path, ec);
|
||||||
if(ec) return nullptr;
|
if(ec) return nullptr;
|
||||||
HMODULE handle = LoadLibraryA((LPCSTR)p.c_str());
|
HMODULE handle = LoadLibraryA((LPCSTR)"test.dll");
|
||||||
|
// get last error
|
||||||
|
// Get the last error code
|
||||||
|
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||||
|
DWORD errorCode = GetLastError();
|
||||||
|
|
||||||
|
// Convert the error code to text
|
||||||
|
LPSTR errorMessage = nullptr;
|
||||||
|
FormatMessageA(
|
||||||
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
nullptr,
|
||||||
|
errorCode,
|
||||||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
|
(LPSTR)&errorMessage,
|
||||||
|
0,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
// Print the error message to stdout
|
||||||
|
printf("%lu: %s\n", errorCode, errorMessage);
|
||||||
|
|
||||||
|
// Free the message buffer
|
||||||
|
LocalFree(errorMessage);
|
||||||
if(!handle) return nullptr;
|
if(!handle) return nullptr;
|
||||||
return (dylib_entry_t)GetProcAddress(handle, "platform_module__init__");
|
return (dylib_entry_t)GetProcAddress(handle, "platform_module__init__");
|
||||||
}
|
}
|
||||||
#elif __EMSCRIPTEN__
|
#elif PK_SUPPORT_DYLIB == 2
|
||||||
|
|
||||||
static dylib_entry_t load_dylib(const char* path){
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif __unix__
|
|
||||||
|
|
||||||
static dylib_entry_t load_dylib(const char* path){
|
static dylib_entry_t load_dylib(const char* path){
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
|
520
src/pocketpy_c.cpp
Normal file
520
src/pocketpy_c.cpp
Normal file
@ -0,0 +1,520 @@
|
|||||||
|
#include "pocketpy.h"
|
||||||
|
#include "pocketpy/obj.h"
|
||||||
|
#include "pocketpy/pocketpy_c.h"
|
||||||
|
#include "pocketpy/tuplelist.h"
|
||||||
|
#include "pocketpy_c.h"
|
||||||
|
|
||||||
|
using namespace pkpy;
|
||||||
|
|
||||||
|
typedef int (*LuaStyleFuncC)(VM*);
|
||||||
|
|
||||||
|
#define C_API_ASSERT(x) if(!(x)) { pkpy_error(vm_handle, "AssertionError", #x); return false; }
|
||||||
|
|
||||||
|
#define PK_ASSERT_N_EXTRA_ELEMENTS(n) \
|
||||||
|
if(!has_n_extra_elements(vm, n)){ \
|
||||||
|
pkpy_error(vm_handle, "StackError", "not enough elements on stack"); \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PK_ASSERT_NO_ERROR() \
|
||||||
|
if(vm->_c.error != nullptr) \
|
||||||
|
return false;
|
||||||
|
|
||||||
|
static int has_n_extra_elements(VM* vm, int n){
|
||||||
|
if(vm->callstack.empty()){
|
||||||
|
return vm->s_data.size() >= n;
|
||||||
|
}
|
||||||
|
PyObject** base = vm->top_frame()->_locals.end();
|
||||||
|
return vm->s_data._sp - base >= n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject* stack_item(VM* vm, int index){
|
||||||
|
PyObject** begin;
|
||||||
|
PyObject** end;
|
||||||
|
if(vm->callstack.empty()){
|
||||||
|
begin = vm->s_data.begin();
|
||||||
|
end = vm->s_data.end();
|
||||||
|
}else{
|
||||||
|
Frame* frame = vm->top_frame().get();
|
||||||
|
begin = frame->_locals.begin();
|
||||||
|
end = frame->_locals.end();
|
||||||
|
}
|
||||||
|
// may raise
|
||||||
|
index = vm->normalized_index(index, end-begin);
|
||||||
|
return begin[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PK_PROTECTED(__B) \
|
||||||
|
try{ __B } \
|
||||||
|
catch(Exception& e ) { \
|
||||||
|
vm->_c.error = py_var(vm, e); \
|
||||||
|
return false; \
|
||||||
|
} catch(const std::exception& re){ \
|
||||||
|
auto e = Exception("std::exception", re.what()); \
|
||||||
|
vm->_c.error = py_var(vm, e); \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
|
pkpy_vm* pkpy_new_vm(bool enable_os){
|
||||||
|
return (pkpy_vm*)new VM(enable_os);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pkpy_delete_vm(pkpy_vm* vm){
|
||||||
|
return delete (VM*)vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_exec(pkpy_vm* vm_handle, const char* source) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PyObject* res;
|
||||||
|
PK_PROTECTED(
|
||||||
|
CodeObject_ code = vm->compile(source, "main.py", EXEC_MODE);
|
||||||
|
res = vm->_exec(code, vm->_main);
|
||||||
|
)
|
||||||
|
return res != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, int mode, const char* module){
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PyObject* res;
|
||||||
|
PyObject* mod;
|
||||||
|
PK_PROTECTED(
|
||||||
|
if(module == nullptr){
|
||||||
|
mod = vm->_main;
|
||||||
|
}else{
|
||||||
|
mod = vm->_modules[module]; // may raise
|
||||||
|
}
|
||||||
|
CodeObject_ code = vm->compile(source, filename, (CompileMode)mode);
|
||||||
|
res = vm->_exec(code, mod);
|
||||||
|
)
|
||||||
|
return res != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_pop(pkpy_vm* vm_handle, int n){
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_ASSERT_N_EXTRA_ELEMENTS(n)
|
||||||
|
vm->s_data.shrink(n);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_pop_top(pkpy_vm* vm_handle){
|
||||||
|
VM* vm = (VM*)vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||||
|
vm->s_data.pop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_dup_top(pkpy_vm* vm_handle){
|
||||||
|
VM* vm = (VM*)vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||||
|
vm->s_data.push(vm->s_data.top());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_rot_two(pkpy_vm* vm_handle){
|
||||||
|
VM* vm = (VM*)vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_ASSERT_N_EXTRA_ELEMENTS(2)
|
||||||
|
std::swap(vm->s_data.top(), vm->s_data.second());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pkpy_stack_size(pkpy_vm* vm_handle){
|
||||||
|
VM* vm = (VM*)vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
if(vm->callstack.empty()){
|
||||||
|
return vm->s_data.size();
|
||||||
|
}
|
||||||
|
return vm->top_frame()->stack_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// int
|
||||||
|
bool pkpy_push_int(pkpy_vm* vm_handle, int value) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PyObject* res;
|
||||||
|
PK_PROTECTED(
|
||||||
|
// int may overflow so we should protect it
|
||||||
|
res = py_var(vm, value);
|
||||||
|
)
|
||||||
|
vm->s_data.push(res);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_is_int(pkpy_vm* vm_handle, int i){
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_PROTECTED(
|
||||||
|
return is_int(stack_item(vm, i));
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_to_int(pkpy_vm* vm_handle, int i, int* out){
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_PROTECTED(
|
||||||
|
PyObject* item = stack_item(vm, i);
|
||||||
|
*out = py_cast<int>(vm, item);
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// float
|
||||||
|
bool pkpy_push_float(pkpy_vm* vm_handle, float value) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PyObject* res = py_var(vm, value);
|
||||||
|
vm->s_data.push(res);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_is_float(pkpy_vm* vm_handle, int i){
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_PROTECTED(
|
||||||
|
PyObject* item = stack_item(vm, i);
|
||||||
|
return is_float(item);
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_to_float(pkpy_vm* vm_handle, int i, float* out){
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_PROTECTED(
|
||||||
|
PyObject* item = stack_item(vm, i);
|
||||||
|
*out = py_cast<float>(vm, item);
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bool
|
||||||
|
bool pkpy_push_bool(pkpy_vm* vm_handle, bool value) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
vm->s_data.push(value ? vm->True : vm->False);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_is_bool(pkpy_vm* vm_handle, int i){
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_PROTECTED(
|
||||||
|
PyObject* item = stack_item(vm, i);
|
||||||
|
return is_non_tagged_type(item, vm->tp_bool);
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_to_bool(pkpy_vm* vm_handle, int i, bool* out){
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_PROTECTED(
|
||||||
|
PyObject* item = stack_item(vm, i);
|
||||||
|
*out = py_cast<bool>(vm, item);
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// string
|
||||||
|
bool pkpy_push_string(pkpy_vm* vm_handle, const char* value) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PyObject* res = py_var(vm, value);
|
||||||
|
vm->s_data.push(res);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_is_string(pkpy_vm* vm_handle, int i){
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_PROTECTED(
|
||||||
|
PyObject* item = stack_item(vm, i);
|
||||||
|
return is_non_tagged_type(item, vm->tp_str);
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_to_string(pkpy_vm* vm_handle, int i, pkpy_CString* out){
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_PROTECTED(
|
||||||
|
PyObject* item = stack_item(vm, i);
|
||||||
|
const Str& s = py_cast<Str&>(vm, item);
|
||||||
|
out->data = s.data;
|
||||||
|
out->size = s.size;
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// void_p
|
||||||
|
bool pkpy_push_voidp(pkpy_vm* vm_handle, void* value) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PyObject* res = py_var(vm, value);
|
||||||
|
vm->s_data.push(res);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_is_voidp(pkpy_vm* vm_handle, int i){
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_PROTECTED(
|
||||||
|
PyObject* item = stack_item(vm, i);
|
||||||
|
return is_non_tagged_type(item, VoidP::_type(vm));
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_to_voidp(pkpy_vm* vm_handle, int i, void** out){
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_PROTECTED(
|
||||||
|
PyObject* item = stack_item(vm, i);
|
||||||
|
VoidP& vp = py_cast<VoidP&>(vm, item);
|
||||||
|
*out = vp.ptr;
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// none
|
||||||
|
bool pkpy_push_none(pkpy_vm* vm_handle) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
vm->s_data.push(vm->None);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_is_none(pkpy_vm* vm_handle, int i){
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_PROTECTED(
|
||||||
|
PyObject* item = stack_item(vm, i);
|
||||||
|
return item == vm->None;
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// null
|
||||||
|
bool pkpy_push_null(pkpy_vm* vm_handle) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
vm->s_data.push(PY_NULL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// function
|
||||||
|
static PyObject* c_function_wrapper(VM* vm, ArgsView args) {
|
||||||
|
LuaStyleFuncC f = lambda_get_userdata<LuaStyleFuncC>(args.begin());
|
||||||
|
PyObject** curr_sp = &vm->s_data.top();
|
||||||
|
int retc = f(vm);
|
||||||
|
// propagate_if_errored
|
||||||
|
if (vm->_c.error != nullptr){
|
||||||
|
Exception e = _py_cast<Exception&>(vm, vm->_c.error);
|
||||||
|
vm->_c.error = nullptr;
|
||||||
|
vm->_error(e);
|
||||||
|
}
|
||||||
|
PK_ASSERT(retc == vm->s_data._sp-curr_sp);
|
||||||
|
if(retc == 0) return vm->None;
|
||||||
|
if (retc == 1) return vm->s_data.popx();
|
||||||
|
ArgsView ret_view(curr_sp, vm->s_data._sp);
|
||||||
|
return py_var(vm, ret_view.to_tuple());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_push_function(pkpy_vm* vm_handle, const char* sig, pkpy_CFunction f) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PyObject* f_obj;
|
||||||
|
PK_PROTECTED(
|
||||||
|
f_obj = vm->bind(
|
||||||
|
nullptr,
|
||||||
|
sig,
|
||||||
|
nullptr,
|
||||||
|
c_function_wrapper,
|
||||||
|
f
|
||||||
|
);
|
||||||
|
)
|
||||||
|
vm->s_data.push(f_obj);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// special push
|
||||||
|
bool pkpy_push_module(pkpy_vm* vm_handle, const char* name) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_PROTECTED(
|
||||||
|
PyObject* module = vm->new_module(name);
|
||||||
|
vm->s_data.push(module);
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// some opt
|
||||||
|
bool pkpy_load_attr(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||||
|
PyObject* o = vm->s_data.top();
|
||||||
|
PK_PROTECTED(
|
||||||
|
o = vm->getattr(o, StrName(name));
|
||||||
|
)
|
||||||
|
vm->s_data.top() = o;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_store_attr(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_ASSERT_N_EXTRA_ELEMENTS(2)
|
||||||
|
PyObject* a = vm->s_data.top();
|
||||||
|
PyObject* val = vm->s_data.second();
|
||||||
|
PK_PROTECTED(
|
||||||
|
vm->setattr(a, StrName(name), val);
|
||||||
|
)
|
||||||
|
vm->s_data.shrink(2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get global will also get bulitins
|
||||||
|
bool pkpy_load_global(pkpy_vm* vm_handle, const char* name) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PyObject* o = vm->_main->attr().try_get(name);
|
||||||
|
if (o == nullptr) {
|
||||||
|
o = vm->builtins->attr().try_get(name);
|
||||||
|
if (o == nullptr){
|
||||||
|
pkpy_error(vm_handle, "NameError", name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vm->s_data.push(o);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_store_global(pkpy_vm* vm_handle, const char* name) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||||
|
vm->_main->attr().set(name, vm->s_data.popx());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_eval(pkpy_vm* vm_handle, const char* source) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_PROTECTED(
|
||||||
|
CodeObject_ co = vm->compile(source, "<eval>", EVAL_MODE);
|
||||||
|
PyObject* ret = vm->_exec(co, vm->_main);
|
||||||
|
vm->s_data.push(ret);
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_unpack_sequence(pkpy_vm* vm_handle, int n) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||||
|
auto _lock = vm->heap.gc_scope_lock();
|
||||||
|
PK_PROTECTED(
|
||||||
|
PyObject* _0 = vm->py_iter(vm->s_data.popx());
|
||||||
|
for(int i=0; i<n; i++){
|
||||||
|
PyObject* _1 = vm->py_next(_0);
|
||||||
|
if(_1 == vm->StopIteration) vm->ValueError("not enough values to unpack");
|
||||||
|
vm->s_data.push(_1);
|
||||||
|
}
|
||||||
|
if(vm->py_next(_0) != vm->StopIteration) vm->ValueError("too many values to unpack");
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_get_unbound_method(pkpy_vm* vm_handle, pkpy_CName name){
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||||
|
PyObject* o = vm->s_data.top();
|
||||||
|
PyObject* self;
|
||||||
|
PK_PROTECTED(
|
||||||
|
o = vm->get_unbound_method(o, StrName(name), &self);
|
||||||
|
)
|
||||||
|
vm->s_data.shrink(2);
|
||||||
|
vm->s_data.push(o);
|
||||||
|
vm->s_data.push(self);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Error Handling */
|
||||||
|
bool pkpy_error(pkpy_vm* vm_handle, const char* name, const char* message) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
vm->_c.error = py_var(vm, Exception(name, message));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_check_error(pkpy_vm* vm_handle) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
return vm->_c.error != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
// no error
|
||||||
|
if (vm->_c.error == nullptr) return false;
|
||||||
|
Exception& e = _py_cast<Exception&>(vm, vm->_c.error);
|
||||||
|
if (message != nullptr)
|
||||||
|
*message = e.summary().c_str_dup();
|
||||||
|
else
|
||||||
|
std::cerr << "ERROR: " << e.summary() << "\n";
|
||||||
|
vm->_c.error = nullptr;
|
||||||
|
// clear the whole stack??
|
||||||
|
vm->callstack.clear();
|
||||||
|
vm->s_data.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_vectorcall(pkpy_vm* vm_handle, int argc) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_N_EXTRA_ELEMENTS(argc + 2)
|
||||||
|
PyObject* res;
|
||||||
|
PK_PROTECTED(
|
||||||
|
res = vm->vectorcall(argc);
|
||||||
|
)
|
||||||
|
vm->s_data.push(res);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*****************************************************************/
|
||||||
|
void pkpy_free(void* p){
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
pkpy_CName pkpy_name(const char* name){
|
||||||
|
return StrName(name).index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pkpy_compile_to_string(pkpy_vm* vm_handle, const char* source, const char* filename, int mode, bool* ok, char** out){
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
try{
|
||||||
|
CodeObject_ code = vm->compile(source, filename, (CompileMode)mode);
|
||||||
|
*out = code->serialize(vm).c_str_dup();
|
||||||
|
*ok = true;
|
||||||
|
}catch(Exception& e){
|
||||||
|
*ok = false;
|
||||||
|
*out = e.summary().c_str_dup();
|
||||||
|
}catch(std::exception& e){
|
||||||
|
*ok = false;
|
||||||
|
*out = strdup(e.what());
|
||||||
|
}catch(...){
|
||||||
|
*ok = false;
|
||||||
|
*out = strdup("unknown error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* pkpy_new_repl(pkpy_vm* vm_handle){
|
||||||
|
return new REPL((VM*)vm_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_repl_input(void* r, const char* line){
|
||||||
|
return ((REPL*)r)->input(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pkpy_delete_repl(void* repl){
|
||||||
|
delete (REPL*)repl;
|
||||||
|
}
|
33
src/repl.cpp
33
src/repl.cpp
@ -1,39 +1,6 @@
|
|||||||
#include "pocketpy/repl.h"
|
#include "pocketpy/repl.h"
|
||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
|
|
||||||
std::string platform_getline(bool* eof){
|
|
||||||
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
|
||||||
std::wstringstream wss;
|
|
||||||
WCHAR buf;
|
|
||||||
DWORD read;
|
|
||||||
while (ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') {
|
|
||||||
if(eof && buf == L'\x1A') *eof = true; // Ctrl+Z
|
|
||||||
wss << buf;
|
|
||||||
}
|
|
||||||
std::wstring wideInput = wss.str();
|
|
||||||
int length = WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), NULL, 0, NULL, NULL);
|
|
||||||
std::string output;
|
|
||||||
output.resize(length);
|
|
||||||
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), &output[0], length, NULL, NULL);
|
|
||||||
if(!output.empty() && output.back() == '\r') output.pop_back();
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
std::string platform_getline(bool* eof){
|
|
||||||
std::string line;
|
|
||||||
if(!std::getline(std::cin, line)){
|
|
||||||
if(eof) *eof = true;
|
|
||||||
}
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
REPL::REPL(VM* vm) : vm(vm){
|
REPL::REPL(VM* vm) : vm(vm){
|
||||||
vm->_stdout(vm, "pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") ");
|
vm->_stdout(vm, "pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") ");
|
||||||
vm->_stdout(vm, fmt("[", sizeof(void*)*8, " bit]" "\n"));
|
vm->_stdout(vm, fmt("[", sizeof(void*)*8, " bit]" "\n"));
|
||||||
|
10
src/vm.cpp
10
src/vm.cpp
@ -956,11 +956,11 @@ void VM::setattr(PyObject* obj, StrName name, PyObject* value){
|
|||||||
obj->attr().set(name, value);
|
obj->attr().set(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* VM::bind(PyObject* obj, const char* sig, NativeFuncC fn, void* userdata){
|
PyObject* VM::bind(PyObject* obj, const char* sig, NativeFuncC fn, UserData userdata){
|
||||||
return bind(obj, sig, nullptr, fn, userdata);
|
return bind(obj, sig, nullptr, fn, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, NativeFuncC fn, void* userdata){
|
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, NativeFuncC fn, UserData userdata){
|
||||||
CodeObject_ co;
|
CodeObject_ co;
|
||||||
try{
|
try{
|
||||||
// fn(a, b, *c, d=1) -> None
|
// fn(a, b, *c, d=1) -> None
|
||||||
@ -977,10 +977,8 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
|
|||||||
decl->docstring = Str(docstring).strip();
|
decl->docstring = Str(docstring).strip();
|
||||||
}
|
}
|
||||||
PyObject* f_obj = VAR(NativeFunc(fn, decl));
|
PyObject* f_obj = VAR(NativeFunc(fn, decl));
|
||||||
if(userdata != nullptr){
|
PK_OBJ_GET(NativeFunc, f_obj).set_userdata(userdata);
|
||||||
PK_OBJ_GET(NativeFunc, f_obj).set_userdata(userdata);
|
if(obj != nullptr) obj->attr().set(decl->code->name, f_obj);
|
||||||
}
|
|
||||||
obj->attr().set(decl->code->name, f_obj);
|
|
||||||
return f_obj;
|
return f_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1 +0,0 @@
|
|||||||
#include "pocketpy.h"
|
|
@ -1,31 +1,64 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "pocketpy.h"
|
#include "pocketpy_c.h"
|
||||||
|
|
||||||
std::string f_input(){
|
|
||||||
return pkpy::platform_getline();
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
std::string pkpy_platform_getline(bool* eof){
|
||||||
|
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
std::wstringstream wss;
|
||||||
|
WCHAR buf;
|
||||||
|
DWORD read;
|
||||||
|
while (ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') {
|
||||||
|
if(eof && buf == L'\x1A') *eof = true; // Ctrl+Z
|
||||||
|
wss << buf;
|
||||||
|
}
|
||||||
|
std::wstring wideInput = wss.str();
|
||||||
|
int length = WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), NULL, 0, NULL, NULL);
|
||||||
|
std::string output;
|
||||||
|
output.resize(length);
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), &output[0], length, NULL, NULL);
|
||||||
|
if(!output.empty() && output.back() == '\r') output.pop_back();
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
std::string pkpy_platform_getline(bool* eof){
|
||||||
|
std::string output;
|
||||||
|
if(!std::getline(std::cin, output)){
|
||||||
|
if(eof) *eof = true;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// std::string f_input(){
|
||||||
|
// return pkpy::platform_getline();
|
||||||
|
// }
|
||||||
|
|
||||||
int main(int argc, char** argv){
|
int main(int argc, char** argv){
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
SetConsoleOutputCP(CP_UTF8);
|
|
||||||
// implicitly load pocketpy.dll in current directory
|
// implicitly load pocketpy.dll in current directory
|
||||||
#elif __linux__
|
#elif __linux__
|
||||||
dlopen("libpocketpy.so", RTLD_NOW | RTLD_GLOBAL);
|
dlopen("libpocketpy.so", RTLD_NOW | RTLD_GLOBAL);
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
dlopen("libpocketpy.dylib", RTLD_NOW | RTLD_GLOBAL);
|
dlopen("libpocketpy.dylib", RTLD_NOW | RTLD_GLOBAL);
|
||||||
#endif
|
#endif
|
||||||
pkpy::VM* vm = pkpy_new_vm();
|
pkpy_vm* vm = pkpy_new_vm(true);
|
||||||
pkpy::_bind(vm, vm->builtins, "input() -> str", &f_input);
|
// pkpy::_bind(vm, vm->builtins, "input() -> str", &f_input);
|
||||||
|
|
||||||
if(argc == 1){
|
if(argc == 1){
|
||||||
pkpy::REPL* repl = pkpy_new_repl(vm);
|
void* repl = pkpy_new_repl(vm);
|
||||||
bool need_more_lines = false;
|
bool need_more_lines = false;
|
||||||
while(true){
|
while(true){
|
||||||
vm->_stdout(vm, need_more_lines ? "... " : ">>> ");
|
std::cout << (need_more_lines ? "... " : ">>> ");
|
||||||
bool eof = false;
|
bool eof = false;
|
||||||
std::string line = pkpy::platform_getline(&eof);
|
std::string line = pkpy_platform_getline(&eof);
|
||||||
if(eof) break;
|
if(eof) break;
|
||||||
need_more_lines = pkpy_repl_input(repl, line.c_str());
|
need_more_lines = pkpy_repl_input(repl, line.c_str());
|
||||||
}
|
}
|
||||||
@ -54,10 +87,10 @@ int main(int argc, char** argv){
|
|||||||
// set parent path as cwd
|
// set parent path as cwd
|
||||||
std::filesystem::current_path(filepath.parent_path());
|
std::filesystem::current_path(filepath.parent_path());
|
||||||
|
|
||||||
pkpy::PyObject* ret = nullptr;
|
pkpy_exec_2(vm, src.c_str(), filepath.filename().string().c_str(), 0, NULL);
|
||||||
ret = vm->exec(src.c_str(), filepath.filename().string(), pkpy::EXEC_MODE);
|
|
||||||
pkpy_delete_vm(vm);
|
pkpy_delete_vm(vm);
|
||||||
return ret != nullptr ? 0 : 1;
|
// return ret != nullptr ? 0 : 1;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__HELP:
|
__HELP:
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#define PK_SHARED_MODULE
|
|
||||||
#include "pocketpy.h"
|
#include "pocketpy.h"
|
||||||
|
|
||||||
using namespace pkpy;
|
using namespace pkpy;
|
||||||
@ -15,15 +14,4 @@ extern "C" {
|
|||||||
});
|
});
|
||||||
return mod;
|
return mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if _WIN32
|
|
||||||
BOOL WINAPI DllMain(
|
|
||||||
HINSTANCE hinstDLL, // handle to DLL module
|
|
||||||
DWORD fdwReason, // reason for calling function
|
|
||||||
LPVOID lpvReserved ) // reserved
|
|
||||||
{
|
|
||||||
return TRUE; // Successful DLL_PROCESS_ATTACH.
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user