Skip to main content

squawk_parser/
lib.rs

1// via https://github.com/rust-lang/rust-analyzer/blob/d8887c0758bbd2d5f752d5bd405d4491e90e7ed6/crates/parser/src/lib.rs
2//
3// Permission is hereby granted, free of charge, to any
4// person obtaining a copy of this software and associated
5// documentation files (the "Software"), to deal in the
6// Software without restriction, including without
7// limitation the rights to use, copy, modify, merge,
8// publish, distribute, sublicense, and/or sell copies of
9// the Software, and to permit persons to whom the Software
10// is furnished to do so, subject to the following
11// conditions:
12//
13// The above copyright notice and this permission notice
14// shall be included in all copies or substantial portions
15// of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25// DEALINGS IN THE SOFTWARE.
26
27use drop_bomb::DropBomb;
28use event::Event;
29use grammar::OPERATOR_FIRST;
30use std::cell::Cell;
31use token_set::TokenSet;
32mod event;
33mod generated;
34mod grammar;
35mod input;
36mod lexed_str;
37mod output;
38mod shortcuts;
39mod syntax_kind;
40mod token_set;
41
42pub use crate::{
43    lexed_str::LexedStr,
44    // output::{Output, Step},
45    shortcuts::StrStep,
46    syntax_kind::{
47        SyntaxKind, is_col_name_keyword, is_reserved_keyword, is_type_func_name_keyword,
48    },
49};
50
51use crate::input::Input;
52pub use crate::output::Output;
53
54/// See [`Parser::start`].
55pub(crate) struct Marker {
56    pos: u32,
57    bomb: DropBomb,
58}
59
60impl Marker {
61    fn new(pos: u32) -> Marker {
62        Marker {
63            pos,
64            bomb: DropBomb::new("Marker must be either completed or abandoned"),
65        }
66    }
67
68    /// Finishes the syntax tree node and assigns `kind` to it,
69    /// and mark the create a `CompletedMarker` for possible future
70    /// operation like `.precede()` to deal with `forward_parent`.
71    pub(crate) fn complete(mut self, p: &mut Parser<'_>, kind: SyntaxKind) -> CompletedMarker {
72        self.bomb.defuse();
73        let idx = self.pos as usize;
74        match &mut p.events[idx] {
75            Event::Start { kind: slot, .. } => {
76                *slot = kind;
77            }
78            _ => unreachable!(),
79        }
80        p.push_event(Event::Finish);
81        CompletedMarker::new(self.pos, kind)
82    }
83
84    /// Abandons the syntax tree node. All its children
85    /// are attached to its parent instead.
86    pub(crate) fn abandon(mut self, p: &mut Parser<'_>) {
87        self.bomb.defuse();
88        let idx = self.pos as usize;
89        if idx == p.events.len() - 1 {
90            match p.events.pop() {
91                Some(Event::Start {
92                    kind: SyntaxKind::TOMBSTONE,
93                    forward_parent: None,
94                }) => (),
95                _ => unreachable!(),
96            }
97        }
98    }
99}
100
101pub(crate) struct CompletedMarker {
102    pos: u32,
103    kind: SyntaxKind,
104}
105
106impl CompletedMarker {
107    fn new(pos: u32, kind: SyntaxKind) -> Self {
108        CompletedMarker { pos, kind }
109    }
110
111    /// This method allows to create a new node which starts
112    /// *before* the current one. That is, parser could start
113    /// node `A`, then complete it, and then after parsing the
114    /// whole `A`, decide that it should have started some node
115    /// `B` before starting `A`. `precede` allows to do exactly
116    /// that. See also docs about
117    /// [`Event::Start::forward_parent`](crate::event::Event::Start::forward_parent).
118    ///
119    /// Given completed events `[START, FINISH]` and its corresponding
120    /// `CompletedMarker(pos: 0, _)`.
121    /// Append a new `START` events as `[START, FINISH, NEWSTART]`,
122    /// then mark `NEWSTART` as `START`'s parent with saving its relative
123    /// distance to `NEWSTART` into `forward_parent`(=2 in this case);
124    pub(crate) fn precede(self, p: &mut Parser<'_>) -> Marker {
125        let new_pos = p.start();
126        let idx = self.pos as usize;
127        match &mut p.events[idx] {
128            Event::Start { forward_parent, .. } => {
129                *forward_parent = Some(new_pos.pos - self.pos);
130            }
131            _ => unreachable!(),
132        }
133        new_pos
134    }
135
136    /// Extends this completed marker *to the left* up to `m`.
137    pub(crate) fn extend_to(self, p: &mut Parser<'_>, mut m: Marker) -> CompletedMarker {
138        m.bomb.defuse();
139        let idx = m.pos as usize;
140        match &mut p.events[idx] {
141            Event::Start { forward_parent, .. } => {
142                *forward_parent = Some(self.pos - m.pos);
143            }
144            _ => unreachable!(),
145        }
146        self
147    }
148
149    pub(crate) fn kind(&self) -> SyntaxKind {
150        self.kind
151    }
152}
153
154pub fn parse(input: &Input) -> Output {
155    let mut p = Parser::new(input);
156    // 2. lex tokens to event vec via parser aka actually run the parser code,
157    // it calls the methods on the parser to create a vector of events
158    grammar::entry_point(&mut p);
159    let events = p.finish();
160    // 3. forward parents
161    event::process(events)
162}
163
164pub(crate) struct Parser<'t> {
165    inp: &'t Input,
166    pos: usize,
167    events: Vec<Event>,
168    steps: Cell<u32>,
169}
170
171const PARSER_STEP_LIMIT: usize = 15_000_000;
172
173enum TrivaBetween {
174    NotAllowed,
175    Allowed,
176}
177
178const OPERATOR_SIGN: TokenSet = TokenSet::new(&[SyntaxKind::PLUS, SyntaxKind::MINUS]);
179
180/// In order for an operator to end in `+` or `-`, it must contain one of the
181/// following chars:
182///
183/// ```sql
184/// ~ ! @ # % ^ & | ` ?
185/// ```
186///
187/// see: <https://www.postgresql.org/docs/18/sql-createoperator.html>
188const SPECIAL_OP_CHARS: TokenSet = TokenSet::new(&[
189    SyntaxKind::TILDE,
190    SyntaxKind::BANG,
191    SyntaxKind::AT,
192    SyntaxKind::POUND,
193    SyntaxKind::PERCENT,
194    SyntaxKind::CARET,
195    SyntaxKind::AMP,
196    SyntaxKind::PIPE,
197    SyntaxKind::BACKTICK,
198    SyntaxKind::QUESTION,
199]);
200
201impl<'t> Parser<'t> {
202    fn new(inp: &'t Input) -> Parser<'t> {
203        Parser {
204            inp,
205            pos: 0,
206            events: vec![],
207            steps: Cell::new(0),
208        }
209    }
210
211    /// Consume the next token if `kind` matches.
212    pub(crate) fn eat(&mut self, kind: SyntaxKind) -> bool {
213        if !self.at(kind) {
214            return false;
215        }
216        let n_raw_tokens = match kind {
217            SyntaxKind::COLON_EQ
218            | SyntaxKind::NEQ
219            | SyntaxKind::NEQB
220            | SyntaxKind::LTEQ
221            | SyntaxKind::FAT_ARROW
222            | SyntaxKind::GTEQ => 2,
223            SyntaxKind::SIMILAR_TO => {
224                let m = self.start();
225                self.bump(SyntaxKind::SIMILAR_KW);
226                self.bump(SyntaxKind::TO_KW);
227                m.complete(self, SyntaxKind::SIMILAR_TO);
228                return true;
229            }
230            SyntaxKind::AT_TIME_ZONE => {
231                let m = self.start();
232                self.bump(SyntaxKind::AT_KW);
233                self.bump(SyntaxKind::TIME_KW);
234                self.bump(SyntaxKind::ZONE_KW);
235                m.complete(self, SyntaxKind::AT_TIME_ZONE);
236                return true;
237            }
238            SyntaxKind::AT_LOCAL => {
239                let m = self.start();
240                self.bump(SyntaxKind::AT_KW);
241                self.bump(SyntaxKind::LOCAL_KW);
242                m.complete(self, SyntaxKind::AT_LOCAL);
243                return true;
244            }
245            SyntaxKind::IS_NOT_NORMALIZED => {
246                let m = self.start();
247                self.bump(SyntaxKind::IS_KW);
248                self.bump(SyntaxKind::NOT_KW);
249                if matches!(
250                    self.current(),
251                    SyntaxKind::NFC_KW
252                        | SyntaxKind::NFD_KW
253                        | SyntaxKind::NFKC_KW
254                        | SyntaxKind::NFKD_KW
255                ) {
256                    let fm = self.start();
257                    self.bump_any();
258                    fm.complete(self, SyntaxKind::UNICODE_NORMAL_FORM);
259                }
260                self.bump(SyntaxKind::NORMALIZED_KW);
261                m.complete(self, SyntaxKind::IS_NOT_NORMALIZED);
262                return true;
263            }
264            SyntaxKind::IS_NORMALIZED => {
265                let m = self.start();
266                self.bump(SyntaxKind::IS_KW);
267                if matches!(
268                    self.current(),
269                    SyntaxKind::NFC_KW
270                        | SyntaxKind::NFD_KW
271                        | SyntaxKind::NFKC_KW
272                        | SyntaxKind::NFKD_KW
273                ) {
274                    let fm = self.start();
275                    self.bump_any();
276                    fm.complete(self, SyntaxKind::UNICODE_NORMAL_FORM);
277                }
278                self.bump(SyntaxKind::NORMALIZED_KW);
279                m.complete(self, SyntaxKind::IS_NORMALIZED);
280                return true;
281            }
282            SyntaxKind::COLON_COLON => {
283                let m = self.start();
284                self.bump(SyntaxKind::COLON);
285                self.bump(SyntaxKind::COLON);
286                m.complete(self, SyntaxKind::COLON_COLON);
287                return true;
288            }
289            SyntaxKind::IS_JSON => {
290                let m = self.start();
291                self.bump(SyntaxKind::IS_KW);
292                self.bump(SyntaxKind::JSON_KW);
293                grammar::opt_json_keys_unique_clause(self);
294                m.complete(self, SyntaxKind::IS_JSON);
295                return true;
296            }
297            SyntaxKind::IS_NOT_JSON => {
298                let m = self.start();
299                self.bump(SyntaxKind::IS_KW);
300                self.bump(SyntaxKind::NOT_KW);
301                self.bump(SyntaxKind::JSON_KW);
302                grammar::opt_json_keys_unique_clause(self);
303                m.complete(self, SyntaxKind::IS_NOT_JSON);
304                return true;
305            }
306            SyntaxKind::IS_NOT_JSON_OBJECT => {
307                let m = self.start();
308                self.bump(SyntaxKind::IS_KW);
309                self.bump(SyntaxKind::NOT_KW);
310                self.bump(SyntaxKind::JSON_KW);
311                self.bump(SyntaxKind::OBJECT_KW);
312                grammar::opt_json_keys_unique_clause(self);
313                m.complete(self, SyntaxKind::IS_NOT_JSON_OBJECT);
314                return true;
315            }
316            SyntaxKind::IS_NOT_JSON_ARRAY => {
317                let m = self.start();
318                self.bump(SyntaxKind::IS_KW);
319                self.bump(SyntaxKind::NOT_KW);
320                self.bump(SyntaxKind::JSON_KW);
321                self.bump(SyntaxKind::ARRAY_KW);
322                grammar::opt_json_keys_unique_clause(self);
323                m.complete(self, SyntaxKind::IS_NOT_JSON_ARRAY);
324                return true;
325            }
326            SyntaxKind::IS_NOT_JSON_VALUE => {
327                let m = self.start();
328                self.bump(SyntaxKind::IS_KW);
329                self.bump(SyntaxKind::NOT_KW);
330                self.bump(SyntaxKind::JSON_KW);
331                self.bump(SyntaxKind::VALUE_KW);
332                grammar::opt_json_keys_unique_clause(self);
333                m.complete(self, SyntaxKind::IS_NOT_JSON_VALUE);
334                return true;
335            }
336            SyntaxKind::IS_NOT_JSON_SCALAR => {
337                let m = self.start();
338                self.bump(SyntaxKind::IS_KW);
339                self.bump(SyntaxKind::NOT_KW);
340                self.bump(SyntaxKind::JSON_KW);
341                self.bump(SyntaxKind::SCALAR_KW);
342                grammar::opt_json_keys_unique_clause(self);
343                m.complete(self, SyntaxKind::IS_NOT_JSON_SCALAR);
344                return true;
345            }
346            SyntaxKind::IS_JSON_OBJECT => {
347                let m = self.start();
348                self.bump(SyntaxKind::IS_KW);
349                self.bump(SyntaxKind::JSON_KW);
350                self.bump(SyntaxKind::OBJECT_KW);
351                grammar::opt_json_keys_unique_clause(self);
352                m.complete(self, SyntaxKind::IS_JSON_OBJECT);
353                return true;
354            }
355            SyntaxKind::IS_JSON_ARRAY => {
356                let m = self.start();
357                self.bump(SyntaxKind::IS_KW);
358                self.bump(SyntaxKind::JSON_KW);
359                self.bump(SyntaxKind::ARRAY_KW);
360                grammar::opt_json_keys_unique_clause(self);
361                m.complete(self, SyntaxKind::IS_JSON_ARRAY);
362                return true;
363            }
364            SyntaxKind::IS_JSON_VALUE => {
365                let m = self.start();
366                self.bump(SyntaxKind::IS_KW);
367                self.bump(SyntaxKind::JSON_KW);
368                self.bump(SyntaxKind::VALUE_KW);
369                grammar::opt_json_keys_unique_clause(self);
370                m.complete(self, SyntaxKind::IS_JSON_VALUE);
371                return true;
372            }
373            SyntaxKind::IS_JSON_SCALAR => {
374                let m = self.start();
375                self.bump(SyntaxKind::IS_KW);
376                self.bump(SyntaxKind::JSON_KW);
377                self.bump(SyntaxKind::SCALAR_KW);
378                grammar::opt_json_keys_unique_clause(self);
379                m.complete(self, SyntaxKind::IS_JSON_SCALAR);
380                return true;
381            }
382            SyntaxKind::NOT_SIMILAR_TO => {
383                let m = self.start();
384                self.bump(SyntaxKind::NOT_KW);
385                self.bump(SyntaxKind::SIMILAR_KW);
386                self.bump(SyntaxKind::TO_KW);
387                m.complete(self, SyntaxKind::NOT_SIMILAR_TO);
388                return true;
389            }
390            SyntaxKind::IS_NOT_DISTINCT_FROM => {
391                let m = self.start();
392                self.bump(SyntaxKind::IS_KW);
393                self.bump(SyntaxKind::NOT_KW);
394                self.bump(SyntaxKind::DISTINCT_KW);
395                self.bump(SyntaxKind::FROM_KW);
396                m.complete(self, SyntaxKind::IS_NOT_DISTINCT_FROM);
397                return true;
398            }
399            SyntaxKind::OPERATOR_CALL => {
400                let m = self.start();
401                self.bump(SyntaxKind::OPERATOR_KW);
402                self.bump(SyntaxKind::L_PAREN);
403
404                // e.g. `+`, `pg_catalog.+`, `db.pg_catalog.+`
405                grammar::qual_op(self);
406
407                self.expect(SyntaxKind::R_PAREN);
408                m.complete(self, SyntaxKind::OPERATOR_CALL);
409                return true;
410            }
411            SyntaxKind::IS_DISTINCT_FROM => {
412                let m = self.start();
413                self.bump(SyntaxKind::IS_KW);
414                self.bump(SyntaxKind::DISTINCT_KW);
415                self.bump(SyntaxKind::FROM_KW);
416                m.complete(self, SyntaxKind::IS_DISTINCT_FROM);
417                return true;
418            }
419            SyntaxKind::NOT_LIKE => {
420                let m = self.start();
421                self.bump(SyntaxKind::NOT_KW);
422                self.bump(SyntaxKind::LIKE_KW);
423                m.complete(self, SyntaxKind::NOT_LIKE);
424                return true;
425            }
426            SyntaxKind::NOT_ILIKE => {
427                let m = self.start();
428                self.bump(SyntaxKind::NOT_KW);
429                self.bump(SyntaxKind::ILIKE_KW);
430                m.complete(self, SyntaxKind::NOT_ILIKE);
431                return true;
432            }
433            SyntaxKind::NOT_IN => {
434                let m = self.start();
435                self.bump(SyntaxKind::NOT_KW);
436                self.bump(SyntaxKind::IN_KW);
437                m.complete(self, SyntaxKind::NOT_IN);
438                return true;
439            }
440            SyntaxKind::IS_NOT => {
441                let m = self.start();
442                self.bump(SyntaxKind::IS_KW);
443                self.bump(SyntaxKind::NOT_KW);
444                m.complete(self, SyntaxKind::IS_NOT);
445                return true;
446            }
447            SyntaxKind::CUSTOM_OP => {
448                let m = self.start();
449                for _ in 0..self.op_len() {
450                    self.bump_any();
451                }
452                m.complete(self, SyntaxKind::CUSTOM_OP);
453                return true;
454            }
455            _ => 1,
456        };
457        self.do_bump(kind, n_raw_tokens);
458        true
459    }
460
461    fn at_composite2(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind, triva: TrivaBetween) -> bool {
462        let tokens_match =
463            self.inp.kind(self.pos + n) == k1 && self.inp.kind(self.pos + n + 1) == k2;
464        // We need to do this so we can say that:
465        // 1 > > 2, is not the same as 1 >> 2
466        match triva {
467            TrivaBetween::Allowed => tokens_match,
468            TrivaBetween::NotAllowed => {
469                return tokens_match
470                    && self.inp.is_joint(self.pos + n)
471                    && self.next_not_joined_op_at(n, n + 1);
472            }
473        }
474    }
475
476    fn at_composite3(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind, k3: SyntaxKind) -> bool {
477        self.inp.kind(self.pos + n) == k1
478            && self.inp.kind(self.pos + n + 1) == k2
479            && self.inp.kind(self.pos + n + 2) == k3
480    }
481
482    fn at_composite4(
483        &self,
484        n: usize,
485        k1: SyntaxKind,
486        k2: SyntaxKind,
487        k3: SyntaxKind,
488        k4: SyntaxKind,
489    ) -> bool {
490        self.inp.kind(self.pos + n) == k1
491            && self.inp.kind(self.pos + n + 1) == k2
492            && self.inp.kind(self.pos + n + 2) == k3
493            && self.inp.kind(self.pos + n + 3) == k4
494    }
495
496    fn next_not_joined_op(&self) -> bool {
497        self.next_not_joined_op_at(0, 0)
498    }
499
500    fn next_not_joined_op_at(&self, start: usize, n: usize) -> bool {
501        if !self.nth_at_ts(start, OPERATOR_FIRST) {
502            return true;
503        }
504        // next isn't an operator so we know we're not joined to it
505        if !self.nth_at_ts(n + 1, OPERATOR_FIRST) {
506            return true;
507        }
508        // current kind isn't joined
509        if !self.inp.is_joint(self.pos + n) {
510            return true;
511        }
512        self.op_len_at(start) == n + 1 - start
513    }
514
515    fn op_len(&self) -> usize {
516        self.op_len_at(0)
517    }
518
519    fn op_len_at(&self, start: usize) -> usize {
520        if !self.nth_at_ts(start, OPERATOR_FIRST) {
521            return 0;
522        }
523
524        let mut len = 1;
525        let mut has_special = self.nth_at_ts(start, SPECIAL_OP_CHARS);
526        while self.inp.is_joint(self.pos + start + len - 1)
527            && self.nth_at_ts(start + len, OPERATOR_FIRST)
528        {
529            has_special |= self.nth_at_ts(start + len, SPECIAL_OP_CHARS);
530            len += 1;
531        }
532
533        // PostgreSQL skips trailing signs from ops if they don't contain a
534        // special char.
535        // This means `2*-3` parses as `2 * -3`.
536        if !has_special {
537            while len > 1 && self.nth_at_ts(start + len - 1, OPERATOR_SIGN) {
538                len -= 1;
539            }
540        }
541
542        len
543    }
544
545    /// Checks if the current token is in `kinds`.
546    pub(crate) fn at_ts(&self, kinds: TokenSet) -> bool {
547        kinds.contains(self.current())
548    }
549
550    /// Starts a new node in the syntax tree. All nodes and tokens
551    /// consumed between the `start` and the corresponding `Marker::complete`
552    /// belong to the same node.
553    pub(crate) fn start(&mut self) -> Marker {
554        let pos = self.events.len() as u32;
555        self.push_event(Event::tombstone());
556        Marker::new(pos)
557    }
558
559    /// Consume the next token. Panics if the parser isn't currently at `kind`.
560    pub(crate) fn bump(&mut self, kind: SyntaxKind) {
561        assert!(self.eat(kind));
562    }
563
564    /// Advances the parser by one token
565    pub(crate) fn bump_any(&mut self) {
566        let kind = self.nth(0);
567        if kind == SyntaxKind::EOF {
568            return;
569        }
570        self.do_bump(kind, 1);
571    }
572
573    /// Consume the next token if it is `kind` or emit an error
574    /// otherwise.
575    pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool {
576        if self.eat(kind) {
577            return true;
578        }
579        self.error(format!("expected {kind:?}"));
580        false
581    }
582
583    /// Create an error node and consume the next token.
584    pub(crate) fn err_and_bump(&mut self, message: &str) {
585        self.err_recover(message, TokenSet::EMPTY);
586    }
587
588    /// Create an error node and consume the next token.
589    pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) {
590        // TODO: maybe we actually want this?
591        // if matches!(self.current(), SyntaxKind::L_PAREN | SyntaxKind::R_PAREN) {
592        //     self.error(message);
593        //     return;
594        // }
595
596        if self.at_ts(recovery) {
597            self.error(message);
598            return;
599        }
600
601        let m = self.start();
602        self.error(message);
603        self.bump_any();
604        m.complete(self, SyntaxKind::ERROR);
605    }
606
607    fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) {
608        self.pos += n_raw_tokens as usize;
609        self.steps.set(0);
610        self.push_event(Event::Token { kind, n_raw_tokens });
611    }
612
613    fn push_event(&mut self, event: Event) {
614        self.events.push(event);
615    }
616
617    fn finish(self) -> Vec<Event> {
618        self.events
619    }
620
621    /// Emit error with the `message`
622    /// FIXME: this should be much more fancy and support
623    /// structured errors with spans and notes, like rustc
624    /// does.
625    pub(crate) fn error<T: Into<String>>(&mut self, message: T) {
626        let msg = message.into();
627        self.push_event(Event::Error { msg });
628    }
629
630    /// Checks if the current token is `kind`.
631    #[must_use]
632    pub(crate) fn at(&self, kind: SyntaxKind) -> bool {
633        self.nth_at(0, kind)
634    }
635
636    /// Checks if the nth token is in `kinds`.
637    #[must_use]
638    pub(crate) fn nth_at_ts(&self, n: usize, kinds: TokenSet) -> bool {
639        kinds.contains(self.nth(n))
640    }
641
642    #[must_use]
643    pub(crate) fn nth_at(&self, n: usize, kind: SyntaxKind) -> bool {
644        match kind {
645            // =>
646            SyntaxKind::FAT_ARROW => self.at_composite2(
647                n,
648                SyntaxKind::EQ,
649                SyntaxKind::R_ANGLE,
650                TrivaBetween::NotAllowed,
651            ),
652            // :=
653            SyntaxKind::COLON_EQ => self.at_composite2(
654                n,
655                SyntaxKind::COLON,
656                SyntaxKind::EQ,
657                TrivaBetween::NotAllowed,
658            ),
659            // ::
660            SyntaxKind::COLON_COLON => self.at_composite2(
661                n,
662                SyntaxKind::COLON,
663                SyntaxKind::COLON,
664                TrivaBetween::NotAllowed,
665            ),
666            // !=
667            SyntaxKind::NEQ => self.at_composite2(
668                n,
669                SyntaxKind::BANG,
670                SyntaxKind::EQ,
671                TrivaBetween::NotAllowed,
672            ),
673            // <>
674            SyntaxKind::NEQB => self.at_composite2(
675                n,
676                SyntaxKind::L_ANGLE,
677                SyntaxKind::R_ANGLE,
678                TrivaBetween::NotAllowed,
679            ),
680            // is not
681            SyntaxKind::IS_NOT => self.at_composite2(
682                n,
683                SyntaxKind::IS_KW,
684                SyntaxKind::NOT_KW,
685                TrivaBetween::Allowed,
686            ),
687            // not like
688            SyntaxKind::NOT_LIKE => self.at_composite2(
689                n,
690                SyntaxKind::NOT_KW,
691                SyntaxKind::LIKE_KW,
692                TrivaBetween::Allowed,
693            ),
694            // not ilike
695            SyntaxKind::NOT_ILIKE => self.at_composite2(
696                n,
697                SyntaxKind::NOT_KW,
698                SyntaxKind::ILIKE_KW,
699                TrivaBetween::Allowed,
700            ),
701            // not in
702            SyntaxKind::NOT_IN => self.at_composite2(
703                n,
704                SyntaxKind::NOT_KW,
705                SyntaxKind::IN_KW,
706                TrivaBetween::Allowed,
707            ),
708            // at time zone
709            SyntaxKind::AT_TIME_ZONE => self.at_composite3(
710                n,
711                SyntaxKind::AT_KW,
712                SyntaxKind::TIME_KW,
713                SyntaxKind::ZONE_KW,
714            ),
715            // at local
716            SyntaxKind::AT_LOCAL => self.at_composite2(
717                n,
718                SyntaxKind::AT_KW,
719                SyntaxKind::LOCAL_KW,
720                TrivaBetween::Allowed,
721            ),
722            // is distinct from
723            SyntaxKind::IS_DISTINCT_FROM => self.at_composite3(
724                n,
725                SyntaxKind::IS_KW,
726                SyntaxKind::DISTINCT_KW,
727                SyntaxKind::FROM_KW,
728            ),
729            // is not distinct from
730            SyntaxKind::IS_NOT_DISTINCT_FROM => self.at_composite4(
731                n,
732                SyntaxKind::IS_KW,
733                SyntaxKind::NOT_KW,
734                SyntaxKind::DISTINCT_KW,
735                SyntaxKind::FROM_KW,
736            ),
737            // is normalized
738            SyntaxKind::IS_NORMALIZED => {
739                if self.at(SyntaxKind::IS_KW) {
740                    if matches!(
741                        self.nth(1),
742                        SyntaxKind::NFC_KW
743                            | SyntaxKind::NFD_KW
744                            | SyntaxKind::NFKC_KW
745                            | SyntaxKind::NFKD_KW
746                    ) {
747                        if self.nth_at(2, SyntaxKind::NORMALIZED_KW) {
748                            return true;
749                        }
750                    } else {
751                        if self.nth_at(1, SyntaxKind::NORMALIZED_KW) {
752                            return true;
753                        }
754                    }
755                }
756                return false;
757            }
758            // is not normalized
759            SyntaxKind::IS_NOT_NORMALIZED => {
760                if self.at(SyntaxKind::IS_KW) && self.nth_at(1, SyntaxKind::NOT_KW) {
761                    if matches!(
762                        self.nth(2),
763                        SyntaxKind::NFC_KW
764                            | SyntaxKind::NFD_KW
765                            | SyntaxKind::NFKC_KW
766                            | SyntaxKind::NFKD_KW
767                    ) {
768                        if self.nth_at(3, SyntaxKind::NORMALIZED_KW) {
769                            return true;
770                        }
771                    } else if self.nth_at(2, SyntaxKind::NORMALIZED_KW) {
772                        return true;
773                    }
774                }
775                return false;
776            }
777            SyntaxKind::NOT_SIMILAR_TO => self.at_composite3(
778                n,
779                SyntaxKind::NOT_KW,
780                SyntaxKind::SIMILAR_KW,
781                SyntaxKind::TO_KW,
782            ),
783            // similar to
784            SyntaxKind::SIMILAR_TO => self.at_composite2(
785                n,
786                SyntaxKind::SIMILAR_KW,
787                SyntaxKind::TO_KW,
788                TrivaBetween::Allowed,
789            ),
790            // https://www.postgresql.org/docs/17/sql-expressions.html#SQL-EXPRESSIONS-OPERATOR-CALLS
791            // TODO: is this right?
792            SyntaxKind::OPERATOR_CALL => self.at_composite2(
793                n,
794                SyntaxKind::OPERATOR_KW,
795                SyntaxKind::L_PAREN,
796                TrivaBetween::Allowed,
797            ),
798            // is json
799            SyntaxKind::IS_JSON => self.at_composite2(
800                n,
801                SyntaxKind::IS_KW,
802                SyntaxKind::JSON_KW,
803                TrivaBetween::Allowed,
804            ),
805            // is not json
806            SyntaxKind::IS_NOT_JSON => self.at_composite3(
807                n,
808                SyntaxKind::IS_KW,
809                SyntaxKind::NOT_KW,
810                SyntaxKind::JSON_KW,
811            ),
812            // is not json object
813            SyntaxKind::IS_NOT_JSON_OBJECT => self.at_composite4(
814                n,
815                SyntaxKind::IS_KW,
816                SyntaxKind::NOT_KW,
817                SyntaxKind::JSON_KW,
818                SyntaxKind::OBJECT_KW,
819            ),
820            // is not json array
821            SyntaxKind::IS_NOT_JSON_ARRAY => self.at_composite4(
822                n,
823                SyntaxKind::IS_KW,
824                SyntaxKind::NOT_KW,
825                SyntaxKind::JSON_KW,
826                SyntaxKind::ARRAY_KW,
827            ),
828            // is not json value
829            SyntaxKind::IS_NOT_JSON_VALUE => self.at_composite4(
830                n,
831                SyntaxKind::IS_KW,
832                SyntaxKind::NOT_KW,
833                SyntaxKind::JSON_KW,
834                SyntaxKind::VALUE_KW,
835            ),
836            // is not json scalar
837            SyntaxKind::IS_NOT_JSON_SCALAR => self.at_composite4(
838                n,
839                SyntaxKind::IS_KW,
840                SyntaxKind::NOT_KW,
841                SyntaxKind::JSON_KW,
842                SyntaxKind::SCALAR_KW,
843            ),
844            // is json object
845            SyntaxKind::IS_JSON_OBJECT => self.at_composite3(
846                n,
847                SyntaxKind::IS_KW,
848                SyntaxKind::JSON_KW,
849                SyntaxKind::OBJECT_KW,
850            ),
851            // is json array
852            SyntaxKind::IS_JSON_ARRAY => self.at_composite3(
853                n,
854                SyntaxKind::IS_KW,
855                SyntaxKind::JSON_KW,
856                SyntaxKind::ARRAY_KW,
857            ),
858            // is json value
859            SyntaxKind::IS_JSON_VALUE => self.at_composite3(
860                n,
861                SyntaxKind::IS_KW,
862                SyntaxKind::JSON_KW,
863                SyntaxKind::VALUE_KW,
864            ),
865            // is json scalar
866            SyntaxKind::IS_JSON_SCALAR => self.at_composite3(
867                n,
868                SyntaxKind::IS_KW,
869                SyntaxKind::JSON_KW,
870                SyntaxKind::SCALAR_KW,
871            ),
872            // <=
873            SyntaxKind::LTEQ => self.at_composite2(
874                n,
875                SyntaxKind::L_ANGLE,
876                SyntaxKind::EQ,
877                TrivaBetween::NotAllowed,
878            ),
879            // <=
880            SyntaxKind::GTEQ => self.at_composite2(
881                n,
882                SyntaxKind::R_ANGLE,
883                SyntaxKind::EQ,
884                TrivaBetween::NotAllowed,
885            ),
886            SyntaxKind::CUSTOM_OP => {
887                // TODO: is this right?
888                if self.at_ts(OPERATOR_FIRST) {
889                    return true;
890                }
891                return false;
892            }
893            // TODO: we probably shouldn't be using a _ for this but be explicit for each type?
894            _ => self.inp.kind(self.pos + n) == kind,
895        }
896    }
897
898    /// Returns the kind of the current token.
899    /// If parser has already reached the end of input,
900    /// the special `EOF` kind is returned.
901    #[must_use]
902    pub(crate) fn current(&self) -> SyntaxKind {
903        self.nth(0)
904    }
905
906    /// Lookahead operation: returns the kind of the next nth
907    /// token.
908    #[must_use]
909    fn nth(&self, n: usize) -> SyntaxKind {
910        let steps = self.steps.get();
911        assert!(
912            (steps as usize) < PARSER_STEP_LIMIT,
913            "the parser seems stuck"
914        );
915        self.steps.set(steps + 1);
916
917        self.inp.kind(self.pos + n)
918    }
919}