use laps::{ast::NonEmptySepList, prelude::*, reader::Reader, span::Result, token::TokenBuffer};
#[token_kind]
#[derive(Tokenize)]
enum TokenKind {
#[skip(r"\s+")]
_Skip,
#[regex(r"[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?")]
Float(f64),
#[regex(r".")]
Other(char),
#[eof]
Eof,
}
type Token = laps::token::Token<TokenKind>;
token_ast! {
macro Token<TokenKind> {
[float] => { kind: TokenKind::Float(_), prompt: "floating-point" },
[+] => { kind: TokenKind::Other('+') },
[-] => { kind: TokenKind::Other('-') },
[*] => { kind: TokenKind::Other('*') },
[/] => { kind: TokenKind::Other('/') },
[%] => { kind: TokenKind::Other('%') },
[lpr] => { kind: TokenKind::Other('(') },
[rpr] => { kind: TokenKind::Other(')') },
[eof] => { kind: TokenKind::Eof },
}
}
#[derive(Parse)]
#[token(Token)]
struct Expr {
add: AddExpr,
_eof: Token![eof],
}
type AddExpr = NonEmptySepList<MulExpr, AddOps>;
#[derive(Parse)]
#[token(Token)]
enum AddOps {
Add(Token![+]),
Sub(Token![-]),
}
type MulExpr = NonEmptySepList<Value, MulOps>;
#[derive(Parse)]
#[token(Token)]
enum MulOps {
Mul(Token![*]),
Div(Token![/]),
Mod(Token![%]),
}
#[derive(Parse)]
#[token(Token)]
enum Value {
Num(Token![float]),
Neg(Token![-], Box<Self>),
Paren(Token![lpr], Box<AddExpr>, Token![rpr]),
}
trait Calculate {
fn calc(&self) -> Result<f64>;
}
impl Calculate for Expr {
fn calc(&self) -> Result<f64> {
self.add.calc()
}
}
impl Calculate for AddExpr {
fn calc(&self) -> Result<f64> {
match self {
Self::One(e) => e.calc(),
Self::More(l, op, r) => {
let (l, r) = (l.calc()?, r.calc()?);
Ok(match op {
AddOps::Add(_) => l + r,
AddOps::Sub(_) => l - r,
})
}
}
}
}
impl Calculate for MulExpr {
fn calc(&self) -> Result<f64> {
match self {
Self::One(e) => e.calc(),
Self::More(l, op, r) => {
let (l, r) = (l.calc()?, r.calc()?);
Ok(match op {
MulOps::Mul(_) => l * r,
MulOps::Div(_) => l / r,
MulOps::Mod(_) => l % r,
})
}
}
}
}
impl Calculate for Value {
fn calc(&self) -> Result<f64> {
match self {
Self::Num(num) => Ok(*num.unwrap_ref::<&f64, _>()),
Self::Neg(_, value) => Ok(-value.calc()?),
Self::Paren(_, add, _) => add.calc(),
}
}
}
fn main() -> Result<()> {
let reader = Reader::from_stdin();
let lexer = TokenKind::lexer(reader);
let mut tokens = TokenBuffer::new(lexer);
println!("{}", tokens.parse::<Expr>()?.calc()?);
Ok(())
}