Skip to main content

lora_ast/
ast.rs

1use smallvec::SmallVec;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
4pub struct Span {
5    pub start: usize,
6    pub end: usize,
7}
8
9impl Span {
10    #[must_use]
11    pub const fn new(start: usize, end: usize) -> Self {
12        Self { start, end }
13    }
14}
15
16#[derive(Debug, Clone)]
17pub struct Document {
18    pub statement: Statement,
19    pub span: Span,
20}
21
22#[derive(Debug, Clone)]
23pub enum Statement {
24    Query(Query),
25    Schema(SchemaCommand),
26}
27
28#[derive(Debug, Clone)]
29pub enum SchemaCommand {
30    CreateIndex(CreateIndex),
31    DropIndex(DropIndex),
32    ShowIndexes(ShowIndexes),
33    CreateConstraint(CreateConstraint),
34    DropConstraint(DropConstraint),
35    ShowConstraints(ShowConstraints),
36}
37
38#[derive(Debug, Clone)]
39pub struct CreateConstraint {
40    pub name: ConstraintNameSpec,
41    pub if_not_exists: bool,
42    pub entity: IndexEntityKind,
43    /// Pattern variable in the `FOR` clause (`n`, `r`).
44    pub variable: String,
45    /// Label / rel-type. Always present — constraints don't accept the
46    /// wildcard form that LOOKUP indexes do.
47    pub label: String,
48    pub properties: Vec<String>,
49    pub kind: ConstraintKind,
50    pub span: Span,
51}
52
53#[derive(Debug, Clone)]
54pub struct DropConstraint {
55    pub name: ConstraintNameSpec,
56    pub if_exists: bool,
57    pub span: Span,
58}
59
60#[derive(Debug, Clone)]
61pub struct ShowConstraints {
62    pub pipeline: Option<ShowPipeline>,
63    pub span: Span,
64}
65
66/// `SHOW INDEXES YIELD … [WHERE …] [RETURN …]` tail. Modelled after
67/// Cypher-style catalog syntax: YIELD is the anchor, optional WHERE filters the
68/// yielded rows, optional RETURN reprojects them. ORDER BY / SKIP /
69/// LIMIT can appear on either YIELD or RETURN — semantically applied
70/// to the rows at that stage.
71#[derive(Debug, Clone)]
72pub struct ShowPipeline {
73    pub yield_part: ShowYield,
74    pub where_: Option<Expr>,
75    pub return_part: Option<ShowReturn>,
76    pub span: Span,
77}
78
79#[derive(Debug, Clone)]
80pub struct ShowYield {
81    /// `YIELD *` — pass every catalog column through unchanged.
82    pub star: bool,
83    /// `YIELD a, b AS x` items (empty when `star` is true).
84    pub items: Vec<YieldItem>,
85    pub order: Vec<SortItem>,
86    pub skip: Option<Expr>,
87    pub limit: Option<Expr>,
88    pub span: Span,
89}
90
91#[derive(Debug, Clone)]
92pub struct ShowReturn {
93    pub items: Vec<ProjectionItem>,
94    pub order: Vec<SortItem>,
95    pub skip: Option<Expr>,
96    pub limit: Option<Expr>,
97    pub span: Span,
98}
99
100/// Type filter for `SHOW [TYPE] INDEXES`. `All` is the explicit
101/// unfiltered form; `Fulltext` and `Vector` parse but yield no rows
102/// because those index types aren't backed by anything in the catalog
103/// yet.
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub enum IndexKindFilter {
106    All,
107    Range,
108    Text,
109    Point,
110    Lookup,
111    Fulltext,
112    Vector,
113}
114
115#[derive(Debug, Clone)]
116pub enum ConstraintNameSpec {
117    Literal(String),
118    Parameter(String),
119}
120
121#[derive(Debug, Clone, PartialEq)]
122pub enum ConstraintKind {
123    /// `IS UNIQUE` — single or composite.
124    Unique,
125    /// `IS NOT NULL` — single property only.
126    Existence,
127    /// `IS NODE KEY` — single or composite, node only.
128    NodeKey,
129    /// `IS RELATIONSHIP KEY` — single or composite, relationship only.
130    RelationshipKey,
131    /// `IS :: Type` — single property only.
132    PropertyType(PropertyTypeExpr),
133}
134
135impl ConstraintKind {
136    /// Human-readable tag for SHOW CONSTRAINTS and diagnostics.
137    #[must_use]
138    pub fn type_tag(&self, entity: IndexEntityKind) -> &'static str {
139        match (self, entity) {
140            (ConstraintKind::Unique, IndexEntityKind::Node) => "NODE_PROPERTY_UNIQUENESS",
141            (ConstraintKind::Unique, IndexEntityKind::Relationship) => {
142                "RELATIONSHIP_PROPERTY_UNIQUENESS"
143            }
144            (ConstraintKind::Existence, IndexEntityKind::Node) => "NODE_PROPERTY_EXISTENCE",
145            (ConstraintKind::Existence, IndexEntityKind::Relationship) => {
146                "RELATIONSHIP_PROPERTY_EXISTENCE"
147            }
148            (ConstraintKind::NodeKey, _) => "NODE_KEY",
149            (ConstraintKind::RelationshipKey, _) => "RELATIONSHIP_KEY",
150            (ConstraintKind::PropertyType(_), IndexEntityKind::Node) => "NODE_PROPERTY_TYPE",
151            (ConstraintKind::PropertyType(_), IndexEntityKind::Relationship) => {
152                "RELATIONSHIP_PROPERTY_TYPE"
153            }
154        }
155    }
156}
157
158/// A closed dynamic union of property types: `T1 | T2 | ...`. A single
159/// type is represented as a one-element union.
160#[derive(Debug, Clone, PartialEq)]
161pub struct PropertyTypeExpr {
162    pub alternatives: Vec<PropertyTypeTerm>,
163}
164
165#[derive(Debug, Clone, PartialEq)]
166pub enum PropertyTypeTerm {
167    Scalar(ScalarType),
168    List {
169        inner: Box<PropertyTypeTerm>,
170        /// `LIST<X NOT NULL>` is the only fully-supported list shape in
171        /// Cypher compatibility mode; we keep the flag for grammar fidelity
172        /// even though we reject `LIST<X>` (nullable elements) at the
173        /// catalog layer.
174        not_null: bool,
175    },
176    Vector {
177        coord: VectorCoordType,
178        dimension: u32,
179    },
180}
181
182#[derive(Debug, Clone, Copy, PartialEq, Eq)]
183pub enum ScalarType {
184    Boolean,
185    String,
186    Integer,
187    Float,
188    Date,
189    LocalTime,
190    ZonedTime,
191    LocalDateTime,
192    ZonedDateTime,
193    Duration,
194    Point,
195    Map,
196    Any,
197}
198
199impl ScalarType {
200    #[must_use]
201    pub const fn as_str(self) -> &'static str {
202        match self {
203            ScalarType::Boolean => "BOOLEAN",
204            ScalarType::String => "STRING",
205            ScalarType::Integer => "INTEGER",
206            ScalarType::Float => "FLOAT",
207            ScalarType::Date => "DATE",
208            ScalarType::LocalTime => "LOCAL TIME",
209            ScalarType::ZonedTime => "ZONED TIME",
210            ScalarType::LocalDateTime => "LOCAL DATETIME",
211            ScalarType::ZonedDateTime => "ZONED DATETIME",
212            ScalarType::Duration => "DURATION",
213            ScalarType::Point => "POINT",
214            ScalarType::Map => "MAP",
215            ScalarType::Any => "ANY",
216        }
217    }
218}
219
220#[derive(Debug, Clone, Copy, PartialEq, Eq)]
221pub enum VectorCoordType {
222    Int8,
223    Int16,
224    Int32,
225    Int64,
226    Float32,
227    Float64,
228}
229
230impl VectorCoordType {
231    #[must_use]
232    pub const fn as_str(self) -> &'static str {
233        match self {
234            VectorCoordType::Int8 => "INT8",
235            VectorCoordType::Int16 => "INT16",
236            VectorCoordType::Int32 => "INT32",
237            VectorCoordType::Int64 => "INT64",
238            VectorCoordType::Float32 => "FLOAT32",
239            VectorCoordType::Float64 => "FLOAT64",
240        }
241    }
242}
243
244#[derive(Debug, Clone)]
245pub struct DropIndex {
246    pub name: IndexNameSpec,
247    pub if_exists: bool,
248    pub span: Span,
249}
250
251#[derive(Debug, Clone)]
252pub struct CreateIndex {
253    pub kind: IndexKind,
254    pub name: Option<IndexNameSpec>,
255    pub if_not_exists: bool,
256    pub entity: IndexEntityKind,
257    /// Pattern variable in the FOR clause (`n` for `(n:Person)`, `r` for `()-[r:KNOWS]-()`).
258    pub variable: String,
259    /// `Some(label_or_type)` for property indexes; `None` for `LOOKUP` token indexes
260    /// where the label/type is the wildcard captured by `labels(n)` / `type(r)`.
261    /// For `FULLTEXT` (which accepts `:A|B|C`) this carries the first label; the
262    /// rest live in `additional_labels`.
263    pub label: Option<String>,
264    /// Extra labels beyond `label`. Only populated for `FULLTEXT` indexes
265    /// declared with the `(n:A|B|C)` pattern.
266    pub additional_labels: Vec<String>,
267    /// Property keys covered by the index. Empty for `LOOKUP` token indexes.
268    pub properties: Vec<String>,
269    pub options: Option<IndexOptions>,
270    pub span: Span,
271}
272
273#[derive(Debug, Clone, Copy, PartialEq, Eq)]
274pub enum IndexKind {
275    Range,
276    Text,
277    Point,
278    Lookup,
279    Vector,
280    Fulltext,
281}
282
283impl IndexKind {
284    #[must_use]
285    pub const fn as_str(self) -> &'static str {
286        match self {
287            IndexKind::Range => "RANGE",
288            IndexKind::Text => "TEXT",
289            IndexKind::Point => "POINT",
290            IndexKind::Lookup => "LOOKUP",
291            IndexKind::Vector => "VECTOR",
292            IndexKind::Fulltext => "FULLTEXT",
293        }
294    }
295}
296
297#[derive(Debug, Clone, Copy, PartialEq, Eq)]
298pub enum IndexEntityKind {
299    Node,
300    Relationship,
301}
302
303impl IndexEntityKind {
304    #[must_use]
305    pub const fn as_str(self) -> &'static str {
306        match self {
307            IndexEntityKind::Node => "NODE",
308            IndexEntityKind::Relationship => "RELATIONSHIP",
309        }
310    }
311}
312
313#[derive(Debug, Clone)]
314pub enum IndexNameSpec {
315    Literal(String),
316    Parameter(String),
317}
318
319#[derive(Debug, Clone)]
320pub struct IndexOptions {
321    pub config: Vec<(String, Expr)>,
322    pub span: Span,
323}
324
325#[derive(Debug, Clone)]
326pub struct ShowIndexes {
327    /// Optional index-type filter (e.g. `SHOW RANGE INDEXES`). `None`
328    /// means no filter clause was written; `Some(IndexKindFilter::All)`
329    /// is the explicit `SHOW ALL INDEXES` form (semantically the same).
330    pub filter: Option<IndexKindFilter>,
331    pub pipeline: Option<ShowPipeline>,
332    pub span: Span,
333}
334
335#[derive(Debug, Clone)]
336pub enum Query {
337    Regular(RegularQuery),
338    StandaloneCall(StandaloneCall),
339}
340
341#[derive(Debug, Clone)]
342pub struct RegularQuery {
343    pub head: SingleQuery,
344    pub unions: Vec<UnionPart>,
345    pub span: Span,
346}
347
348#[derive(Debug, Clone)]
349pub struct UnionPart {
350    pub all: bool,
351    pub query: SingleQuery,
352    pub span: Span,
353}
354
355#[derive(Debug, Clone)]
356pub enum SingleQuery {
357    SinglePart(SinglePartQuery),
358    MultiPart(MultiPartQuery),
359}
360
361#[derive(Debug, Clone)]
362pub struct SinglePartQuery {
363    pub reading_clauses: Vec<ReadingClause>,
364    pub updating_clauses: Vec<UpdatingClause>,
365    pub return_clause: Option<Return>,
366    pub span: Span,
367}
368
369#[derive(Debug, Clone)]
370pub struct MultiPartQuery {
371    pub parts: Vec<QueryPart>,
372    pub tail: Box<SinglePartQuery>,
373    pub span: Span,
374}
375
376#[derive(Debug, Clone)]
377pub struct QueryPart {
378    pub reading_clauses: Vec<ReadingClause>,
379    pub updating_clauses: Vec<UpdatingClause>,
380    pub with_clause: With,
381    pub span: Span,
382}
383
384#[derive(Debug, Clone)]
385pub enum ReadingClause {
386    Match(Match),
387    Unwind(Unwind),
388    InQueryCall(InQueryCall),
389    CallSubquery(CallSubquery),
390}
391
392#[derive(Debug, Clone)]
393pub struct CallSubquery {
394    pub body: Box<RegularQuery>,
395    pub span: Span,
396}
397
398#[derive(Debug, Clone)]
399pub enum UpdatingClause {
400    Create(Create),
401    Merge(Merge),
402    Delete(Delete),
403    Set(Set),
404    Remove(Remove),
405    Foreach(Foreach),
406}
407
408#[derive(Debug, Clone)]
409pub struct Match {
410    pub optional: bool,
411    pub pattern: Pattern,
412    pub where_: Option<Expr>,
413    pub span: Span,
414}
415
416#[derive(Debug, Clone)]
417pub struct Unwind {
418    pub expr: Expr,
419    pub alias: Variable,
420    pub span: Span,
421}
422
423#[derive(Debug, Clone)]
424pub struct Create {
425    pub pattern: Pattern,
426    pub span: Span,
427}
428
429#[derive(Debug, Clone)]
430pub struct Merge {
431    pub pattern_part: PatternPart,
432    pub actions: Vec<MergeAction>,
433    pub span: Span,
434}
435
436#[derive(Debug, Clone)]
437pub struct MergeAction {
438    pub on_match: bool,
439    pub set: Set,
440    pub span: Span,
441}
442
443#[derive(Debug, Clone)]
444pub struct Delete {
445    pub detach: bool,
446    pub expressions: Vec<Expr>,
447    pub span: Span,
448}
449
450#[derive(Debug, Clone)]
451pub struct Set {
452    pub items: Vec<SetItem>,
453    pub span: Span,
454}
455
456#[derive(Debug, Clone)]
457pub enum SetItem {
458    SetProperty {
459        target: Expr,
460        value: Expr,
461        span: Span,
462    },
463    SetVariable {
464        variable: Variable,
465        value: Expr,
466        span: Span,
467    },
468    MutateVariable {
469        variable: Variable,
470        value: Expr,
471        span: Span,
472    },
473    SetLabels {
474        variable: Variable,
475        labels: Vec<String>,
476        span: Span,
477    },
478}
479
480#[derive(Debug, Clone)]
481pub struct Remove {
482    pub items: Vec<RemoveItem>,
483    pub span: Span,
484}
485
486/// `FOREACH (var IN list | body...)` — runs each body updating clause
487/// once per element in `list`, with `var` bound to the element. The
488/// body itself contains only updating clauses (CREATE / MERGE / DELETE
489/// / SET / REMOVE / nested FOREACH).
490#[derive(Debug, Clone)]
491pub struct Foreach {
492    pub variable: Variable,
493    pub list: Expr,
494    pub body: Vec<UpdatingClause>,
495    pub span: Span,
496}
497
498#[derive(Debug, Clone)]
499pub enum RemoveItem {
500    Labels {
501        variable: Variable,
502        labels: Vec<String>,
503        span: Span,
504    },
505    Property {
506        expr: Expr,
507        span: Span,
508    },
509}
510
511#[derive(Debug, Clone)]
512pub struct InQueryCall {
513    pub procedure: ProcedureInvocation,
514    pub yield_items: Vec<YieldItem>,
515    pub where_: Option<Expr>,
516    pub span: Span,
517}
518
519#[derive(Debug, Clone)]
520pub struct StandaloneCall {
521    pub procedure: ProcedureInvocationKind,
522    pub yield_items: Vec<YieldItem>,
523    pub yield_all: bool,
524    pub span: Span,
525}
526
527#[derive(Debug, Clone)]
528pub enum ProcedureInvocationKind {
529    Explicit(ProcedureInvocation),
530    Implicit(ProcedureName),
531}
532
533#[derive(Debug, Clone)]
534pub struct ProcedureInvocation {
535    pub name: ProcedureName,
536    pub args: Vec<Expr>,
537    pub span: Span,
538}
539
540#[derive(Debug, Clone)]
541pub struct YieldItem {
542    pub field: Option<String>,
543    pub alias: Variable,
544    pub span: Span,
545}
546
547#[derive(Debug, Clone)]
548pub struct With {
549    pub body: ProjectionBody,
550    pub where_: Option<Expr>,
551    pub span: Span,
552}
553
554#[derive(Debug, Clone)]
555pub struct Return {
556    pub body: ProjectionBody,
557    pub span: Span,
558}
559
560#[derive(Debug, Clone)]
561pub struct ProjectionBody {
562    pub distinct: bool,
563    pub items: Vec<ProjectionItem>,
564    pub order: Vec<SortItem>,
565    pub skip: Option<Expr>,
566    pub limit: Option<Expr>,
567    pub span: Span,
568}
569
570#[derive(Debug, Clone)]
571pub enum ProjectionItem {
572    Expr {
573        expr: Expr,
574        alias: Option<Variable>,
575        span: Span,
576    },
577    Star {
578        span: Span,
579    },
580}
581
582#[derive(Debug, Clone)]
583pub struct SortItem {
584    pub expr: Expr,
585    pub direction: SortDirection,
586    pub span: Span,
587}
588
589#[derive(Debug, Clone, Copy, PartialEq, Eq)]
590pub enum SortDirection {
591    Asc,
592    Desc,
593}
594
595#[derive(Debug, Clone)]
596pub struct Pattern {
597    pub parts: Vec<PatternPart>,
598    pub span: Span,
599}
600
601#[derive(Debug, Clone)]
602pub struct PatternPart {
603    pub binding: Option<Variable>,
604    pub element: PatternElement,
605    pub span: Span,
606}
607
608#[derive(Debug, Clone)]
609pub enum PatternElement {
610    NodeChain {
611        head: NodePattern,
612        chain: Vec<PatternElementChain>,
613        span: Span,
614    },
615    Parenthesized(Box<PatternElement>, Span),
616    ShortestPath {
617        all: bool,
618        element: Box<PatternElement>,
619        span: Span,
620    },
621}
622
623#[derive(Debug, Clone)]
624pub struct PatternElementChain {
625    pub relationship: RelationshipPattern,
626    pub node: NodePattern,
627    pub span: Span,
628}
629
630#[derive(Debug, Clone)]
631pub struct NodePattern {
632    pub variable: Option<Variable>,
633    /// Each inner `Vec` is a disjunctive group (OR).
634    /// The outer `SmallVec` is conjunctive (AND across groups).
635    /// `:A:B` → `[[A], [B]]`;  `:A|B` → `[[A, B]]`.
636    pub labels: SmallVec<SmallVec<String, 2>, 2>,
637    pub properties: Option<Expr>,
638    pub span: Span,
639}
640
641#[derive(Debug, Clone)]
642pub struct RelationshipPattern {
643    pub direction: Direction,
644    pub detail: Option<RelationshipDetail>,
645    pub span: Span,
646}
647
648#[derive(Debug, Clone)]
649pub struct RelationshipDetail {
650    pub variable: Option<Variable>,
651    pub types: SmallVec<String, 2>,
652    pub range: Option<RangeLiteral>,
653    pub properties: Option<Expr>,
654    pub span: Span,
655}
656
657#[derive(Debug, Clone, Copy, PartialEq, Eq)]
658pub enum Direction {
659    Left,
660    Right,
661    Undirected,
662}
663
664#[derive(Debug, Clone)]
665pub struct RangeLiteral {
666    pub start: Option<u64>,
667    pub end: Option<u64>,
668    pub span: Span,
669}
670
671#[derive(Debug, Clone)]
672pub struct Variable {
673    pub name: String,
674    pub span: Span,
675}
676
677#[derive(Debug, Clone)]
678pub struct ProcedureName {
679    pub parts: Vec<String>,
680    pub span: Span,
681}
682
683#[derive(Debug, Clone)]
684pub enum Expr {
685    Variable(Variable),
686    Integer(i64, Span),
687    Float(f64, Span),
688    String(String, Span),
689    Bool(bool, Span),
690    Null(Span),
691    Parameter(String, Span),
692    List(Vec<Expr>, Span),
693    Map(Vec<(String, Expr)>, Span),
694    Property {
695        expr: Box<Expr>,
696        key: String,
697        span: Span,
698    },
699    Binary {
700        lhs: Box<Expr>,
701        op: BinaryOp,
702        rhs: Box<Expr>,
703        span: Span,
704    },
705    Unary {
706        op: UnaryOp,
707        expr: Box<Expr>,
708        span: Span,
709    },
710    FunctionCall {
711        name: Vec<String>,
712        distinct: bool,
713        args: Vec<Expr>,
714        span: Span,
715    },
716    TypeCast {
717        expr: Box<Expr>,
718        target: LiteralTypeExpr,
719        try_cast: bool,
720        span: Span,
721    },
722    Case {
723        input: Option<Box<Expr>>,
724        alternatives: Vec<(Expr, Expr)>,
725        else_expr: Option<Box<Expr>>,
726        span: Span,
727    },
728    ListPredicate {
729        kind: ListPredicateKind,
730        variable: Variable,
731        list: Box<Expr>,
732        predicate: Box<Expr>,
733        span: Span,
734    },
735    ListComprehension {
736        variable: Variable,
737        list: Box<Expr>,
738        filter: Option<Box<Expr>>,
739        map_expr: Option<Box<Expr>>,
740        span: Span,
741    },
742    Reduce {
743        accumulator: Variable,
744        init: Box<Expr>,
745        variable: Variable,
746        list: Box<Expr>,
747        expr: Box<Expr>,
748        span: Span,
749    },
750    MapProjection {
751        base: Box<Expr>,
752        selectors: Vec<MapProjectionSelector>,
753        span: Span,
754    },
755    Index {
756        expr: Box<Expr>,
757        index: Box<Expr>,
758        span: Span,
759    },
760    Slice {
761        expr: Box<Expr>,
762        from: Option<Box<Expr>>,
763        to: Option<Box<Expr>>,
764        span: Span,
765    },
766    ExistsSubquery {
767        pattern: Pattern,
768        where_: Option<Box<Expr>>,
769        span: Span,
770    },
771    PatternComprehension {
772        pattern: Box<PatternElement>,
773        where_: Option<Box<Expr>>,
774        map_expr: Box<Expr>,
775        span: Span,
776    },
777}
778
779#[derive(Debug, Clone, PartialEq)]
780pub enum LiteralTypeExpr {
781    Named {
782        name: String,
783        span: Span,
784    },
785    List {
786        inner: Box<LiteralTypeExpr>,
787        span: Span,
788    },
789    Vector {
790        coordinate: String,
791        dimension: u32,
792        span: Span,
793    },
794}
795
796impl LiteralTypeExpr {
797    #[must_use]
798    pub fn span(&self) -> Span {
799        match self {
800            LiteralTypeExpr::Named { span, .. }
801            | LiteralTypeExpr::List { span, .. }
802            | LiteralTypeExpr::Vector { span, .. } => *span,
803        }
804    }
805}
806
807#[derive(Debug, Clone)]
808pub enum MapProjectionSelector {
809    /// `.propertyName` — include a specific property
810    Property(String),
811    /// `.*` — include all properties
812    AllProperties,
813    /// `key: expr` — include a computed entry
814    Literal(String, Expr),
815}
816
817#[derive(Debug, Clone, Copy, PartialEq, Eq)]
818pub enum ListPredicateKind {
819    Any,
820    All,
821    None,
822    Single,
823}
824
825impl Expr {
826    #[must_use]
827    pub fn span(&self) -> Span {
828        match self {
829            Expr::Variable(v) => v.span,
830            Expr::Integer(_, s)
831            | Expr::Float(_, s)
832            | Expr::String(_, s)
833            | Expr::Bool(_, s)
834            | Expr::Null(s)
835            | Expr::Parameter(_, s)
836            | Expr::List(_, s)
837            | Expr::Map(_, s)
838            | Expr::Property { span: s, .. }
839            | Expr::Binary { span: s, .. }
840            | Expr::Unary { span: s, .. }
841            | Expr::FunctionCall { span: s, .. }
842            | Expr::TypeCast { span: s, .. }
843            | Expr::Case { span: s, .. }
844            | Expr::ListPredicate { span: s, .. }
845            | Expr::ListComprehension { span: s, .. }
846            | Expr::Reduce { span: s, .. }
847            | Expr::MapProjection { span: s, .. }
848            | Expr::Index { span: s, .. }
849            | Expr::Slice { span: s, .. }
850            | Expr::ExistsSubquery { span: s, .. }
851            | Expr::PatternComprehension { span: s, .. } => *s,
852        }
853    }
854}
855
856#[derive(Debug, Clone, Copy, PartialEq, Eq)]
857pub enum BinaryOp {
858    Or,
859    Xor,
860    And,
861    Eq,
862    Ne,
863    Lt,
864    Gt,
865    Le,
866    Ge,
867    Add,
868    Sub,
869    Mul,
870    Div,
871    Mod,
872    Pow,
873    In,
874    StartsWith,
875    EndsWith,
876    Contains,
877    IsNull,
878    IsNotNull,
879    RegexMatch,
880}
881
882#[derive(Debug, Clone, Copy, PartialEq, Eq)]
883pub enum UnaryOp {
884    Not,
885    Pos,
886    Neg,
887}