Skip to content
This repository was archived by the owner on Apr 2, 2026. It is now read-only.

Commit 009a019

Browse files
committed
Use typle for tuple functions
This generates almost identical code to the existing macros while being more readable. The only semantic difference is for `Choice`, where the final option does not rewind the input.
1 parent e3b91d8 commit 009a019

4 files changed

Lines changed: 167 additions & 239 deletions

File tree

Cargo.lock

Lines changed: 18 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ spin = { version = "0.9", features = ["once"], default-features = false, optiona
7979
lexical = { version = "6.1.1", default-features = false, features = ["parse-integers", "parse-floats", "format"], optional = true }
8080
either = { version = "1.8.1", optional = true }
8181
serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] }
82+
typle = "0.9.4"
8283
unicode-ident = "1.0.10"
8384

8485
[dev-dependencies]

src/pratt.rs

Lines changed: 107 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@
8989
//! );
9090
//! ```
9191
92+
use typle::typle;
93+
9294
use super::*;
9395

9496
trait Operator<'a, I, O, E>
@@ -404,117 +406,124 @@ pub struct Pratt<Atom, Ops> {
404406
pub(crate) ops: Ops,
405407
}
406408

407-
macro_rules! impl_pratt_for_tuple {
408-
() => {};
409-
($head:ident $($X:ident)*) => {
410-
impl_pratt_for_tuple!($($X)*);
411-
impl_pratt_for_tuple!(~ $head $($X)*);
412-
};
413-
(~ $($X:ident)+) => {
414-
#[allow(unused_variables, non_snake_case)]
415-
impl<'a, Atom, $($X),*> Pratt<Atom, ($($X,)*)> {
416-
#[inline]
417-
fn pratt_go<M: Mode, I, O, E>(&self, inp: &mut InputRef<'a, '_, I, E>, min_power: u32) -> PResult<M, O>
418-
where
419-
I: Input<'a>,
420-
E: ParserExtra<'a, I>,
421-
Atom: Parser<'a, I, O, E>,
422-
$($X: Operator<'a, I, O, E>),*
423-
{
424-
let pre_expr = inp.save();
425-
let mut lhs = 'choice: {
426-
let ($($X,)*) = &self.ops;
427-
428-
// Prefix unary operators
429-
$(
430-
if $X::IS_PREFIX {
431-
match $X.op_parser().go::<M>(inp) {
432-
Ok(op) => {
433-
match recursive::recurse(|| self.pratt_go::<M, _, _, _>(inp, $X.associativity().left_power())) {
434-
Ok(rhs) => break 'choice M::combine(op, rhs, |op, rhs| {
435-
$X.fold_prefix(op, rhs, &mut MapExtra::new(pre_expr.offset(), inp))
436-
}),
437-
Err(()) => inp.rewind(pre_expr),
438-
}
439-
},
409+
#[typle(Tuple for 1..=26)]
410+
impl<'a, Atom, T: Tuple> Pratt<Atom, T> {
411+
#[inline]
412+
fn pratt_go<M: Mode, I, O, E>(
413+
&self,
414+
inp: &mut InputRef<'a, '_, I, E>,
415+
min_power: u32,
416+
) -> PResult<M, O>
417+
where
418+
I: Input<'a>,
419+
E: ParserExtra<'a, I>,
420+
Atom: Parser<'a, I, O, E>,
421+
T<_>: Operator<'a, I, O, E>,
422+
{
423+
let pre_expr = inp.save();
424+
let mut lhs = 'choice: {
425+
// Prefix unary operators
426+
for typle_index!(i) in 0..T::LEN {
427+
if T::<{ i }>::IS_PREFIX {
428+
let t = &self.ops[[i]];
429+
match t.op_parser().go::<M>(inp) {
430+
Ok(op) => {
431+
match recursive::recurse(|| {
432+
self.pratt_go::<M, _, _, _>(inp, t.associativity().left_power())
433+
}) {
434+
Ok(rhs) => {
435+
break 'choice M::combine(op, rhs, |op, rhs| {
436+
t.fold_prefix(
437+
op,
438+
rhs,
439+
&mut MapExtra::new(pre_expr.offset(), inp),
440+
)
441+
})
442+
}
440443
Err(()) => inp.rewind(pre_expr),
441444
}
442445
}
443-
)*
444-
445-
self.atom.go::<M>(inp)?
446-
};
447-
448-
loop {
449-
let ($($X,)*) = &self.ops;
450-
451-
let pre_op = inp.save();
452-
453-
// Postfix unary operators
454-
$(
455-
let assoc = $X.associativity();
456-
if $X::IS_POSTFIX && assoc.right_power() >= min_power {
457-
match $X.op_parser().go::<M>(inp) {
458-
Ok(op) => {
459-
lhs = M::combine(lhs, op, |lhs, op| {
460-
$X.fold_postfix(lhs, op, &mut MapExtra::new(pre_expr.offset(), inp))
461-
});
462-
continue
463-
},
464-
Err(()) => inp.rewind(pre_op),
465-
}
446+
Err(()) => inp.rewind(pre_expr),
447+
}
448+
}
449+
}
450+
451+
self.atom.go::<M>(inp)?
452+
};
453+
454+
'start: loop {
455+
let pre_op = inp.save();
456+
457+
// Postfix unary operators
458+
for typle_index!(i) in 0..T::LEN {
459+
let t = &self.ops[[i]];
460+
let assoc = t.associativity();
461+
if T::<{ i }>::IS_POSTFIX && assoc.right_power() >= min_power {
462+
match t.op_parser().go::<M>(inp) {
463+
Ok(op) => {
464+
lhs = M::combine(lhs, op, |lhs, op| {
465+
t.fold_postfix(lhs, op, &mut MapExtra::new(pre_expr.offset(), inp))
466+
});
467+
continue 'start;
466468
}
467-
)*
468-
469-
// Infix binary operators
470-
$(
471-
let assoc = $X.associativity();
472-
if $X::IS_INFIX && assoc.left_power() >= min_power {
473-
match $X.op_parser().go::<M>(inp) {
474-
Ok(op) => match recursive::recurse(|| self.pratt_go::<M, _, _, _>(inp, assoc.right_power())) {
475-
Ok(rhs) => {
476-
lhs = M::combine(
477-
M::combine(lhs, rhs, |lhs, rhs| (lhs, rhs)),
469+
Err(()) => inp.rewind(pre_op),
470+
}
471+
}
472+
}
473+
474+
// Infix binary operators
475+
for typle_index!(i) in 0..T::LEN {
476+
let t = &self.ops[[i]];
477+
let assoc = t.associativity();
478+
if T::<{ i }>::IS_INFIX && assoc.left_power() >= min_power {
479+
match t.op_parser().go::<M>(inp) {
480+
Ok(op) => match recursive::recurse(|| {
481+
self.pratt_go::<M, _, _, _>(inp, assoc.right_power())
482+
}) {
483+
Ok(rhs) => {
484+
lhs = M::combine(
485+
M::combine(lhs, rhs, |lhs, rhs| (lhs, rhs)),
486+
op,
487+
|(lhs, rhs), op| {
488+
t.fold_infix(
489+
lhs,
478490
op,
479-
|(lhs, rhs), op| {
480-
$X.fold_infix(lhs, op, rhs, &mut MapExtra::new(pre_expr.offset(), inp))
481-
},
482-
);
483-
continue
491+
rhs,
492+
&mut MapExtra::new(pre_expr.offset(), inp),
493+
)
484494
},
485-
Err(()) => inp.rewind(pre_op),
486-
},
487-
Err(()) => inp.rewind(pre_op),
495+
);
496+
continue 'start;
488497
}
489-
}
490-
)*
491-
492-
inp.rewind(pre_op);
493-
break;
498+
Err(()) => inp.rewind(pre_op),
499+
},
500+
Err(()) => inp.rewind(pre_op),
501+
}
494502
}
495-
496-
Ok(lhs)
497503
}
498-
}
499504

500-
#[allow(unused_variables, non_snake_case)]
501-
impl<'a, I, O, E, Atom, $($X),*> ParserSealed<'a, I, O, E> for Pratt<Atom, ($($X,)*)>
502-
where
503-
I: Input<'a>,
504-
E: ParserExtra<'a, I>,
505-
Atom: Parser<'a, I, O, E>,
506-
$($X: Operator<'a, I, O, E>),*
507-
{
508-
fn go<M: Mode>(&self, inp: &mut InputRef<'a, '_, I, E>) -> PResult<M, O> {
509-
self.pratt_go::<M, _, _, _>(inp, 0)
510-
}
511-
512-
go_extra!(O);
505+
inp.rewind(pre_op);
506+
break;
513507
}
514-
};
508+
509+
Ok(lhs)
510+
}
515511
}
516512

517-
impl_pratt_for_tuple!(A_ B_ C_ D_ E_ F_ G_ H_ I_ J_ K_ L_ M_ N_ O_ P_ Q_ R_ S_ T_ U_ V_ W_ X_ Y_ Z_);
513+
#[typle(Tuple for 1..=26)]
514+
impl<'a, I, O, E, Atom, T: Tuple> ParserSealed<'a, I, O, E> for Pratt<Atom, T>
515+
where
516+
I: Input<'a>,
517+
E: ParserExtra<'a, I>,
518+
Atom: Parser<'a, I, O, E>,
519+
T<_>: Operator<'a, I, O, E>,
520+
{
521+
fn go<M: Mode>(&self, inp: &mut InputRef<'a, '_, I, E>) -> PResult<M, O> {
522+
self.pratt_go::<M, _, _, _>(inp, 0)
523+
}
524+
525+
go_extra!(O);
526+
}
518527

519528
#[cfg(test)]
520529
mod tests {

0 commit comments

Comments
 (0)