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 TypeDecl {
207 name: String,
208 type_params: Vec<TypeParam>,
209 type_expr: TypeExpr,
210 },
211 SpawnExpr {
212 body: Vec<SNode>,
213 },
214 DurationLiteral(u64),
216 RangeExpr {
218 start: Box<SNode>,
219 end: Box<SNode>,
220 inclusive: bool,
221 },
222 GuardStmt {
224 condition: Box<SNode>,
225 else_body: Vec<SNode>,
226 },
227 RequireStmt {
228 condition: Box<SNode>,
229 message: Option<Box<SNode>>,
230 },
231 DeferStmt {
233 body: Vec<SNode>,
234 },
235 DeadlineBlock {
237 duration: Box<SNode>,
238 body: Vec<SNode>,
239 },
240 YieldExpr {
242 value: Option<Box<SNode>>,
243 },
244 MutexBlock {
246 body: Vec<SNode>,
247 },
248 BreakStmt,
250 ContinueStmt,
252
253 Parallel {
254 mode: ParallelMode,
255 expr: Box<SNode>,
257 variable: Option<String>,
258 body: Vec<SNode>,
259 options: Vec<(String, SNode)>,
264 },
265
266 SelectExpr {
267 cases: Vec<SelectCase>,
268 timeout: Option<(Box<SNode>, Vec<SNode>)>,
269 default_body: Option<Vec<SNode>>,
270 },
271
272 FunctionCall {
273 name: String,
274 args: Vec<SNode>,
275 },
276 MethodCall {
277 object: Box<SNode>,
278 method: String,
279 args: Vec<SNode>,
280 },
281 OptionalMethodCall {
283 object: Box<SNode>,
284 method: String,
285 args: Vec<SNode>,
286 },
287 PropertyAccess {
288 object: Box<SNode>,
289 property: String,
290 },
291 OptionalPropertyAccess {
293 object: Box<SNode>,
294 property: String,
295 },
296 SubscriptAccess {
297 object: Box<SNode>,
298 index: Box<SNode>,
299 },
300 SliceAccess {
301 object: Box<SNode>,
302 start: Option<Box<SNode>>,
303 end: Option<Box<SNode>>,
304 },
305 BinaryOp {
306 op: String,
307 left: Box<SNode>,
308 right: Box<SNode>,
309 },
310 UnaryOp {
311 op: String,
312 operand: Box<SNode>,
313 },
314 Ternary {
315 condition: Box<SNode>,
316 true_expr: Box<SNode>,
317 false_expr: Box<SNode>,
318 },
319 Assignment {
320 target: Box<SNode>,
321 value: Box<SNode>,
322 op: Option<String>,
324 },
325 ThrowStmt {
326 value: Box<SNode>,
327 },
328
329 EnumConstruct {
331 enum_name: String,
332 variant: String,
333 args: Vec<SNode>,
334 },
335 StructConstruct {
337 struct_name: String,
338 fields: Vec<DictEntry>,
339 },
340
341 InterpolatedString(Vec<StringSegment>),
342 StringLiteral(String),
343 RawStringLiteral(String),
345 IntLiteral(i64),
346 FloatLiteral(f64),
347 BoolLiteral(bool),
348 NilLiteral,
349 Identifier(String),
350 ListLiteral(Vec<SNode>),
351 DictLiteral(Vec<DictEntry>),
352 Spread(Box<SNode>),
354 TryOperator {
356 operand: Box<SNode>,
357 },
358 TryStar {
366 operand: Box<SNode>,
367 },
368
369 Block(Vec<SNode>),
370 Closure {
371 params: Vec<TypedParam>,
372 body: Vec<SNode>,
373 fn_syntax: bool,
376 },
377}
378
379#[derive(Debug, Clone, Copy, PartialEq)]
381pub enum ParallelMode {
382 Count,
384 Each,
386 Settle,
388}
389
390#[derive(Debug, Clone, PartialEq)]
391pub struct MatchArm {
392 pub pattern: SNode,
393 pub guard: Option<Box<SNode>>,
395 pub body: Vec<SNode>,
396}
397
398#[derive(Debug, Clone, PartialEq)]
399pub struct SelectCase {
400 pub variable: String,
401 pub channel: Box<SNode>,
402 pub body: Vec<SNode>,
403}
404
405#[derive(Debug, Clone, PartialEq)]
406pub struct DictEntry {
407 pub key: SNode,
408 pub value: SNode,
409}
410
411#[derive(Debug, Clone, PartialEq)]
413pub struct EnumVariant {
414 pub name: String,
415 pub fields: Vec<TypedParam>,
416}
417
418#[derive(Debug, Clone, PartialEq)]
420pub struct StructField {
421 pub name: String,
422 pub type_expr: Option<TypeExpr>,
423 pub optional: bool,
424}
425
426#[derive(Debug, Clone, PartialEq)]
428pub struct InterfaceMethod {
429 pub name: String,
430 pub type_params: Vec<TypeParam>,
431 pub params: Vec<TypedParam>,
432 pub return_type: Option<TypeExpr>,
433}
434
435#[derive(Debug, Clone, PartialEq)]
437pub enum TypeExpr {
438 Named(String),
441 Union(Vec<TypeExpr>),
443 Shape(Vec<ShapeField>),
445 List(Box<TypeExpr>),
447 DictType(Box<TypeExpr>, Box<TypeExpr>),
449 Iter(Box<TypeExpr>),
452 Applied { name: String, args: Vec<TypeExpr> },
454 FnType {
456 params: Vec<TypeExpr>,
457 return_type: Box<TypeExpr>,
458 },
459 Never,
462 LitString(String),
465 LitInt(i64),
467}
468
469#[derive(Debug, Clone, PartialEq)]
471pub struct ShapeField {
472 pub name: String,
473 pub type_expr: TypeExpr,
474 pub optional: bool,
475}
476
477#[derive(Debug, Clone, PartialEq)]
479pub enum BindingPattern {
480 Identifier(String),
482 Dict(Vec<DictPatternField>),
484 List(Vec<ListPatternElement>),
486 Pair(String, String),
489}
490
491#[derive(Debug, Clone, PartialEq)]
493pub struct DictPatternField {
494 pub key: String,
496 pub alias: Option<String>,
498 pub is_rest: bool,
500 pub default_value: Option<Box<SNode>>,
502}
503
504#[derive(Debug, Clone, PartialEq)]
506pub struct ListPatternElement {
507 pub name: String,
509 pub is_rest: bool,
511 pub default_value: Option<Box<SNode>>,
513}
514
515#[derive(Debug, Clone, Copy, PartialEq, Eq)]
527pub enum Variance {
528 Invariant,
529 Covariant,
530 Contravariant,
531}
532
533#[derive(Debug, Clone, PartialEq)]
535pub struct TypeParam {
536 pub name: String,
537 pub variance: Variance,
538}
539
540impl TypeParam {
541 pub fn invariant(name: impl Into<String>) -> Self {
544 Self {
545 name: name.into(),
546 variance: Variance::Invariant,
547 }
548 }
549}
550
551#[derive(Debug, Clone, PartialEq)]
553pub struct WhereClause {
554 pub type_name: String,
555 pub bound: String,
556}
557
558#[derive(Debug, Clone, PartialEq)]
560pub struct TypedParam {
561 pub name: String,
562 pub type_expr: Option<TypeExpr>,
563 pub default_value: Option<Box<SNode>>,
564 pub rest: bool,
566}
567
568impl TypedParam {
569 pub fn untyped(name: impl Into<String>) -> Self {
571 Self {
572 name: name.into(),
573 type_expr: None,
574 default_value: None,
575 rest: false,
576 }
577 }
578
579 pub fn typed(name: impl Into<String>, type_expr: TypeExpr) -> Self {
581 Self {
582 name: name.into(),
583 type_expr: Some(type_expr),
584 default_value: None,
585 rest: false,
586 }
587 }
588
589 pub fn names(params: &[TypedParam]) -> Vec<String> {
591 params.iter().map(|p| p.name.clone()).collect()
592 }
593
594 pub fn default_start(params: &[TypedParam]) -> Option<usize> {
596 params.iter().position(|p| p.default_value.is_some())
597 }
598}