1use crate::ast::{
8 AddressAction, AssignTarget, BinOp, Clause, ClauseKind, Condition, ControlledLoop, DoBlock,
9 DoKind, Expr, NumericFormSetting, NumericSetting, ParseSource, ParseTemplate, Program,
10 SignalAction, TemplateElement, UnaryOp,
11};
12use crate::error::{RexxDiagnostic, RexxError, RexxResult, SourceLoc};
13use crate::lexer::{Token, TokenKind};
14
15pub struct Parser {
16 tokens: Vec<Token>,
17 pos: usize,
18 do_header_depth: usize,
21 condition_depth: usize,
24 if_depth: usize,
27 parse_value_depth: usize,
30}
31
32impl Parser {
33 pub fn new(tokens: Vec<Token>) -> Self {
34 Self {
35 tokens,
36 pos: 0,
37 do_header_depth: 0,
38 condition_depth: 0,
39 if_depth: 0,
40 parse_value_depth: 0,
41 }
42 }
43
44 pub fn parse(&mut self) -> RexxResult<Program> {
45 let mut clauses = Vec::new();
46 self.skip_terminators();
47 while !self.at_end() {
48 clauses.push(self.parse_clause()?);
49 self.skip_terminators();
50 }
51 Ok(Program { clauses })
52 }
53
54 fn peek(&self) -> &Token {
57 &self.tokens[self.pos]
58 }
59
60 fn peek_kind(&self) -> &TokenKind {
61 &self.tokens[self.pos].kind
62 }
63
64 fn at_end(&self) -> bool {
65 matches!(self.peek_kind(), TokenKind::Eof)
66 }
67
68 fn advance(&mut self) -> &Token {
69 let tok = &self.tokens[self.pos];
70 if !self.at_end() {
71 self.pos += 1;
72 }
73 tok
74 }
75
76 fn loc(&self) -> SourceLoc {
77 self.peek().loc.clone()
78 }
79
80 fn expect(&mut self, kind: &TokenKind) -> RexxResult<&Token> {
81 if &self.tokens[self.pos].kind == kind {
82 let tok = &self.tokens[self.pos];
83 self.pos += 1;
84 Ok(tok)
85 } else {
86 Err(RexxDiagnostic::new(RexxError::InvalidExpression)
87 .at(self.loc())
88 .with_detail(format!("expected {kind:?}, found {:?}", self.peek_kind())))
89 }
90 }
91
92 fn is_terminator(&self) -> bool {
94 matches!(
95 self.peek_kind(),
96 TokenKind::Semicolon | TokenKind::Eol | TokenKind::Eof
97 )
98 }
99
100 fn skip_terminators(&mut self) {
101 while matches!(self.peek_kind(), TokenKind::Semicolon | TokenKind::Eol) {
102 self.advance();
103 }
104 }
105
106 fn check_keyword(sym: &str, keyword: &str) -> bool {
108 sym.eq_ignore_ascii_case(keyword)
109 }
110
111 fn is_keyword(&self, keyword: &str) -> bool {
113 if let TokenKind::Symbol(name) = self.peek_kind() {
114 Self::check_keyword(name, keyword)
115 } else {
116 false
117 }
118 }
119
120 fn peek_at(&self, n: usize) -> &TokenKind {
122 let idx = self.pos + n;
123 if idx < self.tokens.len() {
124 &self.tokens[idx].kind
125 } else {
126 &TokenKind::Eof
127 }
128 }
129
130 fn is_then_keyword(&self) -> bool {
132 if let TokenKind::Symbol(name) = self.peek_kind() {
133 Self::check_keyword(name, "THEN")
134 } else {
135 false
136 }
137 }
138
139 fn is_else_keyword(&self) -> bool {
141 if let TokenKind::Symbol(name) = self.peek_kind() {
142 Self::check_keyword(name, "ELSE")
143 } else {
144 false
145 }
146 }
147
148 fn is_with_keyword(&self) -> bool {
150 if let TokenKind::Symbol(name) = self.peek_kind() {
151 Self::check_keyword(name, "WITH")
152 } else {
153 false
154 }
155 }
156
157 fn is_do_header_keyword(&self) -> bool {
160 if let TokenKind::Symbol(name) = self.peek_kind() {
161 name.eq_ignore_ascii_case("TO")
162 || name.eq_ignore_ascii_case("BY")
163 || name.eq_ignore_ascii_case("FOR")
164 || name.eq_ignore_ascii_case("WHILE")
165 || name.eq_ignore_ascii_case("UNTIL")
166 } else {
167 false
168 }
169 }
170
171 #[allow(clippy::too_many_lines)]
174 fn parse_clause(&mut self) -> RexxResult<Clause> {
175 let loc = self.loc();
176
177 if let TokenKind::Symbol(ref name) = self.peek_kind().clone() {
179 if matches!(self.peek_at(1), TokenKind::Colon) {
181 let label = name.to_uppercase();
182 self.advance(); self.advance(); return Ok(Clause {
185 kind: ClauseKind::Label(label),
186 loc,
187 });
188 }
189
190 if matches!(self.peek_at(1), TokenKind::Assign) {
192 return self.parse_assignment(&loc);
193 }
194
195 if Self::check_keyword(name, "SAY") {
197 self.advance(); let expr = if self.is_terminator() {
199 Expr::StringLit(String::new())
201 } else {
202 self.parse_expression()?
203 };
204 return Ok(Clause {
205 kind: ClauseKind::Say(expr),
206 loc,
207 });
208 }
209
210 if Self::check_keyword(name, "NOP") {
212 self.advance();
213 return Ok(Clause {
214 kind: ClauseKind::Nop,
215 loc,
216 });
217 }
218
219 if Self::check_keyword(name, "IF") {
221 return self.parse_if();
222 }
223
224 if Self::check_keyword(name, "DO") {
226 return self.parse_do();
227 }
228
229 if Self::check_keyword(name, "SELECT") {
231 return self.parse_select();
232 }
233
234 if Self::check_keyword(name, "LEAVE") {
236 return Ok(self.parse_leave());
237 }
238
239 if Self::check_keyword(name, "ITERATE") {
241 return Ok(self.parse_iterate());
242 }
243
244 if Self::check_keyword(name, "EXIT") {
246 return self.parse_exit();
247 }
248
249 if Self::check_keyword(name, "RETURN") {
251 return self.parse_return();
252 }
253
254 if Self::check_keyword(name, "CALL") {
256 return self.parse_call();
257 }
258
259 if Self::check_keyword(name, "PROCEDURE") {
261 return Ok(self.parse_procedure());
262 }
263
264 if Self::check_keyword(name, "PARSE") {
266 return self.parse_parse();
267 }
268
269 if Self::check_keyword(name, "PULL") {
271 return self.parse_pull();
272 }
273
274 if Self::check_keyword(name, "ARG") {
276 return self.parse_arg();
277 }
278
279 if Self::check_keyword(name, "DROP") {
281 return Ok(self.parse_drop());
282 }
283
284 if Self::check_keyword(name, "SIGNAL") {
286 return self.parse_signal();
287 }
288
289 if Self::check_keyword(name, "INTERPRET") {
291 return self.parse_interpret();
292 }
293
294 if Self::check_keyword(name, "TRACE") {
296 return self.parse_trace();
297 }
298
299 if Self::check_keyword(name, "NUMERIC") {
301 return self.parse_numeric();
302 }
303
304 if Self::check_keyword(name, "PUSH") {
306 return self.parse_push();
307 }
308
309 if Self::check_keyword(name, "QUEUE") {
311 return self.parse_queue();
312 }
313
314 if Self::check_keyword(name, "ADDRESS") {
316 return self.parse_address();
317 }
318
319 if Self::check_keyword(name, "END") {
321 return Err(RexxDiagnostic::new(RexxError::UnexpectedEnd)
322 .at(loc)
323 .with_detail("END without matching DO or SELECT"));
324 }
325
326 if Self::check_keyword(name, "THEN") || Self::check_keyword(name, "ELSE") {
328 return Err(RexxDiagnostic::new(RexxError::UnexpectedThenElse)
329 .at(loc)
330 .with_detail(format!("unexpected {}", name.to_uppercase())));
331 }
332
333 if Self::check_keyword(name, "WHEN") || Self::check_keyword(name, "OTHERWISE") {
335 return Err(RexxDiagnostic::new(RexxError::UnexpectedWhenOtherwise)
336 .at(loc)
337 .with_detail(format!("unexpected {}", name.to_uppercase())));
338 }
339 }
340
341 let expr = self.parse_expression()?;
343 Ok(Clause {
344 kind: ClauseKind::Command(expr),
345 loc,
346 })
347 }
348
349 fn parse_assignment(&mut self, loc: &SourceLoc) -> RexxResult<Clause> {
350 let name = if let TokenKind::Symbol(s) = self.peek_kind() {
351 s.clone()
352 } else {
353 unreachable!("parse_assignment called on non-symbol token")
354 };
355 self.advance(); self.advance(); let target = if name.contains('.') {
359 let parts: Vec<&str> = name.splitn(2, '.').collect();
361 let stem = parts[0].to_uppercase();
362 let tail_str = parts[1];
363 let tail = parse_tail_elements(tail_str);
364 AssignTarget::Stem { stem, tail }
365 } else {
366 AssignTarget::Simple(name.to_uppercase())
367 };
368
369 let expr = self.parse_expression()?;
370 Ok(Clause {
371 kind: ClauseKind::Assignment { target, expr },
372 loc: loc.clone(),
373 })
374 }
375
376 fn parse_if(&mut self) -> RexxResult<Clause> {
380 let loc = self.loc();
381 self.advance(); self.condition_depth += 1;
385 let condition = self.parse_expression()?;
386 self.condition_depth -= 1;
387
388 self.skip_terminators();
390
391 if !self.is_keyword("THEN") {
393 return Err(RexxDiagnostic::new(RexxError::ExpectedThen)
394 .at(self.loc())
395 .with_detail("expected THEN after IF condition"));
396 }
397 self.advance(); self.skip_terminators();
401
402 self.if_depth += 1;
404 let then_clause = Box::new(self.parse_clause()?);
405
406 let saved_pos = self.pos;
408 self.skip_terminators();
409 let else_clause = if self.is_keyword("ELSE") {
410 self.advance(); self.skip_terminators();
412 let clause = self.parse_clause()?;
413 Some(Box::new(clause))
414 } else {
415 self.pos = saved_pos;
417 None
418 };
419 self.if_depth -= 1;
420
421 Ok(Clause {
422 kind: ClauseKind::If {
423 condition,
424 then_clause,
425 else_clause,
426 },
427 loc,
428 })
429 }
430
431 fn parse_do(&mut self) -> RexxResult<Clause> {
433 let loc = self.loc();
434 self.advance(); if self.is_terminator() {
445 self.skip_terminators();
447 let body = self.parse_do_body()?;
448 return Ok(Clause {
449 kind: ClauseKind::Do(Box::new(DoBlock {
450 kind: DoKind::Simple,
451 body,
452 name: None,
453 })),
454 loc,
455 });
456 }
457
458 if self.is_keyword("FOREVER") {
459 self.advance(); self.skip_terminators();
461 let body = self.parse_do_body()?;
462 return Ok(Clause {
463 kind: ClauseKind::Do(Box::new(DoBlock {
464 kind: DoKind::Forever,
465 body,
466 name: None,
467 })),
468 loc,
469 });
470 }
471
472 if self.is_keyword("WHILE") {
473 self.advance(); let cond = self.parse_expression()?;
475 self.skip_terminators();
476 let body = self.parse_do_body()?;
477 return Ok(Clause {
478 kind: ClauseKind::Do(Box::new(DoBlock {
479 kind: DoKind::While(cond),
480 body,
481 name: None,
482 })),
483 loc,
484 });
485 }
486
487 if self.is_keyword("UNTIL") {
488 self.advance(); let cond = self.parse_expression()?;
490 self.skip_terminators();
491 let body = self.parse_do_body()?;
492 return Ok(Clause {
493 kind: ClauseKind::Do(Box::new(DoBlock {
494 kind: DoKind::Until(cond),
495 body,
496 name: None,
497 })),
498 loc,
499 });
500 }
501
502 if let TokenKind::Symbol(_) = self.peek_kind()
504 && matches!(self.peek_at(1), TokenKind::Assign)
505 {
506 return self.parse_controlled_do(loc);
507 }
508
509 let count_expr = self.parse_expression()?;
511 self.skip_terminators();
512 let body = self.parse_do_body()?;
513 Ok(Clause {
514 kind: ClauseKind::Do(Box::new(DoBlock {
515 kind: DoKind::Count(count_expr),
516 body,
517 name: None,
518 })),
519 loc,
520 })
521 }
522
523 fn parse_controlled_do(&mut self, loc: SourceLoc) -> RexxResult<Clause> {
525 let var_name = if let TokenKind::Symbol(s) = self.peek_kind() {
526 s.to_uppercase()
527 } else {
528 unreachable!()
529 };
530 self.advance(); self.advance(); self.do_header_depth += 1;
535 let start = self.parse_expression()?;
536
537 let mut to: Option<Expr> = None;
538 let mut by: Option<Expr> = None;
539 let mut r#for: Option<Expr> = None;
540 let mut while_cond: Option<Expr> = None;
541 let mut until_cond: Option<Expr> = None;
542
543 loop {
546 if self.is_keyword("TO") {
547 if to.is_some() {
548 return Err(RexxDiagnostic::new(RexxError::InvalidDoSyntax)
549 .at(self.loc())
550 .with_detail("duplicate TO in DO instruction"));
551 }
552 self.advance();
553 to = Some(self.parse_expression()?);
554 } else if self.is_keyword("BY") {
555 if by.is_some() {
556 return Err(RexxDiagnostic::new(RexxError::InvalidDoSyntax)
557 .at(self.loc())
558 .with_detail("duplicate BY in DO instruction"));
559 }
560 self.advance();
561 by = Some(self.parse_expression()?);
562 } else if self.is_keyword("FOR") {
563 if r#for.is_some() {
564 return Err(RexxDiagnostic::new(RexxError::InvalidDoSyntax)
565 .at(self.loc())
566 .with_detail("duplicate FOR in DO instruction"));
567 }
568 self.advance();
569 r#for = Some(self.parse_expression()?);
570 } else if self.is_keyword("WHILE") {
571 if while_cond.is_some() {
572 return Err(RexxDiagnostic::new(RexxError::InvalidDoSyntax)
573 .at(self.loc())
574 .with_detail("duplicate WHILE in DO instruction"));
575 }
576 self.advance();
577 while_cond = Some(self.parse_expression()?);
578 } else if self.is_keyword("UNTIL") {
579 if until_cond.is_some() {
580 return Err(RexxDiagnostic::new(RexxError::InvalidDoSyntax)
581 .at(self.loc())
582 .with_detail("duplicate UNTIL in DO instruction"));
583 }
584 self.advance();
585 until_cond = Some(self.parse_expression()?);
586 } else {
587 break;
588 }
589 }
590
591 self.do_header_depth -= 1;
592
593 self.skip_terminators();
594 let body = self.parse_do_body()?;
595
596 Ok(Clause {
597 kind: ClauseKind::Do(Box::new(DoBlock {
598 kind: DoKind::Controlled(Box::new(ControlledLoop {
599 var: var_name.clone(),
600 start,
601 to,
602 by,
603 r#for,
604 while_cond,
605 until_cond,
606 })),
607 body,
608 name: Some(var_name),
609 })),
610 loc,
611 })
612 }
613
614 fn parse_do_body(&mut self) -> RexxResult<Vec<Clause>> {
616 let mut body = Vec::new();
617 self.skip_terminators();
618 loop {
619 if self.at_end() {
620 return Err(RexxDiagnostic::new(RexxError::IncompleteBlock)
621 .at(self.loc())
622 .with_detail("expected END to close DO block"));
623 }
624 if self.is_keyword("END") {
625 self.advance(); if let TokenKind::Symbol(_) = self.peek_kind()
628 && !self.is_terminator()
629 {
630 self.advance(); }
632 break;
633 }
634 body.push(self.parse_clause()?);
635 self.skip_terminators();
636 }
637 Ok(body)
638 }
639
640 fn parse_select(&mut self) -> RexxResult<Clause> {
642 let loc = self.loc();
643 self.advance(); self.skip_terminators();
645
646 let mut when_clauses: Vec<(Expr, Vec<Clause>)> = Vec::new();
647 let mut otherwise: Option<Vec<Clause>> = None;
648
649 loop {
650 self.skip_terminators();
651
652 if self.at_end() {
653 return Err(RexxDiagnostic::new(RexxError::IncompleteBlock)
654 .at(self.loc())
655 .with_detail("expected END to close SELECT"));
656 }
657
658 if self.is_keyword("END") {
659 self.advance(); break;
661 }
662
663 if self.is_keyword("WHEN") {
664 self.advance(); self.condition_depth += 1;
666 let condition = self.parse_expression()?;
667 self.condition_depth -= 1;
668 self.skip_terminators();
669
670 if !self.is_keyword("THEN") {
671 return Err(RexxDiagnostic::new(RexxError::ExpectedThen)
672 .at(self.loc())
673 .with_detail("expected THEN after WHEN condition"));
674 }
675 self.advance(); self.skip_terminators();
677
678 let mut body = Vec::new();
680 loop {
681 if self.at_end()
682 || self.is_keyword("WHEN")
683 || self.is_keyword("OTHERWISE")
684 || self.is_keyword("END")
685 {
686 break;
687 }
688 body.push(self.parse_clause()?);
689 self.skip_terminators();
690 }
691 when_clauses.push((condition, body));
692 continue;
693 }
694
695 if self.is_keyword("OTHERWISE") {
696 self.advance(); self.skip_terminators();
698
699 let mut body = Vec::new();
700 loop {
701 if self.at_end() || self.is_keyword("END") {
702 break;
703 }
704 body.push(self.parse_clause()?);
705 self.skip_terminators();
706 }
707 otherwise = Some(body);
708 continue;
709 }
710
711 return Err(RexxDiagnostic::new(RexxError::ExpectedWhenOtherwise)
712 .at(self.loc())
713 .with_detail("expected WHEN, OTHERWISE, or END in SELECT"));
714 }
715
716 Ok(Clause {
717 kind: ClauseKind::Select {
718 when_clauses,
719 otherwise,
720 },
721 loc,
722 })
723 }
724
725 fn parse_leave(&mut self) -> Clause {
727 let loc = self.loc();
728 self.advance(); let name = self.try_consume_symbol_name();
730 Clause {
731 kind: ClauseKind::Leave(name),
732 loc,
733 }
734 }
735
736 fn parse_iterate(&mut self) -> Clause {
738 let loc = self.loc();
739 self.advance(); let name = self.try_consume_symbol_name();
741 Clause {
742 kind: ClauseKind::Iterate(name),
743 loc,
744 }
745 }
746
747 fn try_consume_symbol_name(&mut self) -> Option<String> {
749 if self.is_terminator() {
750 return None;
751 }
752 if let TokenKind::Symbol(s) = self.peek_kind() {
753 let n = s.to_uppercase();
754 self.advance();
755 Some(n)
756 } else {
757 None
758 }
759 }
760
761 fn parse_exit(&mut self) -> RexxResult<Clause> {
763 let loc = self.loc();
764 self.advance(); let expr = if self.is_terminator() {
766 None
767 } else {
768 Some(self.parse_expression()?)
769 };
770 Ok(Clause {
771 kind: ClauseKind::Exit(expr),
772 loc,
773 })
774 }
775
776 fn parse_return(&mut self) -> RexxResult<Clause> {
778 let loc = self.loc();
779 self.advance(); let expr = if self.is_terminator() {
781 None
782 } else {
783 Some(self.parse_expression()?)
784 };
785 Ok(Clause {
786 kind: ClauseKind::Return(expr),
787 loc,
788 })
789 }
790
791 fn parse_call(&mut self) -> RexxResult<Clause> {
793 let loc = self.loc();
794 self.advance(); let name = if let TokenKind::Symbol(s) = self.peek_kind() {
798 let n = s.to_uppercase();
799 self.advance();
800 n
801 } else {
802 return Err(RexxDiagnostic::new(RexxError::ExpectedSymbol)
803 .at(self.loc())
804 .with_detail("expected routine name after CALL"));
805 };
806
807 let mut args = Vec::new();
809 if !self.is_terminator() {
810 args.push(self.parse_expression()?);
811 while matches!(self.peek_kind(), TokenKind::Comma) {
812 self.advance(); args.push(self.parse_expression()?);
814 }
815 }
816
817 Ok(Clause {
818 kind: ClauseKind::Call { name, args },
819 loc,
820 })
821 }
822
823 fn parse_procedure(&mut self) -> Clause {
825 let loc = self.loc();
826 self.advance(); let expose = if self.is_keyword("EXPOSE") {
829 self.advance(); let mut names = Vec::new();
831 while !self.is_terminator() {
832 if let TokenKind::Symbol(s) = self.peek_kind() {
833 names.push(s.to_uppercase());
834 self.advance();
835 } else {
836 break;
837 }
838 }
839 Some(names)
840 } else {
841 None
842 };
843
844 Clause {
845 kind: ClauseKind::Procedure(expose),
846 loc,
847 }
848 }
849
850 fn parse_template(&mut self) -> RexxResult<ParseTemplate> {
853 let mut elements = Vec::new();
854 while !self.is_terminator() {
855 match self.peek_kind().clone() {
856 TokenKind::Symbol(name) => {
857 elements.push(TemplateElement::Variable(name.to_uppercase()));
858 self.advance();
859 }
860 TokenKind::Dot => {
861 elements.push(TemplateElement::Dot);
862 self.advance();
863 }
864 TokenKind::StringLit(s) => {
865 elements.push(TemplateElement::Literal(s));
866 self.advance();
867 }
868 TokenKind::Number(n) => {
869 elements.push(TemplateElement::AbsolutePos(Expr::Number(n)));
870 self.advance();
871 }
872 TokenKind::Plus => {
873 self.advance(); if let TokenKind::Number(n) = self.peek_kind().clone() {
875 self.advance();
876 let val: i32 = n.parse().map_err(|_| {
877 RexxDiagnostic::new(RexxError::InvalidTemplate)
878 .at(self.loc())
879 .with_detail(format!("invalid relative position '+{n}'"))
880 })?;
881 elements.push(TemplateElement::RelativePos(val));
882 } else {
883 return Err(RexxDiagnostic::new(RexxError::InvalidTemplate)
884 .at(self.loc())
885 .with_detail("expected number after '+' in template"));
886 }
887 }
888 TokenKind::Minus => {
889 self.advance(); if let TokenKind::Number(n) = self.peek_kind().clone() {
891 self.advance();
892 let val: i32 = n.parse().map_err(|_| {
893 RexxDiagnostic::new(RexxError::InvalidTemplate)
894 .at(self.loc())
895 .with_detail(format!("invalid relative position '-{n}'"))
896 })?;
897 elements.push(TemplateElement::RelativePos(-val));
898 } else {
899 return Err(RexxDiagnostic::new(RexxError::InvalidTemplate)
900 .at(self.loc())
901 .with_detail("expected number after '-' in template"));
902 }
903 }
904 TokenKind::LeftParen => {
905 self.advance(); if let TokenKind::Symbol(name) = self.peek_kind().clone() {
907 let var_name = name.to_uppercase();
908 self.advance(); let err_loc = self.loc();
910 self.expect(&TokenKind::RightParen).map_err(|_| {
911 RexxDiagnostic::new(RexxError::InvalidTemplate)
912 .at(err_loc)
913 .with_detail("expected ')' after variable pattern name")
914 })?;
915 elements.push(TemplateElement::VariablePattern(var_name));
916 } else {
917 return Err(RexxDiagnostic::new(RexxError::InvalidTemplate)
918 .at(self.loc())
919 .with_detail("expected symbol inside '(' ')' in template"));
920 }
921 }
922 TokenKind::Comma => {
923 elements.push(TemplateElement::Comma);
924 self.advance();
925 }
926 _ => break,
927 }
928 }
929 Ok(ParseTemplate { elements })
930 }
931
932 fn parse_parse(&mut self) -> RexxResult<Clause> {
934 let loc = self.loc();
935 self.advance(); let upper = if self.is_keyword("UPPER") {
939 self.advance();
940 true
941 } else {
942 false
943 };
944
945 let source = if self.is_keyword("ARG") {
947 self.advance();
948 ParseSource::Arg
949 } else if self.is_keyword("PULL") {
950 self.advance();
951 ParseSource::Pull
952 } else if self.is_keyword("SOURCE") {
953 self.advance();
954 ParseSource::Source
955 } else if self.is_keyword("VERSION") {
956 self.advance();
957 ParseSource::Version
958 } else if self.is_keyword("LINEIN") {
959 self.advance();
960 ParseSource::LineIn
961 } else if self.is_keyword("VAR") {
962 self.advance();
963 if let TokenKind::Symbol(name) = self.peek_kind().clone() {
964 let var_name = name.to_uppercase();
965 self.advance();
966 ParseSource::Var(var_name)
967 } else {
968 return Err(RexxDiagnostic::new(RexxError::ExpectedSymbol)
969 .at(self.loc())
970 .with_detail("expected variable name after PARSE VAR"));
971 }
972 } else if self.is_keyword("VALUE") {
973 self.advance();
974 self.parse_value_depth += 1;
975 let expr = self.parse_expression();
976 self.parse_value_depth -= 1;
977 let expr = expr?;
978 if !self.is_with_keyword() {
980 return Err(RexxDiagnostic::new(RexxError::InvalidSubKeyword)
981 .at(self.loc())
982 .with_detail("expected WITH after PARSE VALUE expression"));
983 }
984 self.advance(); ParseSource::Value(expr)
986 } else {
987 return Err(RexxDiagnostic::new(RexxError::InvalidSubKeyword)
988 .at(self.loc())
989 .with_detail(
990 "expected ARG, PULL, SOURCE, VERSION, LINEIN, VAR, or VALUE after PARSE",
991 ));
992 };
993
994 let template = if self.is_terminator() {
995 ParseTemplate { elements: vec![] }
996 } else {
997 self.parse_template()?
998 };
999
1000 Ok(Clause {
1001 kind: ClauseKind::Parse {
1002 upper,
1003 source,
1004 template,
1005 },
1006 loc,
1007 })
1008 }
1009
1010 fn parse_pull(&mut self) -> RexxResult<Clause> {
1012 let loc = self.loc();
1013 self.advance(); let template = if self.is_terminator() {
1016 None
1017 } else {
1018 Some(self.parse_template()?)
1019 };
1020
1021 Ok(Clause {
1022 kind: ClauseKind::Pull(template),
1023 loc,
1024 })
1025 }
1026
1027 fn parse_arg(&mut self) -> RexxResult<Clause> {
1029 let loc = self.loc();
1030 self.advance(); let template = if self.is_terminator() {
1032 ParseTemplate { elements: vec![] }
1033 } else {
1034 self.parse_template()?
1035 };
1036 Ok(Clause {
1037 kind: ClauseKind::Arg(template),
1038 loc,
1039 })
1040 }
1041
1042 fn parse_drop(&mut self) -> Clause {
1044 let loc = self.loc();
1045 self.advance(); let mut names = Vec::new();
1048 while !self.is_terminator() {
1049 if let TokenKind::Symbol(s) = self.peek_kind() {
1050 names.push(s.to_uppercase());
1051 self.advance();
1052 } else {
1053 break;
1054 }
1055 }
1056
1057 Clause {
1058 kind: ClauseKind::Drop(names),
1059 loc,
1060 }
1061 }
1062
1063 fn parse_signal(&mut self) -> RexxResult<Clause> {
1067 let loc = self.loc();
1068 self.advance(); if self.is_keyword("ON") {
1071 self.advance(); let condition = self.parse_condition()?;
1073 let name = if self.is_keyword("NAME") {
1074 self.advance(); if let TokenKind::Symbol(s) = self.peek_kind() {
1076 let n = s.to_uppercase();
1077 self.advance();
1078 Some(n)
1079 } else {
1080 return Err(RexxDiagnostic::new(RexxError::ExpectedSymbol)
1081 .at(self.loc())
1082 .with_detail("expected label name after SIGNAL ON condition NAME"));
1083 }
1084 } else {
1085 None
1086 };
1087 return Ok(Clause {
1088 kind: ClauseKind::Signal(SignalAction::On { condition, name }),
1089 loc,
1090 });
1091 }
1092
1093 if self.is_keyword("OFF") {
1094 self.advance(); let condition = self.parse_condition()?;
1096 return Ok(Clause {
1097 kind: ClauseKind::Signal(SignalAction::Off(condition)),
1098 loc,
1099 });
1100 }
1101
1102 if self.is_keyword("VALUE") {
1103 self.advance(); let expr = self.parse_expression()?;
1105 return Ok(Clause {
1106 kind: ClauseKind::Signal(SignalAction::Value(expr)),
1107 loc,
1108 });
1109 }
1110
1111 if let TokenKind::Symbol(s) = self.peek_kind() {
1113 let label = s.to_uppercase();
1114 self.advance();
1115 return Ok(Clause {
1116 kind: ClauseKind::Signal(SignalAction::Label(label)),
1117 loc,
1118 });
1119 }
1120
1121 Err(RexxDiagnostic::new(RexxError::ExpectedSymbol)
1122 .at(self.loc())
1123 .with_detail("expected label name, VALUE, ON, or OFF after SIGNAL"))
1124 }
1125
1126 fn parse_condition(&mut self) -> RexxResult<Condition> {
1128 if let TokenKind::Symbol(s) = self.peek_kind() {
1129 let upper = s.to_uppercase();
1130 let condition = match upper.as_str() {
1131 "ERROR" => Condition::Error,
1132 "FAILURE" => Condition::Failure,
1133 "HALT" => Condition::Halt,
1134 "NOVALUE" => Condition::NoValue,
1135 "NOTREADY" => Condition::NotReady,
1136 "SYNTAX" => Condition::Syntax,
1137 "LOSTDIGITS" => Condition::LostDigits,
1138 _ => {
1139 return Err(RexxDiagnostic::new(RexxError::InvalidSubKeyword)
1140 .at(self.loc())
1141 .with_detail(format!(
1142 "'{upper}' is not a valid condition name; expected ERROR, FAILURE, HALT, NOVALUE, NOTREADY, SYNTAX, or LOSTDIGITS"
1143 )));
1144 }
1145 };
1146 self.advance();
1147 Ok(condition)
1148 } else {
1149 Err(RexxDiagnostic::new(RexxError::ExpectedSymbol)
1150 .at(self.loc())
1151 .with_detail("expected condition name"))
1152 }
1153 }
1154
1155 fn parse_trace(&mut self) -> RexxResult<Clause> {
1159 let loc = self.loc();
1160 self.advance(); let expr = if self.is_terminator() {
1162 Expr::StringLit("N".to_string())
1163 } else {
1164 self.parse_expression()?
1165 };
1166 Ok(Clause {
1167 kind: ClauseKind::Trace(expr),
1168 loc,
1169 })
1170 }
1171
1172 fn parse_interpret(&mut self) -> RexxResult<Clause> {
1176 let loc = self.loc();
1177 self.advance(); let expr = if self.is_terminator() {
1179 Expr::StringLit(String::new())
1180 } else {
1181 self.parse_expression()?
1182 };
1183 Ok(Clause {
1184 kind: ClauseKind::Interpret(expr),
1185 loc,
1186 })
1187 }
1188
1189 fn parse_address(&mut self) -> RexxResult<Clause> {
1193 let loc = self.loc();
1194 self.advance(); if self.is_terminator() {
1198 return Ok(Clause {
1199 kind: ClauseKind::Address(AddressAction::SetEnvironment(String::new())),
1200 loc,
1201 });
1202 }
1203
1204 if self.is_keyword("VALUE") {
1206 self.advance(); let expr = self.parse_expression()?;
1208 return Ok(Clause {
1209 kind: ClauseKind::Address(AddressAction::Value(expr)),
1210 loc,
1211 });
1212 }
1213
1214 if let TokenKind::Symbol(name) = self.peek_kind().clone() {
1216 let env_name = name.to_uppercase();
1217 self.advance(); if self.is_terminator() {
1220 return Ok(Clause {
1222 kind: ClauseKind::Address(AddressAction::SetEnvironment(env_name)),
1223 loc,
1224 });
1225 }
1226
1227 let command = self.parse_expression()?;
1229 return Ok(Clause {
1230 kind: ClauseKind::Address(AddressAction::Temporary {
1231 environment: env_name,
1232 command,
1233 }),
1234 loc,
1235 });
1236 }
1237
1238 Err(RexxDiagnostic::new(RexxError::ExpectedSymbol)
1239 .at(self.loc())
1240 .with_detail("expected environment name, VALUE, or end of clause after ADDRESS"))
1241 }
1242
1243 fn parse_numeric(&mut self) -> RexxResult<Clause> {
1247 let loc = self.loc();
1248 self.advance(); if self.is_keyword("DIGITS") {
1251 self.advance(); let expr = if self.is_terminator() {
1253 None
1254 } else {
1255 Some(self.parse_expression()?)
1256 };
1257 return Ok(Clause {
1258 kind: ClauseKind::Numeric(NumericSetting::Digits(expr)),
1259 loc,
1260 });
1261 }
1262
1263 if self.is_keyword("FORM") {
1264 self.advance(); let form = if self.is_keyword("SCIENTIFIC") {
1266 self.advance();
1267 NumericFormSetting::Scientific
1268 } else if self.is_keyword("ENGINEERING") {
1269 self.advance();
1270 NumericFormSetting::Engineering
1271 } else if self.is_keyword("VALUE") {
1272 self.advance();
1273 let expr = self.parse_expression()?;
1274 NumericFormSetting::Value(expr)
1275 } else if self.is_terminator() {
1276 NumericFormSetting::Scientific
1278 } else {
1279 let expr = self.parse_expression()?;
1280 NumericFormSetting::Value(expr)
1281 };
1282 return Ok(Clause {
1283 kind: ClauseKind::Numeric(NumericSetting::Form(form)),
1284 loc,
1285 });
1286 }
1287
1288 if self.is_keyword("FUZZ") {
1289 self.advance(); let expr = if self.is_terminator() {
1291 None
1292 } else {
1293 Some(self.parse_expression()?)
1294 };
1295 return Ok(Clause {
1296 kind: ClauseKind::Numeric(NumericSetting::Fuzz(expr)),
1297 loc,
1298 });
1299 }
1300
1301 Err(RexxDiagnostic::new(RexxError::InvalidSubKeyword)
1302 .at(self.loc())
1303 .with_detail("expected DIGITS, FORM, or FUZZ after NUMERIC"))
1304 }
1305
1306 fn parse_push(&mut self) -> RexxResult<Clause> {
1310 let loc = self.loc();
1311 self.advance(); let expr = if self.is_terminator() {
1313 None
1314 } else {
1315 Some(self.parse_expression()?)
1316 };
1317 Ok(Clause {
1318 kind: ClauseKind::Push(expr),
1319 loc,
1320 })
1321 }
1322
1323 fn parse_queue(&mut self) -> RexxResult<Clause> {
1325 let loc = self.loc();
1326 self.advance(); let expr = if self.is_terminator() {
1328 None
1329 } else {
1330 Some(self.parse_expression()?)
1331 };
1332 Ok(Clause {
1333 kind: ClauseKind::Queue(expr),
1334 loc,
1335 })
1336 }
1337
1338 fn parse_expression(&mut self) -> RexxResult<Expr> {
1352 self.parse_or_xor()
1353 }
1354
1355 fn parse_or_xor(&mut self) -> RexxResult<Expr> {
1357 let mut left = self.parse_and()?;
1358 loop {
1359 let op = match self.peek_kind() {
1360 TokenKind::Or => BinOp::Or,
1361 TokenKind::Xor => BinOp::Xor,
1362 _ => break,
1363 };
1364 self.advance();
1365 let right = self.parse_and()?;
1366 left = Expr::BinOp {
1367 left: Box::new(left),
1368 op,
1369 right: Box::new(right),
1370 };
1371 }
1372 Ok(left)
1373 }
1374
1375 fn parse_and(&mut self) -> RexxResult<Expr> {
1377 let mut left = self.parse_comparison()?;
1378 loop {
1379 if !matches!(self.peek_kind(), TokenKind::And) {
1380 break;
1381 }
1382 self.advance();
1383 let right = self.parse_comparison()?;
1384 left = Expr::BinOp {
1385 left: Box::new(left),
1386 op: BinOp::And,
1387 right: Box::new(right),
1388 };
1389 }
1390 Ok(left)
1391 }
1392
1393 fn parse_comparison(&mut self) -> RexxResult<Expr> {
1395 let mut left = self.parse_concat()?;
1396 loop {
1397 let op = match self.peek_kind() {
1398 TokenKind::Assign | TokenKind::Equal => BinOp::Eq,
1400 TokenKind::NotEqual => BinOp::NotEq,
1401 TokenKind::Greater => BinOp::Gt,
1402 TokenKind::Less => BinOp::Lt,
1403 TokenKind::GreaterEq => BinOp::GtEq,
1404 TokenKind::LessEq => BinOp::LtEq,
1405 TokenKind::StrictEq => BinOp::StrictEq,
1406 TokenKind::StrictNotEq => BinOp::StrictNotEq,
1407 TokenKind::StrictGt => BinOp::StrictGt,
1408 TokenKind::StrictLt => BinOp::StrictLt,
1409 TokenKind::StrictGte => BinOp::StrictGtEq,
1410 TokenKind::StrictLte => BinOp::StrictLtEq,
1411 _ => break,
1412 };
1413 self.advance();
1414 let right = self.parse_concat()?;
1415 left = Expr::BinOp {
1416 left: Box::new(left),
1417 op,
1418 right: Box::new(right),
1419 };
1420 }
1421 Ok(left)
1422 }
1423
1424 fn parse_concat(&mut self) -> RexxResult<Expr> {
1426 let mut left = self.parse_addition()?;
1427 loop {
1428 if matches!(self.peek_kind(), TokenKind::Concat) {
1430 self.advance();
1431 let right = self.parse_addition()?;
1432 left = Expr::BinOp {
1433 left: Box::new(left),
1434 op: BinOp::Concat,
1435 right: Box::new(right),
1436 };
1437 continue;
1438 }
1439
1440 if self.do_header_depth > 0 && self.is_do_header_keyword() {
1443 break;
1444 }
1445
1446 if self.condition_depth > 0 && self.is_then_keyword() {
1449 break;
1450 }
1451
1452 if self.if_depth > 0 && self.is_else_keyword() {
1455 break;
1456 }
1457
1458 if self.parse_value_depth > 0 && self.is_with_keyword() {
1461 break;
1462 }
1463
1464 if self.can_start_term() && !self.is_binary_op() {
1467 let has_space = self.peek().space_before;
1468 let op = if has_space {
1469 BinOp::ConcatBlank
1470 } else {
1471 BinOp::Concat
1472 };
1473 let right = self.parse_addition()?;
1474 left = Expr::BinOp {
1475 left: Box::new(left),
1476 op,
1477 right: Box::new(right),
1478 };
1479 continue;
1480 }
1481
1482 break;
1483 }
1484 Ok(left)
1485 }
1486
1487 fn can_start_term(&self) -> bool {
1489 matches!(
1490 self.peek_kind(),
1491 TokenKind::StringLit(_)
1492 | TokenKind::Number(_)
1493 | TokenKind::Symbol(_)
1494 | TokenKind::LeftParen
1495 | TokenKind::Plus
1496 | TokenKind::Minus
1497 | TokenKind::Not
1498 )
1499 }
1500
1501 fn is_binary_op(&self) -> bool {
1503 matches!(
1504 self.peek_kind(),
1505 TokenKind::Plus
1506 | TokenKind::Minus
1507 | TokenKind::Star
1508 | TokenKind::Slash
1509 | TokenKind::IntDiv
1510 | TokenKind::Remainder
1511 | TokenKind::Power
1512 | TokenKind::Assign
1513 | TokenKind::Equal
1514 | TokenKind::NotEqual
1515 | TokenKind::Greater
1516 | TokenKind::Less
1517 | TokenKind::GreaterEq
1518 | TokenKind::LessEq
1519 | TokenKind::StrictEq
1520 | TokenKind::StrictNotEq
1521 | TokenKind::StrictGt
1522 | TokenKind::StrictLt
1523 | TokenKind::StrictGte
1524 | TokenKind::StrictLte
1525 | TokenKind::And
1526 | TokenKind::Or
1527 | TokenKind::Xor
1528 | TokenKind::Concat
1529 )
1530 }
1531
1532 fn parse_addition(&mut self) -> RexxResult<Expr> {
1534 let mut left = self.parse_multiplication()?;
1535 loop {
1536 let op = match self.peek_kind() {
1537 TokenKind::Plus => BinOp::Add,
1538 TokenKind::Minus => BinOp::Sub,
1539 _ => break,
1540 };
1541 self.advance();
1542 let right = self.parse_multiplication()?;
1543 left = Expr::BinOp {
1544 left: Box::new(left),
1545 op,
1546 right: Box::new(right),
1547 };
1548 }
1549 Ok(left)
1550 }
1551
1552 fn parse_multiplication(&mut self) -> RexxResult<Expr> {
1554 let mut left = self.parse_power()?;
1555 loop {
1556 let op = match self.peek_kind() {
1557 TokenKind::Star => BinOp::Mul,
1558 TokenKind::Slash => BinOp::Div,
1559 TokenKind::IntDiv => BinOp::IntDiv,
1560 TokenKind::Remainder => BinOp::Remainder,
1561 _ => break,
1562 };
1563 self.advance();
1564 let right = self.parse_power()?;
1565 left = Expr::BinOp {
1566 left: Box::new(left),
1567 op,
1568 right: Box::new(right),
1569 };
1570 }
1571 Ok(left)
1572 }
1573
1574 fn parse_power(&mut self) -> RexxResult<Expr> {
1576 let base = self.parse_unary()?;
1577 if matches!(self.peek_kind(), TokenKind::Power) {
1578 self.advance();
1579 let exp = self.parse_power()?; Ok(Expr::BinOp {
1581 left: Box::new(base),
1582 op: BinOp::Power,
1583 right: Box::new(exp),
1584 })
1585 } else {
1586 Ok(base)
1587 }
1588 }
1589
1590 fn parse_unary(&mut self) -> RexxResult<Expr> {
1592 match self.peek_kind() {
1593 TokenKind::Plus => {
1594 self.advance();
1595 let operand = self.parse_unary()?;
1596 Ok(Expr::UnaryOp {
1597 op: UnaryOp::Plus,
1598 operand: Box::new(operand),
1599 })
1600 }
1601 TokenKind::Minus => {
1602 self.advance();
1603 let operand = self.parse_unary()?;
1604 Ok(Expr::UnaryOp {
1605 op: UnaryOp::Minus,
1606 operand: Box::new(operand),
1607 })
1608 }
1609 TokenKind::Not => {
1610 self.advance();
1611 let operand = self.parse_unary()?;
1612 Ok(Expr::UnaryOp {
1613 op: UnaryOp::Not,
1614 operand: Box::new(operand),
1615 })
1616 }
1617 _ => self.parse_primary(),
1618 }
1619 }
1620
1621 fn parse_primary(&mut self) -> RexxResult<Expr> {
1623 match self.peek_kind().clone() {
1624 TokenKind::StringLit(s) => {
1625 self.advance();
1626 Ok(Expr::StringLit(s))
1627 }
1628 TokenKind::Number(n) => {
1629 self.advance();
1630 Ok(Expr::Number(n))
1631 }
1632 TokenKind::Symbol(name) => {
1633 self.advance();
1634 if matches!(self.peek_kind(), TokenKind::LeftParen) && !self.peek().space_before {
1636 return self.parse_function_call(&name);
1637 }
1638 if name.contains('.') {
1640 let parts: Vec<&str> = name.splitn(2, '.').collect();
1641 let stem = parts[0].to_uppercase();
1642 if stem.is_empty() {
1643 return Err(RexxDiagnostic::new(RexxError::InvalidExpression)
1644 .at(self.loc())
1645 .with_detail("compound variable stem cannot be empty"));
1646 }
1647 let tail_str = parts[1];
1648 let tail = parse_tail_elements(tail_str);
1649 return Ok(Expr::Compound { stem, tail });
1650 }
1651 Ok(Expr::Symbol(name.to_uppercase()))
1652 }
1653 TokenKind::LeftParen => {
1654 self.advance(); let expr = self.parse_expression()?;
1656 let err_loc = self.loc();
1657 self.expect(&TokenKind::RightParen).map_err(|_| {
1658 RexxDiagnostic::new(RexxError::UnmatchedParen)
1659 .at(err_loc)
1660 .with_detail("expected closing ')'")
1661 })?;
1662 Ok(Expr::Paren(Box::new(expr)))
1663 }
1664 _ => Err(RexxDiagnostic::new(RexxError::InvalidExpression)
1665 .at(self.loc())
1666 .with_detail(format!("unexpected token {:?}", self.peek_kind()))),
1667 }
1668 }
1669
1670 fn parse_function_call(&mut self, name: &str) -> RexxResult<Expr> {
1671 self.advance(); let mut args = Vec::new();
1673 if !matches!(self.peek_kind(), TokenKind::RightParen) {
1674 args.push(self.parse_expression()?);
1675 while matches!(self.peek_kind(), TokenKind::Comma) {
1676 self.advance();
1677 args.push(self.parse_expression()?);
1678 }
1679 }
1680 let err_loc = self.loc();
1681 self.expect(&TokenKind::RightParen).map_err(|_| {
1682 RexxDiagnostic::new(RexxError::UnmatchedParen)
1683 .at(err_loc)
1684 .with_detail("expected ')' after function arguments")
1685 })?;
1686 Ok(Expr::FunctionCall {
1687 name: name.to_uppercase(),
1688 args,
1689 })
1690 }
1691}
1692
1693fn parse_tail_elements(tail: &str) -> Vec<crate::ast::TailElement> {
1697 use crate::ast::TailElement;
1698 tail.split('.')
1699 .map(|part| {
1700 if part.is_empty() || part.starts_with(|c: char| c.is_ascii_digit()) {
1701 TailElement::Const(part.to_uppercase())
1702 } else {
1703 TailElement::Var(part.to_uppercase())
1704 }
1705 })
1706 .collect()
1707}
1708
1709#[cfg(test)]
1710mod tests {
1711 use super::*;
1712 use crate::lexer::Lexer;
1713
1714 fn parse(src: &str) -> Program {
1715 let mut lexer = Lexer::new(src);
1716 let tokens = lexer.tokenize().unwrap();
1717 let mut parser = Parser::new(tokens);
1718 parser.parse().unwrap()
1719 }
1720
1721 fn parse_expr(src: &str) -> Expr {
1722 let prog = parse(src);
1724 match prog.clauses.into_iter().next().unwrap().kind {
1725 ClauseKind::Command(e) | ClauseKind::Say(e) => e,
1726 other => panic!("expected expression clause, got {other:?}"),
1727 }
1728 }
1729
1730 #[test]
1731 fn parse_number_literal() {
1732 let expr = parse_expr("42");
1733 assert!(matches!(expr, Expr::Number(n) if n == "42"));
1734 }
1735
1736 #[test]
1737 fn parse_string_literal() {
1738 let expr = parse_expr("'hello'");
1739 assert!(matches!(expr, Expr::StringLit(s) if s == "hello"));
1740 }
1741
1742 #[test]
1743 fn parse_addition() {
1744 let expr = parse_expr("2 + 3");
1745 assert!(matches!(expr, Expr::BinOp { op: BinOp::Add, .. }));
1746 }
1747
1748 #[test]
1749 fn parse_precedence() {
1750 let expr = parse_expr("2 + 3 * 4");
1752 match expr {
1753 Expr::BinOp {
1754 op: BinOp::Add,
1755 ref right,
1756 ..
1757 } => {
1758 assert!(matches!(**right, Expr::BinOp { op: BinOp::Mul, .. }));
1759 }
1760 _ => panic!("expected Add at top level"),
1761 }
1762 }
1763
1764 #[test]
1765 fn parse_power_right_assoc() {
1766 let expr = parse_expr("2 ** 3 ** 4");
1768 match expr {
1769 Expr::BinOp {
1770 op: BinOp::Power,
1771 ref right,
1772 ..
1773 } => {
1774 assert!(matches!(
1775 **right,
1776 Expr::BinOp {
1777 op: BinOp::Power,
1778 ..
1779 }
1780 ));
1781 }
1782 _ => panic!("expected Power at top level"),
1783 }
1784 }
1785
1786 #[test]
1787 fn parse_parens() {
1788 let expr = parse_expr("(2 + 3) * 4");
1789 assert!(matches!(expr, Expr::BinOp { op: BinOp::Mul, .. }));
1790 }
1791
1792 #[test]
1793 fn parse_unary_minus() {
1794 let expr = parse_expr("-5");
1795 assert!(matches!(
1796 expr,
1797 Expr::UnaryOp {
1798 op: UnaryOp::Minus,
1799 ..
1800 }
1801 ));
1802 }
1803
1804 #[test]
1805 fn parse_say_clause() {
1806 let prog = parse("say 'hello'");
1807 match &prog.clauses[0].kind {
1808 ClauseKind::Say(Expr::StringLit(s)) => assert_eq!(s, "hello"),
1809 other => panic!("expected Say, got {other:?}"),
1810 }
1811 }
1812
1813 #[test]
1814 fn parse_assignment_clause() {
1815 let prog = parse("x = 42");
1816 match &prog.clauses[0].kind {
1817 ClauseKind::Assignment {
1818 target: AssignTarget::Simple(name),
1819 expr: Expr::Number(n),
1820 } => {
1821 assert_eq!(name, "X");
1822 assert_eq!(n, "42");
1823 }
1824 other => panic!("expected Assignment, got {other:?}"),
1825 }
1826 }
1827
1828 #[test]
1829 fn parse_label() {
1830 let prog = parse("myLabel:");
1831 match &prog.clauses[0].kind {
1832 ClauseKind::Label(name) => assert_eq!(name, "MYLABEL"),
1833 other => panic!("expected Label, got {other:?}"),
1834 }
1835 }
1836
1837 #[test]
1838 fn parse_concat_forms() {
1839 let expr = parse_expr("'a' 'b'");
1841 assert!(matches!(
1842 expr,
1843 Expr::BinOp {
1844 op: BinOp::ConcatBlank,
1845 ..
1846 }
1847 ));
1848 }
1849
1850 #[test]
1851 fn parse_explicit_concat() {
1852 let expr = parse_expr("'a' || 'b'");
1853 assert!(matches!(
1854 expr,
1855 Expr::BinOp {
1856 op: BinOp::Concat,
1857 ..
1858 }
1859 ));
1860 }
1861
1862 #[test]
1863 fn parse_multiple_clauses() {
1864 let prog = parse("x = 10; say x + 5");
1865 assert_eq!(prog.clauses.len(), 2);
1866 assert!(matches!(
1867 &prog.clauses[0].kind,
1868 ClauseKind::Assignment { .. }
1869 ));
1870 assert!(matches!(&prog.clauses[1].kind, ClauseKind::Say(_)));
1871 }
1872
1873 #[test]
1874 fn parse_unmatched_paren_error() {
1875 let mut lexer = Lexer::new("(2 + 3");
1876 let tokens = lexer.tokenize().unwrap();
1877 let mut parser = Parser::new(tokens);
1878 let result = parser.parse();
1879 assert!(result.is_err());
1880 }
1881
1882 #[test]
1883 fn parse_comparison() {
1884 let expr = parse_expr("3 > 2");
1885 assert!(matches!(expr, Expr::BinOp { op: BinOp::Gt, .. }));
1886 }
1887
1888 #[test]
1889 fn parse_function_call() {
1890 let src = "length('hello')";
1892 let prog = parse(src);
1893 match &prog.clauses[0].kind {
1894 ClauseKind::Command(Expr::FunctionCall { name, args }) => {
1895 assert_eq!(name, "LENGTH");
1896 assert_eq!(args.len(), 1);
1897 }
1898 other => panic!("expected FunctionCall, got {other:?}"),
1899 }
1900 }
1901
1902 #[test]
1903 fn parse_if_then() {
1904 let prog = parse("if 1 then say 'yes'");
1905 assert!(matches!(&prog.clauses[0].kind, ClauseKind::If { .. }));
1906 }
1907
1908 #[test]
1909 fn parse_if_then_else() {
1910 let prog = parse("if 0 then say 'no'; else say 'yes'");
1911 match &prog.clauses[0].kind {
1912 ClauseKind::If { else_clause, .. } => {
1913 assert!(else_clause.is_some());
1914 }
1915 other => panic!("expected If, got {other:?}"),
1916 }
1917 }
1918
1919 #[test]
1920 fn parse_simple_do() {
1921 let prog = parse("do; say 'a'; end");
1922 match &prog.clauses[0].kind {
1923 ClauseKind::Do(block) => {
1924 assert!(matches!(block.kind, DoKind::Simple));
1925 assert_eq!(block.body.len(), 1);
1926 }
1927 other => panic!("expected Do, got {other:?}"),
1928 }
1929 }
1930
1931 #[test]
1932 fn parse_do_count() {
1933 let prog = parse("do 3; say 'x'; end");
1934 match &prog.clauses[0].kind {
1935 ClauseKind::Do(block) => {
1936 assert!(matches!(block.kind, DoKind::Count(_)));
1937 }
1938 other => panic!("expected Do Count, got {other:?}"),
1939 }
1940 }
1941
1942 #[test]
1943 fn parse_controlled_do() {
1944 let prog = parse("do i = 1 to 5; say i; end");
1945 match &prog.clauses[0].kind {
1946 ClauseKind::Do(block) => {
1947 assert!(matches!(block.kind, DoKind::Controlled(_)));
1948 }
1949 other => panic!("expected Do Controlled, got {other:?}"),
1950 }
1951 }
1952
1953 #[test]
1954 fn parse_select() {
1955 let prog = parse("select; when 1 then say 'one'; otherwise say 'other'; end");
1956 assert!(matches!(&prog.clauses[0].kind, ClauseKind::Select { .. }));
1957 }
1958
1959 #[test]
1960 fn parse_leave() {
1961 let prog = parse("do forever; leave; end");
1962 match &prog.clauses[0].kind {
1963 ClauseKind::Do(block) => {
1964 assert!(matches!(&block.body[0].kind, ClauseKind::Leave(None)));
1965 }
1966 other => panic!("expected Do, got {other:?}"),
1967 }
1968 }
1969
1970 #[test]
1971 fn parse_exit() {
1972 let prog = parse("exit");
1973 assert!(matches!(&prog.clauses[0].kind, ClauseKind::Exit(None)));
1974 }
1975
1976 #[test]
1977 fn parse_exit_with_expr() {
1978 let prog = parse("exit 0");
1979 assert!(matches!(&prog.clauses[0].kind, ClauseKind::Exit(Some(_))));
1980 }
1981}