From f2435b81dfbbeaeb7b87c8ba491f57159f5e177c Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sat, 15 Jul 2023 13:35:03 +0800 Subject: [PATCH] ... --- c_bindings/test.c | 124 +++++++++++++++++++++--------------- c_bindings/test_answers.txt | 67 ++++++++++++------- docs/C-API/error.md | 7 +- src/pocketpy_c.cpp | 20 +++--- 4 files changed, 131 insertions(+), 87 deletions(-) diff --git a/c_bindings/test.c b/c_bindings/test.c index ef541a9c..6cb80e21 100644 --- a/c_bindings/test.c +++ b/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"); + + PRINT_TITLE("test error catching"); 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"); + //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; } diff --git a/c_bindings/test_answers.txt b/c_bindings/test_answers.txt index 2222ee03..0a06690e 100644 --- a/c_bindings/test_answers.txt +++ b/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 ====== 123 -testing sizing and indexing +====== test sizing and indexing ====== stack size 6 -testing error catching +====== test error catching ====== successfully errored with this message: - File "", 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 "", 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): - File "", line 1 +NameError: nonexistant +successfully errored with this message: +Traceback (most recent call last): + 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 "", line 1 + File "main.py", line 1 test_nested_error() - File "", 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 diff --git a/docs/C-API/error.md b/docs/C-API/error.md index b2a594b1..ca38a353 100644 --- a/docs/C-API/error.md +++ b/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*)` diff --git a/src/pocketpy_c.cpp b/src/pocketpy_c.cpp index 8b84ab89..3d58cc67 100644 --- a/src/pocketpy_c.cpp +++ b/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(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();