diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index a58269c9..c1303c83 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -324,6 +324,8 @@ bool py_callmethod(py_Ref self, py_Name, int argc, py_Ref argv); /// The result will be set to `py_retval()`. /// The stack remains unchanged after the operation. bool py_callmagic(py_Name name, int argc, py_Ref argv); +/// Call a `py_CFunction` in a safe way. +bool py_callcfunc(py_StackRef p0, py_CFunction cfunc, int argc, py_Ref argv); bool py_str(py_Ref val); #define py_repr(val) py_callmagic(__repr__, 1, val) diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 7608998c..bfc38883 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -267,10 +267,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { py_Ref magic = py_tpfindmagic(SECOND()->type, __getitem__); if(magic) { if(magic->type == tp_nativefunc) { - py_TValue* next_sp = TOP(); - bool ok = magic->_cfunc(2, SECOND()); - if(!ok) goto __ERROR; - SP() = next_sp; + py_TValue* p0 = TOP(); + if(!py_callcfunc(p0, magic->_cfunc, 2, SECOND())) goto __ERROR; *TOP() = self->last_retval; } else { INSERT_THIRD(); // [?, a, b] @@ -321,10 +319,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { if(magic) { PUSH(THIRD()); // [val, a, b, val] if(magic->type == tp_nativefunc) { - py_TValue* next_sp = FOURTH(); - bool ok = magic->_cfunc(3, THIRD()); - if(!ok) goto __ERROR; - SP() = next_sp; + py_TValue* p0 = FOURTH(); + if(!py_callcfunc(p0, magic->_cfunc, 3, THIRD())) goto __ERROR; } else { *FOURTH() = *magic; // [__selitem__, a, b, val] if(!py_vectorcall(2, 0)) goto __ERROR; @@ -391,10 +387,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { py_Ref magic = py_tpfindmagic(SECOND()->type, __delitem__); if(magic) { if(magic->type == tp_nativefunc) { - py_TValue* next_sp = SECOND(); - bool ok = magic->_cfunc(2, SECOND()); - if(!ok) goto __ERROR; - SP() = next_sp; + py_TValue* p0 = SECOND(); + if(!py_callcfunc(p0, magic->_cfunc, 2, SECOND())) goto __ERROR; } else { INSERT_THIRD(); // [?, a, b] *THIRD() = *magic; // [__delitem__, a, b] @@ -533,10 +527,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { py_Ref magic = py_tpfindmagic(SECOND()->type, __contains__); if(magic) { if(magic->type == tp_nativefunc) { - py_TValue* next_sp = TOP(); - bool ok = magic->_cfunc(2, SECOND()); - if(!ok) goto __ERROR; - SP() = next_sp; + py_TValue* p0 = TOP(); + if(!py_callcfunc(p0, magic->_cfunc, 2, SECOND())) goto __ERROR; *TOP() = self->last_retval; } else { INSERT_THIRD(); // [?, b, a] diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 0ce2fd77..c1bfdce5 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -391,8 +391,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo pk_VM__push_frame(self, Frame__new(co, fn->module, p0, p0, argv, co)); return opcall ? RES_CALL : pk_VM__run_top_frame(self); } else { - bool ok = fn->cfunc(co->nlocals, argv); - self->stack.sp = p0; + bool ok = py_callcfunc(p0, fn->cfunc, co->nlocals, argv); return ok ? RES_RETURN : RES_ERROR; } } @@ -431,32 +430,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo } if(p0->type == tp_nativefunc) { - // const auto& f = PK_OBJ_GET(NativeFunc, callable); - // PyVar ret; - // if(f.decl != nullptr) { - // int co_nlocals = f.decl->code->nlocals; - // prepare_py_call(__vectorcall_buffer, args, kwargs, f.decl); - // // copy buffer back to stack - // s_data.reset(_base + co_nlocals); - // for(int j = 0; j < co_nlocals; j++) - // _base[j] = __vectorcall_buffer[j]; - // ret = f.call(vm, ArgsView(s_data._sp - co_nlocals, s_data._sp)); - // } else { - // if(f.argc != -1) { - // if(KWARGC != 0) - // TypeError( - // "old-style native_func does not accept keyword arguments. If you want to - // skip this check, specify `argc` to -1"); - // if(args.size() != f.argc) { - // vm->TypeError(_S("expected ", f.argc, " arguments, got ", args.size())); - // } - // } - // ret = f.call(this, args); - // } - - // `argc` passed to _cfunc must include self if exists - if(!p0->_cfunc(p1 - argv, argv)) return RES_ERROR; - self->stack.sp = p0; + if(!py_callcfunc(p0, p0->_cfunc, p1 - argv, argv)) return RES_ERROR; return RES_RETURN; } diff --git a/src/public/modules.c b/src/public/modules.c index 6b4e0af0..3662f004 100644 --- a/src/public/modules.c +++ b/src/public/modules.c @@ -178,6 +178,27 @@ static bool _py_builtins__sum(int argc, py_Ref argv) { return true; } +static bool _py_builtins__print(int argc, py_Ref argv) { + int length; + py_TValue* args = pk_arrayview(argv, &length); + assert(args != NULL); + c11_sv sep = py_tosv(py_arg(1)); + c11_sv end = py_tosv(py_arg(2)); + c11_sbuf buf; + c11_sbuf__ctor(&buf); + for(int i = 0; i < length; i++) { + if(i > 0) c11_sbuf__write_sv(&buf, sep); + if(!py_str(&args[i])) return false; + c11_sbuf__write_sv(&buf, py_tosv(py_retval())); + } + c11_sbuf__write_sv(&buf, end); + c11_string* res = c11_sbuf__submit(&buf); + pk_current_vm->_stdout("%s", res->data); + c11_string__delete(res); + py_newnone(py_retval()); + return true; +} + py_TValue pk_builtins__register() { py_Ref builtins = py_newmodule("builtins", NULL); py_bindnativefunc(builtins, "repr", _py_builtins__repr); @@ -191,6 +212,7 @@ py_TValue pk_builtins__register() { py_bindnativefunc(builtins, "abs", _py_builtins__abs); py_bindnativefunc(builtins, "sum", _py_builtins__sum); + py_bind(builtins, "print(*args, sep=' ', end='\\n')", _py_builtins__print); py_bind(builtins, "sorted(iterable, key=None, reverse=False)", _py_builtins__sorted); return *builtins; } diff --git a/src/public/py_dict.c b/src/public/py_dict.c index a0b45cbc..8af5db62 100644 --- a/src/public/py_dict.c +++ b/src/public/py_dict.c @@ -250,7 +250,6 @@ static bool _py_dict__delitem__(int argc, py_Ref argv) { PY_CHECK_ARGC(2); Dict* self = py_touserdata(argv); if(!Dict__pop(self, py_arg(1))) return false; - py_newnone(py_retval()); return true; } diff --git a/src/public/py_list.c b/src/public/py_list.c index dd1b2d10..e4f985ea 100644 --- a/src/public/py_list.c +++ b/src/public/py_list.c @@ -174,6 +174,7 @@ static bool _py_list__delitem__(int argc, py_Ref argv) { int index = py_toint(py_arg(1)); if(!pk__normalize_index(&index, self->count)) return false; c11_vector__erase(py_TValue, self, index); + py_newnone(py_retval()); return true; } diff --git a/src/public/values.c b/src/public/values.c index 9a3a1907..c9f35433 100644 --- a/src/public/values.c +++ b/src/public/values.c @@ -66,7 +66,7 @@ void py_bindnativefunc(py_Ref obj, const char* name, py_CFunction f) { void py_bind(py_Ref obj, const char* sig, py_CFunction f) { py_TValue tmp; - do{ + do { char buffer[256]; snprintf(buffer, sizeof(buffer), "def %s: pass", sig); // fn(a, b, *c, d=1) -> None @@ -82,7 +82,7 @@ void py_bind(py_Ref obj, const char* sig, py_CFunction f) { ud->cfunc = f; CodeObject__dtor(&code); PK_DECREF(source); - }while(0); + } while(0); Function* ud = py_touserdata(&tmp); py_Name name = py_name(ud->decl->code.name->data); py_setdict(obj, name, &tmp); diff --git a/src/public/vm.c b/src/public/vm.c index c33d2af3..1526db2c 100644 --- a/src/public/vm.c +++ b/src/public/vm.c @@ -203,7 +203,8 @@ bool py_exec2(const char* source, const char* filename, enum py_CompileMode mode bool py_call(py_Ref f, int argc, py_Ref argv) { if(f->type == tp_nativefunc) { - return f->_cfunc(argc, argv); + py_TValue* p0 = pk_current_vm->stack.sp; + return py_callcfunc(p0, f->_cfunc, argc, argv); } else { py_push(f); py_pushnil(); @@ -311,6 +312,12 @@ bool py_callmagic(py_Name name, int argc, py_Ref argv) { return py_call(tmp, argc, argv); } +bool py_callcfunc(py_StackRef p0, py_CFunction cfunc, int argc, py_Ref argv) { + bool ok = cfunc(argc, argv); + pk_current_vm->stack.sp = p0; + return ok; +} + bool StopIteration() { pk_VM* vm = pk_current_vm; assert(!vm->is_stopiteration); // flag is already set