blueloveTH 2 tahun lalu
induk
melakukan
d5711da2ad
4 mengubah file dengan 95 tambahan dan 15 penghapusan
  1. 39 0
      c_bindings/test.c
  2. 15 0
      c_bindings/test_answers.txt
  3. 1 0
      include/pocketpy/vm.h
  4. 40 15
      src/pocketpy_c.cpp

+ 39 - 0
c_bindings/test.c

@@ -66,6 +66,32 @@ int test_multiple_return(pkpy_vm* vm) {
     return 2;
 }
 
+int test_minus(pkpy_vm* vm) {
+    int a, b;
+    pkpy_to_int(vm, 0, &a);
+    pkpy_to_int(vm, 1, &b);
+    pkpy_push_int(vm, a - b);
+    return 1;
+}
+
+int test_fib(pkpy_vm* vm) {
+    int n;
+    pkpy_to_int(vm, 0, &n);
+    if (n == 1) {
+        pkpy_push_int(vm, n);
+    } else {
+        pkpy_getglobal(vm, pkpy_name("test_fib"));
+        pkpy_push_null(vm);
+        pkpy_push_int(vm, n-1);
+        pkpy_vectorcall(vm, 1);
+        int r_int;
+        pkpy_to_int(vm, -1, &r_int);
+        pkpy_pop_top(vm);
+        pkpy_push_int(vm, r_int + n);
+    }
+    return 1;
+}
+
 int test_default_argument(pkpy_vm* vm){
     int x;
     pkpy_to_int(vm, -1, &x);
@@ -311,6 +337,19 @@ int main(int argc, char** argv) {
     check(pkpy_pop_top(vm));
     check(pkpy_stack_size(vm) == 0);
 
+    PRINT_TITLE("test bindings 2");
+    check(pkpy_push_function(vm, "test_minus(a, b)", test_minus));
+    check(pkpy_setglobal(vm, pkpy_name("test_minus")));
+    check(pkpy_exec(vm, "print(test_minus(5, 3))"));
+    check(pkpy_exec(vm, "for i in range(5): print(test_minus(5, i))"));
+    check(pkpy_stack_size(vm) == 0);
+
+    PRINT_TITLE("test bindings fib");
+    check(pkpy_push_function(vm, "test_fib(n: int) -> int", test_fib));
+    check(pkpy_setglobal(vm, pkpy_name("test_fib")));
+    check(pkpy_exec(vm, "print(test_fib(10))"));
+    check(pkpy_stack_size(vm) == 0);
+
     PRINT_TITLE("test error propagate");
     check(pkpy_push_function(vm, "test_error_propagate()", test_error_propagate));
     check(pkpy_setglobal(vm, pkpy_name("test_error_propagate")));

+ 15 - 0
c_bindings/test_answers.txt

@@ -59,6 +59,17 @@ TypeError: expected 2 positional arguments, got 0 (x)
 ====== test bindings ======
 12
 
+====== test bindings 2 ======
+2
+5
+4
+3
+2
+1
+
+====== test bindings fib ======
+55
+
 ====== test error propagate ======
 successfully errored with this message: 
 Traceback (most recent call last):
@@ -81,6 +92,10 @@ successfully errored with this message:
 TypeError: expected 'int', got 'float'
 
 ====== test complicated errors ======
+Traceback (most recent call last):
+  File "main.py", line 1
+    test_error_propagate()
+NameError: catch me
 successfully errored with this message: 
 Traceback (most recent call last):
 _: test direct error mechanism

+ 1 - 0
include/pocketpy/vm.h

@@ -119,6 +119,7 @@ public:
 
     struct{
         PyObject* error;
+        stack<ArgsView> s_view;
     } _c;
 
     PyObject* None;

+ 40 - 15
src/pocketpy_c.cpp

@@ -21,23 +21,24 @@ static int count_extra_elements(VM* vm, int n){
     if(vm->callstack.empty()){
         return vm->s_data.size();
     }
-    PyObject** base = vm->top_frame()->_locals.end();
-    return vm->s_data._sp - base;
+    PK_ASSERT(!vm->_c.s_view.empty());
+    return vm->s_data._sp - vm->_c.s_view.top().end();
 }
 
 static PyObject* stack_item(VM* vm, int index){
     PyObject** begin;
-    PyObject** end;
+    PyObject** end = vm->s_data.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();
+        PK_ASSERT(!vm->_c.s_view.empty());
+        begin = vm->_c.s_view.top().begin();
+    }
+    int size = end - begin;
+    if(index < 0) index += size;
+    if(index < 0 || index >= size){
+        throw std::runtime_error("stack_item() => index out of range");
     }
-    // may raise
-    index = vm->normalized_index(index, end-begin);
     return begin[index];
 }
 
@@ -126,7 +127,8 @@ int pkpy_stack_size(pkpy_vm* vm_handle){
     if(vm->callstack.empty()){
         return vm->s_data.size();
     }
-    return vm->top_frame()->stack_size();
+    PK_ASSERT(!vm->_c.s_view.empty());
+    return vm->s_data._sp - vm->_c.s_view.top().begin();
 }
 
 // int
@@ -299,11 +301,31 @@ bool pkpy_push_null(pkpy_vm* vm_handle) {
     return true;
 }
 
+struct TempViewPopper{
+    VM* vm;
+    bool used;
+
+    TempViewPopper(VM* vm): vm(vm), used(false) {}
+
+    void restore() noexcept{
+        if(used) return;
+        vm->_c.s_view.pop();
+        used = true;
+    }
+
+    ~TempViewPopper(){ restore(); }
+};
+
 // function
 static PyObject* c_function_wrapper(VM* vm, ArgsView args) {
     LuaStyleFuncC f = lambda_get_userdata<LuaStyleFuncC>(args.begin());
     PyObject** curr_sp = vm->s_data._sp;
-    int retc = f(vm);
+
+    vm->_c.s_view.push(args);
+    TempViewPopper _tvp(vm);
+    int retc = f(vm);       // may raise, _tvp will handle this via RAII
+    _tvp.restore();
+
     // propagate_if_errored
     if (vm->_c.error != nullptr){
         Exception e = _py_cast<Exception&>(vm, vm->_c.error);
@@ -472,11 +494,14 @@ bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
     if (message != nullptr)
         *message = e.summary().c_str_dup();
     else
-        std::cerr << e.summary() << std::endl;
+        std::cout << e.summary() << std::endl;
     vm->_c.error = nullptr;
-    // clear the whole stack??
-    vm->callstack.clear();
-    vm->s_data.clear(); 
+    if(vm->callstack.empty()){
+        vm->s_data.clear();
+    }else{
+        PK_ASSERT(!vm->_c.s_view.empty());
+        vm->s_data.reset(vm->_c.s_view.top().end());
+    }
     return true;
 }