use crate::ast::{ASTNode, LiteralValue, Span}; use crate::parser::common::ParserUtils; use crate::parser::{NyashParser, ParseError}; use crate::tokenizer::TokenType; impl NyashParser { pub(crate) fn expr_parse_primary(&mut self) -> Result { match &self.current_token().token_type { TokenType::LBRACK => { let sugar_on = crate::parser::sugar_gate::is_enabled() || std::env::var("NYASH_ENABLE_ARRAY_LITERAL").ok().as_deref() == Some("1"); if !sugar_on { let line = self.current_token().line; return Err(ParseError::UnexpectedToken { found: self.current_token().token_type.clone(), expected: "enable NYASH_SYNTAX_SUGAR_LEVEL=basic|full or NYASH_ENABLE_ARRAY_LITERAL=1".to_string(), line, }); } self.advance(); let mut elems: Vec = Vec::new(); while !self.match_token(&TokenType::RBRACK) && !self.is_at_end() { crate::must_advance!(self, _unused, "array literal element parsing"); let el = self.parse_expression()?; elems.push(el); if self.match_token(&TokenType::COMMA) { self.advance(); } } self.consume(TokenType::RBRACK)?; Ok(ASTNode::ArrayLiteral { elements: elems, span: Span::unknown(), }) } TokenType::LBRACE => { let sugar_on = crate::parser::sugar_gate::is_enabled() || std::env::var("NYASH_ENABLE_MAP_LITERAL").ok().as_deref() == Some("1"); if !sugar_on { let line = self.current_token().line; return Err(ParseError::UnexpectedToken { found: self.current_token().token_type.clone(), expected: "enable NYASH_SYNTAX_SUGAR_LEVEL=basic|full or NYASH_ENABLE_MAP_LITERAL=1".to_string(), line }); } self.advance(); let mut entries: Vec<(String, ASTNode)> = Vec::new(); let sugar_level = std::env::var("NYASH_SYNTAX_SUGAR_LEVEL").ok(); // デフォルトでIDENTIFIERキーを許可(basicが明示的に指定された場合のみ無効) let ident_key_on = std::env::var("NYASH_ENABLE_MAP_IDENT_KEY").ok().as_deref() == Some("1") || sugar_level.as_deref() != Some("basic"); // basic以外は全て許可(デフォルト含む) // skip_newlines削除: brace_depth > 0なので自動スキップされる while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() { // skip_newlines削除: brace_depth > 0なので自動スキップされる let key = match &self.current_token().token_type { TokenType::STRING(s) => { let v = s.clone(); self.advance(); v } TokenType::IDENTIFIER(id) if ident_key_on => { let v = id.clone(); self.advance(); v } _ => { let line = self.current_token().line; return Err(ParseError::UnexpectedToken { found: self.current_token().token_type.clone(), expected: if ident_key_on { "string or identifier key in map literal".to_string() } else { "string key in map literal (set NYASH_SYNTAX_SUGAR_LEVEL=full for identifier keys)".to_string() }, line, }); } }; // skip_newlines削除: brace_depth > 0なので自動スキップされる self.consume(TokenType::COLON)?; // skip_newlines削除: brace_depth > 0なので自動スキップされる let value_expr = self.parse_expression()?; entries.push((key, value_expr)); // skip_newlines削除: brace_depth > 0なので自動スキップされる if self.match_token(&TokenType::COMMA) { self.advance(); // skip_newlines削除: brace_depth > 0なので自動スキップされる } } // skip_newlines削除: brace_depth > 0なので自動スキップされる self.consume(TokenType::RBRACE)?; Ok(ASTNode::MapLiteral { entries, span: Span::unknown(), }) } TokenType::STRING(s) => { let value = s.clone(); self.advance(); Ok(ASTNode::Literal { value: LiteralValue::String(value), span: Span::unknown(), }) } TokenType::NUMBER(n) => { let value = *n; self.advance(); Ok(ASTNode::Literal { value: LiteralValue::Integer(value), span: Span::unknown(), }) } TokenType::FLOAT(f) => { let value = *f; self.advance(); Ok(ASTNode::Literal { value: LiteralValue::Float(value), span: Span::unknown(), }) } TokenType::TRUE => { self.advance(); Ok(ASTNode::Literal { value: LiteralValue::Bool(true), span: Span::unknown(), }) } TokenType::FALSE => { self.advance(); Ok(ASTNode::Literal { value: LiteralValue::Bool(false), span: Span::unknown(), }) } TokenType::NULL => { self.advance(); Ok(ASTNode::Literal { value: LiteralValue::Null, span: Span::unknown(), }) } TokenType::THIS => { if std::env::var("NYASH_DEPRECATE_THIS").ok().as_deref() == Some("1") { eprintln!( "[deprecate:this] 'this' is deprecated; use 'me' instead (line {})", self.current_token().line ); } self.advance(); Ok(ASTNode::Me { span: Span::unknown(), }) } TokenType::ME => { self.advance(); Ok(ASTNode::Me { span: Span::unknown(), }) } TokenType::NEW => { self.advance(); if let TokenType::IDENTIFIER(class_name) = &self.current_token().token_type { let class = class_name.clone(); self.advance(); let mut type_arguments: Vec = Vec::new(); if self.match_token(&TokenType::LESS) { self.advance(); loop { if let TokenType::IDENTIFIER(tn) = &self.current_token().token_type { type_arguments.push(tn.clone()); self.advance(); } else { let line = self.current_token().line; return Err(ParseError::UnexpectedToken { found: self.current_token().token_type.clone(), expected: "type argument".to_string(), line, }); } if self.match_token(&TokenType::COMMA) { self.advance(); continue; } self.consume(TokenType::GREATER)?; break; } } self.consume(TokenType::LPAREN)?; let mut arguments = Vec::new(); while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() { crate::must_advance!(self, _unused, "new expression argument parsing"); arguments.push(self.parse_expression()?); if self.match_token(&TokenType::COMMA) { self.advance(); } } self.consume(TokenType::RPAREN)?; Ok(ASTNode::New { class, arguments, type_arguments, span: Span::unknown(), }) } else { let line = self.current_token().line; Err(ParseError::UnexpectedToken { found: self.current_token().token_type.clone(), expected: "class name".to_string(), line, }) } } TokenType::FROM => self.parse_from_call(), TokenType::IDENTIFIER(name) => { let parent = name.clone(); self.advance(); if self.match_token(&TokenType::DoubleColon) { self.advance(); let method = match &self.current_token().token_type { TokenType::IDENTIFIER(m) => { let s = m.clone(); self.advance(); s } TokenType::INIT => { self.advance(); "init".to_string() } TokenType::PACK => { self.advance(); "pack".to_string() } TokenType::BIRTH => { self.advance(); "birth".to_string() } _ => { let line = self.current_token().line; return Err(ParseError::UnexpectedToken { found: self.current_token().token_type.clone(), expected: "method name".to_string(), line, }); } }; self.consume(TokenType::LPAREN)?; let mut arguments = Vec::new(); while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() { crate::must_advance!(self, _unused, "Parent::method call argument parsing"); arguments.push(self.parse_expression()?); if self.match_token(&TokenType::COMMA) { self.advance(); } } self.consume(TokenType::RPAREN)?; Ok(ASTNode::FromCall { parent, method, arguments, span: Span::unknown(), }) } else { Ok(ASTNode::Variable { name: parent, span: Span::unknown(), }) } } TokenType::LPAREN => { // Phase 152-A: Try grouped assignment first (Stage-3 only) if let Some(assignment) = self.try_parse_grouped_assignment()? { return Ok(assignment); } // Fallback: normal grouped expression self.advance(); let expr = self.parse_expression()?; self.consume(TokenType::RPAREN)?; Ok(expr) } TokenType::FN => { self.advance(); let mut params: Vec = Vec::new(); if self.match_token(&TokenType::LPAREN) { self.advance(); while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() { if let TokenType::IDENTIFIER(p) = &self.current_token().token_type { params.push(p.clone()); self.advance(); if self.match_token(&TokenType::COMMA) { self.advance(); } } else { let line = self.current_token().line; return Err(ParseError::UnexpectedToken { found: self.current_token().token_type.clone(), expected: "parameter name".to_string(), line, }); } } self.consume(TokenType::RPAREN)?; } self.consume(TokenType::LBRACE)?; let mut body: Vec = Vec::new(); while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() { if !self.match_token(&TokenType::RBRACE) { body.push(self.parse_statement()?); } } self.consume(TokenType::RBRACE)?; Ok(ASTNode::Lambda { params, body, span: Span::unknown(), }) } _ => { let line = self.current_token().line; Err(ParseError::InvalidExpression { line }) } } } }