peon-rewrite/src/frontend/parser/ast.nim

875 lines
29 KiB
Nim

# Copyright 2022 Mattia Giambirtone & All Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## An Abstract Syntax Tree (AST) structure for our recursive-descent
## top-down parser. For more info, check out docs/grammar.md
import std/strformat
import std/strutils
import token
export token
type
NodeKind* = enum
## Enumeration of the AST
## node types, sorted by
## precedence
# Declarations
typeDecl = 0'u8
funDecl,
varDecl,
# Statements
ifStmt,
returnStmt,
breakStmt,
continueStmt,
whileStmt,
forEachStmt,
blockStmt,
namedBlockStmt,
raiseStmt,
assertStmt,
tryStmt,
yieldStmt,
awaitStmt,
importStmt,
exportStmt,
deferStmt,
# An expression followed by a semicolon
exprStmt,
# Expressions
assignExpr,
lambdaExpr,
awaitExpr,
yieldExpr,
setItemExpr, # Set expressions like a.b = "c"
binaryExpr,
unaryExpr,
sliceExpr,
callExpr,
getItemExpr, # Get expressions like a.b
# Primary expressions
groupingExpr, # Parenthesized expressions such as (true) and (3 + 4)
trueExpr,
falseExpr,
strExpr,
charExpr,
intExpr,
floatExpr,
hexExpr,
octExpr,
binExpr,
nanExpr,
infExpr,
identExpr, # Identifier
pragmaExpr,
refExpr,
ptrExpr,
genericExpr,
switchStmt,
lentExpr,
constExpr
# Here I would've rather used object variants, and in fact that's what was in
# place before, but not being able to re-declare a field of the same type in
# another case branch is kind of a deal breaker long-term, so until that is
# fixed (check out https://github.com/nim-lang/RFCs/issues/368 for more info).
# I'll stick to using inheritance instead
# Generic AST node types
ASTNode* = ref object of RootObj
## An AST node
kind*: NodeKind
# Regardless of the type of node, we keep the token in the AST node for internal usage.
# This is not shown when the node is printed, but makes it a heck of a lot easier to report
# errors accurately even deep in the compilation pipeline
token*: Token
file*: string
# This weird inheritance chain is needed for the parser to
# work properly
Declaration* = ref object of ASTNode
## A declaration
isPrivate*: bool
pragmas*: seq[Pragma]
genericTypes*: seq[tuple[name: IdentExpr, cond: Expression]]
genericValues*: seq[tuple[name: IdentExpr, cond: Expression]]
Statement* = ref object of Declaration
## A statement
Expression* = ref object of Statement
## An expression
LiteralExpr* = ref object of Expression
# Using a string for literals makes it much easier to handle numeric types, as
# there is no overflow nor underflow or float precision issues during parsing.
# Numbers are just serialized as strings and then converted back to numbers
# before being passed to the VM, which also keeps the door open in the future
# to implementing bignum arithmetic that can take advantage of natively supported
# machine types, meaning that if a numeric type fits into a 64 bit signed/unsigned
# int then it is stored in such a type to save space, otherwise it is just converted
# to a bigint. Bigfloats with arbitrary-precision arithmetic would also be nice,
# although arguably less useful (and probably significantly slower than bigints)
literal*: Token
IdentExpr* = ref object of Expression
name*: Token
depth*: int
GroupingExpr* = ref object of Expression
expression*: Expression
GetItemExpr* = ref object of Expression
obj*: Expression
name*: IdentExpr
SetItemExpr* = ref object of GetItemExpr
# Since a setItem expression is just
# a getItem one followed by an assignment,
# inheriting it from getItem makes sense
value*: Expression
CallExpr* = ref object of Expression
callee*: Expression # The object being called
arguments*: tuple[positionals: seq[Expression], keyword: seq[tuple[
name: IdentExpr, value: Expression]]]
closeParen*: Token # Needed for error reporting
GenericExpr* = ref object of Expression
ident*: IdentExpr
args*: seq[Expression]
UnaryExpr* = ref object of Expression
operator*: Token
a*: Expression
BinaryExpr* = ref object of UnaryExpr
# Binary expressions can be seen here as unary
# expressions with an extra operand so we just
# inherit from that and add a second operand
b*: Expression
YieldExpr* = ref object of Expression
expression*: Expression
AwaitExpr* = ref object of Expression
expression*: Expression
LambdaExpr* = ref object of Expression
body*: Statement
arguments*: seq[tuple[name: IdentExpr, valueType: Expression]]
defaults*: seq[Expression]
isGenerator*: bool
isAsync*: bool
returnType*: Expression
depth*: int
SliceExpr* = ref object of Expression
expression*: Expression
ends*: seq[Expression]
AssignExpr* = ref object of Expression
name*: IdentExpr
value*: Expression
ExprStmt* = ref object of Statement
expression*: Expression
ImportStmt* = ref object of Statement
moduleName*: IdentExpr
fromStmt*: bool
names*: seq[IdentExpr]
ExportStmt* = ref object of Statement
name*: IdentExpr
AssertStmt* = ref object of Statement
expression*: Expression
RaiseStmt* = ref object of Statement
exception*: Expression
BlockStmt* = ref object of Statement
code*: seq[Declaration]
NamedBlockStmt* = ref object of BlockStmt
name*: IdentExpr
ForStmt* = ref object of Statement
discard # Unused
ForEachStmt* = ref object of Statement
identifier*: IdentExpr
expression*: Expression
body*: Statement
WhileStmt* = ref object of Statement
condition*: Expression
body*: BlockStmt
AwaitStmt* = ref object of Statement
expression*: Expression
BreakStmt* = ref object of Statement
label*: IdentExpr
ContinueStmt* = ref object of Statement
label*: IdentExpr
ReturnStmt* = ref object of Statement
value*: Expression
IfStmt* = ref object of Statement
condition*: Expression
thenBranch*: Statement
elseBranch*: Statement
YieldStmt* = ref object of Statement
expression*: Expression
VarDecl* = ref object of Declaration
name*: IdentExpr
constant*: bool
mutable*: bool
valueType*: Expression
value*: Expression
FunDecl* = ref object of Declaration
name*: IdentExpr
body*: Statement
arguments*: seq[tuple[name: IdentExpr, valueType: Expression]]
defaults*: seq[Expression]
isAsync*: bool
isGenerator*: bool
returnType*: Expression
TypeDecl* = ref object of Declaration
name*: IdentExpr
# Empty if type is an enum
fields*: seq[tuple[name: IdentExpr, valueType: Expression, isPrivate: bool, default: Expression]]
# Empty if type is a structure
members*: seq[TypeDecl]
isEnum*: bool
isRef*: bool
parent*: Expression
value*: Expression
Pragma* = ref object of Expression
name*: IdentExpr
args*: seq[LiteralExpr]
Var* = ref object of Expression
value*: Expression
Ref* = ref object of Expression
value*: Expression
Ptr* = ref object of Expression
value*: Expression
Lent* = ref object of Expression
value*: Expression
Const* = ref object of Expression
value*: Expression
SwitchStmt* = ref object of Statement
switch*: Expression
branches*: seq[tuple[cond: Expression, body: BlockStmt]]
default*: BlockStmt
proc isConst*(self: ASTNode): bool =
## Returns true if the given
## AST node represents a value
## of constant type. All integers,
## strings and singletons count as
## constants
case self.kind:
of intExpr, hexExpr, binExpr, octExpr, strExpr, falseExpr, trueExpr,
floatExpr, nanExpr, infExpr:
return true
else:
return false
proc isDecl*(self: ASTNode): bool =
## Returns true if the given AST node
## represents a declaration
return self.kind in [typeDecl, funDecl, varDecl]
## AST node constructors
proc newASTNode*(kind: NodeKind, token: Token): ASTNode =
## Initializes a new generic ASTNode object
new(result)
result.kind = kind
result.token = token
proc newPragma*(name: IdentExpr, args: seq[LiteralExpr]): Pragma =
new(result)
result.kind = pragmaExpr
result.args = args
result.name = name
result.token = name.token
proc newRefExpr*(expression: Expression, token: Token): Ref =
new(result)
result.kind = refExpr
result.value = expression
result.token = token
proc newPtrExpr*(expression: Expression, token: Token): Ptr =
new(result)
result.kind = ptrExpr
result.value = expression
result.token = token
proc newLentExpr*(expression: Expression, token: Token): Lent =
new(result)
result.kind = lentExpr
result.value = expression
result.token = token
proc newConstExpr*(expression: Expression, token: Token): Const =
new(result)
result.kind = constExpr
result.value = expression
result.token = token
proc newSwitchStmt*(switch: Expression, branches: seq[tuple[cond: Expression, body: BlockStmt]], default: BlockStmt, token: Token): SwitchStmt =
new(result)
result.kind = switchStmt
result.switch = switch
result.branches = branches
result.token = token
result.default = default
proc newIntExpr*(literal: Token): LiteralExpr =
result = LiteralExpr(kind: intExpr)
result.literal = literal
result.token = literal
proc newOctExpr*(literal: Token): LiteralExpr =
result = LiteralExpr(kind: octExpr)
result.literal = literal
result.token = literal
proc newHexExpr*(literal: Token): LiteralExpr =
result = LiteralExpr(kind: hexExpr)
result.literal = literal
result.token = literal
proc newBinExpr*(literal: Token): LiteralExpr =
result = LiteralExpr(kind: binExpr)
result.literal = literal
result.token = literal
proc newFloatExpr*(literal: Token): LiteralExpr =
result = LiteralExpr(kind: floatExpr)
result.literal = literal
result.token = literal
proc newTrueExpr*(token: Token): LiteralExpr = LiteralExpr(kind: trueExpr, token: token, literal: token)
proc newFalseExpr*(token: Token): LiteralExpr = LiteralExpr(kind: falseExpr, token: token, literal: token)
proc newNanExpr*(token: Token): LiteralExpr = LiteralExpr(kind: nanExpr, token: token, literal: token)
proc newInfExpr*(token: Token): LiteralExpr = LiteralExpr(kind: infExpr, token: token, literal: token)
proc newStrExpr*(literal: Token): LiteralExpr =
result = LiteralExpr(kind: strExpr)
result.literal = literal
result.token = literal
proc newCharExpr*(literal: Token): LiteralExpr =
result = LiteralExpr(kind: charExpr)
result.literal = literal
result.token = literal
proc newIdentExpr*(name: Token, depth: int = 0): IdentExpr =
result = IdentExpr(kind: identExpr)
result.name = name
result.token = name
result.depth = depth
proc newGroupingExpr*(expression: Expression, token: Token): GroupingExpr =
result = GroupingExpr(kind: groupingExpr)
result.expression = expression
result.token = token
proc newLambdaExpr*(arguments: seq[tuple[name: IdentExpr, valueType: Expression]], defaults: seq[Expression],
body: Statement, isAsync, isGenerator: bool,
token: Token, depth: int, pragmas: seq[Pragma] = @[],
returnType: Expression, genericTypes: seq[tuple[name: IdentExpr, cond: Expression]] = @[],
genericValues: seq[tuple[name: IdentExpr, cond: Expression]] = @[]): LambdaExpr =
result = LambdaExpr(kind: lambdaExpr)
result.body = body
result.arguments = arguments
result.defaults = defaults
result.isGenerator = isGenerator
result.isAsync = isAsync
result.token = token
result.returnType = returnType
result.pragmas = pragmas
result.genericTypes = genericTypes
result.genericValues = genericValues
result.depth = depth
proc newGetItemExpr*(obj: Expression, name: IdentExpr,
token: Token): GetItemExpr =
result = GetItemExpr(kind: getItemExpr)
result.obj = obj
result.name = name
result.token = token
proc newSetItemExpr*(obj: Expression, name: IdentExpr, value: Expression,
token: Token): SetItemExpr =
result = SetItemExpr(kind: setItemExpr)
result.obj = obj
result.name = name
result.value = value
result.token = token
proc newCallExpr*(callee: Expression, arguments: tuple[positionals: seq[
Expression], keyword: seq[tuple[name: IdentExpr, value: Expression]]],
token: Token): CallExpr =
result = CallExpr(kind: callExpr)
result.callee = callee
result.arguments = arguments
result.token = token
proc newGenericExpr*(ident: IdentExpr, args: seq[Expression]): GenericExpr =
result = GenericExpr(kind: genericExpr)
result.ident = ident
result.args = args
result.token = ident.token
proc newSliceExpr*(expression: Expression, ends: seq[Expression], token: Token): SliceExpr =
result = SliceExpr(kind: sliceExpr)
result.expression = expression
result.ends = ends
result.token = token
proc newUnaryExpr*(operator: Token, a: Expression): UnaryExpr =
result = UnaryExpr(kind: unaryExpr)
result.operator = operator
result.a = a
result.token = result.operator
proc newBinaryExpr*(a: Expression, operator: Token, b: Expression): BinaryExpr =
result = BinaryExpr(kind: binaryExpr)
result.operator = operator
result.a = a
result.b = b
result.token = operator
proc newYieldExpr*(expression: Expression, token: Token): YieldExpr =
result = YieldExpr(kind: yieldExpr)
result.expression = expression
result.token = token
proc newAssignExpr*(name: IdentExpr, value: Expression,
token: Token): AssignExpr =
result = AssignExpr(kind: assignExpr)
result.name = name
result.value = value
result.token = token
proc newAwaitExpr*(expression: Expression, token: Token): AwaitExpr =
result = AwaitExpr(kind: awaitExpr)
result.expression = expression
result.token = token
proc newExprStmt*(expression: Expression, token: Token): ExprStmt =
result = ExprStmt(kind: exprStmt)
result.expression = expression
result.token = token
proc newImportStmt*(moduleName: IdentExpr, fromStmt: bool, names: seq[IdentExpr], token: Token): ImportStmt =
result = ImportStmt(kind: importStmt)
result.moduleName = moduleName
result.token = token
result.fromStmt = fromStmt
result.names = names
proc newExportStmt*(name: IdentExpr, token: Token): ExportStmt =
result = ExportStmt(kind: exportStmt)
result.name = name
result.token = token
proc newYieldStmt*(expression: Expression, token: Token): YieldStmt =
result = YieldStmt(kind: yieldStmt)
result.expression = expression
result.token = token
proc newAwaitStmt*(expression: Expression, token: Token): AwaitStmt =
result = AwaitStmt(kind: awaitStmt)
result.expression = expression
result.token = token
proc newAssertStmt*(expression: Expression, token: Token): AssertStmt =
result = AssertStmt(kind: assertStmt)
result.expression = expression
result.token = token
proc newRaiseStmt*(exception: Expression, token: Token): RaiseStmt =
result = RaiseStmt(kind: raiseStmt)
result.exception = exception
result.token = token
proc newBlockStmt*(code: seq[Declaration], token: Token): BlockStmt =
result = BlockStmt(kind: blockStmt)
result.code = code
result.token = token
proc newNamedBlockStmt*(code: seq[Declaration], name: IdentExpr, token: Token): NamedBlockStmt =
result = NamedBlockStmt(kind: namedBlockStmt)
result.code = code
result.token = token
result.name = name
proc newWhileStmt*(condition: Expression, body: BlockStmt,
token: Token): WhileStmt =
result = WhileStmt(kind: whileStmt)
result.condition = condition
result.body = body
result.token = token
proc newForEachStmt*(identifier: IdentExpr, expression: Expression,
body: Statement, token: Token): ForEachStmt =
result = ForEachStmt(kind: forEachStmt)
result.identifier = identifier
result.expression = expression
result.body = body
result.token = token
proc newBreakStmt*(token: Token, label: IdentExpr = nil): BreakStmt =
result = BreakStmt(kind: breakStmt)
result.token = token
result.label = label
proc newContinueStmt*(token: Token, label: IdentExpr = nil): ContinueStmt =
result = ContinueStmt(kind: continueStmt)
result.token = token
result.label = label
proc newReturnStmt*(value: Expression, token: Token): ReturnStmt =
result = ReturnStmt(kind: returnStmt)
result.value = value
result.token = token
proc newIfStmt*(condition: Expression, thenBranch, elseBranch: Statement,
token: Token): IfStmt =
result = IfStmt(kind: ifStmt)
result.condition = condition
result.thenBranch = thenBranch
result.elseBranch = elseBranch
result.token = token
proc newVarDecl*(name: IdentExpr, valueType, value: Expression, token: Token,
constant: bool = false, isPrivate: bool = true, mutable: bool = false,
pragmas: seq[Pragma] = @[]): VarDecl =
result = VarDecl(kind: varDecl)
result.name = name
result.valueType = valueType
result.value = value
result.constant = constant
result.isPrivate = isPrivate
result.token = token
result.mutable = mutable
result.pragmas = pragmas
proc newFunDecl*(name: IdentExpr, arguments: seq[tuple[name: IdentExpr, valueType: Expression]], defaults: seq[Expression],
body: Statement, isAsync, isGenerator: bool, isPrivate: bool, token: Token, pragmas: seq[Pragma] = @[],
returnType: Expression, genericTypes: seq[tuple[name: IdentExpr, cond: Expression]] = @[],
genericValues: seq[tuple[name: IdentExpr, cond: Expression]] = @[]): FunDecl =
result = FunDecl(kind: funDecl)
result.name = name
result.arguments = arguments
result.defaults = defaults
result.body = body
result.isAsync = isAsync
result.isGenerator = isGenerator
result.isPrivate = isPrivate
result.token = token
result.pragmas = pragmas
result.returnType = returnType
result.genericTypes = genericTypes
result.genericValues = genericValues
proc newTypeDecl*(name: IdentExpr, fields: seq[tuple[name: IdentExpr, valueType: Expression, isPrivate: bool, default: Expression]],
defaults: seq[Expression], isPrivate: bool, token: Token, pragmas: seq[Pragma],
genericTypes: seq[tuple[name: IdentExpr, cond: Expression]],
genericValues: seq[tuple[name: IdentExpr, cond: Expression]],
parent: IdentExpr, isEnum: bool, isRef: bool): TypeDecl =
result = TypeDecl(kind: typeDecl)
result.name = name
result.fields = fields
result.isPrivate = isPrivate
result.token = token
result.pragmas = pragmas
result.genericTypes = genericTypes
result.genericValues = genericValues
result.parent = parent
result.isEnum = isEnum
result.isRef = isRef
result.members = @[]
proc `$`*(self: ASTNode): string =
if self.isNil():
return "nil"
case self.kind:
of intExpr, floatExpr, hexExpr, binExpr, octExpr, strExpr, trueExpr,
falseExpr:
if self.kind in {trueExpr, falseExpr}:
result &= &"Literal({($self.kind)[0..^5]})"
elif self.kind == strExpr:
result &= &"Literal({LiteralExpr(self).literal.lexeme[1..^2].escape()})"
else:
result &= &"Literal({LiteralExpr(self).literal.lexeme})"
of identExpr:
result &= &"Identifier('{IdentExpr(self).name.lexeme}')"
of groupingExpr:
result &= &"Grouping({GroupingExpr(self).expression})"
of getItemExpr:
var self = GetItemExpr(self)
result &= &"GetItem(obj={self.obj}, name={self.name})"
of setItemExpr:
var self = SetItemExpr(self)
result &= &"SetItem(obj={self.obj}, name={self.value}, value={self.value})"
of callExpr:
var self = CallExpr(self)
result &= &"""Call({self.callee}, arguments=(positionals=[{self.arguments.positionals.join(", ")}], keyword=[{self.arguments.keyword.join(", ")}]))"""
of unaryExpr:
var self = UnaryExpr(self)
result &= &"Unary(Operator('{self.operator.lexeme}'), {self.a})"
of binaryExpr:
var self = BinaryExpr(self)
result &= &"Binary({self.a}, Operator('{self.operator.lexeme}'), {self.b})"
of assignExpr:
var self = AssignExpr(self)
result &= &"Assign(name={self.name}, value={self.value})"
of exprStmt:
var self = ExprStmt(self)
result &= &"ExpressionStatement({self.expression})"
of breakStmt:
var self = BreakStmt(self)
if self.label.isNil:
result = "Break()"
else:
result = &"Break({self.label})"
of importStmt:
var self = ImportStmt(self)
result &= &"Import({self.moduleName}, names={self.names}, fromStmt={self.fromStmt})"
of assertStmt:
var self = AssertStmt(self)
result &= &"Assert({self.expression})"
of raiseStmt:
var self = RaiseStmt(self)
result &= &"Raise({self.exception})"
of blockStmt:
var self = BlockStmt(self)
result &= &"""Block([{self.code.join(", ")}])"""
of namedBlockStmt:
var self = NamedBlockStmt(self)
result &= &"""Block(name={self.name}, [{self.code.join(", ")}])"""
of whileStmt:
var self = WhileStmt(self)
result &= &"While(condition={self.condition}, body={self.body})"
of forEachStmt:
var self = ForEachStmt(self)
result &= &"ForEach(identifier={self.identifier}, expression={self.expression}, body={self.body})"
of returnStmt:
var self = ReturnStmt(self)
result &= &"Return({self.value})"
of yieldExpr:
var self = YieldExpr(self)
result &= &"Yield({self.expression})"
of awaitExpr:
var self = AwaitExpr(self)
result &= &"Await({self.expression})"
of ifStmt:
var self = IfStmt(self)
if self.elseBranch == nil:
result &= &"If(condition={self.condition}, thenBranch={self.thenBranch}, elseBranch=nil)"
else:
result &= &"If(condition={self.condition}, thenBranch={self.thenBranch}, elseBranch={self.elseBranch})"
of yieldStmt:
var self = YieldStmt(self)
result &= &"YieldStmt({self.expression})"
of awaitStmt:
var self = AwaitStmt(self)
result &= &"AwaitStmt({self.expression})"
of varDecl:
var self = VarDecl(self)
result &= &"Var(name={self.name}, type={self.valueType}, value={self.value}, mutable={self.mutable}, constant={self.constant}, private={self.isPrivate}, pragmas={self.pragmas})"
of funDecl:
var self = FunDecl(self)
result &= &"""FunDecl(name={self.name}, body={self.body}, type={self.returnType}, arguments=[{self.arguments.join(", ")}], defaults=[{self.defaults.join(", ")}], genericTypes={self.genericTypes}, genericValues={self.genericValues}, async={self.isAsync}, generator={self.isGenerator}, private={self.isPrivate}, pragmas={self.pragmas})"""
of typeDecl:
var self = TypeDecl(self)
result &= &"""TypeDecl(name={self.name}, fields={self.fields}, members={self.members}, private={self.isPrivate}, pragmas={self.pragmas}, genericTypes={self.genericTypes}, genericValues={self.genericValues}, parent={self.parent}, ref={self.isRef}, enum={self.isEnum}, value={self.value})"""
of lambdaExpr:
var self = LambdaExpr(self)
result &= &"""Lambda(body={self.body}, type={self.returnType}, arguments=[{self.arguments.join(", ")}], defaults=[{self.defaults.join(", ")}], generator={self.isGenerator}, async={self.isAsync}, pragmas={self.pragmas})"""
of sliceExpr:
var self = SliceExpr(self)
result &= &"""Slice({self.expression}, ends=[{self.ends.join(", ")}])"""
of pragmaExpr:
var self = Pragma(self)
result &= &"Pragma(name={self.name}, args={self.args})"
of refExpr:
result &= &"Ref({Ref(self).value})"
of ptrExpr:
result &= &"Ptr({Ptr(self).value})"
of constExpr:
result &= &"Const({Const(self).value})"
of lentExpr:
result &= &"Lent({Lent(self).value})"
of genericExpr:
var self = GenericExpr(self)
result &= &"Generic(ident={self.ident}, args={self.args})"
else:
discard
proc `==`*(self, other: IdentExpr): bool {.inline.} = self.token == other.token
proc getRelativeBoundaries*(self: ASTNode): tuple[start, stop: int] =
## Recursively computes the position of a node relative
## to its containing line
case self.kind:
of varDecl:
var self = VarDecl(self)
let start = self.token.relPos.start
var stop = self.name.token.relPos.stop
if not self.valueType.isNil():
stop = self.valueType.getRelativeBoundaries().stop
if not self.value.isNil():
stop = self.value.getRelativeBoundaries().stop
if self.pragmas.len() > 0:
stop = getRelativeBoundaries(self.pragmas[^1]).stop
result = (start, stop)
of typeDecl:
result = (self.token.relPos.start, TypeDecl(self).name.getRelativeBoundaries().stop)
of breakStmt, returnStmt, continueStmt:
result = self.token.relPos
of importStmt:
result = (self.token.relPos.start, getRelativeBoundaries(ImportStmt(self).moduleName).stop)
of exprStmt:
result = getRelativeBoundaries(ExprStmt(self).expression)
of unaryExpr:
var self = UnaryExpr(self)
result = (self.operator.relPos.start, getRelativeBoundaries(self.a).stop)
of binaryExpr:
var self = BinaryExpr(self)
result = (getRelativeBoundaries(self.a).start, getRelativeBoundaries(self.b).stop)
of intExpr, binExpr, hexExpr, octExpr, strExpr, floatExpr, trueExpr, falseExpr:
var self = LiteralExpr(self)
result = self.literal.relPos
of identExpr:
var self = IdentExpr(self)
result = self.token.relPos
of assignExpr:
var self = AssignExpr(self)
result = (getRelativeBoundaries(self.name).start, getRelativeBoundaries(self.value).stop)
of callExpr:
var self = CallExpr(self)
result = (getRelativeBoundaries(self.callee).start, self.closeParen.relPos.stop)
of getItemExpr:
var self = GetItemExpr(self)
result = (getRelativeBoundaries(self.obj).start, getRelativeBoundaries(self.name).stop)
of pragmaExpr:
var self = Pragma(self)
let start = self.token.relPos.start
var stop = 0
if self.args.len() > 0:
stop = self.args[^1].token.relPos.stop + 1
else:
stop = self.token.relPos.stop + 1
# -8 so the error highlights the #pragma[ part as well
result = (self.token.relPos.start - 8, stop)
of genericExpr:
var self = GenericExpr(self)
let ident = getRelativeBoundaries(self.ident)
var stop: int = ident.stop
if self.args.len() > 0:
stop = getRelativeBoundaries(self.args[^1]).stop
# Take the "]" into account
inc(stop)
result = (ident.start, stop)
of refExpr:
var self = Ref(self)
result = (self.token.relPos.start, self.value.getRelativeBoundaries().stop)
of ptrExpr:
var self = Ptr(self)
result = (self.token.relPos.start, self.value.getRelativeBoundaries().stop)
of constExpr:
var self = Const(self)
result = (self.token.relPos.start, self.value.getRelativeBoundaries().stop)
else:
result = (0, 0)