diff --git a/docs/development/current/main/phase152a_assignment_expr_design.md b/docs/development/current/main/phase152a_assignment_expr_design.md new file mode 100644 index 00000000..2ad56892 --- /dev/null +++ b/docs/development/current/main/phase152a_assignment_expr_design.md @@ -0,0 +1,519 @@ +# Phase 152-A: 括弧付き代入式 (x = x + 1) の Rust/Selfhost パーサ両対応 + +## 🎯 ゴール + +**Stage-3 構文として括弧付き代入式を箱化モジュール化パターンで実装** + +仕様: +- `x = expr` は statement のまま +- `(x = expr)` だけ expression として受け入れる(値は右辺と同じ) +- Rust パーサ/selfhost パーサの両方で対応 +- `shortcircuit_and_phi_skip.hako` が selfhost/Rust 両方で動作 + +目的: +- Stage-3 構文の表現力向上 +- Rust/Ny パーサの挙動統一 +- **箱化モジュール化パターン適用**(Phase 133/134-A/134-B 継承) + +## 📋 スコープ(やること・やらないこと) + +### ✅ やること +- Rust パーサ(Stage-3)の拡張: + - `factor` に `'(' assignment_expr ')'` を追加 + - **箱化**: `AssignmentExprParser` モジュール作成 + - AST に `GroupedAssignmentExpr` ノード追加 +- Selfhost パーサ(.hako 側)の拡張: + - Stage-3 受理時に同じ形を受理 + - **箱化**: `assignment_expr_parser.hako` モジュール作成 +- Lowering: + - **箱化**: `assignment_expr_lowering.rs` モジュール作成 + - 既存 assignment statement ロジック流用 + SSA Value 返却 +- テスト追加(Rust/selfhost 両方) + +### ❌ やらないこと +- `x = expr` を expression としてどこでも受け入れる拡張(文のまま) +- Stage-2 パーサや Stage-3 以外の profile の意味論変更 +- C 互換の多段代入 (`x = y = 1`) は対象外 + +--- + +## 🏗️ 6 つのタスク + +### Task 1: 仕様ドキュメント作成(設計確認) + +**ファイル**: `docs/development/current/main/phase152a_assignment_expr_design.md`(このファイル) + +**内容**: + +#### 仕様の要点 + +1. **構文定義**: + ```ebnf + assignment_expr := IDENT '=' expr + factor := ... | '(' expr ')' | '(' assignment_expr ')' + ``` + +2. **値・型**: + - `(x = e)` の値・型は `e` と同じ + - 副作用: `x` に `e` の値を代入 + +3. **使える場所の例**: + ```nyash + local y = (x = x + 1) // y と x が同じ値に + if (x = next()) != null { } // 代入して条件判定 + ``` + +4. **Gate**: + - **Rust**: `parser_stage3_enabled()` / `NYASH_FEATURES=stage3` + - **Selfhost**: `--stage3` / `NYASH_NY_COMPILER_STAGE3=1` + +5. **非対象**: + - 多段代入 `x = (y = 1)` は当面テストしない + +--- + +### Task 2: Rust パーサ対応(箱化モジュール化) + +**目的**: Rust パーサが Stage-3 ON のときだけ `(x = expr)` を expression として受け入れる + +#### 箱化モジュール設計 + +**新規ファイル**: `src/parser/stage3/assignment_expr_parser.rs`(~80行) + +**責務**: +1. `(` の直後に `IDENT '=' expr` パターンを検出 +2. `GroupedAssignmentExpr` AST ノード生成 +3. Stage-3 gate 確認 + +**実装パターン**: +```rust +// src/parser/stage3/assignment_expr_parser.rs + +pub struct AssignmentExprParser; + +impl AssignmentExprParser { + /// Parse grouped assignment expression: (x = expr) + pub fn try_parse_grouped_assignment( + tokens: &mut TokenStream, + config: &ParserConfig, + ) -> Option { + // Stage-3 gate check + if !config.is_stage3_enabled() { + return None; + } + + // Look ahead: '(' IDENT '=' ... + if !Self::is_grouped_assignment_pattern(tokens) { + return None; + } + + // Parse: '(' IDENT '=' expr ')' + tokens.expect(Token::LParen)?; + let ident = tokens.expect_identifier()?; + tokens.expect(Token::Assign)?; + let rhs = parse_expr(tokens, config)?; + tokens.expect(Token::RParen)?; + + Some(AstNode::GroupedAssignmentExpr { + lhs: ident, + rhs: Box::new(rhs) + }) + } + + fn is_grouped_assignment_pattern(tokens: &TokenStream) -> bool { + tokens.peek() == Some(&Token::LParen) && + tokens.peek_ahead(1).is_identifier() && + tokens.peek_ahead(2) == Some(&Token::Assign) + } +} +``` + +#### 既存パーサへの統合 + +**修正ファイル**: `src/parser/stage3/factor.rs` または類似 + +**修正内容**: +```rust +// Before: factor parsing +fn parse_factor(tokens: &mut TokenStream, config: &ParserConfig) -> Result { + match tokens.peek() { + Some(Token::LParen) => { + // Try grouped assignment first (Stage-3 only) + if let Some(assignment) = AssignmentExprParser::try_parse_grouped_assignment(tokens, config) { + return Ok(assignment); + } + + // Fallback: normal grouped expression + parse_grouped_expr(tokens, config) + } + // ... other factor cases + } +} +``` + +#### AST ノード追加 + +**修正ファイル**: `src/ast/mod.rs` + +**追加内容**: +```rust +pub enum AstNode { + // ... existing nodes + + /// Grouped assignment expression: (x = expr) + /// Value and type are same as rhs + GroupedAssignmentExpr { + lhs: String, // variable name + rhs: Box, // right-hand side expression + }, +} +``` + +--- + +### Task 3: Selfhost パーサ対応(箱化モジュール化) + +**目的**: Stage-3 selfhost コンパイラでも Rust パーサと同じ構文を受け入れる + +#### 箱化モジュール設計 + +**新規ファイル**: `apps/lib/parser/assignment_expr_parser.hako`(~100行) + +**責務**: +1. `(` の直後に `IDENT '=' expr` パターンを検出 +2. selfhost AST に `GroupedAssignmentExpr` 相当ノード生成 +3. Stage-3 gate 確認 + +**実装パターン**: +```nyash +// apps/lib/parser/assignment_expr_parser.hako + +static box AssignmentExprParser { + /// Try parse grouped assignment: (x = expr) + tryParseGroupedAssignment(tokens, config) { + // Stage-3 gate check + if not config.isStage3Enabled() { + return null + } + + // Look ahead: '(' IDENT '=' ... + if not me.isGroupedAssignmentPattern(tokens) { + return null + } + + // Parse: '(' IDENT '=' expr ')' + me.expectToken(tokens, TOKEN_LPAREN) + local ident = me.expectIdentifier(tokens) + me.expectToken(tokens, TOKEN_ASSIGN) + local rhs = ExprParser.parseExpr(tokens, config) + me.expectToken(tokens, TOKEN_RPAREN) + + return new GroupedAssignmentExprNode(ident, rhs) + } + + isGroupedAssignmentPattern(tokens) { + return tokens.peek() == TOKEN_LPAREN and + tokens.peekAhead(1).isIdentifier() and + tokens.peekAhead(2) == TOKEN_ASSIGN + } +} +``` + +#### 既存 selfhost パーサへの統合 + +**修正ファイル**: `apps/lib/parser/factor_parser.hako` または類似 + +**修正内容**: +```nyash +// Before: factor parsing +static box FactorParser { + parseFactor(tokens, config) { + if tokens.peek() == TOKEN_LPAREN { + // Try grouped assignment first (Stage-3 only) + local assignment = AssignmentExprParser.tryParseGroupedAssignment(tokens, config) + if assignment != null { + return assignment + } + + // Fallback: normal grouped expression + return me.parseGroupedExpr(tokens, config) + } + // ... other factor cases + } +} +``` + +--- + +### Task 4: Lowering(AST → MIR/JoinIR)箱化モジュール化 + +**目的**: `GroupedAssignmentExpr` を既存の代入文 + SSA 値返却として扱う + +#### 箱化モジュール設計 + +**新規ファイル**: `src/mir/lowering/assignment_expr_lowering.rs`(~120行) + +**責務**: +1. `GroupedAssignmentExpr` を検出 +2. 既存 assignment statement ロジック流用 +3. SSA `ValueId` を式の結果として返す + +**実装パターン**: +```rust +// src/mir/lowering/assignment_expr_lowering.rs + +pub struct AssignmentExprLowering; + +impl AssignmentExprLowering { + /// Lower grouped assignment expression: (x = expr) + /// + /// Returns SSA ValueId representing the assigned value + pub fn lower_grouped_assignment( + builder: &mut MirBuilder, + lhs: &str, + rhs: &AstNode, + ) -> Result { + // 1. Evaluate rhs expression + let rhs_value = builder.lower_expr(rhs)?; + + // 2. Assign to lhs variable (reuse existing assignment logic) + builder.lower_assignment(lhs, rhs_value)?; + + // 3. Return the same SSA value as expression result + Ok(rhs_value) + } +} +``` + +#### 既存 lowering への統合 + +**修正ファイル**: `src/mir/lowering/expr.rs` + +**修正内容**: +```rust +// Before: expression lowering +fn lower_expr(builder: &mut MirBuilder, ast: &AstNode) -> Result { + match ast { + // ... existing expression cases + + AstNode::GroupedAssignmentExpr { lhs, rhs } => { + // Delegate to assignment expression lowering module + AssignmentExprLowering::lower_grouped_assignment(builder, lhs, rhs) + } + + // ... other cases + } +} +``` + +--- + +### Task 5: テスト追加(Rust/Selfhost 両方) + +**テストケース**: + +1. **単純ケース**: `apps/tests/assignment_expr_simple.hako`(新規) + ```nyash + static box Main { + main() { + local x = 0 + local y = (x = x + 1) + return y // 期待値: RC 1 + } + } + ``` + +2. **短絡と組み合わせ**: `apps/tests/assignment_expr_shortcircuit.hako`(新規) + ```nyash + static box Main { + main() { + local x = 0 + if (x = 1) > 0 and true { + return x // 期待値: RC 1 + } + return -1 + } + } + ``` + +3. **問題再現ケース**: `apps/tests/shortcircuit_and_phi_skip.hako`(既存) + - Phase 150 で FAIL だったものが PASS になること + +**テスト実行**: + +```bash +# Rust パーサ直接実行(Stage-3 ON) +NYASH_FEATURES=stage3 ./target/release/hakorune apps/tests/assignment_expr_simple.hako + +# Selfhost 経路(Stage-3 ON) +NYASH_FEATURES=stage3 NYASH_USE_NY_COMPILER=1 NYASH_JOINIR_STRICT=1 \ + ./target/release/hakorune apps/tests/assignment_expr_simple.hako + +# Stage-3 OFF でエラー確認(既存動作維持) +./target/release/hakorune apps/tests/assignment_expr_simple.hako +# 期待: "Unexpected ASSIGN" エラー +``` + +**スモークテスト更新**: + +**修正ファイル**: `tools/smokes/v2/profiles/integration/selfhost_phase150_depth1_smoke.sh` + +**追加内容**: +```bash +# Add new test cases +CANDIDATES=( + "apps/tests/peek_expr_block.hako" + "apps/tests/loop_min_while.hako" + # ... existing cases + "apps/tests/assignment_expr_simple.hako" # NEW + "apps/tests/assignment_expr_shortcircuit.hako" # NEW + "apps/tests/shortcircuit_and_phi_skip.hako" # FIXED +) +``` + +--- + +### Task 6: ドキュメント・CURRENT_TASK 更新 + +**更新対象**: + +1. **phase152a_assignment_expr_design.md** に実装結果追記: + ```markdown + ## Phase 152-A 実装結果 + + ### 箱化モジュール作成(Phase 133/134-A/134-B パターン継承) + + **Rust 側**: + - `src/parser/stage3/assignment_expr_parser.rs` (+80行) - パーサー箱化 + - `src/mir/lowering/assignment_expr_lowering.rs` (+120行) - Lowering 箱化 + - `src/ast/mod.rs` (+10行) - AST ノード追加 + + **Selfhost 側**: + - `apps/lib/parser/assignment_expr_parser.hako` (+100行) - パーサー箱化 + + ### テスト結果 + - Rust パーサ: 3/3 PASS + - Selfhost パーサ: 3/3 PASS + - shortcircuit_and_phi_skip.hako: ✅ 修正完了 + + ### 成果 + - 括弧付き代入式の箱化モジュール化完成 + - Rust/Selfhost パーサ挙動統一 + - Stage-3 構文の表現力向上 + ``` + +2. **phase150_selfhost_stage3_depth1_results.md** の Phase 152-A セクション更新: + ```markdown + ### Phase 152-A: 括弧付き代入式対応 ✅ + + **根本原因**: Stage-3 パーサーが括弧内代入式未対応 + **解決策**: 箱化モジュール化パターンで Rust/Selfhost 両対応 + **影響ケース**: shortcircuit_and_phi_skip.hako が緑化 + ``` + +3. **CURRENT_TASK.md** に Phase 152-A 完了エントリ追加: + ```markdown + ### Phase 152-A: 括弧付き代入式(Rust/Selfhost パーサ両対応)✅ + + **完了内容**: + - 括弧付き代入式 `(x = expr)` の仕様確定 + - 箱化モジュール化パターン適用: + - AssignmentExprParser (Rust/Selfhost) + - AssignmentExprLowering (MIR) + - Rust/Selfhost パーサ挙動統一 + + **修正ファイル**: + - src/parser/stage3/assignment_expr_parser.rs (+80行) + - src/mir/lowering/assignment_expr_lowering.rs (+120行) + - apps/lib/parser/assignment_expr_parser.hako (+100行) + + **テスト結果**: 3/3 PASS(Rust/Selfhost 両方) + + **成果**: + - shortcircuit_and_phi_skip.hako 緑化 + - Stage-3 構文の表現力向上 + - 箱化モジュール化パターン確立(Phase 133/134 継承) + + **次フェーズ**: Phase 152-B - Static method テスト整理 + ``` + +4. **git commit で記録** + +--- + +## ✅ 完成チェックリスト(Phase 152-A) + +- [ ] Task 1: 仕様ドキュメント作成 + - [ ] 構文定義・値/型・使用例を明記 + - [ ] Gate(Rust/Selfhost)を明記 +- [ ] Task 2: Rust パーサ箱化モジュール実装 + - [ ] AssignmentExprParser 作成(~80行) + - [ ] factor.rs への統合(1行委譲) + - [ ] AST ノード追加 +- [ ] Task 3: Selfhost パーサ箱化モジュール実装 + - [ ] assignment_expr_parser.hako 作成(~100行) + - [ ] factor_parser.hako への統合 +- [ ] Task 4: Lowering 箱化モジュール実装 + - [ ] AssignmentExprLowering 作成(~120行) + - [ ] expr.rs への統合(1行委譲) +- [ ] Task 5: テスト追加・実行 + - [ ] assignment_expr_simple.hako: ✅ PASS + - [ ] assignment_expr_shortcircuit.hako: ✅ PASS + - [ ] shortcircuit_and_phi_skip.hako: ✅ PASS + - [ ] スモークテスト更新 +- [ ] Task 6: ドキュメント更新 + - [ ] phase152a_assignment_expr_design.md 完成 + - [ ] phase150_selfhost_stage3_depth1_results.md 更新 + - [ ] CURRENT_TASK.md 更新 + - [ ] git commit で記録 + +--- + +## 所要時間 + +**5-6 時間程度** + +- Task 1(仕様ドキュメント): 30分 +- Task 2(Rust パーサ箱化): 1.5時間 +- Task 3(Selfhost パーサ箱化): 1.5時間 +- Task 4(Lowering 箱化): 1時間 +- Task 5(テスト追加・実行): 1時間 +- Task 6(ドキュメント): 30分 + +--- + +## 箱化モジュール化パターン継承 + +Phase 152-A は **Phase 133/134-A/134-B で確立した箱化モジュール化パターン**を継承: + +| Phase | 箱化対象 | 専用モジュール | 統合先 | +|-------|---------|--------------|--------| +| 133 | ConsoleBox methods | `console_bridge.py` | `boxcall.py` (1行委譲) | +| 134-A | MIR Call | `mir_call/*.py` | `llvm_builder.py` (1行委譲) | +| 134-B | StringBox methods | `stringbox.py` | `boxcall.py` (1行委譲) | +| **152-A** | **Assignment Expr** | **`assignment_expr_parser.rs/hako`** | **`factor.rs` (1行委譲)** | + +**箱化の利点**: +- 責務分離(パーサ/Lowering が肥大化しない) +- テスタビリティ向上(単体テスト可能) +- 保守性向上(変更影響範囲が明確) +- Rust/Selfhost 対応統一(同じパターン適用) + +--- + +## 次のステップ + +**Phase 152-B: Static method テスト整理** +- `stage1_run_min.hako` を static box スタイルに書き換え +- legacy `static method` 構文を削除 + +--- + +## 進捗 + +- ✅ Phase 130-134: LLVM Python バックエンド整理 +- ✅ Phase 150: Selfhost Stage-3 Depth-1 ベースライン強化 +- ✅ Phase 151: ConsoleBox Selfhost Support +- 🎯 Phase 152-A: 括弧付き代入式(Rust/Selfhost パーサ両対応)(← **現在のフェーズ**) +- 📋 Phase 152-B: Static method テスト整理(予定) +