mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +00:00
Compare commits
2 Commits
6f4617b83d
...
c7597dfcdf
Author | SHA1 | Date | |
---|---|---|---|
|
c7597dfcdf | ||
|
c4b52ef684 |
@ -18,6 +18,7 @@ typedef struct c11_string{
|
||||
int c11_string__cmp(c11_string self, c11_string other);
|
||||
int c11_string__cmp2(c11_string self, const char* other, int size);
|
||||
int c11_string__cmp3(c11_string self, const char* other);
|
||||
int c11_string__index(c11_string self, char c);
|
||||
|
||||
typedef struct py_Str{
|
||||
int size;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
60
include/pocketpy/compiler/context.h
Normal file
60
include/pocketpy/compiler/context.h
Normal file
@ -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
|
@ -3,6 +3,7 @@
|
||||
#include <stdbool.h>
|
||||
#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,91 @@ 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;
|
||||
|
||||
typedef struct pk_CompExpr{
|
||||
COMMON_HEADER
|
||||
pk_Expr* expr; // loop expr
|
||||
pk_Expr* vars; // loop vars
|
||||
pk_Expr* iter; // loop iter
|
||||
pk_Expr* cond; // optional if condition
|
||||
|
||||
Opcode op0;
|
||||
Opcode op1;
|
||||
} pk_CompExpr;
|
||||
|
||||
typedef struct pk_LambdaExpr{
|
||||
COMMON_HEADER
|
||||
int index;
|
||||
} pk_LambdaExpr;
|
||||
|
||||
typedef struct pk_FStringExpr{
|
||||
COMMON_HEADER
|
||||
c11_string src;
|
||||
} pk_FStringExpr;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ typedef struct Token {
|
||||
|
||||
// https://docs.python.org/3/reference/expressions.html#operator-precedence
|
||||
enum Precedence {
|
||||
PREC_LOWEST,
|
||||
PREC_LOWEST = 0,
|
||||
PREC_LAMBDA, // lambda
|
||||
PREC_TERNARY, // ?:
|
||||
PREC_LOGICAL_OR, // or
|
||||
|
@ -252,6 +252,13 @@ int c11_string__cmp3(c11_string self, const char *other){
|
||||
return c11_string__cmp2(self, other, strlen(other));
|
||||
}
|
||||
|
||||
int c11_string__index(c11_string self, char c){
|
||||
for(int i=0; i<self.size; i++){
|
||||
if(self.data[i] == c) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int py_Str__cmp(const py_Str *self, const py_Str *other){
|
||||
return py_Str__cmp2(self, py_Str__data(other), other->size);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "pocketpy/compiler/compiler.h"
|
||||
#include "pocketpy/compiler/expr.h"
|
||||
#include "pocketpy/compiler/lexer.h"
|
||||
#include "pocketpy/compiler/context.h"
|
||||
|
||||
typedef struct pk_Compiler pk_Compiler;
|
||||
typedef Error* (*PrattCallback)(pk_Compiler* self);
|
||||
@ -163,18 +164,18 @@ static Error* EXPR_TUPLE(pk_Compiler* self, bool allow_slice){
|
||||
|
||||
// special case for `for loop` and `comp`
|
||||
static Error* EXPR_VARS(pk_Compiler* self){
|
||||
int count = 0;
|
||||
do {
|
||||
consume(TK_ID);
|
||||
ctx()->s_push(make_expr<NameExpr>(prev().str(), name_scope()));
|
||||
count += 1;
|
||||
} while(match(TK_COMMA));
|
||||
if(count > 1){
|
||||
TupleExpr* e = make_expr<TupleExpr>(count);
|
||||
for(int i=count-1; i>=0; i--)
|
||||
e->items[i] = ctx()->s_popx();
|
||||
ctx()->s_push(e);
|
||||
}
|
||||
// int count = 0;
|
||||
// do {
|
||||
// consume(TK_ID);
|
||||
// ctx()->s_push(make_expr<NameExpr>(prev().str(), name_scope()));
|
||||
// count += 1;
|
||||
// } while(match(TK_COMMA));
|
||||
// if(count > 1){
|
||||
// TupleExpr* e = make_expr<TupleExpr>(count);
|
||||
// for(int i=count-1; i>=0; i--)
|
||||
// e->items[i] = ctx()->s_popx();
|
||||
// ctx()->s_push(e);
|
||||
// }
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -253,53 +254,51 @@ Error* pk_compile(pk_SourceData_ src, CodeObject* out){
|
||||
void pk_Compiler__initialize(){
|
||||
// clang-format off
|
||||
// http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
|
||||
#define PK_NO_INFIX NULL, PREC_LOWEST
|
||||
for(int i = 0; i < TK__COUNT__; i++) rules[i] = { NULL, PK_NO_INFIX };
|
||||
rules[TK_DOT] = { NULL, exprAttrib, PREC_PRIMARY };
|
||||
rules[TK_LPAREN] = { exprGroup, exprCall, PREC_PRIMARY };
|
||||
rules[TK_LBRACKET] = { exprList, exprSubscr, PREC_PRIMARY };
|
||||
rules[TK_LBRACE] = { exprMap, PK_NO_INFIX };
|
||||
rules[TK_MOD] = { NULL, exprBinaryOp, PREC_FACTOR };
|
||||
rules[TK_ADD] = { NULL, exprBinaryOp, PREC_TERM };
|
||||
rules[TK_SUB] = { exprUnaryOp, exprBinaryOp, PREC_TERM };
|
||||
rules[TK_MUL] = { exprUnaryOp, exprBinaryOp, PREC_FACTOR };
|
||||
rules[TK_INVERT] = { exprUnaryOp, NULL, PREC_UNARY };
|
||||
rules[TK_DIV] = { NULL, exprBinaryOp, PREC_FACTOR };
|
||||
rules[TK_FLOORDIV] = { NULL, exprBinaryOp, PREC_FACTOR };
|
||||
rules[TK_POW] = { exprUnaryOp, exprBinaryOp, PREC_EXPONENT };
|
||||
rules[TK_GT] = { NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_LT] = { NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_EQ] = { NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_NE] = { NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_GE] = { NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_LE] = { NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_IN] = { NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_IS] = { NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_LSHIFT] = { NULL, exprBinaryOp, PREC_BITWISE_SHIFT };
|
||||
rules[TK_RSHIFT] = { NULL, exprBinaryOp, PREC_BITWISE_SHIFT };
|
||||
rules[TK_AND] = { NULL, exprBinaryOp, PREC_BITWISE_AND };
|
||||
rules[TK_OR] = { NULL, exprBinaryOp, PREC_BITWISE_OR };
|
||||
rules[TK_XOR] = { NULL, exprBinaryOp, PREC_BITWISE_XOR };
|
||||
rules[TK_DECORATOR] = { NULL, exprBinaryOp, PREC_FACTOR };
|
||||
rules[TK_IF] = { NULL, exprTernary, PREC_TERNARY };
|
||||
rules[TK_NOT_IN] = { NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_IS_NOT] = { NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_AND_KW ] = { NULL, exprAnd, PREC_LOGICAL_AND };
|
||||
rules[TK_OR_KW] = { NULL, exprOr, PREC_LOGICAL_OR };
|
||||
rules[TK_NOT_KW] = { exprNot, NULL, PREC_LOGICAL_NOT };
|
||||
rules[TK_TRUE] = { exprLiteral0, PK_NO_INFIX };
|
||||
rules[TK_FALSE] = { exprLiteral0, PK_NO_INFIX };
|
||||
rules[TK_NONE] = { exprLiteral0, PK_NO_INFIX };
|
||||
rules[TK_DOTDOTDOT] = { exprLiteral0, PK_NO_INFIX };
|
||||
rules[TK_LAMBDA] = { exprLambda, PK_NO_INFIX };
|
||||
rules[TK_ID] = { exprName, PK_NO_INFIX };
|
||||
rules[TK_NUM] = { exprLiteral, PK_NO_INFIX };
|
||||
rules[TK_STR] = { exprLiteral, PK_NO_INFIX };
|
||||
rules[TK_FSTR] = { exprFString, PK_NO_INFIX };
|
||||
rules[TK_LONG] = { exprLong, PK_NO_INFIX };
|
||||
rules[TK_IMAG] = { exprImag, PK_NO_INFIX };
|
||||
rules[TK_BYTES] = { exprBytes, PK_NO_INFIX };
|
||||
rules[TK_COLON] = { exprSlice0, exprSlice1, PREC_PRIMARY };
|
||||
rules[TK_DOT] = (PrattRule){ NULL, exprAttrib, PREC_PRIMARY };
|
||||
rules[TK_LPAREN] = (PrattRule){ exprGroup, exprCall, PREC_PRIMARY };
|
||||
rules[TK_LBRACKET] = (PrattRule){ exprList, exprSubscr, PREC_PRIMARY };
|
||||
rules[TK_MOD] = (PrattRule){ NULL, exprBinaryOp, PREC_FACTOR };
|
||||
rules[TK_ADD] = (PrattRule){ NULL, exprBinaryOp, PREC_TERM };
|
||||
rules[TK_SUB] = (PrattRule){ exprUnaryOp, exprBinaryOp, PREC_TERM };
|
||||
rules[TK_MUL] = (PrattRule){ exprUnaryOp, exprBinaryOp, PREC_FACTOR };
|
||||
rules[TK_INVERT] = (PrattRule){ exprUnaryOp, NULL, PREC_UNARY };
|
||||
rules[TK_DIV] = (PrattRule){ NULL, exprBinaryOp, PREC_FACTOR };
|
||||
rules[TK_FLOORDIV] = (PrattRule){ NULL, exprBinaryOp, PREC_FACTOR };
|
||||
rules[TK_POW] = (PrattRule){ exprUnaryOp, exprBinaryOp, PREC_EXPONENT };
|
||||
rules[TK_GT] = (PrattRule){ NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_LT] = (PrattRule){ NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_EQ] = (PrattRule){ NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_NE] = (PrattRule){ NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_GE] = (PrattRule){ NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_LE] = (PrattRule){ NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_IN] = (PrattRule){ NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_IS] = (PrattRule){ NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_LSHIFT] = (PrattRule){ NULL, exprBinaryOp, PREC_BITWISE_SHIFT };
|
||||
rules[TK_RSHIFT] = (PrattRule){ NULL, exprBinaryOp, PREC_BITWISE_SHIFT };
|
||||
rules[TK_AND] = (PrattRule){ NULL, exprBinaryOp, PREC_BITWISE_AND };
|
||||
rules[TK_OR] = (PrattRule){ NULL, exprBinaryOp, PREC_BITWISE_OR };
|
||||
rules[TK_XOR] = (PrattRule){ NULL, exprBinaryOp, PREC_BITWISE_XOR };
|
||||
rules[TK_DECORATOR] = (PrattRule){ NULL, exprBinaryOp, PREC_FACTOR };
|
||||
rules[TK_IF] = (PrattRule){ NULL, exprTernary, PREC_TERNARY };
|
||||
rules[TK_NOT_IN] = (PrattRule){ NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_IS_NOT] = (PrattRule){ NULL, exprBinaryOp, PREC_COMPARISION };
|
||||
rules[TK_AND_KW ] = (PrattRule){ NULL, exprAnd, PREC_LOGICAL_AND };
|
||||
rules[TK_OR_KW] = (PrattRule){ NULL, exprOr, PREC_LOGICAL_OR };
|
||||
rules[TK_NOT_KW] = (PrattRule){ exprNot, NULL, PREC_LOGICAL_NOT };
|
||||
rules[TK_TRUE] = (PrattRule){ exprLiteral0 };
|
||||
rules[TK_FALSE] = (PrattRule){ exprLiteral0 };
|
||||
rules[TK_NONE] = (PrattRule){ exprLiteral0 };
|
||||
rules[TK_DOTDOTDOT] = (PrattRule){ exprLiteral0 };
|
||||
rules[TK_LAMBDA] = (PrattRule){ exprLambda, };
|
||||
rules[TK_ID] = (PrattRule){ exprName, };
|
||||
rules[TK_NUM] = (PrattRule){ exprLiteral, };
|
||||
rules[TK_STR] = (PrattRule){ exprLiteral, };
|
||||
rules[TK_FSTR] = (PrattRule){ exprFString, };
|
||||
rules[TK_LONG] = (PrattRule){ exprLong, };
|
||||
rules[TK_IMAG] = (PrattRule){ exprImag, };
|
||||
rules[TK_BYTES] = (PrattRule){ exprBytes, };
|
||||
rules[TK_LBRACE] = (PrattRule){ exprMap };
|
||||
rules[TK_COLON] = (PrattRule){ exprSlice0, exprSlice1, PREC_PRIMARY };
|
||||
|
||||
#undef PK_METHOD
|
||||
#undef PK_NO_INFIX
|
||||
|
@ -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");
|
||||
}
|
||||
|
58
src/compiler/context.c
Normal file
58
src/compiler/context.c
Normal file
@ -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);
|
||||
}
|
@ -1,56 +1,27 @@
|
||||
#include "pocketpy/compiler/expr.h"
|
||||
#include "pocketpy/compiler/context.h"
|
||||
#include "pocketpy/common/memorypool.h"
|
||||
#include "pocketpy/common/strname.h"
|
||||
#include <ctype.h>
|
||||
|
||||
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 +30,634 @@ 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);
|
||||
}
|
||||
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; 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;
|
||||
}
|
||||
|
||||
static pk_ExprVt CompExprVt;
|
||||
|
||||
void pk_CompExpr__dtor(pk_Expr* self_){
|
||||
pk_CompExpr* self = (pk_CompExpr*)self_;
|
||||
pk_Expr__delete(self->expr);
|
||||
pk_Expr__delete(self->vars);
|
||||
pk_Expr__delete(self->iter);
|
||||
pk_Expr__delete(self->cond);
|
||||
}
|
||||
|
||||
void pk_CompExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_CompExpr* self = (pk_CompExpr*)self_;
|
||||
pk_CodeEmitContext__emit_(ctx, self->op0, 0, self->line);
|
||||
self->iter->vt->emit_(self->iter, ctx);
|
||||
pk_CodeEmitContext__emit_(ctx, OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
|
||||
pk_CodeEmitContext__enter_block(ctx, CodeBlockType_FOR_LOOP);
|
||||
int curr_iblock = ctx->curr_iblock;
|
||||
int for_codei = pk_CodeEmitContext__emit_(ctx, OP_FOR_ITER, curr_iblock, BC_KEEPLINE);
|
||||
bool ok = self->vars->vt->emit_store(self->vars, ctx);
|
||||
// this error occurs in `vars` instead of this line, but...nevermind
|
||||
assert(ok); // this should raise a SyntaxError, but we just assert it
|
||||
pk_CodeEmitContext__try_merge_for_iter_store(ctx, for_codei);
|
||||
if(self->cond) {
|
||||
self->cond->vt->emit_(self->cond, ctx);
|
||||
int patch = pk_CodeEmitContext__emit_(ctx, OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE);
|
||||
self->expr->vt->emit_(self->expr, ctx);
|
||||
pk_CodeEmitContext__emit_(ctx, self->op1, BC_NOARG, BC_KEEPLINE);
|
||||
pk_CodeEmitContext__patch_jump(ctx, patch);
|
||||
} else {
|
||||
self->expr->vt->emit_(self->expr, ctx);
|
||||
pk_CodeEmitContext__emit_(ctx, self->op1, BC_NOARG, BC_KEEPLINE);
|
||||
}
|
||||
pk_CodeEmitContext__emit_(ctx, OP_LOOP_CONTINUE, curr_iblock, BC_KEEPLINE);
|
||||
pk_CodeEmitContext__exit_block(ctx);
|
||||
}
|
||||
|
||||
pk_CompExpr* pk_CompExpr__new(Opcode op0, Opcode op1){
|
||||
static_assert_expr_size(pk_CompExpr);
|
||||
pk_CompExpr* self = PoolExpr_alloc();
|
||||
self->vt = &CompExprVt;
|
||||
self->line = -1;
|
||||
self->op0 = op0;
|
||||
self->op1 = op1;
|
||||
self->expr = NULL;
|
||||
self->vars = NULL;
|
||||
self->iter = NULL;
|
||||
self->cond = NULL;
|
||||
return self;
|
||||
}
|
||||
|
||||
static pk_ExprVt LambdaExprVt;
|
||||
|
||||
pk_LambdaExpr* pk_LambdaExpr__new(int index){
|
||||
static_assert_expr_size(pk_LambdaExpr);
|
||||
pk_LambdaExpr* self = PoolExpr_alloc();
|
||||
self->vt = &LambdaExprVt;
|
||||
self->line = -1;
|
||||
self->index = index;
|
||||
return self;
|
||||
}
|
||||
|
||||
static void pk_LambdaExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_LambdaExpr* self = (pk_LambdaExpr*)self_;
|
||||
pk_CodeEmitContext__emit_(ctx, OP_LOAD_FUNCTION, self->index, self->line);
|
||||
}
|
||||
|
||||
static pk_ExprVt FStringExprVt;
|
||||
|
||||
static bool is_fmt_valid_char(char c) {
|
||||
switch(c) {
|
||||
// clang-format off
|
||||
case '-': case '=': case '*': case '#': case '@': case '!': case '~':
|
||||
case '<': case '>': case '^':
|
||||
case '.': case 'f': case 'd': case 's':
|
||||
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
|
||||
return true;
|
||||
default: return false;
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_identifier(c11_string s) {
|
||||
if(s.size == 0) return false;
|
||||
if(!isalpha(s.data[0]) && s.data[0] != '_') return false;
|
||||
for(int i=0; i<s.size; i++){
|
||||
char c = s.data[i];
|
||||
if(!isalnum(c) && c != '_') return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _load_simple_expr(pk_CodeEmitContext* ctx, c11_string expr, int line) {
|
||||
bool repr = false;
|
||||
const char* expr_end = expr.data + expr.size;
|
||||
if(expr.size >= 2 && expr_end[-2] == '!') {
|
||||
switch(expr_end[-1]) {
|
||||
case 'r':
|
||||
repr = true;
|
||||
expr.size -= 2; // expr[:-2]
|
||||
break;
|
||||
case 's':
|
||||
repr = false;
|
||||
expr.size -= 2; // expr[:-2]
|
||||
break;
|
||||
default: break; // nothing happens
|
||||
}
|
||||
}
|
||||
// name or name.name
|
||||
bool is_fastpath = false;
|
||||
if(is_identifier(expr)) {
|
||||
// ctx->emit_(OP_LOAD_NAME, StrName(expr.sv()).index, line);
|
||||
pk_CodeEmitContext__emit_(
|
||||
ctx,
|
||||
OP_LOAD_NAME,
|
||||
pk_StrName__map2(expr),
|
||||
line
|
||||
);
|
||||
is_fastpath = true;
|
||||
} else {
|
||||
int dot = c11_string__index(expr, '.');
|
||||
if(dot > 0) {
|
||||
// std::string_view a = expr.sv().substr(0, dot);
|
||||
// std::string_view b = expr.sv().substr(dot + 1);
|
||||
c11_string a = {expr.data, dot}; // expr[:dot]
|
||||
c11_string b = {expr.data+(dot+1), expr.size-(dot+1)}; // expr[dot+1:]
|
||||
if(is_identifier(a) && is_identifier(b)) {
|
||||
pk_CodeEmitContext__emit_(ctx, OP_LOAD_NAME, pk_StrName__map2(a), line);
|
||||
pk_CodeEmitContext__emit_(ctx, OP_LOAD_ATTR, pk_StrName__map2(b), line);
|
||||
is_fastpath = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!is_fastpath) {
|
||||
int index = pk_CodeEmitContext__add_const_string(ctx, expr);
|
||||
pk_CodeEmitContext__emit_(ctx, OP_FSTRING_EVAL, index, line);
|
||||
}
|
||||
|
||||
if(repr) {
|
||||
pk_CodeEmitContext__emit_(ctx, OP_REPR, BC_NOARG, line);
|
||||
}
|
||||
}
|
||||
|
||||
static void pk_FStringExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_FStringExpr* self = (pk_FStringExpr*)self_;
|
||||
int i = 0; // left index
|
||||
int j = 0; // right index
|
||||
int count = 0; // how many string parts
|
||||
bool flag = false; // true if we are in a expression
|
||||
|
||||
const char* src = self->src.data;
|
||||
while(j < self->src.size) {
|
||||
if(flag) {
|
||||
if(src[j] == '}') {
|
||||
// add expression
|
||||
c11_string expr = {src+i, j-i}; // src[i:j]
|
||||
// BUG: ':' is not a format specifier in f"{stack[2:]}"
|
||||
int conon = c11_string__index(expr, ':');
|
||||
if(conon >= 0) {
|
||||
c11_string spec = {expr.data+(conon+1), expr.size-(conon+1)}; // expr[conon+1:]
|
||||
// filter some invalid spec
|
||||
bool ok = true;
|
||||
for(int k = 0; k < spec.size; k++) {
|
||||
char c = spec.data[k];
|
||||
if(!is_fmt_valid_char(c)) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(ok) {
|
||||
expr.size = conon; // expr[:conon]
|
||||
_load_simple_expr(ctx, expr, self->line);
|
||||
// ctx->emit_(OP_FORMAT_STRING, ctx->add_const_string(spec.sv()), line);
|
||||
pk_CodeEmitContext__emit_(ctx, OP_FORMAT_STRING, pk_CodeEmitContext__add_const_string(ctx, spec), self->line);
|
||||
} else {
|
||||
// ':' is not a spec indicator
|
||||
_load_simple_expr(ctx, expr, self->line);
|
||||
}
|
||||
} else {
|
||||
_load_simple_expr(ctx, expr, self->line);
|
||||
}
|
||||
flag = false;
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
if(src[j] == '{') {
|
||||
// look at next char
|
||||
if(j + 1 < self->src.size && src[j + 1] == '{') {
|
||||
// {{ -> {
|
||||
j++;
|
||||
pk_CodeEmitContext__emit_(
|
||||
ctx,
|
||||
OP_LOAD_CONST,
|
||||
pk_CodeEmitContext__add_const_string(ctx, (c11_string){"{", 1}),
|
||||
self->line
|
||||
);
|
||||
count++;
|
||||
} else {
|
||||
// { -> }
|
||||
flag = true;
|
||||
i = j + 1;
|
||||
}
|
||||
} else if(src[j] == '}') {
|
||||
// look at next char
|
||||
if(j + 1 < self->src.size && src[j + 1] == '}') {
|
||||
// }} -> }
|
||||
j++;
|
||||
pk_CodeEmitContext__emit_(
|
||||
ctx,
|
||||
OP_LOAD_CONST,
|
||||
pk_CodeEmitContext__add_const_string(ctx, (c11_string){"}", 1}),
|
||||
self->line
|
||||
);
|
||||
count++;
|
||||
} else {
|
||||
// } -> error
|
||||
// throw std::runtime_error("f-string: unexpected }");
|
||||
// just ignore
|
||||
}
|
||||
} else {
|
||||
// literal
|
||||
i = j;
|
||||
while(j < self->src.size && src[j] != '{' && src[j] != '}')
|
||||
j++;
|
||||
c11_string literal = {src+i, j-i}; // src[i:j]
|
||||
pk_CodeEmitContext__emit_(
|
||||
ctx,
|
||||
OP_LOAD_CONST,
|
||||
pk_CodeEmitContext__add_const_string(ctx, literal),
|
||||
self->line
|
||||
);
|
||||
count++;
|
||||
continue; // skip j++
|
||||
}
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
if(flag) {
|
||||
// literal
|
||||
c11_string literal = {src+i, self->src.size-i}; // src[i:]
|
||||
pk_CodeEmitContext__emit_(ctx, OP_LOAD_CONST, pk_CodeEmitContext__add_const_string(ctx, literal), self->line);
|
||||
count++;
|
||||
}
|
||||
pk_CodeEmitContext__emit_(ctx, OP_BUILD_STRING, count, self->line);
|
||||
}
|
||||
|
||||
pk_FStringExpr* pk_FStringExpr__new(c11_string src){
|
||||
static_assert_expr_size(pk_FStringExpr);
|
||||
pk_FStringExpr* self = PoolExpr_alloc();
|
||||
self->vt = &FStringExprVt;
|
||||
self->line = -1;
|
||||
self->src = src;
|
||||
return self;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////
|
||||
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;
|
||||
|
||||
pk_ExprVt__ctor(&CompExprVt);
|
||||
vt = &CompExprVt;
|
||||
vt->dtor = pk_CompExpr__dtor;
|
||||
vt->emit_ = pk_CompExpr__emit_;
|
||||
|
||||
pk_ExprVt__ctor(&LambdaExprVt);
|
||||
vt = &LambdaExprVt;
|
||||
vt->emit_ = pk_LambdaExpr__emit_;
|
||||
|
||||
pk_ExprVt__ctor(&FStringExprVt);
|
||||
vt = &FStringExprVt;
|
||||
vt->emit_ = pk_FStringExpr__emit_;
|
||||
}
|
||||
|
@ -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{
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user