From 170de07bfb816d4f6f063f056a54e84f128db209 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Mon, 6 Feb 2023 18:58:15 +0800 Subject: [PATCH] up --- plugins/flutter/lib/_ffi.dart | 77 +++++++++++++++++++++++++++++++ plugins/flutter/lib/no_web.dart | 52 +++++++++++++-------- plugins/flutter/lib/web.dart | 6 +++ plugins/flutter/src/pocketpy.h | 5 +- plugins/godot/godot-cpp | 2 +- plugins/macos/pocketpy/pocketpy.h | 5 +- src/pocketpy.h | 2 +- src/vm.h | 3 +- 8 files changed, 127 insertions(+), 25 deletions(-) create mode 100644 plugins/flutter/lib/_ffi.dart diff --git a/plugins/flutter/lib/_ffi.dart b/plugins/flutter/lib/_ffi.dart new file mode 100644 index 00000000..35430819 --- /dev/null +++ b/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 _mappings = {}; + +class StrWrapper { + static final Finalizer> finalizer = + Finalizer((p) => malloc.free(p)); + + late final ffi.Pointer _p; + StrWrapper(String s) { + _p = s.toNativeUtf8(); + finalizer.attach(this, _p); + } + + ffi.Pointer get p => _p; +} + +dynamic invoke_f_any(ffi.Pointer p) { + String s = p.toDartString(); + malloc.free(p); + var parts = s.split(' '); + List 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 p) => invoke_f_any(p); +double invoke_f_float(ffi.Pointer p) => invoke_f_any(p); +bool invoke_f_bool(ffi.Pointer p) => invoke_f_any(p); +ffi.Pointer invoke_f_str(ffi.Pointer p) => + StrWrapper(invoke_f_any(p)).p; +void invoke_f_None(ffi.Pointer p) => invoke_f_any(p); + +ffi.Pointer f_int() { + return ffi.Pointer.fromFunction)>( + invoke_f_int, 0); +} + +ffi.Pointer f_float() { + return ffi.Pointer.fromFunction)>( + invoke_f_float, 0.0); +} + +ffi.Pointer f_bool() { + return ffi.Pointer.fromFunction)>( + invoke_f_bool, false); +} + +ffi.Pointer f_str() { + return ffi.Pointer.fromFunction< + ffi.Pointer Function(ffi.Pointer)>(invoke_f_str); +} + +ffi.Pointer f_None() { + return ffi.Pointer.fromFunction)>( + invoke_f_None); +} + +void register(String? key, Function value) { + _mappings[key!] = value; +} + +int t_code() { + 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"); +} diff --git a/plugins/flutter/lib/no_web.dart b/plugins/flutter/lib/no_web.dart index 9fc4c9e6..2e43ea3a 100644 --- a/plugins/flutter/lib/no_web.dart +++ b/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 name, ffi.Pointer source), void Function(ffi.Pointer vm, ffi.Pointer name, ffi.Pointer source)>("pkpy_vm_add_module"); + static final pkpy_vm_bind = _lib.lookupFunction< + ffi.Pointer Function(ffi.Pointer vm, ffi.Pointer mod, + ffi.Pointer name, ffi.Int32 ret_code), + ffi.Pointer Function(ffi.Pointer vm, ffi.Pointer mod, + ffi.Pointer name, int ret_code)>("pkpy_vm_bind"); static final pkpy_vm_eval = _lib.lookupFunction< ffi.Pointer Function(ffi.Pointer vm, ffi.Pointer source), ffi.Pointer Function( @@ -56,21 +67,16 @@ class _Bindings { ffi.Pointer Function(ffi.Pointer vm)>("pkpy_vm_read_output"); } -class _Str { - static final Finalizer> finalizer = - Finalizer((p) => malloc.free(p)); - - late final ffi.Pointer _p; - _Str(String s) { - _p = s.toNativeUtf8(); - finalizer.attach(this, _p); - } - - ffi.Pointer 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(String mod, String name, Function f) { + ffi.Pointer p = _Bindings.pkpy_vm_bind( + pointer, StrWrapper(mod).p, StrWrapper(name).p, t_code()); + 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; } } diff --git a/plugins/flutter/lib/web.dart b/plugins/flutter/lib/web.dart index 8127b447..39f024ec 100644 --- a/plugins/flutter/lib/web.dart +++ b/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); diff --git a/plugins/flutter/src/pocketpy.h b/plugins/flutter/src/pocketpy.h index 84f6622b..6c3bd580 100644 --- a/plugins/flutter/src/pocketpy.h +++ b/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; }); diff --git a/plugins/godot/godot-cpp b/plugins/godot/godot-cpp index 20ace497..3765c554 160000 --- a/plugins/godot/godot-cpp +++ b/plugins/godot/godot-cpp @@ -1 +1 @@ -Subproject commit 20ace497b54f2e625dc06ec95adf357fcdc27cd7 +Subproject commit 3765c55407d883e12457e44981c87062c446b529 diff --git a/plugins/macos/pocketpy/pocketpy.h b/plugins/macos/pocketpy/pocketpy.h index 84f6622b..6c3bd580 100644 --- a/plugins/macos/pocketpy/pocketpy.h +++ b/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; }); diff --git a/src/pocketpy.h b/src/pocketpy.h index 801d0eeb..c50c0aee 100644 --- a/src/pocketpy.h +++ b/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; }); diff --git a/src/vm.h b/src/vm.h index 5b972250..dc10e8bf 100644 --- a/src/vm.h +++ b/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); }