use crate::combinator::empty;
use crate::combinator::fail;
use crate::combinator::opt;
use crate::combinator::trace;
use crate::error::ParserError;
use crate::stream::Stream;
use crate::stream::StreamIsPartial;
use crate::Parser;
use crate::Result;
#[doc(alias = "pratt")]
#[doc(alias = "separated")]
#[doc(alias = "shunting_yard")]
#[doc(alias = "precedence_climbing")]
#[inline(always)]
#[allow(clippy::type_complexity)]
pub fn expression<I, ParseOperand, O, E>(
parse_operand: ParseOperand,
) -> Expression<
I,
O,
ParseOperand,
impl Parser<I, Prefix<I, O, E>, E>,
impl Parser<I, Postfix<I, O, E>, E>,
impl Parser<I, Infix<I, O, E>, E>,
E,
>
where
I: Stream + StreamIsPartial,
ParseOperand: Parser<I, O, E>,
E: ParserError<I>,
{
Expression {
precedence_level: 0,
parse_operand,
parse_prefix: fail,
parse_postfix: fail,
parse_infix: fail,
marker: Default::default(),
}
}
pub struct Expression<I, O, ParseOperand, Pre, Post, Pix, E>
where
I: Stream + StreamIsPartial,
ParseOperand: Parser<I, O, E>,
E: ParserError<I>,
{
precedence_level: i64,
parse_operand: ParseOperand,
parse_prefix: Pre,
parse_postfix: Post,
parse_infix: Pix,
marker: core::marker::PhantomData<(I, O, E)>,
}
impl<I, O, ParseOperand, Pre, Post, Pix, E> Expression<I, O, ParseOperand, Pre, Post, Pix, E>
where
ParseOperand: Parser<I, O, E>,
I: Stream + StreamIsPartial,
E: ParserError<I>,
{
#[inline(always)]
pub fn prefix<NewParsePrefix>(
self,
parser: NewParsePrefix,
) -> Expression<I, O, ParseOperand, NewParsePrefix, Post, Pix, E>
where
NewParsePrefix: Parser<I, Prefix<I, O, E>, E>,
{
Expression {
precedence_level: self.precedence_level,
parse_operand: self.parse_operand,
parse_prefix: parser,
parse_postfix: self.parse_postfix,
parse_infix: self.parse_infix,
marker: Default::default(),
}
}
#[inline(always)]
pub fn postfix<NewParsePostfix>(
self,
parser: NewParsePostfix,
) -> Expression<I, O, ParseOperand, Pre, NewParsePostfix, Pix, E>
where
NewParsePostfix: Parser<I, Postfix<I, O, E>, E>,
{
Expression {
precedence_level: self.precedence_level,
parse_operand: self.parse_operand,
parse_prefix: self.parse_prefix,
parse_postfix: parser,
parse_infix: self.parse_infix,
marker: Default::default(),
}
}
#[inline(always)]
pub fn infix<NewParseInfix>(
self,
parser: NewParseInfix,
) -> Expression<I, O, ParseOperand, Pre, Post, NewParseInfix, E>
where
NewParseInfix: Parser<I, Infix<I, O, E>, E>,
{
Expression {
precedence_level: self.precedence_level,
parse_operand: self.parse_operand,
parse_prefix: self.parse_prefix,
parse_postfix: self.parse_postfix,
parse_infix: parser,
marker: Default::default(),
}
}
#[inline(always)]
pub fn current_precedence_level(
mut self,
level: i64,
) -> Expression<I, O, ParseOperand, Pre, Post, Pix, E> {
self.precedence_level = level;
self
}
}
impl<I, O, Pop, Pre, Post, Pix, E> Parser<I, O, E> for Expression<I, O, Pop, Pre, Post, Pix, E>
where
I: Stream + StreamIsPartial,
Pop: Parser<I, O, E>,
Pix: Parser<I, Infix<I, O, E>, E>,
Pre: Parser<I, Prefix<I, O, E>, E>,
Post: Parser<I, Postfix<I, O, E>, E>,
E: ParserError<I>,
{
#[inline(always)]
fn parse_next(&mut self, input: &mut I) -> Result<O, E> {
trace("expression", move |i: &mut I| {
expression_impl(
i,
&mut self.parse_operand,
&mut self.parse_prefix,
&mut self.parse_postfix,
&mut self.parse_infix,
self.precedence_level,
)
})
.parse_next(input)
}
}
fn expression_impl<I, O, Pop, Pre, Post, Pix, E>(
i: &mut I,
parse_operand: &mut Pop,
prefix: &mut Pre,
postfix: &mut Post,
infix: &mut Pix,
min_power: i64,
) -> Result<O, E>
where
I: Stream + StreamIsPartial,
Pop: Parser<I, O, E>,
Pix: Parser<I, Infix<I, O, E>, E>,
Pre: Parser<I, Prefix<I, O, E>, E>,
Post: Parser<I, Postfix<I, O, E>, E>,
E: ParserError<I>,
{
let operand = opt(trace("operand", parse_operand.by_ref())).parse_next(i)?;
let mut operand = if let Some(operand) = operand {
operand
} else {
let len = i.eof_offset();
let Prefix(power, fold_prefix) = trace("prefix", prefix.by_ref()).parse_next(i)?;
if i.eof_offset() == len {
return Err(E::assert(i, "`prefix` parsers must always consume"));
}
let operand = expression_impl(i, parse_operand, prefix, postfix, infix, power)?;
fold_prefix(i, operand)?
};
let mut prev_op_is_neither = None;
'parse: while i.eof_offset() > 0 {
let start = i.checkpoint();
if let Some(Postfix(power, fold_postfix)) =
opt(trace("postfix", postfix.by_ref())).parse_next(i)?
{
if power < min_power {
i.reset(&start);
break 'parse;
}
operand = fold_postfix(i, operand)?;
continue 'parse;
}
let start = i.checkpoint();
let parse_result = opt(trace("infix", infix.by_ref())).parse_next(i)?;
if let Some(infix_op) = parse_result {
let mut is_neither = None;
let (lpower, rpower, fold_infix) = match infix_op {
Infix::Right(p, f) => (p, p - 1, f),
Infix::Left(p, f) => (p, p + 1, f),
Infix::Neither(p, f) => {
is_neither = Some(p);
(p, p + 1, f)
}
};
if lpower < min_power
|| match prev_op_is_neither {
None => false,
Some(p) => lpower == p,
}
{
i.reset(&start);
break 'parse;
}
prev_op_is_neither = is_neither;
let rhs = expression_impl(i, parse_operand, prefix, postfix, infix, rpower)?;
operand = fold_infix(i, operand, rhs)?;
continue 'parse;
}
break 'parse;
}
Ok(operand)
}
pub struct Prefix<I, O, E>(
pub i64,
pub fn(&mut I, O) -> Result<O, E>,
);
impl<I, O, E> Clone for Prefix<I, O, E> {
#[inline(always)]
fn clone(&self) -> Self {
Prefix(self.0, self.1)
}
}
impl<I: Stream, O, E: ParserError<I>> Parser<I, Prefix<I, O, E>, E> for Prefix<I, O, E> {
#[inline(always)]
fn parse_next(&mut self, input: &mut I) -> Result<Prefix<I, O, E>, E> {
empty.value(self.clone()).parse_next(input)
}
}
pub struct Postfix<I, O, E>(
pub i64,
pub fn(&mut I, O) -> Result<O, E>,
);
impl<I, O, E> Clone for Postfix<I, O, E> {
#[inline(always)]
fn clone(&self) -> Self {
Postfix(self.0, self.1)
}
}
impl<I: Stream, O, E: ParserError<I>> Parser<I, Postfix<I, O, E>, E> for Postfix<I, O, E> {
#[inline(always)]
fn parse_next(&mut self, input: &mut I) -> Result<Postfix<I, O, E>, E> {
empty.value(self.clone()).parse_next(input)
}
}
pub enum Infix<I, O, E> {
Left(
i64,
fn(&mut I, O, O) -> Result<O, E>,
),
Right(
i64,
fn(&mut I, O, O) -> Result<O, E>,
),
Neither(
i64,
fn(&mut I, O, O) -> Result<O, E>,
),
}
impl<I, O, E> Clone for Infix<I, O, E> {
#[inline(always)]
fn clone(&self) -> Self {
match self {
Infix::Left(p, f) => Infix::Left(*p, *f),
Infix::Right(p, f) => Infix::Right(*p, *f),
Infix::Neither(p, f) => Infix::Neither(*p, *f),
}
}
}
impl<I: Stream, O, E: ParserError<I>> Parser<I, Infix<I, O, E>, E> for Infix<I, O, E> {
#[inline(always)]
fn parse_next(&mut self, input: &mut I) -> Result<Infix<I, O, E>, E> {
empty.value(self.clone()).parse_next(input)
}
}
#[cfg(all(test, feature = "ascii"))]
mod tests {
use crate::ascii::digit1;
use crate::combinator::fail;
use crate::dispatch;
use crate::error::ContextError;
use crate::token::any;
use super::*;
fn parser<'i>() -> impl Parser<&'i str, i32, ContextError> {
move |i: &mut &str| {
use Infix::*;
expression(digit1.parse_to::<i32>())
.current_precedence_level(0)
.prefix(dispatch! {any;
'+' => Prefix(12, |_, a| Ok(a)),
'-' => Prefix(12, |_, a: i32| Ok(-a)),
_ => fail
})
.infix(dispatch! {any;
'+' => Left(5, |_, a, b| Ok(a + b)),
'-' => Left(5, |_, a, b| Ok(a - b)),
'*' => Left(7, |_, a, b| Ok(a * b)),
'/' => Left(7, |_, a, b| Ok(a / b)),
'%' => Left(7, |_, a, b| Ok(a % b)),
'^' => Left(9, |_, a, b| Ok(a ^ b)),
_ => fail
})
.parse_next(i)
}
}
#[test]
fn test_expression() {
assert_eq!(parser().parse("-3+-3*4"), Ok(-15));
assert_eq!(parser().parse("+2+3*4"), Ok(14));
assert_eq!(parser().parse("2*3+4"), Ok(10));
}
}