blueloveTH 3 лет назад
Родитель
Сommit
170de07bfb

+ 77 - 0
plugins/flutter/lib/_ffi.dart

@@ -0,0 +1,77 @@
+// ignore_for_file: non_constant_identifier_names
+
+import 'dart:convert';
+import 'dart:ffi' as ffi;
+import 'package:ffi/ffi.dart';
+
+Map<String, Function> _mappings = {};
+
+class StrWrapper {
+  static final Finalizer<ffi.Pointer<Utf8>> finalizer =
+      Finalizer((p) => malloc.free(p));
+
+  late final ffi.Pointer<Utf8> _p;
+  StrWrapper(String s) {
+    _p = s.toNativeUtf8();
+    finalizer.attach(this, _p);
+  }
+
+  ffi.Pointer<Utf8> get p => _p;
+}
+
+dynamic invoke_f_any(ffi.Pointer<Utf8> p) {
+  String s = p.toDartString();
+  malloc.free(p);
+  var parts = s.split(' ');
+  List<dynamic> args = [];
+  for (int i = 1; i < parts.length; i++) {
+    args.add(jsonDecode(parts[i]));
+  }
+  var f = _mappings[parts[0]];
+  return Function.apply(f!, args);
+}
+
+int invoke_f_int(ffi.Pointer<Utf8> p) => invoke_f_any(p);
+double invoke_f_float(ffi.Pointer<Utf8> p) => invoke_f_any(p);
+bool invoke_f_bool(ffi.Pointer<Utf8> p) => invoke_f_any(p);
+ffi.Pointer<Utf8> invoke_f_str(ffi.Pointer<Utf8> p) =>
+    StrWrapper(invoke_f_any(p)).p;
+void invoke_f_None(ffi.Pointer<Utf8> p) => invoke_f_any(p);
+
+ffi.Pointer f_int() {
+  return ffi.Pointer.fromFunction<ffi.Int64 Function(ffi.Pointer<Utf8>)>(
+      invoke_f_int, 0);
+}
+
+ffi.Pointer f_float() {
+  return ffi.Pointer.fromFunction<ffi.Double Function(ffi.Pointer<Utf8>)>(
+      invoke_f_float, 0.0);
+}
+
+ffi.Pointer f_bool() {
+  return ffi.Pointer.fromFunction<ffi.Bool Function(ffi.Pointer<Utf8>)>(
+      invoke_f_bool, false);
+}
+
+ffi.Pointer f_str() {
+  return ffi.Pointer.fromFunction<
+      ffi.Pointer<Utf8> Function(ffi.Pointer<Utf8>)>(invoke_f_str);
+}
+
+ffi.Pointer f_None() {
+  return ffi.Pointer.fromFunction<ffi.Void Function(ffi.Pointer<Utf8>)>(
+      invoke_f_None);
+}
+
+void register(String? key, Function value) {
+  _mappings[key!] = value;
+}
+
+int t_code<T>() {
+  if (T == int) return 'i'.codeUnitAt(0);
+  if (T == double) return 'f'.codeUnitAt(0);
+  if (T == bool) return 'b'.codeUnitAt(0);
+  if (T == String) return 's'.codeUnitAt(0);
+  return 'N'.codeUnitAt(0);
+  // throw Exception("Type must be int/double/bool/String");
+}

+ 34 - 18
plugins/flutter/lib/no_web.dart

@@ -4,6 +4,7 @@ import 'dart:convert' as cvt;
 import 'dart:ffi' as ffi;
 import 'dart:io';
 import 'package:ffi/ffi.dart';
+import '_ffi.dart';
 import 'common.dart';
 
 class _Bindings {
@@ -26,6 +27,11 @@ class _Bindings {
   static final pkpy_delete = _lib.lookupFunction<
       ffi.Void Function(ffi.Pointer p),
       void Function(ffi.Pointer p)>("pkpy_delete");
+  static final pkpy_setup_callbacks = _lib.lookupFunction<
+      ffi.Void Function(ffi.Pointer f_int, ffi.Pointer f_float,
+          ffi.Pointer f_bool, ffi.Pointer f_str, ffi.Pointer f_None),
+      void Function(ffi.Pointer f_int, ffi.Pointer f_float, ffi.Pointer f_bool,
+          ffi.Pointer f_str, ffi.Pointer f_None)>("pkpy_setup_callbacks");
   static final pkpy_new_repl = _lib.lookupFunction<
       ffi.Pointer Function(ffi.Pointer vm),
       ffi.Pointer Function(ffi.Pointer vm)>("pkpy_new_repl");
@@ -40,6 +46,11 @@ class _Bindings {
           ffi.Pointer vm, ffi.Pointer<Utf8> name, ffi.Pointer<Utf8> source),
       void Function(ffi.Pointer vm, ffi.Pointer<Utf8> name,
           ffi.Pointer<Utf8> source)>("pkpy_vm_add_module");
+  static final pkpy_vm_bind = _lib.lookupFunction<
+      ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> mod,
+          ffi.Pointer<Utf8> name, ffi.Int32 ret_code),
+      ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> mod,
+          ffi.Pointer<Utf8> name, int ret_code)>("pkpy_vm_bind");
   static final pkpy_vm_eval = _lib.lookupFunction<
       ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> source),
       ffi.Pointer<Utf8> Function(
@@ -56,21 +67,16 @@ class _Bindings {
       ffi.Pointer<Utf8> Function(ffi.Pointer vm)>("pkpy_vm_read_output");
 }
 
-class _Str {
-  static final Finalizer<ffi.Pointer<Utf8>> finalizer =
-      Finalizer((p) => malloc.free(p));
-
-  late final ffi.Pointer<Utf8> _p;
-  _Str(String s) {
-    _p = s.toNativeUtf8();
-    finalizer.attach(this, _p);
-  }
-
-  ffi.Pointer<Utf8> get p => _p;
-}
-
 class VM {
   late final pointer = _Bindings.pkpy_new_vm(false);
+  static bool _firstNew = true;
+
+  VM() {
+    if (!_firstNew) return;
+    _firstNew = false;
+    _Bindings.pkpy_setup_callbacks(
+        f_int(), f_float(), f_bool(), f_str(), f_None());
+  }
 
   void dispose() {
     _Bindings.pkpy_delete(pointer);
@@ -86,12 +92,13 @@ class VM {
 
   /// Add a source module into a virtual machine.
   void add_module(String name, String source) {
-    _Bindings.pkpy_vm_add_module(pointer, _Str(name).p, _Str(source).p);
+    _Bindings.pkpy_vm_add_module(
+        pointer, StrWrapper(name).p, StrWrapper(source).p);
   }
 
   /// Evaluate an expression.  Return `__repr__` of the result. If there is any error, return `nullptr`.
   String? eval(String source) {
-    var ret = _Bindings.pkpy_vm_eval(pointer, _Str(source).p);
+    var ret = _Bindings.pkpy_vm_eval(pointer, StrWrapper(source).p);
     if (ret == ffi.nullptr) return null;
     String s = ret.toDartString();
     _Bindings.pkpy_delete(ret);
@@ -100,17 +107,26 @@ class VM {
 
   /// Run a given source on a virtual machine.
   void exec(String source) {
-    _Bindings.pkpy_vm_exec(pointer, _Str(source).p);
+    _Bindings.pkpy_vm_exec(pointer, StrWrapper(source).p);
   }
 
   /// Get a global variable of a virtual machine.  Return `__repr__` of the result. If the variable is not found, return `nullptr`.
   String? get_global(String name) {
-    var ret = _Bindings.pkpy_vm_get_global(pointer, _Str(name).p);
+    var ret = _Bindings.pkpy_vm_get_global(pointer, StrWrapper(name).p);
     if (ret == ffi.nullptr) return null;
     String s = ret.toDartString();
     _Bindings.pkpy_delete(ret);
     return s;
   }
+
+  void bind<T>(String mod, String name, Function f) {
+    ffi.Pointer<Utf8> p = _Bindings.pkpy_vm_bind(
+        pointer, StrWrapper(mod).p, StrWrapper(name).p, t_code<T>());
+    if (p == ffi.nullptr) throw Exception("vm.bind() failed");
+    String s = p.toDartString();
+    malloc.free(p);
+    register(s, f);
+  }
 }
 
 class REPL {
@@ -126,7 +142,7 @@ class REPL {
 
   /// Input a source line to an interactive console. Return true if need more lines.
   bool input(String line) {
-    var ret = _Bindings.pkpy_repl_input(pointer, _Str(line).p);
+    var ret = _Bindings.pkpy_repl_input(pointer, StrWrapper(line).p);
     return ret;
   }
 }

+ 6 - 0
plugins/flutter/lib/web.dart

@@ -31,6 +31,12 @@ class _Bindings {
 
 class VM {
   late final pointer = _Bindings.pkpy_new_vm(false);
+  static bool _firstNew = true;
+
+  VM() {
+    if (!_firstNew) return;
+    _firstNew = false;
+  }
 
   void dispose() {
     _Bindings.pkpy_delete(pointer);

+ 3 - 2
plugins/flutter/src/pocketpy.h

@@ -4278,10 +4278,11 @@ public:
                 ret = run_frame(frame);
 
                 if(ret != __py2py_call_signal){
-                    callstack.pop();
                     if(frame->id == base_id){      // [ frameBase<- ]
+                        callstack.pop();
                         return ret;
                     }else{
+                        callstack.pop();
                         frame = callstack.top().get();
                         frame->push(ret);
                     }
@@ -6001,7 +6002,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
 
     _vm->bindBuiltinFunc<-1>("exit", [](VM* vm, const pkpy::Args& args) {
         if(args.size() == 0) std::exit(0);
-        else if(args.size() == 1) std::exit(vm->PyInt_AS_C(args[0]));
+        else if(args.size() == 1) std::exit((int)vm->PyInt_AS_C(args[0]));
         else vm->typeError("exit() takes at most 1 argument");
         return vm->None;
     });

+ 1 - 1
plugins/godot/godot-cpp

@@ -1 +1 @@
-Subproject commit 20ace497b54f2e625dc06ec95adf357fcdc27cd7
+Subproject commit 3765c55407d883e12457e44981c87062c446b529

+ 3 - 2
plugins/macos/pocketpy/pocketpy.h

@@ -4278,10 +4278,11 @@ public:
                 ret = run_frame(frame);
 
                 if(ret != __py2py_call_signal){
-                    callstack.pop();
                     if(frame->id == base_id){      // [ frameBase<- ]
+                        callstack.pop();
                         return ret;
                     }else{
+                        callstack.pop();
                         frame = callstack.top().get();
                         frame->push(ret);
                     }
@@ -6001,7 +6002,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
 
     _vm->bindBuiltinFunc<-1>("exit", [](VM* vm, const pkpy::Args& args) {
         if(args.size() == 0) std::exit(0);
-        else if(args.size() == 1) std::exit(vm->PyInt_AS_C(args[0]));
+        else if(args.size() == 1) std::exit((int)vm->PyInt_AS_C(args[0]));
         else vm->typeError("exit() takes at most 1 argument");
         return vm->None;
     });

+ 1 - 1
src/pocketpy.h

@@ -74,7 +74,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
 
     _vm->bindBuiltinFunc<-1>("exit", [](VM* vm, const pkpy::Args& args) {
         if(args.size() == 0) std::exit(0);
-        else if(args.size() == 1) std::exit(vm->PyInt_AS_C(args[0]));
+        else if(args.size() == 1) std::exit((int)vm->PyInt_AS_C(args[0]));
         else vm->typeError("exit() takes at most 1 argument");
         return vm->None;
     });

+ 2 - 1
src/vm.h

@@ -558,10 +558,11 @@ public:
                 ret = run_frame(frame);
 
                 if(ret != __py2py_call_signal){
-                    callstack.pop();
                     if(frame->id == base_id){      // [ frameBase<- ]
+                        callstack.pop();
                         return ret;
                     }else{
+                        callstack.pop();
                         frame = callstack.top().get();
                         frame->push(ret);
                     }