blueloveTH 2 éve
szülő
commit
515321a0af
3 módosított fájl, 91 hozzáadás és 52 törlés
  1. 41 31
      src/pocketpy.h
  2. 2 0
      src/str.h
  3. 48 21
      src/vm.h

+ 41 - 31
src/pocketpy.h

@@ -204,8 +204,10 @@ inline void init_builtins(VM* _vm) {
     _vm->bind_method<1>("object", "__eq__", CPP_LAMBDA(VAR(args[0] == args[1])));
     _vm->bind_method<1>("object", "__ne__", CPP_LAMBDA(VAR(args[0] != args[1])));
 
-    _vm->bind_static_method<1>("type", "__new__", CPP_LAMBDA(vm->_t(args[0])));
-    _vm->bind_static_method<-1>("range", "__new__", [](VM* vm, ArgsView args) {
+    _vm->bind_constructor<2>("type", CPP_LAMBDA(vm->_t(args[1])));
+
+    _vm->bind_constructor<-1>("range", [](VM* vm, ArgsView args) {
+        args._begin += 1;   // skip cls
         Range r;
         switch (args.size()) {
             case 1: r.stop = CAST(i64, args[0]); break;
@@ -258,12 +260,12 @@ inline void init_builtins(VM* _vm) {
     _vm->bind_method<1>("float", "__pow__", py_number_pow);
 
     /************ PyInt ************/
-    _vm->bind_static_method<1>("int", "__new__", [](VM* vm, ArgsView args) {
-        if (is_type(args[0], vm->tp_float)) return VAR((i64)CAST(f64, args[0]));
-        if (is_type(args[0], vm->tp_int)) return args[0];
-        if (is_type(args[0], vm->tp_bool)) return VAR(_CAST(bool, args[0]) ? 1 : 0);
-        if (is_type(args[0], vm->tp_str)) {
-            const Str& s = CAST(Str&, args[0]);
+    _vm->bind_constructor<2>("int", [](VM* vm, ArgsView args) {
+        if (is_type(args[1], vm->tp_float)) return VAR((i64)CAST(f64, args[1]));
+        if (is_type(args[1], vm->tp_int)) return args[1];
+        if (is_type(args[1], vm->tp_bool)) return VAR(_CAST(bool, args[1]) ? 1 : 0);
+        if (is_type(args[1], vm->tp_str)) {
+            const Str& s = CAST(Str&, args[1]);
             try{
                 size_t parsed = 0;
                 i64 val = Number::stoi(s.str(), &parsed, 10);
@@ -304,12 +306,12 @@ inline void init_builtins(VM* _vm) {
 #undef INT_BITWISE_OP
 
     /************ PyFloat ************/
-    _vm->bind_static_method<1>("float", "__new__", [](VM* vm, ArgsView args) {
-        if (is_type(args[0], vm->tp_int)) return VAR((f64)CAST(i64, args[0]));
-        if (is_type(args[0], vm->tp_float)) return args[0];
-        if (is_type(args[0], vm->tp_bool)) return VAR(_CAST(bool, args[0]) ? 1.0 : 0.0);
-        if (is_type(args[0], vm->tp_str)) {
-            const Str& s = CAST(Str&, args[0]);
+    _vm->bind_constructor<2>("float", [](VM* vm, ArgsView args) {
+        if (is_type(args[1], vm->tp_int)) return VAR((f64)CAST(i64, args[1]));
+        if (is_type(args[1], vm->tp_float)) return args[1];
+        if (is_type(args[1], vm->tp_bool)) return VAR(_CAST(bool, args[1]) ? 1.0 : 0.0);
+        if (is_type(args[1], vm->tp_str)) {
+            const Str& s = CAST(Str&, args[1]);
             if(s == "inf") return VAR(INFINITY);
             if(s == "-inf") return VAR(-INFINITY);
             try{
@@ -340,7 +342,7 @@ inline void init_builtins(VM* _vm) {
     });
 
     /************ PyString ************/
-    _vm->bind_static_method<1>("str", "__new__", CPP_LAMBDA(vm->asStr(args[0])));
+    _vm->bind_constructor<2>("str", CPP_LAMBDA(vm->asStr(args[1])));
 
     _vm->bind_method<1>("str", "__add__", [](VM* vm, ArgsView args) {
         const Str& lhs = _CAST(Str&, args[0]);
@@ -453,16 +455,21 @@ inline void init_builtins(VM* _vm) {
     _vm->bind_method<1>("str", "join", [](VM* vm, ArgsView args) {
         const Str& self = _CAST(Str&, args[0]);
         FastStrStream ss;
-        PyObject* obj = vm->asList(args[1]);
-        const List& list = CAST(List&, obj);
-        for (int i = 0; i < list.size(); ++i) {
-            if (i > 0) ss << self;
-            ss << CAST(Str&, list[i]);
+        PyObject* it = vm->asIter(args[1]);
+        PyObject* obj = vm->PyIterNext(it);
+        while(obj != vm->StopIteration){
+            if(!ss.empty()) ss << self;
+            ss << CAST(Str&, obj);
+            obj = vm->PyIterNext(it);
         }
         return VAR(ss.str());
     });
 
     /************ PyList ************/
+    _vm->bind_constructor<2>("list", [](VM* vm, ArgsView args) {
+        return vm->asList(args[1]);
+    });
+
     _vm->bind_method<1>("list", "append", [](VM* vm, ArgsView args) {
         List& self = _CAST(List&, args[0]);
         self.push_back(args[1]);
@@ -471,9 +478,12 @@ inline void init_builtins(VM* _vm) {
 
     _vm->bind_method<1>("list", "extend", [](VM* vm, ArgsView args) {
         List& self = _CAST(List&, args[0]);
-        PyObject* obj = vm->asList(args[1]);
-        const List& list = CAST(List&, obj);
-        self.extend(list);
+        PyObject* it = vm->asIter(args[1]);
+        PyObject* obj = vm->PyIterNext(it);
+        while(obj != vm->StopIteration){
+            self.push_back(obj);
+            obj = vm->PyIterNext(it);
+        }
         return vm->None;
     });
 
@@ -560,8 +570,8 @@ inline void init_builtins(VM* _vm) {
     });
 
     /************ PyTuple ************/
-    _vm->bind_static_method<1>("tuple", "__new__", [](VM* vm, ArgsView args) {
-        List list = CAST(List, vm->asList(args[0]));
+    _vm->bind_constructor<2>("tuple", [](VM* vm, ArgsView args) {
+        List list = CAST(List, vm->asList(args[1]));
         return VAR(Tuple(std::move(list)));
     });
 
@@ -592,7 +602,7 @@ inline void init_builtins(VM* _vm) {
     });
 
     /************ bool ************/
-    _vm->bind_static_method<1>("bool", "__new__", CPP_LAMBDA(VAR(vm->asBool(args[0]))));
+    _vm->bind_constructor<2>("bool", CPP_LAMBDA(VAR(vm->asBool(args[1]))));
 
     _vm->bind_method<0>("bool", "__repr__", [](VM* vm, ArgsView args) {
         bool val = _CAST(bool, args[0]);
@@ -613,8 +623,8 @@ inline void init_builtins(VM* _vm) {
     _vm->bind_method<0>("ellipsis", "__repr__", CPP_LAMBDA(VAR("Ellipsis")));
 
     /************ bytes ************/
-    _vm->bind_static_method<1>("bytes", "__new__", [](VM* vm, ArgsView args){
-        List& list = CAST(List&, args[0]);
+    _vm->bind_constructor<2>("bytes", [](VM* vm, ArgsView args){
+        List& list = CAST(List&, args[1]);
         std::vector<char> buffer(list.size());
         for(int i=0; i<list.size(); i++){
             i64 b = CAST(i64, list[i]);
@@ -668,8 +678,8 @@ inline void init_builtins(VM* _vm) {
     });
 
     /************ slice ************/
-    _vm->bind_static_method<3>("slice", "__new__", [](VM* vm, ArgsView args) {
-        return VAR(Slice(args[0], args[1], args[2]));
+    _vm->bind_constructor<4>("slice", [](VM* vm, ArgsView args) {
+        return VAR(Slice(args[1], args[2], args[3]));
     });
 
     _vm->bind_method<0>("slice", "__repr__", [](VM* vm, ArgsView args) {
@@ -919,7 +929,7 @@ struct Random{
     }
 
     static void _register(VM* vm, PyObject* mod, PyObject* type){
-        vm->bind_static_method<0>(type, "__new__", CPP_LAMBDA(VAR_T(Random)));
+        vm->bind_default_constructor<Random>(type);
 
         vm->bind_method<1>(type, "seed", [](VM* vm, ArgsView args) {
             Random& self = _CAST(Random&, args[0]);

+ 2 - 0
src/str.h

@@ -359,6 +359,8 @@ struct FastStrStream{
         return *this;
     }
 
+    bool empty() const { return parts.empty(); }
+
     Str str() const{
         int len = 0;
         bool is_ascii = true;

+ 48 - 21
src/vm.h

@@ -64,6 +64,7 @@ struct PyTypeInfo{
     PyObject* obj;
     Type base;
     Str name;
+    bool subclass_enabled;
 };
 
 struct FrameId{
@@ -142,18 +143,12 @@ public:
         return nullptr;
     }
 
-    PyObject* asList(PyObject* it){
-        if(is_non_tagged_type(it, tp_list)) return it;
-        return call(_t(tp_list), it);
-    }
-
     PyObject* find_name_in_mro(PyObject* cls, StrName name){
         PyObject* val;
         do{
             val = cls->attr().try_get(name);
             if(val != nullptr) return val;
-            Type cls_t = OBJ_GET(Type, cls);
-            Type base = _all_types[cls_t].base;
+            Type base = _all_types[OBJ_GET(Type, cls)].base;
             if(base.index == -1) break;
             cls = _all_types[base].obj;
         }while(true);
@@ -242,12 +237,17 @@ public:
         return call(p, _0, _1);
     }
 
-    PyObject* new_type_object(PyObject* mod, StrName name, Type base){
+    PyObject* new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled=true){
         PyObject* obj = heap._new<Type>(tp_type, _all_types.size());
+        const PyTypeInfo& base_info = _all_types[base];
+        if(!base_info.subclass_enabled){
+            TypeError(fmt("type ", base_info.name.escape(), " is not `subclass_enabled`"));
+        }
         PyTypeInfo info{
             obj,
             base,
-            (mod!=nullptr && mod!=builtins) ? Str(OBJ_NAME(mod)+"."+name.sv()): name.sv()
+            (mod!=nullptr && mod!=builtins) ? Str(OBJ_NAME(mod)+"."+name.sv()): name.sv(),
+            subclass_enabled,
         };
         if(mod != nullptr) mod->attr().set(name, obj);
         _all_types.push_back(info);
@@ -255,7 +255,7 @@ public:
     }
 
     Type _new_type_object(StrName name, Type base=0) {
-        PyObject* obj = new_type_object(nullptr, name, base);
+        PyObject* obj = new_type_object(nullptr, name, base, false);
         return OBJ_GET(Type, obj);
     }
 
@@ -278,9 +278,18 @@ public:
         bind_method<ARGC>(_find_type(type), name, fn);
     }
 
-    template<int ARGC, typename... Args>
-    void bind_static_method(Args&&... args) {
-        bind_func<ARGC>(std::forward<Args>(args)...);
+    template<int ARGC, typename __T>
+    void bind_constructor(__T&& type, NativeFuncC fn) {
+        static_assert(ARGC==-1 || ARGC>=1);
+        bind_func<ARGC>(std::forward<__T>(type), "__new__", fn);
+    }
+
+    template<typename T, typename __T>
+    void bind_default_constructor(__T&& type) {
+        bind_constructor<1>(std::forward<__T>(type), [](VM* vm, ArgsView args){
+            Type t = OBJ_GET(Type, args[0]);
+            return vm->heap.gcnew<T>(t, T());
+        });
     }
 
     template<int ARGC>
@@ -382,7 +391,8 @@ public:
     f64 num_to_float(PyObject* obj);
     bool asBool(PyObject* obj);
     i64 hash(PyObject* obj);
-    PyObject* asRepr(PyObject* obj);
+    PyObject* asRepr(PyObject*);
+    PyObject* asList(PyObject*);
     PyObject* new_module(StrName name);
     Str disassemble(CodeObject_ co);
     void init_builtin_types();
@@ -568,6 +578,17 @@ inline bool VM::asBool(PyObject* obj){
     return true;
 }
 
+inline PyObject* VM::asList(PyObject* it){
+    it = asIter(it);
+    List list;
+    PyObject* obj = PyIterNext(it);
+    while(obj != StopIteration){
+        list.push_back(obj);
+        obj = PyIterNext(it);
+    }
+    return VAR(std::move(list));
+}
+
 inline void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step){
     auto clip = [](int value, int min, int max){
         if(value < min) return min;
@@ -838,8 +859,8 @@ inline void VM::_log_s_data(const char* title) {
 }
 
 inline void VM::init_builtin_types(){
-    _all_types.push_back({heap._new<Type>(Type(1), Type(0)), -1, "object"});
-    _all_types.push_back({heap._new<Type>(Type(1), Type(1)), 0, "type"});
+    _all_types.push_back({heap._new<Type>(Type(1), Type(0)), -1, "object", true});
+    _all_types.push_back({heap._new<Type>(Type(1), Type(1)), 0, "type", false});
     tp_object = 0; tp_type = 1;
 
     tp_int = _new_type_object("int");
@@ -947,19 +968,25 @@ inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
         if(method_call) FATAL_ERROR();
         // [type, NULL, args..., kwargs...]
 
-        // TODO: derived __new__ ?
-        PyObject* new_f = callable->attr().try_get(__new__);
+        // __new__
+        const static StrName m_new("__new__");
+        PyObject* new_f = find_name_in_mro(callable, m_new);
         PyObject* obj;
         if(new_f != nullptr){
             PUSH(new_f);
             PUSH(PY_NULL);
+            PUSH(callable);    // cls
             for(PyObject* obj: args) PUSH(obj);
             for(PyObject* obj: kwargs) PUSH(obj);
-            obj = vectorcall(ARGC, KWARGC);
-            if(!isinstance(obj, OBJ_GET(Type, callable))) return obj;
+            // if obj is not an instance of callable, the behavior is undefined
+            obj = vectorcall(ARGC+1, KWARGC);
         }else{
-            obj = heap.gcnew<DummyInstance>(OBJ_GET(Type, callable), {});
+            // fast path for object.__new__
+            Type t = OBJ_GET(Type, callable);
+            obj= vm->heap.gcnew<DummyInstance>(t, {});
         }
+
+        // __init__
         PyObject* self;
         callable = get_unbound_method(obj, __init__, &self, false);
         if (self != PY_NULL) {