mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
Compare commits
3 Commits
8c41065258
...
841cc25a4e
Author | SHA1 | Date | |
---|---|---|---|
|
841cc25a4e | ||
|
e365124af3 | ||
|
1696bb6d66 |
@ -50,10 +50,9 @@ typedef struct pk_VM {
|
||||
void (*_stdout)(const char*, ...);
|
||||
void (*_stderr)(const char*, ...);
|
||||
|
||||
// singleton objects
|
||||
py_TValue True, False, None, NotImplemented, Ellipsis;
|
||||
|
||||
py_TValue last_retval;
|
||||
bool has_error;
|
||||
|
||||
py_TValue reg[8]; // users' registers
|
||||
|
||||
py_TValue __curr_class;
|
||||
|
@ -40,10 +40,10 @@ void py_initialize();
|
||||
void py_finalize();
|
||||
|
||||
/// Run a simple source string. Do not change the stack.
|
||||
bool py_exec(const char*);
|
||||
bool py_exec(const char* source);
|
||||
/// Eval a simple expression.
|
||||
/// The result will be set to `py_retval()`.
|
||||
bool py_eval(const char*);
|
||||
bool py_eval(const char* source);
|
||||
|
||||
/************* Values Creation *************/
|
||||
void py_newint(py_Ref, py_i64);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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, sizeof(c11_string) + 100);
|
||||
self->data.count = sizeof(c11_string);
|
||||
}
|
||||
|
||||
void c11_sbuf__dtor(c11_sbuf* self) { c11_vector__dtor(&self->data); }
|
||||
@ -25,14 +23,16 @@ void c11_sbuf__write_char(c11_sbuf* self, char c) { c11_vector__push(char, &self
|
||||
void c11_sbuf__write_int(c11_sbuf* self, int i) {
|
||||
// len('-2147483648') == 11
|
||||
c11_vector__reserve(&self->data, self->data.count + 11 + 1);
|
||||
int n = snprintf(self->data.data, 11 + 1, "%d", i);
|
||||
char* p = self->data.data + self->data.count;
|
||||
int n = snprintf(p, 11 + 1, "%d", i);
|
||||
self->data.count += n;
|
||||
}
|
||||
|
||||
void c11_sbuf__write_i64(c11_sbuf* self, int64_t val) {
|
||||
// len('-9223372036854775808') == 20
|
||||
c11_vector__reserve(&self->data, self->data.count + 20 + 1);
|
||||
int n = snprintf(self->data.data, 20 + 1, "%lld", (long long)val);
|
||||
char* p = self->data.data + self->data.count;
|
||||
int n = snprintf(p, 20 + 1, "%lld", (long long)val);
|
||||
self->data.count += n;
|
||||
}
|
||||
|
||||
@ -136,8 +136,8 @@ void c11_sbuf__write_ptr(c11_sbuf* self, void* p) {
|
||||
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;
|
||||
c11_string* retval = arr.data;
|
||||
retval->size = arr.count - sizeof(c11_string) - 1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -20,11 +20,6 @@ void py_Name__initialize() {
|
||||
#define MAGIC_METHOD(x) assert(x == py_name(#x));
|
||||
#include "pocketpy/xmacros/magics.h"
|
||||
#undef MAGIC_METHOD
|
||||
|
||||
// print all names
|
||||
for(int i = 0; i < _interned.count; i++) {
|
||||
printf("%d: %s\n", i + 1, c11__getitem(char*, &_r_interned, i));
|
||||
}
|
||||
}
|
||||
|
||||
void py_Name__finalize() {
|
||||
|
@ -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;
|
||||
|
||||
@ -671,7 +671,7 @@ static void FStringExpr__emit_(Expr* self_, Ctx* ctx) {
|
||||
int conon = c11_sv__index(expr, ':');
|
||||
if(conon >= 0) {
|
||||
c11_sv spec = {expr.data + (conon + 1),
|
||||
expr.size - (conon + 1)}; // expr[conon+1:]
|
||||
expr.size - (conon + 1)}; // expr[conon+1:]
|
||||
// filter some invalid spec
|
||||
bool ok = true;
|
||||
for(int k = 0; k < spec.size; k++) {
|
||||
@ -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;
|
||||
|
@ -13,7 +13,6 @@ int NameError(py_Name name) { return -1; }
|
||||
|
||||
static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop);
|
||||
|
||||
|
||||
#define DISPATCH() \
|
||||
do { \
|
||||
frame->ip++; \
|
||||
@ -123,13 +122,13 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
DISPATCH();
|
||||
/*****************************************/
|
||||
case OP_LOAD_CONST: PUSH(c11__at(py_TValue, &frame->co->consts, byte.arg)); DISPATCH();
|
||||
case OP_LOAD_NONE: PUSH(&self->None); DISPATCH();
|
||||
case OP_LOAD_TRUE: PUSH(&self->True); DISPATCH();
|
||||
case OP_LOAD_FALSE: PUSH(&self->False); DISPATCH();
|
||||
case OP_LOAD_NONE: py_newnone(SP()++); DISPATCH();
|
||||
case OP_LOAD_TRUE: py_newbool(SP()++, true); DISPATCH();
|
||||
case OP_LOAD_FALSE: py_newbool(SP()++, false); DISPATCH();
|
||||
/*****************************************/
|
||||
case OP_LOAD_SMALL_INT: py_newint(SP()++, (int64_t)(int16_t)byte.arg); DISPATCH();
|
||||
/*****************************************/
|
||||
case OP_LOAD_ELLIPSIS: PUSH(&self->Ellipsis); DISPATCH();
|
||||
case OP_LOAD_ELLIPSIS: py_newellipsis(SP()++); DISPATCH();
|
||||
case OP_LOAD_FUNCTION: {
|
||||
// FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
|
||||
// py_TValue obj;
|
||||
@ -512,7 +511,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
bool res = py_isidentical(SECOND(), TOP());
|
||||
POP();
|
||||
if(byte.arg) res = !res;
|
||||
*TOP() = res ? self->True : self->False;
|
||||
py_newbool(TOP(), res);
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_CONTAINS_OP: {
|
||||
@ -575,9 +574,9 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
case OP_SHORTCUT_IF_FALSE_OR_POP: {
|
||||
int res = py_bool(TOP());
|
||||
if(res < 0) goto __ERROR;
|
||||
if(!res) { // [b, False]
|
||||
STACK_SHRINK(2); // []
|
||||
PUSH(&self->False); // [False]
|
||||
if(!res) { // [b, False]
|
||||
STACK_SHRINK(2); // []
|
||||
py_newbool(SP()++, false); // [False]
|
||||
DISPATCH_JUMP((int16_t)byte.arg);
|
||||
} else {
|
||||
POP(); // [b]
|
||||
@ -606,7 +605,11 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
// }
|
||||
/*****************************************/
|
||||
case OP_RETURN_VALUE: {
|
||||
self->last_retval = byte.arg == BC_NOARG ? POPX() : self->None;
|
||||
if(byte.arg == BC_NOARG) {
|
||||
self->last_retval = POPX();
|
||||
} else {
|
||||
py_newnone(&self->last_retval);
|
||||
}
|
||||
pk_VM__pop_frame(self);
|
||||
if(frame == base_frame) { // [ frameBase<- ]
|
||||
return RES_RETURN;
|
||||
@ -617,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();
|
||||
}
|
||||
|
||||
@ -625,6 +653,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
__ERROR:
|
||||
// 1. Exception can be handled inside the current frame
|
||||
// 2. Exception need to be propagated to the upper frame
|
||||
printf("byte.op: %d, line: %d\n", byte.op, Frame__lineno(frame));
|
||||
assert(false);
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
self->_stderr = pk_default_stderr;
|
||||
|
||||
self->last_retval = PY_NULL;
|
||||
self->has_error = false;
|
||||
|
||||
self->__curr_class = PY_NULL;
|
||||
self->__cached_object_new = PY_NULL;
|
||||
@ -148,7 +149,10 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
pk_TypeInfo* ti = c11__at(pk_TypeInfo, &self->types, t);
|
||||
py_setdict(&self->builtins, ti->name, py_tpobject(t));
|
||||
}
|
||||
py_setdict(&self->builtins, py_name("NotImplemented"), &self->NotImplemented);
|
||||
|
||||
py_TValue tmp;
|
||||
py_newnotimplemented(&tmp);
|
||||
py_setdict(&self->builtins, py_name("NotImplemented"), &tmp);
|
||||
|
||||
/* Do Buildin Bindings*/
|
||||
pk_VM__init_builtins(self);
|
||||
|
@ -0,0 +1,16 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
void py_printexc(){
|
||||
pk_VM* vm = pk_current_vm;
|
||||
if(vm->has_error){
|
||||
assert(vm->last_retval.type == tp_exception);
|
||||
}else{
|
||||
vm->_stdout("NoneType: None\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void py_formatexc(char *out){
|
||||
|
||||
}
|
141
src/public/vm.c
141
src/public/vm.c
@ -2,6 +2,7 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/compiler/compiler.h"
|
||||
@ -23,17 +24,145 @@ void py_finalize() {
|
||||
pk_MemoryPools__finalize();
|
||||
}
|
||||
|
||||
bool py_exec(const char* source) { PK_UNREACHABLE(); }
|
||||
static void disassemble(CodeObject* co) {
|
||||
const static char* OP_NAMES[] = {
|
||||
#define OPCODE(name) #name,
|
||||
#include "pocketpy/xmacros/opcodes.h"
|
||||
#undef OPCODE
|
||||
};
|
||||
|
||||
bool py_eval(const char* source) {
|
||||
c11_vector /*T=int*/ jumpTargets;
|
||||
c11_vector__ctor(&jumpTargets, sizeof(int));
|
||||
for(int i = 0; i < co->codes.count; i++) {
|
||||
Bytecode* bc = c11__at(Bytecode, &co->codes, i);
|
||||
if(Bytecode__is_forward_jump(bc)) {
|
||||
int target = (int16_t)bc->arg + i;
|
||||
c11_vector__push(int, &jumpTargets, target);
|
||||
}
|
||||
}
|
||||
|
||||
c11_sbuf ss;
|
||||
c11_sbuf__ctor(&ss);
|
||||
|
||||
int prev_line = -1;
|
||||
for(int i = 0; i < co->codes.count; i++) {
|
||||
Bytecode byte = c11__getitem(Bytecode, &co->codes, i);
|
||||
BytecodeEx ex = c11__getitem(BytecodeEx, &co->codes_ex, i);
|
||||
|
||||
char line[8] = "";
|
||||
if(ex.lineno == prev_line) {
|
||||
// do nothing
|
||||
} else {
|
||||
snprintf(line, sizeof(line), "%d", ex.lineno);
|
||||
if(prev_line != -1) c11_sbuf__write_char(&ss, '\n');
|
||||
prev_line = ex.lineno;
|
||||
}
|
||||
|
||||
char pointer[4] = "";
|
||||
c11__foreach(int, &jumpTargets, it) {
|
||||
if(*it == i) {
|
||||
snprintf(pointer, sizeof(pointer), "->");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "%-8s%-3s%-3d", line, pointer, i);
|
||||
c11_sbuf__write_cstr(&ss, buf);
|
||||
|
||||
snprintf(buf, sizeof(buf), " %-24s", OP_NAMES[byte.op]);
|
||||
c11_sbuf__write_cstr(&ss, buf);
|
||||
c11_sbuf__write_char(&ss, ex.is_virtual ? '*' : ' ');
|
||||
|
||||
// _opcode_argstr(this, i, byte, co);
|
||||
do {
|
||||
if(Bytecode__is_forward_jump(&byte)) {
|
||||
c11_sbuf__write_int(&ss, (int16_t)byte.arg);
|
||||
c11_sbuf__write_cstr(&ss, " (to ");
|
||||
c11_sbuf__write_int(&ss, (int16_t)byte.arg + i);
|
||||
c11_sbuf__write_char(&ss, ')');
|
||||
break;
|
||||
}
|
||||
|
||||
c11_sbuf__write_int(&ss, byte.arg);
|
||||
switch(byte.op) {
|
||||
case OP_LOAD_CONST:
|
||||
case OP_FORMAT_STRING:
|
||||
case OP_IMPORT_PATH: {
|
||||
py_Ref tmp = c11__at(py_TValue, &co->consts, byte.arg);
|
||||
c11_sbuf__write_cstr(&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:
|
||||
case OP_LOAD_GLOBAL:
|
||||
case OP_LOAD_NONLOCAL:
|
||||
case OP_STORE_GLOBAL:
|
||||
case OP_LOAD_ATTR:
|
||||
case OP_LOAD_METHOD:
|
||||
case OP_STORE_ATTR:
|
||||
case OP_DELETE_ATTR:
|
||||
case OP_BEGIN_CLASS:
|
||||
case OP_GOTO:
|
||||
case OP_DELETE_GLOBAL:
|
||||
case OP_STORE_CLASS_ATTR:
|
||||
case OP_FOR_ITER_STORE_GLOBAL: {
|
||||
c11_sbuf__write_cstr(&ss, " (");
|
||||
c11_sbuf__write_cstr(&ss, py_name2str(byte.arg));
|
||||
c11_sbuf__write_char(&ss, ')');
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_FAST:
|
||||
case OP_STORE_FAST:
|
||||
case OP_DELETE_FAST:
|
||||
case OP_FOR_ITER_STORE_FAST: {
|
||||
py_Name name = c11__getitem(py_Name, &co->varnames, byte.arg);
|
||||
c11_sbuf__write_cstr(&ss, " (");
|
||||
c11_sbuf__write_cstr(&ss, py_name2str(name));
|
||||
c11_sbuf__write_char(&ss, ')');
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_FUNCTION: {
|
||||
const FuncDecl* decl = c11__getitem(FuncDecl*, &co->func_decls, byte.arg);
|
||||
c11_sbuf__write_cstr(&ss, " (");
|
||||
c11_sbuf__write_cstr(&ss, decl->code.name->data);
|
||||
c11_sbuf__write_char(&ss, ')');
|
||||
break;
|
||||
}
|
||||
case OP_BINARY_OP: {
|
||||
py_Name name = byte.arg & 0xFF;
|
||||
c11_sbuf__write_cstr(&ss, " (");
|
||||
c11_sbuf__write_cstr(&ss, py_name2str(name));
|
||||
c11_sbuf__write_char(&ss, ')');
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(0);
|
||||
|
||||
if(i != co->codes.count - 1) c11_sbuf__write_char(&ss, '\n');
|
||||
}
|
||||
|
||||
c11_string* output = c11_sbuf__submit(&ss);
|
||||
pk_current_vm->_stdout("%s\n", output->data);
|
||||
c11_string__delete(output);
|
||||
c11_vector__dtor(&jumpTargets);
|
||||
}
|
||||
|
||||
static bool
|
||||
pk_VM__exec(pk_VM* vm, const char* source, const char* filename, enum CompileMode mode) {
|
||||
CodeObject co;
|
||||
pk_SourceData_ src = pk_SourceData__rcnew(source, "main.py", EVAL_MODE, false);
|
||||
pk_SourceData_ src = pk_SourceData__rcnew(source, filename, mode, false);
|
||||
Error* err = pk_compile(src, &co);
|
||||
if(err) {
|
||||
PK_DECREF(src);
|
||||
return false;
|
||||
}
|
||||
pk_VM* vm = pk_current_vm;
|
||||
|
||||
disassemble(&co);
|
||||
|
||||
Frame* frame = Frame__new(&co, &vm->main, NULL, vm->stack.sp, vm->stack.sp, &co);
|
||||
pk_VM__push_frame(vm, frame);
|
||||
pk_FrameResult res = pk_VM__run_top_frame(vm);
|
||||
@ -44,6 +173,10 @@ bool py_eval(const char* source) {
|
||||
PK_UNREACHABLE();
|
||||
}
|
||||
|
||||
bool py_exec(const char* source) { return pk_VM__exec(pk_current_vm, source, "<exec>", EXEC_MODE); }
|
||||
|
||||
bool py_eval(const char* source) { return pk_VM__exec(pk_current_vm, source, "<eval>", EVAL_MODE); }
|
||||
|
||||
bool py_call(py_Ref f, int argc, py_Ref argv) { return -1; }
|
||||
|
||||
bool py_callmethod(py_Ref self, py_Name name, int argc, py_Ref argv) { return -1; }
|
||||
|
23
src2/main.c
23
src2/main.c
@ -25,6 +25,7 @@ int main(int argc, char** argv) {
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
py_initialize();
|
||||
const char* source = "1 < 2";
|
||||
|
||||
@ -47,20 +48,18 @@ int main(int argc, char** argv) {
|
||||
|
||||
py_finalize();
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
// if(argc != 2) goto __HELP;
|
||||
// char* source = read_file(argv[1]);
|
||||
// py_initialize();
|
||||
if(argc != 2) goto __HELP;
|
||||
char* source = read_file(argv[1]);
|
||||
py_initialize();
|
||||
|
||||
// if(py_exec(source)){
|
||||
// py_Error* err = py_getlasterror();
|
||||
// py_Error__print(err);
|
||||
// }
|
||||
if(!py_exec(source)) py_printexc();
|
||||
|
||||
// py_finalize();
|
||||
// free(source);
|
||||
py_finalize();
|
||||
free(source);
|
||||
|
||||
// __HELP:
|
||||
// printf("Usage: pocketpy [filename]\n");
|
||||
// return 0;
|
||||
__HELP:
|
||||
printf("Usage: pocketpy [filename]\n");
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user