blueloveTH 3 лет назад
Родитель
Сommit
f0eb29e816
6 измененных файлов с 266 добавлено и 297 удалено
  1. 207 267
      plugins/flutter/src/pocketpy.h
  2. 1 1
      plugins/godot/godot-cpp
  3. 4 4
      src/codeobject.h
  4. 13 6
      src/pocketpy.h
  5. 21 19
      src/vm.h
  6. 20 0
      tests/_eval.py

Разница между файлами не показана из-за своего большого размера
+ 207 - 267
plugins/flutter/src/pocketpy.h


+ 1 - 1
plugins/godot/godot-cpp

@@ -1 +1 @@
-Subproject commit 10ce041877fee516e825365d05e89975ae7d2d46
+Subproject commit 4bbbb85979391fd8b1aa349ad81d6527db069ab2

+ 4 - 4
src/codeobject.h

@@ -178,13 +178,13 @@ private:
 public:
     const _Code code;
     PyVar _module;
-    PyVarDict f_locals;
+    pkpy::shared_ptr<PyVarDict> _locals;
 
-    inline PyVarDict f_locals_copy() const { return f_locals; }
+    inline PyVarDict& f_locals(){ return *_locals; }
     inline PyVarDict& f_globals(){ return _module->attribs; }
 
-    Frame(const _Code code, PyVar _module, PyVarDict&& locals)
-        : code(code), _module(_module), f_locals(std::move(locals)) {
+    Frame(const _Code code, PyVar _module, pkpy::shared_ptr<PyVarDict> _locals)
+        : code(code), _module(_module), _locals(_locals) {
     }
 
     inline const Bytecode& next_bytecode() {

+ 13 - 6
src/pocketpy.h

@@ -54,15 +54,22 @@ void __initializeBuiltinFunctions(VM* _vm) {
     });
 
     _vm->bindBuiltinFunc<0>("super", [](VM* vm, const pkpy::ArgList& args) {
-        auto it = vm->top_frame()->f_locals.find(m_self);
-        if(it == vm->top_frame()->f_locals.end()) vm->typeError("super() can only be called in a class method");
+        auto it = vm->top_frame()->f_locals().find(m_self);
+        if(it == vm->top_frame()->f_locals().end()) vm->typeError("super() can only be called in a class method");
         return vm->new_object(vm->_tp_super, it->second);
     });
 
     _vm->bindBuiltinFunc<1>("eval", [](VM* vm, const pkpy::ArgList& args) {
         const _Str& expr = vm->PyStr_AS_C(args[0]);
         _Code code = vm->compile(expr, "<eval>", EVAL_MODE);
-        return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->f_locals_copy());
+        return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
+    });
+
+    _vm->bindBuiltinFunc<1>("exec", [](VM* vm, const pkpy::ArgList& args) {
+        const _Str& expr = vm->PyStr_AS_C(args[0]);
+        _Code code = vm->compile(expr, "<exec>", EXEC_MODE);
+        vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
+        return vm->None;
     });
 
     _vm->bindBuiltinFunc<1>("repr", CPP_LAMBDA(vm->asRepr(args[0])));
@@ -91,7 +98,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
     });
 
     _vm->bindBuiltinFunc<0>("locals", [](VM* vm, const pkpy::ArgList& args) {
-        const auto& d = vm->top_frame()->f_locals;
+        const auto& d = vm->top_frame()->f_locals();
         PyVar obj = vm->call(vm->builtins->attribs["dict"]);
         for (const auto& [k, v] : d) {
             vm->call(obj, __setitem__, pkpy::twoArgs(vm->PyStr(k), v));
@@ -532,7 +539,7 @@ void __addModuleJson(VM* vm){
     vm->bindFunc<1>(mod, "loads", [](VM* vm, const pkpy::ArgList& args) {
         const _Str& expr = vm->PyStr_AS_C(args[0]);
         _Code code = vm->compile(expr, "<json>", JSON_MODE);
-        return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->f_locals_copy());
+        return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
     });
 
     vm->bindFunc<1>(mod, "dumps", [](VM* vm, const pkpy::ArgList& args) {
@@ -789,7 +796,7 @@ extern "C" {
 
         // add builtins | no exception handler | must succeed
         _Code code = vm->compile(__BUILTINS_CODE, "<builtins>", EXEC_MODE);
-        vm->_exec(code, vm->builtins, {});
+        vm->_exec(code, vm->builtins, pkpy::make_shared<PyVarDict>());
 
         pkpy_vm_add_module(vm, "random", __RANDOM_CODE);
         pkpy_vm_add_module(vm, "os", __OS_CODE);

+ 21 - 19
src/vm.h

@@ -311,7 +311,7 @@ protected:
                             const _Str& source = it2->second;
                             _Code code = compile(source, name, EXEC_MODE);
                             PyVar _m = newModule(name);
-                            _exec(code, _m, {});
+                            _exec(code, _m, pkpy::make_shared<PyVarDict>());
                             frame->push(_m);
                             _lazy_modules.erase(it2);
                         }
@@ -459,7 +459,9 @@ public:
             return f(this, args);
         } else if((*callable)->is_type(_tp_function)){
             const _Func& fn = PyFunction_AS_C((*callable));
-            PyVarDict locals;
+            pkpy::shared_ptr<PyVarDict> _locals = pkpy::make_shared<PyVarDict>();
+            PyVarDict& locals = *_locals;
+
             int i = 0;
             for(const auto& name : fn->args){
                 if(i < args.size()){
@@ -507,10 +509,10 @@ public:
             PyVar* it_m = (*callable)->attribs.try_get(__module__);
             PyVar _module = it_m != nullptr ? *it_m : top_frame()->_module;
             if(opCall){
-                __pushNewFrame(fn->code, _module, std::move(locals));
+                __push_new_frame(fn->code, _module, _locals);
                 return __py2py_call_signal;
             }
-            return _exec(fn->code, _module, std::move(locals));
+            return _exec(fn->code, _module, _locals);
         }
         typeError("'" + UNION_TP_NAME(*callable) + "' object is not callable");
         return None;
@@ -523,7 +525,7 @@ public:
         try {
             _Code code = compile(source, filename, mode);
             //if(filename != "<builtins>") std::cout << disassemble(code) << std::endl;
-            return _exec(code, _module, {});
+            return _exec(code, _module, pkpy::make_shared<PyVarDict>());
         }catch (const _Error& e){
             *_stderr << e.what() << '\n';
         }
@@ -534,18 +536,18 @@ public:
         return nullptr;
     }
 
-    Frame* __pushNewFrame(const _Code& code, PyVar _module, PyVarDict&& locals){
-        if(code == nullptr) UNREACHABLE();
+    template<typename ...Args>
+    Frame* __push_new_frame(Args&&... args){
         if(callstack.size() > maxRecursionDepth){
             throw RuntimeError("RecursionError", "maximum recursion depth exceeded", _cleanErrorAndGetSnapshots());
         }
-        Frame* frame = new Frame(code, _module, std::move(locals));
-        callstack.emplace_back(frame);
-        return frame;
+        callstack.emplace_back(std::make_unique<Frame>(std::forward<Args>(args)...));
+        return callstack.back().get();
     }
 
-    PyVar _exec(_Code code, PyVar _module, PyVarDict&& locals){
-        Frame* frame = __pushNewFrame(code, _module, std::move(locals));
+    template<typename ...Args>
+    PyVar _exec(Args&&... args){
+        Frame* frame = __push_new_frame(std::forward<Args>(args)...);
         Frame* frameBase = frame;
         PyVar ret = nullptr;
 
@@ -945,7 +947,7 @@ public:
 
 PyVar NameRef::get(VM* vm, Frame* frame) const{
     PyVar* val;
-    val = frame->f_locals.try_get(pair->first);
+    val = frame->f_locals().try_get(pair->first);
     if(val) return *val;
     val = frame->f_globals().try_get(pair->first);
     if(val) return *val;
@@ -957,10 +959,10 @@ PyVar NameRef::get(VM* vm, Frame* frame) const{
 
 void NameRef::set(VM* vm, Frame* frame, PyVar val) const{
     switch(pair->second) {
-        case NAME_LOCAL: frame->f_locals[pair->first] = std::move(val); break;
+        case NAME_LOCAL: frame->f_locals()[pair->first] = std::move(val); break;
         case NAME_GLOBAL:
         {
-            PyVar* existing = frame->f_locals.try_get(pair->first);
+            PyVar* existing = frame->f_locals().try_get(pair->first);
             if(existing != nullptr){
                 *existing = std::move(val);
             }else{
@@ -974,16 +976,16 @@ void NameRef::set(VM* vm, Frame* frame, PyVar val) const{
 void NameRef::del(VM* vm, Frame* frame) const{
     switch(pair->second) {
         case NAME_LOCAL: {
-            if(frame->f_locals.contains(pair->first)){
-                frame->f_locals.erase(pair->first);
+            if(frame->f_locals().contains(pair->first)){
+                frame->f_locals().erase(pair->first);
             }else{
                 vm->nameError(pair->first);
             }
         } break;
         case NAME_GLOBAL:
         {
-            if(frame->f_locals.contains(pair->first)){
-                frame->f_locals.erase(pair->first);
+            if(frame->f_locals().contains(pair->first)){
+                frame->f_locals().erase(pair->first);
             }else{
                 if(frame->f_globals().contains(pair->first)){
                     frame->f_globals().erase(pair->first);

+ 20 - 0
tests/_eval.py

@@ -0,0 +1,20 @@
+assert eval('1+1') == 2
+assert eval('[1,2,3]') == [1,2,3]
+
+def f(x):
+    return eval('x')
+
+assert f(1) == 1
+
+
+a = 0
+assert eval('a') == 0
+
+exec('a = 1')
+assert a == 1
+
+def f(x):
+    exec('a = x')
+    return a
+
+assert f(2) == 2

Некоторые файлы не были показаны из-за большого количества измененных файлов