endbasic_core/ast.rs
1// EndBASIC
2// Copyright 2020 Julio Merino
3//
4// Licensed under the Apache License, Version 2.0 (the "License"); you may not
5// use this file except in compliance with the License. You may obtain a copy
6// of the License at:
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13// License for the specific language governing permissions and limitations
14// under the License.
15
16//! Abstract Syntax Tree (AST) for the EndBASIC language.
17
18use crate::{reader::LineCol, syms::SymbolKey};
19use std::fmt;
20
21/// Components of a boolean literal expression.
22#[derive(Clone, Debug, Eq, PartialEq)]
23pub struct BooleanSpan {
24 /// The boolean literal.
25 pub value: bool,
26
27 /// Starting position of the literal.
28 pub pos: LineCol,
29}
30
31/// Components of a double literal expression.
32#[derive(Clone, Debug, PartialEq)]
33pub struct DoubleSpan {
34 /// The double literal.
35 pub value: f64,
36
37 /// Starting position of the literal.
38 pub pos: LineCol,
39}
40
41/// Components of an integer literal expression.
42#[derive(Clone, Debug, Eq, PartialEq)]
43pub struct IntegerSpan {
44 /// The integer literal.
45 pub value: i32,
46
47 /// Starting position of the literal.
48 pub pos: LineCol,
49}
50
51/// Components of a string literal expression.
52#[derive(Clone, Debug, Eq, PartialEq)]
53pub struct TextSpan {
54 /// The string literal.
55 pub value: String,
56
57 /// Starting position of the literal.
58 pub pos: LineCol,
59}
60
61/// Components of a symbol reference expression.
62#[derive(Clone, Debug, Eq, PartialEq)]
63pub struct SymbolSpan {
64 /// The symbol reference.
65 pub vref: VarRef,
66
67 /// Starting position of the symbol reference.
68 pub pos: LineCol,
69}
70
71/// Components of a unary operation expression.
72#[derive(Clone, Debug, PartialEq)]
73pub struct UnaryOpSpan {
74 /// Expression affected by the operator.
75 pub expr: Expr,
76
77 /// Starting position of the operator.
78 pub pos: LineCol,
79}
80
81/// Components of a binary operation expression.
82#[derive(Clone, Debug, PartialEq)]
83pub struct BinaryOpSpan {
84 /// Expression on the left side of the operator.
85 pub lhs: Expr,
86
87 /// Expression on the right side of the operator.
88 pub rhs: Expr,
89
90 /// Starting position of the operator.
91 pub pos: LineCol,
92}
93
94/// Represents an expression and provides mechanisms to evaluate it.
95#[derive(Clone, Debug, PartialEq)]
96pub enum Expr {
97 /// A literal boolean value.
98 Boolean(BooleanSpan),
99 /// A literal double-precision floating point value.
100 Double(DoubleSpan),
101 /// A literal integer value.
102 Integer(IntegerSpan),
103 /// A literal string value.
104 Text(TextSpan),
105
106 /// A reference to a variable.
107 Symbol(SymbolSpan),
108
109 /// Arithmetic addition of two expressions.
110 Add(Box<BinaryOpSpan>),
111 /// Arithmetic subtraction of two expressions.
112 Subtract(Box<BinaryOpSpan>),
113 /// Arithmetic multiplication of two expressions.
114 Multiply(Box<BinaryOpSpan>),
115 /// Arithmetic division of two expressions.
116 Divide(Box<BinaryOpSpan>),
117 /// Arithmetic modulo operation of two expressions.
118 Modulo(Box<BinaryOpSpan>),
119 /// Arithmetic power operation of two expressions.
120 Power(Box<BinaryOpSpan>),
121 /// Arithmetic sign flip of an expression.
122 Negate(Box<UnaryOpSpan>),
123
124 /// Relational equality comparison of two expressions.
125 Equal(Box<BinaryOpSpan>),
126 /// Relational inequality comparison of two expressions.
127 NotEqual(Box<BinaryOpSpan>),
128 /// Relational less-than comparison of two expressions.
129 Less(Box<BinaryOpSpan>),
130 /// Relational less-than or equal-to comparison of two expressions.
131 LessEqual(Box<BinaryOpSpan>),
132 /// Relational greater-than comparison of two expressions.
133 Greater(Box<BinaryOpSpan>),
134 /// Relational greater-than or equal-to comparison of two expressions.
135 GreaterEqual(Box<BinaryOpSpan>),
136
137 /// Logical and of two expressions.
138 And(Box<BinaryOpSpan>),
139 /// Logical not of an expression.
140 Not(Box<UnaryOpSpan>),
141 /// Logical or of two expressions.
142 Or(Box<BinaryOpSpan>),
143 /// Logical xor of two expressions.
144 Xor(Box<BinaryOpSpan>),
145
146 /// Shift left of a signed integer by a number of bits without rotation.
147 ShiftLeft(Box<BinaryOpSpan>),
148 /// Shift right of a signed integer by a number of bits without rotation.
149 ShiftRight(Box<BinaryOpSpan>),
150
151 /// A function call or an array reference.
152 Call(CallSpan),
153}
154
155impl Expr {
156 /// Returns the start position of the expression.
157 pub fn start_pos(&self) -> LineCol {
158 match self {
159 Expr::Boolean(span) => span.pos,
160 Expr::Double(span) => span.pos,
161 Expr::Integer(span) => span.pos,
162 Expr::Text(span) => span.pos,
163
164 Expr::Symbol(span) => span.pos,
165
166 Expr::And(span) => span.lhs.start_pos(),
167 Expr::Or(span) => span.lhs.start_pos(),
168 Expr::Xor(span) => span.lhs.start_pos(),
169 Expr::Not(span) => span.pos,
170
171 Expr::ShiftLeft(span) => span.lhs.start_pos(),
172 Expr::ShiftRight(span) => span.lhs.start_pos(),
173
174 Expr::Equal(span) => span.lhs.start_pos(),
175 Expr::NotEqual(span) => span.lhs.start_pos(),
176 Expr::Less(span) => span.lhs.start_pos(),
177 Expr::LessEqual(span) => span.lhs.start_pos(),
178 Expr::Greater(span) => span.lhs.start_pos(),
179 Expr::GreaterEqual(span) => span.lhs.start_pos(),
180
181 Expr::Add(span) => span.lhs.start_pos(),
182 Expr::Subtract(span) => span.lhs.start_pos(),
183 Expr::Multiply(span) => span.lhs.start_pos(),
184 Expr::Divide(span) => span.lhs.start_pos(),
185 Expr::Modulo(span) => span.lhs.start_pos(),
186 Expr::Power(span) => span.lhs.start_pos(),
187 Expr::Negate(span) => span.pos,
188
189 Expr::Call(span) => span.vref_pos,
190 }
191 }
192}
193
194/// Represents type of an expression.
195#[derive(Clone, Copy, Debug, Eq, PartialEq)]
196pub enum ExprType {
197 /// Type for an expression that evaluates to a boolean.
198 Boolean,
199
200 /// Type for an expression that evaluates to a double.
201 Double,
202
203 /// Type for an expression that evaluates to an integer.
204 Integer,
205
206 /// Type for an expression that evaluates to a string.
207 Text,
208}
209
210impl ExprType {
211 /// Returns true if this expression type is numerical.
212 pub(crate) fn is_numerical(self) -> bool {
213 self == Self::Double || self == Self::Integer
214 }
215
216 /// Returns the textual representation of the annotation for this type.
217 pub fn annotation(&self) -> char {
218 match self {
219 ExprType::Boolean => '?',
220 ExprType::Double => '#',
221 ExprType::Integer => '%',
222 ExprType::Text => '$',
223 }
224 }
225
226 /// Returns the default value to assign to this type.
227 pub(crate) fn default_value(&self) -> Value {
228 match self {
229 ExprType::Boolean => Value::Boolean(false),
230 ExprType::Double => Value::Double(0.0),
231 ExprType::Integer => Value::Integer(0),
232 ExprType::Text => Value::Text("".to_owned()),
233 }
234 }
235}
236
237impl fmt::Display for ExprType {
238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239 match self {
240 ExprType::Boolean => write!(f, "BOOLEAN"),
241 ExprType::Double => write!(f, "DOUBLE"),
242 ExprType::Integer => write!(f, "INTEGER"),
243 ExprType::Text => write!(f, "STRING"),
244 }
245 }
246}
247
248/// Represents a reference to a variable (which doesn't have to exist).
249///
250/// Variable references are different from `SymbolKey`s because they maintain the case of the
251/// reference (for error display purposes) and because they carry an optional type annotation.
252#[derive(Clone, Debug, Eq, PartialEq)]
253pub struct VarRef {
254 /// Name of the variable this points to.
255 name: String,
256
257 /// Type of the variable this points to, if explicitly specified.
258 ///
259 /// If `None`, the type of the variable is subject to type inference.
260 ref_type: Option<ExprType>,
261}
262
263impl VarRef {
264 /// Creates a new reference to the variable with `name` and the optional `ref_type` type.
265 pub fn new<T: Into<String>>(name: T, ref_type: Option<ExprType>) -> Self {
266 Self { name: name.into(), ref_type }
267 }
268
269 /// Returns the name of this reference, without any type annotations.
270 pub fn name(&self) -> &str {
271 &self.name
272 }
273
274 /// Returns the name of this reference, without any type annotations, and consumes the
275 /// reference.
276 pub(crate) fn take_name(self) -> String {
277 self.name
278 }
279
280 /// Returns the type of this reference.
281 pub fn ref_type(&self) -> Option<ExprType> {
282 self.ref_type
283 }
284
285 /// Returns true if this reference is compatible with the given type.
286 pub fn accepts(&self, other: ExprType) -> bool {
287 match self.ref_type {
288 None => true,
289 Some(vtype) => vtype == other,
290 }
291 }
292
293 /// Returns true if this reference is compatible with the return type of a callable.
294 pub fn accepts_callable(&self, other: Option<ExprType>) -> bool {
295 match self.ref_type {
296 None => true,
297 Some(vtype) => match other {
298 Some(other) => vtype == other,
299 None => false,
300 },
301 }
302 }
303
304 /// Converts this variable reference to a symbol key.
305 pub(crate) fn as_symbol_key(&self) -> SymbolKey {
306 SymbolKey::from(&self.name)
307 }
308}
309
310impl fmt::Display for VarRef {
311 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
312 match self.ref_type {
313 None => self.name.fmt(f),
314 Some(vtype) => write!(f, "{}{}", self.name, vtype.annotation()),
315 }
316 }
317}
318
319/// Represents an evaluated value.
320#[derive(Clone, Debug, PartialEq)]
321pub enum Value {
322 /// A boolean value.
323 Boolean(bool),
324
325 /// A double-precision floating point value.
326 Double(f64),
327
328 /// An integer value.
329 Integer(i32),
330
331 /// A string value.
332 Text(String), // Should be `String` but would get confusing with the built-in Rust type.
333
334 /// A reference to a variable.
335 VarRef(SymbolKey, ExprType),
336}
337
338impl From<bool> for Value {
339 fn from(b: bool) -> Self {
340 Value::Boolean(b)
341 }
342}
343
344impl From<f64> for Value {
345 fn from(d: f64) -> Self {
346 Value::Double(d)
347 }
348}
349
350impl From<i32> for Value {
351 fn from(i: i32) -> Self {
352 Value::Integer(i)
353 }
354}
355
356impl From<&str> for Value {
357 fn from(s: &str) -> Self {
358 Value::Text(s.to_owned())
359 }
360}
361
362impl fmt::Display for Value {
363 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364 match self {
365 Value::Boolean(true) => write!(f, "TRUE"),
366 Value::Boolean(false) => write!(f, "FALSE"),
367 Value::Double(d) => {
368 let mut s = format!("{}", d);
369 if d.is_finite() && !d.is_nan() && !s.contains('.') {
370 s += ".0";
371 }
372 write!(f, "{}", s)
373 }
374 Value::Integer(i) => write!(f, "{}", i),
375 Value::Text(s) => write!(f, "\"{}\"", s),
376 Value::VarRef(key, etype) => write!(f, "{}{}", key, etype),
377 }
378 }
379}
380
381impl Value {
382 /// Returns the type of the value as an `ExprType`.
383 pub fn as_exprtype(&self) -> ExprType {
384 match self {
385 Value::Boolean(_) => ExprType::Boolean,
386 Value::Double(_) => ExprType::Double,
387 Value::Integer(_) => ExprType::Integer,
388 Value::Text(_) => ExprType::Text,
389 Value::VarRef(_key, etype) => *etype,
390 }
391 }
392}
393
394/// Types of separators between arguments to a `BuiltinCall`.
395#[derive(Clone, Copy, Debug, Eq, PartialEq)]
396pub enum ArgSep {
397 /// Filler for the separator in the last argument.
398 End = 0,
399
400 /// Short separator (`;`).
401 Short = 1,
402
403 /// Long separator (`,`).
404 Long = 2,
405
406 /// `AS` separator.
407 As = 3,
408}
409
410impl fmt::Display for ArgSep {
411 // TODO(jmmv): Can this be removed in favor of describe()?
412 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
413 match self {
414 ArgSep::End => write!(f, "<END OF STATEMENT>"),
415 ArgSep::Short => write!(f, ";"),
416 ArgSep::Long => write!(f, ","),
417 ArgSep::As => write!(f, "AS"),
418 }
419 }
420}
421
422impl ArgSep {
423 /// Formats the separator for a syntax specification.
424 ///
425 /// The return value contains the textual representation of the separator and a boolean that
426 /// indicates whether the separator requires a leading space.
427 pub(crate) fn describe(&self) -> (&str, bool) {
428 match self {
429 ArgSep::End => ("", false),
430 ArgSep::Short => (";", false),
431 ArgSep::Long => (",", false),
432 ArgSep::As => ("AS", true),
433 }
434 }
435}
436
437/// Components of an array assignment statement.
438#[derive(Debug, PartialEq)]
439#[cfg_attr(test, derive(Clone))]
440pub struct ArrayAssignmentSpan {
441 /// Reference to the array to modify.
442 pub vref: VarRef,
443
444 /// Position of the `vref`.
445 pub vref_pos: LineCol,
446
447 /// Expressions to compute the subscripts to index the array.
448 pub subscripts: Vec<Expr>,
449
450 /// Expression to compute the value of the modified element.
451 pub expr: Expr,
452}
453
454/// Components of an assignment statement.
455#[derive(Debug, PartialEq)]
456#[cfg_attr(test, derive(Clone))]
457pub struct AssignmentSpan {
458 /// Reference to the variable to set.
459 pub vref: VarRef,
460
461 /// Position of the `vref`.
462 pub vref_pos: LineCol,
463
464 /// Expression to compute the value of the modified variable.
465 pub expr: Expr,
466}
467
468/// Single argument to a builtin call statement.
469#[derive(Clone, Debug, PartialEq)]
470pub struct ArgSpan {
471 /// Expression to compute the argument's value. This expression is optional to support calls
472 /// of the form `PRINT a, , b` where some arguments are empty.
473 pub expr: Option<Expr>,
474
475 /// Separator between this argument and the *next*. The last instance of this type in a call
476 /// always carries a value of `ArgSep::End`.
477 pub sep: ArgSep,
478
479 /// Position of the `sep`.
480 pub sep_pos: LineCol,
481}
482
483/// Components of a call statement or expression.
484#[derive(Clone, Debug, PartialEq)]
485pub struct CallSpan {
486 /// Reference to the callable (a command or a function), or the array to index.
487 pub vref: VarRef,
488
489 /// Position of the reference.
490 pub vref_pos: LineCol,
491
492 /// Sequence of arguments to pass to the callable.
493 pub args: Vec<ArgSpan>,
494}
495
496/// Components of a `FUNCTION` or `SUB` definition.
497#[derive(Debug, PartialEq)]
498pub struct CallableSpan {
499 /// Name of the callable, expressed as a variable reference. For functions, this contains
500 /// a type, and for subroutines, it does not.
501 pub name: VarRef,
502
503 /// Position of the name of the callable.
504 pub name_pos: LineCol,
505
506 /// Definition of the callable parameters.
507 pub params: Vec<VarRef>,
508
509 /// Statements within the callable's body.
510 pub body: Vec<Statement>,
511
512 /// Position of the end of the callable, used when injecting the implicit return.
513 pub end_pos: LineCol,
514}
515
516/// Components of a data statement.
517#[derive(Debug, PartialEq)]
518pub struct DataSpan {
519 /// Collection of optional literal values.
520 pub values: Vec<Option<Value>>,
521}
522
523/// Components of a variable definition.
524///
525/// Given that a definition causes the variable to be initialized to a default value, it is
526/// tempting to model this statement as a simple assignment. However, we must be able to
527/// detect variable redeclarations at runtime, so we must treat this statement as a separate
528/// type from assignments.
529#[derive(Debug, Eq, PartialEq)]
530#[cfg_attr(test, derive(Clone))]
531pub struct DimSpan {
532 /// Name of the variable to be defined. Type annotations are not allowed, hence why this is
533 /// not a `VarRef`.
534 pub name: String,
535
536 /// Position of the name.
537 pub name_pos: LineCol,
538
539 /// Whether the variable is global or not.
540 pub shared: bool,
541
542 /// Type of the variable to be defined.
543 pub vtype: ExprType,
544
545 /// Position of the type.
546 pub vtype_pos: LineCol,
547}
548
549/// Components of an array definition.
550#[derive(Debug, PartialEq)]
551#[cfg_attr(test, derive(Clone))]
552pub struct DimArraySpan {
553 /// Name of the array to define. Type annotations are not allowed, hence why this is not a
554 /// `VarRef`.
555 pub name: String,
556
557 /// Position of the name.
558 pub name_pos: LineCol,
559
560 /// Whether the array is global or not.
561 pub shared: bool,
562
563 /// Expressions to compute the dimensions of the array.
564 pub dimensions: Vec<Expr>,
565
566 /// Type of the array to be defined.
567 pub subtype: ExprType,
568
569 /// Position of the subtype.
570 pub subtype_pos: LineCol,
571}
572
573/// Type of the `DO` loop.
574#[derive(Debug, PartialEq)]
575pub enum DoGuard {
576 /// Represents an infinite loop without guards.
577 Infinite,
578
579 /// Represents a loop with an `UNTIL` guard in the `DO` clause.
580 PreUntil(Expr),
581
582 /// Represents a loop with a `WHILE` guard in the `DO` clause.
583 PreWhile(Expr),
584
585 /// Represents a loop with an `UNTIL` guard in the `LOOP` clause.
586 PostUntil(Expr),
587
588 /// Represents a loop with a `WHILE` guard in the `LOOP` clause.
589 PostWhile(Expr),
590}
591
592/// Components of a `DO` statement.
593#[derive(Debug, PartialEq)]
594pub struct DoSpan {
595 /// Expression to compute whether to execute the loop's body or not and where this appears in
596 /// the `DO` statement.
597 pub guard: DoGuard,
598
599 /// Statements within the loop's body.
600 pub body: Vec<Statement>,
601}
602
603/// Components of an `END` statement.
604#[derive(Debug, PartialEq)]
605pub struct EndSpan {
606 /// Integer expression to compute the return code.
607 pub code: Option<Expr>,
608}
609
610/// Components of an `EXIT DO` statement.
611#[derive(Debug, Eq, PartialEq)]
612pub struct ExitDoSpan {
613 /// Position of the statement.
614 pub pos: LineCol,
615}
616
617/// Components of a branch of an `IF` statement.
618#[derive(Debug, PartialEq)]
619pub struct IfBranchSpan {
620 /// Expression that guards execution of this branch.
621 pub guard: Expr,
622
623 /// Statements within the branch.
624 pub body: Vec<Statement>,
625}
626
627/// Components of an `IF` statement.
628#[derive(Debug, PartialEq)]
629pub struct IfSpan {
630 /// Sequence of the branches in the conditional.
631 ///
632 /// Representation of the conditional branches. The final `ELSE` branch, if present, is also
633 /// included here and its guard clause is always a true expression.
634 pub branches: Vec<IfBranchSpan>,
635}
636
637/// Components of a `FOR` statement.
638///
639/// Note that we do not store the original end and step values, and instead use expressions to
640/// represent the loop condition and the computation of the next iterator value. We do this
641/// for run-time efficiency. The reason this is possible is because we force the step to be an
642/// integer literal at parse time and do not allow it to be an expression.
643#[derive(Debug, PartialEq)]
644pub struct ForSpan {
645 /// Iterator name, expressed as a variable reference that must be either automatic or an
646 /// integer.
647 pub iter: VarRef,
648
649 /// Position of the iterator.
650 pub iter_pos: LineCol,
651
652 /// If true, the iterator computation needs to be performed as a double so that, when the
653 /// iterator variable is not yet defined, it gains the correct type.
654 pub iter_double: bool,
655
656 /// Expression to compute the iterator's initial value.
657 pub start: Expr,
658
659 /// Condition to test after each iteration.
660 pub end: Expr,
661
662 /// Expression to compute the iterator's next value.
663 pub next: Expr,
664
665 /// Statements within the loop's body.
666 pub body: Vec<Statement>,
667}
668
669/// Components of a `GOTO` or a `GOSUB` statement.
670#[derive(Clone, Debug, Eq, PartialEq)]
671pub struct GotoSpan {
672 /// Name of the label to jump to.
673 pub target: String,
674
675 /// Position of the label.
676 pub target_pos: LineCol,
677}
678
679/// Components of a label "statement".
680///
681/// In principle, labels should be just a property of a statement but, for simplicity in the
682/// current model, it's easiest to represent them as their own statement.
683#[derive(Debug, Eq, PartialEq)]
684pub struct LabelSpan {
685 /// Name of the label being defined.
686 pub name: String,
687
688 /// Position of the label.
689 pub name_pos: LineCol,
690}
691
692/// Components of an `ON ERROR` statement.
693#[derive(Debug, Eq, PartialEq)]
694pub enum OnErrorSpan {
695 /// Components of an `ON ERROR GOTO @label` statement.
696 Goto(GotoSpan),
697
698 /// Components of an `ON ERROR GOTO 0` statement.
699 Reset,
700
701 /// Components of an `ON ERROR RESUME NEXT` statement.
702 ResumeNext,
703}
704
705/// Components of a `RETURN` statement.
706#[derive(Debug, Eq, PartialEq)]
707pub struct ReturnSpan {
708 /// Position of the statement.
709 pub pos: LineCol,
710}
711
712/// Collection of relational operators that can appear in a `CASE IS` guard..
713#[derive(Debug, Eq, PartialEq)]
714pub enum CaseRelOp {
715 /// Relational operator for `CASE IS =`.
716 Equal,
717
718 /// Relational operator for `CASE IS <>`.
719 NotEqual,
720
721 /// Relational operator for `CASE IS <`.
722 Less,
723
724 /// Relational operator for `CASE IS <=`.
725 LessEqual,
726
727 /// Relational operator for `CASE IS >`.
728 Greater,
729
730 /// Relational operator for `CASE IS >=`.
731 GreaterEqual,
732}
733
734/// Components of a `CASE` guard.
735#[derive(Debug, PartialEq)]
736pub enum CaseGuardSpan {
737 /// Represents an `IS <op> <expr>` guard or a simpler `<expr>` guard.
738 Is(CaseRelOp, Expr),
739
740 /// Represents an `<expr> TO <expr>` guard.
741 To(Expr, Expr),
742}
743
744/// Components of a branch of a `SELECT` statement.
745#[derive(Debug, PartialEq)]
746pub struct CaseSpan {
747 /// Expressions that guard execution of this case.
748 pub guards: Vec<CaseGuardSpan>,
749
750 /// Statements within the case block.
751 pub body: Vec<Statement>,
752}
753
754/// Components of a `SELECT` statement.
755#[derive(Debug, PartialEq)]
756pub struct SelectSpan {
757 /// Expression to test for.
758 pub expr: Expr,
759
760 /// Representation of the cases to select from. The final `CASE ELSE`, if present, is also
761 /// included here without any guards.
762 pub cases: Vec<CaseSpan>,
763
764 /// Position of the `END SELECT` statement.
765 pub end_pos: LineCol,
766}
767
768/// Components of a `WHILE` statement.
769#[derive(Debug, PartialEq)]
770pub struct WhileSpan {
771 /// Expression to compute whether to execute the loop's body or not.
772 pub expr: Expr,
773
774 /// Statements within the loop's body.
775 pub body: Vec<Statement>,
776}
777
778/// Represents a statement in the program along all data to execute it.
779#[derive(Debug, PartialEq)]
780pub enum Statement {
781 /// Represents an assignment to an element of an array.
782 ArrayAssignment(ArrayAssignmentSpan),
783
784 /// Represents a variable assignment.
785 Assignment(AssignmentSpan),
786
787 /// Represents a call to a builtin command such as `PRINT`.
788 Call(CallSpan),
789
790 /// Represents a `FUNCTION` or `SUB` definition. The difference between the two lies in just
791 /// the presence or absence of a return type in the callable.
792 Callable(CallableSpan),
793
794 /// Represents a `DATA` statement.
795 Data(DataSpan),
796
797 /// Represents a variable definition.
798 Dim(DimSpan),
799
800 /// Represents an array definition.
801 DimArray(DimArraySpan),
802
803 /// Represents a `DO` statement.
804 Do(DoSpan),
805
806 /// Represents an `END` statement.
807 End(EndSpan),
808
809 /// Represents an `EXIT DO` statement.
810 ExitDo(ExitDoSpan),
811
812 /// Represents a `FOR` statement.
813 For(ForSpan),
814
815 /// Represents a `GOSUB` statement.
816 Gosub(GotoSpan),
817
818 /// Represents a `GOTO` statement.
819 Goto(GotoSpan),
820
821 /// Represents an `IF` statement.
822 If(IfSpan),
823
824 /// Represents a label "statement".
825 Label(LabelSpan),
826
827 /// Represents an `ON ERROR` statement.
828 OnError(OnErrorSpan),
829
830 /// Represents a `RETURN` statement.
831 Return(ReturnSpan),
832
833 /// Represents a `SELECT` statement.
834 Select(SelectSpan),
835
836 /// Represents a `WHILE` statement.
837 While(WhileSpan),
838}
839
840#[cfg(test)]
841mod tests {
842 use super::*;
843
844 #[test]
845 fn test_varref_display() {
846 assert_eq!("name", format!("{}", VarRef::new("name", None)));
847 assert_eq!("abc?", format!("{}", VarRef::new("abc", Some(ExprType::Boolean))));
848 assert_eq!("cba#", format!("{}", VarRef::new("cba", Some(ExprType::Double))));
849 assert_eq!("def%", format!("{}", VarRef::new("def", Some(ExprType::Integer))));
850 assert_eq!("ghi$", format!("{}", VarRef::new("ghi", Some(ExprType::Text))));
851 }
852
853 #[test]
854 fn test_varref_accepts() {
855 assert!(VarRef::new("a", None).accepts(ExprType::Boolean));
856 assert!(VarRef::new("a", None).accepts(ExprType::Double));
857 assert!(VarRef::new("a", None).accepts(ExprType::Integer));
858 assert!(VarRef::new("a", None).accepts(ExprType::Text));
859
860 assert!(VarRef::new("a", Some(ExprType::Boolean)).accepts(ExprType::Boolean));
861 assert!(!VarRef::new("a", Some(ExprType::Boolean)).accepts(ExprType::Double));
862 assert!(!VarRef::new("a", Some(ExprType::Boolean)).accepts(ExprType::Integer));
863 assert!(!VarRef::new("a", Some(ExprType::Boolean)).accepts(ExprType::Text));
864
865 assert!(!VarRef::new("a", Some(ExprType::Double)).accepts(ExprType::Boolean));
866 assert!(VarRef::new("a", Some(ExprType::Double)).accepts(ExprType::Double));
867 assert!(!VarRef::new("a", Some(ExprType::Double)).accepts(ExprType::Integer));
868 assert!(!VarRef::new("a", Some(ExprType::Double)).accepts(ExprType::Text));
869
870 assert!(!VarRef::new("a", Some(ExprType::Integer)).accepts(ExprType::Boolean));
871 assert!(!VarRef::new("a", Some(ExprType::Integer)).accepts(ExprType::Double));
872 assert!(VarRef::new("a", Some(ExprType::Integer)).accepts(ExprType::Integer));
873 assert!(!VarRef::new("a", Some(ExprType::Integer)).accepts(ExprType::Text));
874
875 assert!(!VarRef::new("a", Some(ExprType::Text)).accepts(ExprType::Boolean));
876 assert!(!VarRef::new("a", Some(ExprType::Text)).accepts(ExprType::Double));
877 assert!(!VarRef::new("a", Some(ExprType::Text)).accepts(ExprType::Integer));
878 assert!(VarRef::new("a", Some(ExprType::Text)).accepts(ExprType::Text));
879 }
880
881 #[test]
882 fn test_value_display() {
883 assert_eq!("TRUE", format!("{}", Value::Boolean(true)));
884 assert_eq!("FALSE", format!("{}", Value::Boolean(false)));
885 assert_eq!("3.0", format!("{}", Value::Double(3.0)));
886 assert_eq!("3.1", format!("{}", Value::Double(3.1)));
887 assert_eq!("0.51", format!("{}", Value::Double(0.51)));
888 assert_eq!("inf", format!("{}", Value::Double(f64::INFINITY)));
889 assert_eq!("-inf", format!("{}", Value::Double(f64::NEG_INFINITY)));
890 assert_eq!("NaN", format!("{}", Value::Double(f64::NAN)));
891 assert_eq!("NaN", format!("{}", Value::Double(-f64::NAN)));
892 assert_eq!("-56", format!("{}", Value::Integer(-56)));
893 assert_eq!("\"some words\"", format!("{}", Value::Text("some words".to_owned())));
894 }
895}