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