mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-21 12:00:18 +00:00
...
This commit is contained in:
parent
2165e29c4f
commit
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/str.h"
|
||||||
#include "pocketpy/common/vector.h"
|
#include "pocketpy/common/vector.h"
|
||||||
#include "pocketpy/objects/sourcedata.h"
|
#include "pocketpy/objects/sourcedata.h"
|
||||||
|
#include "pocketpy/objects/error.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -87,8 +88,6 @@ enum Precedence {
|
|||||||
PREC_HIGHEST,
|
PREC_HIGHEST,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Error Error;
|
|
||||||
|
|
||||||
typedef c11_array pk_TokenArray;
|
typedef c11_array pk_TokenArray;
|
||||||
|
|
||||||
Error* pk_Lexer__process(pk_SourceData_ src, pk_TokenArray* out_tokens);
|
Error* pk_Lexer__process(pk_SourceData_ src, pk_TokenArray* out_tokens);
|
||||||
|
@ -11,14 +11,11 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct Error{
|
typedef struct{
|
||||||
const char* type;
|
|
||||||
pk_SourceData_ src;
|
pk_SourceData_ src;
|
||||||
int lineno;
|
int lineno;
|
||||||
const char* cursor;
|
|
||||||
char msg[100];
|
char msg[100];
|
||||||
int64_t userdata;
|
} Error;
|
||||||
};
|
|
||||||
|
|
||||||
void py_BaseException__set_lineno(py_Ref, int lineno, const CodeObject* code);
|
void py_BaseException__set_lineno(py_Ref, int lineno, const CodeObject* code);
|
||||||
int py_BaseException__get_lineno(py_Ref, const CodeObject* code);
|
int py_BaseException__get_lineno(py_Ref, const CodeObject* code);
|
||||||
|
@ -3,31 +3,41 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "pocketpy/pocketpy.h"
|
#include "pocketpy/pocketpy.h"
|
||||||
#include "pocketpy/common/str.h"
|
#include "pocketpy/common/str.h"
|
||||||
|
#include "pocketpy/common/sstream.h"
|
||||||
#include "pocketpy/common/vector.h"
|
#include "pocketpy/common/vector.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct pk_SourceData {
|
struct pk_SourceData {
|
||||||
RefCounted rc;
|
RefCounted rc;
|
||||||
enum py_CompileMode mode;
|
enum py_CompileMode mode;
|
||||||
bool is_precompiled;
|
bool is_precompiled;
|
||||||
bool is_dynamic; // for exec() and eval()
|
bool is_dynamic; // for exec() and eval()
|
||||||
|
|
||||||
c11_string* filename;
|
c11_string* filename;
|
||||||
c11_string* source;
|
c11_string* source;
|
||||||
|
|
||||||
c11_vector/*T=const char* */ line_starts;
|
c11_vector /*T=const char* */ line_starts;
|
||||||
c11_vector/*T=c11_string* */ _precompiled_tokens;
|
c11_vector /*T=c11_string* */ _precompiled_tokens;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct pk_SourceData* pk_SourceData_;
|
typedef struct pk_SourceData* pk_SourceData_;
|
||||||
|
|
||||||
pk_SourceData_ pk_SourceData__rcnew(const char* source, const char* filename, enum py_CompileMode mode, bool is_dynamic);
|
pk_SourceData_ pk_SourceData__rcnew(const char* source,
|
||||||
bool pk_SourceData__get_line(const struct pk_SourceData* self, int lineno, const char** st, const char** ed);
|
const char* filename,
|
||||||
c11_string* pk_SourceData__snapshot(const struct pk_SourceData *self, int lineno, const char *cursor, const char *name);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,7 @@ py_ObjectRef py_bind2(py_Ref obj,
|
|||||||
// old style argc-based bindings
|
// old style argc-based bindings
|
||||||
void py_bindmethod(py_Type type, const char* name, py_CFunction f);
|
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_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.
|
/// Get the reference to the i-th register.
|
||||||
/// All registers are located in a contiguous memory.
|
/// All registers are located in a contiguous memory.
|
||||||
|
@ -71,41 +71,38 @@ bool pk_SourceData__get_line(const struct pk_SourceData* self,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
c11_string* pk_SourceData__snapshot(const struct pk_SourceData* self,
|
void pk_SourceData__snapshot(const struct pk_SourceData* self,
|
||||||
int lineno,
|
c11_sbuf* ss,
|
||||||
const char* cursor,
|
int lineno,
|
||||||
const char* name) {
|
const char* cursor,
|
||||||
c11_sbuf ss;
|
const char* name) {
|
||||||
c11_sbuf__ctor(&ss);
|
pk_sprintf(ss, " File \"%s\", line %d", self->filename->data, lineno);
|
||||||
|
|
||||||
pk_sprintf(&ss, " File \"%s\", line %d", self->filename->data, lineno);
|
|
||||||
|
|
||||||
if(name && *name) {
|
if(name && *name) {
|
||||||
c11_sbuf__write_cstr(&ss, ", in ");
|
c11_sbuf__write_cstr(ss, ", in ");
|
||||||
c11_sbuf__write_cstr(&ss, name);
|
c11_sbuf__write_cstr(ss, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!self->is_precompiled) {
|
if(!self->is_precompiled) {
|
||||||
c11_sbuf__write_char(&ss, '\n');
|
c11_sbuf__write_char(ss, '\n');
|
||||||
const char *st = NULL, *ed;
|
const char *st = NULL, *ed;
|
||||||
if(pk_SourceData__get_line(self, lineno, &st, &ed)) {
|
if(pk_SourceData__get_line(self, lineno, &st, &ed)) {
|
||||||
while(st < ed && isblank(*st))
|
while(st < ed && isblank(*st))
|
||||||
++st;
|
++st;
|
||||||
if(st < ed) {
|
if(st < ed) {
|
||||||
c11_sbuf__write_cstr(&ss, " ");
|
c11_sbuf__write_cstr(ss, " ");
|
||||||
c11_sbuf__write_cstrn(&ss, st, ed - st);
|
c11_sbuf__write_cstrn(ss, st, ed - st);
|
||||||
if(cursor && st <= cursor && cursor <= ed) {
|
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)
|
for(int i = 0; i < (cursor - st); ++i)
|
||||||
c11_sbuf__write_char(&ss, ' ');
|
c11_sbuf__write_char(ss, ' ');
|
||||||
c11_sbuf__write_cstr(&ss, "^");
|
c11_sbuf__write_cstr(ss, "^");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
st = NULL;
|
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) {
|
static void Compiler__dtor(Compiler* self) {
|
||||||
pk_TokenArray__dtor(&self->tokens);
|
pk_TokenArray__dtor(&self->tokens);
|
||||||
|
c11__foreach(Ctx, &self->contexts, ctx) Ctx__dtor(ctx);
|
||||||
c11_vector__dtor(&self->contexts);
|
c11_vector__dtor(&self->contexts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1458,7 +1459,6 @@ static void Compiler__dtor(Compiler* self) {
|
|||||||
#define prev() tk(self->i - 1)
|
#define prev() tk(self->i - 1)
|
||||||
#define curr() tk(self->i)
|
#define curr() tk(self->i)
|
||||||
#define next() tk(self->i + 1)
|
#define next() tk(self->i + 1)
|
||||||
// #define err() (self->i == self->tokens.count ? prev() : curr())
|
|
||||||
|
|
||||||
#define advance() self->i++
|
#define advance() self->i++
|
||||||
#define mode() self->src->mode
|
#define mode() self->src->mode
|
||||||
@ -1468,11 +1468,12 @@ static void Compiler__dtor(Compiler* self) {
|
|||||||
|
|
||||||
#define consume(expected) \
|
#define consume(expected) \
|
||||||
if(!match(expected)) \
|
if(!match(expected)) \
|
||||||
return SyntaxError("expected '%s', got '%s'", \
|
return SyntaxError(self, \
|
||||||
|
"expected '%s', got '%s'", \
|
||||||
pk_TokenSymbols[expected], \
|
pk_TokenSymbols[expected], \
|
||||||
pk_TokenSymbols[curr()->type]);
|
pk_TokenSymbols[curr()->type]);
|
||||||
#define consume_end_stmt() \
|
#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) \
|
#define check(B) \
|
||||||
if((err = B)) return err
|
if((err = B)) return err
|
||||||
@ -1483,9 +1484,17 @@ static NameScope name_scope(Compiler* self) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* SyntaxError(const char* fmt, ...) {
|
Error* SyntaxError(Compiler* self, const char* fmt, ...) {
|
||||||
c11__abort("%s", fmt);
|
Error* err = malloc(sizeof(Error));
|
||||||
return NULL;
|
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 */
|
/* Matchers */
|
||||||
@ -1522,7 +1531,7 @@ static bool match_end_stmt(Compiler* self) {
|
|||||||
static Error* parse_expression(Compiler* self, int precedence, bool allow_slice) {
|
static Error* parse_expression(Compiler* self, int precedence, bool allow_slice) {
|
||||||
PrattCallback prefix = rules[curr()->type].prefix;
|
PrattCallback prefix = rules[curr()->type].prefix;
|
||||||
if(!prefix || (curr()->type == TK_COLON && !allow_slice)) {
|
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();
|
advance();
|
||||||
Error* err;
|
Error* err;
|
||||||
@ -1612,9 +1621,11 @@ static Error* pop_context(Compiler* self) {
|
|||||||
// some check here
|
// some check here
|
||||||
c11_vector* codes = &co->codes;
|
c11_vector* codes = &co->codes;
|
||||||
if(co->nlocals > PK_MAX_CO_VARNAMES) {
|
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
|
// pre-compute LOOP_BREAK and LOOP_CONTINUE
|
||||||
for(int i = 0; i < codes->count; i++) {
|
for(int i = 0; i < codes->count; i++) {
|
||||||
Bytecode* bc = c11__at(Bytecode, codes, i);
|
Bytecode* bc = c11__at(Bytecode, codes, i);
|
||||||
@ -1635,7 +1646,8 @@ static Error* pop_context(Compiler* self) {
|
|||||||
func->type = FuncType_GENERATOR;
|
func->type = FuncType_GENERATOR;
|
||||||
c11__foreach(Bytecode, &func->code.codes, bc) {
|
c11__foreach(Bytecode, &func->code.codes, bc) {
|
||||||
if(bc->op == OP_RETURN_VALUE && bc->arg == BC_NOARG) {
|
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;
|
break;
|
||||||
@ -1962,7 +1974,7 @@ static Error* exprCall(Compiler* self) {
|
|||||||
} else {
|
} else {
|
||||||
// positional argument
|
// positional argument
|
||||||
if(e->kwargs.count > 0) {
|
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()));
|
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();
|
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);
|
consume(TK_INDENT);
|
||||||
while(curr()->type != TK_DEDENT) {
|
while(curr()->type != TK_DEDENT) {
|
||||||
@ -2119,7 +2131,7 @@ static Error* compile_for_loop(Compiler* self) {
|
|||||||
vtdelete(vars);
|
vtdelete(vars);
|
||||||
if(!ok) {
|
if(!ok) {
|
||||||
// this error occurs in `vars` instead of this line, but...nevermind
|
// 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));
|
check(compile_block_body(self, compile_stmt));
|
||||||
Ctx__emit_virtual(ctx(), OP_LOOP_CONTINUE, Ctx__get_loop(ctx()), BC_KEEPLINE, true);
|
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_IOR:
|
||||||
case TK_IXOR: {
|
case TK_IXOR: {
|
||||||
if(Ctx__s_top(ctx())->vt->is_starred)
|
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)
|
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();
|
advance();
|
||||||
// a[x] += 1; a and x should be evaluated only once
|
// a[x] += 1; a and x should be evaluated only once
|
||||||
// a.x += 1; a 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]
|
// [lhs]
|
||||||
check(EXPR_TUPLE(self)); // [lhs, rhs]
|
check(EXPR_TUPLE(self)); // [lhs, rhs]
|
||||||
if(Ctx__s_top(ctx())->vt->is_starred)
|
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);
|
BinaryExpr* e = BinaryExpr__new(line, op, true);
|
||||||
e->rhs = Ctx__s_popx(ctx()); // [lhs]
|
e->rhs = Ctx__s_popx(ctx()); // [lhs]
|
||||||
e->lhs = Ctx__s_popx(ctx()); // []
|
e->lhs = Ctx__s_popx(ctx()); // []
|
||||||
vtemit_((Expr*)e, ctx());
|
vtemit_((Expr*)e, ctx());
|
||||||
bool ok = vtemit_istore(e->lhs, ctx());
|
bool ok = vtemit_istore(e->lhs, ctx());
|
||||||
vtdelete((Expr*)e);
|
vtdelete((Expr*)e);
|
||||||
if(!ok) return SyntaxError("invalid syntax");
|
if(!ok) return SyntaxError(self, "invalid syntax");
|
||||||
*is_assign = true;
|
*is_assign = true;
|
||||||
return NULL;
|
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);
|
Ctx__emit_(ctx(), OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||||
for(int j = 0; j < n; j++) {
|
for(int j = 0; j < n; j++) {
|
||||||
if(Ctx__s_top(ctx())->vt->is_starred)
|
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());
|
Expr* e = Ctx__s_top(ctx());
|
||||||
bool ok = vtemit_store(e, ctx());
|
bool ok = vtemit_store(e, ctx());
|
||||||
Ctx__s_pop(ctx());
|
Ctx__s_pop(ctx());
|
||||||
if(!ok) return SyntaxError("invalid syntax");
|
if(!ok) return SyntaxError(self, "invalid syntax");
|
||||||
}
|
}
|
||||||
*is_assign = true;
|
*is_assign = true;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -2239,7 +2251,8 @@ static Error* read_literal(Compiler* self, py_Ref out) {
|
|||||||
py_TValue cpnts[4];
|
py_TValue cpnts[4];
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while(true) {
|
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]));
|
check(read_literal(self, &cpnts[count]));
|
||||||
count += 1;
|
count += 1;
|
||||||
if(curr()->type == TK_RPAREN) break;
|
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
|
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
|
||||||
Error* err;
|
Error* err;
|
||||||
do {
|
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();
|
match_newlines();
|
||||||
if(match(TK_MUL)) {
|
if(match(TK_MUL)) {
|
||||||
if(state < 1)
|
if(state < 1)
|
||||||
state = 1;
|
state = 1;
|
||||||
else
|
else
|
||||||
return SyntaxError("*args should be placed before **kwargs");
|
return SyntaxError(self, "*args should be placed before **kwargs");
|
||||||
} else if(match(TK_POW)) {
|
} else if(match(TK_POW)) {
|
||||||
state = 3;
|
state = 3;
|
||||||
}
|
}
|
||||||
@ -2276,7 +2289,7 @@ static Error* _compile_f_args(Compiler* self, FuncDecl* decl, bool enable_type_h
|
|||||||
|
|
||||||
// check duplicate argument name
|
// check duplicate argument name
|
||||||
if(FuncDecl__is_duplicated_arg(decl, name)) {
|
if(FuncDecl__is_duplicated_arg(decl, name)) {
|
||||||
return SyntaxError("duplicate argument name");
|
return SyntaxError(self, "duplicate argument name");
|
||||||
}
|
}
|
||||||
|
|
||||||
// eat type hints
|
// eat type hints
|
||||||
@ -2292,7 +2305,7 @@ static Error* _compile_f_args(Compiler* self, FuncDecl* decl, bool enable_type_h
|
|||||||
consume(TK_ASSIGN);
|
consume(TK_ASSIGN);
|
||||||
py_TValue value;
|
py_TValue value;
|
||||||
check(read_literal(self, &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);
|
FuncDecl__add_kwarg(decl, name, &value);
|
||||||
} break;
|
} break;
|
||||||
case 3:
|
case 3:
|
||||||
@ -2367,7 +2380,7 @@ static Error* compile_class(Compiler* self, int decorators) {
|
|||||||
Ctx__emit_(ctx(), OP_BEGIN_CLASS, name, BC_KEEPLINE);
|
Ctx__emit_(ctx(), OP_BEGIN_CLASS, name, BC_KEEPLINE);
|
||||||
|
|
||||||
c11__foreach(Ctx, &self->contexts, it) {
|
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;
|
ctx()->is_compiling_class = true;
|
||||||
check(compile_block_body(self, compile_stmt));
|
check(compile_block_body(self, compile_stmt));
|
||||||
@ -2384,7 +2397,7 @@ static Error* compile_decorated(Compiler* self) {
|
|||||||
do {
|
do {
|
||||||
check(EXPR(self));
|
check(EXPR(self));
|
||||||
count += 1;
|
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));
|
} while(match(TK_DECORATOR));
|
||||||
|
|
||||||
if(match(TK_CLASS)) {
|
if(match(TK_CLASS)) {
|
||||||
@ -2468,7 +2481,7 @@ __EAT_DOTS_END:
|
|||||||
|
|
||||||
if(match(TK_MUL)) {
|
if(match(TK_MUL)) {
|
||||||
if(name_scope(self) != NAME_GLOBAL)
|
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__
|
// pop the module and import __all__
|
||||||
Ctx__emit_(ctx(), OP_POP_IMPORT_STAR, BC_NOARG, prev()->line);
|
Ctx__emit_(ctx(), OP_POP_IMPORT_STAR, BC_NOARG, prev()->line);
|
||||||
consume_end_stmt();
|
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);
|
patches[patches_length++] = Ctx__emit_(ctx(), OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE);
|
||||||
Ctx__exit_block(ctx());
|
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 {
|
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;
|
py_Name as_name = 0;
|
||||||
consume(TK_EXCEPT);
|
consume(TK_EXCEPT);
|
||||||
if(is_expression(self, false)) {
|
if(is_expression(self, false)) {
|
||||||
@ -2553,24 +2570,24 @@ static Error* compile_stmt(Compiler* self) {
|
|||||||
int curr_loop_block = Ctx__get_loop(ctx());
|
int curr_loop_block = Ctx__get_loop(ctx());
|
||||||
switch(prev()->type) {
|
switch(prev()->type) {
|
||||||
case TK_BREAK:
|
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);
|
Ctx__emit_(ctx(), OP_LOOP_BREAK, curr_loop_block, kw_line);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
case TK_CONTINUE:
|
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);
|
Ctx__emit_(ctx(), OP_LOOP_CONTINUE, curr_loop_block, kw_line);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
case TK_YIELD:
|
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));
|
check(EXPR_TUPLE(self));
|
||||||
Ctx__s_emit_top(ctx());
|
Ctx__s_emit_top(ctx());
|
||||||
Ctx__emit_(ctx(), OP_YIELD_VALUE, BC_NOARG, kw_line);
|
Ctx__emit_(ctx(), OP_YIELD_VALUE, BC_NOARG, kw_line);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
case TK_YIELD_FROM:
|
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));
|
check(EXPR_TUPLE(self));
|
||||||
Ctx__s_emit_top(ctx());
|
Ctx__s_emit_top(ctx());
|
||||||
Ctx__emit_(ctx(), OP_GET_ITER, BC_NOARG, kw_line);
|
Ctx__emit_(ctx(), OP_GET_ITER, BC_NOARG, kw_line);
|
||||||
@ -2582,7 +2599,7 @@ static Error* compile_stmt(Compiler* self) {
|
|||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
case TK_RETURN:
|
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)) {
|
if(match_end_stmt(self)) {
|
||||||
Ctx__emit_(ctx(), OP_RETURN_VALUE, 1, kw_line);
|
Ctx__emit_(ctx(), OP_RETURN_VALUE, 1, kw_line);
|
||||||
} else {
|
} else {
|
||||||
@ -2642,7 +2659,7 @@ static Error* compile_stmt(Compiler* self) {
|
|||||||
case TK_DEL: {
|
case TK_DEL: {
|
||||||
check(EXPR_TUPLE(self));
|
check(EXPR_TUPLE(self));
|
||||||
Expr* e = Ctx__s_top(ctx());
|
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());
|
Ctx__s_pop(ctx());
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
} break;
|
} break;
|
||||||
@ -2660,7 +2677,7 @@ static Error* compile_stmt(Compiler* self) {
|
|||||||
// if(as_name) {
|
// if(as_name) {
|
||||||
// bool ok = as_name->emit_store(ctx());
|
// bool ok = as_name->emit_store(ctx());
|
||||||
// delete_expr(as_name);
|
// delete_expr(as_name);
|
||||||
// if(!ok) return SyntaxError();
|
// if(!ok) return SyntaxError(self, );
|
||||||
// } else {
|
// } else {
|
||||||
// Ctx__emit_(ctx(), OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
// Ctx__emit_(ctx(), OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||||
// }
|
// }
|
||||||
@ -2671,16 +2688,18 @@ static Error* compile_stmt(Compiler* self) {
|
|||||||
/*************************************************/
|
/*************************************************/
|
||||||
case TK_EQ: {
|
case TK_EQ: {
|
||||||
consume(TK_ID);
|
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());
|
c11_sv name = Token__sv(prev());
|
||||||
bool ok = Ctx__add_label(ctx(), py_namev(name));
|
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(TK_EQ);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
} break;
|
} break;
|
||||||
case TK_ARROW:
|
case TK_ARROW:
|
||||||
consume(TK_ID);
|
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()));
|
py_Name name = py_namev(Token__sv(prev()));
|
||||||
Ctx__emit_(ctx(), OP_GOTO, name, prev()->line);
|
Ctx__emit_(ctx(), OP_GOTO, name, prev()->line);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
@ -2710,7 +2729,7 @@ static Error* compile_stmt(Compiler* self) {
|
|||||||
check(try_compile_assignment(self, &is_assign));
|
check(try_compile_assignment(self, &is_assign));
|
||||||
if(!is_assign) {
|
if(!is_assign) {
|
||||||
if(Ctx__s_size(ctx()) > 0 && Ctx__s_top(ctx())->vt->is_starred) {
|
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) {
|
if(!is_typed_name) {
|
||||||
Ctx__s_emit_top(ctx());
|
Ctx__s_emit_top(ctx());
|
||||||
|
@ -192,13 +192,19 @@ static bool is_possible_number_char(char c){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/******************************/
|
/******************************/
|
||||||
static Error* SyntaxError(const char* fmt, ...){
|
static Error* SyntaxError(pk_Lexer* self, const char* fmt, ...){
|
||||||
// va_list args;
|
Error* err = malloc(sizeof(Error));
|
||||||
// va_start(args, fmt);
|
err->src = self->src;
|
||||||
// Error* err = _error(true, "SyntaxError", fmt, &args);
|
PK_INCREF(self->src);
|
||||||
// va_end(args);
|
err->lineno = self->current_line;
|
||||||
// return err;
|
if(*self->curr_char == '\n') {
|
||||||
return NULL;
|
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){
|
static Error* eat_name(pk_Lexer* self){
|
||||||
@ -206,7 +212,7 @@ static Error* eat_name(pk_Lexer* self){
|
|||||||
while(true) {
|
while(true) {
|
||||||
unsigned char c = *self->curr_char;
|
unsigned char c = *self->curr_char;
|
||||||
int u8bytes = c11__u8_header(c, true);
|
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(u8bytes == 1) {
|
||||||
if(isalnum(c) || c == '_') {
|
if(isalnum(c) || c == '_') {
|
||||||
self->curr_char++;
|
self->curr_char++;
|
||||||
@ -238,7 +244,7 @@ static Error* eat_name(pk_Lexer* self){
|
|||||||
}
|
}
|
||||||
|
|
||||||
int length = (int)(self->curr_char - self->token_start);
|
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};
|
c11_sv name = {self->token_start, length};
|
||||||
|
|
||||||
const char** KW_BEGIN = pk_TokenSymbols + TK_FALSE;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
if(c == '\0') {
|
if(c == '\0') {
|
||||||
return SyntaxError("EOL while scanning string literal");
|
return SyntaxError(self, "EOL while scanning string literal");
|
||||||
}
|
}
|
||||||
if(c == '\n') {
|
if(c == '\n') {
|
||||||
if(!quote3)
|
if(!quote3)
|
||||||
return SyntaxError("EOL while scanning string literal");
|
return SyntaxError(self, "EOL while scanning string literal");
|
||||||
else {
|
else {
|
||||||
c11_sbuf__write_char(&buff, c);
|
c11_sbuf__write_char(&buff, c);
|
||||||
continue;
|
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'};
|
char hex[3] = {eatchar(self), eatchar(self), '\0'};
|
||||||
int code;
|
int code;
|
||||||
if(sscanf(hex, "%x", &code) != 1) {
|
if(sscanf(hex, "%x", &code) != 1) {
|
||||||
return SyntaxError("invalid hex char");
|
return SyntaxError(self, "invalid hex char");
|
||||||
}
|
}
|
||||||
c11_sbuf__write_char(&buff, (char)code);
|
c11_sbuf__write_char(&buff, (char)code);
|
||||||
} break;
|
} break;
|
||||||
default: return SyntaxError("invalid escape char");
|
default: return SyntaxError(self, "invalid escape char");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c11_sbuf__write_char(&buff, c);
|
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);
|
add_token_with_value(self, TK_NUM, value);
|
||||||
return NULL;
|
return NULL;
|
||||||
case IntParsing_OVERFLOW:
|
case IntParsing_OVERFLOW:
|
||||||
return SyntaxError("int literal is too large");
|
return SyntaxError(self, "int literal is too large");
|
||||||
case IntParsing_FAILURE:
|
case IntParsing_FAILURE:
|
||||||
break; // do nothing
|
break; // do nothing
|
||||||
}
|
}
|
||||||
@ -380,7 +386,7 @@ static Error* eat_number(pk_Lexer* self){
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SyntaxError("invalid number literal");
|
return SyntaxError(self, "invalid number literal");
|
||||||
}
|
}
|
||||||
|
|
||||||
static Error* lex_one_token(pk_Lexer* self, bool* eof){
|
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
|
// line continuation character
|
||||||
char c = eatchar_include_newline(self);
|
char c = eatchar_include_newline(self);
|
||||||
if(c != '\n') {
|
if(c != '\n') {
|
||||||
return SyntaxError("expected newline after line continuation character");
|
return SyntaxError(self, "expected newline after line continuation character");
|
||||||
}
|
}
|
||||||
eat_spaces(self);
|
eat_spaces(self);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -471,7 +477,7 @@ static Error* lex_one_token(pk_Lexer* self, bool* eof){
|
|||||||
if(matchchar(self, '=')){
|
if(matchchar(self, '=')){
|
||||||
add_token(self, TK_NE);
|
add_token(self, TK_NE);
|
||||||
}else{
|
}else{
|
||||||
Error* err = SyntaxError("expected '=' after '!'");
|
Error* err = SyntaxError(self, "expected '=' after '!'");
|
||||||
if(err) return err;
|
if(err) return err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -494,7 +500,7 @@ static Error* lex_one_token(pk_Lexer* self, bool* eof){
|
|||||||
case '\n': {
|
case '\n': {
|
||||||
add_token(self, TK_EOL);
|
add_token(self, TK_EOL);
|
||||||
if(!eat_indentation(self)){
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -534,10 +540,10 @@ static Error* from_precompiled(pk_Lexer* self) {
|
|||||||
c11_sv version = TokenDeserializer__read_string(&deserializer, '\n');
|
c11_sv version = TokenDeserializer__read_string(&deserializer, '\n');
|
||||||
|
|
||||||
if(c11_sv__cmp2(version, PK_VERSION) != 0) {
|
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){
|
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);
|
int count = TokenDeserializer__read_count(&deserializer);
|
||||||
|
@ -577,6 +577,7 @@ void pk_ManagedHeap__mark(pk_ManagedHeap* self) {
|
|||||||
|
|
||||||
void pk_print_stack(pk_VM* self, Frame* frame, Bytecode byte) {
|
void pk_print_stack(pk_VM* self, Frame* frame, Bytecode byte) {
|
||||||
// return;
|
// return;
|
||||||
|
if(frame == NULL) return;
|
||||||
|
|
||||||
py_TValue* sp = self->stack.sp;
|
py_TValue* sp = self->stack.sp;
|
||||||
c11_sbuf buf;
|
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());
|
|
||||||
}
|
|
@ -204,18 +204,35 @@ static bool _py_NoneType__repr__(int argc, py_Ref argv) {
|
|||||||
return true;
|
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_TValue pk_builtins__register() {
|
||||||
py_Ref builtins = py_newmodule("builtins", NULL);
|
py_Ref builtins = py_newmodule("builtins", NULL);
|
||||||
py_bindnativefunc(builtins, "repr", _py_builtins__repr);
|
py_bindfunc(builtins, "repr", _py_builtins__repr);
|
||||||
py_bindnativefunc(builtins, "exit", _py_builtins__exit);
|
py_bindfunc(builtins, "exit", _py_builtins__exit);
|
||||||
py_bindnativefunc(builtins, "len", _py_builtins__len);
|
py_bindfunc(builtins, "len", _py_builtins__len);
|
||||||
py_bindnativefunc(builtins, "reversed", _py_builtins__reversed);
|
py_bindfunc(builtins, "reversed", _py_builtins__reversed);
|
||||||
py_bindnativefunc(builtins, "hex", _py_builtins__hex);
|
py_bindfunc(builtins, "hex", _py_builtins__hex);
|
||||||
py_bindnativefunc(builtins, "iter", _py_builtins__iter);
|
py_bindfunc(builtins, "iter", _py_builtins__iter);
|
||||||
py_bindnativefunc(builtins, "next", _py_builtins__next);
|
py_bindfunc(builtins, "next", _py_builtins__next);
|
||||||
py_bindnativefunc(builtins, "hash", _py_builtins__hash);
|
py_bindfunc(builtins, "hash", _py_builtins__hash);
|
||||||
py_bindnativefunc(builtins, "abs", _py_builtins__abs);
|
py_bindfunc(builtins, "abs", _py_builtins__abs);
|
||||||
py_bindnativefunc(builtins, "sum", _py_builtins__sum);
|
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, "print(*args, sep=' ', end='\\n')", _py_builtins__print);
|
||||||
py_bind(builtins, "sorted(iterable, key=None, reverse=False)", _py_builtins__sorted);
|
py_bind(builtins, "sorted(iterable, key=None, reverse=False)", _py_builtins__sorted);
|
||||||
|
@ -111,4 +111,90 @@ py_Type pk_BaseException__register() {
|
|||||||
py_Type pk_Exception__register() {
|
py_Type pk_Exception__register() {
|
||||||
py_Type type = pk_newtype("Exception", tp_BaseException, NULL, NULL, false, true);
|
py_Type type = pk_newtype("Exception", tp_BaseException, NULL, NULL, false, true);
|
||||||
return type;
|
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->_stdout("%s\n", msg);
|
||||||
|
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);
|
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_TValue tmp;
|
||||||
py_newnativefunc(&tmp, f);
|
py_newnativefunc(&tmp, f);
|
||||||
py_setdict(obj, py_name(name), &tmp);
|
py_setdict(obj, py_name(name), &tmp);
|
||||||
|
@ -179,7 +179,11 @@ static bool
|
|||||||
pk_SourceData_ src = pk_SourceData__rcnew(source, filename, mode, false);
|
pk_SourceData_ src = pk_SourceData__rcnew(source, filename, mode, false);
|
||||||
Error* err = pk_compile(src, &co);
|
Error* err = pk_compile(src, &co);
|
||||||
if(err) {
|
if(err) {
|
||||||
|
py_exception("SyntaxError", err->msg);
|
||||||
|
py_BaseException__stpush(&vm->curr_exception, src, err->lineno, NULL);
|
||||||
|
|
||||||
PK_DECREF(src);
|
PK_DECREF(src);
|
||||||
|
free(err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user