blueloveTH 1 год назад
Родитель
Сommit
60e1f77f8d

+ 1 - 1
include/pocketpy/common/vector.hpp

@@ -254,7 +254,7 @@ struct vector {
         _data[_size].~T();
     }
 
-    T popx_back() {
+    [[nodiscard]] T popx_back() {
         T retval = std::move(back());
         pop_back();
         return retval;

+ 5 - 4
include/pocketpy/compiler/compiler.hpp

@@ -61,18 +61,19 @@ class Compiler {
     /*************************************************/
     void EXPR();
     void EXPR_TUPLE(bool allow_slice = false);
-    Expr_ EXPR_VARS();  // special case for `for loop` and `comp`
+    Expr* EXPR_VARS();  // special case for `for loop` and `comp`
 
     template <typename T, typename... Args>
-    unique_ptr_128<T> make_expr(Args&&... args) {
+    T* make_expr(Args&&... args) {
         static_assert(sizeof(T) <= kPoolExprBlockSize);
+        static_assert(std::is_base_of_v<Expr, T>);
         void* p = PoolExpr_alloc();
-        unique_ptr_128<T> expr(new (p) T(std::forward<Args>(args)...));
+        T* expr = new (p) T(std::forward<Args>(args)...);
         expr->line = prev().line;
         return expr;
     }
 
-    void consume_comp(unique_ptr_128<CompExpr> ce, Expr_ expr);
+    void consume_comp(CompExpr* ce, Expr* expr);
 
     void exprLiteral();
     void exprLong();

+ 108 - 122
include/pocketpy/compiler/expr.hpp

@@ -8,75 +8,19 @@ namespace pkpy {
 struct CodeEmitContext;
 struct Expr;
 
-template <typename T>
-class unique_ptr_128 {
-    T* ptr;
-
-public:
-    unique_ptr_128() : ptr(nullptr) {}
-
-    unique_ptr_128(T* ptr) : ptr(ptr) {}
-
-    T* operator->() const { return ptr; }
-
-    T* get() const { return ptr; }
-
-    T* detach() {
-        T* p = ptr;
-        ptr = nullptr;
-        return p;
-    }
-
-    unique_ptr_128(const unique_ptr_128&) = delete;
-    unique_ptr_128& operator= (const unique_ptr_128&) = delete;
-
-    bool operator== (std::nullptr_t) const { return ptr == nullptr; }
-
-    bool operator!= (std::nullptr_t) const { return ptr != nullptr; }
-
-    ~unique_ptr_128() {
-        if(ptr) {
-            ptr->~T();
-            PoolExpr_dealloc(ptr);
-        }
-    }
-
-    template <typename U>
-    unique_ptr_128(unique_ptr_128<U>&& other) : ptr(other.detach()) {}
-
-    operator bool () const { return ptr != nullptr; }
-
-    template <typename U>
-    unique_ptr_128& operator= (unique_ptr_128<U>&& other) {
-        if(ptr) {
-            ptr->~T();
-            PoolExpr_dealloc(ptr);
-        };
-        ptr = other.detach();
-        return *this;
-    }
-
-    unique_ptr_128& operator= (std::nullptr_t) {
-        if(ptr) {
-            ptr->~T();
-            PoolExpr_dealloc(ptr);
-        }
-        ptr = nullptr;
-        return *this;
-    }
-};
-
-typedef unique_ptr_128<Expr> Expr_;
-typedef small_vector<Expr_, 4> Expr_vector;
-
-template <>
-constexpr inline bool is_trivially_relocatable_v<Expr_> = true;
+typedef small_vector<Expr*, 4> Expr_vector;
 
 struct Expr {
     int line = 0;
     virtual ~Expr() = default;
     virtual void emit_(CodeEmitContext* ctx) = 0;
 
+    Expr() = default;
+    Expr(const Expr&) = delete;
+    Expr(Expr&&) = delete;
+    Expr& operator=(const Expr&) = delete;
+    Expr& operator=(Expr&&) = delete;
+
     virtual bool is_literal() const { return false; }
 
     virtual bool is_json_object() const { return false; }
@@ -106,11 +50,17 @@ struct Expr {
     [[nodiscard]] virtual bool emit_store_inplace(CodeEmitContext* ctx) { return emit_store(ctx); }
 };
 
+inline void delete_expr(Expr* p){
+    if(!p) return;
+    p->Expr::~Expr();
+    PoolExpr_dealloc(p);
+}
+
 struct CodeEmitContext {
     VM* vm;
     FuncDecl_ func;  // optional
     CodeObject_ co;  // 1 CodeEmitContext <=> 1 CodeObject_
-    vector<Expr_> s_expr;
+    vector<Expr*> s_expr;
     int level;
     vector<StrName> global_names;
 
@@ -125,7 +75,7 @@ struct CodeEmitContext {
     int get_loop() const;
     CodeBlock* enter_block(CodeBlockType type);
     void exit_block();
-    void emit_expr();  // clear the expression stack and generate bytecode
+    void emit_expr(bool emit = true);  // clear the expression stack and generate bytecode
     int emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual = false);
     void revert_last_emit_();
     int emit_int(i64 value, int line);
@@ -152,19 +102,33 @@ struct NameExpr : Expr {
     bool is_name() const override { return true; }
 };
 
-struct InvertExpr : Expr {
-    Expr_ child;
+struct _UnaryExpr : Expr {
+    Expr* child;
+    _UnaryExpr(Expr* child) : child(child) {}
+    _UnaryExpr() : child(nullptr) {}
+    ~_UnaryExpr() { delete_expr(child); }
+};
 
-    InvertExpr(Expr_&& child) : child(std::move(child)) {}
+struct _BinaryExpr : Expr {
+    Expr* lhs;
+    Expr* rhs;
+    _BinaryExpr(Expr* lhs, Expr* rhs) : lhs(lhs), rhs(rhs) {}
+    _BinaryExpr() : lhs(nullptr), rhs(nullptr) {}
+    ~_BinaryExpr() {
+        delete_expr(lhs);
+        delete_expr(rhs);
+    }
+};
 
+struct InvertExpr : _UnaryExpr {
+    using _UnaryExpr::_UnaryExpr;
     void emit_(CodeEmitContext* ctx) override;
 };
 
-struct StarredExpr : Expr {
+struct StarredExpr : _UnaryExpr {
     int level;
-    Expr_ child;
 
-    StarredExpr(int level, Expr_&& child) : level(level), child(std::move(child)) {}
+    StarredExpr(Expr* child, int level) : _UnaryExpr(child), level(level) {}
 
     int star_level() const override { return level; }
 
@@ -172,23 +136,18 @@ struct StarredExpr : Expr {
     bool emit_store(CodeEmitContext* ctx) override;
 };
 
-struct NotExpr : Expr {
-    Expr_ child;
-
-    NotExpr(Expr_&& child) : child(std::move(child)) {}
-
+struct NotExpr : _UnaryExpr {
+    using _UnaryExpr::_UnaryExpr;
     void emit_(CodeEmitContext* ctx) override;
 };
 
-struct AndExpr : Expr {
-    Expr_ lhs;
-    Expr_ rhs;
+struct AndExpr : _BinaryExpr {
+    using _BinaryExpr::_BinaryExpr;
     void emit_(CodeEmitContext* ctx) override;
 };
 
-struct OrExpr : Expr {
-    Expr_ lhs;
-    Expr_ rhs;
+struct OrExpr : _BinaryExpr {
+    using _BinaryExpr::_BinaryExpr;
     void emit_(CodeEmitContext* ctx) override;
 };
 
@@ -240,30 +199,40 @@ struct LiteralExpr : Expr {
     bool is_json_object() const override { return true; }
 };
 
-struct NegatedExpr : Expr {
-    Expr_ child;
-
-    NegatedExpr(Expr_&& child) : child(std::move(child)) {}
-
+struct NegatedExpr : _UnaryExpr {
+    using _UnaryExpr::_UnaryExpr;
     void emit_(CodeEmitContext* ctx) override;
-
     bool is_json_object() const override { return child->is_literal(); }
 };
 
 struct SliceExpr : Expr {
-    Expr_ start;
-    Expr_ stop;
-    Expr_ step;
+    Expr* start = nullptr;
+    Expr* stop = nullptr;
+    Expr* step = nullptr;
+
     void emit_(CodeEmitContext* ctx) override;
+
+    ~SliceExpr() {
+        delete_expr(start);
+        delete_expr(stop);
+        delete_expr(step);
+    }
 };
 
 struct DictItemExpr : Expr {
-    Expr_ key;  // maybe nullptr if it is **kwargs
-    Expr_ value;
+    Expr* key;  // maybe nullptr if it is **kwargs
+    Expr* value;
+
+    DictItemExpr(): key(nullptr), value(nullptr) {}
 
     int star_level() const override { return value->star_level(); }
 
     void emit_(CodeEmitContext* ctx) override;
+
+    ~DictItemExpr() {
+        delete_expr(key);
+        delete_expr(value);
+    }
 };
 
 struct SequenceExpr : Expr {
@@ -278,6 +247,10 @@ struct SequenceExpr : Expr {
             item->emit_(ctx);
         ctx->emit_(opcode(), items.size(), line);
     }
+
+    ~SequenceExpr() {
+        for(Expr* item: items) delete_expr(item);
+    }
 };
 
 struct ListExpr : SequenceExpr {
@@ -330,15 +303,22 @@ struct TupleExpr : SequenceExpr {
 };
 
 struct CompExpr : Expr {
-    Expr_ expr;  // loop expr
-    Expr_ vars;  // loop vars
-    Expr_ iter;  // loop iter
-    Expr_ cond;  // optional if condition
+    Expr* expr = nullptr;  // loop expr
+    Expr* vars = nullptr;  // loop vars
+    Expr* iter = nullptr;  // loop iter
+    Expr* cond = nullptr;  // optional if condition
 
     virtual Opcode op0() = 0;
     virtual Opcode op1() = 0;
 
     void emit_(CodeEmitContext* ctx) override;
+
+    ~CompExpr() {
+        delete_expr(expr);
+        delete_expr(vars);
+        delete_expr(iter);
+        delete_expr(cond);
+    }
 };
 
 struct ListCompExpr : CompExpr {
@@ -379,10 +359,8 @@ struct FStringExpr : Expr {
     void emit_(CodeEmitContext* ctx) override;
 };
 
-struct SubscrExpr : Expr {
-    Expr_ a;
-    Expr_ b;
-
+struct SubscrExpr : _BinaryExpr {
+    using _BinaryExpr::_BinaryExpr;
     bool is_subscr() const override { return true; }
 
     void emit_(CodeEmitContext* ctx) override;
@@ -393,11 +371,10 @@ struct SubscrExpr : Expr {
     bool emit_store_inplace(CodeEmitContext* ctx) override;
 };
 
-struct AttribExpr : Expr {
-    Expr_ a;
-    StrName b;
+struct AttribExpr : _UnaryExpr {
+    StrName name;
 
-    AttribExpr(Expr_ a, StrName b) : a(std::move(a)), b(b) {}
+    AttribExpr(Expr* child, StrName name) : _UnaryExpr(child), name(name) {}
 
     void emit_(CodeEmitContext* ctx) override;
     bool emit_del(CodeEmitContext* ctx) override;
@@ -411,32 +388,34 @@ struct AttribExpr : Expr {
 };
 
 struct CallExpr : Expr {
-    Expr_ callable;
+    Expr* callable;
     Expr_vector args;
     // **a will be interpreted as a special keyword argument: {"**": a}
-    vector<std::pair<Str, Expr_>> kwargs;
+    vector<std::pair<StrName, Expr*>> kwargs;
     void emit_(CodeEmitContext* ctx) override;
-};
 
-struct GroupedExpr : Expr {
-    Expr_ a;
-
-    GroupedExpr(Expr_&& a) : a(std::move(a)) {}
+    ~CallExpr() {
+        delete_expr(callable);
+        for(Expr* arg: args) delete_expr(arg);
+        for(auto [_, arg]: kwargs) delete_expr(arg);
+    }
+};
 
-    void emit_(CodeEmitContext* ctx) override { a->emit_(ctx); }
+struct GroupedExpr : _UnaryExpr {
+    using _UnaryExpr::_UnaryExpr;
+    void emit_(CodeEmitContext* ctx) override { child->emit_(ctx); }
 
-    bool emit_del(CodeEmitContext* ctx) override { return a->emit_del(ctx); }
+    bool emit_del(CodeEmitContext* ctx) override { return child->emit_del(ctx); }
 
-    bool emit_store(CodeEmitContext* ctx) override { return a->emit_store(ctx); }
+    bool emit_store(CodeEmitContext* ctx) override { return child->emit_store(ctx); }
 };
 
-struct BinaryExpr : Expr {
+struct BinaryExpr : _BinaryExpr {
     TokenIndex op;
-    Expr_ lhs;
-    Expr_ rhs;
     bool inplace;
 
-    BinaryExpr(bool inplace = false) : inplace(inplace) {}
+    BinaryExpr(TokenIndex op, bool inplace = false)
+        : _BinaryExpr(), op(op), inplace(inplace) {}
 
     bool is_compare() const override;
     void _emit_compare(CodeEmitContext*, small_vector_2<int, 8>&);
@@ -444,10 +423,17 @@ struct BinaryExpr : Expr {
 };
 
 struct TernaryExpr : Expr {
-    Expr_ cond;
-    Expr_ true_expr;
-    Expr_ false_expr;
+    Expr* cond = nullptr;
+    Expr* true_expr = nullptr;
+    Expr* false_expr = nullptr;
+
     void emit_(CodeEmitContext* ctx) override;
+
+    ~TernaryExpr() {
+        delete_expr(cond);
+        delete_expr(true_expr);
+        delete_expr(false_expr);
+    }
 };
 
 }  // namespace pkpy

+ 28 - 28
src/compiler/compiler.cpp

@@ -31,7 +31,7 @@ FuncDecl_ Compiler::push_f_context(Str name) {
 }
 
 void Compiler::pop_context() {
-    if(!ctx()->s_expr.empty()) { throw std::runtime_error("!ctx()->s_expr.empty()"); }
+    assert(ctx()->s_expr.empty());
     // add a `return None` in the end as a guard
     // previously, we only do this if the last opcode is not a return
     // however, this is buggy...since there may be a jump to the end (out of bound) even if the last opcode is a return
@@ -211,7 +211,7 @@ void Compiler::EXPR_TUPLE(bool allow_slice) {
 }
 
 // special case for `for loop` and `comp`
-Expr_ Compiler::EXPR_VARS() {
+Expr* Compiler::EXPR_VARS() {
     Expr_vector items;
     do {
         consume(TK("@id"));
@@ -276,8 +276,7 @@ void Compiler::exprTernary() {
 }
 
 void Compiler::exprBinaryOp() {
-    auto e = make_expr<BinaryExpr>();
-    e->op = prev().type;
+    auto e = make_expr<BinaryExpr>(prev().type);
     e->lhs = ctx()->s_expr.popx_back();
     parse_expression(rules[e->op].precedence + 1);
     e->rhs = ctx()->s_expr.popx_back();
@@ -286,17 +285,19 @@ void Compiler::exprBinaryOp() {
 
 void Compiler::exprNot() {
     parse_expression(PREC_LOGICAL_NOT + 1);
-    ctx()->s_expr.push_back(make_expr<NotExpr>(ctx()->s_expr.popx_back()));
+    NotExpr* e = make_expr<NotExpr>(ctx()->s_expr.popx_back());
+    ctx()->s_expr.push_back(e);
 }
 
 void Compiler::exprUnaryOp() {
     TokenIndex op = prev().type;
     parse_expression(PREC_UNARY + 1);
+    vector<Expr*>& s_expr = ctx()->s_expr;
     switch(op) {
-        case TK("-"): ctx()->s_expr.push_back(make_expr<NegatedExpr>(ctx()->s_expr.popx_back())); break;
-        case TK("~"): ctx()->s_expr.push_back(make_expr<InvertExpr>(ctx()->s_expr.popx_back())); break;
-        case TK("*"): ctx()->s_expr.push_back(make_expr<StarredExpr>(1, ctx()->s_expr.popx_back())); break;
-        case TK("**"): ctx()->s_expr.push_back(make_expr<StarredExpr>(2, ctx()->s_expr.popx_back())); break;
+        case TK("-"): s_expr.push_back(make_expr<NegatedExpr>(s_expr.popx_back())); break;
+        case TK("~"): s_expr.push_back(make_expr<InvertExpr>(s_expr.popx_back())); break;
+        case TK("*"): s_expr.push_back(make_expr<StarredExpr>(s_expr.popx_back(), 1)); break;
+        case TK("**"): s_expr.push_back(make_expr<StarredExpr>(s_expr.popx_back(), 2)); break;
         default: assert(false);
     }
 }
@@ -307,11 +308,11 @@ void Compiler::exprGroup() {
     match_newlines_repl();
     consume(TK(")"));
     if(ctx()->s_expr.back()->is_tuple()) return;
-    Expr_ g = make_expr<GroupedExpr>(ctx()->s_expr.popx_back());
+    Expr* g = make_expr<GroupedExpr>(ctx()->s_expr.popx_back());
     ctx()->s_expr.push_back(std::move(g));
 }
 
-void Compiler::consume_comp(unique_ptr_128<CompExpr> ce, Expr_ expr) {
+void Compiler::consume_comp(CompExpr* ce, Expr* expr) {
     ce->expr = std::move(expr);
     ce->vars = EXPR_VARS();
     consume(TK("in"));
@@ -358,7 +359,7 @@ void Compiler::exprMap() {
         int star_level = ctx()->s_expr.back()->star_level();
         if(star_level == 2 || curr().type == TK(":")) { parsing_dict = true; }
         if(parsing_dict) {
-            auto dict_item = make_expr<DictItemExpr>();
+            DictItemExpr* dict_item = make_expr<DictItemExpr>();
             if(star_level == 2) {
                 dict_item->key = nullptr;
                 dict_item->value = ctx()->s_expr.popx_back();
@@ -401,7 +402,7 @@ void Compiler::exprCall() {
         if(curr().type == TK(")")) break;
         if(curr().type == TK("@id") && next().type == TK("=")) {
             consume(TK("@id"));
-            Str key = prev().str();
+            StrName key(prev().sv());
             consume(TK("="));
             EXPR();
             e->kwargs.push_back({key, ctx()->s_expr.popx_back()});
@@ -476,9 +477,9 @@ void Compiler::exprSlice1() {
 void Compiler::exprSubscr() {
     auto e = make_expr<SubscrExpr>();
     match_newlines_repl();
-    e->a = ctx()->s_expr.popx_back();  // a
+    e->lhs = ctx()->s_expr.popx_back();  // a
     EXPR_TUPLE(true);
-    e->b = ctx()->s_expr.popx_back();  // a[<expr>]
+    e->rhs = ctx()->s_expr.popx_back();  // a[<expr>]
     match_newlines_repl();
     consume(TK("]"));
     ctx()->s_expr.push_back(std::move(e));
@@ -650,7 +651,7 @@ void Compiler::compile_while_loop() {
 }
 
 void Compiler::compile_for_loop() {
-    Expr_ vars = EXPR_VARS();
+    Expr* vars = EXPR_VARS();
     consume(TK("in"));
     EXPR_TUPLE();
     ctx()->emit_expr();
@@ -764,14 +765,14 @@ bool Compiler::try_compile_assignment() {
         case TK("&="):
         case TK("|="):
         case TK("^="): {
-            Expr* lhs_p = ctx()->s_expr.back().get();
+            Expr* lhs_p = ctx()->s_expr.back();
             if(lhs_p->is_starred()) SyntaxError();
             if(ctx()->is_compiling_class) SyntaxError("can't use inplace operator in class definition");
             advance();
             // a[x] += 1;   a and x should be evaluated only once
             // a.x += 1;    a should be evaluated only once
-            auto e = make_expr<BinaryExpr>(true);  // inplace=true
-            e->op = prev().type - 1;               // -1 to remove =
+            // -1 to remove =; inplace=true
+            auto e = make_expr<BinaryExpr>(prev().type - 1, true);
             e->lhs = ctx()->s_expr.popx_back();
             EXPR_TUPLE();
             e->rhs = ctx()->s_expr.popx_back();
@@ -788,7 +789,7 @@ bool Compiler::try_compile_assignment() {
                 n += 1;
             }
             // stack size is n+1
-            Expr_ val = ctx()->s_expr.popx_back();
+            Expr* val = ctx()->s_expr.popx_back();
             val->emit_(ctx());
             for(int j = 1; j < n; j++)
                 ctx()->emit_(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
@@ -894,7 +895,7 @@ void Compiler::compile_stmt() {
         } break;
         case TK("del"): {
             EXPR_TUPLE();
-            Expr_ e = ctx()->s_expr.popx_back();
+            Expr* e = ctx()->s_expr.popx_back();
             bool ok = e->emit_del(ctx());
             if(!ok) SyntaxError();
             consume_end_stmt();
@@ -903,7 +904,7 @@ void Compiler::compile_stmt() {
             EXPR();  // [ <expr> ]
             ctx()->emit_expr();
             ctx()->enter_block(CodeBlockType::CONTEXT_MANAGER);
-            Expr_ as_name;
+            Expr* as_name = nullptr;;
             if(match(TK("as"))) {
                 consume(TK("@id"));
                 as_name = make_expr<NameExpr>(prev().str(), name_scope());
@@ -949,7 +950,7 @@ void Compiler::compile_stmt() {
                     is_typed_name = true;
 
                     if(ctx()->is_compiling_class) {
-                        NameExpr* ne = static_cast<NameExpr*>(ctx()->s_expr.back().get());
+                        NameExpr* ne = static_cast<NameExpr*>(ctx()->s_expr.back());
                         ctx()->emit_(OP_ADD_CLASS_ANNOTATION, ne->name.index, BC_KEEPLINE);
                     }
                 }
@@ -964,8 +965,7 @@ void Compiler::compile_stmt() {
                         ctx()->emit_(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
                     }
                 } else {
-                    assert(ctx()->s_expr.size() == 1);
-                    ctx()->s_expr.pop_back();
+                    ctx()->emit_expr(false);
                 }
             }
             consume_end_stmt();
@@ -975,7 +975,7 @@ void Compiler::compile_stmt() {
 
 void Compiler::consume_type_hints() {
     EXPR();
-    ctx()->s_expr.pop_back();
+    ctx()->emit_expr(false);
 }
 
 void Compiler::_add_decorators(const Expr_vector& decorators) {
@@ -993,7 +993,7 @@ void Compiler::_add_decorators(const Expr_vector& decorators) {
 void Compiler::compile_class(const Expr_vector& decorators) {
     consume(TK("@id"));
     int namei = StrName(prev().sv()).index;
-    Expr_ base = nullptr;
+    Expr* base = nullptr;
     if(match(TK("("))) {
         if(is_expression()) {
             EXPR();
@@ -1294,7 +1294,7 @@ CodeObject_ Compiler::compile() {
         return code;
     } else if(mode() == JSON_MODE) {
         EXPR();
-        Expr_ e = ctx()->s_expr.popx_back();
+        Expr* e = ctx()->s_expr.popx_back();
         if(!e->is_json_object()) SyntaxError("expect a JSON object, literal or array");
         consume(TK("@eof"));
         e->emit_(ctx());

+ 30 - 29
src/compiler/expr.cpp

@@ -41,10 +41,11 @@ void CodeEmitContext::exit_block() {
 }
 
 // clear the expression stack and generate bytecode
-void CodeEmitContext::emit_expr() {
+void CodeEmitContext::emit_expr(bool emit) {
     assert(s_expr.size() == 1);
-    s_expr.back()->emit_(this);
-    s_expr.pop_back();
+    Expr* e = s_expr.popx_back();
+    if(emit) e->emit_(this);
+    delete_expr(e);
 }
 
 int CodeEmitContext::emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual) {
@@ -277,7 +278,7 @@ void NegatedExpr::emit_(CodeEmitContext* ctx) {
     VM* vm = ctx->vm;
     // if child is a int of float, do constant folding
     if(child->is_literal()) {
-        LiteralExpr* lit = static_cast<LiteralExpr*>(child.get());
+        LiteralExpr* lit = static_cast<LiteralExpr*>(child);
         if(std::holds_alternative<i64>(lit->value)) {
             i64 _val = -std::get<i64>(lit->value);
             ctx->emit_int(_val, line);
@@ -540,13 +541,13 @@ void FStringExpr::emit_(CodeEmitContext* ctx) {
 }
 
 void SubscrExpr::emit_(CodeEmitContext* ctx) {
-    a->emit_(ctx);
-    b->emit_(ctx);
+    lhs->emit_(ctx);
+    rhs->emit_(ctx);
     Bytecode last_bc = ctx->co->codes.back();
-    if(b->is_name() && last_bc.op == OP_LOAD_FAST) {
+    if(rhs->is_name() && last_bc.op == OP_LOAD_FAST) {
         ctx->revert_last_emit_();
         ctx->emit_(OP_LOAD_SUBSCR_FAST, last_bc.arg, line);
-    } else if(b->is_literal() && last_bc.op == OP_LOAD_SMALL_INT) {
+    } else if(rhs->is_literal() && last_bc.op == OP_LOAD_SMALL_INT) {
         ctx->revert_last_emit_();
         ctx->emit_(OP_LOAD_SUBSCR_SMALL_INT, last_bc.arg, line);
     } else {
@@ -555,10 +556,10 @@ void SubscrExpr::emit_(CodeEmitContext* ctx) {
 }
 
 bool SubscrExpr::emit_store(CodeEmitContext* ctx) {
-    a->emit_(ctx);
-    b->emit_(ctx);
+    lhs->emit_(ctx);
+    rhs->emit_(ctx);
     Bytecode last_bc = ctx->co->codes.back();
-    if(b->is_name() && last_bc.op == OP_LOAD_FAST) {
+    if(rhs->is_name() && last_bc.op == OP_LOAD_FAST) {
         ctx->revert_last_emit_();
         ctx->emit_(OP_STORE_SUBSCR_FAST, last_bc.arg, line);
     } else {
@@ -568,8 +569,8 @@ bool SubscrExpr::emit_store(CodeEmitContext* ctx) {
 }
 
 void SubscrExpr::emit_inplace(CodeEmitContext* ctx) {
-    a->emit_(ctx);
-    b->emit_(ctx);
+    lhs->emit_(ctx);
+    rhs->emit_(ctx);
     ctx->emit_(OP_DUP_TOP_TWO, BC_NOARG, line);
     ctx->emit_(OP_LOAD_SUBSCR, BC_NOARG, line);
 }
@@ -582,44 +583,44 @@ bool SubscrExpr::emit_store_inplace(CodeEmitContext* ctx) {
 }
 
 bool SubscrExpr::emit_del(CodeEmitContext* ctx) {
-    a->emit_(ctx);
-    b->emit_(ctx);
+    lhs->emit_(ctx);
+    rhs->emit_(ctx);
     ctx->emit_(OP_DELETE_SUBSCR, BC_NOARG, line);
     return true;
 }
 
 void AttribExpr::emit_(CodeEmitContext* ctx) {
-    a->emit_(ctx);
-    ctx->emit_(OP_LOAD_ATTR, b.index, line);
+    child->emit_(ctx);
+    ctx->emit_(OP_LOAD_ATTR, name.index, line);
 }
 
 bool AttribExpr::emit_del(CodeEmitContext* ctx) {
-    a->emit_(ctx);
-    ctx->emit_(OP_DELETE_ATTR, b.index, line);
+    child->emit_(ctx);
+    ctx->emit_(OP_DELETE_ATTR, name.index, line);
     return true;
 }
 
 bool AttribExpr::emit_store(CodeEmitContext* ctx) {
-    a->emit_(ctx);
-    ctx->emit_(OP_STORE_ATTR, b.index, line);
+    child->emit_(ctx);
+    ctx->emit_(OP_STORE_ATTR, name.index, line);
     return true;
 }
 
 void AttribExpr::emit_method(CodeEmitContext* ctx) {
-    a->emit_(ctx);
-    ctx->emit_(OP_LOAD_METHOD, b.index, line);
+    child->emit_(ctx);
+    ctx->emit_(OP_LOAD_METHOD, name.index, line);
 }
 
 void AttribExpr::emit_inplace(CodeEmitContext* ctx) {
-    a->emit_(ctx);
+    child->emit_(ctx);
     ctx->emit_(OP_DUP_TOP, BC_NOARG, line);
-    ctx->emit_(OP_LOAD_ATTR, b.index, line);
+    ctx->emit_(OP_LOAD_ATTR, name.index, line);
 }
 
 bool AttribExpr::emit_store_inplace(CodeEmitContext* ctx) {
     // [a, val] -> [val, a]
     ctx->emit_(OP_ROT_TWO, BC_NOARG, line);
-    ctx->emit_(OP_STORE_ATTR, b.index, line);
+    ctx->emit_(OP_STORE_ATTR, name.index, line);
     return true;
 }
 
@@ -633,7 +634,7 @@ void CallExpr::emit_(CodeEmitContext* ctx) {
 
     // if callable is a AttrExpr, we should try to use `fast_call` instead of use `boundmethod` proxy
     if(callable->is_attrib()) {
-        auto p = static_cast<AttribExpr*>(callable.get());
+        auto p = static_cast<AttribExpr*>(callable);
         p->emit_method(ctx);  // OP_LOAD_METHOD
     } else {
         callable->emit_(ctx);
@@ -692,7 +693,7 @@ bool BinaryExpr::is_compare() const {
 
 void BinaryExpr::_emit_compare(CodeEmitContext* ctx, small_vector_2<int, 8>& jmps) {
     if(lhs->is_compare()) {
-        static_cast<BinaryExpr*>(lhs.get())->_emit_compare(ctx, jmps);
+        static_cast<BinaryExpr*>(lhs)->_emit_compare(ctx, jmps);
     } else {
         lhs->emit_(ctx);  // [a]
     }
@@ -717,7 +718,7 @@ void BinaryExpr::emit_(CodeEmitContext* ctx) {
     small_vector_2<int, 8> jmps;
     if(is_compare() && lhs->is_compare()) {
         // (a < b) < c
-        static_cast<BinaryExpr*>(lhs.get())->_emit_compare(ctx, jmps);
+        static_cast<BinaryExpr*>(lhs)->_emit_compare(ctx, jmps);
         // [b, RES]
     } else {
         // (1 + 2) < c