From 919d7a465c1dddd19d26879f36066baf6f53c018 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 4 Jun 2023 21:03:14 +0800 Subject: [PATCH] ... --- src/ceval.h | 12 ++++++++++++ src/compiler.h | 12 ++++++------ src/expr.h | 47 +++++++++++++++++++++++++++++++++++++++++++++-- src/lexer.h | 9 ++++++--- src/opcodes.h | 2 ++ 5 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/ceval.h b/src/ceval.h index 523339b6..0a8c94c9 100644 --- a/src/ceval.h +++ b/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(); diff --git a/src/compiler.h b/src/compiler.h index f8a18ee9..fc01d199 100644 --- a/src/compiler.h +++ b/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 }; diff --git a/src/expr.h b/src/expr.h index 2cfc71f8..a654f77c 100644 --- a/src/expr.h +++ b/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& jmps){ + if(lhs->is_compare()){ + static_cast(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 jmps; + static_cast(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; diff --git a/src/lexer.h b/src/lexer.h index 6055831f..c3f09fd6 100644 --- a/src/lexer.h +++ b/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, // & diff --git a/src/opcodes.h b/src/opcodes.h index 739b2c37..4fdfba5d 100644 --- a/src/opcodes.h +++ b/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)