feat: match式オブジェクトリテラル判定修正完了 (peek→match統一 Step 1)

 Step 1完全達成:
- is_object_literal()メソッド追加でmatch式内オブジェクトリテラル対応
- match_token()副作用問題をcurrent_token()で解決
- 3箇所修正: デフォルト・型パターン・リテラルアーム全対応

🧪 動作確認済み:
- 基本match式:  回帰なし
- オブジェクトリテラル単体:  正常動作
- 単行match+オブジェクト:  完全動作

🚀 次段階準備:
- 複数行パース問題発見(後回し決定)
- peek→match完全統一 Step 2開始準備完了
- アーキテクチャクリーンアップによるソースコード美化へ

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Selfhosting Dev
2025-09-23 08:18:23 +09:00
parent 09149be41a
commit f469b80f0a
2 changed files with 71 additions and 40 deletions

View File

@ -48,19 +48,24 @@ impl NyashParser {
}
self.consume(TokenType::FatArrow)?;
let expr = if self.match_token(&TokenType::LBRACE) {
// ブロックを式として扱う(最後の文の値が返る)
self.advance(); // consume '{'
let mut stmts: Vec<ASTNode> = Vec::new();
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
self.skip_newlines();
if !self.match_token(&TokenType::RBRACE) {
stmts.push(self.parse_statement()?);
if self.is_object_literal() {
// オブジェクトリテラルとして処理
self.parse_expression()?
} else {
// ブロックを式として扱う(最後の文の値が返る)
self.advance(); // consume '{'
let mut stmts: Vec<ASTNode> = Vec::new();
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
self.skip_newlines();
if !self.match_token(&TokenType::RBRACE) {
stmts.push(self.parse_statement()?);
}
}
self.consume(TokenType::RBRACE)?;
ASTNode::Program {
statements: stmts,
span: Span::unknown(),
}
}
self.consume(TokenType::RBRACE)?;
ASTNode::Program {
statements: stmts,
span: Span::unknown(),
}
} else {
// 値アームは通常の式全体を受理
@ -104,17 +109,22 @@ impl NyashParser {
} else { None };
self.consume(TokenType::FatArrow)?;
let body = if self.match_token(&TokenType::LBRACE) {
self.advance(); // consume '{'
let mut stmts: Vec<ASTNode> = Vec::new();
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
self.skip_newlines();
if !self.match_token(&TokenType::RBRACE) {
let st = self.parse_statement()?;
stmts.push(st);
if self.is_object_literal() {
// オブジェクトリテラルとして処理
self.parse_expression()?
} else {
self.advance(); // consume '{'
let mut stmts: Vec<ASTNode> = Vec::new();
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
self.skip_newlines();
if !self.match_token(&TokenType::RBRACE) {
let st = self.parse_statement()?;
stmts.push(st);
}
}
self.consume(TokenType::RBRACE)?;
ASTNode::Program { statements: stmts, span: Span::unknown() }
}
self.consume(TokenType::RBRACE)?;
ASTNode::Program { statements: stmts, span: Span::unknown() }
} else {
// 値アームは通常の式全体を受理
self.parse_expression()?
@ -144,17 +154,22 @@ impl NyashParser {
} else { None };
self.consume(TokenType::FatArrow)?;
let expr = if self.match_token(&TokenType::LBRACE) {
self.advance(); // consume '{'
let mut stmts: Vec<ASTNode> = Vec::new();
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
self.skip_newlines();
if !self.match_token(&TokenType::RBRACE) {
let st = self.parse_statement()?;
stmts.push(st);
if self.is_object_literal() {
// オブジェクトリテラルとして処理
self.parse_expression()?
} else {
self.advance(); // consume '{'
let mut stmts: Vec<ASTNode> = Vec::new();
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
self.skip_newlines();
if !self.match_token(&TokenType::RBRACE) {
let st = self.parse_statement()?;
stmts.push(st);
}
}
self.consume(TokenType::RBRACE)?;
ASTNode::Program { statements: stmts, span: Span::unknown() }
}
self.consume(TokenType::RBRACE)?;
ASTNode::Program { statements: stmts, span: Span::unknown() }
} else {
// 値アームは通常の式全体を受理
self.parse_expression()?
@ -309,6 +324,20 @@ impl NyashParser {
})
}
/// オブジェクトリテラル判定: { IDENTIFIER : または { STRING : の場合はtrue
fn is_object_literal(&self) -> bool {
// 副作用を避けるためcurrent_token()を使用
if !matches!(self.current_token().token_type, TokenType::LBRACE) {
return false;
}
match self.peek_token() {
TokenType::IDENTIFIER(_) | TokenType::STRING(_) => {
matches!(self.peek_nth_token(2), TokenType::COLON)
}
_ => false
}
}
// match 用の最小リテラルパーサ(式は受け付けない)
fn lit_only_for_match(&mut self) -> Result<crate::ast::LiteralValue, ParseError> {
match &self.current_token().token_type {