diff --git a/include/pocketpy/interpreter/frame.h b/include/pocketpy/interpreter/frame.h index b4697331..753949cd 100644 --- a/include/pocketpy/interpreter/frame.h +++ b/include/pocketpy/interpreter/frame.h @@ -47,8 +47,7 @@ Frame* Frame__new(const CodeObject* co, py_GlobalRef module, py_StackRef p0, py_StackRef locals, - bool has_function, - bool is_dynamic); + bool has_function); void Frame__delete(Frame* self); int Frame__ip(const Frame* self); diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index b5d0e91c..30c0af50 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -97,6 +97,8 @@ bool pk_arraycontains(py_Ref self, py_Ref val); bool pk_loadmethod(py_StackRef self, py_Name name); bool pk_callmagic(py_Name name, int argc, py_Ref argv); +bool pk_exec(CodeObject* co, py_Ref module); + /// Assumes [a, b] are on the stack, performs a binary op. /// The result is stored in `self->last_retval`. /// The stack remains unchanged. @@ -129,6 +131,7 @@ py_Type pk_classmethod__register(); py_Type pk_generator__register(); py_Type pk_namedict__register(); py_Type pk_locals__register(); +py_Type pk_code__register(); py_TValue pk_builtins__register(); diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index c9c7e87e..50c27e26 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -45,7 +45,7 @@ typedef py_TValue* py_TmpRef; /// @return true if the function is successful. typedef bool (*py_CFunction)(int argc, py_StackRef argv) PY_RAISE; -enum py_CompileMode { EXEC_MODE, EVAL_MODE, REPL_MODE, CELL_MODE }; +enum py_CompileMode { EXEC_MODE, EVAL_MODE, SINGLE_MODE }; extern py_GlobalRef py_True; extern py_GlobalRef py_False; @@ -75,14 +75,16 @@ bool py_exec(const char* source, enum py_CompileMode mode, py_Ref module) PY_RAISE; -/// Run a source string in dynamic mode. -/// Assume `globals()` and `locals()` are pushed to the stack. -/// After the execution, the result will be set to `py_retval()`. -/// The stack size will be reduced by 2. -bool py_execdyn(const char* source, +bool py_compile(const char* source, const char* filename, enum py_CompileMode mode, - py_Ref module) PY_RAISE; + bool is_dynamic) PY_RAISE; + +/// Python equivalent to `globals()`. +void py_newglobals(py_Ref); +/// Python equivalent to `locals()`. +/// NOTE: Return a temporary object, which expires on the associated function return. +void py_newlocals(py_Ref); /************* Values Creation *************/ @@ -343,6 +345,8 @@ py_StackRef py_peek(int i); void py_push(py_Ref src); /// Push a `nil` object to the stack. void py_pushnil(); +/// Push a `None` object to the stack. +void py_pushnone(); /// Pop an object from the stack. void py_pop(); /// Shrink the stack by n. @@ -531,6 +535,7 @@ enum py_PredefinedTypes { tp_bytes, tp_namedict, tp_locals, + tp_code, tp_dict, tp_dict_items, // 1 slot tp_property, // 2 slots (getter + setter) diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 4a608789..e2f89cbb 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -629,17 +629,7 @@ static bool is_fmt_valid_char(char c) { } } -static bool is_identifier(c11_sv s) { - if(s.size == 0) return false; - if(!isalpha(s.data[0]) && s.data[0] != '_') return false; - for(int i = 0; i < s.size; i++) { - char c = s.data[i]; - if(!isalnum(c) && c != '_') return false; - } - return true; -} - -static void _load_simple_expr(Ctx* ctx, c11_sv expr, int line) { +static void _load_expr(Ctx* ctx, c11_sv expr, int line) { bool repr = false; const char* expr_end = expr.data + expr.size; if(expr.size >= 2 && expr_end[-2] == '!') { @@ -655,30 +645,18 @@ static void _load_simple_expr(Ctx* ctx, c11_sv expr, int line) { default: break; // nothing happens } } - // name or name.name - bool is_fastpath = false; - if(is_identifier(expr)) { - Ctx__emit_(ctx, OP_LOAD_NAME, py_namev(expr), line); - is_fastpath = true; - } else { - int dot = c11_sv__index(expr, '.'); - if(dot > 0) { - c11_sv a = {expr.data, dot}; // expr[:dot] - c11_sv b = {expr.data + (dot + 1), expr.size - (dot + 1)}; // expr[dot+1:] - if(is_identifier(a) && is_identifier(b)) { - Ctx__emit_(ctx, OP_LOAD_NAME, py_namev(a), line); - Ctx__emit_(ctx, OP_LOAD_ATTR, py_namev(b), line); - is_fastpath = true; - } - } - } - if(!is_fastpath) { - int index = Ctx__add_const_string(ctx, expr); - Ctx__emit_(ctx, OP_FSTRING_EVAL, index, line); + c11_string* source = c11_string__new2(expr.data, expr.size); + bool ok = py_compile(source->data, "", EVAL_MODE, false); + if(!ok){ + py_printexc(); + c11__abort("f-string: invalid expression"); } + int index = Ctx__add_const(ctx, py_retval()); + c11_string__delete(source); + Ctx__emit_(ctx, OP_FSTRING_EVAL, index, line); - if(repr) { Ctx__emit_(ctx, OP_REPR, BC_NOARG, line); } + if(repr) Ctx__emit_(ctx, OP_REPR, BC_NOARG, line); } static void FStringExpr__emit_(Expr* self_, Ctx* ctx) { @@ -710,18 +688,17 @@ static void FStringExpr__emit_(Expr* self_, Ctx* ctx) { } if(ok) { expr.size = conon; // expr[:conon] - _load_simple_expr(ctx, expr, self->line); - // ctx->emit_(OP_FORMAT_STRING, ctx->add_const_string(spec.sv()), line); + _load_expr(ctx, expr, self->line); Ctx__emit_(ctx, OP_FORMAT_STRING, Ctx__add_const_string(ctx, spec), self->line); } else { // ':' is not a spec indicator - _load_simple_expr(ctx, expr, self->line); + _load_expr(ctx, expr, self->line); } } else { - _load_simple_expr(ctx, expr, self->line); + _load_expr(ctx, expr, self->line); } flag = false; count++; @@ -2743,8 +2720,7 @@ static Error* compile_stmt(Compiler* self) { } if(!is_typed_name) { Ctx__s_emit_top(ctx()); - if((mode() == CELL_MODE || mode() == REPL_MODE) && - name_scope(self) == NAME_GLOBAL) { + if((mode() == SINGLE_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); diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 492bf961..112c9a1a 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -186,22 +186,18 @@ FrameResult VM__run_top_frame(VM* self) { } else { py_newstr(SP()++, py_name2str(name)); // locals - if(py_getitem(&frame->p0[1], TOP())) { - py_assign(TOP(), py_retval()); - DISPATCH(); - } else { - if(py_matchexc(tp_KeyError)) { - py_clearexc(NULL); + if(!py_isnone(&frame->p0[1])) { + if(py_getitem(&frame->p0[1], TOP())) { + py_assign(TOP(), py_retval()); + DISPATCH(); } else { - goto __ERROR; + if(py_matchexc(tp_KeyError)) { + py_clearexc(NULL); + } else { + goto __ERROR; + } } } - // closure - tmp = Frame__f_closure_try_get(frame, name); - if(tmp != NULL) { - py_assign(TOP(), tmp); - DISPATCH(); - } // globals if(py_getitem(&frame->p0[0], TOP())) { py_assign(TOP(), py_retval()); @@ -325,7 +321,7 @@ FrameResult VM__run_top_frame(VM* self) { py_Name name = byte.arg; py_newstr(SP()++, py_name2str(name)); // [value, name] - if(!py_isnone(&frame->p0[1])){ + if(!py_isnone(&frame->p0[1])) { // locals if(py_setitem(&frame->p0[1], TOP(), SECOND())) { STACK_SHRINK(2); @@ -337,7 +333,7 @@ FrameResult VM__run_top_frame(VM* self) { } goto __ERROR; } - }else{ + } else { // globals if(py_setitem(&frame->p0[0], TOP(), SECOND())) { STACK_SHRINK(2); @@ -395,7 +391,7 @@ FrameResult VM__run_top_frame(VM* self) { assert(frame->is_dynamic); py_Name name = byte.arg; py_newstr(SP()++, py_name2str(name)); - if(!py_isnone(&frame->p0[1])){ + if(!py_isnone(&frame->p0[1])) { // locals if(py_delitem(&frame->p0[1], TOP())) { POP(); @@ -407,7 +403,7 @@ FrameResult VM__run_top_frame(VM* self) { } goto __ERROR; } - }else{ + } else { // globals if(py_delitem(&frame->p0[0], TOP())) { POP(); @@ -911,7 +907,7 @@ FrameResult VM__run_top_frame(VM* self) { POP(); py_TypeInfo* base_ti = c11__at(py_TypeInfo, &self->types, base); - if(base_ti->is_sealed){ + if(base_ti->is_sealed) { TypeError("type '%t' is not an acceptable base type", base); goto __ERROR; } @@ -1032,9 +1028,8 @@ FrameResult VM__run_top_frame(VM* self) { ////////////////// case OP_FSTRING_EVAL: { py_TValue* tmp = c11__at(py_TValue, &frame->co->consts, byte.arg); - const char* string = py_tostr(tmp); - // TODO: optimize this - if(!py_exec(string, "", EVAL_MODE, frame->module)) goto __ERROR; + assert(py_istype(tmp, tp_code)); + if(!pk_exec(py_touserdata(tmp), frame->module)) goto __ERROR; PUSH(py_retval()); DISPATCH(); } diff --git a/src/interpreter/frame.c b/src/interpreter/frame.c index e65ba4d5..6706e3c0 100644 --- a/src/interpreter/frame.c +++ b/src/interpreter/frame.c @@ -41,8 +41,7 @@ Frame* Frame__new(const CodeObject* co, py_GlobalRef module, py_StackRef p0, py_StackRef locals, - bool has_function, - bool is_dynamic) { + bool has_function) { static_assert(sizeof(Frame) <= kPoolFrameBlockSize, "!(sizeof(Frame) <= kPoolFrameBlockSize)"); Frame* self = PoolFrame_alloc(); self->f_back = NULL; @@ -52,7 +51,7 @@ Frame* Frame__new(const CodeObject* co, self->p0 = p0; self->locals = locals; self->has_function = has_function; - self->is_dynamic = is_dynamic; + self->is_dynamic = co->src->is_dynamic; self->uw_list = NULL; return self; } @@ -134,7 +133,7 @@ void Frame__set_unwind_target(Frame* self, py_TValue* sp) { } } -void Frame__gc_mark(Frame *self){ +void Frame__gc_mark(Frame* self) { pk__mark_value(self->module); CodeObject__gc_mark(self->co); } diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 4e3590f9..4e009910 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -115,6 +115,7 @@ void VM__ctor(VM* self) { validate(tp_bytes, pk_bytes__register()); validate(tp_namedict, pk_namedict__register()); validate(tp_locals, pk_locals__register()); + validate(tp_code, pk_code__register()); validate(tp_dict, pk_dict__register()); validate(tp_dict_items, pk_dict_items__register()); @@ -435,7 +436,7 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall memcpy(argv, self->__vectorcall_buffer, co->nlocals * sizeof(py_TValue)); // submit the call if(!fn->cfunc) { - VM__push_frame(self, Frame__new(co, &fn->module, p0, argv, true, false)); + VM__push_frame(self, Frame__new(co, &fn->module, p0, argv, true)); return opcall ? RES_CALL : VM__run_top_frame(self); } else { bool ok = py_callcfunc(fn->cfunc, co->nlocals, argv); @@ -459,12 +460,12 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall // initialize local variables to py_NIL memset(p1, 0, (char*)self->stack.sp - (char*)p1); // submit the call - VM__push_frame(self, Frame__new(co, &fn->module, p0, argv, true, false)); + VM__push_frame(self, Frame__new(co, &fn->module, p0, argv, true)); return opcall ? RES_CALL : VM__run_top_frame(self); case FuncType_GENERATOR: { bool ok = prepare_py_call(self->__vectorcall_buffer, argv, p1, kwargc, fn->decl); if(!ok) return RES_ERROR; - Frame* frame = Frame__new(co, &fn->module, p0, argv, false, false); + Frame* frame = Frame__new(co, &fn->module, p0, argv, false); pk_newgenerator(py_retval(), frame, self->__vectorcall_buffer, co->nlocals); self->stack.sp = p0; return RES_RETURN; diff --git a/src/modules/dis.c b/src/modules/dis.c index 527383b6..69a706a6 100644 --- a/src/modules/dis.c +++ b/src/modules/dis.c @@ -113,9 +113,17 @@ static void disassemble(CodeObject* co) { static bool dis_dis(int argc, py_Ref argv) { PY_CHECK_ARGC(1); - PY_CHECK_ARG_TYPE(0, tp_function); - Function* ud = py_touserdata(argv); - disassemble(&ud->decl->code); + + CodeObject* code = NULL; + if(py_istype(argv, tp_function)){ + Function* ud = py_touserdata(argv); + code = &ud->decl->code; + }else if(py_istype(argv, tp_code)){ + code = py_touserdata(argv); + }else{ + return TypeError("dis() expected a code object"); + } + disassemble(code); py_newnone(py_retval()); return true; } diff --git a/src/public/cast.c b/src/public/cast.c index c27b8e8f..3f8d7806 100644 --- a/src/public/cast.c +++ b/src/public/cast.c @@ -19,7 +19,7 @@ bool py_castfloat(py_Ref self, double* out) { switch(self->type) { case tp_int: *out = (double)self->_i64; return true; case tp_float: *out = self->_f64; return true; - default: return TypeError("expected int or float, got %t", self->type); + default: return TypeError("expected 'int' or 'float', got '%t'", self->type); } } @@ -43,7 +43,7 @@ bool py_istype(py_Ref self, py_Type type) { return self->type == type; } bool py_checktype(py_Ref self, py_Type type) { if(self->type == type) return true; - return TypeError("expected %t, got %t", type, self->type); + return TypeError("expected '%t', got '%t'", type, self->type); } bool py_isinstance(py_Ref obj, py_Type type) { return py_issubclass(obj->type, type); } diff --git a/src/public/exec.c b/src/public/exec.c index c429139f..c47dc34c 100644 --- a/src/public/exec.c +++ b/src/public/exec.c @@ -8,47 +8,69 @@ #include "pocketpy/interpreter/vm.h" #include "pocketpy/compiler/compiler.h" -static bool _py_exec(const char* source, - const char* filename, - enum py_CompileMode mode, - py_Ref module, - bool is_dynamic) { +static void code__gc_mark(void* ud) { CodeObject__gc_mark(ud); } + +py_Type pk_code__register() { + py_Type type = pk_newtype("code", tp_object, NULL, (py_Dtor)CodeObject__dtor, false, true); + pk__tp_set_marker(type, code__gc_mark); + return type; +} + +bool _py_compile(CodeObject* out, + const char* source, + const char* filename, + enum py_CompileMode mode, + bool is_dynamic) { VM* vm = pk_current_vm; - CodeObject co; SourceData_ src = SourceData__rcnew(source, filename, mode, is_dynamic); - Error* err = pk_compile(src, &co); + Error* err = pk_compile(src, out); if(err) { py_exception(tp_SyntaxError, err->msg); py_BaseException__stpush(&vm->curr_exception, err->src, err->lineno, NULL); PK_DECREF(src); - + PK_DECREF(err->src); free(err); return false; } + PK_DECREF(src); + return true; +} +bool py_compile(const char* source, + const char* filename, + enum py_CompileMode mode, + bool is_dynamic) { + CodeObject co; + bool ok = _py_compile(&co, source, filename, mode, is_dynamic); + if(ok) { + // compile success + CodeObject* ud = py_newobject(py_retval(), tp_code, 0, sizeof(CodeObject)); + *ud = co; + } + return ok; +} + +bool pk_exec(CodeObject* co, py_Ref module) { + VM* vm = pk_current_vm; if(!module) module = &vm->main; + assert(module->type == tp_module); py_StackRef sp = vm->stack.sp; - if(is_dynamic) { - // [globals, locals] - sp -= 2; - } + if(co->src->is_dynamic) sp -= 3; // [globals, locals, code] - Frame* frame = Frame__new(&co, module, sp, sp, false, is_dynamic); + Frame* frame = Frame__new(co, module, sp, sp, false); VM__push_frame(vm, frame); FrameResult res = VM__run_top_frame(vm); - CodeObject__dtor(&co); - PK_DECREF(src); if(res == RES_ERROR) return false; if(res == RES_RETURN) return true; c11__unreachedable(); } bool py_exec(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) { - return _py_exec(source, filename, mode, module, false); + CodeObject co; + if(!_py_compile(&co, source, filename, mode, false)) return false; + bool ok = pk_exec(&co, module); + CodeObject__dtor(&co); + return ok; } - -bool py_execdyn(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) { - return _py_exec(source, filename, mode, module, true); -} \ No newline at end of file diff --git a/src/public/modules.c b/src/public/modules.c index f47e493b..9ec76ed5 100644 --- a/src/public/modules.c +++ b/src/public/modules.c @@ -388,64 +388,118 @@ static bool builtins_ord(int argc, py_Ref argv) { static bool builtins_globals(int argc, py_Ref argv) { PY_CHECK_ARGC(0); - Frame* frame = pk_current_vm->top_frame; - if(frame->is_dynamic) { - py_assign(py_retval(), &frame->p0[0]); - return true; - } - pk_mappingproxy__namedict(py_retval(), frame->module); + py_newglobals(py_retval()); return true; } static bool builtins_locals(int argc, py_Ref argv) { PY_CHECK_ARGC(0); - Frame* frame = pk_current_vm->top_frame; - if(frame->is_dynamic) { - py_assign(py_retval(), &frame->p0[1]); - return true; - } - if(!frame->has_function) return builtins_globals(argc, argv); - pk_mappingproxy__locals(py_retval(), frame); + py_newlocals(py_retval()); return true; } -static bool _builtins_execdyn(const char* title, int argc, py_Ref argv, enum py_CompileMode mode) { - PY_CHECK_ARG_TYPE(0, tp_str); +void py_newglobals(py_Ref out) { Frame* frame = pk_current_vm->top_frame; + if(frame->is_dynamic) { + py_assign(out, &frame->p0[0]); + } else { + pk_mappingproxy__namedict(out, frame->module); + } +} + +void py_newlocals(py_Ref out) { + Frame* frame = pk_current_vm->top_frame; + if(frame->is_dynamic) { + py_assign(out, &frame->p0[1]); + return; + } + if(frame->has_function) { + pk_mappingproxy__locals(out, frame); + } else { + py_newglobals(out); + } +} + +static bool _builtins_execdyn(const char* title, int argc, py_Ref argv, enum py_CompileMode mode) { switch(argc) { case 1: { - // system globals + system locals - if(!builtins_globals(0, NULL)) return false; - py_push(py_retval()); - if(!builtins_locals(0, NULL)) return false; - py_push(py_retval()); + py_newglobals(py_pushtmp()); + py_newlocals(py_pushtmp()); break; } case 2: { - // user globals + user globals - py_push(py_arg(1)); - py_push(py_arg(1)); + if(py_isnone(py_arg(1))) { + py_newglobals(py_pushtmp()); + } else { + py_push(py_arg(1)); + } + py_pushnone(); break; } case 3: { - // user globals + user locals - py_push(py_arg(1)); + if(py_isnone(py_arg(1))) { + py_newglobals(py_pushtmp()); + } else { + py_push(py_arg(1)); + } py_push(py_arg(2)); break; } default: return TypeError("%s() takes at most 3 arguments", title); } - return py_execdyn(py_tostr(argv), "", mode, frame->module); + + py_Ref code; + if(py_isstr(argv)) { + bool ok = py_compile(py_tostr(argv), "", mode, true); + if(!ok) return false; + code = py_retval(); + } else if(py_istype(argv, tp_code)) { + code = argv; + } else { + return TypeError("%s() expected 'str' or 'code', got '%t'", title, argv->type); + } + + py_push(code); // keep it alive + + // [globals, locals, code] + CodeObject* co = py_touserdata(code); + if(!co->src->is_dynamic) py_shrink(3); + Frame* frame = pk_current_vm->top_frame; + return pk_exec(co, frame ? frame->module : NULL); } static bool builtins_exec(int argc, py_Ref argv) { - return _builtins_execdyn("exec", argc, argv, EXEC_MODE); + bool ok = _builtins_execdyn("exec", argc, argv, EXEC_MODE); + py_newnone(py_retval()); + return ok; } static bool builtins_eval(int argc, py_Ref argv) { return _builtins_execdyn("eval", argc, argv, EVAL_MODE); } +static bool builtins_compile(int argc, py_Ref argv) { + PY_CHECK_ARGC(3); + for(int i = 0; i < 3; i++) { + if(!py_checktype(py_arg(i), tp_str)) return false; + } + const char* source = py_tostr(py_arg(0)); + const char* filename = py_tostr(py_arg(1)); + const char* mode = py_tostr(py_arg(2)); + + enum py_CompileMode compile_mode; + if(strcmp(mode, "exec") == 0) { + compile_mode = EXEC_MODE; + } else if(strcmp(mode, "eval") == 0) { + compile_mode = EVAL_MODE; + } else if(strcmp(mode, "single") == 0) { + compile_mode = SINGLE_MODE; + } else { + return ValueError("compile() mode must be 'exec', 'eval', or 'single'"); + } + return py_compile(source, filename, compile_mode, true); +} + static bool NoneType__repr__(int argc, py_Ref argv) { py_newstr(py_retval(), "None"); return true; @@ -491,6 +545,7 @@ py_TValue pk_builtins__register() { py_bindfunc(builtins, "locals", builtins_locals); py_bindfunc(builtins, "exec", builtins_exec); py_bindfunc(builtins, "eval", builtins_eval); + py_bindfunc(builtins, "compile", builtins_compile); // some patches py_bindmagic(tp_NoneType, __repr__, NoneType__repr__); @@ -502,9 +557,7 @@ py_TValue pk_builtins__register() { static bool function__closure__getter(int argc, py_Ref argv) { PY_CHECK_ARGC(1); Function* ud = py_touserdata(argv); - if(!ud->closure) { - py_newnone(py_retval()); - } + if(!ud->closure) { py_newnone(py_retval()); } py_Ref r0 = py_pushtmp(); py_Ref retval = py_pushtmp(); py_newdict(retval); diff --git a/src/public/py_mappingproxy.c b/src/public/py_mappingproxy.c index e4b4c646..f69b2d7a 100644 --- a/src/public/py_mappingproxy.c +++ b/src/public/py_mappingproxy.c @@ -7,9 +7,9 @@ void pk_mappingproxy__namedict(py_Ref out, py_Ref object){ - py_newobject(py_retval(), tp_namedict, 1, 0); + py_newobject(out, tp_namedict, 1, 0); assert(object->is_ptr && object->_obj->slots == -1); - py_setslot(py_retval(), 0, object); + py_setslot(out, 0, object); } static bool namedict__getitem__(int argc, py_Ref argv){ @@ -63,7 +63,7 @@ py_Type pk_namedict__register() { void pk_mappingproxy__locals(py_Ref out, Frame* frame){ assert(frame->has_function && !frame->is_dynamic); - Frame** ud = py_newobject(py_retval(), tp_locals, 0, sizeof(Frame*)); + Frame** ud = py_newobject(out, tp_locals, 0, sizeof(Frame*)); *ud = frame; } diff --git a/src/public/stack_ops.c b/src/public/stack_ops.c index c598fbde..7bb0c9cb 100644 --- a/src/public/stack_ops.c +++ b/src/public/stack_ops.c @@ -92,6 +92,11 @@ void py_pushnil() { py_newnil(vm->stack.sp++); } +void py_pushnone() { + VM* vm = pk_current_vm; + py_newnone(vm->stack.sp++); +} + py_Ref py_pushtmp() { VM* vm = pk_current_vm; py_newnil(vm->stack.sp++); diff --git a/src2/main.c b/src2/main.c index c1b05488..094950a2 100644 --- a/src2/main.c +++ b/src2/main.c @@ -49,7 +49,11 @@ int main(int argc, char** argv) { int size = py_replinput(buf, sizeof(buf)); assert(size < sizeof(buf)); if(size >= 0) { - if(!py_exec(buf, "", REPL_MODE, NULL)) py_printexc(); + py_StackRef p0 = py_peek(0); + if(!py_exec(buf, "", SINGLE_MODE, NULL)) { + py_printexc(); + py_clearexc(p0); + } } } } else { diff --git a/tests/66_eval.py b/tests/66_eval.py index 633485df..1d4ab6bd 100644 --- a/tests/66_eval.py +++ b/tests/66_eval.py @@ -43,6 +43,8 @@ assert (res==1), res # test locals and globals +assert eval('a', {'a': 2}) == 2 + globals = {'a': 1} locals = {'a': 1}