📚 Phase 15計画を詳細化・更新: Python/llvmlite正式採用とプラグイン全方向ビルド戦略
✅ 主な更新内容: - Python/llvmlite実装の正式採用を明記(開発速度10倍、~2400行) - プラグイン全方向ビルド戦略(.so/.o/.a同時生成)で単一EXE生成可能に - 各実装の予想コード量を具体化(パーサー800行、MIR Builder 2500行、VM 5000行) - 循環依存問題の解決を明記(nyrtがC ABI経由で提供) - 現実的なスケジュール調整(2025年9月~2026年3月) 🎉 最新進捗: - dep_tree_min_string.nyashオブジェクト生成成功(10.4KB) - LLVM verifier green - dominance違反解決 - Resolver patternでSSA安全性確保 🚀 次のマイルストーン: - Python/llvmliteでEXE生成パイプライン完成 - nyash-llvm-compiler分離設計 - NyashパーサーMVP実装開始 Everything is Boxの究極形が、ついに実現へ! 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -1,83 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Experimental llvmlite-based LLVM emission harness for Nyash.
|
||||
Nyash llvmlite harness (scaffold)
|
||||
|
||||
Usage:
|
||||
python3 tools/llvmlite_harness.py [--in MIR.json] --out OUTPUT.o
|
||||
- python3 tools/llvmlite_harness.py --out out.o # dummy ny_main -> object
|
||||
- python3 tools/llvmlite_harness.py --in mir.json --out out.o # MIR(JSON) -> object (partial support)
|
||||
|
||||
Notes:
|
||||
- First cut emits a trivial ny_main that returns 0 to validate toolchain.
|
||||
- Extend to lower MIR14 JSON incrementally.
|
||||
- For initial scaffolding, when --in is omitted, a trivial ny_main that returns 0 is emitted.
|
||||
- When --in is provided, this script delegates to src/llvm_py/llvm_builder.py.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
from llvmlite import ir, binding
|
||||
except Exception as e: # noqa: BLE001
|
||||
sys.stderr.write(
|
||||
"llvmlite is required. Install with: python3 -m pip install llvmlite\n"
|
||||
)
|
||||
sys.stderr.write(f"Import error: {e}\n")
|
||||
sys.exit(2)
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
PY_BUILDER = ROOT / "src" / "llvm_py" / "llvm_builder.py"
|
||||
|
||||
def run_dummy(out_path: str) -> None:
|
||||
# Minimal llvmlite program: ny_main() -> i32 0
|
||||
import llvmlite.ir as ir
|
||||
import llvmlite.binding as llvm
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
ap = argparse.ArgumentParser(description="Nyash llvmlite harness")
|
||||
ap.add_argument("--in", dest="in_path", help="MIR14 JSON input (optional)")
|
||||
ap.add_argument("--out", dest="out_path", required=True, help="Output object file path")
|
||||
return ap.parse_args()
|
||||
llvm.initialize()
|
||||
llvm.initialize_native_target()
|
||||
llvm.initialize_native_asmprinter()
|
||||
|
||||
|
||||
def load_mir(path: str | None) -> dict | None:
|
||||
if not path:
|
||||
return None
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def build_trivial_module() -> ir.Module:
|
||||
mod = ir.Module(name="nyash_harness")
|
||||
mod.triple = binding.get_default_triple()
|
||||
i64 = ir.IntType(64)
|
||||
i8 = ir.IntType(8)
|
||||
i8p = i8.as_pointer()
|
||||
i8pp = i8p.as_pointer()
|
||||
fn_ty = ir.FunctionType(i64, [i64, i8pp])
|
||||
fn = ir.Function(mod, fn_ty, name="ny_main")
|
||||
entry = fn.append_basic_block(name="entry")
|
||||
mod = ir.Module(name="nyash_module")
|
||||
i32 = ir.IntType(32)
|
||||
ny_main_ty = ir.FunctionType(i32, [])
|
||||
ny_main = ir.Function(mod, ny_main_ty, name="ny_main")
|
||||
entry = ny_main.append_basic_block("entry")
|
||||
b = ir.IRBuilder(entry)
|
||||
b.ret(ir.Constant(i64, 0))
|
||||
return mod
|
||||
b.ret(ir.Constant(i32, 0))
|
||||
|
||||
|
||||
def emit_object(mod: ir.Module, out_path: str) -> None:
|
||||
binding.initialize()
|
||||
binding.initialize_native_target()
|
||||
binding.initialize_native_asmprinter()
|
||||
|
||||
target = binding.Target.from_default_triple()
|
||||
# Emit object via target machine
|
||||
m = llvm.parse_assembly(str(mod))
|
||||
m.verify()
|
||||
target = llvm.Target.from_default_triple()
|
||||
tm = target.create_target_machine()
|
||||
llvm_mod = binding.parse_assembly(str(mod))
|
||||
llvm_mod.verify()
|
||||
obj = tm.emit_object(llvm_mod)
|
||||
obj = tm.emit_object(m)
|
||||
Path(out_path).parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(out_path, "wb") as f:
|
||||
f.write(obj)
|
||||
|
||||
def run_from_json(in_path: str, out_path: str) -> None:
|
||||
# Delegate to python builder to keep code unified
|
||||
import runpy
|
||||
# Ensure src/llvm_py is on sys.path for relative imports
|
||||
builder_dir = str(PY_BUILDER.parent)
|
||||
if builder_dir not in sys.path:
|
||||
sys.path.insert(0, builder_dir)
|
||||
# Simulate "python llvm_builder.py <in> -o <out>"
|
||||
sys.argv = [str(PY_BUILDER), str(in_path), "-o", str(out_path)]
|
||||
runpy.run_path(str(PY_BUILDER), run_name="__main__")
|
||||
|
||||
def main() -> int:
|
||||
ns = parse_args()
|
||||
_mir = load_mir(ns.in_path)
|
||||
# For now, ignore MIR content and emit a trivial module.
|
||||
mod = build_trivial_module()
|
||||
os.makedirs(os.path.dirname(ns.out_path) or ".", exist_ok=True)
|
||||
emit_object(mod, ns.out_path)
|
||||
return 0
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--in", dest="infile", help="MIR JSON input", default=None)
|
||||
ap.add_argument("--out", dest="outfile", help="output object (.o)", required=True)
|
||||
args = ap.parse_args()
|
||||
|
||||
if args.infile is None:
|
||||
# Dummy path
|
||||
run_dummy(args.outfile)
|
||||
print(f"[harness] dummy object written: {args.outfile}")
|
||||
else:
|
||||
run_from_json(args.infile, args.outfile)
|
||||
print(f"[harness] object written: {args.outfile}")
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
raise SystemExit(main())
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except Exception as e:
|
||||
import traceback
|
||||
print(f"[harness] error: {e}", file=sys.stderr)
|
||||
if os.environ.get('NYASH_CLI_VERBOSE') == '1':
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
Reference in New Issue
Block a user