mirror of
https://github.com/pocketpy/pocketpy
synced 2025-12-10 12:10:16 +00:00
Compare commits
4 Commits
2d5e515ae7
...
47d2310dc8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47d2310dc8 | ||
|
|
24d4807fef | ||
|
|
46e92166d5 | ||
|
|
f9d6321a09 |
@ -10,6 +10,10 @@
|
||||
// 1. __eq__ and __ne__ fallbacks
|
||||
// 2. un-cleared exception detection
|
||||
// 3. super()
|
||||
// 4. stack balance guanrantee
|
||||
// 5. stack effect of each opcode
|
||||
// 6. py_TypeInfo
|
||||
// 7. Direct assignment of py_NIL, py_True, py_False, py_None. They are slow.
|
||||
|
||||
typedef struct py_TypeInfo {
|
||||
py_Name name;
|
||||
@ -41,9 +45,7 @@ typedef struct VM {
|
||||
py_TValue builtins; // builtins module
|
||||
py_TValue main; // __main__ module
|
||||
|
||||
void (*ceval_on_step)(Frame*, Bytecode);
|
||||
char* (*import_file)(const char*);
|
||||
void (*print)(const char*);
|
||||
py_Callbacks callbacks;
|
||||
|
||||
py_TValue last_retval;
|
||||
py_TValue curr_exception;
|
||||
|
||||
@ -120,15 +120,6 @@ void FuncDecl__add_arg(FuncDecl* self, py_Name name);
|
||||
void FuncDecl__add_kwarg(FuncDecl* self, py_Name name, const py_TValue* value);
|
||||
void FuncDecl__add_starred_arg(FuncDecl* self, py_Name name);
|
||||
void FuncDecl__add_starred_kwarg(FuncDecl* self, py_Name name);
|
||||
FuncDecl_ FuncDecl__build(c11_sv name,
|
||||
c11_sv* args,
|
||||
int argc,
|
||||
c11_sv starred_arg,
|
||||
c11_sv* kwargs,
|
||||
int kwargc,
|
||||
py_Ref kwdefaults, // a tuple contains default values
|
||||
c11_sv starred_kwarg,
|
||||
const char* docstring);
|
||||
|
||||
// runtime function
|
||||
typedef struct Function {
|
||||
|
||||
@ -34,6 +34,14 @@ typedef struct c11_sv {
|
||||
int size;
|
||||
} c11_sv;
|
||||
|
||||
/// A struct contains the callbacks of the VM.
|
||||
typedef struct py_Callbacks {
|
||||
/// Used by `__import__` to load source code of a module.
|
||||
char* (*importfile)(const char*);
|
||||
/// Used by `print` to output a string.
|
||||
void (*print)(const char*);
|
||||
} py_Callbacks;
|
||||
|
||||
#define PY_RAISE
|
||||
#define PY_RETURN
|
||||
|
||||
@ -84,6 +92,8 @@ PK_EXPORT int py_currentvm();
|
||||
PK_EXPORT void py_switchvm(int index);
|
||||
/// Set `sys.argv`. Used for storing command-line arguments.
|
||||
PK_EXPORT void py_sys_setargv(int argc, char** argv);
|
||||
/// Setup the callbacks for the current VM.
|
||||
PK_EXPORT py_Callbacks* py_callbacks();
|
||||
|
||||
/// Run a source string.
|
||||
/// @param source source string.
|
||||
|
||||
@ -2212,9 +2212,9 @@ static Error* _compile_f_args(Compiler* self, FuncDecl* decl, bool enable_type_h
|
||||
static Error* compile_function(Compiler* self, int decorators) {
|
||||
Error* err;
|
||||
consume(TK_ID);
|
||||
c11_sv decl_name = Token__sv(prev());
|
||||
c11_sv decl_name_sv = Token__sv(prev());
|
||||
int decl_index;
|
||||
FuncDecl_ decl = push_f_context(self, decl_name, &decl_index);
|
||||
FuncDecl_ decl = push_f_context(self, decl_name_sv, &decl_index);
|
||||
consume(TK_LPAREN);
|
||||
if(!match(TK_RPAREN)) {
|
||||
check(_compile_f_args(self, decl, true));
|
||||
@ -2242,10 +2242,19 @@ static Error* compile_function(Compiler* self, int decorators) {
|
||||
Ctx__emit_(ctx(), OP_LOAD_FUNCTION, decl_index, prev()->line);
|
||||
Ctx__s_emit_decorators(ctx(), decorators);
|
||||
|
||||
py_Name decl_name = py_namev(decl_name_sv);
|
||||
if(ctx()->is_compiling_class) {
|
||||
Ctx__emit_(ctx(), OP_STORE_CLASS_ATTR, py_namev(decl_name), prev()->line);
|
||||
if(decl_name == __new__ || decl_name == __init__) {
|
||||
if(decl->args.length == 0) {
|
||||
return SyntaxError(self,
|
||||
"%s() should have at least one positional argument",
|
||||
py_name2str(decl_name));
|
||||
}
|
||||
}
|
||||
|
||||
Ctx__emit_(ctx(), OP_STORE_CLASS_ATTR, decl_name, prev()->line);
|
||||
} else {
|
||||
NameExpr* e = NameExpr__new(prev()->line, py_namev(decl_name), name_scope(self));
|
||||
NameExpr* e = NameExpr__new(prev()->line, decl_name, name_scope(self));
|
||||
vtemit_store((Expr*)e, ctx());
|
||||
vtdelete((Expr*)e);
|
||||
}
|
||||
|
||||
@ -120,8 +120,8 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
if(TOP()->type != tp_NoneType) {
|
||||
bool ok = py_repr(TOP());
|
||||
if(!ok) goto __ERROR;
|
||||
self->print(py_tostr(&self->last_retval));
|
||||
self->print("\n");
|
||||
self->callbacks.print(py_tostr(&self->last_retval));
|
||||
self->callbacks.print("\n");
|
||||
}
|
||||
POP();
|
||||
DISPATCH();
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
static char* pk_default_import_file(const char* path) {
|
||||
static char* pk_default_importfile(const char* path) {
|
||||
#if PK_ENABLE_OS
|
||||
FILE* f = fopen(path, "rb");
|
||||
if(f == NULL) return NULL;
|
||||
@ -61,9 +61,8 @@ void VM__ctor(VM* self) {
|
||||
self->builtins = *py_NIL;
|
||||
self->main = *py_NIL;
|
||||
|
||||
self->ceval_on_step = NULL;
|
||||
self->import_file = pk_default_import_file;
|
||||
self->print = pk_default_print;
|
||||
self->callbacks.importfile = pk_default_importfile;
|
||||
self->callbacks.print = pk_default_print;
|
||||
|
||||
self->last_retval = *py_NIL;
|
||||
self->curr_exception = *py_NIL;
|
||||
|
||||
@ -105,8 +105,8 @@ static void disassemble(CodeObject* co) {
|
||||
}
|
||||
|
||||
c11_string* output = c11_sbuf__submit(&ss);
|
||||
pk_current_vm->print(output->data);
|
||||
pk_current_vm->print("\n");
|
||||
pk_current_vm->callbacks.print(output->data);
|
||||
pk_current_vm->callbacks.print("\n");
|
||||
c11_string__delete(output);
|
||||
c11_vector__dtor(&jumpTargets);
|
||||
}
|
||||
|
||||
@ -76,6 +76,8 @@ void py_sys_setargv(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
py_Callbacks* py_getcallbacks() { return &pk_current_vm->callbacks; }
|
||||
|
||||
const char* pk_opname(Opcode op) {
|
||||
const static char* OP_NAMES[] = {
|
||||
#define OPCODE(name) #name,
|
||||
@ -137,6 +139,19 @@ bool py_pushmethod(py_Name name) {
|
||||
|
||||
bool pk_loadmethod(py_StackRef self, py_Name name) {
|
||||
// NOTE: `out` and `out_self` may overlap with `self`
|
||||
|
||||
if(name == __new__ && py_istype(self, tp_type)) {
|
||||
// __new__ acts like a @staticmethod
|
||||
// T.__new__(...)
|
||||
py_Ref cls_var = py_tpfindmagic(py_totype(self), name);
|
||||
if(cls_var) {
|
||||
self[0] = *cls_var;
|
||||
self[1] = *py_NIL;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
py_Type type;
|
||||
// handle super() proxy
|
||||
if(py_istype(self, tp_super)) {
|
||||
|
||||
@ -130,12 +130,12 @@ int py_import(const char* path_cstr) {
|
||||
goto __SUCCESS;
|
||||
}
|
||||
|
||||
data = vm->import_file(filename->data);
|
||||
data = vm->callbacks.importfile(filename->data);
|
||||
if(data != NULL) goto __SUCCESS;
|
||||
|
||||
c11_string__delete(filename);
|
||||
filename = c11_string__new3("%s/__init__.py", slashed_path->data);
|
||||
data = vm->import_file(filename->data);
|
||||
data = vm->callbacks.importfile(filename->data);
|
||||
if(data != NULL) goto __SUCCESS;
|
||||
|
||||
c11_string__delete(filename);
|
||||
@ -290,7 +290,7 @@ static bool builtins_print(int argc, py_Ref argv) {
|
||||
}
|
||||
c11_sbuf__write_sv(&buf, end);
|
||||
c11_string* res = c11_sbuf__submit(&buf);
|
||||
pk_current_vm->print(res->data);
|
||||
pk_current_vm->callbacks.print(res->data);
|
||||
c11_string__delete(res);
|
||||
py_newnone(py_retval());
|
||||
return true;
|
||||
|
||||
@ -160,8 +160,8 @@ void py_clearexc(py_StackRef p0) {
|
||||
void py_printexc() {
|
||||
char* msg = py_formatexc();
|
||||
if(!msg) return;
|
||||
pk_current_vm->print(msg);
|
||||
pk_current_vm->print("\n");
|
||||
pk_current_vm->callbacks.print(msg);
|
||||
pk_current_vm->callbacks.print("\n");
|
||||
free(msg);
|
||||
}
|
||||
|
||||
|
||||
@ -129,10 +129,12 @@ bool py_getattr(py_Ref self, py_Name name) {
|
||||
// bound method is non-data descriptor
|
||||
switch(cls_var->type) {
|
||||
case tp_function: {
|
||||
if(name == __new__) goto __STATIC_NEW;
|
||||
py_newboundmethod(py_retval(), self, cls_var);
|
||||
return true;
|
||||
}
|
||||
case tp_nativefunc: {
|
||||
if(name == __new__) goto __STATIC_NEW;
|
||||
py_newboundmethod(py_retval(), self, cls_var);
|
||||
return true;
|
||||
}
|
||||
@ -145,6 +147,7 @@ bool py_getattr(py_Ref self, py_Name name) {
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
__STATIC_NEW:
|
||||
py_assign(py_retval(), cls_var);
|
||||
return true;
|
||||
}
|
||||
@ -152,7 +155,7 @@ bool py_getattr(py_Ref self, py_Name name) {
|
||||
}
|
||||
|
||||
py_Ref fallback = py_tpfindmagic(type, __getattr__);
|
||||
if(fallback){
|
||||
if(fallback) {
|
||||
py_push(fallback);
|
||||
py_push(self);
|
||||
py_newstr(py_pushtmp(), py_name2str(name));
|
||||
|
||||
@ -98,7 +98,13 @@ py_Name
|
||||
CodeObject__dtor(&code);
|
||||
PK_DECREF(source);
|
||||
assert(decl->rc.count == 1);
|
||||
return py_name(ud->decl->code.name->data);
|
||||
py_Name decl_name = py_name(ud->decl->code.name->data);
|
||||
if(decl_name == __new__ || decl_name == __init__) {
|
||||
if(ud->decl->args.length == 0) {
|
||||
c11__abort("%s() should have at least one positional argument", py_name2str(decl_name));
|
||||
}
|
||||
}
|
||||
return decl_name;
|
||||
}
|
||||
|
||||
void py_newboundmethod(py_Ref out, py_Ref self, py_Ref func) {
|
||||
|
||||
@ -134,3 +134,6 @@ a = [1, 10, 3]
|
||||
a[test()] += 1
|
||||
assert (a == [1, 11, 3]), a
|
||||
assert (g == 1), g
|
||||
|
||||
assert list.__new__(list) == []
|
||||
assert a.__new__ == list.__new__
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user