Skip to main content

lutra_compiler/pr/
expr.rs

1#![allow(unused_assignments)]
2
3use enum_as_inner::EnumAsInner;
4
5use crate::Span;
6use crate::pr::{BinOp, Literal, Ty, UnOp};
7
8use super::{Path, TyParam};
9
10/// Expr is anything that has a value and thus a type.
11/// Most of these can contain other [Expr] themselves; literals should be [ExprKind::Literal].
12#[derive(Debug, Clone, PartialEq)]
13pub struct Expr {
14    pub kind: ExprKind,
15
16    pub span: Option<Span>,
17
18    /// Type of expression this node represents.
19    /// [None] means that type should be inferred.
20    pub ty: Option<Ty>,
21
22    /// When this expression refers to a function with type parameters,
23    /// these params are instantiated into these args and finalized when
24    /// scope closes.
25    pub ty_args: Vec<Ty>,
26
27    /// When this expr is the root of a new scope, this holds the id of
28    /// that scope. This will always be set for [ExprKind::Func], but
29    /// might be set for other nodes too.
30    pub scope_id: Option<usize>,
31
32    /// When this expression is an identifer, this holds information about
33    /// what is being referenced.
34    pub target: Option<Ref>,
35}
36
37impl Expr {
38    pub fn new<K: Into<ExprKind>>(kind: K) -> Self {
39        Expr {
40            kind: kind.into(),
41            span: None,
42            ty: None,
43            ty_args: Vec::new(),
44            target: None,
45            scope_id: None,
46        }
47    }
48
49    pub fn new_with_span<K: Into<ExprKind>>(kind: K, span: Span) -> Expr {
50        Expr {
51            kind: kind.into(),
52            span: Some(span),
53            ty: None,
54            ty_args: Vec::new(),
55            target: None,
56            scope_id: None,
57        }
58    }
59}
60
61#[derive(Debug, Clone, PartialEq, Eq, Hash)]
62pub enum Ref {
63    Global(Path),
64    Local {
65        /// scope id
66        scope: usize,
67
68        /// position of the name within the scope
69        offset: usize,
70    },
71}
72
73#[derive(Debug, EnumAsInner, PartialEq, Clone, strum::AsRefStr)]
74pub enum ExprKind {
75    Ident(Path),
76
77    /// A lookup into an object by name or position.
78    /// Currently, this includes only tuple field lookups, primarily by name.
79    Lookup {
80        base: Box<Expr>,
81        lookup: Lookup,
82    },
83    Literal(Literal),
84    Nested(Box<Expr>),
85    TypeAnnotation(TypeAnnotation),
86
87    Tuple(Vec<TupleField>),
88    Array(Vec<Expr>),
89    Variant(Variant),
90
91    Range(Range),
92    Binary(BinaryExpr),
93    Unary(UnaryExpr),
94    Call(Call),
95    Func(Box<Func>),
96    FuncShort(Box<FuncShort>),
97    FString(Vec<InterpolateItem>),
98    Match(Match),
99    If(If),
100
101    VarBinding(VarBinding),
102}
103
104#[derive(Debug, EnumAsInner, PartialEq, Clone)]
105pub enum Lookup {
106    Name(String),
107    Position(i64),
108}
109
110/// Expression with two operands and an operator, such as `1 + 2`.
111#[derive(Debug, PartialEq, Clone)]
112pub struct BinaryExpr {
113    pub left: Box<Expr>,
114    pub op: BinOp,
115    pub right: Box<Expr>,
116}
117
118/// Expression with one operand and an operator, such as `-1`.
119#[derive(Debug, PartialEq, Clone)]
120pub struct UnaryExpr {
121    pub op: UnOp,
122    pub expr: Box<Expr>,
123}
124
125/// Call of either a function, enum variant, or framed type constructor.
126#[derive(Debug, PartialEq, Clone)]
127pub struct Call {
128    pub subject: Box<Expr>,
129    pub args: Vec<CallArg>,
130}
131
132#[derive(Debug, PartialEq, Clone)]
133pub struct CallArg {
134    pub label: Option<String>,
135    pub expr: Expr,
136    pub span: Option<Span>,
137}
138
139impl CallArg {
140    pub fn simple(expr: Expr) -> Self {
141        CallArg {
142            label: None,
143            span: expr.span,
144            expr,
145        }
146    }
147}
148
149/// Function. `func (p1: P1, p2: P2): B where T -> b`
150#[derive(Debug, PartialEq, Clone)]
151pub struct Func {
152    /// Function parameters.
153    pub params: Vec<FuncParam>,
154
155    /// Type requirement for the function body expression.
156    pub return_ty: Option<Ty>,
157
158    /// Expression containing parameter references.
159    pub body: Option<Box<Expr>>,
160
161    /// Parameters of the types within this function (where clause).
162    pub ty_params: Vec<TyParam>,
163}
164
165/// Function, short notation. `x -> b`
166#[derive(Debug, PartialEq, Clone)]
167pub struct FuncShort {
168    /// Function parameter.
169    pub param: FuncParam,
170
171    /// Expression containing parameter (and environment) references.
172    pub body: Box<Expr>,
173}
174
175#[derive(Debug, PartialEq, Clone)]
176pub struct FuncParam {
177    /// When true, arg used for this param must be a const value.
178    pub constant: bool,
179
180    /// Public name of the paramater, that can be specified in function calls.
181    pub label: Option<String>,
182
183    /// Parameter name that can be referenced in the function.
184    pub name: String,
185
186    /// Type requirement for this param.
187    pub ty: Option<Ty>,
188
189    pub span: Span,
190}
191
192/// A value and a series of functions that are to be applied to that value one after another.
193#[derive(Debug, PartialEq, Clone)]
194pub struct Pipeline {
195    /// Items of the pipeline. Must contain at least one element.
196    pub exprs: Vec<Expr>,
197}
198
199#[derive(Debug, PartialEq, Clone)]
200pub struct TypeAnnotation {
201    pub expr: Box<Expr>,
202    pub ty: Box<Ty>,
203}
204
205/// Tuple field. `name = expr` or `..expr`
206#[derive(Debug, PartialEq, Clone)]
207pub struct TupleField {
208    pub name: Option<String>,
209    pub unpack: bool,
210    pub expr: Expr,
211}
212
213/// Enum variant. `.name(inner)`
214#[derive(Debug, PartialEq, Clone)]
215pub struct Variant {
216    pub name: String,
217    pub inner: Option<Box<Expr>>,
218}
219
220/// Inclusive-inclusive range.
221/// Missing bound means unbounded range.
222#[derive(Debug, Clone, Default, PartialEq)]
223pub struct Range {
224    pub start: Option<Box<Expr>>,
225    pub end: Option<Box<Expr>>,
226}
227
228impl Range {
229    pub const fn unbounded() -> Self {
230        Range {
231            start: None,
232            end: None,
233        }
234    }
235}
236
237#[derive(Debug, Clone, PartialEq)]
238pub enum InterpolateItem {
239    String(String),
240    Expr {
241        expr: Box<Expr>,
242        format: Option<String>,
243    },
244}
245
246#[derive(Debug, Clone, PartialEq)]
247pub struct Match {
248    pub subject: Box<Expr>,
249
250    // contract: there will be at least one branch
251    pub branches: Vec<MatchBranch>,
252}
253
254#[derive(Debug, Clone, PartialEq)]
255pub struct MatchBranch {
256    pub pattern: Pattern,
257    pub value: Box<Expr>,
258}
259
260/// A pattern that can be matched against an expression.
261#[derive(Debug, Clone, PartialEq)]
262pub struct Pattern {
263    pub kind: PatternKind,
264    pub span: Span,
265    pub variant_tag: Option<usize>,
266}
267
268#[derive(Debug, Clone, PartialEq, strum::AsRefStr)]
269pub enum PatternKind {
270    /// Match an enum variant, recurse into matching inner
271    Enum(String, Option<Box<Pattern>>),
272
273    /// Match value of a primitive type
274    Literal(Literal),
275
276    /// Match any of the following
277    AnyOf(Vec<Pattern>),
278
279    /// Match anything, bind it to a name
280    Bind(String),
281}
282
283impl Pattern {
284    pub fn new_with_span(kind: PatternKind, span: Span) -> Self {
285        Self {
286            kind,
287            span,
288            variant_tag: None,
289        }
290    }
291}
292
293#[derive(Debug, Clone, PartialEq)]
294pub struct If {
295    pub condition: Box<Expr>,
296    pub then: Box<Expr>,
297    pub els: Box<Expr>,
298}
299
300#[derive(Debug, Clone, PartialEq)]
301pub struct VarBinding {
302    pub name: String,
303    pub bound: Box<Expr>,
304    pub main: Box<Expr>,
305}
306
307impl From<Literal> for ExprKind {
308    fn from(value: Literal) -> Self {
309        ExprKind::Literal(value)
310    }
311}
312
313impl From<Func> for ExprKind {
314    fn from(value: Func) -> Self {
315        ExprKind::Func(Box::new(value))
316    }
317}
318
319impl From<Path> for ExprKind {
320    fn from(value: Path) -> Self {
321        ExprKind::Ident(value)
322    }
323}
324
325impl From<Range> for ExprKind {
326    fn from(value: Range) -> Self {
327        ExprKind::Range(value)
328    }
329}
330
331impl From<Variant> for ExprKind {
332    fn from(value: Variant) -> Self {
333        ExprKind::Variant(value)
334    }
335}
336
337impl From<TypeAnnotation> for ExprKind {
338    fn from(value: TypeAnnotation) -> Self {
339        ExprKind::TypeAnnotation(value)
340    }
341}