diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index a1033e5d..9db880ff 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -18,6 +18,16 @@ // 5. stack effect of each opcode // 6. py_TypeInfo +typedef struct SourceLocation { + SourceData_ src; + int lineno; +} SourceLocation; + +typedef struct TraceInfo { + SourceLocation prev_loc; + py_TraceFunc tracefunc; +} TraceInfo; + typedef struct VM { Frame* top_frame; @@ -38,9 +48,10 @@ typedef struct VM { py_TValue reg[8]; // users' registers void* ctx; // user-defined context - py_StackRef __curr_class; - py_StackRef __curr_function; - py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES]; + py_StackRef curr_class; + py_StackRef curr_function; + TraceInfo trace_info; + py_TValue vectorcall_buffer[PK_MAX_CO_VARNAMES]; InternedNames names; FixedMemoryPool pool_frame; diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 710438bf..a0cea0e6 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -34,45 +34,6 @@ typedef struct c11_sv { int size; } c11_sv; -// An enum for tracing events. -enum py_TraceEvent { - TraceEvent_Line, - TraceEvent_Call, - TraceEvent_Return, - TraceEvent_Exception, -}; - -/// A struct contains the arguments of the tracing event. -union py_TraceEventArg { - struct { - int _; - } line; - - struct { - int _; - } call; - - struct { - int _; - } return_; - - struct { - int _; - } exception; -}; - -/// A struct contains the callbacks of the VM. -typedef struct py_Callbacks { - /// Used by `__import__` to load source code of a module. - char* (*importfile)(const char*); - /// Used by `print` to output a string. - void (*print)(const char*); - /// Used by `input` to get a character. - int (*getchar)(); - /// C-style `sys.settrace` function. - void (*tracefunc)(enum py_TraceEvent, union py_TraceEventArg); -} py_Callbacks; - #define PY_RAISE #define PY_RETURN @@ -89,6 +50,28 @@ typedef py_TValue* py_ItemRef; /// An output reference for returning a value. typedef py_TValue* py_OutRef; +typedef struct py_Frame py_Frame; + +// An enum for tracing events. +enum py_TraceEvent { + TRACE_EVENT_LINE, + TRACE_EVENT_CALL, + TRACE_EVENT_RETURN, + TRACE_EVENT_EXCEPTION, +}; + +typedef void (*py_TraceFunc)(py_Frame* frame, enum py_TraceEvent); + +/// A struct contains the callbacks of the VM. +typedef struct py_Callbacks { + /// Used by `__import__` to load source code of a module. + char* (*importfile)(const char*); + /// Used by `print` to output a string. + void (*print)(const char*); + /// Used by `input` to get a character. + int (*getchar)(); +} py_Callbacks; + /// Native function signature. /// @param argc number of arguments. /// @param argv array of arguments. Use `py_arg(i)` macro to get the i-th argument. @@ -120,6 +103,8 @@ PK_API void* py_getvmctx(); PK_API void py_setvmctx(void* ctx); /// Set `sys.argv`. Used for storing command-line arguments. PK_API void py_sys_setargv(int argc, char** argv); +/// Set the trace function for the current VM. +PK_API void py_sys_settrace(py_TraceFunc func); /// Setup the callbacks for the current VM. PK_API py_Callbacks* py_callbacks(); diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index f8db639b..a4690dbe 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -1046,7 +1046,7 @@ void CallExpr__emit_(Expr* self_, Ctx* ctx) { Opcode opcode = OP_CALL; if(vargs || vkwargs) { // in this case, there is at least one *args or **kwargs as StarredExpr - // OP_CALL_VARGS needs to unpack them via __vectorcall_buffer + // OP_CALL_VARGS needs to unpack them via vectorcall_buffer opcode = OP_CALL_VARGS; } diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 99a6537a..38f81009 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -97,7 +97,7 @@ FrameResult VM__run_top_frame(VM* self) { frame->ip++; __NEXT_STEP: - if(self->callbacks.tracefunc) { + if(self->trace_info.tracefunc) { // TODO: implement tracing mechanism } @@ -298,9 +298,9 @@ FrameResult VM__run_top_frame(VM* self) { DISPATCH(); } case OP_LOAD_CLASS_GLOBAL: { - assert(self->__curr_class); + assert(self->curr_class); py_Name name = byte.arg; - py_Ref tmp = py_getdict(self->__curr_class, name); + py_Ref tmp = py_getdict(self->curr_class, name); if(tmp) { PUSH(tmp); DISPATCH(); @@ -691,7 +691,7 @@ FrameResult VM__run_top_frame(VM* self) { py_TValue* sp = SP(); py_TValue* p1 = sp - kwargc * 2; py_TValue* base = p1 - argc; - py_TValue* buf = self->__vectorcall_buffer; + py_TValue* buf = self->vectorcall_buffer; for(py_TValue* curr = base; curr != p1; curr++) { if(curr->type != tp_star_wrapper) { @@ -1008,7 +1008,7 @@ FrameResult VM__run_top_frame(VM* self) { base_ti->is_python, false); PUSH(py_tpobject(type)); - self->__curr_class = TOP(); + self->curr_class = TOP(); DISPATCH(); } case OP_END_CLASS: { @@ -1033,11 +1033,11 @@ FrameResult VM__run_top_frame(VM* self) { // class with decorator is unsafe currently // it skips the above check POP(); - self->__curr_class = NULL; + self->curr_class = NULL; DISPATCH(); } case OP_STORE_CLASS_ATTR: { - assert(self->__curr_class); + assert(self->curr_class); py_Name name = byte.arg; // TOP() can be a function, classmethod or custom decorator py_Ref actual_func = TOP(); @@ -1046,16 +1046,16 @@ FrameResult VM__run_top_frame(VM* self) { } if(actual_func->type == tp_function) { Function* ud = py_touserdata(actual_func); - ud->clazz = self->__curr_class->_obj; + ud->clazz = self->curr_class->_obj; } - py_setdict(self->__curr_class, name, TOP()); + py_setdict(self->curr_class, name, TOP()); POP(); DISPATCH(); } case OP_ADD_CLASS_ANNOTATION: { - assert(self->__curr_class); + assert(self->curr_class); // [type_hint string] - py_Type type = py_totype(self->__curr_class); + py_Type type = py_totype(self->curr_class); py_TypeInfo* ti = TypeList__get(&self->types, type); if(py_isnil(&ti->annotations)) py_newdict(&ti->annotations); bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(byte.arg), TOP()); diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 9660186f..7b11af2c 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -68,15 +68,15 @@ void VM__ctor(VM* self) { self->callbacks.importfile = pk_default_importfile; self->callbacks.print = pk_default_print; self->callbacks.getchar = getchar; - self->callbacks.tracefunc = NULL; self->last_retval = *py_NIL(); self->curr_exception = *py_NIL(); self->is_curr_exc_handled = false; self->ctx = NULL; - self->__curr_class = NULL; - self->__curr_function = NULL; + self->curr_class = NULL; + self->curr_function = NULL; + memset(&self->trace_info, 0, sizeof(TraceInfo)); FixedMemoryPool__ctor(&self->pool_frame, sizeof(Frame), 32); @@ -479,11 +479,11 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall switch(fn->decl->type) { case FuncType_NORMAL: { - bool ok = prepare_py_call(self->__vectorcall_buffer, argv, p1, kwargc, fn->decl); + bool ok = prepare_py_call(self->vectorcall_buffer, argv, p1, kwargc, fn->decl); if(!ok) return RES_ERROR; // copy buffer back to stack self->stack.sp = argv + co->nlocals; - memcpy(argv, self->__vectorcall_buffer, co->nlocals * sizeof(py_TValue)); + memcpy(argv, self->vectorcall_buffer, co->nlocals * sizeof(py_TValue)); // submit the call if(!fn->cfunc) { // python function @@ -491,10 +491,10 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall return opcall ? RES_CALL : VM__run_top_frame(self); } else { // decl-based binding - self->__curr_function = p0; + self->curr_function = p0; bool ok = py_callcfunc(fn->cfunc, co->nlocals, argv); self->stack.sp = p0; - self->__curr_function = NULL; + self->curr_function = NULL; return ok ? RES_RETURN : RES_ERROR; } } @@ -520,18 +520,18 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall return opcall ? RES_CALL : VM__run_top_frame(self); } else { // decl-based binding - self->__curr_function = p0; + self->curr_function = p0; bool ok = py_callcfunc(fn->cfunc, co->nlocals, argv); self->stack.sp = p0; - self->__curr_function = NULL; + self->curr_function = NULL; return ok ? RES_RETURN : RES_ERROR; } case FuncType_GENERATOR: { - bool ok = prepare_py_call(self->__vectorcall_buffer, argv, p1, kwargc, fn->decl); + bool ok = prepare_py_call(self->vectorcall_buffer, argv, p1, kwargc, fn->decl); if(!ok) return RES_ERROR; // copy buffer back to stack self->stack.sp = argv + co->nlocals; - memcpy(argv, self->__vectorcall_buffer, co->nlocals * sizeof(py_TValue)); + memcpy(argv, self->vectorcall_buffer, co->nlocals * sizeof(py_TValue)); Frame* frame = Frame__new(co, p0, fn->module, fn->globals, argv, false); pk_newgenerator(py_retval(), frame, p0, self->stack.sp); self->stack.sp = p0; // reset the stack diff --git a/src/public/py_exception.c b/src/public/py_exception.c index ace595b0..66c01c48 100644 --- a/src/public/py_exception.c +++ b/src/public/py_exception.c @@ -154,8 +154,8 @@ void py_clearexc(py_StackRef p0) { vm->curr_exception = *py_NIL(); vm->is_curr_exc_handled = false; /* Don't clear this, because StopIteration() may corrupt the class definition */ - // vm->__curr_class = NULL; - vm->__curr_function = NULL; + // vm->curr_class = NULL; + vm->curr_function = NULL; if(p0) vm->stack.sp = p0; } diff --git a/src/public/stack_ops.c b/src/public/stack_ops.c index c352ddb5..2d4ddf84 100644 --- a/src/public/stack_ops.c +++ b/src/public/stack_ops.c @@ -69,7 +69,7 @@ void py_setslot(py_Ref self, int i, py_Ref val) { } py_StackRef py_inspect_currentfunction(){ - return pk_current_vm->__curr_function; + return pk_current_vm->curr_function; } py_GlobalRef py_inspect_currentmodule(){