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;
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 pub 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 pub 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 true if this reference is compatible with the given type.
270 pub fn accepts(&self, other: ExprType) -> bool {
271 match self.ref_type {
272 None => true,
273 Some(vtype) => vtype == other,
274 }
275 }
276
277 /// Returns true if this reference is compatible with the return type of a callable.
278 pub fn accepts_callable(&self, other: Option<ExprType>) -> bool {
279 match self.ref_type {
280 None => true,
281 Some(vtype) => match other {
282 Some(other) => vtype == other,
283 None => false,
284 },
285 }
286 }
287}
288
289impl fmt::Display for VarRef {
290 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291 match self.ref_type {
292 None => self.name.fmt(f),
293 Some(vtype) => write!(f, "{}{}", self.name, vtype.annotation()),
294 }
295 }
296}
297
298/// Represents an evaluated value.
299#[derive(Clone, Debug, PartialEq)]
300pub enum Value {
301 /// A boolean value.
302 Boolean(bool),
303
304 /// A double-precision floating point value.
305 Double(f64),
306
307 /// An integer value.
308 Integer(i32),
309
310 /// A string value.
311 Text(String), // Should be `String` but would get confusing with the built-in Rust type.
312
313 /// A reference to a variable.
314 VarRef(String, ExprType),
315}
316
317impl From<bool> for Value {
318 fn from(b: bool) -> Self {
319 Value::Boolean(b)
320 }
321}
322
323impl From<f64> for Value {
324 fn from(d: f64) -> Self {
325 Value::Double(d)
326 }
327}
328
329impl From<i32> for Value {
330 fn from(i: i32) -> Self {
331 Value::Integer(i)
332 }
333}
334
335impl From<&str> for Value {
336 fn from(s: &str) -> Self {
337 Value::Text(s.to_owned())
338 }
339}
340
341impl fmt::Display for Value {
342 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343 match self {
344 Value::Boolean(true) => write!(f, "TRUE"),
345 Value::Boolean(false) => write!(f, "FALSE"),
346 Value::Double(d) => {
347 let mut s = format!("{}", d);
348 if d.is_finite() && !d.is_nan() && !s.contains('.') {
349 s += ".0";
350 }
351 write!(f, "{}", s)
352 }
353 Value::Integer(i) => write!(f, "{}", i),
354 Value::Text(s) => write!(f, "\"{}\"", s),
355 Value::VarRef(key, etype) => write!(f, "{}{}", key, etype),
356 }
357 }
358}
359
360impl Value {
361 /// Returns the type of the value as an `ExprType`.
362 pub fn as_exprtype(&self) -> ExprType {
363 match self {
364 Value::Boolean(_) => ExprType::Boolean,
365 Value::Double(_) => ExprType::Double,
366 Value::Integer(_) => ExprType::Integer,
367 Value::Text(_) => ExprType::Text,
368 Value::VarRef(_key, etype) => *etype,
369 }
370 }
371}
372
373/// Types of separators between arguments to a `BuiltinCall`.
374#[derive(Clone, Copy, Debug, Eq, PartialEq)]
375pub enum ArgSep {
376 /// Filler for the separator in the last argument.
377 End = 0,
378
379 /// Short separator (`;`).
380 Short = 1,
381
382 /// Long separator (`,`).
383 Long = 2,
384
385 /// `AS` separator.
386 As = 3,
387}
388
389impl fmt::Display for ArgSep {
390 // TODO(jmmv): Can this be removed in favor of describe()?
391 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
392 match self {
393 ArgSep::End => write!(f, "<END OF STATEMENT>"),
394 ArgSep::Short => write!(f, ";"),
395 ArgSep::Long => write!(f, ","),
396 ArgSep::As => write!(f, "AS"),
397 }
398 }
399}
400
401impl ArgSep {
402 /// Formats the separator for a syntax specification.
403 ///
404 /// The return value contains the textual representation of the separator and a boolean that
405 /// indicates whether the separator requires a leading space.
406 pub(crate) fn describe(&self) -> (&str, bool) {
407 match self {
408 ArgSep::End => ("", false),
409 ArgSep::Short => (";", false),
410 ArgSep::Long => (",", false),
411 ArgSep::As => ("AS", true),
412 }
413 }
414}
415
416/// Components of an array assignment statement.
417#[derive(Debug, PartialEq)]
418#[cfg_attr(test, derive(Clone))]
419pub struct ArrayAssignmentSpan {
420 /// Reference to the array to modify.
421 pub vref: VarRef,
422
423 /// Position of the `vref`.
424 pub vref_pos: LineCol,
425
426 /// Expressions to compute the subscripts to index the array.
427 pub subscripts: Vec<Expr>,
428
429 /// Expression to compute the value of the modified element.
430 pub expr: Expr,
431}
432
433/// Components of an assignment statement.
434#[derive(Debug, PartialEq)]
435#[cfg_attr(test, derive(Clone))]
436pub struct AssignmentSpan {
437 /// Reference to the variable to set.
438 pub vref: VarRef,
439
440 /// Position of the `vref`.
441 pub vref_pos: LineCol,
442
443 /// Expression to compute the value of the modified variable.
444 pub expr: Expr,
445}
446
447/// Single argument to a builtin call statement.
448#[derive(Clone, Debug, PartialEq)]
449pub struct ArgSpan {
450 /// Expression to compute the argument's value. This expression is optional to support calls
451 /// of the form `PRINT a, , b` where some arguments are empty.
452 pub expr: Option<Expr>,
453
454 /// Separator between this argument and the *next*. The last instance of this type in a call
455 /// always carries a value of `ArgSep::End`.
456 pub sep: ArgSep,
457
458 /// Position of the `sep`.
459 pub sep_pos: LineCol,
460}
461
462/// Components of a call statement or expression.
463#[derive(Clone, Debug, PartialEq)]
464pub struct CallSpan {
465 /// Reference to the callable (a command or a function), or the array to index.
466 pub vref: VarRef,
467
468 /// Position of the reference.
469 pub vref_pos: LineCol,
470
471 /// Sequence of arguments to pass to the callable.
472 pub args: Vec<ArgSpan>,
473}
474
475/// Components of a `FUNCTION` or `SUB` definition.
476#[derive(Debug, PartialEq)]
477pub struct CallableSpan {
478 /// Name of the callable, expressed as a variable reference. For functions, this contains
479 /// a type, and for subroutines, it does not.
480 pub name: VarRef,
481
482 /// Position of the name of the callable.
483 pub name_pos: LineCol,
484
485 /// Definition of the callable parameters.
486 pub params: Vec<VarRef>,
487
488 /// Statements within the callable's body.
489 pub body: Vec<Statement>,
490
491 /// Position of the end of the callable, used when injecting the implicit return.
492 pub end_pos: LineCol,
493}
494
495/// Components of a data statement.
496#[derive(Debug, PartialEq)]
497pub struct DataSpan {
498 /// Collection of optional literal values.
499 pub values: Vec<Option<Expr>>,
500}
501
502/// Components of a variable definition.
503///
504/// Given that a definition causes the variable to be initialized to a default value, it is
505/// tempting to model this statement as a simple assignment. However, we must be able to
506/// detect variable redeclarations at runtime, so we must treat this statement as a separate
507/// type from assignments.
508#[derive(Debug, Eq, PartialEq)]
509#[cfg_attr(test, derive(Clone))]
510pub struct DimSpan {
511 /// Name of the variable to be defined. Type annotations are not allowed, hence why this is
512 /// not a `VarRef`.
513 pub name: String,
514
515 /// Position of the name.
516 pub name_pos: LineCol,
517
518 /// Whether the variable is global or not.
519 pub shared: bool,
520
521 /// Type of the variable to be defined.
522 pub vtype: ExprType,
523
524 /// Position of the type.
525 pub vtype_pos: LineCol,
526}
527
528/// Components of an array definition.
529#[derive(Debug, PartialEq)]
530#[cfg_attr(test, derive(Clone))]
531pub struct DimArraySpan {
532 /// Name of the array to define. Type annotations are not allowed, hence why this is not a
533 /// `VarRef`.
534 pub name: String,
535
536 /// Position of the name.
537 pub name_pos: LineCol,
538
539 /// Whether the array is global or not.
540 pub shared: bool,
541
542 /// Expressions to compute the dimensions of the array.
543 pub dimensions: Vec<Expr>,
544
545 /// Type of the array to be defined.
546 pub subtype: ExprType,
547
548 /// Position of the subtype.
549 pub subtype_pos: LineCol,
550}
551
552/// Type of the `DO` loop.
553#[derive(Debug, PartialEq)]
554pub enum DoGuard {
555 /// Represents an infinite loop without guards.
556 Infinite,
557
558 /// Represents a loop with an `UNTIL` guard in the `DO` clause.
559 PreUntil(Expr),
560
561 /// Represents a loop with a `WHILE` guard in the `DO` clause.
562 PreWhile(Expr),
563
564 /// Represents a loop with an `UNTIL` guard in the `LOOP` clause.
565 PostUntil(Expr),
566
567 /// Represents a loop with a `WHILE` guard in the `LOOP` clause.
568 PostWhile(Expr),
569}
570
571/// Components of a `DO` statement.
572#[derive(Debug, PartialEq)]
573pub struct DoSpan {
574 /// Expression to compute whether to execute the loop's body or not and where this appears in
575 /// the `DO` statement.
576 pub guard: DoGuard,
577
578 /// Statements within the loop's body.
579 pub body: Vec<Statement>,
580}
581
582/// Components of an `END` statement.
583#[derive(Debug, PartialEq)]
584pub struct EndSpan {
585 /// Integer expression to compute the return code.
586 pub code: Option<Expr>,
587}
588
589/// Components of an `EXIT` statement.
590#[derive(Debug, Eq, PartialEq)]
591pub struct ExitSpan {
592 /// Position of the statement.
593 pub pos: LineCol,
594}
595
596/// Components of a branch of an `IF` statement.
597#[derive(Debug, PartialEq)]
598pub struct IfBranchSpan {
599 /// Expression that guards execution of this branch.
600 pub guard: Expr,
601
602 /// Statements within the branch.
603 pub body: Vec<Statement>,
604}
605
606/// Components of an `IF` statement.
607#[derive(Debug, PartialEq)]
608pub struct IfSpan {
609 /// Sequence of the branches in the conditional.
610 ///
611 /// Representation of the conditional branches. The final `ELSE` branch, if present, is also
612 /// included here and its guard clause is always a true expression.
613 pub branches: Vec<IfBranchSpan>,
614}
615
616/// Components of a `FOR` statement.
617///
618/// Note that we do not store the original end and step values, and instead use expressions to
619/// represent the loop condition and the computation of the next iterator value. We do this
620/// for run-time efficiency. The reason this is possible is because we force the step to be an
621/// integer literal at parse time and do not allow it to be an expression.
622#[derive(Debug, PartialEq)]
623pub struct ForSpan {
624 /// Iterator name, expressed as a variable reference that must be either automatic or an
625 /// integer.
626 pub iter: VarRef,
627
628 /// Position of the iterator.
629 pub iter_pos: LineCol,
630
631 /// If true, the iterator computation needs to be performed as a double so that, when the
632 /// iterator variable is not yet defined, it gains the correct type.
633 pub iter_double: bool,
634
635 /// Expression to compute the iterator's initial value.
636 pub start: Expr,
637
638 /// Condition to test after each iteration.
639 pub end: Expr,
640
641 /// Expression to compute the iterator's next value.
642 pub next: Expr,
643
644 /// Statements within the loop's body.
645 pub body: Vec<Statement>,
646}
647
648/// Components of a `GOTO` or a `GOSUB` statement.
649#[derive(Clone, Debug, Eq, PartialEq)]
650pub struct GotoSpan {
651 /// Name of the label to jump to.
652 pub target: String,
653
654 /// Position of the label.
655 pub target_pos: LineCol,
656}
657
658/// Components of a label "statement".
659///
660/// In principle, labels should be just a property of a statement but, for simplicity in the
661/// current model, it's easiest to represent them as their own statement.
662#[derive(Debug, Eq, PartialEq)]
663pub struct LabelSpan {
664 /// Name of the label being defined.
665 pub name: String,
666
667 /// Position of the label.
668 pub name_pos: LineCol,
669}
670
671/// Components of an `ON ERROR` statement.
672#[derive(Debug, Eq, PartialEq)]
673pub enum OnErrorSpan {
674 /// Components of an `ON ERROR GOTO @label` statement.
675 Goto(GotoSpan),
676
677 /// Components of an `ON ERROR GOTO 0` statement.
678 Reset,
679
680 /// Components of an `ON ERROR RESUME NEXT` statement.
681 ResumeNext,
682}
683
684/// Components of a `RETURN` statement.
685#[derive(Debug, Eq, PartialEq)]
686pub struct ReturnSpan {
687 /// Position of the statement.
688 pub pos: LineCol,
689}
690
691/// Collection of relational operators that can appear in a `CASE IS` guard..
692#[derive(Debug, Eq, PartialEq)]
693pub enum CaseRelOp {
694 /// Relational operator for `CASE IS =`.
695 Equal,
696
697 /// Relational operator for `CASE IS <>`.
698 NotEqual,
699
700 /// Relational operator for `CASE IS <`.
701 Less,
702
703 /// Relational operator for `CASE IS <=`.
704 LessEqual,
705
706 /// Relational operator for `CASE IS >`.
707 Greater,
708
709 /// Relational operator for `CASE IS >=`.
710 GreaterEqual,
711}
712
713/// Components of a `CASE` guard.
714#[derive(Debug, PartialEq)]
715pub enum CaseGuardSpan {
716 /// Represents an `IS <op> <expr>` guard or a simpler `<expr>` guard.
717 Is(CaseRelOp, Expr),
718
719 /// Represents an `<expr> TO <expr>` guard.
720 To(Expr, Expr),
721}
722
723/// Components of a branch of a `SELECT` statement.
724#[derive(Debug, PartialEq)]
725pub struct CaseSpan {
726 /// Expressions that guard execution of this case.
727 pub guards: Vec<CaseGuardSpan>,
728
729 /// Statements within the case block.
730 pub body: Vec<Statement>,
731}
732
733/// Components of a `SELECT` statement.
734#[derive(Debug, PartialEq)]
735pub struct SelectSpan {
736 /// Expression to test for.
737 pub expr: Expr,
738
739 /// Representation of the cases to select from. The final `CASE ELSE`, if present, is also
740 /// included here without any guards.
741 pub cases: Vec<CaseSpan>,
742
743 /// Position of the `END SELECT` statement.
744 pub end_pos: LineCol,
745}
746
747/// Components of a `WHILE` statement.
748#[derive(Debug, PartialEq)]
749pub struct WhileSpan {
750 /// Expression to compute whether to execute the loop's body or not.
751 pub expr: Expr,
752
753 /// Statements within the loop's body.
754 pub body: Vec<Statement>,
755}
756
757/// Represents a statement in the program along all data to execute it.
758#[derive(Debug, PartialEq)]
759pub enum Statement {
760 /// Represents an assignment to an element of an array.
761 ArrayAssignment(ArrayAssignmentSpan),
762
763 /// Represents a variable assignment.
764 Assignment(AssignmentSpan),
765
766 /// Represents a call to a builtin command such as `PRINT`.
767 Call(CallSpan),
768
769 /// Represents a `FUNCTION` or `SUB` definition. The difference between the two lies in just
770 /// the presence or absence of a return type in the callable.
771 Callable(CallableSpan),
772
773 /// Represents a `DATA` statement.
774 Data(DataSpan),
775
776 /// Represents a variable definition.
777 Dim(DimSpan),
778
779 /// Represents an array definition.
780 DimArray(DimArraySpan),
781
782 /// Represents a `DO` statement.
783 Do(DoSpan),
784
785 /// Represents an `END` statement.
786 End(EndSpan),
787
788 /// Represents an `EXIT DO` statement.
789 ExitDo(ExitSpan),
790
791 /// Represents an `EXIT FOR` statement.
792 ExitFor(ExitSpan),
793
794 /// Represents an `EXIT FUNCTION` statement.
795 ExitFunction(ExitSpan),
796
797 /// Represents an `EXIT SUB` statement.
798 ExitSub(ExitSpan),
799
800 /// Represents a `FOR` statement.
801 For(ForSpan),
802
803 /// Represents a `GOSUB` statement.
804 Gosub(GotoSpan),
805
806 /// Represents a `GOTO` statement.
807 Goto(GotoSpan),
808
809 /// Represents an `IF` statement.
810 If(IfSpan),
811
812 /// Represents a label "statement".
813 Label(LabelSpan),
814
815 /// Represents an `ON ERROR` statement.
816 OnError(OnErrorSpan),
817
818 /// Represents a `RETURN` statement.
819 Return(ReturnSpan),
820
821 /// Represents a `SELECT` statement.
822 Select(SelectSpan),
823
824 /// Represents a `WHILE` statement.
825 While(WhileSpan),
826}
827
828#[cfg(test)]
829mod tests {
830 use super::*;
831
832 #[test]
833 fn test_varref_display() {
834 assert_eq!("name", format!("{}", VarRef::new("name", None)));
835 assert_eq!("abc?", format!("{}", VarRef::new("abc", Some(ExprType::Boolean))));
836 assert_eq!("cba#", format!("{}", VarRef::new("cba", Some(ExprType::Double))));
837 assert_eq!("def%", format!("{}", VarRef::new("def", Some(ExprType::Integer))));
838 assert_eq!("ghi$", format!("{}", VarRef::new("ghi", Some(ExprType::Text))));
839 }
840
841 #[test]
842 fn test_varref_accepts() {
843 assert!(VarRef::new("a", None).accepts(ExprType::Boolean));
844 assert!(VarRef::new("a", None).accepts(ExprType::Double));
845 assert!(VarRef::new("a", None).accepts(ExprType::Integer));
846 assert!(VarRef::new("a", None).accepts(ExprType::Text));
847
848 assert!(VarRef::new("a", Some(ExprType::Boolean)).accepts(ExprType::Boolean));
849 assert!(!VarRef::new("a", Some(ExprType::Boolean)).accepts(ExprType::Double));
850 assert!(!VarRef::new("a", Some(ExprType::Boolean)).accepts(ExprType::Integer));
851 assert!(!VarRef::new("a", Some(ExprType::Boolean)).accepts(ExprType::Text));
852
853 assert!(!VarRef::new("a", Some(ExprType::Double)).accepts(ExprType::Boolean));
854 assert!(VarRef::new("a", Some(ExprType::Double)).accepts(ExprType::Double));
855 assert!(!VarRef::new("a", Some(ExprType::Double)).accepts(ExprType::Integer));
856 assert!(!VarRef::new("a", Some(ExprType::Double)).accepts(ExprType::Text));
857
858 assert!(!VarRef::new("a", Some(ExprType::Integer)).accepts(ExprType::Boolean));
859 assert!(!VarRef::new("a", Some(ExprType::Integer)).accepts(ExprType::Double));
860 assert!(VarRef::new("a", Some(ExprType::Integer)).accepts(ExprType::Integer));
861 assert!(!VarRef::new("a", Some(ExprType::Integer)).accepts(ExprType::Text));
862
863 assert!(!VarRef::new("a", Some(ExprType::Text)).accepts(ExprType::Boolean));
864 assert!(!VarRef::new("a", Some(ExprType::Text)).accepts(ExprType::Double));
865 assert!(!VarRef::new("a", Some(ExprType::Text)).accepts(ExprType::Integer));
866 assert!(VarRef::new("a", Some(ExprType::Text)).accepts(ExprType::Text));
867 }
868
869 #[test]
870 fn test_value_display() {
871 assert_eq!("TRUE", format!("{}", Value::Boolean(true)));
872 assert_eq!("FALSE", format!("{}", Value::Boolean(false)));
873 assert_eq!("3.0", format!("{}", Value::Double(3.0)));
874 assert_eq!("3.1", format!("{}", Value::Double(3.1)));
875 assert_eq!("0.51", format!("{}", Value::Double(0.51)));
876 assert_eq!("inf", format!("{}", Value::Double(f64::INFINITY)));
877 assert_eq!("-inf", format!("{}", Value::Double(f64::NEG_INFINITY)));
878 assert_eq!("NaN", format!("{}", Value::Double(f64::NAN)));
879 assert_eq!("NaN", format!("{}", Value::Double(-f64::NAN)));
880 assert_eq!("-56", format!("{}", Value::Integer(-56)));
881 assert_eq!("\"some words\"", format!("{}", Value::Text("some words".to_owned())));
882 }
883}