From 718ba988d5e56f28257552afce50cc47dd0405ec Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 2 Apr 2023 21:37:10 +0800 Subject: [PATCH] up --- src/compiler.h | 95 +++++++++++++++++++++++++------------------------- src/expr.h | 38 ++++++++++++++------ src/opcodes.h | 2 ++ 3 files changed, 77 insertions(+), 58 deletions(-) diff --git a/src/compiler.h b/src/compiler.h index 6b3dbae6..5d62c235 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -448,8 +448,9 @@ class Compiler { consume(TK("@id")); name = prev().str(); } - int index = ctx()->add_name(name, name_scope()); - ctx()->emit(OP_STORE_NAME, index, prev().line); + int index = ctx()->add_name(name); + auto op = name_scope()==NAME_LOCAL ? OP_STORE_LOCAL : OP_STORE_GLOBAL; + ctx()->emit(op, index, prev().line); } while (match(TK(","))); consume_end_stmt(); } @@ -459,8 +460,8 @@ class Compiler { _compile_import(); consume(TK("import")); if (match(TK("*"))) { - if(name_scope() != NAME_GLOBAL) SyntaxError("import * can only be used in global scope"); - ctx()->emit(OP_STORE_ALL_NAMES, BC_NOARG, prev().line); + if(name_scope() != NAME_GLOBAL) SyntaxError("import * should be used in global scope"); + ctx()->emit(OP_IMPORT_STAR, BC_NOARG, prev().line); consume_end_stmt(); return; } @@ -475,7 +476,8 @@ class Compiler { name = prev().str(); } index = ctx()->add_name(name); - ctx()->emit(OP_STORE_GLOBAL, index, prev().line); + auto op = name_scope()==NAME_LOCAL ? OP_STORE_LOCAL : OP_STORE_GLOBAL; + ctx()->emit(op, index, prev().line); } while (match(TK(","))); ctx()->emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE); consume_end_stmt(); @@ -527,6 +529,7 @@ class Compiler { ctx()->exit_block(); } + // PASS void compile_for_loop() { EXPR_TUPLE(); Expr_ vars = ctx()->s_expr.popx(); @@ -535,42 +538,39 @@ class Compiler { ctx()->emit(OP_GET_ITER, BC_NOARG, BC_KEEPLINE); ctx()->enter_block(FOR_LOOP); ctx()->emit(OP_FOR_ITER, BC_NOARG, BC_KEEPLINE); - // set variables and handle implicit unpack bool ok = vars->emit_store(ctx()); - // this error occurs in `vars` instead of this line - // but...nevermind - if(!ok) SyntaxError(); + if(!ok) SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind compile_block_body(); ctx()->emit(OP_LOOP_CONTINUE, BC_NOARG, BC_KEEPLINE); ctx()->exit_block(); } void compile_try_except() { - ctx()->enter_block(TRY_EXCEPT); - ctx()->emit(OP_TRY_BLOCK_ENTER, BC_NOARG, prev().line); - compile_block_body(); - ctx()->emit(OP_TRY_BLOCK_EXIT, BC_NOARG, BC_KEEPLINE); - std::vector patches = { - ctx()->emit(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE) - }; - ctx()->exit_block(); + // ctx()->enter_block(TRY_EXCEPT); + // ctx()->emit(OP_TRY_BLOCK_ENTER, BC_NOARG, prev().line); + // compile_block_body(); + // ctx()->emit(OP_TRY_BLOCK_EXIT, BC_NOARG, BC_KEEPLINE); + // std::vector patches = { + // ctx()->emit(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE) + // }; + // ctx()->exit_block(); - do { - consume(TK("except")); - if(match(TK("@id"))){ - int name_idx = ctx()->add_name(prev().str(), NAME_SPECIAL); - emit(OP_EXCEPTION_MATCH, name_idx); - }else{ - emit(OP_LOAD_TRUE); - } - int patch = emit(OP_POP_JUMP_IF_FALSE); - emit(OP_POP_TOP); // pop the exception on match - compile_block_body(); - patches.push_back(emit(OP_JUMP_ABSOLUTE)); - patch_jump(patch); - }while(curr().type == TK("except")); - emit(OP_RE_RAISE); // no match, re-raise - for (int patch : patches) patch_jump(patch); + // do { + // consume(TK("except")); + // if(match(TK("@id"))){ + // int name_idx = ctx()->add_name(prev().str(), NAME_SPECIAL); + // emit(OP_EXCEPTION_MATCH, name_idx); + // }else{ + // emit(OP_LOAD_TRUE); + // } + // int patch = emit(OP_POP_JUMP_IF_FALSE); + // emit(OP_POP_TOP); // pop the exception on match + // compile_block_body(); + // patches.push_back(emit(OP_JUMP_ABSOLUTE)); + // patch_jump(patch); + // }while(curr().type == TK("except")); + // emit(OP_RE_RAISE); // no match, re-raise + // for (int patch : patches) patch_jump(patch); } void compile_decorated(){ @@ -650,13 +650,13 @@ class Compiler { case TK("global"): do { consume(TK("@id")); - co()->global_names.insert(prev().str()); + ctx()->co->global_names.insert(prev().str()); } while (match(TK(","))); consume_end_stmt(); break; case TK("raise"): { consume(TK("@id")); - int dummy_t = ctx()->add_name(prev().str(), NAME_SPECIAL); + int dummy_t = ctx()->add_name(prev().str()); if(match(TK("(")) && !match(TK(")"))){ EXPR(false); consume(TK(")")); }else{ @@ -688,17 +688,17 @@ class Compiler { } break; /*************************************************/ // TODO: refactor goto/label use special $ syntax - case TK("label"): + case TK("label"): { if(mode()!=EXEC_MODE) SyntaxError("'label' is only available in EXEC_MODE"); consume(TK(".")); consume(TK("@id")); bool ok = ctx()->add_label(prev().str()); if(!ok) SyntaxError("label " + prev().str().escape(true) + " already exists"); consume_end_stmt(); - break; + } break; case TK("goto"): if(mode()!=EXEC_MODE) SyntaxError("'goto' is only available in EXEC_MODE"); consume(TK(".")); consume(TK("@id")); - emit(OP_GOTO, co()->add_name(prev().str(), NAME_SPECIAL)); + ctx()->emit(OP_GOTO, ctx()->add_name(prev().str()), prev().line); consume_end_stmt(); break; /*************************************************/ @@ -707,9 +707,9 @@ class Compiler { EXPR_TUPLE(true); if(!try_compile_assignment()){ if(mode()==REPL_MODE && name_scope()==NAME_GLOBAL){ - emit(OP_PRINT_EXPR, BC_NOARG, BC_KEEPLINE); + ctx()->emit(OP_PRINT_EXPR, BC_NOARG, BC_KEEPLINE); }else{ - emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE); + ctx()->emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE); } } consume_end_stmt(); @@ -717,21 +717,22 @@ class Compiler { } } + // PASS void compile_class(){ consume(TK("@id")); - int cls_name_idx = co()->add_name(prev().str(), NAME_GLOBAL); - int super_cls_name_idx = -1; + int namei = ctx()->add_name(prev().str()); + int super_namei = -1; if(match(TK("(")) && match(TK("@id"))){ - super_cls_name_idx = co()->add_name(prev().str(), NAME_GLOBAL); + super_namei = ctx()->add_name(prev().str()); consume(TK(")")); } - if(super_cls_name_idx == -1) emit(OP_LOAD_NONE); - else emit(OP_LOAD_NAME, super_cls_name_idx); - emit(OP_BEGIN_CLASS, cls_name_idx); + if(super_namei == -1) ctx()->emit(OP_LOAD_NONE, BC_NOARG, prev().line); + else ctx()->emit(OP_LOAD_NAME, super_namei, prev().line); + ctx()->emit(OP_BEGIN_CLASS, namei, BC_KEEPLINE); ctx()->is_compiling_class = true; compile_block_body(); ctx()->is_compiling_class = false; - emit(OP_END_CLASS); + ctx()->emit(OP_END_CLASS, BC_NOARG, BC_KEEPLINE); } void _compile_f_args(Function& func, bool enable_type_hints){ diff --git a/src/expr.h b/src/expr.h index d3007139..977bf1d4 100644 --- a/src/expr.h +++ b/src/expr.h @@ -23,7 +23,7 @@ struct Expr{ virtual bool emit_del(CodeEmitContext* ctx) { return false; } // for OP_STORE_XXX - virtual bool emit_store(CodeEmitContext* ctx) { return false; } + [[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) { return false; } }; struct CodeEmitContext{ @@ -153,15 +153,12 @@ struct StarredExpr: Expr{ void emit(CodeEmitContext* ctx) override { child->emit(ctx); - // as a rvalue, we should do unpack here - //ctx->emit(OP_UNARY_STAR, (int)false, line); + ctx->emit(OP_UNARY_STAR, BC_NOARG, line); } bool emit_store(CodeEmitContext* ctx) override { - child->emit(ctx); - // as a lvalue, we should do pack here - //ctx->emit(OP_UNARY_STAR, (int)true, line); - return true; + // simply proxy to child + return child->emit_store(ctx); } }; @@ -368,10 +365,29 @@ struct TupleExpr: SequenceExpr{ Opcode opcode() const override { return OP_BUILD_TUPLE; } bool emit_store(CodeEmitContext* ctx) override { - // assume TOS is an iterable - // unpack it and emit several OP_STORE - // https://docs.python.org/3/library/dis.html#opcode-UNPACK_SEQUENCE - // https://docs.python.org/3/library/dis.html#opcode-UNPACK_EX + // TOS is an iterable + // items may contain StarredExpr, we should check it + int starred_i = -1; + for(int i=0; iis_starred()) continue; + if(starred_i == -1) starred_i = i; + else return false; // multiple StarredExpr not allowed + } + + if(starred_i == -1){ + // Unpacks TOS into count individual values, which are put onto the stack right-to-left. + ctx->emit(OP_UNPACK_SEQUENCE, items.size(), line); + }else{ + // starred assignment target must be in a tuple + if(items.size() == 1) return false; + // starred assignment target must be the last one (differ from CPython) + if(starred_i != items.size()-1) return false; + ctx->emit(OP_UNPACK_EX, items.size()-1, line); + } + for(auto& e: items){ + bool ok = e->emit_store(ctx); + if(!ok) return false; + } return true; } diff --git a/src/opcodes.h b/src/opcodes.h index 07325b0c..ffd63177 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -94,5 +94,7 @@ OPCODE(FOR_ITER) OPCODE(IMPORT_NAME) OPCODE(IMPORT_STAR) /**************************/ +OPCODE(UNPACK_SEQUENCE) +OPCODE(UNPACK_EX) /**************************/ #endif \ No newline at end of file