From 48e21faecd49cb7ab44b60c1097eb05c42c00538 Mon Sep 17 00:00:00 2001 From: BLUELOVETH Date: Fri, 14 Jul 2023 17:19:38 +0800 Subject: [PATCH] ... --- include/pocketpy/export.h | 58 ++- include/pocketpy/frame.h | 3 + include/pocketpy/pocketpy_c.h | 119 ++--- include/pocketpy/vm.h | 4 + src/codeobject.cpp | 2 - src/frame.cpp | 2 +- src/pocketpy.cpp | 10 +- src/pocketpy_c.cpp | 819 +++++++++++++++++----------------- src2/main.cpp | 4 +- 9 files changed, 532 insertions(+), 489 deletions(-) diff --git a/include/pocketpy/export.h b/include/pocketpy/export.h index fd51fc52..39a253c4 100644 --- a/include/pocketpy/export.h +++ b/include/pocketpy/export.h @@ -1,28 +1,44 @@ -#ifndef PK_EXPORT +#pragma once -#ifdef _WIN32 +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) + //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 WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif + #ifndef NOMINMAX + #define NOMINMAX + #endif -#ifndef NOMINMAX -#define NOMINMAX -#endif + #include -#include - -#define PK_EXPORT __declspec(dllexport) + #define PK_EXPORT __declspec(dllexport) + #define PK_SUPPORT_DYLIB 1 #elif __EMSCRIPTEN__ -#include -#define PK_EXPORT EMSCRIPTEN_KEEPALIVE + #include + #define PK_EXPORT EMSCRIPTEN_KEEPALIVE + #define PK_SUPPORT_DYLIB 0 +#elif __APPLE__ + #include + #include + #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 + #define PK_SUPPORT_DYLIB 2 + #define PK_EXPORT __attribute__((visibility("default"))) #else -#define PK_EXPORT __attribute__((visibility("default"))) -#endif - -#endif - - -#ifdef __unix__ -#include + #define PK_EXPORT + #define PK_SUPPORT_DYLIB 0 #endif \ No newline at end of file diff --git a/include/pocketpy/frame.h b/include/pocketpy/frame.h index 62b996f8..294cbe9a 100644 --- a/include/pocketpy/frame.h +++ b/include/pocketpy/frame.h @@ -24,6 +24,9 @@ struct FastLocals{ PyObject** try_get_name(StrName name); NameDict_ to_namedict(); + + PyObject** begin() const { return a; } + PyObject** end() const { return a + size(); } }; template diff --git a/include/pocketpy/pocketpy_c.h b/include/pocketpy/pocketpy_c.h index 1917e817..94a72427 100644 --- a/include/pocketpy/pocketpy_c.h +++ b/include/pocketpy/pocketpy_c.h @@ -11,85 +11,90 @@ extern "C" { #include "export.h" typedef struct pkpy_vm_handle pkpy_vm; -typedef int (*pkpy_function)(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* vm); -PK_EXPORT bool pkpy_vm_exec(pkpy_vm* vm, const char* source); -PK_EXPORT bool pkpy_vm_exec_2(pkpy_vm* vm, const char* source, const char* filename, int mode, const char* module); +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 n); +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 bool pkpy_push_function(pkpy_vm*, pkpy_function, int); +PK_EXPORT int pkpy_stack_size(pkpy_vm*); + +// int PK_EXPORT bool pkpy_push_int(pkpy_vm*, int); -PK_EXPORT bool pkpy_push_float(pkpy_vm*, double); +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_push_stringn(pkpy_vm*, const char*, int length); +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_push_eval(pkpy_vm*, const char* source); -PK_EXPORT bool pkpy_push_module(pkpy_vm*, const char* name); +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_clear_error(pkpy_vm*, char** message); PK_EXPORT bool pkpy_error(pkpy_vm*, const char* name, const char* message); -//will return true if the vm is currently in an error state PK_EXPORT bool pkpy_check_error(pkpy_vm*); - -/* Variables */ - -PK_EXPORT bool pkpy_set_global(pkpy_vm*, const char* name); -PK_EXPORT bool pkpy_get_global(pkpy_vm*, const char* name); -//will return true if global exists -PK_EXPORT bool pkpy_check_global(pkpy_vm*, const char* name); -PK_EXPORT bool pkpy_getattr(pkpy_vm*, const char* name); -PK_EXPORT bool pkpy_setattr(pkpy_vm*, const char* name); +PK_EXPORT bool pkpy_clear_error(pkpy_vm*, char** message); /* Callables */ +PK_EXPORT bool pkpy_vectorcall(pkpy_vm*, int argc); -PK_EXPORT bool pkpy_call(pkpy_vm*, int argc); -PK_EXPORT bool pkpy_call_method(pkpy_vm*, const char* name, int argc); - -/* Types */ - -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); - -/* special api */ - -// free a pointer allocated from pkpy's heap +/* Special APIs */ PK_EXPORT void pkpy_free(void* p); -PK_EXPORT void pkpy_vm_compile(void* vm, const char* source, const char* filename, int mode, bool* ok, char** res); -PK_EXPORT void* pkpy_new_repl(void* vm); +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 diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index a047a15f..44e1b756 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -117,6 +117,10 @@ public: NameDict _modules; // loaded modules std::map _lazy_modules; // lazy loaded modules + struct{ + PyObject* error; + } _c; + PyObject* None; PyObject* True; PyObject* False; diff --git a/src/codeobject.cpp b/src/codeobject.cpp index 95a8f3d4..65ce9286 100644 --- a/src/codeobject.cpp +++ b/src/codeobject.cpp @@ -158,14 +158,12 @@ void CodeObjectSerializer::write_code(VM* vm, const CodeObject* co){ this->f = f; this->argc = argc; if(argc != -1) this->argc += (int)method; - _has_userdata = false; } NativeFunc::NativeFunc(NativeFuncC f, FuncDecl_ decl){ this->f = f; this->argc = -1; this->decl = decl; - _has_userdata = false; } } // namespace pkpy \ No newline at end of file diff --git a/src/frame.cpp b/src/frame.cpp index 0b4cea45..5df2957c 100644 --- a/src/frame.cpp +++ b/src/frame.cpp @@ -58,7 +58,7 @@ namespace pkpy{ if(_next_ip >= co->codes.size()){ while(i>=0) i = _exit_block(i); }else{ - // BUG!!! + // BUG (solved) // for i in range(4): // _ = 0 // # if there is no op here, the block check will fail diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index 90bcb94f..c5e4604b 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -6,7 +6,7 @@ using dylib_entry_t = PyObject*(*)(VM*, const char*); #if PK_ENABLE_OS -#if _WIN32 +#if PK_SUPPORT_DYLIB == 1 static dylib_entry_t load_dylib(const char* path){ std::error_code ec; auto p = std::filesystem::absolute(path, ec); @@ -37,13 +37,7 @@ static dylib_entry_t load_dylib(const char* path){ if(!handle) return nullptr; return (dylib_entry_t)GetProcAddress(handle, "platform_module__init__"); } -#elif __EMSCRIPTEN__ - -static dylib_entry_t load_dylib(const char* path){ - return nullptr; -} - -#elif __unix__ +#elif PK_SUPPORT_DYLIB == 2 static dylib_entry_t load_dylib(const char* path){ std::error_code ec; diff --git a/src/pocketpy_c.cpp b/src/pocketpy_c.cpp index 7b637320..2580c916 100644 --- a/src/pocketpy_c.cpp +++ b/src/pocketpy_c.cpp @@ -1,4 +1,6 @@ #include "pocketpy.h" +#include "pocketpy/obj.h" +#include "pocketpy/pocketpy_c.h" #include "pocketpy/tuplelist.h" #include "pocketpy_c.h" @@ -6,13 +8,45 @@ using namespace pkpy; typedef int (*LuaStyleFuncC)(VM*); -#define ERRHANDLER_OPEN \ - if (vm->_c.error != nullptr) \ - return false; \ - try { +#define C_API_ASSERT(x) if(!(x)) { pkpy_error(vm_handle, "AssertionError", #x); return false; } -#define ERRHANDLER_CLOSE \ - } catch(Exception& e ) { \ +#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){ \ @@ -29,75 +63,247 @@ void pkpy_delete_vm(pkpy_vm* vm){ return delete (VM*)vm; } -bool pkpy_vm_exec(pkpy_vm* vm_handle, const char* source) { +bool pkpy_exec(pkpy_vm* vm_handle, const char* source) { VM* vm = (VM*) vm_handle; + PK_ASSERT_NO_ERROR() PyObject* res; - ERRHANDLER_OPEN - CodeObject_ code = vm->compile(source, "main.py", EXEC_MODE); - res = vm->_exec(code, vm->_main); - ERRHANDLER_CLOSE + PK_PROTECTED( + CodeObject_ code = vm->compile(source, "main.py", EXEC_MODE); + res = vm->_exec(code, vm->_main); + ) return res != nullptr; } -bool pkpy_vm_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, int mode, const char* module){ +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; - ERRHANDLER_OPEN - 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); - ERRHANDLER_CLOSE + 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; } - - -//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(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(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(); +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; } -PyObject* c_function_wrapper(VM* vm, ArgsView args) { +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(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(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(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(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(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(args.begin()); PyObject** curr_sp = &vm->s_data.top(); int retc = f(vm); @@ -114,384 +320,201 @@ PyObject* c_function_wrapper(VM* vm, ArgsView args) { return py_var(vm, ret_view.to_tuple()); } -bool pkpy_push_function(pkpy_vm* vm_handle, const char* sig, pkpy_function f) { +bool pkpy_push_function(pkpy_vm* vm_handle, const char* sig, pkpy_CFunction f) { VM* vm = (VM*) vm_handle; - ERRHANDLER_OPEN - PyObject* f_obj = vm->bind( - nullptr, - sig, - nullptr, - c_function_wrapper, - f - ); + 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); - 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 +// 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; } -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 +// 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_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 +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_get_global(pkpy_vm* vm_handle, const char* name) { - CVM* vm = (CVM*) vm_handle; - ERRHANDLER_OPEN +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) - 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(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(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(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(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(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(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) + if (o == nullptr){ + pkpy_error(vm_handle, "NameError", name); return false; + } } + vm->s_data.push(o); 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); +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_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)); +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_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; ipy_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) { - CVM* vm = (CVM*) vm_handle; - // already in error state - if (vm->error != nullptr) return false; - vm->error = py_var(vm, Exception(name, message)); + VM* vm = (VM*) vm_handle; + PK_ASSERT_NO_ERROR() + vm->_c.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 +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(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_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 +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; } - -bool pkpy_eval(pkpy_vm* vm_handle, const char* code) { - CVM* vm = (CVM*) vm_handle; - ERRHANDLER_OPEN - CodeObject_ co = vm->compile(code, "", EVAL_MODE); - PyObject* ret = vm->_exec(co, vm->_main); - vm->c_data->safe_push(ret); - ERRHANDLER_CLOSE - return true; -} - -bool pkpy_new_module(pkpy_vm* vm_handle, const char* name){ - CVM* vm = (CVM*) vm_handle; - ERRHANDLER_OPEN - PyObject* mod = vm->new_module(name); - vm->c_data->safe_push(mod); - ERRHANDLER_CLOSE - return true; -} - /*****************************************************************/ - void pkpy_free(void* p){ - free(p); - } +void pkpy_free(void* p){ + free(p); +} - void pkpy_vm_compile(void* vm_, const char* source, const char* filename, int mode, bool* ok, char** res){ - VM* vm = (VM*)vm_; - try{ - CodeObject_ code = vm->compile(source, filename, (CompileMode)mode); - *res = code->serialize(vm).c_str_dup(); - *ok = true; - }catch(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"); - } - } +pkpy_CName pkpy_name(const char* name){ + return StrName(name).index; +} - void* pkpy_new_repl(void* vm){ - return new REPL((VM*)vm); +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"); } +} - bool pkpy_repl_input(void* r, const char* line){ - return ((REPL*)r)->input(line); - } +void* pkpy_new_repl(pkpy_vm* vm_handle){ + return new REPL((VM*)vm_handle); +} - void pkpy_delete_repl(void* repl){ - delete (REPL*)repl; - } \ No newline at end of file +bool pkpy_repl_input(void* r, const char* line){ + return ((REPL*)r)->input(line); +} + +void pkpy_delete_repl(void* repl){ + delete (REPL*)repl; +} \ No newline at end of file diff --git a/src2/main.cpp b/src2/main.cpp index 1ba4df11..392c3272 100644 --- a/src2/main.cpp +++ b/src2/main.cpp @@ -49,7 +49,7 @@ int main(int argc, char** argv){ #elif __APPLE__ dlopen("libpocketpy.dylib", RTLD_NOW | RTLD_GLOBAL); #endif - void* vm = pkpy_new_vm(); + pkpy_vm* vm = pkpy_new_vm(true); // pkpy::_bind(vm, vm->builtins, "input() -> str", &f_input); if(argc == 1){ @@ -87,7 +87,7 @@ int main(int argc, char** argv){ // set parent path as cwd std::filesystem::current_path(filepath.parent_path()); - pkpy_vm_exec_2(vm, src.c_str(), filepath.filename().string().c_str(), 0, NULL); + pkpy_exec_2(vm, src.c_str(), filepath.filename().string().c_str(), 0, NULL); pkpy_delete_vm(vm); // return ret != nullptr ? 0 : 1; return 0;