mirror of
				https://github.com/pocketpy/pocketpy
				synced 2025-10-30 08:20:16 +00:00 
			
		
		
		
	Compare commits
	
		
			No commits in common. "841cc25a4eaf77ec64885a24bd24e8baacccb1dc" and "8c41065258e2340e7e8f2fe15d9165f56ea90241" have entirely different histories.
		
	
	
		
			841cc25a4e
			...
			8c41065258
		
	
		
| @ -50,9 +50,10 @@ typedef struct pk_VM { | ||||
|     void (*_stdout)(const char*, ...); | ||||
|     void (*_stderr)(const char*, ...); | ||||
| 
 | ||||
|     py_TValue last_retval; | ||||
|     bool has_error; | ||||
|     // singleton objects
 | ||||
|     py_TValue True, False, None, NotImplemented, Ellipsis; | ||||
| 
 | ||||
|     py_TValue last_retval; | ||||
|     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* source); | ||||
| bool py_exec(const char*); | ||||
| /// Eval a simple expression.
 | ||||
| /// The result will be set to `py_retval()`.
 | ||||
| bool py_eval(const char* source); | ||||
| bool py_eval(const char*); | ||||
| 
 | ||||
| /************* Values Creation *************/ | ||||
| void py_newint(py_Ref, py_i64); | ||||
|  | ||||
| @ -27,7 +27,6 @@ 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,10 +10,12 @@ | ||||
| #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, sizeof(c11_string) + 100); | ||||
|     self->data.count = sizeof(c11_string); | ||||
|     c11_vector__reserve(&self->data, 100 + C11_STRING_HEADER_SIZE); | ||||
|     self->data.count = C11_STRING_HEADER_SIZE; | ||||
| } | ||||
| 
 | ||||
| void c11_sbuf__dtor(c11_sbuf* self) { c11_vector__dtor(&self->data); } | ||||
| @ -23,16 +25,14 @@ 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); | ||||
|     char* p = self->data.data + self->data.count; | ||||
|     int n = snprintf(p, 11 + 1, "%d", i); | ||||
|     int n = snprintf(self->data.data, 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); | ||||
|     char* p = self->data.data + self->data.count; | ||||
|     int n = snprintf(p, 20 + 1, "%lld", (long long)val); | ||||
|     int n = snprintf(self->data.data, 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 = arr.data; | ||||
|     retval->size = arr.count - sizeof(c11_string) - 1; | ||||
|     c11_string* retval = (c11_string*)arr.data; | ||||
|     retval->size = arr.count - C11_STRING_HEADER_SIZE - 1; | ||||
|     return retval; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -20,6 +20,11 @@ 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_smallmap_n2i global_names; | ||||
|     c11_vector /*T=py_Name*/ 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_smallmap_n2i__ctor(&self->global_names); | ||||
|     c11_vector__ctor(&self->global_names, sizeof(py_Name)); | ||||
|     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_smallmap_n2i__dtor(&self->global_names); | ||||
|     c11_vector__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(self)) return SyntaxError("expected statement end") | ||||
|     if(!match_end_stmt()) return SyntaxError("expected statement end") | ||||
| #define check_newlines_repl()                                                                      \ | ||||
|     do {                                                                                           \ | ||||
|         bool __nml;                                                                                \ | ||||
| @ -1471,7 +1471,7 @@ static NameScope name_scope(Compiler* self) { | ||||
|     return s; | ||||
| } | ||||
| 
 | ||||
| #define SyntaxError(...) NULL | ||||
| static Error* SyntaxError(const char* fmt, ...) { return NULL; } | ||||
| 
 | ||||
| static Error* NeedMoreLines() { return NULL; } | ||||
| 
 | ||||
| @ -1798,7 +1798,10 @@ 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
 | ||||
|     if(c11_smallmap_n2i__contains(&ctx()->global_names, name)) { scope = NAME_GLOBAL; } | ||||
|     c11_vector* global_names = &ctx()->global_names; | ||||
|     c11__foreach(py_Name, global_names, it) { | ||||
|         if(*it == name) scope = NAME_GLOBAL; | ||||
|     } | ||||
|     NameExpr* e = NameExpr__new(prev()->line, name, scope); | ||||
|     Ctx__s_push(ctx(), (Expr*)e); | ||||
|     return NULL; | ||||
| @ -2002,258 +2005,6 @@ 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) { | ||||
| @ -2275,22 +2026,25 @@ 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(self)); | ||||
|         match_newlines(); | ||||
|     } | ||||
|     check(pop_context(self)); | ||||
|     // while(!match(TK_EOF)) {
 | ||||
|     //     check(compile_stmt());
 | ||||
|     //     match_newlines();
 | ||||
|     // }
 | ||||
|     // check(pop_context());
 | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| @ -2315,8 +2069,6 @@ 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,6 +13,7 @@ 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++;                                                                               \ | ||||
| @ -122,13 +123,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: 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_NONE: PUSH(&self->None); DISPATCH(); | ||||
|             case OP_LOAD_TRUE: PUSH(&self->True); DISPATCH(); | ||||
|             case OP_LOAD_FALSE: PUSH(&self->False); DISPATCH(); | ||||
|             /*****************************************/ | ||||
|             case OP_LOAD_SMALL_INT: py_newint(SP()++, (int64_t)(int16_t)byte.arg); DISPATCH(); | ||||
|             /*****************************************/ | ||||
|             case OP_LOAD_ELLIPSIS: py_newellipsis(SP()++); DISPATCH(); | ||||
|             case OP_LOAD_ELLIPSIS: PUSH(&self->Ellipsis); DISPATCH(); | ||||
|             case OP_LOAD_FUNCTION: { | ||||
|                 // FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
 | ||||
|                 // py_TValue obj;
 | ||||
| @ -511,7 +512,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { | ||||
|                 bool res = py_isidentical(SECOND(), TOP()); | ||||
|                 POP(); | ||||
|                 if(byte.arg) res = !res; | ||||
|                 py_newbool(TOP(), res); | ||||
|                 *TOP() = res ? self->True : self->False; | ||||
|                 DISPATCH(); | ||||
|             } | ||||
|             case OP_CONTAINS_OP: { | ||||
| @ -576,7 +577,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { | ||||
|                 if(res < 0) goto __ERROR; | ||||
|                 if(!res) {               // [b, False]
 | ||||
|                     STACK_SHRINK(2);     // []
 | ||||
|                     py_newbool(SP()++, false);  // [False]
 | ||||
|                     PUSH(&self->False);  // [False]
 | ||||
|                     DISPATCH_JUMP((int16_t)byte.arg); | ||||
|                 } else { | ||||
|                     POP();  // [b]
 | ||||
| @ -605,11 +606,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { | ||||
|                 // }
 | ||||
|                 /*****************************************/ | ||||
|             case OP_RETURN_VALUE: { | ||||
|                 if(byte.arg == BC_NOARG) { | ||||
|                     self->last_retval = POPX(); | ||||
|                 } else { | ||||
|                     py_newnone(&self->last_retval); | ||||
|                 } | ||||
|                 self->last_retval = byte.arg == BC_NOARG ? POPX() : self->None; | ||||
|                 pk_VM__pop_frame(self); | ||||
|                 if(frame == base_frame) {  // [ frameBase<- ]
 | ||||
|                     return RES_RETURN; | ||||
| @ -620,31 +617,6 @@ 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(); | ||||
|         } | ||||
| 
 | ||||
| @ -653,7 +625,6 @@ 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,7 +68,6 @@ 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; | ||||
| @ -149,10 +148,7 @@ 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_TValue tmp; | ||||
|     py_newnotimplemented(&tmp); | ||||
|     py_setdict(&self->builtins, py_name("NotImplemented"), &tmp); | ||||
|     py_setdict(&self->builtins, py_name("NotImplemented"), &self->NotImplemented); | ||||
| 
 | ||||
|     /* Do Buildin Bindings*/ | ||||
|     pk_VM__init_builtins(self); | ||||
|  | ||||
| @ -1,16 +0,0 @@ | ||||
| #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,7 +2,6 @@ | ||||
| #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" | ||||
| @ -24,145 +23,17 @@ void py_finalize() { | ||||
|     pk_MemoryPools__finalize(); | ||||
| } | ||||
| 
 | ||||
| static void disassemble(CodeObject* co) { | ||||
|     const static char* OP_NAMES[] = { | ||||
| #define OPCODE(name) #name, | ||||
| #include "pocketpy/xmacros/opcodes.h" | ||||
| #undef OPCODE | ||||
|     }; | ||||
| bool py_exec(const char* source) { PK_UNREACHABLE(); } | ||||
| 
 | ||||
|     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) { | ||||
| bool py_eval(const char* source) { | ||||
|     CodeObject co; | ||||
|     pk_SourceData_ src = pk_SourceData__rcnew(source, filename, mode, false); | ||||
|     pk_SourceData_ src = pk_SourceData__rcnew(source, "main.py", EVAL_MODE, false); | ||||
|     Error* err = pk_compile(src, &co); | ||||
|     if(err) { | ||||
|         PK_DECREF(src); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     disassemble(&co); | ||||
| 
 | ||||
|     pk_VM* vm = pk_current_vm; | ||||
|     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); | ||||
| @ -173,10 +44,6 @@ static bool | ||||
|     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,7 +25,6 @@ int main(int argc, char** argv) { | ||||
|     SetConsoleOutputCP(CP_UTF8); | ||||
| #endif | ||||
| 
 | ||||
| #if 0 | ||||
|     py_initialize(); | ||||
|     const char* source = "1 < 2"; | ||||
| 
 | ||||
| @ -48,18 +47,20 @@ 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_printexc(); | ||||
|     //     if(py_exec(source)){
 | ||||
|     //         py_Error* err = py_getlasterror();
 | ||||
|     //         py_Error__print(err);
 | ||||
|     //     }
 | ||||
| 
 | ||||
|     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