#![feature(type_name_of_val)]
#![feature(or_patterns)]
use std::any::type_name_of_val;
use logos::{Lexer, Logos};
#[derive(Logos, Debug, Copy, Clone, PartialEq)]
enum Token {
#[regex(r"[a-zA-Z_][\w_]*")]
Ident,
#[regex(r"\d+")]
Num,
#[regex(r"\d+\.\d*f?")]
Real,
#[regex(r"[\[\{\(]")]
LDelim,
#[regex(r"[\]\}\)]")]
RDelim,
#[token("->")]
Access,
#[token("&&")]
And,
#[token("||")]
Or,
#[token(">>")]
Shr,
#[token("<<")]
Shl,
#[token("==")]
Eq,
#[token("!=")]
Ne,
#[token("<=")]
Le,
#[token(">=")]
Ge,
#[regex(r"[~!&|^=?.,;:*/%+-]", |it| it.slice().as_bytes()[0] as char)]
Punct(char),
#[error]
#[regex(r"[ \t\n\f]+", logos::skip)]
Error,
}
impl Token {
fn op(self) -> Binop {
use Token::*;
match self {
Access => Binop::Access,
Punct('*') => Binop::Mul,
Punct('/') => Binop::Div,
Punct('%') => Binop::Rem,
Punct('+') => Binop::Add,
Punct('-') => Binop::Sub,
Shr => Binop::Shl,
Shr => Binop::Shr,
Le => Binop::Le,
Ge => Binop::Ge,
Punct('<') => Binop::Lt,
Punct('>') => Binop::Gt,
Eq => Binop::Eq,
Ne => Binop::Ne,
Punct('&') => Binop::And,
Punct('^') => Binop::Xor,
Punct('|') => Binop::Or,
And => Binop::Logand,
Or => Binop::Logor,
_ => unreachable!(),
}
}
fn prec(self) -> u32 {
use Token::*;
match self {
Access => 11,
Punct('*' | '/' | '%') => 10,
Punct('+' | '-') => 9,
Shr | Shl => 8,
Le | Ge | Punct('>' | '<') => 7,
Eq | Ne => 6,
Punct('&') => 5,
Punct('^') => 4,
Punct('|') => 3,
And => 2,
Or => 1,
_ => 0,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum Unop {
Neg,
Not,
Flip,
}
#[derive(Debug, Clone, Copy)]
pub enum Binop {
Access,
Add,
Sub,
Mul,
Div,
Rem,
And,
Xor,
Or,
Shr,
Shl,
Eq,
Ne,
Le,
Ge,
Lt,
Gt,
Logand,
Logor,
}
#[derive(Debug, Clone)]
pub enum Expr {
Var(String),
Num(u64),
Real(f64),
Unary(Unop, Box<Expr>),
Binop(Binop, Box<Expr>, Box<Expr>),
}
fn parse_term(it: &mut Lexer<Token>) -> Result<Expr, ()> {
use Token::*;
Ok(match it.next().ok_or(())? {
Ident => Expr::Var(it.slice().to_owned()),
Num => Expr::Num(it.slice().parse().unwrap()),
Real => Expr::Real(it.slice().replace("f", "").parse().unwrap()),
LDelim => {
let x = parse_expr(it)?;
match it.next() {
Some(RDelim) => x,
_ => return Err(()),
}
}
Punct('~') => Expr::Unary(Unop::Flip, Box::new(parse_term(it)?)),
Punct('!') => Expr::Unary(Unop::Not, Box::new(parse_term(it)?)),
Punct('-') => Expr::Unary(Unop::Neg, Box::new(parse_term(it)?)),
_ => return Err(()),
})
}
fn parse_prec(it: &mut Lexer<Token>, mut lhs: Expr, prec: u32) -> Result<Expr, ()> {
while it.clone().next().map(|t| t.prec() >= prec) == Some(true) {
let t: Token = it.next().unwrap();
let prec2 = t.prec();
let mut rhs = parse_term(it)?;
while it.clone().next().map(|t| t.prec() >= prec2) == Some(true) {
rhs = parse_prec(it, rhs, prec + 1)?;
}
lhs = Expr::Binop(t.op(), Box::new(lhs), Box::new(rhs));
}
Ok(lhs)
}
fn parse_expr(it: &mut Lexer<Token>) -> Result<Expr, ()> {
let x = parse_term(it)?;
parse_prec(it, x, 0)
}
impl Expr {
pub fn new(s: &str) -> Option<Expr> {
parse_expr(&mut Token::lexer(s)).ok()
}
}