selene_gql/ast/expr.rs
1//! Expression AST nodes.
2
3use std::sync::Arc;
4
5use rust_decimal::Decimal;
6use selene_core::DbString;
7
8use crate::ast::{
9 pattern::LabelExpr, pattern::MatchClause, span::SourceSpan, statement::QueryPipeline,
10 types::GqlType, util::NonEmpty,
11};
12
13/// Value expression.
14#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
15#[non_exhaustive]
16pub enum ValueExpr {
17 /// Literal value expression.
18 Literal(Literal),
19 /// Variable reference parsed from an identifier token.
20 Variable {
21 /// Database-string variable name.
22 name: DbString,
23 /// Source span of the variable reference.
24 span: SourceSpan,
25 },
26 /// Query parameter reference, such as `$name`.
27 Parameter {
28 /// Database-string parameter name without the leading `$`.
29 name: DbString,
30 /// Optional inline declared parameter type.
31 declared_type: Option<GqlType>,
32 /// Source span of the parameter reference.
33 span: SourceSpan,
34 },
35 /// Property access, such as `n.name`.
36 PropertyAccess {
37 /// Target expression.
38 target: Box<ValueExpr>,
39 /// Database-string property key.
40 key: DbString,
41 /// Source span of the full property access.
42 span: SourceSpan,
43 },
44 /// List literal.
45 ListLiteral {
46 /// Literal items.
47 items: Vec<ValueExpr>,
48 /// Source span of the list.
49 span: SourceSpan,
50 },
51 /// Record literal.
52 RecordLiteral {
53 /// Record fields in source order.
54 fields: Vec<(DbString, ValueExpr)>,
55 /// Source span of the record.
56 span: SourceSpan,
57 },
58 /// `PATH[<node>, <edge>, <node>, ...]` constructor.
59 PathConstructor {
60 /// Alternating node/edge/node reference expressions.
61 elements: Vec<ValueExpr>,
62 /// Source span of the path constructor.
63 span: SourceSpan,
64 },
65 /// Binary operator expression.
66 BinaryOp {
67 /// Operator.
68 op: BinaryOp,
69 /// Left operand.
70 lhs: Box<ValueExpr>,
71 /// Right operand.
72 rhs: Box<ValueExpr>,
73 /// Source span of the full expression.
74 span: SourceSpan,
75 },
76 /// Unary operator expression.
77 UnaryOp {
78 /// Operator.
79 op: UnaryOp,
80 /// Operand.
81 operand: Box<ValueExpr>,
82 /// Source span of the full expression.
83 span: SourceSpan,
84 },
85 /// Function call, including aggregate-looking calls.
86 FunctionCall {
87 /// Qualified function name as a list of database-string segments.
88 ///
89 /// Stored as a path so that `foo."bar.baz"` and `foo.bar.baz`
90 /// (which a flat string would alias) parse to distinguishable
91 /// values. Bare functions (`count(...)`) are a single-element
92 /// path; namespaced calls (`db.bar()`, `pkg.subpkg.fn()`) preserve
93 /// every segment.
94 name: NonEmpty<DbString>,
95 /// Function arguments.
96 args: Vec<ValueExpr>,
97 /// `true` for `count(*)`.
98 star: bool,
99 /// `true` when the call included `DISTINCT`.
100 distinct: bool,
101 /// Source span of the call.
102 span: SourceSpan,
103 },
104 /// `DURATION_BETWEEN(<start>, <end>) [<temporal duration qualifier>]`.
105 DurationBetween {
106 /// Start temporal value expression.
107 start: Box<ValueExpr>,
108 /// End temporal value expression.
109 end: Box<ValueExpr>,
110 /// Requested duration unit group.
111 qualifier: TemporalDurationQualifier,
112 /// Source span of the full expression.
113 span: SourceSpan,
114 },
115 /// `IS` predicate family.
116 IsCheck {
117 /// Checked operand.
118 operand: Box<ValueExpr>,
119 /// Predicate kind.
120 kind: IsCheckKind,
121 /// Whether the predicate was negated.
122 negated: bool,
123 /// Source span of the full predicate.
124 span: SourceSpan,
125 },
126 /// `[NOT] IN` predicate.
127 InList {
128 /// Checked operand.
129 operand: Box<ValueExpr>,
130 /// List values.
131 list: Vec<ValueExpr>,
132 /// Whether the predicate was negated.
133 negated: bool,
134 /// Source span of the full predicate.
135 span: SourceSpan,
136 },
137 /// `[NOT] IN` predicate with a list-valued expression on the right.
138 InListExpression {
139 /// Checked operand.
140 operand: Box<ValueExpr>,
141 /// List-valued expression.
142 list: Box<ValueExpr>,
143 /// Whether the predicate was negated.
144 negated: bool,
145 /// Source span of the full predicate.
146 span: SourceSpan,
147 },
148 /// `ALL_DIFFERENT(...)` predicate.
149 ///
150 /// ISO/IEC 39075:2024 section 19.11 takes element variable references.
151 /// The AST keeps a broad item shape so parser construction stays regular;
152 /// analysis enforces the ISO argument rule.
153 AllDifferent {
154 /// Items to compare.
155 items: Vec<ValueExpr>,
156 /// Source span of the predicate.
157 span: SourceSpan,
158 },
159 /// `SAME(...)` predicate.
160 ///
161 /// ISO/IEC 39075:2024 section 19.12 takes element variable references.
162 /// The AST keeps a broad item shape so parser construction stays regular;
163 /// analysis enforces the ISO argument rule.
164 Same {
165 /// Items to compare.
166 items: Vec<ValueExpr>,
167 /// Source span of the predicate.
168 span: SourceSpan,
169 },
170 /// `PROPERTY_EXISTS(target, 'key')` predicate.
171 ///
172 /// ISO/IEC 39075:2024 section 19.13 takes an element variable reference
173 /// and property name. The AST keeps a broad target shape so parser
174 /// construction stays regular; analysis enforces the ISO target rule.
175 PropertyExists {
176 /// Target expression.
177 target: Box<ValueExpr>,
178 /// Database-string property key.
179 key: DbString,
180 /// Source spelling class for the property-key character string literal.
181 key_source_kind: CharacterStringLiteralKind,
182 /// Source span of the predicate.
183 span: SourceSpan,
184 },
185 /// `CASE` expression.
186 Case {
187 /// `(condition, value)` branches.
188 branches: Vec<(ValueExpr, ValueExpr)>,
189 /// Optional else branch.
190 else_branch: Option<Box<ValueExpr>>,
191 /// Source span of the full expression.
192 span: SourceSpan,
193 },
194 /// `EXISTS { ... }` subquery predicate.
195 Exists {
196 /// Nested body.
197 body: ExistsBody,
198 /// Whether the predicate was negated.
199 negated: bool,
200 /// Source span of the full expression.
201 span: SourceSpan,
202 },
203 /// `VALUE { ... }` scalar value query expression.
204 ValueSubquery {
205 /// Nested query body.
206 body: Box<QueryPipeline>,
207 /// Source span of the full expression.
208 span: SourceSpan,
209 },
210 /// `NORMALIZE(<source>[, <normal form>])` Unicode normalization expression.
211 Normalize {
212 /// Source string expression.
213 source: Box<ValueExpr>,
214 /// Optional normalization form; omitted form defaults to NFC.
215 form: Option<NormalForm>,
216 /// Source span of the full expression.
217 span: SourceSpan,
218 },
219 /// Explicit `TRIM([LEADING|TRAILING|BOTH] [char] FROM source)` expression.
220 Trim {
221 /// Trim direction.
222 spec: TrimSpec,
223 /// Optional trim character expression; omitted character defaults to space.
224 character: Option<Box<ValueExpr>>,
225 /// Source string expression.
226 source: Box<ValueExpr>,
227 /// Source span of the full expression.
228 span: SourceSpan,
229 },
230 /// `CAST(<value> AS <target_type>)` explicit cast expression per ISO §22.
231 ///
232 /// `target_type` is boxed to keep the size of [`ValueExpr`] bounded; the
233 /// nested `GqlType::List(Box<GqlType>)` chain is otherwise heap-resident
234 /// already, and the analyzer-recursion test (`addition_statement(100)`)
235 /// stack-overflows if a non-boxed `GqlType` is added inline.
236 Cast {
237 /// Source expression being cast.
238 value: Box<ValueExpr>,
239 /// Declared target GQL type.
240 target_type: Box<GqlType>,
241 /// Source span of the full expression.
242 span: SourceSpan,
243 },
244}
245
246/// Nested body accepted by an `EXISTS` predicate.
247#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
248pub enum ExistsBody {
249 /// Existing single-MATCH body.
250 Match(Box<MatchClause>),
251 /// Full query pipeline body.
252 Query(Box<QueryPipeline>),
253}
254
255/// Temporal duration qualifier for `DURATION_BETWEEN`.
256#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
257pub enum TemporalDurationQualifier {
258 /// `YEAR TO MONTH`.
259 YearToMonth,
260 /// `DAY TO SECOND`.
261 DayToSecond,
262}
263
264impl Drop for ValueExpr {
265 /// Tear this expression down iteratively rather than with the compiler's
266 /// derived recursive destructor.
267 ///
268 /// A left-leaning `Box<ValueExpr>` chain (e.g. the depth-N tree built from
269 /// `a OR a OR …` or a long `a.b.c.…` access chain) overflows the native
270 /// stack when freed recursively — one frame per level — at roughly 130k
271 /// deep. A Rust stack overflow is **non-unwindable** (`catch_unwind` cannot
272 /// trap it), so it hard-kills the host process embedding selene-db. The
273 /// parser caps *accepted* expression depth far below that
274 /// (`parser::depth`), but an over-cap tree is still fully constructed before
275 /// the cap rejects it, and that rejected tree must be dropped without
276 /// recursing. This manual `Drop` hoists every owned child `ValueExpr` onto a
277 /// heap worklist (replacing it in place with a childless placeholder) and
278 /// drops the worklist in a pop-loop, so teardown is O(nodes) iterative.
279 ///
280 /// By the time any hoisted node is itself dropped, its children have already
281 /// been replaced by placeholders, so its re-entrant destructor finds nothing
282 /// to recurse into (recursion depth stays ≤ 2 regardless of tree depth).
283 /// Subquery bodies (`Box<MatchClause>` / `Box<QueryPipeline>`) and the
284 /// `Cast` target type (`Box<GqlType>`) are **not** direct `ValueExpr`
285 /// children (see [`ValueExpr::for_each_child_mut`]); they drop normally,
286 /// which is safe because subquery nesting is bounded by the pre-pest `{`
287 /// delimiter cap and `GqlType` depth by the type builder's gate.
288 fn drop(&mut self) {
289 let mut pending: Vec<ValueExpr> = Vec::new();
290 hoist_children(self, &mut pending);
291 while let Some(mut node) = pending.pop() {
292 hoist_children(&mut node, &mut pending);
293 // `node` drops here with its children already hoisted out.
294 }
295 }
296}
297
298/// Move every direct child [`ValueExpr`] of `expr` onto `pending`, leaving a
299/// childless placeholder in its slot. Shared by the iterative [`Drop`] impl.
300fn hoist_children(expr: &mut ValueExpr, pending: &mut Vec<ValueExpr>) {
301 expr.for_each_child_mut(&mut |child| {
302 pending.push(core::mem::replace(child, drop_placeholder()));
303 });
304}
305
306/// A cheap, childless [`ValueExpr`] swapped in for a hoisted child during
307/// iterative teardown. Constructing it allocates nothing and dropping it
308/// recurses into nothing.
309fn drop_placeholder() -> ValueExpr {
310 ValueExpr::Literal(Literal::Null(SourceSpan::default()))
311}
312
313impl ValueExpr {
314 /// Return the source span for this expression.
315 #[must_use]
316 pub const fn span(&self) -> SourceSpan {
317 match self {
318 Self::Literal(literal) => literal.span(),
319 Self::Variable { span, .. }
320 | Self::Parameter { span, .. }
321 | Self::PropertyAccess { span, .. }
322 | Self::ListLiteral { span, .. }
323 | Self::RecordLiteral { span, .. }
324 | Self::PathConstructor { span, .. }
325 | Self::BinaryOp { span, .. }
326 | Self::UnaryOp { span, .. }
327 | Self::FunctionCall { span, .. }
328 | Self::DurationBetween { span, .. }
329 | Self::IsCheck { span, .. }
330 | Self::InList { span, .. }
331 | Self::InListExpression { span, .. }
332 | Self::AllDifferent { span, .. }
333 | Self::Same { span, .. }
334 | Self::PropertyExists { span, .. }
335 | Self::Case { span, .. }
336 | Self::Exists { span, .. }
337 | Self::ValueSubquery { span, .. }
338 | Self::Normalize { span, .. }
339 | Self::Trim { span, .. }
340 | Self::Cast { span, .. } => *span,
341 }
342 }
343}
344
345/// Binary operator.
346#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
347pub enum BinaryOp {
348 /// Addition.
349 Add,
350 /// Subtraction.
351 Sub,
352 /// Multiplication.
353 Mul,
354 /// Division.
355 Div,
356 /// Remainder.
357 Mod,
358 /// Exponentiation.
359 ///
360 /// selene-db extension: ISO/IEC 39075:2024 section 20.22 uses `POWER(x, y)`;
361 /// the grammar does not emit `^` today.
362 Power,
363 /// Equality.
364 Eq,
365 /// Inequality.
366 Ne,
367 /// Less-than.
368 Lt,
369 /// Less-than-or-equal.
370 Le,
371 /// Greater-than.
372 Gt,
373 /// Greater-than-or-equal.
374 Ge,
375 /// Boolean conjunction.
376 And,
377 /// Boolean disjunction.
378 Or,
379 /// Boolean exclusive-or.
380 Xor,
381 /// String/list/bytes/path concatenation.
382 Concat,
383 /// `CONTAINS`.
384 Contains,
385 /// `STARTS WITH`.
386 StartsWith,
387 /// `ENDS WITH`.
388 EndsWith,
389}
390
391/// Unary operator.
392#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
393pub enum UnaryOp {
394 /// Numeric negation.
395 Negate,
396 /// Boolean negation.
397 Not,
398}
399
400/// `IS` predicate kind.
401#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
402#[non_exhaustive]
403pub enum IsCheckKind {
404 /// `IS NULL`.
405 Null,
406 /// `IS DIRECTED`.
407 Directed,
408 /// `IS LABELED`.
409 Labeled(LabelExpr),
410 /// `IS TRUE/FALSE/UNKNOWN`.
411 TruthValue(TruthValue),
412 /// `IS TYPED`.
413 Typed(GqlType),
414 /// `IS NORMALIZED`.
415 Normalized(NormalForm),
416 /// `IS SOURCE OF`.
417 SourceOf(Box<ValueExpr>),
418 /// `IS DESTINATION OF`.
419 DestinationOf(Box<ValueExpr>),
420}
421
422/// Three-valued boolean predicate target.
423#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
424pub enum TruthValue {
425 /// `TRUE`.
426 True,
427 /// `FALSE`.
428 False,
429 /// `UNKNOWN`.
430 Unknown,
431}
432
433/// Unicode normalization form.
434#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
435pub enum NormalForm {
436 /// NFC.
437 Nfc,
438 /// NFD.
439 Nfd,
440 /// NFKC.
441 Nfkc,
442 /// NFKD.
443 Nfkd,
444}
445
446/// Explicit TRIM direction.
447#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
448pub enum TrimSpec {
449 /// Trim leading characters.
450 Leading,
451 /// Trim trailing characters.
452 Trailing,
453 /// Trim both leading and trailing characters.
454 Both,
455}
456
457/// Literal expression.
458#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
459#[non_exhaustive]
460pub enum Literal {
461 /// Boolean literal.
462 Bool(bool, SourceSpan),
463 /// Signed 64-bit integer literal.
464 Integer(i64, SourceSpan),
465 /// Signed 64-bit integer literal written with a non-decimal radix prefix.
466 RadixInteger(i64, SourceSpan, IntegerLiteralKind),
467 /// Exact fixed-precision decimal literal.
468 Decimal(Decimal, SourceSpan, DecimalLiteralKind),
469 /// 64-bit floating-point literal.
470 Float(f64, SourceSpan, FloatLiteralKind),
471 /// Database-string literal.
472 String(DbString, SourceSpan, CharacterStringLiteralKind),
473 /// Byte-string literal.
474 Bytes(Arc<[u8]>, SourceSpan),
475 /// UUID literal.
476 Uuid(uuid::Uuid, SourceSpan, CharacterStringLiteralKind),
477 /// Zoned datetime literal.
478 ZonedDateTime(Box<jiff::Zoned>, SourceSpan, CharacterStringLiteralKind),
479 /// Local datetime literal.
480 LocalDateTime(
481 jiff::civil::DateTime,
482 SourceSpan,
483 CharacterStringLiteralKind,
484 ),
485 /// Date literal.
486 Date(jiff::civil::Date, SourceSpan, CharacterStringLiteralKind),
487 /// Zoned time literal.
488 ZonedTime(Box<jiff::Zoned>, SourceSpan, CharacterStringLiteralKind),
489 /// Local time literal.
490 LocalTime(jiff::civil::Time, SourceSpan, CharacterStringLiteralKind),
491 /// Duration literal.
492 Duration(Box<jiff::Span>, SourceSpan, CharacterStringLiteralKind),
493 /// Null literal.
494 Null(SourceSpan),
495}
496
497/// Source spelling class for an ISO character string literal.
498#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
499pub enum CharacterStringLiteralKind {
500 /// Standard character string literal with character escaping enabled.
501 Escaped,
502 /// Character string literal prefixed by `<no escape>` (`@`), disabling
503 /// backslash and doubled-delimiter character representations.
504 NoEscape,
505}
506
507/// Source spelling class for an integer literal.
508#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
509pub enum IntegerLiteralKind {
510 /// Hexadecimal literal with a `0x` prefix.
511 Hexadecimal,
512 /// Octal literal with a `0o` prefix.
513 Octal,
514 /// Binary literal with a `0b` prefix.
515 Binary,
516}
517
518/// Source spelling class for an exact decimal literal.
519#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
520pub enum DecimalLiteralKind {
521 /// Common decimal notation without an exact-number suffix.
522 CommonWithoutSuffix,
523 /// Common decimal notation or decimal integer with an exact-number suffix.
524 CommonOrIntegerWithSuffix,
525 /// Scientific decimal notation with an exact-number suffix.
526 ScientificWithSuffix,
527}
528
529/// Source spelling class for an approximate numeric literal.
530#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
531pub enum FloatLiteralKind {
532 /// Scientific decimal notation without an approximate-number suffix.
533 ScientificWithoutSuffix,
534 /// Common decimal notation or decimal integer with an `F` suffix.
535 CommonOrIntegerWithFloatSuffix,
536 /// Common decimal notation or decimal integer with a `D` suffix.
537 CommonOrIntegerWithDoubleSuffix,
538 /// Scientific decimal notation with an `F` suffix.
539 ScientificWithFloatSuffix,
540 /// Scientific decimal notation with a `D` suffix.
541 ScientificWithDoubleSuffix,
542}
543
544impl PartialEq for Literal {
545 fn eq(&self, rhs: &Self) -> bool {
546 match (self, rhs) {
547 (Self::Bool(lhs, lhs_span), Self::Bool(rhs, rhs_span)) => {
548 lhs == rhs && lhs_span == rhs_span
549 }
550 (Self::Integer(lhs, lhs_span), Self::Integer(rhs, rhs_span)) => {
551 lhs == rhs && lhs_span == rhs_span
552 }
553 (
554 Self::RadixInteger(lhs, lhs_span, lhs_kind),
555 Self::RadixInteger(rhs, rhs_span, rhs_kind),
556 ) => lhs == rhs && lhs_span == rhs_span && lhs_kind == rhs_kind,
557 (Self::Decimal(lhs, lhs_span, lhs_kind), Self::Decimal(rhs, rhs_span, rhs_kind)) => {
558 lhs == rhs && lhs_span == rhs_span && lhs_kind == rhs_kind
559 }
560 (Self::Float(lhs, lhs_span, lhs_kind), Self::Float(rhs, rhs_span, rhs_kind)) => {
561 lhs == rhs && lhs_span == rhs_span && lhs_kind == rhs_kind
562 }
563 (Self::String(lhs, lhs_span, lhs_kind), Self::String(rhs, rhs_span, rhs_kind)) => {
564 lhs == rhs && lhs_span == rhs_span && lhs_kind == rhs_kind
565 }
566 (Self::Bytes(lhs, lhs_span), Self::Bytes(rhs, rhs_span)) => {
567 lhs == rhs && lhs_span == rhs_span
568 }
569 (Self::Uuid(lhs, lhs_span, lhs_kind), Self::Uuid(rhs, rhs_span, rhs_kind)) => {
570 lhs == rhs && lhs_span == rhs_span && lhs_kind == rhs_kind
571 }
572 (
573 Self::ZonedDateTime(lhs, lhs_span, lhs_kind),
574 Self::ZonedDateTime(rhs, rhs_span, rhs_kind),
575 ) => lhs == rhs && lhs_span == rhs_span && lhs_kind == rhs_kind,
576 (
577 Self::LocalDateTime(lhs, lhs_span, lhs_kind),
578 Self::LocalDateTime(rhs, rhs_span, rhs_kind),
579 ) => lhs == rhs && lhs_span == rhs_span && lhs_kind == rhs_kind,
580 (Self::Date(lhs, lhs_span, lhs_kind), Self::Date(rhs, rhs_span, rhs_kind)) => {
581 lhs == rhs && lhs_span == rhs_span && lhs_kind == rhs_kind
582 }
583 (
584 Self::ZonedTime(lhs, lhs_span, lhs_kind),
585 Self::ZonedTime(rhs, rhs_span, rhs_kind),
586 ) => lhs == rhs && lhs_span == rhs_span && lhs_kind == rhs_kind,
587 (
588 Self::LocalTime(lhs, lhs_span, lhs_kind),
589 Self::LocalTime(rhs, rhs_span, rhs_kind),
590 ) => lhs == rhs && lhs_span == rhs_span && lhs_kind == rhs_kind,
591 (Self::Duration(lhs, lhs_span, lhs_kind), Self::Duration(rhs, rhs_span, rhs_kind)) => {
592 lhs.fieldwise() == rhs.fieldwise() && lhs_span == rhs_span && lhs_kind == rhs_kind
593 }
594 (Self::Null(lhs_span), Self::Null(rhs_span)) => lhs_span == rhs_span,
595 _ => false,
596 }
597 }
598}
599
600impl Literal {
601 /// Return the source span for this literal.
602 #[must_use]
603 pub const fn span(&self) -> SourceSpan {
604 match self {
605 Self::Bool(_, span)
606 | Self::Integer(_, span)
607 | Self::RadixInteger(_, span, _)
608 | Self::Decimal(_, span, _)
609 | Self::Float(_, span, _)
610 | Self::String(_, span, _)
611 | Self::Bytes(_, span)
612 | Self::Uuid(_, span, _)
613 | Self::ZonedDateTime(_, span, _)
614 | Self::LocalDateTime(_, span, _)
615 | Self::Date(_, span, _)
616 | Self::ZonedTime(_, span, _)
617 | Self::LocalTime(_, span, _)
618 | Self::Duration(_, span, _)
619 | Self::Null(span) => *span,
620 }
621 }
622
623 /// Return a mutable reference to this literal's source span.
624 ///
625 /// Used by [`ValueExpr::for_each_span_mut`](crate::ValueExpr::for_each_span_mut)
626 /// so span-rewriting walkers (parser span rebasing, span-erasing equality)
627 /// can reach the span stored inside the literal variant.
628 pub const fn span_mut(&mut self) -> &mut SourceSpan {
629 match self {
630 Self::Bool(_, span)
631 | Self::Integer(_, span)
632 | Self::RadixInteger(_, span, _)
633 | Self::Decimal(_, span, _)
634 | Self::Float(_, span, _)
635 | Self::String(_, span, _)
636 | Self::Bytes(_, span)
637 | Self::Uuid(_, span, _)
638 | Self::ZonedDateTime(_, span, _)
639 | Self::LocalDateTime(_, span, _)
640 | Self::Date(_, span, _)
641 | Self::ZonedTime(_, span, _)
642 | Self::LocalTime(_, span, _)
643 | Self::Duration(_, span, _)
644 | Self::Null(span) => span,
645 }
646 }
647}