LCOV - code coverage report
Current view: top level - dashql-parser/src/parser - context.rs Coverage Total Hit
Test: DashQL 6e74948 Lines: 96.3 % 378 364
Test Date: 2026-11-06 17:46:50

            Line data    Source code
       1              : //! The parse context.
       2              : //!
       3              : //! The grammar actions build the AST through the parse context. Nodes are appended to a flat buffer
       4              : //! in post-order: `object` and `array` emit the children of a node and return the node itself,
       5              : //! which the enclosing rule emits later. Every method takes `&self` (the state sits in a
       6              : //! [`StateCell`]) so that the translated actions can nest calls like
       7              : //! `ctx.object(.., &[attr(.., ctx.array(..))])`, which emit nodes in argument evaluation order.
       8              : 
       9              : // Release builds hand out a plain `&mut State` from `StateCell::borrow_mut`, so the `mut` that the
      10              : // debug `RefMut` guard needs on `let mut state = ..` is unused there.
      11              : #![cfg_attr(not(debug_assertions), allow(unused_mut))]
      12              : 
      13              : use super::value::{ExprVariant, NodeList};
      14              : use crate::names::NameRegistry;
      15              : use crate::scanner::Symbol;
      16              : use crate::span::TextSpan;
      17              : use dashql_buffers::parser::{AttributeKey, ExpressionOperator, Node, NodeType, NumericType, SampleCountUnit, StatementType, SymbolSpan};
      18              : 
      19              : /// The cell of the parse context state.
      20              : ///
      21              : /// Methods of the parse context borrow the state only within their own body and never call each
      22              : /// other while holding a borrow. Debug builds check this with a `RefCell`, release builds skip the
      23              : /// bookkeeping, which is a hot path of parsing (about a thousand borrows per statement).
      24              : #[cfg(debug_assertions)]
      25              : pub(crate) struct StateCell<T>(std::cell::RefCell<T>);
      26              : 
      27              : #[cfg(debug_assertions)]
      28              : impl<T> StateCell<T> {
      29         7386 :     fn new(value: T) -> Self {
      30         7386 :         Self(std::cell::RefCell::new(value))
      31         7386 :     }
      32       695245 :     pub(crate) fn borrow(&self) -> std::cell::Ref<'_, T> {
      33       695245 :         self.0.borrow()
      34       695245 :     }
      35      2690023 :     pub(crate) fn borrow_mut(&self) -> std::cell::RefMut<'_, T> {
      36      2690023 :         self.0.borrow_mut()
      37      2690023 :     }
      38         7386 :     fn into_inner(self) -> T {
      39         7386 :         self.0.into_inner()
      40         7386 :     }
      41              : }
      42              : 
      43              : /// The cell of the parse context state, unchecked in release builds
      44              : #[cfg(not(debug_assertions))]
      45              : pub(crate) struct StateCell<T>(std::cell::UnsafeCell<T>);
      46              : 
      47              : #[cfg(not(debug_assertions))]
      48              : impl<T> StateCell<T> {
      49              :     fn new(value: T) -> Self {
      50              :         Self(std::cell::UnsafeCell::new(value))
      51              :     }
      52              :     pub(crate) fn borrow(&self) -> &T {
      53              :         // SAFETY: borrows never overlap with a mutable borrow, checked by debug builds.
      54              :         unsafe { &*self.0.get() }
      55              :     }
      56              :     #[allow(clippy::mut_from_ref)]
      57              :     pub(crate) fn borrow_mut(&self) -> &mut T {
      58              :         // SAFETY: borrows never overlap, checked by debug builds.
      59              :         unsafe { &mut *self.0.get() }
      60              :     }
      61              :     fn into_inner(self) -> T {
      62              :         self.0.into_inner()
      63              :     }
      64              : }
      65              : 
      66              : /// The parent of nodes that have none (yet)
      67              : pub const NO_PARENT: u32 = u32::MAX;
      68              : 
      69              : /// A parsed statement
      70              : #[derive(Clone, Copy, Debug, PartialEq, Eq)]
      71              : pub struct Statement {
      72              :     /// The statement type, derived from the type of the root node
      73              :     pub statement_type: StatementType,
      74              :     /// The root node
      75              :     pub root: u32,
      76              :     /// The first node of the statement
      77              :     pub nodes_begin: u32,
      78              :     /// The number of nodes of the statement
      79              :     pub node_count: u32,
      80              : }
      81              : 
      82              : impl Default for Statement {
      83        15738 :     fn default() -> Self {
      84        15738 :         Self {
      85        15738 :             statement_type: StatementType::NONE,
      86        15738 :             root: u32::MAX,
      87        15738 :             nodes_begin: 0,
      88        15738 :             node_count: 0,
      89        15738 :         }
      90        15738 :     }
      91              : }
      92              : 
      93              : /// A parser error, located by symbol indexes
      94              : #[derive(Clone, Debug, PartialEq)]
      95              : pub struct ParseError {
      96              :     /// The symbol indexes of the error
      97              :     pub location: SymbolSpan,
      98              :     /// The error message
      99              :     pub message: String,
     100              :     /// A hint how to fix the error, empty if there is none
     101              :     pub hint: String,
     102              : }
     103              : 
     104              : /// An n-ary expression whose materialization is deferred to flatten conjunctions and disjunctions
     105              : #[derive(Clone, Copy, Debug)]
     106              : struct NaryExpression {
     107              :     /// The symbol indexes of the expression
     108              :     location: SymbolSpan,
     109              :     /// The operator, AND or OR
     110              :     op: ExpressionOperator,
     111              :     /// The operator node
     112              :     op_node: Node,
     113              :     /// The flattened arguments
     114              :     args: NodeList,
     115              : }
     116              : 
     117              : /// The mutable state of the parse context
     118              : #[derive(Default)]
     119              : pub(crate) struct State {
     120              :     /// The AST nodes in post-order
     121              :     pub(crate) nodes: Vec<Node>,
     122              :     /// The finished statements
     123              :     pub(crate) statements: Vec<Statement>,
     124              :     /// The parser errors
     125              :     pub(crate) errors: Vec<ParseError>,
     126              :     /// The names of the scanned script, extended by names the parser registers
     127              :     pub(crate) names: NameRegistry,
     128              :     /// The hint of the next error, produced while building a syntax error message
     129              :     pub(crate) pending_hint: String,
     130              :     /// Set by an action to drop the lookahead (`yyclearin`)
     131              :     pub(crate) clear_lookahead: bool,
     132              :     /// The statement being parsed, its nodes start at `nodes_begin`
     133              :     current_statement: Statement,
     134              :     /// The node lists indexed by list id
     135              :     lists: Vec<Vec<Node>>,
     136              :     /// Consumed lists whose allocation can be reused
     137              :     free_lists: Vec<u32>,
     138              :     /// The deferred n-ary expressions indexed by `ExprVariant::Nary` id
     139              :     nary_expressions: Vec<NaryExpression>,
     140              : }
     141              : 
     142              : impl State {
     143              :     /// A copy of the nodes of a list
     144           81 :     pub(crate) fn lists_snapshot(&self, list: NodeList) -> Vec<Node> {
     145           81 :         self.lists[list.0 as usize].clone()
     146           81 :     }
     147              : }
     148              : 
     149              : /// The parse context
     150              : pub struct ParseContext<'a> {
     151              :     /// The script text
     152              :     text: &'a str,
     153              :     /// The scanned symbols, located by byte spans
     154              :     symbols: &'a [Symbol],
     155              :     /// The mutable parser state
     156              :     pub(crate) state: StateCell<State>,
     157              : }
     158              : 
     159              : /// Arguments that are node lists: list ids and node slices
     160              : pub trait IntoNodeList {
     161              :     fn into_node_list(self, ctx: &ParseContext) -> NodeList;
     162              : }
     163              : 
     164              : impl IntoNodeList for NodeList {
     165       216695 :     fn into_node_list(self, _ctx: &ParseContext) -> NodeList {
     166       216695 :         self
     167       216695 :     }
     168              : }
     169              : 
     170              : impl<const N: usize> IntoNodeList for &[Node; N] {
     171       174860 :     fn into_node_list(self, ctx: &ParseContext) -> NodeList {
     172       174860 :         ctx.list(&self[..])
     173       174860 :     }
     174              : }
     175              : 
     176              : impl IntoNodeList for &[Node] {
     177            0 :     fn into_node_list(self, ctx: &ParseContext) -> NodeList {
     178            0 :         ctx.list(self)
     179            0 :     }
     180              : }
     181              : 
     182              : /// A node with replaced fields
     183       966646 : fn with_parent(n: &Node, parent: u32) -> Node {
     184       966646 :     Node::new(n.symbol_span(), n.node_type(), n.attribute_key(), parent, n.children_begin_or_value(), n.children_count())
     185       966646 : }
     186              : 
     187              : /// The null node, skipped by `object` and `array`
     188       143708 : pub fn null() -> Node {
     189       143708 :     Node::new(&SymbolSpan::default(), NodeType::NONE, AttributeKey::NONE, NO_PARENT, 0, 0)
     190       143708 : }
     191              : 
     192              : impl<'a> ParseContext<'a> {
     193         7386 :     pub fn new(text: &'a str, symbols: &'a [Symbol], names: NameRegistry) -> Self {
     194         7386 :         Self {
     195         7386 :             text,
     196         7386 :             symbols,
     197         7386 :             state: StateCell::new(State {
     198         7386 :                 names,
     199         7386 :                 nodes: Vec::with_capacity(symbols.len() * 3),
     200         7386 :                 ..Default::default()
     201         7386 :             }),
     202         7386 :         }
     203         7386 :     }
     204              : 
     205              :     /// The scanned symbols
     206       340741 :     pub fn symbols(&self) -> &'a [Symbol] {
     207       340741 :         self.symbols
     208       340741 :     }
     209              : 
     210              :     /// Finish parsing and return the state
     211         7386 :     pub(crate) fn into_state(self) -> State {
     212         7386 :         self.state.into_inner()
     213         7386 :     }
     214              : 
     215              :     /// Resolve a span of symbol indexes to a span of bytes
     216          596 :     pub fn resolve_text_span(&self, span: SymbolSpan) -> TextSpan {
     217          596 :         resolve_text_span(self.text, self.symbols, span)
     218          596 :     }
     219              : 
     220              :     /// The text of a span of symbols
     221          130 :     fn text_at(&self, span: SymbolSpan) -> &'a str {
     222          130 :         let ts = self.resolve_text_span(span);
     223          130 :         &self.text[ts.offset as usize..ts.end() as usize]
     224          130 :     }
     225              : 
     226              :     // -----------------------------------------------------------------------------------------
     227              :     // Lists
     228              :     // -----------------------------------------------------------------------------------------
     229              : 
     230              :     /// Create a list
     231       372604 :     pub fn list(&self, nodes: &[Node]) -> NodeList {
     232       372604 :         let mut state = self.state.borrow_mut();
     233       372604 :         if let Some(id) = state.free_lists.pop() {
     234       341637 :             state.lists[id as usize].extend_from_slice(nodes);
     235       341637 :             return NodeList(id);
     236        30967 :         }
     237        30967 :         state.lists.push(nodes.to_vec());
     238        30967 :         NodeList(state.lists.len() as u32 - 1)
     239       372604 :     }
     240              : 
     241              :     /// Release a consumed list, keeping its allocation for reuse
     242       370746 :     fn recycle(&self, list: NodeList, mut nodes: Vec<Node>) {
     243       370746 :         nodes.clear();
     244       370746 :         let mut state = self.state.borrow_mut();
     245       370746 :         state.lists[list.0 as usize] = nodes;
     246       370746 :         state.free_lists.push(list.0);
     247       370746 :     }
     248              : 
     249              :     /// Append a node
     250       101112 :     pub fn push_back(&self, list: NodeList, node: Node) {
     251       101112 :         self.state.borrow_mut().lists[list.0 as usize].push(node);
     252       101112 :     }
     253              : 
     254              :     /// Prepend a node
     255         9568 :     pub fn push_front(&self, list: NodeList, node: Node) {
     256         9568 :         self.state.borrow_mut().lists[list.0 as usize].insert(0, node);
     257         9568 :     }
     258              : 
     259              :     /// Is a list empty?
     260         1671 :     pub fn list_is_empty(&self, list: NodeList) -> bool {
     261         1671 :         self.state.borrow().lists[list.0 as usize].is_empty()
     262         1671 :     }
     263              : 
     264              :     /// Move the nodes of a list
     265       370746 :     fn take_list(&self, list: NodeList) -> Vec<Node> {
     266       370746 :         std::mem::take(&mut self.state.borrow_mut().lists[list.0 as usize])
     267       370746 :     }
     268              : 
     269              :     /// Append the nodes of `other` to `list`
     270        30622 :     fn append(&self, list: NodeList, other: impl IntoNodeList) {
     271        30622 :         let other = other.into_node_list(self);
     272        30622 :         if other == list {
     273            0 :             return;
     274        30622 :         }
     275        30622 :         let nodes = self.take_list(other);
     276        30622 :         self.state.borrow_mut().lists[list.0 as usize].extend_from_slice(&nodes);
     277        30622 :         self.recycle(other, nodes);
     278        30622 :     }
     279              : 
     280              :     /// `Concat(l, r)`
     281        19438 :     pub fn concat2(&self, l: impl IntoNodeList, r: impl IntoNodeList) -> NodeList {
     282        19438 :         let l = l.into_node_list(self);
     283        19438 :         self.append(l, r);
     284        19438 :         l
     285        19438 :     }
     286              : 
     287              :     /// `Concat(v0, v1, v2)`
     288          780 :     pub fn concat3(&self, v0: impl IntoNodeList, v1: impl IntoNodeList, v2: impl IntoNodeList) -> NodeList {
     289          780 :         let v0 = v0.into_node_list(self);
     290          780 :         self.append(v0, v1);
     291          780 :         self.append(v0, v2);
     292          780 :         v0
     293          780 :     }
     294              : 
     295              :     /// `Concat(v0, v1, v2, v3)`
     296          591 :     pub fn concat4(
     297          591 :         &self,
     298          591 :         v0: impl IntoNodeList,
     299          591 :         v1: impl IntoNodeList,
     300          591 :         v2: impl IntoNodeList,
     301          591 :         v3: impl IntoNodeList,
     302          591 :     ) -> NodeList {
     303          591 :         let v0 = v0.into_node_list(self);
     304          591 :         self.append(v0, v1);
     305          591 :         self.append(v0, v2);
     306          591 :         self.append(v0, v3);
     307          591 :         v0
     308          591 :     }
     309              : 
     310              :     // -----------------------------------------------------------------------------------------
     311              :     // Nodes
     312              :     // -----------------------------------------------------------------------------------------
     313              : 
     314              :     /// Emit a node and set the parent of its children
     315       487637 :     pub fn add_node(&self, node: Node) -> u32 {
     316       487637 :         let mut state = self.state.borrow_mut();
     317       487637 :         let node_id = state.nodes.len() as u32;
     318       487637 :         state.nodes.push(with_parent(&node, node_id));
     319       487637 :         let node_type = node.node_type();
     320       487637 :         if (node_type == NodeType::ARRAY || node_type.0 > NodeType::OBJECT_KEYS_.0) && node.children_count() > 0 {
     321       308056 :             let begin = node.children_begin_or_value() as usize;
     322       308056 :             let end = begin + node.children_count() as usize;
     323       479009 :             for child in &mut state.nodes[begin..end] {
     324       479009 :                 *child = with_parent(child, node_id);
     325       479009 :             }
     326       179581 :         }
     327       487637 :         node_id
     328       487637 :     }
     329              : 
     330              :     /// Emit the children of a list and return their range, skipping null nodes
     331       340124 :     fn emit_children(&self, list: NodeList) -> (u32, u32) {
     332       340124 :         let begin = self.state.borrow().nodes.len() as u32;
     333       340124 :         let nodes = self.take_list(list);
     334       618027 :         for node in &nodes {
     335       618027 :             if node.node_type() == NodeType::NONE {
     336       138742 :                 continue;
     337       479285 :             }
     338       479285 :             self.add_node(*node);
     339              :         }
     340       340124 :         self.recycle(list, nodes);
     341       340124 :         let n = self.state.borrow().nodes.len() as u32 - begin;
     342       340124 :         (begin, n)
     343       340124 :     }
     344              : 
     345              :     /// The span from the first to the last of `n` nodes starting at `begin`
     346            0 :     fn shrunk_location(&self, begin: u32, n: u32) -> SymbolSpan {
     347            0 :         let state = self.state.borrow();
     348            0 :         let first = state.nodes[begin as usize].symbol_span().offset();
     349            0 :         let last = state.nodes[(begin + n - 1) as usize].symbol_span();
     350            0 :         SymbolSpan::new(first, last.offset().wrapping_add(last.length()).wrapping_sub(first))
     351            0 :     }
     352              : 
     353              :     /// An array of nodes
     354       165829 :     pub fn array(&self, loc: SymbolSpan, values: impl IntoNodeList) -> Node {
     355       165829 :         self.array_ex(loc, values, true, false)
     356       165829 :     }
     357              : 
     358              :     /// An array of nodes with explicit options
     359       165970 :     pub fn array_ex(&self, mut loc: SymbolSpan, values: impl IntoNodeList, null_if_empty: bool, shrink_location: bool) -> Node {
     360       165970 :         let list = values.into_node_list(self);
     361       165970 :         let (begin, n) = self.emit_children(list);
     362       165970 :         if n == 0 && null_if_empty {
     363        31361 :             return null();
     364       134609 :         }
     365       134609 :         if n > 0 && shrink_location {
     366            0 :             loc = self.shrunk_location(begin, n);
     367       134609 :         }
     368       134609 :         Node::new(&loc, NodeType::ARRAY, AttributeKey::NONE, NO_PARENT, begin, n)
     369       165970 :     }
     370              : 
     371              :     /// An array of expressions
     372        22638 :     pub(crate) fn expression_array(&self, loc: SymbolSpan, exprs: &[ExprVariant]) -> Node {
     373        22638 :         let nodes = self.list(&[]);
     374        46273 :         for &expr in exprs {
     375        46273 :             let node = self.expression(expr);
     376        46273 :             self.push_back(nodes, node);
     377        46273 :         }
     378        22638 :         self.array(loc, nodes)
     379        22638 :     }
     380              : 
     381              :     /// An object
     382       173553 :     pub fn object(&self, loc: SymbolSpan, node_type: NodeType, attrs: impl IntoNodeList) -> Node {
     383       173553 :         self.object_ex(loc, node_type, attrs, true, false)
     384       173553 :     }
     385              : 
     386              :     /// An object with explicit options
     387       174154 :     pub fn object_ex(
     388       174154 :         &self,
     389       174154 :         mut loc: SymbolSpan,
     390       174154 :         node_type: NodeType,
     391       174154 :         attrs: impl IntoNodeList,
     392       174154 :         null_if_empty: bool,
     393       174154 :         shrink_location: bool,
     394       174154 :     ) -> Node {
     395       174154 :         let list = attrs.into_node_list(self);
     396       174154 :         let (begin, n) = self.emit_children(list);
     397       174154 :         if n == 0 && null_if_empty {
     398          208 :             return null();
     399       173946 :         }
     400       173946 :         if n > 0 && shrink_location {
     401            0 :             loc = self.shrunk_location(begin, n);
     402       173946 :         }
     403       173946 :         Node::new(&loc, node_type, AttributeKey::NONE, NO_PARENT, begin, n)
     404       174154 :     }
     405              : 
     406              :     /// Materialize an expression
     407       101614 :     pub fn expression(&self, expr: impl Into<ExprVariant>) -> Node {
     408       101614 :         match expr.into() {
     409        97544 :             ExprVariant::Node(node) => node,
     410         4070 :             ExprVariant::Nary(id) => {
     411         4070 :                 let nary = self.state.borrow().nary_expressions[id as usize];
     412         4070 :                 let args = self.array(nary.location, nary.args);
     413         4070 :                 self.object(
     414         4070 :                     nary.location,
     415              :                     NodeType::OBJECT_SQL_NARY_EXPRESSION,
     416         4070 :                     &[
     417         4070 :                         super::actions::attr(AttributeKey::SQL_EXPRESSION_OPERATOR, nary.op_node),
     418         4070 :                         super::actions::attr(AttributeKey::SQL_EXPRESSION_ARGS, args),
     419         4070 :                     ],
     420              :                 )
     421              :             }
     422              :         }
     423       101614 :     }
     424              : 
     425              :     /// Flatten an AND / OR expression with nested expressions of the same operator
     426        34053 :     pub(crate) fn try_merge(&self, loc: SymbolSpan, op_node: Node, args: &[ExprVariant]) -> Option<ExprVariant> {
     427        34053 :         if op_node.node_type() != NodeType::ENUM_SQL_EXPRESSION_OPERATOR {
     428           96 :             return None;
     429        33957 :         }
     430        33957 :         let op = ExpressionOperator(op_node.children_begin_or_value() as u8);
     431        33957 :         if op != ExpressionOperator::AND && op != ExpressionOperator::OR {
     432        22034 :             return None;
     433        11923 :         }
     434        11923 :         let nary_args = self.list(&[]);
     435        11923 :         let id = {
     436        11923 :             let mut state = self.state.borrow_mut();
     437        11923 :             state.nary_expressions.push(NaryExpression {
     438        11923 :                 location: loc,
     439        11923 :                 op,
     440        11923 :                 op_node,
     441        11923 :                 args: nary_args,
     442        11923 :             });
     443        11923 :             state.nary_expressions.len() as u32 - 1
     444              :         };
     445        23846 :         for &arg in args {
     446        23846 :             match arg {
     447        14682 :                 ExprVariant::Node(node) => self.push_back(nary_args, node),
     448         9164 :                 ExprVariant::Nary(child_id) => {
     449         9164 :                     let child = self.state.borrow().nary_expressions[child_id as usize];
     450         9164 :                     if child.op != op {
     451         1313 :                         let node = self.expression(arg);
     452         1313 :                         self.push_back(nary_args, node);
     453         7853 :                     } else {
     454         7851 :                         self.append(nary_args, child.args);
     455         7851 :                     }
     456              :                 }
     457              :             }
     458              :         }
     459        11923 :         Some(ExprVariant::Nary(id))
     460        34053 :     }
     461              : 
     462              :     // -----------------------------------------------------------------------------------------
     463              :     // Names
     464              :     // -----------------------------------------------------------------------------------------
     465              : 
     466              :     /// A name from a keyword. The symbol span, a span of token indexes, is registered as the name
     467              :     /// location (see docs/design/core_quirks.md).
     468         1399 :     pub fn name_from_keyword(&self, loc: SymbolSpan, text: &str) -> Node {
     469         1399 :         let id = self.state.borrow_mut().names.register(text, TextSpan::new(loc.offset(), loc.length()));
     470         1399 :         Node::new(&loc, NodeType::NAME, AttributeKey::NONE, NO_PARENT, id, 0)
     471         1399 :     }
     472              : 
     473              :     /// A name from a string literal. Only double quotes are trimmed, so single quotes are kept.
     474           49 :     pub fn name_from_string_literal(&self, loc: SymbolSpan) -> Node {
     475           49 :         let text = self.text_at(loc).trim_matches('"');
     476           49 :         let id = self.state.borrow_mut().names.register(text, TextSpan::new(loc.offset(), loc.length()));
     477           49 :         Node::new(&loc, NodeType::NAME, AttributeKey::NONE, NO_PARENT, id, 0)
     478           49 :     }
     479              : 
     480              :     /// Mark a trailing dot
     481           43 :     pub fn trailing_dot(&self, loc: SymbolSpan) -> Node {
     482           43 :         self.add_error(loc, "name has a trailing dot");
     483           43 :         Node::new(&loc, NodeType::OBJECT_EXT_TRAILING_DOT, AttributeKey::NONE, NO_PARENT, 0, 0)
     484           43 :     }
     485              : 
     486              :     // -----------------------------------------------------------------------------------------
     487              :     // Checks
     488              :     // -----------------------------------------------------------------------------------------
     489              : 
     490              :     /// The unit of a sample count written without one: the sampling methods of the SQL standard
     491              :     /// (`bernoulli`, `system`) take a percentage, every other sample takes a number of rows
     492           11 :     pub fn bare_sample_unit(&self, method: &Node, loc: SymbolSpan) -> Node {
     493           11 :         let is_percentage = method.node_type() == NodeType::NAME && {
     494           11 :             let state = self.state.borrow();
     495           11 :             matches!(state.names.get(method.children_begin_or_value()).text.as_str(), "bernoulli" | "system")
     496              :         };
     497           11 :         let unit = if is_percentage { SampleCountUnit::PERCENT } else { SampleCountUnit::ROWS };
     498           11 :         Node::new(&loc, NodeType::ENUM_SQL_SAMPLE_UNIT_TYPE, AttributeKey::NONE, NO_PARENT, unit.0 as u32, 0)
     499           11 :     }
     500              : 
     501              :     /// Report a FROM keyword that is not followed by a table reference. The rule stays lenient to
     502              :     /// keep the tree of an unfinished statement, but only the end of the input may follow the keyword.
     503           33 :     pub fn require_table_ref_after_from(&self, from: SymbolSpan) {
     504           33 :         let next = (from.offset() + from.length()) as usize;
     505           33 :         if self.symbols.get(next).is_some_and(|symbol| symbol.kind != crate::symbol_kind::S_YYEOF) {
     506           18 :             self.error(from, "expected a table reference after FROM");
     507           29 :         }
     508           33 :     }
     509              : 
     510              :     /// Read the precision of a float type
     511           10 :     pub fn read_float_type(&self, bits_loc: SymbolSpan) -> NumericType {
     512           10 :         let text = self.text_at(bits_loc);
     513           10 :         let digits: &str = &text[..text.bytes().take_while(u8::is_ascii_digit).count()];
     514           10 :         let bits: i64 = digits.parse().unwrap_or(0);
     515           10 :         if bits < 1 {
     516            2 :             self.add_error(bits_loc, "precision for float type must be least 1 bit");
     517            8 :         } else if bits < 24 {
     518            4 :             return NumericType::FLOAT4;
     519            4 :         } else if bits < 53 {
     520            2 :             return NumericType::FLOAT8;
     521            2 :         } else {
     522            2 :             self.add_error(bits_loc, "precision for float type must be less than 54 bits");
     523            2 :         }
     524            4 :         NumericType::FLOAT4
     525           10 :     }
     526              : 
     527              :     /// Require punctuation tokens to be adjacent in the source text
     528          233 :     pub fn require_adjacent(&self, left: SymbolSpan, right: SymbolSpan, spelling: &str) {
     529          233 :         let l = self.resolve_text_span(left);
     530          233 :         let r = self.resolve_text_span(right);
     531          233 :         if l.end() != r.offset {
     532           12 :             self.add_error(super::actions::loc(&[left, right]), &format!("expected adjacent punctuation \"{spelling}\""));
     533          221 :         }
     534          233 :     }
     535              : 
     536              :     /// Require a generic operator token to use an exact spelling
     537           71 :     pub fn require_operator(&self, loc: SymbolSpan, spelling: &str) {
     538           71 :         if self.text_at(loc) != spelling {
     539            2 :             self.add_error(loc, &format!("expected operator \"{spelling}\""));
     540           69 :         }
     541           71 :     }
     542              : 
     543              :     // -----------------------------------------------------------------------------------------
     544              :     // Statements and errors
     545              :     // -----------------------------------------------------------------------------------------
     546              : 
     547              :     /// Add a statement
     548        12956 :     pub fn add_statement(&self, node: Node) {
     549        12956 :         if node.node_type() == NodeType::NONE {
     550         4604 :             return;
     551         8352 :         }
     552         8352 :         let root = self.add_node(node);
     553         8352 :         let mut state = self.state.borrow_mut();
     554         8352 :         let statement_type = match node.node_type() {
     555           30 :             NodeType::OBJECT_EXT_SET => StatementType::SET,
     556           70 :             NodeType::OBJECT_SQL_CREATE_AS => StatementType::CREATE_TABLE_AS,
     557         1687 :             NodeType::OBJECT_SQL_CREATE => StatementType::CREATE_TABLE,
     558           76 :             NodeType::OBJECT_SQL_VIEW => StatementType::CREATE_VIEW,
     559           69 :             NodeType::OBJECT_SQL_CREATE_FUNCTION => StatementType::CREATE_FUNCTION,
     560         5836 :             NodeType::OBJECT_SQL_SELECT => select_statement_type(&state.nodes, node),
     561           71 :             NodeType::OBJECT_SQL_DROP_TABLE => StatementType::DROP_TABLE,
     562           28 :             NodeType::OBJECT_SQL_DROP_VIEW => StatementType::DROP_VIEW,
     563           22 :             NodeType::OBJECT_SQL_ATTACH_DATABASE => StatementType::ATTACH_DATABASE,
     564          194 :             NodeType::OBJECT_SQL_INSERT => StatementType::INSERT,
     565           99 :             NodeType::OBJECT_SQL_DELETE => StatementType::DELETE,
     566          170 :             NodeType::OBJECT_EXT_EXPLAIN => StatementType::EXPLAIN,
     567            0 :             other => panic!("unexpected statement root {:?}", other.variant_name()),
     568              :         };
     569         8352 :         let nodes_len = state.nodes.len() as u32;
     570         8352 :         let mut statement = state.current_statement;
     571         8352 :         statement.root = root;
     572         8352 :         statement.statement_type = statement_type;
     573         8352 :         statement.node_count = nodes_len - statement.nodes_begin;
     574         8352 :         state.statements.push(statement);
     575         8352 :         state.current_statement = Statement {
     576         8352 :             nodes_begin: nodes_len,
     577         8352 :             ..Default::default()
     578         8352 :         };
     579        12956 :     }
     580              : 
     581              :     /// Drop the nodes of the current statement after an error
     582          337 :     pub fn reset_statement(&self) {
     583          337 :         let mut state = self.state.borrow_mut();
     584          337 :         state.current_statement.nodes_begin = state.nodes.len() as u32;
     585          337 :     }
     586              : 
     587              :     /// Add an error without a hint
     588           61 :     pub fn add_error(&self, loc: SymbolSpan, message: &str) {
     589           61 :         self.state.borrow_mut().errors.push(ParseError {
     590           61 :             location: loc,
     591           61 :             message: message.to_string(),
     592           61 :             hint: String::new(),
     593           61 :         });
     594           61 :     }
     595              : 
     596              :     /// Report an error from the parser or an action, attaching the pending hint
     597          311 :     pub fn error(&self, loc: SymbolSpan, message: &str) {
     598          311 :         let mut state = self.state.borrow_mut();
     599          311 :         let hint = std::mem::take(&mut state.pending_hint);
     600          311 :         state.errors.push(ParseError {
     601          311 :             location: loc,
     602          311 :             message: message.to_string(),
     603          311 :             hint,
     604          311 :         });
     605          311 :     }
     606              : 
     607              :     /// Drop the lookahead after the action (`yyclearin`)
     608          602 :     pub fn clear_lookahead(&self) {
     609          602 :         self.state.borrow_mut().clear_lookahead = true;
     610          602 :     }
     611              : }
     612              : 
     613              : /// SELECT or SELECT INTO, following the inputs of set operations
     614         5836 : fn select_statement_type(nodes: &[Node], root: Node) -> StatementType {
     615         5836 :     let mut current = root;
     616         5881 :     while current.node_type() == NodeType::OBJECT_SQL_SELECT {
     617         5881 :         let mut next = None;
     618         5881 :         let begin = current.children_begin_or_value() as usize;
     619        14362 :         for child in &nodes[begin..begin + current.children_count() as usize] {
     620        14362 :             if child.attribute_key() == AttributeKey::SQL_SELECT_INTO && child.node_type() != NodeType::NONE {
     621           59 :                 return StatementType::SELECT_INTO;
     622        14303 :             }
     623        14303 :             if child.attribute_key() == AttributeKey::SQL_COMBINE_INPUT
     624           45 :                 && child.node_type() == NodeType::ARRAY
     625           45 :                 && child.children_count() > 0
     626           45 :             {
     627           45 :                 next = Some(nodes[child.children_begin_or_value() as usize]);
     628        14258 :             }
     629              :         }
     630         5822 :         match next {
     631           45 :             Some(n) => current = n,
     632         5777 :             None => break,
     633              :         }
     634              :     }
     635         5777 :     StatementType::SELECT
     636         5836 : }
     637              : 
     638              : /// Resolve a span of symbol indexes to a span of bytes
     639       231462 : pub fn resolve_text_span(text: &str, symbols: &[Symbol], span: SymbolSpan) -> TextSpan {
     640       231462 :     if span.length() == 0 {
     641          243 :         return match symbols.get(span.offset() as usize) {
     642          243 :             Some(symbol) => TextSpan::new(symbol.location.offset, 0),
     643            0 :             None => TextSpan::new(text.len() as u32, 0),
     644              :         };
     645       231219 :     }
     646       231219 :     let first = symbols[span.offset() as usize].location;
     647       231219 :     let last = symbols[(span.offset() + span.length() - 1) as usize].location;
     648       231219 :     TextSpan::new(first.offset, last.end() - first.offset)
     649       231462 : }
        

Generated by: LCOV version 2.0-1