Kaynağa Gözat

Merge branch 'dev'

BLUELOVETH 2 yıl önce
ebeveyn
işleme
1bd443107b

+ 2 - 1
.gitignore

@@ -29,4 +29,5 @@ pocketpy.lib
 APPS
 build
 
-pocketpy.dSYM
+pocketpy.dSYM
+main

+ 7 - 13
CMakeLists.txt

@@ -26,31 +26,25 @@ else()
     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)
 
-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)
 
 option(PK_BUILD_SHARED_LIB "Build shared 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)
-    add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC} ${PK_LIB_CPP})
+    add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC})
 elseif(PK_BUILD_STATIC_LIB)
-    add_library(${PROJECT_NAME} STATIC ${POCKETPY_SRC} ${PK_LIB_CPP})
+    add_library(${PROJECT_NAME} STATIC ${POCKETPY_SRC})
 else()
-    add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC} ${PK_LIB_CPP})
+    add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC})
     set(PROJECT_EXE_NAME main)
     add_executable(${PROJECT_EXE_NAME} src2/main.cpp)
     target_link_libraries(${PROJECT_EXE_NAME} ${PROJECT_NAME})

+ 0 - 16
amalgamate.py

@@ -88,28 +88,12 @@ if sys.platform in ['linux', 'darwin']:
 
 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.cpp", "plugins/flutter/src/pocketpy.cpp")
-
 shutil.copy("amalgamated/pocketpy.h", "plugins/macos/pocketpy/pocketpy.h")
-shutil.copy("amalgamated/pocketpy.cpp", "plugins/macos/pocketpy/pocketpy.cpp")
 
 # unity plugin
 unity_ios_root = 'plugins/unity/PocketPyUnityPlugin/Assets/PocketPython/Plugins/iOS'
 if os.path.exists(unity_ios_root):
 	shutil.copy("amalgamated/pocketpy.h", unity_ios_root)
-	shutil.copy("amalgamated/pocketpy.cpp", unity_ios_root)
 
 

+ 0 - 554
c_bindings/pocketpy_c.cpp

@@ -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;
-}

+ 0 - 122
c_bindings/pocketpy_c.h

@@ -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

+ 13 - 7
docs/LuaC-API/introduction.md

@@ -14,20 +14,26 @@ Special thanks for [@koltenpearson](https://github.com/koltenpearson) for bringi
 
 ## 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
 
-#### `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
 
-#### `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(...)`.

+ 31 - 21
include/pocketpy/codeobject.h

@@ -128,6 +128,29 @@ struct FuncDecl {
     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 {
     NativeFuncC f;
 
@@ -137,29 +160,16 @@ struct NativeFunc {
     // new style decl-based call
     FuncDecl_ decl;
 
-    using UserData = char[32];
     UserData _userdata;
-    bool _has_userdata;
 
-    template <typename T>
-    void set_userdata(T data) {
-        static_assert(std::is_trivially_copyable_v<T>);
-        static_assert(sizeof(T) <= sizeof(UserData));
-        if(_has_userdata) throw std::runtime_error("userdata already set");
-        _has_userdata = true;
-        memcpy(_userdata, &data, sizeof(T));
+    void set_userdata(UserData data) {
+        if(!_userdata.empty && !data.empty){
+            // override is not supported
+            throw std::runtime_error("userdata already set");
+        }
+        _userdata = data;
     }
 
-    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, FuncDecl_ decl);
 
@@ -201,8 +211,8 @@ struct Py_<NativeFunc> final: PyObject {
 
 template<typename T>
 T lambda_get_userdata(PyObject** p){
-    if(p[-1] != PY_NULL) return PK_OBJ_GET(NativeFunc, p[-1]).get_userdata<T>();
-    else return PK_OBJ_GET(NativeFunc, p[-2]).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])._userdata.get<T>();
 }
 
 } // namespace pkpy

+ 2 - 24
include/pocketpy/common.h

@@ -20,7 +20,7 @@
 #include <variant>
 #include <type_traits>
 
-#define PK_VERSION				"1.0.9"
+#define PK_VERSION				"1.1.0"
 
 #include "config.h"
 #include "export.h"
@@ -149,26 +149,4 @@ inline PyObject* const PY_OP_YIELD = (PyObject*)0b110011;
 
 #define ADD_MODULE_PLACEHOLDER(name) namespace pkpy { inline void add_module_##name(void* vm) { (void)vm; } }
 
-} // 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
+} // namespace pkpy

+ 40 - 15
include/pocketpy/export.h

@@ -1,19 +1,44 @@
-#ifndef PK_EXPORT
+#pragma once
 
-#ifdef _WIN32
-#define PK_EXPORT __declspec(dllexport)
-#elif __EMSCRIPTEN__
-#include <emscripten.h>
-#define PK_EXPORT EMSCRIPTEN_KEEPALIVE
-#else
-#define PK_EXPORT __attribute__((visibility("default")))
-#endif
+#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
 
-#define PK_INLINE_EXPORT PK_EXPORT inline
+    #ifndef NOMINMAX
+    #define NOMINMAX
+    #endif
 
-#endif
+    #include <Windows.h>
 
-#ifdef PK_SHARED_MODULE
-#undef PK_INLINE_EXPORT
-#define PK_INLINE_EXPORT inline
-#endif
+    #define PK_EXPORT __declspec(dllexport)
+    #define PK_SUPPORT_DYLIB    1
+#elif __EMSCRIPTEN__
+    #include <emscripten.h>
+    #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
+    #define PK_EXPORT
+    #define PK_SUPPORT_DYLIB    0
+#endif

+ 6 - 0
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<size_t MAX_SIZE>
@@ -62,6 +65,9 @@ struct ValueStackImpl {
     }
     void clear() { _sp = _begin; }
     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(ValueStackImpl&&) = delete;

+ 2 - 2
include/pocketpy/memory.h

@@ -246,8 +246,8 @@ struct MemoryPool{
     }
 };
 
-PK_EXPORT inline MemoryPool<64> pool64;
-PK_EXPORT inline MemoryPool<128> pool128;
+inline MemoryPool<64> pool64;
+inline MemoryPool<128> pool128;
 
 template <typename T>
 struct shared_ptr {

+ 1 - 80
include/pocketpy/pocketpy.h

@@ -94,83 +94,4 @@ void add_module_dis(VM* vm);
 void add_module_traceback(VM* vm);
 void add_module_gc(VM* vm);
 
-}   // 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;
-    }
-}
+}   // namespace pkpy

+ 103 - 0
include/pocketpy/pocketpy_c.h

@@ -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

+ 1 - 3
include/pocketpy/repl.h

@@ -4,9 +4,7 @@
 #include "vm.h"
 
 namespace pkpy{
-
-std::string platform_getline(bool* eof=nullptr);
-
+    
 class REPL {
 protected:
     int need_more_lines = 0;

+ 6 - 2
include/pocketpy/vm.h

@@ -117,6 +117,10 @@ public:
     NameDict _modules;                                 // loaded modules
     std::map<StrName, Str> _lazy_modules;              // lazy loaded modules
 
+    struct{
+        PyObject* error;
+    } _c;
+
     PyObject* None;
     PyObject* True;
     PyObject* False;
@@ -453,8 +457,8 @@ public:
     PyObject* _py_generator(Frame&& frame, ArgsView buffer);
     void _prepare_py_call(PyObject**, ArgsView, ArgsView, const FuncDecl_&);
     // new style binding api
-    PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, void* userdata=nullptr);
-    PyObject* bind(PyObject*, const char*, NativeFuncC, void* userdata=nullptr);
+    PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, UserData userdata={});
+    PyObject* bind(PyObject*, const char*, NativeFuncC, UserData userdata={});
 };
 
 DEF_NATIVE_2(Str, tp_str)

+ 3 - 0
include/pocketpy_c.h

@@ -0,0 +1,3 @@
+#pragma once
+
+#include "pocketpy/pocketpy_c.h"

+ 2 - 2
src/ceval.cpp

@@ -108,7 +108,7 @@ __NEXT_STEP:;
     TARGET(LOAD_FAST) {
         heap._auto_collect();
         _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);
     } DISPATCH();
     TARGET(LOAD_NAME) {
@@ -201,7 +201,7 @@ __NEXT_STEP:;
         DISPATCH();
     TARGET(DELETE_FAST)
         _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;
         DISPATCH();
     TARGET(DELETE_NAME)

+ 0 - 2
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

+ 1 - 1
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

+ 25 - 9
src/pocketpy.cpp

@@ -6,22 +6,38 @@ 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);
     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;
     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;

+ 520 - 0
src/pocketpy_c.cpp

@@ -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;
+}

+ 0 - 33
src/repl.cpp

@@ -1,39 +1,6 @@
 #include "pocketpy/repl.h"
 
 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){
         vm->_stdout(vm, "pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") ");
         vm->_stdout(vm, fmt("[", sizeof(void*)*8, " bit]" "\n"));

+ 4 - 6
src/vm.cpp

@@ -956,11 +956,11 @@ void VM::setattr(PyObject* obj, StrName name, PyObject* 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);
 }
 
-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;
     try{
         // 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();
     }
     PyObject* f_obj = VAR(NativeFunc(fn, decl));
-    if(userdata != nullptr){
-        PK_OBJ_GET(NativeFunc, f_obj).set_userdata(userdata);
-    }
-    obj->attr().set(decl->code->name, f_obj);
+    PK_OBJ_GET(NativeFunc, f_obj).set_userdata(userdata);
+    if(obj != nullptr) obj->attr().set(decl->code->name, f_obj);
     return f_obj;
 }
 

+ 0 - 1
src2/lib.cpp

@@ -1 +0,0 @@
-#include "pocketpy.h"

+ 45 - 12
src2/main.cpp

@@ -1,31 +1,64 @@
 #include <fstream>
 #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){
 #if _WIN32
-    SetConsoleOutputCP(CP_UTF8);
     // implicitly load pocketpy.dll in current directory
 #elif __linux__
     dlopen("libpocketpy.so", RTLD_NOW | RTLD_GLOBAL);
 #elif __APPLE__
     dlopen("libpocketpy.dylib", RTLD_NOW | RTLD_GLOBAL);
 #endif
-    pkpy::VM* vm = pkpy_new_vm();
-    pkpy::_bind(vm, vm->builtins, "input() -> str", &f_input);
+    pkpy_vm* vm = pkpy_new_vm(true);
+    // pkpy::_bind(vm, vm->builtins, "input() -> str", &f_input);
 
     if(argc == 1){
-        pkpy::REPL* repl = pkpy_new_repl(vm);
+        void* repl = pkpy_new_repl(vm);
         bool need_more_lines = false;
         while(true){
-            vm->_stdout(vm, need_more_lines ? "... " : ">>> ");
+            std::cout << (need_more_lines ? "... " : ">>> ");
             bool eof = false;
-            std::string line = pkpy::platform_getline(&eof);
+            std::string line = pkpy_platform_getline(&eof);
             if(eof) break;
             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
         std::filesystem::current_path(filepath.parent_path());
 
-        pkpy::PyObject* ret = nullptr;
-        ret = vm->exec(src.c_str(), filepath.filename().string(), pkpy::EXEC_MODE);
+        pkpy_exec_2(vm, src.c_str(), filepath.filename().string().c_str(), 0, NULL);
         pkpy_delete_vm(vm);
-        return ret != nullptr ? 0 : 1;
+        // return ret != nullptr ? 0 : 1;
+        return 0;
     }
 
 __HELP:

+ 0 - 12
tests/dylib/test.cpp

@@ -1,4 +1,3 @@
-#define PK_SHARED_MODULE
 #include "pocketpy.h"
 
 using namespace pkpy;
@@ -15,15 +14,4 @@ extern "C" {
         });
         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
-
 }