blueloveTH il y a 3 ans
Parent
commit
b5aba376fe
6 fichiers modifiés avec 130 ajouts et 86 suppressions
  1. 7 1
      src/codeobject.h
  2. 61 64
      src/compiler.h
  3. 2 2
      src/opcodes.h
  4. 2 1
      src/parser.h
  5. 10 0
      src/pointer.h
  6. 48 18
      src/vm.h

+ 7 - 1
src/codeobject.h

@@ -139,9 +139,15 @@ public:
         this->ip = i;
         this->ip = i;
     }
     }
 
 
-    inline PyVarList popNReversed(VM* vm, int n){
+    PyVarList popNValuesReversed(VM* vm, int n){
         PyVarList v(n);
         PyVarList v(n);
         for(int i=n-1; i>=0; i--) v[i] = popValue(vm);
         for(int i=n-1; i>=0; i--) v[i] = popValue(vm);
         return v;
         return v;
     }
     }
+
+    PyVarList __popNReversed(int n){
+        PyVarList v(n);
+        for(int i=n-1; i>=0; i--) v[i] = __pop();
+        return v;
+    }
 };
 };

+ 61 - 64
src/compiler.h

@@ -26,19 +26,18 @@ struct Loop {
     Loop(bool forLoop, int start) : forLoop(forLoop), start(start) {}
     Loop(bool forLoop, int start) : forLoop(forLoop), start(start) {}
 };
 };
 
 
-#define ExprCommaSplitArgs(end) \
-    int ARGC = 0;               \
-    do {                        \
-        matchNewLines();        \
-        if (peek() == TK(end)) break;  \
-        compileExpression();    \
-        ARGC++;                \
-        matchNewLines();        \
-    } while (match(TK(",")));   \
-    matchNewLines();            \
+#define ExprCommaSplitArgs(end)     \
+    int ARGC = 0;                   \
+    do {                            \
+        matchNewLines();            \
+        if (peek() == TK(end)) break;   \
+        EXPR();                     \
+        ARGC++;                     \
+        matchNewLines();            \
+    } while (match(TK(",")));       \
+    matchNewLines();                \
     consume(TK(end));
     consume(TK(end));
 
 
-
 class Compiler {
 class Compiler {
 public:
 public:
     std::unique_ptr<Parser> parser;
     std::unique_ptr<Parser> parser;
@@ -104,14 +103,19 @@ public:
         rules[TK("@id")] =      { METHOD(exprName),      NO_INFIX };
         rules[TK("@id")] =      { METHOD(exprName),      NO_INFIX };
         rules[TK("@num")] =     { METHOD(exprLiteral),   NO_INFIX };
         rules[TK("@num")] =     { METHOD(exprLiteral),   NO_INFIX };
         rules[TK("@str")] =     { METHOD(exprLiteral),   NO_INFIX };
         rules[TK("@str")] =     { METHOD(exprLiteral),   NO_INFIX };
-        rules[TK("=")] =        { nullptr,               METHOD(exprAssign),         PREC_LOWEST };
-        rules[TK("+=")] =       { nullptr,               METHOD(exprAssign),         PREC_LOWEST };
-        rules[TK("-=")] =       { nullptr,               METHOD(exprAssign),         PREC_LOWEST };
-        rules[TK("*=")] =       { nullptr,               METHOD(exprAssign),         PREC_LOWEST };
-        rules[TK("/=")] =       { nullptr,               METHOD(exprAssign),         PREC_LOWEST };
-        rules[TK("//=")] =      { nullptr,               METHOD(exprAssign),         PREC_LOWEST };
+        rules[TK("=")] =        { nullptr,               METHOD(exprAssign),         PREC_ASSIGNMENT };
+        rules[TK("+=")] =       { nullptr,               METHOD(exprAssign),         PREC_ASSIGNMENT };
+        rules[TK("-=")] =       { nullptr,               METHOD(exprAssign),         PREC_ASSIGNMENT };
+        rules[TK("*=")] =       { nullptr,               METHOD(exprAssign),         PREC_ASSIGNMENT };
+        rules[TK("/=")] =       { nullptr,               METHOD(exprAssign),         PREC_ASSIGNMENT };
+        rules[TK("//=")] =      { nullptr,               METHOD(exprAssign),         PREC_ASSIGNMENT };
+        rules[TK(",")] =        { nullptr,               METHOD(exprComma),          PREC_COMMA };
 #undef METHOD
 #undef METHOD
 #undef NO_INFIX
 #undef NO_INFIX
+
+#define EXPR() parsePrecedence(PREC_COMMA)              // no '=' and ',' just a simple expression
+#define EXPR_TUPLE() parsePrecedence(PREC_ASSIGNMENT)   // no '=', but ',' is allowed
+#define EXPR_ANY() parsePrecedence(PREC_NONE)
     }
     }
 
 
     void eatString(bool single_quote) {
     void eatString(bool single_quote) {
@@ -297,15 +301,15 @@ public:
 
 
     }
     }
 
 
-    void exprAssign(){
+    void exprAssign() {
         _TokenType op = parser->previous.type;
         _TokenType op = parser->previous.type;
         if(op == TK("=")) {     // a = (expr)
         if(op == TK("=")) {     // a = (expr)
-            compileExpressionTuple();
+            EXPR_TUPLE();
             emitCode(OP_STORE_PTR);
             emitCode(OP_STORE_PTR);
         }else{                  // a += (expr) -> a = a + (expr)
         }else{                  // a += (expr) -> a = a + (expr)
             // TODO: optimization is needed for inplace operators
             // TODO: optimization is needed for inplace operators
             emitCode(OP_DUP_TOP);
             emitCode(OP_DUP_TOP);
-            compileExpression();
+            EXPR();
             switch (op) {
             switch (op) {
                 case TK("+="):      emitCode(OP_BINARY_OP, 0);  break;
                 case TK("+="):      emitCode(OP_BINARY_OP, 0);  break;
                 case TK("-="):      emitCode(OP_BINARY_OP, 1);  break;
                 case TK("-="):      emitCode(OP_BINARY_OP, 1);  break;
@@ -318,6 +322,15 @@ public:
         }
         }
     }
     }
 
 
+    void exprComma() {
+        int size = 1;       // an expr is in the stack now
+        do {
+            EXPR();         // NOTE: "1," will fail, "1,2" will be ok
+            size++;
+        } while(match(TK(",")));
+        emitCode(OP_BUILD_SMART_TUPLE, size);
+    }
+
     void exprOr() {
     void exprOr() {
         int patch = emitCode(OP_JUMP_IF_TRUE_OR_POP);
         int patch = emitCode(OP_JUMP_IF_TRUE_OR_POP);
         parsePrecedence(PREC_LOGICAL_OR);
         parsePrecedence(PREC_LOGICAL_OR);
@@ -371,7 +384,7 @@ public:
 
 
     void exprGrouping() {
     void exprGrouping() {
         matchNewLines();
         matchNewLines();
-        compileExpressionTuple();
+        EXPR_TUPLE();
         matchNewLines();
         matchNewLines();
         consume(TK(")"));
         consume(TK(")"));
     }
     }
@@ -386,8 +399,8 @@ public:
         do {
         do {
             matchNewLines();
             matchNewLines();
             if (peek() == TK("}")) break;
             if (peek() == TK("}")) break;
-            compileExpression();consume(TK(":"));compileExpression();
-            emitCode(OP_BUILD_TUPLE, 2);
+            EXPR();consume(TK(":"));EXPR();
+            emitCode(OP_BUILD_SMART_TUPLE, 2);
             size++;
             size++;
             matchNewLines();
             matchNewLines();
         } while (match(TK(",")));
         } while (match(TK(",")));
@@ -425,17 +438,17 @@ public:
             if(match(TK("]"))){
             if(match(TK("]"))){
                 emitCode(OP_LOAD_NONE);
                 emitCode(OP_LOAD_NONE);
             }else{
             }else{
-                compileExpression();
+                EXPR();
                 consume(TK("]"));
                 consume(TK("]"));
             }
             }
             emitCode(OP_BUILD_SLICE);
             emitCode(OP_BUILD_SLICE);
         }else{
         }else{
-            compileExpression();
+            EXPR();
             if(match(TK(":"))){
             if(match(TK(":"))){
                 if(match(TK("]"))){
                 if(match(TK("]"))){
                     emitCode(OP_LOAD_NONE);
                     emitCode(OP_LOAD_NONE);
                 }else{
                 }else{
-                    compileExpression();
+                    EXPR();
                     consume(TK("]"));
                     consume(TK("]"));
                 }
                 }
                 emitCode(OP_BUILD_SLICE);
                 emitCode(OP_BUILD_SLICE);
@@ -457,23 +470,6 @@ public:
         }
         }
     }
     }
 
 
-    void parsePrecedence(Precedence precedence) {
-        lexToken();
-        GrammarFn prefix = rules[parser->previous.type].prefix;
-
-        if (prefix == nullptr) {
-            throw SyntaxError(path, parser->previous, "expected an expression");
-        }
-
-        (this->*prefix)();
-        while (rules[peek()].precedence >= precedence) {
-            lexToken();
-            _TokenType op = parser->previous.type;
-            GrammarFn infix = rules[op].infix;
-            (this->*infix)();
-        }
-    }
-
     void keepOpcodeLine(){
     void keepOpcodeLine(){
         int i = getCode()->co_code.size() - 1;
         int i = getCode()->co_code.size() - 1;
         getCode()->co_code[i].line = getCode()->co_code[i-1].line;
         getCode()->co_code[i].line = getCode()->co_code[i-1].line;
@@ -527,29 +523,30 @@ public:
             }
             }
             int index = getCode()->addName(tkmodule.str(), NAME_GLOBAL);
             int index = getCode()->addName(tkmodule.str(), NAME_GLOBAL);
             emitCode(OP_STORE_NAME_PTR, index);
             emitCode(OP_STORE_NAME_PTR, index);
-        } while (match(TK(",")) && (matchNewLines(), true));
+        } while (match(TK(",")));
         consumeEndStatement();
         consumeEndStatement();
     }
     }
 
 
-    // Compiles an expression. An expression will result a value on top of the stack.
-    void compileExpression() {
-        parsePrecedence(PREC_LOWEST);
-    }
+    void parsePrecedence(Precedence precedence) {
+        lexToken();
+        GrammarFn prefix = rules[parser->previous.type].prefix;
 
 
-    // Compiles an expression. Support tuple syntax.
-    void compileExpressionTuple() {
-        int size = 0;
-        while (true) {
-            compileExpression();
-            size++;
-            if (!match(TK(","))) break;
+        if (prefix == nullptr) {
+            throw SyntaxError(path, parser->previous, "expected an expression");
+        }
+
+        (this->*prefix)();
+        while (rules[peek()].precedence > precedence) {
+            lexToken();
+            _TokenType op = parser->previous.type;
+            GrammarFn infix = rules[op].infix;
+            (this->*infix)();
         }
         }
-        if(size > 1) emitCode(OP_BUILD_TUPLE, size);
     }
     }
 
 
     void compileIfStatement() {
     void compileIfStatement() {
         matchNewLines();
         matchNewLines();
-        compileExpression(); //< Condition.
+        EXPR_TUPLE();
 
 
         int ifpatch = emitCode(OP_POP_JUMP_IF_FALSE);
         int ifpatch = emitCode(OP_POP_JUMP_IF_FALSE);
         compileBlockBody();
         compileBlockBody();
@@ -583,7 +580,7 @@ public:
 
 
     void compileWhileStatement() {
     void compileWhileStatement() {
         Loop& loop = enterLoop(false);
         Loop& loop = enterLoop(false);
-        compileExpression();
+        EXPR_TUPLE();
         int patch = emitCode(OP_POP_JUMP_IF_FALSE);
         int patch = emitCode(OP_POP_JUMP_IF_FALSE);
         compileBlockBody();
         compileBlockBody();
         emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine();
         emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine();
@@ -598,7 +595,7 @@ public:
             codes.size()>1 ? NAME_LOCAL : NAME_GLOBAL
             codes.size()>1 ? NAME_LOCAL : NAME_GLOBAL
         );
         );
         consume(TK("in"));
         consume(TK("in"));
-        compileExpressionTuple();
+        EXPR_TUPLE();
         emitCode(OP_GET_ITER);
         emitCode(OP_GET_ITER);
         Loop& loop = enterLoop(true);
         Loop& loop = enterLoop(true);
         int patch = emitCode(OP_FOR_ITER);
         int patch = emitCode(OP_FOR_ITER);
@@ -628,7 +625,7 @@ public:
             if(matchEndStatement()){
             if(matchEndStatement()){
                 emitCode(OP_LOAD_NONE);
                 emitCode(OP_LOAD_NONE);
             }else{
             }else{
-                compileExpressionTuple();
+                EXPR_TUPLE();
                 consumeEndStatement();
                 consumeEndStatement();
             }
             }
             emitCode(OP_RETURN_VALUE);
             emitCode(OP_RETURN_VALUE);
@@ -639,23 +636,23 @@ public:
         } else if (match(TK("for"))) {
         } else if (match(TK("for"))) {
             compileForStatement();
             compileForStatement();
         } else if(match(TK("assert"))){
         } else if(match(TK("assert"))){
-            compileExpression();
+            EXPR();
             emitCode(OP_ASSERT);
             emitCode(OP_ASSERT);
             consumeEndStatement();
             consumeEndStatement();
         } else if(match(TK("raise"))){
         } else if(match(TK("raise"))){
             consume(TK("@id"));         // dummy exception type
             consume(TK("@id"));         // dummy exception type
             emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(parser->previous.str())));
             emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(parser->previous.str())));
-            consume(TK("("));compileExpression();consume(TK(")"));
+            consume(TK("("));EXPR();consume(TK(")"));
             emitCode(OP_RAISE_ERROR);
             emitCode(OP_RAISE_ERROR);
             consumeEndStatement();
             consumeEndStatement();
         } else if(match(TK("del"))){
         } else if(match(TK("del"))){
-            compileExpression();
+            EXPR();
             emitCode(OP_DELETE_PTR);
             emitCode(OP_DELETE_PTR);
             consumeEndStatement();
             consumeEndStatement();
         } else if(match(TK("pass"))){
         } else if(match(TK("pass"))){
             consumeEndStatement();
             consumeEndStatement();
         } else {
         } else {
-            compileExpressionTuple();
+            EXPR_ANY();
             consumeEndStatement();
             consumeEndStatement();
 
 
             // If last op is not an assignment, pop the result.
             // If last op is not an assignment, pop the result.

+ 2 - 2
src/opcodes.h

@@ -18,10 +18,8 @@ OPCODE(UNARY_NOT)
 OPCODE(DUP_TOP)
 OPCODE(DUP_TOP)
 
 
 OPCODE(BUILD_LIST)
 OPCODE(BUILD_LIST)
-OPCODE(BUILD_TUPLE)
 OPCODE(BUILD_MAP)
 OPCODE(BUILD_MAP)
 OPCODE(BUILD_SLICE)
 OPCODE(BUILD_SLICE)
-OPCODE(UNPACK_SEQUENCE)
 
 
 OPCODE(GET_ITER)
 OPCODE(GET_ITER)
 OPCODE(FOR_ITER)
 OPCODE(FOR_ITER)
@@ -49,4 +47,6 @@ OPCODE(STORE_NAME_PTR)      // arg for the name_ptr, [expr], directly store to t
 OPCODE(STORE_PTR)           // no arg, [ptr, expr] -> *ptr = expr
 OPCODE(STORE_PTR)           // no arg, [ptr, expr] -> *ptr = expr
 OPCODE(DELETE_PTR)          // no arg, [ptr] -> [] -> delete ptr
 OPCODE(DELETE_PTR)          // no arg, [ptr] -> [] -> delete ptr
 
 
+OPCODE(BUILD_SMART_TUPLE)   // if all elements are pointers, build a compound pointer, otherwise build a tuple
+
 #endif
 #endif

+ 2 - 1
src/parser.h

@@ -65,7 +65,8 @@ struct Token{
 
 
 enum Precedence {
 enum Precedence {
   PREC_NONE,
   PREC_NONE,
-  PREC_LOWEST,
+  PREC_ASSIGNMENT,    // =
+  PREC_COMMA,         // ,
   PREC_LOGICAL_OR,    // or
   PREC_LOGICAL_OR,    // or
   PREC_LOGICAL_AND,   // and
   PREC_LOGICAL_AND,   // and
   PREC_EQUALITY,      // == !=
   PREC_EQUALITY,      // == !=

+ 10 - 0
src/pointer.h

@@ -49,3 +49,13 @@ struct IndexPointer : BasePointer {
     void set(VM* vm, Frame* frame, PyVar val) const;
     void set(VM* vm, Frame* frame, PyVar val) const;
     void del(VM* vm, Frame* frame) const;
     void del(VM* vm, Frame* frame) const;
 };
 };
+
+struct CompoundPointer : BasePointer {
+    const std::vector<_Pointer> pointers;
+    CompoundPointer(std::vector<_Pointer> pointers) : pointers(pointers) {}
+    CompoundPointer(std::vector<_Pointer>&& pointers) : pointers(pointers) {}
+
+    PyVar get(VM* vm, Frame* frame) const;
+    void set(VM* vm, Frame* frame, PyVar val) const;
+    void del(VM* vm, Frame* frame) const;
+};

+ 48 - 18
src/vm.h

@@ -163,6 +163,27 @@ public:
                 _Pointer p = PyPointer_AS_C(frame->__pop());
                 _Pointer p = PyPointer_AS_C(frame->__pop());
                 p->del(this, frame.get());
                 p->del(this, frame.get());
             } break;
             } break;
+            case OP_BUILD_SMART_TUPLE:
+            {
+                PyVarList items = frame->__popNReversed(byte.arg);
+                bool done = false;
+                for(auto& item : items){
+                    if(!item->isType(_tp_pointer)) {
+                        done = true;
+                        PyVarList values(items.size());
+                        for(int i=0; i<items.size(); i++){
+                            values[i] = frame->__deref_pointer(this, items[i]);
+                        }
+                        frame->push(PyTuple(values));
+                        break;
+                    }
+                }
+                if(done) break;
+                std::vector<_Pointer> pointers(items.size());
+                for(int i=0; i<items.size(); i++)
+                    pointers[i] = PyPointer_AS_C(items[i]);
+                frame->push(PyPointer(std::make_shared<CompoundPointer>(pointers)));
+            } break;
             case OP_STORE_FUNCTION:
             case OP_STORE_FUNCTION:
                 {
                 {
                     PyVar obj = frame->popValue(this);
                     PyVar obj = frame->popValue(this);
@@ -190,16 +211,6 @@ public:
                     callstack.pop();
                     callstack.pop();
                     return ret;
                     return ret;
                 } break;
                 } break;
-            case OP_UNPACK_SEQUENCE:
-                {
-                    PyVar seq = frame->popValue(this);
-                    bool iterable = (seq->isType(_tp_tuple) || seq->isType(_tp_list));
-                    if(!iterable) _error("TypeError", "only tuple and list can be unpacked");
-                    const PyVarList& objs = std::get<PyVarList>(seq->_native);
-                    if(objs.size() > byte.arg) _error("ValueError", "too many values to unpack (expected " + std::to_string(byte.arg) + ")");
-                    if(objs.size() < byte.arg) _error("ValueError", "not enough values to unpack (expected " + std::to_string(byte.arg) + ", got " + std::to_string(objs.size()) + ")");
-                    for(auto it=objs.rbegin(); it!=objs.rend(); it++) frame->push(*it);
-                } break;
             case OP_PRINT_EXPR:
             case OP_PRINT_EXPR:
                 {
                 {
                     const PyVar& expr = frame->topValue(this);
                     const PyVar& expr = frame->topValue(this);
@@ -254,24 +265,19 @@ public:
                 } break;
                 } break;
             case OP_BUILD_LIST:
             case OP_BUILD_LIST:
                 {
                 {
-                    PyVarList items = frame->popNReversed(this, byte.arg);
+                    PyVarList items = frame->popNValuesReversed(this, byte.arg);
                     frame->push(PyList(items));
                     frame->push(PyList(items));
                 } break;
                 } break;
             case OP_BUILD_MAP:
             case OP_BUILD_MAP:
                 {
                 {
-                    PyVarList items = frame->popNReversed(this, byte.arg);
+                    PyVarList items = frame->popNValuesReversed(this, byte.arg);
                     PyVar obj = call(builtins->attribs["dict"], {PyList(items)});
                     PyVar obj = call(builtins->attribs["dict"], {PyList(items)});
                     frame->push(obj);
                     frame->push(obj);
                 } break;
                 } break;
-            case OP_BUILD_TUPLE:
-                {
-                    PyVarList items = frame->popNReversed(this, byte.arg);
-                    frame->push(PyTuple(items));
-                } break;
             case OP_DUP_TOP: frame->push(frame->topValue(this)); break;
             case OP_DUP_TOP: frame->push(frame->topValue(this)); break;
             case OP_CALL:
             case OP_CALL:
                 {
                 {
-                    PyVarList args = frame->popNReversed(this, byte.arg);
+                    PyVarList args = frame->popNValuesReversed(this, byte.arg);
                     PyVar callable = frame->popValue(this);
                     PyVar callable = frame->popValue(this);
                     frame->push(call(callable, args));
                     frame->push(call(callable, args));
                 } break;
                 } break;
@@ -640,6 +646,30 @@ void IndexPointer::del(VM* vm, Frame* frame) const{
     vm->call(obj, __delitem__, {index});
     vm->call(obj, __delitem__, {index});
 }
 }
 
 
+PyVar CompoundPointer::get(VM* vm, Frame* frame) const{
+    PyVarList args(pointers.size());
+    for (int i = 0; i < pointers.size(); i++) {
+        args[i] = pointers[i]->get(vm, frame);
+    }
+    return vm->PyTuple(args);
+}
+
+void CompoundPointer::set(VM* vm, Frame* frame, PyVar val) const{
+    if(!val->isType(vm->_tp_tuple) && !val->isType(vm->_tp_list)){
+        vm->_error("TypeError", "only tuple or list can be unpacked");
+    }
+    const PyVarList& args = std::get<PyVarList>(val->_native);
+    if(args.size() > pointers.size()) vm->_error("ValueError", "too many values to unpack");
+    if(args.size() < pointers.size()) vm->_error("ValueError", "not enough values to unpack");
+    for (int i = 0; i < pointers.size(); i++) {
+        pointers[i]->set(vm, frame, args[i]);
+    }
+}
+
+void CompoundPointer::del(VM* vm, Frame* frame) const{
+    for (auto& ptr : pointers) ptr->del(vm, frame);
+}
+
 /**************** Frame ****************/
 /**************** Frame ****************/
 inline PyVar Frame::__deref_pointer(VM* vm, PyVar v){
 inline PyVar Frame::__deref_pointer(VM* vm, PyVar v){
     if(v->isType(vm->_tp_pointer)) v = vm->PyPointer_AS_C(v)->get(vm, this);
     if(v->isType(vm->_tp_pointer)) v = vm->PyPointer_AS_C(v)->get(vm, this);