This commit is contained in:
blueloveTH 2024-07-06 23:07:44 +08:00
parent 4b4351e3fa
commit 803e7f1791
10 changed files with 293 additions and 70 deletions

View File

@ -34,6 +34,7 @@ c11_vector c11_vector__copy(const c11_vector* self);
void c11_vector__reserve(c11_vector* self, int capacity); void c11_vector__reserve(c11_vector* self, int capacity);
void c11_vector__clear(c11_vector* self); void c11_vector__clear(c11_vector* self);
void* c11_vector__emplace(c11_vector* self); void* c11_vector__emplace(c11_vector* self);
bool c11_vector__contains(const c11_vector* self, void* elem);
c11_array c11_vector__submit(c11_vector* self); c11_array c11_vector__submit(c11_vector* self);
#define c11__getitem(T, self, index) (((T*)(self)->data)[index]) #define c11__getitem(T, self, index) (((T*)(self)->data)[index])

View File

@ -7,6 +7,7 @@
#include "pocketpy/common/smallmap.h" #include "pocketpy/common/smallmap.h"
#include "pocketpy/objects/base.h" #include "pocketpy/objects/base.h"
#include "pocketpy/objects/sourcedata.h" #include "pocketpy/objects/sourcedata.h"
#include "pocketpy/objects/namedict.h"
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -39,6 +40,7 @@ typedef enum CodeBlockType {
} CodeBlockType; } CodeBlockType;
typedef enum Opcode { typedef enum Opcode {
#define OPCODE(name) OP_##name, #define OPCODE(name) OP_##name,
#include "pocketpy/xmacros/opcodes.h" #include "pocketpy/xmacros/opcodes.h"
#undef OPCODE #undef OPCODE
@ -121,6 +123,17 @@ void FuncDecl__dtor(FuncDecl* self);
void FuncDecl__add_kwarg(FuncDecl* self, int index, uint16_t key, const py_TValue* value); void FuncDecl__add_kwarg(FuncDecl* self, int index, uint16_t key, const py_TValue* value);
void FuncDecl__gc_mark(const FuncDecl* self); void FuncDecl__gc_mark(const FuncDecl* self);
// runtime function
typedef struct Function {
FuncDecl_ decl;
PyObject* module; // weak ref
PyObject* clazz; // weak ref
pk_NameDict* closure; // strong ref
} Function;
void Function__ctor(Function* self, FuncDecl_ decl, PyObject* module);
void Function__dtor(Function* self);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -63,6 +63,14 @@ void* c11_vector__emplace(c11_vector* self){
return p; return p;
} }
bool c11_vector__contains(const c11_vector *self, void *elem){
for(int i = 0; i < self->count; i++){
void* p = (char*)self->data + self->elem_size * i;
if(memcmp(p, elem, self->elem_size) == 0) return true;
}
return false;
}
c11_array c11_vector__submit(c11_vector* self){ c11_array c11_vector__submit(c11_vector* self){
c11_array retval = { c11_array retval = {
.data = self->data, .data = self->data,

View File

@ -635,7 +635,6 @@ static void _load_simple_expr(Ctx* ctx, c11_sv expr, int line) {
// name or name.name // name or name.name
bool is_fastpath = false; bool is_fastpath = false;
if(is_identifier(expr)) { if(is_identifier(expr)) {
// ctx->emit_(OP_LOAD_NAME, py_Name(expr.sv()).index, line);
Ctx__emit_(ctx, OP_LOAD_NAME, py_name2(expr), line); Ctx__emit_(ctx, OP_LOAD_NAME, py_name2(expr), line);
is_fastpath = true; is_fastpath = true;
} else { } else {
@ -2188,6 +2187,174 @@ Error* try_compile_assignment(Compiler* self, bool* is_assign) {
return NULL; return NULL;
} }
static FuncDecl_ push_f_context(Compiler* self, c11_sv name, int* out_index) {
FuncDecl_ decl = FuncDecl__rcnew(self->src, name);
decl->code.start_line = self->i == 0 ? 1 : prev()->line;
decl->nested = name_scope(self) == NAME_LOCAL;
// add_func_decl
Ctx* top_ctx = ctx();
c11_vector__push(FuncDecl_, &top_ctx->co->func_decls, decl);
*out_index = top_ctx->co->func_decls.count - 1;
// push new context
top_ctx = c11_vector__emplace(&self->contexts);
// contexts.push_back(CodeEmitContext(vm, decl->code, contexts.size()));
Ctx__ctor(top_ctx, &decl->code, decl, self->contexts.count);
return decl;
}
static Error* read_literal(Compiler* self, py_Ref out) {
Error* err;
advance();
const TokenValue* value = &prev()->value;
bool negated = false;
switch(prev()->type) {
case TK_SUB:
consume(TK_NUM);
value = &prev()->value;
negated = true;
case TK_NUM: {
if(value->index == TokenValue_I64) {
py_newint(out, negated ? -value->_i64 : value->_i64);
} else if(value->index == TokenValue_F64) {
py_newfloat(out, negated ? -value->_f64 : value->_f64);
} else {
return SyntaxError();
}
return NULL;
}
case TK_STR: py_newstr(out, value->_str->data); return NULL;
case TK_TRUE: py_newbool(out, true); return NULL;
case TK_FALSE: py_newbool(out, false); return NULL;
case TK_NONE: py_newnone(out); return NULL;
case TK_DOTDOTDOT: py_newellipsis(out); return NULL;
case TK_LPAREN: {
py_TValue cpnts[4];
int count = 0;
while(true) {
if(count == 4) return SyntaxError("default argument tuple exceeds 4 elements");
check(read_literal(self, &cpnts[count]));
count += 1;
if(curr()->type == TK_RPAREN) break;
consume(TK_COMMA);
if(curr()->type == TK_RPAREN) break;
}
consume(TK_RPAREN);
py_newtuple(out, count);
for(int i = 0; i < count; i++) {
py_tuple__setitem(out, i, &cpnts[i]);
}
return NULL;
}
default: *out = PY_NIL; return NULL;
}
}
static Error* _compile_f_args(Compiler* self, FuncDecl* decl, bool enable_type_hints) {
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
Error* err;
do {
if(state > 3) return SyntaxError();
if(state == 3) return SyntaxError("**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");
} else if(match(TK_POW)) {
state = 3;
}
consume(TK_ID);
py_Name name = py_name2(Token__sv(prev()));
// check duplicate argument name
py_Name tmp_name;
c11__foreach(int, &decl->args, j) {
tmp_name = c11__getitem(py_Name, &decl->args, *j);
if(tmp_name == name) return SyntaxError("duplicate argument name");
}
c11__foreach(FuncDeclKwArg, &decl->kwargs, kv) {
tmp_name = c11__getitem(py_Name, &decl->code.varnames, kv->index);
if(tmp_name == name) return SyntaxError("duplicate argument name");
}
if(decl->starred_arg != -1) {
tmp_name = c11__getitem(py_Name, &decl->code.varnames, decl->starred_arg);
if(tmp_name == name) return SyntaxError("duplicate argument name");
}
if(decl->starred_kwarg != -1) {
tmp_name = c11__getitem(py_Name, &decl->code.varnames, decl->starred_kwarg);
if(tmp_name == name) return SyntaxError("duplicate argument name");
}
// eat type hints
if(enable_type_hints && match(TK_COLON)) check(consume_type_hints(self));
if(state == 0 && curr()->type == TK_ASSIGN) state = 2;
int index = Ctx__add_varname(ctx(), name);
switch(state) {
case 0: c11_vector__push(int, &decl->args, index); break;
case 1:
decl->starred_arg = index;
state += 1;
break;
case 2: {
consume(TK_ASSIGN);
py_TValue value;
check(read_literal(self, &value));
if(py_isnil(&value)) return SyntaxError("default argument must be a literal");
FuncDecl__add_kwarg(decl, index, name, &value);
} break;
case 3:
decl->starred_kwarg = index;
state += 1;
break;
}
} while(match(TK_COMMA));
return NULL;
}
static Error* compile_function(Compiler* self, int decorators) {
Error* err;
consume(TK_ID);
c11_sv decl_name = Token__sv(prev());
int decl_index;
FuncDecl_ decl = push_f_context(self, decl_name, &decl_index);
consume(TK_LPAREN);
if(!match(TK_RPAREN)) {
check(_compile_f_args(self, decl, true));
consume(TK_RPAREN);
}
if(match(TK_ARROW)) check(consume_type_hints(self));
check(compile_block_body(self, compile_stmt));
check(pop_context(self));
if(decl->code.codes.count >= 2) {
Bytecode* codes = (Bytecode*)decl->code.codes.data;
if(codes[0].op == OP_LOAD_CONST && codes[1].op == OP_POP_TOP) {
// handle optional docstring
py_TValue* consts = decl->code.consts.data;
py_TValue* c = &consts[codes[0].arg];
if(py_isstr(c)) {
decl->docstring = py_tostr(c);
codes[0].op = OP_NO_OP;
codes[1].op = OP_NO_OP;
}
}
}
Ctx__emit_(ctx(), OP_LOAD_FUNCTION, decl_index, prev()->line);
Ctx__s_emit_decorators(ctx(), decorators);
if(ctx()->is_compiling_class) {
Ctx__emit_(ctx(), OP_STORE_CLASS_ATTR, py_name2(decl_name), prev()->line);
} else {
NameExpr* e = NameExpr__new(prev()->line, py_name2(decl_name), name_scope(self));
vtemit_store((Expr*)e, ctx());
vtdelete((Expr*)e);
}
return NULL;
}
static Error* compile_stmt(Compiler* self) { static Error* compile_stmt(Compiler* self) {
Error* err; Error* err;
if(match(TK_CLASS)) { if(match(TK_CLASS)) {
@ -2244,7 +2411,7 @@ static Error* compile_stmt(Compiler* self) {
case TK_FOR: check(compile_for_loop(self)); break; case TK_FOR: check(compile_for_loop(self)); break;
// case TK_IMPORT: check(compile_normal_import()); break; // case TK_IMPORT: check(compile_normal_import()); break;
// case TK_FROM: check(compile_from_import()); break; // case TK_FROM: check(compile_from_import()); break;
// case TK_DEF: check(compile_function()); break; case TK_DEF: check(compile_function(self, 0)); break;
// case TK_DECORATOR: check(compile_decorated()); break; // case TK_DECORATOR: check(compile_decorated()); break;
// case TK_TRY: check(compile_try_except()); break; // case TK_TRY: check(compile_try_except()); break;
case TK_PASS: consume_end_stmt(); break; case TK_PASS: consume_end_stmt(); break;

View File

@ -164,20 +164,17 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
/*****************************************/ /*****************************************/
case OP_LOAD_ELLIPSIS: py_newellipsis(SP()++); DISPATCH(); case OP_LOAD_ELLIPSIS: py_newellipsis(SP()++); DISPATCH();
case OP_LOAD_FUNCTION: { case OP_LOAD_FUNCTION: {
// FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg); FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
// py_TValue obj; Function* ud = py_newobject(SP(), tp_function, 0, sizeof(Function));
// if(decl->nested) { Function__ctor(ud, decl, frame->module);
// NameDict* captured = frame->_locals.to_namedict(); if(decl->nested) {
// obj = ud->closure = FastLocals__to_namedict(frame->locals, frame->locals_co);
// new_object<Function>(tp_function, decl, frame->_module, nullptr, py_Name name = py_name2(c11_string__sv(decl->code.name));
// captured); // capture itself to allow recursion
// uint16_t name = py_Name__map2(py_Str__sv(&decl->code->name)); pk_NameDict__set(ud->closure, name, *SP());
// captured->set(name, obj); }
// } else { SP()++;
// obj = new_object<Function>(tp_function, decl, frame->_module, nullptr, DISPATCH();
// nullptr);
// }
// PUSH(obj);DISPATCH();
} }
case OP_LOAD_NULL: case OP_LOAD_NULL:
py_newnil(SP()++); py_newnil(SP()++);

View File

@ -6,9 +6,7 @@ void ValueStack__ctor(ValueStack* self) {
self->end = self->begin + PK_VM_STACK_SIZE; self->end = self->begin + PK_VM_STACK_SIZE;
} }
void ValueStack__clear(ValueStack* self) { void ValueStack__clear(ValueStack* self) { self->sp = self->begin; }
self->sp = self->begin;
}
py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co, py_Name name) { py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co, py_Name name) {
int index = c11_smallmap_n2i__get(&co->varnames_inv, name, -1); int index = c11_smallmap_n2i__get(&co->varnames_inv, name, -1);
@ -20,9 +18,7 @@ pk_NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co) {
pk_NameDict* dict = pk_NameDict__new(); pk_NameDict* dict = pk_NameDict__new();
c11__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) { c11__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) {
py_TValue value = locals[entry->value]; py_TValue value = locals[entry->value];
if(!py_isnil(&value)){ if(!py_isnil(&value)) { pk_NameDict__set(dict, entry->key, value); }
pk_NameDict__set(dict, entry->key, value);
}
} }
return dict; return dict;
} }
@ -35,11 +31,14 @@ UnwindTarget* UnwindTarget__new(UnwindTarget* next, int iblock, int offset){
return self; return self;
} }
void UnwindTarget__delete(UnwindTarget* self){ void UnwindTarget__delete(UnwindTarget* self) { free(self); }
free(self);
}
Frame* Frame__new(const CodeObject* co, const py_TValue* module, const py_TValue* function, py_TValue* p0, py_TValue* locals, const CodeObject* locals_co){ Frame* Frame__new(const CodeObject* co,
const py_TValue* module,
const py_TValue* function,
py_TValue* p0,
py_TValue* locals,
const CodeObject* locals_co) {
static_assert(sizeof(Frame) <= kPoolFrameBlockSize, "!(sizeof(Frame) <= kPoolFrameBlockSize)"); static_assert(sizeof(Frame) <= kPoolFrameBlockSize, "!(sizeof(Frame) <= kPoolFrameBlockSize)");
Frame* self = PoolFrame_alloc(); Frame* self = PoolFrame_alloc();
self->f_back = NULL; self->f_back = NULL;
@ -82,7 +81,8 @@ int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s){
void Frame__prepare_jump_break(Frame* self, ValueStack* _s, int target) { void Frame__prepare_jump_break(Frame* self, ValueStack* _s, int target) {
int iblock = Frame__iblock(self); int iblock = Frame__iblock(self);
if(target >= self->co->codes.count) { if(target >= self->co->codes.count) {
while(iblock >= 0) iblock = Frame__exit_block(self, _s, iblock); while(iblock >= 0)
iblock = Frame__exit_block(self, _s, iblock);
} else { } else {
// BUG (solved) // BUG (solved)
// for i in range(4): // for i in range(4):

View File

@ -92,3 +92,16 @@ void CodeObject__dtor(CodeObject* self) {
} }
c11_vector__dtor(&self->func_decls); c11_vector__dtor(&self->func_decls);
} }
void Function__ctor(Function* self, FuncDecl_ decl, PyObject* module) {
PK_INCREF(decl);
self->decl = decl;
self->module = module;
self->clazz = NULL;
self->closure = NULL;
}
void Function__dtor(Function* self) {
PK_DECREF(self->decl);
if(self->closure) pk_NameDict__delete(self->closure);
}

View File

@ -1,4 +1,5 @@
#include "pocketpy/interpreter/vm.h" #include "pocketpy/interpreter/vm.h"
#include "pocketpy/common/sstream.h"
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
static bool _py_object__new__(int argc, py_Ref argv) { static bool _py_object__new__(int argc, py_Ref argv) {
@ -29,9 +30,22 @@ static bool _py_object__ne__(int argc, py_Ref argv) {
return true; return true;
} }
static bool _py_object__repr__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
assert(argv->is_ptr);
c11_sbuf buf;
c11_sbuf__ctor(&buf);
pk_sprintf(&buf, "<%t object at %p>", argv->type, argv->_obj);
c11_string* res = c11_sbuf__submit(&buf);
py_newstrn(py_retval(), res->data, res->size);
c11_string__delete(res);
return true;
}
void pk_object__register() { void pk_object__register() {
py_bindmagic(tp_object, __new__, _py_object__new__); py_bindmagic(tp_object, __new__, _py_object__new__);
py_bindmagic(tp_object, __hash__, _py_object__hash__); py_bindmagic(tp_object, __hash__, _py_object__hash__);
py_bindmagic(tp_object, __eq__, _py_object__eq__); py_bindmagic(tp_object, __eq__, _py_object__eq__);
py_bindmagic(tp_object, __ne__, _py_object__ne__); py_bindmagic(tp_object, __ne__, _py_object__ne__);
py_bindmagic(tp_object, __repr__, _py_object__repr__);
} }

View File

@ -36,9 +36,17 @@ int main(int argc, char** argv) {
if(argc == 1) { if(argc == 1) {
printf("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") "); printf("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") ");
printf("[%d bit] on %s" "\n", (int)(sizeof(void*) * 8), PY_SYS_PLATFORM_STRING); printf(
printf("https://github.com/pocketpy/pocketpy" "\n"); "[%d bit] on %s"
printf("Type \"exit()\" to exit." "\n"); "\n",
(int)(sizeof(void*) * 8),
PY_SYS_PLATFORM_STRING);
printf(
"https://github.com/pocketpy/pocketpy"
"\n");
printf(
"Type \"exit()\" to exit."
"\n");
while(true) { while(true) {
int size = py_replinput(buf); int size = py_replinput(buf);
@ -49,9 +57,11 @@ int main(int argc, char** argv) {
} }
} else { } else {
char* source = read_file(argv[1]); char* source = read_file(argv[1]);
if(source) {
if(!py_exec(source)) py_printexc(); if(!py_exec(source)) py_printexc();
free(source); free(source);
} }
}
py_finalize(); py_finalize();
return 0; return 0;

View File

@ -1,7 +1,3 @@
def eq(a, b):
dt = a - b
return dt > -0.001 and dt < 0.001
# test == != >= <= < > # test == != >= <= < >
assert 1.0 == 1.0 assert 1.0 == 1.0
assert 1.0 != 1.1 assert 1.0 != 1.1
@ -10,6 +6,10 @@ assert 1.0 <= 1.0
assert 1.0 < 1.1 assert 1.0 < 1.1
assert 1.1 > 1.0 assert 1.1 > 1.0
def eq(a, b):
dt = a - b
return dt > -0.001 and dt < 0.001
# test + - * ** / # test + - * ** /
assert eq(1.5 + 3, 4.5) assert eq(1.5 + 3, 4.5)
assert eq(1.5 + 3.9, 5.4) assert eq(1.5 + 3.9, 5.4)