1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// SPDX-License-Identifier: MIT
// Copyright (c) 2026 Moderately AI Inc.
//! The Pratt (precedence-climbing) expression parser.
//!
//! One binding-power table drives every operator: [`parse_expr_bp`](crate::parser::Parser::parse_expr_bp)
//! recurses the right-hand side at the operator's *own* right binding power, so
//! the prior art's precedence mis-bind — a `parse_infix` hook that ignored the
//! precedence handed to it — is structurally impossible here: there is no
//! precedence *parameter* to ignore. Left-associativity falls out of recursing at
//! `right` (which is `left + 1`, so a same-level operator's `left` cannot clear
//! the bumped minimum and re-enter); non-associativity is rejected explicitly,
//! because the climbing loop would otherwise silently *left*-associate it.
//!
//! Parentheses are grouping only: they are consumed and discarded, never stored
//! as a node. During parsing they still form a transient
//! barrier for non-associative chain checks; render-time parenthesization is then
//! derived from the same binding powers, so the AST need not remember where the
//! source put parens.
//!
//! Richer expression families land as focused parser branches around the core:
//! `CAST` is a prefix primary because type names are shared parser surface for
//! casts, DDL, and parameters; subquery predicates bind at the comparison level
//! without becoming ordinary binary RHS expressions.
use crate;
pub use ;
/// Parser-internal expression plus transient source grouping state.
///
/// The public AST intentionally has no `Expr::Nested` node, but a
/// grouped expression must suppress exactly the next non-associative chain check:
/// `(a < b) < c` is valid PostgreSQL syntax, while `a < b < c` is not.
/// Classify a `Number` lexeme as a money, integer, or float literal.
///
/// The tokenizer already validated the numeric shape. A `$` currency sigil marks a
/// T-SQL money literal (`$1234.56`); the check comes first because a money body holds
/// the same `.` that otherwise marks a float. The sigil may sit behind a folded sign
/// in SET-value position (`-$1000`), where the sign is part of the span (unlike
/// expression position), so an optional leading `+`/`-` is skipped. A
/// `0x`/`0o`/`0b` radix integer is recognised next — through the shared
/// [`split_radix_prefix`](crate::ast::split_radix_prefix) recognizer the AST value
/// decoders also use, so this classification and `as_i64`/`as_decimal_text` cannot
/// disagree on which spellings are radix integers — because such a literal has
/// no exponent form: its `E`/`e` bytes are hex *digits* (`0xBEEF`, `0x1E`), so they must
/// be ruled out before the decimal scan that would otherwise mistag them `Float`. With
/// neither sigil nor radix prefix, a fractional point or exponent marker distinguishes a
/// float (`3.14`, `1e9`, `.5`) from an integer (`42`).
///
/// When `parse_float_as_decimal` is set (the parser's off-by-default
/// [`ParseConfig::parse_float_as_decimal`](crate::parser::ParseConfig::parse_float_as_decimal)
/// consumer request), the float case is tagged [`LiteralKind::Decimal`] instead — the
/// only thing the flag changes. Integers, radix integers, and money are unaffected, and
/// the spelling round-trips from the span either way, so the flag is pure classification
/// metadata (see the `Decimal` variant's docs).
pub
/// Map a special-function [`Keyword`] to its [`SpecialFunctionKeyword`] tag and
/// whether it accepts a `(precision)` argument.
///
/// Only the four temporal forms (`CURRENT_TIME`, `CURRENT_TIMESTAMP`,
/// `LOCALTIME`, `LOCALTIMESTAMP`) take a precision; the rest are strictly nullary.
/// `pub(super)` so [`super::from`]'s `FROM`-position special function table
/// reference (`SELECT * FROM current_date`, the same grammar production
/// promoted to `func_table`) shares this one mapping.
pub
/// True if `keyword` opens a SQL special value function (PostgreSQL
/// `SQLValueFunction`): `CURRENT_DATE`, `CURRENT_USER`, `USER`, or one of the
/// four temporal forms. Mirrors the keyword set in the expression dispatch
/// (`Parser::parse_keyword_prefix` in `keyword_forms.rs`; kept as a separate list
/// rather than refactored to share it, so as not to disturb that already-tested
/// match); a new special-function keyword valid in FROM position must be added to
/// both.
///
/// The MySQL `UTC_DATE`/`UTC_TIME`/`UTC_TIMESTAMP` forms are deliberately absent: they
/// are expression-position-only (MySQL has no PostgreSQL-style `func_table` promotion),
/// so admitting them here would wrongly parse `FROM utc_date` as a special function
/// across every dialect. The expression dispatch gates them behind the MySQL-only flag.
pub