📚 Phase 12: Nyashスクリプトプラグインシステム設計と埋め込みVM構想
## 主な成果 - Nyashスクリプトでプラグイン作成可能という革命的発見 - C ABI制約の分析と埋め込みVMによる解決策 - MIR/VM/JIT層での箱引数サポートの詳細分析 ## ドキュメント作成 - Phase 12基本構想(README.md) - Gemini/Codex先生の技術分析 - C ABIとの整合性問題と解決策 - 埋め込みVM実装ロードマップ - 箱引数サポートの技術詳細 ## 重要な洞察 - 制約は「リンク時にC ABI必要」のみ - 埋め込みVMでMIRバイトコード実行により解決可能 - Nyashスクリプト→C ABIプラグイン変換が実現可能 Everything is Box → Everything is Plugin → Everything is Possible!
This commit is contained in:
@ -55,3 +55,26 @@ NYASH_JIT_THRESHOLD=1 NYASH_JIT_HOSTCALL=1 \
|
||||
- DebugConfigBox(events/stats/dump/dot)と GcConfigBox は Box から `apply()` で環境へ反映できます。
|
||||
- `--emit-cfg path.dot` または `DebugConfigBox.setPath("jit_dot", path)` でCFGのDOT出力。いずれもdumpを自動有効化。
|
||||
- イベントは `phase` フィールドで区別(lower/execute)。`jit_events_path` でJSONL出力先を指定可能。
|
||||
|
||||
## 5) AOT最小手順(--compile-native)
|
||||
- 目的: Craneliftでオブジェクトを生成し、`libnyrt` とリンクしてEXE化。
|
||||
- 事前: `cargo build --release --features cranelift-jit`
|
||||
- 実行例(String/Integer/Consoleの最小):
|
||||
```
|
||||
./target/release/nyash --compile-native examples/aot_min_string_len.nyash -o app && ./app
|
||||
# 結果は `Result: <val>` として標準出力に表示
|
||||
```
|
||||
- Python最小チェーン(RO):
|
||||
```
|
||||
./target/release/nyash --compile-native examples/aot_py_min_chain.nyash -o app && ./app
|
||||
```
|
||||
- スクリプト版(詳細な手順): `tools/build_aot.sh <file> -o <out>`(Windowsは `tools/build_aot.ps1`)
|
||||
|
||||
## 6) Scheduler(Phase 10.6b 準備)
|
||||
- 目的: 協調スケジューラのSafepoint連携を観測
|
||||
- 実行(デモ):
|
||||
```
|
||||
NYASH_SCHED_DEMO=1 NYASH_SCHED_POLL_BUDGET=2 \
|
||||
./target/release/nyash --backend vm examples/scheduler_demo.nyash
|
||||
```
|
||||
- 期待: `[SCHED] immediate task ran at safepoint` と `[SCHED] delayed task ran at safepoint` が出力
|
||||
|
||||
19
examples/aot_py_eval_kwargs_env.nyash
Normal file
19
examples/aot_py_eval_kwargs_env.nyash
Normal file
@ -0,0 +1,19 @@
|
||||
// AOT Python kwargs via env-injected eval code (暫定ブリッジ)
|
||||
// 目的: TLVでのkwargs未整備の間、evalコードに **dict で渡す
|
||||
// Build:
|
||||
// cargo build --release --features cranelift-jit
|
||||
// Run:
|
||||
// NYASH_PY_EVAL_CODE="(__import__('builtins').int)(**{'x':'FF','base':16})" \
|
||||
// ./target/release/nyash --compile-native examples/aot_py_eval_kwargs_env.nyash -o app && \
|
||||
// NYASH_PY_EVAL_CODE="(__import__('builtins').int)(**{'x':'FF','base':16})" ./app
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
local py, r
|
||||
py = new PyRuntimeBox()
|
||||
r = py.eval() // code is read from NYASH_PY_EVAL_CODE (host side)
|
||||
me.console.println(r)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
17
examples/aot_py_min_chain.nyash
Normal file
17
examples/aot_py_min_chain.nyash
Normal file
@ -0,0 +1,17 @@
|
||||
// AOT Python minimal chain: import -> getattr -> call
|
||||
// Build AOT (example):
|
||||
// cargo build --release --features cranelift-jit
|
||||
// ./target/release/nyash --compile-native examples/aot_py_min_chain.nyash -o app && ./app
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
local py, math, sqrt_fn, x, r
|
||||
py = new PyRuntimeBox()
|
||||
math = py.import("math")
|
||||
sqrt_fn = py.getattr(math, "sqrt")
|
||||
x = new IntegerBox(16)
|
||||
r = py.call(sqrt_fn, x)
|
||||
return r // expects 4.0 (autodecode may convert FloatBox→f64)
|
||||
}
|
||||
}
|
||||
|
||||
16
examples/aot_py_result_err.nyash
Normal file
16
examples/aot_py_result_err.nyash
Normal file
@ -0,0 +1,16 @@
|
||||
// AOT Python evalR Err demo (returns Result.Err)
|
||||
// Build:
|
||||
// cargo build --release --features cranelift-jit
|
||||
// ./target/release/nyash --compile-native examples/aot_py_result_err.nyash -o app && ./app
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
local py, r
|
||||
py = new PyRuntimeBox()
|
||||
// Division by zero triggers a Python exception → Err(...)
|
||||
r = py.evalR(1/0)
|
||||
me.console.println(r)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
16
examples/aot_py_result_ok.nyash
Normal file
16
examples/aot_py_result_ok.nyash
Normal file
@ -0,0 +1,16 @@
|
||||
// AOT Python evalR OK demo (returns Result.Ok)
|
||||
// Build:
|
||||
// cargo build --release --features cranelift-jit
|
||||
// ./target/release/nyash --compile-native examples/aot_py_result_ok.nyash -o app && ./app
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
local py, r
|
||||
py = new PyRuntimeBox()
|
||||
// evalR returns a Result-like box; VM prints Ok(...), AOT prints numeric when autodecode is enabled
|
||||
r = py.evalR("1 + 2")
|
||||
me.console.println(r)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
6
examples/include_expr_test.nyash
Normal file
6
examples/include_expr_test.nyash
Normal file
@ -0,0 +1,6 @@
|
||||
static box Main {
|
||||
main() {
|
||||
return include "examples/include_math.nyash"
|
||||
}
|
||||
}
|
||||
|
||||
7
examples/include_main.nyash
Normal file
7
examples/include_main.nyash
Normal file
@ -0,0 +1,7 @@
|
||||
static box Main {
|
||||
main() {
|
||||
local Math = include "examples/include_math.nyash"
|
||||
local r = Math.add(1, 2)
|
||||
return r
|
||||
}
|
||||
}
|
||||
6
examples/include_math.nyash
Normal file
6
examples/include_math.nyash
Normal file
@ -0,0 +1,6 @@
|
||||
static box Math {
|
||||
add(a, b) {
|
||||
return a + b
|
||||
}
|
||||
}
|
||||
|
||||
19
examples/py_min_chain_vm.nyash
Normal file
19
examples/py_min_chain_vm.nyash
Normal file
@ -0,0 +1,19 @@
|
||||
// Python minimal chain (VM): import -> getattr -> call
|
||||
// @env NYASH_PLUGIN_ONLY=1
|
||||
// @env NYASH_PY_AUTODECODE=1
|
||||
// Run:
|
||||
// cargo build --release && ./target/release/nyash --backend vm examples/py_min_chain_vm.nyash
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
local py, math, sqrt_fn, x, r
|
||||
py = new PyRuntimeBox()
|
||||
math = py.import("math")
|
||||
sqrt_fn = py.getattr(math, "sqrt")
|
||||
x = new IntegerBox(16)
|
||||
r = py.call(sqrt_fn, x)
|
||||
print(r) // expects 4.0
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
197
examples/python_compiler_box.nyash
Normal file
197
examples/python_compiler_box.nyash
Normal file
@ -0,0 +1,197 @@
|
||||
// PythonCompilerBox - C2: Python AST → Nyash変換ロジック
|
||||
// Rust製パーサープラグイン(C1)からのJSONを受け取って処理
|
||||
|
||||
box PythonCompilerBox {
|
||||
init { supportedNodes, corePyIR }
|
||||
|
||||
birth() {
|
||||
// サポートするノードタイプを定義
|
||||
me.supportedNodes = new MapBox()
|
||||
me.supportedNodes.set("Module", true)
|
||||
me.supportedNodes.set("FunctionDef", true)
|
||||
me.supportedNodes.set("Return", true)
|
||||
me.supportedNodes.set("Constant", true)
|
||||
me.supportedNodes.set("If", true)
|
||||
me.supportedNodes.set("While", true)
|
||||
me.supportedNodes.set("For", true)
|
||||
me.supportedNodes.set("BinOp", true)
|
||||
me.supportedNodes.set("Add", true)
|
||||
me.supportedNodes.set("Sub", true)
|
||||
me.supportedNodes.set("Mult", true)
|
||||
me.supportedNodes.set("Div", true)
|
||||
}
|
||||
|
||||
// メインのコンパイル関数
|
||||
compile(astJson) {
|
||||
local console = new ConsoleBox()
|
||||
|
||||
// JSONパース(現在はスタブ)
|
||||
// TODO: JSONBoxが実装されたら使用
|
||||
local ast = me.parseJson(astJson)
|
||||
|
||||
if ast == null {
|
||||
return me.error("Failed to parse AST JSON")
|
||||
}
|
||||
|
||||
// All-or-Nothingチェック
|
||||
local checkResult = me.checkSupported(ast)
|
||||
if not checkResult.isOk {
|
||||
return me.error("Unsupported features: " + checkResult.unsupported)
|
||||
}
|
||||
|
||||
// CorePy IR生成
|
||||
me.corePyIR = me.generateCorePyIR(ast)
|
||||
|
||||
// Nyashコード生成
|
||||
local nyashCode = me.generateNyash(me.corePyIR)
|
||||
|
||||
return me.ok(nyashCode)
|
||||
}
|
||||
|
||||
// AST全体のサポートチェック
|
||||
checkSupported(ast) {
|
||||
local result = new MapBox()
|
||||
result.set("isOk", true)
|
||||
result.set("unsupported", new ArrayBox())
|
||||
|
||||
// 再帰的にチェック(簡易版)
|
||||
if ast.get("counts") {
|
||||
local counts = ast.get("counts")
|
||||
if counts.get("unsupported") > 0 {
|
||||
result.set("isOk", false)
|
||||
local unsupportedList = ast.get("unsupported")
|
||||
result.set("unsupported", unsupportedList)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// CorePy IR生成(中間表現)
|
||||
generateCorePyIR(ast) {
|
||||
local ir = new MapBox()
|
||||
ir.set("version", "0.1")
|
||||
ir.set("module", new MapBox())
|
||||
|
||||
// シンプルな例:main関数のみ
|
||||
local functions = new ArrayBox()
|
||||
|
||||
local mainFunc = new MapBox()
|
||||
mainFunc.set("name", "main")
|
||||
mainFunc.set("params", new ArrayBox())
|
||||
mainFunc.set("body", new ArrayBox())
|
||||
|
||||
// return 0 を追加
|
||||
local returnStmt = new MapBox()
|
||||
returnStmt.set("type", "return")
|
||||
returnStmt.set("value", 0)
|
||||
mainFunc.get("body").push(returnStmt)
|
||||
|
||||
functions.push(mainFunc)
|
||||
ir.get("module").set("functions", functions)
|
||||
|
||||
return ir
|
||||
}
|
||||
|
||||
// Nyashコード生成
|
||||
generateNyash(ir) {
|
||||
local code = new StringBox()
|
||||
code.append("// Generated from Python by PythonCompilerBox\n")
|
||||
code.append("// CorePy IR version: " + ir.get("version") + "\n\n")
|
||||
|
||||
// static box Main生成
|
||||
code.append("static box Main {\n")
|
||||
|
||||
// 関数生成
|
||||
local module = ir.get("module")
|
||||
if module and module.get("functions") {
|
||||
local functions = module.get("functions")
|
||||
local i = 0
|
||||
loop(i < functions.length()) {
|
||||
local func = functions.get(i)
|
||||
code.append(me.generateFunction(func))
|
||||
i = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
code.append("}\n")
|
||||
|
||||
return code.toString()
|
||||
}
|
||||
|
||||
// 個別関数の生成
|
||||
generateFunction(func) {
|
||||
local code = new StringBox()
|
||||
|
||||
local name = func.get("name")
|
||||
local params = func.get("params")
|
||||
local body = func.get("body")
|
||||
|
||||
// 関数シグネチャ
|
||||
code.append(" " + name + "(")
|
||||
// TODO: パラメータ処理
|
||||
code.append(") {\n")
|
||||
|
||||
// 関数本体
|
||||
if body {
|
||||
local i = 0
|
||||
loop(i < body.length()) {
|
||||
local stmt = body.get(i)
|
||||
code.append(me.generateStatement(stmt))
|
||||
i = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
code.append(" }\n")
|
||||
|
||||
return code.toString()
|
||||
}
|
||||
|
||||
// 文の生成
|
||||
generateStatement(stmt) {
|
||||
local type = stmt.get("type")
|
||||
|
||||
if type == "return" {
|
||||
return " return " + stmt.get("value") + "\n"
|
||||
}
|
||||
|
||||
// TODO: 他の文タイプを追加
|
||||
|
||||
return " // TODO: " + type + "\n"
|
||||
}
|
||||
|
||||
// ヘルパー関数
|
||||
ok(value) {
|
||||
local result = new MapBox()
|
||||
result.set("success", true)
|
||||
result.set("value", value)
|
||||
return result
|
||||
}
|
||||
|
||||
error(message) {
|
||||
local result = new MapBox()
|
||||
result.set("success", false)
|
||||
result.set("error", message)
|
||||
return result
|
||||
}
|
||||
|
||||
// 仮のJSONパーサー(スタブ)
|
||||
parseJson(jsonStr) {
|
||||
// TODO: 実際のJSONパース実装
|
||||
// 今は固定のテスト用データを返す
|
||||
local mock = new MapBox()
|
||||
mock.set("success", true)
|
||||
mock.set("dump", "Module(...)")
|
||||
|
||||
local counts = new MapBox()
|
||||
counts.set("total_nodes", 5)
|
||||
counts.set("functions", 1)
|
||||
counts.set("supported", 5)
|
||||
counts.set("unsupported", 0)
|
||||
mock.set("counts", counts)
|
||||
|
||||
mock.set("unsupported", new ArrayBox())
|
||||
|
||||
return mock
|
||||
}
|
||||
}
|
||||
BIN
examples/test_python_compiler
Normal file
BIN
examples/test_python_compiler
Normal file
Binary file not shown.
35
examples/test_python_compiler.c
Normal file
35
examples/test_python_compiler.c
Normal file
@ -0,0 +1,35 @@
|
||||
// PythonCompilerBox 簡易テスト
|
||||
// 環境変数 NYASH_PY_IR からJSON IRを読み取ってNyashコードを生成
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// 超簡易的なコンパイラ(JSONパースなし)
|
||||
const char* compile_simple(const char* ir) {
|
||||
// JSONをちゃんとパースせずに、簡単なパターンマッチング
|
||||
if (strstr(ir, "\"name\":\"main\"") && strstr(ir, "\"return_value\":0")) {
|
||||
return "// Generated from Python\n"
|
||||
"static box Main {\n"
|
||||
" main() {\n"
|
||||
" return 0\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
}
|
||||
return "// Unsupported IR\n";
|
||||
}
|
||||
|
||||
int main() {
|
||||
const char* ir = getenv("NYASH_PY_IR");
|
||||
if (!ir) {
|
||||
ir = "{\"module\":{\"functions\":[{\"name\":\"main\",\"return_value\":0}]}}";
|
||||
printf("Using default IR: %s\n\n", ir);
|
||||
} else {
|
||||
printf("Compiling IR from NYASH_PY_IR: %s\n\n", ir);
|
||||
}
|
||||
|
||||
printf("=== Generated Nyash Code ===\n");
|
||||
printf("%s", compile_simple(ir));
|
||||
|
||||
return 0;
|
||||
}
|
||||
42
examples/test_python_parser.nyash
Normal file
42
examples/test_python_parser.nyash
Normal file
@ -0,0 +1,42 @@
|
||||
// Test Python Parser Plugin
|
||||
// 環境変数 NYASH_PY_CODE からPythonコードを読み取ってパース
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
local console = new ConsoleBox()
|
||||
|
||||
// 環境変数からPythonコードを取得
|
||||
local env_code = ConsoleBox.getEnv("NYASH_PY_CODE")
|
||||
if env_code == null {
|
||||
console.log("Usage: NYASH_PY_CODE='def main(): return 0' nyash test_python_parser.nyash")
|
||||
return 1
|
||||
}
|
||||
|
||||
console.log("=== Python Code ===")
|
||||
console.log(env_code)
|
||||
console.log("")
|
||||
|
||||
// パーサープラグインを読み込み(仮想的に)
|
||||
// 実際にはプラグインローダー経由で呼び出す必要がある
|
||||
console.log("=== Parse Result ===")
|
||||
console.log("(Parser plugin integration pending)")
|
||||
|
||||
// 期待される出力形式を表示
|
||||
console.log("")
|
||||
console.log("Expected output format:")
|
||||
console.log("{")
|
||||
console.log(' "success": true,')
|
||||
console.log(' "dump": "Module(body=[FunctionDef(...)])",')
|
||||
console.log(' "counts": {')
|
||||
console.log(' "total_nodes": 5,')
|
||||
console.log(' "functions": 1,')
|
||||
console.log(' "classes": 0,')
|
||||
console.log(' "supported": 1,')
|
||||
console.log(' "unsupported": 0')
|
||||
console.log(' },')
|
||||
console.log(' "unsupported": []')
|
||||
console.log("}")
|
||||
|
||||
return 0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user