use core::cmp::Ordering;
use crate::lexer::{Kind, Lexer, Token};
use crate::{Error, ErrorKind, Number, PercentSign, Span};
#[derive(Debug, Clone, Copy)]
pub(crate) struct Syntax {
pub max_depth: usize,
pub percent_sign: PercentSign,
pub implicit_multiplication: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Binary {
Add,
Subtract,
Multiply,
Divide,
Remainder,
Power,
Less,
LessEqual,
Greater,
GreaterEqual,
Equal,
NotEqual,
}
impl Binary {
pub fn apply<N: Number>(self, left: N, right: N) -> Result<N, ErrorKind> {
let ordering = |accept: fn(Ordering) -> bool| {
left.compare(right)
.and_then(|ordering| N::from_bool(accept(ordering)))
};
match self {
Self::Add => left.add(right),
Self::Subtract => left.subtract(right),
Self::Multiply => left.multiply(right),
Self::Divide => left.divide(right),
Self::Remainder => left.remainder(right),
Self::Power => left.power(right),
Self::Less => ordering(Ordering::is_lt),
Self::LessEqual => ordering(Ordering::is_le),
Self::Greater => ordering(Ordering::is_gt),
Self::GreaterEqual => ordering(Ordering::is_ge),
Self::Equal => ordering(Ordering::is_eq),
Self::NotEqual => ordering(Ordering::is_ne),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Unary {
Negate,
Not,
Percentage,
Factorial,
}
impl Unary {
pub fn apply<N: Number>(self, operand: N) -> Result<N, ErrorKind> {
match self {
Self::Negate => operand.negate(),
Self::Not => N::from_bool(operand.is_zero()?),
Self::Percentage => operand.divide(N::parse("100").ok_or(ErrorKind::Overflow)?),
Self::Factorial => operand.factorial(),
}
}
}
#[derive(Clone, Copy)]
enum Operator {
Binary(Binary),
Implicit,
And,
Or,
Conditional,
Postfix(Unary),
}
const CONDITIONAL: (u8, u8) = (2, 1);
const OR: (u8, u8) = (3, 4);
const AND: (u8, u8) = (5, 6);
const EQUALITY: (u8, u8) = (7, 8);
const RELATIONAL: (u8, u8) = (9, 10);
const ADDITIVE: (u8, u8) = (11, 12);
const MULTIPLICATIVE: (u8, u8) = (13, 14);
const UNARY: u8 = 15;
const POWER: (u8, u8) = (18, 17);
const POSTFIX: u8 = 19;
pub(crate) trait Backend<'i> {
type Value: Copy + Default;
type Branch: Copy;
fn number(&mut self, literal: &'i str, span: Span) -> Result<Self::Value, Error>;
fn variable(&mut self, name: &'i str, span: Span) -> Result<Self::Value, Error>;
fn call(
&mut self,
name: &'i str,
name_span: Span,
arguments: &[Self::Value],
span: Span,
) -> Result<Self::Value, Error>;
fn unary(
&mut self,
operator: Unary,
operand: Self::Value,
span: Span,
) -> Result<Self::Value, Error>;
fn binary(
&mut self,
operator: Binary,
left: Self::Value,
right: Self::Value,
span: Span,
) -> Result<Self::Value, Error>;
fn logic(&mut self, or: bool, left: Self::Value, span: Span) -> Result<Self::Branch, Error>;
fn logic_end(
&mut self,
or: bool,
branch: Self::Branch,
right: Self::Value,
span: Span,
) -> Result<Self::Value, Error>;
fn condition(&mut self, condition: Self::Value, span: Span) -> Result<Self::Branch, Error>;
fn otherwise(&mut self, branch: Self::Branch, span: Span) -> Result<Self::Branch, Error>;
fn conditional_end(
&mut self,
branch: Self::Branch,
then: Self::Value,
otherwise: Self::Value,
) -> Self::Value;
}
pub(crate) struct Parser<'i, B, const ARGUMENTS: usize> {
lexer: Lexer<'i>,
token: Token<'i>,
end: usize,
depth: usize,
syntax: Syntax,
pub backend: B,
}
impl<'i, B: Backend<'i>, const ARGUMENTS: usize> Parser<'i, B, ARGUMENTS> {
pub fn parse(input: &'i str, syntax: Syntax, backend: B) -> Result<(B::Value, B), Error> {
let mut lexer = Lexer::new(input);
let token = lexer.next()?;
let mut parser = Self {
lexer,
token,
end: 0,
depth: 0,
syntax,
backend,
};
let value = parser.expression(0)?;
match parser.token.kind {
Kind::End => Ok((value, parser.backend)),
_ => Err(Error::new(ErrorKind::UnexpectedToken, parser.token.span)),
}
}
fn advance(&mut self) -> Result<Token<'i>, Error> {
let token = self.token;
self.end = token.span.end;
self.token = self.lexer.next()?;
Ok(token)
}
fn from(&self, start: usize) -> Span {
Span::new(start, self.end)
}
fn infix(&self) -> Option<(Operator, (u8, u8))> {
let binary = |operator, powers| Some((Operator::Binary(operator), powers));
let postfix = |operator| Some((Operator::Postfix(operator), (POSTFIX, POSTFIX)));
match self.token.kind {
Kind::Plus => binary(Binary::Add, ADDITIVE),
Kind::Minus => binary(Binary::Subtract, ADDITIVE),
Kind::Star => binary(Binary::Multiply, MULTIPLICATIVE),
Kind::Slash => binary(Binary::Divide, MULTIPLICATIVE),
Kind::Percent => match self.syntax.percent_sign {
PercentSign::Remainder => binary(Binary::Remainder, MULTIPLICATIVE),
PercentSign::Percentage => postfix(Unary::Percentage),
},
Kind::Name("mod") => binary(Binary::Remainder, MULTIPLICATIVE),
Kind::Caret => binary(Binary::Power, POWER),
Kind::Less => binary(Binary::Less, RELATIONAL),
Kind::LessEqual => binary(Binary::LessEqual, RELATIONAL),
Kind::Greater => binary(Binary::Greater, RELATIONAL),
Kind::GreaterEqual => binary(Binary::GreaterEqual, RELATIONAL),
Kind::Equal => binary(Binary::Equal, EQUALITY),
Kind::NotEqual => binary(Binary::NotEqual, EQUALITY),
Kind::And => Some((Operator::And, AND)),
Kind::Or => Some((Operator::Or, OR)),
Kind::Question => Some((Operator::Conditional, CONDITIONAL)),
Kind::Not => postfix(Unary::Factorial),
Kind::Name(_) | Kind::LeftParenthesis if self.syntax.implicit_multiplication => {
Some((Operator::Implicit, MULTIPLICATIVE))
}
_ => None,
}
}
fn expression(&mut self, minimum: u8) -> Result<B::Value, Error> {
if self.depth == self.syntax.max_depth {
return Err(Error::new(ErrorKind::TooDeep, self.token.span));
}
self.depth += 1;
let start = self.token.span.start;
let mut left = self.prefix()?;
while let Some((operator, (left_power, right_power))) = self.infix() {
if left_power < minimum {
break;
}
if !matches!(operator, Operator::Implicit) {
self.advance()?;
}
left = match operator {
Operator::Binary(operator) => {
let right = self.expression(right_power)?;
self.backend
.binary(operator, left, right, self.from(start))?
}
Operator::Implicit => {
let right = self.expression(right_power)?;
self.backend
.binary(Binary::Multiply, left, right, self.from(start))?
}
Operator::Postfix(operator) => {
self.backend.unary(operator, left, self.from(start))?
}
Operator::And | Operator::Or => {
let or = matches!(operator, Operator::Or);
let branch = self.backend.logic(or, left, self.from(start))?;
let right = self.expression(right_power)?;
self.backend
.logic_end(or, branch, right, self.from(start))?
}
Operator::Conditional => self.conditional(start, left)?,
};
}
self.depth -= 1;
Ok(left)
}
fn conditional(&mut self, start: usize, condition: B::Value) -> Result<B::Value, Error> {
let branch = self.backend.condition(condition, self.from(start))?;
let then = self.expression(0)?;
let colon = match self.token.kind {
Kind::Colon => self.advance()?,
Kind::End => return Err(Error::new(ErrorKind::UnexpectedEnd, self.token.span)),
_ => return Err(Error::new(ErrorKind::UnexpectedToken, self.token.span)),
};
let branch = self.backend.otherwise(branch, colon.span)?;
let otherwise = self.expression(CONDITIONAL.1)?;
Ok(self.backend.conditional_end(branch, then, otherwise))
}
fn prefix(&mut self) -> Result<B::Value, Error> {
let token = self.advance()?;
let start = token.span.start;
match token.kind {
Kind::Number(literal) => self.backend.number(literal, token.span),
Kind::Name(name) if self.token.kind == Kind::LeftParenthesis => self.call(name, token),
Kind::Name(name) => self.backend.variable(name, token.span),
Kind::LeftParenthesis => {
let value = self.expression(0)?;
self.close(token)?;
Ok(value)
}
Kind::Minus => {
let operand = self.expression(UNARY)?;
self.backend.unary(Unary::Negate, operand, self.from(start))
}
Kind::Plus => self.expression(UNARY),
Kind::Not => {
let operand = self.expression(UNARY)?;
self.backend.unary(Unary::Not, operand, self.from(start))
}
Kind::End => Err(Error::new(ErrorKind::UnexpectedEnd, token.span)),
_ => Err(Error::new(ErrorKind::UnexpectedToken, token.span)),
}
}
fn close(&mut self, opening: Token<'i>) -> Result<(), Error> {
match self.token.kind {
Kind::RightParenthesis => self.advance().map(drop),
Kind::End => Err(Error::new(ErrorKind::UnclosedParenthesis, opening.span)),
_ => Err(Error::new(ErrorKind::UnexpectedToken, self.token.span)),
}
}
#[inline(never)]
fn call(&mut self, name: &'i str, name_token: Token<'i>) -> Result<B::Value, Error> {
let opening = self.advance()?;
let mut arguments = [B::Value::default(); ARGUMENTS];
let mut count = 0;
if self.token.kind != Kind::RightParenthesis {
loop {
let start = self.token.span.start;
let value = self.expression(0)?;
let slot = arguments
.get_mut(count)
.ok_or(Error::new(ErrorKind::TooManyArguments, self.from(start)))?;
*slot = value;
count += 1;
if self.token.kind != Kind::Comma {
break;
}
self.advance()?;
}
}
self.close(opening)?;
self.backend.call(
name,
name_token.span,
&arguments[..count],
self.from(name_token.span.start),
)
}
}