This commit is contained in:
blueloveTH 2023-07-15 13:35:03 +08:00
parent fd2996eb87
commit f2435b81df
4 changed files with 131 additions and 87 deletions

View File

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

View File

@ -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):
File "<c-bound>", 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 "<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

View File

@ -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*)`

View File

@ -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();