blueloveTH %!s(int64=2) %!d(string=hai) anos
pai
achega
919d7a465c
Modificáronse 5 ficheiros con 71 adicións e 11 borrados
  1. 12 0
      src/ceval.h
  2. 6 6
      src/compiler.h
  3. 45 2
      src/expr.h
  4. 6 3
      src/lexer.h
  5. 2 0
      src/opcodes.h

+ 12 - 0
src/ceval.h

@@ -69,6 +69,12 @@ __NEXT_STEP:;
     TARGET(POP_TOP) POP(); DISPATCH();
     TARGET(DUP_TOP) PUSH(TOP()); DISPATCH();
     TARGET(ROT_TWO) std::swap(TOP(), SECOND()); DISPATCH();
+    TARGET(ROT_THREE)
+        _0 = TOP();
+        TOP() = SECOND();
+        SECOND() = THIRD();
+        THIRD() = _0;
+        DISPATCH();
     TARGET(PRINT_EXPR)
         if(TOP() != None) _stdout(this, CAST(Str&, py_repr(TOP())) + "\n");
         POP();
@@ -408,6 +414,12 @@ __NEXT_STEP:;
         if(py_bool(TOP()) == false) frame->jump_abs(byte.arg);
         else POP();
         DISPATCH();
+    TARGET(SHORTCUT_IF_FALSE_OR_POP)
+        if(py_bool(TOP()) == false){        // [b, False]
+            STACK_SHRINK(2);                // []
+            PUSH(vm->False);                // [False]
+            frame->jump_abs(byte.arg);
+        } else POP();                       // [b]
     TARGET(LOOP_CONTINUE)
         frame->jump_abs(co_blocks[byte.block].start);
         DISPATCH();

+ 6 - 6
src/compiler.h

@@ -93,12 +93,12 @@ class Compiler {
         rules[TK("**")] =       { nullptr,               METHOD(exprBinaryOp),       PREC_EXPONENT };
         rules[TK(">")] =        { nullptr,               METHOD(exprBinaryOp),       PREC_COMPARISION };
         rules[TK("<")] =        { nullptr,               METHOD(exprBinaryOp),       PREC_COMPARISION };
-        rules[TK("==")] =       { nullptr,               METHOD(exprBinaryOp),       PREC_EQUALITY };
-        rules[TK("!=")] =       { nullptr,               METHOD(exprBinaryOp),       PREC_EQUALITY };
+        rules[TK("==")] =       { nullptr,               METHOD(exprBinaryOp),       PREC_COMPARISION };
+        rules[TK("!=")] =       { nullptr,               METHOD(exprBinaryOp),       PREC_COMPARISION };
         rules[TK(">=")] =       { nullptr,               METHOD(exprBinaryOp),       PREC_COMPARISION };
         rules[TK("<=")] =       { nullptr,               METHOD(exprBinaryOp),       PREC_COMPARISION };
-        rules[TK("in")] =       { nullptr,               METHOD(exprBinaryOp),       PREC_TEST };
-        rules[TK("is")] =       { nullptr,               METHOD(exprBinaryOp),       PREC_TEST };
+        rules[TK("in")] =       { nullptr,               METHOD(exprBinaryOp),       PREC_COMPARISION };
+        rules[TK("is")] =       { nullptr,               METHOD(exprBinaryOp),       PREC_COMPARISION };
         rules[TK("<<")] =       { nullptr,               METHOD(exprBinaryOp),       PREC_BITWISE_SHIFT };
         rules[TK(">>")] =       { nullptr,               METHOD(exprBinaryOp),       PREC_BITWISE_SHIFT };
         rules[TK("&")] =        { nullptr,               METHOD(exprBinaryOp),       PREC_BITWISE_AND };
@@ -107,8 +107,8 @@ class Compiler {
         rules[TK("@")] =        { nullptr,               METHOD(exprBinaryOp),       PREC_FACTOR };
         rules[TK("if")] =       { nullptr,               METHOD(exprTernary),        PREC_TERNARY };
         rules[TK(",")] =        { nullptr,               METHOD(exprTuple),          PREC_TUPLE };
-        rules[TK("not in")] =   { nullptr,               METHOD(exprBinaryOp),       PREC_TEST };
-        rules[TK("is not")] =   { nullptr,               METHOD(exprBinaryOp),       PREC_TEST };
+        rules[TK("not in")] =   { nullptr,               METHOD(exprBinaryOp),       PREC_COMPARISION };
+        rules[TK("is not")] =   { nullptr,               METHOD(exprBinaryOp),       PREC_COMPARISION };
         rules[TK("and") ] =     { nullptr,               METHOD(exprAnd),            PREC_LOGICAL_AND };
         rules[TK("or")] =       { nullptr,               METHOD(exprOr),             PREC_LOGICAL_OR };
         rules[TK("not")] =      { METHOD(exprNot),       nullptr,                    PREC_LOGICAL_NOT };

+ 45 - 2
src/expr.h

@@ -23,6 +23,7 @@ struct Expr{
     virtual bool is_literal() const { return false; }
     virtual bool is_json_object() const { return false; }
     virtual bool is_attrib() const { return false; }
+    virtual bool is_compare() const { return false; }
 
     // for OP_DELETE_XXX
     [[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) { return false; }
@@ -683,8 +684,50 @@ struct BinaryExpr: Expr{
     Expr_ rhs;
     std::string str() const override { return TK_STR(op); }
 
+    bool is_compare() const override {
+        switch(op){
+            case TK("<"): case TK("<="): case TK("=="):
+            case TK("!="): case TK(">"): case TK(">="): return true;
+            default: return false;
+        }
+    }
+
+    void _emit_compare(CodeEmitContext* ctx, std::vector<int>& jmps){
+        if(lhs->is_compare()){
+            static_cast<BinaryExpr*>(lhs.get())->_emit_compare(ctx, jmps);
+        }else{
+            lhs->emit(ctx); // [a]
+        }
+        rhs->emit(ctx); // [a, b]
+        ctx->emit(OP_DUP_TOP, BC_NOARG, line);      // [a, b, b]
+        ctx->emit(OP_ROT_THREE, BC_NOARG, line);    // [b, a, b]
+        switch(op){
+            case TK("<"):   ctx->emit(OP_COMPARE_LT, BC_NOARG, line);  break;
+            case TK("<="):  ctx->emit(OP_COMPARE_LE, BC_NOARG, line);  break;
+            case TK("=="):  ctx->emit(OP_COMPARE_EQ, BC_NOARG, line);  break;
+            case TK("!="):  ctx->emit(OP_COMPARE_NE, BC_NOARG, line);  break;
+            case TK(">"):   ctx->emit(OP_COMPARE_GT, BC_NOARG, line);  break;
+            case TK(">="):  ctx->emit(OP_COMPARE_GE, BC_NOARG, line);  break;
+            default: UNREACHABLE();
+        }
+        // [b, RES]
+        int index = ctx->emit(OP_SHORTCUT_IF_FALSE_OR_POP, BC_NOARG, line);
+        jmps.push_back(index);
+    }
+
     void emit(CodeEmitContext* ctx) override {
-        lhs->emit(ctx);
+        
+        if(is_compare() && lhs->is_compare()){
+            // (a < b) < c
+            std::vector<int> jmps;
+            static_cast<BinaryExpr*>(lhs.get())->_emit_compare(ctx, jmps);
+            // [b, RES]
+            for(int i: jmps) ctx->patch_jump(i);
+        }else{
+            // (1 + 2) < c
+            lhs->emit(ctx);
+        }
+
         rhs->emit(ctx);
         switch (op) {
             case TK("+"):   ctx->emit(OP_BINARY_ADD, BC_NOARG, line);  break;
@@ -701,7 +744,7 @@ struct BinaryExpr: Expr{
             case TK("!="):  ctx->emit(OP_COMPARE_NE, BC_NOARG, line);  break;
             case TK(">"):   ctx->emit(OP_COMPARE_GT, BC_NOARG, line);  break;
             case TK(">="):  ctx->emit(OP_COMPARE_GE, BC_NOARG, line);  break;
-            
+
             case TK("in"):      ctx->emit(OP_CONTAINS_OP, 0, line);   break;
             case TK("not in"):  ctx->emit(OP_CONTAINS_OP, 1, line);   break;
             case TK("is"):      ctx->emit(OP_IS_OP, 0, line);         break;

+ 6 - 3
src/lexer.h

@@ -79,9 +79,12 @@ enum Precedence {
   PREC_LOGICAL_OR,    // or
   PREC_LOGICAL_AND,   // and
   PREC_LOGICAL_NOT,   // not
-  PREC_EQUALITY,      // == !=
-  PREC_TEST,          // in / is / is not / not in
-  PREC_COMPARISION,   // < > <= >=
+  /* https://docs.python.org/3/reference/expressions.html#comparisons
+   * Unlike C, all comparison operations in Python have the same priority,
+   * which is lower than that of any arithmetic, shifting or bitwise operation.
+   * Also unlike C, expressions like a < b < c have the interpretation that is conventional in mathematics.
+   */
+  PREC_COMPARISION,   // < > <= >= != ==, in / is / is not / not in
   PREC_BITWISE_OR,    // |
   PREC_BITWISE_XOR,   // ^
   PREC_BITWISE_AND,   // &

+ 2 - 0
src/opcodes.h

@@ -6,6 +6,7 @@ OPCODE(NO_OP)
 OPCODE(POP_TOP)
 OPCODE(DUP_TOP)
 OPCODE(ROT_TWO)
+OPCODE(ROT_THREE)
 OPCODE(PRINT_EXPR)
 /**************************/
 OPCODE(LOAD_CONST)
@@ -75,6 +76,7 @@ OPCODE(JUMP_ABSOLUTE)
 OPCODE(POP_JUMP_IF_FALSE)
 OPCODE(JUMP_IF_TRUE_OR_POP)
 OPCODE(JUMP_IF_FALSE_OR_POP)
+OPCODE(SHORTCUT_IF_FALSE_OR_POP)
 OPCODE(LOOP_CONTINUE)
 OPCODE(LOOP_BREAK)
 OPCODE(GOTO)