This commit is contained in:
blueloveTH 2024-07-03 00:48:45 +08:00
parent 1696bb6d66
commit e365124af3
5 changed files with 311 additions and 37 deletions

View File

@ -27,6 +27,7 @@ static void pk_SourceData__ctor(struct pk_SourceData* self,
}
self->source = c11_sbuf__submit(&ss);
self->is_precompiled = (strncmp(source, "pkpy:", 5) == 0);
self->is_dynamic = is_dynamic;
c11_vector__push(const char*, &self->line_starts, self->source->data);
}

View File

@ -10,12 +10,10 @@
#include <ctype.h>
#include <math.h>
const static int C11_STRING_HEADER_SIZE = sizeof(c11_string);
void c11_sbuf__ctor(c11_sbuf* self) {
c11_vector__ctor(&self->data, sizeof(char));
c11_vector__reserve(&self->data, 100 + C11_STRING_HEADER_SIZE);
self->data.count = C11_STRING_HEADER_SIZE;
c11_vector__reserve(&self->data, 100 + sizeof(c11_string));
self->data.count = sizeof(c11_string);
}
void c11_sbuf__dtor(c11_sbuf* self) { c11_vector__dtor(&self->data); }
@ -137,7 +135,7 @@ c11_string* c11_sbuf__submit(c11_sbuf* self) {
c11_vector__push(char, &self->data, '\0');
c11_array arr = c11_vector__submit(&self->data);
c11_string* retval = (c11_string*)arr.data;
retval->size = arr.count - C11_STRING_HEADER_SIZE - 1;
retval->size = arr.count - sizeof(c11_string) - 1;
return retval;
}

View File

@ -64,7 +64,7 @@ typedef struct Ctx {
int curr_iblock;
bool is_compiling_class;
c11_vector /*T=Expr* */ s_expr;
c11_vector /*T=py_Name*/ global_names;
c11_smallmap_n2i global_names;
c11_smallmap_s2n co_consts_string_dedup_map;
} Ctx;
@ -1209,7 +1209,7 @@ void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level) {
self->curr_iblock = 0;
self->is_compiling_class = false;
c11_vector__ctor(&self->s_expr, sizeof(Expr*));
c11_vector__ctor(&self->global_names, sizeof(py_Name));
c11_smallmap_n2i__ctor(&self->global_names);
c11_smallmap_s2n__ctor(&self->co_consts_string_dedup_map);
}
@ -1220,7 +1220,7 @@ void Ctx__dtor(Ctx* self) {
}
c11_vector__clear(&self->s_expr);
c11_vector__dtor(&self->s_expr);
c11_vector__dtor(&self->global_names);
c11_smallmap_n2i__dtor(&self->global_names);
c11_smallmap_s2n__dtor(&self->co_consts_string_dedup_map);
}
@ -1455,7 +1455,7 @@ static void Compiler__dtor(Compiler* self) {
pk_TokenSymbols[expected], \
pk_TokenSymbols[curr()->type]);
#define consume_end_stmt() \
if(!match_end_stmt()) return SyntaxError("expected statement end")
if(!match_end_stmt(self)) return SyntaxError("expected statement end")
#define check_newlines_repl() \
do { \
bool __nml; \
@ -1471,7 +1471,7 @@ static NameScope name_scope(Compiler* self) {
return s;
}
static Error* SyntaxError(const char* fmt, ...) { return NULL; }
#define SyntaxError(...) NULL
static Error* NeedMoreLines() { return NULL; }
@ -1798,10 +1798,7 @@ static Error* exprName(Compiler* self) {
py_Name name = py_name2(Token__sv(prev()));
NameScope scope = name_scope(self);
// promote this name to global scope if needed
c11_vector* global_names = &ctx()->global_names;
c11__foreach(py_Name, global_names, it) {
if(*it == name) scope = NAME_GLOBAL;
}
if(c11_smallmap_n2i__contains(&ctx()->global_names, name)) { scope = NAME_GLOBAL; }
NameExpr* e = NameExpr__new(prev()->line, name, scope);
Ctx__s_push(ctx(), (Expr*)e);
return NULL;
@ -2005,6 +2002,258 @@ static Error* exprSubscr(Compiler* self) {
return NULL;
}
////////////////
static Error* consume_type_hints(Compiler* self) {
Error* err;
check(EXPR(self));
Ctx__s_pop(ctx());
return NULL;
}
Error* try_compile_assignment(Compiler* self, bool* is_assign) {
Error* err;
switch(curr()->type) {
case TK_IADD:
case TK_ISUB:
case TK_IMUL:
case TK_IDIV:
case TK_IFLOORDIV:
case TK_IMOD:
case TK_ILSHIFT:
case TK_IRSHIFT:
case TK_IAND:
case TK_IOR:
case TK_IXOR: {
if(Ctx__s_top(ctx())->vt->is_starred) return SyntaxError();
if(ctx()->is_compiling_class) {
return SyntaxError("can't use inplace operator in class definition");
}
advance();
// a[x] += 1; a and x should be evaluated only once
// a.x += 1; a should be evaluated only once
// -1 to remove =; inplace=true
int line = prev()->line;
TokenIndex op = (TokenIndex)(prev()->type - 1);
// [lhs]
check(EXPR_TUPLE(self)); // [lhs, rhs]
if(Ctx__s_top(ctx())->vt->is_starred) return SyntaxError();
BinaryExpr* e = BinaryExpr__new(line, op, true);
e->rhs = Ctx__s_popx(ctx()); // [lhs]
e->lhs = Ctx__s_popx(ctx()); // []
vtemit_((Expr*)e, ctx());
bool ok = vtemit_istore(e->lhs, ctx());
vtdelete((Expr*)e);
if(!ok) return SyntaxError();
*is_assign = true;
return NULL;
}
case TK_ASSIGN: {
int n = 0;
while(match(TK_ASSIGN)) {
check(EXPR_TUPLE(self));
n += 1;
}
// stack size is n+1
Ctx__s_emit_top(ctx());
for(int j = 1; j < n; j++)
Ctx__emit_(ctx(), OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
for(int j = 0; j < n; j++) {
if(Ctx__s_top(ctx())->vt->is_starred) return SyntaxError();
Expr* e = Ctx__s_top(ctx());
bool ok = vtemit_store(e, ctx());
Ctx__s_pop(ctx());
if(!ok) return SyntaxError();
}
*is_assign = true;
return NULL;
}
default: *is_assign = false;
}
return NULL;
}
static Error* compile_stmt(Compiler* self) {
Error* err;
if(match(TK_CLASS)) {
// check(compile_class());
assert(false);
return NULL;
}
advance();
int kw_line = prev()->line; // backup line number
int curr_loop_block = Ctx__get_loop(ctx());
switch(prev()->type) {
case TK_BREAK:
if(curr_loop_block < 0) return SyntaxError("'break' outside loop");
Ctx__emit_(ctx(), OP_LOOP_BREAK, curr_loop_block, kw_line);
consume_end_stmt();
break;
case TK_CONTINUE:
if(curr_loop_block < 0) return SyntaxError("'continue' not properly in loop");
Ctx__emit_(ctx(), OP_LOOP_CONTINUE, curr_loop_block, kw_line);
consume_end_stmt();
break;
case TK_YIELD:
if(self->contexts.count <= 1) return SyntaxError("'yield' outside function");
check(EXPR_TUPLE(self));
Ctx__s_emit_top(ctx());
Ctx__emit_(ctx(), OP_YIELD_VALUE, BC_NOARG, kw_line);
consume_end_stmt();
break;
case TK_YIELD_FROM:
if(self->contexts.count <= 1) return SyntaxError("'yield from' outside function");
check(EXPR_TUPLE(self));
Ctx__s_emit_top(ctx());
Ctx__emit_(ctx(), OP_GET_ITER_NEW, BC_NOARG, kw_line);
Ctx__enter_block(ctx(), CodeBlockType_FOR_LOOP);
Ctx__emit_(ctx(), OP_FOR_ITER_YIELD_VALUE, BC_NOARG, kw_line);
Ctx__emit_(ctx(), OP_LOOP_CONTINUE, Ctx__get_loop(ctx()), kw_line);
Ctx__exit_block(ctx());
consume_end_stmt();
break;
case TK_RETURN:
if(self->contexts.count <= 1) return SyntaxError("'return' outside function");
if(match_end_stmt(self)) {
Ctx__emit_(ctx(), OP_RETURN_VALUE, 1, kw_line);
} else {
check(EXPR_TUPLE(self));
Ctx__s_emit_top(ctx());
consume_end_stmt();
Ctx__emit_(ctx(), OP_RETURN_VALUE, BC_NOARG, kw_line);
}
break;
/*************************************************/
// case TK_IF: check(compile_if_stmt()); break;
// case TK_WHILE: check(compile_while_loop()); break;
// case TK_FOR: check(compile_for_loop()); break;
// case TK_IMPORT: check(compile_normal_import()); break;
// case TK_FROM: check(compile_from_import()); break;
// case TK_DEF: check(compile_function()); break;
// case TK_DECORATOR: check(compile_decorated()); break;
// case TK_TRY: check(compile_try_except()); break;
case TK_PASS: consume_end_stmt(); break;
/*************************************************/
case TK_ASSERT: {
check(EXPR(self)); // condition
Ctx__s_emit_top(ctx());
int index = Ctx__emit_(ctx(), OP_POP_JUMP_IF_TRUE, BC_NOARG, kw_line);
int has_msg = 0;
if(match(TK_COMMA)) {
check(EXPR(self)); // message
Ctx__s_emit_top(ctx());
has_msg = 1;
}
Ctx__emit_(ctx(), OP_RAISE_ASSERT, has_msg, kw_line);
Ctx__patch_jump(ctx(), index);
consume_end_stmt();
break;
}
case TK_GLOBAL:
do {
consume(TK_ID);
py_Name name = py_name2(Token__sv(prev()));
c11_smallmap_n2i__set(&ctx()->global_names, name, 0);
} while(match(TK_COMMA));
consume_end_stmt();
break;
case TK_RAISE: {
check(EXPR(self));
Ctx__s_emit_top(ctx());
Ctx__emit_(ctx(), OP_RAISE, BC_NOARG, kw_line);
consume_end_stmt();
} break;
case TK_DEL: {
check(EXPR_TUPLE(self));
Expr* e = Ctx__s_top(ctx());
if(!vtemit_del(e, ctx())) return SyntaxError();
Ctx__s_pop(ctx());
consume_end_stmt();
} break;
// case TK_WITH: {
// check(EXPR(self)); // [ <expr> ]
// Ctx__s_emit_top(ctx());
// Ctx__enter_block(ctx(), CodeBlockType_CONTEXT_MANAGER);
// Expr* as_name = nullptr;
// if(match(TK_AS)) {
// consume(TK_ID);
// as_name = make_expr<NameExpr>(prev().str(), name_scope());
// }
// Ctx__emit_(ctx(), OP_WITH_ENTER, BC_NOARG, prev().line);
// // [ <expr> <expr>.__enter__() ]
// if(as_name) {
// bool ok = as_name->emit_store(ctx());
// delete_expr(as_name);
// if(!ok) return SyntaxError();
// } else {
// Ctx__emit_(ctx(), OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
// }
// check(compile_block_body());
// Ctx__emit_(ctx(), OP_WITH_EXIT, BC_NOARG, prev().line);
// Ctx__exit_block(ctx());
// } break;
/*************************************************/
case TK_EQ: {
consume(TK_ID);
if(mode() != EXEC_MODE) return SyntaxError("'label' is only available in EXEC_MODE");
c11_sv name = Token__sv(prev());
bool ok = Ctx__add_label(ctx(), py_name2(name));
if(!ok) return SyntaxError("label %q already exists", name);
consume(TK_EQ);
consume_end_stmt();
} break;
case TK_ARROW:
consume(TK_ID);
if(mode() != EXEC_MODE) return SyntaxError("'goto' is only available in EXEC_MODE");
py_Name name = py_name2(Token__sv(prev()));
Ctx__emit_(ctx(), OP_GOTO, name, prev()->line);
consume_end_stmt();
break;
/*************************************************/
// handle dangling expression or assignment
default: {
// do revert since we have pre-called advance() at the beginning
--self->i;
check(EXPR_TUPLE(self));
bool is_typed_name = false; // e.g. x: int
// eat variable's type hint if it is a single name
if(Ctx__s_top(ctx())->vt->is_name) {
if(match(TK_COLON)) {
check(consume_type_hints(self));
is_typed_name = true;
if(ctx()->is_compiling_class) {
NameExpr* ne = (NameExpr*)Ctx__s_top(ctx());
Ctx__emit_(ctx(), OP_ADD_CLASS_ANNOTATION, ne->name, BC_KEEPLINE);
}
}
}
bool is_assign = false;
check(try_compile_assignment(self, &is_assign));
if(!is_assign) {
if(Ctx__s_size(ctx()) > 0 && Ctx__s_top(ctx())->vt->is_starred) {
return SyntaxError();
}
if(!is_typed_name) {
Ctx__s_emit_top(ctx());
if((mode() == CELL_MODE || mode() == REPL_MODE) &&
name_scope(self) == NAME_GLOBAL) {
Ctx__emit_(ctx(), OP_PRINT_EXPR, BC_NOARG, BC_KEEPLINE);
} else {
Ctx__emit_(ctx(), OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
}
} else {
Ctx__s_pop(ctx());
}
}
consume_end_stmt();
break;
}
}
return NULL;
}
/////////////////////////////////////////////////////////////////
Error* Compiler__compile(Compiler* self, CodeObject* out) {
@ -2026,25 +2275,22 @@ Error* Compiler__compile(Compiler* self, CodeObject* out) {
Ctx__emit_(ctx(), OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
check(pop_context(self));
return NULL;
} else if(mode() == JSON_MODE) {
check(EXPR(self));
Expr* e = Ctx__s_popx(ctx());
if(!e->vt->is_json_object) { return SyntaxError("expect a JSON object, literal or array"); }
consume(TK_EOF);
vtemit_(e, ctx());
Ctx__emit_(ctx(), OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
check(pop_context(self));
return NULL;
}
// } else if(mode() == JSON_MODE) {
// check(EXPR(self));
// Expr* e = Ctx__s_popx(ctx());
// if(!e->is_json_object()){
// return SyntaxError("expect a JSON object, literal or array");
// }
// consume(TK_EOF);
// e->emit_(ctx());
// ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
// check(pop_context());
// return NULL;
// }
// while(!match(TK_EOF)) {
// check(compile_stmt());
// match_newlines();
// }
// check(pop_context());
while(!match(TK_EOF)) {
check(compile_stmt(self));
match_newlines();
}
check(pop_context(self));
return NULL;
}
@ -2069,6 +2315,8 @@ Error* pk_compile(pk_SourceData_ src, CodeObject* out) {
if(err) {
// if error occurs, dispose the code object
CodeObject__dtor(out);
} else {
assert(out->codes.count);
}
Compiler__dtor(&compiler);
return err;

View File

@ -605,9 +605,9 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
// }
/*****************************************/
case OP_RETURN_VALUE: {
if(byte.arg == BC_NOARG){
if(byte.arg == BC_NOARG) {
self->last_retval = POPX();
}else{
} else {
py_newnone(&self->last_retval);
}
pk_VM__pop_frame(self);
@ -620,6 +620,31 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
}
DISPATCH();
}
/////////
case OP_UNARY_NEGATIVE: {
if(!py_callmagic(__neg__, 1, TOP())) goto __ERROR;
*TOP() = self->last_retval;
DISPATCH();
}
case OP_UNARY_NOT: {
int res = py_bool(TOP());
if(res < 0) goto __ERROR;
py_newbool(TOP(), !res);
DISPATCH();
}
// case OP_UNARY_STAR: TOP() = VAR(StarWrapper(byte.arg, TOP())); DISPATCH();
// case OP_UNARY_INVERT: {
// PyVar _0;
// auto _ti = _tp_info(TOP());
// if(_ti->m__invert__)
// _0 = _ti->m__invert__(this, TOP());
// else
// _0 = call_method(TOP(), __invert__);
// TOP() = _0;
// DISPATCH();
// }
default: PK_UNREACHABLE();
}

View File

@ -89,10 +89,12 @@ static void disassemble(CodeObject* co) {
case OP_LOAD_CONST:
case OP_FORMAT_STRING:
case OP_IMPORT_PATH: {
c11_string* ud = py_touserdata(c11__at(py_TValue, &co->consts, byte.arg));
py_Ref tmp = c11__at(py_TValue, &co->consts, byte.arg);
c11_sbuf__write_cstr(&ss, " (");
c11_sbuf__write_cstr(&ss, ud->data);
c11_sbuf__write_char(&ss, ')');
// here we need to use py_repr, however this function is not ready yet
c11_sbuf__write_cstr(&ss, "<class '");
c11_sbuf__write_cstr(&ss, py_tpname(tmp->type));
c11_sbuf__write_cstr(&ss, "'>)");
break;
}
case OP_LOAD_NAME: