Documentation ¶
Overview ¶
Package parser generates an AST for Evy programs.
First, Evy source code is tokenized by the lexer, then the generated tokens are parsed into an Abstract Syntax Tree (AST) by the Parse function. Finally, the evaluator walks the AST and executes the program. This package is concerned with the second step of parsing tokens into an AST.
Parsing ¶
The Parse function in this package uses a top-down, recursive descent parsing approach. This means that parsing starts with the top-level structure of the program and recursively descends into its components.
Expression parsing is a particularly tricky part of the parsing process. Expressions are used in variable declarations, assignments, function calls, and many other places. Expressions are not simply evaluated top-down, left-to-right. For example, in the expression 2+3*4, the multiplication operator * has higher precedence than the addition operator +. This means that the expression 3*4 must be evaluated before the expression 2+3.
To handle expressions with different levels of precedence, the Parse function uses a Pratt parser. A Pratt parser is a type of top-down, recursive descent parser that can handle expressions with different levels of precedence.
Abstract Syntax Tree ¶
The Abstract Syntax Tree (AST) is a hierarchical representation of an Evy program's structure. It is the result of the Parse function. It can be used for evaluation, further analysis, and code generation, such as formatted printing of the Evy source code with Program.Format. The AST consists of a tree of nodes, each of which implements the Node interface.
Each node in the AST represents a different element of the program's structure. The root node of the AST represents the entire Program. The root node's direct child nodes are block statements and basic statements.
Block statements contain further statements. They include:
- FuncDefStmt: A statement that defines a function.
- EventHandlerStmt: A statement that defines an event handler.
- IfStmt: A statement that executes a block of code if a condition is met.
- ForStmt: A statement that executes a block of code repeatedly.
- WhileStmt: A statement that executes a block of code repeatedly while a condition is met.
Basic statements are statements that cannot be broken down into further statements. They include:
- TypedDeclStmt: A statement that declares a variable of an explicitly specified type.
- InferredDeclStmt: A statement that declares a variable with a type that is inferred from the value.
- AssignmentStmt: A statement that assigns a value to a variable.
- FuncCallStmt: A statement that calls a function.
- ReturnStmt: A statement that returns from a function.
- BreakStmt: A statement that breaks out of a loop.
The components of basic statements are:
- Variables: Var
- Literals: NumLiteral, StringLiteral, BoolLiteral, ArrayLiteral, MapLiteral
- Expressions: UnaryExpression, BinaryExpression, IndexExpression, SliceExpression, DotExpression, GroupExpression, TypeAssertion, and FuncCall
Variables are named references to values. Literals are values that are directly represented in the Evy source code. Expressions are combinations of variables, literals, operators and function calls to form new values.
This structure closely resembles the grammar of the Evy programming language, as defined in the language specification.
Index ¶
- Variables
- type Any
- type ArrayLiteral
- type AssignmentStmt
- type BinaryExpression
- type BlockStatement
- type BoolLiteral
- type BreakStmt
- type Builtins
- type ConditionalBlock
- type Decl
- type DotExpression
- type EmptyStmt
- type Error
- type Errors
- type EventHandlerStmt
- type ForStmt
- type FuncCall
- type FuncCallStmt
- type FuncDefStmt
- type GroupExpression
- type IfStmt
- type IndexExpression
- type InferredDeclStmt
- type MapLiteral
- type Node
- type NumLiteral
- type Operator
- type Program
- type ReturnStmt
- type SliceExpression
- type StepRange
- type StringLiteral
- type Type
- type TypeAssertion
- type TypeName
- type TypedDeclStmt
- type UnaryExpression
- type Var
- type WhileStmt
Constants ¶
This section is empty.
Variables ¶
var ( NUM_TYPE = &Type{Name: NUM} BOOL_TYPE = &Type{Name: BOOL} STRING_TYPE = &Type{Name: STRING} ANY_TYPE = &Type{Name: ANY} NONE_TYPE = &Type{Name: NONE} EMPTY_ARRAY = &Type{Name: ARRAY, Sub: NONE_TYPE} EMPTY_MAP = &Type{Name: MAP, Sub: NONE_TYPE} GENERIC_ARRAY = &Type{Name: ARRAY} GENERIC_MAP = &Type{Name: MAP} )
Basic types, any, none, and untyped arrays and untyped maps are interned into variables for reuse, such as NUM_TYPE or EMPTY_MAP.
Functions ¶
This section is empty.
Types ¶
type Any ¶ added in v0.0.194
type Any struct { Value Node // contains filtered or unexported fields }
Any is an AST node that wraps literals and non-any variables if the target assignable requires it.
type ArrayLiteral ¶
ArrayLiteral is an AST node that represents an array literal, such as: [1 2 3].
ArrayLiteral implements the Node interface.
func (*ArrayLiteral) String ¶
func (a *ArrayLiteral) String() string
String returns a string representation of the ArrayLiteral node.
func (*ArrayLiteral) Token ¶
func (a *ArrayLiteral) Token() *lexer.Token
Token returns the token of the Evy source program associated with the ArrayLiteral node.
func (*ArrayLiteral) Type ¶
func (a *ArrayLiteral) Type() *Type
Type returns the type of the array literal, such as []num for [1 2 3].
type AssignmentStmt ¶
type AssignmentStmt struct { Target Node // Variable, index or field expression Value Node // literal, expression, variable... // contains filtered or unexported fields }
AssignmentStmt is an AST node that represents an assignment statement. An assignment statement assigns a value to a variable, such as n = 2.
AssignmentStmt implements the Node interface.
func (*AssignmentStmt) String ¶
func (a *AssignmentStmt) String() string
String returns a string representation of the AssignmentStmt node.
func (*AssignmentStmt) Token ¶
func (a *AssignmentStmt) Token() *lexer.Token
Token returns the token of the Evy source program associated with the AssignmentStmt node.
func (*AssignmentStmt) Type ¶
func (a *AssignmentStmt) Type() *Type
Type returns the type of the variable that is assigned.
type BinaryExpression ¶
type BinaryExpression struct { T *Type Op Operator Left Node Right Node // contains filtered or unexported fields }
BinaryExpression is an AST node that represents a binary expression. A binary expression is an expression that has two operands and an operator, such as a + b.
BinaryExpression implements the Node interface.
func (*BinaryExpression) String ¶
func (b *BinaryExpression) String() string
String returns a string representation of the BinaryExpression node.
func (*BinaryExpression) Token ¶
func (b *BinaryExpression) Token() *lexer.Token
Token returns the token of the Evy source program associated with the BinaryExpression node.
func (*BinaryExpression) Type ¶
func (b *BinaryExpression) Type() *Type
Type returns the type of the BinaryExpression, such as bool, num or string.
type BlockStatement ¶
type BlockStatement struct { Statements []Node // contains filtered or unexported fields }
BlockStatement is an AST node that represents a block of statements. A block of statements is a sequence of statements that are executed together, such as those used in FuncDefStmt and IfStmt.
BlockStatement implements the Node interface.
func (*BlockStatement) String ¶
func (b *BlockStatement) String() string
String returns a string representation of the BlockStatement node.
func (*BlockStatement) Token ¶
func (b *BlockStatement) Token() *lexer.Token
Token returns the token of the Evy source program associated with the BlockStatement node.
func (*BlockStatement) Type ¶
func (b *BlockStatement) Type() *Type
Type returns NONE_TYPE for BlockStatement because a block statement does not have a type.
type BoolLiteral ¶
type BoolLiteral struct { Value bool // contains filtered or unexported fields }
BoolLiteral is an AST node that represents a boolean literal. A boolean literal is a value that can be either true or false.
BoolLiteral implements the Node interface.
func (*BoolLiteral) String ¶
func (b *BoolLiteral) String() string
String returns a string representation of the BoolLiteral node.
func (*BoolLiteral) Token ¶
func (b *BoolLiteral) Token() *lexer.Token
Token returns the token of the Evy source program associated with the BoolLiteral node.
func (*BoolLiteral) Type ¶
func (b *BoolLiteral) Type() *Type
Type returns BOOL_TYPE for BoolLiteral as a bool literal always has the bool type.
type BreakStmt ¶
type BreakStmt struct {
// contains filtered or unexported fields
}
BreakStmt is an AST node that represents a break statement. A break statement is used to terminate the current loop statement, for example:
while true break end
BreakStmt implements the Node interface.
type Builtins ¶
type Builtins struct { Funcs map[string]*FuncDefStmt EventHandlers map[string]*EventHandlerStmt Globals map[string]*Var }
Builtins holds all predefined, built-in function and event handler signatures, such as print and on animate. It also holds all global variables, such as err. The parsing process validates the Evy source code against the known built-ins.
type ConditionalBlock ¶
type ConditionalBlock struct { Condition Node // must be of type bool Block *BlockStatement // contains filtered or unexported fields }
ConditionalBlock is an AST node that represents a conditional block. A conditional block is a block of statements that is executed only if a certain condition is met. Conditional blocks are used in IfStmt and WhileStmt statements.
ConditionalBlock implements the Node interface.
func (*ConditionalBlock) String ¶
func (c *ConditionalBlock) String() string
String returns a string representation of the ConditionalBlock node.
func (*ConditionalBlock) Token ¶
func (c *ConditionalBlock) Token() *lexer.Token
Token returns the token of the Evy source program associated with the ConditionalBlock node.
func (*ConditionalBlock) Type ¶
func (c *ConditionalBlock) Type() *Type
Type returns NONE_TYPE for ConditionalBlock because a conditional block statement does not have a type.
type Decl ¶
type Decl struct { Var *Var Value Node // literal, expression, variable, ... // contains filtered or unexported fields }
Decl is an AST node that represents a variable declaration. A variable declaration is a statement that creates a new variable and assigns it a value. Variable declarations are used in TypedDeclStmt and InferredDeclStmt statements.
Decl implements the Node interface.
type DotExpression ¶
type DotExpression struct { T *Type Left Node Key string // m := { age: 42}; m.age => key: "age" // contains filtered or unexported fields }
DotExpression is an AST node that represents a field access expression. A field access expression is an expression that accesses the value of a field in a map, such as person.age.
DotExpression implements the Node interface.
func (*DotExpression) String ¶
func (d *DotExpression) String() string
String returns a string representation of the DotExpression node.
func (*DotExpression) Token ¶
func (d *DotExpression) Token() *lexer.Token
Token returns the token of the Evy source program associated with the DotExpression node.
func (*DotExpression) Type ¶
func (d *DotExpression) Type() *Type
Type returns the type of the DotExpression, which is the type of the map's values. For map := {a: true}, the type of map.a is bool.
type EmptyStmt ¶
type EmptyStmt struct {
// contains filtered or unexported fields
}
EmptyStmt is an AST node that represents an empty statement. An empty statement is a statement that does nothing. Empty statement is used for formatting, such as to add a blank line between statements.
EmptyStmt implements the Node interface.
type Error ¶
type Error struct {
// contains filtered or unexported fields
}
Error is an Evy parse error.
type Errors ¶
type Errors []*Error
Errors is a list of parse errors as we typically report more than a single parser error at a time to the end user. Errors itself also implements the error interfaced and can be treated like a single Error.
type EventHandlerStmt ¶
type EventHandlerStmt struct { Name string Params []*Var Body *BlockStatement // contains filtered or unexported fields }
EventHandlerStmt is an AST node that represents an event handler definition. It includes the handler body, such as:
on key k:string print "key pressed:" k end
EventHandlerStmt implements the Node interface.
func (*EventHandlerStmt) String ¶
func (e *EventHandlerStmt) String() string
String returns a string representation of the EventHandlerStmt node.
func (*EventHandlerStmt) Token ¶
func (e *EventHandlerStmt) Token() *lexer.Token
Token returns the token of the Evy source program associated with the EventHandlerStmt node.
func (*EventHandlerStmt) Type ¶
func (e *EventHandlerStmt) Type() *Type
Type returns NONE_TYPE for EventHandlerStmt because an event handler definition does not have a type.
type ForStmt ¶
type ForStmt struct { LoopVar *Var Range Node // StepRange or array/map/string expression Block *BlockStatement // contains filtered or unexported fields }
ForStmt is an AST node that represents a for loop. A for loop is a statement that repeats a block of code a certain number of times. The following code snippet is an example of a for loop:
for n := range 1 10 2 print n // 1 3 5 7 9 end
ForStmt implements the Node interface.
type FuncCall ¶
type FuncCall struct { Name string Arguments []Node FuncDef *FuncDefStmt // contains filtered or unexported fields }
FuncCall is an AST node that represents a function call. It can be used either as a standalone statement or as part of an expression.
FuncCall implements the Node interface.
type FuncCallStmt ¶
type FuncCallStmt struct { FuncCall *FuncCall // contains filtered or unexported fields }
FuncCallStmt is an AST node that represents a standalone function call statement. It is a statement that calls a function without any surrounding expressions.
FuncCallStmt implements the Node interface.
func (*FuncCallStmt) String ¶
func (f *FuncCallStmt) String() string
String returns a string representation of the FuncCallStmt node.
func (*FuncCallStmt) Token ¶
func (f *FuncCallStmt) Token() *lexer.Token
Token returns the token of the Evy source program associated with the FuncCallStmt node.
func (*FuncCallStmt) Type ¶
func (f *FuncCallStmt) Type() *Type
Type returns the return type of the called function.
type FuncDefStmt ¶
type FuncDefStmt struct { Name string Params []*Var VariadicParam *Var ReturnType *Type VariadicParamType *Type Body *BlockStatement // contains filtered or unexported fields }
FuncDefStmt is an AST node that represents a function definition. It defines a new function with a name, a parameter list, return type, and a body. For example:
func greet print "howdy!" end
FuncDefStmt implements the Node interface.
func (*FuncDefStmt) String ¶
func (f *FuncDefStmt) String() string
String returns a string representation of the FuncDefStmt node.
func (*FuncDefStmt) Token ¶
func (f *FuncDefStmt) Token() *lexer.Token
Token returns the token of the Evy source program associated with the FuncDefStmt node.
func (*FuncDefStmt) Type ¶
func (f *FuncDefStmt) Type() *Type
Type returns the return type of the function.
type GroupExpression ¶
type GroupExpression struct { Expr Node // contains filtered or unexported fields }
GroupExpression is an AST node that represents a parenthesized expression. It groups together an expression so that it can be evaluated as a single unit, such as:(a+b)*3.
GroupExpression implements the Node interface.
func (*GroupExpression) String ¶
func (d *GroupExpression) String() string
String returns a string representation of the GroupExpression node.
func (*GroupExpression) Token ¶
func (d *GroupExpression) Token() *lexer.Token
Token returns the token of the Evy source program associated with the GroupExpression node.
func (*GroupExpression) Type ¶
func (d *GroupExpression) Type() *Type
Type returns the type of the GroupExpression, for example num for 2*(3+4).
type IfStmt ¶
type IfStmt struct { IfBlock *ConditionalBlock ElseIfBlocks []*ConditionalBlock Else *BlockStatement // contains filtered or unexported fields }
IfStmt is an AST node that represents a conditional statement. It specifies a condition that must be met for a block of statements to be executed. It can optionally have else-if and else blocks. For example:
if 2 * 5 == 10 print "✔" end
IfStmt implements the Node interface.
type IndexExpression ¶
type IndexExpression struct { T *Type Left Node Index Node // contains filtered or unexported fields }
IndexExpression is an AST node that represents an indexing expression. It accesses the value of an element in an array, map or string. For example: array[i].
IndexExpression implements the Node interface.
func (*IndexExpression) String ¶
func (i *IndexExpression) String() string
String returns a string representation of the IndexExpression node.
func (*IndexExpression) Token ¶
func (i *IndexExpression) Token() *lexer.Token
Token returns the token of the Evy source program associated with the IndexExpression node.
func (*IndexExpression) Type ¶
func (i *IndexExpression) Type() *Type
Type returns the type of the IndexExpression, for example num for an array of numbers with type []num.
type InferredDeclStmt ¶
type InferredDeclStmt struct { Decl *Decl // contains filtered or unexported fields }
InferredDeclStmt is an AST node that represents an inferred declaration statement. It declares a variable with a type that is inferred from the value that is assigned to it. For example: n := 1.
InferredDeclStmt implements the Node interface.
func (*InferredDeclStmt) String ¶
func (d *InferredDeclStmt) String() string
String returns a string representation of the InferredDeclStmt node.
func (*InferredDeclStmt) Token ¶
func (d *InferredDeclStmt) Token() *lexer.Token
Token returns the token of the Evy source program associated with the InferredDeclStmt node.
func (*InferredDeclStmt) Type ¶
func (d *InferredDeclStmt) Type() *Type
Type returns the type of the variable that is declared.
type MapLiteral ¶
type MapLiteral struct { Pairs map[string]Node Order []string // Track insertion order of keys for deterministic output. T *Type // contains filtered or unexported fields }
MapLiteral is an AST node that represents a map literal. A map literal is a collection of key-value pairs, such as {a: 1, b: 2}.
MapLiteral implements the Node interface.
func (*MapLiteral) String ¶
func (m *MapLiteral) String() string
String returns a string representation of the MapLiteral node.
func (*MapLiteral) Token ¶
func (m *MapLiteral) Token() *lexer.Token
Token returns the token of the Evy source program associated with the MapLiteral node.
func (*MapLiteral) Type ¶
func (m *MapLiteral) Type() *Type
Type returns the type of the map literal such as {}num for {a:1 b:2}.
type Node ¶
type Node interface { // Token returns the token of the Evy source program associated with the node. Token() *lexer.Token // String returns a string representation of the node. String() string // Type returns the Evy type of the node, such as num, []string, NONE. Type() *Type }
Node represents a node in the AST.
type NumLiteral ¶
type NumLiteral struct { Value float64 // contains filtered or unexported fields }
NumLiteral is an AST node that represents a numeric literal. A numeric literal is a number, such as 12 or 34.567.
NumLiteral implements the Node interface.
func (*NumLiteral) String ¶
func (n *NumLiteral) String() string
String returns a string representation of the NumLiteral node.
func (*NumLiteral) Token ¶
func (n *NumLiteral) Token() *lexer.Token
Token returns the token of the Evy source program associated with the NumLiteral node.
func (*NumLiteral) Type ¶
func (n *NumLiteral) Type() *Type
Type returns NUM_TYPE for NumLiteral as a number literal always has the num type.
type Operator ¶
type Operator int
Operator represents the operators used in binary and unary expressions. For example, the OP_ASTERISK operator represents the multiplication operator (*).
const ( OP_ILLEGAL Operator = iota OP_PLUS OP_MINUS OP_SLASH OP_ASTERISK OP_PERCENT OP_OR OP_AND OP_EQ OP_NOT_EQ OP_LT OP_GT OP_LTEQ OP_GTEQ OP_INDEX OP_DOT OP_BANG )
Operators are represented as constants and are used in BinaryExpression and UnaryExpression.
type Program ¶
type Program struct { // Statements is the ordered list of top level block and basic statements of the given Evy program. Statements []Node // EventHandlers maps event names to their event handler statements. // It is used in web interface to set connect up relevant handlers with JS event handlers. EventHandlers map[string]*EventHandlerStmt // CalledBuiltinFuncs is a list of builtin functions that are called // in the program. It is used in web interface to hide or show // Canvas and input widgets, such as sliders or readline text field. CalledBuiltinFuncs []string // contains filtered or unexported fields }
Program is the top-level or root AST node. It represents the entire Evy program.
Program implements the Node interface.
func Parse ¶
Parse takes an Evy program and predefined builtin declarations and returns program's AST.
func (*Program) Format ¶
Format returns a string of the formatted program with consistent indentation and vertical whitespace.
type ReturnStmt ¶
type ReturnStmt struct { Value Node // literal, expression, variable, ... T *Type // contains filtered or unexported fields }
ReturnStmt is an AST node that represents a return statement. A return statement terminates the execution of a function and can return a value. For example:
func square:num n:num return n * n end
ReturnStmt implements the Node interface.
func (*ReturnStmt) String ¶
func (r *ReturnStmt) String() string
String returns a string representation of the ReturnStmt node.
func (*ReturnStmt) Token ¶
func (r *ReturnStmt) Token() *lexer.Token
Token returns the token of the Evy source program associated with the ReturnStmt node.
func (*ReturnStmt) Type ¶
func (r *ReturnStmt) Type() *Type
Type returns the type of the value returned by the return statement.
type SliceExpression ¶
type SliceExpression struct { T *Type Left Node Start Node End Node // contains filtered or unexported fields }
SliceExpression is an AST node that represents a slice expression. A slice expression is used to access a subsequence of an array or string, such as: array[1:4].
SliceExpression implements the Node interface.
func (*SliceExpression) String ¶
func (s *SliceExpression) String() string
String returns a string representation of the SliceExpression node.
func (*SliceExpression) Token ¶
func (s *SliceExpression) Token() *lexer.Token
Token returns the token of the Evy source program associated with the SliceExpression node.
func (*SliceExpression) Type ¶
func (s *SliceExpression) Type() *Type
Type returns the type of the SliceExpression, which is the same type as the array that is sliced or string if a string is sliced.
type StepRange ¶
type StepRange struct { Start Node // num expression or nil Stop Node // num expression Step Node // num expression or nil // contains filtered or unexported fields }
StepRange is an AST node that represents a step range in a for loop. A step range is used to iterate over a sequence of numbers, starting from the first number and ending with the last number, incrementing by the step size. For example:
for n := range 1 10 2 print n // 1 3 5 7 9 end
StepRange implements the Node interface.
type StringLiteral ¶
type StringLiteral struct { Value string // contains filtered or unexported fields }
StringLiteral is an AST node that represents a string literal. A string literal is a sequence of characters enclosed in double quotes, such as "abc".
StringLiteral implements the Node interface.
func (*StringLiteral) String ¶
func (s *StringLiteral) String() string
String returns a string representation of the StringLiteral node.
func (*StringLiteral) Token ¶
func (s *StringLiteral) Token() *lexer.Token
Token returns the token of the Evy source program associated with the StringLiteral node.
func (*StringLiteral) Type ¶
func (s *StringLiteral) Type() *Type
Type returns STRING_TYPE for StringLiteral as a string literal always has the string type.
type Type ¶
type Type struct { Name TypeName // string, num, bool, composite types array, map Sub *Type // e.g.: `[]int` : Type{Name: "array", Sub: &Type{Name: "int"} } }
Type holds a full representation of any Evy variable or value. It can represent basic types, such as numbers and strings, as well as composite types, such as arrays and maps. It is also used to represent the dynamic ANY_TYPE. For AST nodes that have no type NONE_TYPE is used.
type TypeAssertion ¶
TypeAssertion is an AST node that represents a type assertion expression. A type assertion expression is used to enforce the specific type of an any value. For example:
val:any val = 1 print val.(num)+2 // 3
TypeAssertion implements the Node interface.
func (*TypeAssertion) String ¶
func (t *TypeAssertion) String() string
String returns a string representation of the TypeAssertion node.
func (*TypeAssertion) Token ¶
func (t *TypeAssertion) Token() *lexer.Token
Token returns the token of the Evy source program associated with the TypeAssertion node.
func (*TypeAssertion) Type ¶
func (t *TypeAssertion) Type() *Type
Type returns the type of the TypeAssertion, which is the type that is asserted.
type TypeName ¶
type TypeName int
TypeName represents the enumerable basic types (such as num, string, and bool), categories of composite types (such as array and map), the dynamic type (any), and the none type, which is used where no type is expected. TypeName is used in the Type struct which fully specifies all types, including composite types.
type TypedDeclStmt ¶
type TypedDeclStmt struct { Decl *Decl // contains filtered or unexported fields }
TypedDeclStmt is an AST node that represents a typed declaration statement. A typed declaration statement declares a variable of an explicitly specified type, such as n:num.
TypedDeclStmt implements the Node interface.
func (*TypedDeclStmt) String ¶
func (d *TypedDeclStmt) String() string
String returns a string representation of the TypedDeclStmt node.
func (*TypedDeclStmt) Token ¶
func (d *TypedDeclStmt) Token() *lexer.Token
Token returns the token of the Evy source program associated with the TypedDeclStmt node.
func (*TypedDeclStmt) Type ¶
func (d *TypedDeclStmt) Type() *Type
Type returns the type of the variable that is declared.
type UnaryExpression ¶
UnaryExpression is an AST node that represents a unary expression, such as: -n.
UnaryExpression implements the Node interface.
func (*UnaryExpression) String ¶
func (u *UnaryExpression) String() string
String returns a string representation of the UnaryExpression node.
func (*UnaryExpression) Token ¶
func (u *UnaryExpression) Token() *lexer.Token
Token returns the token of the Evy source program associated with the UnaryExpression node.
func (*UnaryExpression) Type ¶
func (u *UnaryExpression) Type() *Type
Type returns the type of the UnaryExpression, such as bool or num.
type Var ¶
Var is an AST node that represents a variable, its name and type but not its value.
Var implements the Node interface.
type WhileStmt ¶
type WhileStmt struct {
ConditionalBlock
}
WhileStmt is an AST node that represents a while statement, such as
while true print "🌞" end
WhileStmt implements the Node interface.