Skip to main content

endbasic_core/
ast.rs

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