blueloveTH d7dddf8c22 update flutter plugin 3 lat temu
..
android c8acb10698 add android build 3 lat temu
example d7dddf8c22 update flutter plugin 3 lat temu
ios 5fe61c2e11 up 3 lat temu
lib e2762bff3e up 3 lat temu
src 90ef21e195 up 3 lat temu
windows 5fe61c2e11 up 3 lat temu
.gitignore 5fe61c2e11 up 3 lat temu
.metadata 5fe61c2e11 up 3 lat temu
CHANGELOG.md d7dddf8c22 update flutter plugin 3 lat temu
LICENSE ea3fc010f3 change license 3 lat temu
README.md e2762bff3e up 3 lat temu
analysis_options.yaml 5fe61c2e11 up 3 lat temu
pubspec.yaml d7dddf8c22 update flutter plugin 3 lat temu

README.md

Introduction

This plugin provides object-oriented interfaces including full functionality of PocketPy C-API.

Run the following script to install this plugin.

flutter pub add pocketpy

Requirements

For Android

You may need to set the Android NDK version to "21.4.7075529" or higher in android/app/build.gradle.

android {
    ndkVersion "21.4.7075529"
}

For iOS

It should work without any setup.

For Web

Download an artifact from https://github.com/blueloveTH/pocketpy/releases/latest.

Unzip it and copy web/lib into your root folder where index.html locates.

...
lib/pocketpy.js
lib/pocketpy.wasm
index.html
...

Then open index.html and add this line before flutter.js tag.

...
  <!-- This script initializes WASM of pocketpy -->
  <script src="./lib/pocketpy.js"></script>

  <!-- This script adds the flutter initialization JS code -->
  <script src="flutter.js" defer></script>
...

For Windows

VS2017 or higher is required to build the windows .dll. Make sure you have C++ component installed.

Basic Example

import 'package:pocketpy/pocketpy.dart' as pkpy;

// Create a virtual machine
pkpy.VM vm = pkpy.VM();

// Run a script
String code = 'print("Hello World!")';
vm.exec(code);

// Read the output
var _o = vm.read_output();
print(_o.stdout)	// "Hello world!\n"
print(_o.stderr)	// ""
    
// Create a binding
vm.bind<int>("builtins", "add", (int x, int y) => x + y);
vm.eval("add(1, 2)");	// '3'

REPL Widget Example

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:pocketpy/pocketpy.dart' as pkpy;

void main() {
  runApp(const MaterialApp(home: MyApp()));
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late final pkpy.VM vm;
  late final pkpy.REPL repl;
  bool needMoreLines = false;

  final TextEditingController _controller = TextEditingController();
  final StringBuffer buffer = StringBuffer();

  @override
  void initState() {
    super.initState();

    // create a pocketpy virtual machine
    vm = pkpy.VM();

    // create a REPL
    repl = pkpy.REPL(vm);

    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      refresh();
    });
  }

  void addMessage(String text) {
    setState(() {
      buffer.write(text);
    });
  }

  void submitCode() {
    var text = _controller.text;
    _controller.clear();
    setState(() {
      buffer.write(needMoreLines ? '... $text' : '>>> $text\n');
    });

    needMoreLines = repl.input(text);
    refresh();
  }

  void refresh() {
    // ignore: no_leading_underscores_for_local_identifiers
    var _o = vm.read_output();
    if (_o.stdout.isNotEmpty) buffer.write(_o.stdout);
    if (_o.stderr.isNotEmpty) buffer.write(_o.stderr);
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    var style = const TextStyle(fontSize: 16);
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
          Expanded(
            child: SingleChildScrollView(
              reverse: true,
              child: Text(
                buffer.toString(),
                style: style,
                textAlign: TextAlign.left,
              ),
            ),
          ),
          const SizedBox(
            height: 16,
          ),
          SizedBox(
            height: 50,
            child: TextFormField(
              controller: _controller,
              style: style,
              maxLines: 1,
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                hintText: 'Enter Python code',
              ),
            ),
          ),
          Container(
            height: 60,
            alignment: Alignment.centerRight,
            child: MaterialButton(
                onPressed: submitCode,
                color: Colors.blue,
                textColor: Colors.white,
                child: const Text('Run')),
          ),
        ]),
      ),
    );
  }
}

basic

The following table shows the basic features of PocketPy with respect to CPython. The features marked with YES are supported, and the features marked with NO are not supported.

Name Example Supported
If Else if..else..elif YES
Loop for/while/break/continue YES
Function def f(x,*args,y=1): YES
Subclass class A(B): YES
List [1, 2, 'a'] YES
ListComp [i for i in range(5)] YES
Slice a[1:2], a[:2], a[1:] YES
Tuple (1, 2, 'a') YES
Dict {'a': 1, 'b': 2} YES
F-String f'value is {x}' YES
Unpacking a, b = 1, 2 YES
Star Unpacking a, *b = [1, 2, 3] YES
Exception raise/try..catch YES
Dynamic Code eval()/exec() YES
Reflection hasattr()/getattr()/setattr() YES
Import import/from..import YES
Context Block with <expr> as <id>: YES
Type Annotation def f(a:int, b:float=1) YES
Generator yield i YES
Decorator @cache YES