Compare commits

...

3 Commits

Author SHA1 Message Date
blueloveTH
db0acc854c ... 2024-07-30 12:24:47 +08:00
blueloveTH
1bbba50003 ... 2024-07-30 12:15:50 +08:00
blueloveTH
ec30ba9d02 ... 2024-07-30 12:14:07 +08:00
19 changed files with 257 additions and 816 deletions

View File

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

View File

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

View File

@ -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')]

View File

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

View File

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

View File

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

View File

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

View File

@ -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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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