// Copyright 2022 Gregory Petrosyan <pgregory@pgregory.net>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use crate::ast::{Expr, Opcode};
use super::Error;
use lalrpop_util::ParseError;
use lalrpop_util::ErrorRecovery;
grammar<'err>(errors: &'err mut Vec<ErrorRecovery<usize, Token<'input>, Error>>);
extern {
type Error = Error;
}
pub Exprs = Comma<Expr>;
Comma<T>: Vec<T> = {
<v:(<T> ",")*> <e:T?> => match e {
None => v,
Some(e) => {
let mut v = v;
v.push(e);
v
}
}
};
Tier<Op,NextTier>: Box<Expr> = {
Tier<Op,NextTier> Op NextTier => Box::new(Expr::Op(<>)),
NextTier
};
Expr = Tier<ExprOp, Factor>;
Factor = Tier<FactorOp, Term>;
ExprOp: Opcode = {
"+" => Opcode::Add,
"-" => Opcode::Sub,
};
FactorOp: Opcode = {
"*" => Opcode::Mul,
"/" => Opcode::Div,
};
Term: Box<Expr> = {
Num => Box::new(Expr::Number(<>)),
"(" <Expr> ")",
! => { errors.push(<>); Box::new(Expr::Error) },
};
Num: i32 = {
r"[0-9]+" =>? <>.parse::<i32>()
.map_err(|_| ParseError::User {
error: Error::InputTooBig
})
};