Browse Source

function calls are working

Kolten Pearson 2 years ago
parent
commit
aea01c5aca
7 changed files with 207 additions and 72 deletions
  1. 10 6
      c_bindings/main.c
  2. 144 35
      c_bindings/pocketpy_c.cpp
  3. 40 11
      c_bindings/pocketpy_c.h
  4. 1 1
      src/error.h
  5. 5 12
      src/frame.h
  6. 6 6
      src/main.cpp
  7. 1 1
      src/str.h

+ 10 - 6
c_bindings/main.c

@@ -1,6 +1,8 @@
 #include "pocketpy_c.h"
 #include <stdio.h>
 
+//tests the c bindings for pocketpy
+
 
 void test_binding(pkpy_vm vm) {
     pkpy_push_int(vm, 12);
@@ -15,22 +17,24 @@ int main(int argc, char** argv) {
     pkpy_push_int(vm, 11);
     pkpy_set_global(vm, "eleven");
 
-    pkpy_push_cfunction(vm, test_binding);
-    pkpy_set_global(vm, "binding");
+    //pkpy_push_cfunction(vm, test_binding);
+    //pkpy_set_global(vm, "binding");
 
     pkpy_vm_exec(vm, "print(eleven)");
-    pkpy_vm_exec(vm, "print(binding())");
+    //pkpy_vm_exec(vm, "print(binding())");
 
-    pkpy_vm_exec(vm, "x = lambda x : x + 1");
+    pkpy_vm_exec(vm, "def x(x) : return x + 1");
 
     pkpy_get_global(vm, "x");
-    pkpy_push_null(vm);
     pkpy_push_int(vm, 1);
     pkpy_call(vm, 1);
 
-    int64_t r = pkpy_toint(vm, 1);
+    int r;
+    pkpy_to_int(vm, -1, &r);
     printf("%li\n", r);
 
+    pkpy_clear_error(vm, NULL);
+
     pkpy_vm_destroy(vm);
     return 0;
 }

+ 144 - 35
c_bindings/pocketpy_c.cpp

@@ -1,71 +1,180 @@
 #include "pocketpy.h"
 #include "pocketpy_c.h"
 
+using namespace pkpy;
+
+
+#define ERRHANDLER_OPEN try { \
+    try { \
+    if (vm->c_data.top() == nullptr) \
+        return false; \
+
+#define ERRHANDLER_CLOSE \
+    } catch( Exception e ) { \
+        vm->c_data.clear(); \
+        vm->c_data.push(VAR(e.summary())); \
+        vm->c_data.push(NULL); \
+        return false; \
+    } \
+    } catch(...) { \
+        std::cerr << "ERROR: a non pocketpy exeception was thrown " \
+        << "this probably means pocketpy itself has a bug!\n"; \
+        exit(2); \
+    }
+
+bool pkpy_clear_error(pkpy_vm vm_handle, const char** message) {
+    VM* vm = (VM*) vm_handle;
+
+    try {
+        if (vm->c_data.top() != nullptr) 
+            return false;
+
+        vm->c_data.pop();
+        Str wrapped_message = CAST(Str&, vm->c_data.top());
+        if (message != nullptr) 
+            *message = wrapped_message.c_str_dup();
+        else
+            std::cerr << "ERROR: " << wrapped_message << "\n";
+
+        vm->c_data.pop();
+        //at this point the stack is clear
+
+        return true;
+
+    } catch(...) {
+        std::cerr << "ERROR: a non pocketpy exeception was thrown " 
+        << "this probably means pocketpy itself has a bug!\n"; 
+        exit(2); 
+    }
+}
+
 pkpy_vm pkpy_vm_create(bool use_stdio, bool enable_os) {
-    pkpy::VM* p = new pkpy::VM(use_stdio, enable_os);
+    VM* vm = new VM(use_stdio, enable_os);
 
-    return (pkpy_vm) p;
+    return (pkpy_vm) vm;
 }
 
-void pkpy_vm_exec(pkpy_vm vm_handle, const char* source) {
-    pkpy::VM* vm = (pkpy::VM*) vm_handle;
+bool pkpy_vm_exec(pkpy_vm vm_handle, const char* source) {
+    VM* vm = (VM*) vm_handle;
+    ERRHANDLER_OPEN
+
+    vm->exec(source, "main.py", EXEC_MODE);
 
-    vm->exec(source, "main.py", pkpy::EXEC_MODE);
+    return true;
+    ERRHANDLER_CLOSE
 }
 
 void pkpy_vm_destroy(pkpy_vm vm_handle) {
-    pkpy::VM* vm = (pkpy::VM*) vm_handle;
-
+    VM* vm = (VM*) vm_handle;
     delete vm;
 }
 
-void pkpy_push_cfunction(pkpy_vm vm_handle, pkpy_cfunction f) {
-    pkpy::VM* vm = (pkpy::VM*) vm_handle;
-    vm->s_data.push(VAR((pkpy::StackFunc) f));
+bool pkpy_push_function(pkpy_vm vm_handle, pkpy_function f) {
+    return true;
 }
 
-void pkpy_push_int(pkpy_vm vm_handle, int64_t value) {
-    pkpy::VM* vm = (pkpy::VM*) vm_handle;
-    vm->s_data.push(VAR(value));
+bool pkpy_push_int(pkpy_vm vm_handle, int value) {
+    VM* vm = (VM*) vm_handle;
+    ERRHANDLER_OPEN
+
+    vm->c_data.push(VAR(value));
+
+    return true;
+    ERRHANDLER_CLOSE
 }
 
-void pkpy_push_null(pkpy_vm vm_handle) {
-    pkpy::VM* vm = (pkpy::VM*) vm_handle;
-    vm->s_data.push(pkpy::PY_NULL);
+bool pkpy_push_float(pkpy_vm vm_handle, double value) {
+    VM* vm = (VM*) vm_handle;
+
+    ERRHANDLER_OPEN
+    vm->c_data.push(VAR(value));
+
+    return true;
+    ERRHANDLER_CLOSE
 }
 
+bool pkpy_set_global(pkpy_vm vm_handle, const char* name) {
+    VM* vm = (VM*) vm_handle;
+
+    ERRHANDLER_OPEN
 
-void pkpy_push_float(pkpy_vm vm_handle, double value) {
-    pkpy::VM* vm = (pkpy::VM*) vm_handle;
-    vm->s_data.push(VAR(value));
+    vm->_main->attr().set(name, vm->c_data.top());
+
+    vm->c_data.pop();
+
+    return true;
+    ERRHANDLER_CLOSE
 }
 
-void pkpy_set_global(pkpy_vm vm_handle, const char* name) {
-    pkpy::VM* vm = (pkpy::VM*) vm_handle;
+bool pkpy_get_global(pkpy_vm vm_handle, const char* name) {
+    VM* vm = (VM*) vm_handle;
+
+    ERRHANDLER_OPEN
 
-    vm->_main->attr().set(name, vm->s_data.top());
+    PyObject* o = vm->_main->attr().try_get(name);
 
-    vm->s_data.pop();
+    vm->c_data.push(o);
+
+    return true;
+    ERRHANDLER_CLOSE
 }
 
-void pkpy_get_global(pkpy_vm vm_handle, const char* name) {
-    pkpy::VM* vm = (pkpy::VM*) vm_handle;
+static void call_wrapper(VM* vm, int argc, bool method_call) {
+    int callable_index = vm->c_data.size() - argc  - 1;
+
+    PyObject* callable = vm->c_data.get(callable_index);
+
+    vm->s_data.push(callable);
+    if (method_call) 
+        vm->s_data.push(vm->c_data.get(callable_index - 1));
+    else 
+        vm->s_data.push(PY_NULL);
 
-    pkpy::PyObject* o = vm->_main->attr().try_get(name);
+    for (int i = 0; i < argc; i++) 
+        vm->s_data.push(vm->c_data.get(callable_index + i + 1));
 
-    vm->s_data.push(o);
+    PyObject* o = vm->vectorcall(argc);
+
+    vm->c_data.shrink(argc + 1 + (int) method_call);
+
+    //TODO unpack tuple? 
+    vm->c_data.push(o);
 }
 
-void pkpy_call(pkpy_vm vm_handle, int argc) {
-    pkpy::VM* vm = (pkpy::VM*) vm_handle;
-    pkpy::PyObject* o = vm->vectorcall(argc, 0, 0);
-    vm->s_data.push(o);
+bool pkpy_call(pkpy_vm vm_handle, int argc) {
+    VM* vm = (VM*) vm_handle;
+    ERRHANDLER_OPEN
+    call_wrapper(vm, argc, false);
+
+    return true;
+    ERRHANDLER_CLOSE
 }
 
-int pkpy_toint(pkpy_vm vm_handle, int index) {
-    pkpy::VM* vm = (pkpy::VM*) vm_handle;
+bool pkpy_call_method(pkpy_vm vm_handle, int argc) {
+    VM* vm = (VM*) vm_handle;
+    ERRHANDLER_OPEN
+    call_wrapper(vm, argc, true);
 
-    pkpy::PyObject* o = vm->s_data.peek(index);
-    return pkpy::py_cast<int>(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) {
+    VM* vm = (VM*) vm_handle;
+    ERRHANDLER_OPEN
+
+    index = lua_to_cstack_index(index, vm->c_data.size());
+
+    PyObject* o = vm->c_data.get(index);
+    if (ret != nullptr)
+        *ret = py_cast<int>(vm, o);
+
+    return true;
+    ERRHANDLER_CLOSE
+}

+ 40 - 11
c_bindings/pocketpy_c.h

@@ -10,23 +10,52 @@ extern "C" {
 
 typedef struct pkpy_vm_handle* pkpy_vm;
 
+//we mostly follow the lua api for these bindings
+//the key difference being each method returns a bool, true if it succeeded
+//false if it did not
+
+//if a method returns false call this next method to check the error and clear it
+//if this method returns false it means that no error was set, and no action is taken
+//if it 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)
+//NOTE : you need to free the message that is passed back after you are done using it
+//or else pass in null
+bool pkpy_clear_error(pkpy_vm, const char** message);
+
+
+
 pkpy_vm pkpy_vm_create(bool use_stdio, bool enable_os);
-void pkpy_vm_exec(pkpy_vm vm_handle, const char* source);
+bool pkpy_vm_exec(pkpy_vm vm_handle, const char* source);
 void pkpy_vm_destroy(pkpy_vm vm);
 
-////////binding a c function to pocketpy
-typedef int (*pkpy_cfunction)(pkpy_vm); 
 
-void pkpy_push_cfunction(pkpy_vm, pkpy_cfunction);
-void pkpy_push_int(pkpy_vm, int64_t);
-void pkpy_push_float(pkpy_vm, double);
-void pkpy_push_null(pkpy_vm);
+typedef int (*pkpy_function)(pkpy_vm); 
+
+bool pkpy_push_function(pkpy_vm, pkpy_function);
+bool pkpy_push_int(pkpy_vm, int);
+bool pkpy_push_float(pkpy_vm, double);
+
+bool pkpy_set_global(pkpy_vm, const char* name);
+bool pkpy_get_global(pkpy_vm vm_handle, const char* name);
+
+//first push callable you want to call
+//then push the arguments to send
+//argc is the number of arguments
+bool pkpy_call(pkpy_vm vm_handle, int argc);
+
+//first push the object the method belongs to (self)
+//then push the callable you want to call
+//then push the the argments
+//argc is the number of arguments that was pushed
+bool pkpy_call_method(pkpy_vm vm_handle, int argc);
+
+
 
-void pkpy_set_global(pkpy_vm, const char* name);
-void pkpy_get_global(pkpy_vm vm_handle, const char* name);
+//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
 
-void pkpy_call(pkpy_vm vm_handle, int argc);
-int pkpy_toint(pkpy_vm vm_handle, int index);
+bool pkpy_to_int(pkpy_vm vm_handle, int index, int* ret);
 
 
 

+ 1 - 1
src/error.h

@@ -101,4 +101,4 @@ public:
     }
 };
 
-}   // namespace pkpy
+}   // namespace pkpy

+ 5 - 12
src/frame.h

@@ -101,14 +101,13 @@ struct ValueStack {
 //stack for working with c bindings
 struct CVirtualStack {
     static const size_t MAX_SIZE = 256;
-    // We allocate 512 more bytes to keep `_sp` valid when `is_overflow() == true`.
     PyObject* _begin[MAX_SIZE];
     PyObject** _sp;
 
     CVirtualStack(): _sp(_begin) {}
 
     PyObject* top() const { return _sp[-1]; }
-    PyObject* peek(int n) const { return _sp[-n]; }
+    PyObject* get(int index) const { return _begin[index]; }
     void push(PyObject* v){ *_sp++ = v; }
     void pop(){ --_sp; }
     void shrink(int n){ _sp -= n; }
@@ -116,18 +115,12 @@ struct CVirtualStack {
     bool empty() const { return _sp == _begin; }
     PyObject** begin() { return _begin; }
     PyObject** end() { return _sp; }
-    void reset(PyObject** sp) {
-#if DEBUG_EXTRA_CHECK
-        if(sp < _begin || sp > _begin + MAX_SIZE) FATAL_ERROR();
-#endif
-        _sp = sp;
-    }
     void clear() { _sp = _begin; }
     
-    ValueStack(const ValueStack&) = delete;
-    ValueStack(ValueStack&&) = delete;
-    ValueStack& operator=(const ValueStack&) = delete;
-    ValueStack& operator=(ValueStack&&) = delete;
+    CVirtualStack(const CVirtualStack&) = delete;
+    CVirtualStack(CVirtualStack&&) = delete;
+    CVirtualStack& operator=(const CVirtualStack&) = delete;
+    CVirtualStack& operator=(CVirtualStack&&) = delete;
 };
 
 struct Frame {

+ 6 - 6
src/main.cpp

@@ -6,21 +6,21 @@
 #ifndef __EMSCRIPTEN__
 
 int main(int argc, char** argv){
-    pkpy::VM* vm = pkpy_new_vm();
+    pkpy::VM* vm = new pkpy::VM();
     vm->bind_builtin_func<0>("input", [](pkpy::VM* vm, pkpy::ArgsView args){
         return VAR(pkpy::getline());
     });
     if(argc == 1){
-        pkpy::REPL* repl = pkpy_new_repl(vm);
+        pkpy::REPL* repl = new pkpy::REPL(vm);
         bool need_more_lines = false;
         while(true){
             (*vm->_stdout) << (need_more_lines ? "... " : ">>> ");
             bool eof = false;
             std::string line = pkpy::getline(&eof);
             if(eof) break;
-            need_more_lines = pkpy_repl_input(repl, line.c_str());
+            need_more_lines = repl->input(line.c_str());
         }
-        pkpy_delete(vm);
+        delete vm;
         return 0;
     }
     
@@ -47,7 +47,7 @@ int main(int argc, char** argv){
 
         pkpy::PyObject* ret = nullptr;
         ret = vm->exec(src.c_str(), argv_1, pkpy::EXEC_MODE);
-        pkpy_delete(vm);
+        delete vm;
         return ret != nullptr ? 0 : 1;
     }
 
@@ -56,4 +56,4 @@ __HELP:
     return 0;
 }
 
-#endif
+#endif

+ 1 - 1
src/str.h

@@ -434,4 +434,4 @@ const StrName __and__ = StrName::get("__and__");
 const StrName __or__ = StrName::get("__or__");
 const StrName __xor__ = StrName::get("__xor__");
 
-} // namespace pkpy
+} // namespace pkpy