-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathast.rs
More file actions
397 lines (369 loc) · 11.9 KB
/
ast.rs
File metadata and controls
397 lines (369 loc) · 11.9 KB
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
//! Abstract syntax tree (AST) types for EventQL.
//!
//! This module defines the structure of parsed EventQL queries as an abstract
//! syntax tree. The AST represents the semantic structure of a query, making it
//! easy to analyze, transform, or execute queries.
//!
//! # Core Types
//!
//! - [`Query`] - The root of the AST, representing a complete query
//! - [`Expr`] - Expressions with position and type information
//! - [`Value`] - The various kinds of expression values (literals, operators, etc.)
//! - [`Source`] - Data sources in FROM clauses
//!
use crate::token::{Operator, Token};
use ordered_float::OrderedFloat;
use serde::Serialize;
use std::hash::{Hash, Hasher};
/// Position information for source code locations.
///
/// This struct tracks the line and column number of tokens and AST nodes,
/// which is useful for error reporting and debugging.
///
/// # Examples
///
/// ```
/// use eventql_parser::Pos;
///
/// let pos = Pos { line: 1, col: 10 };
/// assert_eq!(pos.line, 1);
/// assert_eq!(pos.col, 10);
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub struct Pos {
/// Line number (1-indexed)
pub line: u32,
/// Column number (1-indexed)
pub col: u32,
}
impl From<Token<'_>> for Pos {
fn from(value: Token<'_>) -> Self {
Self {
line: value.line,
col: value.col,
}
}
}
/// Attributes attached to each expression node.
///
/// These attributes provide metadata about an expression, including its
/// position in the source code, scope information, and type information.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
pub struct Attrs {
/// Source position of this expression
pub pos: Pos,
}
impl Attrs {
/// Create new attributes with unspecified type.
pub fn new(pos: Pos) -> Self {
Self { pos }
}
}
impl<'a> From<Token<'a>> for Attrs {
fn from(value: Token<'a>) -> Self {
Self { pos: value.into() }
}
}
/// A reference to a string stored in the [`StringArena`](crate::arena::StringArena).
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
pub struct StrRef(pub(crate) usize);
/// A reference to a vector of expressions stored in the [`ExprArena`](crate::arena::ExprArena).
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
pub struct VecRef(pub(crate) usize);
/// A reference to a vector of record fields stored in the [`ExprArena`](crate::arena::ExprArena).
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
pub struct RecRef(pub(crate) usize);
/// Internal pointer to an expression in the arena.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize)]
pub struct ExprPtr(pub(crate) usize);
/// Internal hash key for an expression to provide structural equality.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
pub struct ExprKey(pub(crate) u64);
/// A reference to an expression stored in an [`ExprArena`](crate::arena::ExprArena).
///
/// This is a lightweight handle that combines a hash key for fast comparison
/// and a pointer for fast lookup.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize)]
pub struct ExprRef {
pub(crate) key: ExprKey,
pub(crate) ptr: ExprPtr,
}
impl Hash for ExprRef {
fn hash<H: Hasher>(&self, state: &mut H) {
self.key.hash(state);
}
}
/// Field access expression (e.g., `e.data.price`).
///
/// Represents accessing a field of a record or object using dot notation.
/// Can be chained for nested field access.
///
/// # Examples
///
/// In the query `WHERE e.data.user.id == 1`, the expression `e.data.user.id`
/// is parsed as nested `Access` nodes.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
pub struct Access {
/// The target expression being accessed
pub target: ExprRef,
/// The name of the field being accessed
pub field: StrRef,
}
/// Function application (e.g., `sum(e.price)`, `count()`).
///
/// Represents a function call with zero or more arguments.
///
/// # Examples
///
/// In the query `WHERE count(e.items) > 5`, the `count(e.items)` is an `App` node.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
pub struct App {
/// Name of the function being called
pub func: StrRef,
/// Arguments passed to the function
pub args: VecRef,
}
/// A field in a record literal (e.g., `{name: "Alice", age: 30}`).
///
/// Represents a key-value pair in a record construction.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
pub struct Field {
/// Field attributes
pub attrs: Attrs,
/// Field name
pub name: StrRef,
/// Field value expression
pub expr: ExprRef,
}
/// Binary operation (e.g., `a + b`, `x == y`, `p AND q`).
///
/// Represents operations that take two operands, including arithmetic,
/// comparison, and logical operators.
///
/// # Examples
///
/// In `WHERE e.price > 100 AND e.active == true`, there are multiple
/// binary operations: `>`, `==`, and `AND`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
pub struct Binary {
/// Left-hand side operand
pub lhs: ExprRef,
/// The operator
pub operator: Operator,
/// Right-hand side operand
pub rhs: ExprRef,
}
/// Unary operation (e.g., `-x`, `NOT active`).
///
/// Represents operations that take a single operand.
///
/// # Examples
///
/// In `WHERE NOT e.deleted`, the `NOT e.deleted` is a unary operation.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
pub struct Unary {
/// The operator (Add for +, Sub for -, Not for NOT)
pub operator: Operator,
/// The operand expression
pub expr: ExprRef,
}
/// The kind of value an expression represents.
///
/// This enum contains all the different types of expressions that can appear
/// in an EventQL query, from simple literals to complex operations.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
pub enum Value {
/// Numeric literal (e.g., `42`, `3.14`)
Number(OrderedFloat<f64>),
/// String literal (e.g., `"hello"`)
String(StrRef),
/// Boolean literal (`true` or `false`)
Bool(bool),
/// Identifier (e.g., variable name `e`, `x`)
Id(StrRef),
/// Array literal (e.g., `[1, 2, 3]`)
Array(VecRef),
/// Record literal (e.g., `{name: "Alice", age: 30}`)
Record(RecRef),
/// Field access (e.g., `e.data.price`)
Access(Access),
/// Function application (e.g., `sum(e.price)`)
App(App),
/// Binary operation (e.g., `a + b`, `x == y`)
Binary(Binary),
/// Unary operation (e.g., `-x`, `NOT active`)
Unary(Unary),
/// Grouped/parenthesized expression (e.g., `(a + b)`)
Group(ExprRef),
}
/// A source binding. A name attached to a source of events.
///
/// # Examples
/// in `FROM e IN events`, `e` is the binding.
#[derive(Debug, Clone, Copy, Serialize)]
pub struct Binding {
/// Name attached to a source of events
pub name: StrRef,
/// Position in the source code where that binding was introduced
pub pos: Pos,
}
/// A data source in a FROM clause.
///
/// Sources specify where data comes from in a query. Each source has a binding
/// (the variable name) and a kind (what it binds to).
///
/// # Examples
///
/// In `FROM e IN events`, the source has:
/// - `binding`: `"e"`
/// - `kind`: `SourceKind::Name("events")`
#[derive(Debug, Clone, Serialize)]
pub struct Source<A> {
/// Variable name bound to this source
pub binding: Binding,
/// What this source represents
pub kind: SourceKind<A>,
}
/// The kind of data source.
///
/// EventQL supports three types of sources:
/// - Named sources (e.g., `FROM e IN events`)
/// - Subject patterns (e.g., `FROM e IN "users/john"`)
/// - Subqueries (e.g., `FROM e IN (SELECT ...)`)
#[derive(Debug, Clone, Serialize)]
pub enum SourceKind<A> {
/// Named source (identifier)
Name(StrRef),
/// Subject pattern (string literal used as event subject pattern)
Subject(StrRef),
/// Nested subquery
Subquery(Box<Query<A>>),
}
/// ORDER BY clause specification.
///
/// Defines how query results should be sorted.
///
/// # Examples
///
/// In `ORDER BY e.timestamp DESC`, this would be represented as:
/// - `expr`: expression for `e.timestamp`
/// - `order`: `Order::Desc`
#[derive(Debug, Clone, Copy, Serialize)]
pub struct OrderBy {
/// Expression to sort by
pub expr: ExprRef,
/// Sort direction (ascending or descending)
pub order: Order,
}
/// Sort order direction.
///
/// Specifies whether sorting is ascending or descending.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum Order {
/// Ascending order (smallest to largest)
Asc,
/// Descending order (largest to smallest)
Desc,
}
/// GROUP BY clause specification
///
/// Defines how query results should be order by.
/// # Examples
///
/// In `GROUP BY e.age HAVING age > 123`, this would be represented as:
/// - `expr`: expression for `e.age`
/// - `predicate`: `age > 123`
#[derive(Debug, Clone, Serialize)]
pub struct GroupBy {
/// Expression to group by
pub expr: ExprRef,
/// Predicate to filter groups after aggregation
pub predicate: Option<ExprRef>,
}
/// Result set limit specification.
///
/// EventQL supports two types of limits:
/// - `TOP n` - Take the first n results
/// - `SKIP n` - Skip the first n results
///
/// # Examples
///
/// - `TOP 10` limits to first 10 results
/// - `SKIP 20` skips first 20 results
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum Limit {
/// Skip the first n results
Skip(u64),
/// Take only the first n results
Top(u64),
}
/// Represents the state of a query that only has a valid syntax. There are no guarantee that all
/// the variables exists or that the query is sound. For example, if the user is asking for an event
/// that has field that should be a string or a number at the same time.
#[derive(Debug, Clone, Copy, Serialize)]
pub struct Raw;
/// A complete EventQL query.
///
/// This is the root node of the AST, representing a full query with all its clauses.
/// A query must have at least one source and a projection; other clauses are optional.
///
/// # Structure
///
/// ```text
/// FROM <alias> <source>
/// [FROM <alias> <source>] ...
/// [WHERE <condition>]
/// [GROUP BY <field> [HAVING <condition>]]
/// [ORDER BY <field> ASC|DESC]
/// [TOP|SKIP <n>]
/// PROJECT INTO [DISTINCT] <projection>
/// ```
///
/// # Examples
///
/// ```
/// use eventql_parser::Session;
///
/// let mut session = Session::builder().use_stdlib().build();
/// let query = session.parse(
/// "FROM e IN events \
/// WHERE e.price > 100 \
/// ORDER BY e.timestamp DESC \
/// TOP 10 \
/// PROJECT INTO {id: e.id, price: e.price}"
/// ).unwrap();
///
/// assert_eq!(query.sources.len(), 1);
/// assert!(query.predicate.is_some());
/// assert!(query.order_by.is_some());
/// assert!(query.limit.is_some());
/// ```
#[derive(Debug, Clone, Serialize)]
pub struct Query<A> {
/// Metadata about this query
pub attrs: Attrs,
/// FROM clause sources (must have at least one)
pub sources: Vec<Source<A>>,
/// Optional WHERE clause filter predicate
pub predicate: Option<ExprRef>,
/// Optional GROUP BY clause expression
pub group_by: Option<GroupBy>,
/// Optional ORDER BY clause
pub order_by: Option<OrderBy>,
/// Optional LIMIT clause (TOP or SKIP)
pub limit: Option<Limit>,
/// PROJECT INTO clause expression (required)
pub projection: ExprRef,
/// Remove duplicate rows from the query's results
pub distinct: bool,
/// Type-level metadata about the query's analysis state.
///
/// This field uses a generic type parameter to track whether the query
/// is in a raw (unparsed/untyped) state or has been statically analyzed:
/// - `Query<Raw>`: Query parsed but not yet type-checked
/// - `Query<Typed>`: Query that has passed static analysis with validated
/// types and variable scopes
///
/// This provides compile-time guarantees about the query's type safety.
pub meta: A,
}