🐍 Python統合をAOTレベルまで完成(eval方式でunsupported=0達成)

- PyRuntimeBox.eval() で完全AOT対応(FloatBox返却)
- NYASH_PY_AUTODECODE=1 によるプリミティブ型自動変換
- ConsoleBox経由の出力もAOT対応
- 多数のPythonテストサンプル追加
- 論文「1ヶ月でインタープリターからネイティブまで」執筆開始

課題:
- import/getattr/callはプラグイン側の実装待ち
- importとevalの文脈共有は未対応

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Moe Charm
2025-08-30 07:47:21 +09:00
parent 0976326a6e
commit db265d7f29
41 changed files with 1899 additions and 14 deletions

View File

@ -0,0 +1,18 @@
// AOT Python eval with code string - simplest possible
static box Main {
init { py, code, result }
main() {
// Create Python runtime
me.py = new PyRuntimeBox()
// Create code string
me.code = new StringBox("1 + 2 + 3")
// Eval the code
me.result = me.py.eval(me.code)
// Return the result (should be 6)
return me.result
}
}

View File

@ -0,0 +1,27 @@
// AOT Python eval with ConsoleBox output
static box Main {
main() {
local py, code, result, console, msg1, msg2
// Create console for output
console = new ConsoleBox()
// Create Python runtime
py = new PyRuntimeBox()
// Print start message
msg1 = new StringBox("Starting calculation...")
console.log(msg1)
// Eval-only approach for sqrt(16)
code = new StringBox("(__import__('math').sqrt)(16)")
result = py.eval(code)
// Print done message
msg2 = new StringBox("Calculation complete!")
console.log(msg2)
// Return result (should be 4.0)
return result
}
}

View File

@ -0,0 +1,19 @@
// Minimal AOT Python demo: uses env to avoid string args
// @env NYASH_PLUGIN_ONLY=1
// Notes:
// - PyRuntimeBox.eval() with zero args reads NYASH_PY_EVAL_CODE on the host side.
// - Avoids StringBox and println to minimize unsupported JIT lowerings.
// - Build AOT:
// bash tools/build_python_aot.sh examples/aot_py_eval_env_min.nyash -o app
// - Run:
// NYASH_PY_EVAL_CODE="(__import__('math').sqrt)(9)" ./app
static box Main {
main() {
local py, _
py = new PyRuntimeBox()
_ = py.eval() // no args; plugin reads NYASH_PY_EVAL_CODE
return 0 // keep return simple for AOT strict
}
}

View File

@ -0,0 +1,18 @@
// AOT Python eval sqrt - direct eval approach
static box Main {
main() {
local py, code, result
// Create Python runtime
py = new PyRuntimeBox()
// Create code string for sqrt
code = new StringBox("(__import__('math').sqrt)(16)")
// Eval the code
result = py.eval(code)
// Return result directly (should be 4.0)
return result
}
}

View File

@ -0,0 +1,19 @@
// Import then eval
static box Main {
main() {
local py, math_name, math, code, result
// Create Python runtime
py = new PyRuntimeBox()
// Import math module
math_name = new StringBox("math")
math = py.import(math_name)
// Then use eval to call sqrt
code = new StringBox("math.sqrt(16)")
result = py.eval(code)
return result
}
}

View File

@ -0,0 +1,15 @@
// Test just import
static box Main {
main() {
local py, math_name, math
// Create Python runtime
py = new PyRuntimeBox()
// Import math module
math_name = new StringBox("math")
math = py.import(math_name)
return 0
}
}

View File

@ -0,0 +1,24 @@
// AOT Python math.sqrt(16) demo
// Demonstrates import/getattr/call chain
static box Main {
init { py, math, sqrt_func, result }
main() {
// Create Python runtime
me.py = new PyRuntimeBox()
// Import math module
me.math = me.py.import("math")
// Get sqrt function from math module
me.sqrt_func = me.py.getattr(me.math, "sqrt")
// Call sqrt(16)
local sixteen
sixteen = new IntegerBox(16)
me.result = me.py.call(me.sqrt_func, sixteen)
// Return the result (should be 4.0)
return me.result
}
}

View File

@ -0,0 +1,33 @@
// AOT Python math.sqrt with ConsoleBox output
static box Main {
main() {
local py, math, sqrt_func, sixteen, result, console
// Create console for output
console = new ConsoleBox()
// Create Python runtime
py = new PyRuntimeBox()
// Print start message
console.log("Starting sqrt calculation...")
// Import math module
math = py.import("math")
// Get sqrt function
sqrt_func = py.getattr(math, "sqrt")
// Create number
sixteen = new IntegerBox(16)
// Call sqrt(16)
result = py.call(sqrt_func, sixteen)
// Print result message
console.log("Result calculated")
// Return result (should be 4.0)
return result
}
}

View File

@ -0,0 +1,24 @@
// AOT Python math.sqrt minimal - no println
static box Main {
main() {
local py, math, sqrt_func, sixteen, result
// Create Python runtime
py = new PyRuntimeBox()
// Import math module
math = py.import("math")
// Get sqrt function
sqrt_func = py.getattr(math, "sqrt")
// Create number
sixteen = new IntegerBox(16)
// Call sqrt(16)
result = py.call(sqrt_func, sixteen)
// Return result directly (should be 4.0)
return result
}
}

View File

@ -0,0 +1,22 @@
// Minimal math.sqrt example with console output
static box Main {
main() {
local py, code, result, console, msg
// Create console
console = new ConsoleBox()
// Create Python runtime
py = new PyRuntimeBox()
// Since import/getattr not available, use eval approach
code = new StringBox("__import__('math').sqrt(16)")
result = py.eval(code)
// Log result
msg = new StringBox("sqrt(16) = ")
console.log(msg)
return result
}
}

View File

@ -0,0 +1,37 @@
// AOT Python math.sqrt with separate print calls
static box Main {
main() {
local py, math, sqrt_func, sixteen, result, console
// Create console for output
console = new ConsoleBox()
// Create Python runtime
py = new PyRuntimeBox()
// Print just text first
local msg1
msg1 = new StringBox("Starting calculation")
console.log(msg1)
// Import math module
math = py.import("math")
// Get sqrt function
sqrt_func = py.getattr(math, "sqrt")
// Create number
sixteen = new IntegerBox(16)
// Call sqrt(16)
result = py.call(sqrt_func, sixteen)
// Print just text again
local msg2
msg2 = new StringBox("Calculation done")
console.log(msg2)
// Return result (should be 4.0)
return result
}
}

View File

@ -0,0 +1,24 @@
// AOT minimal example with split println
static box Main {
main() {
local py, code, result, console, msg
// Create console
console = new ConsoleBox()
// Create Python runtime
py = new PyRuntimeBox()
// Eval math.sqrt
code = new StringBox("__import__('math').sqrt(16)")
result = py.eval(code)
// Print text first
msg = new StringBox("Result is:")
console.log(msg)
// Print value separately (would need toString method)
// For now just return the result
return result
}
}

View File

@ -0,0 +1,20 @@
// AOT Python simple call demo - single print to avoid doubling
static box Main {
init { py, abs_func, result }
main() {
// Create Python runtime
me.py = new PyRuntimeBox()
// Get built-in abs function
me.abs_func = me.py.eval("abs")
// Call abs(-42)
local neg42
neg42 = new IntegerBox(-42)
me.result = me.py.call(me.abs_func, neg42)
// Return the result (should be 42)
return me.result
}
}

View File

@ -0,0 +1,22 @@
// Python callKwR OK demo (returns Result.Ok(value))
// @env NYASH_PLUGIN_ONLY=1
// @env NYASH_PY_AUTODECODE=1
// Run:
// ./target/release/nyash --backend vm examples/py_callKwR_ok_demo.nyash
static box Main {
main() {
local py, bi, dictf, r
py = new PyRuntimeBox()
bi = py.import("builtins")
dictf = bi.getattr("dict")
// dict(a=1, b=2) => {'a': 1, 'b': 2}
r = dictf.callKwR("a", 1, "b", 2)
me.console.println(r) // expect Ok(PyObjectBox(...))
// For readability, also show string form via .str()
local s
s = dictf.callKw("a", 1, "b", 2).str()
me.console.println(s)
return 0
}
}

View File

@ -0,0 +1,17 @@
// Python callR error demo (returns Result.Err)
// Run:
// NYASH_PLUGIN_ONLY=1 ./target/release/nyash --backend vm examples/py_callR_error_demo.nyash
static box Main {
main() {
local py, mod, sqrt, r
py = new PyRuntimeBox()
mod = py.import("math")
sqrt = mod.getattr("sqrt")
// wrong type to trigger TypeError
r = sqrt.callR("oops")
me.console.println(r)
return 0
}
}

View File

@ -0,0 +1,17 @@
// Python callR positional args demo: int('FF', 16) => Ok(255)
// @env NYASH_PLUGIN_ONLY=1
// @env NYASH_PY_AUTODECODE=1
// Run:
// ./target/release/nyash --backend vm examples/py_callR_int_base16_ok_demo.nyash
static box Main {
main() {
local py, bi, intf, r
py = new PyRuntimeBox()
bi = py.import("builtins")
intf = bi.getattr("int")
r = intf.callR("FF", 16)
me.console.println(r) // expect Ok(255)
return 0
}
}

View File

@ -0,0 +1,17 @@
// Python callR OK demo (returns Result.Ok(value))
// @env NYASH_PLUGIN_ONLY=1
// @env NYASH_PY_AUTODECODE=1
// Run:
// ./target/release/nyash --backend vm examples/py_callR_ok_demo.nyash
static box Main {
main() {
local py, mod, sqrt, r
py = new PyRuntimeBox()
mod = py.import("math")
sqrt = mod.getattr("sqrt")
r = sqrt.callR(16)
me.console.println(r) // expect Ok(4.0)
return 0
}
}

View File

@ -0,0 +1,22 @@
// Python plugin demo (Phase 10.5 scaffold) - Simplified version
// Requires: plugins/nyash-python-plugin built (release) and nyash.toml updated
// Run:
// NYASH_PLUGIN_ONLY=1 ./target/release/nyash --backend vm examples/py_eval_demo_simple.nyash
static box Main {
main() {
local py, obj, result
py = new PyRuntimeBox()
// Evaluate simple Python expression
obj = py.eval("'hello' * 3")
// Get string representation
result = obj.str()
// Print result
print("Python eval result: " + result)
return 0
}
}

View File

@ -0,0 +1,17 @@
// Python plugin demo via env-provided code (avoids StringBox arg path)
// Build:
// cargo build --release && (cd plugins/nyash-python-plugin && cargo build --release)
// Run:
// NYASH_PY_EVAL_CODE="'hello' * 3" ./target/release/nyash --backend vm examples/py_eval_env_demo.nyash
static box Main {
main() {
local py, obj
py = new PyRuntimeBox()
// Evaluate code from env var (NYASH_PY_EVAL_CODE)
obj = py.eval()
me.console.println(obj.str())
return 0
}
}

View File

@ -0,0 +1,15 @@
// Python getattrR OK demo (returns Result.Ok(handle))
// Run:
// NYASH_PLUGIN_ONLY=1 ./target/release/nyash --backend vm examples/py_getattrR_ok_demo.nyash
static box Main {
main() {
local py, mod, r
py = new PyRuntimeBox()
mod = py.import("math")
r = mod.getattrR("sqrt")
me.console.println(r)
return 0
}
}

View File

@ -1,22 +1,20 @@
// Python plugin demo: import math, getattr sqrt, call(9), str()
// Build plugin:
// (cd plugins/nyash-python-plugin && cargo build --release)
// Python math.sqrt demo via plugin (autodecode on)
// @env NYASH_PLUGIN_ONLY=1
// @env NYASH_PY_AUTODECODE=1
// @env NYASH_DEBUG_PLUGIN=1
// Build:
// cargo build --release && (cd plugins/nyash-python-plugin && cargo build --release)
// Run:
// NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_math_sqrt_demo.nyash
// ./target/release/nyash --backend vm examples/py_math_sqrt_demo.nyash
static box Main {
init { console }
main() {
me.console = new ConsoleBox()
local py, m, f, r
local py, math, sqrt, r
py = new PyRuntimeBox()
m = py.import("math")
f = m.getattr("sqrt")
r = f.call(9)
print("sqrt(9) = " + r.str())
math = py.import("math")
sqrt = math.getattr("sqrt")
r = sqrt.call(9)
me.console.println(r) // expects 3.0
return 0
}
}

View File

@ -0,0 +1,35 @@
// Python native build demo (AOT/EXE) via plugin
//
// Build prerequisites:
// 1) System has CPython shared library available (e.g. libpython3.11.so)
// - Linux: export LD_LIBRARY_PATH=/usr/lib:/usr/local/lib:$LD_LIBRARY_PATH
// - macOS: export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH
// - Windows: python3xx.dll resolvable via PATH or set PYTHONHOME
// 2) Build nyash and python plugin in release mode
// cargo build --release --features cranelift-jit
// (cd plugins/nyash-python-plugin && cargo build --release)
//
// Build native EXE:
// bash tools/build_aot.sh examples/py_native_sqrt_app.nyash -o app
//
// Run (autodecode on makes float results come back as primitives):
// NYASH_PY_AUTODECODE=1 ./app
//
// Expected output line (among others):
// Result: 0
static box Main {
main() {
local c, py, mod, fun, r
c = new ConsoleBox()
py = new PyRuntimeBox()
mod = py.import("math")
fun = mod.getattr("sqrt")
// With NYASH_PY_AUTODECODE=1, this returns a primitive float 3.0
r = fun.call(9)
// Avoid string concatenation for AOT strict; print in two calls
c.println("sqrt(9) = ")
c.println(r)
return 0
}
}

View File

@ -0,0 +1,15 @@
// Python evalR error demo (returns Result.Err)
// @env NYASH_PLUGIN_ONLY=1
// Run:
// ./target/release/nyash --backend vm examples/py_result_error_demo.nyash
static box Main {
main() {
local py, r
py = new PyRuntimeBox()
// Division by zero triggers a Python exception
r = py.evalR("1/0")
me.console.println(r)
return 0
}
}

View File

@ -0,0 +1,15 @@
// Python evalR OK demo (returns Result.Ok)
// @env NYASH_PLUGIN_ONLY=1
// @env NYASH_PY_AUTODECODE=1
// Run:
// ./target/release/nyash --backend vm examples/py_result_ok_demo.nyash
static box Main {
main() {
local py, r
py = new PyRuntimeBox()
r = py.evalR("1 + 2")
me.console.println(r)
return 0
}
}