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