Skip to main content

lux/
ast.rs

1//! The abstract syntax tree: the shape of a parsed lux program.
2//!
3//! A program is a list of statements. Statements declare names, assign to
4//! them, branch, loop, define functions, return, or evaluate an expression for
5//! its effect (like `print`). Expressions produce values. Every node carries a
6//! `Span` so the interpreter can blame the right place when something goes
7//! wrong.
8
9use crate::diagnostic::Span;
10
11/// A written type annotation, like the `int` in `var count: int` or the
12/// `[int]` in `let primes: [int]`. Types nest, so this is recursive.
13#[derive(Debug, Clone)]
14pub struct TypeAnn {
15    pub kind: TypeKind,
16    pub span: Span,
17}
18
19#[derive(Debug, Clone)]
20pub enum TypeKind {
21    /// A plain named type: `int`, `float`, `string`, `bool`.
22    Named(String),
23    /// An array type: `[int]`, `[[string]]`.
24    Array(Box<TypeAnn>),
25    /// A type with parameters: `Option<int>`, `Result<int, string>`. So far
26    /// only the built-in `Option` and `Result` take parameters — user-defined
27    /// generics are a later milestone.
28    Generic(String, Vec<TypeAnn>),
29}
30
31/// One parameter in a function signature, like the `x: int` in `func f(x: int)`.
32#[derive(Debug, Clone)]
33pub struct Param {
34    pub name: String,
35    pub ty: TypeAnn,
36    pub span: Span,
37}
38
39/// One field in a struct, or one labelled value carried by an enum case, like
40/// the `x: int` in `struct Point { x: int }` or the `radius: float` in
41/// `circle(radius: float)`. Same shape as a parameter, but it names data rather
42/// than an argument, so it gets its own type for clarity.
43#[derive(Debug, Clone)]
44pub struct FieldDef {
45    pub name: String,
46    pub ty: TypeAnn,
47    pub span: Span,
48}
49
50/// One case of an enum, like `circle(radius: float)` or the payload-less `dot`.
51#[derive(Debug, Clone)]
52pub struct VariantDef {
53    pub name: String,
54    pub fields: Vec<FieldDef>,
55    pub span: Span,
56}
57
58#[derive(Debug, Clone)]
59pub enum Stmt {
60    /// `let name = value` — an immutable binding.
61    Let {
62        name: String,
63        ty: Option<TypeAnn>,
64        value: Expr,
65        span: Span,
66    },
67    /// `var name = value` or `var name: type` — a mutable binding.
68    Var {
69        name: String,
70        ty: Option<TypeAnn>,
71        value: Option<Expr>,
72        span: Span,
73    },
74    /// `name = value`, `name += value`, `name -= value`.
75    Assign {
76        name: String,
77        name_span: Span,
78        op: AssignOp,
79        value: Expr,
80        span: Span,
81    },
82    /// `func name(params) -> ret { body }`. A missing `-> ret` means the
83    /// function returns nothing.
84    Func {
85        name: String,
86        params: Vec<Param>,
87        ret: Option<TypeAnn>,
88        body: Vec<Stmt>,
89        span: Span,
90    },
91    /// `return` or `return value`.
92    Return { value: Option<Expr>, span: Span },
93    /// `struct Name { field: type ... }` — declares a record type.
94    Struct {
95        name: String,
96        fields: Vec<FieldDef>,
97        span: Span,
98    },
99    /// `enum Name { case ... }` — declares a type that is exactly one of a
100    /// fixed set of cases, each of which may carry its own values.
101    Enum {
102        name: String,
103        variants: Vec<VariantDef>,
104        span: Span,
105    },
106    /// `if cond { ... } else { ... }`. An `else if` is represented as an
107    /// `else` body holding a single nested `If`.
108    If {
109        cond: Expr,
110        then_body: Vec<Stmt>,
111        else_body: Option<Vec<Stmt>>,
112        span: Span,
113    },
114    /// `while cond { ... }`.
115    While {
116        cond: Expr,
117        body: Vec<Stmt>,
118        span: Span,
119    },
120    /// `for var in iter { ... }`, where `iter` is an array or a range.
121    For {
122        var: String,
123        iter: Expr,
124        body: Vec<Stmt>,
125        span: Span,
126    },
127    /// A bare expression run for its effect, like `print("hi")`.
128    Expr(Expr),
129}
130
131#[derive(Debug, Clone, Copy, PartialEq)]
132pub enum AssignOp {
133    Set,
134    Add,
135    Sub,
136}
137
138#[derive(Debug, Clone)]
139pub enum Expr {
140    Int(i64, Span),
141    Float(f64, Span),
142    Str(String, Span),
143    Bool(bool, Span),
144    Ident(String, Span),
145    /// An array literal: `[2, 3, 5]`.
146    Array(Vec<Expr>, Span),
147    Unary {
148        op: UnOp,
149        rhs: Box<Expr>,
150        span: Span,
151    },
152    Binary {
153        op: BinOp,
154        lhs: Box<Expr>,
155        rhs: Box<Expr>,
156        span: Span,
157    },
158    /// Reading an element by position: `xs[0]`.
159    Index {
160        base: Box<Expr>,
161        index: Box<Expr>,
162        span: Span,
163    },
164    /// A half-open range: `0..5` means 0, 1, 2, 3, 4.
165    Range {
166        start: Box<Expr>,
167        end: Box<Expr>,
168        span: Span,
169    },
170    /// A function call. Built-ins (print, string, int, float, length) and
171    /// user-defined functions share this node.
172    Call {
173        name: String,
174        args: Vec<Expr>,
175        span: Span,
176    },
177    /// Building a struct by naming its fields: `Point(x: 0, y: 0)`.
178    StructLit {
179        name: String,
180        fields: Vec<(String, Expr)>,
181        span: Span,
182    },
183    /// Building an enum case: `Shape.circle(radius: 2.0)`. A payload-less case
184    /// like `Shape.dot` parses as a `Field` and is resolved at run time.
185    EnumLit {
186        enum_name: String,
187        variant: String,
188        fields: Vec<(String, Expr)>,
189        span: Span,
190    },
191    /// Reading a struct field with a dot: `origin.x`.
192    Field {
193        base: Box<Expr>,
194        field: String,
195        span: Span,
196    },
197    /// `match scrutinee { pattern => expr ... }`. An expression: it evaluates to
198    /// the body of the one arm that matches.
199    Match {
200        scrutinee: Box<Expr>,
201        arms: Vec<MatchArm>,
202        span: Span,
203    },
204}
205
206/// One arm of a `match`: a pattern and the expression to evaluate when it fits.
207#[derive(Debug, Clone)]
208pub struct MatchArm {
209    pub pattern: Pattern,
210    pub body: Expr,
211    pub span: Span,
212}
213
214/// What a `match` arm tests for.
215#[derive(Debug, Clone)]
216pub enum Pattern {
217    /// `_` — matches anything, binds nothing.
218    Wildcard(Span),
219    /// A literal value: `0`, `"hi"`, `true`.
220    Int(i64, Span),
221    Str(String, Span),
222    Bool(bool, Span),
223    /// An enum case, optionally capturing its values: `dot`, `circle(let r)`.
224    Variant {
225        name: String,
226        bindings: Vec<String>,
227        span: Span,
228    },
229}
230
231impl Pattern {
232    pub fn span(&self) -> Span {
233        match self {
234            Pattern::Wildcard(s)
235            | Pattern::Int(_, s)
236            | Pattern::Str(_, s)
237            | Pattern::Bool(_, s) => *s,
238            Pattern::Variant { span, .. } => *span,
239        }
240    }
241}
242
243impl Expr {
244    /// The source span covering this whole expression.
245    pub fn span(&self) -> Span {
246        match self {
247            Expr::Int(_, s)
248            | Expr::Float(_, s)
249            | Expr::Str(_, s)
250            | Expr::Bool(_, s)
251            | Expr::Ident(_, s)
252            | Expr::Array(_, s) => *s,
253            Expr::Unary { span, .. }
254            | Expr::Binary { span, .. }
255            | Expr::Index { span, .. }
256            | Expr::Range { span, .. }
257            | Expr::Call { span, .. }
258            | Expr::StructLit { span, .. }
259            | Expr::EnumLit { span, .. }
260            | Expr::Field { span, .. }
261            | Expr::Match { span, .. } => *span,
262        }
263    }
264}
265
266#[derive(Debug, Clone, Copy, PartialEq)]
267pub enum UnOp {
268    Neg,
269    Not,
270}
271
272#[derive(Debug, Clone, Copy, PartialEq)]
273pub enum BinOp {
274    Add,
275    Sub,
276    Mul,
277    Div,
278    Mod,
279    Eq,
280    Ne,
281    Lt,
282    Gt,
283    Le,
284    Ge,
285    And,
286    Or,
287}