diff --git a/include/pocketpy/common/vector.h b/include/pocketpy/common/vector.h index 8acf246c..891e5944 100644 --- a/include/pocketpy/common/vector.h +++ b/include/pocketpy/common/vector.h @@ -47,10 +47,7 @@ c11_array c11_vector__submit(c11_vector* self); (self)->count++; \ }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) \ (((T*)(self)->data)[(self)->count - 1]) @@ -89,7 +86,7 @@ c11_array c11_vector__submit(c11_vector* self); } \ }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++) #ifdef __cplusplus diff --git a/include/pocketpy/compiler/compiler.h b/include/pocketpy/compiler/compiler.h index 12df28d6..956a4d80 100644 --- a/include/pocketpy/compiler/compiler.h +++ b/include/pocketpy/compiler/compiler.h @@ -10,6 +10,7 @@ extern "C" { #endif Error* pk_compile(pk_SourceData_ src, CodeObject* out); + void pk_Compiler__initialize(); #define pk_Compiler__finalize() // do nothing diff --git a/include/pocketpy/compiler/context.h b/include/pocketpy/compiler/context.h new file mode 100644 index 00000000..09222441 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/include/pocketpy/compiler/expr.h b/include/pocketpy/compiler/expr.h index 1ec5065c..1d71f870 100644 --- a/include/pocketpy/compiler/expr.h +++ b/include/pocketpy/compiler/expr.h @@ -3,6 +3,7 @@ #include #include "pocketpy/common/memorypool.h" #include "pocketpy/compiler/lexer.h" +#include "pocketpy/common/strname.h" #include "pocketpy/objects/codeobject.h" #ifdef __cplusplus @@ -15,14 +16,14 @@ typedef struct pk_CodeEmitContext pk_CodeEmitContext; typedef struct pk_ExprVt{ void (*dtor)(pk_Expr*); /* 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*); int (*star_level)(const pk_Expr*); - bool (*is_tuple)(const pk_Expr*); - bool (*is_name)(const pk_Expr*); /* emit */ void (*emit_)(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*); } pk_ExprVt; -typedef struct pk_Expr{ - pk_ExprVt* vt; +#define COMMON_HEADER \ + pk_ExprVt* vt; \ int line; + +typedef struct pk_Expr{ + COMMON_HEADER } pk_Expr; 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); -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; +void pk_Expr__initialize(); +#define pk_Expr__finalize() // do nothing -void pk_CodeEmitContext__ctor(pk_CodeEmitContext* self, CodeObject* co, FuncDecl* func, int level); -void pk_CodeEmitContext__dtor(pk_CodeEmitContext* self); +typedef struct pk_NameExpr{ + COMMON_HEADER + StrName name; + NameScope scope; +} pk_NameExpr; + +typedef struct pk_StarredExpr{ + COMMON_HEADER + pk_Expr* child; + int level; +} 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 } diff --git a/src/compiler/compiler.cpp b/src/compiler/compiler.cpp index 507fb886..c0ac3554 100644 --- a/src/compiler/compiler.cpp +++ b/src/compiler/compiler.cpp @@ -77,10 +77,10 @@ Error* Compiler::pop_context() noexcept{ FuncDecl* func = contexts.back().func; if(func) { // 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) { 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) { 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 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); 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); if(tmp_name == name.index) return SyntaxError("duplicate argument name"); } diff --git a/src/compiler/context.c b/src/compiler/context.c new file mode 100644 index 00000000..dec8d4f1 --- /dev/null +++ b/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; is_expr.count; i++){ + pk_Expr__delete(c11__getitem(pk_Expr*, &self->s_expr, i)); + } + c11_vector__clear(&self->s_expr); +} \ No newline at end of file diff --git a/src/compiler/expr.c b/src/compiler/expr.c index dc2c8169..310b8312 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -1,4 +1,5 @@ #include "pocketpy/compiler/expr.h" +#include "pocketpy/compiler/context.h" #include "pocketpy/common/memorypool.h" #include "pocketpy/common/strname.h" @@ -6,51 +7,20 @@ static bool default_false(const pk_Expr* e) { return false; } static int default_zero(const pk_Expr* e) { return 0; } 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){ 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->is_tuple = default_false; - vt->is_name = default_false; + vt->is_compare = default_false; vt->emit_ = NULL; // must be set - vt->emit_del = NULL; - vt->emit_store = NULL; - vt->emit_inplace = NULL; - vt->emit_store_inplace = NULL; -} - -void pk_Expr__emit_(pk_Expr* self, pk_CodeEmitContext* ctx){ - assert(self->vt->emit_); - self->vt->emit_(self, ctx); -} - -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); -} - -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_Expr__emit_inplace(pk_Expr* self, pk_CodeEmitContext* ctx){ - if(!self->vt->emit_inplace){ - pk_Expr__emit_(self, ctx); - return; - } - self->vt->emit_inplace(self, ctx); -} - -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); - } - return self->vt->emit_store_inplace(self, ctx); + 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__delete(pk_Expr* self){ @@ -59,21 +29,365 @@ void pk_Expr__delete(pk_Expr* self){ PoolExpr_dealloc(self); } -/* CodeEmitContext */ +/* Implementations */ +#define static_assert_expr_size(T) static_assert(sizeof(T) <= kPoolExprBlockSize, "size is too large") -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); +static pk_ExprVt NameExprVt; + +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_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); -} \ No newline at end of file +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(); + } + return true; +} + +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; + } + pk_CodeEmitContext__emit_store_name(ctx, self->scope, self->name, self->line); + return true; +} + +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; +} + +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); +} + +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; + 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; iitems.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; +} diff --git a/src/compiler/expr.cpp b/src/compiler/expr.cpp index 9bcd7d8f..d11381d9 100644 --- a/src/compiler/expr.cpp +++ b/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{ - 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{ diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 5944e6e2..ece53a0e 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -168,7 +168,7 @@ static bool eat_indentation(pk_Lexer* self){ c11_vector__push(Token, &self->nexts, t); } else if(spaces < indents_back) { 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}; c11_vector__push(Token, &self->nexts, t); 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; while(self->indents.count > 1) { - c11_vector__pop(int, &self->indents); + c11_vector__pop(&self->indents); add_token(self, TK_DEDENT); 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__ctor(&token_indices); - c11_vector__foreach(Token, &nexts, token) { + c11__foreach(Token, &nexts, token) { if(is_raw_string_used(token->type)) { c11_string token_sv = {token->start, token->length}; if(!c11_smallmap_s2n__contains(&token_indices, token_sv)) { diff --git a/src/interpreter/frame.c b/src/interpreter/frame.c index 36e6b3bd..ab807db6 100644 --- a/src/interpreter/frame.c +++ b/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* 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]; if(!py_isnull(&value)){ pk_NameDict__set(dict, entry->key, value);