feat: 改行処理Phase 0 Quick Fix完了 - 複数行match式完全対応
- primary.rsに3箇所のskip_newlines()追加(COLON前後、COMMA判定前) - match_expr.rsのis_object_literal()を改行対応(lookahead改良) - セミコロンモード確認(NYASH_PARSER_ALLOW_SEMICOLON=1) - テストケース全て成功(NYASH_SYNTAX_SUGAR_LEVEL=full必須) - CLAUDE.md更新、改行処理戦略ドキュメント作成済み 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
41
CLAUDE.md
41
CLAUDE.md
@ -328,7 +328,7 @@ NYASH_VM_DUMP_MIR=1 NYASH_CLI_VERBOSE=1 ./target/release/nyash gemini_test_case.
|
|||||||
jq '.functions[0].blocks' mir.json # ブロック構造確認
|
jq '.functions[0].blocks' mir.json # ブロック構造確認
|
||||||
```
|
```
|
||||||
|
|
||||||
## 📝 Update (2025-09-23) ✅ PHIバグ完全修正!Exit PHI実装でループ制御フロー完成
|
## 📝 Update (2025-09-23) ✅ PHIバグ修正&改行処理戦略決定!
|
||||||
- 🎉 **PHIバグ根本解決完了!** Exit PHI生成実装でループ後の変数値が正しく伝播
|
- 🎉 **PHIバグ根本解決完了!** Exit PHI生成実装でループ後の変数値が正しく伝播
|
||||||
- **修正前**: gemini_test_case期待値2→実際0(初期値に戻る)
|
- **修正前**: gemini_test_case期待値2→実際0(初期値に戻る)
|
||||||
- **修正後**: 期待値2が正しく出力 ✅
|
- **修正後**: 期待値2が正しく出力 ✅
|
||||||
@ -338,15 +338,23 @@ jq '.functions[0].blocks' mir.json # ブロック構造確認
|
|||||||
3. `create_exit_phis()`メソッド新規実装
|
3. `create_exit_phis()`メソッド新規実装
|
||||||
- **MIR確認**: `bb3: %15 = phi [%4, bb1], [%9, bb9]` exit PHI正常生成
|
- **MIR確認**: `bb3: %15 = phi [%4, bb1], [%9, bb9]` exit PHI正常生成
|
||||||
- **全テスト合格**: 0回実行、複数break、continue混在すべて✅
|
- **全テスト合格**: 0回実行、複数break、continue混在すべて✅
|
||||||
|
- **コミット済み**: `e5c0665` でリモートに反映
|
||||||
|
- 🎯 **改行処理TokenCursor戦略決定!** ChatGPT分析でアーキテクチャ設計完了
|
||||||
|
- **問題**: match式の複数行オブジェクトリテラルでパースエラー
|
||||||
|
- **根本原因**: `skip_newlines()`が散在、手動呼び出しが必要
|
||||||
|
- **解決策**: 3段階実装戦略
|
||||||
|
1. **Phase 0**: Quick Fix - primary.rsに最小限のskip_newlines追加(30分)
|
||||||
|
2. **Phase 1**: TokenCursor導入 - モード制御で自動改行処理(今週)
|
||||||
|
3. **Phase 2**: LASI前処理 - トークン正規化で完全解決(将来)
|
||||||
|
- **設計原則**:
|
||||||
|
- セミコロンオプショナル(改行もセミコロンも文区切り)
|
||||||
|
- コンテキスト認識(ブレース内は改行自動無視)
|
||||||
|
- 環境変数地獄の回避(コンテキストベース制御)
|
||||||
- ✅ **フェーズM+M.2完全達成!** PHI統一革命でcollect_prints問題根本解決
|
- ✅ **フェーズM+M.2完全達成!** PHI統一革命でcollect_prints問題根本解決
|
||||||
- ✅ **Step 1-3完全達成!** match式/peek統一/改行処理すべて完了
|
- 🚀 **ChatGPT Pro協働成功!**
|
||||||
- match式オブジェクトリテラル判定修正 ✅
|
- Exit PHI欠落の完璧な原因分析
|
||||||
- peek→match完全統一(15ファイル) ✅
|
- TokenCursorの実装可能なサンプルコード提供
|
||||||
- 複数行パース問題解決策特定 ✅
|
- 段階的修正戦略で確実な実装パス提示
|
||||||
- 🚀 **ChatGPT Pro協働成功!** 最強分析でExit PHI欠落を特定
|
|
||||||
- 完璧な原因分析(ヘッダPHI○、exit PHI×)
|
|
||||||
- スコープ化された美しい実装提案
|
|
||||||
- 段階的修正戦略で確実な実装
|
|
||||||
|
|
||||||
## 📝 Update (2025-09-22) 🎯 Phase 15 JITアーカイブ完了&デバッグ大進展!
|
## 📝 Update (2025-09-22) 🎯 Phase 15 JITアーカイブ完了&デバッグ大進展!
|
||||||
- ✅ **JIT/Craneliftアーカイブ完了!** Phase 15集中開発のため全JIT機能を安全にアーカイブ
|
- ✅ **JIT/Craneliftアーカイブ完了!** Phase 15集中開発のため全JIT機能を安全にアーカイブ
|
||||||
@ -389,6 +397,21 @@ jq '.functions[0].blocks' mir.json # ブロック構造確認
|
|||||||
- 🗃️ **アーカイブ整理**: 古いphaseファイル群をarchiveに移動、導線クリーンアップ完了
|
- 🗃️ **アーカイブ整理**: 古いphaseファイル群をarchiveに移動、導線クリーンアップ完了
|
||||||
- 📋 詳細: [Property System仕様](docs/proposals/unified-members.md) | [Python統合計画](docs/development/roadmap/phases/phase-10.7/)
|
- 📋 詳細: [Property System仕様](docs/proposals/unified-members.md) | [Python統合計画](docs/development/roadmap/phases/phase-10.7/)
|
||||||
|
|
||||||
|
## 📝 Update (2025-09-24) ✅ 改行処理Phase 0 Quick Fix完了!
|
||||||
|
- ✅ **複数行match式パース成功!** たった5箇所の修正で複数行オブジェクトリテラル完全動作
|
||||||
|
- **修正箇所**:
|
||||||
|
1. `primary.rs`: COLON前後とCOMMA判定前にskip_newlines()追加(3箇所)
|
||||||
|
2. `match_expr.rs`: is_object_literal()関数を改行対応(lookahead改良)
|
||||||
|
- **必須環境変数**: `NYASH_SYNTAX_SUGAR_LEVEL=full`(IDENTIFIERキー使用のため)
|
||||||
|
- **テスト結果**: MapBox正常出力 `{'__box__': 'MapBox', '__map': {'value': 42, 'name': 'answer'}}`
|
||||||
|
- 🎯 **セミコロンモード確認完了!** `NYASH_PARSER_ALLOW_SEMICOLON=1`で動作確認
|
||||||
|
- セミコロンと改行を自由に混在可能
|
||||||
|
- JavaScript/Go風の書き方も完全サポート
|
||||||
|
- 📚 **改行処理戦略ドキュメント完成**: [newline-handling-strategy.md](docs/development/strategies/newline-handling-strategy.md)
|
||||||
|
- 3段階実装計画(Phase 0: Quick Fix ✅, Phase 1: TokenCursor, Phase 2: LASI)
|
||||||
|
- ChatGPT Pro提案のTokenCursorサンプルコード含む
|
||||||
|
- 🚀 **次の実装**: Phase 1 TokenCursor導入で改行処理を根本解決へ
|
||||||
|
|
||||||
## 📝 Update (2025-09-23) ✅ フェーズS実装完了!break制御フロー根治開始
|
## 📝 Update (2025-09-23) ✅ フェーズS実装完了!break制御フロー根治開始
|
||||||
- ✅ **フェーズS完了!** PHI incoming修正+終端ガード徹底→重複処理4箇所統一
|
- ✅ **フェーズS完了!** PHI incoming修正+終端ガード徹底→重複処理4箇所統一
|
||||||
- 🔧 **新ユーティリティ**: `src/mir/utils/control_flow.rs`で制御フロー処理統一化
|
- 🔧 **新ユーティリティ**: `src/mir/utils/control_flow.rs`で制御フロー処理統一化
|
||||||
|
|||||||
284
docs/development/strategies/newline-handling-strategy.md
Normal file
284
docs/development/strategies/newline-handling-strategy.md
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
# Nyash改行処理戦略
|
||||||
|
*作成日: 2025-09-23*
|
||||||
|
*ステータス: 承認済み・実装開始*
|
||||||
|
|
||||||
|
## 概要
|
||||||
|
Nyashパーサーにおける改行処理の統一戦略。現在の`skip_newlines()`散在問題を解決し、コンテキスト認識による自動改行処理を実現する。
|
||||||
|
|
||||||
|
## 現状の問題
|
||||||
|
|
||||||
|
### 1. skip_newlines()の散在
|
||||||
|
```rust
|
||||||
|
// 現状:各所で手動呼び出しが必要
|
||||||
|
fn parse_object_literal() {
|
||||||
|
self.skip_newlines(); // ここにも
|
||||||
|
self.consume(TokenType::COLON)?;
|
||||||
|
self.skip_newlines(); // あそこにも
|
||||||
|
let value = self.parse_expression()?;
|
||||||
|
self.skip_newlines(); // どこにでも
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 複数行構文のパースエラー
|
||||||
|
```nyash
|
||||||
|
// これがパースできない
|
||||||
|
local result = match "test" {
|
||||||
|
"test" => {
|
||||||
|
value: 42, // ← 改行でエラー
|
||||||
|
name: "answer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 保守性の問題
|
||||||
|
- 新しい構文追加時に`skip_newlines()`の配置を忘れやすい
|
||||||
|
- 一貫性のない改行処理
|
||||||
|
- デバッグが困難
|
||||||
|
|
||||||
|
## 設計原則
|
||||||
|
|
||||||
|
### 1. セミコロンオプショナル
|
||||||
|
- 改行もセミコロンも文の区切りとして扱う
|
||||||
|
- ユーザーは好みのスタイルを選択可能
|
||||||
|
|
||||||
|
### 2. コンテキスト認識
|
||||||
|
- `{}`, `[]`, `()`内では改行を自動的に無視
|
||||||
|
- 式コンテキストでは改行をスキップ
|
||||||
|
- 文コンテキストでは改行を文区切りとして扱う
|
||||||
|
|
||||||
|
### 3. 環境変数地獄の回避
|
||||||
|
- コンテキストベースの制御を優先
|
||||||
|
- 環境変数は互換性のためのみに限定
|
||||||
|
|
||||||
|
## 実装戦略(3段階)
|
||||||
|
|
||||||
|
### Phase 0: Quick Fix(即座実装)
|
||||||
|
**目的**: 緊急対応として最小限の修正で問題を解決
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// src/parser/expr/primary.rs L77付近
|
||||||
|
self.skip_newlines(); // COLON前に追加
|
||||||
|
self.consume(TokenType::COLON)?;
|
||||||
|
self.skip_newlines(); // 値パース前に追加
|
||||||
|
let value_expr = self.parse_expression()?;
|
||||||
|
self.skip_newlines(); // COMMA判定前に追加
|
||||||
|
```
|
||||||
|
|
||||||
|
**期間**: 30分
|
||||||
|
**効果**: match式の複数行オブジェクトリテラルが動作
|
||||||
|
|
||||||
|
### Phase 1: TokenCursor導入(今週実装)
|
||||||
|
**目的**: 改行処理を一元管理し、`skip_newlines()`散在を根絶
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// src/parser/cursor.rs(新規)
|
||||||
|
pub struct TokenCursor<'a> {
|
||||||
|
tokens: &'a [Token],
|
||||||
|
idx: usize,
|
||||||
|
mode: NewlineMode,
|
||||||
|
paren_depth: usize,
|
||||||
|
brace_depth: usize,
|
||||||
|
bracket_depth: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum NewlineMode {
|
||||||
|
Stmt, // 文モード:改行は文区切り
|
||||||
|
Expr, // 式モード:改行を自動スキップ
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TokenCursor<'a> {
|
||||||
|
pub fn with_expr_mode<F, T>(&mut self, f: F) -> T
|
||||||
|
where F: FnOnce(&mut Self) -> T {
|
||||||
|
let old = self.mode;
|
||||||
|
self.mode = NewlineMode::Expr;
|
||||||
|
let result = f(self);
|
||||||
|
self.mode = old;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_skip_newline(&self) -> bool {
|
||||||
|
// ブレース内 or 式モード or 行継続
|
||||||
|
self.brace_depth > 0 ||
|
||||||
|
self.mode == NewlineMode::Expr ||
|
||||||
|
self.prev_is_line_continuation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**使用例**:
|
||||||
|
```rust
|
||||||
|
fn parse_expression(cursor: &mut TokenCursor) -> Result<Expr> {
|
||||||
|
cursor.with_expr_mode(|c| {
|
||||||
|
// この中では改行が自動的にスキップされる
|
||||||
|
parse_binary_expr(c, 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**期間**: 1週間
|
||||||
|
**効果**:
|
||||||
|
- 改行処理の一元化
|
||||||
|
- 新規構文追加時のミス防止
|
||||||
|
- デバッグの容易化
|
||||||
|
|
||||||
|
### Phase 2: LASI前処理(将来実装)
|
||||||
|
**目的**: トークンレベルで改行を正規化し、パーサーを単純化
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// トークン正規化層
|
||||||
|
fn normalize_tokens(tokens: Vec<Token>) -> Vec<Token> {
|
||||||
|
let mut result = Vec::new();
|
||||||
|
let mut iter = tokens.into_iter();
|
||||||
|
|
||||||
|
while let Some(token) = iter.next() {
|
||||||
|
match token.token_type {
|
||||||
|
TokenType::NEWLINE => {
|
||||||
|
if should_insert_eol(&prev, &next) {
|
||||||
|
result.push(Token::EOL);
|
||||||
|
}
|
||||||
|
// それ以外のNEWLINEは削除
|
||||||
|
}
|
||||||
|
_ => result.push(token),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**期間**: Phase 15完了後
|
||||||
|
**効果**:
|
||||||
|
- パーサーの大幅な簡略化
|
||||||
|
- 完全な改行処理の分離
|
||||||
|
- LosslessToken/Triviaとの統合
|
||||||
|
|
||||||
|
## 行継続ルール
|
||||||
|
|
||||||
|
### 継続と判定する記号(直前)
|
||||||
|
- 二項演算子: `+`, `-`, `*`, `/`, `%`, `&&`, `||`, `|`, `&`, `^`
|
||||||
|
- メンバアクセス: `.`, `::`
|
||||||
|
- Optional系: `?`, `?.`, `??`
|
||||||
|
- Arrow: `=>`, `->`
|
||||||
|
- カンマ: `,`
|
||||||
|
|
||||||
|
### 文終端強制(ハザード回避)
|
||||||
|
- `return`, `break`, `continue`の直後の改行は常に文終端
|
||||||
|
- JavaScriptのASIハザードと同様の考え方
|
||||||
|
|
||||||
|
## テストケース
|
||||||
|
|
||||||
|
### 基本ケース
|
||||||
|
```nyash
|
||||||
|
// 2文として解釈
|
||||||
|
a = 1
|
||||||
|
b = 2
|
||||||
|
|
||||||
|
// 1文として解釈(行継続)
|
||||||
|
a = 1 +
|
||||||
|
2
|
||||||
|
|
||||||
|
// セミコロンも可
|
||||||
|
a = 1; b = 2
|
||||||
|
```
|
||||||
|
|
||||||
|
### 括弧内改行
|
||||||
|
```nyash
|
||||||
|
// すべてOK
|
||||||
|
f(
|
||||||
|
arg1,
|
||||||
|
arg2
|
||||||
|
)
|
||||||
|
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3
|
||||||
|
]
|
||||||
|
|
||||||
|
{
|
||||||
|
key1: value1,
|
||||||
|
key2: value2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### match式
|
||||||
|
```nyash
|
||||||
|
local result = match value {
|
||||||
|
"test" => {
|
||||||
|
name: "foo",
|
||||||
|
value: 42
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
name: "default",
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### returnハザード
|
||||||
|
```nyash
|
||||||
|
return // returnのみ
|
||||||
|
42 // 別の文として解釈
|
||||||
|
|
||||||
|
return 42 // return 42として解釈
|
||||||
|
```
|
||||||
|
|
||||||
|
## 影響分析
|
||||||
|
|
||||||
|
### 後方互換性
|
||||||
|
- Phase 0: 完全互換
|
||||||
|
- Phase 1: 完全互換(内部実装の変更のみ)
|
||||||
|
- Phase 2: セミコロン使用時のみ互換性確認必要
|
||||||
|
|
||||||
|
### パフォーマンス
|
||||||
|
- Phase 0: 影響なし
|
||||||
|
- Phase 1: わずかなオーバーヘッド(カーソル管理)
|
||||||
|
- Phase 2: 前処理により若干の初期化コスト
|
||||||
|
|
||||||
|
## 参考:他言語の実装
|
||||||
|
|
||||||
|
### Go
|
||||||
|
- トークナイザレベルでセミコロン自動挿入
|
||||||
|
- 特定トークン後に改行があれば`;`を挿入
|
||||||
|
|
||||||
|
### JavaScript
|
||||||
|
- ASI(Automatic Semicolon Insertion)
|
||||||
|
- returnハザード等の特殊ルールあり
|
||||||
|
|
||||||
|
### Python
|
||||||
|
- インデントベース(Nyashとは異なるアプローチ)
|
||||||
|
|
||||||
|
### Rust
|
||||||
|
- セミコロン必須(式vs文の区別)
|
||||||
|
|
||||||
|
## 決定事項
|
||||||
|
|
||||||
|
1. **TokenCursorアプローチを採用**
|
||||||
|
- ChatGPT提案のサンプルコードをベースに実装
|
||||||
|
- 環境変数ではなくコンテキストベースの制御
|
||||||
|
|
||||||
|
2. **3段階実装で段階的改善**
|
||||||
|
- まずQuick Fixで緊急対応
|
||||||
|
- TokenCursorで本質的解決
|
||||||
|
- 将来的にLASI前処理で完成形へ
|
||||||
|
|
||||||
|
3. **セミコロン完全オプショナル**
|
||||||
|
- 改行とセミコロンを同等に扱う
|
||||||
|
- ユーザーの好みに応じて選択可能
|
||||||
|
|
||||||
|
## 実装タイムライン
|
||||||
|
|
||||||
|
- **2025-09-23**: Quick Fix実装(30分)
|
||||||
|
- **2025-09-30**: TokenCursor Phase 1完了(1週間)
|
||||||
|
- **Phase 15後**: LASI前処理検討開始
|
||||||
|
|
||||||
|
## 関連ドキュメント
|
||||||
|
|
||||||
|
- [Parser Architecture](../../reference/parser/)
|
||||||
|
- [Language Syntax](../../reference/language/)
|
||||||
|
- [Phase 15 Roadmap](../../roadmap/phases/phase-15/)
|
||||||
|
|
||||||
|
## 承認
|
||||||
|
|
||||||
|
- ChatGPT Pro: 技術分析・実装提案
|
||||||
|
- Claude: 実装戦略決定・ドキュメント化
|
||||||
|
- 実装開始: 2025-09-23
|
||||||
@ -330,9 +330,19 @@ impl NyashParser {
|
|||||||
if !matches!(self.current_token().token_type, TokenType::LBRACE) {
|
if !matches!(self.current_token().token_type, TokenType::LBRACE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
match self.peek_token() {
|
// Phase 0 Quick Fix: 改行をスキップして判定
|
||||||
|
let mut lookahead_idx = 1;
|
||||||
|
while matches!(self.peek_nth_token(lookahead_idx), TokenType::NEWLINE) {
|
||||||
|
lookahead_idx += 1;
|
||||||
|
}
|
||||||
|
match self.peek_nth_token(lookahead_idx) {
|
||||||
TokenType::IDENTIFIER(_) | TokenType::STRING(_) => {
|
TokenType::IDENTIFIER(_) | TokenType::STRING(_) => {
|
||||||
matches!(self.peek_nth_token(2), TokenType::COLON)
|
// 次のトークンも改行をスキップして判定
|
||||||
|
lookahead_idx += 1;
|
||||||
|
while matches!(self.peek_nth_token(lookahead_idx), TokenType::NEWLINE) {
|
||||||
|
lookahead_idx += 1;
|
||||||
|
}
|
||||||
|
matches!(self.peek_nth_token(lookahead_idx), TokenType::COLON)
|
||||||
}
|
}
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,9 +73,12 @@ impl NyashParser {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
self.skip_newlines(); // Phase 0 Quick Fix: COLON前に改行スキップ
|
||||||
self.consume(TokenType::COLON)?;
|
self.consume(TokenType::COLON)?;
|
||||||
|
self.skip_newlines(); // Phase 0 Quick Fix: 値パース前に改行スキップ
|
||||||
let value_expr = self.parse_expression()?;
|
let value_expr = self.parse_expression()?;
|
||||||
entries.push((key, value_expr));
|
entries.push((key, value_expr));
|
||||||
|
self.skip_newlines(); // Phase 0 Quick Fix: COMMA判定前に改行スキップ
|
||||||
if self.match_token(&TokenType::COMMA) {
|
if self.match_token(&TokenType::COMMA) {
|
||||||
self.advance();
|
self.advance();
|
||||||
self.skip_newlines();
|
self.skip_newlines();
|
||||||
|
|||||||
Reference in New Issue
Block a user