diff --git a/include/pocketpy/interpreter/frame.h b/include/pocketpy/interpreter/frame.h index b51fb1a8..e6310d9c 100644 --- a/include/pocketpy/interpreter/frame.h +++ b/include/pocketpy/interpreter/frame.h @@ -71,6 +71,10 @@ PK_INLINE py_TValue* Frame__f_globals_try_get(Frame* self, py_Name name){ return pk_NameDict__try_get(Frame__f_globals(self), name); } +PK_INLINE py_TValue* Frame__f_locals_try_get(Frame* self, py_Name name){ + return FastLocals__try_get_by_name(self->locals, self->locals_co, name); +} + py_TValue* Frame__f_closure_try_get(Frame* self, py_Name name); int Frame__prepare_jump_exception_handler(Frame* self, ValueStack*); diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 0ae27667..1e156250 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -12,7 +12,7 @@ typedef py_TValue* py_Ref; typedef struct py_Str py_Str; typedef int (*py_CFunction)(int argc, py_Ref argv); -typedef struct py_Error{ +typedef struct py_Error { py_Type type; } py_Error; @@ -30,8 +30,8 @@ void py_finalize(); /// Run a simple source string. Do not change the stack. int py_exec(const char*); -/// Eval a simple expression. If succeed, the result will be pushed onto the stack. -int py_eval(const char*); +/// Eval a simple expression. +int py_eval(const char*, py_Ref out); /************* Values Creation *************/ void py_newint(py_Ref, int64_t); @@ -49,10 +49,20 @@ void py_newtuple(py_Ref, int); // new style decl-based function void py_newfunction(py_Ref out, py_CFunction, const char* sig); -void py_newfunction2(py_Ref out, py_CFunction, const char* sig, BindType bt, const char* docstring, const py_Ref upvalue); +void py_newfunction2(py_Ref out, + py_CFunction, + const char* sig, + BindType bt, + const char* docstring, + const py_Ref upvalue); // old style argc-based function void py_newnativefunc(py_Ref out, py_CFunction, int argc); -void py_newnativefunc2(py_Ref out, py_CFunction, int argc, BindType bt, const char* docstring, const py_Ref upvalue); +void py_newnativefunc2(py_Ref out, + py_CFunction, + int argc, + BindType bt, + const char* docstring, + const py_Ref upvalue); /// Create a new object. /// @param out output reference. @@ -146,8 +156,8 @@ int py_eq(const py_Ref, const py_Ref); int py_le(const py_Ref, const py_Ref); int py_hash(const py_Ref, int64_t* out); -int py_str(const py_Ref); -int py_repr(const py_Ref); +int py_str(const py_Ref, py_Ref out); +int py_repr(const py_Ref, py_Ref out); int py_vectorcall(int argc, int kwargc); int py_call(py_Ref f, ...); diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index f62ac75e..a859bf2f 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -4,6 +4,10 @@ #include "pocketpy/objects/codeobject.h" #include "pocketpy/pocketpy.h" +int UnboundLocalError(py_Name name) { return -1; } + +int NameError(py_Name name) { return -1; } + #define DISPATCH() \ do { \ frame->ip++; \ @@ -83,7 +87,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { } case OP_PRINT_EXPR: if(TOP().type != tp_none_type) { - int err = py_repr(&TOP()); + int err = py_repr(&TOP(), NULL); if(err) goto __ERROR; self->_stdout("%s\n", py_tostr(&TOP())); POP(); @@ -91,15 +95,14 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { POP(); DISPATCH(); /*****************************************/ - case OP_LOAD_CONST: PUSH(c11__getitem(py_TValue, &frame->co->consts, byte.arg)); DISPATCH(); + case OP_LOAD_CONST: + PUSH(c11__getitem(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_SMALL_INT: - py_newint(SP(), (int64_t)(int16_t)byte.arg); - SP()++; - 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_FUNCTION: { @@ -119,10 +122,88 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { // PUSH(obj);DISPATCH(); } case OP_LOAD_NULL: - py_newnull(SP()); - SP()++; + py_newnull(SP()++); DISPATCH(); - /*****************************************/ + /*****************************************/ + case OP_LOAD_FAST: { + PUSH(frame->locals[byte.arg]); + if(py_isnull(&TOP())) { + py_Name name = c11__getitem(uint16_t, &frame->co->varnames, byte.arg); + UnboundLocalError(name); + goto __ERROR; + } + DISPATCH(); + } + case OP_LOAD_NAME: { + py_Name name = byte.arg; + py_Ref tmp = Frame__f_locals_try_get(frame, name); + if(tmp != NULL) { + if(py_isnull(tmp)) { + UnboundLocalError(name); + goto __ERROR; + } + PUSH(*tmp); + DISPATCH(); + } + tmp = Frame__f_closure_try_get(frame, name); + if(tmp != NULL) { + PUSH(*tmp); + DISPATCH(); + } + tmp = Frame__f_globals_try_get(frame, name); + if(tmp != NULL) { + PUSH(*tmp); + DISPATCH(); + } + tmp = py_getdict(&self->builtins, name); + if(tmp != NULL) { + PUSH(*tmp); + DISPATCH(); + } + NameError(name); + goto __ERROR; + } + case OP_LOAD_NONLOCAL: { + py_Name name = byte.arg; + py_Ref tmp = Frame__f_closure_try_get(frame, name); + if(tmp != NULL) { + PUSH(*tmp); + DISPATCH(); + } + tmp = Frame__f_globals_try_get(frame, name); + if(tmp != NULL) { + PUSH(*tmp); + DISPATCH(); + } + tmp = py_getdict(&self->builtins, name); + if(tmp != NULL) { + PUSH(*tmp); + DISPATCH(); + } + NameError(name); + goto __ERROR; + } + case OP_LOAD_GLOBAL: { + py_Name name = byte.arg; + py_Ref tmp = Frame__f_globals_try_get(frame, name); + if(tmp != NULL) { + PUSH(*tmp); + DISPATCH(); + } + tmp = py_getdict(&self->builtins, name); + if(tmp != NULL) { + PUSH(*tmp); + DISPATCH(); + } + NameError(name); + goto __ERROR; + } + case OP_LOAD_ATTR: { + int err = py_getattr(&TOP(), byte.arg, &TOP()); + if(err) goto __ERROR; + DISPATCH(); + } + default: PK_UNREACHABLE(); } diff --git a/src/public/py_ops.c b/src/public/py_ops.c index 41baa2e4..c609a2f3 100644 --- a/src/public/py_ops.c +++ b/src/public/py_ops.c @@ -7,10 +7,14 @@ int py_le(const py_Ref lhs, const py_Ref rhs) { return 0; } int py_hash(const py_Ref val, int64_t* out) { return 0; } -int py_str(const py_Ref val) { return 0; } +int py_str(const py_Ref val, py_Ref out) { return 0; } -int py_repr(const py_Ref val) { +int py_repr(const py_Ref val, py_Ref out) { const pk_TypeInfo* ti = c11__at(pk_TypeInfo, &pk_current_vm->types, val->type); - if(ti->m__repr__) return ti->m__repr__(1, val); - return py_callmethod(val, __repr__); + int err; + if(ti->m__repr__) err = ti->m__repr__(1, val); + err = py_callmethod(val, __repr__); + if(err) return err; + if(out) *out = *--pk_current_vm->stack.sp; + return 0; } \ No newline at end of file diff --git a/src/public/vm.c b/src/public/vm.c index cc4b8a36..c6dce675 100644 --- a/src/public/vm.c +++ b/src/public/vm.c @@ -25,7 +25,7 @@ void py_finalize() { int py_exec(const char* source) { PK_UNREACHABLE(); } -int py_eval(const char* source) { +int py_eval(const char* source, py_Ref out) { CodeObject co; pk_SourceData_ src = pk_SourceData__rcnew(source, "main.py", EVAL_MODE, false); Error* err = pk_compile(src, &co); @@ -40,6 +40,9 @@ int py_eval(const char* source) { CodeObject__dtor(&co); PK_DECREF(src); if(res == RES_ERROR) return vm->last_error->type; - if(res == RES_RETURN) return 0; + if(res == RES_RETURN){ + if(out) *out = *--vm->stack.sp; + return 0; + } PK_UNREACHABLE(); } \ No newline at end of file diff --git a/src2/main.c b/src2/main.c index ad4867ec..635dd94c 100644 --- a/src2/main.c +++ b/src2/main.c @@ -27,7 +27,7 @@ int main(int argc, char** argv) { py_initialize(); const char* source = "[1, 'a']"; - if(py_eval(source)){ + if(py_eval(source, NULL)){ py_Error* err = py_getlasterror(); py_Error__print(err); }else{