Skip to main content

rl_lang/ast/
statements.rs

1//! Statement AST nodes, type annotations, and parameter definitions.
2//!
3//! A [`Statement`] is any construct that does not directly produce a value
4//! (declarations, control flow, imports). Every node carries the source [`Span`]
5//! it was parsed from.
6//!
7//! # Resolved variants
8//! The [`Resolver`] pass rewrites name-based declaration and loop variants into
9//! their `Resolved*` counterparts, adding a `slot: usize` field that gives the
10//! variable's index in its environment frame. This eliminates all runtime
11//! HashMap lookups in the evaluator.
12//!
13//! # Type annotations
14//! [`TypeAnnotation`] distinguishes mutable (`dec`) and constant (`const`)
15//! bindings at the type level via separate variants (`Int` vs `CInt`, etc.).
16//!
17//! [`Resolver`]: crate::resolver
18use std::rc::Rc;
19
20use crate::ast::ExprId;
21use crate::utils::span::Span;
22
23/// A statement paired with its source span.
24#[derive(Debug, Clone, PartialEq)]
25pub struct Statement {
26    pub kind: StatementKind,
27    pub span: Span,
28}
29
30impl Statement {
31    pub fn new(kind: StatementKind, span: Span) -> Self {
32        Self { kind, span }
33    }
34}
35
36#[derive(Debug, Clone, PartialEq)]
37pub enum StatementKind {
38    /// A mutable variable declaration: `dec T name = value`.
39    VariableDeclaration {
40        name: String,
41        type_annotation: TypeAnnotation,
42        value: ExprId,
43    },
44    /// Resolver-annotated mutable variable declaration. `slot` is the index
45    /// in the current environment frame.
46    ResolvedVariableDeclaration {
47        name: String,
48        slot: usize,
49        type_annotation: TypeAnnotation,
50        value: ExprId,
51    },
52    /// An immutable constant declaration: `const T NAME = value`.
53    ConstantDeclaration {
54        name: String,
55        type_annotation: TypeAnnotation,
56        value: ExprId,
57    },
58    /// Resolver-annotated constant declaration.
59    ResolvedConstantDeclaration {
60        name: String,
61        slot: usize,
62        type_annotation: TypeAnnotation,
63        value: ExprId,
64    },
65    /// A mutable array declaration with an inline literal: `dec array[T] name = [items]`.
66    Array {
67        name: String,
68        type_annotation: TypeAnnotation,
69        value: Vec<ExprId>,
70    },
71    /// An immutable array declaration with an inline literal: `const array[T] NAME = [items]`.
72    ConstantArray {
73        name: String,
74        type_annotation: TypeAnnotation,
75        value: Vec<ExprId>,
76    },
77    /// Resolver-annotated mutable array declaration. `value` is the
78    /// initialiser expression (may be an [`ExpressionKind::ArrayLiteral`]).
79    ///
80    /// [`ExpressionKind::ArrayLiteral`]: crate::ast::nodes::ExpressionKind::ArrayLiteral
81    ResolvedArray {
82        name: String,
83        slot: usize,
84        type_annotation: TypeAnnotation,
85        value: ExprId,
86    },
87    /// Resolver-annotated constant array declaration.
88    ResolvedConstantArray {
89        name: String,
90        slot: usize,
91        type_annotation: TypeAnnotation,
92        value: ExprId,
93    },
94
95    Map {
96        name: String,
97        type_annotation: TypeAnnotation,
98        entries: Vec<(ExprId, ExprId)>,
99    },
100    ConstantMap {
101        name: String,
102        type_annotation: TypeAnnotation,
103        entries: Vec<(ExprId, ExprId)>,
104    },
105    ResolvedMap {
106        name: String,
107        slot: usize,
108        type_annotation: TypeAnnotation,
109        value: ExprId,
110    },
111    ResolvedConstantMap {
112        name: String,
113        slot: usize,
114        type_annotation: TypeAnnotation,
115        value: ExprId,
116    },
117
118    Set {
119        name: String,
120        type_annotation: TypeAnnotation,
121        items: Vec<ExprId>,
122    },
123    ConstantSet {
124        name: String,
125        type_annotation: TypeAnnotation,
126        items: Vec<ExprId>,
127    },
128    ResolvedSet {
129        name: String,
130        slot: usize,
131        type_annotation: TypeAnnotation,
132        value: ExprId,
133    },
134    ResolvedConstantSet {
135        name: String,
136        slot: usize,
137        type_annotation: TypeAnnotation,
138        value: ExprId,
139    },
140    /// A bare expression used as a statement (e.g. a function call whose
141    /// return value is discarded, or a newline placeholder).
142    Expression(ExprId),
143    /// A `while condition { body }` loop.
144    While {
145        condition: ExprId,
146        body: Vec<Statement>,
147    },
148    /// A C-style `for [init, cond, incr] { body }` loop.
149    For {
150        initializer: Box<Statement>,
151        condition: ExprId,
152        increment: ExprId,
153        body: Vec<Statement>,
154    },
155    /// Resolver-annotated C-style for loop.
156    ResolvedFor {
157        initializer: Box<Statement>,
158        condition: ExprId,
159        increment: ExprId,
160        body: Vec<Statement>,
161    },
162    /// A range-based `for x in N..M { body }` loop. The range is pre-evaluated
163    /// at parse time into a [`Range`] statement.
164    ForRange {
165        variable: String,
166        range: Box<Statement>,
167        body: Vec<Statement>,
168    },
169    /// Resolver-annotated range-based for loop. `slot` is the loop variable's
170    /// environment index.
171    ResolvedForRange {
172        slot: usize,
173        variable: String,
174        range: Box<Statement>,
175        body: Vec<Statement>,
176    },
177    /// A foreach `for item in iterable { body }` loop over an array expression.
178    ForEach {
179        variable: String,
180        iterable: ExprId,
181        body: Vec<Statement>,
182    },
183    /// Resolver-annotated foreach loop.
184    ResolvedForEach {
185        slot: usize,
186        variable: String,
187        iterable: ExprId,
188        body: Vec<Statement>,
189    },
190    /// A pre-evaluated integer range produced by the parser for `for x in N..M`.
191    Range(Vec<i64>),
192    /// A single branch of a conditional: either `if condition { body }` (`condition`
193    /// is `Some`) or `else { body }` (`condition` is `None`).
194    ConditionalBranch {
195        condition: Option<ExprId>,
196        body: Vec<Statement>,
197        /// Precomputed by the resolver
198        /// true if `body` declares any local variable/constant
199        /// and therefore needs its own scope frame
200        needs_scope: bool,
201    },
202    /// A full if / else-if / else chain.
203    Conditional {
204        if_branch: Box<Statement>,
205        else_branch: Option<Box<Statement>>,
206    },
207    /// A named function declaration.
208    FunctionDeclaration {
209        name: String,
210        params: Vec<Param>,
211        return_type: TypeAnnotation,
212        body: Vec<Statement>,
213        /// `true` when the function is marked with `!#[entry]`.
214        attribute: Option<FunctionAttribute>,
215    },
216    /// Resolver-annotated function declaration. `slot` is the function's
217    /// index in the current environment frame.
218    ResolvedFunctionDeclaration {
219        name: String,
220        slot: usize,
221        params: Vec<Param>,
222        return_type: TypeAnnotation,
223        body: Vec<Statement>,
224        attribute: Option<FunctionAttribute>,
225    },
226    /// A `return expr` or bare `return` statement.
227    Return(Option<ExprId>),
228    /// Breaks out of the nearest enclosing loop.
229    Break,
230    /// Skips to the next iteration of the nearest enclosing loop.
231    Continue,
232    /// A stdlib import: `get std::ns::fn` or `get fn from std::ns`.
233    Import {
234        /// names of the imported functions
235        names: Vec<String>,
236        /// module path (e.g. `["std", "math"]`)
237        path: Vec<String>,
238    },
239    /// A file module import: `get mymodule` or `get mymodule::sub`.
240    ImportFile { path: Vec<String> },
241    /// A resolved file import - the imported file's statements are inlined here.
242    ResolvedImportFile {
243        path: Vec<String>,
244        body: Vec<Statement>,
245    },
246    /// A named file import: `get fn, fn from mymodule::sub`.
247    ImportFileNamed {
248        path: Vec<String>,
249        names: Vec<String>,
250    },
251
252    DestructureDeclaration {
253        bindings: Vec<(TypeAnnotation, String)>,
254        value: ExprId,
255    },
256    ResolvedDestructureDeclaration {
257        bindings: Vec<(TypeAnnotation, String)>,
258        slots: Vec<usize>,
259        value: ExprId,
260    },
261
262    Match {
263        value: ExprId,
264        arms: Vec<(MatchPattern, Vec<Statement>)>,
265    },
266
267    /// A record (struct) type declaration: `record Name { int a, string b }`.
268    RecordDeclaration {
269        name: String,
270        fields: Vec<(String, TypeAnnotation)>,
271    },
272
273    /// A tag (enum) type declaration: `tag Name { VariantA, VariantB }`.
274    TagDeclaration { name: String, variants: Vec<String> },
275}
276
277#[derive(Debug, PartialEq, Clone)]
278pub enum MatchPattern {
279    Literal(ExprId),
280    Wildcard,
281}
282
283#[derive(Debug, Clone, PartialEq)]
284pub enum FunctionAttribute {
285    Entry,
286    Init,
287    Final,
288    Test,
289}
290
291/// The type of a variable, constant, or parameter binding.
292///
293/// Mutable variants (`Int`, `Float`, etc.) are produced by `dec` declarations.
294/// Constant variants (`CInt`, `CFloat`, etc.) are produced by `const` declarations.
295/// `Array(T)` / `CArray(T)` are the mutable / constant array forms.
296#[derive(Debug, Clone, PartialEq)]
297pub enum TypeAnnotation {
298    /// Mutable 64-bit signed integer.
299    Int,
300    /// Mutable 64-bit float.
301    Float,
302    /// Mutable boolean.
303    Bool,
304    /// Mutable string.
305    String,
306    /// Mutable byte (`u8`).
307    Byte,
308    /// Mutable character.
309    Char,
310    /// Mutable array with a typed element.
311    Array(Box<TypeAnnotation>),
312    Map(Box<TypeAnnotation>, Box<TypeAnnotation>),
313    Set(Box<TypeAnnotation>),
314    /// Constant 64-bit signed integer.
315    CInt,
316    /// Constant 64-bit float.
317    CFloat,
318    /// Constant boolean.
319    CBool,
320    /// Constant string.
321    CString,
322    /// Constant byte.
323    CByte,
324    /// Constant character.
325    CChar,
326    /// Constant array with a typed element.
327    CArray(Box<TypeAnnotation>),
328    CMap(Box<TypeAnnotation>, Box<TypeAnnotation>),
329    CSet(Box<TypeAnnotation>),
330    /// A function value (used for `fn`-typed parameters and variables).
331    Fn,
332    /// Absence of a type - used as the default return type when none is annotated.
333    Null,
334
335    Tuple(Rc<Vec<TypeAnnotation>>),
336    CTuple(Rc<Vec<TypeAnnotation>>),
337
338    Error,
339    CError,
340
341    Result(Box<TypeAnnotation>),
342    CResult(Box<TypeAnnotation>),
343
344    /// A named record (struct) type, mutable binding.
345    Record(String),
346    /// A named record (struct) type, constant binding.
347    CRecord(String),
348
349    /// A named tag (enum) type, mutable binding.
350    Enum(String),
351    /// A named tag (enum) type, constant binding.
352    CEnum(String),
353}
354
355/// A single function or lambda parameter: a name and its type annotation.
356#[derive(Debug, Clone, PartialEq)]
357pub struct Param {
358    pub param_name: String,
359    pub param_type: TypeAnnotation,
360}