Skip to main content

ion_core/
ast.rs

1/// Represents a location in source for error reporting.
2#[derive(Debug, Clone, Copy)]
3pub struct Span {
4    pub line: usize,
5    pub col: usize,
6}
7
8/// Top-level program: a list of statements.
9#[derive(Debug, Clone)]
10pub struct Program {
11    pub stmts: Vec<Stmt>,
12}
13
14#[derive(Debug, Clone)]
15pub struct Stmt {
16    pub kind: StmtKind,
17    pub span: Span,
18}
19
20#[derive(Debug, Clone)]
21pub enum StmtKind {
22    /// `let [mut] pattern [: type] = expr;`
23    Let {
24        mutable: bool,
25        pattern: Pattern,
26        type_ann: Option<TypeAnn>,
27        value: Expr,
28    },
29    /// Expression statement (with trailing semicolon = discards value)
30    ExprStmt { expr: Expr, has_semi: bool },
31    /// `fn name(params) { body }`
32    FnDecl {
33        name: String,
34        params: Vec<Param>,
35        body: Vec<Stmt>,
36    },
37    /// `['label:] for pattern in expr { body }`
38    For {
39        label: Option<String>,
40        pattern: Pattern,
41        iter: Expr,
42        body: Vec<Stmt>,
43    },
44    /// `['label:] while cond { body }`
45    While {
46        label: Option<String>,
47        cond: Expr,
48        body: Vec<Stmt>,
49    },
50    /// `['label:] while let pattern = expr { body }`
51    WhileLet {
52        label: Option<String>,
53        pattern: Pattern,
54        expr: Expr,
55        body: Vec<Stmt>,
56    },
57    /// `['label:] loop { body }`
58    Loop {
59        label: Option<String>,
60        body: Vec<Stmt>,
61    },
62    /// `break ['label] [expr];`
63    Break {
64        label: Option<String>,
65        value: Option<Expr>,
66    },
67    /// `continue ['label];`
68    Continue { label: Option<String> },
69    /// `use module::{name1, name2}` or `use module::*`
70    Use {
71        path: Vec<String>,
72        imports: UseImports,
73    },
74    /// `return [expr];`
75    Return { value: Option<Expr> },
76    /// Assignment: `lhs = rhs;` or `lhs += rhs;`
77    Assign {
78        target: AssignTarget,
79        op: AssignOp,
80        value: Expr,
81    },
82}
83
84#[derive(Debug, Clone)]
85pub struct Param {
86    pub name: String,
87    pub default: Option<Expr>,
88}
89
90#[derive(Debug, Clone)]
91pub enum AssignTarget {
92    Ident(String),
93    Index(Box<Expr>, Box<Expr>),
94    Field(Box<Expr>, String),
95}
96
97#[derive(Debug, Clone, Copy)]
98pub enum AssignOp {
99    Eq,
100    PlusEq,
101    MinusEq,
102    StarEq,
103    SlashEq,
104}
105
106#[derive(Debug, Clone)]
107pub struct Expr {
108    pub kind: ExprKind,
109    pub span: Span,
110}
111
112#[derive(Debug, Clone)]
113pub enum ExprKind {
114    // Literals
115    Int(i64),
116    Float(f64),
117    Bool(bool),
118    Str(String),
119    /// f-string: list of parts (literal strings and expressions)
120    FStr(Vec<FStrPart>),
121    Bytes(Vec<u8>),
122    None,
123    Unit,
124
125    // Variables
126    Ident(String),
127    /// `module::path::name` — module path access
128    ModulePath(Vec<String>),
129
130    // Constructors
131    /// `Some(expr)`
132    SomeExpr(Box<Expr>),
133    /// `Ok(expr)`
134    OkExpr(Box<Expr>),
135    /// `Err(expr)`
136    ErrExpr(Box<Expr>),
137
138    // Collections
139    /// `[a, b, ...c]` with optional spread entries
140    List(Vec<ListEntry>),
141    /// `#{ "key": val, ... }` with optional spread entries
142    Dict(Vec<DictEntry>),
143    /// `(a, b, c)`
144    Tuple(Vec<Expr>),
145    /// `[expr for pattern in iter if cond]`
146    ListComp {
147        expr: Box<Expr>,
148        pattern: Pattern,
149        iter: Box<Expr>,
150        cond: Option<Box<Expr>>,
151    },
152    /// `#{ key: val for pattern in iter if cond }`
153    DictComp {
154        key: Box<Expr>,
155        value: Box<Expr>,
156        pattern: Pattern,
157        iter: Box<Expr>,
158        cond: Option<Box<Expr>>,
159    },
160
161    // Operations
162    BinOp {
163        left: Box<Expr>,
164        op: BinOp,
165        right: Box<Expr>,
166    },
167    UnaryOp {
168        op: UnaryOp,
169        expr: Box<Expr>,
170    },
171    /// `expr?`
172    Try(Box<Expr>),
173    /// `a |> b`
174    PipeOp {
175        left: Box<Expr>,
176        right: Box<Expr>,
177    },
178
179    // Access
180    /// `expr.field`
181    FieldAccess {
182        expr: Box<Expr>,
183        field: String,
184    },
185    /// `expr[index]`
186    Index {
187        expr: Box<Expr>,
188        index: Box<Expr>,
189    },
190    /// `expr[start..end]`, `expr[..end]`, `expr[start..]`
191    Slice {
192        expr: Box<Expr>,
193        start: Option<Box<Expr>>,
194        end: Option<Box<Expr>>,
195        inclusive: bool,
196    },
197    /// `expr.method(args)`
198    MethodCall {
199        expr: Box<Expr>,
200        method: String,
201        args: Vec<CallArg>,
202    },
203
204    // Functions
205    /// `func(args)`
206    Call {
207        func: Box<Expr>,
208        args: Vec<CallArg>,
209    },
210    /// `|params| body`
211    Lambda {
212        params: Vec<String>,
213        body: Box<Expr>,
214    },
215
216    // Control flow (all are expressions)
217    /// `if cond { then } [else { else_ }]`
218    If {
219        cond: Box<Expr>,
220        then_body: Vec<Stmt>,
221        else_body: Option<Vec<Stmt>>,
222    },
223    /// `if let pattern = expr { then } [else { else_ }]`
224    IfLet {
225        pattern: Pattern,
226        expr: Box<Expr>,
227        then_body: Vec<Stmt>,
228        else_body: Option<Vec<Stmt>>,
229    },
230    /// `match expr { arms }`
231    Match {
232        expr: Box<Expr>,
233        arms: Vec<MatchArm>,
234    },
235    /// `{ stmts }`
236    Block(Vec<Stmt>),
237    /// `loop { body }` as expression (returns break value)
238    LoopExpr(Vec<Stmt>),
239    /// `try { body } catch ident { handler }`
240    TryCatch {
241        body: Vec<Stmt>,
242        var: String,
243        handler: Vec<Stmt>,
244    },
245
246    // Host type constructor: `TypeName { field: val, ... }` or `TypeName { ...spread, field: val }`
247    StructConstruct {
248        name: String,
249        fields: Vec<(String, Expr)>,
250        spread: Option<Box<Expr>>,
251    },
252
253    // Enum variant access: `Enum::Variant` or `Enum::Variant(args)`
254    EnumVariant {
255        enum_name: String,
256        variant: String,
257    },
258    EnumVariantCall {
259        enum_name: String,
260        variant: String,
261        args: Vec<Expr>,
262    },
263
264    // Range
265    Range {
266        start: Box<Expr>,
267        end: Box<Expr>,
268        inclusive: bool,
269    },
270
271    // Concurrency
272    /// `async { body }` — structured concurrency scope
273    AsyncBlock(Vec<Stmt>),
274    /// `spawn expr` — launch a child task, returns Task handle
275    SpawnExpr(Box<Expr>),
276    /// `expr.await` — wait for a task/future result
277    AwaitExpr(Box<Expr>),
278    /// `select { branch => expr, ... }` — race multiple async expressions
279    SelectExpr(Vec<SelectBranch>),
280}
281
282/// A list entry: either a single element or a spread `...expr`.
283#[derive(Debug, Clone)]
284pub enum ListEntry {
285    Elem(Expr),
286    Spread(Expr),
287}
288
289/// A dict entry: either a key-value pair or a spread `...expr`.
290#[derive(Debug, Clone)]
291pub enum DictEntry {
292    KeyValue(Expr, Expr),
293    Spread(Expr),
294}
295
296#[derive(Debug, Clone)]
297pub enum FStrPart {
298    Literal(String),
299    Expr(Expr),
300}
301
302#[derive(Debug, Clone)]
303pub struct CallArg {
304    pub name: Option<String>,
305    pub value: Expr,
306}
307
308/// A branch in a `select {}` expression.
309#[derive(Debug, Clone)]
310pub struct SelectBranch {
311    pub pattern: Pattern,
312    pub future_expr: Expr,
313    pub body: Expr,
314}
315
316#[derive(Debug, Clone)]
317pub struct MatchArm {
318    pub pattern: Pattern,
319    pub guard: Option<Expr>,
320    pub body: Expr,
321}
322
323#[derive(Debug, Clone)]
324pub enum Pattern {
325    Wildcard,
326    Ident(String),
327    Int(i64),
328    Float(f64),
329    Bool(bool),
330    Str(String),
331    Bytes(Vec<u8>),
332    None,
333    /// `Some(pattern)`
334    Some(Box<Pattern>),
335    /// `Ok(pattern)`
336    Ok(Box<Pattern>),
337    /// `Err(pattern)`
338    Err(Box<Pattern>),
339    /// `(a, b, c)`
340    Tuple(Vec<Pattern>),
341    /// `[a, b, ...rest]`
342    List(Vec<Pattern>, Option<Box<Pattern>>),
343    /// `EnumName::Variant` or `EnumName::Variant(patterns)` or `EnumName::Variant { fields }`
344    EnumVariant {
345        enum_name: String,
346        variant: String,
347        fields: EnumPatternFields,
348    },
349    /// `StructName { field1, field2: pattern }`
350    Struct {
351        name: String,
352        fields: Vec<(String, Option<Pattern>)>,
353    },
354}
355
356#[derive(Debug, Clone)]
357pub enum EnumPatternFields {
358    None,
359    Positional(Vec<Pattern>),
360    Named(Vec<(String, Option<Pattern>)>),
361}
362
363#[derive(Debug, Clone, Copy)]
364pub enum BinOp {
365    Add,
366    Sub,
367    Mul,
368    Div,
369    Mod,
370    Eq,
371    Ne,
372    Lt,
373    Gt,
374    Le,
375    Ge,
376    And,
377    Or,
378    BitAnd,
379    BitOr,
380    BitXor,
381    Shl,
382    Shr,
383}
384
385/// Optional type annotation for `let` bindings.
386/// Inner/generic types are parsed but only the outer type is checked at runtime
387/// (e.g. `list<int>` checks that the value is a list, not that elements are ints).
388#[derive(Debug, Clone)]
389pub enum TypeAnn {
390    Simple(String),                     // int, float, bool, string, list, dict, set, etc.
391    Option(Box<TypeAnn>),               // Option<T>
392    Result(Box<TypeAnn>, Box<TypeAnn>), // Result<T, E>
393    List(Box<TypeAnn>),                 // list<T>
394    Dict(Box<TypeAnn>, Box<TypeAnn>),   // dict<K, V>
395}
396
397#[derive(Debug, Clone, Copy)]
398pub enum UnaryOp {
399    Neg,
400    Not,
401}
402
403/// What to import from a module path.
404#[derive(Debug, Clone)]
405pub enum UseImports {
406    /// `use path::*` — import all names
407    Glob,
408    /// `use path::{a, b, c}` — import specific names
409    Names(Vec<String>),
410    /// `use path::name` — import a single name (sugar for Names(vec![name]))
411    Single(String),
412}