feat: 改行処理Phase 1 Smart advance完全実装 - 深度追跡でskip_newlines削減開始

 Smart advance()による自動改行処理を実装
- depth_tracking.rsで括弧深度(paren/brace/bracket)を自動管理
- 括弧内では改行を自動スキップ、演算子後の行継続も自動判定
- デフォルトで有効化(NYASH_SMART_ADVANCE=0で無効化可能)

♻️ skip_newlines()の段階的削除を開始
- primary.rsのオブジェクトリテラル内8箇所を削除(48→40箇所、17%削減)
- 深度追跡により手動skip_newlines()が不要に

🧪 テスト結果
- 文区切り、演算子行継続、括弧内改行、次行演算子すべて成功

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Selfhosting Dev
2025-09-23 10:59:51 +09:00
parent 0012f65f0a
commit 5eb23f9b4c
5 changed files with 226 additions and 45 deletions

View File

@ -397,29 +397,27 @@ jq '.functions[0].blocks' mir.json # ブロック構造確認
- 🗃️ **アーカイブ整理**: 古いphaseファイル群をarchiveに移動、導線クリーンアップ完了
- 📋 詳細: [Property System仕様](docs/proposals/unified-members.md) | [Python統合計画](docs/development/roadmap/phases/phase-10.7/)
## 📝 Update (2025-09-24) ✅ 改行処理実装IDENTIFIERキーのデフォルト化
- **IDENTIFIERキーがデフォルトで使える** 環境変数不要で快適開発
- **変更前**: `NYASH_SYNTAX_SUGAR_LEVEL=full`が必須(面倒
- **変更後**: デフォルトで`{name: "value"}`が書ける!
- **厳密モード**: `NYASH_SYNTAX_SUGAR_LEVEL=basic`で文字列キーのみに制限可能
- **実装**: `primary.rs``sugar_level != "basic"`をデフォルト判定
-**Phase 0 Quick Fix完了** たった5箇所の修正で複数行オブジェクトリテラル完全動作
- `primary.rs`: COLON前後とCOMMA判定前にskip_newlines()追加3箇所
- `match_expr.rs`: is_object_literal()関数を改行対応lookahead改良
- **テスト結果**: MapBox正常出力環境変数なしで動作
- 🎯 **Phase 1 TokenCursor基本実装完了** 改行処理を一元管理する仕組み構築
- **新規実装ファイル**:
1. `src/parser/cursor.rs`: TokenCursor本体230行- モード制御・深度追跡・自動改行処理
2. `src/parser/expr_cursor.rs`: TokenCursor版式パーサー250行- 実験的実装
- **主要機能**:
- NewlineModeStmt/Exprによる文脈認識改行処理
- ブレース/パーレン/ブラケット深度の自動追跡
- 行継続判定(演算子・カンマ等)
- with_expr_mode/with_stmt_mode によるモード一時切り替え
- **ビルド成功**: warning のみでエラーなし
- 🎯 **セミコロンモード確認完了!** `NYASH_PARSER_ALLOW_SEMICOLON=1`で動作確認
- 📚 **改行処理戦略ドキュメント完成**: [newline-handling-strategy.md](docs/development/strategies/newline-handling-strategy.md)
- 🚀 **次の実装**: Phase 2 LASI前処理でトークン正規化Phase 15後
## 📝 Update (2025-09-24) ✅ 改行処理Smart advance完全実装skip_newlines()削減開始
- 🎉 **改行処理Phase 0-1完全達成** ChatGPT Pro戦略に基づく段階的実装が成功
- **Phase 0 Quick Fix**: ✅ 完了primary.rsに緊急対応
- **Phase 1 Smart advance**: ✅ 完全実装&デフォルト有効化
- **Phase 2 TokenCursor**: 基盤実装済み、部分適用中
- **Phase 3 LASI前処理**: 将来計画として整理
-**Smart advance()機能の完成!** 深度追跡による自動改行処理
- **深度追跡実装**: `depth_tracking.rs`で括弧深度paren/brace/bracketを自動管理
- **デフォルト有効化**: 環境変数不要!`NYASH_SMART_ADVANCE=0`で無効化可能
- **賢い行継続判定**:
- 演算子後の改行を自動スキップ
- 次行が演算子で始まる場合もスキップ(`.toUpperCase()`形式対応)
- 括弧内では常に改行を無視
-**skip_newlines()削減開始!** 48箇所→40箇所17%削減)
- **削除完了**: primary.rsのオブジェクトリテラル内8箇所
- **残り40箇所**: 段階的削除計画策定中
- **最終目標**: skip_newlines()完全排除でコード品質向上
- 🧪 **テスト結果**: 全ケース成功!
- 文区切り、演算子行継続、括弧内改行、オブジェクトリテラル、次行演算子すべて✅
- 📚 **改行処理戦略ドキュメント**: [newline-handling-strategy.md](docs/development/strategies/newline-handling-strategy.md)
- 🚀 **次のステップ**: 残り40箇所のskip_newlines()削除→TokenCursor本格活用
## 📝 Update (2025-09-23) ✅ フェーズS実装完了break制御フロー根治開始
-**フェーズS完了** PHI incoming修正+終端ガード徹底→重複処理4箇所統一

View File

@ -43,10 +43,74 @@ pub trait ParserUtils {
}
}
/// 位置を1つ進める
/// 位置を1つ進める(改行自動スキップ対応)
fn advance(&mut self) {
if !self.is_at_end() {
// 現在のトークンで深度を更新(進める前)
self.update_depth_before_advance();
*self.current_mut() += 1;
// 新しいトークンで深度を更新(進めた後)
self.update_depth_after_advance();
// Phase 1: Smart advance - コンテキストに応じて改行を自動スキップ
if self.should_auto_skip_newlines() {
self.skip_newlines_internal();
}
}
}
/// advance前の深度更新閉じ括弧の処理
fn update_depth_before_advance(&mut self) {
// デフォルト実装は何もしないNyashParserでオーバーライド
}
/// advance後の深度更新開き括弧の処理
fn update_depth_after_advance(&mut self) {
// デフォルト実装は何もしないNyashParserでオーバーライド
}
/// 改行を自動スキップすべきか判定
fn should_auto_skip_newlines(&self) -> bool {
// 環境変数でSmart advanceを有効化
if std::env::var("NYASH_SMART_ADVANCE").ok().as_deref() != Some("1") {
return false;
}
// 現在のトークンがブレースやパーレンの後の場合
if self.current() > 0 {
let prev_token = &self.tokens()[self.current() - 1].token_type;
match prev_token {
TokenType::LBRACE | TokenType::LPAREN | TokenType::LBRACK => return true,
// 演算子の後(行継続)
TokenType::PLUS | TokenType::MINUS | TokenType::MULTIPLY |
TokenType::DIVIDE | TokenType::MODULO |
TokenType::AND | TokenType::OR |
TokenType::DOT | TokenType::DoubleColon |
TokenType::COMMA | TokenType::FatArrow => return true,
_ => {}
}
}
false
}
/// 内部用改行スキップ(再帰防止)
fn skip_newlines_internal(&mut self) {
let allow_sc = std::env::var("NYASH_PARSER_ALLOW_SEMICOLON").ok().map(|v| {
let lv = v.to_ascii_lowercase();
lv == "1" || lv == "true" || lv == "on"
}).unwrap_or(false);
while !self.is_at_end() {
let is_nl = matches!(self.current_token().token_type, TokenType::NEWLINE);
let is_sc = allow_sc && matches!(self.current_token().token_type, TokenType::SEMICOLON);
if is_nl || is_sc {
*self.current_mut() += 1; // advance()を使わず直接更新(再帰防止)
} else {
break;
}
}
}

View File

@ -0,0 +1,124 @@
/*!
* 深度追跡機能 - Smart advance用
*
* 括弧の深度を追跡し、改行の自動スキップを判定
*/
use super::{NyashParser, ParserUtils};
use crate::tokenizer::TokenType;
impl NyashParser {
/// 現在の括弧深度を取得(デバッグ用)
#[allow(dead_code)]
pub fn get_depths(&self) -> (usize, usize, usize) {
(self.paren_depth, self.brace_depth, self.bracket_depth)
}
/// 括弧の深度が0以上か何かの括弧内にいるか
pub fn in_brackets(&self) -> bool {
self.paren_depth > 0 || self.brace_depth > 0 || self.bracket_depth > 0
}
}
impl ParserUtils for NyashParser {
fn tokens(&self) -> &Vec<crate::tokenizer::Token> {
&self.tokens
}
fn current(&self) -> usize {
self.current
}
fn current_mut(&mut self) -> &mut usize {
&mut self.current
}
/// advance前の深度更新現在のトークンを処理
fn update_depth_before_advance(&mut self) {
if std::env::var("NYASH_DEBUG_DEPTH").ok().as_deref() == Some("1") {
eprintln!("🔍 BEFORE advance: token={:?}, depths=({},{},{})",
self.current_token().token_type, self.paren_depth, self.brace_depth, self.bracket_depth);
}
// 開き括弧の場合は深度を増やす(進む前に)
match &self.current_token().token_type {
TokenType::LPAREN => {
self.paren_depth += 1;
}
TokenType::LBRACE => {
self.brace_depth += 1;
}
TokenType::LBRACK => {
self.bracket_depth += 1;
}
_ => {}
}
}
/// advance後の深度更新新しいトークンを処理
fn update_depth_after_advance(&mut self) {
if !self.is_at_end() {
// 閉じ括弧の場合は深度を減らす(進んだ後)
match &self.current_token().token_type {
TokenType::RPAREN => {
self.paren_depth = self.paren_depth.saturating_sub(1);
}
TokenType::RBRACE => {
self.brace_depth = self.brace_depth.saturating_sub(1);
}
TokenType::RBRACK => {
self.bracket_depth = self.bracket_depth.saturating_sub(1);
}
_ => {}
}
if std::env::var("NYASH_DEBUG_DEPTH").ok().as_deref() == Some("1") {
eprintln!("🔍 AFTER advance: token={:?}, depths=({},{},{})",
self.current_token().token_type, self.paren_depth, self.brace_depth, self.bracket_depth);
}
}
}
/// 改行を自動スキップすべきか判定NyashParser版
fn should_auto_skip_newlines(&self) -> bool {
// Smart advanceをデフォルトで有効化NYASH_SMART_ADVANCE=0で無効化可能
if std::env::var("NYASH_SMART_ADVANCE").ok().as_deref() == Some("0") {
return false;
}
// 括弧内では常に改行をスキップ
if self.in_brackets() {
return true;
}
// 行継続判定
// 1. 直前のトークンが演算子等の場合
if self.current() > 0 {
let prev_token = &self.tokens[self.current() - 1].token_type;
match prev_token {
// 演算子の後(行継続)
TokenType::PLUS | TokenType::MINUS | TokenType::MULTIPLY |
TokenType::DIVIDE | TokenType::MODULO |
TokenType::AND | TokenType::OR |
TokenType::DOT | TokenType::DoubleColon |
TokenType::COMMA | TokenType::FatArrow |
TokenType::ASSIGN | TokenType::COLON => return true,
_ => {}
}
}
// 2. 現在のトークンが改行で、次のトークンが行継続演算子の場合
if matches!(self.current_token().token_type, TokenType::NEWLINE) {
if self.current() + 1 < self.tokens.len() {
let next_token = &self.tokens[self.current() + 1].token_type;
match next_token {
// 次の行が演算子で始まる場合も行継続
TokenType::DOT | TokenType::PLUS | TokenType::MINUS |
TokenType::MULTIPLY | TokenType::DIVIDE | TokenType::MODULO |
TokenType::AND | TokenType::OR | TokenType::DoubleColon => return true,
_ => {}
}
}
}
false
}
}

View File

@ -47,9 +47,9 @@ impl NyashParser {
let ident_key_on = std::env::var("NYASH_ENABLE_MAP_IDENT_KEY").ok().as_deref()
== Some("1")
|| sugar_level.as_deref() != Some("basic"); // basic以外は全て許可デフォルト含む
self.skip_newlines();
// skip_newlines削除: brace_depth > 0なので自動スキップされる
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
self.skip_newlines();
// skip_newlines削除: brace_depth > 0なので自動スキップされる
let key = match &self.current_token().token_type {
TokenType::STRING(s) => {
let v = s.clone();
@ -74,18 +74,18 @@ impl NyashParser {
});
}
};
self.skip_newlines(); // Phase 0 Quick Fix: COLON前に改行スキップ
// skip_newlines削除: brace_depth > 0なので自動スキップされる
self.consume(TokenType::COLON)?;
self.skip_newlines(); // Phase 0 Quick Fix: 値パース前に改行スキップ
// skip_newlines削除: brace_depth > 0なので自動スキップされる
let value_expr = self.parse_expression()?;
entries.push((key, value_expr));
self.skip_newlines(); // Phase 0 Quick Fix: COMMA判定前に改行スキップ
// skip_newlines削除: brace_depth > 0なので自動スキップされる
if self.match_token(&TokenType::COMMA) {
self.advance();
self.skip_newlines();
// skip_newlines削除: brace_depth > 0なので自動スキップされる
}
}
self.skip_newlines();
// skip_newlines削除: brace_depth > 0なので自動スキップされる
self.consume(TokenType::RBRACE)?;
Ok(ASTNode::MapLiteral {
entries,

View File

@ -20,6 +20,7 @@
mod common;
mod cursor; // TokenCursor: 改行処理を一元管理
mod declarations;
mod depth_tracking; // Phase 1: 深度追跡機能Smart advance用
pub mod entry_sugar; // helper to parse with sugar level
mod expr;
mod expr_cursor; // TokenCursorを使用した式パーサー実験的
@ -138,22 +139,13 @@ pub struct NyashParser {
std::collections::HashMap<String, std::collections::HashSet<String>>,
/// 🔥 デバッグ燃料:無限ループ検出用制限値 (None = 無制限)
pub(super) debug_fuel: Option<usize>,
/// Phase 1: Smart advance用深度カウンタ改行自動スキップ判定
pub(super) paren_depth: usize, // ()
pub(super) brace_depth: usize, // {}
pub(super) bracket_depth: usize, // []
}
// Implement ParserUtils trait
impl ParserUtils for NyashParser {
fn tokens(&self) -> &Vec<Token> {
&self.tokens
}
fn current(&self) -> usize {
self.current
}
fn current_mut(&mut self) -> &mut usize {
&mut self.current
}
}
// ParserUtils trait implementation is in depth_tracking.rs
impl NyashParser {
/// 新しいパーサーを作成
@ -163,6 +155,9 @@ impl NyashParser {
current: 0,
static_box_dependencies: std::collections::HashMap::new(),
debug_fuel: Some(100_000), // デフォルト値
paren_depth: 0,
brace_depth: 0,
bracket_depth: 0,
}
}