blueloveTH 2 лет назад
Родитель
Сommit
f2435b81df
4 измененных файлов с 131 добавлено и 87 удалено
  1. 73 51
      c_bindings/test.c
  2. 45 22
      c_bindings/test_answers.txt
  3. 5 2
      docs/C-API/error.md
  4. 8 12
      src/pocketpy_c.cpp

+ 73 - 51
c_bindings/test.c

@@ -66,6 +66,14 @@ int test_multiple_return(pkpy_vm* vm) {
     return 2;
 }
 
+int test_default_argument(pkpy_vm* vm){
+    int x;
+    pkpy_to_int(vm, -1, &x);
+    bool ok = x == 5;
+    pkpy_push_bool(vm, ok);
+    return 1;
+}
+
 int test_return_none(pkpy_vm* vm) {
     return 0;
 }
@@ -82,13 +90,17 @@ int test_nested_error(pkpy_vm* vm) {
     return 0;
 }
 
+#define PRINT_TITLE(x) printf("\n====== %s ======\n", x)
+
 int main(int argc, char** argv) {
     pkpy_vm* vm = pkpy_new_vm(true);
 
+    PRINT_TITLE("test basic exec");
     check(pkpy_exec(vm, "print('hello world!')"));
     error(pkpy_getglobal(vm, pkpy_name("nonexistatn")));
 
-    printf("\ntesting int methods\n");
+    // test int methods
+    PRINT_TITLE("test int methods");
     int r_int;
     check(pkpy_push_int(vm, 11));
     pkpy_CName m_eleven = pkpy_name("eleven");
@@ -97,30 +109,32 @@ int main(int argc, char** argv) {
     check(pkpy_getglobal(vm, m_eleven));
     check(pkpy_is_int(vm, -1));
     check(pkpy_to_int(vm, -1, &r_int));
-    printf("%i\n", r_int);
+    printf("%i\n", r_int);                      // 11
+    printf("%i\n", pkpy_stack_size(vm));        // 1
+
     fail(pkpy_is_float(vm, -1));
     fail(pkpy_is_bool(vm, -1));
     fail(pkpy_is_string(vm, -1));
     fail(pkpy_is_none(vm, -1));
     fail(pkpy_is_voidp(vm, -1));
 
-    printf("\ntesting float methods\n");
+    PRINT_TITLE("test float methods");
     float r_float;
-    check(pkpy_push_float(vm, 11.11));
+    check(pkpy_push_float(vm, 11.125));
     pkpy_CName m_elevenf = pkpy_name("elevenf");
     check(pkpy_setglobal(vm, m_elevenf));
     check(pkpy_exec(vm, "print(elevenf)"));
     check(pkpy_getglobal(vm, m_elevenf));
     check(pkpy_is_float(vm, -1));
     check(pkpy_to_float(vm, -1, &r_float));
-    printf("%f\n", r_float);
+    printf("%.3f\n", r_float);
     fail(pkpy_is_int(vm, -1));
     fail(pkpy_is_bool(vm, -1));
     fail(pkpy_is_string(vm, -1));
     fail(pkpy_is_none(vm, -1));
     fail(pkpy_is_voidp(vm, -1));
 
-    printf("\ntesting bool methods\n");
+    PRINT_TITLE("test bool methods");
     bool r_bool;
     check(pkpy_push_bool(vm, false));
     pkpy_CName m_false_test = pkpy_name("false_test");
@@ -136,7 +150,7 @@ int main(int argc, char** argv) {
     fail(pkpy_is_none(vm, -1));
     fail(pkpy_is_voidp(vm, -1));
 
-    printf("\ntesting string methods\n");
+    PRINT_TITLE("test string methods");
     pkpy_CString r_string;
     check(pkpy_push_string(vm, pkpy_string("hello!")));
     check(pkpy_setglobal(vm, pkpy_name("hello1")));
@@ -156,7 +170,7 @@ int main(int argc, char** argv) {
     fail(pkpy_is_none(vm, -1));
     fail(pkpy_is_voidp(vm, -1));
 
-    printf("\ntesting None methods\n");
+    PRINT_TITLE("test none methods");
     check(pkpy_push_none(vm));
     pkpy_CName m_none = pkpy_name("none");
     check(pkpy_setglobal(vm, m_none));
@@ -169,7 +183,7 @@ int main(int argc, char** argv) {
     fail(pkpy_is_string(vm, -1));
     fail(pkpy_is_voidp(vm, -1));
 
-    printf("\ntesting voidp methods\n");
+    PRINT_TITLE("test voidp methods");
     void* vp = (void*) 123;
     check(pkpy_push_voidp(vm, vp));
     check(pkpy_setglobal(vm, pkpy_name("vp")));
@@ -185,8 +199,7 @@ int main(int argc, char** argv) {
     fail(pkpy_is_string(vm, -1));
     fail(pkpy_is_none(vm, -1));
 
-
-    printf("\ntesting sizing and indexing\n");
+    PRINT_TITLE("test sizing and indexing");
     int stack_size = pkpy_stack_size(vm);
     printf("stack size %i\n", stack_size);
     check(pkpy_is_int(vm, 0));
@@ -201,18 +214,14 @@ int main(int argc, char** argv) {
     check(pkpy_is_string(vm, -3));
     check(pkpy_is_none(vm, -2));
     check(pkpy_is_voidp(vm, -1));
-    
-    printf("\ntesting error catching\n");
-    error(pkpy_exec(vm, "let's make sure syntax errors get caught"));
-    check(pkpy_stack_size(vm) == 0); //stack should be cleared after error is resolved
 
-    printf("\ntesting calls\n");
+    PRINT_TITLE("test error catching");
+    error(pkpy_exec(vm, "let's make sure syntax errors get caught"));
+    //stack should be cleared after error is resolved
+    check(pkpy_stack_size(vm) == 0);
 
+    PRINT_TITLE("test simple call");
     check(pkpy_exec(vm, "def x(x, y) : return x - y"));
-    check(pkpy_exec(vm, "def vararg_x(*x) : return sum(x)"));
-    check(pkpy_exec(vm, "def keyword_x(x=1, y=1) : return x+y"));
-    check(pkpy_exec(vm, "def retmany_x() : return 1, 2, 3"));
-
     check(pkpy_getglobal(vm, pkpy_name("x")));
     check(pkpy_push_null(vm));
     check(pkpy_push_int(vm, 2));
@@ -221,6 +230,8 @@ int main(int argc, char** argv) {
     check(pkpy_to_int(vm, -1, &r_int));
     printf("x : %i\n", r_int);
 
+    PRINT_TITLE("test vararg call");
+    check(pkpy_exec(vm, "def vararg_x(*x) : return sum(x)"));
     check(pkpy_getglobal(vm, pkpy_name("vararg_x")));
     check(pkpy_push_null(vm));
     check(pkpy_push_int(vm, 1));
@@ -233,25 +244,33 @@ int main(int argc, char** argv) {
     check(pkpy_to_int(vm, -1, &r_int));
     printf("vararg_x : %i\n", r_int);
 
+    PRINT_TITLE("test keyword call");
+    check(pkpy_exec(vm, "def keyword_x(x=1, y=1) : return x+y"));
     check(pkpy_getglobal(vm, pkpy_name("keyword_x")));
     check(pkpy_push_null(vm));
     check(pkpy_push_int(vm, 3));
     check(pkpy_vectorcall(vm, 1));
     check(pkpy_to_int(vm, -1, &r_int));
-    printf("keyword_x : %i\n", r_int);
+    printf("keyword_x : %i\n", r_int);      // 3+1
 
     check(pkpy_getglobal(vm, pkpy_name("keyword_x")));
     check(pkpy_push_null(vm));
     check(pkpy_vectorcall(vm, 0));
     check(pkpy_to_int(vm, -1, &r_int));
-    printf("keyword_x : %i\n", r_int);
-
+    printf("keyword_x : %i\n", r_int);      // 1+1
     check(pkpy_stack_size(vm) == 4);
+    check(pkpy_pop(vm, 4));     // clear stack
 
+    PRINT_TITLE("test return many");
+    check(pkpy_exec(vm, "def retmany_x() : return 1, 2, 3"));
     check(pkpy_getglobal(vm, pkpy_name("retmany_x")));
     check(pkpy_push_null(vm));
     check(pkpy_vectorcall(vm, 0));
-    check(pkpy_stack_size(vm) == 7);
+
+    check(pkpy_stack_size(vm) == 1);
+    check(pkpy_unpack_sequence(vm, 3));
+    check(pkpy_stack_size(vm) == 3);
+
     check(pkpy_to_int(vm, -3, &r_int));
     printf("retmany_x : %i\n", r_int);
     check(pkpy_to_int(vm, -2, &r_int));
@@ -259,33 +278,40 @@ int main(int argc, char** argv) {
     check(pkpy_to_int(vm, -1, &r_int));
     printf("retmany_x : %i\n", r_int);
 
+    // test argument error
     check(pkpy_getglobal(vm, pkpy_name("x")));
     check(pkpy_push_null(vm));
     error(pkpy_vectorcall(vm, 0));
 
     check(pkpy_exec(vm, "l = []"));
-
     check(pkpy_getglobal(vm, pkpy_name("l")));
     check(pkpy_get_unbound_method(vm, pkpy_name("append")));
     check(pkpy_push_string(vm, pkpy_string("hello")));
     check(pkpy_vectorcall(vm, 1));
+    check(pkpy_pop_top(vm));        // pop None returned by append()
     check(pkpy_exec(vm, "print(l)"));
 
-
-    printf("\ntesting pushing functions\n");
-
+    PRINT_TITLE("test bindings");
     check(pkpy_push_function(vm, "test_binding()", test_binding));
     check(pkpy_setglobal(vm, pkpy_name("test_binding")));
     check(pkpy_exec(vm, "print(test_binding())"));
+    check(pkpy_stack_size(vm) == 0);
 
     check(pkpy_push_function(vm, "test_multiple_return()", test_multiple_return));
     check(pkpy_setglobal(vm, pkpy_name("test_multiple_return")));
+    check(pkpy_stack_size(vm) == 0);
 
-    //uncomment if _exec changes
-    //check(pkpy_exec(vm, "test_multiple_return()"));
-    //check(pkpy_stack_size(vm) == 2);
-
+    check(pkpy_push_function(vm, "test_default_argument(x=5)", test_default_argument));
+    check(pkpy_push_null(vm));
+    check(pkpy_vectorcall(vm, 0));
+    check(pkpy_stack_size(vm) == 1);
+    check(pkpy_is_bool(vm, -1) == true);
+    check(pkpy_to_bool(vm, -1, &r_bool));
+    check(r_bool == true);
+    check(pkpy_pop_top(vm));
+    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")));
     error(pkpy_exec(vm, "test_error_propagate()"));
@@ -293,58 +319,54 @@ int main(int argc, char** argv) {
     check(pkpy_getglobal(vm, pkpy_name("test_multiple_return")));
     check(pkpy_push_null(vm));
     check(pkpy_vectorcall(vm, 0));
+    check(pkpy_stack_size(vm) == 1);
+    check(pkpy_unpack_sequence(vm, 2));
     check(pkpy_stack_size(vm) == 2);
-
-    
     check(pkpy_pop(vm, 2));
     check(pkpy_stack_size(vm) == 0);
 
+    PRINT_TITLE("test other errors");
     check(pkpy_getglobal(vm, pkpy_name("test_error_propagate")));
     check(pkpy_pop_top(vm));
-    fail(pkpy_getglobal(vm, pkpy_name("nonexistant")));
-
+    error(pkpy_getglobal(vm, pkpy_name("nonexistant")));
     error(pkpy_exec(vm, "raise NameError('testing error throwing from python')"));
 
+    PRINT_TITLE("test TypeError");
+    check(pkpy_push_float(vm, 2.0));
+    error(pkpy_to_int(vm, -1, &r_int));
+
+    PRINT_TITLE("test complicated errors");
     pkpy_exec(vm, "test_error_propagate()");
     check(pkpy_check_error(vm));
-    // testing code going to standard error, can ignore next error
     pkpy_clear_error(vm, NULL);
 
-    //errors
     //this should be catchable
     check(pkpy_exec(vm, "try : test_error_propagate(); except NameError : pass"));
-
     error(pkpy_error(vm, "_", pkpy_string("test direct error mechanism")));
 
-
     //more complicated error handling
     check(pkpy_exec(vm, "def error_from_python() : raise NotImplementedError()"));
     check(pkpy_push_function(vm, "test_nested_error()", test_nested_error));
     check(pkpy_setglobal(vm, pkpy_name("test_nested_error")));
     error(pkpy_exec(vm, "test_nested_error()"));
 
+    PRINT_TITLE("test getattr/setattr");
     check(pkpy_exec(vm, "import math"));
     check(pkpy_getglobal(vm, pkpy_name("math")));
     check(pkpy_getattr(vm, pkpy_name("pi")));
     check(pkpy_to_float(vm, -1, &r_float));
     printf("pi: %.2f\n", r_float);
 
-    check(pkpy_eval(vm, "math.pi"));
-    check(pkpy_to_float(vm, -1, &r_float));
-    printf("pi: %.2f\n", r_float);
-
-    check(pkpy_pop(vm, 1));
-
     // math.pi = 2
     check(pkpy_push_int(vm, 2));
     check(pkpy_eval(vm, "math"));
     check(pkpy_setattr(vm, pkpy_name("pi")));
     check(pkpy_exec(vm, "print(math.pi)"));
 
-
-    //should give a type error
-    check(pkpy_push_float(vm, 2.0));
-    error(pkpy_to_int(vm, -1, &r_int));
-
+    PRINT_TITLE("test eval");
+    check(pkpy_eval(vm, "math.pi"));
+    check(pkpy_to_float(vm, -1, &r_float));
+    printf("pi: %.2f\n", r_float);
+    check(pkpy_pop(vm, 1));
     return 0;
 }

+ 45 - 22
c_bindings/test_answers.txt

@@ -1,46 +1,54 @@
+
+====== test basic exec ======
 hello world!
 successfully errored with this message: 
 Traceback (most recent call last):
 NameError: nonexistatn
 
-testing int methods
+====== test int methods ======
 11
 11
+1
 
-testing float methods
-11.11
-11.110000
+====== test float methods ======
+11.125
+11.125
 
-testing bool methods
+====== test bool methods ======
 False
 0
 
-testing string methods
+====== test string methods ======
+hello!
 hello!
-hello
-hello
 
-testing None methods
+====== test none methods ======
 None
 
-testing voidp methods
+====== test voidp methods ======
 <void* at 0x7b>
 123
 
-testing sizing and indexing
+====== test sizing and indexing ======
 stack size 6
 
-testing error catching
+====== test error catching ======
 successfully errored with this message: 
-  File "<c-bound>", line 1
+  File "main.py", line 1
     let's make sure syntax errors get caught
 SyntaxError: EOL while scanning string literal
 
-testing calls
+====== test simple call ======
 x : -1
+
+====== test vararg call ======
 vararg_x : 21
+
+====== test keyword call ======
 keyword_x : 4
 keyword_x : 2
+
+====== test return many ======
 retmany_x : 1
 retmany_x : 2
 retmany_x : 3
@@ -48,30 +56,45 @@ successfully errored with this message:
 TypeError: expected 2 positional arguments, got 0 (x)
 ['hello']
 
-testing pushing functions
+====== test bindings ======
 12
+
+====== test error propagate ======
 successfully errored with this message: 
 Traceback (most recent call last):
-  File "<c-bound>", line 1
+  File "main.py", line 1
     test_error_propagate()
 NameError: catch me
+
+====== test other errors ======
+successfully errored with this message: 
+Traceback (most recent call last):
+NameError: nonexistant
 successfully errored with this message: 
 Traceback (most recent call last):
-  File "<c-bound>", line 1
+  File "main.py", line 1
     raise NameError('testing error throwing from python')
 NameError: testing error throwing from python
+
+====== test TypeError ======
+successfully errored with this message: 
+TypeError: expected 'int', got 'float'
+
+====== test complicated errors ======
 successfully errored with this message: 
 Traceback (most recent call last):
 _: test direct error mechanism
 successfully errored with this message: 
 Traceback (most recent call last):
-  File "<c-bound>", line 1
+  File "main.py", line 1
     test_nested_error()
-  File "<c-bound>", line 1
+  File "main.py", line 1
     def error_from_python() : raise NotImplementedError()
 NotImplementedError
-pi: 3.14
+
+====== test getattr/setattr ======
 pi: 3.14
 2
-successfully errored with this message: 
-TypeError: expected 'int', got 'float'
+
+====== test eval ======
+pi: 2.00

+ 5 - 2
docs/C-API/error.md

@@ -8,8 +8,11 @@ order: 5
 
 + 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.
-+ You are responsible for freeing `message`.
++ 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`.
+
+!!!
+You are responsible for freeing `message`.
+!!!
 
 #### `bool pkpy_check_error(pkpy_vm*)`
 

+ 8 - 12
src/pocketpy_c.cpp

@@ -374,15 +374,14 @@ bool pkpy_setattr(pkpy_vm* vm_handle, pkpy_CName name) {
 }
 
 //get global will also get bulitins
-bool pkpy_getglobal(pkpy_vm* vm_handle, pkpy_CName name_) {
+bool pkpy_getglobal(pkpy_vm* vm_handle, pkpy_CName name) {
     VM* vm = (VM*) vm_handle;
-    StrName name(name_);
     PK_ASSERT_NO_ERROR()
-    PyObject* o = vm->_main->attr().try_get(name);
+    PyObject* o = vm->_main->attr().try_get(StrName(name));
     if (o == nullptr) {
-        o = vm->builtins->attr().try_get(name);
+        o = vm->builtins->attr().try_get(StrName(name));
         if (o == nullptr){
-            pkpy_error(vm_handle, "NameError", pkpy_name_to_string(name_));
+            pkpy_error(vm_handle, "NameError", pkpy_name_to_string(name));
             return false;
         }
     }
@@ -390,11 +389,11 @@ bool pkpy_getglobal(pkpy_vm* vm_handle, pkpy_CName name_) {
     return true;
 }
 
-bool pkpy_setglobal(pkpy_vm* vm_handle, pkpy_CName name_) {
+bool pkpy_setglobal(pkpy_vm* vm_handle, pkpy_CName name) {
     VM* vm = (VM*) vm_handle;
     PK_ASSERT_NO_ERROR()
     PK_ASSERT_N_EXTRA_ELEMENTS(1)
-    vm->_main->attr().set(StrName(name_), vm->s_data.popx());
+    vm->_main->attr().set(StrName(name), vm->s_data.popx());
     return true;
 }
 
@@ -435,7 +434,7 @@ bool pkpy_get_unbound_method(pkpy_vm* vm_handle, pkpy_CName name){
     PK_PROTECTED(
         o = vm->get_unbound_method(o, StrName(name), &self);
     )
-    vm->s_data.shrink(2);
+    vm->s_data.pop();
     vm->s_data.push(o);
     vm->s_data.push(self);
     return true;
@@ -459,10 +458,7 @@ bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
     // 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";
+    if (message != nullptr) *message = e.summary().c_str_dup();
     vm->_c.error = nullptr;
     // clear the whole stack??
     vm->callstack.clear();