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}