From e365124af3fc44d790cd2d07a90c6f63521bb165 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Wed, 3 Jul 2024 00:48:45 +0800 Subject: [PATCH] some up --- src/common/sourcedata.c | 1 + src/common/sstream.c | 8 +- src/compiler/compiler.c | 302 ++++++++++++++++++++++++++++++++++++---- src/interpreter/ceval.c | 29 +++- src/public/vm.c | 8 +- 5 files changed, 311 insertions(+), 37 deletions(-) diff --git a/src/common/sourcedata.c b/src/common/sourcedata.c index f275e9a6..5394822c 100644 --- a/src/common/sourcedata.c +++ b/src/common/sourcedata.c @@ -27,6 +27,7 @@ static void pk_SourceData__ctor(struct pk_SourceData* self, } self->source = c11_sbuf__submit(&ss); self->is_precompiled = (strncmp(source, "pkpy:", 5) == 0); + self->is_dynamic = is_dynamic; c11_vector__push(const char*, &self->line_starts, self->source->data); } diff --git a/src/common/sstream.c b/src/common/sstream.c index 068bf6b9..46c68855 100644 --- a/src/common/sstream.c +++ b/src/common/sstream.c @@ -10,12 +10,10 @@ #include #include -const static int C11_STRING_HEADER_SIZE = sizeof(c11_string); - void c11_sbuf__ctor(c11_sbuf* self) { c11_vector__ctor(&self->data, sizeof(char)); - c11_vector__reserve(&self->data, 100 + C11_STRING_HEADER_SIZE); - self->data.count = C11_STRING_HEADER_SIZE; + c11_vector__reserve(&self->data, 100 + sizeof(c11_string)); + self->data.count = sizeof(c11_string); } void c11_sbuf__dtor(c11_sbuf* self) { c11_vector__dtor(&self->data); } @@ -137,7 +135,7 @@ c11_string* c11_sbuf__submit(c11_sbuf* self) { c11_vector__push(char, &self->data, '\0'); c11_array arr = c11_vector__submit(&self->data); c11_string* retval = (c11_string*)arr.data; - retval->size = arr.count - C11_STRING_HEADER_SIZE - 1; + retval->size = arr.count - sizeof(c11_string) - 1; return retval; } diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 1e6ea94b..58ee9129 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -64,7 +64,7 @@ typedef struct Ctx { int curr_iblock; bool is_compiling_class; c11_vector /*T=Expr* */ s_expr; - c11_vector /*T=py_Name*/ global_names; + c11_smallmap_n2i global_names; c11_smallmap_s2n co_consts_string_dedup_map; } Ctx; @@ -671,7 +671,7 @@ static void FStringExpr__emit_(Expr* self_, Ctx* ctx) { int conon = c11_sv__index(expr, ':'); if(conon >= 0) { c11_sv spec = {expr.data + (conon + 1), - expr.size - (conon + 1)}; // expr[conon+1:] + expr.size - (conon + 1)}; // expr[conon+1:] // filter some invalid spec bool ok = true; for(int k = 0; k < spec.size; k++) { @@ -1209,7 +1209,7 @@ void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level) { self->curr_iblock = 0; self->is_compiling_class = false; c11_vector__ctor(&self->s_expr, sizeof(Expr*)); - c11_vector__ctor(&self->global_names, sizeof(py_Name)); + c11_smallmap_n2i__ctor(&self->global_names); c11_smallmap_s2n__ctor(&self->co_consts_string_dedup_map); } @@ -1220,7 +1220,7 @@ void Ctx__dtor(Ctx* self) { } c11_vector__clear(&self->s_expr); c11_vector__dtor(&self->s_expr); - c11_vector__dtor(&self->global_names); + c11_smallmap_n2i__dtor(&self->global_names); c11_smallmap_s2n__dtor(&self->co_consts_string_dedup_map); } @@ -1455,7 +1455,7 @@ static void Compiler__dtor(Compiler* self) { pk_TokenSymbols[expected], \ pk_TokenSymbols[curr()->type]); #define consume_end_stmt() \ - if(!match_end_stmt()) return SyntaxError("expected statement end") + if(!match_end_stmt(self)) return SyntaxError("expected statement end") #define check_newlines_repl() \ do { \ bool __nml; \ @@ -1471,7 +1471,7 @@ static NameScope name_scope(Compiler* self) { return s; } -static Error* SyntaxError(const char* fmt, ...) { return NULL; } +#define SyntaxError(...) NULL static Error* NeedMoreLines() { return NULL; } @@ -1798,10 +1798,7 @@ static Error* exprName(Compiler* self) { py_Name name = py_name2(Token__sv(prev())); NameScope scope = name_scope(self); // promote this name to global scope if needed - c11_vector* global_names = &ctx()->global_names; - c11__foreach(py_Name, global_names, it) { - if(*it == name) scope = NAME_GLOBAL; - } + if(c11_smallmap_n2i__contains(&ctx()->global_names, name)) { scope = NAME_GLOBAL; } NameExpr* e = NameExpr__new(prev()->line, name, scope); Ctx__s_push(ctx(), (Expr*)e); return NULL; @@ -2005,6 +2002,258 @@ static Error* exprSubscr(Compiler* self) { return NULL; } +//////////////// +static Error* consume_type_hints(Compiler* self) { + Error* err; + check(EXPR(self)); + Ctx__s_pop(ctx()); + return NULL; +} + +Error* try_compile_assignment(Compiler* self, bool* is_assign) { + Error* err; + switch(curr()->type) { + case TK_IADD: + case TK_ISUB: + case TK_IMUL: + case TK_IDIV: + case TK_IFLOORDIV: + case TK_IMOD: + case TK_ILSHIFT: + case TK_IRSHIFT: + case TK_IAND: + case TK_IOR: + case TK_IXOR: { + if(Ctx__s_top(ctx())->vt->is_starred) return SyntaxError(); + if(ctx()->is_compiling_class) { + return SyntaxError("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 + // -1 to remove =; inplace=true + int line = prev()->line; + TokenIndex op = (TokenIndex)(prev()->type - 1); + // [lhs] + check(EXPR_TUPLE(self)); // [lhs, rhs] + if(Ctx__s_top(ctx())->vt->is_starred) return SyntaxError(); + 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(); + *is_assign = true; + return NULL; + } + case TK_ASSIGN: { + int n = 0; + while(match(TK_ASSIGN)) { + check(EXPR_TUPLE(self)); + n += 1; + } + // stack size is n+1 + Ctx__s_emit_top(ctx()); + for(int j = 1; j < n; j++) + 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(); + Expr* e = Ctx__s_top(ctx()); + bool ok = vtemit_store(e, ctx()); + Ctx__s_pop(ctx()); + if(!ok) return SyntaxError(); + } + *is_assign = true; + return NULL; + } + default: *is_assign = false; + } + return NULL; +} + +static Error* compile_stmt(Compiler* self) { + Error* err; + if(match(TK_CLASS)) { + // check(compile_class()); + assert(false); + return NULL; + } + advance(); + int kw_line = prev()->line; // backup line number + int curr_loop_block = Ctx__get_loop(ctx()); + switch(prev()->type) { + case TK_BREAK: + if(curr_loop_block < 0) return SyntaxError("'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"); + 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"); + 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"); + check(EXPR_TUPLE(self)); + Ctx__s_emit_top(ctx()); + Ctx__emit_(ctx(), OP_GET_ITER_NEW, BC_NOARG, kw_line); + Ctx__enter_block(ctx(), CodeBlockType_FOR_LOOP); + Ctx__emit_(ctx(), OP_FOR_ITER_YIELD_VALUE, BC_NOARG, kw_line); + Ctx__emit_(ctx(), OP_LOOP_CONTINUE, Ctx__get_loop(ctx()), kw_line); + Ctx__exit_block(ctx()); + consume_end_stmt(); + break; + case TK_RETURN: + if(self->contexts.count <= 1) return SyntaxError("'return' outside function"); + if(match_end_stmt(self)) { + Ctx__emit_(ctx(), OP_RETURN_VALUE, 1, kw_line); + } else { + check(EXPR_TUPLE(self)); + Ctx__s_emit_top(ctx()); + consume_end_stmt(); + Ctx__emit_(ctx(), OP_RETURN_VALUE, BC_NOARG, kw_line); + } + break; + /*************************************************/ + // case TK_IF: check(compile_if_stmt()); break; + // case TK_WHILE: check(compile_while_loop()); break; + // case TK_FOR: check(compile_for_loop()); break; + // case TK_IMPORT: check(compile_normal_import()); break; + // case TK_FROM: check(compile_from_import()); break; + // case TK_DEF: check(compile_function()); break; + // case TK_DECORATOR: check(compile_decorated()); break; + // case TK_TRY: check(compile_try_except()); break; + case TK_PASS: consume_end_stmt(); break; + /*************************************************/ + case TK_ASSERT: { + check(EXPR(self)); // condition + Ctx__s_emit_top(ctx()); + int index = Ctx__emit_(ctx(), OP_POP_JUMP_IF_TRUE, BC_NOARG, kw_line); + int has_msg = 0; + if(match(TK_COMMA)) { + check(EXPR(self)); // message + Ctx__s_emit_top(ctx()); + has_msg = 1; + } + Ctx__emit_(ctx(), OP_RAISE_ASSERT, has_msg, kw_line); + Ctx__patch_jump(ctx(), index); + consume_end_stmt(); + break; + } + case TK_GLOBAL: + do { + consume(TK_ID); + py_Name name = py_name2(Token__sv(prev())); + c11_smallmap_n2i__set(&ctx()->global_names, name, 0); + } while(match(TK_COMMA)); + consume_end_stmt(); + break; + case TK_RAISE: { + check(EXPR(self)); + Ctx__s_emit_top(ctx()); + Ctx__emit_(ctx(), OP_RAISE, BC_NOARG, kw_line); + consume_end_stmt(); + } break; + case TK_DEL: { + check(EXPR_TUPLE(self)); + Expr* e = Ctx__s_top(ctx()); + if(!vtemit_del(e, ctx())) return SyntaxError(); + Ctx__s_pop(ctx()); + consume_end_stmt(); + } break; + // case TK_WITH: { + // check(EXPR(self)); // [ ] + // Ctx__s_emit_top(ctx()); + // Ctx__enter_block(ctx(), CodeBlockType_CONTEXT_MANAGER); + // Expr* as_name = nullptr; + // if(match(TK_AS)) { + // consume(TK_ID); + // as_name = make_expr(prev().str(), name_scope()); + // } + // Ctx__emit_(ctx(), OP_WITH_ENTER, BC_NOARG, prev().line); + // // [ .__enter__() ] + // if(as_name) { + // bool ok = as_name->emit_store(ctx()); + // delete_expr(as_name); + // if(!ok) return SyntaxError(); + // } else { + // Ctx__emit_(ctx(), OP_POP_TOP, BC_NOARG, BC_KEEPLINE); + // } + // check(compile_block_body()); + // Ctx__emit_(ctx(), OP_WITH_EXIT, BC_NOARG, prev().line); + // Ctx__exit_block(ctx()); + // } break; + /*************************************************/ + case TK_EQ: { + consume(TK_ID); + if(mode() != EXEC_MODE) return SyntaxError("'label' is only available in EXEC_MODE"); + c11_sv name = Token__sv(prev()); + bool ok = Ctx__add_label(ctx(), py_name2(name)); + if(!ok) return SyntaxError("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"); + py_Name name = py_name2(Token__sv(prev())); + Ctx__emit_(ctx(), OP_GOTO, name, prev()->line); + consume_end_stmt(); + break; + /*************************************************/ + // handle dangling expression or assignment + default: { + // do revert since we have pre-called advance() at the beginning + --self->i; + + check(EXPR_TUPLE(self)); + + bool is_typed_name = false; // e.g. x: int + // eat variable's type hint if it is a single name + if(Ctx__s_top(ctx())->vt->is_name) { + if(match(TK_COLON)) { + check(consume_type_hints(self)); + is_typed_name = true; + + if(ctx()->is_compiling_class) { + NameExpr* ne = (NameExpr*)Ctx__s_top(ctx()); + Ctx__emit_(ctx(), OP_ADD_CLASS_ANNOTATION, ne->name, BC_KEEPLINE); + } + } + } + bool is_assign = false; + 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(); + } + if(!is_typed_name) { + Ctx__s_emit_top(ctx()); + if((mode() == CELL_MODE || mode() == REPL_MODE) && + name_scope(self) == NAME_GLOBAL) { + Ctx__emit_(ctx(), OP_PRINT_EXPR, BC_NOARG, BC_KEEPLINE); + } else { + Ctx__emit_(ctx(), OP_POP_TOP, BC_NOARG, BC_KEEPLINE); + } + } else { + Ctx__s_pop(ctx()); + } + } + consume_end_stmt(); + break; + } + } + return NULL; +} + ///////////////////////////////////////////////////////////////// Error* Compiler__compile(Compiler* self, CodeObject* out) { @@ -2026,25 +2275,22 @@ Error* Compiler__compile(Compiler* self, CodeObject* out) { Ctx__emit_(ctx(), OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE); check(pop_context(self)); return NULL; + } else if(mode() == JSON_MODE) { + check(EXPR(self)); + Expr* e = Ctx__s_popx(ctx()); + if(!e->vt->is_json_object) { return SyntaxError("expect a JSON object, literal or array"); } + consume(TK_EOF); + vtemit_(e, ctx()); + Ctx__emit_(ctx(), OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE); + check(pop_context(self)); + return NULL; } - // } else if(mode() == JSON_MODE) { - // check(EXPR(self)); - // Expr* e = Ctx__s_popx(ctx()); - // if(!e->is_json_object()){ - // return SyntaxError("expect a JSON object, literal or array"); - // } - // consume(TK_EOF); - // e->emit_(ctx()); - // ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE); - // check(pop_context()); - // return NULL; - // } - // while(!match(TK_EOF)) { - // check(compile_stmt()); - // match_newlines(); - // } - // check(pop_context()); + while(!match(TK_EOF)) { + check(compile_stmt(self)); + match_newlines(); + } + check(pop_context(self)); return NULL; } @@ -2069,6 +2315,8 @@ Error* pk_compile(pk_SourceData_ src, CodeObject* out) { if(err) { // if error occurs, dispose the code object CodeObject__dtor(out); + } else { + assert(out->codes.count); } Compiler__dtor(&compiler); return err; diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 29e3148b..5629aaa7 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -605,9 +605,9 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { // } /*****************************************/ case OP_RETURN_VALUE: { - if(byte.arg == BC_NOARG){ + if(byte.arg == BC_NOARG) { self->last_retval = POPX(); - }else{ + } else { py_newnone(&self->last_retval); } pk_VM__pop_frame(self); @@ -620,6 +620,31 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { } DISPATCH(); } + + ///////// + case OP_UNARY_NEGATIVE: { + if(!py_callmagic(__neg__, 1, TOP())) goto __ERROR; + *TOP() = self->last_retval; + DISPATCH(); + } + case OP_UNARY_NOT: { + int res = py_bool(TOP()); + if(res < 0) goto __ERROR; + py_newbool(TOP(), !res); + DISPATCH(); + } + // case OP_UNARY_STAR: TOP() = VAR(StarWrapper(byte.arg, TOP())); DISPATCH(); + // case OP_UNARY_INVERT: { + // PyVar _0; + // auto _ti = _tp_info(TOP()); + // if(_ti->m__invert__) + // _0 = _ti->m__invert__(this, TOP()); + // else + // _0 = call_method(TOP(), __invert__); + // TOP() = _0; + // DISPATCH(); + // } + default: PK_UNREACHABLE(); } diff --git a/src/public/vm.c b/src/public/vm.c index 4aa9651b..abc40e6a 100644 --- a/src/public/vm.c +++ b/src/public/vm.c @@ -89,10 +89,12 @@ static void disassemble(CodeObject* co) { case OP_LOAD_CONST: case OP_FORMAT_STRING: case OP_IMPORT_PATH: { - c11_string* ud = py_touserdata(c11__at(py_TValue, &co->consts, byte.arg)); + py_Ref tmp = c11__at(py_TValue, &co->consts, byte.arg); c11_sbuf__write_cstr(&ss, " ("); - c11_sbuf__write_cstr(&ss, ud->data); - c11_sbuf__write_char(&ss, ')'); + // here we need to use py_repr, however this function is not ready yet + c11_sbuf__write_cstr(&ss, "type)); + c11_sbuf__write_cstr(&ss, "'>)"); break; } case OP_LOAD_NAME: