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