blueloveTH 2 anni fa
parent
commit
c89a74db1e
10 ha cambiato i file con 90 aggiunte e 48 eliminazioni
  1. 15 14
      src/ceval.h
  2. 1 1
      src/cffi.h
  3. 1 1
      src/common.h
  4. 6 1
      src/frame.h
  5. 11 7
      src/iter.h
  6. 3 5
      src/pocketpy.h
  7. 2 1
      src/repl.h
  8. 0 3
      src/tuplelist.h
  9. 32 14
      src/vm.h
  10. 19 1
      tests/21_functions.py

+ 15 - 14
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);

+ 1 - 1
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 << "<void* at " << self.ptr << ">";

+ 1 - 1
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

+ 6 - 1
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; }
     

+ 11 - 7
src/iter.h

@@ -27,14 +27,17 @@ public:
 template <typename T>
 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<typename T>

+ 3 - 5
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<Args>(vm, args[0]));
+        return vm->PyIter(ArrayIter<Tuple>(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<args.size(); i++){

+ 2 - 1
src/repl.h

@@ -45,7 +45,8 @@ protected:
     VM* vm;
 public:
     REPL(VM* vm) : vm(vm){
-        (*vm->_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");
     }

+ 0 - 3
src/tuplelist.h

@@ -93,7 +93,4 @@ struct ArgsView{
         return ret;
     }
 };
-
-using Args = ArgsView;
-
 }   // namespace pkpy

+ 32 - 14
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<BaseIter*>(obj->value());
     }
+
+    BaseIter* _PyIter_AS_C(PyObject* obj)
+    {
+        return static_cast<BaseIter*>(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<PyObject**> sp_bases;
+    std::map<PyObject**, int> 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 << "<class " + _all_types[t].name.escape() + ">";
+        } 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;
 }
 

+ 19 - 1
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