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
31pub fn peel_attributes(node: &SNode) -> (&[Attribute], &SNode) {
36 match &node.node {
37 Node::AttributedDecl { attributes, inner } => (attributes.as_slice(), inner.as_ref()),
38 _ => (&[], node),
39 }
40}
41
42#[derive(Debug, Clone, PartialEq)]
46pub struct AttributeArg {
47 pub name: Option<String>,
48 pub value: SNode,
49 pub span: Span,
50}
51
52#[derive(Debug, Clone, PartialEq)]
54pub struct Attribute {
55 pub name: String,
56 pub args: Vec<AttributeArg>,
57 pub span: Span,
58}
59
60impl Attribute {
61 pub fn named_arg(&self, key: &str) -> Option<&SNode> {
63 self.args
64 .iter()
65 .find(|a| a.name.as_deref() == Some(key))
66 .map(|a| &a.value)
67 }
68
69 pub fn positional(&self, idx: usize) -> Option<&SNode> {
71 self.args
72 .iter()
73 .filter(|a| a.name.is_none())
74 .nth(idx)
75 .map(|a| &a.value)
76 }
77
78 pub fn string_arg(&self, key: &str) -> Option<String> {
80 match self.named_arg(key).map(|n| &n.node) {
81 Some(Node::StringLiteral(s)) => Some(s.clone()),
82 Some(Node::RawStringLiteral(s)) => Some(s.clone()),
83 _ => None,
84 }
85 }
86}
87
88#[derive(Debug, Clone, PartialEq)]
90pub enum Node {
91 AttributedDecl {
95 attributes: Vec<Attribute>,
96 inner: Box<SNode>,
97 },
98 Pipeline {
99 name: String,
100 params: Vec<String>,
101 return_type: Option<TypeExpr>,
102 body: Vec<SNode>,
103 extends: Option<String>,
104 is_pub: bool,
105 },
106 LetBinding {
107 pattern: BindingPattern,
108 type_ann: Option<TypeExpr>,
109 value: Box<SNode>,
110 },
111 VarBinding {
112 pattern: BindingPattern,
113 type_ann: Option<TypeExpr>,
114 value: Box<SNode>,
115 },
116 OverrideDecl {
117 name: String,
118 params: Vec<String>,
119 body: Vec<SNode>,
120 },
121 ImportDecl {
122 path: String,
123 },
124 SelectiveImport {
126 names: Vec<String>,
127 path: String,
128 },
129 EnumDecl {
130 name: String,
131 type_params: Vec<TypeParam>,
132 variants: Vec<EnumVariant>,
133 is_pub: bool,
134 },
135 StructDecl {
136 name: String,
137 type_params: Vec<TypeParam>,
138 fields: Vec<StructField>,
139 is_pub: bool,
140 },
141 InterfaceDecl {
142 name: String,
143 type_params: Vec<TypeParam>,
144 associated_types: Vec<(String, Option<TypeExpr>)>,
145 methods: Vec<InterfaceMethod>,
146 },
147 ImplBlock {
149 type_name: String,
150 methods: Vec<SNode>,
151 },
152
153 IfElse {
154 condition: Box<SNode>,
155 then_body: Vec<SNode>,
156 else_body: Option<Vec<SNode>>,
157 },
158 ForIn {
159 pattern: BindingPattern,
160 iterable: Box<SNode>,
161 body: Vec<SNode>,
162 },
163 MatchExpr {
164 value: Box<SNode>,
165 arms: Vec<MatchArm>,
166 },
167 WhileLoop {
168 condition: Box<SNode>,
169 body: Vec<SNode>,
170 },
171 Retry {
172 count: Box<SNode>,
173 body: Vec<SNode>,
174 },
175 ReturnStmt {
176 value: Option<Box<SNode>>,
177 },
178 TryCatch {
179 body: Vec<SNode>,
180 error_var: Option<String>,
181 error_type: Option<TypeExpr>,
182 catch_body: Vec<SNode>,
183 finally_body: Option<Vec<SNode>>,
184 },
185 TryExpr {
187 body: Vec<SNode>,
188 },
189 FnDecl {
190 name: String,
191 type_params: Vec<TypeParam>,
192 params: Vec<TypedParam>,
193 return_type: Option<TypeExpr>,
194 where_clauses: Vec<WhereClause>,
195 body: Vec<SNode>,
196 is_pub: bool,
197 },
198 ToolDecl {
199 name: String,
200 description: Option<String>,
201 params: Vec<TypedParam>,
202 return_type: Option<TypeExpr>,
203 body: Vec<SNode>,
204 is_pub: bool,
205 },
206 SkillDecl {
214 name: String,
215 fields: Vec<(String, SNode)>,
216 is_pub: bool,
217 },
218 TypeDecl {
219 name: String,
220 type_params: Vec<TypeParam>,
221 type_expr: TypeExpr,
222 },
223 SpawnExpr {
224 body: Vec<SNode>,
225 },
226 DurationLiteral(u64),
228 RangeExpr {
230 start: Box<SNode>,
231 end: Box<SNode>,
232 inclusive: bool,
233 },
234 GuardStmt {
236 condition: Box<SNode>,
237 else_body: Vec<SNode>,
238 },
239 RequireStmt {
240 condition: Box<SNode>,
241 message: Option<Box<SNode>>,
242 },
243 DeferStmt {
245 body: Vec<SNode>,
246 },
247 DeadlineBlock {
249 duration: Box<SNode>,
250 body: Vec<SNode>,
251 },
252 YieldExpr {
254 value: Option<Box<SNode>>,
255 },
256 MutexBlock {
258 body: Vec<SNode>,
259 },
260 BreakStmt,
262 ContinueStmt,
264
265 Parallel {
266 mode: ParallelMode,
267 expr: Box<SNode>,
269 variable: Option<String>,
270 body: Vec<SNode>,
271 options: Vec<(String, SNode)>,
276 },
277
278 SelectExpr {
279 cases: Vec<SelectCase>,
280 timeout: Option<(Box<SNode>, Vec<SNode>)>,
281 default_body: Option<Vec<SNode>>,
282 },
283
284 FunctionCall {
285 name: String,
286 args: Vec<SNode>,
287 },
288 MethodCall {
289 object: Box<SNode>,
290 method: String,
291 args: Vec<SNode>,
292 },
293 OptionalMethodCall {
295 object: Box<SNode>,
296 method: String,
297 args: Vec<SNode>,
298 },
299 PropertyAccess {
300 object: Box<SNode>,
301 property: String,
302 },
303 OptionalPropertyAccess {
305 object: Box<SNode>,
306 property: String,
307 },
308 SubscriptAccess {
309 object: Box<SNode>,
310 index: Box<SNode>,
311 },
312 SliceAccess {
313 object: Box<SNode>,
314 start: Option<Box<SNode>>,
315 end: Option<Box<SNode>>,
316 },
317 BinaryOp {
318 op: String,
319 left: Box<SNode>,
320 right: Box<SNode>,
321 },
322 UnaryOp {
323 op: String,
324 operand: Box<SNode>,
325 },
326 Ternary {
327 condition: Box<SNode>,
328 true_expr: Box<SNode>,
329 false_expr: Box<SNode>,
330 },
331 Assignment {
332 target: Box<SNode>,
333 value: Box<SNode>,
334 op: Option<String>,
336 },
337 ThrowStmt {
338 value: Box<SNode>,
339 },
340
341 EnumConstruct {
343 enum_name: String,
344 variant: String,
345 args: Vec<SNode>,
346 },
347 StructConstruct {
349 struct_name: String,
350 fields: Vec<DictEntry>,
351 },
352
353 InterpolatedString(Vec<StringSegment>),
354 StringLiteral(String),
355 RawStringLiteral(String),
357 IntLiteral(i64),
358 FloatLiteral(f64),
359 BoolLiteral(bool),
360 NilLiteral,
361 Identifier(String),
362 ListLiteral(Vec<SNode>),
363 DictLiteral(Vec<DictEntry>),
364 Spread(Box<SNode>),
366 TryOperator {
368 operand: Box<SNode>,
369 },
370 TryStar {
378 operand: Box<SNode>,
379 },
380
381 OrPattern(Vec<SNode>),
385
386 Block(Vec<SNode>),
387 Closure {
388 params: Vec<TypedParam>,
389 body: Vec<SNode>,
390 fn_syntax: bool,
393 },
394}
395
396#[derive(Debug, Clone, Copy, PartialEq)]
398pub enum ParallelMode {
399 Count,
401 Each,
403 Settle,
405}
406
407#[derive(Debug, Clone, PartialEq)]
408pub struct MatchArm {
409 pub pattern: SNode,
410 pub guard: Option<Box<SNode>>,
412 pub body: Vec<SNode>,
413}
414
415#[derive(Debug, Clone, PartialEq)]
416pub struct SelectCase {
417 pub variable: String,
418 pub channel: Box<SNode>,
419 pub body: Vec<SNode>,
420}
421
422#[derive(Debug, Clone, PartialEq)]
423pub struct DictEntry {
424 pub key: SNode,
425 pub value: SNode,
426}
427
428#[derive(Debug, Clone, PartialEq)]
430pub struct EnumVariant {
431 pub name: String,
432 pub fields: Vec<TypedParam>,
433}
434
435#[derive(Debug, Clone, PartialEq)]
437pub struct StructField {
438 pub name: String,
439 pub type_expr: Option<TypeExpr>,
440 pub optional: bool,
441}
442
443#[derive(Debug, Clone, PartialEq)]
445pub struct InterfaceMethod {
446 pub name: String,
447 pub type_params: Vec<TypeParam>,
448 pub params: Vec<TypedParam>,
449 pub return_type: Option<TypeExpr>,
450}
451
452#[derive(Debug, Clone, PartialEq)]
454pub enum TypeExpr {
455 Named(String),
458 Union(Vec<TypeExpr>),
460 Shape(Vec<ShapeField>),
462 List(Box<TypeExpr>),
464 DictType(Box<TypeExpr>, Box<TypeExpr>),
466 Iter(Box<TypeExpr>),
469 Applied { name: String, args: Vec<TypeExpr> },
471 FnType {
473 params: Vec<TypeExpr>,
474 return_type: Box<TypeExpr>,
475 },
476 Never,
479 LitString(String),
482 LitInt(i64),
484}
485
486#[derive(Debug, Clone, PartialEq)]
488pub struct ShapeField {
489 pub name: String,
490 pub type_expr: TypeExpr,
491 pub optional: bool,
492}
493
494#[derive(Debug, Clone, PartialEq)]
496pub enum BindingPattern {
497 Identifier(String),
499 Dict(Vec<DictPatternField>),
501 List(Vec<ListPatternElement>),
503 Pair(String, String),
506}
507
508#[derive(Debug, Clone, PartialEq)]
510pub struct DictPatternField {
511 pub key: String,
513 pub alias: Option<String>,
515 pub is_rest: bool,
517 pub default_value: Option<Box<SNode>>,
519}
520
521#[derive(Debug, Clone, PartialEq)]
523pub struct ListPatternElement {
524 pub name: String,
526 pub is_rest: bool,
528 pub default_value: Option<Box<SNode>>,
530}
531
532#[derive(Debug, Clone, Copy, PartialEq, Eq)]
544pub enum Variance {
545 Invariant,
546 Covariant,
547 Contravariant,
548}
549
550#[derive(Debug, Clone, PartialEq)]
552pub struct TypeParam {
553 pub name: String,
554 pub variance: Variance,
555}
556
557impl TypeParam {
558 pub fn invariant(name: impl Into<String>) -> Self {
561 Self {
562 name: name.into(),
563 variance: Variance::Invariant,
564 }
565 }
566}
567
568#[derive(Debug, Clone, PartialEq)]
570pub struct WhereClause {
571 pub type_name: String,
572 pub bound: String,
573}
574
575#[derive(Debug, Clone, PartialEq)]
577pub struct TypedParam {
578 pub name: String,
579 pub type_expr: Option<TypeExpr>,
580 pub default_value: Option<Box<SNode>>,
581 pub rest: bool,
583}
584
585impl TypedParam {
586 pub fn untyped(name: impl Into<String>) -> Self {
588 Self {
589 name: name.into(),
590 type_expr: None,
591 default_value: None,
592 rest: false,
593 }
594 }
595
596 pub fn typed(name: impl Into<String>, type_expr: TypeExpr) -> Self {
598 Self {
599 name: name.into(),
600 type_expr: Some(type_expr),
601 default_value: None,
602 rest: false,
603 }
604 }
605
606 pub fn names(params: &[TypedParam]) -> Vec<String> {
608 params.iter().map(|p| p.name.clone()).collect()
609 }
610
611 pub fn default_start(params: &[TypedParam]) -> Option<usize> {
613 params.iter().position(|p| p.default_value.is_some())
614 }
615}