Skip to main content

eventql_parser/
ast.rs

1//! Abstract syntax tree (AST) types for EventQL.
2//!
3//! This module defines the structure of parsed EventQL queries as an abstract
4//! syntax tree. The AST represents the semantic structure of a query, making it
5//! easy to analyze, transform, or execute queries.
6//!
7//! # Core Types
8//!
9//! - [`Query`] - The root of the AST, representing a complete query
10//! - [`Expr`] - Expressions with position and type information
11//! - [`Value`] - The various kinds of expression values (literals, operators, etc.)
12//! - [`Source`] - Data sources in FROM clauses
13//!
14use crate::token::{Operator, Token};
15use ordered_float::OrderedFloat;
16use serde::Serialize;
17use std::hash::{Hash, Hasher};
18
19/// Position information for source code locations.
20///
21/// This struct tracks the line and column number of tokens and AST nodes,
22/// which is useful for error reporting and debugging.
23///
24/// # Examples
25///
26/// ```
27/// use eventql_parser::Pos;
28///
29/// let pos = Pos { line: 1, col: 10 };
30/// assert_eq!(pos.line, 1);
31/// assert_eq!(pos.col, 10);
32/// ```
33#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
34pub struct Pos {
35    /// Line number (1-indexed)
36    pub line: u32,
37    /// Column number (1-indexed)
38    pub col: u32,
39}
40
41impl From<Token<'_>> for Pos {
42    fn from(value: Token<'_>) -> Self {
43        Self {
44            line: value.line,
45            col: value.col,
46        }
47    }
48}
49
50/// Attributes attached to each expression node.
51///
52/// These attributes provide metadata about an expression, including its
53/// position in the source code, scope information, and type information.
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
55pub struct Attrs {
56    /// Source position of this expression
57    pub pos: Pos,
58}
59
60impl Attrs {
61    /// Create new attributes with unspecified type.
62    pub fn new(pos: Pos) -> Self {
63        Self { pos }
64    }
65}
66
67impl<'a> From<Token<'a>> for Attrs {
68    fn from(value: Token<'a>) -> Self {
69        Self { pos: value.into() }
70    }
71}
72
73/// A reference to a string stored in the [`StringArena`](crate::arena::StringArena).
74#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
75pub struct StrRef(pub(crate) usize);
76
77/// A reference to a vector of expressions stored in the [`ExprArena`](crate::arena::ExprArena).
78#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
79pub struct VecRef(pub(crate) usize);
80
81/// A reference to a vector of record fields stored in the [`ExprArena`](crate::arena::ExprArena).
82#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
83pub struct RecRef(pub(crate) usize);
84
85/// Internal pointer to an expression in the arena.
86#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize)]
87pub struct ExprPtr(pub(crate) usize);
88
89/// Internal hash key for an expression to provide structural equality.
90#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
91pub struct ExprKey(pub(crate) u64);
92
93/// A reference to an expression stored in an [`ExprArena`](crate::arena::ExprArena).
94///
95/// This is a lightweight handle that combines a hash key for fast comparison
96/// and a pointer for fast lookup.
97#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize)]
98pub struct ExprRef {
99    pub(crate) key: ExprKey,
100    pub(crate) ptr: ExprPtr,
101}
102
103impl Hash for ExprRef {
104    fn hash<H: Hasher>(&self, state: &mut H) {
105        self.key.hash(state);
106    }
107}
108
109/// Field access expression (e.g., `e.data.price`).
110///
111/// Represents accessing a field of a record or object using dot notation.
112/// Can be chained for nested field access.
113///
114/// # Examples
115///
116/// In the query `WHERE e.data.user.id == 1`, the expression `e.data.user.id`
117/// is parsed as nested `Access` nodes.
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
119pub struct Access {
120    /// The target expression being accessed
121    pub target: ExprRef,
122    /// The name of the field being accessed
123    pub field: StrRef,
124}
125
126/// Function application (e.g., `sum(e.price)`, `count()`).
127///
128/// Represents a function call with zero or more arguments.
129///
130/// # Examples
131///
132/// In the query `WHERE count(e.items) > 5`, the `count(e.items)` is an `App` node.
133#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
134pub struct App {
135    /// Name of the function being called
136    pub func: StrRef,
137    /// Arguments passed to the function
138    pub args: VecRef,
139}
140
141/// A field in a record literal (e.g., `{name: "Alice", age: 30}`).
142///
143/// Represents a key-value pair in a record construction.
144#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
145pub struct Field {
146    /// Field attributes
147    pub attrs: Attrs,
148    /// Field name
149    pub name: StrRef,
150    /// Field value expression
151    pub expr: ExprRef,
152}
153
154/// Binary operation (e.g., `a + b`, `x == y`, `p AND q`).
155///
156/// Represents operations that take two operands, including arithmetic,
157/// comparison, and logical operators.
158///
159/// # Examples
160///
161/// In `WHERE e.price > 100 AND e.active == true`, there are multiple
162/// binary operations: `>`, `==`, and `AND`.
163#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
164pub struct Binary {
165    /// Left-hand side operand
166    pub lhs: ExprRef,
167    /// The operator
168    pub operator: Operator,
169    /// Right-hand side operand
170    pub rhs: ExprRef,
171}
172
173/// Unary operation (e.g., `-x`, `NOT active`).
174///
175/// Represents operations that take a single operand.
176///
177/// # Examples
178///
179/// In `WHERE NOT e.deleted`, the `NOT e.deleted` is a unary operation.
180#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
181pub struct Unary {
182    /// The operator (Add for +, Sub for -, Not for NOT)
183    pub operator: Operator,
184    /// The operand expression
185    pub expr: ExprRef,
186}
187
188/// The kind of value an expression represents.
189///
190/// This enum contains all the different types of expressions that can appear
191/// in an EventQL query, from simple literals to complex operations.
192#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
193pub enum Value {
194    /// Numeric literal (e.g., `42`, `3.14`)
195    Number(OrderedFloat<f64>),
196    /// String literal (e.g., `"hello"`)
197    String(StrRef),
198    /// Boolean literal (`true` or `false`)
199    Bool(bool),
200    /// Identifier (e.g., variable name `e`, `x`)
201    Id(StrRef),
202    /// Array literal (e.g., `[1, 2, 3]`)
203    Array(VecRef),
204    /// Record literal (e.g., `{name: "Alice", age: 30}`)
205    Record(RecRef),
206    /// Field access (e.g., `e.data.price`)
207    Access(Access),
208    /// Function application (e.g., `sum(e.price)`)
209    App(App),
210    /// Binary operation (e.g., `a + b`, `x == y`)
211    Binary(Binary),
212    /// Unary operation (e.g., `-x`, `NOT active`)
213    Unary(Unary),
214    /// Grouped/parenthesized expression (e.g., `(a + b)`)
215    Group(ExprRef),
216}
217
218/// A source binding. A name attached to a source of events.
219///
220/// # Examples
221/// in `FROM e IN events`, `e` is the binding.
222#[derive(Debug, Clone, Copy, Serialize)]
223pub struct Binding {
224    /// Name attached to a source of events
225    pub name: StrRef,
226    /// Position in the source code where that binding was introduced
227    pub pos: Pos,
228}
229
230/// A data source in a FROM clause.
231///
232/// Sources specify where data comes from in a query. Each source has a binding
233/// (the variable name) and a kind (what it binds to).
234///
235/// # Examples
236///
237/// In `FROM e IN events`, the source has:
238/// - `binding`: `"e"`
239/// - `kind`: `SourceKind::Name("events")`
240#[derive(Debug, Clone, Serialize)]
241pub struct Source<A> {
242    /// Variable name bound to this source
243    pub binding: Binding,
244    /// What this source represents
245    pub kind: SourceKind<A>,
246}
247
248/// The kind of data source.
249///
250/// EventQL supports three types of sources:
251/// - Named sources (e.g., `FROM e IN events`)
252/// - Subject patterns (e.g., `FROM e IN "users/john"`)
253/// - Subqueries (e.g., `FROM e IN (SELECT ...)`)
254#[derive(Debug, Clone, Serialize)]
255pub enum SourceKind<A> {
256    /// Named source (identifier)
257    Name(StrRef),
258    /// Subject pattern (string literal used as event subject pattern)
259    Subject(StrRef),
260    /// Nested subquery
261    Subquery(Box<Query<A>>),
262}
263
264/// ORDER BY clause specification.
265///
266/// Defines how query results should be sorted.
267///
268/// # Examples
269///
270/// In `ORDER BY e.timestamp DESC`, this would be represented as:
271/// - `expr`: expression for `e.timestamp`
272/// - `order`: `Order::Desc`
273#[derive(Debug, Clone, Copy, Serialize)]
274pub struct OrderBy {
275    /// Expression to sort by
276    pub expr: ExprRef,
277    /// Sort direction (ascending or descending)
278    pub order: Order,
279}
280
281/// Sort order direction.
282///
283/// Specifies whether sorting is ascending or descending.
284#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
285pub enum Order {
286    /// Ascending order (smallest to largest)
287    Asc,
288    /// Descending order (largest to smallest)
289    Desc,
290}
291
292/// GROUP BY clause specification
293///
294/// Defines how query results should be order by.
295/// # Examples
296///
297/// In `GROUP BY e.age HAVING age > 123`, this would be represented as:
298/// - `expr`: expression for `e.age`
299/// - `predicate`: `age > 123`
300#[derive(Debug, Clone, Serialize)]
301pub struct GroupBy {
302    /// Expression to group by
303    pub expr: ExprRef,
304
305    /// Predicate to filter groups after aggregation
306    pub predicate: Option<ExprRef>,
307}
308
309/// Result set limit specification.
310///
311/// EventQL supports two types of limits:
312/// - `TOP n` - Take the first n results
313/// - `SKIP n` - Skip the first n results
314///
315/// # Examples
316///
317/// - `TOP 10` limits to first 10 results
318/// - `SKIP 20` skips first 20 results
319#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
320pub enum Limit {
321    /// Skip the first n results
322    Skip(u64),
323    /// Take only the first n results
324    Top(u64),
325}
326
327/// Represents the state of a query that only has a valid syntax. There are no guarantee that all
328/// the variables exists or that the query is sound. For example, if the user is asking for an event
329/// that has field that should be a string or a number at the same time.
330#[derive(Debug, Clone, Copy, Serialize)]
331pub struct Raw;
332
333/// A complete EventQL query.
334///
335/// This is the root node of the AST, representing a full query with all its clauses.
336/// A query must have at least one source and a projection; other clauses are optional.
337///
338/// # Structure
339///
340/// ```text
341/// FROM <alias> <source>
342/// [FROM <alias> <source>] ...
343/// [WHERE <condition>]
344/// [GROUP BY <field> [HAVING <condition>]]
345/// [ORDER BY <field> ASC|DESC]
346/// [TOP|SKIP <n>]
347/// PROJECT INTO [DISTINCT] <projection>
348/// ```
349///
350/// # Examples
351///
352/// ```
353/// use eventql_parser::Session;
354///
355/// let mut session = Session::builder().use_stdlib().build();
356/// let query = session.parse(
357///     "FROM e IN events \
358///      WHERE e.price > 100 \
359///      ORDER BY e.timestamp DESC \
360///      TOP 10 \
361///      PROJECT INTO {id: e.id, price: e.price}"
362/// ).unwrap();
363///
364/// assert_eq!(query.sources.len(), 1);
365/// assert!(query.predicate.is_some());
366/// assert!(query.order_by.is_some());
367/// assert!(query.limit.is_some());
368/// ```
369#[derive(Debug, Clone, Serialize)]
370pub struct Query<A> {
371    /// Metadata about this query
372    pub attrs: Attrs,
373    /// FROM clause sources (must have at least one)
374    pub sources: Vec<Source<A>>,
375    /// Optional WHERE clause filter predicate
376    pub predicate: Option<ExprRef>,
377    /// Optional GROUP BY clause expression
378    pub group_by: Option<GroupBy>,
379    /// Optional ORDER BY clause
380    pub order_by: Option<OrderBy>,
381    /// Optional LIMIT clause (TOP or SKIP)
382    pub limit: Option<Limit>,
383    /// PROJECT INTO clause expression (required)
384    pub projection: ExprRef,
385    /// Remove duplicate rows from the query's results
386    pub distinct: bool,
387    /// Type-level metadata about the query's analysis state.
388    ///
389    /// This field uses a generic type parameter to track whether the query
390    /// is in a raw (unparsed/untyped) state or has been statically analyzed:
391    /// - `Query<Raw>`: Query parsed but not yet type-checked
392    /// - `Query<Typed>`: Query that has passed static analysis with validated
393    ///   types and variable scopes
394    ///
395    /// This provides compile-time guarantees about the query's type safety.
396    pub meta: A,
397}