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}