1use crate::ast::*;
2use harn_lexer::{Span, Token, TokenKind};
3use std::collections::HashSet;
4use std::fmt;
5
6#[derive(Debug, Clone, PartialEq)]
8pub enum ParserError {
9 Unexpected {
10 got: String,
11 expected: String,
12 span: Span,
13 },
14 UnexpectedEof {
15 expected: String,
16 span: Span,
17 },
18}
19
20impl fmt::Display for ParserError {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 match self {
23 ParserError::Unexpected {
24 got,
25 expected,
26 span,
27 } => write!(
28 f,
29 "Expected {expected}, got {got} at {}:{}",
30 span.line, span.column
31 ),
32 ParserError::UnexpectedEof { expected, .. } => {
33 write!(f, "Unexpected end of file, expected {expected}")
34 }
35 }
36 }
37}
38
39impl std::error::Error for ParserError {}
40
41pub struct Parser {
43 tokens: Vec<Token>,
44 pos: usize,
45 errors: Vec<ParserError>,
46 struct_names: HashSet<String>,
47}
48
49impl Parser {
50 pub fn new(tokens: Vec<Token>) -> Self {
51 Self {
52 tokens,
53 pos: 0,
54 errors: Vec::new(),
55 struct_names: HashSet::new(),
56 }
57 }
58
59 fn current_span(&self) -> Span {
60 self.tokens
61 .get(self.pos)
62 .map(|t| t.span)
63 .unwrap_or(Span::dummy())
64 }
65
66 fn current_kind(&self) -> Option<&TokenKind> {
67 self.tokens.get(self.pos).map(|t| &t.kind)
68 }
69
70 fn prev_span(&self) -> Span {
71 if self.pos > 0 {
72 self.tokens[self.pos - 1].span
73 } else {
74 Span::dummy()
75 }
76 }
77
78 pub fn parse(&mut self) -> Result<Vec<SNode>, ParserError> {
80 let mut nodes = Vec::new();
81 self.skip_newlines();
82
83 while !self.is_at_end() {
84 if self.check(&TokenKind::RBrace) {
86 self.advance();
87 self.skip_newlines();
88 continue;
89 }
90
91 let result = if self.check(&TokenKind::Import) {
92 self.parse_import()
93 } else if self.check(&TokenKind::At) {
94 self.parse_attributed_decl()
95 } else if self.check(&TokenKind::Pipeline) {
96 self.parse_pipeline()
97 } else {
98 self.parse_statement()
99 };
100
101 match result {
102 Ok(node) => nodes.push(node),
103 Err(err) => {
104 self.errors.push(err);
105 self.synchronize();
106 }
107 }
108 self.skip_newlines();
109 }
110
111 if let Some(first) = self.errors.first() {
112 return Err(first.clone());
113 }
114 Ok(nodes)
115 }
116
117 pub fn all_errors(&self) -> &[ParserError] {
119 &self.errors
120 }
121
122 fn is_statement_start(&self) -> bool {
124 matches!(
125 self.current_kind(),
126 Some(
127 TokenKind::Let
128 | TokenKind::Var
129 | TokenKind::If
130 | TokenKind::For
131 | TokenKind::While
132 | TokenKind::Match
133 | TokenKind::Retry
134 | TokenKind::Return
135 | TokenKind::Throw
136 | TokenKind::Fn
137 | TokenKind::Pub
138 | TokenKind::Try
139 | TokenKind::Select
140 | TokenKind::Pipeline
141 | TokenKind::Import
142 | TokenKind::Parallel
143 | TokenKind::Enum
144 | TokenKind::Struct
145 | TokenKind::Interface
146 | TokenKind::Guard
147 | TokenKind::Require
148 | TokenKind::Deadline
149 | TokenKind::Yield
150 | TokenKind::Mutex
151 | TokenKind::Tool
152 )
153 )
154 }
155
156 fn synchronize(&mut self) {
158 while !self.is_at_end() {
159 if self.check(&TokenKind::Newline) {
160 self.advance();
161 if self.is_at_end() || self.is_statement_start() {
162 return;
163 }
164 continue;
165 }
166 if self.check(&TokenKind::RBrace) {
167 return;
168 }
169 self.advance();
170 }
171 }
172
173 pub fn parse_single_expression(&mut self) -> Result<SNode, ParserError> {
175 self.skip_newlines();
176 self.parse_expression()
177 }
178
179 fn parse_pipeline_with_pub(&mut self, is_pub: bool) -> Result<SNode, ParserError> {
180 let start = self.current_span();
181 self.consume(&TokenKind::Pipeline, "pipeline")?;
182 let name = self.consume_identifier("pipeline name")?;
183
184 self.consume(&TokenKind::LParen, "(")?;
185 let params = self.parse_param_list()?;
186 self.consume(&TokenKind::RParen, ")")?;
187
188 let return_type = if self.check(&TokenKind::Arrow) {
189 self.advance();
190 Some(self.parse_type_expr()?)
191 } else {
192 None
193 };
194
195 let extends = if self.check(&TokenKind::Extends) {
196 self.advance();
197 Some(self.consume_identifier("parent pipeline name")?)
198 } else {
199 None
200 };
201
202 self.consume(&TokenKind::LBrace, "{")?;
203 let body = self.parse_block()?;
204 self.consume(&TokenKind::RBrace, "}")?;
205
206 Ok(spanned(
207 Node::Pipeline {
208 name,
209 params,
210 return_type,
211 body,
212 extends,
213 is_pub,
214 },
215 Span::merge(start, self.prev_span()),
216 ))
217 }
218
219 fn parse_pipeline(&mut self) -> Result<SNode, ParserError> {
220 self.parse_pipeline_with_pub(false)
221 }
222
223 fn parse_import(&mut self) -> Result<SNode, ParserError> {
224 let start = self.current_span();
225 self.consume(&TokenKind::Import, "import")?;
226
227 if self.check(&TokenKind::LBrace) {
229 self.advance();
230 self.skip_newlines();
231 let mut names = Vec::new();
232 while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
233 let name = self.consume_identifier("import name")?;
234 names.push(name);
235 self.skip_newlines();
236 if self.check(&TokenKind::Comma) {
237 self.advance();
238 self.skip_newlines();
239 }
240 }
241 self.consume(&TokenKind::RBrace, "}")?;
242 self.consume(&TokenKind::From, "from")?;
243 if let Some(tok) = self.current() {
244 if let TokenKind::StringLiteral(path) = &tok.kind {
245 let path = path.clone();
246 self.advance();
247 return Ok(spanned(
248 Node::SelectiveImport { names, path },
249 Span::merge(start, self.prev_span()),
250 ));
251 }
252 }
253 return Err(self.error("import path string"));
254 }
255
256 if let Some(tok) = self.current() {
257 if let TokenKind::StringLiteral(path) = &tok.kind {
258 let path = path.clone();
259 self.advance();
260 return Ok(spanned(
261 Node::ImportDecl { path },
262 Span::merge(start, self.prev_span()),
263 ));
264 }
265 }
266 Err(self.error("import path string"))
267 }
268
269 fn parse_block(&mut self) -> Result<Vec<SNode>, ParserError> {
270 let mut stmts = Vec::new();
271 self.skip_newlines();
272
273 while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
274 stmts.push(self.parse_statement()?);
275 self.skip_newlines();
276 }
277 Ok(stmts)
278 }
279
280 fn parse_statement(&mut self) -> Result<SNode, ParserError> {
281 self.skip_newlines();
282
283 let tok = self.current().ok_or_else(|| ParserError::UnexpectedEof {
284 expected: "statement".into(),
285 span: self.prev_span(),
286 })?;
287
288 match &tok.kind {
289 TokenKind::At => self.parse_attributed_decl(),
290 TokenKind::Let => self.parse_let_binding(),
291 TokenKind::Var => self.parse_var_binding(),
292 TokenKind::If => self.parse_if_else(),
293 TokenKind::For => self.parse_for_in(),
294 TokenKind::Match => self.parse_match(),
295 TokenKind::Retry => self.parse_retry(),
296 TokenKind::While => self.parse_while_loop(),
297 TokenKind::Parallel => self.parse_parallel(),
298 TokenKind::Return => self.parse_return(),
299 TokenKind::Throw => self.parse_throw(),
300 TokenKind::Override => self.parse_override(),
301 TokenKind::Try => self.parse_try_catch(),
302 TokenKind::Select => self.parse_select(),
303 TokenKind::Fn => self.parse_fn_decl_with_pub(false),
304 TokenKind::Tool => self.parse_tool_decl(false),
305 TokenKind::Pub => {
306 self.advance(); let tok = self.current().ok_or_else(|| ParserError::UnexpectedEof {
308 expected: "fn, struct, enum, or pipeline after pub".into(),
309 span: self.prev_span(),
310 })?;
311 match &tok.kind {
312 TokenKind::Fn => self.parse_fn_decl_with_pub(true),
313 TokenKind::Tool => self.parse_tool_decl(true),
314 TokenKind::Pipeline => self.parse_pipeline_with_pub(true),
315 TokenKind::Enum => self.parse_enum_decl_with_pub(true),
316 TokenKind::Struct => self.parse_struct_decl_with_pub(true),
317 _ => Err(self.error("fn, tool, struct, enum, or pipeline after pub")),
318 }
319 }
320 TokenKind::TypeKw => self.parse_type_decl(),
321 TokenKind::Enum => self.parse_enum_decl(),
322 TokenKind::Struct => self.parse_struct_decl(),
323 TokenKind::Interface => self.parse_interface_decl(),
324 TokenKind::Impl => self.parse_impl_block(),
325 TokenKind::Guard => self.parse_guard(),
326 TokenKind::Require => self.parse_require(),
327 TokenKind::Deadline => self.parse_deadline(),
328 TokenKind::Yield => self.parse_yield(),
329 TokenKind::Mutex => self.parse_mutex(),
330 TokenKind::Defer => self.parse_defer(),
331 TokenKind::Break => {
332 let span = self.current_span();
333 self.advance();
334 Ok(spanned(Node::BreakStmt, span))
335 }
336 TokenKind::Continue => {
337 let span = self.current_span();
338 self.advance();
339 Ok(spanned(Node::ContinueStmt, span))
340 }
341 _ => self.parse_expression_statement(),
342 }
343 }
344
345 fn parse_let_binding(&mut self) -> Result<SNode, ParserError> {
346 let start = self.current_span();
347 self.consume(&TokenKind::Let, "let")?;
348 let pattern = self.parse_binding_pattern()?;
349 let type_ann = if matches!(pattern, BindingPattern::Identifier(_)) {
350 self.try_parse_type_annotation()?
351 } else {
352 None
353 };
354 self.consume(&TokenKind::Assign, "=")?;
355 let value = self.parse_expression()?;
356 Ok(spanned(
357 Node::LetBinding {
358 pattern,
359 type_ann,
360 value: Box::new(value),
361 },
362 Span::merge(start, self.prev_span()),
363 ))
364 }
365
366 fn parse_var_binding(&mut self) -> Result<SNode, ParserError> {
367 let start = self.current_span();
368 self.consume(&TokenKind::Var, "var")?;
369 let pattern = self.parse_binding_pattern()?;
370 let type_ann = if matches!(pattern, BindingPattern::Identifier(_)) {
371 self.try_parse_type_annotation()?
372 } else {
373 None
374 };
375 self.consume(&TokenKind::Assign, "=")?;
376 let value = self.parse_expression()?;
377 Ok(spanned(
378 Node::VarBinding {
379 pattern,
380 type_ann,
381 value: Box::new(value),
382 },
383 Span::merge(start, self.prev_span()),
384 ))
385 }
386
387 fn parse_if_else(&mut self) -> Result<SNode, ParserError> {
388 let start = self.current_span();
389 self.consume(&TokenKind::If, "if")?;
390 let condition = self.parse_expression()?;
391 self.consume(&TokenKind::LBrace, "{")?;
392 let then_body = self.parse_block()?;
393 self.consume(&TokenKind::RBrace, "}")?;
394 self.skip_newlines();
395
396 let else_body = if self.check(&TokenKind::Else) {
397 self.advance();
398 if self.check(&TokenKind::If) {
399 Some(vec![self.parse_if_else()?])
400 } else {
401 self.consume(&TokenKind::LBrace, "{")?;
402 let body = self.parse_block()?;
403 self.consume(&TokenKind::RBrace, "}")?;
404 Some(body)
405 }
406 } else {
407 None
408 };
409
410 Ok(spanned(
411 Node::IfElse {
412 condition: Box::new(condition),
413 then_body,
414 else_body,
415 },
416 Span::merge(start, self.prev_span()),
417 ))
418 }
419
420 fn parse_for_in(&mut self) -> Result<SNode, ParserError> {
421 let start = self.current_span();
422 self.consume(&TokenKind::For, "for")?;
423 let pattern = if self.check(&TokenKind::LParen) {
424 self.advance();
426 let first = self.consume_identifier("pair pattern element")?;
427 self.consume(&TokenKind::Comma, ",")?;
428 let second = self.consume_identifier("pair pattern element")?;
429 self.consume(&TokenKind::RParen, ")")?;
430 BindingPattern::Pair(first, second)
431 } else {
432 self.parse_binding_pattern()?
433 };
434 self.consume(&TokenKind::In, "in")?;
435 let iterable = self.parse_expression()?;
436 self.consume(&TokenKind::LBrace, "{")?;
437 let body = self.parse_block()?;
438 self.consume(&TokenKind::RBrace, "}")?;
439 Ok(spanned(
440 Node::ForIn {
441 pattern,
442 iterable: Box::new(iterable),
443 body,
444 },
445 Span::merge(start, self.prev_span()),
446 ))
447 }
448
449 fn parse_binding_pattern(&mut self) -> Result<BindingPattern, ParserError> {
452 self.skip_newlines();
453 if self.check(&TokenKind::LBrace) {
454 self.advance();
455 let mut fields = Vec::new();
456 while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
457 if self.check(&TokenKind::Dot) {
458 self.advance();
459 self.consume(&TokenKind::Dot, ".")?;
460 self.consume(&TokenKind::Dot, ".")?;
461 let name = self.consume_identifier("rest variable name")?;
462 fields.push(DictPatternField {
463 key: name,
464 alias: None,
465 is_rest: true,
466 default_value: None,
467 });
468 break;
470 }
471 let key = self.consume_identifier("field name")?;
472 let alias = if self.check(&TokenKind::Colon) {
473 self.advance();
474 Some(self.consume_identifier("alias name")?)
475 } else {
476 None
477 };
478 let default_value = if self.check(&TokenKind::Assign) {
479 self.advance();
480 Some(Box::new(self.parse_expression()?))
481 } else {
482 None
483 };
484 fields.push(DictPatternField {
485 key,
486 alias,
487 is_rest: false,
488 default_value,
489 });
490 if self.check(&TokenKind::Comma) {
491 self.advance();
492 }
493 }
494 self.consume(&TokenKind::RBrace, "}")?;
495 Ok(BindingPattern::Dict(fields))
496 } else if self.check(&TokenKind::LBracket) {
497 self.advance();
498 let mut elements = Vec::new();
499 while !self.is_at_end() && !self.check(&TokenKind::RBracket) {
500 if self.check(&TokenKind::Dot) {
501 self.advance();
502 self.consume(&TokenKind::Dot, ".")?;
503 self.consume(&TokenKind::Dot, ".")?;
504 let name = self.consume_identifier("rest variable name")?;
505 elements.push(ListPatternElement {
506 name,
507 is_rest: true,
508 default_value: None,
509 });
510 break;
511 }
512 let name = self.consume_identifier("element name")?;
513 let default_value = if self.check(&TokenKind::Assign) {
514 self.advance();
515 Some(Box::new(self.parse_expression()?))
516 } else {
517 None
518 };
519 elements.push(ListPatternElement {
520 name,
521 is_rest: false,
522 default_value,
523 });
524 if self.check(&TokenKind::Comma) {
525 self.advance();
526 }
527 }
528 self.consume(&TokenKind::RBracket, "]")?;
529 Ok(BindingPattern::List(elements))
530 } else {
531 let name = self.consume_identifier("variable name or destructuring pattern")?;
532 Ok(BindingPattern::Identifier(name))
533 }
534 }
535
536 fn parse_match(&mut self) -> Result<SNode, ParserError> {
537 let start = self.current_span();
538 self.consume(&TokenKind::Match, "match")?;
539 let value = self.parse_expression()?;
540 self.consume(&TokenKind::LBrace, "{")?;
541 self.skip_newlines();
542
543 let mut arms = Vec::new();
544 while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
545 let pattern = self.parse_expression()?;
546 let guard = if self.check(&TokenKind::If) {
547 self.advance();
548 Some(Box::new(self.parse_expression()?))
549 } else {
550 None
551 };
552 self.consume(&TokenKind::Arrow, "->")?;
553 self.consume(&TokenKind::LBrace, "{")?;
554 let body = self.parse_block()?;
555 self.consume(&TokenKind::RBrace, "}")?;
556 arms.push(MatchArm {
557 pattern,
558 guard,
559 body,
560 });
561 self.skip_newlines();
562 }
563
564 self.consume(&TokenKind::RBrace, "}")?;
565 Ok(spanned(
566 Node::MatchExpr {
567 value: Box::new(value),
568 arms,
569 },
570 Span::merge(start, self.prev_span()),
571 ))
572 }
573
574 fn parse_while_loop(&mut self) -> Result<SNode, ParserError> {
575 let start = self.current_span();
576 self.consume(&TokenKind::While, "while")?;
577 let condition = if self.check(&TokenKind::LParen) {
578 self.advance();
579 let c = self.parse_expression()?;
580 self.consume(&TokenKind::RParen, ")")?;
581 c
582 } else {
583 self.parse_expression()?
584 };
585 self.consume(&TokenKind::LBrace, "{")?;
586 let body = self.parse_block()?;
587 self.consume(&TokenKind::RBrace, "}")?;
588 Ok(spanned(
589 Node::WhileLoop {
590 condition: Box::new(condition),
591 body,
592 },
593 Span::merge(start, self.prev_span()),
594 ))
595 }
596
597 fn parse_retry(&mut self) -> Result<SNode, ParserError> {
598 let start = self.current_span();
599 self.consume(&TokenKind::Retry, "retry")?;
600 let count = if self.check(&TokenKind::LParen) {
601 self.advance();
602 let c = self.parse_expression()?;
603 self.consume(&TokenKind::RParen, ")")?;
604 c
605 } else {
606 self.parse_primary()?
607 };
608 self.consume(&TokenKind::LBrace, "{")?;
609 let body = self.parse_block()?;
610 self.consume(&TokenKind::RBrace, "}")?;
611 Ok(spanned(
612 Node::Retry {
613 count: Box::new(count),
614 body,
615 },
616 Span::merge(start, self.prev_span()),
617 ))
618 }
619
620 fn parse_parallel(&mut self) -> Result<SNode, ParserError> {
621 let start = self.current_span();
622 self.consume(&TokenKind::Parallel, "parallel")?;
623
624 let mode = if self.check_identifier("each") {
625 self.advance();
626 ParallelMode::Each
627 } else if self.check_identifier("settle") {
628 self.advance();
629 ParallelMode::Settle
630 } else {
631 ParallelMode::Count
632 };
633
634 let expr = self.parse_expression()?;
635
636 let options = if self.check_identifier("with") {
639 self.advance();
640 self.consume(&TokenKind::LBrace, "{")?;
641 let mut options = Vec::new();
642 loop {
643 self.skip_newlines();
644 if matches!(
645 self.current().map(|t| &t.kind),
646 Some(&TokenKind::RBrace) | None
647 ) {
648 break;
649 }
650 let key_span = self.current_span();
651 let key = match self.current().map(|t| &t.kind) {
652 Some(TokenKind::Identifier(name)) => name.clone(),
653 _ => {
654 return Err(ParserError::Unexpected {
655 got: self
656 .current()
657 .map(|t| format!("{:?}", t.kind))
658 .unwrap_or_else(|| "end of input".to_string()),
659 expected: "option name in `parallel ... with { ... }` block"
660 .to_string(),
661 span: key_span,
662 });
663 }
664 };
665 self.advance();
666 if key != "max_concurrent" {
667 return Err(ParserError::Unexpected {
668 got: key.clone(),
669 expected: format!(
670 "known option (only `max_concurrent` is supported in \
671 `parallel ... with {{ ... }}`; got `{key}`)"
672 ),
673 span: key_span,
674 });
675 }
676 self.consume(&TokenKind::Colon, ":")?;
677 let value = self.parse_expression()?;
678 options.push((key, value));
679 self.skip_newlines();
680 if matches!(self.current().map(|t| &t.kind), Some(&TokenKind::Comma)) {
681 self.advance();
682 self.skip_newlines();
683 }
684 }
685 self.consume(&TokenKind::RBrace, "}")?;
686 options
687 } else {
688 Vec::new()
689 };
690
691 self.consume(&TokenKind::LBrace, "{")?;
692
693 let mut variable = None;
694 self.skip_newlines();
695 if let Some(tok) = self.current() {
696 if let TokenKind::Identifier(name) = &tok.kind {
697 if self.peek_kind() == Some(&TokenKind::Arrow) {
698 let name = name.clone();
699 self.advance();
700 self.advance();
701 variable = Some(name);
702 }
703 }
704 }
705
706 let body = self.parse_block()?;
707 self.consume(&TokenKind::RBrace, "}")?;
708 Ok(spanned(
709 Node::Parallel {
710 mode,
711 expr: Box::new(expr),
712 variable,
713 body,
714 options,
715 },
716 Span::merge(start, self.prev_span()),
717 ))
718 }
719
720 fn parse_return(&mut self) -> Result<SNode, ParserError> {
721 let start = self.current_span();
722 self.consume(&TokenKind::Return, "return")?;
723 if self.is_at_end() || self.check(&TokenKind::Newline) || self.check(&TokenKind::RBrace) {
724 return Ok(spanned(
725 Node::ReturnStmt { value: None },
726 Span::merge(start, self.prev_span()),
727 ));
728 }
729 let value = self.parse_expression()?;
730 Ok(spanned(
731 Node::ReturnStmt {
732 value: Some(Box::new(value)),
733 },
734 Span::merge(start, self.prev_span()),
735 ))
736 }
737
738 fn parse_throw(&mut self) -> Result<SNode, ParserError> {
739 let start = self.current_span();
740 self.consume(&TokenKind::Throw, "throw")?;
741 let value = self.parse_expression()?;
742 Ok(spanned(
743 Node::ThrowStmt {
744 value: Box::new(value),
745 },
746 Span::merge(start, self.prev_span()),
747 ))
748 }
749
750 fn parse_override(&mut self) -> Result<SNode, ParserError> {
751 let start = self.current_span();
752 self.consume(&TokenKind::Override, "override")?;
753 let name = self.consume_identifier("override name")?;
754 self.consume(&TokenKind::LParen, "(")?;
755 let params = self.parse_param_list()?;
756 self.consume(&TokenKind::RParen, ")")?;
757 self.consume(&TokenKind::LBrace, "{")?;
758 let body = self.parse_block()?;
759 self.consume(&TokenKind::RBrace, "}")?;
760 Ok(spanned(
761 Node::OverrideDecl { name, params, body },
762 Span::merge(start, self.prev_span()),
763 ))
764 }
765
766 fn parse_try_catch(&mut self) -> Result<SNode, ParserError> {
767 let start = self.current_span();
768 self.consume(&TokenKind::Try, "try")?;
769 if self.check(&TokenKind::Star) {
770 self.advance();
771 let operand = self.parse_unary()?;
772 return Ok(spanned(
773 Node::TryStar {
774 operand: Box::new(operand),
775 },
776 Span::merge(start, self.prev_span()),
777 ));
778 }
779 self.consume(&TokenKind::LBrace, "{")?;
780 let body = self.parse_block()?;
781 self.consume(&TokenKind::RBrace, "}")?;
782 self.skip_newlines();
783
784 let has_catch = self.check(&TokenKind::Catch);
785 let (error_var, error_type, catch_body) = if has_catch {
786 self.advance();
787 let (ev, et) = if self.check(&TokenKind::LParen) {
788 self.advance();
789 let name = self.consume_identifier("error variable")?;
790 let ty = self.try_parse_type_annotation()?;
791 self.consume(&TokenKind::RParen, ")")?;
792 (Some(name), ty)
793 } else if matches!(
794 self.current().map(|t| &t.kind),
795 Some(TokenKind::Identifier(_))
796 ) {
797 let name = self.consume_identifier("error variable")?;
798 (Some(name), None)
799 } else {
800 (None, None)
801 };
802 self.consume(&TokenKind::LBrace, "{")?;
803 let cb = self.parse_block()?;
804 self.consume(&TokenKind::RBrace, "}")?;
805 (ev, et, cb)
806 } else {
807 (None, None, Vec::new())
808 };
809
810 self.skip_newlines();
811
812 let finally_body = if self.check(&TokenKind::Finally) {
813 self.advance();
814 self.consume(&TokenKind::LBrace, "{")?;
815 let fb = self.parse_block()?;
816 self.consume(&TokenKind::RBrace, "}")?;
817 Some(fb)
818 } else {
819 None
820 };
821
822 if !has_catch && finally_body.is_none() {
824 return Ok(spanned(
825 Node::TryExpr { body },
826 Span::merge(start, self.prev_span()),
827 ));
828 }
829
830 Ok(spanned(
831 Node::TryCatch {
832 body,
833 error_var,
834 error_type,
835 catch_body,
836 finally_body,
837 },
838 Span::merge(start, self.prev_span()),
839 ))
840 }
841
842 fn parse_select(&mut self) -> Result<SNode, ParserError> {
843 let start = self.current_span();
844 self.consume(&TokenKind::Select, "select")?;
845 self.consume(&TokenKind::LBrace, "{")?;
846 self.skip_newlines();
847
848 let mut cases = Vec::new();
849 let mut timeout = None;
850 let mut default_body = None;
851
852 while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
853 self.skip_newlines();
854 if let Some(tok) = self.current() {
856 if let TokenKind::Identifier(ref id) = tok.kind {
857 if id == "timeout" {
858 self.advance();
859 let duration = self.parse_expression()?;
860 self.consume(&TokenKind::LBrace, "{")?;
861 let body = self.parse_block()?;
862 self.consume(&TokenKind::RBrace, "}")?;
863 timeout = Some((Box::new(duration), body));
864 self.skip_newlines();
865 continue;
866 }
867 if id == "default" {
868 self.advance();
869 self.consume(&TokenKind::LBrace, "{")?;
870 let body = self.parse_block()?;
871 self.consume(&TokenKind::RBrace, "}")?;
872 default_body = Some(body);
873 self.skip_newlines();
874 continue;
875 }
876 }
877 }
878 let variable = self.consume_identifier("select case variable")?;
879 self.consume(&TokenKind::From, "from")?;
880 let channel = self.parse_expression()?;
881 self.consume(&TokenKind::LBrace, "{")?;
882 let body = self.parse_block()?;
883 self.consume(&TokenKind::RBrace, "}")?;
884 cases.push(SelectCase {
885 variable,
886 channel: Box::new(channel),
887 body,
888 });
889 self.skip_newlines();
890 }
891
892 self.consume(&TokenKind::RBrace, "}")?;
893
894 if cases.is_empty() && timeout.is_none() && default_body.is_none() {
895 return Err(self.error("at least one select case"));
896 }
897 if timeout.is_some() && default_body.is_some() {
898 return Err(self.error("select cannot have both timeout and default"));
899 }
900
901 Ok(spanned(
902 Node::SelectExpr {
903 cases,
904 timeout,
905 default_body,
906 },
907 Span::merge(start, self.prev_span()),
908 ))
909 }
910
911 fn parse_attributed_decl(&mut self) -> Result<SNode, ParserError> {
917 let start = self.current_span();
918 let mut attributes = Vec::new();
919 while self.check(&TokenKind::At) {
920 attributes.push(self.parse_one_attribute()?);
921 self.skip_newlines();
922 }
923 let inner = if self.check(&TokenKind::Pipeline) {
926 self.parse_pipeline()?
927 } else {
928 self.parse_statement()?
929 };
930 match &inner.node {
931 Node::FnDecl { .. }
932 | Node::ToolDecl { .. }
933 | Node::Pipeline { .. }
934 | Node::StructDecl { .. }
935 | Node::EnumDecl { .. }
936 | Node::TypeDecl { .. }
937 | Node::InterfaceDecl { .. }
938 | Node::ImplBlock { .. } => {}
939 _ => {
940 return Err(ParserError::Unexpected {
941 got: "non-declaration statement".into(),
942 expected:
943 "fn/tool/pipeline/struct/enum/type/interface/impl declaration after `@attr`"
944 .into(),
945 span: inner.span,
946 });
947 }
948 }
949 Ok(spanned(
950 Node::AttributedDecl {
951 attributes,
952 inner: Box::new(inner),
953 },
954 Span::merge(start, self.prev_span()),
955 ))
956 }
957
958 fn parse_one_attribute(&mut self) -> Result<Attribute, ParserError> {
959 let at_span = self.current_span();
960 self.consume(&TokenKind::At, "@")?;
961 let name_span = self.current_span();
962 let name = self.consume_identifier("attribute name")?;
963 let mut args = Vec::new();
964 if self.check(&TokenKind::LParen) {
965 self.advance();
966 while !self.check(&TokenKind::RParen) {
967 args.push(self.parse_attribute_arg()?);
968 if self.check(&TokenKind::Comma) {
969 self.advance();
970 self.skip_newlines();
971 } else {
972 break;
973 }
974 }
975 self.consume(&TokenKind::RParen, ")")?;
976 }
977 let _ = name_span;
978 Ok(Attribute {
979 name,
980 args,
981 span: Span::merge(at_span, self.prev_span()),
982 })
983 }
984
985 fn parse_attribute_arg(&mut self) -> Result<AttributeArg, ParserError> {
986 let start = self.current_span();
987 if let (Some(t1), Some(t2)) = (self.peek_kind_at(0), self.peek_kind_at(1)) {
989 if matches!(t1, TokenKind::Identifier(_)) && matches!(t2, TokenKind::Colon) {
990 let key = self.consume_identifier("argument name")?;
991 self.consume(&TokenKind::Colon, ":")?;
992 let value = self.parse_attribute_value()?;
993 return Ok(AttributeArg {
994 name: Some(key),
995 value,
996 span: Span::merge(start, self.prev_span()),
997 });
998 }
999 }
1000 let value = self.parse_attribute_value()?;
1001 Ok(AttributeArg {
1002 name: None,
1003 value,
1004 span: Span::merge(start, self.prev_span()),
1005 })
1006 }
1007
1008 fn parse_attribute_value(&mut self) -> Result<SNode, ParserError> {
1013 let span = self.current_span();
1014 let tok = self.current().ok_or_else(|| ParserError::UnexpectedEof {
1015 expected: "attribute value".into(),
1016 span: self.prev_span(),
1017 })?;
1018 let node = match &tok.kind {
1019 TokenKind::StringLiteral(s) => Node::StringLiteral(s.clone()),
1020 TokenKind::RawStringLiteral(s) => Node::RawStringLiteral(s.clone()),
1021 TokenKind::IntLiteral(i) => Node::IntLiteral(*i),
1022 TokenKind::FloatLiteral(f) => Node::FloatLiteral(*f),
1023 TokenKind::True => Node::BoolLiteral(true),
1024 TokenKind::False => Node::BoolLiteral(false),
1025 TokenKind::Nil => Node::NilLiteral,
1026 TokenKind::Identifier(name) => Node::Identifier(name.clone()),
1027 TokenKind::Minus => {
1028 self.advance();
1029 let inner_tok = self.current().ok_or_else(|| ParserError::UnexpectedEof {
1030 expected: "number after '-'".into(),
1031 span: self.prev_span(),
1032 })?;
1033 let n = match &inner_tok.kind {
1034 TokenKind::IntLiteral(i) => Node::IntLiteral(-i),
1035 TokenKind::FloatLiteral(f) => Node::FloatLiteral(-f),
1036 _ => {
1037 return Err(self.error("number after '-' in attribute argument"));
1038 }
1039 };
1040 self.advance();
1041 return Ok(spanned(n, Span::merge(span, self.prev_span())));
1042 }
1043 _ => return Err(self.error("attribute argument value (literal or identifier)")),
1044 };
1045 self.advance();
1046 Ok(spanned(node, span))
1047 }
1048
1049 fn parse_fn_decl_with_pub(&mut self, is_pub: bool) -> Result<SNode, ParserError> {
1050 let start = self.current_span();
1051 self.consume(&TokenKind::Fn, "fn")?;
1052 let name = self.consume_identifier("function name")?;
1053
1054 let type_params = if self.check(&TokenKind::Lt) {
1055 self.advance();
1056 self.parse_type_param_list()?
1057 } else {
1058 Vec::new()
1059 };
1060
1061 self.consume(&TokenKind::LParen, "(")?;
1062 let params = self.parse_typed_param_list()?;
1063 self.consume(&TokenKind::RParen, ")")?;
1064 let return_type = if self.check(&TokenKind::Arrow) {
1065 self.advance();
1066 Some(self.parse_type_expr()?)
1067 } else {
1068 None
1069 };
1070
1071 let where_clauses = self.parse_where_clauses()?;
1072
1073 self.consume(&TokenKind::LBrace, "{")?;
1074 let body = self.parse_block()?;
1075 self.consume(&TokenKind::RBrace, "}")?;
1076 Ok(spanned(
1077 Node::FnDecl {
1078 name,
1079 type_params,
1080 params,
1081 return_type,
1082 where_clauses,
1083 body,
1084 is_pub,
1085 },
1086 Span::merge(start, self.prev_span()),
1087 ))
1088 }
1089
1090 fn parse_tool_decl(&mut self, is_pub: bool) -> Result<SNode, ParserError> {
1091 let start = self.current_span();
1092 self.consume(&TokenKind::Tool, "tool")?;
1093 let name = self.consume_identifier("tool name")?;
1094
1095 self.consume(&TokenKind::LParen, "(")?;
1096 let params = self.parse_typed_param_list()?;
1097 self.consume(&TokenKind::RParen, ")")?;
1098
1099 let return_type = if self.check(&TokenKind::Arrow) {
1100 self.advance();
1101 Some(self.parse_type_expr()?)
1102 } else {
1103 None
1104 };
1105
1106 self.consume(&TokenKind::LBrace, "{")?;
1107
1108 self.skip_newlines();
1110 let mut description = None;
1111 if let Some(TokenKind::Identifier(id)) = self.current_kind().cloned() {
1112 if id == "description" {
1113 let saved_pos = self.pos;
1114 self.advance();
1115 self.skip_newlines();
1116 if let Some(TokenKind::StringLiteral(s)) = self.current_kind().cloned() {
1117 description = Some(s);
1118 self.advance();
1119 } else {
1120 self.pos = saved_pos;
1121 }
1122 }
1123 }
1124
1125 let body = self.parse_block()?;
1126 self.consume(&TokenKind::RBrace, "}")?;
1127
1128 Ok(spanned(
1129 Node::ToolDecl {
1130 name,
1131 description,
1132 params,
1133 return_type,
1134 body,
1135 is_pub,
1136 },
1137 Span::merge(start, self.prev_span()),
1138 ))
1139 }
1140
1141 fn parse_type_decl(&mut self) -> Result<SNode, ParserError> {
1142 let start = self.current_span();
1143 self.consume(&TokenKind::TypeKw, "type")?;
1144 let name = self.consume_identifier("type name")?;
1145 let type_params = if self.check(&TokenKind::Lt) {
1146 self.advance();
1147 self.parse_type_param_list()?
1148 } else {
1149 Vec::new()
1150 };
1151 self.consume(&TokenKind::Assign, "=")?;
1152 let type_expr = self.parse_type_expr()?;
1153 Ok(spanned(
1154 Node::TypeDecl {
1155 name,
1156 type_params,
1157 type_expr,
1158 },
1159 Span::merge(start, self.prev_span()),
1160 ))
1161 }
1162
1163 fn parse_enum_decl_with_pub(&mut self, is_pub: bool) -> Result<SNode, ParserError> {
1164 let start = self.current_span();
1165 self.consume(&TokenKind::Enum, "enum")?;
1166 let name = self.consume_identifier("enum name")?;
1167 let type_params = if self.check(&TokenKind::Lt) {
1168 self.advance();
1169 self.parse_type_param_list()?
1170 } else {
1171 Vec::new()
1172 };
1173 self.consume(&TokenKind::LBrace, "{")?;
1174 self.skip_newlines();
1175
1176 let mut variants = Vec::new();
1177 while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
1178 let variant_name = self.consume_identifier("variant name")?;
1179 let fields = if self.check(&TokenKind::LParen) {
1180 self.advance();
1181 let params = self.parse_typed_param_list()?;
1182 self.consume(&TokenKind::RParen, ")")?;
1183 params
1184 } else {
1185 Vec::new()
1186 };
1187 variants.push(EnumVariant {
1188 name: variant_name,
1189 fields,
1190 });
1191 self.skip_newlines();
1192 if self.check(&TokenKind::Comma) {
1193 self.advance();
1194 self.skip_newlines();
1195 }
1196 }
1197
1198 self.consume(&TokenKind::RBrace, "}")?;
1199 Ok(spanned(
1200 Node::EnumDecl {
1201 name,
1202 type_params,
1203 variants,
1204 is_pub,
1205 },
1206 Span::merge(start, self.prev_span()),
1207 ))
1208 }
1209
1210 fn parse_enum_decl(&mut self) -> Result<SNode, ParserError> {
1211 self.parse_enum_decl_with_pub(false)
1212 }
1213
1214 fn parse_struct_decl_with_pub(&mut self, is_pub: bool) -> Result<SNode, ParserError> {
1215 let start = self.current_span();
1216 self.consume(&TokenKind::Struct, "struct")?;
1217 let name = self.consume_identifier("struct name")?;
1218 self.struct_names.insert(name.clone());
1219 let type_params = if self.check(&TokenKind::Lt) {
1220 self.advance();
1221 self.parse_type_param_list()?
1222 } else {
1223 Vec::new()
1224 };
1225 self.consume(&TokenKind::LBrace, "{")?;
1226 self.skip_newlines();
1227
1228 let mut fields = Vec::new();
1229 while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
1230 let field_name = self.consume_identifier("field name")?;
1231 let optional = if self.check(&TokenKind::Question) {
1232 self.advance();
1233 true
1234 } else {
1235 false
1236 };
1237 let type_expr = self.try_parse_type_annotation()?;
1238 fields.push(StructField {
1239 name: field_name,
1240 type_expr,
1241 optional,
1242 });
1243 self.skip_newlines();
1244 if self.check(&TokenKind::Comma) {
1245 self.advance();
1246 self.skip_newlines();
1247 }
1248 }
1249
1250 self.consume(&TokenKind::RBrace, "}")?;
1251 Ok(spanned(
1252 Node::StructDecl {
1253 name,
1254 type_params,
1255 fields,
1256 is_pub,
1257 },
1258 Span::merge(start, self.prev_span()),
1259 ))
1260 }
1261
1262 fn parse_struct_decl(&mut self) -> Result<SNode, ParserError> {
1263 self.parse_struct_decl_with_pub(false)
1264 }
1265
1266 fn parse_interface_decl(&mut self) -> Result<SNode, ParserError> {
1267 let start = self.current_span();
1268 self.consume(&TokenKind::Interface, "interface")?;
1269 let name = self.consume_identifier("interface name")?;
1270 let type_params = if self.check(&TokenKind::Lt) {
1271 self.advance();
1272 self.parse_type_param_list()?
1273 } else {
1274 Vec::new()
1275 };
1276 self.consume(&TokenKind::LBrace, "{")?;
1277 self.skip_newlines();
1278
1279 let mut associated_types = Vec::new();
1280 let mut methods = Vec::new();
1281 while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
1282 if self.check(&TokenKind::TypeKw) {
1283 self.advance();
1284 let assoc_name = self.consume_identifier("associated type name")?;
1285 let assoc_type = if self.check(&TokenKind::Assign) {
1286 self.advance();
1287 Some(self.parse_type_expr()?)
1288 } else {
1289 None
1290 };
1291 associated_types.push((assoc_name, assoc_type));
1292 } else {
1293 self.consume(&TokenKind::Fn, "fn")?;
1294 let method_name = self.consume_identifier("method name")?;
1295 let method_type_params = if self.check(&TokenKind::Lt) {
1296 self.advance();
1297 self.parse_type_param_list()?
1298 } else {
1299 Vec::new()
1300 };
1301 self.consume(&TokenKind::LParen, "(")?;
1302 let params = self.parse_typed_param_list()?;
1303 self.consume(&TokenKind::RParen, ")")?;
1304 let return_type = if self.check(&TokenKind::Arrow) {
1305 self.advance();
1306 Some(self.parse_type_expr()?)
1307 } else {
1308 None
1309 };
1310 methods.push(InterfaceMethod {
1311 name: method_name,
1312 type_params: method_type_params,
1313 params,
1314 return_type,
1315 });
1316 }
1317 self.skip_newlines();
1318 }
1319
1320 self.consume(&TokenKind::RBrace, "}")?;
1321 Ok(spanned(
1322 Node::InterfaceDecl {
1323 name,
1324 type_params,
1325 associated_types,
1326 methods,
1327 },
1328 Span::merge(start, self.prev_span()),
1329 ))
1330 }
1331
1332 fn parse_impl_block(&mut self) -> Result<SNode, ParserError> {
1333 let start = self.current_span();
1334 self.consume(&TokenKind::Impl, "impl")?;
1335 let type_name = self.consume_identifier("type name")?;
1336 self.consume(&TokenKind::LBrace, "{")?;
1337 self.skip_newlines();
1338
1339 let mut methods = Vec::new();
1340 while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
1341 let is_pub = self.check(&TokenKind::Pub);
1342 if is_pub {
1343 self.advance();
1344 }
1345 let method = self.parse_fn_decl_with_pub(is_pub)?;
1346 methods.push(method);
1347 self.skip_newlines();
1348 }
1349
1350 self.consume(&TokenKind::RBrace, "}")?;
1351 Ok(spanned(
1352 Node::ImplBlock { type_name, methods },
1353 Span::merge(start, self.prev_span()),
1354 ))
1355 }
1356
1357 fn parse_guard(&mut self) -> Result<SNode, ParserError> {
1358 let start = self.current_span();
1359 self.consume(&TokenKind::Guard, "guard")?;
1360 let condition = self.parse_expression()?;
1361 self.consume(&TokenKind::Else, "else")?;
1362 self.consume(&TokenKind::LBrace, "{")?;
1363 let else_body = self.parse_block()?;
1364 self.consume(&TokenKind::RBrace, "}")?;
1365 Ok(spanned(
1366 Node::GuardStmt {
1367 condition: Box::new(condition),
1368 else_body,
1369 },
1370 Span::merge(start, self.prev_span()),
1371 ))
1372 }
1373
1374 fn parse_require(&mut self) -> Result<SNode, ParserError> {
1375 let start = self.current_span();
1376 self.consume(&TokenKind::Require, "require")?;
1377 let condition = self.parse_expression()?;
1378 let message = if self.check(&TokenKind::Comma) {
1379 self.advance();
1380 Some(Box::new(self.parse_expression()?))
1381 } else {
1382 None
1383 };
1384 Ok(spanned(
1385 Node::RequireStmt {
1386 condition: Box::new(condition),
1387 message,
1388 },
1389 Span::merge(start, self.prev_span()),
1390 ))
1391 }
1392
1393 fn parse_deadline(&mut self) -> Result<SNode, ParserError> {
1394 let start = self.current_span();
1395 self.consume(&TokenKind::Deadline, "deadline")?;
1396 let duration = self.parse_primary()?;
1397 self.consume(&TokenKind::LBrace, "{")?;
1398 let body = self.parse_block()?;
1399 self.consume(&TokenKind::RBrace, "}")?;
1400 Ok(spanned(
1401 Node::DeadlineBlock {
1402 duration: Box::new(duration),
1403 body,
1404 },
1405 Span::merge(start, self.prev_span()),
1406 ))
1407 }
1408
1409 fn parse_yield(&mut self) -> Result<SNode, ParserError> {
1410 let start = self.current_span();
1411 self.consume(&TokenKind::Yield, "yield")?;
1412 if self.is_at_end() || self.check(&TokenKind::Newline) || self.check(&TokenKind::RBrace) {
1413 return Ok(spanned(
1414 Node::YieldExpr { value: None },
1415 Span::merge(start, self.prev_span()),
1416 ));
1417 }
1418 let value = self.parse_expression()?;
1419 Ok(spanned(
1420 Node::YieldExpr {
1421 value: Some(Box::new(value)),
1422 },
1423 Span::merge(start, self.prev_span()),
1424 ))
1425 }
1426
1427 fn parse_mutex(&mut self) -> Result<SNode, ParserError> {
1428 let start = self.current_span();
1429 self.consume(&TokenKind::Mutex, "mutex")?;
1430 self.consume(&TokenKind::LBrace, "{")?;
1431 let body = self.parse_block()?;
1432 self.consume(&TokenKind::RBrace, "}")?;
1433 Ok(spanned(
1434 Node::MutexBlock { body },
1435 Span::merge(start, self.prev_span()),
1436 ))
1437 }
1438
1439 fn parse_defer(&mut self) -> Result<SNode, ParserError> {
1440 let start = self.current_span();
1441 self.consume(&TokenKind::Defer, "defer")?;
1442 self.consume(&TokenKind::LBrace, "{")?;
1443 let body = self.parse_block()?;
1444 self.consume(&TokenKind::RBrace, "}")?;
1445 Ok(spanned(
1446 Node::DeferStmt { body },
1447 Span::merge(start, self.prev_span()),
1448 ))
1449 }
1450
1451 fn parse_expression_statement(&mut self) -> Result<SNode, ParserError> {
1452 let start = self.current_span();
1453 let expr = self.parse_expression()?;
1454
1455 let is_assignable = matches!(
1458 expr.node,
1459 Node::Identifier(_) | Node::PropertyAccess { .. } | Node::SubscriptAccess { .. }
1460 );
1461 if is_assignable {
1462 if self.check(&TokenKind::Assign) {
1463 self.advance();
1464 let value = self.parse_expression()?;
1465 return Ok(spanned(
1466 Node::Assignment {
1467 target: Box::new(expr),
1468 value: Box::new(value),
1469 op: None,
1470 },
1471 Span::merge(start, self.prev_span()),
1472 ));
1473 }
1474 let compound_op = if self.check(&TokenKind::PlusAssign) {
1475 Some("+")
1476 } else if self.check(&TokenKind::MinusAssign) {
1477 Some("-")
1478 } else if self.check(&TokenKind::StarAssign) {
1479 Some("*")
1480 } else if self.check(&TokenKind::SlashAssign) {
1481 Some("/")
1482 } else if self.check(&TokenKind::PercentAssign) {
1483 Some("%")
1484 } else {
1485 None
1486 };
1487 if let Some(op) = compound_op {
1488 self.advance();
1489 let value = self.parse_expression()?;
1490 return Ok(spanned(
1491 Node::Assignment {
1492 target: Box::new(expr),
1493 value: Box::new(value),
1494 op: Some(op.into()),
1495 },
1496 Span::merge(start, self.prev_span()),
1497 ));
1498 }
1499 }
1500
1501 Ok(expr)
1502 }
1503
1504 fn parse_expression(&mut self) -> Result<SNode, ParserError> {
1505 self.skip_newlines();
1506 self.parse_pipe()
1507 }
1508
1509 fn parse_pipe(&mut self) -> Result<SNode, ParserError> {
1510 let mut left = self.parse_range()?;
1511 while self.check_skip_newlines(&TokenKind::Pipe) {
1512 let start = left.span;
1513 self.advance();
1514 let right = self.parse_range()?;
1515 left = spanned(
1516 Node::BinaryOp {
1517 op: "|>".into(),
1518 left: Box::new(left),
1519 right: Box::new(right),
1520 },
1521 Span::merge(start, self.prev_span()),
1522 );
1523 }
1524 Ok(left)
1525 }
1526
1527 fn parse_range(&mut self) -> Result<SNode, ParserError> {
1528 let left = self.parse_ternary()?;
1529 if self.check(&TokenKind::To) {
1530 let start = left.span;
1531 self.advance();
1532 let right = self.parse_ternary()?;
1533 let inclusive = if self.check(&TokenKind::Exclusive) {
1534 self.advance();
1535 false
1536 } else {
1537 true
1538 };
1539 return Ok(spanned(
1540 Node::RangeExpr {
1541 start: Box::new(left),
1542 end: Box::new(right),
1543 inclusive,
1544 },
1545 Span::merge(start, self.prev_span()),
1546 ));
1547 }
1548 Ok(left)
1549 }
1550
1551 fn parse_ternary(&mut self) -> Result<SNode, ParserError> {
1552 let condition = self.parse_logical_or()?;
1553 if !self.check(&TokenKind::Question) {
1554 return Ok(condition);
1555 }
1556 let start = condition.span;
1557 self.advance(); let true_val = self.parse_logical_or()?;
1559 self.consume(&TokenKind::Colon, ":")?;
1560 let false_val = self.parse_logical_or()?;
1561 Ok(spanned(
1562 Node::Ternary {
1563 condition: Box::new(condition),
1564 true_expr: Box::new(true_val),
1565 false_expr: Box::new(false_val),
1566 },
1567 Span::merge(start, self.prev_span()),
1568 ))
1569 }
1570
1571 fn parse_nil_coalescing(&mut self) -> Result<SNode, ParserError> {
1574 let mut left = self.parse_multiplicative()?;
1575 while self.check(&TokenKind::NilCoal) {
1576 let start = left.span;
1577 self.advance();
1578 let right = self.parse_multiplicative()?;
1579 left = spanned(
1580 Node::BinaryOp {
1581 op: "??".into(),
1582 left: Box::new(left),
1583 right: Box::new(right),
1584 },
1585 Span::merge(start, self.prev_span()),
1586 );
1587 }
1588 Ok(left)
1589 }
1590
1591 fn parse_logical_or(&mut self) -> Result<SNode, ParserError> {
1592 let mut left = self.parse_logical_and()?;
1593 while self.check_skip_newlines(&TokenKind::Or) {
1594 let start = left.span;
1595 self.advance();
1596 let right = self.parse_logical_and()?;
1597 left = spanned(
1598 Node::BinaryOp {
1599 op: "||".into(),
1600 left: Box::new(left),
1601 right: Box::new(right),
1602 },
1603 Span::merge(start, self.prev_span()),
1604 );
1605 }
1606 Ok(left)
1607 }
1608
1609 fn parse_logical_and(&mut self) -> Result<SNode, ParserError> {
1610 let mut left = self.parse_equality()?;
1611 while self.check_skip_newlines(&TokenKind::And) {
1612 let start = left.span;
1613 self.advance();
1614 let right = self.parse_equality()?;
1615 left = spanned(
1616 Node::BinaryOp {
1617 op: "&&".into(),
1618 left: Box::new(left),
1619 right: Box::new(right),
1620 },
1621 Span::merge(start, self.prev_span()),
1622 );
1623 }
1624 Ok(left)
1625 }
1626
1627 fn parse_equality(&mut self) -> Result<SNode, ParserError> {
1628 let mut left = self.parse_comparison()?;
1629 while self.check(&TokenKind::Eq) || self.check(&TokenKind::Neq) {
1630 let start = left.span;
1631 let op = if self.check(&TokenKind::Eq) {
1632 "=="
1633 } else {
1634 "!="
1635 };
1636 self.advance();
1637 let right = self.parse_comparison()?;
1638 left = spanned(
1639 Node::BinaryOp {
1640 op: op.into(),
1641 left: Box::new(left),
1642 right: Box::new(right),
1643 },
1644 Span::merge(start, self.prev_span()),
1645 );
1646 }
1647 Ok(left)
1648 }
1649
1650 fn parse_comparison(&mut self) -> Result<SNode, ParserError> {
1651 let mut left = self.parse_additive()?;
1652 loop {
1653 if self.check(&TokenKind::Lt)
1654 || self.check(&TokenKind::Gt)
1655 || self.check(&TokenKind::Lte)
1656 || self.check(&TokenKind::Gte)
1657 {
1658 let start = left.span;
1659 let op = match self.current().map(|t| &t.kind) {
1660 Some(TokenKind::Lt) => "<",
1661 Some(TokenKind::Gt) => ">",
1662 Some(TokenKind::Lte) => "<=",
1663 Some(TokenKind::Gte) => ">=",
1664 _ => "<",
1665 };
1666 self.advance();
1667 let right = self.parse_additive()?;
1668 left = spanned(
1669 Node::BinaryOp {
1670 op: op.into(),
1671 left: Box::new(left),
1672 right: Box::new(right),
1673 },
1674 Span::merge(start, self.prev_span()),
1675 );
1676 } else if self.check(&TokenKind::In) {
1677 let start = left.span;
1678 self.advance();
1679 let right = self.parse_additive()?;
1680 left = spanned(
1681 Node::BinaryOp {
1682 op: "in".into(),
1683 left: Box::new(left),
1684 right: Box::new(right),
1685 },
1686 Span::merge(start, self.prev_span()),
1687 );
1688 } else if self.check_identifier("not") {
1689 let saved = self.pos;
1690 self.advance();
1691 if self.check(&TokenKind::In) {
1692 let start = left.span;
1693 self.advance();
1694 let right = self.parse_additive()?;
1695 left = spanned(
1696 Node::BinaryOp {
1697 op: "not_in".into(),
1698 left: Box::new(left),
1699 right: Box::new(right),
1700 },
1701 Span::merge(start, self.prev_span()),
1702 );
1703 } else {
1704 self.pos = saved;
1705 break;
1706 }
1707 } else {
1708 break;
1709 }
1710 }
1711 Ok(left)
1712 }
1713
1714 fn parse_additive(&mut self) -> Result<SNode, ParserError> {
1715 let mut left = self.parse_nil_coalescing()?;
1716 while self.check_skip_newlines(&TokenKind::Plus) || self.check(&TokenKind::Minus) {
1717 let start = left.span;
1718 let op = if self.check(&TokenKind::Plus) {
1719 "+"
1720 } else {
1721 "-"
1722 };
1723 self.advance();
1724 let right = self.parse_nil_coalescing()?;
1725 left = spanned(
1726 Node::BinaryOp {
1727 op: op.into(),
1728 left: Box::new(left),
1729 right: Box::new(right),
1730 },
1731 Span::merge(start, self.prev_span()),
1732 );
1733 }
1734 Ok(left)
1735 }
1736
1737 fn parse_multiplicative(&mut self) -> Result<SNode, ParserError> {
1738 let mut left = self.parse_exponent()?;
1739 while self.check_skip_newlines(&TokenKind::Star)
1740 || self.check_skip_newlines(&TokenKind::Slash)
1741 || self.check_skip_newlines(&TokenKind::Percent)
1742 {
1743 let start = left.span;
1744 let op = if self.check(&TokenKind::Star) {
1745 "*"
1746 } else if self.check(&TokenKind::Slash) {
1747 "/"
1748 } else {
1749 "%"
1750 };
1751 self.advance();
1752 let right = self.parse_exponent()?;
1753 left = spanned(
1754 Node::BinaryOp {
1755 op: op.into(),
1756 left: Box::new(left),
1757 right: Box::new(right),
1758 },
1759 Span::merge(start, self.prev_span()),
1760 );
1761 }
1762 Ok(left)
1763 }
1764
1765 fn parse_exponent(&mut self) -> Result<SNode, ParserError> {
1766 let left = self.parse_unary()?;
1767 if !self.check_skip_newlines(&TokenKind::Pow) {
1768 return Ok(left);
1769 }
1770
1771 let start = left.span;
1772 self.advance();
1773 let right = self.parse_exponent()?;
1774 Ok(spanned(
1775 Node::BinaryOp {
1776 op: "**".into(),
1777 left: Box::new(left),
1778 right: Box::new(right),
1779 },
1780 Span::merge(start, self.prev_span()),
1781 ))
1782 }
1783
1784 fn parse_unary(&mut self) -> Result<SNode, ParserError> {
1785 if self.check(&TokenKind::Not) {
1786 let start = self.current_span();
1787 self.advance();
1788 let operand = self.parse_unary()?;
1789 return Ok(spanned(
1790 Node::UnaryOp {
1791 op: "!".into(),
1792 operand: Box::new(operand),
1793 },
1794 Span::merge(start, self.prev_span()),
1795 ));
1796 }
1797 if self.check(&TokenKind::Minus) {
1798 let start = self.current_span();
1799 self.advance();
1800 let operand = self.parse_unary()?;
1801 return Ok(spanned(
1802 Node::UnaryOp {
1803 op: "-".into(),
1804 operand: Box::new(operand),
1805 },
1806 Span::merge(start, self.prev_span()),
1807 ));
1808 }
1809 self.parse_postfix()
1810 }
1811
1812 fn parse_postfix(&mut self) -> Result<SNode, ParserError> {
1813 let mut expr = self.parse_primary()?;
1814
1815 loop {
1816 if self.check_skip_newlines(&TokenKind::Dot)
1817 || self.check_skip_newlines(&TokenKind::QuestionDot)
1818 {
1819 let optional = self.check(&TokenKind::QuestionDot);
1820 let start = expr.span;
1821 self.advance();
1822 let member = self.consume_identifier_or_keyword("member name")?;
1823 if self.check(&TokenKind::LParen) {
1824 self.advance();
1825 let args = self.parse_arg_list()?;
1826 self.consume(&TokenKind::RParen, ")")?;
1827 if optional {
1828 expr = spanned(
1829 Node::OptionalMethodCall {
1830 object: Box::new(expr),
1831 method: member,
1832 args,
1833 },
1834 Span::merge(start, self.prev_span()),
1835 );
1836 } else {
1837 expr = spanned(
1838 Node::MethodCall {
1839 object: Box::new(expr),
1840 method: member,
1841 args,
1842 },
1843 Span::merge(start, self.prev_span()),
1844 );
1845 }
1846 } else if optional {
1847 expr = spanned(
1848 Node::OptionalPropertyAccess {
1849 object: Box::new(expr),
1850 property: member,
1851 },
1852 Span::merge(start, self.prev_span()),
1853 );
1854 } else {
1855 expr = spanned(
1856 Node::PropertyAccess {
1857 object: Box::new(expr),
1858 property: member,
1859 },
1860 Span::merge(start, self.prev_span()),
1861 );
1862 }
1863 } else if self.check(&TokenKind::LBracket) {
1864 let start = expr.span;
1865 self.advance();
1866
1867 if self.check(&TokenKind::Colon) {
1870 self.advance();
1871 let end_expr = if self.check(&TokenKind::RBracket) {
1872 None
1873 } else {
1874 Some(Box::new(self.parse_expression()?))
1875 };
1876 self.consume(&TokenKind::RBracket, "]")?;
1877 expr = spanned(
1878 Node::SliceAccess {
1879 object: Box::new(expr),
1880 start: None,
1881 end: end_expr,
1882 },
1883 Span::merge(start, self.prev_span()),
1884 );
1885 } else {
1886 let index = self.parse_expression()?;
1887 if self.check(&TokenKind::Colon) {
1888 self.advance();
1889 let end_expr = if self.check(&TokenKind::RBracket) {
1890 None
1891 } else {
1892 Some(Box::new(self.parse_expression()?))
1893 };
1894 self.consume(&TokenKind::RBracket, "]")?;
1895 expr = spanned(
1896 Node::SliceAccess {
1897 object: Box::new(expr),
1898 start: Some(Box::new(index)),
1899 end: end_expr,
1900 },
1901 Span::merge(start, self.prev_span()),
1902 );
1903 } else {
1904 self.consume(&TokenKind::RBracket, "]")?;
1905 expr = spanned(
1906 Node::SubscriptAccess {
1907 object: Box::new(expr),
1908 index: Box::new(index),
1909 },
1910 Span::merge(start, self.prev_span()),
1911 );
1912 }
1913 }
1914 } else if self.check(&TokenKind::LBrace)
1915 && matches!(&expr.node, Node::Identifier(name) if self.struct_names.contains(name))
1916 {
1917 let start = expr.span;
1918 let struct_name = match expr.node {
1919 Node::Identifier(name) => name,
1920 _ => unreachable!("checked above"),
1921 };
1922 self.advance();
1923 let dict = self.parse_dict_literal(start)?;
1924 let fields = match dict.node {
1925 Node::DictLiteral(fields) => fields,
1926 _ => unreachable!("dict parser must return a dict literal"),
1927 };
1928 expr = spanned(
1929 Node::StructConstruct {
1930 struct_name,
1931 fields,
1932 },
1933 dict.span,
1934 );
1935 } else if self.check(&TokenKind::LParen) && matches!(expr.node, Node::Identifier(_)) {
1936 let start = expr.span;
1937 self.advance();
1938 let args = self.parse_arg_list()?;
1939 self.consume(&TokenKind::RParen, ")")?;
1940 if let Node::Identifier(name) = expr.node {
1941 expr = spanned(
1942 Node::FunctionCall { name, args },
1943 Span::merge(start, self.prev_span()),
1944 );
1945 }
1946 } else if self.check(&TokenKind::Question) {
1947 let next_pos = self.pos + 1;
1950 let is_ternary = self.tokens.get(next_pos).is_some_and(|t| {
1951 matches!(
1952 t.kind,
1953 TokenKind::Identifier(_)
1954 | TokenKind::IntLiteral(_)
1955 | TokenKind::FloatLiteral(_)
1956 | TokenKind::StringLiteral(_)
1957 | TokenKind::InterpolatedString(_)
1958 | TokenKind::True
1959 | TokenKind::False
1960 | TokenKind::Nil
1961 | TokenKind::LParen
1962 | TokenKind::LBracket
1963 | TokenKind::LBrace
1964 | TokenKind::Not
1965 | TokenKind::Minus
1966 | TokenKind::Fn
1967 )
1968 });
1969 if is_ternary {
1970 break;
1971 }
1972 let start = expr.span;
1973 self.advance();
1974 expr = spanned(
1975 Node::TryOperator {
1976 operand: Box::new(expr),
1977 },
1978 Span::merge(start, self.prev_span()),
1979 );
1980 } else {
1981 break;
1982 }
1983 }
1984
1985 Ok(expr)
1986 }
1987
1988 fn parse_primary(&mut self) -> Result<SNode, ParserError> {
1989 let tok = self.current().ok_or_else(|| ParserError::UnexpectedEof {
1990 expected: "expression".into(),
1991 span: self.prev_span(),
1992 })?;
1993 let start = self.current_span();
1994
1995 match &tok.kind {
1996 TokenKind::StringLiteral(s) => {
1997 let s = s.clone();
1998 self.advance();
1999 Ok(spanned(
2000 Node::StringLiteral(s),
2001 Span::merge(start, self.prev_span()),
2002 ))
2003 }
2004 TokenKind::RawStringLiteral(s) => {
2005 let s = s.clone();
2006 self.advance();
2007 Ok(spanned(
2008 Node::RawStringLiteral(s),
2009 Span::merge(start, self.prev_span()),
2010 ))
2011 }
2012 TokenKind::InterpolatedString(segments) => {
2013 let segments = segments.clone();
2014 self.advance();
2015 Ok(spanned(
2016 Node::InterpolatedString(segments),
2017 Span::merge(start, self.prev_span()),
2018 ))
2019 }
2020 TokenKind::IntLiteral(n) => {
2021 let n = *n;
2022 self.advance();
2023 Ok(spanned(
2024 Node::IntLiteral(n),
2025 Span::merge(start, self.prev_span()),
2026 ))
2027 }
2028 TokenKind::FloatLiteral(n) => {
2029 let n = *n;
2030 self.advance();
2031 Ok(spanned(
2032 Node::FloatLiteral(n),
2033 Span::merge(start, self.prev_span()),
2034 ))
2035 }
2036 TokenKind::True => {
2037 self.advance();
2038 Ok(spanned(
2039 Node::BoolLiteral(true),
2040 Span::merge(start, self.prev_span()),
2041 ))
2042 }
2043 TokenKind::False => {
2044 self.advance();
2045 Ok(spanned(
2046 Node::BoolLiteral(false),
2047 Span::merge(start, self.prev_span()),
2048 ))
2049 }
2050 TokenKind::Nil => {
2051 self.advance();
2052 Ok(spanned(
2053 Node::NilLiteral,
2054 Span::merge(start, self.prev_span()),
2055 ))
2056 }
2057 TokenKind::Identifier(name) => {
2058 let name = name.clone();
2059 self.advance();
2060 Ok(spanned(
2061 Node::Identifier(name),
2062 Span::merge(start, self.prev_span()),
2063 ))
2064 }
2065 TokenKind::LParen => {
2066 self.advance();
2067 let expr = self.parse_expression()?;
2068 self.consume(&TokenKind::RParen, ")")?;
2069 Ok(expr)
2070 }
2071 TokenKind::LBracket => self.parse_list_literal(),
2072 TokenKind::LBrace => self.parse_dict_or_closure(),
2073 TokenKind::Parallel => self.parse_parallel(),
2074 TokenKind::Retry => self.parse_retry(),
2075 TokenKind::If => self.parse_if_else(),
2076 TokenKind::Spawn => self.parse_spawn_expr(),
2077 TokenKind::DurationLiteral(ms) => {
2078 let ms = *ms;
2079 self.advance();
2080 Ok(spanned(
2081 Node::DurationLiteral(ms),
2082 Span::merge(start, self.prev_span()),
2083 ))
2084 }
2085 TokenKind::Deadline => self.parse_deadline(),
2086 TokenKind::Try => self.parse_try_catch(),
2087 TokenKind::Match => self.parse_match(),
2088 TokenKind::Fn => self.parse_fn_expr(),
2089 TokenKind::Lt
2092 if matches!(self.peek_kind(), Some(&TokenKind::Lt))
2093 && matches!(self.peek_kind_at(2), Some(TokenKind::Identifier(_))) =>
2094 {
2095 Err(ParserError::Unexpected {
2096 got: "`<<` heredoc-like syntax".to_string(),
2097 expected: "an expression — heredocs are only valid \
2098 inside LLM tool-call argument JSON; \
2099 for multiline strings in source code use \
2100 triple-quoted `\"\"\"...\"\"\"`"
2101 .to_string(),
2102 span: start,
2103 })
2104 }
2105 _ => Err(self.error("expression")),
2106 }
2107 }
2108
2109 fn parse_fn_expr(&mut self) -> Result<SNode, ParserError> {
2112 let start = self.current_span();
2113 self.consume(&TokenKind::Fn, "fn")?;
2114 self.consume(&TokenKind::LParen, "(")?;
2115 let params = self.parse_typed_param_list()?;
2116 self.consume(&TokenKind::RParen, ")")?;
2117 self.consume(&TokenKind::LBrace, "{")?;
2118 let body = self.parse_block()?;
2119 self.consume(&TokenKind::RBrace, "}")?;
2120 Ok(spanned(
2121 Node::Closure {
2122 params,
2123 body,
2124 fn_syntax: true,
2125 },
2126 Span::merge(start, self.prev_span()),
2127 ))
2128 }
2129
2130 fn parse_spawn_expr(&mut self) -> Result<SNode, ParserError> {
2131 let start = self.current_span();
2132 self.consume(&TokenKind::Spawn, "spawn")?;
2133 self.consume(&TokenKind::LBrace, "{")?;
2134 let body = self.parse_block()?;
2135 self.consume(&TokenKind::RBrace, "}")?;
2136 Ok(spanned(
2137 Node::SpawnExpr { body },
2138 Span::merge(start, self.prev_span()),
2139 ))
2140 }
2141
2142 fn parse_list_literal(&mut self) -> Result<SNode, ParserError> {
2143 let start = self.current_span();
2144 self.consume(&TokenKind::LBracket, "[")?;
2145 let mut elements = Vec::new();
2146 self.skip_newlines();
2147
2148 while !self.is_at_end() && !self.check(&TokenKind::RBracket) {
2149 if self.check(&TokenKind::Dot) {
2150 let saved_pos = self.pos;
2151 self.advance();
2152 if self.check(&TokenKind::Dot) {
2153 self.advance();
2154 self.consume(&TokenKind::Dot, ".")?;
2155 let spread_start = self.tokens[saved_pos].span;
2156 let expr = self.parse_expression()?;
2157 elements.push(spanned(
2158 Node::Spread(Box::new(expr)),
2159 Span::merge(spread_start, self.prev_span()),
2160 ));
2161 } else {
2162 self.pos = saved_pos;
2163 elements.push(self.parse_expression()?);
2164 }
2165 } else {
2166 elements.push(self.parse_expression()?);
2167 }
2168 self.skip_newlines();
2169 if self.check(&TokenKind::Comma) {
2170 self.advance();
2171 self.skip_newlines();
2172 }
2173 }
2174
2175 self.consume(&TokenKind::RBracket, "]")?;
2176 Ok(spanned(
2177 Node::ListLiteral(elements),
2178 Span::merge(start, self.prev_span()),
2179 ))
2180 }
2181
2182 fn parse_dict_or_closure(&mut self) -> Result<SNode, ParserError> {
2183 let start = self.current_span();
2184 self.consume(&TokenKind::LBrace, "{")?;
2185 self.skip_newlines();
2186
2187 if self.check(&TokenKind::RBrace) {
2188 self.advance();
2189 return Ok(spanned(
2190 Node::DictLiteral(Vec::new()),
2191 Span::merge(start, self.prev_span()),
2192 ));
2193 }
2194
2195 let saved = self.pos;
2197 if self.is_closure_lookahead() {
2198 self.pos = saved;
2199 return self.parse_closure_body(start);
2200 }
2201 self.pos = saved;
2202 self.parse_dict_literal(start)
2203 }
2204
2205 fn is_closure_lookahead(&mut self) -> bool {
2207 let mut depth = 0;
2208 while !self.is_at_end() {
2209 if let Some(tok) = self.current() {
2210 match &tok.kind {
2211 TokenKind::Arrow if depth == 0 => return true,
2212 TokenKind::LBrace | TokenKind::LParen | TokenKind::LBracket => depth += 1,
2213 TokenKind::RBrace if depth == 0 => return false,
2214 TokenKind::RBrace => depth -= 1,
2215 TokenKind::RParen | TokenKind::RBracket if depth > 0 => depth -= 1,
2216 _ => {}
2217 }
2218 self.advance();
2219 } else {
2220 return false;
2221 }
2222 }
2223 false
2224 }
2225
2226 fn parse_closure_body(&mut self, start: Span) -> Result<SNode, ParserError> {
2228 let params = self.parse_typed_param_list_until_arrow()?;
2229 self.consume(&TokenKind::Arrow, "->")?;
2230 let body = self.parse_block()?;
2231 self.consume(&TokenKind::RBrace, "}")?;
2232 Ok(spanned(
2233 Node::Closure {
2234 params,
2235 body,
2236 fn_syntax: false,
2237 },
2238 Span::merge(start, self.prev_span()),
2239 ))
2240 }
2241
2242 fn parse_typed_param_list_until_arrow(&mut self) -> Result<Vec<TypedParam>, ParserError> {
2244 self.parse_typed_params_until(|tok| tok == &TokenKind::Arrow)
2245 }
2246
2247 fn parse_dict_literal(&mut self, start: Span) -> Result<SNode, ParserError> {
2248 let entries = self.parse_dict_entries()?;
2249 Ok(spanned(
2250 Node::DictLiteral(entries),
2251 Span::merge(start, self.prev_span()),
2252 ))
2253 }
2254
2255 fn parse_dict_entries(&mut self) -> Result<Vec<DictEntry>, ParserError> {
2256 let mut entries = Vec::new();
2257 self.skip_newlines();
2258
2259 while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
2260 if self.check(&TokenKind::Dot) {
2261 let saved_pos = self.pos;
2262 self.advance();
2263 if self.check(&TokenKind::Dot) {
2264 self.advance();
2265 if self.check(&TokenKind::Dot) {
2266 self.advance();
2267 let spread_start = self.tokens[saved_pos].span;
2268 let expr = self.parse_expression()?;
2269 entries.push(DictEntry {
2270 key: spanned(Node::NilLiteral, spread_start),
2271 value: spanned(
2272 Node::Spread(Box::new(expr)),
2273 Span::merge(spread_start, self.prev_span()),
2274 ),
2275 });
2276 self.skip_newlines();
2277 if self.check(&TokenKind::Comma) {
2278 self.advance();
2279 self.skip_newlines();
2280 }
2281 continue;
2282 }
2283 self.pos = saved_pos;
2284 } else {
2285 self.pos = saved_pos;
2286 }
2287 }
2288 let key = if self.check(&TokenKind::LBracket) {
2289 self.advance();
2290 let k = self.parse_expression()?;
2291 self.consume(&TokenKind::RBracket, "]")?;
2292 k
2293 } else if matches!(
2294 self.current().map(|t| &t.kind),
2295 Some(TokenKind::StringLiteral(_))
2296 ) {
2297 let key_span = self.current_span();
2298 let name =
2299 if let Some(TokenKind::StringLiteral(s)) = self.current().map(|t| &t.kind) {
2300 s.clone()
2301 } else {
2302 unreachable!()
2303 };
2304 self.advance();
2305 spanned(Node::StringLiteral(name), key_span)
2306 } else {
2307 let key_span = self.current_span();
2308 let name = self.consume_identifier_or_keyword("dict key")?;
2309 spanned(Node::StringLiteral(name), key_span)
2310 };
2311 self.consume(&TokenKind::Colon, ":")?;
2312 let value = self.parse_expression()?;
2313 entries.push(DictEntry { key, value });
2314 self.skip_newlines();
2315 if self.check(&TokenKind::Comma) {
2316 self.advance();
2317 self.skip_newlines();
2318 }
2319 }
2320
2321 self.consume(&TokenKind::RBrace, "}")?;
2322 Ok(entries)
2323 }
2324
2325 fn parse_param_list(&mut self) -> Result<Vec<String>, ParserError> {
2327 let mut params = Vec::new();
2328 self.skip_newlines();
2329
2330 while !self.is_at_end() && !self.check(&TokenKind::RParen) {
2331 params.push(self.consume_identifier("parameter name")?);
2332 if self.check(&TokenKind::Comma) {
2333 self.advance();
2334 self.skip_newlines();
2335 }
2336 }
2337 Ok(params)
2338 }
2339
2340 fn parse_typed_param_list(&mut self) -> Result<Vec<TypedParam>, ParserError> {
2342 self.parse_typed_params_until(|tok| tok == &TokenKind::RParen)
2343 }
2344
2345 fn parse_typed_params_until(
2348 &mut self,
2349 is_terminator: impl Fn(&TokenKind) -> bool,
2350 ) -> Result<Vec<TypedParam>, ParserError> {
2351 let mut params = Vec::new();
2352 let mut seen_default = false;
2353 self.skip_newlines();
2354
2355 while !self.is_at_end() {
2356 if let Some(tok) = self.current() {
2357 if is_terminator(&tok.kind) {
2358 break;
2359 }
2360 } else {
2361 break;
2362 }
2363 let is_rest = if self.check(&TokenKind::Dot) {
2364 let p1 = self.pos + 1;
2365 let p2 = self.pos + 2;
2366 let is_ellipsis = p1 < self.tokens.len()
2367 && p2 < self.tokens.len()
2368 && self.tokens[p1].kind == TokenKind::Dot
2369 && self.tokens[p2].kind == TokenKind::Dot;
2370 if is_ellipsis {
2371 self.advance();
2372 self.advance();
2373 self.advance();
2374 true
2375 } else {
2376 false
2377 }
2378 } else {
2379 false
2380 };
2381 let name = self.consume_identifier("parameter name")?;
2382 let type_expr = self.try_parse_type_annotation()?;
2383 let default_value = if self.check(&TokenKind::Assign) {
2384 self.advance();
2385 seen_default = true;
2386 Some(Box::new(self.parse_expression()?))
2387 } else {
2388 if seen_default && !is_rest {
2389 return Err(self.error(
2390 "Required parameter cannot follow a parameter with a default value",
2391 ));
2392 }
2393 None
2394 };
2395 if is_rest
2396 && !is_terminator(
2397 &self
2398 .current()
2399 .map(|t| t.kind.clone())
2400 .unwrap_or(TokenKind::Eof),
2401 )
2402 {
2403 return Err(self.error("Rest parameter must be the last parameter"));
2404 }
2405 params.push(TypedParam {
2406 name,
2407 type_expr,
2408 default_value,
2409 rest: is_rest,
2410 });
2411 if self.check(&TokenKind::Comma) {
2412 self.advance();
2413 self.skip_newlines();
2414 }
2415 }
2416 Ok(params)
2417 }
2418
2419 fn parse_type_param_list(&mut self) -> Result<Vec<TypeParam>, ParserError> {
2425 let mut params = Vec::new();
2426 self.skip_newlines();
2427 while !self.is_at_end() && !self.check(&TokenKind::Gt) {
2428 let variance = self.parse_optional_variance_marker();
2429 let name = self.consume_identifier("type parameter name")?;
2430 params.push(TypeParam { name, variance });
2431 if self.check(&TokenKind::Comma) {
2432 self.advance();
2433 self.skip_newlines();
2434 }
2435 }
2436 self.consume(&TokenKind::Gt, ">")?;
2437 Ok(params)
2438 }
2439
2440 fn parse_optional_variance_marker(&mut self) -> Variance {
2446 if self.check(&TokenKind::In) {
2447 self.advance();
2448 return Variance::Contravariant;
2449 }
2450 if self.check_identifier("out") {
2451 if let Some(kind) = self.peek_kind() {
2452 if matches!(kind, TokenKind::Identifier(_)) {
2453 self.advance();
2454 return Variance::Covariant;
2455 }
2456 }
2457 }
2458 Variance::Invariant
2459 }
2460
2461 fn parse_where_clauses(&mut self) -> Result<Vec<WhereClause>, ParserError> {
2463 if let Some(tok) = self.current() {
2464 if let TokenKind::Identifier(ref id) = tok.kind {
2465 if id == "where" {
2466 self.advance();
2467 let mut clauses = Vec::new();
2468 loop {
2469 self.skip_newlines();
2470 if self.check(&TokenKind::LBrace) || self.is_at_end() {
2471 break;
2472 }
2473 let type_name = self.consume_identifier("type parameter name")?;
2474 self.consume(&TokenKind::Colon, ":")?;
2475 let bound = self.consume_identifier("type bound")?;
2476 clauses.push(WhereClause { type_name, bound });
2477 if self.check(&TokenKind::Comma) {
2478 self.advance();
2479 } else {
2480 break;
2481 }
2482 }
2483 return Ok(clauses);
2484 }
2485 }
2486 }
2487 Ok(Vec::new())
2488 }
2489
2490 fn try_parse_type_annotation(&mut self) -> Result<Option<TypeExpr>, ParserError> {
2492 if !self.check(&TokenKind::Colon) {
2493 return Ok(None);
2494 }
2495 self.advance();
2496 Ok(Some(self.parse_type_expr()?))
2497 }
2498
2499 fn parse_type_expr(&mut self) -> Result<TypeExpr, ParserError> {
2501 self.skip_newlines();
2502 let first = self.parse_type_primary()?;
2503
2504 if self.check(&TokenKind::Bar) {
2505 let mut types = vec![first];
2506 while self.check(&TokenKind::Bar) {
2507 self.advance();
2508 types.push(self.parse_type_primary()?);
2509 }
2510 return Ok(TypeExpr::Union(types));
2511 }
2512
2513 Ok(first)
2514 }
2515
2516 fn parse_type_primary(&mut self) -> Result<TypeExpr, ParserError> {
2518 self.skip_newlines();
2519 if self.check(&TokenKind::LBrace) {
2520 return self.parse_shape_type();
2521 }
2522 if let Some(tok) = self.current() {
2523 match &tok.kind {
2524 TokenKind::Nil => {
2525 self.advance();
2526 return Ok(TypeExpr::Named("nil".to_string()));
2527 }
2528 TokenKind::True | TokenKind::False => {
2529 self.advance();
2530 return Ok(TypeExpr::Named("bool".to_string()));
2531 }
2532 TokenKind::StringLiteral(text) | TokenKind::RawStringLiteral(text) => {
2533 let text = text.clone();
2534 self.advance();
2535 return Ok(TypeExpr::LitString(text));
2536 }
2537 TokenKind::IntLiteral(value) => {
2538 let value = *value;
2539 self.advance();
2540 return Ok(TypeExpr::LitInt(value));
2541 }
2542 TokenKind::Minus => {
2543 if let Some(TokenKind::IntLiteral(v)) = self.peek_kind_at(1) {
2545 let v = *v;
2546 self.advance();
2547 self.advance();
2548 return Ok(TypeExpr::LitInt(-v));
2549 }
2550 }
2551 _ => {}
2552 }
2553 }
2554 if self.check(&TokenKind::Fn) {
2555 self.advance();
2556 self.consume(&TokenKind::LParen, "(")?;
2557 let mut params = Vec::new();
2558 self.skip_newlines();
2559 while !self.is_at_end() && !self.check(&TokenKind::RParen) {
2560 params.push(self.parse_type_expr()?);
2561 self.skip_newlines();
2562 if self.check(&TokenKind::Comma) {
2563 self.advance();
2564 self.skip_newlines();
2565 }
2566 }
2567 self.consume(&TokenKind::RParen, ")")?;
2568 self.consume(&TokenKind::Arrow, "->")?;
2569 let return_type = self.parse_type_expr()?;
2570 return Ok(TypeExpr::FnType {
2571 params,
2572 return_type: Box::new(return_type),
2573 });
2574 }
2575 let name = self.consume_identifier("type name")?;
2576 if name == "never" {
2577 return Ok(TypeExpr::Never);
2578 }
2579 if self.check(&TokenKind::Lt) {
2580 self.advance();
2581 let mut type_args = vec![self.parse_type_expr()?];
2582 while self.check(&TokenKind::Comma) {
2583 self.advance();
2584 type_args.push(self.parse_type_expr()?);
2585 }
2586 self.consume(&TokenKind::Gt, ">")?;
2587 if name == "list" && type_args.len() == 1 {
2588 return Ok(TypeExpr::List(Box::new(type_args.remove(0))));
2589 } else if name == "dict" && type_args.len() == 2 {
2590 return Ok(TypeExpr::DictType(
2591 Box::new(type_args.remove(0)),
2592 Box::new(type_args.remove(0)),
2593 ));
2594 } else if (name == "iter" || name == "Iter") && type_args.len() == 1 {
2595 return Ok(TypeExpr::Iter(Box::new(type_args.remove(0))));
2596 }
2597 return Ok(TypeExpr::Applied {
2598 name,
2599 args: type_args,
2600 });
2601 }
2602 Ok(TypeExpr::Named(name))
2603 }
2604
2605 fn parse_shape_type(&mut self) -> Result<TypeExpr, ParserError> {
2607 self.consume(&TokenKind::LBrace, "{")?;
2608 let mut fields = Vec::new();
2609 self.skip_newlines();
2610
2611 while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
2612 let name = self.consume_identifier("field name")?;
2613 let optional = if self.check(&TokenKind::Question) {
2614 self.advance();
2615 true
2616 } else {
2617 false
2618 };
2619 self.consume(&TokenKind::Colon, ":")?;
2620 let type_expr = self.parse_type_expr()?;
2621 fields.push(ShapeField {
2622 name,
2623 type_expr,
2624 optional,
2625 });
2626 self.skip_newlines();
2627 if self.check(&TokenKind::Comma) {
2628 self.advance();
2629 self.skip_newlines();
2630 }
2631 }
2632
2633 self.consume(&TokenKind::RBrace, "}")?;
2634 Ok(TypeExpr::Shape(fields))
2635 }
2636
2637 fn parse_arg_list(&mut self) -> Result<Vec<SNode>, ParserError> {
2638 let mut args = Vec::new();
2639 self.skip_newlines();
2640
2641 while !self.is_at_end() && !self.check(&TokenKind::RParen) {
2642 if self.check(&TokenKind::Dot) {
2643 let saved_pos = self.pos;
2644 self.advance();
2645 if self.check(&TokenKind::Dot) {
2646 self.advance();
2647 self.consume(&TokenKind::Dot, ".")?;
2648 let spread_start = self.tokens[saved_pos].span;
2649 let expr = self.parse_expression()?;
2650 args.push(spanned(
2651 Node::Spread(Box::new(expr)),
2652 Span::merge(spread_start, self.prev_span()),
2653 ));
2654 } else {
2655 self.pos = saved_pos;
2656 args.push(self.parse_expression()?);
2657 }
2658 } else {
2659 args.push(self.parse_expression()?);
2660 }
2661 self.skip_newlines();
2662 if self.check(&TokenKind::Comma) {
2663 self.advance();
2664 self.skip_newlines();
2665 }
2666 }
2667 Ok(args)
2668 }
2669
2670 fn is_at_end(&self) -> bool {
2671 self.pos >= self.tokens.len()
2672 || matches!(self.tokens.get(self.pos), Some(t) if t.kind == TokenKind::Eof)
2673 }
2674
2675 fn current(&self) -> Option<&Token> {
2676 self.tokens.get(self.pos)
2677 }
2678
2679 fn peek_kind(&self) -> Option<&TokenKind> {
2680 self.tokens.get(self.pos + 1).map(|t| &t.kind)
2681 }
2682
2683 fn peek_kind_at(&self, offset: usize) -> Option<&TokenKind> {
2684 self.tokens.get(self.pos + offset).map(|t| &t.kind)
2685 }
2686
2687 fn check(&self, kind: &TokenKind) -> bool {
2688 self.current()
2689 .map(|t| std::mem::discriminant(&t.kind) == std::mem::discriminant(kind))
2690 .unwrap_or(false)
2691 }
2692
2693 fn check_skip_newlines(&mut self, kind: &TokenKind) -> bool {
2696 let saved = self.pos;
2697 self.skip_newlines();
2698 if self.check(kind) {
2699 true
2700 } else {
2701 self.pos = saved;
2702 false
2703 }
2704 }
2705
2706 fn check_identifier(&self, name: &str) -> bool {
2708 matches!(self.current().map(|t| &t.kind), Some(TokenKind::Identifier(s)) if s == name)
2709 }
2710
2711 fn advance(&mut self) {
2712 if self.pos < self.tokens.len() {
2713 self.pos += 1;
2714 }
2715 }
2716
2717 fn consume(&mut self, kind: &TokenKind, expected: &str) -> Result<Token, ParserError> {
2718 self.skip_newlines();
2719 let tok = self.current().ok_or_else(|| self.make_error(expected))?;
2720 if std::mem::discriminant(&tok.kind) != std::mem::discriminant(kind) {
2721 return Err(self.make_error(expected));
2722 }
2723 let tok = tok.clone();
2724 self.advance();
2725 Ok(tok)
2726 }
2727
2728 fn consume_identifier(&mut self, expected: &str) -> Result<String, ParserError> {
2729 self.skip_newlines();
2730 let tok = self.current().ok_or_else(|| self.make_error(expected))?;
2731 if let TokenKind::Identifier(name) = &tok.kind {
2732 let name = name.clone();
2733 self.advance();
2734 Ok(name)
2735 } else {
2736 let kw_name = harn_lexer::KEYWORDS
2739 .iter()
2740 .find(|&&kw| kw == tok.kind.to_string());
2741 if let Some(kw) = kw_name {
2742 Err(ParserError::Unexpected {
2743 got: format!("'{kw}' (reserved keyword)"),
2744 expected: expected.into(),
2745 span: tok.span,
2746 })
2747 } else {
2748 Err(self.make_error(expected))
2749 }
2750 }
2751 }
2752
2753 fn consume_identifier_or_keyword(&mut self, expected: &str) -> Result<String, ParserError> {
2757 self.skip_newlines();
2758 let tok = self.current().ok_or_else(|| self.make_error(expected))?;
2759 if let TokenKind::Identifier(name) = &tok.kind {
2760 let name = name.clone();
2761 self.advance();
2762 return Ok(name);
2763 }
2764 let name = match &tok.kind {
2765 TokenKind::Pipeline => "pipeline",
2766 TokenKind::Extends => "extends",
2767 TokenKind::Override => "override",
2768 TokenKind::Let => "let",
2769 TokenKind::Var => "var",
2770 TokenKind::If => "if",
2771 TokenKind::Else => "else",
2772 TokenKind::For => "for",
2773 TokenKind::In => "in",
2774 TokenKind::Match => "match",
2775 TokenKind::Retry => "retry",
2776 TokenKind::Parallel => "parallel",
2777 TokenKind::Return => "return",
2778 TokenKind::Import => "import",
2779 TokenKind::True => "true",
2780 TokenKind::False => "false",
2781 TokenKind::Nil => "nil",
2782 TokenKind::Try => "try",
2783 TokenKind::Catch => "catch",
2784 TokenKind::Throw => "throw",
2785 TokenKind::Fn => "fn",
2786 TokenKind::Spawn => "spawn",
2787 TokenKind::While => "while",
2788 TokenKind::TypeKw => "type",
2789 TokenKind::Enum => "enum",
2790 TokenKind::Struct => "struct",
2791 TokenKind::Interface => "interface",
2792 TokenKind::Pub => "pub",
2793 TokenKind::From => "from",
2794 TokenKind::To => "to",
2795 TokenKind::Tool => "tool",
2796 TokenKind::Exclusive => "exclusive",
2797 TokenKind::Guard => "guard",
2798 TokenKind::Deadline => "deadline",
2799 TokenKind::Defer => "defer",
2800 TokenKind::Yield => "yield",
2801 TokenKind::Mutex => "mutex",
2802 TokenKind::Break => "break",
2803 TokenKind::Continue => "continue",
2804 TokenKind::Impl => "impl",
2805 _ => return Err(self.make_error(expected)),
2806 };
2807 let name = name.to_string();
2808 self.advance();
2809 Ok(name)
2810 }
2811
2812 fn skip_newlines(&mut self) {
2813 while self.pos < self.tokens.len() && self.tokens[self.pos].kind == TokenKind::Newline {
2814 self.pos += 1;
2815 }
2816 }
2817
2818 fn make_error(&self, expected: &str) -> ParserError {
2819 if let Some(tok) = self.tokens.get(self.pos) {
2820 if tok.kind == TokenKind::Eof {
2821 return ParserError::UnexpectedEof {
2822 expected: expected.into(),
2823 span: tok.span,
2824 };
2825 }
2826 ParserError::Unexpected {
2827 got: tok.kind.to_string(),
2828 expected: expected.into(),
2829 span: tok.span,
2830 }
2831 } else {
2832 ParserError::UnexpectedEof {
2833 expected: expected.into(),
2834 span: self.prev_span(),
2835 }
2836 }
2837 }
2838
2839 fn error(&self, expected: &str) -> ParserError {
2840 self.make_error(expected)
2841 }
2842}
2843
2844#[cfg(test)]
2845mod tests {
2846 use super::*;
2847 use harn_lexer::Lexer;
2848
2849 fn parse_source(source: &str) -> Result<Vec<SNode>, ParserError> {
2850 let mut lexer = Lexer::new(source);
2851 let tokens = lexer.tokenize().unwrap();
2852 let mut parser = Parser::new(tokens);
2853 parser.parse()
2854 }
2855
2856 #[test]
2857 fn parses_match_expression_with_let_in_arm_body() {
2858 let source = r#"
2859pipeline p() {
2860 let x = match 1 {
2861 1 -> {
2862 let a = 1
2863 a
2864 }
2865 _ -> { 0 }
2866 }
2867}
2868"#;
2869
2870 assert!(parse_source(source).is_ok());
2871 }
2872
2873 #[test]
2874 fn parses_public_declarations_and_generic_interfaces() {
2875 let source = r#"
2876pub pipeline build(task) extends base {
2877 return
2878}
2879
2880pub enum Result {
2881 Ok(value: string),
2882 Err(message: string, code: int),
2883}
2884
2885pub struct Config {
2886 host: string
2887 port?: int
2888}
2889
2890interface Repository<T> {
2891 type Item
2892 fn get(id: string) -> T
2893 fn map<U>(value: T, f: fn(T) -> U) -> U
2894}
2895"#;
2896
2897 let program = parse_source(source).expect("should parse");
2898 assert!(matches!(
2899 &program[0].node,
2900 Node::Pipeline {
2901 is_pub: true,
2902 extends: Some(base),
2903 ..
2904 } if base == "base"
2905 ));
2906 assert!(matches!(
2907 &program[1].node,
2908 Node::EnumDecl {
2909 is_pub: true,
2910 type_params,
2911 ..
2912 } if type_params.is_empty()
2913 ));
2914 assert!(matches!(
2915 &program[2].node,
2916 Node::StructDecl {
2917 is_pub: true,
2918 type_params,
2919 ..
2920 } if type_params.is_empty()
2921 ));
2922 assert!(matches!(
2923 &program[3].node,
2924 Node::InterfaceDecl {
2925 type_params,
2926 associated_types,
2927 methods,
2928 ..
2929 }
2930 if type_params.len() == 1
2931 && associated_types.len() == 1
2932 && methods.len() == 2
2933 && methods[1].type_params.len() == 1
2934 ));
2935 }
2936
2937 #[test]
2938 fn parses_generic_structs_and_enums() {
2939 let source = r#"
2940struct Pair<A, B> {
2941 first: A
2942 second: B
2943}
2944
2945enum Option<T> {
2946 Some(value: T)
2947 None
2948}
2949"#;
2950
2951 let program = parse_source(source).expect("should parse");
2952 assert!(matches!(
2953 &program[0].node,
2954 Node::StructDecl { type_params, .. } if type_params.len() == 2
2955 ));
2956 assert!(matches!(
2957 &program[1].node,
2958 Node::EnumDecl { type_params, .. } if type_params.len() == 1
2959 ));
2960 }
2961
2962 #[test]
2963 fn parses_struct_literal_syntax_for_known_structs() {
2964 let source = r#"
2965struct Point {
2966 x: int
2967 y: int
2968}
2969
2970pipeline test(task) {
2971 let point = Point { x: 3, y: 4 }
2972}
2973"#;
2974
2975 let program = parse_source(source).expect("should parse");
2976 let pipeline = program
2977 .iter()
2978 .find(|node| matches!(node.node, Node::Pipeline { .. }))
2979 .expect("pipeline node");
2980 let body = match &pipeline.node {
2981 Node::Pipeline { body, .. } => body,
2982 _ => unreachable!(),
2983 };
2984 assert!(matches!(
2985 &body[0].node,
2986 Node::LetBinding { value, .. }
2987 if matches!(
2988 value.node,
2989 Node::StructConstruct { ref struct_name, ref fields }
2990 if struct_name == "Point" && fields.len() == 2
2991 )
2992 ));
2993 }
2994
2995 #[test]
2996 fn parses_exponentiation_as_right_associative() {
2997 let mut lexer = Lexer::new("a ** b ** c");
2998 let tokens = lexer.tokenize().expect("tokens");
2999 let mut parser = Parser::new(tokens);
3000 let expr = parser.parse_single_expression().expect("expression");
3001
3002 assert!(matches!(
3003 expr.node,
3004 Node::BinaryOp { ref op, ref left, ref right }
3005 if op == "**"
3006 && matches!(left.node, Node::Identifier(ref name) if name == "a")
3007 && matches!(
3008 right.node,
3009 Node::BinaryOp { ref op, ref left, ref right }
3010 if op == "**"
3011 && matches!(left.node, Node::Identifier(ref name) if name == "b")
3012 && matches!(right.node, Node::Identifier(ref name) if name == "c")
3013 )
3014 ));
3015 }
3016
3017 #[test]
3018 fn parses_exponentiation_tighter_than_multiplication() {
3019 let mut lexer = Lexer::new("a * b ** c");
3020 let tokens = lexer.tokenize().expect("tokens");
3021 let mut parser = Parser::new(tokens);
3022 let expr = parser.parse_single_expression().expect("expression");
3023
3024 assert!(matches!(
3025 expr.node,
3026 Node::BinaryOp { ref op, ref left, ref right }
3027 if op == "*"
3028 && matches!(left.node, Node::Identifier(ref name) if name == "a")
3029 && matches!(
3030 right.node,
3031 Node::BinaryOp { ref op, ref left, ref right }
3032 if op == "**"
3033 && matches!(left.node, Node::Identifier(ref name) if name == "b")
3034 && matches!(right.node, Node::Identifier(ref name) if name == "c")
3035 )
3036 ));
3037 }
3038}