blueloveTH пре 3 година
родитељ
комит
4bb967d426
5 измењених фајлова са 65 додато и 55 уклоњено
  1. 9 1
      src/codeobject.h
  2. 39 47
      src/compiler.h
  3. 3 0
      src/opcodes.h
  4. 1 1
      src/parser.h
  5. 13 6
      src/vm.h

+ 9 - 1
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<int> 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();
     }

+ 39 - 47
src/compiler.h

@@ -15,19 +15,12 @@ struct GrammarRule{
     Precedence precedence;
 };
 
-struct Loop {
-    int start;
-    std::vector<int> breaks;
-    Loop(int start) : start(start) {}
-};
-
 enum StringType { NORMAL_STRING, RAW_STRING, F_STRING };
 
 class Compiler {
 public:
     pkpy::unique_ptr<Parser> parser;
     std::stack<_Code> codes;
-    std::stack<Loop> 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<Parser>(
@@ -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);

+ 3 - 0
src/opcodes.h

@@ -76,4 +76,7 @@ OPCODE(JUMP_RELATIVE)
 
 OPCODE(RAISE_VARARGS)
 
+OPCODE(LOOP_BREAK)
+OPCODE(LOOP_CONTINUE)
+
 #endif

+ 1 - 1
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 **/

+ 13 - 6
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 != "<builtins>"){
-                std::cout << disassemble(code) << std::endl;
-            }
-            
+            // if(filename != "<builtins>") std::cout << disassemble(code) << std::endl;
             return _exec(code, _module, {});
         }catch (const _Error& e){
             *_stderr << e.what() << '\n';