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 },
197
198 SelectExpr {
199 cases: Vec<SelectCase>,
200 timeout: Option<(Box<SNode>, Vec<SNode>)>,
201 default_body: Option<Vec<SNode>>,
202 },
203
204 FunctionCall {
206 name: String,
207 args: Vec<SNode>,
208 },
209 MethodCall {
210 object: Box<SNode>,
211 method: String,
212 args: Vec<SNode>,
213 },
214 OptionalMethodCall {
216 object: Box<SNode>,
217 method: String,
218 args: Vec<SNode>,
219 },
220 PropertyAccess {
221 object: Box<SNode>,
222 property: String,
223 },
224 OptionalPropertyAccess {
226 object: Box<SNode>,
227 property: String,
228 },
229 SubscriptAccess {
230 object: Box<SNode>,
231 index: Box<SNode>,
232 },
233 SliceAccess {
234 object: Box<SNode>,
235 start: Option<Box<SNode>>,
236 end: Option<Box<SNode>>,
237 },
238 BinaryOp {
239 op: String,
240 left: Box<SNode>,
241 right: Box<SNode>,
242 },
243 UnaryOp {
244 op: String,
245 operand: Box<SNode>,
246 },
247 Ternary {
248 condition: Box<SNode>,
249 true_expr: Box<SNode>,
250 false_expr: Box<SNode>,
251 },
252 Assignment {
253 target: Box<SNode>,
254 value: Box<SNode>,
255 op: Option<String>,
257 },
258 ThrowStmt {
259 value: Box<SNode>,
260 },
261
262 EnumConstruct {
264 enum_name: String,
265 variant: String,
266 args: Vec<SNode>,
267 },
268 StructConstruct {
270 struct_name: String,
271 fields: Vec<DictEntry>,
272 },
273
274 InterpolatedString(Vec<StringSegment>),
276 StringLiteral(String),
277 RawStringLiteral(String),
279 IntLiteral(i64),
280 FloatLiteral(f64),
281 BoolLiteral(bool),
282 NilLiteral,
283 Identifier(String),
284 ListLiteral(Vec<SNode>),
285 DictLiteral(Vec<DictEntry>),
286 Spread(Box<SNode>),
288 TryOperator {
290 operand: Box<SNode>,
291 },
292
293 Block(Vec<SNode>),
295 Closure {
296 params: Vec<TypedParam>,
297 body: Vec<SNode>,
298 fn_syntax: bool,
301 },
302}
303
304#[derive(Debug, Clone, Copy, PartialEq)]
306pub enum ParallelMode {
307 Count,
309 Each,
311 Settle,
313}
314
315#[derive(Debug, Clone, PartialEq)]
316pub struct MatchArm {
317 pub pattern: SNode,
318 pub guard: Option<Box<SNode>>,
320 pub body: Vec<SNode>,
321}
322
323#[derive(Debug, Clone, PartialEq)]
324pub struct SelectCase {
325 pub variable: String,
326 pub channel: Box<SNode>,
327 pub body: Vec<SNode>,
328}
329
330#[derive(Debug, Clone, PartialEq)]
331pub struct DictEntry {
332 pub key: SNode,
333 pub value: SNode,
334}
335
336#[derive(Debug, Clone, PartialEq)]
338pub struct EnumVariant {
339 pub name: String,
340 pub fields: Vec<TypedParam>,
341}
342
343#[derive(Debug, Clone, PartialEq)]
345pub struct StructField {
346 pub name: String,
347 pub type_expr: Option<TypeExpr>,
348 pub optional: bool,
349}
350
351#[derive(Debug, Clone, PartialEq)]
353pub struct InterfaceMethod {
354 pub name: String,
355 pub type_params: Vec<TypeParam>,
356 pub params: Vec<TypedParam>,
357 pub return_type: Option<TypeExpr>,
358}
359
360#[derive(Debug, Clone, PartialEq)]
362pub enum TypeExpr {
363 Named(String),
366 Union(Vec<TypeExpr>),
368 Shape(Vec<ShapeField>),
370 List(Box<TypeExpr>),
372 DictType(Box<TypeExpr>, Box<TypeExpr>),
374 Applied { name: String, args: Vec<TypeExpr> },
376 FnType {
378 params: Vec<TypeExpr>,
379 return_type: Box<TypeExpr>,
380 },
381 Never,
384}
385
386#[derive(Debug, Clone, PartialEq)]
388pub struct ShapeField {
389 pub name: String,
390 pub type_expr: TypeExpr,
391 pub optional: bool,
392}
393
394#[derive(Debug, Clone, PartialEq)]
396pub enum BindingPattern {
397 Identifier(String),
399 Dict(Vec<DictPatternField>),
401 List(Vec<ListPatternElement>),
403}
404
405#[derive(Debug, Clone, PartialEq)]
407pub struct DictPatternField {
408 pub key: String,
410 pub alias: Option<String>,
412 pub is_rest: bool,
414 pub default_value: Option<Box<SNode>>,
416}
417
418#[derive(Debug, Clone, PartialEq)]
420pub struct ListPatternElement {
421 pub name: String,
423 pub is_rest: bool,
425 pub default_value: Option<Box<SNode>>,
427}
428
429#[derive(Debug, Clone, PartialEq)]
431pub struct TypeParam {
432 pub name: String,
433}
434
435#[derive(Debug, Clone, PartialEq)]
437pub struct WhereClause {
438 pub type_name: String,
439 pub bound: String,
440}
441
442#[derive(Debug, Clone, PartialEq)]
444pub struct TypedParam {
445 pub name: String,
446 pub type_expr: Option<TypeExpr>,
447 pub default_value: Option<Box<SNode>>,
448 pub rest: bool,
450}
451
452impl TypedParam {
453 pub fn untyped(name: impl Into<String>) -> Self {
455 Self {
456 name: name.into(),
457 type_expr: None,
458 default_value: None,
459 rest: false,
460 }
461 }
462
463 pub fn typed(name: impl Into<String>, type_expr: TypeExpr) -> Self {
465 Self {
466 name: name.into(),
467 type_expr: Some(type_expr),
468 default_value: None,
469 rest: false,
470 }
471 }
472
473 pub fn names(params: &[TypedParam]) -> Vec<String> {
475 params.iter().map(|p| p.name.clone()).collect()
476 }
477
478 pub fn default_start(params: &[TypedParam]) -> Option<usize> {
480 params.iter().position(|p| p.default_value.is_some())
481 }
482}