blueloveTH 1 年之前
父節點
當前提交
c4b52ef684

+ 2 - 5
include/pocketpy/common/vector.h

@@ -47,10 +47,7 @@ c11_array c11_vector__submit(c11_vector* self);
         (self)->count++; \
         (self)->count++; \
     }while(0)
     }while(0)
 
 
-#define c11_vector__pop(T, self) \
-    do{ \
-        (self)->count--; \
-    }while(0)
+#define c11_vector__pop(self) (--(self)->count)
 
 
 #define c11_vector__back(T, self) \
 #define c11_vector__back(T, self) \
     (((T*)(self)->data)[(self)->count - 1])
     (((T*)(self)->data)[(self)->count - 1])
@@ -89,7 +86,7 @@ c11_array c11_vector__submit(c11_vector* self);
         } \
         } \
     }while(0)
     }while(0)
 
 
-#define c11_vector__foreach(T, self, it) \
+#define c11__foreach(T, self, it) \
     for(T* it = (T*)(self)->data; it != (T*)(self)->data + (self)->count; it++)
     for(T* it = (T*)(self)->data; it != (T*)(self)->data + (self)->count; it++)
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus

+ 1 - 0
include/pocketpy/compiler/compiler.h

@@ -10,6 +10,7 @@ extern "C" {
 #endif
 #endif
 
 
 Error* pk_compile(pk_SourceData_ src, CodeObject* out);
 Error* pk_compile(pk_SourceData_ src, CodeObject* out);
+
 void pk_Compiler__initialize();
 void pk_Compiler__initialize();
 #define pk_Compiler__finalize()  // do nothing
 #define pk_Compiler__finalize()  // do nothing
 
 

+ 60 - 0
include/pocketpy/compiler/context.h

@@ -0,0 +1,60 @@
+#pragma once
+
+#include "pocketpy/objects/codeobject.h"
+#include "pocketpy/common/strname.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct pk_CodeEmitContext{
+    CodeObject* co;  // 1 CodeEmitContext <=> 1 CodeObject*
+    FuncDecl* func;  // optional, weakref
+    int level;
+    int curr_iblock;
+    bool is_compiling_class;
+    c11_vector/*T=Expr* */ s_expr;
+    c11_vector/*T=StrName*/ global_names;
+    c11_smallmap_s2n co_consts_string_dedup_map;
+} pk_CodeEmitContext;
+
+typedef struct pk_Expr pk_Expr;
+
+void pk_CodeEmitContext__ctor(pk_CodeEmitContext* self, CodeObject* co, FuncDecl* func, int level);
+void pk_CodeEmitContext__dtor(pk_CodeEmitContext* self);
+
+int pk_CodeEmitContext__get_loop(pk_CodeEmitContext* self);
+CodeBlock* pk_CodeEmitContext__enter_block(pk_CodeEmitContext* self, CodeBlockType type);
+void pk_CodeEmitContext__exit_block(pk_CodeEmitContext* self);
+int pk_CodeEmitContext__emit_(pk_CodeEmitContext* self, Opcode opcode, uint16_t arg, int line);
+int pk_CodeEmitContext__emit_virtual(pk_CodeEmitContext* self, Opcode opcode, uint16_t arg, int line);
+void pk_CodeEmitContext__revert_last_emit_(pk_CodeEmitContext* self);
+int pk_CodeEmitContext__emit_int(pk_CodeEmitContext* self, int64_t value, int line);
+void pk_CodeEmitContext__patch_jump(pk_CodeEmitContext* self, int index);
+bool pk_CodeEmitContext__add_label(pk_CodeEmitContext* self, StrName name);
+int pk_CodeEmitContext__add_varname(pk_CodeEmitContext* self, StrName name);
+int pk_CodeEmitContext__add_const(pk_CodeEmitContext* self, py_Ref);
+int pk_CodeEmitContext__add_const_string(pk_CodeEmitContext* self, c11_string);
+void pk_CodeEmitContext__emit_store_name(pk_CodeEmitContext* self, NameScope scope, StrName name, int line);
+void pk_CodeEmitContext__try_merge_for_iter_store(pk_CodeEmitContext* self, int);
+
+// emit top -> pop -> delete
+void pk_CodeEmitContext__s_emit_top(pk_CodeEmitContext*);
+// push
+void pk_CodeEmitContext__s_push(pk_CodeEmitContext*, pk_Expr*);
+// top
+pk_Expr* pk_CodeEmitContext__s_top(pk_CodeEmitContext*);
+// size
+int pk_CodeEmitContext__s_size(pk_CodeEmitContext*);
+// pop -> delete
+void pk_CodeEmitContext__s_pop(pk_CodeEmitContext*);
+// pop move
+pk_Expr* pk_CodeEmitContext__s_popx(pk_CodeEmitContext*);
+// clean
+void pk_CodeEmitContext__s_clean(pk_CodeEmitContext*);
+// emit decorators
+void pk_CodeEmitContext__s_emit_decorators(pk_CodeEmitContext*, int count);
+
+#ifdef __cplusplus
+}
+#endif

+ 64 - 25
include/pocketpy/compiler/expr.h

@@ -3,6 +3,7 @@
 #include <stdbool.h>
 #include <stdbool.h>
 #include "pocketpy/common/memorypool.h"
 #include "pocketpy/common/memorypool.h"
 #include "pocketpy/compiler/lexer.h"
 #include "pocketpy/compiler/lexer.h"
+#include "pocketpy/common/strname.h"
 #include "pocketpy/objects/codeobject.h"
 #include "pocketpy/objects/codeobject.h"
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -15,14 +16,14 @@ typedef struct pk_CodeEmitContext pk_CodeEmitContext;
 typedef struct pk_ExprVt{
 typedef struct pk_ExprVt{
     void (*dtor)(pk_Expr*);
     void (*dtor)(pk_Expr*);
     /* reflections */
     /* reflections */
-    bool (*is_literal)(const pk_Expr*);
-    bool (*is_json_object)(const pk_Expr*);
-    bool (*is_attrib)(const pk_Expr*);
-    bool (*is_subscr)(const pk_Expr*);
+    bool is_literal;
+    bool is_json_object;
+    bool is_name;
+    bool is_tuple;
+    bool is_attrib;
+    bool is_subscr;
     bool (*is_compare)(const pk_Expr*);
     bool (*is_compare)(const pk_Expr*);
     int (*star_level)(const pk_Expr*);
     int (*star_level)(const pk_Expr*);
-    bool (*is_tuple)(const pk_Expr*);
-    bool (*is_name)(const pk_Expr*);
     /* emit */
     /* emit */
     void (*emit_)(pk_Expr*, pk_CodeEmitContext*);
     void (*emit_)(pk_Expr*, pk_CodeEmitContext*);
     bool (*emit_del)(pk_Expr*, pk_CodeEmitContext*);
     bool (*emit_del)(pk_Expr*, pk_CodeEmitContext*);
@@ -31,32 +32,70 @@ typedef struct pk_ExprVt{
     bool (*emit_store_inplace)(pk_Expr*, pk_CodeEmitContext*);
     bool (*emit_store_inplace)(pk_Expr*, pk_CodeEmitContext*);
 } pk_ExprVt;
 } pk_ExprVt;
 
 
-typedef struct pk_Expr{
-    pk_ExprVt* vt;
+#define COMMON_HEADER \
+    pk_ExprVt* vt; \
     int line;
     int line;
+
+typedef struct pk_Expr{
+    COMMON_HEADER
 } pk_Expr;
 } pk_Expr;
 
 
 void pk_ExprVt__ctor(pk_ExprVt* vt);
 void pk_ExprVt__ctor(pk_ExprVt* vt);
-void pk_Expr__emit_(pk_Expr* self, pk_CodeEmitContext* ctx);
-bool pk_Expr__emit_del(pk_Expr* self, pk_CodeEmitContext* ctx);
-bool pk_Expr__emit_store(pk_Expr* self, pk_CodeEmitContext* ctx);
-void pk_Expr__emit_inplace(pk_Expr* self, pk_CodeEmitContext* ctx);
-bool pk_Expr__emit_store_inplace(pk_Expr* self, pk_CodeEmitContext* ctx);
 void pk_Expr__delete(pk_Expr* self);
 void pk_Expr__delete(pk_Expr* self);
 
 
-typedef struct pk_CodeEmitContext{
-    CodeObject* co;  // 1 CodeEmitContext <=> 1 CodeObject*
-    FuncDecl* func;  // optional, weakref
+void pk_Expr__initialize();
+#define pk_Expr__finalize()  // do nothing
+
+typedef struct pk_NameExpr{
+    COMMON_HEADER
+    StrName name;
+    NameScope scope;
+} pk_NameExpr;
+
+typedef struct pk_StarredExpr{
+    COMMON_HEADER
+    pk_Expr* child;
     int level;
     int level;
-    int curr_iblock;
-    bool is_compiling_class;
-    c11_vector/*T=Expr* */ s_expr;
-    c11_vector/*T=StrName*/ global_names;
-    c11_smallmap_s2n co_consts_string_dedup_map;
-} pk_CodeEmitContext;
-
-void pk_CodeEmitContext__ctor(pk_CodeEmitContext* self, CodeObject* co, FuncDecl* func, int level);
-void pk_CodeEmitContext__dtor(pk_CodeEmitContext* self);
+} pk_StarredExpr;
+
+// InvertExpr, NotExpr, AndExpr, OrExpr, NegatedExpr
+// NOTE: NegatedExpr always contains a non-const child. Should not generate -1 or -0.1
+typedef struct pk_UnaryExpr{
+    COMMON_HEADER
+    pk_Expr* child;
+    Opcode opcode;
+} pk_UnaryExpr;
+
+// LongExpr, BytesExpr
+typedef struct pk_RawStringExpr{
+    COMMON_HEADER
+    c11_string value;
+    Opcode opcode;
+} pk_RawStringExpr;
+
+typedef struct pk_ImagExpr{
+    COMMON_HEADER
+    double value;
+} pk_ImagExpr;
+
+typedef struct pk_LiteralExpr{
+    COMMON_HEADER
+    const TokenValue* value;
+} pk_LiteralExpr;
+
+typedef struct pk_SliceExpr{
+    COMMON_HEADER
+    pk_Expr* start;
+    pk_Expr* stop;
+    pk_Expr* step;
+} pk_SliceExpr;
+
+// ListExpr, DictExpr, SetExpr, TupleExpr
+typedef struct pk_SequenceExpr{
+    COMMON_HEADER
+    c11_array/*T=Expr* */ items;
+    Opcode opcode;
+} pk_SequenceExpr;
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 4 - 4
src/compiler/compiler.cpp

@@ -77,10 +77,10 @@ Error* Compiler::pop_context() noexcept{
     FuncDecl* func = contexts.back().func;
     FuncDecl* func = contexts.back().func;
     if(func) {
     if(func) {
         // check generator
         // check generator
-        c11_vector__foreach(Bytecode, &func->code->codes, bc) {
+        c11__foreach(Bytecode, &func->code->codes, bc) {
             if(bc->op == OP_YIELD_VALUE || bc->op == OP_FOR_ITER_YIELD_VALUE) {
             if(bc->op == OP_YIELD_VALUE || bc->op == OP_FOR_ITER_YIELD_VALUE) {
                 func->type = FuncType_GENERATOR;
                 func->type = FuncType_GENERATOR;
-                c11_vector__foreach(Bytecode, &func->code->codes, bc) {
+                c11__foreach(Bytecode, &func->code->codes, bc) {
                     if(bc->op == OP_RETURN_VALUE && bc->arg == BC_NOARG) {
                     if(bc->op == OP_RETURN_VALUE && bc->arg == BC_NOARG) {
                         return SyntaxError("'return' with argument inside generator function");
                         return SyntaxError("'return' with argument inside generator function");
                     }
                     }
@@ -1119,11 +1119,11 @@ Error* Compiler::_compile_f_args(FuncDecl* decl, bool enable_type_hints) noexcep
 
 
         // check duplicate argument name
         // check duplicate argument name
         uint16_t tmp_name;
         uint16_t tmp_name;
-        c11_vector__foreach(int, &decl->args, j) {
+        c11__foreach(int, &decl->args, j) {
             tmp_name = c11__getitem(uint16_t, &decl->args, *j);
             tmp_name = c11__getitem(uint16_t, &decl->args, *j);
             if(tmp_name == name.index) return SyntaxError("duplicate argument name");
             if(tmp_name == name.index) return SyntaxError("duplicate argument name");
         }
         }
-        c11_vector__foreach(FuncDeclKwArg, &decl->kwargs, kv) {
+        c11__foreach(FuncDeclKwArg, &decl->kwargs, kv) {
             tmp_name = c11__getitem(uint16_t, &decl->code->varnames, kv->index);
             tmp_name = c11__getitem(uint16_t, &decl->code->varnames, kv->index);
             if(tmp_name == name.index) return SyntaxError("duplicate argument name");
             if(tmp_name == name.index) return SyntaxError("duplicate argument name");
         }
         }

+ 58 - 0
src/compiler/context.c

@@ -0,0 +1,58 @@
+#include "pocketpy/compiler/context.h"
+#include "pocketpy/compiler/expr.h"
+
+void pk_CodeEmitContext__ctor(pk_CodeEmitContext* self, CodeObject* co, FuncDecl* func, int level){
+    self->co = co;
+    self->func = func;
+    self->level = level;
+    self->curr_iblock = 0;
+    self->is_compiling_class = false;
+    c11_vector__ctor(&self->s_expr, sizeof(pk_Expr*));
+    c11_vector__ctor(&self->global_names, sizeof(StrName));
+    c11_smallmap_s2n__ctor(&self->co_consts_string_dedup_map);
+}
+
+void pk_CodeEmitContext__dtor(pk_CodeEmitContext* self){
+    c11_vector__dtor(&self->s_expr);
+    c11_vector__dtor(&self->global_names);
+    c11_smallmap_s2n__dtor(&self->co_consts_string_dedup_map);
+}
+
+// emit top -> pop -> delete
+void pk_CodeEmitContext__s_emit_top(pk_CodeEmitContext* self) {
+    pk_Expr* top = c11_vector__back(pk_Expr*, &self->s_expr);
+    top->vt->emit_(top, self);
+    c11_vector__pop(&self->s_expr);
+    pk_Expr__delete(top);
+}
+// push
+void pk_CodeEmitContext__s_push(pk_CodeEmitContext* self, pk_Expr* expr) {
+    c11_vector__push(pk_Expr*, &self->s_expr, expr);
+}
+// top
+pk_Expr* pk_CodeEmitContext__s_top(pk_CodeEmitContext* self){
+    return c11_vector__back(pk_Expr*, &self->s_expr);
+}
+// size
+int pk_CodeEmitContext__s_size(pk_CodeEmitContext* self) {
+    return self->s_expr.count;
+}
+// pop -> delete
+void pk_CodeEmitContext__s_pop(pk_CodeEmitContext* self){
+    pk_Expr__delete(c11_vector__back(pk_Expr*, &self->s_expr));
+    c11_vector__pop(&self->s_expr);
+}
+// pop move
+pk_Expr* pk_CodeEmitContext__s_popx(pk_CodeEmitContext* self){
+    pk_Expr* e = c11_vector__back(pk_Expr*, &self->s_expr);
+    c11_vector__pop(&self->s_expr);
+    return e;
+}
+// clean
+void pk_CodeEmitContext__s_clean(pk_CodeEmitContext* self){
+    c11_smallmap_s2n__dtor(&self->co_consts_string_dedup_map);  // ??
+    for(int i=0; i<self->s_expr.count; i++){
+        pk_Expr__delete(c11__getitem(pk_Expr*, &self->s_expr, i));
+    }
+    c11_vector__clear(&self->s_expr);
+}

+ 364 - 50
src/compiler/expr.c

@@ -1,4 +1,5 @@
 #include "pocketpy/compiler/expr.h"
 #include "pocketpy/compiler/expr.h"
+#include "pocketpy/compiler/context.h"
 #include "pocketpy/common/memorypool.h"
 #include "pocketpy/common/memorypool.h"
 #include "pocketpy/common/strname.h"
 #include "pocketpy/common/strname.h"
 
 
@@ -6,74 +7,387 @@ static bool default_false(const pk_Expr* e) { return false; }
 static int default_zero(const pk_Expr* e) { return 0; }
 static int default_zero(const pk_Expr* e) { return 0; }
 static void default_dtor(pk_Expr* e) {}
 static void default_dtor(pk_Expr* e) {}
 
 
+static bool default_emit_del(pk_Expr* e, pk_CodeEmitContext* ctx) { return false; }
+static bool default_emit_store(pk_Expr* e, pk_CodeEmitContext* ctx) { return false; }
+static void default_emit_inplace(pk_Expr* e, pk_CodeEmitContext* ctx) { e->vt->emit_(e, ctx); }
+static bool default_emit_store_inplace(pk_Expr* e, pk_CodeEmitContext* ctx) { return e->vt->emit_store(e, ctx); }
+
 void pk_ExprVt__ctor(pk_ExprVt* vt){
 void pk_ExprVt__ctor(pk_ExprVt* vt){
     vt->dtor = default_dtor;
     vt->dtor = default_dtor;
-    vt->is_literal = default_false;
-    vt->is_json_object = default_false;
-    vt->is_attrib = default_false;
-    vt->is_subscr = default_false;
-    vt->is_compare = default_false;
     vt->star_level = default_zero;
     vt->star_level = default_zero;
-    vt->is_tuple = default_false;
-    vt->is_name = default_false;
+    vt->is_compare = default_false;
     vt->emit_ = NULL;   // must be set
     vt->emit_ = NULL;   // must be set
-    vt->emit_del = NULL;
-    vt->emit_store = NULL;
-    vt->emit_inplace = NULL;
-    vt->emit_store_inplace = NULL;
+    vt->emit_del = default_emit_del;
+    vt->emit_store = default_emit_store;
+    vt->emit_inplace = default_emit_inplace;
+    vt->emit_store_inplace = default_emit_store_inplace;
 }
 }
 
 
-void pk_Expr__emit_(pk_Expr* self, pk_CodeEmitContext* ctx){
-    assert(self->vt->emit_);
-    self->vt->emit_(self, ctx);
+void pk_Expr__delete(pk_Expr* self){
+    if(!self) return;
+    self->vt->dtor(self);
+    PoolExpr_dealloc(self);
 }
 }
 
 
-bool pk_Expr__emit_del(pk_Expr* self, pk_CodeEmitContext* ctx){
-    if(!self->vt->emit_del) return false;
-    return self->vt->emit_del(self, ctx);
-}
+/* Implementations */
+#define static_assert_expr_size(T) static_assert(sizeof(T) <= kPoolExprBlockSize, "size is too large")
+
+static pk_ExprVt NameExprVt;
 
 
-bool pk_Expr__emit_store(pk_Expr* self, pk_CodeEmitContext* ctx){
-    if(!self->vt->emit_store) return false;
-    return self->vt->emit_store(self, ctx);
+void pk_NameExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
+    pk_NameExpr* self = (pk_NameExpr*)self_;
+    int index = c11_smallmap_n2i__get(&ctx->co->varnames_inv, self->name, -1);
+    if(self->scope == NAME_LOCAL && index >= 0) {
+        pk_CodeEmitContext__emit_(ctx, OP_LOAD_FAST, index, self->line);
+    } else {
+        Opcode op = ctx->level <= 1 ? OP_LOAD_GLOBAL : OP_LOAD_NONLOCAL;
+        if(ctx->is_compiling_class && self->scope == NAME_GLOBAL) {
+            // if we are compiling a class, we should use OP_LOAD_ATTR_GLOBAL instead of OP_LOAD_GLOBAL
+            // this supports @property.setter
+            op = OP_LOAD_CLASS_GLOBAL;
+            // exec()/eval() won't work with OP_LOAD_ATTR_GLOBAL in class body
+        } else {
+            // we cannot determine the scope when calling exec()/eval()
+            if(self->scope == NAME_GLOBAL_UNKNOWN) op = OP_LOAD_NAME;
+        }
+        pk_CodeEmitContext__emit_(ctx, op, self->name, self->line);
+    }
 }
 }
 
 
-void pk_Expr__emit_inplace(pk_Expr* self, pk_CodeEmitContext* ctx){
-    if(!self->vt->emit_inplace){
-        pk_Expr__emit_(self, ctx);
-        return;
+bool pk_NameExpr__emit_del(pk_Expr* self_, pk_CodeEmitContext* ctx) {
+    pk_NameExpr* self = (pk_NameExpr*)self_;
+    switch(self->scope) {
+        case NAME_LOCAL:
+            pk_CodeEmitContext__emit_(
+                ctx, OP_DELETE_FAST,
+                pk_CodeEmitContext__add_varname(ctx, self->name),
+                self->line
+            );
+            break;
+        case NAME_GLOBAL:
+            pk_CodeEmitContext__emit_(ctx, OP_DELETE_GLOBAL, self->name, self->line);
+            break;
+        case NAME_GLOBAL_UNKNOWN:
+            pk_CodeEmitContext__emit_(ctx, OP_DELETE_NAME, self->name, self->line);
+            break;
+        default: PK_UNREACHABLE();
     }
     }
-    self->vt->emit_inplace(self, ctx);
+    return true;
 }
 }
 
 
-bool pk_Expr__emit_store_inplace(pk_Expr* self, pk_CodeEmitContext* ctx){
-    if(!self->vt->emit_store_inplace){
-        return pk_Expr__emit_store(self, ctx);
+bool pk_NameExpr__emit_store(pk_Expr* self_, pk_CodeEmitContext* ctx) {
+    pk_NameExpr* self = (pk_NameExpr*)self_;
+    if(ctx->is_compiling_class) {
+        pk_CodeEmitContext__emit_(ctx, OP_STORE_CLASS_ATTR, self->name, self->line);
+        return true;
     }
     }
-    return self->vt->emit_store_inplace(self, ctx);
+    pk_CodeEmitContext__emit_store_name(ctx, self->scope, self->name, self->line);
+    return true;
 }
 }
 
 
-void pk_Expr__delete(pk_Expr* self){
-    if(!self) return;
-    self->vt->dtor(self);
-    PoolExpr_dealloc(self);
+pk_NameExpr* pk_NameExpr__new(StrName name, NameScope scope){
+    static_assert_expr_size(pk_NameExpr);
+    pk_NameExpr* self = PoolExpr_alloc();
+    self->vt = &NameExprVt;
+    self->line = -1;
+    self->name = name;
+    self->scope = scope;
+    return self;
+}
+
+static pk_ExprVt StarredExprVt;
+
+int pk_ExprVt__star_level(const pk_Expr* self) {
+    return ((pk_StarredExpr*)self)->level;
 }
 }
 
 
-/* CodeEmitContext */
+void pk_StarredExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
+    pk_StarredExpr* self = (pk_StarredExpr*)self_;
+    self->child->vt->emit_(self->child, ctx);
+    pk_CodeEmitContext__emit_(ctx, OP_UNARY_STAR, self->level, self->line);
+}
 
 
-void pk_CodeEmitContext__ctor(pk_CodeEmitContext* self, CodeObject* co, FuncDecl* func, int level){
-    self->co = co;
-    self->func = func;
+bool pk_StarredExpr__emit_store(pk_Expr* self_, pk_CodeEmitContext* ctx) {
+    pk_StarredExpr* self = (pk_StarredExpr*)self_;
+    if(self->level != 1) return false;
+    // simply proxy to child
+    return self->child->vt->emit_store(self->child, ctx);
+}
+
+pk_StarredExpr* pk_StarredExpr__new(pk_Expr* child, int level){
+    static_assert_expr_size(pk_StarredExpr);
+    pk_StarredExpr* self = PoolExpr_alloc();
+    self->vt = &StarredExprVt;
+    self->line = -1;
+    self->child = child;
     self->level = level;
     self->level = level;
-    self->curr_iblock = 0;
-    self->is_compiling_class = false;
-    c11_vector__ctor(&self->s_expr, sizeof(pk_Expr*));
-    c11_vector__ctor(&self->global_names, sizeof(StrName));
-    c11_smallmap_s2n__ctor(&self->co_consts_string_dedup_map);
-}
-
-void pk_CodeEmitContext__dtor(pk_CodeEmitContext* self){
-    c11_vector__dtor(&self->s_expr);
-    c11_vector__dtor(&self->global_names);
-    c11_smallmap_s2n__dtor(&self->co_consts_string_dedup_map);
-}
+    return self;
+}
+
+static pk_ExprVt UnaryExprVt;
+
+void pk_UnaryExpr__dtor(pk_Expr* self_){
+    pk_UnaryExpr* self = (pk_UnaryExpr*)self_;
+    pk_Expr__delete(self->child);
+}
+
+static void pk_UnaryExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
+    pk_UnaryExpr* self = (pk_UnaryExpr*)self_;
+    self->child->vt->emit_(self->child, ctx);
+    pk_CodeEmitContext__emit_(ctx, self->opcode, BC_NOARG, self->line);
+}
+
+pk_UnaryExpr* pk_UnaryExpr__new(pk_Expr* child, Opcode opcode){
+    static_assert_expr_size(pk_UnaryExpr);
+    pk_UnaryExpr* self = PoolExpr_alloc();
+    self->vt = &UnaryExprVt;
+    self->line = -1;
+    self->child = child;
+    self->opcode = opcode;
+    return self;
+}
+
+static pk_ExprVt RawStringExprVt;
+
+void pk_RawStringExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
+    pk_RawStringExpr* self = (pk_RawStringExpr*)self_;
+    int index = pk_CodeEmitContext__add_const_string(ctx, self->value);
+    pk_CodeEmitContext__emit_(ctx, OP_LOAD_CONST, index, self->line);
+    pk_CodeEmitContext__emit_(ctx, self->opcode, BC_NOARG, self->line);
+}
+
+pk_RawStringExpr* pk_RawStringExpr__new(c11_string value, Opcode opcode){
+    static_assert_expr_size(pk_RawStringExpr);
+    pk_RawStringExpr* self = PoolExpr_alloc();
+    self->vt = &RawStringExprVt;
+    self->line = -1;
+    self->value = value;
+    self->opcode = opcode;
+    return self;
+}
+
+static pk_ExprVt ImagExprVt;
+
+void pk_ImagExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
+    pk_ImagExpr* self = (pk_ImagExpr*)self_;
+    PyVar value;
+    py_newfloat(&value, self->value);
+    int index = pk_CodeEmitContext__add_const(ctx, &value);
+    pk_CodeEmitContext__emit_(ctx, OP_LOAD_CONST, index, self->line);
+    pk_CodeEmitContext__emit_(ctx, OP_BUILD_IMAG, BC_NOARG, self->line);
+}
+
+pk_ImagExpr* pk_ImagExpr__new(double value){
+    static_assert_expr_size(pk_ImagExpr);
+    pk_ImagExpr* self = PoolExpr_alloc();
+    self->vt = &ImagExprVt;
+    self->line = -1;
+    self->value = value;
+    return self;
+}
+
+static pk_ExprVt LiteralExprVt;
+
+void pk_LiteralExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
+    pk_LiteralExpr* self = (pk_LiteralExpr*)self_;
+    switch(self->value->index){
+        case TokenValue_I64: {
+            int64_t val = self->value->_i64;
+            pk_CodeEmitContext__emit_int(ctx, val, self->line);
+            break;
+        }
+        case TokenValue_F64: {
+            PyVar value;
+            py_newfloat(&value, self->value->_f64);
+            int index = pk_CodeEmitContext__add_const(ctx, &value);
+            pk_CodeEmitContext__emit_(ctx, OP_LOAD_CONST, index, self->line);
+            break;
+        }
+        case TokenValue_STR: {
+            c11_string sv = py_Str__sv(&self->value->_str);
+            int index = pk_CodeEmitContext__add_const_string(ctx, sv);
+            pk_CodeEmitContext__emit_(ctx, OP_LOAD_CONST, index, self->line);
+            break;
+        }
+        default: PK_UNREACHABLE();
+    }
+}
+
+pk_LiteralExpr* pk_LiteralExpr__new(const TokenValue* value){
+    static_assert_expr_size(pk_LiteralExpr);
+    pk_LiteralExpr* self = PoolExpr_alloc();
+    self->vt = &LiteralExprVt;
+    self->line = -1;
+    self->value = value;
+    return self;
+}
+
+static pk_ExprVt SliceExprVt;
+
+void pk_SliceExpr__dtor(pk_Expr* self_){
+    pk_SliceExpr* self = (pk_SliceExpr*)self_;
+    pk_Expr__delete(self->start);
+    pk_Expr__delete(self->stop);
+    pk_Expr__delete(self->step);
+}
+
+void pk_SliceExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
+    pk_SliceExpr* self = (pk_SliceExpr*)self_;
+    if(self->start) self->start->vt->emit_(self->start, ctx);
+    else pk_CodeEmitContext__emit_(ctx, OP_LOAD_NONE, BC_NOARG, self->line);
+    if(self->stop) self->stop->vt->emit_(self->stop, ctx);
+    else pk_CodeEmitContext__emit_(ctx, OP_LOAD_NONE, BC_NOARG, self->line);
+    if(self->step) self->step->vt->emit_(self->step, ctx);
+    else pk_CodeEmitContext__emit_(ctx, OP_LOAD_NONE, BC_NOARG, self->line);
+    pk_CodeEmitContext__emit_(ctx, OP_BUILD_SLICE, BC_NOARG, self->line);
+}
+
+pk_SliceExpr* pk_SliceExpr__new(){
+    static_assert_expr_size(pk_SliceExpr);
+    pk_SliceExpr* self = PoolExpr_alloc();
+    self->vt = &SliceExprVt;
+    self->line = -1;
+    self->start = NULL;
+    self->stop = NULL;
+    self->step = NULL;
+    return self;
+}
+
+static pk_ExprVt ListExprVt;
+static pk_ExprVt DictExprVt;
+static pk_ExprVt SetExprVt;
+static pk_ExprVt TupleExprVt;
+
+pk_SequenceExpr* pk_SequenceExpr__new(pk_ExprVt* vt, int count, Opcode opcode){
+    static_assert_expr_size(pk_SequenceExpr);
+    pk_SequenceExpr* self = PoolExpr_alloc();
+    self->vt = vt;
+    self->line = -1;
+    self->opcode = opcode;
+    c11_array__ctor(&self->items, count, sizeof(pk_Expr*));
+    return self;
+}
+
+static void pk_SequenceExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
+    pk_SequenceExpr* self = (pk_SequenceExpr*)self_;
+    for(int i=0; i<self->items.count; i++){
+        pk_Expr* item = c11__getitem(pk_Expr*, &self->items, i);
+        item->vt->emit_(item, ctx);
+    }
+    pk_CodeEmitContext__emit_(ctx, self->opcode, self->items.count, self->line);
+}
+
+void pk_SequenceExpr__dtor(pk_Expr* self_){
+    pk_SequenceExpr* self = (pk_SequenceExpr*)self_;
+    c11__foreach(pk_Expr*, &self->items, e){
+        pk_Expr__delete(*e);
+    }
+    c11_array__dtor(&self->items);
+}
+
+bool pk_TupleExpr__emit_store(pk_Expr* self_, pk_CodeEmitContext* ctx) {
+    pk_SequenceExpr* self = (pk_SequenceExpr*)self_;
+    // TOS is an iterable
+    // items may contain StarredExpr, we should check it
+    int starred_i = -1;
+    for(int i = 0; i < self->items.count; i++) {
+        pk_Expr* e = c11__getitem(pk_Expr*, &self->items, i);
+        if(e->vt->star_level(e) == 0) continue;
+        if(starred_i == -1) starred_i = i;
+        else return false;  // multiple StarredExpr not allowed
+    }
+
+    if(starred_i == -1) {
+        Bytecode* prev = c11__at(Bytecode, &ctx->co->codes, ctx->co->codes.count - 1);
+        if(prev->op == OP_BUILD_TUPLE && prev->arg == self->items.count) {
+            // build tuple and unpack it is meaningless
+            pk_CodeEmitContext__revert_last_emit_(ctx);
+        } else {
+            if(prev->op == OP_FOR_ITER) {
+                prev->op = OP_FOR_ITER_UNPACK;
+                prev->arg = self->items.count;
+            } else {
+                pk_CodeEmitContext__emit_(ctx, OP_UNPACK_SEQUENCE, self->items.count, self->line);
+            }
+        }
+    } else {
+        // starred assignment target must be in a tuple
+        if(self->items.count == 1) return false;
+        // starred assignment target must be the last one (differ from cpython)
+        if(starred_i != self->items.count - 1) return false;
+        // a,*b = [1,2,3]
+        // stack is [1,2,3] -> [1,[2,3]]
+        pk_CodeEmitContext__emit_(ctx, OP_UNPACK_EX, self->items.count - 1, self->line);
+    }
+    // do reverse emit
+    for(int i = self->items.count - 1; i >= 0; i--) {
+        pk_Expr* e = c11__getitem(pk_Expr*, &self->items, i);
+        bool ok = e->vt->emit_store(e, ctx);
+        if(!ok) return false;
+    }
+    return true;
+}
+
+bool pk_TupleExpr__emit_del(pk_Expr* self_, pk_CodeEmitContext* ctx) {
+    pk_SequenceExpr* self = (pk_SequenceExpr*)self_;
+    c11__foreach(pk_Expr*, &self->items, e){
+        bool ok = (*e)->vt->emit_del(*e, ctx);
+        if(!ok) return false;
+    }
+    return true;
+}
+
+/////////////////////////////////////////////
+void pk_Expr__initialize(){
+    pk_ExprVt__ctor(&NameExprVt);
+    pk_ExprVt* vt = &NameExprVt;
+    vt->emit_ = pk_NameExpr__emit_;
+    vt->emit_del = pk_NameExpr__emit_del;
+    vt->emit_store = pk_NameExpr__emit_store;
+
+    pk_ExprVt__ctor(&StarredExprVt);
+    vt = &StarredExprVt;
+    vt->dtor = pk_UnaryExpr__dtor;
+    vt->star_level = pk_ExprVt__star_level;
+    vt->emit_ = pk_StarredExpr__emit_;
+    vt->emit_store = pk_StarredExpr__emit_store;
+
+    pk_ExprVt__ctor(&UnaryExprVt);
+    vt = &UnaryExprVt;
+    vt->dtor = pk_UnaryExpr__dtor;
+    vt->emit_ = pk_UnaryExpr__emit_;
+
+    pk_ExprVt__ctor(&RawStringExprVt);
+    vt = &RawStringExprVt;
+    vt->emit_ = pk_RawStringExpr__emit_;
+
+    pk_ExprVt__ctor(&ImagExprVt);
+    vt = &ImagExprVt;
+    vt->emit_ = pk_ImagExpr__emit_;
+
+    pk_ExprVt__ctor(&LiteralExprVt);
+    vt = &LiteralExprVt;
+    vt->emit_ = pk_LiteralExpr__emit_;
+    vt->is_literal = true;
+    vt->is_json_object = true;
+
+    pk_ExprVt__ctor(&SliceExprVt);
+    vt = &SliceExprVt;
+    vt->dtor = pk_SliceExpr__dtor;
+    vt->emit_ = pk_SliceExpr__emit_;
+
+    pk_ExprVt* seqVt[] = {&ListExprVt, &DictExprVt, &SetExprVt, &TupleExprVt};
+    for(int i=0; i<4; i++){
+        pk_ExprVt__ctor(seqVt[i]);
+        vt = seqVt[i];
+        vt->dtor = pk_SequenceExpr__dtor;
+        vt->emit_ = pk_SequenceExpr__emit_;
+    }
+
+    ListExprVt.is_json_object = true;
+    DictExprVt.is_json_object = true;
+
+    TupleExprVt.is_tuple = true;
+    TupleExprVt.emit_store = pk_TupleExpr__emit_store;
+    TupleExprVt.emit_del = pk_TupleExpr__emit_del;
+}

+ 2 - 2
src/compiler/expr.cpp

@@ -71,8 +71,8 @@ int CodeEmitContext::emit_(Opcode opcode, uint16_t arg, int line, bool is_virtua
 }
 }
 
 
 void CodeEmitContext::revert_last_emit_() noexcept{
 void CodeEmitContext::revert_last_emit_() noexcept{
-    c11_vector__pop(Bytecode, &co->codes);
-    c11_vector__pop(BytecodeEx, &co->codes_ex);
+    c11_vector__pop(&co->codes);
+    c11_vector__pop(&co->codes_ex);
 }
 }
 
 
 void CodeEmitContext::try_merge_for_iter_store(int i) noexcept{
 void CodeEmitContext::try_merge_for_iter_store(int i) noexcept{

+ 3 - 3
src/compiler/lexer.c

@@ -168,7 +168,7 @@ static bool eat_indentation(pk_Lexer* self){
         c11_vector__push(Token, &self->nexts, t);
         c11_vector__push(Token, &self->nexts, t);
     } else if(spaces < indents_back) {
     } else if(spaces < indents_back) {
         do {
         do {
-            c11_vector__pop(int, &self->indents);
+            c11_vector__pop(&self->indents);
             Token t = {TK_DEDENT, self->token_start, 0, self->current_line, self->brackets_level, EmptyTokenValue};
             Token t = {TK_DEDENT, self->token_start, 0, self->current_line, self->brackets_level, EmptyTokenValue};
             c11_vector__push(Token, &self->nexts, t);
             c11_vector__push(Token, &self->nexts, t);
             indents_back = c11_vector__back(int, &self->indents);
             indents_back = c11_vector__back(int, &self->indents);
@@ -543,7 +543,7 @@ static Error* lex_one_token(pk_Lexer* self, bool* eof){
 
 
     self->token_start = self->curr_char;
     self->token_start = self->curr_char;
     while(self->indents.count > 1) {
     while(self->indents.count > 1) {
-        c11_vector__pop(int, &self->indents);
+        c11_vector__pop(&self->indents);
         add_token(self, TK_DEDENT);
         add_token(self, TK_DEDENT);
         return NULL;
         return NULL;
     }
     }
@@ -763,7 +763,7 @@ Error* pk_Lexer__process_and_dump(pk_SourceData_ src, py_Str* out) {
     c11_smallmap_s2n token_indices;
     c11_smallmap_s2n token_indices;
     c11_smallmap_s2n__ctor(&token_indices);
     c11_smallmap_s2n__ctor(&token_indices);
 
 
-    c11_vector__foreach(Token, &nexts, token) {
+    c11__foreach(Token, &nexts, token) {
         if(is_raw_string_used(token->type)) {
         if(is_raw_string_used(token->type)) {
             c11_string token_sv = {token->start, token->length};
             c11_string token_sv = {token->start, token->length};
             if(!c11_smallmap_s2n__contains(&token_indices, token_sv)) {
             if(!c11_smallmap_s2n__contains(&token_indices, token_sv)) {

+ 1 - 1
src/interpreter/frame.c

@@ -18,7 +18,7 @@ PyVar* FastLocals__try_get_by_name(PyVar* locals, const CodeObject* co, py_Name
 
 
 pk_NameDict* FastLocals__to_namedict(PyVar* locals, const CodeObject* co) {
 pk_NameDict* FastLocals__to_namedict(PyVar* locals, const CodeObject* co) {
     pk_NameDict* dict = pk_NameDict__new();
     pk_NameDict* dict = pk_NameDict__new();
-    c11_vector__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) {
+    c11__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) {
         PyVar value = locals[entry->value];
         PyVar value = locals[entry->value];
         if(!py_isnull(&value)){
         if(!py_isnull(&value)){
             pk_NameDict__set(dict, entry->key, value);
             pk_NameDict__set(dict, entry->key, value);