From 4bb967d426353fdf6ed4643e17bbdd5ae108f995 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Thu, 5 Jan 2023 19:41:51 +0800 Subject: [PATCH] reimpl break/continue --- src/codeobject.h | 10 +++++- src/compiler.h | 86 ++++++++++++++++++++++-------------------------- src/opcodes.h | 3 ++ src/parser.h | 2 +- src/vm.h | 19 +++++++---- 5 files changed, 65 insertions(+), 55 deletions(-) diff --git a/src/codeobject.h b/src/codeobject.h index f79bc48d..95a8b436 100644 --- a/src/codeobject.h +++ b/src/codeobject.h @@ -30,6 +30,7 @@ _Str pad(const _Str& s, const int n){ enum CodeBlockType { NO_BLOCK, FOR_LOOP, + WHILE_LOOP, CONTEXT_MANAGER, TRY_EXCEPT, }; @@ -39,6 +40,9 @@ struct CodeBlock { std::vector id; int parent; // parent index in co_blocks + int start; // start index of this block in co_code, inclusive + int end; // end index of this block in co_code, exclusive + std::string toString() const { if(parent == -1) return ""; std::string s = "["; @@ -87,6 +91,9 @@ struct CodeObject { // tmp variables int _currBlockIndex = 0; + bool __isCurrBlockLoop() const { + return co_blocks[_currBlockIndex].type == FOR_LOOP || co_blocks[_currBlockIndex].type == WHILE_LOOP; + } void __enterBlock(CodeBlockType type){ const CodeBlock& currBlock = co_blocks[_currBlockIndex]; @@ -99,11 +106,12 @@ struct CodeObject { if(it == co_blocks.end()) break; t++; } - co_blocks.push_back(CodeBlock{type, copy, _currBlockIndex}); + co_blocks.push_back(CodeBlock{type, copy, _currBlockIndex, (int)co_code.size()}); _currBlockIndex = co_blocks.size()-1; } void __exitBlock(){ + co_blocks[_currBlockIndex].end = co_code.size(); _currBlockIndex = co_blocks[_currBlockIndex].parent; if(_currBlockIndex < 0) UNREACHABLE(); } diff --git a/src/compiler.h b/src/compiler.h index d018c06d..8e598025 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -15,19 +15,12 @@ struct GrammarRule{ Precedence precedence; }; -struct Loop { - int start; - std::vector breaks; - Loop(int start) : start(start) {} -}; - enum StringType { NORMAL_STRING, RAW_STRING, F_STRING }; class Compiler { public: pkpy::unique_ptr parser; std::stack<_Code> codes; - std::stack loops; bool isCompilingClass = false; int lexingCnt = 0; VM* vm; @@ -42,10 +35,6 @@ public: return parser->src->mode; } - Loop& getLoop() { - return loops.top(); - } - Compiler(VM* vm, const char* source, _Str filename, CompileMode mode){ this->vm = vm; this->parser = pkpy::make_unique( @@ -575,8 +564,8 @@ __LISTCOMP: patchJump(_skipPatch); emitCode(OP_GET_ITER); - Loop& loop = enterLoop(); getCode()->__enterBlock(FOR_LOOP); - int patch = emitCode(OP_FOR_ITER); + getCode()->__enterBlock(FOR_LOOP); + emitCode(OP_FOR_ITER); if(_cond_end_return != -1) { // there is an if condition emitCode(OP_JUMP_ABSOLUTE, _cond_start); @@ -592,9 +581,8 @@ __LISTCOMP: emitCode(OP_LIST_APPEND); } - emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine(); - patchJump(patch); - exitLoop(); getCode()->__exitBlock(); + emitCode(OP_LOOP_CONTINUE); keepOpcodeLine(); + getCode()->__exitBlock(); matchNewLines(mode()==SINGLE_MODE); consume(TK("]")); } @@ -817,26 +805,14 @@ __LISTCOMP: } } - Loop& enterLoop(){ - Loop lp((int)getCode()->co_code.size()); - loops.push(lp); - return loops.top(); - } - - void exitLoop(){ - Loop& lp = loops.top(); - for(int addr : lp.breaks) patchJump(addr); - loops.pop(); - } - void compileWhileLoop() { - Loop& loop = enterLoop(); + getCode()->__enterBlock(WHILE_LOOP); EXPR_TUPLE(); int patch = emitCode(OP_POP_JUMP_IF_FALSE); compileBlockBody(); - emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine(); + emitCode(OP_LOOP_CONTINUE); keepOpcodeLine(); patchJump(patch); - exitLoop(); + getCode()->__exitBlock(); } void EXPR_FOR_VARS(){ @@ -851,24 +827,42 @@ __LISTCOMP: void compileForLoop() { EXPR_FOR_VARS();consume(TK("in")); EXPR_TUPLE(); emitCode(OP_GET_ITER); - Loop& loop = enterLoop(); getCode()->__enterBlock(FOR_LOOP); - int patch = emitCode(OP_FOR_ITER); + getCode()->__enterBlock(FOR_LOOP); + emitCode(OP_FOR_ITER); compileBlockBody(); - emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine(); + emitCode(OP_LOOP_CONTINUE); keepOpcodeLine(); + getCode()->__exitBlock(); + } + + void compileTryExcept() { + getCode()->__enterBlock(TRY_EXCEPT); + compileBlockBody(); + getCode()->__exitBlock(); + int patch = emitCode(OP_JUMP_ABSOLUTE); + consume(TK("except")); + if(match(TK("@id"))){ // exception name + if(match(TK("as"))){ // exception name as alias + consume(TK("@id")); + exprName(); + } + compileBlockBody(); + } + if(match(TK("finally"))){ + consume(TK(":")); + syntaxError("finally is not supported yet"); + } patchJump(patch); - exitLoop(); getCode()->__exitBlock(); } void compileStatement() { if (match(TK("break"))) { - if (loops.empty()) syntaxError("'break' outside loop"); + if (!getCode()->__isCurrBlockLoop()) syntaxError("'break' outside loop"); consumeEndStatement(); - int patch = emitCode(OP_SAFE_JUMP_ABSOLUTE); - getLoop().breaks.push_back(patch); + emitCode(OP_LOOP_BREAK); } else if (match(TK("continue"))) { - if (loops.empty()) syntaxError("'continue' not properly in loop"); + if (!getCode()->__isCurrBlockLoop()) syntaxError("'continue' not properly in loop"); consumeEndStatement(); - emitCode(OP_JUMP_ABSOLUTE, getLoop().start); + emitCode(OP_LOOP_CONTINUE); } else if (match(TK("return"))) { if (codes.size() == 1) syntaxError("'return' outside function"); @@ -885,7 +879,9 @@ __LISTCOMP: compileWhileLoop(); } else if (match(TK("for"))) { compileForLoop(); - } else if(match(TK("assert"))){ + } else if (match(TK("try"))) { + compileTryExcept(); + }else if(match(TK("assert"))){ EXPR(); emitCode(OP_ASSERT); consumeEndStatement(); @@ -937,13 +933,10 @@ __LISTCOMP: } else { EXPR_ANY(); consumeEndStatement(); - // If last op is not an assignment, pop the result. uint8_t lastOp = getCode()->co_code.back().op; - if( lastOp != OP_STORE_NAME_REF && lastOp != OP_STORE_REF){ - if(mode()==SINGLE_MODE && parser->indents.top() == 0){ - emitCode(OP_PRINT_EXPR); - } + if( lastOp!=OP_STORE_NAME_REF && lastOp!=OP_STORE_REF){ + if(mode()==SINGLE_MODE && parser->indents.top()==0) emitCode(OP_PRINT_EXPR); emitCode(OP_POP_TOP); } } @@ -962,7 +955,6 @@ __LISTCOMP: isCompilingClass = true; __compileBlockBody(&Compiler::compileFunction); isCompilingClass = false; - if(superClsNameIdx == -1) emitCode(OP_LOAD_NONE); else emitCode(OP_LOAD_NAME_REF, superClsNameIdx); emitCode(OP_BUILD_CLASS, clsNameIdx); diff --git a/src/opcodes.h b/src/opcodes.h index 65146fa8..65eff463 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -76,4 +76,7 @@ OPCODE(JUMP_RELATIVE) OPCODE(RAISE_VARARGS) +OPCODE(LOOP_BREAK) +OPCODE(LOOP_CONTINUE) + #endif \ No newline at end of file diff --git a/src/parser.h b/src/parser.h index 3f54ef8f..a4089056 100644 --- a/src/parser.h +++ b/src/parser.h @@ -13,7 +13,7 @@ constexpr const char* __TOKENS[] = { "+=", "-=", "*=", "/=", "//=", "%=", "&=", "|=", "^=", /** KW_BEGIN **/ "class", "import", "as", "def", "lambda", "pass", "del", "from", "with", - "None", "in", "is", "and", "or", "not", "True", "False", "global", + "None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally", "goto", "label", // extended keywords, not available in cpython "while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise", /** KW_END **/ diff --git a/src/vm.h b/src/vm.h index ae58805a..138a0cc6 100644 --- a/src/vm.h +++ b/src/vm.h @@ -279,9 +279,20 @@ protected: PyRef_AS_C(it->var)->set(this, frame, it->next()); } else{ - frame->jumpAbsoluteSafe(byte.arg); + int blockEnd = frame->code->co_blocks[byte.block].end; + frame->jumpAbsoluteSafe(blockEnd); } } break; + case OP_LOOP_CONTINUE: + { + int blockStart = frame->code->co_blocks[byte.block].start; + frame->jumpAbsolute(blockStart); + } break; + case OP_LOOP_BREAK: + { + int blockEnd = frame->code->co_blocks[byte.block].end; + frame->jumpAbsoluteSafe(blockEnd); + } break; case OP_JUMP_IF_FALSE_OR_POP: { const PyVar expr = frame->topValue(this); @@ -546,11 +557,7 @@ public: if(_module == nullptr) _module = _main; try { _Code code = compile(source, filename, mode); - - if(filename != ""){ - std::cout << disassemble(code) << std::endl; - } - + // if(filename != "") std::cout << disassemble(code) << std::endl; return _exec(code, _module, {}); }catch (const _Error& e){ *_stderr << e.what() << '\n';