Line data Source code
1 : //! The DashQL SQL grammar.
2 : //!
3 : //! [`tables`] holds the LALR(1) automaton and the actions that bison computes from the rules of
4 : //! `//grammar` (`grammar/rules`), emitted through `//grammar/rust:tables.rs.m4`.
5 : //!
6 : //! [`scanner`] is a logos scanner of the grammar's tokens. [`parser`] runs the automaton with the
7 : //! actions of `grammar/rules`.
8 :
9 : use std::borrow::Cow;
10 :
11 : pub mod attributes;
12 : pub mod comment_blocks;
13 : pub mod keywords;
14 : pub mod names;
15 : pub mod parser;
16 : pub mod scanner;
17 : pub mod span;
18 :
19 : #[allow(dead_code, non_upper_case_globals, unused_braces, unused_parens, unused_variables, unused_mut)]
20 : #[allow(clippy::all)]
21 : #[rustfmt::skip]
22 : pub mod tables;
23 :
24 : pub use tables::symbol_kind;
25 :
26 : /// A bison symbol kind: terminals in `0..YYNTOKENS`, nonterminals after them.
27 : pub type SymbolKind = u16;
28 :
29 : /// Is the symbol a terminal?
30 2 : pub fn is_terminal(kind: SymbolKind) -> bool {
31 2 : (kind as usize) < tables::YYNTOKENS
32 2 : }
33 :
34 : /// The name of a symbol as bison's verbose error messages print it.
35 : ///
36 : /// Mirrors bison's `yytnamerr_`: a quoted alias such as `"identifier literal"` loses its
37 : /// double quotes unless it contains an apostrophe, a comma or a backslash.
38 335 : pub fn symbol_name(kind: SymbolKind) -> Cow<'static, str> {
39 335 : let name = tables::YYTNAME[kind as usize];
40 335 : let Some(quoted) = name.strip_prefix('"') else {
41 206 : return Cow::Borrowed(name);
42 : };
43 129 : let mut unquoted = String::with_capacity(quoted.len());
44 129 : let mut chars = quoted.chars();
45 2418 : while let Some(c) = chars.next() {
46 2418 : match c {
47 0 : '\'' | ',' => break,
48 0 : '\\' => match chars.next() {
49 0 : Some('\\') => unquoted.push('\\'),
50 0 : _ => break,
51 : },
52 129 : '"' => return Cow::Owned(unquoted),
53 2289 : c => unquoted.push(c),
54 : }
55 : }
56 0 : Cow::Borrowed(name)
57 335 : }
58 :
59 : #[cfg(test)]
60 : mod tests {
61 : use super::*;
62 :
63 : #[test]
64 1 : fn automaton_size() {
65 1 : assert_eq!(tables::YYNTOKENS, 511);
66 1 : assert_eq!(tables::YYPACT.len(), tables::YYNSTATES);
67 1 : assert_eq!(tables::YYDEFACT.len(), tables::YYNSTATES);
68 1 : assert_eq!(tables::YYSTOS.len(), tables::YYNSTATES);
69 1 : assert_eq!(tables::YYR1.len(), tables::YYNRULES + 1);
70 1 : assert_eq!(tables::YYR2.len(), tables::YYNRULES + 1);
71 1 : assert_eq!(tables::YYPGOTO.len(), tables::YYNNTS);
72 1 : assert_eq!(tables::YYDEFGOTO.len(), tables::YYNNTS);
73 1 : assert_eq!(tables::YYTABLE.len(), tables::YYLAST as usize + 1);
74 1 : assert_eq!(tables::YYCHECK.len(), tables::YYLAST as usize + 1);
75 : // The symbol names end with bison's YY_NULLPTR sentinel.
76 1 : assert_eq!(tables::YYTNAME.len(), tables::YYNTOKENS + tables::YYNNTS + 1);
77 1 : }
78 :
79 : #[test]
80 1 : fn symbol_kinds() {
81 1 : assert_eq!(symbol_kind::S_YYEOF, 0);
82 1 : assert_eq!(symbol_kind::S_YYerror, 1);
83 1 : assert_eq!(symbol_kind::S_YYUNDEF, 2);
84 1 : assert_eq!(symbol_kind::S_IDENT, 3);
85 1 : assert!(is_terminal(symbol_kind::S_SELECT));
86 1 : assert!(!is_terminal(symbol_kind::S_sql_select_stmt));
87 1 : }
88 :
89 : #[test]
90 1 : fn symbol_names() {
91 1 : assert_eq!(symbol_name(symbol_kind::S_YYEOF), "EOF");
92 1 : assert_eq!(symbol_name(symbol_kind::S_IDENT), "identifier literal");
93 1 : assert_eq!(symbol_name(symbol_kind::S_SCONST), "string literal");
94 1 : assert_eq!(symbol_name(symbol_kind::S_YYUNDEF), "invalid token");
95 1 : assert_eq!(symbol_name(symbol_kind::S_SELECT), "SELECT");
96 1 : assert_eq!(symbol_name(symbol_kind::S_RRB), "RRB");
97 1 : }
98 : }
|