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 OptionalSubscriptAccess {
314 object: Box<SNode>,
315 index: Box<SNode>,
316 },
317 SliceAccess {
318 object: Box<SNode>,
319 start: Option<Box<SNode>>,
320 end: Option<Box<SNode>>,
321 },
322 BinaryOp {
323 op: String,
324 left: Box<SNode>,
325 right: Box<SNode>,
326 },
327 UnaryOp {
328 op: String,
329 operand: Box<SNode>,
330 },
331 Ternary {
332 condition: Box<SNode>,
333 true_expr: Box<SNode>,
334 false_expr: Box<SNode>,
335 },
336 Assignment {
337 target: Box<SNode>,
338 value: Box<SNode>,
339 op: Option<String>,
341 },
342 ThrowStmt {
343 value: Box<SNode>,
344 },
345
346 EnumConstruct {
348 enum_name: String,
349 variant: String,
350 args: Vec<SNode>,
351 },
352 StructConstruct {
354 struct_name: String,
355 fields: Vec<DictEntry>,
356 },
357
358 InterpolatedString(Vec<StringSegment>),
359 StringLiteral(String),
360 RawStringLiteral(String),
362 IntLiteral(i64),
363 FloatLiteral(f64),
364 BoolLiteral(bool),
365 NilLiteral,
366 Identifier(String),
367 ListLiteral(Vec<SNode>),
368 DictLiteral(Vec<DictEntry>),
369 Spread(Box<SNode>),
371 TryOperator {
373 operand: Box<SNode>,
374 },
375 TryStar {
383 operand: Box<SNode>,
384 },
385
386 OrPattern(Vec<SNode>),
390
391 Block(Vec<SNode>),
392 Closure {
393 params: Vec<TypedParam>,
394 body: Vec<SNode>,
395 fn_syntax: bool,
398 },
399}
400
401#[derive(Debug, Clone, Copy, PartialEq)]
403pub enum ParallelMode {
404 Count,
406 Each,
408 Settle,
410}
411
412#[derive(Debug, Clone, PartialEq)]
413pub struct MatchArm {
414 pub pattern: SNode,
415 pub guard: Option<Box<SNode>>,
417 pub body: Vec<SNode>,
418}
419
420#[derive(Debug, Clone, PartialEq)]
421pub struct SelectCase {
422 pub variable: String,
423 pub channel: Box<SNode>,
424 pub body: Vec<SNode>,
425}
426
427#[derive(Debug, Clone, PartialEq)]
428pub struct DictEntry {
429 pub key: SNode,
430 pub value: SNode,
431}
432
433#[derive(Debug, Clone, PartialEq)]
435pub struct EnumVariant {
436 pub name: String,
437 pub fields: Vec<TypedParam>,
438}
439
440#[derive(Debug, Clone, PartialEq)]
442pub struct StructField {
443 pub name: String,
444 pub type_expr: Option<TypeExpr>,
445 pub optional: bool,
446}
447
448#[derive(Debug, Clone, PartialEq)]
450pub struct InterfaceMethod {
451 pub name: String,
452 pub type_params: Vec<TypeParam>,
453 pub params: Vec<TypedParam>,
454 pub return_type: Option<TypeExpr>,
455}
456
457#[derive(Debug, Clone, PartialEq)]
459pub enum TypeExpr {
460 Named(String),
463 Union(Vec<TypeExpr>),
465 Shape(Vec<ShapeField>),
467 List(Box<TypeExpr>),
469 DictType(Box<TypeExpr>, Box<TypeExpr>),
471 Iter(Box<TypeExpr>),
474 Applied { name: String, args: Vec<TypeExpr> },
476 FnType {
478 params: Vec<TypeExpr>,
479 return_type: Box<TypeExpr>,
480 },
481 Never,
484 LitString(String),
487 LitInt(i64),
489}
490
491#[derive(Debug, Clone, PartialEq)]
493pub struct ShapeField {
494 pub name: String,
495 pub type_expr: TypeExpr,
496 pub optional: bool,
497}
498
499#[derive(Debug, Clone, PartialEq)]
501pub enum BindingPattern {
502 Identifier(String),
504 Dict(Vec<DictPatternField>),
506 List(Vec<ListPatternElement>),
508 Pair(String, String),
511}
512
513pub fn is_discard_name(name: &str) -> bool {
515 name == "_"
516}
517
518#[derive(Debug, Clone, PartialEq)]
520pub struct DictPatternField {
521 pub key: String,
523 pub alias: Option<String>,
525 pub is_rest: bool,
527 pub default_value: Option<Box<SNode>>,
529}
530
531#[derive(Debug, Clone, PartialEq)]
533pub struct ListPatternElement {
534 pub name: String,
536 pub is_rest: bool,
538 pub default_value: Option<Box<SNode>>,
540}
541
542#[derive(Debug, Clone, Copy, PartialEq, Eq)]
554pub enum Variance {
555 Invariant,
556 Covariant,
557 Contravariant,
558}
559
560#[derive(Debug, Clone, PartialEq)]
562pub struct TypeParam {
563 pub name: String,
564 pub variance: Variance,
565}
566
567impl TypeParam {
568 pub fn invariant(name: impl Into<String>) -> Self {
571 Self {
572 name: name.into(),
573 variance: Variance::Invariant,
574 }
575 }
576}
577
578#[derive(Debug, Clone, PartialEq)]
580pub struct WhereClause {
581 pub type_name: String,
582 pub bound: String,
583}
584
585#[derive(Debug, Clone, PartialEq)]
587pub struct TypedParam {
588 pub name: String,
589 pub type_expr: Option<TypeExpr>,
590 pub default_value: Option<Box<SNode>>,
591 pub rest: bool,
593}
594
595impl TypedParam {
596 pub fn untyped(name: impl Into<String>) -> Self {
598 Self {
599 name: name.into(),
600 type_expr: None,
601 default_value: None,
602 rest: false,
603 }
604 }
605
606 pub fn typed(name: impl Into<String>, type_expr: TypeExpr) -> Self {
608 Self {
609 name: name.into(),
610 type_expr: Some(type_expr),
611 default_value: None,
612 rest: false,
613 }
614 }
615
616 pub fn names(params: &[TypedParam]) -> Vec<String> {
618 params.iter().map(|p| p.name.clone()).collect()
619 }
620
621 pub fn default_start(params: &[TypedParam]) -> Option<usize> {
623 params.iter().position(|p| p.default_value.is_some())
624 }
625}