docs: restore docs/private/roadmap from 7b4908f9 (Phase 20.31)

This commit is contained in:
nyash-codex
2025-10-31 18:00:10 +09:00
parent 1d49e24bf0
commit 8fd3a2b509
433 changed files with 108935 additions and 0 deletions

View File

@ -0,0 +1,121 @@
# Parser Integration - Pythonパーサー統合
## 📋 概要
PythonのAST抽象構文木をHakoruneで扱うためのパーサー統合設計です。
## 📁 ファイル一覧
### 実装計画
- **[implementation-plan.md](implementation-plan.md)** - PythonパーサーBox実装計画
- **[builtin-box-flow.md](builtin-box-flow.md)** - ビルトインBox実装フロー
## 🎯 目的
### PythonパーサーBoxの役割
1. **Python AST解析**
- Pythonコードをパース
- AST抽象構文木を生成
- Hakorune内で操作可能な形式に変換
2. **型推論・スコープ解決**
- Python動的型の静的解析
- スコープ情報の抽出
- 型アノテーション活用
3. **Hakorune MIRへの変換**
- Python AST → Hakorune AST
- Hakorune AST → MIR
- 最適化情報の付与
## 🏗️ アーキテクチャ
### PythonParserBox計画
```hakorune
box PythonParserBox {
// パース
parse(code: StringBox) -> ASTBox
// AST操作
visit_nodes(ast: ASTBox, visitor: FunctionBox)
get_node_type(node: ASTBox) -> StringBox
// 変換
to_hakorune_ast(ast: ASTBox) -> HakoruneASTBox
to_mir(ast: ASTBox) -> MIRBox
}
```
### ビルトインBox統合フロー
1. **パーサー初期化**
- CPython APIの初期化
- パーサーモジュールのロード
2. **パース実行**
- コード文字列を受け取り
- Python ASTを生成
- エラーハンドリング
3. **AST変換**
- Python AST → Hakorune AST
- 型情報の付与
- スコープ情報の追加
4. **MIR生成**
- Hakorune AST → MIR
- 最適化パスの適用
## 🔧 技術的課題
### 1. Python AST API統合
- CPython C API使用
- `ast` モジュールとの連携
- メモリ管理(参照カウント)
### 2. 型推論
- Python動的型の静的解析
- 型アノテーション活用
- 型推論アルゴリズム
### 3. スコープ解決
- PythonのスコープルールLEGB
- Hakoruneスコープへのマッピング
- クロージャ・ネストスコープ対応
### 4. 構文マッピング
- Python構文 → Hakorune構文
- イディオム変換
- サポートする機能範囲の決定
## 📊 実装ステータス
| コンポーネント | ステータス | 備考 |
|--------------|----------|------|
| パーサーBox設計 | ✅ 完了 | 設計書完成 |
| CPython API統合 | 📅 未実装 | - |
| AST変換 | 📅 未実装 | - |
| 型推論 | 📅 未実装 | - |
| MIR生成 | 📅 未実装 | - |
## ⚠️ リスク要因
1. **CPython依存**
- CPythonバージョン互換性
- プラットフォーム固有の問題
2. **型推論の精度**
- Python動的型の限界
- 型アノテーションの不完全性
3. **パフォーマンス**
- パース・変換のオーバーヘッド
- 大規模コードベースでの性能
## 🔗 関連ドキュメント
- [Phase 20 メインREADME](../README.md)
- [Planning](../planning/)
- [Core Implementation](../core-implementation/)

View File

@ -0,0 +1,553 @@
# PythonParserBox ビルトインBox実装フローエキスパート統合版
CPythonパーサー統合とPhase 1実装の具体的な流れ
更新日: 2025-08-27
## 🎯 全体の実装フロー
### Step 0: Python 3.11固定(エキスパート推奨)
```
- Python 3.11.9を使用AST安定性確保
- pyenvまたはpython3.11コマンドで固定
- py_versionとast_formatをJSON IRに必ず含める
```
### Step 1: ビルトインBoxとしての基盤作成
```
1. src/boxes/python_parser_box/mod.rs を作成
2. BoxBase + BoxCore統一アーキテクチャに準拠
3. PythonParserBoxの基本構造を定義
4. src/boxes/mod.rs に登録
5. テレメトリー基盤を初期から組み込む
```
### Step 2: pyo3統合とCPythonパーサー接続
```
1. Cargo.tomlに pyo3依存関係追加
2. pyo3::prepare_freethreaded_python()で一度だけ初期化
3. ast.parse()へのFFIブリッジ実装
4. JSON中間表現への変換Python側でJSON生成
5. GILは最小限に、py.allow_threads()でRust処理
```
### Step 3: Phase 1機能の実装必須意味論要素
```
必須要素Codex先生強調:
- LEGBスコーピング + locals/freevars
- デフォルト引数の定義時評価
- イテレータプロトコルfor文
- for/else + while/else
- Python真偽値判定
- 短絡評価and/or
実装手順:
1. 関数単位フォールバック戦略の実装
2. 基本的なAST変換def, if, for, while, return
3. 式の変換(算術/比較/論理演算子、関数呼び出し)
4. Nyash ASTへの意味論を保ったマッピング
5. Differential Testingフレームワーク
```
## 📝 具体的な実装コード
### 1. ビルトインBox定義src/boxes/python_parser_box/mod.rs
```rust
use crate::core::{BoxBase, BoxCore, NyashBox};
use crate::ast;
use pyo3::prelude::*;
use std::sync::{Arc, Mutex};
pub struct PythonParserBox {
base: BoxBase,
py_helper: Arc<Mutex<PyHelper>>, // Python実行環境
}
impl BoxCore for PythonParserBox {
fn box_id(&self) -> u64 {
self.base.box_id()
}
fn parent_type_id(&self) -> Option<std::any::TypeId> {
self.base.parent_type_id()
}
fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "PythonParserBox#{}", self.box_id())
}
}
impl NyashBox for PythonParserBox {
fn type_name(&self) -> &'static str {
"PythonParserBox"
}
fn clone_box(&self) -> Box<dyn NyashBox> {
Box::new(PythonParserBox {
base: BoxBase::new(),
py_helper: self.py_helper.clone(),
})
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}
```
### 2. メソッド実装Phase 1対応
```rust
// テレメトリー用構造体
#[derive(Default)]
pub struct CompilationTelemetry {
compiled_functions: Vec<String>,
fallback_functions: Vec<(String, String, usize)>, // (name, reason, lineno)
unsupported_nodes: HashMap<String, usize>, // node_type -> count
}
impl PythonParserBox {
// コンストラクタ
pub fn new() -> Result<Self, String> {
// 一度だけ初期化
static INIT: std::sync::Once = std::sync::Once::new();
INIT.call_once(|| {
pyo3::prepare_freethreaded_python();
});
// Python環境の初期化
Python::with_gil(|py| {
// Python 3.11確認
let version = py.version_info();
if version.major != 3 || version.minor != 11 {
return Err(format!("Python 3.11 required, got {}.{}",
version.major, version.minor));
}
let helper = PyHelper::new(py)?;
Ok(PythonParserBox {
base: BoxBase::new(),
py_helper: Arc::new(Mutex::new(helper)),
})
})
}
// Python code → JSON AST
pub fn parse_to_json(&self, code: &str) -> Result<String, String> {
let helper = self.py_helper.lock().unwrap();
Python::with_gil(|py| {
helper.parse_to_json(py, code)
})
}
// JSON AST → Nyash ASTPhase 1機能のみ
pub fn json_to_nyash_ast(&self, json: &str) -> Result<ast::Program, String> {
let py_ast: Phase1PythonAst = serde_json::from_str(json)
.map_err(|e| format!("JSON parse error: {}", e))?;
let converter = Phase1Converter::new();
converter.convert(py_ast)
}
// 直接実行(関数単位フォールバック)
pub fn run(&self, code: &str) -> Result<Box<dyn NyashBox>, String> {
// まずJSON ASTを取得
let json_ast = self.parse_to_json(code)?;
let py_ast: serde_json::Value = serde_json::from_str(&json_ast)?;
// モジュール内の各関数をチェック
let compiler = FunctionCompiler::new();
let module_result = compiler.compile_module(&py_ast)?;
// テレメトリー出力(環境変数で制御)
if std::env::var("NYASH_PYTHONPARSER_TELEMETRY").is_ok() {
compiler.print_telemetry();
}
// 実行コンパイル済み関数はMIR、他はCPython
module_result.execute()
}
}
```
### 3. Python側ヘルパー実装
```rust
// Pythonコードを文字列として埋め込み
const PYTHON_HELPER_CODE: &str = r#"
import ast
import json
import sys
# Python 3.11固定チェック
assert sys.version_info[:2] == (3, 11), f"Python 3.11 required, got {sys.version}"
def ast_to_dict(node):
"""Phase 1: 基本的なAST要素のみ変換エキスパート推奨JSON IR"""
result = {
"node_type": node.__class__.__name__,
"py_version": "3.11",
"ast_format": "v1"
}
# 位置情報(エラー診断用)
if hasattr(node, 'lineno'):
result['lineno'] = node.lineno
result['col_offset'] = node.col_offset
if hasattr(node, 'end_lineno'):
result['end_lineno'] = node.end_lineno
result['end_col_offset'] = node.end_col_offset
if isinstance(node, ast.Module):
return {
"type": "Module",
"body": [ast_to_dict(stmt) for stmt in node.body]
}
elif isinstance(node, ast.FunctionDef):
# 意味論上重要:デフォルト引数情報を保存
args_info = {
"args": [arg.arg for arg in node.args.args],
"defaults": [ast_to_dict(default) for default in node.args.defaults],
"kwonlyargs": [arg.arg for arg in node.args.kwonlyargs],
"kw_defaults": [ast_to_dict(d) if d else None for d in node.args.kw_defaults]
}
result.update({
"name": node.name,
"args": args_info,
"body": [ast_to_dict(stmt) for stmt in node.body],
"decorator_list": [], # Phase 1では未対応
"support_level": "full" # コンパイル可能
})
return result
elif isinstance(node, ast.Return):
return {
"type": "Return",
"value": ast_to_dict(node.value) if node.value else None
}
elif isinstance(node, ast.BinOp):
return {
"type": "BinOp",
"op": node.op.__class__.__name__,
"left": ast_to_dict(node.left),
"right": ast_to_dict(node.right)
}
elif isinstance(node, ast.Call):
return {
"type": "Call",
"func": ast_to_dict(node.func),
"args": [ast_to_dict(arg) for arg in node.args]
}
elif isinstance(node, ast.Name):
return {
"type": "Name",
"id": node.id
}
elif isinstance(node, ast.Constant):
return {
"type": "Constant",
"value": node.value
}
elif isinstance(node, ast.If):
return {
"type": "If",
"test": ast_to_dict(node.test),
"body": [ast_to_dict(stmt) for stmt in node.body],
"orelse": [ast_to_dict(stmt) for stmt in node.orelse]
}
elif isinstance(node, ast.For):
# 意味論上重要for/else構文
result.update({
"target": ast_to_dict(node.target),
"iter": ast_to_dict(node.iter),
"body": [ast_to_dict(stmt) for stmt in node.body],
"orelse": [ast_to_dict(stmt) for stmt in node.orelse], # else節
"support_level": "full"
})
return result
elif isinstance(node, ast.While):
# 意味論上重要while/else構文
result.update({
"test": ast_to_dict(node.test),
"body": [ast_to_dict(stmt) for stmt in node.body],
"orelse": [ast_to_dict(stmt) for stmt in node.orelse], # else節
"support_level": "full"
})
return result
elif isinstance(node, ast.BoolOp):
# 意味論上重要:短絡評価
result.update({
"op": node.op.__class__.__name__, # And, Or
"values": [ast_to_dict(v) for v in node.values],
"support_level": "full"
})
return result
else:
# Phase 1では未対応テレメトリー用
return {
"node_type": "Unsupported",
"original_type": type(node).__name__,
"support_level": "fallback",
"lineno": getattr(node, 'lineno', -1)
}
def parse_to_json(code):
try:
tree = ast.parse(code)
return json.dumps(ast_to_dict(tree))
except Exception as e:
return json.dumps({"type": "Error", "message": str(e)})
"#;
struct PyHelper {
// Python側のヘルパー関数への参照を保持
parse_func: PyObject,
}
impl PyHelper {
fn new(py: Python) -> PyResult<Self> {
// ヘルパーコードをPythonで実行
let helpers = PyModule::from_code(py, PYTHON_HELPER_CODE, "helper.py", "helper")?;
let parse_func = helpers.getattr("parse_to_json")?.to_object(py);
Ok(PyHelper { parse_func })
}
fn parse_to_json(&self, py: Python, code: &str) -> Result<String, String> {
match self.parse_func.call1(py, (code,)) {
Ok(result) => result.extract::<String>(py)
.map_err(|e| format!("Extract error: {}", e)),
Err(e) => Err(format!("Parse error: {}", e))
}
}
}
```
### 4. Phase 1 AST変換器
```rust
struct Phase1Converter;
impl Phase1Converter {
fn new() -> Self {
Phase1Converter
}
fn convert(&self, py_ast: Phase1PythonAst) -> Result<ast::Program, String> {
match py_ast {
Phase1PythonAst::Module { body } => {
let mut items = vec![];
for stmt in body {
match self.convert_statement(stmt)? {
Some(item) => items.push(item),
None => {} // 未対応要素はスキップ
}
}
Ok(ast::Program { items })
}
_ => Err("Expected Module at top level".into())
}
}
fn convert_statement(&self, stmt: Phase1PythonAst) -> Result<Option<ast::ProgramItem>, String> {
match stmt {
Phase1PythonAst::FunctionDef { name, args, body } => {
// Python def → Nyash function
let params = args.into_iter()
.map(|arg| ast::Parameter { name: arg, ty: None })
.collect();
let nyash_body = self.convert_body(body)?;
Ok(Some(ast::ProgramItem::Function(ast::FunctionDef {
name,
params,
body: nyash_body,
return_type: None,
})))
}
Phase1PythonAst::Return { value } => {
let expr = value
.map(|v| self.convert_expression(v))
.transpose()?;
Ok(Some(ast::ProgramItem::Statement(ast::Statement::Return(expr))))
}
// 他の文も同様に変換
_ => Ok(None) // Phase 1では未対応
}
}
fn convert_expression(&self, expr: Phase1PythonAst) -> Result<ast::Expression, String> {
match expr {
Phase1PythonAst::BinOp { op, left, right } => {
let left = Box::new(self.convert_expression(*left)?);
let right = Box::new(self.convert_expression(*right)?);
let op = match op.as_str() {
"Add" => ast::BinaryOp::Add,
"Sub" => ast::BinaryOp::Sub,
"Mul" => ast::BinaryOp::Mul,
"Div" => ast::BinaryOp::Div,
_ => return Err(format!("Unsupported operator: {}", op))
};
Ok(ast::Expression::BinaryOp { op, left, right })
}
Phase1PythonAst::Constant { value } => {
// Python定数 → Nyashリテラル
match value {
serde_json::Value::Number(n) => {
if let Some(i) = n.as_i64() {
Ok(ast::Expression::Integer(i))
} else if let Some(f) = n.as_f64() {
Ok(ast::Expression::Float(f))
} else {
Err("Unsupported number type".into())
}
}
serde_json::Value::String(s) => {
Ok(ast::Expression::String(s))
}
serde_json::Value::Bool(b) => {
Ok(ast::Expression::Bool(b))
}
_ => Err("Unsupported constant type".into())
}
}
// 他の式も同様
_ => Err("Unsupported expression in Phase 1".into())
}
}
}
```
### 5. インタープリター統合src/interpreter/builtins.rs
```rust
// ビルトインBox登録に追加
pub fn register_builtin_boxes(env: &mut Environment) {
// 既存のBox登録...
// PythonParserBox追加
env.register_builtin_box("PythonParserBox", || {
match PythonParserBox::new() {
Ok(parser) => Arc::new(parser) as Arc<dyn NyashBox>,
Err(e) => panic!("Failed to initialize PythonParserBox: {}", e)
}
});
}
```
### 6. 使用例とテストケース
```nyash
// test_python_parser_phase1.nyash
local py = new PythonParserBox()
// Phase 1: 基本的な関数定義と演算
local code = """
def add(x, y):
return x + y
def multiply(x, y):
return x * y
def calculate(a, b):
sum_val = add(a, b)
prod_val = multiply(a, b)
return sum_val + prod_val
"""
// パースしてJSON ASTを確認
local json_ast = py.parse_to_json(code)
print("JSON AST: " + json_ast)
// Nyash ASTに変換
local nyash_ast = py.json_to_nyash_ast(json_ast)
print("Conversion successful!")
// 実行最初はCPython経由
local result = py.run(code + "\nprint(calculate(10, 5))")
```
## 📊 段階的な実装計画
### Week 1: 基盤構築
- [ ] PythonParserBoxの基本構造
- [ ] pyo3統合とPython環境初期化
- [ ] parse_to_json基本実装
- [ ] エラーハンドリング
### Week 2: Phase 1変換器
- [ ] Phase1PythonAstの定義
- [ ] Phase1Converterの実装
- [ ] 基本的な文と式の変換
- [ ] テストケース作成
### Week 3: 統合とテスト
- [ ] インタープリター統合
- [ ] CPython exec経由の実行
- [ ] ベンチマーク準備
- [ ] ドキュメント整備
## 🚀 期待される成果
### Phase 1完了時点で実現できること
1. **基本的なPythonコードの実行**
- 関数定義、算術演算、条件分岐、ループ
2. **Nyash ASTへの変換**
- 将来のMIR/JIT最適化への道筋
3. **統合開発環境**
- PythonコードとNyashコードの混在実行
4. **性能測定基盤**
- CPython実行 vs Nyash実行の比較
## 📡 テレメトリー出力例
```bash
# 環境変数で制御
export NYASH_PYTHONPARSER_TELEMETRY=1 # 基本統計
export NYASH_PYTHONPARSER_TELEMETRY=2 # 詳細ログ
export NYASH_PYTHONPARSER_STRICT=1 # フォールバック時にパニック
# 実行例
./target/release/nyash test_python_parser.nyash
# 出力
[PythonParser] Module: test.py (Python 3.11)
Functions: 10 total
Compiled: 7 (70%) → Nyash MIR/JIT
Fallback: 3 (30%) → CPython exec
- async_function: unsupported node 'AsyncFunctionDef' at line 23
- generator_func: unsupported node 'Yield' at line 45
- decorator_func: unsupported node 'decorator_list' at line 67
Unsupported Nodes Summary:
AsyncFunctionDef: 1
Yield: 2
ClassDef: 1
```
## 📊 Differential Testingフレームワーク
```rust
// CPythonとNyashの出力比較
pub fn differential_test(code: &str) -> TestResult {
// CPythonで実行オラクル
let python_result = Python::with_gil(|py| {
capture_python_execution(py, code)
})?;
// Nyashで実行
let nyash_result = execute_with_pythonparser(code)?;
// 結果比較
compare_results(python_result, nyash_result)
}
```
---
作成日: 2025-08-27
Phase 1実装の具体的な手順とエキスパートフィードバック統合

View File

@ -0,0 +1,361 @@
# PythonParserBox実装計画統合版
更新日: 2025-08-27
## 🎯 エキスパートからの統合フィードバック
### 最重要ポイント(両エキスパートが一致)
1. **関数単位のフォールバック戦略**
- ファイル全体でなく関数レベルでコンパイル/フォールバックを切り替え
- 未対応機能を含む関数はCPython exec、対応済み関数はNyash MIR/JIT
2. **Python 3.11固定**
- AST安定性の確保3.8 Constant統一、3.10 match/case、3.12位置情報)
- `py_version``ast_format`をJSON IRに埋め込む
3. **意味論の正確な実装が最優先**
- 最適化より先にPython互換性を確保
- 特に: イテレータプロトコル、真偽値判定、スコーピング規則LEGB
4. **GIL管理の最小化**
- Python側でJSON生成`ast.NodeVisitor` + `json.dumps`
- Rust側で解析GIL外で実行
- `py.allow_threads(|| { ... })`で重い処理をGIL外実行
5. **テレメトリー重視**
- 未対応ノードの記録(`support_level`フィールド)
- フォールバック率の計測
- ソース位置情報の保持(`lineno/col_offset/end_*`
### Differential Testing戦略
- **世界中のPythonコードがNyashのテストケース**
- CPythonを「オラクル」として使用
- 出力、戻り値、例外を比較
- Grammar-based fuzzingHypothesis活用
## 技術的実装方針
### 1. CPythonパーサー統合pyo3使用
```rust
// Cargo.toml
[dependencies]
pyo3 = { version = "0.22", features = ["auto-initialize"] }
pyo3-numpy = "0.22" // NumPy連携用
// 初期化(一度だけ)
pyo3::prepare_freethreaded_python();
// Python側ヘルパーembedded
const PYTHON_HELPER: &str = r#"
import ast
import json
import sys
def parse_to_json(code, filename="<string>", mode="exec"):
tree = ast.parse(code, filename, mode)
return json.dumps(ast_to_dict(tree))
def ast_to_dict(node):
result = {}
# 必須フィールド
result['node_type'] = node.__class__.__name__
result['py_version'] = f"{sys.version_info.major}.{sys.version_info.minor}"
# 位置情報(エラー診断用)
if hasattr(node, 'lineno'):
result['lineno'] = node.lineno
result['col_offset'] = node.col_offset
if hasattr(node, 'end_lineno'): # Python 3.8+
result['end_lineno'] = node.end_lineno
result['end_col_offset'] = node.end_col_offset
# サポートレベルNyash側で設定
result['support_level'] = 'unknown'
# ASTフィールド
if isinstance(node, ast.AST):
for field in node._fields:
value = getattr(node, field)
result[field] = ast_to_dict(value)
elif isinstance(node, list):
return [ast_to_dict(x) for x in node]
else:
return node
return result
"#;
```
### 2. 最小実装セットPhase 1: Must-Have
```
Phase 1 意味論の必須要素Codex先生強調:
- LEGB + locals/freevarsスコーピング
- デフォルト引数の評価タイミング(定義時)
- イテレータベースのfor文
- for/else + while/elsePython独特
- Python真偽値判定__bool__ → __len__
- 短絡評価and/or
Phase 1 AST構造:
├─ Module (py_version, ast_format)
├─ FunctionDef (name, args, body, decorator_list=[])
│ └─ arguments (args, defaults, kwonlyargs=[], kw_defaults=[])
├─ Return (value)
├─ Assign (targets, value)
├─ AugAssign (target, op, value) # +=, -=等
└─ Expr (value)
Phase 1 式:
├─ BinOp (left, op, right)
│ └─ ops: Add, Sub, Mult, Div, FloorDiv, Mod, Pow
├─ Compare (left, ops, comparators)
│ └─ ops: Eq, NotEq, Lt, LtE, Gt, GtE, Is, IsNot
├─ BoolOp (op, values) # and/or
├─ UnaryOp (op, operand) # not, -, +
├─ Call (func, args, keywords=[])
├─ Name (id, ctx=Load/Store/Del)
├─ Constant (value) # Python 3.8+統一
└─ IfExp (test, body, orelse) # 三項演算子
Phase 1 制御フロー:
├─ If (test, body, orelse)
├─ While (test, body, orelse) # else節対応必須
├─ For (target, iter, body, orelse) # else節対応必須
├─ Break
└─ Continue
```
### 3. 関数単位フォールバック戦略
```rust
// 関数単位のコンパイル判定
pub struct FunctionCompiler {
supported_nodes: HashSet<&'static str>,
telemetry: CompilationTelemetry,
}
impl FunctionCompiler {
pub fn can_compile(&self, func_def: &PythonAst) -> CompileResult {
let mut visitor = SupportChecker::new(&self.supported_nodes);
visitor.visit(func_def);
if visitor.has_unsupported() {
// CPython execへフォールバック
CompileResult::Fallback {
reason: visitor.unsupported_nodes(),
location: func_def.location(),
}
} else {
// Nyash MIR/JITへコンパイル
CompileResult::Compile
}
}
pub fn compile_module(&mut self, module: &PythonAst) -> ModuleUnit {
let mut units = vec![];
// モジュールトップレベルはPythonで実行globals設定
units.push(ExecutionUnit::PythonExec(module.top_level));
// 各関数を判定
for func in module.functions() {
match self.can_compile(func) {
CompileResult::Compile => {
let mir = self.compile_to_mir(func);
units.push(ExecutionUnit::NyashFunction(mir));
self.telemetry.record_compiled(func.name);
}
CompileResult::Fallback { reason, location } => {
units.push(ExecutionUnit::PythonThunk(func));
self.telemetry.record_fallback(func.name, reason, location);
}
}
}
ModuleUnit { units }
}
}
```
### 4. データ共有戦略
```rust
// NdArrayBox定義
pub struct NdArrayBox {
base: BoxBase,
py_array: Py<PyArray<f64, Dim<[usize; 2]>>>, // Python側の参照保持
// 操作時のみGIL取得してArrayViewを取る
}
impl NdArrayBox {
pub fn to_view(&self) -> PyResult<ArrayView2<f64>> {
Python::with_gil(|py| {
let array = self.py_array.as_ref(py);
Ok(array.readonly())
})
}
}
```
### 4. 実装ロードマップ
#### Phase 1: パーサー統合1-2週間
- [ ] pyo3セットアップとPythonParserBox骨格
- [ ] Python側parse_to_jsonヘルパー実装
- [ ] JSON→Nyash AST最小変換
- [ ] run()メソッドCPython exec委譲
- [ ] 例外変換PyErr → NyashError
#### Phase 2: MIR変換2-4週間
- [ ] AST→MIR変換器最小セット
- [ ] 数値演算プリミティブ実装
- [ ] スコープ解決(関数ローカル/グローバル)
- [ ] 基本的な制御フローIf/While
#### Phase 3: NumPy統合並行可能
- [ ] pyo3-numpy統合
- [ ] NdArrayBox実装
- [ ] ゼロコピーベンチマーク
- [ ] バッファプロトコル対応
#### Phase 4: 最適化と拡張
- [ ] 型特化とガード最適化
- [ ] 例外処理try/except
- [ ] クラス/メソッド対応
- [ ] import統合
## 性能目標(現実的な見積もり)
| コードタイプ | 期待される高速化 | 備考 |
|------------|----------------|------|
| 純Pythonループ | 2-10倍 | 型安定なホットパス |
| 関数呼び出し多 | 1.5-3倍 | インライン化効果 |
| NumPy処理中心 | 1.0-1.2倍 | 既に最適化済み |
| 動的特性多用 | 1.2-3倍 | ガード頻発で限定的 |
## 実装上の注意点(エキスパート推奨)
### 意味論の重要な違いPhase 1で対応必須
1. **制御フロー**
- `for`文: イテレータプロトコル必須(`__iter__`/`__next__`
- `for/else`, `while/else`: breakしなかった場合のelse実行
- 短絡評価: `and`は左がFalseなら右を評価しない
2. **スコープ規則LEGB**
```python
# Local → Enclosing → Global → Builtins
global_var = 1
def outer():
enclosing_var = 2
def inner():
local_var = 3
nonlocal enclosing_var # 明示的な宣言
global global_var # 明示的な宣言
```
3. **数値演算の違い**
- `/`: Python 3では常にfloattrue division
- `//`: floor division整数除算
- 大整数: デフォルトで無限精度
- `is` vs `==`: オブジェクト同一性 vs 値の等価性
4. **関数定義の罠**
```python
def f(x, y=[]): # デフォルト引数は定義時に1度だけ評価
y.append(x) # 全呼び出しで同じリストを共有
return y
```
### GIL管理のベストプラクティス
```rust
// ❌ 悪い例: GILを長時間保持
let result = Python::with_gil(|py| {
let ast = parse_python(py, code)?;
let json = convert_to_json(py, ast)?; // ここまでGIL必要
let nyash_ast = parse_json(&json)?; // GIL不要なのに保持
compile_to_mir(nyash_ast)? // GIL不要なのに保持
});
// ✅ 良い例: GILを最小限に
let json = Python::with_gil(|py| {
let ast = parse_python(py, code)?;
convert_to_json(py, ast) // JSON生成まで
})?;
// GIL外で重い処理
let nyash_ast = parse_json(&json)?;
let mir = compile_to_mir(nyash_ast)?;
// 必要時のみ再取得
Python::with_gil(|py| {
py.allow_threads(|| {
// 時間のかかるRust処理
optimize_mir(mir)
})
})
```
### テレメトリーとデバッグ
```rust
// 環境変数で制御
NYASH_PYTHONPARSER_TELEMETRY=1 # 基本統計
NYASH_PYTHONPARSER_TELEMETRY=2 # 詳細ログ
NYASH_PYTHONPARSER_STRICT=1 # フォールバック時にパニックCI用
// 出力例
[PythonParser] Module: example.py
Functions: 10 total
Compiled: 7 (70%)
Fallback: 3 (30%)
- async_function: unsupported node 'AsyncFunctionDef' at line 23
- generator_func: unsupported node 'Yield' at line 45
- class_method: unsupported node 'ClassDef' at line 67
```
## 次のステップ
### 即座に開始すべきこと
1. **Python 3.11環境固定**
```bash
pyenv install 3.11.9
pyenv local 3.11.9
```
2. **最小動作確認**
```python
# test_minimal.py
def add(x, y):
return x + y
result = add(10, 5)
print(f"Result: {result}") # → Nyashで15が出力されれば成功
```
3. **テレメトリー基盤構築**
- 未対応ノードの記録システム
- フォールバック率の可視化
- ソース位置情報の保持
4. **Differential Testingの準備**
- CPythonとの出力比較フレームワーク
- 標準出力、戻り値、例外のキャプチャ
- テストコーパスの選定
### 成功の測定基準
| フェーズ | 目標 | 測定指標 |
|---------|------|----------|
| Phase 1 | 基本動作 | 簡単な数値計算の70%がコンパイル可能 |
| Phase 2 | 実用性 | scikit-learnの基本アルゴリズムが動作 |
| Phase 3 | 性能 | 純Pythonループで5倍以上の高速化 |
| Phase 4 | 成熟度 | PyPIトップ100の30%が基本動作 |
## まとめ
このPythonParserBox実装は、単なる機能追加ではなく、Nyash言語の成熟度を飛躍的に高める戦略的プロジェクト。
エキスパートの指摘を踏まえ、関数単位のフォールバック、Python 3.11固定、意味論の正確な実装、
GIL最小化、テレメトリー重視で着実に実装を進める。