1use harn_lexer::{Span, StringSegment};
2
3#[derive(Debug, Clone, PartialEq)]
5pub struct Spanned<T> {
6 pub node: T,
7 pub span: Span,
8}
9
10impl<T> Spanned<T> {
11 pub fn new(node: T, span: Span) -> Self {
12 Self { node, span }
13 }
14
15 pub fn dummy(node: T) -> Self {
16 Self {
17 node,
18 span: Span::dummy(),
19 }
20 }
21}
22
23pub type SNode = Spanned<Node>;
25
26pub fn spanned(node: Node, span: Span) -> SNode {
28 SNode::new(node, span)
29}
30
31#[derive(Debug, Clone, PartialEq)]
33pub enum Node {
34 Pipeline {
36 name: String,
37 params: Vec<String>,
38 body: Vec<SNode>,
39 extends: Option<String>,
40 },
41 LetBinding {
42 pattern: BindingPattern,
43 type_ann: Option<TypeExpr>,
44 value: Box<SNode>,
45 },
46 VarBinding {
47 pattern: BindingPattern,
48 type_ann: Option<TypeExpr>,
49 value: Box<SNode>,
50 },
51 OverrideDecl {
52 name: String,
53 params: Vec<String>,
54 body: Vec<SNode>,
55 },
56 ImportDecl {
57 path: String,
58 },
59 SelectiveImport {
61 names: Vec<String>,
62 path: String,
63 },
64 EnumDecl {
65 name: String,
66 variants: Vec<EnumVariant>,
67 },
68 StructDecl {
69 name: String,
70 fields: Vec<StructField>,
71 },
72 InterfaceDecl {
73 name: String,
74 methods: Vec<InterfaceMethod>,
75 },
76
77 IfElse {
79 condition: Box<SNode>,
80 then_body: Vec<SNode>,
81 else_body: Option<Vec<SNode>>,
82 },
83 ForIn {
84 pattern: BindingPattern,
85 iterable: Box<SNode>,
86 body: Vec<SNode>,
87 },
88 MatchExpr {
89 value: Box<SNode>,
90 arms: Vec<MatchArm>,
91 },
92 WhileLoop {
93 condition: Box<SNode>,
94 body: Vec<SNode>,
95 },
96 Retry {
97 count: Box<SNode>,
98 body: Vec<SNode>,
99 },
100 ReturnStmt {
101 value: Option<Box<SNode>>,
102 },
103 TryCatch {
104 body: Vec<SNode>,
105 error_var: Option<String>,
106 error_type: Option<TypeExpr>,
107 catch_body: Vec<SNode>,
108 finally_body: Option<Vec<SNode>>,
109 },
110 FnDecl {
111 name: String,
112 type_params: Vec<TypeParam>,
113 params: Vec<TypedParam>,
114 return_type: Option<TypeExpr>,
115 where_clauses: Vec<WhereClause>,
116 body: Vec<SNode>,
117 is_pub: bool,
118 },
119 TypeDecl {
120 name: String,
121 type_expr: TypeExpr,
122 },
123 SpawnExpr {
124 body: Vec<SNode>,
125 },
126 DurationLiteral(u64),
128 RangeExpr {
130 start: Box<SNode>,
131 end: Box<SNode>,
132 inclusive: bool,
133 },
134 GuardStmt {
136 condition: Box<SNode>,
137 else_body: Vec<SNode>,
138 },
139 AskExpr {
141 fields: Vec<DictEntry>,
142 },
143 DeadlineBlock {
145 duration: Box<SNode>,
146 body: Vec<SNode>,
147 },
148 YieldExpr {
150 value: Option<Box<SNode>>,
151 },
152 MutexBlock {
154 body: Vec<SNode>,
155 },
156 BreakStmt,
158 ContinueStmt,
160
161 Parallel {
163 count: Box<SNode>,
164 variable: Option<String>,
165 body: Vec<SNode>,
166 },
167 ParallelMap {
168 list: Box<SNode>,
169 variable: String,
170 body: Vec<SNode>,
171 },
172
173 SelectExpr {
174 cases: Vec<SelectCase>,
175 timeout: Option<(Box<SNode>, Vec<SNode>)>,
176 default_body: Option<Vec<SNode>>,
177 },
178
179 FunctionCall {
181 name: String,
182 args: Vec<SNode>,
183 },
184 MethodCall {
185 object: Box<SNode>,
186 method: String,
187 args: Vec<SNode>,
188 },
189 OptionalMethodCall {
191 object: Box<SNode>,
192 method: String,
193 args: Vec<SNode>,
194 },
195 PropertyAccess {
196 object: Box<SNode>,
197 property: String,
198 },
199 OptionalPropertyAccess {
201 object: Box<SNode>,
202 property: String,
203 },
204 SubscriptAccess {
205 object: Box<SNode>,
206 index: Box<SNode>,
207 },
208 SliceAccess {
209 object: Box<SNode>,
210 start: Option<Box<SNode>>,
211 end: Option<Box<SNode>>,
212 },
213 BinaryOp {
214 op: String,
215 left: Box<SNode>,
216 right: Box<SNode>,
217 },
218 UnaryOp {
219 op: String,
220 operand: Box<SNode>,
221 },
222 Ternary {
223 condition: Box<SNode>,
224 true_expr: Box<SNode>,
225 false_expr: Box<SNode>,
226 },
227 Assignment {
228 target: Box<SNode>,
229 value: Box<SNode>,
230 op: Option<String>,
232 },
233 ThrowStmt {
234 value: Box<SNode>,
235 },
236
237 EnumConstruct {
239 enum_name: String,
240 variant: String,
241 args: Vec<SNode>,
242 },
243 StructConstruct {
245 struct_name: String,
246 fields: Vec<DictEntry>,
247 },
248
249 InterpolatedString(Vec<StringSegment>),
251 StringLiteral(String),
252 IntLiteral(i64),
253 FloatLiteral(f64),
254 BoolLiteral(bool),
255 NilLiteral,
256 Identifier(String),
257 ListLiteral(Vec<SNode>),
258 DictLiteral(Vec<DictEntry>),
259 Spread(Box<SNode>),
261
262 Block(Vec<SNode>),
264 Closure {
265 params: Vec<TypedParam>,
266 body: Vec<SNode>,
267 },
268}
269
270#[derive(Debug, Clone, PartialEq)]
271pub struct MatchArm {
272 pub pattern: SNode,
273 pub body: Vec<SNode>,
274}
275
276#[derive(Debug, Clone, PartialEq)]
277pub struct SelectCase {
278 pub variable: String,
279 pub channel: Box<SNode>,
280 pub body: Vec<SNode>,
281}
282
283#[derive(Debug, Clone, PartialEq)]
284pub struct DictEntry {
285 pub key: SNode,
286 pub value: SNode,
287}
288
289#[derive(Debug, Clone, PartialEq)]
291pub struct EnumVariant {
292 pub name: String,
293 pub fields: Vec<TypedParam>,
294}
295
296#[derive(Debug, Clone, PartialEq)]
298pub struct StructField {
299 pub name: String,
300 pub type_expr: Option<TypeExpr>,
301 pub optional: bool,
302}
303
304#[derive(Debug, Clone, PartialEq)]
306pub struct InterfaceMethod {
307 pub name: String,
308 pub params: Vec<TypedParam>,
309 pub return_type: Option<TypeExpr>,
310}
311
312#[derive(Debug, Clone, PartialEq)]
314pub enum TypeExpr {
315 Named(String),
318 Union(Vec<TypeExpr>),
320 Shape(Vec<ShapeField>),
322 List(Box<TypeExpr>),
324 DictType(Box<TypeExpr>, Box<TypeExpr>),
326 FnType {
328 params: Vec<TypeExpr>,
329 return_type: Box<TypeExpr>,
330 },
331}
332
333#[derive(Debug, Clone, PartialEq)]
335pub struct ShapeField {
336 pub name: String,
337 pub type_expr: TypeExpr,
338 pub optional: bool,
339}
340
341#[derive(Debug, Clone, PartialEq)]
343pub enum BindingPattern {
344 Identifier(String),
346 Dict(Vec<DictPatternField>),
348 List(Vec<ListPatternElement>),
350}
351
352#[derive(Debug, Clone, PartialEq)]
354pub struct DictPatternField {
355 pub key: String,
357 pub alias: Option<String>,
359 pub is_rest: bool,
361}
362
363#[derive(Debug, Clone, PartialEq)]
365pub struct ListPatternElement {
366 pub name: String,
368 pub is_rest: bool,
370}
371
372#[derive(Debug, Clone, PartialEq)]
374pub struct TypeParam {
375 pub name: String,
376}
377
378#[derive(Debug, Clone, PartialEq)]
380pub struct WhereClause {
381 pub type_name: String,
382 pub bound: String,
383}
384
385#[derive(Debug, Clone, PartialEq)]
387pub struct TypedParam {
388 pub name: String,
389 pub type_expr: Option<TypeExpr>,
390 pub default_value: Option<Box<SNode>>,
391}
392
393impl TypedParam {
394 pub fn untyped(name: impl Into<String>) -> Self {
396 Self {
397 name: name.into(),
398 type_expr: None,
399 default_value: None,
400 }
401 }
402
403 pub fn typed(name: impl Into<String>, type_expr: TypeExpr) -> Self {
405 Self {
406 name: name.into(),
407 type_expr: Some(type_expr),
408 default_value: None,
409 }
410 }
411
412 pub fn names(params: &[TypedParam]) -> Vec<String> {
414 params.iter().map(|p| p.name.clone()).collect()
415 }
416
417 pub fn default_start(params: &[TypedParam]) -> Option<usize> {
419 params.iter().position(|p| p.default_value.is_some())
420 }
421}