blueloveTH пре 3 година
родитељ
комит
91b314d7f2

+ 4 - 0
plugins/flutter/CHANGELOG.md

@@ -1,3 +1,7 @@
+## 0.8.0+1
+
++ Reconstruction
+
 ## 0.6.2+1
 
 + Break change

+ 0 - 1
plugins/flutter/README.md

@@ -36,7 +36,6 @@ The features marked with `YES` are supported, and the features marked with `NO`
 </p>
 
 This plugin provides object-oriented interfaces including full functionality of PocketPy [C-API](https://pocketpy.dev/c-api/vm).
-It also provides `JsonRpcServer` class and `os` module bindings.
 
 Run the following script to install this plugin.
 

+ 1 - 2
plugins/flutter/example/lib/main.dart

@@ -50,8 +50,7 @@ class _MyAppState extends State<MyApp> {
       buffer.write(needMoreLines ? '... $text' : '>>> $text\n');
     });
     if (text == "exit()") exit(0);
-    repl.input(text);
-    needMoreLines = repl.last_input_result() == 0;
+    needMoreLines = repl.input(text) == 0;
     refresh();
   }
 

+ 1 - 1
plugins/flutter/example/pubspec.lock

@@ -108,7 +108,7 @@ packages:
       path: ".."
       relative: true
     source: path
-    version: "0.6.1+2"
+    version: "0.8.0+1"
   sky_engine:
     dependency: transitive
     description: flutter

+ 0 - 149
plugins/flutter/lib/jsonrpc.dart

@@ -1,149 +0,0 @@
-// ignore_for_file: no_leading_underscores_for_local_identifiers, non_constant_identifier_names
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
-
-import 'no_web.dart' if (dart.library.html) 'web.dart';
-
-class _JsonRpcError {
-  final Map<String, dynamic> payload = {};
-
-  _JsonRpcError(int code, String message, {dynamic data}) {
-    payload['code'] = code;
-    payload['message'] = message;
-    if (data != null) {
-      payload['data'] = data;
-    }
-  }
-}
-
-class JsonRpcServer {
-  final Map<String, FutureOr<dynamic> Function(List)> _methods = {};
-
-  final void Function()? onPreDispatch;
-  final void Function()? onPostDispatch;
-  final bool enableFileAccess;
-
-  JsonRpcServer(
-      {this.onPreDispatch,
-      this.onPostDispatch,
-      this.enableFileAccess = false}) {
-    if (!enableFileAccess) return;
-    _registerOS(this);
-  }
-
-  /// Register a JSONRPC handler.
-  void register(String name, FutureOr<dynamic> Function(List) method) {
-    _methods[name] = method;
-  }
-
-  FutureOr<dynamic> _dispatch(ThreadedVM vm) {
-    if (vm.state != ThreadState.suspended) throw Exception("Unexpected state");
-    String? json = vm.read_jsonrpc_request();
-    if (json == null) throw Exception("JSONRPC request is null");
-    var request = jsonDecode(json);
-    var f = _methods[request['method']];
-    if (f == null) throw _JsonRpcError(-32601, "Method not found");
-    try {
-      return f(request['params'] as List);
-    } catch (e) {
-      throw _JsonRpcError(-32000, e.toString());
-    }
-  }
-
-  /// Dispatch a JSONRPC request.
-  FutureOr<void> dispatch(ThreadedVM vm) async {
-    onPreDispatch?.call();
-    try {
-      dynamic ret = _dispatch(vm);
-      if (ret is Future<dynamic>) ret = await ret;
-      vm.write_jsonrpc_response(jsonEncode({"result": ret}));
-      onPostDispatch?.call();
-    } on _JsonRpcError catch (e) {
-      vm.write_jsonrpc_response(jsonEncode({"error": e.payload}));
-      return;
-    }
-  }
-
-  /// Attach the JsonRpcServer into a ThreadedVM. Once the ThreadedVM encounters JSONRPC request, it takes care of it automatically. This process will be stopped when the whole execution is done.
-  Future<void> attach(ThreadedVM vm,
-      {Duration? spinFreq = const Duration(milliseconds: 20)}) async {
-    while (vm.state.index <= ThreadState.running.index) {
-      if (spinFreq != null) await Future.delayed(spinFreq);
-    }
-    switch (vm.state) {
-      case ThreadState.suspended:
-        await dispatch(vm);
-        await attach(vm, spinFreq: spinFreq);
-        break;
-      case ThreadState.finished:
-        break;
-      default:
-        throw Exception("Unexpected state");
-    }
-  }
-
-  int _fileId = 0;
-  final Map<int, File> _files = {};
-
-  void _registerOS(JsonRpcServer rpcServer) {
-    rpcServer.register("fopen", (params) {
-      var path = params[0];
-      //var mode = params[1];
-      var fp = File(path);
-      _fileId += 1;
-      _files[_fileId] = fp;
-      return _fileId;
-    });
-
-    rpcServer.register("fclose", (params) {
-      var fp = _files[params[0]];
-      if (fp == null) throw Exception("FileIO was closed");
-      _files.remove(params[0]);
-    });
-
-    rpcServer.register("fread", (params) {
-      var fp = _files[params[0]];
-      if (fp == null) throw Exception("FileIO was closed");
-      return fp.readAsStringSync();
-    });
-
-    rpcServer.register("fwrite", (params) {
-      var fp = _files[params[0]];
-      if (fp == null) throw Exception("FileIO was closed");
-      fp.writeAsStringSync(params[1]);
-    });
-
-    rpcServer.register("os.listdir", (params) {
-      String path = params[0];
-      var entries = Directory(path).listSync(followLinks: false);
-      var ret = entries.map((e) {
-        return e.path.split(Platform.pathSeparator).last;
-      }).toList();
-      return ret;
-    });
-
-    rpcServer.register("os.mkdir", (params) {
-      String path = params[0];
-      Directory(path).createSync();
-    });
-
-    rpcServer.register("os.rmdir", (params) {
-      String path = params[0];
-      Directory(path).deleteSync(recursive: true);
-    });
-
-    rpcServer.register("os.remove", (params) {
-      String path = params[0];
-      File(path).deleteSync();
-    });
-
-    rpcServer.register("os.path.exists", (params) {
-      String path = params[0];
-      bool _0 = Directory(path).existsSync();
-      bool _1 = File(path).existsSync();
-      return (_0 || _1);
-    });
-  }
-}

+ 90 - 16
plugins/flutter/lib/no_web.dart

@@ -6,8 +6,7 @@ import 'dart:io';
 import 'package:ffi/ffi.dart';
 import 'common.dart';
 
-class _Bindings
-{
+class _Bindings {
   static ffi.DynamicLibrary _load() {
     String _libName = "pocketpy";
     if (Platform.isIOS) {
@@ -24,20 +23,98 @@ class _Bindings
 
   static final _lib = _load();
 
-  static final pkpy_delete = _lib.lookupFunction<ffi.Void Function(ffi.Pointer p), void Function(ffi.Pointer p)>("pkpy_delete");
-  static final pkpy_new_repl = _lib.lookupFunction<ffi.Pointer Function(ffi.Pointer vm), ffi.Pointer Function(ffi.Pointer vm)>("pkpy_new_repl");
-  static final pkpy_repl_input = _lib.lookupFunction<ffi.Int32 Function(ffi.Pointer r, ffi.Pointer<Utf8> line), int Function(ffi.Pointer r, ffi.Pointer<Utf8> line)>("pkpy_repl_input");
-  static final pkpy_new_vm = _lib.lookupFunction<ffi.Pointer Function(ffi.Bool use_stdio), ffi.Pointer Function(bool use_stdio)>("pkpy_new_vm");
-  static final pkpy_vm_add_module = _lib.lookupFunction<ffi.Void Function(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_eval = _lib.lookupFunction<ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> source), ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> source)>("pkpy_vm_eval");
-  static final pkpy_vm_exec = _lib.lookupFunction<ffi.Void Function(ffi.Pointer vm, ffi.Pointer<Utf8> source), void Function(ffi.Pointer vm, ffi.Pointer<Utf8> source)>("pkpy_vm_exec");
-  static final pkpy_vm_get_global = _lib.lookupFunction<ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> name), ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> name)>("pkpy_vm_get_global");
-  static final pkpy_vm_read_output = _lib.lookupFunction<ffi.Pointer<Utf8> Function(ffi.Pointer vm), ffi.Pointer<Utf8> Function(ffi.Pointer vm)>("pkpy_vm_read_output");
+  static final pkpy_delete = _lib.lookupFunction<
+      ffi.Void Function(ffi.Pointer p),
+      void Function(ffi.Pointer p)>("pkpy_delete");
+  static final pkpy_new_repl = _lib.lookupFunction<
+      ffi.Pointer Function(ffi.Pointer vm),
+      ffi.Pointer Function(ffi.Pointer vm)>("pkpy_new_repl");
+  static final pkpy_repl_input = _lib.lookupFunction<
+      ffi.Int32 Function(ffi.Pointer r, ffi.Pointer<Utf8> line),
+      int Function(ffi.Pointer r, ffi.Pointer<Utf8> line)>("pkpy_repl_input");
+  static final pkpy_new_vm = _lib.lookupFunction<
+      ffi.Pointer Function(ffi.Bool use_stdio),
+      ffi.Pointer Function(bool use_stdio)>("pkpy_new_vm");
+  static final pkpy_vm_add_module = _lib.lookupFunction<
+      ffi.Void Function(
+          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_eval = _lib.lookupFunction<
+      ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> source),
+      ffi.Pointer<Utf8> Function(
+          ffi.Pointer vm, ffi.Pointer<Utf8> source)>("pkpy_vm_eval");
+  static final pkpy_vm_exec = _lib.lookupFunction<
+      ffi.Void Function(ffi.Pointer vm, ffi.Pointer<Utf8> source),
+      void Function(ffi.Pointer vm, ffi.Pointer<Utf8> source)>("pkpy_vm_exec");
+  static final pkpy_vm_get_global = _lib.lookupFunction<
+      ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> name),
+      ffi.Pointer<Utf8> Function(
+          ffi.Pointer vm, ffi.Pointer<Utf8> name)>("pkpy_vm_get_global");
+  static final pkpy_vm_read_output = _lib.lookupFunction<
+      ffi.Pointer<Utf8> Function(ffi.Pointer vm),
+      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);
+
+  void dispose() {
+    _Bindings.pkpy_delete(pointer);
+  }
+
+  PyOutput read_output() {
+    var _o = _Bindings.pkpy_vm_read_output(pointer);
+    String _j = _o.toDartString();
+    var ret = PyOutput.fromJson(cvt.jsonDecode(_j));
+    _Bindings.pkpy_delete(_o);
+    return ret;
+  }
+
+  /// 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);
+  }
+
+  /// 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);
+    if (ret == ffi.nullptr) return null;
+    String s = ret.toDartString();
+    _Bindings.pkpy_delete(ret);
+    return s;
+  }
+
+  /// Run a given source on a virtual machine.
+  void exec(String source) {
+    _Bindings.pkpy_vm_exec(pointer, _Str(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);
+    if (ret == ffi.nullptr) return null;
+    String s = ret.toDartString();
+    _Bindings.pkpy_delete(ret);
+    return s;
+  }
+}
 
 class REPL {
-  late final ffi.Pointer pointer;
+  late final dynamic pointer;
 
   REPL(VM vm) {
     pointer = _Bindings.pkpy_new_repl(vm.pointer);
@@ -48,11 +125,8 @@ class REPL {
   }
 
   /// Input a source line to an interactive console.
-  int input(String line)
-  {
+  int input(String line) {
     var ret = _Bindings.pkpy_repl_input(pointer, _Str(line).p);
     return ret;
   }
-
 }
-

+ 0 - 2
plugins/flutter/lib/pocketpy.dart

@@ -1,5 +1,3 @@
 library pocketpy;
-
-export 'jsonrpc.dart';
 export 'common.dart';
 export 'no_web.dart' if (dart.library.html) 'web.dart';

+ 62 - 17
plugins/flutter/lib/web.dart

@@ -4,19 +4,67 @@ import 'package:js/js.dart';
 import 'common.dart';
 
 @JS("Module.ccall")
-external dynamic ccall(String name, String? returnType, List<String> argTypes, List<dynamic> args);
-
-class _Bindings
-{
-  static final pkpy_delete = (dynamic p) => ccall("pkpy_delete", null, ["number"], [p]);
-  static final pkpy_new_repl = (dynamic vm) => ccall("pkpy_new_repl", "number", ["number"], [vm]);
-  static final pkpy_repl_input = (dynamic r, String line) => ccall("pkpy_repl_input", "number", ["number", "string"], [r, line]);
-  static final pkpy_new_vm = (bool use_stdio) => ccall("pkpy_new_vm", "number", ["boolean"], [use_stdio]);
-  static final pkpy_vm_add_module = (dynamic vm, String name, String source) => ccall("pkpy_vm_add_module", null, ["number", "string", "string"], [vm, name, source]);
-  static final pkpy_vm_eval = (dynamic vm, String source) => ccall("pkpy_vm_eval", "string", ["number", "string"], [vm, source]);
-  static final pkpy_vm_exec = (dynamic vm, String source) => ccall("pkpy_vm_exec", null, ["number", "string"], [vm, source]);
-  static final pkpy_vm_get_global = (dynamic vm, String name) => ccall("pkpy_vm_get_global", "string", ["number", "string"], [vm, name]);
-  static final pkpy_vm_read_output = (dynamic vm) => ccall("pkpy_vm_read_output", "string", ["number"], [vm]);
+external dynamic ccall(
+    String name, String? returnType, List<String> argTypes, List<dynamic> args);
+
+class _Bindings {
+  static final pkpy_delete =
+      (dynamic p) => ccall("pkpy_delete", null, ["number"], [p]);
+  static final pkpy_new_repl =
+      (dynamic vm) => ccall("pkpy_new_repl", "number", ["number"], [vm]);
+  static final pkpy_repl_input = (dynamic r, String line) =>
+      ccall("pkpy_repl_input", "number", ["number", "string"], [r, line]);
+  static final pkpy_new_vm = (bool use_stdio) =>
+      ccall("pkpy_new_vm", "number", ["boolean"], [use_stdio]);
+  static final pkpy_vm_add_module = (dynamic vm, String name, String source) =>
+      ccall("pkpy_vm_add_module", null, ["number", "string", "string"],
+          [vm, name, source]);
+  static final pkpy_vm_eval = (dynamic vm, String source) =>
+      ccall("pkpy_vm_eval", "string", ["number", "string"], [vm, source]);
+  static final pkpy_vm_exec = (dynamic vm, String source) =>
+      ccall("pkpy_vm_exec", null, ["number", "string"], [vm, source]);
+  static final pkpy_vm_get_global = (dynamic vm, String name) =>
+      ccall("pkpy_vm_get_global", "string", ["number", "string"], [vm, name]);
+  static final pkpy_vm_read_output =
+      (dynamic vm) => ccall("pkpy_vm_read_output", "string", ["number"], [vm]);
+}
+
+class VM {
+  late final pointer = _Bindings.pkpy_new_vm(false);
+
+  void dispose() {
+    _Bindings.pkpy_delete(pointer);
+  }
+
+  PyOutput read_output() {
+    var _o = _Bindings.pkpy_vm_read_output(pointer);
+    String _j = _o;
+    var ret = PyOutput.fromJson(cvt.jsonDecode(_j));
+
+    return ret;
+  }
+
+  /// Add a source module into a virtual machine.
+  void add_module(String name, String source) {
+    _Bindings.pkpy_vm_add_module(pointer, name, source);
+  }
+
+  /// 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, source);
+    return ret;
+  }
+
+  /// Run a given source on a virtual machine.
+  void exec(String source) {
+    _Bindings.pkpy_vm_exec(pointer, source);
+  }
+
+  /// 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, name);
+    return ret;
+  }
 }
 
 class REPL {
@@ -31,11 +79,8 @@ class REPL {
   }
 
   /// Input a source line to an interactive console.
-  int input(String line)
-  {
+  int input(String line) {
     var ret = _Bindings.pkpy_repl_input(pointer, line);
     return ret;
   }
-
 }
-

+ 1 - 1
plugins/flutter/pubspec.yaml

@@ -1,6 +1,6 @@
 name: pocketpy
 description: A lightweight Python interpreter for game engines.
-version: 0.6.2+1
+version: 0.8.0+1
 homepage: https://pocketpy.dev
 repository: https://github.com/blueloveth/pocketpy