Deprecated: Function get_magic_quotes_gpc() is deprecated in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 99

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 619

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1169

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176
8000 Attempt At Non-Infix Pratt Parsing by lancylot2004 · Pull Request #728 · zesterer/chumsky · GitHub
Nothing Special   »   [go: up one dir, main page]

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 106 additions & 38 deletions src/pratt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,10 @@ macro_rules! op_check_and_emit {
>,
lhs: (),
min_power: u32,
max_power: &mut u32,
f: &dyn Fn(&mut InputRef<'src, 'parse, I, E>, u32) -> PResult<Check, O>,
) -> Result<(), ()> {
self.do_parse_infix::<Check>(inp, pre_expr, pre_op, lhs, min_power, &f)
self.do_parse_infix::<Check>(inp, pre_expr, pre_op, lhs, min_power, max_power, &f)
}
#[inline(always)]
fn do_parse_infix_emit<'parse>(
Expand All @@ -179,9 +180,10 @@ macro_rules! op_check_and_emit {
>,
lhs: O,
min_power: u32,
max_power: &mut u32,
f: &dyn Fn(&mut InputRef<'src, 'parse, I, E>, u32) -> PResult<Emit, O>,
) -> Result<O, O> {
self.do_parse_infix::<Emit>(inp, pre_expr, pre_op, lhs, min_power, &f)
self.do_parse_infix::<Emit>(inp, pre_expr, pre_op, lhs, min_power, max_power, &f)
}
};
}
Expand Down Expand Up @@ -244,6 +246,7 @@ where
_pre_op: &input::Checkpoint<'src, 'parse, I, <E::State as Inspector<'src, I>>::Checkpoint>,
lhs: M::Output<O>,
_min_power: u32,
_max_power: &mut u32,
_f: &impl Fn(&mut InputRef<'src, 'parse, I, E>, u32) -> PResult<M, O>,
) -> Result<M::Output<O>, M::Output<O>>
where
Expand Down Expand Up @@ -292,6 +295,7 @@ where
pre_op: &input::Checkpoint<'src, 'parse, I, <E::State as Inspector<'src, I>>::Checkpoint>,
lhs: (),
min_power: u32,
max_power: &mut u32,
f: &dyn Fn(&mut InputRef<'src, 'parse, I, E>, u32) -> PResult<Check, O>,
) -> Result<(), ()>;
#[doc(hidden)]
Expand All @@ -302,6 +306,7 @@ where
pre_op: &input::Checkpoint<'src, 'parse, I, <E::State as Inspector<'src, I>>::Checkpoint>,
lhs: O,
min_power: u32,
max_power: &mut u32,
f: &dyn Fn(&mut InputRef<'src, 'parse, I, E>, u32) -> PResult<Emit, O>,
) -> Result<O, O>;
}
Expand Down Expand Up @@ -356,12 +361,13 @@ where
pre_op: &input::Checkpoint<'src, 'parse, I, <E::State as Inspector<'src, I>>::Checkpoint>,
lhs: M::Output<O>,
min_power: u32,
max_power: &mut u32,
f: &impl Fn(&mut InputRef<'src, 'parse, I, E>, u32) -> PResult<M, O>,
) -> Result<M::Output<O>, M::Output<O>>
where
Self: Sized,
{
M::invoke_pratt_op_infix(self, inp, pre_expr, pre_op, lhs, min_power, f)
M::invoke_pratt_op_infix(self, inp, pre_expr, pre_op, lhs, min_power, max_power, f)
}

#[inline(always)]
Expand Down Expand Up @@ -414,10 +420,11 @@ where
pre_op: &input::Checkpoint<'src, 'parse, I, <E::State as Inspector<'src, I>>::Checkpoint>,
lhs: (),
min_power: u32,
max_power: &mut u32,
f: &dyn Fn(&mut InputRef<'src, 'parse, I, E>, u32) -> PResult<Check, O>,
) -> Result<(), ()> {
self.0
.do_parse_infix_check(inp, pre_expr, pre_op, lhs, min_power, &f)
.do_parse_infix_check(inp, pre_expr, pre_op, lhs, min_power, max_power, &f)
}
#[inline(always)]
fn do_parse_infix_emit<'parse>(
Expand All @@ -427,23 +434,35 @@ where
pre_op: &input::Checkpoint<'src, 'parse, I, <E::State as Inspector<'src, I>>::Checkpoint>,
lhs: O,
min_power: u32,
max_power: &mut u32,
f: &dyn Fn(&mut InputRef<'src, 'parse, I, E>, u32) -> PResult<Emit, O>,
) -> Result<O, O> {
self.0
.do_parse_infix_emit(inp, pre_expr, pre_op, lhs, min_power, &f)
.do_parse_infix_emit(inp, pre_expr, pre_op, lhs, min_power, max_power, &f)
}
}

/// Defines the [associativity](https://en.wikipedia.org/wiki/Associative_property) and binding power of an [`infix`]
/// operator (see [`left`] and [`right`]).
/// operator (see [`left`], [`right`], and [`non`]).
///
/// Higher binding powers should be used for higher precedence operators.
///
/// The left, right, and next binding powers are used to determine precedence in the parser. They
/// are calculated as follows:
///
/// | | left power | right power | next power |
/// |-------|------------|-------------|------------|
/// | Left | bp * 3 | bp * 3 + 1 | bp * 3 |
/// | Right | bp * 3 + 1 | bp * 3 | bp * 3 |
/// | Non | bp * 3 | bp * 3 | bp * 3 + 1 |
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Associativity {
/// Specifies that the operator should be left-associative, with the given binding power (see [`left`]).
Left(u16),
/// Specifies that the operator should be right-associative, with the given binding power (see [`right`]).
Right(u16),
/// Specifies that the operator should non-associative, with the given binding power (see [`non`]).
Non(u16),
}

/// Specifies a left [`Associativity`] with the given binding power.
Expand All @@ -462,18 +481,32 @@ pub fn right(binding_power: u16) -> Associativity {
Associativity::Right(binding_power)
}

/// Specifies a non-associative [`Associativity`] with the given binding power.
///
/// Non-associative operators cannot be chained, but otherwise respect binding powers. For example,
/// the expression `a == b == c` is invalid if `==` is a non-associative operator (which in
/// general, all comparison operators are).
pub fn non(binding_power: u16) -> Associativity {
Associativity::Non(binding_power)
}

impl Associativity {
fn left_power(&self) -> u32 {
let (&Self::Left(x) | &Self::Non(x) | &Self::Right(x)) = self;
x as u32 * 3 + 1
}

fn right_power(&self) -> u32 {
match self {
Self::Left(x) => *x as u32 * 2,
Self::Right(x) => *x as u32 * 2 + 1,
&Self::Left(x) | &Self::Non(x) => x as u32 * 3 + 2,
&Self::Right(x) => x as u32 * 3 + 1,
}
Comment on lines +499 to 503
Copy link
Owner
@zesterer zesterer Feb 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem to match up with the table above it. Perhaps this is the cause of the test failure?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies I should've changed the table - the values in the table don't work either!

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean the values in the table are correct now? Apologies about not having gotten back to you in a while!

}

fn right_power(&self) -> u32 {
fn next_power(&self) -> u32 {
match self {
Self::Left(x) => *x as u32 * 2 + 1,
Self::Right(x) => *x as u32 * 2,
&Self::Left(x) | &Self::Right(x) => x as u32 * 3 + 1,
&Self::Non(x) => x as u32 * 3,
}
}
}
Expand Down Expand Up @@ -536,42 +569,50 @@ where
A: Parser<'src, I, Op, E>,
F: Fn(O, Op, O, &mut MapExtra<'src, '_, I, E>) -> O,
{
#[inline]
fn do_parse_infix<'parse, M: Mode>(
&self,
inp: &mut InputRef<'src, 'parse, I, E>,
pre_expr: &input::Cursor<'src, 'parse, I>,
pre_op: &input::Checkpoint<'src, 'parse, I, <E::State as Inspector<'src, I>>::Checkpoint>,
lhs: M::Output<O>,
min_power: u32,
max_power: &mut u32,
f: &impl Fn(&mut InputRef<'src, 'parse, I, E>, u32) -> PResult<M, O>,
) -> Result<M::Output<O>, M::Output<O>>
where
Self: Sized,
{
if self.associativity.left_power() >= min_power {
match self.op_parser.go::<M>(inp) {
Ok(op) => match f(inp, self.associativity.right_power()) {
Ok(rhs) => Ok(M::combine(
M::combine(lhs, rhs, |lhs, rhs| (lhs, rhs)),
op,
|(lhs, rhs), op| {
(self.fold)(lhs, op, rhs, &mut MapExtra::new(pre_expr, inp))
},
775E )),
Err(()) => {
inp.rewind(pre_op.clone());
Err(lhs)
}
},
Err(()) => {
inp.rewind(pre_op.clone());
Err(lhs)
}
let assoc = self.associativity;
if assoc.left_power() < min_power || assoc.left_power() > *max_power {
return Err(lhs);
}

let op = match self.op_parser.go::<M>(inp) {
Ok(op) => op,
Err(()) => {
inp.rewind(pre_op.clone());
return Err(lhs);
}
} else {
Err(lhs)
};

let rhs = match f(inp, assoc.right_power()) {
Ok(rhs) => rhs,
Err(()) => {
inp.rewind(pre_op.clone());
return Err(lhs);
}
};

let res = M::combine(
M::combine(lhs, rhs, |lhs, rhs| (lhs, rhs)),
op,
|(lhs, rhs), op| { (self.fold)(lhs, op, rhs, &mut MapExtra::new(pre_expr, inp)) },
);

if let Associativity::Non(_) | Associativity::Left(_) = assoc {
*max_power = assoc.next_power();
}
Ok(res)
}

op_check_and_emit!();
Expand Down Expand Up @@ -818,14 +859,15 @@ macro_rules! impl_operator_for_tuple {
pre_op: &input::Checkpoint<'src, 'parse, I, <E::State as Inspector<'src, I>>::Checkpoint>,
mut lhs: M::Output<O>,
min_power: u32,
max_power: &mut u32,
f: &impl Fn(&mut InputRef<'src, 'parse, I, E>, u32) -> PResult<M, O>,
) -> Result<M::Output<O>, M::Output<O>>
where
Self: Sized,
{
let ($($X,)*) = self;
$(
match $X.do_parse_infix::<M>(inp, pre_expr, pre_op, lhs, min_power, f) {
match $X.do_parse_infix::<M>(inp, pre_expr, pre_op, lhs, min_power, max_power, f) {
Ok(out) => return Ok(out),
Err(out) => lhs = out,
}
Expand Down Expand Up @@ -894,13 +936,14 @@ where
pre_op: &input::Checkpoint<'src, 'parse, I, <E::State as Inspector<'src, I>>::Checkpoint>,
mut lhs: M::Output<O>,
min_power: u32,
max_power: &mut u32,
f: &impl Fn(&mut InputRef<'src, 'parse, I, E>, u32) -> PResult<M, O>,
) -> Result<M::Output<O>, M::Output<O>>
where
Self: Sized,
{
for op in self {
match op.do_parse_infix::<M>(inp, pre_expr, pre_op, lhs, min_power, f) {
match op.do_parse_infix::<M>(inp, pre_expr, pre_op, lhs, min_power, max_power, f) {
Ok(out) => return Ok(out),
Err(out) => lhs = out,
}
Expand All @@ -918,19 +961,21 @@ impl<'src, Atom, Ops> Pratt<Atom, Ops> {
&self,
inp: &mut InputRef<'src, '_, I, E>,
min_power: u32,
max_power: Option<u32>,
) -> PResult<M, O>
where
I: Input<'src>,
E: ParserExtra<'src, I>,
Atom: Parser<'src, I, O, E>,
Ops: Operator<'src, I, O, E>,
{
let mut max_power: u32 = max_power.unwrap_or(u32::MAX);
let pre_expr = inp.save();
// Prefix unary operators
let mut lhs = match self
.ops
.do_parse_prefix::<M>(inp, &pre_expr, &|inp, min_power| {
recursive::recurse(|| self.pratt_go::<M, _, _, _>(inp, min_power))
recursive::recurse(|| self.pratt_go::<M, _, _, _>(inp, min_power, None))
}) {
Ok(out) => out,
Err(()) => self.atom.go::<M>(inp)?,
Expand Down Expand Up @@ -958,8 +1003,9 @@ impl<'src, Atom, Ops> Pratt<Atom, Ops> {
&pre_op,
lhs,
min_power,
&mut max_power,
&|inp, min_power| {
recursive::recurse(|| self.pratt_go::<M, _, _, _>(inp, min_power))
recursive::recurse(|| self.pratt_go::<M, _, _, _>(inp, min_power, None))
},
) {
Ok(out) => {
Expand All @@ -986,7 +1032,7 @@ where
Ops: Operator<'src, I, O, E>,
{
fn go<M: Mode>(&self, inp: &mut InputRef<'src, '_, I, E>) -> PResult<M, O> {
self.pratt_go::<M, _, _, _>(inp, 0)
self.pratt_go::<M, _, _, _>(inp, 0, None)
}

go_extra!(O);
Expand Down Expand Up @@ -1254,4 +1300,26 @@ mod tests {
Ok("(((§(1 + (-(~(2!)))))$) * 3)".to_string()),
)
}

#[test]
fn with_pre_and_postfix_ops_and_parentheses() {
let atom = text::int::<_, Err<Simple<char>>>(10)
.from_str()
.unwrapped()
.map(Expr::Literal);

let parser = atom
.pratt((
// -- Infix
infix(left(1), just('+'), |l, _, r, _| i(Expr::Add, l, r)),
infix(non(2), just('*'), |l, _, r, _| i(Expr::Mul, l, r)),
))
.map(|x| x.to_string());
assert_eq!(
parser.parse("1+2*3").into_result(),
Ok("(1 + (2 * 3))".to_string())
);
assert!(parser.parse("1+2*3*3").has_errors());
Comment on lines +1311 to +1322
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be a good idea to check that 1+2*3*5 fails here too. assert!(parser.parse(...).has_errors()) should be sufficient.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added!

assert!(parser.parse("1+2*3*5").has_errors());
}
}
7 changes: 5 additions & 2 deletions src/private.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ pub trait Mode {
pre_op: &input::Checkpoint<'src, 'parse, I, <E::State as Inspector<'src, I>>::Checkpoint>,
lhs: Self::Output<O>,
min_power: u32,
max_power: &mut u32,
f: &impl Fn(&mut InputRef<'src, 'parse, I, E>, u32) -> PResult<Self, O>,
) -> Result<Self::Output<O>, Self::Output<O>>
where
Expand Down Expand Up @@ -228,14 +229,15 @@ impl Mode for Emit {
pre_op: &input::Checkpoint<'src, 'parse, I, <E::State as Inspector<'src, I>>::Checkpoint>,
lhs: Self::Output<O>,
min_power: u32,
max_power: &mut u32,
f: &impl Fn(&mut InputRef<'src, 'parse, I, E>, u32) -> PResult<Self, O>,
) -> Result<Self::Output<O>, Self::Output<O>>
where
Op: pratt::Operator<'src, I, O, E>,
I: Input<'src>,
E: ParserExtra<'src, I>,
{
op.do_parse_infix_emit(inp, pre_expr, pre_op, lhs, min_power, &f)
op.do_parse_infix_emit(inp, pre_expr, pre_op, lhs, min_power, max_power, &f)
}
}

Expand Down Expand Up @@ -339,14 +341,15 @@ impl Mode for Check {
pre_op: &input::Checkpoint<'src, 'parse, I, <E::State as Inspector<'src, I>>::Checkpoint>,
lhs: Self::Output<O>,
min_power: u32,
max_power: &mut u32,
f: &impl Fn(&mut InputRef<'src, 'parse, I, E>, u32) -> PResult<Self, O>,
) -> Result<Self::Output<O>, Self::Output<O>>
where
Op: pratt::Operator<'src, I, O, E>,
I: Input<'src>,
E: ParserExtra<'src, I>,
{
op.do_parse_infix_check(inp, pre_expr, pre_op, lhs, min_power, &f)
op.do_parse_infix_check(inp, pre_expr, pre_op, lhs, min_power, max_power, &f)
}
}

Expand Down
Loading
0