diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index a40e2520..8ebffa47 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -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; diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 90447b7a..502c1115 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -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); diff --git a/src/common/strname.c b/src/common/strname.c index 622ced37..f9d56ba8 100644 --- a/src/common/strname.c +++ b/src/common/strname.c @@ -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() { diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 91550ef8..29e3148b 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -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; diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index d19eee9b..214e99e5 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -68,7 +68,8 @@ 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; self->__dynamic_func_decl = 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); diff --git a/src/public/error.c b/src/public/error.c index e69de29b..f7b0aeeb 100644 --- a/src/public/error.c +++ b/src/public/error.c @@ -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){ + +} \ No newline at end of file diff --git a/src/public/vm.c b/src/public/vm.c index ae86e5f7..4aa9651b 100644 --- a/src/public/vm.c +++ b/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,136 @@ 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) { + line[0] = '\0'; + } 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[64]; + 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: { + c11_string* ud = py_touserdata(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, ')'); + 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; + } + } + } 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 +164,10 @@ bool py_eval(const char* source) { PK_UNREACHABLE(); } +bool py_exec(const char* source) { return pk_VM__exec(pk_current_vm, source, "", EXEC_MODE); } + +bool py_eval(const char* source) { return pk_VM__exec(pk_current_vm, source, "", 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; }