//! implements `Parser`. //! //! パーサーを実装する //! use std::mem; use erg_common::config::ErgConfig; use erg_common::error::Location; use erg_common::io::{Input, InputKind}; use erg_common::set::Set as HashSet; use erg_common::str::Str; use erg_common::traits::{DequeStream, ExitStatus, Locational, New, Runnable, Stream}; use erg_common::{ caused_by, debug_power_assert, enum_unwrap, fn_name, impl_display_for_enum, impl_locational_for_enum, log, set, switch_lang, switch_unreachable, }; use crate::ast::*; use crate::desugar::Desugarer; use crate::error::{ CompleteArtifact, IncompleteArtifact, ParseError, ParseErrors, ParseResult, ParserRunnerError, ParserRunnerErrors, }; use crate::lex::Lexer; use crate::token::{Token, TokenCategory, TokenKind, TokenStream}; use TokenCategory as TC; use TokenKind::*; #[macro_export] /// Display the name of the called function for debugging the parser macro_rules! debug_call_info { ($self: ident) => { $self.level += 1; log!( c DEBUG_MAIN, "\n{} ({}) entered {}, cur: {}", "・".repeat(($self.level as f32 / 4.0).floor() as usize), $self.level, fn_name!(), $self.peek().unwrap_or(&$crate::token::Token::DUMMY) ); }; } #[macro_export] macro_rules! debug_exit_info { ($self: ident) => { $self.level -= 1; log!( c DEBUG_MAIN, "\n{} ({}) exit {}, cur: {}", "・".repeat(($self.level as f32 / 4.0).floor() as usize), $self.level, fn_name!(), $self.peek().unwrap_or(&$crate::token::Token::DUMMY) ); }; } macro_rules! expect_pop { ($self: ident, category $cate: expr) => { if $self.cur_category_is($cate) { $self.lpop() } else { let loc = $self.peek().map(|t| t.loc()).unwrap_or(Location::Unknown); let got = $self.peek().map(|t| t.kind).unwrap_or(EOF); let err = ParseError::unexpected_token(line!() as usize, loc, $cate, got); $self.errs.push(err); debug_exit_info!($self); return Err(()); } }; ($self: ident, fail_next $kind: expr) => { if $self.cur_is($kind) { $self.lpop() } else { let loc = $self.peek().map(|t| t.loc()).unwrap_or(Location::Unknown); let got = $self.peek().map(|t| t.kind).unwrap_or(EOF); let err = ParseError::unexpected_token(line!() as usize, loc, $kind, got); $self.next_line(); $self.errs.push(err); debug_exit_info!($self); return Err(()); } }; ($self: ident, $kind: expr) => { if $self.cur_is($kind) { $self.lpop() } else { let loc = $self.peek().map(|t| t.loc()).unwrap_or(Location::Unknown); let got = $self.peek().map(|t| t.kind).unwrap_or(EOF); let err = ParseError::unexpected_token(line!() as usize, loc, $kind, got); $self.errs.push(err); debug_exit_info!($self); return Err(()); } }; } pub trait Parsable: 'static { fn parse(code: String) -> Result>; } #[cfg_attr(feature = "pylib", pyo3::pyclass)] pub struct SimpleParser {} impl Parsable for SimpleParser { fn parse(code: String) -> Result { let ts = Lexer::from_str(code).lex().map_err(|(_, es)| es)?; let mut parser = Parser::new(ts); let mut desugarer = Desugarer::new(); let artifact = parser .parse() .map_err(|iart| iart.map_mod(|module| desugarer.desugar(module)))?; Ok(artifact.map(|module| desugarer.desugar(module))) } } impl SimpleParser { pub fn parse(code: String) -> Result { ::parse(code) } } enum ExprOrOp { Expr(Expr), Op(Token), } enum ArgKind { Pos(PosArg), Var(PosArg), Kw(KwArg), KwVar(PosArg), } pub enum ListInner { Normal(Args), WithLength(PosArg, Expr), Comprehension { layout: Option, generators: Vec<(Identifier, Expr)>, guard: Option, }, } impl ListInner { pub const fn comp( layout: Option, generators: Vec<(Identifier, Expr)>, guard: Option, ) -> Self { Self::Comprehension { layout, generators, guard, } } } pub enum BraceContainer { Set(Set), Dict(Dict), Record(Record), } impl_locational_for_enum!(BraceContainer; Set, Dict, Record); impl_display_for_enum!(BraceContainer; Set, Dict, Record); impl BraceContainer { pub const fn kind(&self) -> &str { match self { BraceContainer::Set(_) => "Set", BraceContainer::Dict(_) => "Dict", BraceContainer::Record(_) => "Record", } } } pub enum ArgsStyle { SingleCommaWithParen, SingleCommaNoParen, MultiComma, // with parentheses Colon, // with no parentheses } impl ArgsStyle { pub const fn needs_parens(&self) -> bool { match self { Self::SingleCommaWithParen | Self::MultiComma => true, Self::SingleCommaNoParen | Self::Colon => false, } } pub const fn is_colon(&self) -> bool { matches!(self, Self::Colon) } pub const fn is_multi_comma(&self) -> bool { matches!(self, Self::MultiComma) } } /// Perform recursive descent parsing. /// /// `level` is raised by 1 by `debug_call_info!` in each analysis method and lowered by 1 when leaving (`.map_err` is called to lower the level). /// /// To enhance error descriptions, the parsing process will continue as long as it's not fatal. #[derive(Debug)] pub struct Parser { counter: DefId, pub(super) level: usize, // nest level (for debugging) tokens: TokenStream, warns: ParseErrors, pub(crate) errs: ParseErrors, } impl Parsable for Parser { fn parse(code: String) -> Result> { let ts = Lexer::from_str(code).lex().map_err(|(_, es)| es)?; Parser::new(ts).parse() } } impl Parser { pub const fn new(ts: TokenStream) -> Self { Self { counter: DefId(0), level: 0, tokens: ts, warns: ParseErrors::empty(), errs: ParseErrors::empty(), } } #[inline] pub fn peek(&self) -> Option<&Token> { self.tokens.first() } pub fn peek_kind(&self) -> Option { self.peek().map(|tok| tok.kind) } #[inline] fn nth(&self, idx: usize) -> Option<&Token> { self.tokens.get(idx) } #[inline] fn skip(&mut self) { self.tokens.pop_front(); } #[inline] fn lpop(&mut self) -> Token { self.tokens.pop_front().unwrap() } fn cur_category_is(&self, category: TokenCategory) -> bool { self.peek() .map(|t| t.category_is(category)) .unwrap_or(false) } fn cur_is(&self, kind: TokenKind) -> bool { self.peek().map(|t| t.is(kind)).unwrap_or(false) } fn nth_is(&self, idx: usize, kind: TokenKind) -> bool { self.nth(idx).map(|t| t.is(kind)).unwrap_or(false) } /// 解析を諦めて次の解析できる要素に移行する /// give up parsing and move to the next element that can be parsed fn next_expr(&mut self) { while let Some(t) = self.peek() { match t.category() { TC::Separator => { self.skip(); return; } TC::EOF => { return; } _ => { self.skip(); } } } } fn next_line(&mut self) { while let Some(t) = self.peek() { match t.kind { Newline => { self.skip(); return; } EOF => return, _ => { self.skip(); } } } } fn until_dedent(&mut self) { let mut nest_cnt = 1; while let Some(t) = self.peek() { match t.kind { Indent => { self.skip(); nest_cnt += 1; } Dedent => { self.skip(); nest_cnt -= 1; if nest_cnt <= 0 { return; } } EOF => return, _ => { self.skip(); } } } } fn unexpected_none(&self, errno: u32, caused_by: &str) -> ParseError { log!(err "error caused by: {caused_by}"); ParseError::invalid_none_match(0, Location::Unknown, file!(), errno) } fn skip_and_throw_syntax_err(&mut self, errno: u32, caused_by: &str) -> ParseError { let loc = self.peek().map(|t| t.loc()).unwrap_or_default(); log!(err "error caused by: {caused_by}"); self.next_expr(); ParseError::simple_syntax_error(errno as usize, loc) } fn skip_and_throw_invalid_unclosed_err( &mut self, caused_by: &str, line: u32, closer: &str, ty: &str, ) -> ParseError { log!(err "error caused by: {caused_by}"); let loc = self.peek().map(|t| t.loc()).unwrap_or_default(); self.next_expr(); ParseError::unclosed_error(line as usize, loc, closer, ty) } fn skip_and_throw_invalid_seq_err( &mut self, caused_by: &str, errno: usize, expected: &[impl std::fmt::Display], found: TokenKind, ) -> ParseError { log!(err "error caused by: {caused_by}"); let loc = self.peek().map(|t| t.loc()).unwrap_or_default(); self.next_expr(); ParseError::invalid_seq_elems_error(errno, loc, expected, found) } fn skip_and_throw_invalid_chunk_err( &mut self, caused_by: &str, line: u32, loc: Location, ) -> ParseError { log!(err "error caused by: {caused_by}"); self.next_line(); ParseError::invalid_chunk_error(line as usize, loc) } fn get_stream_op_syntax_error( &mut self, errno: usize, loc: Location, caused_by: &str, ) -> ParseError { log!(err "error caused by: {caused_by}"); self.next_expr(); ParseError::syntax_error( errno, loc, switch_lang!( "japanese" => "パイプ演算子の後には関数・メソッド・サブルーチンのみ呼び出しができます", "simplified_chinese" => "流操作符后只能调用函数、方法或子程序", "traditional_chinese" => "流操作符後只能調用函數、方法或子程序", "english" => "Only a call of function, method or subroutine is available after stream operator", ), None, ) } #[inline] fn restore(&mut self, token: Token) { self.tokens.push_front(token); } pub(crate) fn stack_dec(&mut self, fn_name: &str) { self.level -= 1; log!( c DEBUG_MAIN, "\n{} ({}) exit {}, cur: {}", "・".repeat((self.level as f32 / 4.0).floor() as usize), self.level, fn_name, self.peek().unwrap() ); } } #[derive(Debug, Default)] pub struct ParserRunner { cfg: ErgConfig, } impl New for ParserRunner { #[inline] fn new(cfg: ErgConfig) -> Self { Self { cfg } } } impl Runnable for ParserRunner { type Err = ParserRunnerError; type Errs = ParserRunnerErrors; const NAME: &'static str = "Erg parser"; #[inline] fn cfg(&self) -> &ErgConfig { &self.cfg } #[inline] fn cfg_mut(&mut self) -> &mut ErgConfig { &mut self.cfg } #[inline] fn finish(&mut self) {} #[inline] fn initialize(&mut self) {} #[inline] fn clear(&mut self) {} fn exec(&mut self) -> Result { let src = self.cfg_mut().input.read(); let artifact = self.parse(src).map_err(|iart| iart.errors)?; println!("{}", artifact.ast); Ok(ExitStatus::OK) } fn eval(&mut self, src: String) -> Result { let artifact = self.parse(src).map_err(|iart| iart.errors)?; Ok(format!("{}", artifact.ast)) } } impl ParserRunner { #[inline] pub fn new(cfg: ErgConfig) -> Self { New::new(cfg) } pub fn parse_token_stream( &mut self, ts: TokenStream, ) -> Result> { Parser::new(ts) .parse() .map_err(|iart| iart.map_errs(|errs| ParserRunnerErrors::convert(self.input(), errs))) } pub fn parse( &mut self, src: String, ) -> Result> { let ts = Lexer::new(Input::new(InputKind::Str(src), self.cfg.input.id())) .lex() .map_err(|(_, errs)| ParserRunnerErrors::convert(self.input(), errs))?; Parser::new(ts) .parse() .map_err(|iart| iart.map_errs(|errs| ParserRunnerErrors::convert(self.input(), errs))) } } impl Parser { pub fn parse(&mut self) -> Result { if self.tokens.is_empty() { return Ok(CompleteArtifact::new(Module::empty(), ParseErrors::empty())); } log!(info "the parsing process has started."); log!(info "token stream: {}", self.tokens); let module = match self.try_reduce_module() { Ok(module) => module, Err(_) => { return Err(IncompleteArtifact::new( None, mem::take(&mut self.warns), mem::take(&mut self.errs), )); } }; log!(info "the parsing process has completed (errs: {}).", self.errs.len()); log!(info "AST:\n{module}"); if self.errs.is_empty() { Ok(CompleteArtifact::new(module, mem::take(&mut self.warns))) } else { Err(IncompleteArtifact::new( Some(module), mem::take(&mut self.warns), mem::take(&mut self.errs), )) } } /// Reduce to the largest unit of syntax, the module (this is called only once) #[inline] fn try_reduce_module(&mut self) -> ParseResult { debug_call_info!(self); let mut chunks = Module::empty(); loop { match self.peek_kind() { Some(Newline | Semi) => { self.skip(); } Some(EOF) => { break; } Some(_) => { if let Ok(expr) = self.try_reduce_chunk(true, false) { if !self.cur_is(EOF) && !self.cur_category_is(TC::Separator) { let err = self.skip_and_throw_invalid_chunk_err( caused_by!(), line!(), expr.loc(), ); self.errs.push(err); } chunks.push(expr); } } None => { if !self.errs.is_empty() { let err = if let Some(last) = chunks.last() { self.skip_and_throw_invalid_chunk_err(caused_by!(), line!(), last.loc()) } else { self.unexpected_none(line!(), caused_by!()) }; self.errs.push(err); break; } else { switch_unreachable!() } } } } debug_exit_info!(self); Ok(chunks) } // expect the block`= ; . -> =>` fn try_reduce_block(&mut self) -> ParseResult { debug_call_info!(self); let mut block = Block::with_capacity(2); // single line block if !self.cur_is(Newline) { let expr = self .try_reduce_expr(true, false, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; block.push(expr); if !self.cur_is(Dedent) && !self.cur_category_is(TC::Separator) && !self.cur_category_is(TC::REnclosure) { let err = self.skip_and_throw_invalid_chunk_err( caused_by!(), line!(), block.last().unwrap().loc(), ); debug_exit_info!(self); self.errs.push(err); } if block.last().unwrap().is_definition() { let err = ParseError::invalid_definition_of_last_block( line!() as usize, block.last().unwrap().loc(), ); self.errs.push(err); debug_exit_info!(self); return Err(()); } else { debug_exit_info!(self); return Ok(block); } } expect_pop!(self, Newline); while self.cur_is(Newline) { self.skip(); } expect_pop!(self, Indent); loop { match self.peek_kind() { Some(Newline) if self.nth_is(1, Dedent) => { let nl = self.lpop(); self.skip(); self.restore(nl); break; } // last line dedent without newline Some(Dedent) => { self.skip(); break; } Some(Newline | Semi) => { self.skip(); } Some(EOF) => { break; } Some(_) => { if let Ok(expr) = self.try_reduce_chunk(true, false) { if !self.cur_is(Dedent) && !self.cur_category_is(TC::Separator) { let err = self.skip_and_throw_invalid_chunk_err( caused_by!(), line!(), expr.loc(), ); debug_exit_info!(self); self.errs.push(err); } block.push(expr); } } None => { let err = ParseError::failed_to_analyze_block(line!() as usize, Location::Unknown); self.errs.push(err); break; } } } if block.is_empty() { let loc = if let Some(u) = self.peek() { u.loc() } else { Location::Unknown }; let err = ParseError::failed_to_analyze_block(line!() as usize, loc); self.errs.push(err); debug_exit_info!(self); Err(()) } else if block.last().unwrap().is_definition() { let err = ParseError::invalid_chunk_error(line!() as usize, block.last().unwrap().loc()); self.errs.push(err); debug_exit_info!(self); Err(()) } else { debug_exit_info!(self); Ok(block) } } #[inline] fn opt_reduce_decorator(&mut self) -> ParseResult> { debug_call_info!(self); if self.cur_is(TokenKind::AtSign) { self.lpop(); let expr = self .try_reduce_expr(false, false, false, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: デコレータ", "simplified_chinese" => "期望: 装饰器", "traditional_chinese" => "期望: 裝飾器", "english" => "expect: decorator", )) } self.stack_dec(fn_name!()) })?; debug_exit_info!(self); Ok(Some(Decorator::new(expr))) } else { debug_exit_info!(self); Ok(None) } } #[inline] fn opt_reduce_decorators(&mut self) -> ParseResult> { debug_call_info!(self); let mut decs = set![]; while let Some(deco) = self .opt_reduce_decorator() .map_err(|_| self.stack_dec(fn_name!()))? { if self.cur_is(EOF) { let err = ParseError::expect_next_line_error(line!() as usize, deco.0.loc(), "AtMark"); self.errs.push(err); return Err(()); } decs.insert(deco); expect_pop!(self, fail_next Newline); } debug_exit_info!(self); Ok(decs) } fn try_reduce_type_app_args(&mut self) -> ParseResult { debug_call_info!(self); let l_vbar = expect_pop!(self, VBar); let args = match self.peek_kind() { Some(SubtypeOf) => { let op = self.lpop(); let t_spec_as_expr = self.try_reduce_expr(false, true, false, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: 型指定", "simplified_chinese" => "期望: 类型规范", "traditional_chinese" => "期望: 類型規範", "english" => "expect: type specification", )) } self.stack_dec(fn_name!()) })?; match Parser::expr_to_type_spec(t_spec_as_expr.clone()) { Ok(t_spec) => { let t_spec = TypeSpecWithOp::new(op, t_spec, t_spec_as_expr); TypeAppArgsKind::SubtypeOf(Box::new(t_spec)) } Err(_) => { let err = ParseError::simple_syntax_error(0, t_spec_as_expr.loc()); self.errs.push(err); debug_exit_info!(self); return Err(()); } } } _ => { let args = self .try_reduce_args(true) .map_err(|_| self.stack_dec(fn_name!()))?; TypeAppArgsKind::Args(args) } }; let r_vbar = expect_pop!(self, VBar); debug_exit_info!(self); Ok(TypeAppArgs::new(l_vbar.loc(), args, r_vbar.loc())) } fn try_reduce_restriction(&mut self) -> ParseResult { debug_call_info!(self); expect_pop!(self, LSqBr); let rest = match self.peek_kind() { Some(SubtypeOf) => { self.lpop(); let t_spec_as_expr = self .try_reduce_expr(false, true, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; match Parser::expr_to_type_spec(t_spec_as_expr) { Ok(t_spec) => VisRestriction::SubtypeOf(Box::new(t_spec)), Err(err) => { self.errs.push(err); debug_exit_info!(self); return Err(()); } } } _ => { // FIXME: reduce namespaces let acc = self .try_reduce_acc_lhs() .map_err(|_| self.stack_dec(fn_name!()))?; VisRestriction::Namespaces(Namespaces::new(vec![acc])) } }; expect_pop!(self, RSqBr); debug_exit_info!(self); Ok(rest) } fn try_reduce_ident(&mut self) -> ParseResult { debug_call_info!(self); let ident = match self.peek_kind() { Some(Symbol) => { let symbol = self.lpop(); Identifier::private_from_token(symbol) } Some(Dot) => { let dot = self.lpop(); let symbol = expect_pop!(self, Symbol); Identifier::public_from_token(dot, symbol) } _ => { let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); } }; debug_exit_info!(self); Ok(ident) } fn try_reduce_acc_lhs(&mut self) -> ParseResult { debug_call_info!(self); let acc = match self.peek_kind() { Some(Symbol | UBar) => Accessor::local(self.lpop()), Some(Dot) => { let dot = self.lpop(); let maybe_symbol = self.lpop(); if maybe_symbol.is(Symbol) { Accessor::public(dot.loc(), maybe_symbol) } else { let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); } } Some(DblColon) => { let dbl_colon = self.lpop(); if let Some(LSqBr) = self.peek_kind() { let rest = self .try_reduce_restriction() .map_err(|_| self.stack_dec(fn_name!()))?; let symbol = expect_pop!(self, Symbol); Accessor::restricted(rest, symbol) } else { let symbol = expect_pop!(self, Symbol); Accessor::explicit_local(dbl_colon.loc(), symbol) } } _ => { let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); } }; debug_exit_info!(self); Ok(acc) } fn try_reduce_list_elems(&mut self) -> ParseResult { debug_call_info!(self); if self.cur_is(EOF) { let tk = self.tokens.last().unwrap(); let err = ParseError::expect_next_line_error(line!() as usize, tk.loc(), "Collections"); self.errs.push(err); return Err(()); } if self.cur_category_is(TC::REnclosure) { let args = Args::empty(); debug_exit_info!(self); return Ok(ListInner::Normal(args)); } let first = self .try_reduce_elem() .map_err(|_| self.stack_dec(fn_name!()))?; let mut elems = Args::single(first); match self.peek_kind() { Some(Semi) => { self.lpop(); let len = self .try_reduce_expr(false, false, false, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: Nat型", "simplified_chinese" => "期望: Nat类型", "traditional_chinese" => "期望: Nat類型", "english" => "expect: Nat type", )) } self.stack_dec(fn_name!()) })?; debug_exit_info!(self); return Ok(ListInner::WithLength(elems.remove_pos(0), len)); } Some(PreStar) => { self.lpop(); let rest = self .try_reduce_expr(false, false, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; elems.set_var_args(PosArg::new(rest)); debug_exit_info!(self); return Ok(ListInner::Normal(elems)); } Some(Inclusion) => { self.lpop(); let Expr::Accessor(Accessor::Ident(sym)) = elems.remove_pos(0).expr else { let err = self.skip_and_throw_invalid_seq_err( caused_by!(), line!() as usize, &["identifier"], Inclusion, ); self.errs.push(err); debug_exit_info!(self); return Err(()); }; let mut generators = vec![]; let expr = self .try_reduce_expr(false, false, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; generators.push((sym, expr)); let _ = expect_pop!(self, VBar); let guard = self .try_reduce_expr(false, false, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); return Ok(ListInner::comp(None, generators, Some(guard))); } Some(VBar) => { self.lpop(); let elem = elems.remove_pos(0).expr; let mut generators = vec![]; loop { let sym = self .try_reduce_ident() .map_err(|_| self.stack_dec(fn_name!()))?; let _ = expect_pop!(self, Inclusion); let expr = self .try_reduce_expr(false, false, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; generators.push((sym, expr)); if !self.cur_is(Semi) { break; } else { self.lpop(); } } let guard = if self.cur_is(VBar) { self.lpop(); let expr = self .try_reduce_expr(false, false, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; Some(expr) } else { None }; debug_exit_info!(self); return Ok(ListInner::comp(Some(elem), generators, guard)); } Some(RParen | RSqBr | RBrace | Dedent | Comma) => {} Some(_) => { let elem = self .try_reduce_elem() .map_err(|_| self.stack_dec(fn_name!()))?; elems.push_pos(elem); } None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); return Err(()); } } loop { match self.peek_kind() { Some(Comma) => { self.skip(); match self.peek_kind() { Some(Comma) => { let err = self.skip_and_throw_invalid_seq_err( caused_by!(), line!() as usize, &["]", "element"], Comma, ); self.errs.push(err); debug_exit_info!(self); return Err(()); } Some(RParen | RSqBr | RBrace | Dedent) => { break; } Some(PreStar) => { self.lpop(); let rest = self .try_reduce_expr(false, false, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; elems.set_var_args(PosArg::new(rest)); break; } _ => {} } elems.push_pos( self.try_reduce_elem() .map_err(|_| self.stack_dec(fn_name!()))?, ); } Some(RParen | RSqBr | RBrace | Dedent) => { break; } Some(_other) => { let err = self.skip_and_throw_invalid_unclosed_err( caused_by!(), line!(), "]", "array", ); self.errs.push(err); debug_exit_info!(self); return Err(()); } None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); return Err(()); } } } debug_exit_info!(self); Ok(ListInner::Normal(elems)) } fn try_reduce_elem(&mut self) -> ParseResult { debug_call_info!(self); match self.peek() { Some(_) => { let expr = self .try_reduce_expr(false, false, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); Ok(PosArg::new(expr)) } None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); Err(()) } } } fn opt_reduce_args(&mut self, in_type_args: bool) -> Option> { debug_call_info!(self); match self.peek() { Some(t) if t.category_is(TC::Literal) || t.is(StrInterpLeft) || t.is(Symbol) || t.category_is(TC::UnaryOp) || t.is(LParen) || t.is(LSqBr) || t.is(LBrace) || t.is(UBar) => { Some(self.try_reduce_args(in_type_args)) } Some(t) if (t.is(Dot) || t.is(DblColon)) && !self.nth_is(1, Newline) && !self.nth_is(1, LBrace) && !self.nth_is(1, LSqBr) => { Some(self.try_reduce_args(in_type_args)) } _ => None, } } /// 引数はインデントで区切ることができる(ただしコンマに戻すことはできない) /// /// ```erg /// x = if True, 1, 2 /// # is equal to /// x = if True: /// 1 /// 2 /// ``` fn try_reduce_args(&mut self, in_type_args: bool) -> ParseResult { debug_call_info!(self); let mut lp = None; let rp; if self.cur_is(LParen) { lp = Some(self.lpop()); } let mut style = if lp.is_some() { ArgsStyle::SingleCommaWithParen } else { ArgsStyle::SingleCommaNoParen }; match self.peek_kind() { Some(RParen) => { rp = self.lpop(); debug_exit_info!(self); return Ok(Args::pos_only(vec![], Some((lp.unwrap().loc(), rp.loc())))); } Some(RBrace | RSqBr | Dedent) => { debug_exit_info!(self); return Ok(Args::empty()); } Some(Newline) if style.needs_parens() => { self.skip(); if self.cur_is(Indent) { self.skip(); } style = ArgsStyle::MultiComma; } _ => {} } let mut args = match self .try_reduce_arg(in_type_args) .map_err(|_| self.stack_dec(fn_name!()))? { ArgKind::Pos(arg) => Args::single(arg), ArgKind::Var(arg) => Args::new(vec![], Some(arg), vec![], None, None), ArgKind::Kw(arg) => Args::new(vec![], None, vec![arg], None, None), ArgKind::KwVar(arg) => Args::new(vec![], None, vec![], Some(arg), None), }; loop { match self.peek_kind() { Some(Colon) if style.is_colon() || lp.is_some() => { self.skip(); let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); } Some(Colon) => { self.skip(); style = ArgsStyle::Colon; while self.cur_is(Newline) { self.skip(); } expect_pop!(self, fail_next Indent); } Some(Comma) => { self.skip(); if style.is_colon() || self.cur_is(Comma) { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let loc = self.peek().map(|t| t.loc()).unwrap_or_default(); let err = ParseError::invalid_colon_style(line!() as usize, loc); self.errs.push(err); self.until_dedent(); debug_exit_info!(self); return Err(()); } if style.is_multi_comma() { while self.cur_is(Newline) { self.skip(); } if self.cur_is(Dedent) { self.skip(); } } if style.needs_parens() && self.cur_is(RParen) { let rp = self.lpop(); args.set_parens((lp.unwrap().loc(), rp.loc())); break; } if !args.kw_is_empty() { args.push_kw( self.try_reduce_kw_arg(in_type_args) .map_err(|_| self.stack_dec(fn_name!()))?, ); } else { match self .try_reduce_arg(in_type_args) .map_err(|_| self.stack_dec(fn_name!()))? { ArgKind::Pos(arg) => { args.push_pos(arg); } ArgKind::Var(var) => { args.set_var_args(var); } ArgKind::Kw(arg) => { args.push_kw(arg); } ArgKind::KwVar(arg) => { args.set_kw_var(arg); } } } } Some(RParen) => { if let Some(lp) = lp { let rp = self.lpop(); args.set_parens((lp.loc(), rp.loc())); } else { // e.g. f(g 1) let (pos_args, var_args, kw_args, kw_var, _) = args.deconstruct(); args = Args::new(pos_args, var_args, kw_args, kw_var, None); } break; } Some(Newline) => { if !style.is_colon() { if style.needs_parens() && !style.is_multi_comma() { let err = self.skip_and_throw_invalid_seq_err( caused_by!(), line!() as usize, &[")"], Newline, ); self.errs.push(err); debug_exit_info!(self); return Err(()); } if style.is_multi_comma() { self.skip(); while self.cur_is(Dedent) { self.skip(); } let rp = expect_pop!(self, fail_next RParen); args.set_parens((lp.unwrap().loc(), rp.loc())); } break; } let last = self.lpop(); if self.cur_is(Dedent) { self.skip(); self.restore(last); break; } } Some(Dedent) if style.is_colon() => { self.skip(); break; } Some(_) if style.is_colon() => { if !args.kw_is_empty() { args.push_kw( self.try_reduce_kw_arg(in_type_args) .map_err(|_| self.stack_dec(fn_name!()))?, ); } else { match self .try_reduce_arg(in_type_args) .map_err(|_| self.stack_dec(fn_name!()))? { ArgKind::Pos(arg) => { args.push_pos(arg); } ArgKind::Var(var) => { args.set_var_args(var); } ArgKind::Kw(arg) => { args.push_kw(arg); } ArgKind::KwVar(arg) => { args.set_kw_var(arg); } } } } None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); return Err(()); } _ => break, } } debug_exit_info!(self); Ok(args) } fn try_reduce_arg(&mut self, in_type_args: bool) -> ParseResult { debug_call_info!(self); match self.peek_kind() { Some(Symbol) => { if self.nth_is(1, Walrus) { let acc = self .try_reduce_acc_lhs() .map_err(|_| self.stack_dec(fn_name!()))?; debug_power_assert!(self.cur_is(Walrus)); self.skip(); let kw = if let Accessor::Ident(n) = acc { n.name.into_token() } else { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::expect_keyword(line!() as usize, acc.loc()); self.errs.push(err); self.next_expr(); debug_exit_info!(self); return Err(()); }; let expr = self .try_reduce_expr(false, in_type_args, false, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: Nat型", "simplified_chinese" => "期望: Nat类型", "traditional_chinese" => "期望: Nat類型", "english" => "expect: Nat type", )) } self.stack_dec(fn_name!()) })?; debug_exit_info!(self); Ok(ArgKind::Kw(KwArg::new(kw, None, expr))) } else { let expr = self .try_reduce_expr(false, in_type_args, false, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: 型指定", "simplified_chinese" => "期望: 类型规范", "traditional_chinese" => "期望: 類型規範", "english" => "expect: type specification", )) } self.stack_dec(fn_name!()) })?; if self.cur_is(Walrus) { self.skip(); let (kw, t_spec) = match expr { Expr::Accessor(Accessor::Ident(n)) => (n.name.into_token(), None), Expr::TypeAscription(tasc) => { if let Expr::Accessor(Accessor::Ident(n)) = *tasc.expr { (n.name.into_token(), Some(tasc.t_spec)) } else { let err = self.skip_and_throw_invalid_seq_err( caused_by!(), line!() as usize, &["right enclosure", "element"], Comma, ); self.errs.push(err); debug_exit_info!(self); return Err(()); } } _ => { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::expect_keyword(line!() as usize, expr.loc()); self.errs.push(err); self.next_expr(); debug_exit_info!(self); return Err(()); } }; let expr = self .try_reduce_expr(false, in_type_args, false, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: 型指定", "simplified_chinese" => "期望: 类型规范", "traditional_chinese" => "期望: 類型規範", "english" => "expect: type specification", )) } self.stack_dec(fn_name!()) })?; debug_exit_info!(self); Ok(ArgKind::Kw(KwArg::new(kw, t_spec, expr))) } else { debug_exit_info!(self); Ok(ArgKind::Pos(PosArg::new(expr))) } } } Some(star @ (PreStar | PreDblStar)) => { self.skip(); let expr = self .try_reduce_expr(false, in_type_args, false, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: 型指定", "simplified_chinese" => "期望: 类型规范", "traditional_chinese" => "期望: 類型規範", "english" => "expect: type specification", )) } self.stack_dec(fn_name!()) })?; debug_exit_info!(self); if star == PreStar { Ok(ArgKind::Var(PosArg::new(expr))) } else { Ok(ArgKind::KwVar(PosArg::new(expr))) } } Some(_) => { let expr = self .try_reduce_expr(false, in_type_args, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); Ok(ArgKind::Pos(PosArg::new(expr))) } None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); Err(()) } } } fn try_reduce_kw_arg(&mut self, in_type_args: bool) -> ParseResult { debug_call_info!(self); match self.peek() { Some(t) if t.is(Symbol) => { if self.nth_is(1, Walrus) { let acc = self .try_reduce_acc_lhs() .map_err(|_| self.stack_dec(fn_name!()))?; debug_power_assert!(self.cur_is(Walrus)); self.skip(); let keyword = if let Accessor::Ident(n) = acc { n.name.into_token() } else { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::expect_keyword(line!() as usize, acc.loc()); self.errs.push(err); self.next_expr(); debug_exit_info!(self); return Err(()); }; let expr = self .try_reduce_expr(false, in_type_args, false, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: 引数", "simplified_chinese" => "期望: 参数", "traditional_chinese" => "期望: 參數", "english" => "expect: an argument", )) } self.stack_dec(fn_name!()) })?; debug_exit_info!(self); Ok(KwArg::new(keyword, None, expr)) } else if self.nth_is(1, Colon) { let acc = self .try_reduce_acc_lhs() .map_err(|_| self.stack_dec(fn_name!()))?; let colon = expect_pop!(self, Colon); let t_spec_as_expr = self .try_reduce_expr(false, true, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; let t_spec = match Parser::expr_to_type_spec(t_spec_as_expr.clone()) { Ok(t_spec) => TypeSpecWithOp::new(colon, t_spec, t_spec_as_expr), Err(err) => { self.errs.push(err); debug_exit_info!(self); return Err(()); } }; debug_power_assert!(self.cur_is(Walrus)); self.skip(); let keyword = if let Accessor::Ident(n) = acc { n.name.into_token() } else { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::expect_keyword(line!() as usize, acc.loc()); self.errs.push(err); self.next_expr(); debug_exit_info!(self); return Err(()); }; let expr = self .try_reduce_expr(false, in_type_args, false, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: 引数", "simplified_chinese" => "期望: 参数", "traditional_chinese" => "期望: 參數", "english" => "expect: an argument", )) } self.stack_dec(fn_name!()) })?; debug_exit_info!(self); Ok(KwArg::new(keyword, Some(t_spec), expr)) } else { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::invalid_non_default_parameter(line!() as usize, t.loc()); self.errs.push(err); self.next_expr(); debug_exit_info!(self); Err(()) } } Some(lit) if lit.category_is(TC::Literal) => { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::invalid_non_default_parameter(line!() as usize, lit.loc()); self.errs.push(err); self.next_expr(); debug_exit_info!(self); Err(()) } Some(other) => { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::expect_keyword(line!() as usize, other.loc()); self.errs.push(err); self.next_expr(); debug_exit_info!(self); Err(()) } None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); Err(()) } } } fn try_reduce_class_attr_defs( &mut self, class: Expr, vis: VisModifierSpec, ) -> ParseResult { debug_call_info!(self); expect_pop!(self, fail_next Indent); while self.cur_is(Newline) { self.skip(); } let first = self.try_reduce_chunk(false, false).map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "メソッドか属性のみ定義できます", "simplified_chinese" => "只能定义方法或属性", "traditional_chinese" => "只能定義方法或屬性", "english" => "only a method or attribute can be defined", )) } self.stack_dec(fn_name!()) })?; let first = match first { Expr::Def(def) => ClassAttr::Def(def), Expr::TypeAscription(tasc) => ClassAttr::Decl(tasc), Expr::Literal(lit) if lit.is_doc_comment() => ClassAttr::Doc(lit), other => { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let hint = switch_lang!( "japanese" => "メソッドか属性のみ定義できます", "simplified_chinese" => "只能定义方法或属性", "traditional_chinese" => "只能定義方法或屬性", "english" => "only a method or attribute can be defined", ) .to_string(); let err = ParseError::syntax_error( line!() as usize, other.loc(), switch_lang!( "japanese" => "クラス属性を定義するのに失敗しました", "simplified_chinese" => "定义类属性失败", "traditional_chinese" => "定義類屬性失敗", "english" => "failed to define a class attribute", ), Some(hint), ); self.errs.push(err); self.until_dedent(); debug_exit_info!(self); return Err(()); } }; let mut attrs = vec![first]; loop { match self.peek() { Some(t) if t.is(Newline) && self.nth_is(1, Dedent) => { let nl = self.lpop(); self.skip(); self.restore(nl); break; } Some(t) if t.is(Dedent) => { self.skip(); break; } Some(t) if t.category_is(TC::Separator) => { self.skip(); } Some(_) => { let def = self.try_reduce_chunk(false, false).map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "クラス属性かメソッドを定義してください", "simplified_chinese" => "应声明类属性或方法", "traditional_chinese" => "應聲明類屬性或方法", "english" => "class attribute or method should be declared", )) } self.stack_dec(fn_name!()) })?; match def { Expr::Def(def) => { attrs.push(ClassAttr::Def(def)); } Expr::TypeAscription(tasc) => { attrs.push(ClassAttr::Decl(tasc)); } Expr::Literal(lit) if lit.is_doc_comment() => { attrs.push(ClassAttr::Doc(lit)); } other => { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::syntax_error( line!() as usize, other.loc(), switch_lang!( "japanese" => "クラス属性を定義するのに失敗しました", "simplified_chinese" => "定义类属性失败", "traditional_chinese" => "定義類屬性失敗", "english" => "failed to define a class attribute", ), None, ); self.errs.push(err); self.next_expr(); debug_exit_info!(self); return Err(()); } } match self.peek() { Some(t) if !t.is(Dedent) && !t.category_is(TC::Separator) => { let err = self.skip_and_throw_invalid_chunk_err( caused_by!(), line!(), t.loc(), ); self.errs.push(err); debug_exit_info!(self); return Err(()); } Some(_) => {} None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); return Err(()); } } } None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); return Err(()); } } } let attrs = ClassAttrs::from(attrs); let t_spec = Self::expr_to_type_spec(class.clone()).map_err(|e| { self.errs.push(e); self.stack_dec(fn_name!()) })?; debug_exit_info!(self); self.counter.inc(); Ok(Methods::new(self.counter, t_spec, class, vis, attrs)) } fn try_reduce_do_block(&mut self) -> ParseResult { debug_call_info!(self); let do_symbol = self.lpop(); let sig = LambdaSignature::do_sig(&do_symbol); let op = match &do_symbol.inspect()[..] { "do" => Token::from_str(FuncArrow, "->"), "do!" => Token::from_str(ProcArrow, "=>"), _ => unreachable!(), }; if self.cur_is(Colon) { self.lpop(); if self.cur_is(EOF) { let err = ParseError::expect_next_line_error(line!() as usize, op.loc(), "Lambda"); self.errs.push(err); return Err(()); } let body = self .try_reduce_block() .map_err(|_| self.stack_dec(fn_name!()))?; self.counter.inc(); debug_exit_info!(self); Ok(Lambda::new(sig, op, body, self.counter)) } else { let expr = self .try_reduce_expr(false, false, false, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: 式", "simplified_chinese" => "期望: 表达", "traditional_chinese" => "期望: 表達", "english" => "expect: expression", )) } self.stack_dec(fn_name!()) })?; let block = Block::new(vec![expr]); debug_exit_info!(self); Ok(Lambda::new(sig, op, block, self.counter)) } } /// chunk = normal expr + def fn try_reduce_chunk(&mut self, winding: bool, in_brace: bool) -> ParseResult { debug_call_info!(self); let mut stack = Vec::::new(); stack.push(ExprOrOp::Expr( self.try_reduce_bin_lhs(false, in_brace) .map_err(|_| self.stack_dec(fn_name!()))?, )); loop { match self.peek() { Some(arg) if arg.is(Symbol) || arg.category_is(TC::Literal) => { let args = self .try_reduce_args(false) .map_err(|_| self.stack_dec(fn_name!()))?; let obj = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); stack.push(ExprOrOp::Expr(obj.call_expr(args))); } Some(op) if op.category_is(TC::DefOp) => { let op = self.lpop(); if self.cur_is(EOF) { let err = ParseError::expect_next_line_error( line!() as usize, op.loc(), "Assignment", ); self.errs.push(err); return Err(()); } let is_multiline_block = self.cur_is(Newline); let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); let sig = self .convert_rhs_to_sig(lhs) .map_err(|_| self.stack_dec(fn_name!()))?; self.counter.inc(); let block = if is_multiline_block { self.try_reduce_block() .map_err(|_| self.stack_dec(fn_name!()))? } else { // precedence: `=` < `,` let expr = self.try_reduce_expr(true, false, false, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: 式", "simplified_chinese" => "期望: 表达", "traditional_chinese" => "期望: 表達", "english" => "expect: expression", )) } self.stack_dec(fn_name!()) })?; Block::new(vec![expr]) }; let body = DefBody::new(op, block, self.counter); debug_exit_info!(self); return Ok(Expr::Def(Def::new(sig, body))); } Some(op) if op.category_is(TC::LambdaOp) => { let op = self.lpop(); if self.cur_is(EOF) { let err = ParseError::expect_next_line_error( line!() as usize, op.loc(), "Lambda", ); self.errs.push(err); return Err(()); } let is_multiline_block = self.cur_is(Newline); let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); let sig = self .convert_rhs_to_lambda_sig(lhs) .map_err(|_| self.stack_dec(fn_name!()))?; self.counter.inc(); let block = if is_multiline_block { self.try_reduce_block() .map_err(|_| self.stack_dec(fn_name!()))? } else { // precedence: `->` > `,` let expr = self.try_reduce_expr(false, false, false, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: 式", "simplified_chinese" => "期望: 表达", "traditional_chinese" => "期望: 表達", "english" => "expect: expression", )) } self.stack_dec(fn_name!()) })?; Block::new(vec![expr]) }; stack.push(ExprOrOp::Expr(Expr::Lambda(Lambda::new( sig, op, block, self.counter, )))); } // type ascription Some(op) if (op.is(Colon) && !self.nth_is(1, Newline)) || (op.is(SubtypeOf) || op.is(SupertypeOf) || op.is(As)) => { // "a": 1 (key-value pair) if in_brace { while stack.len() >= 3 { collect_last_binop_on_stack(&mut stack); } break; } let op = self.lpop(); let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); let t_spec_as_expr = self .try_reduce_expr(false, false, false, false) .map(Desugarer::desugar_simple_expr) .map_err(|_| self.stack_dec(fn_name!()))?; let t_spec = Self::expr_to_type_spec(t_spec_as_expr.clone()).map_err(|e| { self.errs.push(e); self.stack_dec(fn_name!()) })?; let t_spec_op = TypeSpecWithOp::new(op, t_spec, t_spec_as_expr); let expr = lhs.type_asc_expr(t_spec_op); stack.push(ExprOrOp::Expr(expr)); } Some(op) if op.category_is(TC::BinOp) => { let op_prec = op.kind.precedence(); if stack.len() >= 2 { while let Some(ExprOrOp::Op(prev_op)) = stack.get(stack.len() - 2) { if prev_op.category_is(TC::BinOp) && prev_op.kind.precedence() >= op_prec { collect_last_binop_on_stack(&mut stack); } else { break; } if stack.len() <= 1 { break; } } } stack.push(ExprOrOp::Op(self.lpop())); stack.push(ExprOrOp::Expr( self.try_reduce_bin_lhs(false, in_brace).map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: 数値、式", "simplified_chinese" => "期望: 数字或表达式", "traditional_chinese" => "期望: 數字或表達式", "english" => "expect: number or expression", )); } self.stack_dec(fn_name!()) })?, )); } Some(t) if t.is(DblColon) => { let dcolon = self.lpop(); let token = self.lpop(); match token.kind { Symbol => { let Some(ExprOrOp::Expr(obj)) = stack.pop() else { let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); }; if let Some(args) = self .opt_reduce_args(false) .transpose() .map_err(|_| self.stack_dec(fn_name!()))? { let ident = Identifier::new(VisModifierSpec::Private, VarName::new(token)); let call = Call::new(obj, Some(ident), args); stack.push(ExprOrOp::Expr(Expr::Call(call))); } else { let ident = Identifier::new(VisModifierSpec::Private, VarName::new(token)); stack.push(ExprOrOp::Expr(obj.attr_expr(ident))); } } Newline => { let vis = VisModifierSpec::ExplicitPrivate(dcolon.loc()); let maybe_class = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); let defs = self .try_reduce_class_attr_defs(maybe_class, vis) .map_err(|_| self.stack_dec(fn_name!()))?; let expr = Expr::Methods(defs); assert_eq!(stack.len(), 0); debug_exit_info!(self); return Ok(expr); } LSqBr => { self.restore(token); let restriction = self .try_reduce_restriction() .map_err(|_| self.stack_dec(fn_name!()))?; let vis = VisModifierSpec::Restricted(restriction); expect_pop!(self, Newline); let maybe_class = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); let defs = self .try_reduce_class_attr_defs(maybe_class, vis) .map_err(|_| self.stack_dec(fn_name!()))?; let expr = Expr::Methods(defs); assert_eq!(stack.len(), 0); debug_exit_info!(self); return Ok(expr); } LBrace => { let vis = VisModifierSpec::ExplicitPrivate(dcolon.loc()); let maybe_class = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); self.restore(token); let container = self .try_reduce_brace_container() .map_err(|_| self.stack_dec(fn_name!()))?; match container { BraceContainer::Record(args) => { let pack = DataPack::new(maybe_class, vis, args); stack.push(ExprOrOp::Expr(Expr::DataPack(pack))); } other => { let err = ParseError::invalid_data_pack_definition( line!() as usize, other.loc(), other.kind(), ); self.errs.push(err); debug_exit_info!(self); return Err(()); } } } _ => { self.restore(token); let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); } } } Some(t) if t.is(Dot) => { let dot = self.lpop(); let token = self.lpop(); match token.kind { Symbol => { let Some(ExprOrOp::Expr(obj)) = stack.pop() else { let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); }; if let Some(args) = self .opt_reduce_args(false) .transpose() .map_err(|_| self.stack_dec(fn_name!()))? { let ident = Identifier::public_from_token(dot, token); let call = Expr::Call(Call::new(obj, Some(ident), args)); stack.push(ExprOrOp::Expr(call)); } else { let ident = Identifier::public_from_token(dot, token); stack.push(ExprOrOp::Expr(obj.attr_expr(ident))); } } Newline => { let vis = VisModifierSpec::Public(dot.loc()); let maybe_class = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); let defs = self .try_reduce_class_attr_defs(maybe_class, vis) .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); return Ok(Expr::Methods(defs)); } _ => { self.restore(token); let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); } } } Some(t) if t.is(LSqBr) => { let Some(ExprOrOp::Expr(obj)) = stack.pop() else { let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); }; self.skip(); let index = self .try_reduce_expr(false, false, in_brace, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: Nat型", "simplified_chinese" => "期望: Nat类型", "traditional_chinese" => "期望: Nat類型", "english" => "expect: Nat type", )) } self.stack_dec(fn_name!()) })?; let r_sqbr = expect_pop!(self, fail_next RSqBr); let acc = Accessor::subscr(obj, index, r_sqbr); stack.push(ExprOrOp::Expr(Expr::Accessor(acc))); } Some(t) if t.is(Comma) && winding => { let first_elem = ArgKind::Pos(PosArg::new( enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))), )); let tup = self .try_reduce_nonempty_tuple(first_elem, false) .map_err(|_| self.stack_dec(fn_name!()))?; stack.push(ExprOrOp::Expr(Expr::Tuple(tup))); } Some(t) if t.is(Walrus) && winding => { let tuple = self .try_reduce_default_parameters(&mut stack, in_brace) .map_err(|_| self.stack_dec(fn_name!()))?; stack.push(ExprOrOp::Expr(Expr::Tuple(tuple))); } Some(t) if t.is(Pipe) => self .try_reduce_stream_operator(&mut stack) .map_err(|_| self.stack_dec(fn_name!()))?, Some(t) if t.category_is(TC::Reserved) => { let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); } _ => { if stack.len() <= 1 { break; } // else if stack.len() == 2 { switch_unreachable!() } else { while stack.len() >= 3 { collect_last_binop_on_stack(&mut stack); } } } } } match stack.pop() { Some(ExprOrOp::Expr(expr)) if stack.is_empty() => { debug_exit_info!(self); Ok(expr) } Some(ExprOrOp::Expr(expr)) => { let extra = stack.pop().unwrap(); let loc = match extra { ExprOrOp::Expr(expr) => expr.loc(), ExprOrOp::Op(op) => op.loc(), }; self.warns .push(ParseError::compiler_bug(0, loc, fn_name!(), line!())); debug_exit_info!(self); Ok(expr) } Some(ExprOrOp::Op(op)) => { self.errs .push(ParseError::compiler_bug(0, op.loc(), fn_name!(), line!())); debug_exit_info!(self); Err(()) } _ => switch_unreachable!(), } } /// chunk = expr + def /// winding: true => parse paren-less tuple /// in_brace: true => (1: 1) will not be a syntax error (key-value pair) fn try_reduce_expr( &mut self, winding: bool, in_type_args: bool, in_brace: bool, line_break: bool, ) -> ParseResult { debug_call_info!(self); let mut stack = Vec::::new(); stack.push(ExprOrOp::Expr( self.try_reduce_bin_lhs(in_type_args, in_brace) .map_err(|_| self.stack_dec(fn_name!()))?, )); loop { match self.peek() { Some(op) if op.category_is(TC::LambdaOp) => { let op = self.lpop(); let is_multiline_block = self.cur_is(Newline); let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); let sig = self .convert_rhs_to_lambda_sig(lhs) .map_err(|_| self.stack_dec(fn_name!()))?; self.counter.inc(); if self.cur_is(EOF) { let err = ParseError::expect_next_line_error( line!() as usize, op.loc(), "Lambda", ); self.errs.push(err); return Err(()); } let block = if is_multiline_block { self.try_reduce_block() .map_err(|_| self.stack_dec(fn_name!()))? } else { let expr = self .try_reduce_expr(false, false, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; Block::new(vec![expr]) }; stack.push(ExprOrOp::Expr(Expr::Lambda(Lambda::new( sig, op, block, self.counter, )))); } // type ascription Some(op) if (op.is(Colon) && !self.nth_is(1, Newline)) || (op.is(SubtypeOf) || op.is(SupertypeOf) || op.is(As)) => { // "a": 1 (key-value pair) if in_brace { break; } let op = self.lpop(); if self.cur_is(EOF) { let err = ParseError::expect_next_line_error( line!() as usize, op.loc(), "Lambda", ); self.errs.push(err); return Err(()); } let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); let t_spec_as_expr = self .try_reduce_expr(false, in_type_args, in_brace, false) .map(Desugarer::desugar_simple_expr) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: Nat型", "simplified_chinese" => "期望: Nat类型", "traditional_chinese" => "期望: Nat類型", "english" => "expect: Nat type", )) } self.stack_dec(fn_name!()) })?; let t_spec = Self::expr_to_type_spec(t_spec_as_expr.clone()) .map_err(|e| self.errs.push(e))?; let t_spec_op = TypeSpecWithOp::new(op, t_spec, t_spec_as_expr); let expr = lhs.type_asc_expr(t_spec_op); stack.push(ExprOrOp::Expr(expr)); } Some(op) if op.category_is(TC::BinOp) => { let op_prec = op.kind.precedence(); if stack.len() >= 2 { while let Some(ExprOrOp::Op(prev_op)) = stack.get(stack.len() - 2) { if prev_op.category_is(TC::BinOp) && prev_op.kind.precedence() >= op_prec { let rhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); let prev_op = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Op:(_))); let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); let bin = BinOp::new(prev_op, lhs, rhs); stack.push(ExprOrOp::Expr(Expr::BinOp(bin))); } else { break; } if stack.len() <= 1 { break; } } } stack.push(ExprOrOp::Op(self.lpop())); stack.push(ExprOrOp::Expr( self.try_reduce_bin_lhs(in_type_args, in_brace) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: 式、被演算子", "simplified_chinese" => "期望:表达式或操作数", "traditional_chinese" => "期望:表達式或操作數", "english" => "expect: expression or operand", )) } self.stack_dec(fn_name!()) })?, )); } Some(t) if t.is(Dot) => { let vis = self.lpop(); match self.lpop() { symbol if symbol.is(Symbol) => { let Some(ExprOrOp::Expr(obj)) = stack.pop() else { let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); }; if let Some(args) = self .opt_reduce_args(in_type_args) .transpose() .map_err(|_| self.stack_dec(fn_name!()))? { let ident = Identifier::new( VisModifierSpec::Public(vis.loc()), VarName::new(symbol), ); let call = Call::new(obj, Some(ident), args); stack.push(ExprOrOp::Expr(Expr::Call(call))); } else { let ident = Identifier::new( VisModifierSpec::Public(vis.loc()), VarName::new(symbol), ); stack.push(ExprOrOp::Expr(obj.attr_expr(ident))); } } other => { self.restore(other); let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); } } } Some(t) if t.is(LSqBr) => { let Some(ExprOrOp::Expr(obj)) = stack.pop() else { let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); }; self.skip(); // l_sqbr let index = self .try_reduce_expr(false, false, in_brace, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: Nat型", "simplified_chinese" => "期望: Nat类型", "traditional_chinese" => "期望: Nat類型", "english" => "expect: Nat type", )) } self.stack_dec(fn_name!()); })?; let r_sqbr = self.lpop(); if !r_sqbr.is(RSqBr) { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::expect_accessor(line!() as usize, index.loc()); self.errs.push(err); self.next_expr(); debug_exit_info!(self); return Err(()); } let acc = Accessor::subscr(obj, index, r_sqbr); stack.push(ExprOrOp::Expr(Expr::Accessor(acc))); } Some(t) if t.is(Comma) && winding => { let first_elem = ArgKind::Pos(PosArg::new( enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))), )); let tup = self .try_reduce_nonempty_tuple(first_elem, line_break) .map_err(|_| self.stack_dec(fn_name!()))?; stack.push(ExprOrOp::Expr(Expr::Tuple(tup))); } Some(t) if t.is(Walrus) && winding => { let tuple = self .try_reduce_default_parameters(&mut stack, in_brace) .map_err(|_| self.stack_dec(fn_name!()))?; stack.push(ExprOrOp::Expr(Expr::Tuple(tuple))); } Some(t) if t.is(Pipe) => self .try_reduce_stream_operator(&mut stack) .map_err(|_| self.stack_dec(fn_name!()))?, Some(t) if t.category_is(TC::Reserved) => { let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); } _ => { if stack.len() <= 1 { break; } // else if stack.len() == 2 { switch_unreachable!() } else { while stack.len() >= 3 { collect_last_binop_on_stack(&mut stack); } } } } } match stack.pop() { Some(ExprOrOp::Expr(expr)) if stack.is_empty() => { debug_exit_info!(self); Ok(expr) } Some(ExprOrOp::Expr(expr)) => { let extra = stack.pop().unwrap(); let loc = match extra { ExprOrOp::Expr(expr) => expr.loc(), ExprOrOp::Op(op) => op.loc(), }; self.warns .push(ParseError::compiler_bug(0, loc, fn_name!(), line!())); debug_exit_info!(self); Ok(expr) } Some(ExprOrOp::Op(op)) => { self.errs .push(ParseError::compiler_bug(0, op.loc(), fn_name!(), line!())); debug_exit_info!(self); Err(()) } _ => switch_unreachable!(), } } #[inline] fn try_reduce_default_parameters( &mut self, stack: &mut Vec, in_brace: bool, ) -> ParseResult { debug_call_info!(self); let first_elem = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); let (keyword, t_spec) = match first_elem { Expr::Accessor(Accessor::Ident(ident)) => (ident.name.into_token(), None), Expr::TypeAscription(tasc) => { if let Expr::Accessor(Accessor::Ident(ident)) = *tasc.expr { (ident.name.into_token(), Some(tasc.t_spec)) } else { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::expect_keyword(line!() as usize, tasc.loc()); self.errs.push(err); self.next_expr(); debug_exit_info!(self); return Err(()); } } // foo, arg/*args/**kwargs | := rhs Expr::Tuple(Tuple::Normal(mut tuple)) => { self.skip(); // := let rhs = self .try_reduce_expr(false, false, in_brace, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: デフォルト引数", "simplified_chinese" => "期望: 默认参数", "traditional_chinese" => "期望: 默認參數", "english" => "expect: default parameter", )) } self.stack_dec(fn_name!()) })?; if tuple.elems.kw_var_args.is_some() { tuple.elems.set_kw_var(PosArg::new(rhs)); } else if tuple.elems.var_args.is_some() { tuple.elems.set_var_args(PosArg::new(rhs)); } else { let (kw, t_spec) = match tuple.elems.pos_args.pop().unwrap().expr { Expr::Accessor(Accessor::Ident(ident)) => (ident.name.into_token(), None), Expr::TypeAscription(tasc) => { let kw = if let Expr::Accessor(Accessor::Ident(ident)) = *tasc.expr { ident.name.into_token() } else { Token::symbol("_") }; (kw, Some(tasc.t_spec)) } _ => (Token::symbol("_"), None), }; tuple.elems.push_kw(KwArg::new(kw, t_spec, rhs)); } debug_exit_info!(self); return Ok(Tuple::Normal(tuple)); } other => { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::expect_keyword(line!() as usize, other.loc()); self.errs.push(err); self.next_expr(); debug_exit_info!(self); return Err(()); } }; self.skip(); // := let rhs = self .try_reduce_expr(false, false, in_brace, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: デフォルト引数", "simplified_chinese" => "期望: 默认参数", "traditional_chinese" => "期望: 默認參數", "english" => "expect: default parameter", )) } self.stack_dec(fn_name!()) })?; let first_elem = ArgKind::Kw(KwArg::new(keyword, t_spec, rhs)); let tuple = self .try_reduce_nonempty_tuple(first_elem, self.nth_is(1, Newline)) .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); Ok(tuple) } /// "LHS" is the smallest unit that can be the left-hand side of an BinOp. /// e.g. Call, Name, UnaryOp, Lambda fn try_reduce_bin_lhs(&mut self, in_type_args: bool, in_brace: bool) -> ParseResult { debug_call_info!(self); match self.peek() { Some(t) if &t.inspect()[..] == "do" || &t.inspect()[..] == "do!" => { let lambda = self .try_reduce_do_block() .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); Ok(Expr::Lambda(lambda)) } Some(t) if t.category_is(TC::Literal) => { let lit = self .try_reduce_lit() .map_err(|_| self.stack_dec(fn_name!()))?; if let Some(tk) = self.peek() { if tk.is(Mutate) { self.skip(); let main_msg = switch_lang!( "japanese" => "可変演算子は、後置演算子ではなく前置演算子です ", "simplified_chinese" => "突变运算符是前缀运算符,不是后缀运算符", "traditional_chinese" => "突變運算符是前綴運算符,不是後綴運算符", "english" => "the mutation operator is a prefix operator, not a postfix operator ", ); let lit_loc = lit.loc(); let lit = lit.token.inspect(); let err = ParseError::invalid_token_error( line!() as usize, lit_loc, main_msg, &format!("!{lit}"), &format!("{lit}!"), ); self.errs.push(err); debug_exit_info!(self); return Err(()); } else if lit.is_number() && tk.is(Symbol) { // *-less multiplication (e.g. 3x, 3x.y) let rhs = self.try_reduce_call_or_acc(false)?; let lhs = Expr::Literal(lit); debug_exit_info!(self); let op = Token::dummy(Star, "*"); return Ok(Expr::BinOp(lhs.bin_op(op, rhs))); } else if lit.is_number() && tk.is(LParen) { // *-less multiplication (e.g. 3(4+1), 3(4+1).y) self.lpop(); let rhs = self.try_reduce_expr(false, false, false, false)?; expect_pop!(self, RParen); let lhs = Expr::Literal(lit); debug_exit_info!(self); let op = Token::dummy(Star, "*"); return Ok(Expr::BinOp(lhs.bin_op(op, rhs))); } } debug_exit_info!(self); Ok(Expr::Literal(lit)) } Some(t) if t.is(StrInterpLeft) => { let str_interp = self .try_reduce_string_interpolation() .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); Ok(str_interp) } Some(t) if t.is(AtSign) => { let decos = self.opt_reduce_decorators()?; let expr = self.try_reduce_chunk(false, in_brace).map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "期待: デコレータ", "simplified_chinese" => "期望: 装饰器", "traditional_chinese" => "期望: 裝飾器", "english" => "expect: decorator", )) } self.stack_dec(fn_name!()) })?; let Expr::Def(mut def) = expr else { // self.restore(other); let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); }; match def.sig { Signature::Subr(mut subr) => { subr.decorators = decos; let expr = Expr::Def(Def::new(Signature::Subr(subr), def.body)); debug_exit_info!(self); Ok(expr) } Signature::Var(var) => { let mut last = def.body.block.pop().unwrap(); for deco in decos.into_iter() { last = deco.into_expr().call_expr(Args::single(PosArg::new(last))); } def.body.block.push(last); let expr = Expr::Def(Def::new(Signature::Var(var), def.body)); debug_exit_info!(self); Ok(expr) } } } Some(t) if t.is(Symbol) || t.is(Dot) || t.is(DblColon) || t.is(UBar) => { let call_or_acc = self .try_reduce_call_or_acc(in_type_args) .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); Ok(call_or_acc) } // REVIEW: correct? Some(t) if t.is(PreStar) || t.is(PreDblStar) => { let kind = t.kind; let _ = self.lpop(); let expr = self .try_reduce_expr(false, in_type_args, in_brace, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "期待: 可変長引数", "simplified_chinese" => "期望: 可变长度参数", "traditional_chinese" => "期望: 可變長度參數", "english" => "expect: variable-length arguments", )) } self.stack_dec(fn_name!()) })?; let arg = match kind { PreStar => ArgKind::Var(PosArg::new(expr)), PreDblStar => ArgKind::KwVar(PosArg::new(expr)), _ => switch_unreachable!(), }; let tuple = self .try_reduce_nonempty_tuple(arg, false) .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); Ok(Expr::Tuple(tuple)) } Some(t) if t.category_is(TC::UnaryOp) => { let unaryop = self .try_reduce_unary() .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); Ok(Expr::UnaryOp(unaryop)) } Some(t) if t.is(LParen) => { let lparen = self.lpop(); while self.cur_is(Newline) { self.skip(); } let line_break = if self.cur_is(Indent) { self.skip(); true } else { false }; if self.cur_is(RParen) { let rparen = self.lpop(); let args = Args::pos_only(vec![], Some((lparen.loc(), rparen.loc()))); let unit = Tuple::Normal(NormalTuple::new(args)); debug_exit_info!(self); return Ok(Expr::Tuple(unit)); } let mut expr = self .try_reduce_expr(true, false, false, line_break) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "期待: 要素", "simplified_chinese" => "期望: 元素", "traditional_chinese" => "期望: 元素", "english" => "expect: an element", )) } self.stack_dec(fn_name!()) })?; if line_break { while self.cur_is(Newline) { self.skip(); } if self.cur_is(Dedent) { self.skip(); } } let rparen = match self.peek_kind() { Some(RParen) => self.lpop(), Some(_) => { let err = self.skip_and_throw_invalid_unclosed_err( caused_by!(), line!(), ")", "tuple", ); self.errs.push(err); return Err(()); } None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); return Err(()); } }; if let Expr::Tuple(Tuple::Normal(tup)) = &mut expr { tup.elems.paren = Some((lparen.loc(), rparen.loc())); } debug_exit_info!(self); Ok(expr) } Some(t) if t.is(LSqBr) => { let list = self .try_reduce_list() .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); Ok(Expr::List(list)) } Some(t) if t.is(LBrace) => { match self .try_reduce_brace_container() .map_err(|_| self.stack_dec(fn_name!()))? { BraceContainer::Dict(dic) => { debug_exit_info!(self); Ok(Expr::Dict(dic)) } BraceContainer::Record(rec) => { debug_exit_info!(self); Ok(Expr::Record(rec)) } BraceContainer::Set(set) => { debug_exit_info!(self); Ok(Expr::Set(set)) } } } Some(t) if t.is(VBar) => { let type_args = self .try_reduce_type_app_args() .map_err(|_| self.stack_dec(fn_name!()))?; let bounds = self .convert_type_args_to_bounds(type_args) .map_err(|_| self.stack_dec(fn_name!()))?; let args = self .try_reduce_args(false) .map_err(|_| self.stack_dec(fn_name!()))?; let params = self .convert_args_to_params(args) .map_err(|_| self.stack_dec(fn_name!()))?; let sig = LambdaSignature::new(params, None, bounds); let op = expect_pop!(self, category TC::LambdaOp); let block = self .try_reduce_block() .map_err(|_| self.stack_dec(fn_name!()))?; self.counter.inc(); let lambda = Lambda::new(sig, op, block, self.counter); debug_exit_info!(self); Ok(Expr::Lambda(lambda)) } Some(t) if t.is(UBar) => { let token = self.lpop(); let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); self.errs.push(ParseError::feature_error( line!() as usize, token.loc(), "discard pattern", )); debug_exit_info!(self); Err(()) } Some(_other) => { let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); Err(()) } None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); Err(()) } } } #[inline] fn try_reduce_call_or_acc(&mut self, in_type_args: bool) -> ParseResult { debug_call_info!(self); let acc = self .try_reduce_acc_lhs() .map_err(|_| self.stack_dec(fn_name!()))?; let mut call_or_acc = self .try_reduce_acc_chain(acc, in_type_args) .map_err(|_| self.stack_dec(fn_name!()))?; while let Some(res) = self.opt_reduce_args(in_type_args) { let args = res.map_err(|_| self.stack_dec(fn_name!()))?; let call = call_or_acc.call(args); call_or_acc = Expr::Call(call); } debug_exit_info!(self); Ok(call_or_acc) } /// [y], .0, .attr, .method(...), (...) #[inline] fn try_reduce_acc_chain(&mut self, acc: Accessor, in_type_args: bool) -> ParseResult { debug_call_info!(self); let mut obj = Expr::Accessor(acc); loop { match self.peek() { Some(t) if t.is(LSqBr) && obj.col_end() == t.col_begin() => { let _l_sqbr = self.lpop(); let index = self .try_reduce_expr(true, false, false, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "期待: Nat型", "simplified_chinese" => "期望: Nat类型", "traditional_chinese" => "期望: Nat類型", "english" => "expect: Nat type", )) } self.stack_dec(fn_name!()) })?; let r_sqbr = expect_pop!(self, fail_next RSqBr); obj = Expr::Accessor(Accessor::subscr(obj, index, r_sqbr)); } Some(t) if t.is(Dot) && obj.col_end() == t.col_begin() => { let vis = self.lpop(); let token = self.lpop(); match token.kind { Symbol => { let ident = Identifier::new( VisModifierSpec::Public(vis.loc()), VarName::new(token), ); obj = obj.attr_expr(ident); } NatLit => { let index = Literal::from(token); obj = obj.tuple_attr_expr(index); } Newline => { self.restore(token); self.restore(vis); break; } EOF => { let err = ParseError::expect_next_line_error( line!() as usize, token.loc(), "ClassPub", ); self.errs.push(err); self.restore(token); self.level -= 1; return Err(()); } _ => { let err = ParseError::invalid_acc_chain( line!() as usize, token.loc(), &token.inspect()[..], ); self.errs.push(err); debug_exit_info!(self); return Err(()); } } } // e.g. l[0].0 Some(t) if t.is(RatioLit) && obj.col_end() == t.col_begin() => { let mut token = self.lpop(); token.content = Str::rc(&token.content[1..]); token.kind = NatLit; token.col_begin += 1; obj = obj.tuple_attr_expr(Literal::from(token)); } Some(t) if t.is(DblColon) && obj.col_end() == t.col_begin() => { let vis = self.lpop(); let token = self.lpop(); match token.kind { Symbol => { let ident = Identifier::new( VisModifierSpec::ExplicitPrivate(vis.loc()), VarName::new(token), ); obj = obj.attr_expr(ident); } LBrace => { self.restore(token); let args = self .try_reduce_brace_container() .map_err(|_| self.stack_dec(fn_name!()))?; match args { BraceContainer::Record(args) => { let vis = VisModifierSpec::ExplicitPrivate(vis.loc()); obj = Expr::DataPack(DataPack::new(obj, vis, args)); } other => { let err = ParseError::invalid_data_pack_definition( line!() as usize, other.loc(), other.kind(), ); self.errs.push(err); debug_exit_info!(self); return Err(()); } } } // MethodDefs Newline | LSqBr => { self.restore(token); self.restore(vis); break; } EOF => { let err = ParseError::expect_next_line_error( line!() as usize, token.loc(), "ClassPriv", ); self.errs.push(err); self.restore(token); self.level -= 1; return Err(()); } _ => { self.restore(token); let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); } } } Some(t) if t.is(LParen) && obj.col_end() == t.col_begin() => { let args = self .try_reduce_args(false) .map_err(|_| self.stack_dec(fn_name!()))?; let (receiver, attr_name) = match obj { Expr::Accessor(Accessor::Attr(attr)) => (*attr.obj, Some(attr.ident)), other => (other, None), }; let call = Call::new(receiver, attr_name, args); obj = Expr::Call(call); } Some(t) if t.is(VBar) && !in_type_args && !self.nth_is(2, Inclusion) => { let type_args = self .try_reduce_type_app_args() .map_err(|_| self.stack_dec(fn_name!()))?; obj = Expr::Accessor(Accessor::TypeApp(TypeApp::new(obj, type_args))); } _ => { break; } } } debug_exit_info!(self); Ok(obj) } #[inline] fn try_reduce_unary(&mut self) -> ParseResult { debug_call_info!(self); let op = self.lpop(); let expr = self .try_reduce_expr(false, false, false, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: 式", "simplified_chinese" => "期待:表达式", "traditional_chinese" => "期待:表達式", "english" => "expect: expression", )) } self.stack_dec(fn_name!()) })?; debug_exit_info!(self); Ok(UnaryOp::new(op, expr)) } #[inline] fn try_reduce_list(&mut self) -> ParseResult { debug_call_info!(self); let l_sqbr = expect_pop!(self, fail_next LSqBr); let inner = self .try_reduce_list_elems() .map_err(|_| self.stack_dec(fn_name!()))?; let r_sqbr = expect_pop!(self, fail_next RSqBr); let lis = match inner { ListInner::Normal(mut elems) => { let elems = if elems .pos_args() .first() .map(|pos| match &pos.expr { Expr::Tuple(tup) => tup.paren().is_none(), _ => false, }) .unwrap_or(false) { enum_unwrap!(elems.remove_pos(0).expr, Expr::Tuple:(Tuple::Normal:(_))).elems } else { elems }; List::Normal(NormalList::new(l_sqbr, r_sqbr, elems)) } ListInner::WithLength(elem, len) => { List::WithLength(ListWithLength::new(l_sqbr, r_sqbr, elem, len)) } ListInner::Comprehension { layout, generators, guard, } => List::Comprehension(ListComprehension::new( l_sqbr, r_sqbr, layout, generators, guard, )), }; debug_exit_info!(self); Ok(lis) } /// Set, Dict, Record fn try_reduce_brace_container(&mut self) -> ParseResult { debug_call_info!(self); let l_brace = expect_pop!(self, fail_next LBrace); if self.cur_is(EOF) { let err = ParseError::expect_next_line_error(line!() as usize, l_brace.loc(), "Collections"); self.errs.push(err); return Err(()); } // Empty brace literals match self.peek_kind() { Some(RBrace) => { let r_brace = self.lpop(); let arg = Args::empty(); let set = NormalSet::new(l_brace, r_brace, arg); debug_exit_info!(self); return Ok(BraceContainer::Set(Set::Normal(set))); } Some(Assign) => { let _eq = self.lpop(); if let Some(t) = self.peek() { if t.is(RBrace) { let r_brace = self.lpop(); debug_exit_info!(self); return Ok(BraceContainer::Record(Record::empty(l_brace, r_brace))); } } else { let caused_by = caused_by!(); let err = self.unexpected_none(line!(), caused_by); self.errs.push(err); return Err(()); } let t = self.lpop(); let mut err = ParseError::invalid_token_error( line!() as usize, t.loc(), switch_lang!( "japanese" => "無効なレコードの宣言です", "simplified_chinese" => "无效的Record定义", "traditional_chinese" => "無效的Record定義", "english" => "invalid record", ), "}", &t.inspect()[..], ); err.set_hint(switch_lang!( "japanese" => "空のレコードが期待されています: {=}", "simplified_chinese" => "期望空Record: {=}", "traditional_chinese" => "期望空Record: {=}", "english" => "expect empty record: {=}", )); self.errs.push(err); debug_exit_info!(self); return Err(()); } Some(Colon) => { let _colon = self.lpop(); if let Some(t) = self.peek() { if t.is(RBrace) { let r_brace = self.lpop(); let dict = NormalDict::new(l_brace, r_brace, vec![]); debug_exit_info!(self); return Ok(BraceContainer::Dict(Dict::Normal(dict))); } } else { let caused_by = caused_by!(); let err = self.unexpected_none(line!(), caused_by); self.errs.push(err); return Err(()); } let t = self.lpop(); let mut err = ParseError::invalid_token_error( line!() as usize, t.loc(), switch_lang!( "japanese" => "無効な辞書の宣言です", "simplified_chinese" => "无效的字典定义", "traditional_chinese" => "無效的字典定義", "english" => "invalid dict", ), "}", &t.inspect()[..], ); err.set_hint(switch_lang!( "japanese" => "空の辞書が期待されています: {:}", "simplified_chinese" => "期望空字典: {:}", "traditional_chinese" => "期望空字典: {:}", "english" => "expect empty dict: {:}", )); self.errs.push(err); debug_exit_info!(self); return Err(()); } _ => {} } let first = self.try_reduce_chunk(false, true).map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "期待: 要素", "simplified_chinese" => "期望: 元素", "traditional_chinese" => "期望: 元素", "english" => "expect: an element", )) } self.stack_dec(fn_name!()) })?; match first { Expr::Def(def) => { let attr = RecordAttrOrIdent::Attr(def); let record = self .try_reduce_record(l_brace, attr) .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); Ok(BraceContainer::Record(record)) } // TODO: {X; Y} will conflict with Set Expr::Accessor(acc) if self.cur_is(Semi) && !self.nth_is(1, TokenKind::NatLit) && !self.nth_is(1, UBar) => { let ident = match acc { Accessor::Ident(ident) => ident, other => { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::invalid_record_element_err(line!() as usize, other.loc()); self.errs.push(err); self.next_expr(); debug_exit_info!(self); return Err(()); } }; let attr = RecordAttrOrIdent::Ident(ident); let record = self .try_reduce_record(l_brace, attr) .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); Ok(BraceContainer::Record(record)) } other => { match self.peek_kind() { Some(Colon) => { let res = self .try_reduce_normal_dict_or_refine_type(l_brace, other) .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); return Ok(res); } Some(Inclusion) => { self.skip(); let mut generators = vec![]; let Expr::Accessor(Accessor::Ident(ident)) = other else { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::invalid_record_element_err( line!() as usize, other.loc(), ); self.errs.push(err); self.next_expr(); debug_exit_info!(self); return Err(()); }; let expr = self .try_reduce_expr(false, false, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; generators.push((ident, expr)); let _ = expect_pop!(self, VBar); let guard = self .try_reduce_expr(false, false, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; let r_brace = expect_pop!(self, fail_next RBrace); debug_exit_info!(self); let comp = SetComprehension::new(l_brace, r_brace, None, generators, Some(guard)); return Ok(BraceContainer::Set(Set::Comprehension(comp))); } Some(VBar) => { self.skip(); let mut generators = vec![]; loop { let ident = self.try_reduce_ident()?; let _ = expect_pop!(self, fail_next Inclusion); let expr = self .try_reduce_expr(false, false, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; generators.push((ident, expr)); if self.cur_is(Semi) { self.skip(); } else { break; } } let guard = if self.cur_is(VBar) { self.skip(); let expr = self .try_reduce_expr(false, false, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; Some(expr) } else { None }; let r_brace = expect_pop!(self, fail_next RBrace); debug_exit_info!(self); let comp = SetComprehension::new(l_brace, r_brace, Some(other), generators, guard); return Ok(BraceContainer::Set(Set::Comprehension(comp))); } Some(RBrace) => { let arg = Args::new(vec![PosArg::new(other)], None, vec![], None, None); let r_brace = self.lpop(); debug_exit_info!(self); return Ok(BraceContainer::Set(Set::Normal(NormalSet::new( l_brace, r_brace, arg, )))); } _ => {} } let set = self .try_reduce_set(l_brace, other) .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); Ok(BraceContainer::Set(set)) } } } // Note that this accepts: // - {x=expr;y=expr;...} // - {x;y} // - {x;y=expr} (shorthand/normal mixed) fn try_reduce_record( &mut self, l_brace: Token, first_attr: RecordAttrOrIdent, ) -> ParseResult { debug_call_info!(self); let mut attrs = vec![first_attr]; loop { match self.peek_kind() { Some(Newline | Semi) => { self.skip(); match self.peek() { Some(t) if t.is(Semi) => { let err = self.skip_and_throw_invalid_seq_err( caused_by!(), line!() as usize, &["}", "element"], Semi, ); self.errs.push(err); debug_exit_info!(self); return Err(()); } Some(_) => {} None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); return Err(()); } } } Some(Dedent) => { self.skip(); let r_brace = expect_pop!(self, fail_next RBrace); debug_exit_info!(self); return Ok(Record::new_mixed(l_brace, r_brace, attrs)); } Some(RBrace) => { let r_brace = self.lpop(); debug_exit_info!(self); return Ok(Record::new_mixed(l_brace, r_brace, attrs)); } Some(_) => { let next = self.try_reduce_chunk(false, false).map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: 属性", "simplified_chinese" => "期望: 属性", "traditional_chinese" => "期望: 屬性", "english" => "expect: an attribute", )) } self.stack_dec(fn_name!()) })?; match next { Expr::Def(def) => { if attrs.iter().any(|attr| { attr.ident() .zip(def.sig.ident()) .is_some_and(|(l, r)| l == r) }) { self.warns.push(ParseError::duplicate_elem_warning( line!() as usize, def.sig.loc(), def.sig.to_string(), )); } attrs.push(RecordAttrOrIdent::Attr(def)); } Expr::Accessor(acc) => { let ident = match acc { Accessor::Ident(ident) => ident, other => { let err = ParseError::invalid_record_element_err( line!() as usize, other.loc(), ); self.errs.push(err); debug_exit_info!(self); return Err(()); } }; attrs.push(RecordAttrOrIdent::Ident(ident)); } other => { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::invalid_record_element_err( line!() as usize, other.loc(), ); self.errs.push(err); self.next_expr(); debug_exit_info!(self); return Err(()); } } } None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); return Err(()); } } } } fn try_reduce_normal_dict_or_refine_type( &mut self, l_brace: Token, lhs: Expr, ) -> ParseResult { debug_call_info!(self); let _colon = expect_pop!(self, fail_next Colon); let rhs = self .try_reduce_expr(false, true, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; if self.cur_is(VBar) { self.skip(); let Expr::Accessor(Accessor::Ident(var)) = lhs else { let err = ParseError::simple_syntax_error(line!() as usize, lhs.loc()); self.errs.push(err); debug_exit_info!(self); return Err(()); }; let generators = vec![(var, rhs)]; let guard = self .try_reduce_chunk(false, false) .map_err(|_| self.stack_dec(fn_name!()))?; let r_brace = expect_pop!(self, fail_next RBrace); let set_comp = SetComprehension::new(l_brace, r_brace, None, generators, Some(guard)); debug_exit_info!(self); Ok(BraceContainer::Set(Set::Comprehension(set_comp))) } else { let dict = self .try_reduce_normal_dict(l_brace, lhs, rhs) .map_err(|_| self.stack_dec(fn_name!()))?; debug_exit_info!(self); Ok(BraceContainer::Dict(Dict::Normal(dict))) } } fn try_reduce_normal_dict( &mut self, l_brace: Token, first_key: Expr, value: Expr, ) -> ParseResult { debug_call_info!(self); let mut kvs = vec![KeyValue::new(first_key, value)]; loop { match self.peek_kind() { Some(Comma) => { self.skip(); match self.peek_kind() { Some(Comma) => { let err = self.skip_and_throw_invalid_seq_err( caused_by!(), line!() as usize, &["}", "element"], Comma, ); self.errs.push(err); debug_exit_info!(self); return Err(()); } Some(RBrace) => { let dict = NormalDict::new(l_brace, self.lpop(), kvs); debug_exit_info!(self); return Ok(dict); } Some(Newline) => { self.skip(); } _ => {} } let key = self .try_reduce_expr(false, false, true, false) .map_err(|_| self.stack_dec(fn_name!()))?; expect_pop!(self, fail_next Colon); let value = self.try_reduce_chunk(false, false).map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: キー", "simplified_chinese" => "期望: 关键", "traditional_chinese" => "期望: 關鍵", "english" => "expect: key", )) } self.stack_dec(fn_name!()) })?; kvs.push(KeyValue::new(key, value)); } Some(Newline | Indent | Dedent) => { self.skip(); } Some(RBrace) => { let dict = NormalDict::new(l_brace, self.lpop(), kvs); debug_exit_info!(self); return Ok(dict); } Some(_) => { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::unclosed_error( line!() as usize, self.lpop().loc(), "}", "dict", ); self.errs.push(err); debug_exit_info!(self); return Err(()); } _ => break, } } let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); debug_exit_info!(self); Err(()) } fn try_reduce_set(&mut self, l_brace: Token, first_elem: Expr) -> ParseResult { debug_call_info!(self); if self.cur_is(Semi) { match first_elem { Expr::Accessor(_) => {} other => { let err = ParseError::expect_type_specified(line!() as usize, other.loc()); self.errs.push(err); debug_exit_info!(self); return Err(()); } } self.skip(); let len = self .try_reduce_expr(false, false, false, false) .map_err(|_| { if let Some(err) = self.errs.last_mut() { err.set_hint(switch_lang!( "japanese" => "予期: }か要素", "simplified_chinese" => "期望: }或元素", "traditional_chinese" => "期望: }或元素", "english" => "expect: } or element", )) } self.stack_dec(fn_name!()) })?; let r_brace = self.lpop(); if !r_brace.is(RBrace) { let err = self.skip_and_throw_invalid_unclosed_err( caused_by!(), line!(), "}", "set type specification", ); self.errs.push(err); debug_exit_info!(self); return Err(()); } return Ok(Set::WithLength(SetWithLength::new( l_brace, r_brace, PosArg::new(first_elem), len, ))); } let mut args = Args::single(PosArg::new(first_elem)); loop { match self.peek_kind() { Some(Comma) => { self.skip(); match self.peek_kind() { Some(Comma) => { let err = self.skip_and_throw_invalid_seq_err( caused_by!(), line!() as usize, &["}", "element"], Comma, ); self.errs.push(err); debug_exit_info!(self); return Err(()); } Some(RBrace) => { let set = Set::Normal(NormalSet::new(l_brace, self.lpop(), args)); debug_exit_info!(self); return Ok(set); } Some(Newline | Indent | Dedent) => { self.skip(); } _ => {} } match self .try_reduce_arg(false) .map_err(|_| self.stack_dec(fn_name!()))? { ArgKind::Pos(arg) => match arg.expr { Expr::Set(Set::Normal(set)) if set.elems.paren.is_none() => { args.extend_pos(set.elems.into_iters().0); } other => { let pos = PosArg::new(other); if !args.has_pos_arg(&pos) { args.push_pos(pos); } } }, ArgKind::Var(var) | ArgKind::KwVar(var) => { let err = ParseError::simple_syntax_error(line!() as usize, var.loc()); self.errs.push(err); debug_exit_info!(self); return Err(()); } ArgKind::Kw(arg) => { let err = ParseError::simple_syntax_error(line!() as usize, arg.loc()); self.errs.push(err); debug_exit_info!(self); return Err(()); } } } Some(Newline | Indent | Dedent) => { self.skip(); } Some(RBrace) => { let set = Set::Normal(NormalSet::new(l_brace, self.lpop(), args)); debug_exit_info!(self); return Ok(set); } Some(other) => { let err = self.skip_and_throw_invalid_seq_err( caused_by!(), line!() as usize, &["}", "element"], other, ); self.errs.push(err); debug_exit_info!(self); return Err(()); } None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); return Err(()); } } } } fn try_reduce_nonempty_tuple( &mut self, first_elem: ArgKind, line_break: bool, ) -> ParseResult { debug_call_info!(self); let mut args = match first_elem { ArgKind::Pos(pos) => Args::single(pos), ArgKind::Var(var) => Args::new(vec![], Some(var), vec![], None, None), ArgKind::Kw(kw) => Args::new(vec![], None, vec![kw], None, None), ArgKind::KwVar(kw_var) => Args::new(vec![], None, vec![], Some(kw_var), None), }; #[allow(clippy::while_let_loop)] loop { match self.peek_kind() { Some(Comma) => { self.skip(); while self.cur_is(Newline) && line_break { self.skip(); } if self.cur_is(Comma) { let err = self.skip_and_throw_invalid_seq_err( caused_by!(), line!() as usize, &[")", "element"], Comma, ); self.errs.push(err); debug_exit_info!(self); return Err(()); } else if self.cur_is(Dedent) || self.cur_is(RParen) { break; } match self .try_reduce_arg(false) .map_err(|_| self.stack_dec(fn_name!()))? { ArgKind::Pos(arg) if args.kw_is_empty() && args.var_args.is_none() => { match arg.expr { Expr::Tuple(Tuple::Normal(tup)) if tup.elems.paren.is_none() => { args.extend_pos(tup.elems.into_iters().0); } other => { args.push_pos(PosArg::new(other)); } } } ArgKind::Var(var) => { args.set_var_args(var); } ArgKind::Pos(arg) => { let err = ParseError::syntax_error( line!() as usize, arg.loc(), switch_lang!( "japanese" => "非デフォルト引数はデフォルト引数の後に指定できません", "simplified_chinese" => "不能在默认参数之后指定非默认参数", "traditional_chinese" => "不能在默認參數之後指定非默認參數", "english" => "Non-default arguments cannot be specified after default arguments", ), None, ); self.errs.push(err); self.next_expr(); debug_exit_info!(self); return Err(()); } // e.g. (x, y:=1) -> ... // Syntax error will occur when trying to use it as a tuple ArgKind::Kw(arg) => { args.push_kw(arg); } ArgKind::KwVar(arg) => { args.set_kw_var(arg); } } } Some(_other) => { break; } None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); return Err(()); } } } let tup = Tuple::Normal(NormalTuple::new(args)); debug_exit_info!(self); Ok(tup) } #[inline] fn try_reduce_lit(&mut self) -> ParseResult { debug_call_info!(self); match self.peek() { Some(t) if t.category_is(TC::Literal) => Ok(Literal::from(self.lpop())), Some(other) => { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::unexpected_token_error( line!() as usize, other.loc(), &other.inspect()[..], ); self.errs.push(err); debug_exit_info!(self); Err(()) } None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); Err(()) } } } /// "...\{, expr, }..." ==> "..." + str(expr) + "..." /// "...\{, expr, }..." ==> "..." + str(expr) + "..." fn try_reduce_string_interpolation(&mut self) -> ParseResult { debug_call_info!(self); let mut left = self.lpop(); left.content = Str::from(left.content.trim_end_matches("\\{").to_string() + "\""); left.kind = StrLit; let mut expr = Expr::Literal(Literal::from(left)); loop { match self.peek() { Some(l) if l.is(StrInterpRight) => { let mut right = self.lpop(); right.content = Str::from(format!("\"{}", right.content.trim_start_matches('}'))); right.kind = StrLit; let right = Expr::Literal(Literal::from(right)); let op = Token::new_fake( Plus, "+", right.ln_begin().unwrap_or(0), right.col_begin().unwrap_or(0), right.col_end().unwrap_or(0), ); expr = Expr::BinOp(BinOp::new(op, expr, right)); debug_exit_info!(self); return Ok(expr); } Some(t) if t.is(EOF) => { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::syntax_error( line!() as usize, expr.loc(), switch_lang!( "japanese" => "文字列補間の終わりが見つかりませんでした", "simplified_chinese" => "未找到字符串的结束插值", "traditional_chinese" => "未找到字符串的結束插值", "english" => "end of a string interpolation not found", ), None, ); self.errs.push(err); debug_exit_info!(self); return Err(()); } Some(_) => { let mid_expr = self .try_reduce_expr(true, false, false, false) .map_err(|_| self.stack_dec(fn_name!()))?; let str_func = Expr::local( "str", mid_expr.ln_begin().unwrap_or(0), mid_expr.col_begin().unwrap_or(0), mid_expr.col_end().unwrap_or(0), ); let call = Call::new(str_func, None, Args::single(PosArg::new(mid_expr))); let op = Token::new_fake( Plus, "+", call.ln_begin().unwrap_or(0), call.col_begin().unwrap_or(0), call.col_end().unwrap_or(0), ); let bin = BinOp::new(op, expr, Expr::Call(call)); expr = Expr::BinOp(bin); if self.cur_is(StrInterpMid) { let mut mid = self.lpop(); mid.content = Str::from(format!( "\"{}\"", mid.content.trim_start_matches('}').trim_end_matches("\\{") )); mid.kind = StrLit; let mid = Expr::Literal(Literal::from(mid)); let op = Token::new_fake( Plus, "+", mid.ln_begin().unwrap_or(0), mid.col_begin().unwrap_or(0), mid.col_end().unwrap_or(0), ); expr = Expr::BinOp(BinOp::new(op, expr, mid)); } } None => { self.errs.push(self.unexpected_none(line!(), caused_by!())); debug_exit_info!(self); return Err(()); } } } } /// x |> f() => f(x) fn try_reduce_stream_operator(&mut self, stack: &mut Vec) -> ParseResult<()> { debug_call_info!(self); let op = self.lpop(); while stack.len() >= 3 { collect_last_binop_on_stack(stack); } if stack.len() == 2 { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::compiler_bug(0, op.loc(), fn_name!(), line!()); self.errs.push(err); debug_exit_info!(self); return Err(()); } if matches!(self.peek_kind(), Some(Dot)) { // obj |> .method(...) let vis = self.lpop(); match self.lpop() { symbol if symbol.is(Symbol) => { let Some(ExprOrOp::Expr(obj)) = stack.pop() else { let err = self.skip_and_throw_syntax_err(line!(), caused_by!()); self.errs.push(err); debug_exit_info!(self); return Err(()); }; if let Some(args) = self .opt_reduce_args(false) .transpose() .map_err(|_| self.stack_dec(fn_name!()))? { let ident = Identifier::new( VisModifierSpec::Public(vis.loc()), VarName::new(symbol), ); let mut call = Expr::Call(Call::new(obj, Some(ident), args)); while let Some(res) = self.opt_reduce_args(false) { let args = res.map_err(|_| self.stack_dec(fn_name!()))?; call = call.call_expr(args); } stack.push(ExprOrOp::Expr(call)); } else { let err = self.get_stream_op_syntax_error( line!() as usize, obj.loc(), caused_by!(), ); self.errs.push(err); debug_exit_info!(self); return Err(()); } } other => { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = ParseError::expect_method_error(line!() as usize, other.loc()); self.errs.push(err); debug_exit_info!(self); return Err(()); } } } else { let expect_call = self .try_reduce_call_or_acc(false) .map_err(|_| self.stack_dec(fn_name!()))?; let Expr::Call(mut call) = expect_call else { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); let err = self.get_stream_op_syntax_error( line!() as usize, expect_call.loc(), caused_by!(), ); self.errs.push(err); debug_exit_info!(self); return Err(()); }; let ExprOrOp::Expr(first_arg) = stack.pop().unwrap() else { let caused_by = caused_by!(); log!(err "error caused by: {caused_by}"); self.errs.push(ParseError::compiler_bug( line!() as usize, call.loc(), fn_name!(), line!(), )); debug_exit_info!(self); return Err(()); }; call.args.insert_pos(0, PosArg::new(first_arg)); stack.push(ExprOrOp::Expr(Expr::Call(call))); } debug_exit_info!(self); Ok(()) } } fn collect_last_binop_on_stack(stack: &mut Vec) { let rhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); let op = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Op:(_))); let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); let bin = BinOp::new(op, lhs, rhs); stack.push(ExprOrOp::Expr(Expr::BinOp(bin))); }