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 is_pub: bool,
126 },
127 SelectiveImport {
129 names: Vec<String>,
130 path: String,
131 is_pub: bool,
134 },
135 EnumDecl {
136 name: String,
137 type_params: Vec<TypeParam>,
138 variants: Vec<EnumVariant>,
139 is_pub: bool,
140 },
141 StructDecl {
142 name: String,
143 type_params: Vec<TypeParam>,
144 fields: Vec<StructField>,
145 is_pub: bool,
146 },
147 InterfaceDecl {
148 name: String,
149 type_params: Vec<TypeParam>,
150 associated_types: Vec<(String, Option<TypeExpr>)>,
151 methods: Vec<InterfaceMethod>,
152 },
153 ImplBlock {
155 type_name: String,
156 methods: Vec<SNode>,
157 },
158
159 IfElse {
160 condition: Box<SNode>,
161 then_body: Vec<SNode>,
162 else_body: Option<Vec<SNode>>,
163 },
164 ForIn {
165 pattern: BindingPattern,
166 iterable: Box<SNode>,
167 body: Vec<SNode>,
168 },
169 MatchExpr {
170 value: Box<SNode>,
171 arms: Vec<MatchArm>,
172 },
173 WhileLoop {
174 condition: Box<SNode>,
175 body: Vec<SNode>,
176 },
177 Retry {
178 count: Box<SNode>,
179 body: Vec<SNode>,
180 },
181 ReturnStmt {
182 value: Option<Box<SNode>>,
183 },
184 TryCatch {
185 body: Vec<SNode>,
186 error_var: Option<String>,
187 error_type: Option<TypeExpr>,
188 catch_body: Vec<SNode>,
189 finally_body: Option<Vec<SNode>>,
190 },
191 TryExpr {
194 body: Vec<SNode>,
195 },
196 FnDecl {
197 name: String,
198 type_params: Vec<TypeParam>,
199 params: Vec<TypedParam>,
200 return_type: Option<TypeExpr>,
201 where_clauses: Vec<WhereClause>,
202 body: Vec<SNode>,
203 is_pub: bool,
204 },
205 ToolDecl {
206 name: String,
207 description: Option<String>,
208 params: Vec<TypedParam>,
209 return_type: Option<TypeExpr>,
210 body: Vec<SNode>,
211 is_pub: bool,
212 },
213 SkillDecl {
221 name: String,
222 fields: Vec<(String, SNode)>,
223 is_pub: bool,
224 },
225 TypeDecl {
226 name: String,
227 type_params: Vec<TypeParam>,
228 type_expr: TypeExpr,
229 },
230 SpawnExpr {
231 body: Vec<SNode>,
232 },
233 DurationLiteral(u64),
235 RangeExpr {
237 start: Box<SNode>,
238 end: Box<SNode>,
239 inclusive: bool,
240 },
241 GuardStmt {
243 condition: Box<SNode>,
244 else_body: Vec<SNode>,
245 },
246 RequireStmt {
247 condition: Box<SNode>,
248 message: Option<Box<SNode>>,
249 },
250 DeferStmt {
252 body: Vec<SNode>,
253 },
254 DeadlineBlock {
256 duration: Box<SNode>,
257 body: Vec<SNode>,
258 },
259 YieldExpr {
261 value: Option<Box<SNode>>,
262 },
263 MutexBlock {
265 body: Vec<SNode>,
266 },
267 BreakStmt,
269 ContinueStmt,
271
272 Parallel {
273 mode: ParallelMode,
274 expr: Box<SNode>,
276 variable: Option<String>,
277 body: Vec<SNode>,
278 options: Vec<(String, SNode)>,
283 },
284
285 SelectExpr {
286 cases: Vec<SelectCase>,
287 timeout: Option<(Box<SNode>, Vec<SNode>)>,
288 default_body: Option<Vec<SNode>>,
289 },
290
291 FunctionCall {
292 name: String,
293 args: Vec<SNode>,
294 },
295 MethodCall {
296 object: Box<SNode>,
297 method: String,
298 args: Vec<SNode>,
299 },
300 OptionalMethodCall {
302 object: Box<SNode>,
303 method: String,
304 args: Vec<SNode>,
305 },
306 PropertyAccess {
307 object: Box<SNode>,
308 property: String,
309 },
310 OptionalPropertyAccess {
312 object: Box<SNode>,
313 property: String,
314 },
315 SubscriptAccess {
316 object: Box<SNode>,
317 index: Box<SNode>,
318 },
319 OptionalSubscriptAccess {
321 object: Box<SNode>,
322 index: Box<SNode>,
323 },
324 SliceAccess {
325 object: Box<SNode>,
326 start: Option<Box<SNode>>,
327 end: Option<Box<SNode>>,
328 },
329 BinaryOp {
330 op: String,
331 left: Box<SNode>,
332 right: Box<SNode>,
333 },
334 UnaryOp {
335 op: String,
336 operand: Box<SNode>,
337 },
338 Ternary {
339 condition: Box<SNode>,
340 true_expr: Box<SNode>,
341 false_expr: Box<SNode>,
342 },
343 Assignment {
344 target: Box<SNode>,
345 value: Box<SNode>,
346 op: Option<String>,
348 },
349 ThrowStmt {
350 value: Box<SNode>,
351 },
352
353 EnumConstruct {
355 enum_name: String,
356 variant: String,
357 args: Vec<SNode>,
358 },
359 StructConstruct {
361 struct_name: String,
362 fields: Vec<DictEntry>,
363 },
364
365 InterpolatedString(Vec<StringSegment>),
366 StringLiteral(String),
367 RawStringLiteral(String),
369 IntLiteral(i64),
370 FloatLiteral(f64),
371 BoolLiteral(bool),
372 NilLiteral,
373 Identifier(String),
374 ListLiteral(Vec<SNode>),
375 DictLiteral(Vec<DictEntry>),
376 Spread(Box<SNode>),
378 TryOperator {
380 operand: Box<SNode>,
381 },
382 TryStar {
390 operand: Box<SNode>,
391 },
392
393 OrPattern(Vec<SNode>),
397
398 Block(Vec<SNode>),
399 Closure {
400 params: Vec<TypedParam>,
401 body: Vec<SNode>,
402 fn_syntax: bool,
405 },
406}
407
408#[derive(Debug, Clone, Copy, PartialEq)]
410pub enum ParallelMode {
411 Count,
413 Each,
415 Settle,
417}
418
419#[derive(Debug, Clone, PartialEq)]
420pub struct MatchArm {
421 pub pattern: SNode,
422 pub guard: Option<Box<SNode>>,
424 pub body: Vec<SNode>,
425}
426
427#[derive(Debug, Clone, PartialEq)]
428pub struct SelectCase {
429 pub variable: String,
430 pub channel: Box<SNode>,
431 pub body: Vec<SNode>,
432}
433
434#[derive(Debug, Clone, PartialEq)]
435pub struct DictEntry {
436 pub key: SNode,
437 pub value: SNode,
438}
439
440#[derive(Debug, Clone, PartialEq)]
442pub struct EnumVariant {
443 pub name: String,
444 pub fields: Vec<TypedParam>,
445}
446
447#[derive(Debug, Clone, PartialEq)]
449pub struct StructField {
450 pub name: String,
451 pub type_expr: Option<TypeExpr>,
452 pub optional: bool,
453}
454
455#[derive(Debug, Clone, PartialEq)]
457pub struct InterfaceMethod {
458 pub name: String,
459 pub type_params: Vec<TypeParam>,
460 pub params: Vec<TypedParam>,
461 pub return_type: Option<TypeExpr>,
462}
463
464#[derive(Debug, Clone, PartialEq)]
466pub enum TypeExpr {
467 Named(String),
470 Union(Vec<TypeExpr>),
472 Shape(Vec<ShapeField>),
474 List(Box<TypeExpr>),
476 DictType(Box<TypeExpr>, Box<TypeExpr>),
478 Iter(Box<TypeExpr>),
481 Applied { name: String, args: Vec<TypeExpr> },
483 FnType {
485 params: Vec<TypeExpr>,
486 return_type: Box<TypeExpr>,
487 },
488 Never,
491 LitString(String),
494 LitInt(i64),
496}
497
498#[derive(Debug, Clone, PartialEq)]
500pub struct ShapeField {
501 pub name: String,
502 pub type_expr: TypeExpr,
503 pub optional: bool,
504}
505
506#[derive(Debug, Clone, PartialEq)]
508pub enum BindingPattern {
509 Identifier(String),
511 Dict(Vec<DictPatternField>),
513 List(Vec<ListPatternElement>),
515 Pair(String, String),
518}
519
520pub fn is_discard_name(name: &str) -> bool {
522 name == "_"
523}
524
525#[derive(Debug, Clone, PartialEq)]
527pub struct DictPatternField {
528 pub key: String,
530 pub alias: Option<String>,
532 pub is_rest: bool,
534 pub default_value: Option<Box<SNode>>,
536}
537
538#[derive(Debug, Clone, PartialEq)]
540pub struct ListPatternElement {
541 pub name: String,
543 pub is_rest: bool,
545 pub default_value: Option<Box<SNode>>,
547}
548
549#[derive(Debug, Clone, Copy, PartialEq, Eq)]
561pub enum Variance {
562 Invariant,
563 Covariant,
564 Contravariant,
565}
566
567#[derive(Debug, Clone, PartialEq)]
569pub struct TypeParam {
570 pub name: String,
571 pub variance: Variance,
572}
573
574impl TypeParam {
575 pub fn invariant(name: impl Into<String>) -> Self {
578 Self {
579 name: name.into(),
580 variance: Variance::Invariant,
581 }
582 }
583}
584
585#[derive(Debug, Clone, PartialEq)]
587pub struct WhereClause {
588 pub type_name: String,
589 pub bound: String,
590}
591
592#[derive(Debug, Clone, PartialEq)]
594pub struct TypedParam {
595 pub name: String,
596 pub type_expr: Option<TypeExpr>,
597 pub default_value: Option<Box<SNode>>,
598 pub rest: bool,
600}
601
602impl TypedParam {
603 pub fn untyped(name: impl Into<String>) -> Self {
605 Self {
606 name: name.into(),
607 type_expr: None,
608 default_value: None,
609 rest: false,
610 }
611 }
612
613 pub fn typed(name: impl Into<String>, type_expr: TypeExpr) -> Self {
615 Self {
616 name: name.into(),
617 type_expr: Some(type_expr),
618 default_value: None,
619 rest: false,
620 }
621 }
622
623 pub fn names(params: &[TypedParam]) -> Vec<String> {
625 params.iter().map(|p| p.name.clone()).collect()
626 }
627
628 pub fn default_start(params: &[TypedParam]) -> Option<usize> {
630 params.iter().position(|p| p.default_value.is_some())
631 }
632}