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 body: Vec<SNode>,
102 extends: Option<String>,
103 is_pub: bool,
104 },
105 LetBinding {
106 pattern: BindingPattern,
107 type_ann: Option<TypeExpr>,
108 value: Box<SNode>,
109 },
110 VarBinding {
111 pattern: BindingPattern,
112 type_ann: Option<TypeExpr>,
113 value: Box<SNode>,
114 },
115 OverrideDecl {
116 name: String,
117 params: Vec<String>,
118 body: Vec<SNode>,
119 },
120 ImportDecl {
121 path: String,
122 },
123 SelectiveImport {
125 names: Vec<String>,
126 path: String,
127 },
128 EnumDecl {
129 name: String,
130 type_params: Vec<TypeParam>,
131 variants: Vec<EnumVariant>,
132 is_pub: bool,
133 },
134 StructDecl {
135 name: String,
136 type_params: Vec<TypeParam>,
137 fields: Vec<StructField>,
138 is_pub: bool,
139 },
140 InterfaceDecl {
141 name: String,
142 type_params: Vec<TypeParam>,
143 associated_types: Vec<(String, Option<TypeExpr>)>,
144 methods: Vec<InterfaceMethod>,
145 },
146 ImplBlock {
148 type_name: String,
149 methods: Vec<SNode>,
150 },
151
152 IfElse {
153 condition: Box<SNode>,
154 then_body: Vec<SNode>,
155 else_body: Option<Vec<SNode>>,
156 },
157 ForIn {
158 pattern: BindingPattern,
159 iterable: Box<SNode>,
160 body: Vec<SNode>,
161 },
162 MatchExpr {
163 value: Box<SNode>,
164 arms: Vec<MatchArm>,
165 },
166 WhileLoop {
167 condition: Box<SNode>,
168 body: Vec<SNode>,
169 },
170 Retry {
171 count: Box<SNode>,
172 body: Vec<SNode>,
173 },
174 ReturnStmt {
175 value: Option<Box<SNode>>,
176 },
177 TryCatch {
178 body: Vec<SNode>,
179 error_var: Option<String>,
180 error_type: Option<TypeExpr>,
181 catch_body: Vec<SNode>,
182 finally_body: Option<Vec<SNode>>,
183 },
184 TryExpr {
186 body: Vec<SNode>,
187 },
188 FnDecl {
189 name: String,
190 type_params: Vec<TypeParam>,
191 params: Vec<TypedParam>,
192 return_type: Option<TypeExpr>,
193 where_clauses: Vec<WhereClause>,
194 body: Vec<SNode>,
195 is_pub: bool,
196 },
197 ToolDecl {
198 name: String,
199 description: Option<String>,
200 params: Vec<TypedParam>,
201 return_type: Option<TypeExpr>,
202 body: Vec<SNode>,
203 is_pub: bool,
204 },
205 TypeDecl {
206 name: String,
207 type_params: Vec<TypeParam>,
208 type_expr: TypeExpr,
209 },
210 SpawnExpr {
211 body: Vec<SNode>,
212 },
213 DurationLiteral(u64),
215 RangeExpr {
217 start: Box<SNode>,
218 end: Box<SNode>,
219 inclusive: bool,
220 },
221 GuardStmt {
223 condition: Box<SNode>,
224 else_body: Vec<SNode>,
225 },
226 RequireStmt {
227 condition: Box<SNode>,
228 message: Option<Box<SNode>>,
229 },
230 DeferStmt {
232 body: Vec<SNode>,
233 },
234 DeadlineBlock {
236 duration: Box<SNode>,
237 body: Vec<SNode>,
238 },
239 YieldExpr {
241 value: Option<Box<SNode>>,
242 },
243 MutexBlock {
245 body: Vec<SNode>,
246 },
247 BreakStmt,
249 ContinueStmt,
251
252 Parallel {
253 mode: ParallelMode,
254 expr: Box<SNode>,
256 variable: Option<String>,
257 body: Vec<SNode>,
258 options: Vec<(String, SNode)>,
263 },
264
265 SelectExpr {
266 cases: Vec<SelectCase>,
267 timeout: Option<(Box<SNode>, Vec<SNode>)>,
268 default_body: Option<Vec<SNode>>,
269 },
270
271 FunctionCall {
272 name: String,
273 args: Vec<SNode>,
274 },
275 MethodCall {
276 object: Box<SNode>,
277 method: String,
278 args: Vec<SNode>,
279 },
280 OptionalMethodCall {
282 object: Box<SNode>,
283 method: String,
284 args: Vec<SNode>,
285 },
286 PropertyAccess {
287 object: Box<SNode>,
288 property: String,
289 },
290 OptionalPropertyAccess {
292 object: Box<SNode>,
293 property: String,
294 },
295 SubscriptAccess {
296 object: Box<SNode>,
297 index: Box<SNode>,
298 },
299 SliceAccess {
300 object: Box<SNode>,
301 start: Option<Box<SNode>>,
302 end: Option<Box<SNode>>,
303 },
304 BinaryOp {
305 op: String,
306 left: Box<SNode>,
307 right: Box<SNode>,
308 },
309 UnaryOp {
310 op: String,
311 operand: Box<SNode>,
312 },
313 Ternary {
314 condition: Box<SNode>,
315 true_expr: Box<SNode>,
316 false_expr: Box<SNode>,
317 },
318 Assignment {
319 target: Box<SNode>,
320 value: Box<SNode>,
321 op: Option<String>,
323 },
324 ThrowStmt {
325 value: Box<SNode>,
326 },
327
328 EnumConstruct {
330 enum_name: String,
331 variant: String,
332 args: Vec<SNode>,
333 },
334 StructConstruct {
336 struct_name: String,
337 fields: Vec<DictEntry>,
338 },
339
340 InterpolatedString(Vec<StringSegment>),
341 StringLiteral(String),
342 RawStringLiteral(String),
344 IntLiteral(i64),
345 FloatLiteral(f64),
346 BoolLiteral(bool),
347 NilLiteral,
348 Identifier(String),
349 ListLiteral(Vec<SNode>),
350 DictLiteral(Vec<DictEntry>),
351 Spread(Box<SNode>),
353 TryOperator {
355 operand: Box<SNode>,
356 },
357 TryStar {
365 operand: Box<SNode>,
366 },
367
368 Block(Vec<SNode>),
369 Closure {
370 params: Vec<TypedParam>,
371 body: Vec<SNode>,
372 fn_syntax: bool,
375 },
376}
377
378#[derive(Debug, Clone, Copy, PartialEq)]
380pub enum ParallelMode {
381 Count,
383 Each,
385 Settle,
387}
388
389#[derive(Debug, Clone, PartialEq)]
390pub struct MatchArm {
391 pub pattern: SNode,
392 pub guard: Option<Box<SNode>>,
394 pub body: Vec<SNode>,
395}
396
397#[derive(Debug, Clone, PartialEq)]
398pub struct SelectCase {
399 pub variable: String,
400 pub channel: Box<SNode>,
401 pub body: Vec<SNode>,
402}
403
404#[derive(Debug, Clone, PartialEq)]
405pub struct DictEntry {
406 pub key: SNode,
407 pub value: SNode,
408}
409
410#[derive(Debug, Clone, PartialEq)]
412pub struct EnumVariant {
413 pub name: String,
414 pub fields: Vec<TypedParam>,
415}
416
417#[derive(Debug, Clone, PartialEq)]
419pub struct StructField {
420 pub name: String,
421 pub type_expr: Option<TypeExpr>,
422 pub optional: bool,
423}
424
425#[derive(Debug, Clone, PartialEq)]
427pub struct InterfaceMethod {
428 pub name: String,
429 pub type_params: Vec<TypeParam>,
430 pub params: Vec<TypedParam>,
431 pub return_type: Option<TypeExpr>,
432}
433
434#[derive(Debug, Clone, PartialEq)]
436pub enum TypeExpr {
437 Named(String),
440 Union(Vec<TypeExpr>),
442 Shape(Vec<ShapeField>),
444 List(Box<TypeExpr>),
446 DictType(Box<TypeExpr>, Box<TypeExpr>),
448 Iter(Box<TypeExpr>),
451 Applied { name: String, args: Vec<TypeExpr> },
453 FnType {
455 params: Vec<TypeExpr>,
456 return_type: Box<TypeExpr>,
457 },
458 Never,
461 LitString(String),
464 LitInt(i64),
466}
467
468#[derive(Debug, Clone, PartialEq)]
470pub struct ShapeField {
471 pub name: String,
472 pub type_expr: TypeExpr,
473 pub optional: bool,
474}
475
476#[derive(Debug, Clone, PartialEq)]
478pub enum BindingPattern {
479 Identifier(String),
481 Dict(Vec<DictPatternField>),
483 List(Vec<ListPatternElement>),
485 Pair(String, String),
488}
489
490#[derive(Debug, Clone, PartialEq)]
492pub struct DictPatternField {
493 pub key: String,
495 pub alias: Option<String>,
497 pub is_rest: bool,
499 pub default_value: Option<Box<SNode>>,
501}
502
503#[derive(Debug, Clone, PartialEq)]
505pub struct ListPatternElement {
506 pub name: String,
508 pub is_rest: bool,
510 pub default_value: Option<Box<SNode>>,
512}
513
514#[derive(Debug, Clone, Copy, PartialEq, Eq)]
526pub enum Variance {
527 Invariant,
528 Covariant,
529 Contravariant,
530}
531
532#[derive(Debug, Clone, PartialEq)]
534pub struct TypeParam {
535 pub name: String,
536 pub variance: Variance,
537}
538
539impl TypeParam {
540 pub fn invariant(name: impl Into<String>) -> Self {
543 Self {
544 name: name.into(),
545 variance: Variance::Invariant,
546 }
547 }
548}
549
550#[derive(Debug, Clone, PartialEq)]
552pub struct WhereClause {
553 pub type_name: String,
554 pub bound: String,
555}
556
557#[derive(Debug, Clone, PartialEq)]
559pub struct TypedParam {
560 pub name: String,
561 pub type_expr: Option<TypeExpr>,
562 pub default_value: Option<Box<SNode>>,
563 pub rest: bool,
565}
566
567impl TypedParam {
568 pub fn untyped(name: impl Into<String>) -> Self {
570 Self {
571 name: name.into(),
572 type_expr: None,
573 default_value: None,
574 rest: false,
575 }
576 }
577
578 pub fn typed(name: impl Into<String>, type_expr: TypeExpr) -> Self {
580 Self {
581 name: name.into(),
582 type_expr: Some(type_expr),
583 default_value: None,
584 rest: false,
585 }
586 }
587
588 pub fn names(params: &[TypedParam]) -> Vec<String> {
590 params.iter().map(|p| p.name.clone()).collect()
591 }
592
593 pub fn default_start(params: &[TypedParam]) -> Option<usize> {
595 params.iter().position(|p| p.default_value.is_some())
596 }
597}