2025-08-09 15:14:44 +09:00
/*!
* Nyash Parser - Statement Parsing Module
2025-09-17 07:43:07 +09:00
*
2025-08-09 15:14:44 +09:00
* 文 ( Statement ) の 解 析 を 担 当 す る モ ジ ュ ー ル
* if , loop , break , return , print等の制御構文を処理
* /
2025-08-16 11:35:57 +09:00
use super ::common ::ParserUtils ;
2025-09-17 07:43:07 +09:00
use super ::{ NyashParser , ParseError } ;
use crate ::ast ::{ ASTNode , CatchClause , Span } ;
use crate ::tokenizer ::TokenType ;
2025-08-09 15:14:44 +09:00
impl NyashParser {
2025-09-19 02:07:38 +09:00
/// Helper: parse a block `{ stmt* }` and return its statements
pub ( super ) fn parse_block_statements ( & mut self ) -> Result < Vec < ASTNode > , ParseError > {
self . consume ( TokenType ::LBRACE ) ? ;
let mut body = Vec ::new ( ) ;
while ! self . match_token ( & TokenType ::RBRACE ) & & ! self . is_at_end ( ) {
self . skip_newlines ( ) ;
if ! self . match_token ( & TokenType ::RBRACE ) {
body . push ( self . parse_statement ( ) ? ) ;
}
}
self . consume ( TokenType ::RBRACE ) ? ;
Ok ( body )
}
/// Helper: parse catch parameter inside parentheses (after '(' consumed)
/// Forms: (Type ident) | (ident) | ()
pub ( super ) fn parse_catch_param ( & mut self ) -> Result < ( Option < String > , Option < String > ) , ParseError > {
if self . match_token ( & TokenType ::RPAREN ) {
return Ok ( ( None , None ) ) ;
}
match & self . current_token ( ) . token_type {
TokenType ::IDENTIFIER ( first ) = > {
let first_str = first . clone ( ) ;
let two_idents = matches! ( self . peek_token ( ) , TokenType ::IDENTIFIER ( _ ) ) ;
if two_idents {
self . advance ( ) ; // consume type ident
if let TokenType ::IDENTIFIER ( var_name ) = & self . current_token ( ) . token_type {
let var = var_name . clone ( ) ;
self . advance ( ) ;
Ok ( ( Some ( first_str ) , Some ( var ) ) )
} else {
let line = self . current_token ( ) . line ;
Err ( ParseError ::UnexpectedToken { found : self . current_token ( ) . token_type . clone ( ) , expected : " exception variable name " . to_string ( ) , line } )
}
} else {
self . advance ( ) ;
Ok ( ( None , Some ( first_str ) ) )
}
}
_ = > {
if self . match_token ( & TokenType ::RPAREN ) {
Ok ( ( None , None ) )
} else {
let line = self . current_token ( ) . line ;
Err ( ParseError ::UnexpectedToken { found : self . current_token ( ) . token_type . clone ( ) , expected : " ) or identifier " . to_string ( ) , line } )
}
}
}
}
2025-08-09 15:14:44 +09:00
/// 文をパース
pub ( super ) fn parse_statement ( & mut self ) -> Result < ASTNode , ParseError > {
2025-09-02 17:12:51 +09:00
// For grammar diff: capture starting token to classify statement keyword
let start_tok = self . current_token ( ) . token_type . clone ( ) ;
let result = match & start_tok {
2025-09-19 02:07:38 +09:00
TokenType ::LBRACE = > {
// Standalone block (Phase 15.5): may be followed by block‑ postfix catch/finally
// Only enabled under gate; otherwise treat as error via expression fallback
// Parse the block body first
let try_body = self . parse_block_statements ( ) ? ;
// Allow whitespace/newlines between block and postfix keywords
self . skip_newlines ( ) ;
if crate ::config ::env ::block_postfix_catch ( )
& & ( self . match_token ( & TokenType ::CATCH ) | | self . match_token ( & TokenType ::CLEANUP ) )
{
// Parse at most one catch, then optional cleanup
let mut catch_clauses : Vec < CatchClause > = Vec ::new ( ) ;
if self . match_token ( & TokenType ::CATCH ) {
self . advance ( ) ; // consume 'catch'
self . consume ( TokenType ::LPAREN ) ? ;
let ( exception_type , exception_var ) = self . parse_catch_param ( ) ? ;
self . consume ( TokenType ::RPAREN ) ? ;
let catch_body = self . parse_block_statements ( ) ? ;
catch_clauses . push ( CatchClause {
exception_type ,
variable_name : exception_var ,
body : catch_body ,
span : Span ::unknown ( ) ,
} ) ;
// Single‑ catch policy (MVP): disallow multiple catch in postfix form
self . skip_newlines ( ) ;
if self . match_token ( & TokenType ::CATCH ) {
let line = self . current_token ( ) . line ;
return Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " single catch only after standalone block " . to_string ( ) ,
line ,
} ) ;
}
}
// Optional cleanup
let finally_body = if self . match_token ( & TokenType ::CLEANUP ) {
self . advance ( ) ; // consume 'cleanup'
Some ( self . parse_block_statements ( ) ? )
} else {
None
} ;
Ok ( ASTNode ::TryCatch {
try_body ,
catch_clauses ,
finally_body ,
span : Span ::unknown ( ) ,
} )
} else {
// No postfix keywords. If gate is on, enforce MVP static check:
// direct top-level `throw` inside the standalone block must be followed by catch
if crate ::config ::env ::block_postfix_catch ( )
& & try_body . iter ( ) . any ( | n | matches! ( n , ASTNode ::Throw { .. } ) )
{
let line = self . current_token ( ) . line ;
return Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " block with direct 'throw' must be followed by 'catch' " . to_string ( ) ,
line ,
} ) ;
}
Ok ( ASTNode ::Program {
statements : try_body ,
span : Span ::unknown ( ) ,
} )
}
}
2025-09-17 07:43:07 +09:00
TokenType ::BOX = > self . parse_box_declaration ( ) ,
TokenType ::IMPORT = > self . parse_import ( ) ,
TokenType ::INTERFACE = > self . parse_interface_box_declaration ( ) ,
TokenType ::GLOBAL = > self . parse_global_var ( ) ,
TokenType ::FUNCTION = > self . parse_function_declaration ( ) ,
2025-08-10 07:54:03 +09:00
TokenType ::STATIC = > {
2025-09-17 07:43:07 +09:00
self . parse_static_declaration ( ) // 🔥 静的宣言 (function/box)
}
TokenType ::IF = > self . parse_if ( ) ,
TokenType ::LOOP = > self . parse_loop ( ) ,
TokenType ::BREAK = > self . parse_break ( ) ,
TokenType ::CONTINUE = > self . parse_continue ( ) ,
TokenType ::RETURN = > self . parse_return ( ) ,
TokenType ::PRINT = > self . parse_print ( ) ,
TokenType ::NOWAIT = > self . parse_nowait ( ) ,
TokenType ::INCLUDE = > self . parse_include ( ) ,
TokenType ::LOCAL = > self . parse_local ( ) ,
TokenType ::OUTBOX = > self . parse_outbox ( ) ,
2025-09-19 02:07:38 +09:00
TokenType ::TRY = > {
if crate ::config ::env ::parser_stage3 ( ) {
self . parse_try_catch ( )
} else {
Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " enable NYASH_PARSER_STAGE3=1 to use 'try' " . to_string ( ) ,
line : self . current_token ( ) . line ,
} )
}
}
TokenType ::THROW = > {
if crate ::config ::env ::parser_stage3 ( ) {
self . parse_throw ( )
} else {
Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " enable NYASH_PARSER_STAGE3=1 to use 'throw' " . to_string ( ) ,
line : self . current_token ( ) . line ,
} )
}
}
TokenType ::CATCH = > {
// Provide a friendlier error when someone writes: if { .. } catch { .. }
if crate ::config ::env ::block_postfix_catch ( ) {
Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " postfix 'catch' is only allowed immediately after a standalone block: { ... } catch (...) { ... } (wrap if/else/loop in a standalone block) " . to_string ( ) ,
line : self . current_token ( ) . line ,
} )
} else {
Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " enable NYASH_BLOCK_CATCH=1 (or NYASH_PARSER_STAGE3=1) to use postfix 'catch' after a standalone block " . to_string ( ) ,
line : self . current_token ( ) . line ,
} )
}
}
TokenType ::CLEANUP = > {
if crate ::config ::env ::block_postfix_catch ( ) {
Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " postfix 'cleanup' is only allowed immediately after a standalone block: { ... } cleanup { ... } " . to_string ( ) ,
line : self . current_token ( ) . line ,
} )
} else {
Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " enable NYASH_BLOCK_CATCH=1 (or NYASH_PARSER_STAGE3=1) to use postfix 'cleanup' after a standalone block " . to_string ( ) ,
line : self . current_token ( ) . line ,
} )
}
}
2025-09-17 07:43:07 +09:00
TokenType ::USING = > self . parse_using ( ) ,
2025-08-11 07:55:41 +09:00
TokenType ::FROM = > {
// 🔥 from構文: from Parent.method(args) または from Parent.constructor(args)
self . parse_from_call_statement ( )
2025-09-17 07:43:07 +09:00
}
2025-08-16 17:39:04 +09:00
TokenType ::IDENTIFIER ( _name ) = > {
2025-08-09 15:14:44 +09:00
// function宣言 または 代入文 または 関数呼び出し
self . parse_assignment_or_function_call ( )
}
TokenType ::THIS | TokenType ::ME = > {
// this/me で始まる文も通常の代入文または関数呼び出しとして処理
self . parse_assignment_or_function_call ( )
}
_ = > {
2025-09-14 19:16:32 +09:00
// Fallback: treat as expression statement
// Allows forms like: print("x") or a bare literal as the last value in a block
Ok ( self . parse_expression ( ) ? )
2025-08-09 15:14:44 +09:00
}
2025-08-10 07:54:03 +09:00
} ;
2025-09-17 07:43:07 +09:00
2025-09-02 17:12:51 +09:00
// Non-invasive syntax rule check
if std ::env ::var ( " NYASH_GRAMMAR_DIFF " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
let kw = match start_tok {
TokenType ::BOX = > Some ( " box " ) ,
TokenType ::GLOBAL = > Some ( " global " ) ,
TokenType ::FUNCTION = > Some ( " function " ) ,
TokenType ::STATIC = > Some ( " static " ) ,
TokenType ::IF = > Some ( " if " ) ,
TokenType ::LOOP = > Some ( " loop " ) ,
TokenType ::BREAK = > Some ( " break " ) ,
TokenType ::RETURN = > Some ( " return " ) ,
TokenType ::PRINT = > Some ( " print " ) ,
TokenType ::NOWAIT = > Some ( " nowait " ) ,
TokenType ::INCLUDE = > Some ( " include " ) ,
TokenType ::LOCAL = > Some ( " local " ) ,
TokenType ::OUTBOX = > Some ( " outbox " ) ,
TokenType ::TRY = > Some ( " try " ) ,
TokenType ::THROW = > Some ( " throw " ) ,
TokenType ::USING = > Some ( " using " ) ,
TokenType ::FROM = > Some ( " from " ) ,
_ = > None ,
} ;
if let Some ( k ) = kw {
let ok = crate ::grammar ::engine ::get ( ) . syntax_is_allowed_statement ( k ) ;
2025-09-17 07:43:07 +09:00
if ! ok {
eprintln! (
" [GRAMMAR-DIFF][Parser] statement '{}' not allowed by syntax rules " ,
k
) ;
}
2025-09-02 17:12:51 +09:00
}
}
2025-08-10 07:54:03 +09:00
result
2025-08-09 15:14:44 +09:00
}
2025-09-08 04:35:50 +09:00
/// import文をパース: import "path" (as Alias)?
pub ( super ) fn parse_import ( & mut self ) -> Result < ASTNode , ParseError > {
self . advance ( ) ; // consume 'import'
let path = if let TokenType ::STRING ( s ) = & self . current_token ( ) . token_type {
let v = s . clone ( ) ;
self . advance ( ) ;
v
} else {
2025-09-17 07:43:07 +09:00
return Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " string literal " . to_string ( ) ,
line : self . current_token ( ) . line ,
} ) ;
2025-09-08 04:35:50 +09:00
} ;
// Optional: 'as' Alias (treat 'as' as identifier literal)
let mut alias : Option < String > = None ;
if let TokenType ::IDENTIFIER ( w ) = & self . current_token ( ) . token_type {
if w = = " as " {
self . advance ( ) ;
if let TokenType ::IDENTIFIER ( name ) = & self . current_token ( ) . token_type {
alias = Some ( name . clone ( ) ) ;
self . advance ( ) ;
} else {
2025-09-17 07:43:07 +09:00
return Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " alias name " . to_string ( ) ,
line : self . current_token ( ) . line ,
} ) ;
2025-09-08 04:35:50 +09:00
}
}
}
2025-09-17 07:43:07 +09:00
Ok ( ASTNode ::ImportStatement {
path ,
alias ,
span : Span ::unknown ( ) ,
} )
2025-09-08 04:35:50 +09:00
}
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
/// if文をパース: if (condition) { body } else if ... else { body }
pub ( super ) fn parse_if ( & mut self ) -> Result < ASTNode , ParseError > {
self . advance ( ) ; // consume 'if'
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
// 条件部分を取得
let condition = Box ::new ( self . parse_expression ( ) ? ) ;
2025-09-17 07:43:07 +09:00
2025-09-19 02:07:38 +09:00
// then部分を取得( 共通ブロックヘルパー)
let then_body = self . parse_block_statements ( ) ? ;
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
// else if/else部分を処理
let else_body = if self . match_token ( & TokenType ::ELSE ) {
self . advance ( ) ; // consume 'else'
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
if self . match_token ( & TokenType ::IF ) {
// else if を ネストしたifとして処理
let nested_if = self . parse_if ( ) ? ;
Some ( vec! [ nested_if ] )
} else {
2025-09-19 02:07:38 +09:00
// plain else( 共通ブロックヘルパー)
Some ( self . parse_block_statements ( ) ? )
2025-08-09 15:14:44 +09:00
}
} else {
None
} ;
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
Ok ( ASTNode ::If {
condition ,
then_body ,
else_body ,
span : Span ::unknown ( ) ,
} )
}
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
/// loop文をパース
pub ( super ) fn parse_loop ( & mut self ) -> Result < ASTNode , ParseError > {
self . advance ( ) ; // consume 'loop'
2025-09-17 07:43:07 +09:00
2025-08-20 04:45:26 +09:00
// 条件部分を取得(省略可: `loop { ... }` は無条件ループとして扱う)
let condition = if self . match_token ( & TokenType ::LPAREN ) {
self . advance ( ) ; // consume '('
let cond = Box ::new ( self . parse_expression ( ) ? ) ;
self . consume ( TokenType ::RPAREN ) ? ;
cond
} else {
// default: true
2025-09-17 07:43:07 +09:00
Box ::new ( ASTNode ::Literal {
value : crate ::ast ::LiteralValue ::Bool ( true ) ,
span : Span ::unknown ( ) ,
} )
2025-08-20 04:45:26 +09:00
} ;
2025-09-17 07:43:07 +09:00
2025-09-19 02:07:38 +09:00
// body部分を取得( 共通ブロックヘルパー)
let body = self . parse_block_statements ( ) ? ;
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
Ok ( ASTNode ::Loop {
2025-08-20 04:45:26 +09:00
condition ,
2025-08-09 15:14:44 +09:00
body ,
span : Span ::unknown ( ) ,
} )
}
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
/// break文をパース
pub ( super ) fn parse_break ( & mut self ) -> Result < ASTNode , ParseError > {
self . advance ( ) ; // consume 'break'
2025-09-17 07:43:07 +09:00
Ok ( ASTNode ::Break {
span : Span ::unknown ( ) ,
} )
2025-08-09 15:14:44 +09:00
}
grammar(P0): add peek expression, continue statement, and field type annotations acceptance; add sample apps and interpreter path\n\n- tokenizer: add keywords (peek, continue), tokens (=> as FatArrow, :: as DoubleColon), keep >> as Arrow\n- parser: implement peek as expression (literal patterns only, else required), add continue; accept field 'name: Type' (discard type P0)\n- interpreter: evaluate PeekExpr; add Continue control flow handling\n- apps: add peek-demo, loop-continue-demo, adjust field-decl demo; use ConsoleBox instead of env.console for interpreter backend\n- docs: CURRENT_TASK updated earlier for Phase 12.7 P0\n\nNOTE: peek arms currently single-expression (no block expr yet); VM/MIR path does not lower PeekExpr yet; use --backend interpreter for demos
2025-09-03 15:26:15 +09:00
/// continue文をパース
pub ( super ) fn parse_continue ( & mut self ) -> Result < ASTNode , ParseError > {
self . advance ( ) ; // consume 'continue'
2025-09-17 07:43:07 +09:00
Ok ( ASTNode ::Continue {
span : Span ::unknown ( ) ,
} )
grammar(P0): add peek expression, continue statement, and field type annotations acceptance; add sample apps and interpreter path\n\n- tokenizer: add keywords (peek, continue), tokens (=> as FatArrow, :: as DoubleColon), keep >> as Arrow\n- parser: implement peek as expression (literal patterns only, else required), add continue; accept field 'name: Type' (discard type P0)\n- interpreter: evaluate PeekExpr; add Continue control flow handling\n- apps: add peek-demo, loop-continue-demo, adjust field-decl demo; use ConsoleBox instead of env.console for interpreter backend\n- docs: CURRENT_TASK updated earlier for Phase 12.7 P0\n\nNOTE: peek arms currently single-expression (no block expr yet); VM/MIR path does not lower PeekExpr yet; use --backend interpreter for demos
2025-09-03 15:26:15 +09:00
}
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
/// return文をパース
pub ( super ) fn parse_return ( & mut self ) -> Result < ASTNode , ParseError > {
self . advance ( ) ; // consume 'return'
2025-09-17 07:43:07 +09:00
// 許容: 改行をスキップしてから式有無を判定
2025-09-14 19:16:32 +09:00
self . skip_newlines ( ) ;
// returnの後に式があるかチェック( RBRACE/EOFなら値なし)
let value = if self . is_at_end ( ) | | self . match_token ( & TokenType ::RBRACE ) {
2025-08-09 15:14:44 +09:00
None
} else {
Some ( Box ::new ( self . parse_expression ( ) ? ) )
} ;
2025-09-17 07:43:07 +09:00
Ok ( ASTNode ::Return {
value ,
span : Span ::unknown ( ) ,
} )
2025-08-09 15:14:44 +09:00
}
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
/// print文をパース
pub ( super ) fn parse_print ( & mut self ) -> Result < ASTNode , ParseError > {
self . advance ( ) ; // consume 'print'
self . consume ( TokenType ::LPAREN ) ? ;
let value = Box ::new ( self . parse_expression ( ) ? ) ;
self . consume ( TokenType ::RPAREN ) ? ;
2025-09-17 07:43:07 +09:00
Ok ( ASTNode ::Print {
expression : value ,
span : Span ::unknown ( ) ,
} )
2025-08-09 15:14:44 +09:00
}
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
/// nowait文をパース: nowait variable = expression
pub ( super ) fn parse_nowait ( & mut self ) -> Result < ASTNode , ParseError > {
self . advance ( ) ; // consume 'nowait'
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
// 変数名を取得
let variable = if let TokenType ::IDENTIFIER ( name ) = & self . current_token ( ) . token_type {
let name = name . clone ( ) ;
self . advance ( ) ;
name
} else {
let line = self . current_token ( ) . line ;
return Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " variable name " . to_string ( ) ,
line ,
} ) ;
} ;
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
self . consume ( TokenType ::ASSIGN ) ? ;
let expression = Box ::new ( self . parse_expression ( ) ? ) ;
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
Ok ( ASTNode ::Nowait {
variable ,
expression ,
span : Span ::unknown ( ) ,
} )
}
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
/// include文をパース
pub ( super ) fn parse_include ( & mut self ) -> Result < ASTNode , ParseError > {
self . advance ( ) ; // consume 'include'
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
let path = if let TokenType ::STRING ( path ) = & self . current_token ( ) . token_type {
let path = path . clone ( ) ;
self . advance ( ) ;
path
} else {
let line = self . current_token ( ) . line ;
return Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " string literal " . to_string ( ) ,
line ,
} ) ;
} ;
2025-09-17 07:43:07 +09:00
Ok ( ASTNode ::Include {
filename : path ,
span : Span ::unknown ( ) ,
} )
2025-08-09 15:14:44 +09:00
}
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
/// local変数宣言をパース: local var1, var2, var3 または local x = 10
pub ( super ) fn parse_local ( & mut self ) -> Result < ASTNode , ParseError > {
self . advance ( ) ; // consume 'local'
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
let mut names = Vec ::new ( ) ;
let mut initial_values = Vec ::new ( ) ;
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
// 最初の変数名を取得
if let TokenType ::IDENTIFIER ( name ) = & self . current_token ( ) . token_type {
names . push ( name . clone ( ) ) ;
self . advance ( ) ;
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
// = があれば初期値を設定
if self . match_token ( & TokenType ::ASSIGN ) {
self . advance ( ) ; // consume '='
initial_values . push ( Some ( Box ::new ( self . parse_expression ( ) ? ) ) ) ;
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
// 初期化付きlocalは単一変数のみ( カンマ区切り不可)
Ok ( ASTNode ::Local {
variables : names ,
initial_values ,
span : Span ::unknown ( ) ,
} )
} else {
// 初期化なしの場合はカンマ区切りで複数変数可能
initial_values . push ( None ) ;
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
// カンマ区切りで追加の変数名を取得
while self . match_token ( & TokenType ::COMMA ) {
self . advance ( ) ; // consume ','
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
if let TokenType ::IDENTIFIER ( name ) = & self . current_token ( ) . token_type {
names . push ( name . clone ( ) ) ;
initial_values . push ( None ) ;
self . advance ( ) ;
} else {
let line = self . current_token ( ) . line ;
return Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " identifier " . to_string ( ) ,
line ,
} ) ;
}
}
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
Ok ( ASTNode ::Local {
variables : names ,
initial_values ,
span : Span ::unknown ( ) ,
} )
}
} else {
let line = self . current_token ( ) . line ;
Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " identifier " . to_string ( ) ,
line ,
} )
}
}
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
/// outbox変数宣言をパース: outbox var1, var2, var3
pub ( super ) fn parse_outbox ( & mut self ) -> Result < ASTNode , ParseError > {
self . advance ( ) ; // consume 'outbox'
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
let mut names = Vec ::new ( ) ;
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
// 最初の変数名を取得
if let TokenType ::IDENTIFIER ( name ) = & self . current_token ( ) . token_type {
names . push ( name . clone ( ) ) ;
self . advance ( ) ;
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
// カンマ区切りで追加の変数名を取得
while self . match_token ( & TokenType ::COMMA ) {
self . advance ( ) ; // consume ','
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
if let TokenType ::IDENTIFIER ( name ) = & self . current_token ( ) . token_type {
names . push ( name . clone ( ) ) ;
self . advance ( ) ;
} else {
let line = self . current_token ( ) . line ;
return Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " identifier " . to_string ( ) ,
line ,
} ) ;
}
}
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
let num_vars = names . len ( ) ;
Ok ( ASTNode ::Outbox {
variables : names ,
initial_values : vec ! [ None ; num_vars ] ,
span : Span ::unknown ( ) ,
} )
} else {
let line = self . current_token ( ) . line ;
Err ( ParseError ::UnexpectedToken {
found : self . current_token ( ) . token_type . clone ( ) ,
expected : " identifier " . to_string ( ) ,
line ,
} )
}
}
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
/// try-catch文をパース
pub ( super ) fn parse_try_catch ( & mut self ) -> Result < ASTNode , ParseError > {
self . advance ( ) ; // consume 'try'
2025-09-19 02:07:38 +09:00
let try_body = self . parse_block_statements ( ) ? ;
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
let mut catch_clauses = Vec ::new ( ) ;
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
// catch節をパース
while self . match_token ( & TokenType ::CATCH ) {
self . advance ( ) ; // consume 'catch'
self . consume ( TokenType ::LPAREN ) ? ;
2025-09-19 02:07:38 +09:00
let ( exception_type , exception_var ) = self . parse_catch_param ( ) ? ;
2025-08-09 15:14:44 +09:00
self . consume ( TokenType ::RPAREN ) ? ;
2025-09-19 02:07:38 +09:00
let catch_body = self . parse_block_statements ( ) ? ;
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
catch_clauses . push ( CatchClause {
exception_type ,
2025-09-19 02:07:38 +09:00
variable_name : exception_var ,
2025-08-09 15:14:44 +09:00
body : catch_body ,
span : Span ::unknown ( ) ,
} ) ;
}
2025-09-17 07:43:07 +09:00
2025-09-19 02:07:38 +09:00
// cleanup節をパース (オプション)
let finally_body = if self . match_token ( & TokenType ::CLEANUP ) {
self . advance ( ) ; // consume 'cleanup'
Some ( self . parse_block_statements ( ) ? )
2025-08-09 15:14:44 +09:00
} else {
None
} ;
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
Ok ( ASTNode ::TryCatch {
try_body ,
catch_clauses ,
finally_body ,
span : Span ::unknown ( ) ,
} )
}
2025-09-17 07:43:07 +09:00
2025-08-09 15:14:44 +09:00
/// throw文をパース
pub ( super ) fn parse_throw ( & mut self ) -> Result < ASTNode , ParseError > {
self . advance ( ) ; // consume 'throw'
let value = Box ::new ( self . parse_expression ( ) ? ) ;
2025-09-17 07:43:07 +09:00
Ok ( ASTNode ::Throw {
expression : value ,
span : Span ::unknown ( ) ,
} )
2025-08-09 15:14:44 +09:00
}
2025-09-17 07:43:07 +09:00
2025-08-11 07:55:41 +09:00
/// 🔥 from構文を文としてパース: from Parent.method(args)
pub ( super ) fn parse_from_call_statement ( & mut self ) -> Result < ASTNode , ParseError > {
// 既存のparse_from_call()を使用してFromCall ASTノ ードを作成
let from_call_expr = self . parse_from_call ( ) ? ;
2025-09-17 07:43:07 +09:00
2025-08-11 07:55:41 +09:00
// FromCallは式でもあるが、文としても使用可能
// 例: from Animal.constructor() (戻り値を使わない)
Ok ( from_call_expr )
}
2025-09-17 07:43:07 +09:00
2025-08-16 01:12:10 +09:00
/// using文をパース: using namespace_name
pub ( super ) fn parse_using ( & mut self ) -> Result < ASTNode , ParseError > {
self . advance ( ) ; // consume 'using'
2025-09-17 07:43:07 +09:00
2025-08-16 01:12:10 +09:00
// 名前空間名を取得
if let TokenType ::IDENTIFIER ( namespace_name ) = & self . current_token ( ) . token_type {
let name = namespace_name . clone ( ) ;
self . advance ( ) ;
2025-09-17 07:43:07 +09:00
2025-08-16 01:12:10 +09:00
// Phase 0では "nyashstd" のみ許可
if name ! = " nyashstd " {
2025-09-17 07:43:07 +09:00
return Err ( ParseError ::UnsupportedNamespace {
name ,
line : self . current_token ( ) . line ,
2025-08-16 01:12:10 +09:00
} ) ;
}
2025-09-17 07:43:07 +09:00
2025-08-16 01:12:10 +09:00
Ok ( ASTNode ::UsingStatement {
namespace_name : name ,
span : Span ::unknown ( ) ,
} )
} else {
2025-09-17 07:43:07 +09:00
Err ( ParseError ::ExpectedIdentifier {
line : self . current_token ( ) . line ,
2025-08-16 01:12:10 +09:00
} )
}
}
2025-08-20 04:45:26 +09:00
}