1use crate::ast::*;
19use crate::lexer::{Lexer, PeekableLexer, Token, TokenSpan};
20use crate::reader::LineCol;
21use std::cmp::Ordering;
22use std::io;
23
24#[derive(Debug, thiserror::Error)]
26pub enum Error {
27 #[error("{}:{}: {}", .0.line, .0.col, .1)]
29 Bad(LineCol, String),
30
31 #[error("read error")]
33 Io(#[from] io::Error),
34}
35
36pub type Result<T> = std::result::Result<T, Error>;
38
39fn vref_to_unannotated_string(vref: VarRef, pos: LineCol) -> Result<String> {
43 if vref.ref_type().is_some() {
44 return Err(Error::Bad(pos, format!("Type annotation not allowed in {}", vref)));
45 }
46 Ok(vref.take_name())
47}
48
49pub(crate) fn argspans_to_exprs(spans: Vec<ArgSpan>) -> Vec<Expr> {
52 let nargs = spans.len();
53 let mut exprs = Vec::with_capacity(spans.len());
54 for (i, span) in spans.into_iter().enumerate() {
55 debug_assert!(
56 (span.sep == ArgSep::End || i < nargs - 1)
57 || (span.sep != ArgSep::End || i == nargs - 1)
58 );
59 match span.expr {
60 Some(expr) => exprs.push(expr),
61 None => unreachable!(),
62 }
63 }
64 exprs
65}
66
67#[derive(Debug, Eq, PartialEq)]
76enum ExprOp {
77 LeftParen,
78
79 Add,
80 Subtract,
81 Multiply,
82 Divide,
83 Modulo,
84 Power,
85 Negate,
86
87 Equal,
88 NotEqual,
89 Less,
90 LessEqual,
91 Greater,
92 GreaterEqual,
93
94 And,
95 Not,
96 Or,
97 Xor,
98
99 ShiftLeft,
100 ShiftRight,
101}
102
103impl ExprOp {
104 fn from(t: Token) -> Self {
106 match t {
107 Token::Equal => ExprOp::Equal,
108 Token::NotEqual => ExprOp::NotEqual,
109 Token::Less => ExprOp::Less,
110 Token::LessEqual => ExprOp::LessEqual,
111 Token::Greater => ExprOp::Greater,
112 Token::GreaterEqual => ExprOp::GreaterEqual,
113 Token::Plus => ExprOp::Add,
114 Token::Multiply => ExprOp::Multiply,
115 Token::Divide => ExprOp::Divide,
116 Token::Modulo => ExprOp::Modulo,
117 Token::Exponent => ExprOp::Power,
118 Token::And => ExprOp::And,
119 Token::Or => ExprOp::Or,
120 Token::Xor => ExprOp::Xor,
121 Token::ShiftLeft => ExprOp::ShiftLeft,
122 Token::ShiftRight => ExprOp::ShiftRight,
123 Token::Minus => panic!("Ambiguous token; cannot derive ExprOp"),
124 _ => panic!("Called on an non-operator"),
125 }
126 }
127
128 fn priority(&self) -> i8 {
131 match self {
132 ExprOp::LeftParen => 6,
133 ExprOp::Power => 6,
134
135 ExprOp::Negate => 5,
136 ExprOp::Not => 5,
137
138 ExprOp::Multiply => 4,
139 ExprOp::Divide => 4,
140 ExprOp::Modulo => 4,
141
142 ExprOp::Add => 3,
143 ExprOp::Subtract => 3,
144
145 ExprOp::ShiftLeft => 2,
146 ExprOp::ShiftRight => 2,
147
148 ExprOp::Equal => 1,
149 ExprOp::NotEqual => 1,
150 ExprOp::Less => 1,
151 ExprOp::LessEqual => 1,
152 ExprOp::Greater => 1,
153 ExprOp::GreaterEqual => 1,
154
155 ExprOp::And => 0,
156 ExprOp::Or => 0,
157 ExprOp::Xor => 0,
158 }
159 }
160}
161
162struct ExprOpSpan {
164 op: ExprOp,
166
167 pos: LineCol,
169}
170
171impl ExprOpSpan {
172 fn new(op: ExprOp, pos: LineCol) -> Self {
174 Self { op, pos }
175 }
176
177 fn apply(&self, exprs: &mut Vec<Expr>) -> Result<()> {
179 fn apply1(
180 exprs: &mut Vec<Expr>,
181 pos: LineCol,
182 f: fn(Box<UnaryOpSpan>) -> Expr,
183 ) -> Result<()> {
184 if exprs.is_empty() {
185 return Err(Error::Bad(pos, "Not enough values to apply operator".to_owned()));
186 }
187 let expr = exprs.pop().unwrap();
188 exprs.push(f(Box::from(UnaryOpSpan { expr, pos })));
189 Ok(())
190 }
191
192 fn apply2(
193 exprs: &mut Vec<Expr>,
194 pos: LineCol,
195 f: fn(Box<BinaryOpSpan>) -> Expr,
196 ) -> Result<()> {
197 if exprs.len() < 2 {
198 return Err(Error::Bad(pos, "Not enough values to apply operator".to_owned()));
199 }
200 let rhs = exprs.pop().unwrap();
201 let lhs = exprs.pop().unwrap();
202 exprs.push(f(Box::from(BinaryOpSpan { lhs, rhs, pos })));
203 Ok(())
204 }
205
206 match self.op {
207 ExprOp::Add => apply2(exprs, self.pos, Expr::Add),
208 ExprOp::Subtract => apply2(exprs, self.pos, Expr::Subtract),
209 ExprOp::Multiply => apply2(exprs, self.pos, Expr::Multiply),
210 ExprOp::Divide => apply2(exprs, self.pos, Expr::Divide),
211 ExprOp::Modulo => apply2(exprs, self.pos, Expr::Modulo),
212 ExprOp::Power => apply2(exprs, self.pos, Expr::Power),
213
214 ExprOp::Equal => apply2(exprs, self.pos, Expr::Equal),
215 ExprOp::NotEqual => apply2(exprs, self.pos, Expr::NotEqual),
216 ExprOp::Less => apply2(exprs, self.pos, Expr::Less),
217 ExprOp::LessEqual => apply2(exprs, self.pos, Expr::LessEqual),
218 ExprOp::Greater => apply2(exprs, self.pos, Expr::Greater),
219 ExprOp::GreaterEqual => apply2(exprs, self.pos, Expr::GreaterEqual),
220
221 ExprOp::And => apply2(exprs, self.pos, Expr::And),
222 ExprOp::Or => apply2(exprs, self.pos, Expr::Or),
223 ExprOp::Xor => apply2(exprs, self.pos, Expr::Xor),
224
225 ExprOp::ShiftLeft => apply2(exprs, self.pos, Expr::ShiftLeft),
226 ExprOp::ShiftRight => apply2(exprs, self.pos, Expr::ShiftRight),
227
228 ExprOp::Negate => apply1(exprs, self.pos, Expr::Negate),
229 ExprOp::Not => apply1(exprs, self.pos, Expr::Not),
230
231 ExprOp::LeftParen => Ok(()),
232 }
233 }
234}
235
236pub struct Parser<'a> {
238 lexer: PeekableLexer<'a>,
239}
240
241impl<'a> Parser<'a> {
242 fn from(input: &'a mut dyn io::Read) -> Self {
244 Self { lexer: Lexer::from(input).peekable() }
245 }
246
247 fn expect_and_consume<E: Into<String>>(&mut self, t: Token, err: E) -> Result<TokenSpan> {
250 let peeked = self.lexer.peek()?;
251 if peeked.token != t {
252 return Err(Error::Bad(peeked.pos, err.into()));
253 }
254 Ok(self.lexer.consume_peeked())
255 }
256
257 fn expect_and_consume_with_pos<E: Into<String>>(
261 &mut self,
262 t: Token,
263 pos: LineCol,
264 err: E,
265 ) -> Result<()> {
266 let peeked = self.lexer.peek()?;
267 if peeked.token != t {
268 return Err(Error::Bad(pos, err.into()));
269 }
270 self.lexer.consume_peeked();
271 Ok(())
272 }
273
274 fn parse_until(&mut self, delim: Token) -> Result<Vec<Statement>> {
276 let mut stmts = vec![];
277 loop {
278 let peeked = self.lexer.peek()?;
279 if peeked.token == delim {
280 break;
281 } else if peeked.token == Token::Eol {
282 self.lexer.consume_peeked();
283 continue;
284 }
285 match self.parse_one_safe()? {
286 Some(stmt) => stmts.push(stmt),
287 None => break,
288 }
289 }
290 Ok(stmts)
291 }
292
293 fn parse_assignment(&mut self, vref: VarRef, vref_pos: LineCol) -> Result<Statement> {
295 let expr = self.parse_required_expr("Missing expression in assignment")?;
296
297 let next = self.lexer.peek()?;
298 match &next.token {
299 Token::Eof | Token::Eol | Token::Else => (),
300 t => return Err(Error::Bad(next.pos, format!("Unexpected {} in assignment", t))),
301 }
302 Ok(Statement::Assignment(AssignmentSpan { vref, vref_pos, expr }))
303 }
304
305 fn parse_array_assignment(
308 &mut self,
309 vref: VarRef,
310 vref_pos: LineCol,
311 subscripts: Vec<Expr>,
312 ) -> Result<Statement> {
313 let expr = self.parse_required_expr("Missing expression in array assignment")?;
314
315 let next = self.lexer.peek()?;
316 match &next.token {
317 Token::Eof | Token::Eol | Token::Else => (),
318 t => return Err(Error::Bad(next.pos, format!("Unexpected {} in array assignment", t))),
319 }
320 Ok(Statement::ArrayAssignment(ArrayAssignmentSpan { vref, vref_pos, subscripts, expr }))
321 }
322
323 fn parse_builtin_call(
325 &mut self,
326 vref: VarRef,
327 vref_pos: LineCol,
328 mut first: Option<Expr>,
329 ) -> Result<Statement> {
330 let mut name = vref_to_unannotated_string(vref, vref_pos)?;
331 name.make_ascii_uppercase();
332
333 let mut args = vec![];
334 loop {
335 let expr = self.parse_expr(first.take())?;
336
337 let peeked = self.lexer.peek()?;
338 match peeked.token {
339 Token::Eof | Token::Eol | Token::Else => {
340 if expr.is_some() || !args.is_empty() {
341 args.push(ArgSpan { expr, sep: ArgSep::End, sep_pos: peeked.pos });
342 }
343 break;
344 }
345 Token::Semicolon => {
346 let peeked = self.lexer.consume_peeked();
347 args.push(ArgSpan { expr, sep: ArgSep::Short, sep_pos: peeked.pos });
348 }
349 Token::Comma => {
350 let peeked = self.lexer.consume_peeked();
351 args.push(ArgSpan { expr, sep: ArgSep::Long, sep_pos: peeked.pos });
352 }
353 Token::As => {
354 let peeked = self.lexer.consume_peeked();
355 args.push(ArgSpan { expr, sep: ArgSep::As, sep_pos: peeked.pos });
356 }
357 _ => {
358 return Err(Error::Bad(
359 peeked.pos,
360 "Expected comma, semicolon, or end of statement".to_owned(),
361 ))
362 }
363 }
364 }
365 Ok(Statement::Call(CallSpan { vref: VarRef::new(name, None), vref_pos, args }))
366 }
367
368 fn parse_array_or_builtin_call(
371 &mut self,
372 vref: VarRef,
373 vref_pos: LineCol,
374 ) -> Result<Statement> {
375 match self.lexer.peek()?.token {
376 Token::LeftParen => {
377 let left_paren = self.lexer.consume_peeked();
378 let spans = self.parse_comma_separated_exprs()?;
379 let mut exprs = spans.into_iter().map(|span| span.expr.unwrap()).collect();
380 match self.lexer.peek()?.token {
381 Token::Equal => {
382 self.lexer.consume_peeked();
383 self.parse_array_assignment(vref, vref_pos, exprs)
384 }
385 _ => {
386 if exprs.len() != 1 {
387 return Err(Error::Bad(
388 left_paren.pos,
389 "Expected expression".to_owned(),
390 ));
391 }
392 self.parse_builtin_call(vref, vref_pos, Some(exprs.remove(0)))
393 }
394 }
395 }
396 _ => self.parse_builtin_call(vref, vref_pos, None),
397 }
398 }
399
400 fn parse_as_type(&mut self) -> Result<(ExprType, LineCol)> {
405 let token_span = self.lexer.read()?;
406 match token_span.token {
407 Token::BooleanName => Ok((ExprType::Boolean, token_span.pos)),
408 Token::DoubleName => Ok((ExprType::Double, token_span.pos)),
409 Token::IntegerName => Ok((ExprType::Integer, token_span.pos)),
410 Token::TextName => Ok((ExprType::Text, token_span.pos)),
411 t => Err(Error::Bad(
412 token_span.pos,
413 format!("Invalid type name {} in AS type definition", t),
414 )),
415 }
416 }
417
418 fn parse_data(&mut self) -> Result<Statement> {
420 let mut values = vec![];
421 loop {
422 let peeked = self.lexer.peek()?;
423 match peeked.token {
424 Token::Eof | Token::Eol | Token::Else => {
425 values.push(None);
426 break;
427 }
428 _ => (),
429 }
430
431 let token_span = self.lexer.read()?;
432 match token_span.token {
433 Token::Boolean(b) => values.push(Some(Value::Boolean(b))),
434 Token::Double(d) => values.push(Some(Value::Double(d))),
435 Token::Integer(i) => values.push(Some(Value::Integer(i))),
436 Token::Text(t) => values.push(Some(Value::Text(t))),
437
438 Token::Minus => {
439 let token_span = self.lexer.read()?;
440 match token_span.token {
441 Token::Double(d) => values.push(Some(Value::Double(-d))),
442 Token::Integer(i) => values.push(Some(Value::Integer(-i))),
443 _ => {
444 return Err(Error::Bad(
445 token_span.pos,
446 "Expected number after -".to_owned(),
447 ))
448 }
449 }
450 }
451
452 Token::Eof | Token::Eol | Token::Else => {
453 panic!("Should not be consumed here; handled above")
454 }
455
456 Token::Comma => {
457 values.push(None);
458 continue;
459 }
460
461 t => {
462 return Err(Error::Bad(
463 token_span.pos,
464 format!("Unexpected {} in DATA statement", t),
465 ))
466 }
467 }
468
469 let peeked = self.lexer.peek()?;
470 match &peeked.token {
471 Token::Eof | Token::Eol | Token::Else => {
472 break;
473 }
474
475 Token::Comma => {
476 self.lexer.consume_peeked();
477 }
478
479 t => {
480 return Err(Error::Bad(
481 peeked.pos,
482 format!("Expected comma after datum but found {}", t),
483 ))
484 }
485 }
486 }
487 Ok(Statement::Data(DataSpan { values }))
488 }
489
490 fn parse_dim_as(&mut self) -> Result<(ExprType, LineCol)> {
493 let peeked = self.lexer.peek()?;
494 let (vtype, vtype_pos) = match peeked.token {
495 Token::Eof | Token::Eol => (ExprType::Integer, peeked.pos),
496 Token::As => {
497 self.lexer.consume_peeked();
498 self.parse_as_type()?
499 }
500 _ => return Err(Error::Bad(peeked.pos, "Expected AS or end of statement".to_owned())),
501 };
502
503 let next = self.lexer.peek()?;
504 match &next.token {
505 Token::Eof | Token::Eol => (),
506 t => return Err(Error::Bad(next.pos, format!("Unexpected {} in DIM statement", t))),
507 }
508
509 Ok((vtype, vtype_pos))
510 }
511
512 fn parse_dim(&mut self) -> Result<Statement> {
514 let peeked = self.lexer.peek()?;
515 let mut shared = false;
516 if peeked.token == Token::Shared {
517 self.lexer.consume_peeked();
518 shared = true;
519 }
520
521 let token_span = self.lexer.read()?;
522 let vref = match token_span.token {
523 Token::Symbol(vref) => vref,
524 _ => {
525 return Err(Error::Bad(
526 token_span.pos,
527 "Expected variable name after DIM".to_owned(),
528 ))
529 }
530 };
531 let name = vref_to_unannotated_string(vref, token_span.pos)?;
532 let name_pos = token_span.pos;
533
534 match self.lexer.peek()?.token {
535 Token::LeftParen => {
536 let peeked = self.lexer.consume_peeked();
537 let dimensions = self.parse_comma_separated_exprs()?;
538 if dimensions.is_empty() {
539 return Err(Error::Bad(
540 peeked.pos,
541 "Arrays require at least one dimension".to_owned(),
542 ));
543 }
544 let (subtype, subtype_pos) = self.parse_dim_as()?;
545 Ok(Statement::DimArray(DimArraySpan {
546 name,
547 name_pos,
548 shared,
549 dimensions: argspans_to_exprs(dimensions),
550 subtype,
551 subtype_pos,
552 }))
553 }
554 _ => {
555 let (vtype, vtype_pos) = self.parse_dim_as()?;
556 Ok(Statement::Dim(DimSpan { name, name_pos, shared, vtype, vtype_pos }))
557 }
558 }
559 }
560
561 fn parse_do_guard(&mut self, part: &str) -> Result<Option<(Expr, bool)>> {
568 let peeked = self.lexer.peek()?;
569 match peeked.token {
570 Token::Until => {
571 self.lexer.consume_peeked();
572 let expr = self.parse_required_expr("No expression in UNTIL clause")?;
573 Ok(Some((expr, true)))
574 }
575 Token::While => {
576 self.lexer.consume_peeked();
577 let expr = self.parse_required_expr("No expression in WHILE clause")?;
578 Ok(Some((expr, false)))
579 }
580 Token::Eof | Token::Eol => Ok(None),
581 _ => {
582 let token_span = self.lexer.consume_peeked();
583 Err(Error::Bad(
584 token_span.pos,
585 format!("Expecting newline, UNTIL or WHILE after {}", part),
586 ))
587 }
588 }
589 }
590
591 fn parse_do(&mut self, do_pos: LineCol) -> Result<Statement> {
593 let pre_guard = self.parse_do_guard("DO")?;
594 self.expect_and_consume(Token::Eol, "Expecting newline after DO")?;
595
596 let stmts = self.parse_until(Token::Loop)?;
597 self.expect_and_consume_with_pos(Token::Loop, do_pos, "DO without LOOP")?;
598
599 let post_guard = self.parse_do_guard("LOOP")?;
600
601 let guard = match (pre_guard, post_guard) {
602 (None, None) => DoGuard::Infinite,
603 (Some((guard, true)), None) => DoGuard::PreUntil(guard),
604 (Some((guard, false)), None) => DoGuard::PreWhile(guard),
605 (None, Some((guard, true))) => DoGuard::PostUntil(guard),
606 (None, Some((guard, false))) => DoGuard::PostWhile(guard),
607 (Some(_), Some(_)) => {
608 return Err(Error::Bad(
609 do_pos,
610 "DO loop cannot have pre and post guards at the same time".to_owned(),
611 ))
612 }
613 };
614
615 Ok(Statement::Do(DoSpan { guard, body: stmts }))
616 }
617
618 fn reset_do(&mut self) -> Result<()> {
620 loop {
621 match self.lexer.peek()?.token {
622 Token::Eof => break,
623 Token::Loop => {
624 self.lexer.consume_peeked();
625 loop {
626 match self.lexer.peek()?.token {
627 Token::Eof | Token::Eol => break,
628 _ => {
629 self.lexer.consume_peeked();
630 }
631 }
632 }
633 break;
634 }
635 _ => {
636 self.lexer.consume_peeked();
637 }
638 }
639 }
640 self.reset()
641 }
642
643 fn maybe_parse_end(&mut self) -> Result<std::result::Result<Statement, Token>> {
646 match self.lexer.peek()?.token {
647 Token::Function => Ok(Err(Token::Function)),
648 Token::If => Ok(Err(Token::If)),
649 Token::Select => Ok(Err(Token::Select)),
650 Token::Sub => Ok(Err(Token::Sub)),
651 _ => {
652 let code = self.parse_expr(None)?;
653 Ok(Ok(Statement::End(EndSpan { code })))
654 }
655 }
656 }
657
658 fn parse_end(&mut self, pos: LineCol) -> Result<Statement> {
660 match self.maybe_parse_end()? {
661 Ok(stmt) => Ok(stmt),
662 Err(token) => Err(Error::Bad(pos, format!("END {} without {}", token, token))),
663 }
664 }
665
666 fn parse_exit_do(&mut self, pos: LineCol) -> Result<Statement> {
668 self.expect_and_consume(Token::Do, "Expecting DO after EXIT")?;
669 Ok(Statement::ExitDo(ExitDoSpan { pos }))
670 }
671
672 fn parse_comma_separated_exprs(&mut self) -> Result<Vec<ArgSpan>> {
676 let mut spans = vec![];
677
678 let mut is_first = true;
680 let mut prev_expr = self.parse_expr(None)?;
681
682 loop {
683 let peeked = self.lexer.peek()?;
684 let pos = peeked.pos;
685 match &peeked.token {
686 Token::RightParen => {
687 self.lexer.consume_peeked();
688
689 if let Some(expr) = prev_expr.take() {
690 spans.push(ArgSpan { expr: Some(expr), sep: ArgSep::End, sep_pos: pos });
691 } else {
692 if !is_first {
693 return Err(Error::Bad(pos, "Missing expression".to_owned()));
694 }
695 }
696
697 break;
698 }
699 Token::Comma => {
700 self.lexer.consume_peeked();
701
702 if let Some(expr) = prev_expr.take() {
703 spans.push(ArgSpan { expr: Some(expr), sep: ArgSep::Long, sep_pos: pos });
706 } else {
707 return Err(Error::Bad(pos, "Missing expression".to_owned()));
708 }
709
710 prev_expr = self.parse_expr(None)?;
711 }
712 t => return Err(Error::Bad(pos, format!("Unexpected {}", t))),
713 }
714
715 is_first = false;
716 }
717
718 Ok(spans)
719 }
720
721 fn parse_expr(&mut self, first: Option<Expr>) -> Result<Option<Expr>> {
731 let mut exprs: Vec<Expr> = vec![];
732 let mut op_spans: Vec<ExprOpSpan> = vec![];
733
734 let mut need_operand = true; if let Some(e) = first {
736 exprs.push(e);
737 need_operand = false;
738 }
739
740 loop {
741 let mut handle_operand = |e, pos| {
742 if !need_operand {
743 return Err(Error::Bad(pos, "Unexpected value in expression".to_owned()));
744 }
745 need_operand = false;
746 exprs.push(e);
747 Ok(())
748 };
749
750 match self.lexer.peek()?.token {
753 Token::Eof
754 | Token::Eol
755 | Token::As
756 | Token::Comma
757 | Token::Else
758 | Token::Semicolon
759 | Token::Then
760 | Token::To
761 | Token::Step => break,
762 Token::RightParen => {
763 if !op_spans.iter().any(|eos| eos.op == ExprOp::LeftParen) {
764 break;
770 }
771 }
772 _ => (),
773 };
774
775 let ts = self.lexer.consume_peeked();
776 match ts.token {
777 Token::Boolean(value) => {
778 handle_operand(Expr::Boolean(BooleanSpan { value, pos: ts.pos }), ts.pos)?
779 }
780 Token::Double(value) => {
781 handle_operand(Expr::Double(DoubleSpan { value, pos: ts.pos }), ts.pos)?
782 }
783 Token::Integer(value) => {
784 handle_operand(Expr::Integer(IntegerSpan { value, pos: ts.pos }), ts.pos)?
785 }
786 Token::Text(value) => {
787 handle_operand(Expr::Text(TextSpan { value, pos: ts.pos }), ts.pos)?
788 }
789 Token::Symbol(vref) => {
790 handle_operand(Expr::Symbol(SymbolSpan { vref, pos: ts.pos }), ts.pos)?
791 }
792
793 Token::LeftParen => {
794 match exprs.pop() {
797 Some(Expr::Symbol(span)) => {
798 if !need_operand {
799 exprs.push(Expr::Call(CallSpan {
800 vref: span.vref,
801 vref_pos: span.pos,
802 args: self.parse_comma_separated_exprs()?,
803 }));
804 need_operand = false;
805 } else {
806 op_spans.push(ExprOpSpan::new(ExprOp::LeftParen, ts.pos));
811 exprs.push(Expr::Symbol(span));
812 need_operand = true;
813 }
814 }
815 e => {
816 if let Some(e) = e {
817 exprs.push(e);
821 }
822 if !need_operand {
823 return Err(Error::Bad(
824 ts.pos,
825 format!("Unexpected {} in expression", ts.token),
826 ));
827 }
828 op_spans.push(ExprOpSpan::new(ExprOp::LeftParen, ts.pos));
829 need_operand = true;
830 }
831 };
832 }
833 Token::RightParen => {
834 let mut found = false;
835 while let Some(eos) = op_spans.pop() {
836 eos.apply(&mut exprs)?;
837 if eos.op == ExprOp::LeftParen {
838 found = true;
839 break;
840 }
841 }
842 assert!(found, "Unbalanced parenthesis should have been handled above");
843 need_operand = false;
844 }
845
846 Token::Not => {
847 op_spans.push(ExprOpSpan::new(ExprOp::Not, ts.pos));
848 need_operand = true;
849 }
850 Token::Minus => {
851 let op;
852 if need_operand {
853 op = ExprOp::Negate;
854 } else {
855 op = ExprOp::Subtract;
856 while let Some(eos2) = op_spans.last() {
857 if eos2.op == ExprOp::LeftParen || eos2.op.priority() < op.priority() {
858 break;
859 }
860 let eos2 = op_spans.pop().unwrap();
861 eos2.apply(&mut exprs)?;
862 }
863 }
864 op_spans.push(ExprOpSpan::new(op, ts.pos));
865 need_operand = true;
866 }
867
868 Token::Equal
869 | Token::NotEqual
870 | Token::Less
871 | Token::LessEqual
872 | Token::Greater
873 | Token::GreaterEqual
874 | Token::Plus
875 | Token::Multiply
876 | Token::Divide
877 | Token::Modulo
878 | Token::Exponent
879 | Token::And
880 | Token::Or
881 | Token::Xor
882 | Token::ShiftLeft
883 | Token::ShiftRight => {
884 let op = ExprOp::from(ts.token);
885 while let Some(eos2) = op_spans.last() {
886 if eos2.op == ExprOp::LeftParen || eos2.op.priority() < op.priority() {
887 break;
888 }
889 let eos2 = op_spans.pop().unwrap();
890 eos2.apply(&mut exprs)?;
891 }
892 op_spans.push(ExprOpSpan::new(op, ts.pos));
893 need_operand = true;
894 }
895
896 Token::Bad(e) => return Err(Error::Bad(ts.pos, e)),
897
898 Token::Eof
899 | Token::Eol
900 | Token::As
901 | Token::Comma
902 | Token::Else
903 | Token::Semicolon
904 | Token::Then
905 | Token::To
906 | Token::Step => {
907 panic!("Field separators handled above")
908 }
909
910 Token::BooleanName
911 | Token::Case
912 | Token::Data
913 | Token::Do
914 | Token::Dim
915 | Token::DoubleName
916 | Token::Elseif
917 | Token::End
918 | Token::Error
919 | Token::Exit
920 | Token::For
921 | Token::Function
922 | Token::Gosub
923 | Token::Goto
924 | Token::If
925 | Token::Is
926 | Token::IntegerName
927 | Token::Label(_)
928 | Token::Loop
929 | Token::Next
930 | Token::On
931 | Token::Resume
932 | Token::Return
933 | Token::Select
934 | Token::Shared
935 | Token::Sub
936 | Token::TextName
937 | Token::Until
938 | Token::Wend
939 | Token::While => {
940 return Err(Error::Bad(ts.pos, "Unexpected keyword in expression".to_owned()));
941 }
942 };
943 }
944
945 while let Some(eos) = op_spans.pop() {
946 match eos.op {
947 ExprOp::LeftParen => {
948 return Err(Error::Bad(eos.pos, "Unbalanced parenthesis".to_owned()))
949 }
950 _ => eos.apply(&mut exprs)?,
951 }
952 }
953
954 if let Some(expr) = exprs.pop() {
955 Ok(Some(expr))
956 } else {
957 Ok(None)
958 }
959 }
960
961 fn parse_required_expr(&mut self, msg: &'static str) -> Result<Expr> {
964 let next_pos = self.lexer.peek()?.pos;
965 match self.parse_expr(None)? {
966 Some(expr) => Ok(expr),
967 None => Err(Error::Bad(next_pos, msg.to_owned())),
968 }
969 }
970
971 fn parse_gosub(&mut self) -> Result<Statement> {
973 let token_span = self.lexer.read()?;
974 match token_span.token {
975 Token::Integer(i) => {
976 let target = format!("{}", i);
977 Ok(Statement::Gosub(GotoSpan { target, target_pos: token_span.pos }))
978 }
979 Token::Label(target) => {
980 Ok(Statement::Gosub(GotoSpan { target, target_pos: token_span.pos }))
981 }
982 _ => Err(Error::Bad(token_span.pos, "Expected label name after GOSUB".to_owned())),
983 }
984 }
985
986 fn parse_goto(&mut self) -> Result<Statement> {
988 let token_span = self.lexer.read()?;
989 match token_span.token {
990 Token::Integer(i) => {
991 let target = format!("{}", i);
992 Ok(Statement::Goto(GotoSpan { target, target_pos: token_span.pos }))
993 }
994 Token::Label(target) => {
995 Ok(Statement::Goto(GotoSpan { target, target_pos: token_span.pos }))
996 }
997 _ => Err(Error::Bad(token_span.pos, "Expected label name after GOTO".to_owned())),
998 }
999 }
1000
1001 fn parse_if_uniline(&mut self, branches: &mut Vec<IfBranchSpan>) -> Result<()> {
1003 debug_assert!(!branches.is_empty(), "Caller must populate the guard of the first branch");
1004
1005 let mut has_else = false;
1006 let peeked = self.lexer.peek()?;
1007 match peeked.token {
1008 Token::Else => has_else = true,
1009 _ => {
1010 let stmt = self
1011 .parse_uniline()?
1012 .expect("The caller already checked for a non-empty token");
1013 branches[0].body.push(stmt);
1014 }
1015 }
1016
1017 let peeked = self.lexer.peek()?;
1018 has_else |= peeked.token == Token::Else;
1019
1020 if has_else {
1021 let else_span = self.lexer.consume_peeked();
1022 let expr = Expr::Boolean(BooleanSpan { value: true, pos: else_span.pos });
1023 branches.push(IfBranchSpan { guard: expr, body: vec![] });
1024 if let Some(stmt) = self.parse_uniline()? {
1025 branches[1].body.push(stmt);
1026 }
1027 }
1028
1029 Ok(())
1030 }
1031
1032 fn parse_if_multiline(
1034 &mut self,
1035 if_pos: LineCol,
1036 branches: &mut Vec<IfBranchSpan>,
1037 ) -> Result<()> {
1038 debug_assert!(!branches.is_empty(), "Caller must populate the guard of the first branch");
1039
1040 let mut i = 0;
1041 let mut last = false;
1042 loop {
1043 let peeked = self.lexer.peek()?;
1044 match peeked.token {
1045 Token::Eol => {
1046 self.lexer.consume_peeked();
1047 }
1048
1049 Token::Elseif => {
1050 if last {
1051 return Err(Error::Bad(
1052 peeked.pos,
1053 "Unexpected ELSEIF after ELSE".to_owned(),
1054 ));
1055 }
1056
1057 self.lexer.consume_peeked();
1058 let expr = self.parse_required_expr("No expression in ELSEIF statement")?;
1059 self.expect_and_consume(Token::Then, "No THEN in ELSEIF statement")?;
1060 self.expect_and_consume(Token::Eol, "Expecting newline after THEN")?;
1061 branches.push(IfBranchSpan { guard: expr, body: vec![] });
1062 i += 1;
1063 }
1064
1065 Token::Else => {
1066 if last {
1067 return Err(Error::Bad(peeked.pos, "Duplicate ELSE after ELSE".to_owned()));
1068 }
1069
1070 let else_span = self.lexer.consume_peeked();
1071 self.expect_and_consume(Token::Eol, "Expecting newline after ELSE")?;
1072
1073 let expr = Expr::Boolean(BooleanSpan { value: true, pos: else_span.pos });
1074 branches.push(IfBranchSpan { guard: expr, body: vec![] });
1075 i += 1;
1076
1077 last = true;
1078 }
1079
1080 Token::End => {
1081 let token_span = self.lexer.consume_peeked();
1082 match self.maybe_parse_end()? {
1083 Ok(stmt) => {
1084 branches[i].body.push(stmt);
1085 }
1086 Err(Token::If) => {
1087 break;
1088 }
1089 Err(token) => {
1090 return Err(Error::Bad(
1091 token_span.pos,
1092 format!("END {} without {}", token, token),
1093 ));
1094 }
1095 }
1096 }
1097
1098 _ => match self.parse_one_safe()? {
1099 Some(stmt) => {
1100 branches[i].body.push(stmt);
1101 }
1102 None => {
1103 break;
1104 }
1105 },
1106 }
1107 }
1108
1109 self.expect_and_consume_with_pos(Token::If, if_pos, "IF without END IF")
1110 }
1111
1112 fn parse_if(&mut self, if_pos: LineCol) -> Result<Statement> {
1114 let expr = self.parse_required_expr("No expression in IF statement")?;
1115 self.expect_and_consume(Token::Then, "No THEN in IF statement")?;
1116
1117 let mut branches = vec![IfBranchSpan { guard: expr, body: vec![] }];
1118
1119 let peeked = self.lexer.peek()?;
1120 match peeked.token {
1121 Token::Eol | Token::Eof => self.parse_if_multiline(if_pos, &mut branches)?,
1122 _ => self.parse_if_uniline(&mut branches)?,
1123 }
1124
1125 Ok(Statement::If(IfSpan { branches }))
1126 }
1127
1128 fn reset_if(&mut self, if_pos: LineCol) -> Result<()> {
1130 loop {
1131 match self.lexer.peek()?.token {
1132 Token::Eof => break,
1133 Token::End => {
1134 self.lexer.consume_peeked();
1135 self.expect_and_consume_with_pos(Token::If, if_pos, "IF without END IF")?;
1136 break;
1137 }
1138 _ => {
1139 self.lexer.consume_peeked();
1140 }
1141 }
1142 }
1143 self.reset()
1144 }
1145
1146 fn parse_step(&mut self) -> Result<(Expr, Ordering, bool)> {
1151 let peeked = self.lexer.peek()?;
1152 match peeked.token {
1153 Token::Step => self.lexer.consume_peeked(),
1154 _ => {
1155 return Ok((
1159 Expr::Integer(IntegerSpan { value: 1, pos: peeked.pos }),
1160 Ordering::Greater,
1161 false,
1162 ));
1163 }
1164 };
1165
1166 let peeked = self.lexer.peek()?;
1167 match peeked.token {
1168 Token::Double(d) => {
1169 let peeked = self.lexer.consume_peeked();
1170 let sign = if d == 0.0 { Ordering::Equal } else { Ordering::Greater };
1171 Ok((Expr::Double(DoubleSpan { value: d, pos: peeked.pos }), sign, true))
1172 }
1173 Token::Integer(i) => {
1174 let peeked = self.lexer.consume_peeked();
1175 Ok((Expr::Integer(IntegerSpan { value: i, pos: peeked.pos }), i.cmp(&0), false))
1176 }
1177 Token::Minus => {
1178 self.lexer.consume_peeked();
1179 let peeked = self.lexer.peek()?;
1180 match peeked.token {
1181 Token::Double(d) => {
1182 let peeked = self.lexer.consume_peeked();
1183 let sign = if d == 0.0 { Ordering::Equal } else { Ordering::Less };
1184 Ok((Expr::Double(DoubleSpan { value: -d, pos: peeked.pos }), sign, true))
1185 }
1186 Token::Integer(i) => {
1187 let peeked = self.lexer.consume_peeked();
1188 Ok((
1189 Expr::Integer(IntegerSpan { value: -i, pos: peeked.pos }),
1190 (-i).cmp(&0),
1191 false,
1192 ))
1193 }
1194 _ => Err(Error::Bad(peeked.pos, "STEP needs a literal number".to_owned())),
1195 }
1196 }
1197 _ => Err(Error::Bad(peeked.pos, "STEP needs a literal number".to_owned())),
1198 }
1199 }
1200
1201 fn parse_for(&mut self, for_pos: LineCol) -> Result<Statement> {
1203 let token_span = self.lexer.read()?;
1204 let iterator = match token_span.token {
1205 Token::Symbol(iterator) => match iterator.ref_type() {
1206 None | Some(ExprType::Double) | Some(ExprType::Integer) => iterator,
1207 _ => {
1208 return Err(Error::Bad(
1209 token_span.pos,
1210 "Iterator name in FOR statement must be a numeric reference".to_owned(),
1211 ))
1212 }
1213 },
1214 _ => {
1215 return Err(Error::Bad(
1216 token_span.pos,
1217 "No iterator name in FOR statement".to_owned(),
1218 ))
1219 }
1220 };
1221 let iterator_pos = token_span.pos;
1222
1223 self.expect_and_consume(Token::Equal, "No equal sign in FOR statement")?;
1224 let start = self.parse_required_expr("No start expression in FOR statement")?;
1225
1226 let to_span = self.expect_and_consume(Token::To, "No TO in FOR statement")?;
1227 let end = self.parse_required_expr("No end expression in FOR statement")?;
1228
1229 let (step, step_sign, iter_double) = self.parse_step()?;
1230 let end_condition = match step_sign {
1231 Ordering::Greater => Expr::LessEqual(Box::from(BinaryOpSpan {
1232 lhs: Expr::Symbol(SymbolSpan { vref: iterator.clone(), pos: iterator_pos }),
1233 rhs: end,
1234 pos: to_span.pos,
1235 })),
1236 Ordering::Less => Expr::GreaterEqual(Box::from(BinaryOpSpan {
1237 lhs: Expr::Symbol(SymbolSpan { vref: iterator.clone(), pos: iterator_pos }),
1238 rhs: end,
1239 pos: to_span.pos,
1240 })),
1241 Ordering::Equal => {
1242 return Err(Error::Bad(
1243 step.start_pos(),
1244 "Infinite FOR loop; STEP cannot be 0".to_owned(),
1245 ))
1246 }
1247 };
1248
1249 let next_value = Expr::Add(Box::from(BinaryOpSpan {
1250 lhs: Expr::Symbol(SymbolSpan { vref: iterator.clone(), pos: iterator_pos }),
1251 rhs: step,
1252 pos: to_span.pos,
1253 }));
1254
1255 self.expect_and_consume(Token::Eol, "Expecting newline after FOR")?;
1256
1257 let stmts = self.parse_until(Token::Next)?;
1258 self.expect_and_consume_with_pos(Token::Next, for_pos, "FOR without NEXT")?;
1259
1260 Ok(Statement::For(ForSpan {
1261 iter: iterator,
1262 iter_pos: iterator_pos,
1263 iter_double,
1264 start,
1265 end: end_condition,
1266 next: next_value,
1267 body: stmts,
1268 }))
1269 }
1270
1271 fn reset_for(&mut self) -> Result<()> {
1273 loop {
1274 match self.lexer.peek()?.token {
1275 Token::Eof => break,
1276 Token::Next => {
1277 self.lexer.consume_peeked();
1278 break;
1279 }
1280 _ => {
1281 self.lexer.consume_peeked();
1282 }
1283 }
1284 }
1285 self.reset()
1286 }
1287
1288 fn parse_callable_args(&mut self) -> Result<Vec<VarRef>> {
1291 let mut params = vec![];
1292 let peeked = self.lexer.peek()?;
1293 if peeked.token == Token::LeftParen {
1294 self.lexer.consume_peeked();
1295
1296 loop {
1297 let token_span = self.lexer.read()?;
1298 match token_span.token {
1299 Token::Symbol(param) => {
1300 let peeked = self.lexer.peek()?;
1301 if peeked.token == Token::As {
1302 self.lexer.consume_peeked();
1303
1304 let name = vref_to_unannotated_string(param, token_span.pos)?;
1305 let (vtype, _pos) = self.parse_as_type()?;
1306 params.push(VarRef::new(name, Some(vtype)));
1307 } else {
1308 params.push(param);
1309 }
1310 }
1311 _ => {
1312 return Err(Error::Bad(
1313 token_span.pos,
1314 "Expected a parameter name".to_owned(),
1315 ));
1316 }
1317 }
1318
1319 let token_span = self.lexer.read()?;
1320 match token_span.token {
1321 Token::Comma => (),
1322 Token::RightParen => break,
1323 _ => {
1324 return Err(Error::Bad(
1325 token_span.pos,
1326 "Expected comma, AS, or end of parameters list".to_owned(),
1327 ));
1328 }
1329 }
1330 }
1331 }
1332 Ok(params)
1333 }
1334
1335 fn parse_callable_body(
1338 &mut self,
1339 start_pos: LineCol,
1340 exp_token: Token,
1341 ) -> Result<(Vec<Statement>, LineCol)> {
1342 debug_assert!(matches!(exp_token, Token::Function | Token::Sub));
1343
1344 let mut body = vec![];
1345 let end_pos;
1346 loop {
1347 let peeked = self.lexer.peek()?;
1348 match peeked.token {
1349 Token::Eof => {
1350 end_pos = peeked.pos;
1351 break;
1352 }
1353
1354 Token::Eol => {
1355 self.lexer.consume_peeked();
1356 }
1357
1358 Token::Function | Token::Sub => {
1359 return Err(Error::Bad(
1360 peeked.pos,
1361 "Cannot nest FUNCTION or SUB definitions".to_owned(),
1362 ));
1363 }
1364
1365 Token::End => {
1366 let end_span = self.lexer.consume_peeked();
1367 match self.maybe_parse_end()? {
1368 Ok(stmt) => {
1369 body.push(stmt);
1370 }
1371 Err(token) if token == exp_token => {
1372 end_pos = end_span.pos;
1373 break;
1374 }
1375 Err(token) => {
1376 return Err(Error::Bad(
1377 end_span.pos,
1378 format!("END {} without {}", token, token),
1379 ));
1380 }
1381 }
1382 }
1383
1384 _ => match self.parse_one_safe()? {
1386 Some(stmt) => body.push(stmt),
1387 None => {
1388 return Err(Error::Bad(
1389 start_pos,
1390 format!("{} without END {}", exp_token, exp_token),
1391 ));
1392 }
1393 },
1394 }
1395 }
1396
1397 self.expect_and_consume_with_pos(
1398 exp_token.clone(),
1399 start_pos,
1400 format!("{} without END {}", exp_token, exp_token),
1401 )?;
1402
1403 Ok((body, end_pos))
1404 }
1405
1406 fn parse_function(&mut self, function_pos: LineCol) -> Result<Statement> {
1408 let token_span = self.lexer.read()?;
1409 let name = match token_span.token {
1410 Token::Symbol(name) => {
1411 if name.ref_type().is_none() {
1412 VarRef::new(name.take_name(), Some(ExprType::Integer))
1413 } else {
1414 name
1415 }
1416 }
1417 _ => {
1418 return Err(Error::Bad(
1419 token_span.pos,
1420 "Expected a function name after FUNCTION".to_owned(),
1421 ));
1422 }
1423 };
1424 let name_pos = token_span.pos;
1425
1426 let params = self.parse_callable_args()?;
1427 self.expect_and_consume(Token::Eol, "Expected newline after FUNCTION name")?;
1428
1429 let (body, end_pos) = self.parse_callable_body(function_pos, Token::Function)?;
1430
1431 Ok(Statement::Callable(CallableSpan { name, name_pos, params, body, end_pos }))
1432 }
1433
1434 fn parse_sub(&mut self, sub_pos: LineCol) -> Result<Statement> {
1436 let token_span = self.lexer.read()?;
1437 let name = match token_span.token {
1438 Token::Symbol(name) => {
1439 if name.ref_type().is_some() {
1440 return Err(Error::Bad(
1441 token_span.pos,
1442 "SUBs cannot return a value so type annotations are not allowed".to_owned(),
1443 ));
1444 }
1445 name
1446 }
1447 _ => {
1448 return Err(Error::Bad(
1449 token_span.pos,
1450 "Expected a function name after SUB".to_owned(),
1451 ));
1452 }
1453 };
1454 let name_pos = token_span.pos;
1455
1456 let params = self.parse_callable_args()?;
1457 self.expect_and_consume(Token::Eol, "Expected newline after SUB name")?;
1458
1459 let (body, end_pos) = self.parse_callable_body(sub_pos, Token::Sub)?;
1460
1461 Ok(Statement::Callable(CallableSpan { name, name_pos, params, body, end_pos }))
1462 }
1463
1464 fn reset_callable(&mut self, exp_token: Token) -> Result<()> {
1466 loop {
1467 match self.lexer.peek()?.token {
1468 Token::Eof => break,
1469 Token::End => {
1470 self.lexer.consume_peeked();
1471
1472 let token_span = self.lexer.read()?;
1473 if token_span.token == exp_token {
1474 break;
1475 }
1476 }
1477 _ => {
1478 self.lexer.consume_peeked();
1479 }
1480 }
1481 }
1482 self.reset()
1483 }
1484
1485 fn parse_on(&mut self) -> Result<Statement> {
1487 self.expect_and_consume(Token::Error, "Expected ERROR after ON")?;
1488
1489 let token_span = self.lexer.read()?;
1490 match token_span.token {
1491 Token::Goto => {
1492 let token_span = self.lexer.read()?;
1493 match token_span.token {
1494 Token::Integer(0) => Ok(Statement::OnError(OnErrorSpan::Reset)),
1495 Token::Integer(i) => Ok(Statement::OnError(OnErrorSpan::Goto(GotoSpan {
1496 target: format!("{}", i),
1497 target_pos: token_span.pos,
1498 }))),
1499 Token::Label(target) => Ok(Statement::OnError(OnErrorSpan::Goto(GotoSpan {
1500 target,
1501 target_pos: token_span.pos,
1502 }))),
1503 _ => Err(Error::Bad(
1504 token_span.pos,
1505 "Expected label name or 0 after ON ERROR GOTO".to_owned(),
1506 )),
1507 }
1508 }
1509 Token::Resume => {
1510 self.expect_and_consume(Token::Next, "Expected NEXT after ON ERROR RESUME")?;
1511 Ok(Statement::OnError(OnErrorSpan::ResumeNext))
1512 }
1513 _ => {
1514 Err(Error::Bad(token_span.pos, "Expected GOTO or RESUME after ON ERROR".to_owned()))
1515 }
1516 }
1517 }
1518
1519 fn parse_case_guards(&mut self) -> Result<Vec<CaseGuardSpan>> {
1521 let mut guards = vec![];
1522
1523 loop {
1524 let peeked = self.lexer.peek()?;
1525 match peeked.token {
1526 Token::Else => {
1527 let token_span = self.lexer.consume_peeked();
1528
1529 if !guards.is_empty() {
1530 return Err(Error::Bad(
1531 token_span.pos,
1532 "CASE ELSE must be on its own".to_owned(),
1533 ));
1534 }
1535
1536 let peeked = self.lexer.peek()?;
1537 if peeked.token != Token::Eol && peeked.token != Token::Eof {
1538 return Err(Error::Bad(
1539 peeked.pos,
1540 "Expected newline after CASE ELSE".to_owned(),
1541 ));
1542 }
1543
1544 break;
1545 }
1546
1547 Token::Is => {
1548 self.lexer.consume_peeked();
1549
1550 let token_span = self.lexer.read()?;
1551 let rel_op = match token_span.token {
1552 Token::Equal => CaseRelOp::Equal,
1553 Token::NotEqual => CaseRelOp::NotEqual,
1554 Token::Less => CaseRelOp::Less,
1555 Token::LessEqual => CaseRelOp::LessEqual,
1556 Token::Greater => CaseRelOp::Greater,
1557 Token::GreaterEqual => CaseRelOp::GreaterEqual,
1558 _ => {
1559 return Err(Error::Bad(
1560 token_span.pos,
1561 "Expected relational operator".to_owned(),
1562 ));
1563 }
1564 };
1565
1566 let expr =
1567 self.parse_required_expr("Missing expression after relational operator")?;
1568 guards.push(CaseGuardSpan::Is(rel_op, expr));
1569 }
1570
1571 _ => {
1572 let from_expr = self.parse_required_expr("Missing expression in CASE guard")?;
1573
1574 let peeked = self.lexer.peek()?;
1575 match peeked.token {
1576 Token::Eol | Token::Comma => {
1577 guards.push(CaseGuardSpan::Is(CaseRelOp::Equal, from_expr));
1578 }
1579 Token::To => {
1580 self.lexer.consume_peeked();
1581 let to_expr = self
1582 .parse_required_expr("Missing expression after TO in CASE guard")?;
1583 guards.push(CaseGuardSpan::To(from_expr, to_expr));
1584 }
1585 _ => {
1586 return Err(Error::Bad(
1587 peeked.pos,
1588 "Expected comma, newline, or TO after expression".to_owned(),
1589 ));
1590 }
1591 }
1592 }
1593 }
1594
1595 let peeked = self.lexer.peek()?;
1596 match peeked.token {
1597 Token::Eol => {
1598 break;
1599 }
1600 Token::Comma => {
1601 self.lexer.consume_peeked();
1602 }
1603 _ => {
1604 return Err(Error::Bad(
1605 peeked.pos,
1606 "Expected comma, newline, or TO after expression".to_owned(),
1607 ));
1608 }
1609 }
1610 }
1611
1612 Ok(guards)
1613 }
1614
1615 fn parse_select(&mut self, select_pos: LineCol) -> Result<Statement> {
1617 self.expect_and_consume(Token::Case, "Expecting CASE after SELECT")?;
1618
1619 let expr = self.parse_required_expr("No expression in SELECT CASE statement")?;
1620 self.expect_and_consume(Token::Eol, "Expecting newline after SELECT CASE")?;
1621
1622 let mut cases = vec![];
1623
1624 let mut i = 0;
1625 let mut last = false;
1626 let end_pos;
1627 loop {
1628 let peeked = self.lexer.peek()?;
1629 match peeked.token {
1630 Token::Eof => {
1631 end_pos = peeked.pos;
1632 break;
1633 }
1634
1635 Token::Eol => {
1636 self.lexer.consume_peeked();
1637 }
1638
1639 Token::Case => {
1640 let peeked = self.lexer.consume_peeked();
1641 let guards = self.parse_case_guards()?;
1642 self.expect_and_consume(Token::Eol, "Expecting newline after CASE")?;
1643
1644 let is_last = guards.is_empty();
1645 if last {
1646 if is_last {
1647 return Err(Error::Bad(
1648 peeked.pos,
1649 "CASE ELSE must be unique".to_owned(),
1650 ));
1651 } else {
1652 return Err(Error::Bad(peeked.pos, "CASE ELSE is not last".to_owned()));
1653 }
1654 }
1655 last |= is_last;
1656
1657 cases.push(CaseSpan { guards, body: vec![] });
1658 if cases.len() > 1 {
1659 i += 1;
1660 }
1661 }
1662
1663 Token::End => {
1664 let end_span = self.lexer.consume_peeked();
1665 match self.maybe_parse_end()? {
1666 Ok(stmt) => {
1667 if cases.is_empty() {
1668 return Err(Error::Bad(
1669 end_span.pos,
1670 "Expected CASE after SELECT CASE before any statement"
1671 .to_owned(),
1672 ));
1673 }
1674
1675 cases[i].body.push(stmt);
1676 }
1677 Err(Token::Select) => {
1678 end_pos = end_span.pos;
1679 break;
1680 }
1681 Err(token) => {
1682 if cases.is_empty() {
1683 return Err(Error::Bad(
1684 end_span.pos,
1685 "Expected CASE after SELECT CASE before any statement"
1686 .to_owned(),
1687 ));
1688 } else {
1689 return Err(Error::Bad(
1690 end_span.pos,
1691 format!("END {} without {}", token, token),
1692 ));
1693 }
1694 }
1695 }
1696 }
1697
1698 _ => {
1699 if cases.is_empty() {
1700 return Err(Error::Bad(
1701 peeked.pos,
1702 "Expected CASE after SELECT CASE before any statement".to_owned(),
1703 ));
1704 }
1705
1706 if let Some(stmt) = self.parse_one_safe()? {
1707 cases[i].body.push(stmt);
1708 }
1709 }
1710 }
1711 }
1712
1713 self.expect_and_consume_with_pos(Token::Select, select_pos, "SELECT without END SELECT")?;
1714
1715 Ok(Statement::Select(SelectSpan { expr, cases, end_pos }))
1716 }
1717
1718 fn reset_select(&mut self, select_pos: LineCol) -> Result<()> {
1720 loop {
1721 match self.lexer.peek()?.token {
1722 Token::Eof => break,
1723 Token::End => {
1724 self.lexer.consume_peeked();
1725 self.expect_and_consume_with_pos(
1726 Token::Select,
1727 select_pos,
1728 "SELECT without END SELECT",
1729 )?;
1730 break;
1731 }
1732 _ => {
1733 self.lexer.consume_peeked();
1734 }
1735 }
1736 }
1737 self.reset()
1738 }
1739
1740 fn parse_while(&mut self, while_pos: LineCol) -> Result<Statement> {
1742 let expr = self.parse_required_expr("No expression in WHILE statement")?;
1743 self.expect_and_consume(Token::Eol, "Expecting newline after WHILE")?;
1744
1745 let stmts = self.parse_until(Token::Wend)?;
1746 self.expect_and_consume_with_pos(Token::Wend, while_pos, "WHILE without WEND")?;
1747
1748 Ok(Statement::While(WhileSpan { expr, body: stmts }))
1749 }
1750
1751 fn reset_while(&mut self) -> Result<()> {
1753 loop {
1754 match self.lexer.peek()?.token {
1755 Token::Eof => break,
1756 Token::Wend => {
1757 self.lexer.consume_peeked();
1758 break;
1759 }
1760 _ => {
1761 self.lexer.consume_peeked();
1762 }
1763 }
1764 }
1765 self.reset()
1766 }
1767
1768 fn parse_uniline(&mut self) -> Result<Option<Statement>> {
1777 let token_span = self.lexer.read()?;
1778 match token_span.token {
1779 Token::Data => Ok(Some(self.parse_data()?)),
1780 Token::End => Ok(Some(self.parse_end(token_span.pos)?)),
1781 Token::Eof | Token::Eol => Ok(None),
1782 Token::Exit => Ok(Some(self.parse_exit_do(token_span.pos)?)),
1783 Token::Gosub => Ok(Some(self.parse_gosub()?)),
1784 Token::Goto => Ok(Some(self.parse_goto()?)),
1785 Token::On => Ok(Some(self.parse_on()?)),
1786 Token::Return => Ok(Some(Statement::Return(ReturnSpan { pos: token_span.pos }))),
1787 Token::Symbol(vref) => {
1788 let peeked = self.lexer.peek()?;
1789 if peeked.token == Token::Equal {
1790 self.lexer.consume_peeked();
1791 Ok(Some(self.parse_assignment(vref, token_span.pos)?))
1792 } else {
1793 Ok(Some(self.parse_array_or_builtin_call(vref, token_span.pos)?))
1794 }
1795 }
1796 Token::Bad(msg) => Err(Error::Bad(token_span.pos, msg)),
1797 t => Err(Error::Bad(token_span.pos, format!("Unexpected {} in uniline IF branch", t))),
1798 }
1799 }
1800
1801 fn parse_one(&mut self) -> Result<Option<Statement>> {
1806 loop {
1807 match self.lexer.peek()?.token {
1808 Token::Eol => {
1809 self.lexer.consume_peeked();
1810 }
1811 Token::Eof => return Ok(None),
1812 _ => break,
1813 }
1814 }
1815 let token_span = self.lexer.read()?;
1816 let res = match token_span.token {
1817 Token::Data => Ok(Some(self.parse_data()?)),
1818 Token::Dim => Ok(Some(self.parse_dim()?)),
1819 Token::Do => {
1820 let result = self.parse_do(token_span.pos);
1821 if result.is_err() {
1822 self.reset_do()?;
1823 }
1824 Ok(Some(result?))
1825 }
1826 Token::End => Ok(Some(self.parse_end(token_span.pos)?)),
1827 Token::Eof => return Ok(None),
1828 Token::Eol => Ok(None),
1829 Token::Exit => Ok(Some(self.parse_exit_do(token_span.pos)?)),
1830 Token::If => {
1831 let result = self.parse_if(token_span.pos);
1832 if result.is_err() {
1833 self.reset_if(token_span.pos)?;
1834 }
1835 Ok(Some(result?))
1836 }
1837 Token::For => {
1838 let result = self.parse_for(token_span.pos);
1839 if result.is_err() {
1840 self.reset_for()?;
1841 }
1842 Ok(Some(result?))
1843 }
1844 Token::Function => {
1845 let result = self.parse_function(token_span.pos);
1846 if result.is_err() {
1847 self.reset_callable(Token::Function)?;
1848 }
1849 Ok(Some(result?))
1850 }
1851 Token::Gosub => {
1852 let result = self.parse_gosub();
1853 Ok(Some(result?))
1854 }
1855 Token::Goto => {
1856 let result = self.parse_goto();
1857 Ok(Some(result?))
1858 }
1859 Token::Integer(i) => {
1860 let name = format!("{}", i);
1861 return Ok(Some(Statement::Label(LabelSpan { name, name_pos: token_span.pos })));
1864 }
1865 Token::Label(name) => {
1866 return Ok(Some(Statement::Label(LabelSpan { name, name_pos: token_span.pos })));
1869 }
1870 Token::On => Ok(Some(self.parse_on()?)),
1871 Token::Return => Ok(Some(Statement::Return(ReturnSpan { pos: token_span.pos }))),
1872 Token::Select => {
1873 let result = self.parse_select(token_span.pos);
1874 if result.is_err() {
1875 self.reset_select(token_span.pos)?;
1876 }
1877 Ok(Some(result?))
1878 }
1879 Token::Sub => {
1880 let result = self.parse_sub(token_span.pos);
1881 if result.is_err() {
1882 self.reset_callable(Token::Sub)?;
1883 }
1884 Ok(Some(result?))
1885 }
1886 Token::Symbol(vref) => {
1887 let peeked = self.lexer.peek()?;
1888 if peeked.token == Token::Equal {
1889 self.lexer.consume_peeked();
1890 Ok(Some(self.parse_assignment(vref, token_span.pos)?))
1891 } else {
1892 Ok(Some(self.parse_array_or_builtin_call(vref, token_span.pos)?))
1893 }
1894 }
1895 Token::While => {
1896 let result = self.parse_while(token_span.pos);
1897 if result.is_err() {
1898 self.reset_while()?;
1899 }
1900 Ok(Some(result?))
1901 }
1902 Token::Bad(msg) => return Err(Error::Bad(token_span.pos, msg)),
1903 t => return Err(Error::Bad(token_span.pos, format!("Unexpected {} in statement", t))),
1904 };
1905
1906 let token_span = self.lexer.peek()?;
1907 match token_span.token {
1908 Token::Eof => (),
1909 Token::Eol => {
1910 self.lexer.consume_peeked();
1911 }
1912 _ => {
1913 return Err(Error::Bad(
1914 token_span.pos,
1915 format!("Expected newline but found {}", token_span.token),
1916 ))
1917 }
1918 };
1919
1920 res
1921 }
1922
1923 fn reset(&mut self) -> Result<()> {
1925 loop {
1926 match self.lexer.peek()?.token {
1927 Token::Eof => break,
1928 Token::Eol => {
1929 self.lexer.consume_peeked();
1930 break;
1931 }
1932 _ => {
1933 self.lexer.consume_peeked();
1934 }
1935 }
1936 }
1937 Ok(())
1938 }
1939
1940 fn parse_one_safe(&mut self) -> Result<Option<Statement>> {
1944 let result = self.parse_one();
1945 if result.is_err() {
1946 self.reset()?;
1947 }
1948 result
1949 }
1950}
1951
1952pub fn parse(input: &mut dyn io::Read) -> Result<Vec<Statement>> {
1954 let mut parser = Parser::from(input);
1955 let mut statements = vec![];
1956 while let Some(statement) = parser.parse_one_safe()? {
1957 statements.push(statement);
1958 }
1959 Ok(statements)
1960}
1961
1962#[cfg(test)]
1963mod tests {
1964 use super::*;
1965 use crate::ast::ExprType;
1966
1967 fn lc(line: usize, col: usize) -> LineCol {
1969 LineCol { line, col }
1970 }
1971
1972 fn expr_boolean(value: bool, line: usize, col: usize) -> Expr {
1974 Expr::Boolean(BooleanSpan { value, pos: LineCol { line, col } })
1975 }
1976
1977 fn expr_double(value: f64, line: usize, col: usize) -> Expr {
1979 Expr::Double(DoubleSpan { value, pos: LineCol { line, col } })
1980 }
1981
1982 fn expr_integer(value: i32, line: usize, col: usize) -> Expr {
1984 Expr::Integer(IntegerSpan { value, pos: LineCol { line, col } })
1985 }
1986
1987 fn expr_text<S: Into<String>>(value: S, line: usize, col: usize) -> Expr {
1989 Expr::Text(TextSpan { value: value.into(), pos: LineCol { line, col } })
1990 }
1991
1992 fn expr_symbol(vref: VarRef, line: usize, col: usize) -> Expr {
1994 Expr::Symbol(SymbolSpan { vref, pos: LineCol { line, col } })
1995 }
1996
1997 #[test]
1998 fn test_varref_to_unannotated_string() {
1999 assert_eq!(
2000 "print",
2001 &vref_to_unannotated_string(VarRef::new("print", None), LineCol { line: 0, col: 0 })
2002 .unwrap()
2003 );
2004
2005 assert_eq!(
2006 "7:6: Type annotation not allowed in print$",
2007 format!(
2008 "{}",
2009 &vref_to_unannotated_string(
2010 VarRef::new("print", Some(ExprType::Text)),
2011 LineCol { line: 7, col: 6 }
2012 )
2013 .unwrap_err()
2014 )
2015 );
2016 }
2017
2018 fn do_ok_test(input: &str, exp_statements: &[Statement]) {
2021 let mut input = input.as_bytes();
2022 let statements = parse(&mut input).expect("Parsing failed");
2023 assert_eq!(exp_statements, statements.as_slice());
2024 }
2025
2026 fn do_error_test(input: &str, expected_err: &str) {
2028 let mut input = input.as_bytes();
2029 let mut parser = Parser::from(&mut input);
2030 assert_eq!(
2031 expected_err,
2032 format!("{}", parser.parse_one_safe().expect_err("Parsing did not fail"))
2033 );
2034 assert!(parser.parse_one_safe().unwrap().is_none());
2035 }
2036
2037 fn do_error_test_no_reset(input: &str, expected_err: &str) {
2043 let mut input = input.as_bytes();
2044 assert_eq!(
2045 expected_err,
2046 format!("{}", parse(&mut input).expect_err("Parsing did not fail"))
2047 );
2048 }
2049
2050 #[test]
2051 fn test_empty() {
2052 do_ok_test("", &[]);
2053 }
2054
2055 #[test]
2056 fn test_statement_separators() {
2057 do_ok_test(
2058 "a=1\nb=2:c=3:' A comment: that follows\nd=4",
2059 &[
2060 Statement::Assignment(AssignmentSpan {
2061 vref: VarRef::new("a", None),
2062 vref_pos: lc(1, 1),
2063 expr: expr_integer(1, 1, 3),
2064 }),
2065 Statement::Assignment(AssignmentSpan {
2066 vref: VarRef::new("b", None),
2067 vref_pos: lc(2, 1),
2068 expr: expr_integer(2, 2, 3),
2069 }),
2070 Statement::Assignment(AssignmentSpan {
2071 vref: VarRef::new("c", None),
2072 vref_pos: lc(2, 5),
2073 expr: expr_integer(3, 2, 7),
2074 }),
2075 Statement::Assignment(AssignmentSpan {
2076 vref: VarRef::new("d", None),
2077 vref_pos: lc(3, 1),
2078 expr: expr_integer(4, 3, 3),
2079 }),
2080 ],
2081 );
2082 }
2083
2084 #[test]
2085 fn test_array_assignments() {
2086 do_ok_test(
2087 "a(1)=100\nfoo(2, 3)=\"text\"\nabc$ (5 + z, 6) = TRUE OR FALSE",
2088 &[
2089 Statement::ArrayAssignment(ArrayAssignmentSpan {
2090 vref: VarRef::new("a", None),
2091 vref_pos: lc(1, 1),
2092 subscripts: vec![expr_integer(1, 1, 3)],
2093 expr: expr_integer(100, 1, 6),
2094 }),
2095 Statement::ArrayAssignment(ArrayAssignmentSpan {
2096 vref: VarRef::new("foo", None),
2097 vref_pos: lc(2, 1),
2098 subscripts: vec![expr_integer(2, 2, 5), expr_integer(3, 2, 8)],
2099 expr: expr_text("text", 2, 11),
2100 }),
2101 Statement::ArrayAssignment(ArrayAssignmentSpan {
2102 vref: VarRef::new("abc", Some(ExprType::Text)),
2103 vref_pos: lc(3, 1),
2104 subscripts: vec![
2105 Expr::Add(Box::from(BinaryOpSpan {
2106 lhs: expr_integer(5, 3, 7),
2107 rhs: expr_symbol(VarRef::new("z".to_owned(), None), 3, 11),
2108 pos: lc(3, 9),
2109 })),
2110 expr_integer(6, 3, 14),
2111 ],
2112 expr: Expr::Or(Box::from(BinaryOpSpan {
2113 lhs: expr_boolean(true, 3, 19),
2114 rhs: expr_boolean(false, 3, 27),
2115 pos: lc(3, 24),
2116 })),
2117 }),
2118 ],
2119 );
2120 }
2121
2122 #[test]
2123 fn test_array_assignment_errors() {
2124 do_error_test("a(", "1:3: Unexpected <<EOF>>");
2125 do_error_test("a()", "1:2: Expected expression");
2126 do_error_test("a() =", "1:6: Missing expression in array assignment");
2127 do_error_test("a() IF", "1:2: Expected expression");
2128 do_error_test("a() = 3 4", "1:9: Unexpected value in expression");
2129 do_error_test("a() = 3 THEN", "1:9: Unexpected THEN in array assignment");
2130 do_error_test("a(,) = 3", "1:3: Missing expression");
2131 do_error_test("a(2;3) = 3", "1:4: Unexpected ;");
2132 do_error_test("(2) = 3", "1:1: Unexpected ( in statement");
2133 }
2134
2135 #[test]
2136 fn test_assignments() {
2137 do_ok_test(
2138 "a=1\nfoo$ = \"bar\"\nb$ = 3 + z",
2139 &[
2140 Statement::Assignment(AssignmentSpan {
2141 vref: VarRef::new("a", None),
2142 vref_pos: lc(1, 1),
2143 expr: expr_integer(1, 1, 3),
2144 }),
2145 Statement::Assignment(AssignmentSpan {
2146 vref: VarRef::new("foo", Some(ExprType::Text)),
2147 vref_pos: lc(2, 1),
2148 expr: expr_text("bar", 2, 8),
2149 }),
2150 Statement::Assignment(AssignmentSpan {
2151 vref: VarRef::new("b", Some(ExprType::Text)),
2152 vref_pos: lc(3, 1),
2153 expr: Expr::Add(Box::from(BinaryOpSpan {
2154 lhs: expr_integer(3, 3, 6),
2155 rhs: expr_symbol(VarRef::new("z", None), 3, 10),
2156 pos: lc(3, 8),
2157 })),
2158 }),
2159 ],
2160 );
2161 }
2162
2163 #[test]
2164 fn test_assignment_errors() {
2165 do_error_test("a =", "1:4: Missing expression in assignment");
2166 do_error_test("a = b 3", "1:7: Unexpected value in expression");
2167 do_error_test("a = b, 3", "1:6: Unexpected , in assignment");
2168 do_error_test("a = if 3", "1:5: Unexpected keyword in expression");
2169 do_error_test("true = 1", "1:1: Unexpected TRUE in statement");
2170 }
2171
2172 #[test]
2173 fn test_builtin_calls() {
2174 do_ok_test(
2175 "PRINT a\nPRINT ; 3 , c$\nNOARGS\nNAME 3 AS 4",
2176 &[
2177 Statement::Call(CallSpan {
2178 vref: VarRef::new("PRINT", None),
2179 vref_pos: lc(1, 1),
2180 args: vec![ArgSpan {
2181 expr: Some(expr_symbol(VarRef::new("a", None), 1, 7)),
2182 sep: ArgSep::End,
2183 sep_pos: lc(1, 8),
2184 }],
2185 }),
2186 Statement::Call(CallSpan {
2187 vref: VarRef::new("PRINT", None),
2188 vref_pos: lc(2, 1),
2189 args: vec![
2190 ArgSpan { expr: None, sep: ArgSep::Short, sep_pos: lc(2, 7) },
2191 ArgSpan {
2192 expr: Some(expr_integer(3, 2, 9)),
2193 sep: ArgSep::Long,
2194 sep_pos: lc(2, 11),
2195 },
2196 ArgSpan {
2197 expr: Some(expr_symbol(VarRef::new("c", Some(ExprType::Text)), 2, 13)),
2198 sep: ArgSep::End,
2199 sep_pos: lc(2, 15),
2200 },
2201 ],
2202 }),
2203 Statement::Call(CallSpan {
2204 vref: VarRef::new("NOARGS", None),
2205 vref_pos: lc(3, 1),
2206 args: vec![],
2207 }),
2208 Statement::Call(CallSpan {
2209 vref: VarRef::new("NAME", None),
2210 vref_pos: lc(4, 1),
2211 args: vec![
2212 ArgSpan {
2213 expr: Some(expr_integer(3, 4, 6)),
2214 sep: ArgSep::As,
2215 sep_pos: lc(4, 8),
2216 },
2217 ArgSpan {
2218 expr: Some(expr_integer(4, 4, 11)),
2219 sep: ArgSep::End,
2220 sep_pos: lc(4, 12),
2221 },
2222 ],
2223 }),
2224 ],
2225 );
2226 }
2227
2228 #[test]
2229 fn test_builtin_calls_and_array_references_disambiguation() {
2230 use Expr::*;
2231
2232 do_ok_test(
2233 "PRINT(1)",
2234 &[Statement::Call(CallSpan {
2235 vref: VarRef::new("PRINT", None),
2236 vref_pos: lc(1, 1),
2237 args: vec![ArgSpan {
2238 expr: Some(expr_integer(1, 1, 7)),
2239 sep: ArgSep::End,
2240 sep_pos: lc(1, 9),
2241 }],
2242 })],
2243 );
2244
2245 do_ok_test(
2246 "PRINT(1), 2",
2247 &[Statement::Call(CallSpan {
2248 vref: VarRef::new("PRINT", None),
2249 vref_pos: lc(1, 1),
2250 args: vec![
2251 ArgSpan {
2252 expr: Some(expr_integer(1, 1, 7)),
2253 sep: ArgSep::Long,
2254 sep_pos: lc(1, 9),
2255 },
2256 ArgSpan {
2257 expr: Some(expr_integer(2, 1, 11)),
2258 sep: ArgSep::End,
2259 sep_pos: lc(1, 12),
2260 },
2261 ],
2262 })],
2263 );
2264
2265 do_ok_test(
2266 "PRINT(1); 2",
2267 &[Statement::Call(CallSpan {
2268 vref: VarRef::new("PRINT", None),
2269 vref_pos: lc(1, 1),
2270 args: vec![
2271 ArgSpan {
2272 expr: Some(expr_integer(1, 1, 7)),
2273 sep: ArgSep::Short,
2274 sep_pos: lc(1, 9),
2275 },
2276 ArgSpan {
2277 expr: Some(expr_integer(2, 1, 11)),
2278 sep: ArgSep::End,
2279 sep_pos: lc(1, 12),
2280 },
2281 ],
2282 })],
2283 );
2284
2285 do_ok_test(
2286 "PRINT(1);",
2287 &[Statement::Call(CallSpan {
2288 vref: VarRef::new("PRINT", None),
2289 vref_pos: lc(1, 1),
2290 args: vec![
2291 ArgSpan {
2292 expr: Some(expr_integer(1, 1, 7)),
2293 sep: ArgSep::Short,
2294 sep_pos: lc(1, 9),
2295 },
2296 ArgSpan { expr: None, sep: ArgSep::End, sep_pos: lc(1, 10) },
2297 ],
2298 })],
2299 );
2300
2301 do_ok_test(
2302 "PRINT(1) + 2; 3",
2303 &[Statement::Call(CallSpan {
2304 vref: VarRef::new("PRINT", None),
2305 vref_pos: lc(1, 1),
2306 args: vec![
2307 ArgSpan {
2308 expr: Some(Add(Box::from(BinaryOpSpan {
2309 lhs: expr_integer(1, 1, 7),
2310 rhs: expr_integer(2, 1, 12),
2311 pos: lc(1, 10),
2312 }))),
2313 sep: ArgSep::Short,
2314 sep_pos: lc(1, 13),
2315 },
2316 ArgSpan {
2317 expr: Some(expr_integer(3, 1, 15)),
2318 sep: ArgSep::End,
2319 sep_pos: lc(1, 16),
2320 },
2321 ],
2322 })],
2323 );
2324 }
2325
2326 #[test]
2327 fn test_builtin_calls_errors() {
2328 do_error_test("FOO 3 5\n", "1:7: Unexpected value in expression");
2329 do_error_test("INPUT$ a\n", "1:1: Type annotation not allowed in INPUT$");
2330 do_error_test("PRINT IF 1\n", "1:7: Unexpected keyword in expression");
2331 do_error_test("PRINT 3, IF 1\n", "1:10: Unexpected keyword in expression");
2332 do_error_test("PRINT 3 THEN\n", "1:9: Expected comma, semicolon, or end of statement");
2333 do_error_test("PRINT ()\n", "1:7: Expected expression");
2334 do_error_test("PRINT (2, 3)\n", "1:7: Expected expression");
2335 do_error_test("PRINT (2, 3); 4\n", "1:7: Expected expression");
2336 }
2337
2338 #[test]
2339 fn test_data() {
2340 do_ok_test("DATA", &[Statement::Data(DataSpan { values: vec![None] })]);
2341
2342 do_ok_test("DATA , ", &[Statement::Data(DataSpan { values: vec![None, None] })]);
2343 do_ok_test(
2344 "DATA , , ,",
2345 &[Statement::Data(DataSpan { values: vec![None, None, None, None] })],
2346 );
2347
2348 do_ok_test(
2349 "DATA 1: DATA 2",
2350 &[
2351 Statement::Data(DataSpan { values: vec![Some(Value::Integer(1))] }),
2352 Statement::Data(DataSpan { values: vec![Some(Value::Integer(2))] }),
2353 ],
2354 );
2355
2356 do_ok_test(
2357 "DATA TRUE, -3, 5.1, \"foo\"",
2358 &[Statement::Data(DataSpan {
2359 values: vec![
2360 Some(Value::Boolean(true)),
2361 Some(Value::Integer(-3)),
2362 Some(Value::Double(5.1)),
2363 Some(Value::Text("foo".to_owned())),
2364 ],
2365 })],
2366 );
2367
2368 do_ok_test(
2369 "DATA , TRUE, , 3, , 5.1, , \"foo\",",
2370 &[Statement::Data(DataSpan {
2371 values: vec![
2372 None,
2373 Some(Value::Boolean(true)),
2374 None,
2375 Some(Value::Integer(3)),
2376 None,
2377 Some(Value::Double(5.1)),
2378 None,
2379 Some(Value::Text("foo".to_owned())),
2380 None,
2381 ],
2382 })],
2383 );
2384
2385 do_ok_test(
2386 "DATA -3, -5.1",
2387 &[Statement::Data(DataSpan {
2388 values: vec![Some(Value::Integer(-3)), Some(Value::Double(-5.1))],
2389 })],
2390 );
2391 }
2392
2393 #[test]
2394 fn test_data_errors() {
2395 do_error_test("DATA + 2", "1:6: Unexpected + in DATA statement");
2396 do_error_test("DATA ;", "1:6: Unexpected ; in DATA statement");
2397 do_error_test("DATA 5 + 1", "1:8: Expected comma after datum but found +");
2398 do_error_test("DATA 5 ; 1", "1:8: Expected comma after datum but found ;");
2399 do_error_test("DATA -FALSE", "1:7: Expected number after -");
2400 do_error_test("DATA -\"abc\"", "1:7: Expected number after -");
2401 do_error_test("DATA -foo", "1:7: Expected number after -");
2402 }
2403
2404 #[test]
2405 fn test_dim_default_type() {
2406 do_ok_test(
2407 "DIM i",
2408 &[Statement::Dim(DimSpan {
2409 name: "i".to_owned(),
2410 name_pos: lc(1, 5),
2411 shared: false,
2412 vtype: ExprType::Integer,
2413 vtype_pos: lc(1, 6),
2414 })],
2415 );
2416 }
2417
2418 #[test]
2419 fn test_dim_as_simple_types() {
2420 do_ok_test(
2421 "DIM i AS BOOLEAN",
2422 &[Statement::Dim(DimSpan {
2423 name: "i".to_owned(),
2424 name_pos: lc(1, 5),
2425 shared: false,
2426 vtype: ExprType::Boolean,
2427 vtype_pos: lc(1, 10),
2428 })],
2429 );
2430 do_ok_test(
2431 "DIM i AS DOUBLE",
2432 &[Statement::Dim(DimSpan {
2433 name: "i".to_owned(),
2434 name_pos: lc(1, 5),
2435 shared: false,
2436 vtype: ExprType::Double,
2437 vtype_pos: lc(1, 10),
2438 })],
2439 );
2440 do_ok_test(
2441 "DIM i AS INTEGER",
2442 &[Statement::Dim(DimSpan {
2443 name: "i".to_owned(),
2444 name_pos: lc(1, 5),
2445 shared: false,
2446 vtype: ExprType::Integer,
2447 vtype_pos: lc(1, 10),
2448 })],
2449 );
2450 do_ok_test(
2451 "DIM i AS STRING",
2452 &[Statement::Dim(DimSpan {
2453 name: "i".to_owned(),
2454 name_pos: lc(1, 5),
2455 shared: false,
2456 vtype: ExprType::Text,
2457 vtype_pos: lc(1, 10),
2458 })],
2459 );
2460 }
2461
2462 #[test]
2463 fn test_dim_consecutive() {
2464 do_ok_test(
2465 "DIM i\nDIM j AS BOOLEAN\nDIM k",
2466 &[
2467 Statement::Dim(DimSpan {
2468 name: "i".to_owned(),
2469 name_pos: lc(1, 5),
2470 shared: false,
2471 vtype: ExprType::Integer,
2472 vtype_pos: lc(1, 6),
2473 }),
2474 Statement::Dim(DimSpan {
2475 name: "j".to_owned(),
2476 name_pos: lc(2, 5),
2477 shared: false,
2478 vtype: ExprType::Boolean,
2479 vtype_pos: lc(2, 10),
2480 }),
2481 Statement::Dim(DimSpan {
2482 name: "k".to_owned(),
2483 name_pos: lc(3, 5),
2484 shared: false,
2485 vtype: ExprType::Integer,
2486 vtype_pos: lc(3, 6),
2487 }),
2488 ],
2489 );
2490 }
2491
2492 #[test]
2493 fn test_dim_shared() {
2494 do_ok_test(
2495 "DIM SHARED i",
2496 &[Statement::Dim(DimSpan {
2497 name: "i".to_owned(),
2498 name_pos: lc(1, 12),
2499 shared: true,
2500 vtype: ExprType::Integer,
2501 vtype_pos: lc(1, 13),
2502 })],
2503 );
2504 do_ok_test(
2505 "DIM SHARED i AS BOOLEAN",
2506 &[Statement::Dim(DimSpan {
2507 name: "i".to_owned(),
2508 name_pos: lc(1, 12),
2509 shared: true,
2510 vtype: ExprType::Boolean,
2511 vtype_pos: lc(1, 17),
2512 })],
2513 );
2514 }
2515
2516 #[test]
2517 fn test_dim_array() {
2518 use Expr::*;
2519
2520 do_ok_test(
2521 "DIM i(10)",
2522 &[Statement::DimArray(DimArraySpan {
2523 name: "i".to_owned(),
2524 name_pos: lc(1, 5),
2525 shared: false,
2526 dimensions: vec![expr_integer(10, 1, 7)],
2527 subtype: ExprType::Integer,
2528 subtype_pos: lc(1, 10),
2529 })],
2530 );
2531
2532 do_ok_test(
2533 "DIM foo(-5, 0) AS STRING",
2534 &[Statement::DimArray(DimArraySpan {
2535 name: "foo".to_owned(),
2536 name_pos: lc(1, 5),
2537 shared: false,
2538 dimensions: vec![
2539 Negate(Box::from(UnaryOpSpan { expr: expr_integer(5, 1, 10), pos: lc(1, 9) })),
2540 expr_integer(0, 1, 13),
2541 ],
2542 subtype: ExprType::Text,
2543 subtype_pos: lc(1, 19),
2544 })],
2545 );
2546
2547 do_ok_test(
2548 "DIM foo(bar$() + 3, 8, -1)",
2549 &[Statement::DimArray(DimArraySpan {
2550 name: "foo".to_owned(),
2551 name_pos: lc(1, 5),
2552 shared: false,
2553 dimensions: vec![
2554 Add(Box::from(BinaryOpSpan {
2555 lhs: Call(CallSpan {
2556 vref: VarRef::new("bar", Some(ExprType::Text)),
2557 vref_pos: lc(1, 9),
2558 args: vec![],
2559 }),
2560 rhs: expr_integer(3, 1, 18),
2561 pos: lc(1, 16),
2562 })),
2563 expr_integer(8, 1, 21),
2564 Negate(Box::from(UnaryOpSpan { expr: expr_integer(1, 1, 25), pos: lc(1, 24) })),
2565 ],
2566 subtype: ExprType::Integer,
2567 subtype_pos: lc(1, 27),
2568 })],
2569 );
2570
2571 do_ok_test(
2572 "DIM SHARED i(10)",
2573 &[Statement::DimArray(DimArraySpan {
2574 name: "i".to_owned(),
2575 name_pos: lc(1, 12),
2576 shared: true,
2577 dimensions: vec![expr_integer(10, 1, 14)],
2578 subtype: ExprType::Integer,
2579 subtype_pos: lc(1, 17),
2580 })],
2581 );
2582 }
2583
2584 #[test]
2585 fn test_dim_errors() {
2586 do_error_test("DIM", "1:4: Expected variable name after DIM");
2587 do_error_test("DIM 3", "1:5: Expected variable name after DIM");
2588 do_error_test("DIM AS", "1:5: Expected variable name after DIM");
2589 do_error_test("DIM foo 3", "1:9: Expected AS or end of statement");
2590 do_error_test("DIM a AS", "1:9: Invalid type name <<EOF>> in AS type definition");
2591 do_error_test("DIM a$ AS", "1:5: Type annotation not allowed in a$");
2592 do_error_test("DIM a AS 3", "1:10: Invalid type name 3 in AS type definition");
2593 do_error_test("DIM a AS INTEGER 3", "1:18: Unexpected 3 in DIM statement");
2594
2595 do_error_test("DIM a()", "1:6: Arrays require at least one dimension");
2596 do_error_test("DIM a(,)", "1:7: Missing expression");
2597 do_error_test("DIM a(, 3)", "1:7: Missing expression");
2598 do_error_test("DIM a(3, )", "1:10: Missing expression");
2599 do_error_test("DIM a(3, , 4)", "1:10: Missing expression");
2600 do_error_test("DIM a(1) AS INTEGER 3", "1:21: Unexpected 3 in DIM statement");
2601 }
2602
2603 #[test]
2604 fn test_do_until_empty() {
2605 do_ok_test(
2606 "DO UNTIL TRUE\nLOOP",
2607 &[Statement::Do(DoSpan {
2608 guard: DoGuard::PreUntil(expr_boolean(true, 1, 10)),
2609 body: vec![],
2610 })],
2611 );
2612
2613 do_ok_test(
2614 "DO UNTIL FALSE\nREM foo\nLOOP",
2615 &[Statement::Do(DoSpan {
2616 guard: DoGuard::PreUntil(expr_boolean(false, 1, 10)),
2617 body: vec![],
2618 })],
2619 );
2620 }
2621
2622 #[test]
2623 fn test_do_infinite_empty() {
2624 do_ok_test("DO\nLOOP", &[Statement::Do(DoSpan { guard: DoGuard::Infinite, body: vec![] })]);
2625 }
2626
2627 #[test]
2628 fn test_do_pre_until_loops() {
2629 do_ok_test(
2630 "DO UNTIL TRUE\nA\nB\nLOOP",
2631 &[Statement::Do(DoSpan {
2632 guard: DoGuard::PreUntil(expr_boolean(true, 1, 10)),
2633 body: vec![make_bare_builtin_call("A", 2, 1), make_bare_builtin_call("B", 3, 1)],
2634 })],
2635 );
2636 }
2637
2638 #[test]
2639 fn test_do_pre_while_loops() {
2640 do_ok_test(
2641 "DO WHILE TRUE\nA\nB\nLOOP",
2642 &[Statement::Do(DoSpan {
2643 guard: DoGuard::PreWhile(expr_boolean(true, 1, 10)),
2644 body: vec![make_bare_builtin_call("A", 2, 1), make_bare_builtin_call("B", 3, 1)],
2645 })],
2646 );
2647 }
2648
2649 #[test]
2650 fn test_do_post_until_loops() {
2651 do_ok_test(
2652 "DO\nA\nB\nLOOP UNTIL TRUE",
2653 &[Statement::Do(DoSpan {
2654 guard: DoGuard::PostUntil(expr_boolean(true, 4, 12)),
2655
2656 body: vec![make_bare_builtin_call("A", 2, 1), make_bare_builtin_call("B", 3, 1)],
2657 })],
2658 );
2659 }
2660
2661 #[test]
2662 fn test_do_post_while_loops() {
2663 do_ok_test(
2664 "DO\nA\nB\nLOOP WHILE FALSE",
2665 &[Statement::Do(DoSpan {
2666 guard: DoGuard::PostWhile(expr_boolean(false, 4, 12)),
2667 body: vec![make_bare_builtin_call("A", 2, 1), make_bare_builtin_call("B", 3, 1)],
2668 })],
2669 );
2670 }
2671
2672 #[test]
2673 fn test_do_nested() {
2674 let code = r#"
2675 DO WHILE TRUE
2676 A
2677 DO
2678 B
2679 LOOP UNTIL FALSE
2680 C
2681 LOOP
2682 "#;
2683 do_ok_test(
2684 code,
2685 &[Statement::Do(DoSpan {
2686 guard: DoGuard::PreWhile(expr_boolean(true, 2, 22)),
2687 body: vec![
2688 make_bare_builtin_call("A", 3, 17),
2689 Statement::Do(DoSpan {
2690 guard: DoGuard::PostUntil(expr_boolean(false, 6, 28)),
2691 body: vec![make_bare_builtin_call("B", 5, 21)],
2692 }),
2693 make_bare_builtin_call("C", 7, 17),
2694 ],
2695 })],
2696 );
2697 }
2698
2699 #[test]
2700 fn test_do_errors() {
2701 do_error_test("DO\n", "1:1: DO without LOOP");
2702 do_error_test("DO FOR\n", "1:4: Expecting newline, UNTIL or WHILE after DO");
2703
2704 do_error_test("\n\nDO UNTIL TRUE\n", "3:1: DO without LOOP");
2705 do_error_test("\n\nDO WHILE TRUE\n", "3:1: DO without LOOP");
2706 do_error_test("DO UNTIL TRUE\nEND", "1:1: DO without LOOP");
2707 do_error_test("DO WHILE TRUE\nEND", "1:1: DO without LOOP");
2708 do_error_test("DO UNTIL TRUE\nEND\n", "1:1: DO without LOOP");
2709 do_error_test("DO WHILE TRUE\nEND\n", "1:1: DO without LOOP");
2710 do_error_test("DO UNTIL TRUE\nEND WHILE\n", "2:5: Unexpected keyword in expression");
2711 do_error_test("DO WHILE TRUE\nEND WHILE\n", "2:5: Unexpected keyword in expression");
2712
2713 do_error_test("DO UNTIL\n", "1:9: No expression in UNTIL clause");
2714 do_error_test("DO WHILE\n", "1:9: No expression in WHILE clause");
2715 do_error_test("DO UNTIL TRUE", "1:14: Expecting newline after DO");
2716 do_error_test("DO WHILE TRUE", "1:14: Expecting newline after DO");
2717
2718 do_error_test("DO\nLOOP UNTIL", "2:11: No expression in UNTIL clause");
2719 do_error_test("DO\nLOOP WHILE\n", "2:11: No expression in WHILE clause");
2720
2721 do_error_test("DO UNTIL ,\nLOOP", "1:10: No expression in UNTIL clause");
2722 do_error_test("DO WHILE ,\nLOOP", "1:10: No expression in WHILE clause");
2723
2724 do_error_test("DO\nLOOP UNTIL ,\n", "2:12: No expression in UNTIL clause");
2725 do_error_test("DO\nLOOP WHILE ,\n", "2:12: No expression in WHILE clause");
2726
2727 do_error_test(
2728 "DO WHILE TRUE\nLOOP UNTIL FALSE",
2729 "1:1: DO loop cannot have pre and post guards at the same time",
2730 );
2731 }
2732
2733 #[test]
2734 fn test_exit_do() {
2735 do_ok_test(" EXIT DO", &[Statement::ExitDo(ExitDoSpan { pos: lc(1, 3) })]);
2736 }
2737
2738 #[test]
2739 fn test_exit_do_errors() {
2740 do_error_test("EXIT", "1:5: Expecting DO after EXIT");
2741 do_error_test("EXIT 5", "1:6: Expecting DO after EXIT");
2742 }
2743
2744 fn do_expr_ok_test(input: &str, expr: Expr) {
2748 do_ok_test(
2749 &format!("PRINT {}, 1", input),
2750 &[Statement::Call(CallSpan {
2751 vref: VarRef::new("PRINT", None),
2752 vref_pos: lc(1, 1),
2753 args: vec![
2754 ArgSpan {
2755 expr: Some(expr),
2756 sep: ArgSep::Long,
2757 sep_pos: lc(1, 7 + input.len()),
2758 },
2759 ArgSpan {
2760 expr: Some(expr_integer(1, 1, 6 + input.len() + 3)),
2761 sep: ArgSep::End,
2762 sep_pos: lc(1, 10 + input.len()),
2763 },
2764 ],
2765 })],
2766 );
2767 }
2768
2769 fn do_expr_error_test(input: &str, msg: &str) {
2773 do_error_test(&format!("PRINT {}, 1", input), msg)
2774 }
2775
2776 #[test]
2777 fn test_expr_literals() {
2778 do_expr_ok_test("TRUE", expr_boolean(true, 1, 7));
2779 do_expr_ok_test("FALSE", expr_boolean(false, 1, 7));
2780 do_expr_ok_test("5", expr_integer(5, 1, 7));
2781 do_expr_ok_test("\"some text\"", expr_text("some text", 1, 7));
2782 }
2783
2784 #[test]
2785 fn test_expr_symbols() {
2786 do_expr_ok_test("foo", expr_symbol(VarRef::new("foo", None), 1, 7));
2787 do_expr_ok_test("bar$", expr_symbol(VarRef::new("bar", Some(ExprType::Text)), 1, 7));
2788 }
2789
2790 #[test]
2791 fn test_expr_parens() {
2792 use Expr::*;
2793 do_expr_ok_test("(1)", expr_integer(1, 1, 8));
2794 do_expr_ok_test("((1))", expr_integer(1, 1, 9));
2795 do_expr_ok_test(" ( ( 1 ) ) ", expr_integer(1, 1, 12));
2796 do_expr_ok_test(
2797 "3 * (2 + 5)",
2798 Multiply(Box::from(BinaryOpSpan {
2799 lhs: expr_integer(3, 1, 7),
2800 rhs: Add(Box::from(BinaryOpSpan {
2801 lhs: expr_integer(2, 1, 12),
2802 rhs: expr_integer(5, 1, 16),
2803 pos: lc(1, 14),
2804 })),
2805 pos: lc(1, 9),
2806 })),
2807 );
2808 do_expr_ok_test(
2809 "(7) - (1) + (-2)",
2810 Add(Box::from(BinaryOpSpan {
2811 lhs: Subtract(Box::from(BinaryOpSpan {
2812 lhs: expr_integer(7, 1, 8),
2813 rhs: expr_integer(1, 1, 14),
2814 pos: lc(1, 11),
2815 })),
2816 rhs: Negate(Box::from(UnaryOpSpan {
2817 expr: expr_integer(2, 1, 21),
2818 pos: lc(1, 20),
2819 })),
2820 pos: lc(1, 17),
2821 })),
2822 );
2823 }
2824
2825 #[test]
2826 fn test_expr_arith_ops() {
2827 use Expr::*;
2828 let span = Box::from(BinaryOpSpan {
2829 lhs: expr_integer(1, 1, 7),
2830 rhs: expr_integer(2, 1, 11),
2831 pos: lc(1, 9),
2832 });
2833 do_expr_ok_test("1 + 2", Add(span.clone()));
2834 do_expr_ok_test("1 - 2", Subtract(span.clone()));
2835 do_expr_ok_test("1 * 2", Multiply(span.clone()));
2836 do_expr_ok_test("1 / 2", Divide(span.clone()));
2837 do_expr_ok_test("1 ^ 2", Power(span));
2838 let span = Box::from(BinaryOpSpan {
2839 lhs: expr_integer(1, 1, 7),
2840 rhs: expr_integer(2, 1, 13),
2841 pos: lc(1, 9),
2842 });
2843 do_expr_ok_test("1 MOD 2", Modulo(span));
2844 }
2845
2846 #[test]
2847 fn test_expr_rel_ops() {
2848 use Expr::*;
2849 let span1 = Box::from(BinaryOpSpan {
2850 lhs: expr_integer(1, 1, 7),
2851 rhs: expr_integer(2, 1, 11),
2852 pos: lc(1, 9),
2853 });
2854 let span2 = Box::from(BinaryOpSpan {
2855 lhs: expr_integer(1, 1, 7),
2856 rhs: expr_integer(2, 1, 12),
2857 pos: lc(1, 9),
2858 });
2859 do_expr_ok_test("1 = 2", Equal(span1.clone()));
2860 do_expr_ok_test("1 <> 2", NotEqual(span2.clone()));
2861 do_expr_ok_test("1 < 2", Less(span1.clone()));
2862 do_expr_ok_test("1 <= 2", LessEqual(span2.clone()));
2863 do_expr_ok_test("1 > 2", Greater(span1));
2864 do_expr_ok_test("1 >= 2", GreaterEqual(span2));
2865 }
2866
2867 #[test]
2868 fn test_expr_logical_ops() {
2869 use Expr::*;
2870 do_expr_ok_test(
2871 "1 AND 2",
2872 And(Box::from(BinaryOpSpan {
2873 lhs: expr_integer(1, 1, 7),
2874 rhs: expr_integer(2, 1, 13),
2875 pos: lc(1, 9),
2876 })),
2877 );
2878 do_expr_ok_test(
2879 "1 OR 2",
2880 Or(Box::from(BinaryOpSpan {
2881 lhs: expr_integer(1, 1, 7),
2882 rhs: expr_integer(2, 1, 12),
2883 pos: lc(1, 9),
2884 })),
2885 );
2886 do_expr_ok_test(
2887 "1 XOR 2",
2888 Xor(Box::from(BinaryOpSpan {
2889 lhs: expr_integer(1, 1, 7),
2890 rhs: expr_integer(2, 1, 13),
2891 pos: lc(1, 9),
2892 })),
2893 );
2894 }
2895
2896 #[test]
2897 fn test_expr_logical_ops_not() {
2898 use Expr::*;
2899 do_expr_ok_test(
2900 "NOT TRUE",
2901 Not(Box::from(UnaryOpSpan { expr: expr_boolean(true, 1, 11), pos: lc(1, 7) })),
2902 );
2903 do_expr_ok_test(
2904 "NOT 6",
2905 Not(Box::from(UnaryOpSpan { expr: expr_integer(6, 1, 11), pos: lc(1, 7) })),
2906 );
2907 do_expr_ok_test(
2908 "NOT NOT TRUE",
2909 Not(Box::from(UnaryOpSpan {
2910 expr: Not(Box::from(UnaryOpSpan {
2911 expr: expr_boolean(true, 1, 15),
2912 pos: lc(1, 11),
2913 })),
2914 pos: lc(1, 7),
2915 })),
2916 );
2917 do_expr_ok_test(
2918 "1 - NOT 4",
2919 Subtract(Box::from(BinaryOpSpan {
2920 lhs: expr_integer(1, 1, 7),
2921 rhs: Not(Box::from(UnaryOpSpan { expr: expr_integer(4, 1, 15), pos: lc(1, 11) })),
2922 pos: lc(1, 9),
2923 })),
2924 );
2925 }
2926
2927 #[test]
2928 fn test_expr_bitwise_ops() {
2929 use Expr::*;
2930 do_expr_ok_test(
2931 "1 << 2",
2932 ShiftLeft(Box::from(BinaryOpSpan {
2933 lhs: expr_integer(1, 1, 7),
2934 rhs: expr_integer(2, 1, 12),
2935 pos: lc(1, 9),
2936 })),
2937 );
2938 do_expr_ok_test(
2939 "1 >> 2",
2940 ShiftRight(Box::from(BinaryOpSpan {
2941 lhs: expr_integer(1, 1, 7),
2942 rhs: expr_integer(2, 1, 12),
2943 pos: lc(1, 9),
2944 })),
2945 );
2946 }
2947
2948 #[test]
2949 fn test_expr_op_priorities() {
2950 use Expr::*;
2951 do_expr_ok_test(
2952 "3 * (2 + 5) = (3 + 1 = 2 OR 1 = 3 XOR FALSE * \"a\")",
2953 Equal(Box::from(BinaryOpSpan {
2954 lhs: Multiply(Box::from(BinaryOpSpan {
2955 lhs: expr_integer(3, 1, 7),
2956 rhs: Add(Box::from(BinaryOpSpan {
2957 lhs: expr_integer(2, 1, 12),
2958 rhs: expr_integer(5, 1, 16),
2959 pos: lc(1, 14),
2960 })),
2961 pos: lc(1, 9),
2962 })),
2963 rhs: Xor(Box::from(BinaryOpSpan {
2964 lhs: Or(Box::from(BinaryOpSpan {
2965 lhs: Equal(Box::from(BinaryOpSpan {
2966 lhs: Add(Box::from(BinaryOpSpan {
2967 lhs: expr_integer(3, 1, 22),
2968 rhs: expr_integer(1, 1, 26),
2969 pos: lc(1, 24),
2970 })),
2971 rhs: expr_integer(2, 1, 30),
2972 pos: lc(1, 28),
2973 })),
2974 rhs: Equal(Box::from(BinaryOpSpan {
2975 lhs: expr_integer(1, 1, 35),
2976 rhs: expr_integer(3, 1, 39),
2977 pos: lc(1, 37),
2978 })),
2979 pos: lc(1, 32),
2980 })),
2981 rhs: Multiply(Box::from(BinaryOpSpan {
2982 lhs: expr_boolean(false, 1, 45),
2983 rhs: expr_text("a", 1, 53),
2984 pos: lc(1, 51),
2985 })),
2986 pos: lc(1, 41),
2987 })),
2988 pos: lc(1, 19),
2989 })),
2990 );
2991 do_expr_ok_test(
2992 "-1 ^ 3",
2993 Negate(Box::from(UnaryOpSpan {
2994 expr: Power(Box::from(BinaryOpSpan {
2995 lhs: expr_integer(1, 1, 8),
2996 rhs: expr_integer(3, 1, 12),
2997 pos: lc(1, 10),
2998 })),
2999 pos: lc(1, 7),
3000 })),
3001 );
3002 do_expr_ok_test(
3003 "-(1 ^ 3)",
3004 Negate(Box::from(UnaryOpSpan {
3005 expr: Power(Box::from(BinaryOpSpan {
3006 lhs: expr_integer(1, 1, 9),
3007 rhs: expr_integer(3, 1, 13),
3008 pos: lc(1, 11),
3009 })),
3010 pos: lc(1, 7),
3011 })),
3012 );
3013 do_expr_ok_test(
3014 "(-1) ^ 3",
3015 Power(Box::from(BinaryOpSpan {
3016 lhs: Negate(Box::from(UnaryOpSpan { expr: expr_integer(1, 1, 9), pos: lc(1, 8) })),
3017 rhs: expr_integer(3, 1, 14),
3018 pos: lc(1, 12),
3019 })),
3020 );
3021 do_expr_ok_test(
3022 "1 ^ (-3)",
3023 Power(Box::from(BinaryOpSpan {
3024 lhs: expr_integer(1, 1, 7),
3025 rhs: Negate(Box::from(UnaryOpSpan {
3026 expr: expr_integer(3, 1, 13),
3027 pos: lc(1, 12),
3028 })),
3029 pos: lc(1, 9),
3030 })),
3031 );
3032 do_expr_ok_test(
3033 "0 <> 2 >> 1",
3034 NotEqual(Box::from(BinaryOpSpan {
3035 lhs: expr_integer(0, 1, 7),
3036 rhs: ShiftRight(Box::from(BinaryOpSpan {
3037 lhs: expr_integer(2, 1, 12),
3038 rhs: expr_integer(1, 1, 17),
3039 pos: lc(1, 14),
3040 })),
3041 pos: lc(1, 9),
3042 })),
3043 );
3044 }
3045
3046 #[test]
3047 fn test_expr_numeric_signs() {
3048 use Expr::*;
3049
3050 do_expr_ok_test(
3051 "-a",
3052 Negate(Box::from(UnaryOpSpan {
3053 expr: expr_symbol(VarRef::new("a", None), 1, 8),
3054 pos: lc(1, 7),
3055 })),
3056 );
3057
3058 do_expr_ok_test(
3059 "1 - -3",
3060 Subtract(Box::from(BinaryOpSpan {
3061 lhs: expr_integer(1, 1, 7),
3062 rhs: Negate(Box::from(UnaryOpSpan {
3063 expr: expr_integer(3, 1, 12),
3064 pos: lc(1, 11),
3065 })),
3066 pos: lc(1, 9),
3067 })),
3068 );
3069 do_expr_ok_test(
3070 "-1 - 3",
3071 Subtract(Box::from(BinaryOpSpan {
3072 lhs: Negate(Box::from(UnaryOpSpan { expr: expr_integer(1, 1, 8), pos: lc(1, 7) })),
3073 rhs: expr_integer(3, 1, 12),
3074 pos: lc(1, 10),
3075 })),
3076 );
3077 do_expr_ok_test(
3078 "5 + -1",
3079 Add(Box::from(BinaryOpSpan {
3080 lhs: expr_integer(5, 1, 7),
3081 rhs: Negate(Box::from(UnaryOpSpan {
3082 expr: expr_integer(1, 1, 12),
3083 pos: lc(1, 11),
3084 })),
3085 pos: lc(1, 9),
3086 })),
3087 );
3088 do_expr_ok_test(
3089 "-5 + 1",
3090 Add(Box::from(BinaryOpSpan {
3091 lhs: Negate(Box::from(UnaryOpSpan { expr: expr_integer(5, 1, 8), pos: lc(1, 7) })),
3092 rhs: expr_integer(1, 1, 12),
3093 pos: lc(1, 10),
3094 })),
3095 );
3096 do_expr_ok_test(
3097 "NOT -3",
3098 Not(Box::from(UnaryOpSpan {
3099 expr: Negate(Box::from(UnaryOpSpan {
3100 expr: expr_integer(3, 1, 12),
3101 pos: lc(1, 11),
3102 })),
3103 pos: lc(1, 7),
3104 })),
3105 );
3106
3107 do_expr_ok_test(
3108 "1.0 - -3.5",
3109 Subtract(Box::from(BinaryOpSpan {
3110 lhs: expr_double(1.0, 1, 7),
3111 rhs: Negate(Box::from(UnaryOpSpan {
3112 expr: expr_double(3.5, 1, 14),
3113 pos: lc(1, 13),
3114 })),
3115 pos: lc(1, 11),
3116 })),
3117 );
3118 do_expr_ok_test(
3119 "5.12 + -0.50",
3120 Add(Box::from(BinaryOpSpan {
3121 lhs: expr_double(5.12, 1, 7),
3122 rhs: Negate(Box::from(UnaryOpSpan {
3123 expr: expr_double(0.50, 1, 15),
3124 pos: lc(1, 14),
3125 })),
3126 pos: lc(1, 12),
3127 })),
3128 );
3129 do_expr_ok_test(
3130 "NOT -3",
3131 Not(Box::from(UnaryOpSpan {
3132 expr: Negate(Box::from(UnaryOpSpan {
3133 expr: expr_integer(3, 1, 12),
3134 pos: lc(1, 11),
3135 })),
3136 pos: lc(1, 7),
3137 })),
3138 );
3139 }
3140
3141 #[test]
3142 fn test_expr_functions_variadic() {
3143 use Expr::*;
3144 do_expr_ok_test(
3145 "zero()",
3146 Call(CallSpan { vref: VarRef::new("zero", None), vref_pos: lc(1, 7), args: vec![] }),
3147 );
3148 do_expr_ok_test(
3149 "one%(1)",
3150 Call(CallSpan {
3151 vref: VarRef::new("one", Some(ExprType::Integer)),
3152 vref_pos: lc(1, 7),
3153 args: vec![ArgSpan {
3154 expr: Some(expr_integer(1, 1, 12)),
3155 sep: ArgSep::End,
3156 sep_pos: lc(1, 13),
3157 }],
3158 }),
3159 );
3160 do_expr_ok_test(
3161 "many$(3, \"x\", TRUE)",
3162 Call(CallSpan {
3163 vref: VarRef::new("many", Some(ExprType::Text)),
3164 vref_pos: lc(1, 7),
3165 args: vec![
3166 ArgSpan {
3167 expr: Some(expr_integer(3, 1, 13)),
3168 sep: ArgSep::Long,
3169 sep_pos: lc(1, 14),
3170 },
3171 ArgSpan {
3172 expr: Some(expr_text("x", 1, 16)),
3173 sep: ArgSep::Long,
3174 sep_pos: lc(1, 19),
3175 },
3176 ArgSpan {
3177 expr: Some(expr_boolean(true, 1, 21)),
3178 sep: ArgSep::End,
3179 sep_pos: lc(1, 25),
3180 },
3181 ],
3182 }),
3183 );
3184 }
3185
3186 #[test]
3187 fn test_expr_functions_nested() {
3188 use Expr::*;
3189 do_expr_ok_test(
3190 "consecutive(parenthesis())",
3191 Call(CallSpan {
3192 vref: VarRef::new("consecutive", None),
3193 vref_pos: lc(1, 7),
3194 args: vec![ArgSpan {
3195 expr: Some(Call(CallSpan {
3196 vref: VarRef::new("parenthesis", None),
3197 vref_pos: lc(1, 19),
3198 args: vec![],
3199 })),
3200 sep: ArgSep::End,
3201 sep_pos: lc(1, 32),
3202 }],
3203 }),
3204 );
3205 do_expr_ok_test(
3206 "outer?(1, inner1(2, 3), 4, inner2(), 5)",
3207 Call(CallSpan {
3208 vref: VarRef::new("outer", Some(ExprType::Boolean)),
3209 vref_pos: lc(1, 7),
3210 args: vec![
3211 ArgSpan {
3212 expr: Some(expr_integer(1, 1, 14)),
3213 sep: ArgSep::Long,
3214 sep_pos: lc(1, 15),
3215 },
3216 ArgSpan {
3217 expr: Some(Call(CallSpan {
3218 vref: VarRef::new("inner1", None),
3219 vref_pos: lc(1, 17),
3220 args: vec![
3221 ArgSpan {
3222 expr: Some(expr_integer(2, 1, 24)),
3223 sep: ArgSep::Long,
3224 sep_pos: lc(1, 25),
3225 },
3226 ArgSpan {
3227 expr: Some(expr_integer(3, 1, 27)),
3228 sep: ArgSep::End,
3229 sep_pos: lc(1, 28),
3230 },
3231 ],
3232 })),
3233 sep: ArgSep::Long,
3234 sep_pos: lc(1, 29),
3235 },
3236 ArgSpan {
3237 expr: Some(expr_integer(4, 1, 31)),
3238 sep: ArgSep::Long,
3239 sep_pos: lc(1, 32),
3240 },
3241 ArgSpan {
3242 expr: Some(Call(CallSpan {
3243 vref: VarRef::new("inner2", None),
3244 vref_pos: lc(1, 34),
3245 args: vec![],
3246 })),
3247 sep: ArgSep::Long,
3248 sep_pos: lc(1, 42),
3249 },
3250 ArgSpan {
3251 expr: Some(expr_integer(5, 1, 44)),
3252 sep: ArgSep::End,
3253 sep_pos: lc(1, 45),
3254 },
3255 ],
3256 }),
3257 );
3258 }
3259
3260 #[test]
3261 fn test_expr_functions_and_ops() {
3262 use Expr::*;
3263 do_expr_ok_test(
3264 "b AND ask?(34 + 15, ask(1, FALSE), -5)",
3265 And(Box::from(BinaryOpSpan {
3266 lhs: expr_symbol(VarRef::new("b".to_owned(), None), 1, 7),
3267 rhs: Call(CallSpan {
3268 vref: VarRef::new("ask", Some(ExprType::Boolean)),
3269 vref_pos: lc(1, 13),
3270 args: vec![
3271 ArgSpan {
3272 expr: Some(Add(Box::from(BinaryOpSpan {
3273 lhs: expr_integer(34, 1, 18),
3274 rhs: expr_integer(15, 1, 23),
3275 pos: lc(1, 21),
3276 }))),
3277 sep: ArgSep::Long,
3278 sep_pos: lc(1, 25),
3279 },
3280 ArgSpan {
3281 expr: Some(Call(CallSpan {
3282 vref: VarRef::new("ask", None),
3283 vref_pos: lc(1, 27),
3284 args: vec![
3285 ArgSpan {
3286 expr: Some(expr_integer(1, 1, 31)),
3287 sep: ArgSep::Long,
3288 sep_pos: lc(1, 32),
3289 },
3290 ArgSpan {
3291 expr: Some(expr_boolean(false, 1, 34)),
3292 sep: ArgSep::End,
3293 sep_pos: lc(1, 39),
3294 },
3295 ],
3296 })),
3297 sep: ArgSep::Long,
3298 sep_pos: lc(1, 40),
3299 },
3300 ArgSpan {
3301 expr: Some(Negate(Box::from(UnaryOpSpan {
3302 expr: expr_integer(5, 1, 43),
3303 pos: lc(1, 42),
3304 }))),
3305 sep: ArgSep::End,
3306 sep_pos: lc(1, 44),
3307 },
3308 ],
3309 }),
3310 pos: lc(1, 9),
3311 })),
3312 );
3313 }
3314
3315 #[test]
3316 fn test_expr_functions_not_confused_with_symbols() {
3317 use Expr::*;
3318 let iref = VarRef::new("i", None);
3319 let jref = VarRef::new("j", None);
3320 do_expr_ok_test(
3321 "i = 0 OR i = (j - 1)",
3322 Or(Box::from(BinaryOpSpan {
3323 lhs: Equal(Box::from(BinaryOpSpan {
3324 lhs: expr_symbol(iref.clone(), 1, 7),
3325 rhs: expr_integer(0, 1, 11),
3326 pos: lc(1, 9),
3327 })),
3328 rhs: Equal(Box::from(BinaryOpSpan {
3329 lhs: expr_symbol(iref, 1, 16),
3330 rhs: Subtract(Box::from(BinaryOpSpan {
3331 lhs: expr_symbol(jref, 1, 21),
3332 rhs: expr_integer(1, 1, 25),
3333 pos: lc(1, 23),
3334 })),
3335 pos: lc(1, 18),
3336 })),
3337 pos: lc(1, 13),
3338 })),
3339 );
3340 }
3341
3342 #[test]
3343 fn test_expr_errors() {
3344 do_expr_error_test("+3", "1:7: Not enough values to apply operator");
3348 do_expr_error_test("2 + * 3", "1:9: Not enough values to apply operator");
3349 do_expr_error_test("(2(3))", "1:9: Unexpected ( in expression");
3350 do_expr_error_test("((3)2)", "1:11: Unexpected value in expression");
3351 do_expr_error_test("2 3", "1:9: Unexpected value in expression");
3352
3353 do_expr_error_test("(", "1:8: Missing expression");
3354
3355 do_expr_error_test(")", "1:7: Expected comma, semicolon, or end of statement");
3356 do_expr_error_test("(()", "1:10: Missing expression");
3357 do_expr_error_test("())", "1:7: Expected expression");
3358 do_expr_error_test("3 + (2 + 1) + (4 - 5", "1:21: Unbalanced parenthesis");
3359 do_expr_error_test(
3360 "3 + 2 + 1) + (4 - 5)",
3361 "1:16: Expected comma, semicolon, or end of statement",
3362 );
3363
3364 do_expr_error_test("foo(,)", "1:11: Missing expression");
3365 do_expr_error_test("foo(, 3)", "1:11: Missing expression");
3366 do_expr_error_test("foo(3, )", "1:14: Missing expression");
3367 do_expr_error_test("foo(3, , 4)", "1:14: Missing expression");
3368 do_expr_error_test("(,)", "1:8: Missing expression");
3370 do_expr_error_test("(3, 4)", "1:7: Expected expression");
3371 do_expr_error_test("((), ())", "1:10: Missing expression");
3372
3373 use Expr::*;
3378 do_expr_ok_test(
3379 "1 + PRINT",
3380 Add(Box::from(BinaryOpSpan {
3381 lhs: expr_integer(1, 1, 7),
3382 rhs: expr_symbol(VarRef::new("PRINT", None), 1, 11),
3383 pos: lc(1, 9),
3384 })),
3385 );
3386 }
3387
3388 #[test]
3389 fn test_expr_errors_due_to_keywords() {
3390 for kw in &[
3391 "BOOLEAN", "CASE", "DATA", "DIM", "DOUBLE", "ELSEIF", "END", "ERROR", "EXIT", "FOR",
3392 "GOSUB", "GOTO", "IF", "IS", "INTEGER", "LOOP", "NEXT", "ON", "RESUME", "RETURN",
3393 "SELECT", "STRING", "UNTIL", "WEND", "WHILE",
3394 ] {
3395 do_expr_error_test(
3396 &format!("2 + {} - 1", kw),
3397 "1:11: Unexpected keyword in expression",
3398 );
3399 }
3400 }
3401
3402 #[test]
3403 fn test_if_empty_branches() {
3404 do_ok_test(
3405 "IF 1 THEN\nEND IF",
3406 &[Statement::If(IfSpan {
3407 branches: vec![IfBranchSpan { guard: expr_integer(1, 1, 4), body: vec![] }],
3408 })],
3409 );
3410 do_ok_test(
3411 "IF 1 THEN\nREM Some comment to skip over\n\nEND IF",
3412 &[Statement::If(IfSpan {
3413 branches: vec![IfBranchSpan { guard: expr_integer(1, 1, 4), body: vec![] }],
3414 })],
3415 );
3416 do_ok_test(
3417 "IF 1 THEN\nELSEIF 2 THEN\nEND IF",
3418 &[Statement::If(IfSpan {
3419 branches: vec![
3420 IfBranchSpan { guard: expr_integer(1, 1, 4), body: vec![] },
3421 IfBranchSpan { guard: expr_integer(2, 2, 8), body: vec![] },
3422 ],
3423 })],
3424 );
3425 do_ok_test(
3426 "IF 1 THEN\nELSEIF 2 THEN\nELSE\nEND IF",
3427 &[Statement::If(IfSpan {
3428 branches: vec![
3429 IfBranchSpan { guard: expr_integer(1, 1, 4), body: vec![] },
3430 IfBranchSpan { guard: expr_integer(2, 2, 8), body: vec![] },
3431 IfBranchSpan { guard: expr_boolean(true, 3, 1), body: vec![] },
3432 ],
3433 })],
3434 );
3435 do_ok_test(
3436 "IF 1 THEN\nELSE\nEND IF",
3437 &[Statement::If(IfSpan {
3438 branches: vec![
3439 IfBranchSpan { guard: expr_integer(1, 1, 4), body: vec![] },
3440 IfBranchSpan { guard: expr_boolean(true, 2, 1), body: vec![] },
3441 ],
3442 })],
3443 );
3444 }
3445
3446 fn make_bare_builtin_call(name: &str, line: usize, col: usize) -> Statement {
3448 Statement::Call(CallSpan {
3449 vref: VarRef::new(name, None),
3450 vref_pos: LineCol { line, col },
3451 args: vec![],
3452 })
3453 }
3454
3455 #[test]
3456 fn test_if_with_one_statement_or_empty_lines() {
3457 do_ok_test(
3458 "IF 1 THEN\nPRINT\nEND IF",
3459 &[Statement::If(IfSpan {
3460 branches: vec![IfBranchSpan {
3461 guard: expr_integer(1, 1, 4),
3462 body: vec![make_bare_builtin_call("PRINT", 2, 1)],
3463 }],
3464 })],
3465 );
3466 do_ok_test(
3467 "IF 1 THEN\nREM foo\nELSEIF 2 THEN\nPRINT\nEND IF",
3468 &[Statement::If(IfSpan {
3469 branches: vec![
3470 IfBranchSpan { guard: expr_integer(1, 1, 4), body: vec![] },
3471 IfBranchSpan {
3472 guard: expr_integer(2, 3, 8),
3473 body: vec![make_bare_builtin_call("PRINT", 4, 1)],
3474 },
3475 ],
3476 })],
3477 );
3478 do_ok_test(
3479 "IF 1 THEN\nELSEIF 2 THEN\nELSE\n\nPRINT\nEND IF",
3480 &[Statement::If(IfSpan {
3481 branches: vec![
3482 IfBranchSpan { guard: expr_integer(1, 1, 4), body: vec![] },
3483 IfBranchSpan { guard: expr_integer(2, 2, 8), body: vec![] },
3484 IfBranchSpan {
3485 guard: expr_boolean(true, 3, 1),
3486 body: vec![make_bare_builtin_call("PRINT", 5, 1)],
3487 },
3488 ],
3489 })],
3490 );
3491 do_ok_test(
3492 "IF 1 THEN\n\n\nELSE\nPRINT\nEND IF",
3493 &[Statement::If(IfSpan {
3494 branches: vec![
3495 IfBranchSpan { guard: expr_integer(1, 1, 4), body: vec![] },
3496 IfBranchSpan {
3497 guard: expr_boolean(true, 4, 1),
3498 body: vec![make_bare_builtin_call("PRINT", 5, 1)],
3499 },
3500 ],
3501 })],
3502 );
3503 }
3504
3505 #[test]
3506 fn test_if_complex() {
3507 let code = r#"
3508 IF 1 THEN 'First branch
3509 A
3510 B
3511 ELSEIF 2 THEN 'Second branch
3512 C
3513 D
3514 ELSEIF 3 THEN 'Third branch
3515 E
3516 F
3517 ELSE 'Last branch
3518 G
3519 H
3520 END IF
3521 "#;
3522 do_ok_test(
3523 code,
3524 &[Statement::If(IfSpan {
3525 branches: vec![
3526 IfBranchSpan {
3527 guard: expr_integer(1, 2, 16),
3528 body: vec![
3529 make_bare_builtin_call("A", 3, 17),
3530 make_bare_builtin_call("B", 4, 17),
3531 ],
3532 },
3533 IfBranchSpan {
3534 guard: expr_integer(2, 5, 20),
3535 body: vec![
3536 make_bare_builtin_call("C", 6, 17),
3537 make_bare_builtin_call("D", 7, 17),
3538 ],
3539 },
3540 IfBranchSpan {
3541 guard: expr_integer(3, 8, 20),
3542 body: vec![
3543 make_bare_builtin_call("E", 9, 17),
3544 make_bare_builtin_call("F", 10, 17),
3545 ],
3546 },
3547 IfBranchSpan {
3548 guard: expr_boolean(true, 11, 13),
3549 body: vec![
3550 make_bare_builtin_call("G", 12, 17),
3551 make_bare_builtin_call("H", 13, 17),
3552 ],
3553 },
3554 ],
3555 })],
3556 );
3557 }
3558
3559 #[test]
3560 fn test_if_with_interleaved_end_complex() {
3561 let code = r#"
3562 IF 1 THEN 'First branch
3563 A
3564 END
3565 B
3566 ELSEIF 2 THEN 'Second branch
3567 C
3568 END 8
3569 D
3570 ELSEIF 3 THEN 'Third branch
3571 E
3572 END
3573 F
3574 ELSE 'Last branch
3575 G
3576 END 5
3577 H
3578 END IF
3579 "#;
3580 do_ok_test(
3581 code,
3582 &[Statement::If(IfSpan {
3583 branches: vec![
3584 IfBranchSpan {
3585 guard: expr_integer(1, 2, 16),
3586 body: vec![
3587 make_bare_builtin_call("A", 3, 17),
3588 Statement::End(EndSpan { code: None }),
3589 make_bare_builtin_call("B", 5, 17),
3590 ],
3591 },
3592 IfBranchSpan {
3593 guard: expr_integer(2, 6, 20),
3594 body: vec![
3595 make_bare_builtin_call("C", 7, 17),
3596 Statement::End(EndSpan {
3597 code: Some(Expr::Integer(IntegerSpan { value: 8, pos: lc(8, 21) })),
3598 }),
3599 make_bare_builtin_call("D", 9, 17),
3600 ],
3601 },
3602 IfBranchSpan {
3603 guard: expr_integer(3, 10, 20),
3604 body: vec![
3605 make_bare_builtin_call("E", 11, 17),
3606 Statement::End(EndSpan { code: None }),
3607 make_bare_builtin_call("F", 13, 17),
3608 ],
3609 },
3610 IfBranchSpan {
3611 guard: expr_boolean(true, 14, 13),
3612 body: vec![
3613 make_bare_builtin_call("G", 15, 17),
3614 Statement::End(EndSpan {
3615 code: Some(Expr::Integer(IntegerSpan {
3616 value: 5,
3617 pos: lc(16, 21),
3618 })),
3619 }),
3620 make_bare_builtin_call("H", 17, 17),
3621 ],
3622 },
3623 ],
3624 })],
3625 );
3626 }
3627
3628 #[test]
3629 fn test_if_nested() {
3630 let code = r#"
3631 IF 1 THEN
3632 A
3633 ELSEIF 2 THEN
3634 IF 3 THEN
3635 B
3636 END IF
3637 END IF
3638 "#;
3639 do_ok_test(
3640 code,
3641 &[Statement::If(IfSpan {
3642 branches: vec![
3643 IfBranchSpan {
3644 guard: expr_integer(1, 2, 16),
3645 body: vec![make_bare_builtin_call("A", 3, 17)],
3646 },
3647 IfBranchSpan {
3648 guard: expr_integer(2, 4, 20),
3649 body: vec![Statement::If(IfSpan {
3650 branches: vec![IfBranchSpan {
3651 guard: expr_integer(3, 5, 20),
3652 body: vec![make_bare_builtin_call("B", 6, 21)],
3653 }],
3654 })],
3655 },
3656 ],
3657 })],
3658 );
3659 }
3660
3661 #[test]
3662 fn test_if_errors() {
3663 do_error_test("IF\n", "1:3: No expression in IF statement");
3664 do_error_test("IF 3 + 1", "1:9: No THEN in IF statement");
3665 do_error_test("IF 3 + 1\n", "1:9: No THEN in IF statement");
3666 do_error_test("IF 3 + 1 PRINT foo\n", "1:10: Unexpected value in expression");
3667 do_error_test("IF 3 + 1\nPRINT foo\n", "1:9: No THEN in IF statement");
3668 do_error_test("IF 3 + 1 THEN", "1:1: IF without END IF");
3669
3670 do_error_test("IF 1 THEN\n", "1:1: IF without END IF");
3671 do_error_test("IF 1 THEN\nELSEIF 1 THEN\n", "1:1: IF without END IF");
3672 do_error_test("IF 1 THEN\nELSE\n", "1:1: IF without END IF");
3673 do_error_test("REM\n IF 1 THEN\n", "2:4: IF without END IF");
3674
3675 do_error_test("IF 1 THEN\nELSEIF\n", "2:7: No expression in ELSEIF statement");
3676 do_error_test("IF 1 THEN\nELSEIF 3 + 1", "2:13: No THEN in ELSEIF statement");
3677 do_error_test("IF 1 THEN\nELSEIF 3 + 1\n", "2:13: No THEN in ELSEIF statement");
3678 do_error_test(
3679 "IF 1 THEN\nELSEIF 3 + 1 PRINT foo\n",
3680 "2:14: Unexpected value in expression",
3681 );
3682 do_error_test("IF 1 THEN\nELSEIF 3 + 1\nPRINT foo\n", "2:13: No THEN in ELSEIF statement");
3683 do_error_test("IF 1 THEN\nELSEIF 3 + 1 THEN", "2:18: Expecting newline after THEN");
3684
3685 do_error_test("IF 1 THEN\nELSE", "2:5: Expecting newline after ELSE");
3686 do_error_test("IF 1 THEN\nELSE foo", "2:6: Expecting newline after ELSE");
3687
3688 do_error_test("IF 1 THEN\nEND", "1:1: IF without END IF");
3689 do_error_test("IF 1 THEN\nEND\n", "1:1: IF without END IF");
3690 do_error_test("IF 1 THEN\nEND IF foo", "2:8: Expected newline but found foo");
3691 do_error_test("IF 1 THEN\nEND SELECT\n", "2:1: END SELECT without SELECT");
3692 do_error_test("IF 1 THEN\nEND SELECT\nEND IF\n", "2:1: END SELECT without SELECT");
3693
3694 do_error_test(
3695 "IF 1 THEN\nELSE\nELSEIF 2 THEN\nEND IF",
3696 "3:1: Unexpected ELSEIF after ELSE",
3697 );
3698 do_error_test("IF 1 THEN\nELSE\nELSE\nEND IF", "3:1: Duplicate ELSE after ELSE");
3699
3700 do_error_test_no_reset("ELSEIF 1 THEN\nEND IF", "1:1: Unexpected ELSEIF in statement");
3701 do_error_test_no_reset("ELSE 1\nEND IF", "1:1: Unexpected ELSE in statement");
3702
3703 do_error_test("IF 1 THEN\nEND 3 IF", "2:7: Unexpected keyword in expression");
3704 do_error_test("END 3 IF", "1:7: Unexpected keyword in expression");
3705 do_error_test("END IF", "1:1: END IF without IF");
3706
3707 do_error_test("IF TRUE THEN PRINT ELSE ELSE", "1:25: Unexpected ELSE in uniline IF branch");
3708 }
3709
3710 #[test]
3711 fn test_if_uniline_then() {
3712 do_ok_test(
3713 "IF 1 THEN A",
3714 &[Statement::If(IfSpan {
3715 branches: vec![IfBranchSpan {
3716 guard: expr_integer(1, 1, 4),
3717 body: vec![make_bare_builtin_call("A", 1, 11)],
3718 }],
3719 })],
3720 );
3721 }
3722
3723 #[test]
3724 fn test_if_uniline_then_else() {
3725 do_ok_test(
3726 "IF 1 THEN A ELSE B",
3727 &[Statement::If(IfSpan {
3728 branches: vec![
3729 IfBranchSpan {
3730 guard: expr_integer(1, 1, 4),
3731 body: vec![make_bare_builtin_call("A", 1, 11)],
3732 },
3733 IfBranchSpan {
3734 guard: expr_boolean(true, 1, 13),
3735 body: vec![make_bare_builtin_call("B", 1, 18)],
3736 },
3737 ],
3738 })],
3739 );
3740 }
3741
3742 #[test]
3743 fn test_if_uniline_empty_then_else() {
3744 do_ok_test(
3745 "IF 1 THEN ELSE B",
3746 &[Statement::If(IfSpan {
3747 branches: vec![
3748 IfBranchSpan { guard: expr_integer(1, 1, 4), body: vec![] },
3749 IfBranchSpan {
3750 guard: expr_boolean(true, 1, 11),
3751 body: vec![make_bare_builtin_call("B", 1, 16)],
3752 },
3753 ],
3754 })],
3755 );
3756 }
3757
3758 #[test]
3759 fn test_if_uniline_then_empty_else() {
3760 do_ok_test(
3761 "IF 1 THEN A ELSE",
3762 &[Statement::If(IfSpan {
3763 branches: vec![
3764 IfBranchSpan {
3765 guard: expr_integer(1, 1, 4),
3766 body: vec![make_bare_builtin_call("A", 1, 11)],
3767 },
3768 IfBranchSpan { guard: expr_boolean(true, 1, 13), body: vec![] },
3769 ],
3770 })],
3771 );
3772 }
3773
3774 #[test]
3775 fn test_if_uniline_empty_then_empty_else() {
3776 do_ok_test(
3777 "IF 1 THEN ELSE",
3778 &[Statement::If(IfSpan {
3779 branches: vec![
3780 IfBranchSpan { guard: expr_integer(1, 1, 4), body: vec![] },
3781 IfBranchSpan { guard: expr_boolean(true, 1, 11), body: vec![] },
3782 ],
3783 })],
3784 );
3785 }
3786
3787 fn do_if_uniline_allowed_test(text: &str, stmt: Statement) {
3793 do_ok_test(
3794 &format!("IF 1 THEN {}\nZ", text),
3795 &[
3796 Statement::If(IfSpan {
3797 branches: vec![IfBranchSpan { guard: expr_integer(1, 1, 4), body: vec![stmt] }],
3798 }),
3799 make_bare_builtin_call("Z", 2, 1),
3800 ],
3801 );
3802 }
3803
3804 #[test]
3805 fn test_if_uniline_allowed_data() {
3806 do_if_uniline_allowed_test("DATA", Statement::Data(DataSpan { values: vec![None] }));
3807 }
3808
3809 #[test]
3810 fn test_if_uniline_allowed_end() {
3811 do_if_uniline_allowed_test(
3812 "END 8",
3813 Statement::End(EndSpan { code: Some(expr_integer(8, 1, 15)) }),
3814 );
3815 }
3816
3817 #[test]
3818 fn test_if_uniline_allowed_exit() {
3819 do_if_uniline_allowed_test("EXIT DO", Statement::ExitDo(ExitDoSpan { pos: lc(1, 11) }));
3820
3821 do_error_test("IF 1 THEN EXIT", "1:15: Expecting DO after EXIT");
3822 }
3823
3824 #[test]
3825 fn test_if_uniline_allowed_gosub() {
3826 do_if_uniline_allowed_test(
3827 "GOSUB 10",
3828 Statement::Gosub(GotoSpan { target: "10".to_owned(), target_pos: lc(1, 17) }),
3829 );
3830
3831 do_error_test("IF 1 THEN GOSUB", "1:16: Expected label name after GOSUB");
3832 }
3833
3834 #[test]
3835 fn test_if_uniline_allowed_goto() {
3836 do_if_uniline_allowed_test(
3837 "GOTO 10",
3838 Statement::Goto(GotoSpan { target: "10".to_owned(), target_pos: lc(1, 16) }),
3839 );
3840
3841 do_error_test("IF 1 THEN GOTO", "1:15: Expected label name after GOTO");
3842 }
3843
3844 #[test]
3845 fn test_if_uniline_allowed_on_error() {
3846 do_if_uniline_allowed_test(
3847 "ON ERROR RESUME NEXT",
3848 Statement::OnError(OnErrorSpan::ResumeNext),
3849 );
3850
3851 do_error_test("IF 1 THEN ON", "1:13: Expected ERROR after ON");
3852 }
3853
3854 #[test]
3855 fn test_if_uniline_allowed_return() {
3856 do_if_uniline_allowed_test("RETURN", Statement::Return(ReturnSpan { pos: lc(1, 11) }));
3857 }
3858
3859 #[test]
3860 fn test_if_uniline_allowed_assignment() {
3861 do_if_uniline_allowed_test(
3862 "a = 3",
3863 Statement::Assignment(AssignmentSpan {
3864 vref: VarRef::new("a", None),
3865 vref_pos: lc(1, 11),
3866 expr: expr_integer(3, 1, 15),
3867 }),
3868 );
3869 }
3870
3871 #[test]
3872 fn test_if_uniline_allowed_array_assignment() {
3873 do_if_uniline_allowed_test(
3874 "a(3) = 5",
3875 Statement::ArrayAssignment(ArrayAssignmentSpan {
3876 vref: VarRef::new("a", None),
3877 vref_pos: lc(1, 11),
3878 subscripts: vec![expr_integer(3, 1, 13)],
3879 expr: expr_integer(5, 1, 18),
3880 }),
3881 );
3882 }
3883
3884 #[test]
3885 fn test_if_uniline_allowed_builtin_call() {
3886 do_if_uniline_allowed_test(
3887 "a 0",
3888 Statement::Call(CallSpan {
3889 vref: VarRef::new("A", None),
3890 vref_pos: lc(1, 11),
3891 args: vec![ArgSpan {
3892 expr: Some(expr_integer(0, 1, 13)),
3893 sep: ArgSep::End,
3894 sep_pos: lc(1, 14),
3895 }],
3896 }),
3897 );
3898 }
3899
3900 #[test]
3901 fn test_if_uniline_unallowed_statements() {
3902 for t in ["DIM", "DO", "IF", "FOR", "10", "@label", "SELECT", "WHILE"] {
3903 do_error_test(
3904 &format!("IF 1 THEN {}", t),
3905 &format!("1:11: Unexpected {} in uniline IF branch", t),
3906 );
3907 }
3908 }
3909
3910 #[test]
3911 fn test_for_empty() {
3912 let auto_iter = VarRef::new("i", None);
3913 do_ok_test(
3914 "FOR i = 1 TO 10\nNEXT",
3915 &[Statement::For(ForSpan {
3916 iter: auto_iter.clone(),
3917 iter_pos: lc(1, 5),
3918 iter_double: false,
3919 start: expr_integer(1, 1, 9),
3920 end: Expr::LessEqual(Box::from(BinaryOpSpan {
3921 lhs: expr_symbol(auto_iter.clone(), 1, 5),
3922 rhs: expr_integer(10, 1, 14),
3923 pos: lc(1, 11),
3924 })),
3925 next: Expr::Add(Box::from(BinaryOpSpan {
3926 lhs: expr_symbol(auto_iter, 1, 5),
3927 rhs: expr_integer(1, 1, 16),
3928 pos: lc(1, 11),
3929 })),
3930 body: vec![],
3931 })],
3932 );
3933
3934 let typed_iter = VarRef::new("d", Some(ExprType::Double));
3935 do_ok_test(
3936 "FOR d# = 1.0 TO 10.2\nREM Nothing to do\nNEXT",
3937 &[Statement::For(ForSpan {
3938 iter: typed_iter.clone(),
3939 iter_pos: lc(1, 5),
3940 iter_double: false,
3941 start: expr_double(1.0, 1, 10),
3942 end: Expr::LessEqual(Box::from(BinaryOpSpan {
3943 lhs: expr_symbol(typed_iter.clone(), 1, 5),
3944 rhs: expr_double(10.2, 1, 17),
3945 pos: lc(1, 14),
3946 })),
3947 next: Expr::Add(Box::from(BinaryOpSpan {
3948 lhs: expr_symbol(typed_iter, 1, 5),
3949 rhs: expr_integer(1, 1, 21),
3950 pos: lc(1, 14),
3951 })),
3952 body: vec![],
3953 })],
3954 );
3955 }
3956
3957 #[test]
3958 fn test_for_incrementing() {
3959 let iter = VarRef::new("i", None);
3960 do_ok_test(
3961 "FOR i = 0 TO 5\nA\nB\nNEXT",
3962 &[Statement::For(ForSpan {
3963 iter: iter.clone(),
3964 iter_pos: lc(1, 5),
3965 iter_double: false,
3966 start: expr_integer(0, 1, 9),
3967 end: Expr::LessEqual(Box::from(BinaryOpSpan {
3968 lhs: expr_symbol(iter.clone(), 1, 5),
3969 rhs: expr_integer(5, 1, 14),
3970 pos: lc(1, 11),
3971 })),
3972 next: Expr::Add(Box::from(BinaryOpSpan {
3973 lhs: expr_symbol(iter, 1, 5),
3974 rhs: expr_integer(1, 1, 15),
3975 pos: lc(1, 11),
3976 })),
3977 body: vec![make_bare_builtin_call("A", 2, 1), make_bare_builtin_call("B", 3, 1)],
3978 })],
3979 );
3980 }
3981
3982 #[test]
3983 fn test_for_incrementing_with_step() {
3984 let iter = VarRef::new("i", None);
3985 do_ok_test(
3986 "FOR i = 0 TO 5 STEP 2\nA\nNEXT",
3987 &[Statement::For(ForSpan {
3988 iter: iter.clone(),
3989 iter_pos: lc(1, 5),
3990 iter_double: false,
3991 start: expr_integer(0, 1, 9),
3992 end: Expr::LessEqual(Box::from(BinaryOpSpan {
3993 lhs: expr_symbol(iter.clone(), 1, 5),
3994 rhs: expr_integer(5, 1, 14),
3995 pos: lc(1, 11),
3996 })),
3997 next: Expr::Add(Box::from(BinaryOpSpan {
3998 lhs: expr_symbol(iter, 1, 5),
3999 rhs: expr_integer(2, 1, 21),
4000 pos: lc(1, 11),
4001 })),
4002 body: vec![make_bare_builtin_call("A", 2, 1)],
4003 })],
4004 );
4005
4006 let iter = VarRef::new("i", None);
4007 do_ok_test(
4008 "FOR i = 0 TO 5 STEP 2.5\nA\nNEXT",
4009 &[Statement::For(ForSpan {
4010 iter: iter.clone(),
4011 iter_pos: lc(1, 5),
4012 iter_double: true,
4013 start: expr_integer(0, 1, 9),
4014 end: Expr::LessEqual(Box::from(BinaryOpSpan {
4015 lhs: expr_symbol(iter.clone(), 1, 5),
4016 rhs: expr_integer(5, 1, 14),
4017 pos: lc(1, 11),
4018 })),
4019 next: Expr::Add(Box::from(BinaryOpSpan {
4020 lhs: expr_symbol(iter, 1, 5),
4021 rhs: expr_double(2.5, 1, 21),
4022 pos: lc(1, 11),
4023 })),
4024 body: vec![make_bare_builtin_call("A", 2, 1)],
4025 })],
4026 );
4027 }
4028
4029 #[test]
4030 fn test_for_decrementing_with_step() {
4031 let iter = VarRef::new("i", None);
4032 do_ok_test(
4033 "FOR i = 5 TO 0 STEP -1\nA\nNEXT",
4034 &[Statement::For(ForSpan {
4035 iter: iter.clone(),
4036 iter_pos: lc(1, 5),
4037 iter_double: false,
4038 start: expr_integer(5, 1, 9),
4039 end: Expr::GreaterEqual(Box::from(BinaryOpSpan {
4040 lhs: expr_symbol(iter.clone(), 1, 5),
4041 rhs: expr_integer(0, 1, 14),
4042 pos: lc(1, 11),
4043 })),
4044 next: Expr::Add(Box::from(BinaryOpSpan {
4045 lhs: expr_symbol(iter, 1, 5),
4046 rhs: expr_integer(-1, 1, 22),
4047 pos: lc(1, 11),
4048 })),
4049 body: vec![make_bare_builtin_call("A", 2, 1)],
4050 })],
4051 );
4052
4053 let iter = VarRef::new("i", None);
4054 do_ok_test(
4055 "FOR i = 5 TO 0 STEP -1.2\nA\nNEXT",
4056 &[Statement::For(ForSpan {
4057 iter: iter.clone(),
4058 iter_pos: lc(1, 5),
4059 iter_double: true,
4060 start: expr_integer(5, 1, 9),
4061 end: Expr::GreaterEqual(Box::from(BinaryOpSpan {
4062 lhs: expr_symbol(iter.clone(), 1, 5),
4063 rhs: expr_integer(0, 1, 14),
4064 pos: lc(1, 11),
4065 })),
4066 next: Expr::Add(Box::from(BinaryOpSpan {
4067 lhs: expr_symbol(iter, 1, 5),
4068 rhs: expr_double(-1.2, 1, 22),
4069 pos: lc(1, 11),
4070 })),
4071 body: vec![make_bare_builtin_call("A", 2, 1)],
4072 })],
4073 );
4074 }
4075
4076 #[test]
4077 fn test_for_errors() {
4078 do_error_test("FOR\n", "1:4: No iterator name in FOR statement");
4079 do_error_test("FOR =\n", "1:5: No iterator name in FOR statement");
4080 do_error_test(
4081 "FOR a$\n",
4082 "1:5: Iterator name in FOR statement must be a numeric reference",
4083 );
4084
4085 do_error_test("FOR d#\n", "1:7: No equal sign in FOR statement");
4086 do_error_test("FOR i 3\n", "1:7: No equal sign in FOR statement");
4087 do_error_test("FOR i = TO\n", "1:9: No start expression in FOR statement");
4088 do_error_test("FOR i = NEXT\n", "1:9: Unexpected keyword in expression");
4089
4090 do_error_test("FOR i = 3 STEP\n", "1:11: No TO in FOR statement");
4091 do_error_test("FOR i = 3 TO STEP\n", "1:14: No end expression in FOR statement");
4092 do_error_test("FOR i = 3 TO NEXT\n", "1:14: Unexpected keyword in expression");
4093
4094 do_error_test("FOR i = 3 TO 1 STEP a\n", "1:21: STEP needs a literal number");
4095 do_error_test("FOR i = 3 TO 1 STEP -a\n", "1:22: STEP needs a literal number");
4096 do_error_test("FOR i = 3 TO 1 STEP NEXT\n", "1:21: STEP needs a literal number");
4097 do_error_test("FOR i = 3 TO 1 STEP 0\n", "1:21: Infinite FOR loop; STEP cannot be 0");
4098 do_error_test("FOR i = 3 TO 1 STEP 0.0\n", "1:21: Infinite FOR loop; STEP cannot be 0");
4099
4100 do_error_test("FOR i = 3 TO 1", "1:15: Expecting newline after FOR");
4101 do_error_test("FOR i = 1 TO 3 STEP 1", "1:22: Expecting newline after FOR");
4102 do_error_test("FOR i = 3 TO 1 STEP -1", "1:23: Expecting newline after FOR");
4103
4104 do_error_test(" FOR i = 0 TO 10\nPRINT i\n", "1:5: FOR without NEXT");
4105 }
4106
4107 #[test]
4108 fn test_function_empty() {
4109 do_ok_test(
4110 "FUNCTION foo$\nEND FUNCTION",
4111 &[Statement::Callable(CallableSpan {
4112 name: VarRef::new("foo", Some(ExprType::Text)),
4113 name_pos: lc(1, 10),
4114 params: vec![],
4115 body: vec![],
4116 end_pos: lc(2, 1),
4117 })],
4118 );
4119 }
4120
4121 #[test]
4122 fn test_function_some_content() {
4123 do_ok_test(
4124 r#"
4125 FUNCTION foo$
4126 A
4127 END
4128 END 8
4129 B
4130 END FUNCTION
4131 "#,
4132 &[Statement::Callable(CallableSpan {
4133 name: VarRef::new("foo", Some(ExprType::Text)),
4134 name_pos: lc(2, 26),
4135 params: vec![],
4136 body: vec![
4137 make_bare_builtin_call("A", 3, 21),
4138 Statement::End(EndSpan { code: None }),
4139 Statement::End(EndSpan {
4140 code: Some(Expr::Integer(IntegerSpan { value: 8, pos: lc(5, 25) })),
4141 }),
4142 make_bare_builtin_call("B", 6, 21),
4143 ],
4144 end_pos: lc(7, 17),
4145 })],
4146 );
4147 }
4148
4149 #[test]
4150 fn test_function_one_param() {
4151 do_ok_test(
4152 "FUNCTION foo$(x)\nEND FUNCTION",
4153 &[Statement::Callable(CallableSpan {
4154 name: VarRef::new("foo", Some(ExprType::Text)),
4155 name_pos: lc(1, 10),
4156 params: vec![VarRef::new("x", None)],
4157 body: vec![],
4158 end_pos: lc(2, 1),
4159 })],
4160 );
4161 }
4162
4163 #[test]
4164 fn test_function_multiple_params() {
4165 do_ok_test(
4166 "FUNCTION foo$(x$, y, z AS BOOLEAN)\nEND FUNCTION",
4167 &[Statement::Callable(CallableSpan {
4168 name: VarRef::new("foo", Some(ExprType::Text)),
4169 name_pos: lc(1, 10),
4170 params: vec![
4171 VarRef::new("x", Some(ExprType::Text)),
4172 VarRef::new("y", None),
4173 VarRef::new("z", Some(ExprType::Boolean)),
4174 ],
4175 body: vec![],
4176 end_pos: lc(2, 1),
4177 })],
4178 );
4179 }
4180
4181 #[test]
4182 fn test_function_errors() {
4183 do_error_test("FUNCTION", "1:9: Expected a function name after FUNCTION");
4184 do_error_test("FUNCTION foo", "1:13: Expected newline after FUNCTION name");
4185 do_error_test("FUNCTION foo 3", "1:14: Expected newline after FUNCTION name");
4186 do_error_test("FUNCTION foo\nEND", "1:1: FUNCTION without END FUNCTION");
4187 do_error_test("FUNCTION foo\nEND IF", "2:1: END IF without IF");
4188 do_error_test("FUNCTION foo\nEND SUB", "2:1: END SUB without SUB");
4189 do_error_test(
4190 "FUNCTION foo\nFUNCTION bar\nEND FUNCTION\nEND FUNCTION",
4191 "2:1: Cannot nest FUNCTION or SUB definitions",
4192 );
4193 do_error_test(
4194 "FUNCTION foo\nSUB bar\nEND SUB\nEND FUNCTION",
4195 "2:1: Cannot nest FUNCTION or SUB definitions",
4196 );
4197 do_error_test("FUNCTION foo (", "1:15: Expected a parameter name");
4198 do_error_test("FUNCTION foo ()", "1:15: Expected a parameter name");
4199 do_error_test("FUNCTION foo (,)", "1:15: Expected a parameter name");
4200 do_error_test("FUNCTION foo (a,)", "1:17: Expected a parameter name");
4201 do_error_test("FUNCTION foo (,b)", "1:15: Expected a parameter name");
4202 do_error_test("FUNCTION foo (a AS)", "1:19: Invalid type name ) in AS type definition");
4203 do_error_test(
4204 "FUNCTION foo (a INTEGER)",
4205 "1:17: Expected comma, AS, or end of parameters list",
4206 );
4207 do_error_test("FUNCTION foo (a? AS BOOLEAN)", "1:15: Type annotation not allowed in a?");
4208 }
4209
4210 #[test]
4211 fn test_gosub_ok() {
4212 do_ok_test(
4213 "GOSUB 10",
4214 &[Statement::Gosub(GotoSpan { target: "10".to_owned(), target_pos: lc(1, 7) })],
4215 );
4216
4217 do_ok_test(
4218 "GOSUB @foo",
4219 &[Statement::Gosub(GotoSpan { target: "foo".to_owned(), target_pos: lc(1, 7) })],
4220 );
4221 }
4222
4223 #[test]
4224 fn test_gosub_errors() {
4225 do_error_test("GOSUB\n", "1:6: Expected label name after GOSUB");
4226 do_error_test("GOSUB foo\n", "1:7: Expected label name after GOSUB");
4227 do_error_test("GOSUB \"foo\"\n", "1:7: Expected label name after GOSUB");
4228 do_error_test("GOSUB @foo, @bar\n", "1:11: Expected newline but found ,");
4229 do_error_test("GOSUB @foo, 3\n", "1:11: Expected newline but found ,");
4230 }
4231
4232 #[test]
4233 fn test_goto_ok() {
4234 do_ok_test(
4235 "GOTO 10",
4236 &[Statement::Goto(GotoSpan { target: "10".to_owned(), target_pos: lc(1, 6) })],
4237 );
4238
4239 do_ok_test(
4240 "GOTO @foo",
4241 &[Statement::Goto(GotoSpan { target: "foo".to_owned(), target_pos: lc(1, 6) })],
4242 );
4243 }
4244
4245 #[test]
4246 fn test_goto_errors() {
4247 do_error_test("GOTO\n", "1:5: Expected label name after GOTO");
4248 do_error_test("GOTO foo\n", "1:6: Expected label name after GOTO");
4249 do_error_test("GOTO \"foo\"\n", "1:6: Expected label name after GOTO");
4250 do_error_test("GOTO @foo, @bar\n", "1:10: Expected newline but found ,");
4251 do_error_test("GOTO @foo, 3\n", "1:10: Expected newline but found ,");
4252 }
4253
4254 #[test]
4255 fn test_label_own_line() {
4256 do_ok_test(
4257 "@foo\nPRINT",
4258 &[
4259 Statement::Label(LabelSpan { name: "foo".to_owned(), name_pos: lc(1, 1) }),
4260 make_bare_builtin_call("PRINT", 2, 1),
4261 ],
4262 );
4263 }
4264
4265 #[test]
4266 fn test_label_before_statement() {
4267 do_ok_test(
4268 "@foo PRINT",
4269 &[
4270 Statement::Label(LabelSpan { name: "foo".to_owned(), name_pos: lc(1, 1) }),
4271 make_bare_builtin_call("PRINT", 1, 6),
4272 ],
4273 );
4274 }
4275
4276 #[test]
4277 fn test_label_multiple_same_line() {
4278 do_ok_test(
4279 "@foo @bar",
4280 &[
4281 Statement::Label(LabelSpan { name: "foo".to_owned(), name_pos: lc(1, 1) }),
4282 Statement::Label(LabelSpan { name: "bar".to_owned(), name_pos: lc(1, 6) }),
4283 ],
4284 );
4285 }
4286
4287 #[test]
4288 fn test_label_errors() {
4289 do_error_test("PRINT @foo", "1:7: Unexpected keyword in expression");
4290 }
4291
4292 #[test]
4293 fn test_parse_on_error_ok() {
4294 do_ok_test("ON ERROR GOTO 0", &[Statement::OnError(OnErrorSpan::Reset)]);
4295
4296 do_ok_test(
4297 "ON ERROR GOTO 10",
4298 &[Statement::OnError(OnErrorSpan::Goto(GotoSpan {
4299 target: "10".to_owned(),
4300 target_pos: lc(1, 15),
4301 }))],
4302 );
4303
4304 do_ok_test(
4305 "ON ERROR GOTO @foo",
4306 &[Statement::OnError(OnErrorSpan::Goto(GotoSpan {
4307 target: "foo".to_owned(),
4308 target_pos: lc(1, 15),
4309 }))],
4310 );
4311
4312 do_ok_test("ON ERROR RESUME NEXT", &[Statement::OnError(OnErrorSpan::ResumeNext)]);
4313 }
4314
4315 #[test]
4316 fn test_parse_on_error_errors() {
4317 do_error_test("ON", "1:3: Expected ERROR after ON");
4318 do_error_test("ON NEXT", "1:4: Expected ERROR after ON");
4319 do_error_test("ON ERROR", "1:9: Expected GOTO or RESUME after ON ERROR");
4320 do_error_test("ON ERROR FOR", "1:10: Expected GOTO or RESUME after ON ERROR");
4321
4322 do_error_test("ON ERROR RESUME", "1:16: Expected NEXT after ON ERROR RESUME");
4323 do_error_test("ON ERROR RESUME 3", "1:17: Expected NEXT after ON ERROR RESUME");
4324 do_error_test("ON ERROR RESUME NEXT 3", "1:22: Expected newline but found 3");
4325
4326 do_error_test("ON ERROR GOTO", "1:14: Expected label name or 0 after ON ERROR GOTO");
4327 do_error_test("ON ERROR GOTO NEXT", "1:15: Expected label name or 0 after ON ERROR GOTO");
4328 do_error_test("ON ERROR GOTO 0 @a", "1:17: Expected newline but found @a");
4329 }
4330
4331 #[test]
4332 fn test_select_empty() {
4333 do_ok_test(
4334 "SELECT CASE 7\nEND SELECT",
4335 &[Statement::Select(SelectSpan {
4336 expr: expr_integer(7, 1, 13),
4337 cases: vec![],
4338 end_pos: lc(2, 1),
4339 })],
4340 );
4341
4342 do_ok_test(
4343 "SELECT CASE 5 - TRUE\n \nEND SELECT",
4344 &[Statement::Select(SelectSpan {
4345 expr: Expr::Subtract(Box::from(BinaryOpSpan {
4346 lhs: expr_integer(5, 1, 13),
4347 rhs: expr_boolean(true, 1, 17),
4348 pos: lc(1, 15),
4349 })),
4350 cases: vec![],
4351 end_pos: lc(3, 1),
4352 })],
4353 );
4354 }
4355
4356 #[test]
4357 fn test_select_case_else_only() {
4358 do_ok_test(
4359 "SELECT CASE 7\nCASE ELSE\nA\nEND SELECT",
4360 &[Statement::Select(SelectSpan {
4361 expr: expr_integer(7, 1, 13),
4362 cases: vec![CaseSpan {
4363 guards: vec![],
4364 body: vec![make_bare_builtin_call("A", 3, 1)],
4365 }],
4366 end_pos: lc(4, 1),
4367 })],
4368 );
4369 }
4370
4371 #[test]
4372 fn test_select_multiple_cases_without_else() {
4373 do_ok_test(
4374 "SELECT CASE 7\nCASE 1\nA\nCASE 2\nB\nEND SELECT",
4375 &[Statement::Select(SelectSpan {
4376 expr: expr_integer(7, 1, 13),
4377 cases: vec![
4378 CaseSpan {
4379 guards: vec![CaseGuardSpan::Is(CaseRelOp::Equal, expr_integer(1, 2, 6))],
4380 body: vec![make_bare_builtin_call("A", 3, 1)],
4381 },
4382 CaseSpan {
4383 guards: vec![CaseGuardSpan::Is(CaseRelOp::Equal, expr_integer(2, 4, 6))],
4384 body: vec![make_bare_builtin_call("B", 5, 1)],
4385 },
4386 ],
4387 end_pos: lc(6, 1),
4388 })],
4389 );
4390 }
4391
4392 #[test]
4393 fn test_select_multiple_cases_with_else() {
4394 do_ok_test(
4395 "SELECT CASE 7\nCASE 1\nA\nCASE 2\nB\nCASE ELSE\nC\nEND SELECT",
4396 &[Statement::Select(SelectSpan {
4397 expr: expr_integer(7, 1, 13),
4398 cases: vec![
4399 CaseSpan {
4400 guards: vec![CaseGuardSpan::Is(CaseRelOp::Equal, expr_integer(1, 2, 6))],
4401 body: vec![make_bare_builtin_call("A", 3, 1)],
4402 },
4403 CaseSpan {
4404 guards: vec![CaseGuardSpan::Is(CaseRelOp::Equal, expr_integer(2, 4, 6))],
4405 body: vec![make_bare_builtin_call("B", 5, 1)],
4406 },
4407 CaseSpan { guards: vec![], body: vec![make_bare_builtin_call("C", 7, 1)] },
4408 ],
4409 end_pos: lc(8, 1),
4410 })],
4411 );
4412 }
4413
4414 #[test]
4415 fn test_select_multiple_cases_empty_bodies() {
4416 do_ok_test(
4417 "SELECT CASE 7\nCASE 1\n\nCASE 2\n\nCASE ELSE\n\nEND SELECT",
4418 &[Statement::Select(SelectSpan {
4419 expr: expr_integer(7, 1, 13),
4420 cases: vec![
4421 CaseSpan {
4422 guards: vec![CaseGuardSpan::Is(CaseRelOp::Equal, expr_integer(1, 2, 6))],
4423 body: vec![],
4424 },
4425 CaseSpan {
4426 guards: vec![CaseGuardSpan::Is(CaseRelOp::Equal, expr_integer(2, 4, 6))],
4427 body: vec![],
4428 },
4429 CaseSpan { guards: vec![], body: vec![] },
4430 ],
4431 end_pos: lc(8, 1),
4432 })],
4433 );
4434 }
4435
4436 #[test]
4437 fn test_select_multiple_cases_with_interleaved_end() {
4438 let code = r#"
4439 SELECT CASE 7
4440 CASE 1
4441 A
4442 END
4443 B
4444 CASE 2 ' Second case.
4445 C
4446 END 8
4447 D
4448 CASE ELSE
4449 E
4450 END
4451 F
4452 END SELECT
4453 "#;
4454 do_ok_test(
4455 code,
4456 &[Statement::Select(SelectSpan {
4457 expr: expr_integer(7, 2, 25),
4458 cases: vec![
4459 CaseSpan {
4460 guards: vec![CaseGuardSpan::Is(CaseRelOp::Equal, expr_integer(1, 3, 22))],
4461 body: vec![
4462 make_bare_builtin_call("A", 4, 21),
4463 Statement::End(EndSpan { code: None }),
4464 make_bare_builtin_call("B", 6, 21),
4465 ],
4466 },
4467 CaseSpan {
4468 guards: vec![CaseGuardSpan::Is(CaseRelOp::Equal, expr_integer(2, 7, 22))],
4469 body: vec![
4470 make_bare_builtin_call("C", 8, 21),
4471 Statement::End(EndSpan {
4472 code: Some(Expr::Integer(IntegerSpan { value: 8, pos: lc(9, 25) })),
4473 }),
4474 make_bare_builtin_call("D", 10, 21),
4475 ],
4476 },
4477 CaseSpan {
4478 guards: vec![],
4479 body: vec![
4480 make_bare_builtin_call("E", 12, 21),
4481 Statement::End(EndSpan { code: None }),
4482 make_bare_builtin_call("F", 14, 21),
4483 ],
4484 },
4485 ],
4486 end_pos: lc(15, 13),
4487 })],
4488 );
4489 }
4490
4491 #[test]
4492 fn test_select_case_guards_equals() {
4493 do_ok_test(
4494 "SELECT CASE 7: CASE 9, 10, FALSE: END SELECT",
4495 &[Statement::Select(SelectSpan {
4496 expr: expr_integer(7, 1, 13),
4497 cases: vec![CaseSpan {
4498 guards: vec![
4499 CaseGuardSpan::Is(CaseRelOp::Equal, expr_integer(9, 1, 21)),
4500 CaseGuardSpan::Is(CaseRelOp::Equal, expr_integer(10, 1, 24)),
4501 CaseGuardSpan::Is(CaseRelOp::Equal, expr_boolean(false, 1, 28)),
4502 ],
4503 body: vec![],
4504 }],
4505 end_pos: lc(1, 35),
4506 })],
4507 );
4508 }
4509
4510 #[test]
4511 fn test_select_case_guards_is() {
4512 do_ok_test(
4513 "SELECT CASE 7: CASE IS = 1, IS <> 2, IS < 3, IS <= 4, IS > 5, IS >= 6: END SELECT",
4514 &[Statement::Select(SelectSpan {
4515 expr: expr_integer(7, 1, 13),
4516 cases: vec![CaseSpan {
4517 guards: vec![
4518 CaseGuardSpan::Is(CaseRelOp::Equal, expr_integer(1, 1, 26)),
4519 CaseGuardSpan::Is(CaseRelOp::NotEqual, expr_integer(2, 1, 35)),
4520 CaseGuardSpan::Is(CaseRelOp::Less, expr_integer(3, 1, 43)),
4521 CaseGuardSpan::Is(CaseRelOp::LessEqual, expr_integer(4, 1, 52)),
4522 CaseGuardSpan::Is(CaseRelOp::Greater, expr_integer(5, 1, 60)),
4523 CaseGuardSpan::Is(CaseRelOp::GreaterEqual, expr_integer(6, 1, 69)),
4524 ],
4525 body: vec![],
4526 }],
4527 end_pos: lc(1, 72),
4528 })],
4529 );
4530 }
4531
4532 #[test]
4533 fn test_select_case_guards_to() {
4534 do_ok_test(
4535 "SELECT CASE 7: CASE 1 TO 20, 10 TO 1: END SELECT",
4536 &[Statement::Select(SelectSpan {
4537 expr: expr_integer(7, 1, 13),
4538 cases: vec![CaseSpan {
4539 guards: vec![
4540 CaseGuardSpan::To(expr_integer(1, 1, 21), expr_integer(20, 1, 26)),
4541 CaseGuardSpan::To(expr_integer(10, 1, 30), expr_integer(1, 1, 36)),
4542 ],
4543 body: vec![],
4544 }],
4545 end_pos: lc(1, 39),
4546 })],
4547 );
4548 }
4549
4550 #[test]
4551 fn test_select_errors() {
4552 do_error_test("SELECT\n", "1:7: Expecting CASE after SELECT");
4553 do_error_test("SELECT CASE\n", "1:12: No expression in SELECT CASE statement");
4554 do_error_test("SELECT CASE 3 + 7", "1:18: Expecting newline after SELECT CASE");
4555 do_error_test("SELECT CASE 3 + 7 ,", "1:19: Expecting newline after SELECT CASE");
4556 do_error_test("SELECT CASE 3 + 7 IF", "1:19: Unexpected keyword in expression");
4557
4558 do_error_test("SELECT CASE 1\n", "1:1: SELECT without END SELECT");
4559
4560 do_error_test(
4561 "SELECT CASE 1\nEND",
4562 "2:1: Expected CASE after SELECT CASE before any statement",
4563 );
4564 do_error_test(
4565 "SELECT CASE 1\nEND IF",
4566 "2:1: Expected CASE after SELECT CASE before any statement",
4567 );
4568 do_error_test(
4569 "SELECT CASE 1\na = 1",
4570 "2:1: Expected CASE after SELECT CASE before any statement",
4571 );
4572
4573 do_error_test(
4574 "SELECT CASE 1\nCASE 1",
4575 "2:7: Expected comma, newline, or TO after expression",
4576 );
4577 do_error_test("SELECT CASE 1\nCASE ELSE", "2:10: Expecting newline after CASE");
4578
4579 do_error_test("SELECT CASE 1\nCASE ELSE\nEND", "1:1: SELECT without END SELECT");
4580 do_error_test("SELECT CASE 1\nCASE ELSE\nEND IF", "3:1: END IF without IF");
4581
4582 do_error_test("SELECT CASE 1\nCASE ELSE\nCASE ELSE\n", "3:1: CASE ELSE must be unique");
4583 do_error_test("SELECT CASE 1\nCASE ELSE\nCASE 1\n", "3:1: CASE ELSE is not last");
4584 }
4585
4586 #[test]
4587 fn test_select_case_errors() {
4588 fn do_case_error_test(cases: &str, exp_error: &str) {
4589 do_error_test(&format!("SELECT CASE 1\nCASE {}\n", cases), exp_error);
4590 }
4591
4592 do_case_error_test("ELSE, ELSE", "2:10: Expected newline after CASE ELSE");
4593 do_case_error_test("ELSE, 7", "2:10: Expected newline after CASE ELSE");
4594 do_case_error_test("7, ELSE", "2:9: CASE ELSE must be on its own");
4595
4596 do_case_error_test("IS 7", "2:9: Expected relational operator");
4597 do_case_error_test("IS AND", "2:9: Expected relational operator");
4598 do_case_error_test("IS END", "2:9: Expected relational operator");
4599
4600 do_case_error_test("IS <>", "2:11: Missing expression after relational operator");
4601 do_case_error_test("IS <> IF", "2:12: Unexpected keyword in expression");
4602
4603 do_case_error_test("", "2:6: Missing expression in CASE guard");
4604 do_case_error_test("2 + 5 TO", "2:14: Missing expression after TO in CASE guard");
4605 do_case_error_test("2 + 5 TO AS", "2:15: Missing expression after TO in CASE guard");
4606 do_case_error_test(
4607 "2 + 5 TO 8 AS",
4608 "2:17: Expected comma, newline, or TO after expression",
4609 );
4610 }
4611
4612 #[test]
4613 fn test_sub_empty() {
4614 do_ok_test(
4615 "SUB foo\nEND SUB",
4616 &[Statement::Callable(CallableSpan {
4617 name: VarRef::new("foo", None),
4618 name_pos: lc(1, 5),
4619 params: vec![],
4620 body: vec![],
4621 end_pos: lc(2, 1),
4622 })],
4623 );
4624 }
4625
4626 #[test]
4627 fn test_sub_some_content() {
4628 do_ok_test(
4629 r#"
4630 SUB foo
4631 A
4632 END
4633 END 8
4634 B
4635 END SUB
4636 "#,
4637 &[Statement::Callable(CallableSpan {
4638 name: VarRef::new("foo", None),
4639 name_pos: lc(2, 21),
4640 params: vec![],
4641 body: vec![
4642 make_bare_builtin_call("A", 3, 21),
4643 Statement::End(EndSpan { code: None }),
4644 Statement::End(EndSpan {
4645 code: Some(Expr::Integer(IntegerSpan { value: 8, pos: lc(5, 25) })),
4646 }),
4647 make_bare_builtin_call("B", 6, 21),
4648 ],
4649 end_pos: lc(7, 17),
4650 })],
4651 );
4652 }
4653
4654 #[test]
4655 fn test_sub_one_param() {
4656 do_ok_test(
4657 "SUB foo(x)\nEND SUB",
4658 &[Statement::Callable(CallableSpan {
4659 name: VarRef::new("foo", None),
4660 name_pos: lc(1, 5),
4661 params: vec![VarRef::new("x", None)],
4662 body: vec![],
4663 end_pos: lc(2, 1),
4664 })],
4665 );
4666 }
4667
4668 #[test]
4669 fn test_sub_multiple_params() {
4670 do_ok_test(
4671 "SUB foo(x$, y, z AS BOOLEAN)\nEND SUB",
4672 &[Statement::Callable(CallableSpan {
4673 name: VarRef::new("foo", None),
4674 name_pos: lc(1, 5),
4675 params: vec![
4676 VarRef::new("x", Some(ExprType::Text)),
4677 VarRef::new("y", None),
4678 VarRef::new("z", Some(ExprType::Boolean)),
4679 ],
4680 body: vec![],
4681 end_pos: lc(2, 1),
4682 })],
4683 );
4684 }
4685
4686 #[test]
4687 fn test_sub_errors() {
4688 do_error_test("SUB", "1:4: Expected a function name after SUB");
4689 do_error_test("SUB foo", "1:8: Expected newline after SUB name");
4690 do_error_test("SUB foo 3", "1:9: Expected newline after SUB name");
4691 do_error_test("SUB foo\nEND", "1:1: SUB without END SUB");
4692 do_error_test("SUB foo\nEND IF", "2:1: END IF without IF");
4693 do_error_test("SUB foo\nEND FUNCTION", "2:1: END FUNCTION without FUNCTION");
4694 do_error_test(
4695 "SUB foo\nSUB bar\nEND SUB\nEND SUB",
4696 "2:1: Cannot nest FUNCTION or SUB definitions",
4697 );
4698 do_error_test(
4699 "SUB foo\nFUNCTION bar\nEND FUNCTION\nEND SUB",
4700 "2:1: Cannot nest FUNCTION or SUB definitions",
4701 );
4702 do_error_test("SUB foo (", "1:10: Expected a parameter name");
4703 do_error_test("SUB foo ()", "1:10: Expected a parameter name");
4704 do_error_test("SUB foo (,)", "1:10: Expected a parameter name");
4705 do_error_test("SUB foo (a,)", "1:12: Expected a parameter name");
4706 do_error_test("SUB foo (,b)", "1:10: Expected a parameter name");
4707 do_error_test("SUB foo (a AS)", "1:14: Invalid type name ) in AS type definition");
4708 do_error_test("SUB foo (a INTEGER)", "1:12: Expected comma, AS, or end of parameters list");
4709 do_error_test("SUB foo (a? AS BOOLEAN)", "1:10: Type annotation not allowed in a?");
4710 do_error_test(
4711 "SUB foo$",
4712 "1:5: SUBs cannot return a value so type annotations are not allowed",
4713 );
4714 do_error_test(
4715 "SUB foo$\nEND SUB",
4716 "1:5: SUBs cannot return a value so type annotations are not allowed",
4717 );
4718 }
4719
4720 #[test]
4721 fn test_while_empty() {
4722 do_ok_test(
4723 "WHILE 2 + 3\nWEND",
4724 &[Statement::While(WhileSpan {
4725 expr: Expr::Add(Box::from(BinaryOpSpan {
4726 lhs: expr_integer(2, 1, 7),
4727 rhs: expr_integer(3, 1, 11),
4728 pos: lc(1, 9),
4729 })),
4730 body: vec![],
4731 })],
4732 );
4733 do_ok_test(
4734 "WHILE 5\n\nREM foo\n\nWEND\n",
4735 &[Statement::While(WhileSpan { expr: expr_integer(5, 1, 7), body: vec![] })],
4736 );
4737 }
4738
4739 #[test]
4740 fn test_while_loops() {
4741 do_ok_test(
4742 "WHILE TRUE\nA\nB\nWEND",
4743 &[Statement::While(WhileSpan {
4744 expr: expr_boolean(true, 1, 7),
4745 body: vec![make_bare_builtin_call("A", 2, 1), make_bare_builtin_call("B", 3, 1)],
4746 })],
4747 );
4748 }
4749
4750 #[test]
4751 fn test_while_nested() {
4752 let code = r#"
4753 WHILE TRUE
4754 A
4755 WHILE FALSE
4756 B
4757 WEND
4758 C
4759 WEND
4760 "#;
4761 do_ok_test(
4762 code,
4763 &[Statement::While(WhileSpan {
4764 expr: expr_boolean(true, 2, 19),
4765 body: vec![
4766 make_bare_builtin_call("A", 3, 17),
4767 Statement::While(WhileSpan {
4768 expr: expr_boolean(false, 4, 23),
4769 body: vec![make_bare_builtin_call("B", 5, 21)],
4770 }),
4771 make_bare_builtin_call("C", 7, 17),
4772 ],
4773 })],
4774 );
4775 }
4776
4777 #[test]
4778 fn test_while_errors() {
4779 do_error_test("WHILE\n", "1:6: No expression in WHILE statement");
4780 do_error_test("WHILE TRUE", "1:11: Expecting newline after WHILE");
4781 do_error_test("\n\nWHILE TRUE\n", "3:1: WHILE without WEND");
4782 do_error_test("WHILE TRUE\nEND", "1:1: WHILE without WEND");
4783 do_error_test("WHILE TRUE\nEND\n", "1:1: WHILE without WEND");
4784 do_error_test("WHILE TRUE\nEND WHILE\n", "2:5: Unexpected keyword in expression");
4785
4786 do_error_test("WHILE ,\nWEND", "1:7: No expression in WHILE statement");
4787 do_error_test("WHILE ,\nEND", "1:7: No expression in WHILE statement");
4788 }
4789}