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 as HashSet;
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::*;
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<Expr>,
},
}
pub enum BraceContainer {
Set(Set),
Dict(Dict),
Record(Record),
}
#[derive(Debug)]
pub struct Parser {
counter: DefId,
level: usize, 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<TokenCategory> {
self.nth(idx).map(|t| t.category())
}
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
}
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 {
if equal < sep {
Side::LhsAssign
}
else if self.arrow_distance(0, 0) == 1 {
Side::LhsLambda
} else {
Side::Rhs
}
}
}
(Some(_eq), Some(_arrow), None) => Side::LhsAssign,
(Some(equal), None, Some(sep)) => {
if equal < sep {
Side::LhsAssign
} else {
Side::Rhs
}
}
(None, Some(arrow), Some(sep)) => {
if arrow < sep {
if self.arrow_distance(0, 0) == 1 {
Side::LhsLambda
} else {
Side::Rhs
}
}
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,
}
}
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<String, ParserRunnerErrors> {
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<AST, ParserRunnerErrors> {
Parser::new(ts)
.parse(Str::ever(self.cfg.module))
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))
}
pub fn parse(&mut self) -> Result<AST, ParserRunnerErrors> {
let ts = Lexer::new(self.input().clone())
.lex()
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
self.parse_token_stream(ts)
}
pub fn parse_with_default_config(input: Input) -> Result<AST, ParserRunnerErrors> {
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<AST, ParseErrors> {
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))
}
}
#[inline]
fn try_reduce_module(&mut self) -> ParseResult<Module> {
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<Block> {
debug_call_info!(self);
let mut block = Block::with_capacity(2);
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<Option<Decorator>> {
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<HashSet<Decorator>> {
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<Signature> {
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 ident = self.try_reduce_ident().map_err(|_| self.stack_dec())?;
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, ident, 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 ident.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::Ident(ident),
t_spec,
)))
}
}
#[inline]
fn try_reduce_var_sig(&mut self) -> ParseResult<VarSignature> {
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))
}
fn try_reduce_param_sig(&mut self) -> ParseResult<ParamSignature> {
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<ParamSignature> {
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<LambdaSignature> {
debug_call_info!(self);
let bounds = match self.peek() {
Some(t) if t.is(VBar) => {
self.skip();
self.try_reduce_bounds().map_err(|_| self.stack_dec())?
}
_ => TypeBoundSpecs::empty(),
};
let params = self.try_reduce_params().map_err(|_| self.stack_dec())?;
let return_t = match self.peek() {
Some(t) if t.is(Colon) => {
self.skip();
Some(self.try_reduce_type_spec().map_err(|_| self.stack_dec())?)
}
_ => None,
};
self.level -= 1;
Ok(LambdaSignature::new(params, return_t, bounds))
}
fn try_reduce_acc(&mut self) -> ParseResult<Accessor> {
debug_call_info!(self);
let mut acc = match self.peek() {
Some(t) if t.is(Symbol) => Accessor::local(self.lpop()),
Some(t) if t.is(Dot) => {
let dot = self.lpop();
let maybe_symbol = self.lpop();
if maybe_symbol.is(Symbol) {
Accessor::public(dot, maybe_symbol)
} else {
self.level -= 1;
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(());
}
};
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;
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<Vars> {
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<ParseResult<Params>> {
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<Params> {
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));
}
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(),
"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;
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;
let err = self.skip_and_throw_syntax_err(caused_by!());
self.errs.push(err);
return Err(());
}
}
}
}
fn try_reduce_var_pattern(&mut self) -> ParseResult<VarPattern> {
debug_call_info!(self);
match self.peek() {
Some(t) if t.is(Symbol) => {
let ident = self.try_reduce_ident().map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(VarPattern::Ident(ident))
}
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;
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;
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<ParamPattern> {
debug_call_info!(self);
match self.peek() {
Some(t) if t.is(Symbol) => {
let ident = self.try_reduce_ident().map_err(|_| self.stack_dec())?;
if let Some(dot) = &ident.dot {
let loc = dot.loc();
self.level -= 1;
self.errs.push(ParseError::syntax_error(
line!() as usize,
loc,
switch_lang!(
"japanese" => "仮引数に`.`は使えません",
"simplified_chinese" => "参数不能使用点(`.`)",
"traditional_chinese" => "參數不能使用點(`.`)",
"english" => "`.` is not allowed in parameters",
),
None,
));
return Err(());
}
self.level -= 1;
Ok(ParamPattern::VarName(ident.name))
}
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;
Ok(ParamPattern::Lit(lit))
}
Some(t) if t.is(Spread) => {
self.skip();
let ident = self.try_reduce_ident().map_err(|_| self.stack_dec())?;
if let Some(dot) = &ident.dot {
let loc = dot.loc();
self.level -= 1;
self.errs.push(ParseError::syntax_error(
line!() as usize,
loc,
switch_lang!(
"japanese" => "仮引数に`.`は使えません",
"simplified_chinese" => "参数不能使用点(`.`)",
"traditional_chinese" => "參數不能使用點(`.`)",
"english" => "`.` is not allowed in parameters",
),
None,
));
return Err(());
}
self.level -= 1;
Ok(ParamPattern::VarArgsName(ident.name))
}
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;
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;
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(());
}
}
}
fn try_reduce_type_spec(&mut self) -> ParseResult<TypeSpec> {
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())?;
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(());
};
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<ParamTySpec> {
debug_call_info!(self);
if self.cur_is(Symbol) && self.nth_is(1, Colon) {
let ident = self.try_reduce_ident().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(ident.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))
}
}
fn try_reduce_func_type(&mut self) -> ParseResult<TypeSpec> {
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<SimpleTypeSpec> {
debug_call_info!(self);
match self.peek() {
Some(t) if t.is(Symbol) => {
let ident = self.try_reduce_ident().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(ident.name, args))
} else {
self.level -= 1;
Ok(SimpleTypeSpec::new(ident.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<TypeBoundSpecs> {
todo!()
}
fn validate_const_expr(&mut self, expr: Expr) -> ParseResult<ConstExpr> {
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)))
}
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<ConstPosArg> {
let expr = self.validate_const_expr(arg.expr)?;
Ok(ConstPosArg::new(expr))
}
fn validate_const_kw_arg(&mut self, arg: KwArg) -> ParseResult<ConstKwArg> {
let expr = self.validate_const_expr(arg.expr)?;
Ok(ConstKwArg::new(arg.keyword, expr))
}
fn validate_const_args(&mut self, args: Args) -> ParseResult<ConstArgs> {
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)
}
fn try_reduce_elems(&mut self) -> ParseResult<ArrayInner> {
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<PosArg> {
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<ParseResult<Args>> {
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,
}
}
fn try_reduce_args(&mut self) -> ParseResult<Args> {
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<PosOrKwArg> {
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;
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<KwArg> {
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<ConstExpr> {
debug_call_info!(self);
let expr = self.try_reduce_expr().map_err(|_| self.stack_dec())?;
self.level -= 1;
self.validate_const_expr(expr)
}
#[inline]
fn try_reduce_def(&mut self) -> ParseResult<Def> {
debug_call_info!(self);
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(Def::new(sig, body))
}
_other => {
self.level -= 1;
let err = self.skip_and_throw_syntax_err(caused_by!());
self.errs.push(err);
return Err(());
}
}
}
#[inline]
fn try_reduce_lambda(&mut self) -> ParseResult<Lambda> {
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(());
}
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))
}
fn try_reduce_expr(&mut self) -> ParseResult<Expr> {
debug_call_info!(self);
let mut stack = Vec::<ExprOrOp>::new();
match self.cur_side() {
Side::LhsAssign => {
let def = self.try_reduce_def().map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(Expr::Def(def))
}
Side::LhsLambda => {
let lambda = self.try_reduce_lambda().map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(Expr::Lambda(lambda))
}
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(());
};
if let Some(args) = self
.opt_reduce_args()
.transpose()
.map_err(|_| self.stack_dec())?
{
let call = Call::new(obj, Some(symbol), args);
stack.push(ExprOrOp::Expr(Expr::Call(call)));
} else {
let acc = Accessor::attr(obj, Local::new(symbol));
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 {
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!(),
}
}
}
}
fn try_reduce_bin_lhs(&mut self) -> ParseResult<Expr> {
debug_call_info!(self);
match self.peek() {
Some(t) if t.category_is(TC::Literal) => {
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) => {
match self
.try_reduce_brace_container()
.map_err(|_| self.stack_dec())?
{
BraceContainer::Dict(dic) => {
self.level -= 1;
Ok(Expr::Dict(dic))
}
BraceContainer::Record(rec) => {
self.level -= 1;
Ok(Expr::Record(rec))
}
BraceContainer::Set(set) => {
self.level -= 1;
Ok(Expr::Set(set))
}
}
}
Some(t) if t.is(UBar) => {
let token = self.lpop();
self.level -= 1;
self.errs.push(ParseError::feature_error(
line!() as usize,
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<Expr> {
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 (obj, method_name) = match acc {
Accessor::Attr(attr) => (*attr.obj, Some(attr.name.symbol)),
Accessor::Local(local) => (Expr::Accessor(Accessor::Local(local)), None),
_ => todo!(),
};
let call = Call::new(obj, method_name, args);
self.level -= 1;
Ok(Expr::Call(call))
} else {
self.level -= 1;
Ok(Expr::Accessor(acc))
}
}
#[inline]
fn try_reduce_unary(&mut self) -> ParseResult<UnaryOp> {
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<Array> {
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)
}
fn try_reduce_brace_container(&mut self) -> ParseResult<BraceContainer> {
debug_call_info!(self);
let l_brace = self.lpop();
if self.cur_is(Newline) {
self.skip();
if self.cur_is(Indent) {
self.skip();
} else {
todo!()
}
}
let first = self.try_reduce_expr().map_err(|_| self.stack_dec())?;
match first {
Expr::Def(def) => {
let record = self
.try_reduce_record(l_brace, def)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(BraceContainer::Record(record))
}
Expr::Decl(_) => todo!(), other => {
let set = self
.try_reduce_set(l_brace, other)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(BraceContainer::Set(set))
}
}
}
fn try_reduce_record(&mut self, l_brace: Token, first: Def) -> ParseResult<Record> {
debug_call_info!(self);
let mut attrs = vec![first];
loop {
match self.peek() {
Some(t) if t.category_is(TC::Separator) => {
self.skip();
if self.cur_is(Dedent) {
self.skip();
if self.cur_is(RBrace) {
let r_brace = self.lpop();
self.level -= 1;
let attrs = RecordAttrs::from(attrs);
return Ok(Record::new(l_brace, r_brace, attrs));
} else {
todo!()
}
}
let def = self.try_reduce_def().map_err(|_| self.stack_dec())?;
attrs.push(def);
}
Some(term) if term.is(RBrace) => {
let r_brace = self.lpop();
self.level -= 1;
let attrs = RecordAttrs::from(attrs);
return Ok(Record::new(l_brace, r_brace, attrs));
}
_ => todo!(),
}
}
}
fn _try_reduce_dict() -> ParseResult<Dict> {
todo!()
}
fn try_reduce_set(&mut self, _l_brace: Token, _first: Expr) -> ParseResult<Set> {
todo!()
}
#[inline]
fn try_reduce_ident(&mut self) -> ParseResult<Identifier> {
debug_call_info!(self);
self.level -= 1;
match self.peek() {
Some(t) if t.is(Dot) => {
let dot = self.lpop();
assert!(self.cur_category_is(TC::Symbol));
let ident = Identifier::new(Some(dot), VarName::new(self.lpop()));
Ok(ident)
}
Some(t) if t.is(Symbol) => {
let ident = Identifier::new(None, VarName::new(self.lpop()));
Ok(ident)
}
_ => {
let err = self.skip_and_throw_syntax_err(caused_by!());
self.errs.push(err);
Err(())
}
}
}
#[inline]
fn try_reduce_lit(&mut self) -> ParseResult<Literal> {
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(())
}
}
}
}