From c89a74db1e48beabdddd7075a092cba87955e5da Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Tue, 18 Apr 2023 00:03:29 +0800 Subject: [PATCH] ... --- src/ceval.h | 29 ++++++++++++++------------- src/cffi.h | 2 +- src/common.h | 2 +- src/frame.h | 7 ++++++- src/iter.h | 18 ++++++++++------- src/pocketpy.h | 8 +++----- src/repl.h | 3 ++- src/tuplelist.h | 3 --- src/vm.h | 46 ++++++++++++++++++++++++++++++------------- tests/21_functions.py | 20 ++++++++++++++++++- 10 files changed, 90 insertions(+), 48 deletions(-) diff --git a/src/ceval.h b/src/ceval.h index 7e2e1482..64b75b87 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -399,18 +399,14 @@ __NEXT_STEP:; list.push_back(obj); } DISPATCH(); TARGET(DICT_ADD) { - PyObject* kv = POPX(); - Tuple& t = CAST(Tuple&, kv); - PyObject* self; - PyObject* callable = get_unbound_method(SECOND(), __setitem__, &self); - call_method(self, callable, t[0], t[1]); - } DISPATCH(); - TARGET(SET_ADD) { - PyObject* val = POPX(); - PyObject* self; - PyObject* callable = get_unbound_method(SECOND(), m_add, &self); - call_method(self, callable, val); + _0 = POPX(); + Tuple& t = CAST(Tuple&, _0); + call_method(SECOND(), __setitem__, t[0], t[1]); } DISPATCH(); + TARGET(SET_ADD) + _0 = POPX(); + call_method(SECOND(), m_add, _0); + DISPATCH(); /*****************************************/ TARGET(UNARY_NEGATIVE) TOP() = num_negated(TOP()); @@ -421,12 +417,17 @@ __NEXT_STEP:; /*****************************************/ TARGET(GET_ITER) TOP() = asIter(TOP()); + check_type(TOP(), tp_iterator); DISPATCH(); TARGET(FOR_ITER) { +#if DEBUG_EXTRA_CHECK BaseIter* it = PyIter_AS_C(TOP()); - _0 = it->next(); - if(_0 != nullptr){ - PUSH(_0); +#else + BaseIter* it = _PyIter_AS_C(TOP()); +#endif + PyObject* obj = it->next(); + if(obj != nullptr){ + PUSH(obj); }else{ int target = co_blocks[byte.block].end; frame->jump_abs_break(target); diff --git a/src/cffi.h b/src/cffi.h index c90c0a31..406fc900 100644 --- a/src/cffi.h +++ b/src/cffi.h @@ -81,7 +81,7 @@ struct VoidP{ static void _register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_static_method<1>(type, "__new__", CPP_NOT_IMPLEMENTED()); - vm->bind_static_method<1>(type, "__repr__", [](VM* vm, const Args& args){ + vm->bind_static_method<1>(type, "__repr__", [](VM* vm, ArgsView args){ VoidP& self = CAST(VoidP&, args[0]); std::stringstream ss; ss << ""; diff --git a/src/common.h b/src/common.h index 3c73be4d..2d628c05 100644 --- a/src/common.h +++ b/src/common.h @@ -35,7 +35,7 @@ #define DEBUG_NO_BUILTIN_MODULES 0 #define DEBUG_EXTRA_CHECK 1 #define DEBUG_DIS_EXEC 0 -#define DEBUG_CEVAL_STEP 1 +#define DEBUG_CEVAL_STEP 0 #define DEBUG_CEVAL_STEP_MIN 0 #define DEBUG_FULL_EXCEPTION 0 #define DEBUG_MEMORY_POOL 0 diff --git a/src/frame.h b/src/frame.h index 487f1dc6..3a6daa3e 100644 --- a/src/frame.h +++ b/src/frame.h @@ -154,7 +154,12 @@ struct ValueStack { bool empty() const { return _sp == _begin; } PyObject** begin() { return _begin; } PyObject** end() { return _sp; } - void reset(PyObject** sp) { _sp = sp; } + void reset(PyObject** sp) { +#if DEBUG_EXTRA_CHECK + if(sp < _begin || sp > _begin + MAX_SIZE) FATAL_ERROR(); +#endif + _sp = sp; + } void clear() { _sp = _begin; } bool is_overflow() const { return _sp >= _begin + MAX_SIZE; } diff --git a/src/iter.h b/src/iter.h index 4c250824..0a41863b 100644 --- a/src/iter.h +++ b/src/iter.h @@ -27,14 +27,17 @@ public: template class ArrayIter final: public BaseIter { PyObject* ref; + T* array; int index; public: - ArrayIter(VM* vm, PyObject* ref) : BaseIter(vm), ref(ref), index(0) {} + ArrayIter(VM* vm, PyObject* ref) : BaseIter(vm), ref(ref) { + array = &OBJ_GET(T, ref); + index = 0; + } PyObject* next() override{ - const T* p = &OBJ_GET(T, ref); - if(index == p->size()) return nullptr; - return p->operator[](index++); + if(index >= array->size()) return nullptr; + return array->operator[](index++); } void _gc_mark() const override { @@ -66,15 +69,15 @@ inline PyObject* Generator::next(){ // reset frame._sp_base frame._sp_base = frame._s->_sp; // restore the context - for(PyObject* obj: s_data) frame._s->push(obj); - s_data.clear(); + for(PyObject* obj: s_backup) frame._s->push(obj); + s_backup.clear(); vm->callstack.push(std::move(frame)); PyObject* ret = vm->_run_top_frame(); if(ret == vm->_py_op_yield){ // backup the context frame = std::move(vm->callstack.top()); PyObject* ret = frame._s->popx(); - for(PyObject* obj: frame.stack_view()) s_data.push_back(obj); + for(PyObject* obj: frame.stack_view()) s_backup.push_back(obj); vm->_pop_frame(); state = 1; return ret; @@ -86,6 +89,7 @@ inline PyObject* Generator::next(){ inline void Generator::_gc_mark() const{ frame._gc_mark(); + for(PyObject* obj: s_backup) OBJ_MARK(obj); } template diff --git a/src/pocketpy.h b/src/pocketpy.h index 821ff898..d1e642a8 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -118,9 +118,7 @@ inline void init_builtins(VM* _vm) { _vm->bind_builtin_func<1>("repr", CPP_LAMBDA(vm->asRepr(args[0]))); _vm->bind_builtin_func<1>("len", [](VM* vm, ArgsView args){ - PyObject* self; - PyObject* len_f = vm->get_unbound_method(args[0], __len__, &self); - return vm->call_method(self, len_f); + return vm->call_method(args[0], __len__); }); _vm->bind_builtin_func<1>("hash", [](VM* vm, ArgsView args){ @@ -524,7 +522,7 @@ inline void init_builtins(VM* _vm) { }); _vm->bind_method<0>("tuple", "__iter__", [](VM* vm, ArgsView args) { - return vm->PyIter(ArrayIter(vm, args[0])); + return vm->PyIter(ArrayIter(vm, args[0])); }); _vm->bind_method<1>("tuple", "__getitem__", [](VM* vm, ArgsView args) { @@ -958,7 +956,7 @@ extern "C" { for(int i=0; name[i]; i++) if(name[i] == ' ') return nullptr; std::string f_header = std::string(mod) + '.' + name + '#' + std::to_string(kGlobalBindId++); pkpy::PyObject* obj = vm->_modules.contains(mod) ? vm->_modules[mod] : vm->new_module(mod); - vm->bind_func<-1>(obj, name, [ret_code, f_header](pkpy::VM* vm, const pkpy::Args& args){ + vm->bind_func<-1>(obj, name, [ret_code, f_header](pkpy::VM* vm, pkpy::ArgsView args){ std::stringstream ss; ss << f_header; for(int i=0; i_stdout) << ("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ")\n"); + (*vm->_stdout) << ("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") "); + (*vm->_stdout) << "[" << std::to_string(sizeof(void*) * 8) << " bit]" "\n"; (*vm->_stdout) << ("https://github.com/blueloveTH/pocketpy" "\n"); (*vm->_stdout) << ("Type \"exit()\" to exit." "\n"); } diff --git a/src/tuplelist.h b/src/tuplelist.h index 53b56c6a..1403c504 100644 --- a/src/tuplelist.h +++ b/src/tuplelist.h @@ -93,7 +93,4 @@ struct ArgsView{ return ret; } }; - -using Args = ArgsView; - } // namespace pkpy \ No newline at end of file diff --git a/src/vm.h b/src/vm.h index d07f8bda..3cd4e11c 100644 --- a/src/vm.h +++ b/src/vm.h @@ -49,7 +49,7 @@ Str _read_file_cwd(const Str& name, bool* ok); class Generator final: public BaseIter { Frame frame; int state; // 0,1,2 - List s_data; // backup + List s_backup; public: Generator(VM* vm, Frame&& frame): BaseIter(vm), frame(std::move(frame)), state(0) {} @@ -311,6 +311,11 @@ public: check_type(obj, tp_iterator); return static_cast(obj->value()); } + + BaseIter* _PyIter_AS_C(PyObject* obj) + { + return static_cast(obj->value()); + } /***** Error Reporter *****/ void _error(StrName name, const Str& msg){ @@ -658,19 +663,18 @@ inline void VM::_log_s_data(const char* title) { if(callstack.empty()) return; std::stringstream ss; if(title) ss << title << " | "; - std::vector sp_bases; + std::map sp_bases; for(Frame& f: callstack.data()){ - sp_bases.push_back(f._sp_base); + if(f._sp_base == nullptr) FATAL_ERROR(); + sp_bases[f._sp_base] += 1; } - std::reverse(sp_bases.begin(), sp_bases.end()); FrameId frame = top_frame(); int line = frame->co->lines[frame->_ip]; ss << frame->co->name << ":" << line << " ["; - for(PyObject*& obj: s_data){ - if(&obj == sp_bases.back()){ - ss << "| "; - sp_bases.pop_back(); - } + for(PyObject** p=s_data.begin(); p!=s_data.end(); p++){ + ss << std::string(sp_bases[p], '|'); + if(sp_bases[p] > 0) ss << " "; + PyObject* obj = *p; if(obj == nullptr) ss << "(nil)"; else if(obj == _py_begin_call) ss << "BEGIN_CALL"; else if(obj == _py_null) ss << "NULL"; @@ -680,8 +684,19 @@ inline void VM::_log_s_data(const char* title) { else if(obj == None) ss << "None"; else if(obj == True) ss << "True"; else if(obj == False) ss << "False"; - // else ss << obj << "(" << obj_type_name(this, obj->type) << ")"; - else ss << "(" << obj_type_name(this, obj->type) << ")"; + else if(is_type(obj, tp_function)){ + auto& f = CAST(Function&, obj); + ss << f.decl->code->name << "(...)"; + } else if(is_type(obj, tp_type)){ + Type t = OBJ_GET(Type, obj); + ss << ""; + } else if(is_type(obj, tp_list)){ + auto& t = CAST(List&, obj); + ss << "list(size=" << t.size() << ")"; + } else if(is_type(obj, tp_tuple)){ + auto& t = CAST(Tuple&, obj); + ss << "tuple(size=" << t.size() << ")"; + } else ss << "(" << obj_type_name(this, obj->type) << ")"; ss << ", "; } std::string output = ss.str(); @@ -891,12 +906,15 @@ inline PyObject* VM::_py_call(PyObject** sp_base, PyObject* callable, ArgsView a if(!ok) TypeError(fmt(key.escape(), " is an invalid keyword argument for ", co->name, "()")); } PyObject* _module = fn._module != nullptr ? fn._module : top_frame()->_module; + + // TODO: callable may be garbage collected + s_data.reset(sp_base); + PyObject** curr_sp = s_data._sp; if(co->is_generator){ - PyObject* ret = PyIter(Generator(this, Frame(&s_data, sp_base, co, _module, std::move(locals), fn._closure))); - s_data.reset(sp_base); + PyObject* ret = PyIter(Generator(this, Frame(&s_data, curr_sp, co, _module, std::move(locals), fn._closure))); return ret; } - callstack.emplace(&s_data, sp_base, co, _module, std::move(locals), fn._closure); + callstack.emplace(&s_data, curr_sp, co, _module, std::move(locals), fn._closure); return nullptr; } diff --git a/tests/21_functions.py b/tests/21_functions.py index 651e790d..c2d90aae 100644 --- a/tests/21_functions.py +++ b/tests/21_functions.py @@ -1,6 +1,5 @@ ## Function Tests. - def f1(): return 'f1' assert f1() == 'f1' @@ -11,6 +10,11 @@ def f3(a,b): return a - b assert f3(1,2) == -1 +def f4(a,b): + return a + f3(a, b) + +assert f4(1,2) == 0 + def fact(n): if n == 1: return 1 @@ -27,9 +31,23 @@ assert f(b=5) == 6 assert f(a=5) == 4 assert f(b=5, a=5) == 10 +def f(*args): + return 10 * sum(args) + +assert f(1, 2, 3) == 60 + +def f(x, *args, y=3): + i = 0 + for j in args: + i += j + return i * y + +assert f(10, 1, 2, 3) == 18 + def f(a, b, *c, d=2, e=5): return a + b + d + e + sum(c) +assert f(1, 2, 3, 4) == 17 assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 62 assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, d=1, e=2) == 58 assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, e=1, d=2) == 58