blueloveTH 1 год назад
Родитель
Сommit
b51bf33572

+ 1 - 2
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);

+ 3 - 0
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();
 

+ 12 - 7
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)

+ 14 - 38
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, "<f-string>", 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);

+ 16 - 21
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, "<f-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();
             }

+ 3 - 4
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);
 }

+ 4 - 3
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;

+ 11 - 3
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;
 }

+ 2 - 2
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); }

+ 42 - 20
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);
-}

+ 81 - 28
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);
+    py_newlocals(py_retval());
+    return true;
+}
+
+void py_newglobals(py_Ref out) {
     Frame* frame = pk_current_vm->top_frame;
     if(frame->is_dynamic) {
-        py_assign(py_retval(), &frame->p0[1]);
-        return true;
+        py_assign(out, &frame->p0[0]);
+    } else {
+        pk_mappingproxy__namedict(out, frame->module);
     }
-    if(!frame->has_function) return builtins_globals(argc, argv);
-    pk_mappingproxy__locals(py_retval(), frame);
-    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_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), "<string>", mode, frame->module);
+
+    py_Ref code;
+    if(py_isstr(argv)) {
+        bool ok = py_compile(py_tostr(argv), "<string>", 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);

+ 3 - 3
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;
 }
 

+ 5 - 0
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++);

+ 5 - 1
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, "<stdin>", REPL_MODE, NULL)) py_printexc();
+                py_StackRef p0 = py_peek(0);
+                if(!py_exec(buf, "<stdin>", SINGLE_MODE, NULL)) {
+                    py_printexc();
+                    py_clearexc(p0);
+                }
             }
         }
     } else {

+ 2 - 0
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}