//! implements `Parser`. //! //! パーサーを実装する //! use std::fmt::Debug; use std::mem; use erg_common::color::{GREEN, RED, RESET}; use erg_common::config::ErgConfig; use erg_common::config::Input; use erg_common::error::Location; use erg_common::set::Set; use erg_common::traits::Runnable; use erg_common::traits::{Locational, Stream}; use erg_common::Str; use erg_common::{ caused_by, debug_power_assert, enum_unwrap, fn_name, log, set, switch_lang, switch_unreachable, }; use crate::ast::*; use crate::desugar::Desugarer; use crate::error::{ParseError, ParseErrors, ParseResult, ParserRunnerError, ParserRunnerErrors}; use crate::lex::Lexer; use crate::token::{Token, TokenCategory, TokenKind, TokenStream}; use TokenCategory as TC; use TokenKind::*; /// Display the name of the called function for debugging the parser macro_rules! debug_call_info { ($self: ident) => { $self.level += 1; log!( "[DEBUG]\n{} ({}) entered {}, cur: {}", " ".repeat($self.level), $self.level, fn_name!(), $self.peek().unwrap() ); }; } enum ExprOrOp { Expr(Expr), Op(Token), } enum PosOrKwArg { Pos(PosArg), Kw(KwArg), } pub enum Side { LhsAssign, LhsLambda, Rhs, } pub enum ArrayInner { Normal(Args), WithLength(PosArg, Expr), Comprehension { elem: PosArg, generators: Vec<(Local, Expr)>, guards: Vec, }, } /// Perform recursive descent parsing. /// /// To enhance error descriptions, the parsing process will continue as long as it's not fatal. #[derive(Debug)] pub struct Parser { counter: DefId, level: usize, // nest level (for debugging) tokens: TokenStream, warns: ParseErrors, errs: ParseErrors, } impl Parser { const fn new(ts: TokenStream) -> Self { Self { counter: DefId(0), level: 0, tokens: ts, warns: ParseErrors::empty(), errs: ParseErrors::empty(), } } #[inline] fn peek(&self) -> Option<&Token> { self.tokens.get(0) } #[inline] fn nth(&self, idx: usize) -> Option<&Token> { self.tokens.get(idx) } #[inline] fn skip(&mut self) { self.tokens.remove(0); } #[inline] fn lpop(&mut self) -> Token { self.tokens.remove(0) } 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) } fn nth_category(&self, idx: usize) -> Option { self.nth(idx).map(|t| t.category()) } /// `+1`: true /// `+ 1`: false /// `F()`: true /// `F ()`: false fn cur_is_in_contact_with_next(&self) -> bool { let cur_loc = self.peek().unwrap().ln_end().unwrap(); let next_loc = self.nth(1).unwrap().ln_end().unwrap(); cur_loc + 1 == next_loc } /// returns if the current position is a left-hand side value. /// /// ``` /// f(x: Int) = { y = x+1; z = [v: Int, w: Int] -> w + x } /// LhsAssign | Rhs | LhsLambda | Rhs /// ``` /// `(Rhs) ; (LhsAssign) =` /// `(Rhs) ; (LhsLambda) ->` /// `(Rhs) , (LhsLambda) ->` /// `(Rhs) (LhsLambda) -> (Rhs);` fn cur_side(&self) -> Side { // 以降に=, ->などがないならすべて右辺値 let opt_equal_pos = self.tokens.iter().skip(1).position(|t| t.is(Equal)); let opt_arrow_pos = self .tokens .iter() .skip(1) .position(|t| t.category_is(TC::LambdaOp)); let opt_sep_pos = self .tokens .iter() .skip(1) .position(|t| t.category_is(TC::Separator)); match (opt_equal_pos, opt_arrow_pos, opt_sep_pos) { (Some(equal), Some(arrow), Some(sep)) => { let min = [equal, arrow, sep].into_iter().min().unwrap(); if min == sep { Side::Rhs } else if min == equal { Side::LhsAssign } else { // (cur) -> ... = ... ; if equal < sep { Side::LhsAssign } // (cur) -> ... ; ... = else if self.arrow_distance(0, 0) == 1 { Side::LhsLambda } else { Side::Rhs } } } // (cur) = ... -> ... // (cur) -> ... = ... (Some(_eq), Some(_arrow), None) => Side::LhsAssign, // (cur) = ... ; // (cur) ; ... = (Some(equal), None, Some(sep)) => { if equal < sep { Side::LhsAssign } else { Side::Rhs } } (None, Some(arrow), Some(sep)) => { // (cur) -> ... ; if arrow < sep { if self.arrow_distance(0, 0) == 1 { Side::LhsLambda } else { Side::Rhs } } // (cur) ; ... -> else { Side::Rhs } } (Some(_eq), None, None) => Side::LhsAssign, (None, Some(_arrow), None) => { if self.arrow_distance(0, 0) == 1 { Side::LhsLambda } else { Side::Rhs } } (None, None, Some(_)) | (None, None, None) => Side::Rhs, } } /// `->`: 0 /// `i ->`: 1 /// `i: Int ->`: 1 /// `a: Array(Int) ->`: 1 /// `(i, j) ->`: 1 /// `F () ->`: 2 /// `F() ->`: 1 /// `if True, () ->`: 3 fn arrow_distance(&self, cur: usize, enc_nest_level: usize) -> usize { match self.nth_category(cur).unwrap() { TC::LambdaOp => 0, TC::LEnclosure => { if self.nth_category(cur + 1).unwrap() == TC::REnclosure { 1 + self.arrow_distance(cur + 2, enc_nest_level) } else { self.arrow_distance(cur + 1, enc_nest_level + 1) } } TC::REnclosure => self.arrow_distance(cur + 1, enc_nest_level - 1), _ => match self.nth_category(cur + 1).unwrap() { TC::SpecialBinOp => self.arrow_distance(cur + 1, enc_nest_level), TC::LEnclosure if self.cur_is_in_contact_with_next() => { self.arrow_distance(cur + 2, enc_nest_level + 1) } _ if enc_nest_level == 0 => 1 + self.arrow_distance(cur + 1, enc_nest_level), _ => self.arrow_distance(cur + 1, enc_nest_level), }, } } /// 解析を諦めて次の解析できる要素に移行する fn next_expr(&mut self) { while let Some(t) = self.peek() { match t.category() { TC::Separator | TC::DefOp | TC::LambdaOp => { self.skip(); return; } TC::EOF => { return; } _ => { self.skip(); } } } } fn skip_and_throw_syntax_err(&mut self, caused_by: &str) -> ParseError { let loc = self.peek().unwrap().loc(); log!("{RED}[DEBUG] error caused by: {caused_by}{GREEN}"); self.next_expr(); ParseError::simple_syntax_error(0, loc) } #[inline] fn restore(&mut self, token: Token) { self.tokens.insert(0, token); } fn stack_dec(&mut self) -> () { self.level -= 1; } } #[derive(Debug)] pub struct ParserRunner { cfg: ErgConfig, } impl Runnable for ParserRunner { type Err = ParserRunnerError; type Errs = ParserRunnerErrors; const NAME: &'static str = "Erg parser"; #[inline] fn new(cfg: ErgConfig) -> Self { Self { cfg } } #[inline] fn input(&self) -> &Input { &self.cfg.input } #[inline] fn finish(&mut self) {} #[inline] fn clear(&mut self) {} fn exec(&mut self) -> Result<(), Self::Errs> { todo!() } fn eval(&mut self, src: Str) -> Result { self.cfg.input = Input::Str(src); let ast = self.parse()?; Ok(format!("{ast}")) } } impl ParserRunner { pub fn parse_token_stream(&mut self, ts: TokenStream) -> Result { Parser::new(ts) .parse(Str::ever(self.cfg.module)) .map_err(|errs| ParserRunnerErrors::convert(self.input(), errs)) } pub fn parse(&mut self) -> Result { let ts = Lexer::new(self.input().clone()) .lex() .map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?; self.parse_token_stream(ts) } /// Parses with default configuration pub fn parse_with_default_config(input: Input) -> Result { let mut cfg = ErgConfig::default(); cfg.input = input; let mut self_ = Self::new(cfg); self_.parse() } } impl Parser { pub fn parse(&mut self, mod_name: Str) -> Result { if self.tokens.is_empty() { return Ok(AST::new(mod_name, Module::empty())); } log!("{GREEN}[DEBUG] the parsing process has started."); log!("token stream: {}", self.tokens); let module = match self.try_reduce_module() { Ok(module) => module, Err(_) => { return Err(mem::take(&mut self.errs)); } }; if !self.cur_is(EOF) { let loc = self.peek().unwrap().loc(); self.errs .push(ParseError::compiler_bug(0, loc, fn_name!(), line!())); return Err(mem::take(&mut self.errs)); } log!("[DEBUG] the parsing process has completed."); log!("AST:\n{module}"); log!("[DEBUG] the desugaring process has started."); let mut desugarer = Desugarer::new(); let module = desugarer.desugar(module); log!("AST (desugared):\n{module}"); log!("[DEBUG] the desugaring process has completed.{RESET}"); if self.errs.is_empty() { Ok(AST::new(mod_name, module)) } else { Err(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() { Some(t) if t.category_is(TC::Separator) => { self.skip(); } Some(t) if t.is(EOF) => { break; } Some(t) if t.is(Indent) || t.is(Dedent) => { switch_unreachable!() } Some(_) => match self.try_reduce_expr() { Ok(expr) => { chunks.push(expr); } Err(_) => {} }, _ => switch_unreachable!(), } } self.level -= 1; Ok(chunks) } 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 chunk = self.try_reduce_expr().map_err(|_| self.stack_dec())?; block.push(chunk); self.level -= 1; return Ok(block); } loop { match self.peek() { Some(t) if t.category_is(TC::Separator) => { self.skip(); } Some(t) => { if t.is(Indent) { self.skip(); while self.cur_is(Newline) { self.skip(); } } else if self.cur_is(Dedent) { self.skip(); break; } else if t.is(EOF) { break; } match self.try_reduce_expr() { Ok(expr) => { block.push(expr); if self.cur_is(Dedent) { self.skip(); break; } } Err(_) => {} } } _ => switch_unreachable!(), } } if block.is_empty() { let loc = if let Some(u) = self.peek() { u.loc() } else { Location::Unknown }; let err = ParseError::syntax_error( line!() as usize, loc, switch_lang!( "japanese" => "ブロックの解析に失敗しました", "simplified_chinese" => "无法解析块", "traditional_chinese" => "無法解析塊", "english" => "failed to parse a block", ), None, ); self.level -= 1; self.errs.push(err); Err(()) } else { self.level -= 1; 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().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(Some(Decorator::new(expr))) } else { self.level -= 1; 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())? { decs.insert(deco); } self.level -= 1; Ok(decs) } #[inline] fn try_reduce_decl(&mut self) -> ParseResult { debug_call_info!(self); if self.peek().unwrap().category_is(TC::LEnclosure) { let var = self.try_reduce_var_sig().map_err(|_| self.stack_dec())?; self.level -= 1; return Ok(Signature::Var(var)); } let decorators = self.opt_reduce_decorators().map_err(|_| self.stack_dec())?; let name = self.try_reduce_name().map_err(|_| self.stack_dec())?; // TODO: parse bounds |...| let bounds = TypeBoundSpecs::empty(); if self.cur_is(VBar) { todo!("type bounds are not supported yet"); } if let Some(params) = self .opt_reduce_params() .transpose() .map_err(|_| self.stack_dec())? { let t_spec = if self.cur_is(Colon) { self.skip(); Some(self.try_reduce_type_spec().map_err(|_| self.stack_dec())?) } else { None }; self.level -= 1; Ok(Signature::Subr(SubrSignature::new( decorators, name, params, t_spec, bounds, ))) } else { if !bounds.is_empty() { let err = ParseError::syntax_error( 0, self.peek().unwrap().loc(), switch_lang!( "japanese" => "変数宣言で型制約は使えません", "simplified_chinese" => "变量声明中不允许类型约束", "traditional_chinese" => "變量聲明中不允許類型約束", "english" => "Cannot use type bounds in a declaration of a variable", ), None, ); self.next_expr(); self.level -= 1; self.errs.push(err); return Err(()); } let t_spec = if name.is_const() { if self.cur_is(SubtypeOf) { self.skip(); Some(self.try_reduce_type_spec().map_err(|_| self.stack_dec())?) } else { None } } else if self.cur_is(Colon) { self.skip(); Some(self.try_reduce_type_spec().map_err(|_| self.stack_dec())?) } else { None }; self.level -= 1; Ok(Signature::Var(VarSignature::new( VarPattern::VarName(name), t_spec, ))) } } #[inline] fn try_reduce_var_sig(&mut self) -> ParseResult { debug_call_info!(self); let pat = self .try_reduce_var_pattern() .map_err(|_| self.stack_dec())?; let t_spec = if self.cur_is(Colon) { self.skip(); Some(self.try_reduce_type_spec().map_err(|_| self.stack_dec())?) } else { None }; if self.cur_is(VBar) { todo!() } self.level -= 1; Ok(VarSignature::new(pat, t_spec)) } /// default_param ::= non_default_param `|=` const_expr fn try_reduce_param_sig(&mut self) -> ParseResult { debug_call_info!(self); let lhs = self .try_reduce_non_default_param_sig() .map_err(|_| self.stack_dec())?; if self.cur_is(OrEqual) { self.skip(); let val = self.try_reduce_const_expr().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(ParamSignature::new(lhs.pat, lhs.t_spec, Some(val))) } else { self.level -= 1; Ok(ParamSignature::new(lhs.pat, lhs.t_spec, None)) } } #[inline] fn try_reduce_non_default_param_sig(&mut self) -> ParseResult { debug_call_info!(self); let pat = self .try_reduce_param_pattern() .map_err(|_| self.stack_dec())?; let t_spec = if self.cur_is(Colon) { self.skip(); Some(self.try_reduce_type_spec().map_err(|_| self.stack_dec())?) } else { None }; self.level -= 1; Ok(ParamSignature::new(pat, t_spec, None)) } #[inline] fn try_reduce_lambda_sig(&mut self) -> ParseResult { debug_call_info!(self); let params = self.try_reduce_params().map_err(|_| self.stack_dec())?; let return_t = match self.peek() { Some(t) if t.is(SupertypeOf) => { self.skip(); Some(self.try_reduce_type_spec().map_err(|_| self.stack_dec())?) } _ => None, }; let bounds = match self.peek() { Some(t) if t.is(VBar) => { self.skip(); self.try_reduce_bounds().map_err(|_| self.stack_dec())? } _ => TypeBoundSpecs::empty(), }; self.level -= 1; Ok(LambdaSignature::new(params, return_t, bounds)) } fn try_reduce_acc(&mut self) -> ParseResult { debug_call_info!(self); let mut acc = match self.peek() { Some(t) if t.is(Symbol) => Accessor::local(self.lpop()), // TODO: SelfDot _ => { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } }; loop { match self.peek() { Some(t) if t.is(Dot) => { self.skip(); let symbol = self.lpop(); debug_power_assert!(symbol.is(Symbol)); let attr = Local::new(symbol); acc = Accessor::attr(Expr::Accessor(acc), attr); } Some(t) if t.is(LSqBr) => { self.skip(); let index = self.try_reduce_expr().map_err(|_| self.stack_dec())?; if self.cur_is(RSqBr) { self.skip(); } else { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } acc = Accessor::subscr(Expr::Accessor(acc), index); if self.cur_is(RSqBr) { self.lpop(); } else { self.level -= 1; // TODO: error report: RSqBr not found let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } _ => { break; } } } self.level -= 1; Ok(acc) } fn try_reduce_elems_pattern(&mut self) -> ParseResult { debug_call_info!(self); let mut elems = Vars::empty(); match self.peek() { Some(t) if t.is_block_op() => { self.level -= 1; return Ok(Vars::empty()); } Some(_) => { let elem = self.try_reduce_var_sig().map_err(|_| self.stack_dec())?; elems.push(elem); } _ => { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } loop { match self.peek() { Some(t) if t.is(Comma) => { self.skip(); let elem = self.try_reduce_var_sig().map_err(|_| self.stack_dec())?; elems.push(elem); } Some(t) if t.category_is(TC::BinOp) => { log!("[DEBUG] error caused by: {}", fn_name!()); let err = ParseError::syntax_error( line!() as usize, t.loc(), switch_lang!( "japanese" => "左辺値の中で中置演算子は使えません", "simplified_chinese" => "二元运算符不能用于左值", "traditional_chinese" => "二元運算符不能用於左值", "english" => "Binary operators cannot be used in left-values", ), None, ); self.next_expr(); self.level -= 1; self.errs.push(err); return Err(()); } _ => { break; } } } self.level -= 1; Ok(elems) } fn opt_reduce_params(&mut self) -> Option> { match self.peek() { Some(t) if t.category_is(TC::Literal) || t.is(Symbol) || t.category_is(TC::UnaryOp) || t.is(Dot) || t.category_is(TC::Caret) || t.is(LParen) || t.is(LSqBr) || t.is(LBrace) => { Some(self.try_reduce_params()) } _ => None, } } fn try_reduce_params(&mut self) -> ParseResult { debug_call_info!(self); let lp = if self.cur_is(TokenKind::LParen) { Some(self.lpop()) } else { None }; let mut non_default_params = vec![]; let mut default_params = vec![]; let mut default_appeared = false; match self.peek() { Some(t) if t.is(RParen) => { let parens = (lp.unwrap(), self.lpop()); self.level -= 1; return Ok(Params::new( non_default_params, default_params, Some(parens), )); } Some(t) if t.is_block_op() => { if lp.is_none() { self.level -= 1; return Ok(Params::new(non_default_params, default_params, None)); } // TODO: RParen not found else { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } Some(_) => { let param = self.try_reduce_param_sig().map_err(|_| self.stack_dec())?; if param.has_default() { default_appeared = true; default_params.push(param); } else { non_default_params.push(param); } } _ => { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } loop { match self.peek() { Some(t) if t.is(Comma) => { self.skip(); let param = self.try_reduce_param_sig().map_err(|_| self.stack_dec())?; match (param.has_default(), default_appeared) { (true, true) => { default_params.push(param); } (true, false) => { default_appeared = true; default_params.push(param); } (false, true) => { self.level -= 1; let err = ParseError::syntax_error( 0, param.loc(), // TODO: switch_lang! "non-default argument follows default argument", None, ); self.errs.push(err); return Err(()); } (false, false) => { non_default_params.push(param); } } } Some(t) if t.category_is(TC::BinOp) => { let err = ParseError::syntax_error( line!() as usize, t.loc(), switch_lang!( "japanese" => "仮引数の中で中置演算子は使えません", "simplified_chinese" => "参数中不能使用二元运算符", "traditional_chinese" => "參數中不能使用二元運算符", "english" => "Binary operators cannot be used in parameters", ), None, ); self.next_expr(); self.level -= 1; self.errs.push(err); return Err(()); } Some(t) if t.is(TokenKind::RParen) => { let rp = self.lpop(); if let Some(lp) = lp { self.level -= 1; return Ok(Params::new( non_default_params, default_params, Some((lp, rp)), )); } else { self.level -= 1; // LParen not found let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } _ if lp.is_none() => { self.level -= 1; return Ok(Params::new(non_default_params, default_params, None)); } _ => { self.level -= 1; // TODO: RParen not found let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } } } fn try_reduce_var_pattern(&mut self) -> ParseResult { debug_call_info!(self); match self.peek() { Some(t) if t.is(Symbol) => { let varname = self.try_reduce_name().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(VarPattern::VarName(varname)) } Some(t) if t.is(UBar) => { self.level -= 1; Ok(VarPattern::Discard(self.lpop())) } Some(t) if t.is(LSqBr) => { let l_sqbr = self.lpop(); let elems = self .try_reduce_elems_pattern() .map_err(|_| self.stack_dec())?; if self.cur_is(RSqBr) { let r_sqbr = self.lpop(); self.level -= 1; Ok(VarPattern::Array(VarArrayPattern::new( l_sqbr, elems, r_sqbr, ))) } else { self.level -= 1; // TODO: error report: RSqBr not found let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); Err(()) } } Some(t) if t.is(LParen) => { self.skip(); let pat = self .try_reduce_var_pattern() .map_err(|_| self.stack_dec())?; if self.cur_is(RParen) { self.skip(); self.level -= 1; Ok(pat) } else { self.level -= 1; // TODO: error report: RParen not found let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); Err(()) } } _ => { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } } fn try_reduce_param_pattern(&mut self) -> ParseResult { debug_call_info!(self); match self.peek() { Some(t) if t.is(Symbol) => { let varname = self.try_reduce_name().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(ParamPattern::VarName(varname)) } Some(t) if t.is(UBar) => { self.level -= 1; Ok(ParamPattern::Discard(self.lpop())) } Some(t) if t.category_is(TC::Literal) => { let lit = self.try_reduce_lit().map_err(|_| self.stack_dec())?; self.level -= 1; // TODO: range pattern Ok(ParamPattern::Lit(lit)) } Some(t) if t.is(Spread) => { self.skip(); self.level -= 1; Ok(ParamPattern::VarArgsName( self.try_reduce_name().map_err(|_| self.stack_dec())?, )) } Some(t) if t.is(LSqBr) => { let l_sqbr = self.lpop(); let elems = self.try_reduce_params().map_err(|_| self.stack_dec())?; if self.cur_is(RSqBr) { let r_sqbr = self.lpop(); self.level -= 1; Ok(ParamPattern::Array(ParamArrayPattern::new( l_sqbr, elems, r_sqbr, ))) } else { self.level -= 1; // TODO: error report: RSqBr not found let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } Some(t) if t.is(LParen) => { self.skip(); let pat = self .try_reduce_param_pattern() .map_err(|_| self.stack_dec())?; if self.cur_is(RParen) { self.skip(); self.level -= 1; Ok(pat) } else { self.level -= 1; // TODO: error report: RParen not found let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } _ => { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } } // TODO: set type fn try_reduce_type_spec(&mut self) -> ParseResult { debug_call_info!(self); let mut typ = match self.peek() { Some(t) if t.is(Symbol) => { let simple = self .try_reduce_simple_type_spec() .map_err(|_| self.stack_dec())?; // not finished TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(simple)) } Some(t) if t.category_is(TC::Literal) => { let lit = self.try_reduce_lit().map_err(|_| self.stack_dec())?; let lhs = ConstExpr::Lit(lit); let maybe_op = self.lpop(); let op = if maybe_op.is(Closed) || maybe_op.is(LeftOpen) || maybe_op.is(RightOpen) || maybe_op.is(Open) { maybe_op } else { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); }; // TODO: maybe Name let rhs = ConstExpr::Lit(self.try_reduce_lit().map_err(|_| self.stack_dec())?); TypeSpec::interval(op, lhs, rhs) } Some(t) if t.is(LParen) => { let func_type_spec = self.try_reduce_func_type().map_err(|_| self.stack_dec())?; func_type_spec } Some(t) if t.is(LSqBr) => { self.skip(); let mut tys = vec![self.try_reduce_type_spec().map_err(|_| self.stack_dec())?]; loop { match self.peek() { Some(t) if t.is(Comma) => { self.skip(); let t = self.try_reduce_type_spec().map_err(|_| self.stack_dec())?; tys.push(t); } Some(t) if t.is(RSqBr) => { self.skip(); break; } _ => { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } } TypeSpec::Tuple(tys) } _ => { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } }; loop { match self.peek() { Some(t) if t.is(AndOp) => { let rhs = self.try_reduce_type_spec().map_err(|_| self.stack_dec())?; typ = TypeSpec::and(typ, rhs); } Some(t) if t.is(OrOp) => { let rhs = self.try_reduce_type_spec().map_err(|_| self.stack_dec())?; typ = TypeSpec::or(typ, rhs); } Some(t) if t.category_is(TC::LambdaOp) => { let is_func = t.is(FuncArrow); self.skip(); let rhs = self.try_reduce_type_spec().map_err(|_| self.stack_dec())?; typ = if is_func { TypeSpec::func(None, vec![ParamTySpec::anonymous(typ)], vec![], rhs) } else { TypeSpec::proc(None, vec![ParamTySpec::anonymous(typ)], vec![], rhs) }; } _ => { break; } } } self.level -= 1; Ok(typ) } fn try_reduce_func_type_param(&mut self) -> ParseResult { debug_call_info!(self); if self.cur_is(Symbol) && self.nth_is(1, Colon) { let name = self.try_reduce_name().map_err(|_| self.stack_dec())?; self.skip(); let typ = self.try_reduce_type_spec().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(ParamTySpec::new(Some(name.into_token()), typ)) } else { let ty_spec = self.try_reduce_type_spec().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(ParamTySpec::anonymous(ty_spec)) } } // TODO: default parameters fn try_reduce_func_type(&mut self) -> ParseResult { debug_call_info!(self); let lparen = Some(self.lpop()); let mut non_defaults = vec![self .try_reduce_func_type_param() .map_err(|_| self.stack_dec())?]; loop { match self.peek() { Some(t) if t.is(Comma) => { self.skip(); non_defaults.push( self.try_reduce_func_type_param() .map_err(|_| self.stack_dec())?, ); } Some(t) if t.is(RParen) => { self.skip(); break; } _ => { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } } match self.peek() { Some(t) if t.category_is(TC::LambdaOp) => { let is_func = t.is(FuncArrow); self.skip(); let rhs = self.try_reduce_type_spec().map_err(|_| self.stack_dec())?; self.level -= 1; if is_func { Ok(TypeSpec::func(lparen, non_defaults, vec![], rhs)) } else { Ok(TypeSpec::proc(lparen, non_defaults, vec![], rhs)) } } _ => { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } } #[inline] fn try_reduce_simple_type_spec(&mut self) -> ParseResult { debug_call_info!(self); match self.peek() { Some(t) if t.is(Symbol) => { let name = self.try_reduce_name().map_err(|_| self.stack_dec())?; if let Some(res) = self.opt_reduce_args() { let args = self.validate_const_args(res?)?; self.level -= 1; Ok(SimpleTypeSpec::new(name, args)) } else { self.level -= 1; Ok(SimpleTypeSpec::new(name, ConstArgs::empty())) } } _ => { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } } fn try_reduce_bounds(&mut self) -> ParseResult { todo!() } fn validate_const_expr(&mut self, expr: Expr) -> ParseResult { match expr { Expr::Lit(l) => Ok(ConstExpr::Lit(l)), Expr::Accessor(Accessor::Local(local)) => { let local = ConstLocal::new(local.symbol); Ok(ConstExpr::Accessor(ConstAccessor::Local(local))) } // TODO: App, Array, Record, BinOp, UnaryOp, other => { self.errs.push(ParseError::syntax_error( 0, other.loc(), switch_lang!( "japanese" => "この式はコンパイル時計算できないため、型引数には使用できません", "simplified_chinese" => "此表达式在编译时不可计算,因此不能用作类型参数", "traditional_chinese" => "此表達式在編譯時不可計算,因此不能用作類型參數", "english" => "this expression is not computable at the compile-time, so cannot used as a type-argument", ), None, )); Err(()) } } } fn validate_const_pos_arg(&mut self, arg: PosArg) -> ParseResult { let expr = self.validate_const_expr(arg.expr)?; Ok(ConstPosArg::new(expr)) } fn validate_const_kw_arg(&mut self, arg: KwArg) -> ParseResult { let expr = self.validate_const_expr(arg.expr)?; Ok(ConstKwArg::new(arg.keyword, expr)) } // exprが定数式か確認する fn validate_const_args(&mut self, args: Args) -> ParseResult { let (pos, kw, paren) = args.deconstruct(); let mut const_args = ConstArgs::new(vec![], vec![], paren); for arg in pos.into_iter() { match self.validate_const_pos_arg(arg) { Ok(arg) => { const_args.push_pos(arg); } Err(e) => return Err(e), } } for arg in kw.into_iter() { match self.validate_const_kw_arg(arg) { Ok(arg) => { const_args.push_kw(arg); } Err(e) => return Err(e), } } Ok(const_args) } /// For parsing elements of arrays and tuples /// The second return value is a specified length, the third return value is a guard fn try_reduce_elems(&mut self) -> ParseResult { debug_call_info!(self); if self.cur_category_is(TC::REnclosure) { let args = Args::new(vec![], vec![], None); self.level -= 1; return Ok(ArrayInner::Normal(args)); } let first = self.try_reduce_elem().map_err(|_| self.stack_dec())?; let mut elems = Args::new(vec![first], vec![], None); match self.peek() { Some(semi) if semi.is(Semi) => { self.lpop(); let len = self.try_reduce_expr().map_err(|_| self.stack_dec())?; self.level -= 1; return Ok(ArrayInner::WithLength(elems.remove_pos(0), len)); } Some(vbar) if vbar.is(VBar) => { let err = ParseError::feature_error(line!() as usize, vbar.loc(), "comprehension"); self.lpop(); self.errs.push(err); self.level -= 1; return Err(()); } Some(t) if t.category_is(TC::REnclosure) || t.is(Comma) => {} Some(_) => { let elem = self.try_reduce_elem().map_err(|_| self.stack_dec())?; elems.push_pos(elem); } None => { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } loop { match self.peek() { Some(comma) if comma.is(Comma) => { self.skip(); if self.cur_is(Comma) { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } elems.push_pos(self.try_reduce_elem().map_err(|_| self.stack_dec())?); } Some(t) if t.category_is(TC::REnclosure) => { break; } _ => { self.skip(); self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } } self.level -= 1; Ok(ArrayInner::Normal(elems)) } fn try_reduce_elem(&mut self) -> ParseResult { debug_call_info!(self); match self.peek() { Some(_) => { let expr = self.try_reduce_expr().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(PosArg::new(expr)) } None => switch_unreachable!(), } } fn opt_reduce_args(&mut self) -> Option> { // debug_call_info!(self); match self.peek() { Some(t) if t.category_is(TC::Literal) || t.is(Symbol) || t.category_is(TC::UnaryOp) || t.is(Dot) || t.category_is(TC::Caret) || t.is(LParen) || t.is(LSqBr) || t.is(LBrace) || t.is(Colon) => { Some(self.try_reduce_args()) } _ => None, } } /// 引数はインデントで区切ることができる(ただしコンマに戻すことはできない) /// /// ``` /// x = if true, 1, 2 /// # is equal to /// x = if true: /// 1 /// 2 /// ``` fn try_reduce_args(&mut self) -> ParseResult { debug_call_info!(self); let mut lp = None; let rp; if self.cur_is(LParen) { lp = Some(self.lpop()); } if self.cur_is(RParen) { rp = Some(self.lpop()); self.level -= 1; return Ok(Args::new(vec![], vec![], Some((lp.unwrap(), rp.unwrap())))); } else if self.cur_category_is(TC::REnclosure) { self.level -= 1; return Ok(Args::new(vec![], vec![], None)); } let mut args = match self.try_reduce_arg().map_err(|_| self.stack_dec())? { PosOrKwArg::Pos(arg) => Args::new(vec![arg], vec![], None), PosOrKwArg::Kw(arg) => Args::new(vec![], vec![arg], None), }; let mut colon_style = false; loop { match self.peek() { Some(t) if t.is(Colon) && colon_style => { self.skip(); self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } Some(t) if t.is(Colon) => { self.skip(); colon_style = true; while self.cur_is(Newline) { self.skip(); } debug_power_assert!(self.cur_is(Indent)); self.skip(); if !args.kw_is_empty() { args.push_kw(self.try_reduce_kw_arg().map_err(|_| self.stack_dec())?); } else { match self.try_reduce_arg().map_err(|_| self.stack_dec())? { PosOrKwArg::Pos(arg) => { args.push_pos(arg); } PosOrKwArg::Kw(arg) => { args.push_kw(arg); } } } } Some(t) if t.is(Comma) => { self.skip(); if colon_style || self.cur_is(Comma) { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } if !args.kw_is_empty() { args.push_kw(self.try_reduce_kw_arg().map_err(|_| self.stack_dec())?); } else { match self.try_reduce_arg().map_err(|_| self.stack_dec())? { PosOrKwArg::Pos(arg) => { args.push_pos(arg); } PosOrKwArg::Kw(arg) => { args.push_kw(arg); } } } } Some(t) if t.is(Newline) && colon_style => { while self.cur_is(Newline) { self.skip(); } if self.cur_is(Dedent) { self.skip(); break; } if !args.kw_is_empty() { args.push_kw(self.try_reduce_kw_arg().map_err(|_| self.stack_dec())?); } else { match self.try_reduce_arg().map_err(|_| self.stack_dec())? { PosOrKwArg::Pos(arg) => { args.push_pos(arg); } PosOrKwArg::Kw(arg) => { args.push_kw(arg); } } } } Some(t) if t.is(RParen) => { rp = Some(self.lpop()); let (pos_args, kw_args, _) = args.deconstruct(); args = Args::new(pos_args, kw_args, Some((lp.unwrap(), rp.unwrap()))); break; } _ => { break; } } } self.level -= 1; Ok(args) } fn try_reduce_arg(&mut self) -> ParseResult { debug_call_info!(self); match self.peek() { Some(t) if t.is(Symbol) => { if self.nth_is(1, Colon) { let acc = self.try_reduce_acc().map_err(|_| self.stack_dec())?; debug_power_assert!(self.cur_is(Colon)); if self.nth_is(1, Newline) { self.level -= 1; // colon style call Ok(PosOrKwArg::Pos(PosArg::new(Expr::Accessor(acc)))) } else { self.skip(); let kw = if let Accessor::Local(n) = acc { n.symbol } else { self.next_expr(); self.level -= 1; let err = ParseError::simple_syntax_error(0, acc.loc()); self.errs.push(err); return Err(()); }; let expr = self.try_reduce_expr().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(PosOrKwArg::Kw(KwArg::new(kw, expr))) } } else { let expr = self.try_reduce_expr().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(PosOrKwArg::Pos(PosArg::new(expr))) } } Some(_) => { let expr = self.try_reduce_expr().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(PosOrKwArg::Pos(PosArg::new(expr))) } None => switch_unreachable!(), } } fn try_reduce_kw_arg(&mut self) -> ParseResult { debug_call_info!(self); match self.peek() { Some(t) if t.is(Symbol) => { if self.nth_is(1, Colon) { let acc = self.try_reduce_acc().map_err(|_| self.stack_dec())?; debug_power_assert!(self.cur_is(Colon)); self.skip(); let keyword = if let Accessor::Local(n) = acc { n.symbol } else { self.next_expr(); self.level -= 1; self.errs .push(ParseError::simple_syntax_error(0, acc.loc())); return Err(()); }; let expr = self.try_reduce_expr().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(KwArg::new(keyword, expr)) } else { let loc = t.loc(); self.level -= 1; self.errs.push(ParseError::simple_syntax_error(0, loc)); Err(()) } } Some(other) => { let loc = other.loc(); self.level -= 1; self.errs.push(ParseError::simple_syntax_error(0, loc)); Err(()) } None => switch_unreachable!(), } } fn try_reduce_const_expr(&mut self) -> ParseResult { debug_call_info!(self); let expr = self.try_reduce_expr().map_err(|_| self.stack_dec())?; self.level -= 1; self.validate_const_expr(expr) } fn try_reduce_expr(&mut self) -> ParseResult { debug_call_info!(self); let mut stack = Vec::::new(); match self.cur_side() { Side::LhsAssign => { let sig = self.try_reduce_decl().map_err(|_| self.stack_dec())?; match self.peek() { Some(t) if t.is(Equal) => { let op = self.lpop(); self.counter.inc(); let block = self.try_reduce_block().map_err(|_| self.stack_dec())?; let body = DefBody::new(op, block, self.counter); self.level -= 1; Ok(Expr::Def(Def::new(sig, body))) } _other => { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } } Side::LhsLambda => { let params = self.try_reduce_params().map_err(|_| self.stack_dec())?; match self.peek() { Some(t) if t.category_is(TC::LambdaOp) => { let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty()); let op = self.lpop(); let body = self.try_reduce_block().map_err(|_| self.stack_dec())?; self.counter.inc(); self.level -= 1; Ok(Expr::Lambda(Lambda::new(sig, op, body, self.counter))) } Some(t) if t.is(Colon) => { self.lpop(); let spec_t = self.try_reduce_type_spec().map_err(|_| self.stack_dec())?; let sig = LambdaSignature::new(params, Some(spec_t), TypeBoundSpecs::empty()); let op = self.lpop(); let body = self.try_reduce_block().map_err(|_| self.stack_dec())?; self.counter.inc(); self.level -= 1; Ok(Expr::Lambda(Lambda::new(sig, op, body, self.counter))) } _other => { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } } Side::Rhs => { stack.push(ExprOrOp::Expr( self.try_reduce_bin_lhs().map_err(|_| self.stack_dec())?, )); loop { match self.peek() { 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().map_err(|_| self.stack_dec())?, )); } Some(t) if t.category_is(TC::DefOp) => { switch_unreachable!() } Some(t) if t.is(Dot) => { self.skip(); match self.lpop() { symbol if symbol.is(Symbol) => { let obj = if let Some(ExprOrOp::Expr(expr)) = stack.pop() { expr } else { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); }; let acc = Accessor::attr(obj, Local::new(symbol)); if let Ok(args) = self.try_reduce_args() { let call = Call::new(Expr::Accessor(acc), args); stack.push(ExprOrOp::Expr(Expr::Call(call))); } else { stack.push(ExprOrOp::Expr(Expr::Accessor(acc))); } } other => { self.restore(other); self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } } _ => { if stack.len() <= 1 { break; } // else if stack.len() == 2 { switch_unreachable!() } else { while stack.len() >= 3 { 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))); } } } } } match stack.pop() { Some(ExprOrOp::Expr(expr)) if stack.is_empty() => { self.level -= 1; 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!())); self.level -= 1; Ok(expr) } Some(ExprOrOp::Op(op)) => { self.level -= 1; self.errs .push(ParseError::compiler_bug(0, op.loc(), fn_name!(), line!())); Err(()) } _ => switch_unreachable!(), } } } } /// "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) -> ParseResult { debug_call_info!(self); match self.peek() { Some(t) if t.category_is(TC::Literal) => { // TODO: 10.times ...などメソッド呼び出しもある let lit = self.try_reduce_lit().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(Expr::Lit(lit)) } Some(t) if t.is(Symbol) || t.is(Dot) => { let acc = self .try_reduce_call_or_acc() .map_err(|_| self.stack_dec())?; self.level -= 1; Ok(acc) } Some(t) if t.category_is(TC::UnaryOp) => { let unaryop = self.try_reduce_unary().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(Expr::UnaryOp(unaryop)) } Some(t) if t.category_is(TC::Caret) => { let lambda = self.try_reduce_lambda().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(Expr::Lambda(lambda)) } Some(t) if t.is(LParen) => { self.skip(); let expr = self.try_reduce_expr().map_err(|_| self.stack_dec())?; if self.cur_is(RParen) { self.skip(); self.level -= 1; Ok(expr) } else { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } Some(t) if t.is(LSqBr) => { let array = self.try_reduce_array().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(Expr::Array(array)) } Some(t) if t.is(LBrace) => { todo!() } Some(t) if t.is(UBar) => { let token = self.lpop(); self.level -= 1; self.errs .push(ParseError::feature_error(0, token.loc(), "discard pattern")); Err(()) } _other => { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } } } #[inline] fn try_reduce_call_or_acc(&mut self) -> ParseResult { debug_call_info!(self); let acc = self.try_reduce_acc().map_err(|_| self.stack_dec())?; if let Some(res) = self.opt_reduce_args() { let args = res.map_err(|_| self.stack_dec())?; let call = Call::new(Expr::Accessor(acc), args); self.level -= 1; Ok(Expr::Call(call)) } else { self.level -= 1; Ok(Expr::Accessor(acc)) } } #[inline] fn try_reduce_lambda(&mut self) -> ParseResult { debug_call_info!(self); let sig = self.try_reduce_lambda_sig().map_err(|_| self.stack_dec())?; let op = self.lpop(); if op.category() != TC::LambdaOp { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); return Err(()); } // REVIEW: この箇所必要か while self.cur_is(Newline) { self.skip(); } let body = self.try_reduce_block().map_err(|_| self.stack_dec())?; self.counter.inc(); self.level -= 1; Ok(Lambda::new(sig, op, body, self.counter)) } #[inline] fn try_reduce_unary(&mut self) -> ParseResult { debug_call_info!(self); let op = self.lpop(); let expr = self.try_reduce_expr().map_err(|_| self.stack_dec())?; self.level -= 1; Ok(UnaryOp::new(op, expr)) } #[inline] fn try_reduce_array(&mut self) -> ParseResult { debug_call_info!(self); let l_sqbr = self.lpop(); let inner = self.try_reduce_elems().map_err(|_| self.stack_dec())?; let r_sqbr = self.lpop(); if !r_sqbr.is(RSqBr) { self.level -= 1; self.errs .push(ParseError::simple_syntax_error(0, r_sqbr.loc())); return Err(()); } let arr = match inner { ArrayInner::Normal(elems) => Array::Normal(NormalArray::new(l_sqbr, r_sqbr, elems)), ArrayInner::WithLength(elem, len) => { Array::WithLength(ArrayWithLength::new(l_sqbr, r_sqbr, elem, len)) } ArrayInner::Comprehension { .. } => todo!(), }; self.level -= 1; Ok(arr) } #[inline] fn try_reduce_name(&mut self) -> ParseResult { debug_call_info!(self); self.level -= 1; match self.peek() { Some(t) if t.is(Symbol) => Ok(VarName::new(self.lpop())), _ => { let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); Err(()) } } } #[inline] fn try_reduce_lit(&mut self) -> ParseResult { debug_call_info!(self); self.level -= 1; match self.peek() { Some(t) if t.category_is(TC::Literal) => Ok(Literal::from(self.lpop())), _ => { let err = self.skip_and_throw_syntax_err(caused_by!()); self.errs.push(err); Err(()) } } } }