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 is_stream: bool,
205 },
206 ToolDecl {
207 name: String,
208 description: Option<String>,
209 params: Vec<TypedParam>,
210 return_type: Option<TypeExpr>,
211 body: Vec<SNode>,
212 is_pub: bool,
213 },
214 SkillDecl {
222 name: String,
223 fields: Vec<(String, SNode)>,
224 is_pub: bool,
225 },
226 TypeDecl {
227 name: String,
228 type_params: Vec<TypeParam>,
229 type_expr: TypeExpr,
230 },
231 SpawnExpr {
232 body: Vec<SNode>,
233 },
234 DurationLiteral(u64),
236 RangeExpr {
238 start: Box<SNode>,
239 end: Box<SNode>,
240 inclusive: bool,
241 },
242 GuardStmt {
244 condition: Box<SNode>,
245 else_body: Vec<SNode>,
246 },
247 RequireStmt {
248 condition: Box<SNode>,
249 message: Option<Box<SNode>>,
250 },
251 DeferStmt {
253 body: Vec<SNode>,
254 },
255 DeadlineBlock {
257 duration: Box<SNode>,
258 body: Vec<SNode>,
259 },
260 YieldExpr {
262 value: Option<Box<SNode>>,
263 },
264 EmitExpr {
266 value: Box<SNode>,
267 },
268 MutexBlock {
270 body: Vec<SNode>,
271 },
272 BreakStmt,
274 ContinueStmt,
276
277 Parallel {
278 mode: ParallelMode,
279 expr: Box<SNode>,
281 variable: Option<String>,
282 body: Vec<SNode>,
283 options: Vec<(String, SNode)>,
288 },
289
290 SelectExpr {
291 cases: Vec<SelectCase>,
292 timeout: Option<(Box<SNode>, Vec<SNode>)>,
293 default_body: Option<Vec<SNode>>,
294 },
295
296 FunctionCall {
297 name: String,
298 args: Vec<SNode>,
299 },
300 MethodCall {
301 object: Box<SNode>,
302 method: String,
303 args: Vec<SNode>,
304 },
305 OptionalMethodCall {
307 object: Box<SNode>,
308 method: String,
309 args: Vec<SNode>,
310 },
311 PropertyAccess {
312 object: Box<SNode>,
313 property: String,
314 },
315 OptionalPropertyAccess {
317 object: Box<SNode>,
318 property: String,
319 },
320 SubscriptAccess {
321 object: Box<SNode>,
322 index: Box<SNode>,
323 },
324 OptionalSubscriptAccess {
326 object: Box<SNode>,
327 index: Box<SNode>,
328 },
329 SliceAccess {
330 object: Box<SNode>,
331 start: Option<Box<SNode>>,
332 end: Option<Box<SNode>>,
333 },
334 BinaryOp {
335 op: String,
336 left: Box<SNode>,
337 right: Box<SNode>,
338 },
339 UnaryOp {
340 op: String,
341 operand: Box<SNode>,
342 },
343 Ternary {
344 condition: Box<SNode>,
345 true_expr: Box<SNode>,
346 false_expr: Box<SNode>,
347 },
348 Assignment {
349 target: Box<SNode>,
350 value: Box<SNode>,
351 op: Option<String>,
353 },
354 ThrowStmt {
355 value: Box<SNode>,
356 },
357
358 EnumConstruct {
360 enum_name: String,
361 variant: String,
362 args: Vec<SNode>,
363 },
364 StructConstruct {
366 struct_name: String,
367 fields: Vec<DictEntry>,
368 },
369
370 InterpolatedString(Vec<StringSegment>),
371 StringLiteral(String),
372 RawStringLiteral(String),
374 IntLiteral(i64),
375 FloatLiteral(f64),
376 BoolLiteral(bool),
377 NilLiteral,
378 Identifier(String),
379 ListLiteral(Vec<SNode>),
380 DictLiteral(Vec<DictEntry>),
381 Spread(Box<SNode>),
383 TryOperator {
385 operand: Box<SNode>,
386 },
387 TryStar {
395 operand: Box<SNode>,
396 },
397
398 OrPattern(Vec<SNode>),
402
403 Block(Vec<SNode>),
404 Closure {
405 params: Vec<TypedParam>,
406 body: Vec<SNode>,
407 fn_syntax: bool,
410 },
411}
412
413#[derive(Debug, Clone, Copy, PartialEq)]
415pub enum ParallelMode {
416 Count,
418 Each,
420 Settle,
422}
423
424#[derive(Debug, Clone, PartialEq)]
425pub struct MatchArm {
426 pub pattern: SNode,
427 pub guard: Option<Box<SNode>>,
429 pub body: Vec<SNode>,
430}
431
432#[derive(Debug, Clone, PartialEq)]
433pub struct SelectCase {
434 pub variable: String,
435 pub channel: Box<SNode>,
436 pub body: Vec<SNode>,
437}
438
439#[derive(Debug, Clone, PartialEq)]
440pub struct DictEntry {
441 pub key: SNode,
442 pub value: SNode,
443}
444
445#[derive(Debug, Clone, PartialEq)]
447pub struct EnumVariant {
448 pub name: String,
449 pub fields: Vec<TypedParam>,
450}
451
452#[derive(Debug, Clone, PartialEq)]
454pub struct StructField {
455 pub name: String,
456 pub type_expr: Option<TypeExpr>,
457 pub optional: bool,
458}
459
460#[derive(Debug, Clone, PartialEq)]
462pub struct InterfaceMethod {
463 pub name: String,
464 pub type_params: Vec<TypeParam>,
465 pub params: Vec<TypedParam>,
466 pub return_type: Option<TypeExpr>,
467}
468
469#[derive(Debug, Clone, PartialEq)]
471pub enum TypeExpr {
472 Named(String),
475 Union(Vec<TypeExpr>),
477 Shape(Vec<ShapeField>),
479 List(Box<TypeExpr>),
481 DictType(Box<TypeExpr>, Box<TypeExpr>),
483 Iter(Box<TypeExpr>),
486 Generator(Box<TypeExpr>),
489 Stream(Box<TypeExpr>),
491 Applied { name: String, args: Vec<TypeExpr> },
493 FnType {
495 params: Vec<TypeExpr>,
496 return_type: Box<TypeExpr>,
497 },
498 Never,
501 LitString(String),
504 LitInt(i64),
506}
507
508#[derive(Debug, Clone, PartialEq)]
510pub struct ShapeField {
511 pub name: String,
512 pub type_expr: TypeExpr,
513 pub optional: bool,
514}
515
516#[derive(Debug, Clone, PartialEq)]
518pub enum BindingPattern {
519 Identifier(String),
521 Dict(Vec<DictPatternField>),
523 List(Vec<ListPatternElement>),
525 Pair(String, String),
528}
529
530pub fn is_discard_name(name: &str) -> bool {
532 name == "_"
533}
534
535#[derive(Debug, Clone, PartialEq)]
537pub struct DictPatternField {
538 pub key: String,
540 pub alias: Option<String>,
542 pub is_rest: bool,
544 pub default_value: Option<Box<SNode>>,
546}
547
548#[derive(Debug, Clone, PartialEq)]
550pub struct ListPatternElement {
551 pub name: String,
553 pub is_rest: bool,
555 pub default_value: Option<Box<SNode>>,
557}
558
559#[derive(Debug, Clone, Copy, PartialEq, Eq)]
571pub enum Variance {
572 Invariant,
573 Covariant,
574 Contravariant,
575}
576
577#[derive(Debug, Clone, PartialEq)]
579pub struct TypeParam {
580 pub name: String,
581 pub variance: Variance,
582}
583
584impl TypeParam {
585 pub fn invariant(name: impl Into<String>) -> Self {
588 Self {
589 name: name.into(),
590 variance: Variance::Invariant,
591 }
592 }
593}
594
595#[derive(Debug, Clone, PartialEq)]
597pub struct WhereClause {
598 pub type_name: String,
599 pub bound: String,
600}
601
602#[derive(Debug, Clone, PartialEq)]
604pub struct TypedParam {
605 pub name: String,
606 pub type_expr: Option<TypeExpr>,
607 pub default_value: Option<Box<SNode>>,
608 pub rest: bool,
610}
611
612impl TypedParam {
613 pub fn untyped(name: impl Into<String>) -> Self {
615 Self {
616 name: name.into(),
617 type_expr: None,
618 default_value: None,
619 rest: false,
620 }
621 }
622
623 pub fn typed(name: impl Into<String>, type_expr: TypeExpr) -> Self {
625 Self {
626 name: name.into(),
627 type_expr: Some(type_expr),
628 default_value: None,
629 rest: false,
630 }
631 }
632
633 pub fn names(params: &[TypedParam]) -> Vec<String> {
635 params.iter().map(|p| p.name.clone()).collect()
636 }
637
638 pub fn default_start(params: &[TypedParam]) -> Option<usize> {
640 params.iter().position(|p| p.default_value.is_some())
641 }
642}