## Introduction
   
This plugin provides object-oriented interfaces including full functionality of PocketPy [C-API](https://pocketpy.dev/c-api/vm).
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.
```
...
  
  
  
  
...
```
#### For Windows
VS2017 or higher is required to build the windows `.dll`.
Make sure you have C++ component installed.
## Basic Example
```dart
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("builtins", "add", (int x, int y) => x + y);
vm.eval("add(1, 2)");	// '3'
```
## REPL Widget Example
```dart
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 createState() => _MyAppState();
}
class _MyAppState extends State {
  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 pkpy with respect to [cpython](https://github.com/python/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  as :`          | YES       |
| Type Annotation | `def  f(a:int, b:float=1)`      | YES       |
| Generator       | `yield i`                       | YES       |
| Decorator       | `@cache`                        | YES       |