Skip to content

Commit 41203ff

Browse files
committed
refactor: replace nom-language to pratt-parser
1 parent 222c1bc commit 41203ff

File tree

15 files changed

+1011
-1375
lines changed

15 files changed

+1011
-1375
lines changed

Cargo.lock

Lines changed: 1 addition & 10 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 & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,8 +555,8 @@ gix = "0.71.0"
555555
indent = "0.1.1"
556556
logos = "0.12.1"
557557
nom = "8.0.0"
558-
nom-language = "0.1.0"
559558
nom-rule = "0.5.1"
559+
pratt = "0.4.0"
560560
rspack-codespan-reporting = "0.11"
561561
rustc-demangle = "0.1"
562562
strsim = "0.10"

src/query/ast/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ indent = { workspace = true }
1919
itertools = { workspace = true }
2020
logos = { workspace = true }
2121
nom = { workspace = true }
22-
nom-language = { workspace = true }
2322
nom-rule = { workspace = true }
2423
ordered-float = { workspace = true }
2524
percent-encoding = { workspace = true }
25+
pratt = { workspace = true }
2626
pretty_assertions = { workspace = true }
2727
recursive = { workspace = true }
2828
rspack-codespan-reporting = { workspace = true }

src/query/ast/benches/bench.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ fn main() {
1818

1919
// bench fastest │ slowest │ median │ mean │ samples │ iters
2020
// ╰─ dummy │ │ │ │ │
21-
// ├─ deep_function_call 242.8 µs │ 525.3 µs │ 258.9 µs │ 262.8 µs │ 100 │ 100
22-
// ├─ deep_query 235.6 µs │ 364.8 µs │ 244.8 µs │ 249.3 µs │ 100 │ 100
23-
// ├─ large_query 362.9 µs │ 451.6 µs │ 376.5 µs │ 379.7 µs │ 100 │ 100
24-
// ├─ large_statement 364.8 µs │ 418.4 µs │ 380.2 µs │ 382.8 µs │ 100 │ 100
25-
// ╰─ wide_expr 96.97 µs │ 270.2 µs │ 102.8 µs │ 105.3 µs │ 100 │ 100
21+
// ├─ deep_function_call 174.4 µs │ 405.3 µs │ 186.3 µs │ 189.7 µs │ 100 │ 100
22+
// ├─ deep_query 226.1 µs │ 396.8 µs │ 239.3 µs │ 242.2 µs │ 100 │ 100
23+
// ├─ large_query 270.5 µs │ 362.8 µs │ 289.7 µs │ 294 µs │ 100 │ 100
24+
// ├─ large_statement 283.4 µs │ 313.5 µs │ 294.6 µs │ 295 µs │ 100 │ 100
25+
// ╰─ wide_expr 38.01 µs │ 189 µs │ 39.04 µs │ 40.81 µs │ 100 │ 100
2626

2727
#[divan::bench_group(max_time = 0.5)]
2828
mod dummy {

src/query/ast/src/ast/expr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ use derive_visitor::DriveMut;
2020
use educe::Educe;
2121
use enum_as_inner::EnumAsInner;
2222
use ethnum::i256;
23+
use pratt::Affix;
24+
use pratt::Associativity;
2325

2426
use super::ColumnRef;
2527
use super::OrderByExpr;
@@ -30,8 +32,6 @@ use crate::ast::write_dot_separated_list;
3032
use crate::ast::Identifier;
3133
use crate::ast::Indirection;
3234
use crate::ast::Query;
33-
use crate::precedence::Affix;
34-
use crate::precedence::Associativity;
3535
use crate::span::merge_span;
3636
use crate::ParseError;
3737
use crate::Result;

src/query/ast/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
pub mod ast;
1919
pub mod parser;
2020
mod parser_error;
21-
pub mod precedence;
2221
pub mod span;
2322
mod visitor;
2423

src/query/ast/src/parser/common.rs

Lines changed: 105 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,23 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use std::cell::RefCell;
16+
use std::rc::Rc;
17+
1518
pub use nom::branch::alt;
1619
pub use nom::branch::permutation;
1720
pub use nom::combinator::consumed;
1821
pub use nom::combinator::map;
1922
pub use nom::combinator::not;
2023
pub use nom::combinator::value;
21-
use nom::error::Error as NomError;
22-
use nom::error::ErrorKind as NomErrorKind;
2324
pub use nom::multi::many1;
2425
use nom::sequence::terminated;
26+
use nom::Offset;
2527
use nom::Parser;
2628
use nom_rule::rule;
29+
use pratt::PrattError;
30+
use pratt::PrattParser;
31+
use pratt::Precedence;
2732

2833
pub fn parser_fn<'a, O, P>(mut parser: P) -> impl FnMut(Input<'a>) -> IResult<'a, O>
2934
where P: nom::Parser<Input<'a>, Output = O, Error = Error<'a>> {
@@ -44,78 +49,11 @@ use crate::parser::query::with_options;
4449
use crate::parser::token::*;
4550
use crate::parser::Error;
4651
use crate::parser::ErrorKind;
47-
pub use crate::precedence::Affix;
48-
pub use crate::precedence::Associativity;
49-
pub use crate::precedence::Precedence;
5052
use crate::Range;
5153
use crate::Span;
5254

5355
pub type IResult<'a, Output> = nom::IResult<Input<'a>, Output, Error<'a>>;
5456

55-
pub type ElementsInput<'a, T> = &'a [WithSpan<'a, T>];
56-
pub type ElementsError<'a, T> = NomError<ElementsInput<'a, T>>;
57-
pub type ElementsResult<'a, T, O> = nom::IResult<ElementsInput<'a, T>, O, ElementsError<'a, T>>;
58-
59-
pub fn match_prefix<'a, T>(
60-
affix_fn: impl Fn(&T) -> Affix + Copy,
61-
precedence: Precedence,
62-
) -> impl FnMut(ElementsInput<'a, T>) -> ElementsResult<'a, T, WithSpan<'a, T>>
63-
where
64-
T: Clone,
65-
{
66-
match_affix(
67-
affix_fn,
68-
move |affix| matches!(affix, Affix::Prefix(p) if p == precedence),
69-
)
70-
}
71-
72-
pub fn match_postfix<'a, T>(
73-
affix_fn: impl Fn(&T) -> Affix + Copy,
74-
precedence: Precedence,
75-
) -> impl FnMut(ElementsInput<'a, T>) -> ElementsResult<'a, T, WithSpan<'a, T>>
76-
where
77-
T: Clone,
78-
{
79-
match_affix(
80-
affix_fn,
81-
move |affix| matches!(affix, Affix::Postfix(p) if p == precedence),
82-
)
83-
}
84-
85-
pub fn match_binary<'a, T>(
86-
affix_fn: impl Fn(&T) -> Affix + Copy,
87-
precedence: Precedence,
88-
associativity: Associativity,
89-
) -> impl FnMut(ElementsInput<'a, T>) -> ElementsResult<'a, T, WithSpan<'a, T>>
90-
where
91-
T: Clone,
92-
{
93-
match_affix(
94-
affix_fn,
95-
move |affix| matches!(affix, Affix::Infix(p, assoc) if p == precedence && assoc == associativity),
96-
)
97-
}
98-
99-
pub fn match_nilfix<'a, T>(
100-
affix_fn: impl Fn(&T) -> Affix + Copy,
101-
) -> impl FnMut(ElementsInput<'a, T>) -> ElementsResult<'a, T, WithSpan<'a, T>>
102-
where T: Clone {
103-
match_affix(affix_fn, |affix| matches!(affix, Affix::Nilfix))
104-
}
105-
106-
fn match_affix<'a, T>(
107-
affix_fn: impl Fn(&T) -> Affix + Copy,
108-
predicate: impl Fn(Affix) -> bool + Copy,
109-
) -> impl FnMut(ElementsInput<'a, T>) -> ElementsResult<'a, T, WithSpan<'a, T>>
110-
where
111-
T: Clone,
112-
{
113-
move |input| match input.split_first() {
114-
Some((elem, rest)) if predicate(affix_fn(&elem.elem)) => Ok((rest, elem.clone())),
115-
_ => Err(nom::Err::Error(NomError::new(input, NomErrorKind::Tag))),
116-
}
117-
}
118-
11957
pub fn match_text(text: &'static str) -> impl FnMut(Input) -> IResult<&Token> {
12058
move |i| match i.tokens.first().filter(|token| token.text() == text) {
12159
Some(token) => Ok((i.slice(1..), token)),
@@ -667,6 +605,104 @@ pub fn transform_span(tokens: &[Token]) -> Span {
667605
})
668606
}
669607

608+
pub(crate) trait IterProvider<'a> {
609+
type Item;
610+
type Iter: Iterator<Item = Self::Item> + ExactSizeIterator;
611+
612+
fn create_iter(self, span: Rc<RefCell<Option<Input<'a>>>>) -> Self::Iter;
613+
}
614+
615+
impl<'a, T> IterProvider<'a> for Vec<WithSpan<'a, T>>
616+
where T: Clone
617+
{
618+
type Item = WithSpan<'a, T>;
619+
type Iter = ErrorSpan<'a, T, std::vec::IntoIter<WithSpan<'a, T>>>;
620+
621+
fn create_iter(self, span: Rc<RefCell<Option<Input<'a>>>>) -> Self::Iter {
622+
ErrorSpan::new(self.into_iter(), span)
623+
}
624+
}
625+
626+
pub(crate) struct ErrorSpan<'a, T, I: Iterator<Item = WithSpan<'a, T>>> {
627+
iter: I,
628+
span: Rc<RefCell<Option<Input<'a>>>>,
629+
}
630+
631+
impl<'a, T, I: Iterator<Item = WithSpan<'a, T>>> ErrorSpan<'a, T, I> {
632+
fn new(iter: I, span: Rc<RefCell<Option<Input<'a>>>>) -> Self {
633+
Self { iter, span }
634+
}
635+
}
636+
637+
impl<'a, T, I: Iterator<Item = WithSpan<'a, T>>> Iterator for ErrorSpan<'a, T, I> {
638+
type Item = WithSpan<'a, T>;
639+
640+
fn next(&mut self) -> Option<Self::Item> {
641+
self.iter
642+
.next()
643+
.inspect(|item| *self.span.borrow_mut() = Some(item.span))
644+
}
645+
}
646+
647+
impl<'a, T, I: Iterator<Item = WithSpan<'a, T>>> ExactSizeIterator for ErrorSpan<'a, T, I> {}
648+
649+
pub fn run_pratt_parser<'a, I, P, E, T>(
650+
mut parser: P,
651+
parsers: T,
652+
rest: Input<'a>,
653+
input: Input<'a>,
654+
) -> IResult<'a, P::Output>
655+
where
656+
E: std::fmt::Debug,
657+
P: PrattParser<I, Input = WithSpan<'a, E>, Error = &'static str>,
658+
I: Iterator<Item = P::Input> + ExactSizeIterator,
659+
T: IterProvider<'a, Item = P::Input, Iter = I>,
660+
{
661+
let span = Rc::new(RefCell::new(None));
662+
let mut iter = parsers.create_iter(span.clone()).peekable();
663+
let expr = parser
664+
.parse_input(&mut iter, Precedence(0))
665+
.map_err(|err| {
666+
// Rollback parsing footprint on unused expr elements.
667+
input.backtrace.clear();
668+
669+
let err_kind = match err {
670+
PrattError::EmptyInput => ErrorKind::Other("expecting an operand"),
671+
PrattError::UnexpectedNilfix(i) => {
672+
*span.borrow_mut() = Some(i.span);
673+
ErrorKind::Other("unable to parse the element")
674+
}
675+
PrattError::UnexpectedPrefix(i) => {
676+
*span.borrow_mut() = Some(i.span);
677+
ErrorKind::Other("unable to parse the prefix operator")
678+
}
679+
PrattError::UnexpectedInfix(i) => {
680+
*span.borrow_mut() = Some(i.span);
681+
ErrorKind::Other("missing lhs or rhs for the binary operator")
682+
}
683+
PrattError::UnexpectedPostfix(i) => {
684+
*span.borrow_mut() = Some(i.span);
685+
ErrorKind::Other("unable to parse the postfix operator")
686+
}
687+
PrattError::UserError(err) => ErrorKind::Other(err),
688+
};
689+
690+
let span = span
691+
.take()
692+
// It's safe to slice one more token because input must contain EOI.
693+
.unwrap_or_else(|| rest.slice(..1));
694+
695+
nom::Err::Error(Error::from_error_kind(span, err_kind))
696+
})?;
697+
if let Some(elem) = iter.peek() {
698+
// Rollback parsing footprint on unused expr elements.
699+
input.backtrace.clear();
700+
Ok((input.slice(input.offset(&elem.span)..), expr))
701+
} else {
702+
Ok((rest, expr))
703+
}
704+
}
705+
670706
pub fn check_template_mode<'a, O, F>(mut parser: F) -> impl FnMut(Input<'a>) -> IResult<'a, O>
671707
where F: nom::Parser<Input<'a>, Output = O, Error = Error<'a>> {
672708
move |input: Input| {

0 commit comments

Comments
 (0)