rudb_parse/matcher.rs
1//! Walking the rule table over a token vector, producing a parse tree.
2//!
3//! This is a PEG matcher and nothing more. It decides where every rule in the grammar started and
4//! stopped, and it does not know what any of them mean. Turning the tree into an AST is the
5//! transformer's job, and keeping the two apart is what lets the grammar be vendored: a grammar
6//! bump changes the table and this file does not move.
7//!
8//! Three things about it are worth knowing before reading it.
9//!
10//! It has no Rust stack recursion. A PEG over a grammar with a thousand rules nests as deep as the
11//! query does, and `a + (b + (c + ...))` nests as deep as the user cares to type. A recursive
12//! matcher blows the thread stack on input that is merely rude rather than adversarial, and it does
13//! it with a segfault rather than an error, so the recursion is an explicit `Vec` of frames with a
14//! cap on it and the cap reports a parser error like any other.
15//!
16//! Failure does not truncate the arena. A choice that tries thirty alternatives builds and
17//! abandons tree nodes for twenty nine of them, and the obvious cleanup is to roll the arena back
18//! to where the alternative started. That is wrong here, because a memoized rule that succeeded
19//! inside a failed alternative keeps its memo entry, and the entry points at nodes in the arena. So
20//! abandoned nodes stay, unreferenced, and the arena is a bump allocator that is freed all at once.
21//! For a query that parses, the waste is small; for one that does not, it does not matter.
22//!
23//! The FIRST filter is a superset test and only its negative answer is used. `Statement` is a
24//! choice of thirty six alternatives and upstream descends into each one far enough to fail. Here
25//! an alternative whose FIRST set does not contain the token in hand is skipped on one AND. A
26//! nullable node is never skipped, because it can match without looking at the token at all, which
27//! is why the guard tests the nullable bit before it tests the set. Both live in the node, so the
28//! guard and the work it guards read the same twenty four bytes.
29//!
30//! `spec/20-the-grammar.md` sections 3, 5 and 6.
31
32use rudb_common::{Error, Result};
33
34use crate::generated::keywords::{KEYWORDS, UNRESERVED};
35use crate::generated::rules::{CHILDREN, NODES, PROGRAM, RULES, SYMBOLS};
36use crate::rules::{Node, Op, Suggestion};
37use crate::token::{Flags, Kind, Token};
38use crate::tokenize::tokenize;
39
40/// No node.
41///
42/// `u32::MAX` rather than an `Option<u32>`, so that a `ParseNode` is twenty bytes and a tree of a
43/// hundred thousand nodes is two megabytes rather than four.
44pub const NONE: u32 = u32::MAX;
45
46/// How deep the frame stack may go before the parse is called a runaway.
47///
48/// Two hundred and sixty two thousand frames is far past anything a person writes and far short of
49/// anything that takes noticeable time or memory to reach. It exists because a PEG has no other
50/// bound: `(((((...)))))` nests one frame per paren and the grammar is happy to keep going. The
51/// number is a power of two for no reason other than that a round one invites being tuned.
52const MAX_DEPTH: usize = 262_144;
53
54/// An empty memo slot, meaning this rule has not been tried at this position.
55const MEMO_EMPTY: u32 = u32::MAX;
56/// A memo slot holding a failure, meaning this rule was tried here and did not match.
57const MEMO_FAILED: u32 = u32::MAX - 1;
58
59/// One node of the parse tree. Twenty bytes.
60///
61/// Children are a linked list rather than a slice, because a node's children are discovered one at
62/// a time and interleaved with the children of every other node being built at the same moment, so
63/// a contiguous list would need either a second pass or a per node vector. The list is built in
64/// order and read in order, which is the only access pattern the transformer has.
65///
66/// Terminals get no node. A keyword, a symbol and a literal are all recoverable from the token
67/// span of the rule that contains them, and giving each one a node would roughly triple the tree
68/// for information that is already in the token vector.
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70pub struct ParseNode {
71 /// Which rule this is, as an index into `RULES`.
72 pub rule: u32,
73 /// The first token it covers.
74 pub start: u32,
75 /// One past the last token it covers.
76 pub end: u32,
77 /// Its first child, or `NONE`.
78 pub first_child: u32,
79 /// The next child of this node's parent, or `NONE`.
80 pub next_sibling: u32,
81}
82
83/// A parsed query.
84#[derive(Debug, Clone)]
85pub struct Tree {
86 nodes: Vec<ParseNode>,
87 root: u32,
88 steps: u64,
89}
90
91impl Tree {
92 /// The root node, which is the rule the parse was started from.
93 pub fn root(&self) -> u32 {
94 self.root
95 }
96
97 /// How many nodes the tree has, abandoned ones included.
98 ///
99 /// Not the size of the tree that is reachable from the root. It is the size of the arena, which
100 /// is what the parse cost, and telling the two apart is what the ratio between them is for.
101 pub fn arena_len(&self) -> usize {
102 self.nodes.len()
103 }
104
105 /// How many nodes of the rule table the matcher went into to produce this.
106 ///
107 /// The one number that says what a parse cost, and the one to watch when the grammar or the
108 /// filter changes. A parse that is linear in the query does a roughly constant number of these
109 /// per token; one that is backtracking badly does thousands.
110 pub fn steps(&self) -> u64 {
111 self.steps
112 }
113
114 /// One node.
115 pub fn node(&self, index: u32) -> ParseNode {
116 self.nodes[index as usize]
117 }
118
119 /// The name of the rule a node is.
120 pub fn name(&self, index: u32) -> &'static str {
121 RULES[self.node(index).rule as usize].name
122 }
123
124 /// The children of a node, in order.
125 pub fn children(&self, index: u32) -> Children<'_> {
126 Children { tree: self, next: self.node(index).first_child }
127 }
128
129 /// The text a node covers, given the query and its tokens.
130 ///
131 /// A node that covers no tokens, which is any rule whose body matched nothing, gets the empty
132 /// string at the point it started rather than a span running backwards.
133 pub fn text<'a>(&self, index: u32, query: &'a str, tokens: &[Token]) -> &'a str {
134 let node = self.node(index);
135 if node.end <= node.start {
136 let at = tokens.get(node.start as usize).map_or(query.len(), |t| t.start as usize);
137 return &query[at..at];
138 }
139 let start = tokens[node.start as usize].start as usize;
140 let end = tokens[node.end as usize - 1].end as usize;
141 &query[start..end]
142 }
143}
144
145/// The children of one node.
146#[derive(Debug)]
147pub struct Children<'a> {
148 tree: &'a Tree,
149 next: u32,
150}
151
152impl Iterator for Children<'_> {
153 type Item = u32;
154
155 fn next(&mut self) -> Option<u32> {
156 if self.next == NONE {
157 return None;
158 }
159 let current = self.next;
160 self.next = self.tree.node(current).next_sibling;
161 Some(current)
162 }
163}
164
165/// Parse a whole script.
166pub fn parse(query: &str) -> Result<Tree> {
167 let tokens = tokenize(query)?;
168 parse_tokens(query, &tokens, PROGRAM, true)
169}
170
171/// Parse from a named rule, for tests and for the differential harness.
172///
173/// `filter` off runs the same walk with the FIRST filter disabled, which is how the harness checks
174/// that the filter is the superset it claims to be: the two modes have to accept the same queries
175/// and build the same trees, and if they ever do not, the filter is wrong and not the grammar.
176pub fn parse_from(query: &str, rule_name: &str, filter: bool) -> Result<Tree> {
177 let index = RULES
178 .binary_search_by(|candidate| candidate.name.cmp(rule_name))
179 .map_err(|_| Error::parser(format!("no rule named {rule_name}")))?;
180 let tokens = tokenize(query)?;
181 parse_tokens(query, &tokens, index as u32, filter)
182}
183
184/// Parse tokens that have already been produced.
185pub fn parse_tokens(query: &str, tokens: &[Token], root: u32, filter: bool) -> Result<Tree> {
186 Matcher::new(query, tokens, filter).run(root)
187}
188
189/// Which frame this is, decided once when it is pushed rather than read back off the node.
190///
191/// The five composite ops are the five kinds of frame. Terminals never get one, because they match
192/// or they do not and there is nothing to come back to.
193#[derive(Debug, Clone, Copy, PartialEq, Eq)]
194enum FrameOp {
195 Rule,
196 Sequence,
197 Choice,
198 Optional,
199 Repeat,
200}
201
202/// One suspended node.
203///
204/// `a` and `b` mean what they mean on the node this came from: the rule index for a rule, the child
205/// node for an optional or a repeat, and the start and length of the child list for a sequence or a
206/// choice. Copying them in is what keeps the loop from touching `NODES` on the way back up.
207#[derive(Debug, Clone, Copy)]
208struct Frame {
209 op: FrameOp,
210 a: u32,
211 b: u32,
212 /// Where the token position was on entry, which is where a failure puts it back.
213 start: u32,
214 /// Which child a sequence or a choice is on, or how many times a repeat has gone round.
215 step: u32,
216 /// Where a repeat's last successful iteration ended.
217 mark: u32,
218 /// The children collected so far, as a list.
219 head: u32,
220 tail: u32,
221}
222
223/// What the loop does next.
224enum Action {
225 /// Go into this node.
226 Enter(u32),
227 /// The thing that just ran matched, and contributed this list of children.
228 Succeed(u32, u32),
229 /// The thing that just ran did not match.
230 Fail,
231 /// The stack is empty. `Some` is the root's node, `None` is a parse that failed.
232 Done(Option<u32>),
233}
234
235struct Matcher<'a> {
236 query: &'a str,
237 tokens: &'a [Token],
238 /// One FIRST key per token, computed once. The filter asks for the key of the token at the
239 /// current position on every node it enters, and the same token is entered on many times.
240 keys: Vec<u64>,
241 arena: Vec<ParseNode>,
242 stack: Vec<Frame>,
243 /// One slot per memoized rule per token position, holding an arena index, `MEMO_FAILED` or
244 /// `MEMO_EMPTY`. A flat array rather than a map: twenty two rules against the token count is a
245 /// few tens of kilobytes for a normal query, and the lookup is an index rather than a hash.
246 memo: Vec<u32>,
247 /// Which memo row a rule uses, or `NONE`.
248 slot_of: &'static [u32],
249 filter: bool,
250 pos: u32,
251 /// How many nodes have been entered. Diagnostic only, and free next to the work it counts.
252 steps: u64,
253 /// The furthest token any terminal was tried at, which is where the error goes. The furthest
254 /// failure is what a person reads as the place the query went wrong, and the place the matcher
255 /// finally gives up is usually the start of the statement.
256 furthest: u32,
257}
258
259/// The memo row each rule uses, built once for the process.
260///
261/// Twenty two rules memoize, out of one thousand and eighty eight, so a row per rule would be a
262/// table forty nine times bigger than it needs to be and the memo is sized per token on top of
263/// that.
264fn slots() -> &'static (Box<[u32]>, usize) {
265 use std::sync::OnceLock;
266 static SLOTS: OnceLock<(Box<[u32]>, usize)> = OnceLock::new();
267 SLOTS.get_or_init(build_slots)
268}
269
270fn build_slots() -> (Box<[u32]>, usize) {
271 let mut slots = vec![NONE; RULES.len()];
272 let mut next = 0;
273 for (index, rule) in RULES.iter().enumerate() {
274 if rule.memoized {
275 slots[index] = next;
276 next += 1;
277 }
278 }
279 (slots.into_boxed_slice(), next as usize)
280}
281
282impl<'a> Matcher<'a> {
283 fn new(query: &'a str, tokens: &'a [Token], filter: bool) -> Self {
284 let keys = tokens.iter().map(|token| crate::rules::token_key(*token)).collect();
285 // One row per memoized rule, one column per token plus one for the position past the end.
286 let memo = vec![MEMO_EMPTY; slots().1 * (tokens.len() + 1)];
287 Self {
288 query,
289 tokens,
290 keys,
291 // The arena grows as the tree does. A guess here saves a handful of reallocations on
292 // anything but the smallest query, and a token is worth about a node in practice.
293 arena: Vec::with_capacity(tokens.len()),
294 stack: Vec::with_capacity(64),
295 memo,
296 slot_of: &slots().0,
297 filter,
298 pos: 0,
299 steps: 0,
300 furthest: 0,
301 }
302 }
303
304 fn run(mut self, root: u32) -> Result<Tree> {
305 self.push(Frame {
306 op: FrameOp::Rule,
307 a: root,
308 b: 0,
309 start: 0,
310 step: 0,
311 mark: 0,
312 head: NONE,
313 tail: NONE,
314 })?;
315
316 let mut action = Action::Enter(RULES[root as usize].root);
317 let node = loop {
318 action = match action {
319 Action::Enter(node) => self.enter(node)?,
320 Action::Succeed(head, tail) => self.settle_ok(head, tail),
321 Action::Fail => self.settle_fail(),
322 Action::Done(result) => match result {
323 Some(node) => break node,
324 None => return Err(self.syntax_error(self.furthest)),
325 },
326 };
327 };
328
329 // Everything has to be consumed. `Program <- TopLevelStatement*` stops at the first token
330 // it cannot start a statement with and calls that a successful parse of the part it read,
331 // so without this `SELECT 1 rubbish here` parses as `SELECT 1` and the rest is silently
332 // dropped. The token vector always ends with an end of input token, so a parse that
333 // reached the end is at `len`, and one that stopped short is pointing at the offender.
334 if (self.pos as usize) < self.tokens.len()
335 && self.tokens[self.pos as usize].kind != Kind::EndOfInput
336 {
337 return Err(self.syntax_error(self.pos.max(self.furthest)));
338 }
339
340 Ok(Tree { nodes: self.arena, root: node, steps: self.steps })
341 }
342
343 /// The token at a position, or the end of input past the end.
344 ///
345 /// Only the FIRST filter asks past the end. The terminals all check the bound themselves,
346 /// because `EndOfInputMatcher` advancing over a synthetic token would let
347 /// `TopLevelStatement <- Statement? (';'+ / EndOfInput)` match forever at the end of a script.
348 fn token(&self, pos: u32) -> Token {
349 self.tokens.get(pos as usize).copied().unwrap_or(Token {
350 kind: Kind::EndOfInput,
351 flags: Flags::default(),
352 keyword: crate::token::NOT_A_KEYWORD,
353 start: self.query.len() as u32,
354 end: self.query.len() as u32,
355 })
356 }
357
358 fn key(&self, pos: u32) -> u64 {
359 self.keys.get(pos as usize).copied().unwrap_or(crate::rules::FIRST_END)
360 }
361
362 /// Suspends a node, which every composite node the matcher enters does.
363 ///
364 /// Inlined into the loop because out of line the caller built the frame on its stack a field
365 /// at a time and this read it back as one 32 byte load, which cannot be forwarded from those
366 /// narrower stores and waits for them to reach the cache. That stall was a fifth of the whole
367 /// parse on the ClickBench queries. Inlined, the frame goes straight to the stack's slot.
368 #[inline(always)]
369 fn push(&mut self, frame: Frame) -> Result<()> {
370 if self.stack.len() >= MAX_DEPTH {
371 return Err(self.too_deep());
372 }
373 self.stack.push(frame);
374 Ok(())
375 }
376
377 /// The error for a query nested deeper than [`MAX_DEPTH`], out of line so [`Self::push`] stays
378 /// small.
379 #[cold]
380 #[inline(never)]
381 fn too_deep(&self) -> Error {
382 let token = self.token(self.pos);
383 Error::parser(format!("memory exhausted at or near \"{}\"", token.text(self.query)))
384 .with_span(token.span())
385 }
386
387 fn alloc(&mut self, node: ParseNode) -> u32 {
388 self.arena.push(node);
389 (self.arena.len() - 1) as u32
390 }
391
392 /// Record that something was tried here, for the error message.
393 fn reached(&mut self, pos: u32) {
394 if pos > self.furthest {
395 self.furthest = pos;
396 }
397 }
398
399 fn syntax_error(&self, pos: u32) -> Error {
400 let token = self.token(pos);
401 if token.kind == Kind::EndOfInput {
402 return Error::parser("syntax error at end of input").with_span(token.span());
403 }
404 Error::parser(format!("syntax error at or near \"{}\"", token.text(self.query)))
405 .with_span(token.span())
406 }
407
408 /// Handle one node.
409 fn enter(&mut self, index: u32) -> Result<Action> {
410 self.steps += 1;
411 let node = NODES[index as usize];
412 // The superset test, and only its no. A nullable node can match without reading a token at
413 // all, so its FIRST set says nothing about whether it applies and asking would reject the
414 // empty match that is the whole point of it.
415 if self.filter && !node.can_start(self.key(self.pos)) {
416 self.reached(self.pos);
417 return Ok(Action::Fail);
418 }
419
420 match node.op {
421 Op::Rule => self.enter_rule(node.a, node.b),
422 Op::Sequence => {
423 self.push(self.frame(FrameOp::Sequence, node.a, node.b))?;
424 Ok(Action::Enter(CHILDREN[node.a as usize]))
425 }
426 Op::Choice => {
427 let step = self.viable(node.a, node.b, 0);
428 if step == node.b {
429 self.reached(self.pos);
430 return Ok(Action::Fail);
431 }
432 let mut frame = self.frame(FrameOp::Choice, node.a, node.b);
433 frame.step = step;
434 self.push(frame)?;
435 Ok(Action::Enter(CHILDREN[(node.a + step) as usize]))
436 }
437 Op::Optional => {
438 self.push(self.frame(FrameOp::Optional, node.a, 0))?;
439 Ok(Action::Enter(node.a))
440 }
441 Op::Repeat => {
442 self.push(self.frame(FrameOp::Repeat, node.a, 0))?;
443 Ok(Action::Enter(node.a))
444 }
445 _ => Ok(self.terminal(node)),
446 }
447 }
448
449 /// The first alternative at or after `step` that could match the token in hand.
450 ///
451 /// A choice used to enter every alternative in turn and let the guard at the top of `enter`
452 /// reject it, and `Statement` has thirty six of them. That costs a step, a stack push and a
453 /// stack pop per rejection, for a test that is a load and an AND. Doing the test here means an
454 /// alternative that cannot match never becomes a step at all, which is why the step counts in
455 /// the bench moved and not only the times.
456 fn viable(&self, a: u32, b: u32, mut step: u32) -> u32 {
457 if !self.filter {
458 return step;
459 }
460 let key = self.key(self.pos);
461 while step < b && !NODES[CHILDREN[(a + step) as usize] as usize].can_start(key) {
462 step += 1;
463 }
464 step
465 }
466
467 fn frame(&self, op: FrameOp, a: u32, b: u32) -> Frame {
468 Frame { op, a, b, start: self.pos, step: 0, mark: self.pos, head: NONE, tail: NONE }
469 }
470
471 /// A reference to a rule, which is the only thing that makes a tree node.
472 fn enter_rule(&mut self, rule: u32, root: u32) -> Result<Action> {
473 let slot = self.slot_of[rule as usize];
474 if slot != NONE {
475 match self.memo[self.memo_index(slot)] {
476 MEMO_EMPTY => {}
477 MEMO_FAILED => return Ok(Action::Fail),
478 stored => {
479 // The stored node is shared by every parent that adopts it, and `next_sibling`
480 // is written by whichever one that is, so the node itself is copied and only
481 // its children are shared. The children are safe to share because nothing ever
482 // rewrites a link inside a finished list, only the link out of its head.
483 let source = self.arena[stored as usize];
484 self.pos = source.end;
485 let copy = self.alloc(ParseNode { next_sibling: NONE, ..source });
486 return Ok(Action::Succeed(copy, copy));
487 }
488 }
489 }
490 self.push(self.frame(FrameOp::Rule, rule, 0))?;
491 Ok(Action::Enter(root))
492 }
493
494 fn memo_index(&self, slot: u32) -> usize {
495 slot as usize * (self.tokens.len() + 1) + self.pos as usize
496 }
497
498 /// Something matched. Give its children to the frame above and decide what that frame does now.
499 fn settle_ok(&mut self, head: u32, tail: u32) -> Action {
500 // Popped rather than looked at, and pushed back by the two cases that carry on. A frame is
501 // thirty two bytes of `Copy`, so this is a couple of moves, and the alternative is holding
502 // a mutable borrow of the stack across every write to the arena.
503 let Some(mut frame) = self.stack.pop() else {
504 return Action::Done(Some(head));
505 };
506
507 if head != NONE {
508 if frame.head == NONE {
509 frame.head = head;
510 } else {
511 self.arena[frame.tail as usize].next_sibling = head;
512 }
513 frame.tail = tail;
514 }
515
516 match frame.op {
517 FrameOp::Rule => {
518 let node = self.alloc(ParseNode {
519 rule: frame.a,
520 start: frame.start,
521 end: self.pos,
522 first_child: frame.head,
523 next_sibling: NONE,
524 });
525 self.remember(frame.a, frame.start, node);
526 Action::Succeed(node, node)
527 }
528 FrameOp::Sequence => {
529 frame.step += 1;
530 if frame.step == frame.b {
531 Action::Succeed(frame.head, frame.tail)
532 } else {
533 let next = CHILDREN[(frame.a + frame.step) as usize];
534 self.stack.push(frame);
535 Action::Enter(next)
536 }
537 }
538 FrameOp::Choice | FrameOp::Optional => Action::Succeed(frame.head, frame.tail),
539 FrameOp::Repeat => {
540 // A repeat wraps something that cannot match nothing, which the generator checks
541 // and `a_repeat_never_wraps_something_that_matches_nothing` asserts, so this always
542 // moves. The guard is here because the alternative to a wrong answer would be a
543 // hang, and a hang in a parser is the failure nobody can diagnose from a bug
544 // report.
545 debug_assert!(self.pos != frame.mark, "a repeat went round without consuming");
546 if self.pos == frame.mark {
547 return Action::Succeed(frame.head, frame.tail);
548 }
549 frame.mark = self.pos;
550 frame.step += 1;
551 let child = frame.a;
552 self.stack.push(frame);
553 Action::Enter(child)
554 }
555 }
556 }
557
558 /// Something did not match. Put the position back and decide what the frame above does now.
559 fn settle_fail(&mut self) -> Action {
560 let Some(mut frame) = self.stack.pop() else {
561 return Action::Done(None);
562 };
563
564 match frame.op {
565 FrameOp::Rule => {
566 self.pos = frame.start;
567 // A failure is worth remembering for the same reason a success is. The rules that
568 // memoize are the ones an expression re-enters at the same position from every
569 // alternative in turn, and most of those re-entries fail.
570 self.remember(frame.a, frame.start, MEMO_FAILED);
571 Action::Fail
572 }
573 FrameOp::Sequence => {
574 self.pos = frame.start;
575 Action::Fail
576 }
577 FrameOp::Choice => {
578 self.pos = frame.start;
579 frame.step = self.viable(frame.a, frame.b, frame.step + 1);
580 if frame.step == frame.b {
581 Action::Fail
582 } else {
583 // The children of a failed alternative are dropped by not being spliced. The
584 // nodes stay in the arena, unreferenced, which is the trade this file's header
585 // is about.
586 frame.head = NONE;
587 frame.tail = NONE;
588 let next = CHILDREN[(frame.a + frame.step) as usize];
589 self.stack.push(frame);
590 Action::Enter(next)
591 }
592 }
593 FrameOp::Optional => {
594 self.pos = frame.start;
595 Action::Succeed(NONE, NONE)
596 }
597 FrameOp::Repeat => {
598 self.pos = frame.mark;
599 if frame.step == 0 { Action::Fail } else { Action::Succeed(frame.head, frame.tail) }
600 }
601 }
602 }
603
604 /// Write a memo entry, if this rule is one of the twenty two that get one.
605 fn remember(&mut self, rule: u32, start: u32, entry: u32) {
606 let slot = self.slot_of[rule as usize];
607 if slot != NONE {
608 let index = slot as usize * (self.tokens.len() + 1) + start as usize;
609 self.memo[index] = entry;
610 }
611 }
612
613 /// A node that matches tokens directly, or does not.
614 fn terminal(&mut self, node: Node) -> Action {
615 self.reached(self.pos);
616 if self.pos as usize >= self.tokens.len() {
617 return Action::Fail;
618 }
619 let token = self.tokens[self.pos as usize];
620 let matched = match node.op {
621 // An index compare, not a text compare. The tokenizer already folded the word and
622 // looked it up, and everything that is not a word carries `NOT_A_KEYWORD`, which is
623 // larger than any index, so the compare rejects them without asking what they are.
624 Op::Keyword => u32::from(token.keyword) == node.a,
625 Op::KeywordClass => {
626 token.kind == Kind::Keyword && u32::from(class_of(token)) & node.a != 0
627 }
628 // A text compare and nothing else, which is upstream's, and it matters. A `.` between
629 // two names arrives as a number token, because the tokenizer cannot tell `a.b` from
630 // `.5` until it has read past the dot, so a check that the token is an operator would
631 // make `DottedIdentifier` unmatchable. Nothing is lost by dropping it: every symbol is
632 // punctuation, no word or literal has punctuation for its whole text, and a quoted or
633 // string token carries its quotes in its text and so cannot collide either.
634 Op::Symbol => token.text(self.query) == SYMBOLS[node.a as usize],
635 // The other half of the same fact. Upstream rejects a lone dot here, and this is why:
636 // without it `a.b` would parse `.` as a numeric literal and `SELECT a.b` would come
637 // out as three expressions rather than one qualified name.
638 Op::Number => token.kind == Kind::Number && token.text(self.query) != ".",
639 Op::Operator => {
640 token.kind == Kind::Operator && is_bare_operator(token.text(self.query))
641 }
642 Op::EndOfInput => token.kind == Kind::EndOfInput,
643 Op::String => return self.string(token),
644 Op::Identifier => self.identifier(token, node),
645 other => unreachable!("{other:?} is a composite and never reaches here"),
646 };
647 if matched {
648 self.pos += 1;
649 Action::Succeed(NONE, NONE)
650 } else {
651 Action::Fail
652 }
653 }
654
655 /// A string literal and the literals that continue it.
656 ///
657 /// `'a'` on one line and `'b'` on the next is one string in SQL, and the rule for when it is
658 /// comes from PostgreSQL: the pieces have to be plain single quoted literals, there has to be a
659 /// line break between them, and a block comment in the gap stops the run. `'a' 'b'` on one line
660 /// is not a continuation and neither is `E'a'` followed by anything, so a prefixed or dollar
661 /// quoted literal matches alone.
662 fn string(&mut self, token: Token) -> Action {
663 if token.kind != Kind::String {
664 return Action::Fail;
665 }
666 self.pos += 1;
667 if !is_plain_string(token.text(self.query)) {
668 return Action::Succeed(NONE, NONE);
669 }
670 while let Some(next) = self.tokens.get(self.pos as usize) {
671 if next.kind != Kind::String
672 || !next.flags.has(Flags::NEWLINE)
673 || next.flags.has(Flags::BLOCK_COMMENT)
674 || !is_plain_string(next.text(self.query))
675 {
676 break;
677 }
678 self.pos += 1;
679 }
680 Action::Succeed(NONE, NONE)
681 }
682
683 /// A name, in whichever of the eleven positions the grammar is at.
684 ///
685 /// Two questions, in upstream's order. Is this the shape of a name at all, and if it is a
686 /// keyword, is this a position that lets that keyword through. The second is where the keyword
687 /// classes earn their existence: `SELECT * FROM binary` is an error and `SELECT binary(x)` is
688 /// not, and the only difference between them is which suggestion the matcher was built with.
689 fn identifier(&mut self, token: Token, node: Node) -> bool {
690 let suggestion = SUGGESTIONS[node.a as usize];
691 let shaped = match token.kind {
692 Kind::QuotedIdentifier => true,
693 Kind::Identifier | Kind::Keyword => true,
694 // `FROM 'file.parquet'` and `COPY t TO 'out.csv'`, and nowhere else. Anywhere else a
695 // single quoted string has to stay a string, or `SELECT 'x' FROM t` becomes a column.
696 Kind::String => {
697 suggestion.supports_string_literal() && is_plain_string(token.text(self.query))
698 }
699 _ => false,
700 };
701 if !shaped {
702 return false;
703 }
704 // The whole of `ReservedIdentifierMatcher`, which is what the rule named `ReservedKeyword`
705 // is overridden with. It skips the class check entirely, so it takes any word at all rather
706 // than the seventy five reserved ones. See `Node::RESERVED`.
707 if node.flags & Node::RESERVED != 0 {
708 return true;
709 }
710 if token.kind != Kind::Keyword {
711 return true;
712 }
713 let class = class_of(token);
714 class & UNRESERVED != 0 || class & suggestion.allowed_class() != 0
715 }
716}
717
718/// Which classes a token's word is in.
719fn class_of(token: Token) -> u8 {
720 KEYWORDS[token.keyword as usize].1
721}
722
723/// Whether a string literal is the plain single quoted kind.
724///
725/// Prefixed forms (`E'a'`, `x'ff'`) and dollar quoting start with something else, and the two
726/// places this is asked both care about the same distinction.
727fn is_plain_string(text: &str) -> bool {
728 text.starts_with('\'')
729}
730
731/// The characters `OperatorMatcher` will accept a token made entirely of.
732const OPERATOR_CHARACTERS: &[u8] = b"+-*/%^<>=~!@&|";
733
734/// The tokens that look like operators and are not, because the grammar spells them itself.
735///
736/// Upstream lists these out in `OperatorMatcher` and the reason is the same for all of them: a rule
737/// somewhere writes the token as a literal and means something specific by it, so letting the
738/// generic operator node take it first would make that rule unreachable. `->` is JSON extraction,
739/// the comparisons are comparisons, and the tilde family is the pattern matching operators.
740const NOT_OPERATORS: [&str; 15] = [
741 "->", "->>", "<=", ">=", "!=", "==", "<>", "~~", "~~*", "~~~", "~*", "!~~", "!~~*", "!~", "!~*",
742];
743
744/// Whether this text is an operator in the sense the `Operator` node means.
745///
746/// A single character is never one, which is not an oversight: every single character operator in
747/// the language is spelled by a rule, so the generic node is only ever for the multi character ones
748/// a user might define.
749fn is_bare_operator(text: &str) -> bool {
750 if text.len() < 2 || NOT_OPERATORS.contains(&text) {
751 return false;
752 }
753 text.bytes().all(|byte| OPERATOR_CHARACTERS.contains(&byte))
754}
755
756/// The eleven suggestions by discriminant, so that a node's `a` can be turned back into one.
757///
758/// A table rather than a `match`, because the discriminants are dense and written by the generator
759/// and the table is checked against them by `the_suggestions_are_dense_and_in_order`.
760pub(crate) const SUGGESTIONS: [Suggestion; 11] = [
761 Suggestion::Variable,
762 Suggestion::CatalogName,
763 Suggestion::SchemaName,
764 Suggestion::TableName,
765 Suggestion::ColumnName,
766 Suggestion::ScalarFunctionName,
767 Suggestion::TableFunctionName,
768 Suggestion::TypeName,
769 Suggestion::PragmaName,
770 Suggestion::SettingName,
771 Suggestion::FileName,
772];
773
774#[cfg(test)]
775mod tests {
776 use super::{
777 NONE, SUGGESTIONS, Tree, is_bare_operator, is_plain_string, parse, parse_from, parse_tokens,
778 };
779 use crate::corpus::CORPUS;
780 use crate::generated::rules::PROGRAM;
781 use crate::tokenize::tokenize;
782
783 /// The rules a tree has, outermost first, for asserting on shape without writing out the whole
784 /// thing.
785 fn names(tree: &Tree, node: u32, into: &mut Vec<&'static str>) {
786 into.push(tree.name(node));
787 for child in tree.children(node) {
788 names(tree, child, into);
789 }
790 }
791
792 /// The first node with this rule name, depth first.
793 fn find(tree: &Tree, node: u32, name: &str) -> Option<u32> {
794 if tree.name(node) == name {
795 return Some(node);
796 }
797 tree.children(node).find_map(|child| find(tree, child, name))
798 }
799
800 fn shape(query: &str) -> Vec<&'static str> {
801 let tree = parse(query).expect("parses");
802 let mut out = Vec::new();
803 names(&tree, tree.root(), &mut out);
804 out
805 }
806
807 #[test]
808 fn the_suggestions_are_dense_and_in_order() {
809 for (index, suggestion) in SUGGESTIONS.iter().enumerate() {
810 assert_eq!(*suggestion as usize, index);
811 }
812 }
813
814 #[test]
815 fn an_empty_script_parses() {
816 let tree = parse("").expect("an empty script is a script with no statements");
817 assert_eq!(tree.name(tree.root()), "Program");
818 }
819
820 #[test]
821 fn a_select_parses_and_the_root_is_the_program() {
822 let tree = parse("SELECT 1").expect("parses");
823 assert_eq!(tree.name(tree.root()), "Program");
824 let statements: Vec<_> = tree.children(tree.root()).collect();
825 assert_eq!(statements.len(), 1);
826 assert_eq!(tree.name(statements[0]), "TopLevelStatement");
827 }
828
829 #[test]
830 fn the_shape_has_the_rules_the_grammar_names() {
831 let shape = shape("SELECT 1");
832 assert!(shape.contains(&"SelectStatement"), "{shape:?}");
833 }
834
835 #[test]
836 fn a_statement_covers_the_text_it_came_from() {
837 let query = " SELECT 1 ";
838 let tokens = tokenize(query).expect("tokenizes");
839 let tree = parse_tokens(query, &tokens, PROGRAM, true).expect("parses");
840 // The statement and not the `TopLevelStatement` that wraps it. `TopLevelStatement` covers
841 // the terminator too, and at the end of a script the terminator is the end of input token,
842 // whose span is the end of the query, so its text runs out to the trailing whitespace.
843 let statement = find(&tree, tree.root(), "SelectStatement").expect("there is one");
844 assert_eq!(tree.text(statement, query, &tokens), "SELECT 1");
845 }
846
847 #[test]
848 fn several_statements_parse_as_several() {
849 let tree = parse("SELECT 1; SELECT 2; SELECT 3").expect("parses");
850 let shape = shape("SELECT 1; SELECT 2; SELECT 3");
851 assert_eq!(shape.iter().filter(|name| **name == "SelectStatement").count(), 3);
852 assert!(tree.children(tree.root()).count() >= 3);
853 }
854
855 #[test]
856 fn a_trailing_semicolon_makes_an_empty_statement() {
857 // Not a bug and not worth working around here. `TopLevelStatement <- Statement? (';'+ /
858 // EndOfInput)` has both halves optional in effect, so at the end of `SELECT 1;` the
859 // repetition goes round once more, matches no statement and the end of input, and stops.
860 // The extra node has an `EndOfInput` child and no `Statement` one, which is how the
861 // transformer tells it apart, and upstream drops it in the same place for the same reason.
862 let one = parse("SELECT 1").expect("parses");
863 let two = parse("SELECT 1;").expect("parses");
864 assert_eq!(one.children(one.root()).count(), 1);
865 assert_eq!(two.children(two.root()).count(), 2);
866 let last = two.children(two.root()).last().expect("there is a last one");
867 let inside: Vec<_> = two.children(last).map(|child| two.name(child)).collect();
868 assert_eq!(inside, ["EndOfInput"], "the extra one holds no statement");
869 }
870
871 #[test]
872 fn rubbish_after_a_statement_is_an_error() {
873 // Without the consumed-everything check this parses as `SELECT 1` and drops the rest,
874 // because `Program <- TopLevelStatement*` is allowed to stop early.
875 let error = parse("SELECT 1 rubbish here").expect_err("not a query");
876 assert!(error.message().starts_with("syntax error at or near"), "{}", error.message());
877 }
878
879 #[test]
880 fn a_word_that_is_not_a_statement_is_an_error() {
881 let error = parse("SELCT 1").expect_err("not a query");
882 assert!(error.message().contains("syntax error"), "{}", error.message());
883 }
884
885 #[test]
886 fn the_error_points_at_the_furthest_token_reached() {
887 // The parse gives up at the start of the statement, having tried every alternative. The
888 // place worth reporting is the furthest one any of them got to, which is the `from`.
889 let error = parse("SELECT 1 FROM").expect_err("not a query");
890 assert!(error.span().is_some(), "an error about a place should say which place");
891 }
892
893 #[test]
894 fn a_soft_keyword_is_a_column_name_and_also_a_keyword() {
895 // `ascending` is spelled by a rule and is in no class, so it is both of these and the
896 // FIRST set for the literal has to be the identifier bit rather than a keyword bucket.
897 parse("SELECT ascending FROM t").expect("a soft word is a name");
898 parse("SELECT x FROM t ORDER BY x ASCENDING").expect("a soft word is also a literal");
899 }
900
901 #[test]
902 fn a_reserved_word_is_not_a_column_name() {
903 parse("SELECT x FROM t").expect("an ordinary name is fine");
904 parse("SELECT * FROM t WHERE all").expect_err("`all` is reserved");
905 }
906
907 #[test]
908 fn an_unreserved_word_is_a_column_name_everywhere() {
909 parse("SELECT abort FROM t").expect("`abort` is unreserved");
910 }
911
912 #[test]
913 fn a_function_name_keyword_is_a_function_and_not_a_column() {
914 // The whole point of the classes. `binary` is in the function name class and nowhere else,
915 // so the two positions disagree about it.
916 parse("SELECT binary(x) FROM t").expect("a function name position takes it");
917 parse("SELECT binary FROM t").expect_err("a column name position does not");
918 }
919
920 #[test]
921 fn a_quoted_name_is_a_name_whatever_it_spells() {
922 parse(r#"SELECT "all" FROM t"#).expect("quoting takes a word out of every class");
923 }
924
925 #[test]
926 fn adjacent_strings_across_a_line_are_one_literal() {
927 parse("SELECT 'a'\n'b'").expect("a continuation");
928 parse("SELECT 'a' 'b'").expect_err("on one line they are two strings and a syntax error");
929 }
930
931 #[test]
932 fn deep_nesting_is_an_error_and_not_a_crash() {
933 // A thread stack would be gone long before this. The number is well past the cap.
934 let query = format!("SELECT {}1{}", "(".repeat(200_000), ")".repeat(200_000));
935 let error = parse(&query).expect_err("too deep to parse");
936 assert!(error.message().contains("memory exhausted"), "{}", error.message());
937 }
938
939 #[test]
940 fn nesting_that_is_merely_rude_still_parses() {
941 let query = format!("SELECT {}1{}", "(".repeat(500), ")".repeat(500));
942 parse(&query).expect("five hundred deep is fine");
943 }
944
945 #[test]
946 fn a_named_rule_can_be_parsed_on_its_own() {
947 let tree = parse_from("SELECT 1", "SelectStatement", true).expect("parses");
948 assert_eq!(tree.name(tree.root()), "SelectStatement");
949 }
950
951 #[test]
952 fn asking_for_a_rule_that_does_not_exist_says_so() {
953 let error = parse_from("SELECT 1", "NoSuchRule", true).expect_err("no such rule");
954 assert!(error.message().contains("NoSuchRule"));
955 }
956
957 #[test]
958 fn the_children_of_a_leaf_rule_are_none() {
959 let tree = parse("SELECT 1").expect("parses");
960 let mut leaves = 0;
961 for index in 0..tree.arena_len() as u32 {
962 if tree.node(index).first_child == NONE {
963 leaves += 1;
964 }
965 }
966 assert!(leaves > 0, "every tree has leaves");
967 }
968
969 #[test]
970 fn what_counts_as_a_bare_operator() {
971 // The ones a user can define, which is the only thing the generic node is for.
972 for text in ["&&", "@>", "<@", "||", "^@", "<<", ">>", "//", "**", "<<=", ">>="] {
973 assert!(is_bare_operator(text), "{text} should be an operator");
974 }
975 // Spelled by a rule, so the generic node has to leave them alone.
976 for text in ["->", "->>", "<=", ">=", "!=", "==", "<>", "~~", "!~~*"] {
977 assert!(!is_bare_operator(text), "{text} is spelled by a rule");
978 }
979 // A colon is not an operator character, so neither of these is one.
980 for text in ["::", ":=", "+", "(", ","] {
981 assert!(!is_bare_operator(text), "{text} is not an operator");
982 }
983 }
984
985 #[test]
986 fn the_corpus_parses() {
987 for query in CORPUS {
988 parse(query).unwrap_or_else(|error| panic!("{query}\n {}", error.message()));
989 }
990 }
991
992 #[test]
993 fn the_corpus_parses_the_same_with_the_filter_off() {
994 for query in CORPUS {
995 let filtered = parse_from(query, "Program", true).expect("parses");
996 let plain = parse_from(query, "Program", false).expect("parses unfiltered");
997 let mut a = Vec::new();
998 let mut b = Vec::new();
999 names(&filtered, filtered.root(), &mut a);
1000 names(&plain, plain.root(), &mut b);
1001 assert_eq!(a, b, "{query} parsed differently with the filter on");
1002 }
1003 }
1004
1005 #[test]
1006 fn the_work_stays_proportional_to_the_query() {
1007 // A guard against the kind of regression that does not fail a test: a grammar or filter
1008 // change that leaves every query still parsing and quietly triples what it costs. The
1009 // numbers are what the table does today with a little room, not a target. The expression
1010 // grammar is about twenty rules deep from `Expression` down to `BaseExpression` and every
1011 // operand walks all of them, which is where most of these go.
1012 for query in CORPUS {
1013 let tree = parse(query).expect("parses");
1014 let tokens = tokenize(query).expect("tokenizes").len() as u64;
1015 let per_token = tree.steps() / tokens;
1016 assert!(per_token < 200, "{query} took {per_token} steps a token");
1017 }
1018 }
1019
1020 #[test]
1021 fn what_counts_as_a_plain_string() {
1022 assert!(is_plain_string("'a'"));
1023 assert!(!is_plain_string("E'a'"));
1024 assert!(!is_plain_string("$$a$$"));
1025 assert!(!is_plain_string(r#""a""#));
1026 }
1027}