Skip to main content

rl_lang/ast/
nodes.rs

1//! Expression AST nodes.
2//!
3//! An [`Expression`] is any construct that produces a value. Every expression
4//! node carries the source [`Span`] it was parsed from so that error reports
5//! and the LSP can point at exact locations.
6//!
7//! # Resolved variants
8//! After the [`Resolver`] pass runs, unresolved name-based variants
9//! (`Identifier`, `Assign`, `Lambda`) are replaced with their `Resolved*`
10//! counterparts that carry `(depth, slot)` integer pairs for direct
11//! environment lookup, eliminating runtime name searches.
12//!
13//! [`Resolver`]: crate::resolver
14use crate::ast::ExprId;
15use crate::ast::statements::{Param, Statement, TypeAnnotation};
16use crate::lexer::tokentypes;
17use crate::utils::span::Span;
18
19/// An expression paired with its source span.
20#[derive(Debug, Clone, PartialEq)]
21pub struct Expression {
22    pub kind: ExpressionKind,
23    pub span: Span,
24}
25
26impl Expression {
27    pub fn new(kind: ExpressionKind, span: Span) -> Self {
28        Self { kind, span }
29    }
30}
31
32#[derive(Debug, Clone, PartialEq)]
33pub enum ExpressionKind {
34    /// The `null` literal.
35    Null,
36    /// A 64-bit signed integer literal.
37    Integer(i64),
38    /// A byte literal (`u8`).
39    Byte(u8),
40    /// A binary operation: `left operator right`.
41    Binary {
42        left: ExprId,
43        operator: tokentypes::TokenType,
44        right: ExprId,
45    },
46    /// A unary prefix operation: `operator operand`.
47    Unary {
48        operator: tokentypes::TokenType,
49        operand: ExprId,
50    },
51    /// A parenthesised expression `(expr)` - preserves grouping in the AST.
52    Grouping(ExprId),
53    /// A string literal.
54    String(String),
55    /// A boolean literal.
56    Bool(bool),
57    /// A 64-bit float literal.
58    Float(f64),
59    /// A character literal.
60    Character(char),
61    /// An unresolved variable or function reference by name.
62    /// Replaced by [`ResolvedIdentifier`] after the resolver pass.
63    Identifier(String),
64    /// A lexically-resolved variable reference.
65    /// `depth` is the number of scopes to walk up; `slot` is the index within that scope.
66    ResolvedIdentifier {
67        name: String,
68        depth: usize,
69        slot: usize,
70    },
71    /// An array literal `[a, b, c]`.
72    ArrayLiteral(Vec<ExprId>),
73    MapLiteral(Vec<(ExprId, ExprId)>),
74    SetLiteral(Vec<ExprId>),
75    /// An unresolved variable assignment `name = value`.
76    /// Replaced by [`ResolvedAssign`] after the resolver pass.
77    Assign {
78        name: String,
79        value: ExprId,
80    },
81    /// A lexically-resolved variable assignment.
82    ResolvedAssign {
83        name: String,
84        depth: usize,
85        slot: usize,
86        value: ExprId,
87    },
88    /// A function call via a module path: `std::io::println(args)` or `f(args)`.
89    Call {
90        path: Vec<String>,
91        args: Vec<ExprId>,
92    },
93    /// A method call chain: `expr.method(args)`.
94    MethodCall {
95        caller: ExprId,
96        method: Vec<String>,
97        args: Vec<ExprId>,
98    },
99    /// An index access: `target[index]`.
100    Index {
101        target: ExprId,
102        index: ExprId,
103    },
104    /// An index assignment: `target[index] = value`.
105    IndexAssign {
106        target: ExprId,
107        index: ExprId,
108        value: ExprId,
109    },
110    /// An unresolved anonymous function (lambda) expression.
111    /// Replaced by [`ResolvedLambda`] after the resolver pass.
112    Lambda {
113        params: Vec<Param>,
114        return_type: Option<TypeAnnotation>,
115        body: Vec<Statement>,
116    },
117    /// A lexically-resolved lambda. `capture_depth` is the scope depth at the
118    /// point of definition, used to correctly capture the enclosing environment.
119    ResolvedLambda {
120        params: Vec<Param>,
121        return_type: Option<TypeAnnotation>,
122        body: Vec<Statement>,
123        capture_depth: usize,
124    },
125    /// A call on an arbitrary callee expression, e.g. `fns[0](args)` or
126    /// an immediately-invoked lambda.
127    CallExpr {
128        callee: ExprId,
129        args: Vec<ExprId>,
130    },
131
132    /// A type cast expression ` value as type `.
133    /// Used for non-literal casts; literal casts are constant-folded in the parser.
134    Cast {
135        value: ExprId,
136        target_type: TypeAnnotation,
137    },
138
139    TupleLiteral(Vec<ExprId>),
140    ErrorLiteral(ExprId),
141
142    OkLiteral(ExprId),
143    ErrLiteral(ExprId),
144
145    Propagate(ExprId),
146
147    /// A record (struct) literal: `Name { field: value, ... }`.
148    StructLiteral {
149        name: String,
150        fields: Vec<(String, ExprId)>,
151    },
152    /// A field access: `target.field`.
153    FieldAccess {
154        target: ExprId,
155        field: String,
156    },
157    /// A field assignment: `target.field = value`.
158    FieldAssign {
159        target: ExprId,
160        field: String,
161        value: ExprId,
162    },
163    /// A tag (enum) variant reference: `EnumName.Variant`.
164    EnumVariant {
165        enum_name: String,
166        variant: String,
167    },
168}