mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
Compare commits
3 Commits
2165e29c4f
...
db0acc854c
Author | SHA1 | Date | |
---|---|---|---|
|
db0acc854c | ||
|
1bbba50003 | ||
|
ec30ba9d02 |
@ -1,23 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.17)
|
||||
|
||||
project(test_c_bindings)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
option(PK_BUILD_STATIC_LIB "Build static library" ON)
|
||||
|
||||
add_subdirectory(
|
||||
${CMAKE_CURRENT_LIST_DIR}/../
|
||||
${CMAKE_CURRENT_LIST_DIR}/build/pocketpy/
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_LIST_DIR}/../include
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} test.c)
|
||||
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
pocketpy
|
||||
)
|
@ -1,415 +0,0 @@
|
||||
#include "pocketpy_c.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//tests the c bindings for pocketpy
|
||||
|
||||
void check_impl(pkpy_vm* vm, bool result, int lineno) {
|
||||
if (!result) {
|
||||
printf("ERROR: failed where it should have succeed at line %i\n", lineno);
|
||||
if (!pkpy_clear_error(vm, NULL)) {
|
||||
printf("clear error reported everything was fine\n");
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void fail_impl(pkpy_vm* vm, bool result, int lineno) {
|
||||
if (result) {
|
||||
printf("ERROR: succeeded where it should have failed line %i\n", lineno);
|
||||
exit(1);
|
||||
} else {
|
||||
char* message;
|
||||
if (pkpy_clear_error(vm, &message)) {
|
||||
printf("actually errored! line %i\n", lineno);
|
||||
free(message);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void error_impl(pkpy_vm* vm, bool result, int lineno) {
|
||||
if (result) {
|
||||
printf("ERROR: succeeded where it should have failed line %i\n", lineno);
|
||||
exit(1);
|
||||
} else {
|
||||
char* message;
|
||||
if (!pkpy_clear_error(vm, &message)){
|
||||
printf("clear error reported everything was fine\n");
|
||||
exit(1);
|
||||
} else {
|
||||
printf("successfully errored with this message: \n");
|
||||
printf("%s\n", message);
|
||||
free(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define check(r) check_impl(vm, (r), __LINE__)
|
||||
#define fail(r) fail_impl(vm, (r), __LINE__)
|
||||
#define error(r) error_impl(vm, (r), __LINE__)
|
||||
|
||||
int test_binding(pkpy_vm* vm) {
|
||||
pkpy_push_int(vm, 12);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_multiple_return(pkpy_vm* vm) {
|
||||
pkpy_push_int(vm, 12);
|
||||
pkpy_push_int(vm, 13);
|
||||
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);
|
||||
bool ok = x == 5;
|
||||
pkpy_push_bool(vm, ok);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_return_none(pkpy_vm* vm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_error_propagate(pkpy_vm* vm) {
|
||||
pkpy_error(vm, "NameError", pkpy_string("catch me"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_nested_error(pkpy_vm* vm) {
|
||||
pkpy_getglobal(vm, pkpy_name("error_from_python"));
|
||||
pkpy_push_null(vm);
|
||||
pkpy_vectorcall(vm, 0);
|
||||
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!')"));
|
||||
fail(pkpy_getglobal(vm, pkpy_name("nonexistatn")));
|
||||
|
||||
// test int methods
|
||||
PRINT_TITLE("test int methods");
|
||||
int r_int;
|
||||
check(pkpy_push_int(vm, 11));
|
||||
pkpy_CName m_eleven = pkpy_name("eleven");
|
||||
check(pkpy_setglobal(vm, m_eleven));
|
||||
check(pkpy_exec(vm, "print(eleven)"));
|
||||
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); // 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));
|
||||
|
||||
PRINT_TITLE("test float methods");
|
||||
double r_float;
|
||||
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("%.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));
|
||||
|
||||
PRINT_TITLE("test bool methods");
|
||||
bool r_bool;
|
||||
check(pkpy_push_bool(vm, false));
|
||||
pkpy_CName m_false_test = pkpy_name("false_test");
|
||||
check(pkpy_setglobal(vm, m_false_test));
|
||||
check(pkpy_exec(vm, "print(false_test)"));
|
||||
check(pkpy_getglobal(vm, m_false_test));
|
||||
check(pkpy_is_bool(vm, -1));
|
||||
check(pkpy_to_bool(vm, -1, &r_bool));
|
||||
printf("%i\n", r_bool);
|
||||
fail(pkpy_is_int(vm, -1));
|
||||
fail(pkpy_is_float(vm, -1));
|
||||
fail(pkpy_is_string(vm, -1));
|
||||
fail(pkpy_is_none(vm, -1));
|
||||
fail(pkpy_is_voidp(vm, -1));
|
||||
|
||||
PRINT_TITLE("test string methods");
|
||||
pkpy_CString r_string;
|
||||
check(pkpy_push_string(vm, pkpy_string("hello!")));
|
||||
check(pkpy_setglobal(vm, pkpy_name("hello1")));
|
||||
check(pkpy_exec(vm, "print(hello1)"));
|
||||
check(pkpy_push_string(vm, pkpy_string("hello!")));
|
||||
check(pkpy_is_string(vm, -1));
|
||||
check(pkpy_to_string(vm, -1, &r_string));
|
||||
|
||||
puts(r_string);
|
||||
|
||||
fail(pkpy_is_int(vm, -1));
|
||||
fail(pkpy_is_float(vm, -1));
|
||||
fail(pkpy_is_bool(vm, -1));
|
||||
fail(pkpy_is_none(vm, -1));
|
||||
fail(pkpy_is_voidp(vm, -1));
|
||||
|
||||
PRINT_TITLE("test none methods");
|
||||
check(pkpy_push_none(vm));
|
||||
pkpy_CName m_none = pkpy_name("none");
|
||||
check(pkpy_setglobal(vm, m_none));
|
||||
check(pkpy_exec(vm, "print(none)"));
|
||||
check(pkpy_getglobal(vm, m_none));
|
||||
check(pkpy_is_none(vm, -1));
|
||||
fail(pkpy_is_int(vm, -1));
|
||||
fail(pkpy_is_float(vm, -1));
|
||||
fail(pkpy_is_bool(vm, -1));
|
||||
fail(pkpy_is_string(vm, -1));
|
||||
fail(pkpy_is_voidp(vm, -1));
|
||||
|
||||
PRINT_TITLE("test voidp methods");
|
||||
void* vp = (void*) 123;
|
||||
check(pkpy_push_voidp(vm, vp));
|
||||
check(pkpy_setglobal(vm, pkpy_name("vp")));
|
||||
check(pkpy_exec(vm, "print(vp)"));
|
||||
check(pkpy_getglobal(vm, pkpy_name("vp")));
|
||||
check(pkpy_is_voidp(vm, -1));
|
||||
vp = NULL;
|
||||
check(pkpy_to_voidp(vm, -1, &vp));
|
||||
printf("%i\n", (int) (intptr_t) vp);
|
||||
fail(pkpy_is_int(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));
|
||||
|
||||
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));
|
||||
check(pkpy_is_float(vm, 1));
|
||||
check(pkpy_is_bool(vm, 2));
|
||||
check(pkpy_is_string(vm, 3));
|
||||
check(pkpy_is_none(vm, 4));
|
||||
check(pkpy_is_voidp(vm, 5));
|
||||
check(pkpy_is_int(vm, -6));
|
||||
check(pkpy_is_float(vm, -5));
|
||||
check(pkpy_is_bool(vm, -4));
|
||||
check(pkpy_is_string(vm, -3));
|
||||
check(pkpy_is_none(vm, -2));
|
||||
check(pkpy_is_voidp(vm, -1));
|
||||
|
||||
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_getglobal(vm, pkpy_name("x")));
|
||||
check(pkpy_push_null(vm));
|
||||
check(pkpy_push_int(vm, 2));
|
||||
check(pkpy_push_int(vm, 3));
|
||||
check(pkpy_vectorcall(vm, 2));
|
||||
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));
|
||||
check(pkpy_push_int(vm, 2));
|
||||
check(pkpy_push_int(vm, 3));
|
||||
check(pkpy_push_int(vm, 4));
|
||||
check(pkpy_push_int(vm, 5));
|
||||
check(pkpy_push_int(vm, 6));
|
||||
check(pkpy_vectorcall(vm, 6));
|
||||
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); // 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); // 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) == 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));
|
||||
printf("retmany_x : %i\n", r_int);
|
||||
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)"));
|
||||
|
||||
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);
|
||||
|
||||
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 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")));
|
||||
error(pkpy_exec(vm, "test_error_propagate()"));
|
||||
|
||||
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_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));
|
||||
pkpy_clear_error(vm, NULL);
|
||||
|
||||
//this should be catchable
|
||||
check(pkpy_exec(vm, "try :\n test_error_propagate()\nexcept NameError : pass"));
|
||||
error(pkpy_error(vm, "Exception", 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_stack_size(vm) == 0);
|
||||
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", (float)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)"));
|
||||
|
||||
PRINT_TITLE("test eval");
|
||||
check(pkpy_eval(vm, "math.pi"));
|
||||
check(pkpy_to_float(vm, -1, &r_float));
|
||||
printf("pi: %.2f\n", (float)r_float);
|
||||
check(pkpy_pop(vm, 1));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
PRINT_TITLE("test py_repr");
|
||||
check(pkpy_eval(vm, "['1', 2, (3, '4')]"));
|
||||
check(pkpy_py_repr(vm));
|
||||
check(pkpy_to_string(vm, -1, &r_string));
|
||||
|
||||
puts(r_string);
|
||||
check(pkpy_pop_top(vm));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
return 0;
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
|
||||
====== test basic exec ======
|
||||
hello world!
|
||||
|
||||
====== test int methods ======
|
||||
11
|
||||
11
|
||||
1
|
||||
|
||||
====== test float methods ======
|
||||
11.125
|
||||
11.125
|
||||
|
||||
====== test bool methods ======
|
||||
False
|
||||
0
|
||||
|
||||
====== test string methods ======
|
||||
hello!
|
||||
hello!
|
||||
|
||||
====== test none methods ======
|
||||
None
|
||||
|
||||
====== test voidp methods ======
|
||||
<void* at 0x7b>
|
||||
123
|
||||
|
||||
====== test sizing and indexing ======
|
||||
stack size 6
|
||||
|
||||
====== test error catching ======
|
||||
successfully errored with this message:
|
||||
File "main.py", line 1
|
||||
let's make sure syntax errors get caught
|
||||
SyntaxError: EOL while scanning string literal
|
||||
|
||||
====== 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
|
||||
successfully errored with this message:
|
||||
TypeError: x() takes 2 positional arguments but 0 were given
|
||||
['hello']
|
||||
|
||||
====== 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):
|
||||
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 "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 ======
|
||||
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):
|
||||
Exception: test direct error mechanism
|
||||
successfully errored with this message:
|
||||
Traceback (most recent call last):
|
||||
File "main.py", line 1
|
||||
test_nested_error()
|
||||
File "main.py", line 1, in error_from_python
|
||||
def error_from_python() : raise NotImplementedError()
|
||||
NotImplementedError
|
||||
|
||||
====== test getattr/setattr ======
|
||||
pi: 3.14
|
||||
2
|
||||
|
||||
====== test eval ======
|
||||
pi: 2.00
|
||||
|
||||
====== test py_repr ======
|
||||
['1', 2, (3, '4')]
|
@ -3,6 +3,7 @@
|
||||
#include "pocketpy/common/str.h"
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/objects/sourcedata.h"
|
||||
#include "pocketpy/objects/error.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -87,8 +88,6 @@ enum Precedence {
|
||||
PREC_HIGHEST,
|
||||
};
|
||||
|
||||
typedef struct Error Error;
|
||||
|
||||
typedef c11_array pk_TokenArray;
|
||||
|
||||
Error* pk_Lexer__process(pk_SourceData_ src, pk_TokenArray* out_tokens);
|
||||
|
@ -38,10 +38,9 @@ typedef struct pk_VM {
|
||||
py_TValue builtins; // builtins module
|
||||
py_TValue main; // __main__ module
|
||||
|
||||
void (*_ceval_on_step)(Frame*, Bytecode);
|
||||
unsigned char* (*_import_file)(const char*);
|
||||
void (*_stdout)(const char*, ...);
|
||||
void (*_stderr)(const char*, ...);
|
||||
void (*ceval_on_step)(Frame*, Bytecode);
|
||||
unsigned char* (*import_file)(const char*);
|
||||
void (*print)(const char*);
|
||||
|
||||
py_TValue last_retval;
|
||||
py_TValue curr_exception;
|
||||
|
@ -11,14 +11,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Error{
|
||||
const char* type;
|
||||
typedef struct{
|
||||
pk_SourceData_ src;
|
||||
int lineno;
|
||||
const char* cursor;
|
||||
char msg[100];
|
||||
int64_t userdata;
|
||||
};
|
||||
} Error;
|
||||
|
||||
void py_BaseException__set_lineno(py_Ref, int lineno, const CodeObject* code);
|
||||
int py_BaseException__get_lineno(py_Ref, const CodeObject* code);
|
||||
|
@ -3,31 +3,41 @@
|
||||
#include <stdbool.h>
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/common/str.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/common/vector.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
struct pk_SourceData {
|
||||
RefCounted rc;
|
||||
enum py_CompileMode mode;
|
||||
bool is_precompiled;
|
||||
bool is_dynamic; // for exec() and eval()
|
||||
bool is_dynamic; // for exec() and eval()
|
||||
|
||||
c11_string* filename;
|
||||
c11_string* source;
|
||||
|
||||
c11_vector/*T=const char* */ line_starts;
|
||||
c11_vector/*T=c11_string* */ _precompiled_tokens;
|
||||
c11_vector /*T=const char* */ line_starts;
|
||||
c11_vector /*T=c11_string* */ _precompiled_tokens;
|
||||
};
|
||||
|
||||
typedef struct pk_SourceData* pk_SourceData_;
|
||||
|
||||
pk_SourceData_ pk_SourceData__rcnew(const char* source, const char* filename, enum py_CompileMode mode, bool is_dynamic);
|
||||
bool pk_SourceData__get_line(const struct pk_SourceData* self, int lineno, const char** st, const char** ed);
|
||||
c11_string* pk_SourceData__snapshot(const struct pk_SourceData *self, int lineno, const char *cursor, const char *name);
|
||||
pk_SourceData_ pk_SourceData__rcnew(const char* source,
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
bool is_dynamic);
|
||||
bool pk_SourceData__get_line(const struct pk_SourceData* self,
|
||||
int lineno,
|
||||
const char** st,
|
||||
const char** ed);
|
||||
void pk_SourceData__snapshot(const struct pk_SourceData* self,
|
||||
c11_sbuf* ss,
|
||||
int lineno,
|
||||
const char* cursor,
|
||||
const char* name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ py_ObjectRef py_bind2(py_Ref obj,
|
||||
// old style argc-based bindings
|
||||
void py_bindmethod(py_Type type, const char* name, py_CFunction f);
|
||||
void py_bindmethod2(py_Type type, const char* name, py_CFunction f, enum BindType bt);
|
||||
void py_bindnativefunc(py_Ref obj, const char* name, py_CFunction f);
|
||||
void py_bindfunc(py_Ref obj, const char* name, py_CFunction f);
|
||||
|
||||
/// Get the reference to the i-th register.
|
||||
/// All registers are located in a contiguous memory.
|
||||
|
@ -71,41 +71,38 @@ bool pk_SourceData__get_line(const struct pk_SourceData* self,
|
||||
return true;
|
||||
}
|
||||
|
||||
c11_string* pk_SourceData__snapshot(const struct pk_SourceData* self,
|
||||
int lineno,
|
||||
const char* cursor,
|
||||
const char* name) {
|
||||
c11_sbuf ss;
|
||||
c11_sbuf__ctor(&ss);
|
||||
|
||||
pk_sprintf(&ss, " File \"%s\", line %d", self->filename->data, lineno);
|
||||
void pk_SourceData__snapshot(const struct pk_SourceData* self,
|
||||
c11_sbuf* ss,
|
||||
int lineno,
|
||||
const char* cursor,
|
||||
const char* name) {
|
||||
pk_sprintf(ss, " File \"%s\", line %d", self->filename->data, lineno);
|
||||
|
||||
if(name && *name) {
|
||||
c11_sbuf__write_cstr(&ss, ", in ");
|
||||
c11_sbuf__write_cstr(&ss, name);
|
||||
c11_sbuf__write_cstr(ss, ", in ");
|
||||
c11_sbuf__write_cstr(ss, name);
|
||||
}
|
||||
|
||||
if(!self->is_precompiled) {
|
||||
c11_sbuf__write_char(&ss, '\n');
|
||||
c11_sbuf__write_char(ss, '\n');
|
||||
const char *st = NULL, *ed;
|
||||
if(pk_SourceData__get_line(self, lineno, &st, &ed)) {
|
||||
while(st < ed && isblank(*st))
|
||||
++st;
|
||||
if(st < ed) {
|
||||
c11_sbuf__write_cstr(&ss, " ");
|
||||
c11_sbuf__write_cstrn(&ss, st, ed - st);
|
||||
c11_sbuf__write_cstr(ss, " ");
|
||||
c11_sbuf__write_cstrn(ss, st, ed - st);
|
||||
if(cursor && st <= cursor && cursor <= ed) {
|
||||
c11_sbuf__write_cstr(&ss, "\n ");
|
||||
c11_sbuf__write_cstr(ss, "\n ");
|
||||
for(int i = 0; i < (cursor - st); ++i)
|
||||
c11_sbuf__write_char(&ss, ' ');
|
||||
c11_sbuf__write_cstr(&ss, "^");
|
||||
c11_sbuf__write_char(ss, ' ');
|
||||
c11_sbuf__write_cstr(ss, "^");
|
||||
}
|
||||
} else {
|
||||
st = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if(!st) { c11_sbuf__write_cstr(&ss, " <?>"); }
|
||||
if(!st) { c11_sbuf__write_cstr(ss, " <?>"); }
|
||||
}
|
||||
return c11_sbuf__submit(&ss);
|
||||
}
|
||||
|
@ -1450,6 +1450,7 @@ static void Compiler__ctor(Compiler* self, pk_SourceData_ src, pk_TokenArray tok
|
||||
|
||||
static void Compiler__dtor(Compiler* self) {
|
||||
pk_TokenArray__dtor(&self->tokens);
|
||||
c11__foreach(Ctx, &self->contexts, ctx) Ctx__dtor(ctx);
|
||||
c11_vector__dtor(&self->contexts);
|
||||
}
|
||||
|
||||
@ -1458,7 +1459,6 @@ static void Compiler__dtor(Compiler* self) {
|
||||
#define prev() tk(self->i - 1)
|
||||
#define curr() tk(self->i)
|
||||
#define next() tk(self->i + 1)
|
||||
// #define err() (self->i == self->tokens.count ? prev() : curr())
|
||||
|
||||
#define advance() self->i++
|
||||
#define mode() self->src->mode
|
||||
@ -1468,11 +1468,12 @@ static void Compiler__dtor(Compiler* self) {
|
||||
|
||||
#define consume(expected) \
|
||||
if(!match(expected)) \
|
||||
return SyntaxError("expected '%s', got '%s'", \
|
||||
return SyntaxError(self, \
|
||||
"expected '%s', got '%s'", \
|
||||
pk_TokenSymbols[expected], \
|
||||
pk_TokenSymbols[curr()->type]);
|
||||
#define consume_end_stmt() \
|
||||
if(!match_end_stmt(self)) return SyntaxError("expected statement end")
|
||||
if(!match_end_stmt(self)) return SyntaxError(self, "expected statement end")
|
||||
|
||||
#define check(B) \
|
||||
if((err = B)) return err
|
||||
@ -1483,9 +1484,17 @@ static NameScope name_scope(Compiler* self) {
|
||||
return s;
|
||||
}
|
||||
|
||||
Error* SyntaxError(const char* fmt, ...) {
|
||||
c11__abort("%s", fmt);
|
||||
return NULL;
|
||||
Error* SyntaxError(Compiler* self, const char* fmt, ...) {
|
||||
Error* err = malloc(sizeof(Error));
|
||||
err->src = self->src;
|
||||
PK_INCREF(self->src);
|
||||
Token* t = self->i == self->tokens.count ? prev() : curr();
|
||||
err->lineno = t->line;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(err->msg, sizeof(err->msg), fmt, args);
|
||||
va_end(args);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Matchers */
|
||||
@ -1522,7 +1531,7 @@ static bool match_end_stmt(Compiler* self) {
|
||||
static Error* parse_expression(Compiler* self, int precedence, bool allow_slice) {
|
||||
PrattCallback prefix = rules[curr()->type].prefix;
|
||||
if(!prefix || (curr()->type == TK_COLON && !allow_slice)) {
|
||||
return SyntaxError("expected an expression, got %s", pk_TokenSymbols[curr()->type]);
|
||||
return SyntaxError(self, "expected an expression, got %s", pk_TokenSymbols[curr()->type]);
|
||||
}
|
||||
advance();
|
||||
Error* err;
|
||||
@ -1612,9 +1621,11 @@ static Error* pop_context(Compiler* self) {
|
||||
// some check here
|
||||
c11_vector* codes = &co->codes;
|
||||
if(co->nlocals > PK_MAX_CO_VARNAMES) {
|
||||
return SyntaxError("maximum number of local variables exceeded");
|
||||
return SyntaxError(self, "maximum number of local variables exceeded");
|
||||
}
|
||||
if(co->consts.count > 65530) {
|
||||
return SyntaxError(self, "maximum number of constants exceeded");
|
||||
}
|
||||
if(co->consts.count > 65530) { return SyntaxError("maximum number of constants exceeded"); }
|
||||
// pre-compute LOOP_BREAK and LOOP_CONTINUE
|
||||
for(int i = 0; i < codes->count; i++) {
|
||||
Bytecode* bc = c11__at(Bytecode, codes, i);
|
||||
@ -1635,7 +1646,8 @@ static Error* pop_context(Compiler* self) {
|
||||
func->type = FuncType_GENERATOR;
|
||||
c11__foreach(Bytecode, &func->code.codes, bc) {
|
||||
if(bc->op == OP_RETURN_VALUE && bc->arg == BC_NOARG) {
|
||||
return SyntaxError("'return' with argument inside generator function");
|
||||
return SyntaxError(self,
|
||||
"'return' with argument inside generator function");
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1962,7 +1974,7 @@ static Error* exprCall(Compiler* self) {
|
||||
} else {
|
||||
// positional argument
|
||||
if(e->kwargs.count > 0) {
|
||||
return SyntaxError("positional argument follows keyword argument");
|
||||
return SyntaxError(self, "positional argument follows keyword argument");
|
||||
}
|
||||
c11_vector__push(Expr*, &e->args, Ctx__s_popx(ctx()));
|
||||
}
|
||||
@ -2052,7 +2064,7 @@ static Error* compile_block_body(Compiler* self, PrattCallback callback) {
|
||||
}
|
||||
|
||||
bool consumed = match_newlines();
|
||||
if(!consumed) return SyntaxError("expected a new line after ':'");
|
||||
if(!consumed) return SyntaxError(self, "expected a new line after ':'");
|
||||
|
||||
consume(TK_INDENT);
|
||||
while(curr()->type != TK_DEDENT) {
|
||||
@ -2119,7 +2131,7 @@ static Error* compile_for_loop(Compiler* self) {
|
||||
vtdelete(vars);
|
||||
if(!ok) {
|
||||
// this error occurs in `vars` instead of this line, but...nevermind
|
||||
return SyntaxError("invalid syntax");
|
||||
return SyntaxError(self, "invalid syntax");
|
||||
}
|
||||
check(compile_block_body(self, compile_stmt));
|
||||
Ctx__emit_virtual(ctx(), OP_LOOP_CONTINUE, Ctx__get_loop(ctx()), BC_KEEPLINE, true);
|
||||
@ -2147,9 +2159,9 @@ Error* try_compile_assignment(Compiler* self, bool* is_assign) {
|
||||
case TK_IOR:
|
||||
case TK_IXOR: {
|
||||
if(Ctx__s_top(ctx())->vt->is_starred)
|
||||
return SyntaxError("can't use inplace operator with starred expression");
|
||||
return SyntaxError(self, "can't use inplace operator with starred expression");
|
||||
if(ctx()->is_compiling_class)
|
||||
return SyntaxError("can't use inplace operator in class definition");
|
||||
return SyntaxError(self, "can't use inplace operator in class definition");
|
||||
advance();
|
||||
// a[x] += 1; a and x should be evaluated only once
|
||||
// a.x += 1; a should be evaluated only once
|
||||
@ -2159,14 +2171,14 @@ Error* try_compile_assignment(Compiler* self, bool* is_assign) {
|
||||
// [lhs]
|
||||
check(EXPR_TUPLE(self)); // [lhs, rhs]
|
||||
if(Ctx__s_top(ctx())->vt->is_starred)
|
||||
return SyntaxError("can't use starred expression here");
|
||||
return SyntaxError(self, "can't use starred expression here");
|
||||
BinaryExpr* e = BinaryExpr__new(line, op, true);
|
||||
e->rhs = Ctx__s_popx(ctx()); // [lhs]
|
||||
e->lhs = Ctx__s_popx(ctx()); // []
|
||||
vtemit_((Expr*)e, ctx());
|
||||
bool ok = vtemit_istore(e->lhs, ctx());
|
||||
vtdelete((Expr*)e);
|
||||
if(!ok) return SyntaxError("invalid syntax");
|
||||
if(!ok) return SyntaxError(self, "invalid syntax");
|
||||
*is_assign = true;
|
||||
return NULL;
|
||||
}
|
||||
@ -2182,11 +2194,11 @@ Error* try_compile_assignment(Compiler* self, bool* is_assign) {
|
||||
Ctx__emit_(ctx(), OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||
for(int j = 0; j < n; j++) {
|
||||
if(Ctx__s_top(ctx())->vt->is_starred)
|
||||
return SyntaxError("can't use starred expression here");
|
||||
return SyntaxError(self, "can't use starred expression here");
|
||||
Expr* e = Ctx__s_top(ctx());
|
||||
bool ok = vtemit_store(e, ctx());
|
||||
Ctx__s_pop(ctx());
|
||||
if(!ok) return SyntaxError("invalid syntax");
|
||||
if(!ok) return SyntaxError(self, "invalid syntax");
|
||||
}
|
||||
*is_assign = true;
|
||||
return NULL;
|
||||
@ -2239,7 +2251,8 @@ static Error* read_literal(Compiler* self, py_Ref out) {
|
||||
py_TValue cpnts[4];
|
||||
int count = 0;
|
||||
while(true) {
|
||||
if(count == 4) return SyntaxError("default argument tuple exceeds 4 elements");
|
||||
if(count == 4)
|
||||
return SyntaxError(self, "default argument tuple exceeds 4 elements");
|
||||
check(read_literal(self, &cpnts[count]));
|
||||
count += 1;
|
||||
if(curr()->type == TK_RPAREN) break;
|
||||
@ -2261,13 +2274,13 @@ static Error* _compile_f_args(Compiler* self, FuncDecl* decl, bool enable_type_h
|
||||
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
|
||||
Error* err;
|
||||
do {
|
||||
if(state >= 3) return SyntaxError("**kwargs should be the last argument");
|
||||
if(state >= 3) return SyntaxError(self, "**kwargs should be the last argument");
|
||||
match_newlines();
|
||||
if(match(TK_MUL)) {
|
||||
if(state < 1)
|
||||
state = 1;
|
||||
else
|
||||
return SyntaxError("*args should be placed before **kwargs");
|
||||
return SyntaxError(self, "*args should be placed before **kwargs");
|
||||
} else if(match(TK_POW)) {
|
||||
state = 3;
|
||||
}
|
||||
@ -2276,7 +2289,7 @@ static Error* _compile_f_args(Compiler* self, FuncDecl* decl, bool enable_type_h
|
||||
|
||||
// check duplicate argument name
|
||||
if(FuncDecl__is_duplicated_arg(decl, name)) {
|
||||
return SyntaxError("duplicate argument name");
|
||||
return SyntaxError(self, "duplicate argument name");
|
||||
}
|
||||
|
||||
// eat type hints
|
||||
@ -2292,7 +2305,7 @@ static Error* _compile_f_args(Compiler* self, FuncDecl* decl, bool enable_type_h
|
||||
consume(TK_ASSIGN);
|
||||
py_TValue value;
|
||||
check(read_literal(self, &value));
|
||||
if(py_isnil(&value)) return SyntaxError("default argument must be a literal");
|
||||
if(py_isnil(&value)) return SyntaxError(self, "default argument must be a literal");
|
||||
FuncDecl__add_kwarg(decl, name, &value);
|
||||
} break;
|
||||
case 3:
|
||||
@ -2367,7 +2380,7 @@ static Error* compile_class(Compiler* self, int decorators) {
|
||||
Ctx__emit_(ctx(), OP_BEGIN_CLASS, name, BC_KEEPLINE);
|
||||
|
||||
c11__foreach(Ctx, &self->contexts, it) {
|
||||
if(it->is_compiling_class) return SyntaxError("nested class is not allowed");
|
||||
if(it->is_compiling_class) return SyntaxError(self, "nested class is not allowed");
|
||||
}
|
||||
ctx()->is_compiling_class = true;
|
||||
check(compile_block_body(self, compile_stmt));
|
||||
@ -2384,7 +2397,7 @@ static Error* compile_decorated(Compiler* self) {
|
||||
do {
|
||||
check(EXPR(self));
|
||||
count += 1;
|
||||
if(!match_newlines()) return SyntaxError("expected a newline after '@'");
|
||||
if(!match_newlines()) return SyntaxError(self, "expected a newline after '@'");
|
||||
} while(match(TK_DECORATOR));
|
||||
|
||||
if(match(TK_CLASS)) {
|
||||
@ -2468,7 +2481,7 @@ __EAT_DOTS_END:
|
||||
|
||||
if(match(TK_MUL)) {
|
||||
if(name_scope(self) != NAME_GLOBAL)
|
||||
return SyntaxError("from <module> import * can only be used in global scope");
|
||||
return SyntaxError(self, "from <module> import * can only be used in global scope");
|
||||
// pop the module and import __all__
|
||||
Ctx__emit_(ctx(), OP_POP_IMPORT_STAR, BC_NOARG, prev()->line);
|
||||
consume_end_stmt();
|
||||
@ -2503,10 +2516,14 @@ static Error* compile_try_except(Compiler* self) {
|
||||
patches[patches_length++] = Ctx__emit_(ctx(), OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE);
|
||||
Ctx__exit_block(ctx());
|
||||
|
||||
if(curr()->type == TK_FINALLY) { return SyntaxError("finally clause is not supported yet"); }
|
||||
if(curr()->type == TK_FINALLY) {
|
||||
return SyntaxError(self, "finally clause is not supported yet");
|
||||
}
|
||||
|
||||
do {
|
||||
if(patches_length == 8) { return SyntaxError("maximum number of except clauses reached"); }
|
||||
if(patches_length == 8) {
|
||||
return SyntaxError(self, "maximum number of except clauses reached");
|
||||
}
|
||||
py_Name as_name = 0;
|
||||
consume(TK_EXCEPT);
|
||||
if(is_expression(self, false)) {
|
||||
@ -2553,24 +2570,24 @@ static Error* compile_stmt(Compiler* self) {
|
||||
int curr_loop_block = Ctx__get_loop(ctx());
|
||||
switch(prev()->type) {
|
||||
case TK_BREAK:
|
||||
if(curr_loop_block < 0) return SyntaxError("'break' outside loop");
|
||||
if(curr_loop_block < 0) return SyntaxError(self, "'break' outside loop");
|
||||
Ctx__emit_(ctx(), OP_LOOP_BREAK, curr_loop_block, kw_line);
|
||||
consume_end_stmt();
|
||||
break;
|
||||
case TK_CONTINUE:
|
||||
if(curr_loop_block < 0) return SyntaxError("'continue' not properly in loop");
|
||||
if(curr_loop_block < 0) return SyntaxError(self, "'continue' not properly in loop");
|
||||
Ctx__emit_(ctx(), OP_LOOP_CONTINUE, curr_loop_block, kw_line);
|
||||
consume_end_stmt();
|
||||
break;
|
||||
case TK_YIELD:
|
||||
if(self->contexts.count <= 1) return SyntaxError("'yield' outside function");
|
||||
if(self->contexts.count <= 1) return SyntaxError(self, "'yield' outside function");
|
||||
check(EXPR_TUPLE(self));
|
||||
Ctx__s_emit_top(ctx());
|
||||
Ctx__emit_(ctx(), OP_YIELD_VALUE, BC_NOARG, kw_line);
|
||||
consume_end_stmt();
|
||||
break;
|
||||
case TK_YIELD_FROM:
|
||||
if(self->contexts.count <= 1) return SyntaxError("'yield from' outside function");
|
||||
if(self->contexts.count <= 1) return SyntaxError(self, "'yield from' outside function");
|
||||
check(EXPR_TUPLE(self));
|
||||
Ctx__s_emit_top(ctx());
|
||||
Ctx__emit_(ctx(), OP_GET_ITER, BC_NOARG, kw_line);
|
||||
@ -2582,7 +2599,7 @@ static Error* compile_stmt(Compiler* self) {
|
||||
consume_end_stmt();
|
||||
break;
|
||||
case TK_RETURN:
|
||||
if(self->contexts.count <= 1) return SyntaxError("'return' outside function");
|
||||
if(self->contexts.count <= 1) return SyntaxError(self, "'return' outside function");
|
||||
if(match_end_stmt(self)) {
|
||||
Ctx__emit_(ctx(), OP_RETURN_VALUE, 1, kw_line);
|
||||
} else {
|
||||
@ -2642,7 +2659,7 @@ static Error* compile_stmt(Compiler* self) {
|
||||
case TK_DEL: {
|
||||
check(EXPR_TUPLE(self));
|
||||
Expr* e = Ctx__s_top(ctx());
|
||||
if(!vtemit_del(e, ctx())) return SyntaxError("invalid syntax");
|
||||
if(!vtemit_del(e, ctx())) return SyntaxError(self, "invalid syntax");
|
||||
Ctx__s_pop(ctx());
|
||||
consume_end_stmt();
|
||||
} break;
|
||||
@ -2660,7 +2677,7 @@ static Error* compile_stmt(Compiler* self) {
|
||||
// if(as_name) {
|
||||
// bool ok = as_name->emit_store(ctx());
|
||||
// delete_expr(as_name);
|
||||
// if(!ok) return SyntaxError();
|
||||
// if(!ok) return SyntaxError(self, );
|
||||
// } else {
|
||||
// Ctx__emit_(ctx(), OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||
// }
|
||||
@ -2671,16 +2688,18 @@ static Error* compile_stmt(Compiler* self) {
|
||||
/*************************************************/
|
||||
case TK_EQ: {
|
||||
consume(TK_ID);
|
||||
if(mode() != EXEC_MODE) return SyntaxError("'label' is only available in EXEC_MODE");
|
||||
if(mode() != EXEC_MODE)
|
||||
return SyntaxError(self, "'label' is only available in EXEC_MODE");
|
||||
c11_sv name = Token__sv(prev());
|
||||
bool ok = Ctx__add_label(ctx(), py_namev(name));
|
||||
if(!ok) return SyntaxError("label %q already exists", name);
|
||||
if(!ok) return SyntaxError(self, "label %q already exists", name);
|
||||
consume(TK_EQ);
|
||||
consume_end_stmt();
|
||||
} break;
|
||||
case TK_ARROW:
|
||||
consume(TK_ID);
|
||||
if(mode() != EXEC_MODE) return SyntaxError("'goto' is only available in EXEC_MODE");
|
||||
if(mode() != EXEC_MODE)
|
||||
return SyntaxError(self, "'goto' is only available in EXEC_MODE");
|
||||
py_Name name = py_namev(Token__sv(prev()));
|
||||
Ctx__emit_(ctx(), OP_GOTO, name, prev()->line);
|
||||
consume_end_stmt();
|
||||
@ -2710,7 +2729,7 @@ static Error* compile_stmt(Compiler* self) {
|
||||
check(try_compile_assignment(self, &is_assign));
|
||||
if(!is_assign) {
|
||||
if(Ctx__s_size(ctx()) > 0 && Ctx__s_top(ctx())->vt->is_starred) {
|
||||
return SyntaxError("can't use starred expression here");
|
||||
return SyntaxError(self, "can't use starred expression here");
|
||||
}
|
||||
if(!is_typed_name) {
|
||||
Ctx__s_emit_top(ctx());
|
||||
|
@ -192,13 +192,19 @@ static bool is_possible_number_char(char c){
|
||||
}
|
||||
|
||||
/******************************/
|
||||
static Error* SyntaxError(const char* fmt, ...){
|
||||
// va_list args;
|
||||
// va_start(args, fmt);
|
||||
// Error* err = _error(true, "SyntaxError", fmt, &args);
|
||||
// va_end(args);
|
||||
// return err;
|
||||
return NULL;
|
||||
static Error* SyntaxError(pk_Lexer* self, const char* fmt, ...){
|
||||
Error* err = malloc(sizeof(Error));
|
||||
err->src = self->src;
|
||||
PK_INCREF(self->src);
|
||||
err->lineno = self->current_line;
|
||||
if(*self->curr_char == '\n') {
|
||||
err->lineno--;
|
||||
}
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(err->msg, sizeof(err->msg), fmt, args);
|
||||
va_end(args);
|
||||
return err;
|
||||
}
|
||||
|
||||
static Error* eat_name(pk_Lexer* self){
|
||||
@ -206,7 +212,7 @@ static Error* eat_name(pk_Lexer* self){
|
||||
while(true) {
|
||||
unsigned char c = *self->curr_char;
|
||||
int u8bytes = c11__u8_header(c, true);
|
||||
if(u8bytes == 0) return SyntaxError("invalid char: %c", c);
|
||||
if(u8bytes == 0) return SyntaxError(self, "invalid char: %c", c);
|
||||
if(u8bytes == 1) {
|
||||
if(isalnum(c) || c == '_') {
|
||||
self->curr_char++;
|
||||
@ -238,7 +244,7 @@ static Error* eat_name(pk_Lexer* self){
|
||||
}
|
||||
|
||||
int length = (int)(self->curr_char - self->token_start);
|
||||
if(length == 0) return SyntaxError("@id contains invalid char");
|
||||
if(length == 0) return SyntaxError(self, "@id contains invalid char");
|
||||
c11_sv name = {self->token_start, length};
|
||||
|
||||
const char** KW_BEGIN = pk_TokenSymbols + TK_FALSE;
|
||||
@ -271,11 +277,11 @@ static Error* eat_string_until(pk_Lexer* self, char quote, bool raw, c11_string*
|
||||
break;
|
||||
}
|
||||
if(c == '\0') {
|
||||
return SyntaxError("EOL while scanning string literal");
|
||||
return SyntaxError(self, "EOL while scanning string literal");
|
||||
}
|
||||
if(c == '\n') {
|
||||
if(!quote3)
|
||||
return SyntaxError("EOL while scanning string literal");
|
||||
return SyntaxError(self, "EOL while scanning string literal");
|
||||
else {
|
||||
c11_sbuf__write_char(&buff, c);
|
||||
continue;
|
||||
@ -294,11 +300,11 @@ static Error* eat_string_until(pk_Lexer* self, char quote, bool raw, c11_string*
|
||||
char hex[3] = {eatchar(self), eatchar(self), '\0'};
|
||||
int code;
|
||||
if(sscanf(hex, "%x", &code) != 1) {
|
||||
return SyntaxError("invalid hex char");
|
||||
return SyntaxError(self, "invalid hex char");
|
||||
}
|
||||
c11_sbuf__write_char(&buff, (char)code);
|
||||
} break;
|
||||
default: return SyntaxError("invalid escape char");
|
||||
default: return SyntaxError(self, "invalid escape char");
|
||||
}
|
||||
} else {
|
||||
c11_sbuf__write_char(&buff, c);
|
||||
@ -357,7 +363,7 @@ static Error* eat_number(pk_Lexer* self){
|
||||
add_token_with_value(self, TK_NUM, value);
|
||||
return NULL;
|
||||
case IntParsing_OVERFLOW:
|
||||
return SyntaxError("int literal is too large");
|
||||
return SyntaxError(self, "int literal is too large");
|
||||
case IntParsing_FAILURE:
|
||||
break; // do nothing
|
||||
}
|
||||
@ -380,7 +386,7 @@ static Error* eat_number(pk_Lexer* self){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return SyntaxError("invalid number literal");
|
||||
return SyntaxError(self, "invalid number literal");
|
||||
}
|
||||
|
||||
static Error* lex_one_token(pk_Lexer* self, bool* eof){
|
||||
@ -411,7 +417,7 @@ static Error* lex_one_token(pk_Lexer* self, bool* eof){
|
||||
// line continuation character
|
||||
char c = eatchar_include_newline(self);
|
||||
if(c != '\n') {
|
||||
return SyntaxError("expected newline after line continuation character");
|
||||
return SyntaxError(self, "expected newline after line continuation character");
|
||||
}
|
||||
eat_spaces(self);
|
||||
return NULL;
|
||||
@ -471,7 +477,7 @@ static Error* lex_one_token(pk_Lexer* self, bool* eof){
|
||||
if(matchchar(self, '=')){
|
||||
add_token(self, TK_NE);
|
||||
}else{
|
||||
Error* err = SyntaxError("expected '=' after '!'");
|
||||
Error* err = SyntaxError(self, "expected '=' after '!'");
|
||||
if(err) return err;
|
||||
}
|
||||
break;
|
||||
@ -494,7 +500,7 @@ static Error* lex_one_token(pk_Lexer* self, bool* eof){
|
||||
case '\n': {
|
||||
add_token(self, TK_EOL);
|
||||
if(!eat_indentation(self)){
|
||||
return SyntaxError("unindent does not match any outer indentation level");
|
||||
return SyntaxError(self, "unindent does not match any outer indentation level");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -534,10 +540,10 @@ static Error* from_precompiled(pk_Lexer* self) {
|
||||
c11_sv version = TokenDeserializer__read_string(&deserializer, '\n');
|
||||
|
||||
if(c11_sv__cmp2(version, PK_VERSION) != 0) {
|
||||
return SyntaxError("precompiled version mismatch");
|
||||
return SyntaxError(self, "precompiled version mismatch");
|
||||
}
|
||||
if(TokenDeserializer__read_uint(&deserializer, '\n') != (int64_t)self->src->mode){
|
||||
return SyntaxError("precompiled mode mismatch");
|
||||
return SyntaxError(self, "precompiled mode mismatch");
|
||||
}
|
||||
|
||||
int count = TokenDeserializer__read_count(&deserializer);
|
||||
|
@ -117,7 +117,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
if(TOP()->type != tp_NoneType) {
|
||||
bool ok = py_repr(TOP());
|
||||
if(!ok) goto __ERROR;
|
||||
self->_stdout("%s\n", py_tostr(&self->last_retval));
|
||||
self->print(py_tostr(&self->last_retval));
|
||||
self->print("\n");
|
||||
}
|
||||
POP();
|
||||
DISPATCH();
|
||||
|
@ -11,21 +11,7 @@
|
||||
|
||||
static unsigned char* pk_default_import_file(const char* path) { return NULL; }
|
||||
|
||||
static void pk_default_stdout(const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(stdout, fmt, args);
|
||||
va_end(args);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void pk_default_stderr(const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
fflush(stderr);
|
||||
}
|
||||
static void pk_default_print(const char* data) { printf("%s", data); }
|
||||
|
||||
static void pk_TypeInfo__ctor(pk_TypeInfo* self,
|
||||
py_Name name,
|
||||
@ -62,10 +48,9 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
self->builtins = *py_NIL;
|
||||
self->main = *py_NIL;
|
||||
|
||||
self->_ceval_on_step = NULL;
|
||||
self->_import_file = pk_default_import_file;
|
||||
self->_stdout = pk_default_stdout;
|
||||
self->_stderr = pk_default_stderr;
|
||||
self->ceval_on_step = NULL;
|
||||
self->import_file = pk_default_import_file;
|
||||
self->print = pk_default_print;
|
||||
|
||||
self->last_retval = *py_NIL;
|
||||
self->curr_exception = *py_NIL;
|
||||
@ -177,10 +162,10 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
"ImportError",
|
||||
"AssertionError",
|
||||
"KeyError",
|
||||
NULL, // sentinel
|
||||
NULL, // sentinel
|
||||
};
|
||||
const char** it = builtin_exceptions;
|
||||
while(*it){
|
||||
while(*it) {
|
||||
py_Type type = pk_newtype(*it, tp_Exception, &self->builtins, NULL, false, true);
|
||||
py_setdict(&self->builtins, py_name(*it), py_tpobject(type));
|
||||
it++;
|
||||
@ -278,9 +263,7 @@ bool pk__parse_int_slice(py_Ref slice, int length, int* start, int* stop, int* s
|
||||
|
||||
bool pk__normalize_index(int* index, int length) {
|
||||
if(*index < 0) *index += length;
|
||||
if(*index < 0 || *index >= length) {
|
||||
return IndexError("%d not in [0, %d)", *index, length);
|
||||
}
|
||||
if(*index < 0 || *index >= length) { return IndexError("%d not in [0, %d)", *index, length); }
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -294,9 +277,7 @@ py_Type pk_newtype(const char* name,
|
||||
py_Type index = types->count;
|
||||
pk_TypeInfo* ti = c11_vector__emplace(types);
|
||||
pk_TypeInfo__ctor(ti, py_name(name), index, base, module ? *module : *py_NIL);
|
||||
if(!dtor && base){
|
||||
dtor = c11__at(pk_TypeInfo, types, base)->dtor;
|
||||
}
|
||||
if(!dtor && base) { dtor = c11__at(pk_TypeInfo, types, base)->dtor; }
|
||||
ti->dtor = dtor;
|
||||
ti->is_python = is_python;
|
||||
ti->is_sealed = is_sealed;
|
||||
@ -577,6 +558,7 @@ void pk_ManagedHeap__mark(pk_ManagedHeap* self) {
|
||||
|
||||
void pk_print_stack(pk_VM* self, Frame* frame, Bytecode byte) {
|
||||
// return;
|
||||
if(frame == NULL) return;
|
||||
|
||||
py_TValue* sp = self->stack.sp;
|
||||
c11_sbuf buf;
|
||||
|
@ -1,59 +0,0 @@
|
||||
// #include "pocketpy/objects/error.h"
|
||||
// #include "pocketpy/common/strname.h"
|
||||
// #include "pocketpy/common/sstream.h"
|
||||
|
||||
// void pkpy_Exception__ctor(pkpy_Exception* self, py_Name type){
|
||||
// self->type = type;
|
||||
// self->is_re = true;
|
||||
// self->_ip_on_error = -1;
|
||||
// self->_code_on_error = NULL;
|
||||
// self->self = NULL;
|
||||
|
||||
// py_Str__ctor(&self->msg, "");
|
||||
// c11_vector__ctor(&self->stacktrace, sizeof(pkpy_ExceptionFrame));
|
||||
// }
|
||||
|
||||
// void pkpy_Exception__dtor(pkpy_Exception* self){
|
||||
// for(int i=0; i<self->stacktrace.count; i++){
|
||||
// pkpy_ExceptionFrame* frame = c11__at(pkpy_ExceptionFrame, &self->stacktrace, i);
|
||||
// PK_DECREF(frame->src);
|
||||
// py_Str__dtor(&frame->name);
|
||||
// }
|
||||
// py_Str__dtor(&self->msg);
|
||||
// c11_vector__dtor(&self->stacktrace);
|
||||
// }
|
||||
|
||||
// void pkpy_Exception__stpush(pkpy_Exception* self, pk_SourceData_ src, int lineno, const char* cursor, const char* name){
|
||||
// if(self->stacktrace.count >= 7) return;
|
||||
// PK_INCREF(src);
|
||||
// pkpy_ExceptionFrame* frame = c11_vector__emplace(&self->stacktrace);
|
||||
// frame->src = src;
|
||||
// frame->lineno = lineno;
|
||||
// frame->cursor = cursor;
|
||||
// py_Str__ctor(&frame->name, name);
|
||||
// }
|
||||
|
||||
// py_Str pkpy_Exception__summary(pkpy_Exception* self){
|
||||
// c11_sbuf ss;
|
||||
// c11_sbuf__ctor(&ss);
|
||||
|
||||
// if(self->is_re){
|
||||
// c11_sbuf__write_cstr(&ss, "Traceback (most recent call last):\n");
|
||||
// }
|
||||
// for(int i=self->stacktrace.count-1; i >= 0; i--) {
|
||||
// pkpy_ExceptionFrame* frame = c11__at(pkpy_ExceptionFrame, &self->stacktrace, i);
|
||||
// py_Str s = pk_SourceData__snapshot(frame->src, frame->lineno, frame->cursor, py_Str__data(&frame->name));
|
||||
// c11_sbuf__write_Str(&ss, &s);
|
||||
// py_Str__dtor(&s);
|
||||
// c11_sbuf__write_cstr(&ss, "\n");
|
||||
// }
|
||||
|
||||
// const char* name = py_Name__rmap(self->type);
|
||||
// c11_sbuf__write_cstr(&ss, name);
|
||||
|
||||
// if(self->msg.size > 0){
|
||||
// c11_sbuf__write_cstr(&ss, ": ");
|
||||
// c11_sbuf__write_Str(&ss, &self->msg);
|
||||
// }
|
||||
// return c11_sbuf__submit(&ss);
|
||||
// }
|
@ -1,69 +0,0 @@
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
bool py_checkexc() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
return !py_isnil(&vm->curr_exception);
|
||||
}
|
||||
|
||||
void py_printexc() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
if(py_isnil(&vm->curr_exception)) {
|
||||
vm->_stdout("NoneType: None\n");
|
||||
} else {
|
||||
const char* name = py_tpname(vm->curr_exception.type);
|
||||
bool ok = py_str(&vm->curr_exception);
|
||||
if(!ok) c11__abort("py_printexc(): failed to convert exception to string");
|
||||
const char* message = py_tostr(py_retval());
|
||||
vm->_stdout("%s: %s\n", name, message);
|
||||
}
|
||||
}
|
||||
|
||||
char* py_formatexc() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
if(py_isnil(&vm->curr_exception)) {
|
||||
return NULL;
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
bool py_exception(const char* name, const char* fmt, ...) {
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
pk_vsprintf(&buf, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
c11_string* res = c11_sbuf__submit(&buf);
|
||||
py_Ref message = py_pushtmp();
|
||||
py_newstrn(message, res->data, res->size);
|
||||
c11_string__delete(res);
|
||||
|
||||
py_Ref exc_type = py_getdict(&pk_current_vm->builtins, py_name(name));
|
||||
if(exc_type == NULL) c11__abort("py_exception(): '%s' not found", name);
|
||||
bool ok = py_call(exc_type, 1, message);
|
||||
if(!ok) c11__abort("py_exception(): failed to create exception object");
|
||||
py_pop();
|
||||
|
||||
return py_raise(py_retval());
|
||||
}
|
||||
|
||||
bool py_raise(py_Ref exc) {
|
||||
assert(py_isinstance(exc, tp_BaseException));
|
||||
pk_VM* vm = pk_current_vm;
|
||||
vm->curr_exception = *exc;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KeyError(py_Ref key){
|
||||
py_Ref cls = py_getdict(&pk_current_vm->builtins, py_name("KeyError"));
|
||||
bool ok = py_call(cls, 1, key);
|
||||
if(!ok) return false;
|
||||
return py_raise(py_retval());
|
||||
}
|
@ -193,7 +193,7 @@ static bool _py_builtins__print(int argc, py_Ref argv) {
|
||||
}
|
||||
c11_sbuf__write_sv(&buf, end);
|
||||
c11_string* res = c11_sbuf__submit(&buf);
|
||||
pk_current_vm->_stdout("%s", res->data);
|
||||
pk_current_vm->print(res->data);
|
||||
c11_string__delete(res);
|
||||
py_newnone(py_retval());
|
||||
return true;
|
||||
@ -204,18 +204,35 @@ static bool _py_NoneType__repr__(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_builtins__exec(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
PY_CHECK_ARG_TYPE(0, tp_str);
|
||||
bool ok = py_exec(py_tostr(argv));
|
||||
py_newnone(py_retval());
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool _py_builtins__eval(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
PY_CHECK_ARG_TYPE(0, tp_str);
|
||||
return py_eval(py_tostr(argv));
|
||||
}
|
||||
|
||||
py_TValue pk_builtins__register() {
|
||||
py_Ref builtins = py_newmodule("builtins", NULL);
|
||||
py_bindnativefunc(builtins, "repr", _py_builtins__repr);
|
||||
py_bindnativefunc(builtins, "exit", _py_builtins__exit);
|
||||
py_bindnativefunc(builtins, "len", _py_builtins__len);
|
||||
py_bindnativefunc(builtins, "reversed", _py_builtins__reversed);
|
||||
py_bindnativefunc(builtins, "hex", _py_builtins__hex);
|
||||
py_bindnativefunc(builtins, "iter", _py_builtins__iter);
|
||||
py_bindnativefunc(builtins, "next", _py_builtins__next);
|
||||
py_bindnativefunc(builtins, "hash", _py_builtins__hash);
|
||||
py_bindnativefunc(builtins, "abs", _py_builtins__abs);
|
||||
py_bindnativefunc(builtins, "sum", _py_builtins__sum);
|
||||
py_bindfunc(builtins, "repr", _py_builtins__repr);
|
||||
py_bindfunc(builtins, "exit", _py_builtins__exit);
|
||||
py_bindfunc(builtins, "len", _py_builtins__len);
|
||||
py_bindfunc(builtins, "reversed", _py_builtins__reversed);
|
||||
py_bindfunc(builtins, "hex", _py_builtins__hex);
|
||||
py_bindfunc(builtins, "iter", _py_builtins__iter);
|
||||
py_bindfunc(builtins, "next", _py_builtins__next);
|
||||
py_bindfunc(builtins, "hash", _py_builtins__hash);
|
||||
py_bindfunc(builtins, "abs", _py_builtins__abs);
|
||||
py_bindfunc(builtins, "sum", _py_builtins__sum);
|
||||
|
||||
py_bindfunc(builtins, "exec", _py_builtins__exec);
|
||||
py_bindfunc(builtins, "eval", _py_builtins__eval);
|
||||
|
||||
py_bind(builtins, "print(*args, sep=' ', end='\\n')", _py_builtins__print);
|
||||
py_bind(builtins, "sorted(iterable, key=None, reverse=False)", _py_builtins__sorted);
|
||||
|
@ -111,4 +111,91 @@ py_Type pk_BaseException__register() {
|
||||
py_Type pk_Exception__register() {
|
||||
py_Type type = pk_newtype("Exception", tp_BaseException, NULL, NULL, false, true);
|
||||
return type;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
bool py_checkexc() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
return !py_isnil(&vm->curr_exception);
|
||||
}
|
||||
|
||||
void py_printexc() {
|
||||
char* msg = py_formatexc();
|
||||
if(!msg) return;
|
||||
pk_current_vm->print(msg);
|
||||
pk_current_vm->print("\n");
|
||||
free(msg);
|
||||
}
|
||||
|
||||
char* py_formatexc() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
if(py_isnil(&vm->curr_exception)) { return NULL; }
|
||||
c11_sbuf ss;
|
||||
c11_sbuf__ctor(&ss);
|
||||
|
||||
if(true) { c11_sbuf__write_cstr(&ss, "Traceback (most recent call last):\n"); }
|
||||
|
||||
BaseException* ud = py_touserdata(&vm->curr_exception);
|
||||
|
||||
for(int i = ud->stacktrace.count - 1; i >= 0; i--) {
|
||||
BaseExceptionFrame* frame = c11__at(BaseExceptionFrame, &ud->stacktrace, i);
|
||||
pk_SourceData__snapshot(frame->src,
|
||||
&ss,
|
||||
frame->lineno,
|
||||
NULL,
|
||||
frame->name ? frame->name->data : NULL);
|
||||
c11_sbuf__write_char(&ss, '\n');
|
||||
}
|
||||
|
||||
const char* name = py_tpname(vm->curr_exception.type);
|
||||
bool ok = py_str(&vm->curr_exception);
|
||||
if(!ok) c11__abort("py_printexc(): failed to convert exception to string");
|
||||
const char* message = py_tostr(py_retval());
|
||||
|
||||
c11_sbuf__write_cstr(&ss, name);
|
||||
c11_sbuf__write_cstr(&ss, ": ");
|
||||
c11_sbuf__write_cstr(&ss, message);
|
||||
|
||||
c11_string* res = c11_sbuf__submit(&ss);
|
||||
char* dup = malloc(res->size + 1);
|
||||
memcpy(dup, res->data, res->size);
|
||||
dup[res->size] = '\0';
|
||||
c11_string__delete(res);
|
||||
return dup;
|
||||
}
|
||||
|
||||
bool py_exception(const char* name, const char* fmt, ...) {
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
pk_vsprintf(&buf, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
c11_string* res = c11_sbuf__submit(&buf);
|
||||
py_Ref message = py_pushtmp();
|
||||
py_newstrn(message, res->data, res->size);
|
||||
c11_string__delete(res);
|
||||
|
||||
py_Ref exc_type = py_getdict(&pk_current_vm->builtins, py_name(name));
|
||||
if(exc_type == NULL) c11__abort("py_exception(): '%s' not found", name);
|
||||
bool ok = py_call(exc_type, 1, message);
|
||||
if(!ok) c11__abort("py_exception(): failed to create exception object");
|
||||
py_pop();
|
||||
|
||||
return py_raise(py_retval());
|
||||
}
|
||||
|
||||
bool py_raise(py_Ref exc) {
|
||||
assert(py_isinstance(exc, tp_BaseException));
|
||||
pk_VM* vm = pk_current_vm;
|
||||
vm->curr_exception = *exc;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KeyError(py_Ref key) {
|
||||
py_Ref cls = py_getdict(&pk_current_vm->builtins, py_name("KeyError"));
|
||||
bool ok = py_call(cls, 1, key);
|
||||
if(!ok) return false;
|
||||
return py_raise(py_retval());
|
||||
}
|
@ -58,7 +58,7 @@ void py_bindmethod2(py_Type type, const char* name, py_CFunction f, enum BindTyp
|
||||
py_setdict(py_tpobject(type), py_name(name), &tmp);
|
||||
}
|
||||
|
||||
void py_bindnativefunc(py_Ref obj, const char* name, py_CFunction f) {
|
||||
void py_bindfunc(py_Ref obj, const char* name, py_CFunction f) {
|
||||
py_TValue tmp;
|
||||
py_newnativefunc(&tmp, f);
|
||||
py_setdict(obj, py_name(name), &tmp);
|
||||
|
@ -168,7 +168,8 @@ static void disassemble(CodeObject* co) {
|
||||
}
|
||||
|
||||
c11_string* output = c11_sbuf__submit(&ss);
|
||||
pk_current_vm->_stdout("%s\n", output->data);
|
||||
pk_current_vm->print(output->data);
|
||||
pk_current_vm->print("\n");
|
||||
c11_string__delete(output);
|
||||
c11_vector__dtor(&jumpTargets);
|
||||
}
|
||||
@ -179,7 +180,11 @@ static bool
|
||||
pk_SourceData_ src = pk_SourceData__rcnew(source, filename, mode, false);
|
||||
Error* err = pk_compile(src, &co);
|
||||
if(err) {
|
||||
py_exception("SyntaxError", err->msg);
|
||||
py_BaseException__stpush(&vm->curr_exception, src, err->lineno, NULL);
|
||||
|
||||
PK_DECREF(src);
|
||||
free(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user