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 is_pub: bool,
41 },
42 LetBinding {
43 pattern: BindingPattern,
44 type_ann: Option<TypeExpr>,
45 value: Box<SNode>,
46 },
47 VarBinding {
48 pattern: BindingPattern,
49 type_ann: Option<TypeExpr>,
50 value: Box<SNode>,
51 },
52 OverrideDecl {
53 name: String,
54 params: Vec<String>,
55 body: Vec<SNode>,
56 },
57 ImportDecl {
58 path: String,
59 },
60 SelectiveImport {
62 names: Vec<String>,
63 path: String,
64 },
65 EnumDecl {
66 name: String,
67 type_params: Vec<TypeParam>,
68 variants: Vec<EnumVariant>,
69 is_pub: bool,
70 },
71 StructDecl {
72 name: String,
73 type_params: Vec<TypeParam>,
74 fields: Vec<StructField>,
75 is_pub: bool,
76 },
77 InterfaceDecl {
78 name: String,
79 type_params: Vec<TypeParam>,
80 associated_types: Vec<(String, Option<TypeExpr>)>,
81 methods: Vec<InterfaceMethod>,
82 },
83 ImplBlock {
85 type_name: String,
86 methods: Vec<SNode>,
87 },
88
89 IfElse {
91 condition: Box<SNode>,
92 then_body: Vec<SNode>,
93 else_body: Option<Vec<SNode>>,
94 },
95 ForIn {
96 pattern: BindingPattern,
97 iterable: Box<SNode>,
98 body: Vec<SNode>,
99 },
100 MatchExpr {
101 value: Box<SNode>,
102 arms: Vec<MatchArm>,
103 },
104 WhileLoop {
105 condition: Box<SNode>,
106 body: Vec<SNode>,
107 },
108 Retry {
109 count: Box<SNode>,
110 body: Vec<SNode>,
111 },
112 ReturnStmt {
113 value: Option<Box<SNode>>,
114 },
115 TryCatch {
116 body: Vec<SNode>,
117 error_var: Option<String>,
118 error_type: Option<TypeExpr>,
119 catch_body: Vec<SNode>,
120 finally_body: Option<Vec<SNode>>,
121 },
122 TryExpr {
124 body: Vec<SNode>,
125 },
126 FnDecl {
127 name: String,
128 type_params: Vec<TypeParam>,
129 params: Vec<TypedParam>,
130 return_type: Option<TypeExpr>,
131 where_clauses: Vec<WhereClause>,
132 body: Vec<SNode>,
133 is_pub: bool,
134 },
135 ToolDecl {
136 name: String,
137 description: Option<String>,
138 params: Vec<TypedParam>,
139 return_type: Option<TypeExpr>,
140 body: Vec<SNode>,
141 is_pub: bool,
142 },
143 TypeDecl {
144 name: String,
145 type_expr: TypeExpr,
146 },
147 SpawnExpr {
148 body: Vec<SNode>,
149 },
150 DurationLiteral(u64),
152 RangeExpr {
154 start: Box<SNode>,
155 end: Box<SNode>,
156 inclusive: bool,
157 },
158 GuardStmt {
160 condition: Box<SNode>,
161 else_body: Vec<SNode>,
162 },
163 RequireStmt {
164 condition: Box<SNode>,
165 message: Option<Box<SNode>>,
166 },
167 DeferStmt {
169 body: Vec<SNode>,
170 },
171 DeadlineBlock {
173 duration: Box<SNode>,
174 body: Vec<SNode>,
175 },
176 YieldExpr {
178 value: Option<Box<SNode>>,
179 },
180 MutexBlock {
182 body: Vec<SNode>,
183 },
184 BreakStmt,
186 ContinueStmt,
188
189 Parallel {
191 mode: ParallelMode,
192 expr: Box<SNode>,
194 variable: Option<String>,
195 body: Vec<SNode>,
196 options: Vec<(String, SNode)>,
201 },
202
203 SelectExpr {
204 cases: Vec<SelectCase>,
205 timeout: Option<(Box<SNode>, Vec<SNode>)>,
206 default_body: Option<Vec<SNode>>,
207 },
208
209 FunctionCall {
211 name: String,
212 args: Vec<SNode>,
213 },
214 MethodCall {
215 object: Box<SNode>,
216 method: String,
217 args: Vec<SNode>,
218 },
219 OptionalMethodCall {
221 object: Box<SNode>,
222 method: String,
223 args: Vec<SNode>,
224 },
225 PropertyAccess {
226 object: Box<SNode>,
227 property: String,
228 },
229 OptionalPropertyAccess {
231 object: Box<SNode>,
232 property: String,
233 },
234 SubscriptAccess {
235 object: Box<SNode>,
236 index: Box<SNode>,
237 },
238 SliceAccess {
239 object: Box<SNode>,
240 start: Option<Box<SNode>>,
241 end: Option<Box<SNode>>,
242 },
243 BinaryOp {
244 op: String,
245 left: Box<SNode>,
246 right: Box<SNode>,
247 },
248 UnaryOp {
249 op: String,
250 operand: Box<SNode>,
251 },
252 Ternary {
253 condition: Box<SNode>,
254 true_expr: Box<SNode>,
255 false_expr: Box<SNode>,
256 },
257 Assignment {
258 target: Box<SNode>,
259 value: Box<SNode>,
260 op: Option<String>,
262 },
263 ThrowStmt {
264 value: Box<SNode>,
265 },
266
267 EnumConstruct {
269 enum_name: String,
270 variant: String,
271 args: Vec<SNode>,
272 },
273 StructConstruct {
275 struct_name: String,
276 fields: Vec<DictEntry>,
277 },
278
279 InterpolatedString(Vec<StringSegment>),
281 StringLiteral(String),
282 RawStringLiteral(String),
284 IntLiteral(i64),
285 FloatLiteral(f64),
286 BoolLiteral(bool),
287 NilLiteral,
288 Identifier(String),
289 ListLiteral(Vec<SNode>),
290 DictLiteral(Vec<DictEntry>),
291 Spread(Box<SNode>),
293 TryOperator {
295 operand: Box<SNode>,
296 },
297
298 Block(Vec<SNode>),
300 Closure {
301 params: Vec<TypedParam>,
302 body: Vec<SNode>,
303 fn_syntax: bool,
306 },
307}
308
309#[derive(Debug, Clone, Copy, PartialEq)]
311pub enum ParallelMode {
312 Count,
314 Each,
316 Settle,
318}
319
320#[derive(Debug, Clone, PartialEq)]
321pub struct MatchArm {
322 pub pattern: SNode,
323 pub guard: Option<Box<SNode>>,
325 pub body: Vec<SNode>,
326}
327
328#[derive(Debug, Clone, PartialEq)]
329pub struct SelectCase {
330 pub variable: String,
331 pub channel: Box<SNode>,
332 pub body: Vec<SNode>,
333}
334
335#[derive(Debug, Clone, PartialEq)]
336pub struct DictEntry {
337 pub key: SNode,
338 pub value: SNode,
339}
340
341#[derive(Debug, Clone, PartialEq)]
343pub struct EnumVariant {
344 pub name: String,
345 pub fields: Vec<TypedParam>,
346}
347
348#[derive(Debug, Clone, PartialEq)]
350pub struct StructField {
351 pub name: String,
352 pub type_expr: Option<TypeExpr>,
353 pub optional: bool,
354}
355
356#[derive(Debug, Clone, PartialEq)]
358pub struct InterfaceMethod {
359 pub name: String,
360 pub type_params: Vec<TypeParam>,
361 pub params: Vec<TypedParam>,
362 pub return_type: Option<TypeExpr>,
363}
364
365#[derive(Debug, Clone, PartialEq)]
367pub enum TypeExpr {
368 Named(String),
371 Union(Vec<TypeExpr>),
373 Shape(Vec<ShapeField>),
375 List(Box<TypeExpr>),
377 DictType(Box<TypeExpr>, Box<TypeExpr>),
379 Applied { name: String, args: Vec<TypeExpr> },
381 FnType {
383 params: Vec<TypeExpr>,
384 return_type: Box<TypeExpr>,
385 },
386 Never,
389}
390
391#[derive(Debug, Clone, PartialEq)]
393pub struct ShapeField {
394 pub name: String,
395 pub type_expr: TypeExpr,
396 pub optional: bool,
397}
398
399#[derive(Debug, Clone, PartialEq)]
401pub enum BindingPattern {
402 Identifier(String),
404 Dict(Vec<DictPatternField>),
406 List(Vec<ListPatternElement>),
408}
409
410#[derive(Debug, Clone, PartialEq)]
412pub struct DictPatternField {
413 pub key: String,
415 pub alias: Option<String>,
417 pub is_rest: bool,
419 pub default_value: Option<Box<SNode>>,
421}
422
423#[derive(Debug, Clone, PartialEq)]
425pub struct ListPatternElement {
426 pub name: String,
428 pub is_rest: bool,
430 pub default_value: Option<Box<SNode>>,
432}
433
434#[derive(Debug, Clone, PartialEq)]
436pub struct TypeParam {
437 pub name: String,
438}
439
440#[derive(Debug, Clone, PartialEq)]
442pub struct WhereClause {
443 pub type_name: String,
444 pub bound: String,
445}
446
447#[derive(Debug, Clone, PartialEq)]
449pub struct TypedParam {
450 pub name: String,
451 pub type_expr: Option<TypeExpr>,
452 pub default_value: Option<Box<SNode>>,
453 pub rest: bool,
455}
456
457impl TypedParam {
458 pub fn untyped(name: impl Into<String>) -> Self {
460 Self {
461 name: name.into(),
462 type_expr: None,
463 default_value: None,
464 rest: false,
465 }
466 }
467
468 pub fn typed(name: impl Into<String>, type_expr: TypeExpr) -> Self {
470 Self {
471 name: name.into(),
472 type_expr: Some(type_expr),
473 default_value: None,
474 rest: false,
475 }
476 }
477
478 pub fn names(params: &[TypedParam]) -> Vec<String> {
480 params.iter().map(|p| p.name.clone()).collect()
481 }
482
483 pub fn default_start(params: &[TypedParam]) -> Option<usize> {
485 params.iter().position(|p| p.default_value.is_some())
486 }
487}