Skip to main content

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}