Renamed all infer* functions to inferType, minor changes to signatures of declaration() and statement()

This commit is contained in:
Mattia Giambirtone 2022-05-04 14:27:15 +02:00
parent a1c5430773
commit c7500f610e
1 changed files with 46 additions and 55 deletions

View File

@ -35,12 +35,9 @@ export multibyte
type
Name = ref object
## A compile-time wrapper around
## statically resolved names.
## Depth indicates to which scope
## the variable belongs, zero meaning
## the global one
## statically resolved names
name: IdentExpr # Name of the identifier
owner: string # Owner of the identifier
owner: string # Owner of the identifier (module)
depth: int # Scope depth
isPrivate: bool # Is this name private?
isConst: bool # Is this a constant?
@ -60,10 +57,11 @@ type
## statements
start: int # Position in the bytecode where the loop starts
depth: int # Scope depth where the loop is located
breakPos: seq[int] # List of positions where
breakPos: seq[int] # List of positions into our bytecode where we need to
# patch jumps. Used for break statements
Compiler* = ref object
## A wrapper around the compiler's state
## A wrapper around the Peon compiler's state
# The bytecode chunk where we write code to
chunk: Chunk
@ -122,14 +120,14 @@ proc newCompiler*(enableOptimizations: bool = true): Compiler =
## Forward declarations
proc expression(self: Compiler, node: ASTNode)
proc statement(self: Compiler, node: ASTNode)
proc declaration(self: Compiler, node: ASTNode)
proc expression(self: Compiler, node: Expression)
proc statement(self: Compiler, node: Statement)
proc declaration(self: Compiler, node: Declaration)
proc peek(self: Compiler, distance: int = 0): ASTNode
proc identifier(self: Compiler, node: IdentExpr)
proc varDecl(self: Compiler, node: VarDecl)
proc inferValueType(self: Compiler, node: ASTNode): Type
proc inferExprType(self: Compiler, node: ASTNode): Type
proc inferType(self: Compiler, node: LiteralExpr): Type
proc inferType(self: Compiler, node: Expression): Type
## End of forward declarations
## Public getter for nicer error formatting
@ -212,7 +210,7 @@ proc makeConstant(self: Compiler, val: LiteralExpr): array[3, uint8] =
proc emitConstant(self: Compiler, obj: LiteralExpr) =
## Emits a LoadConstant instruction along
## with its operand
case self.inferExprType(obj).kind:
case self.inferType(obj).kind:
of Int64:
self.emitByte(LoadInt64)
else:
@ -351,11 +349,10 @@ proc detectClosureVariable(self: Compiler, name: IdentExpr, depth: int = self.sc
proc inferValueType(self: Compiler, node: ASTNode): Type =
proc inferType(self: Compiler, node: LiteralExpr): Type =
## Infers the type of a given literal expression
case node.kind:
of intExpr, binExpr, octExpr, hexExpr:
let node = LiteralExpr(node)
let size = node.token.lexeme.split("'")
if len(size) notin 1..2:
self.error("invalid state: inferValueType -> invalid size specifier (This is an internal error and most likely a bug!)")
@ -367,7 +364,6 @@ proc inferValueType(self: Compiler, node: ASTNode): Type =
else:
self.error(&"invalid type specifier '{size[1]}' for int")
of floatExpr:
let node = LiteralExpr(node)
let size = node.token.lexeme.split("'")
if len(size) notin 1..2:
self.error("invalid state: inferValueType -> invalid size specifier (This is an internal error and most likely a bug!)")
@ -392,33 +388,33 @@ proc inferValueType(self: Compiler, node: ASTNode): Type =
discard # TODO
proc inferExprType(self: Compiler, node: ASTNode): Type =
proc inferType(self: Compiler, node: Expression): Type =
## Infers the type of a given expression and
## returns it
case node.kind:
of identExpr:
var node = IdentExpr(node)
var name = self.resolve(node)
return name.valueType
let name = self.resolve(IdentExpr(node))
if name != nil:
return name.valueType
of unaryExpr:
return self.inferValueType(UnaryExpr(node).a)
return self.inferType(UnaryExpr(node).a)
of binaryExpr:
var node = BinaryExpr(node)
var a = self.inferExprType(node.a)
var b = self.inferExprType(node.b)
if a == nil or b == nil:
let node = BinaryExpr(node)
var a = self.inferType(node.a)
var b = self.inferType(node.b)
if a != b:
return nil
return a
of {intExpr, hexExpr, binExpr, octExpr,
strExpr, falseExpr, trueExpr, infExpr,
nanExpr, floatExpr, nilExpr
}:
return self.inferValueType(node)
return self.inferType(LiteralExpr(node))
else:
discard # Unreachable
proc inferDeclType(self: Compiler, node: Declaration): Type =
proc inferType(self: Compiler, node: Declaration): Type =
## Infers the type of a given declaration if it's
## not already defined and returns it
case node.kind:
@ -433,7 +429,7 @@ proc inferDeclType(self: Compiler, node: Declaration): Type =
if resolved != nil:
return resolved.valueType
else:
return self.inferExprType(node.value)
return self.inferType(node.value)
else:
return # Unreachable
@ -453,7 +449,7 @@ proc typeToStr(self: Compiler, typ: Type): string =
of funDecl:
var node = FunDecl(typ.node)
for i, argument in node.arguments:
result &= &"{argument.name.token.lexeme}: {self.typeToStr(self.inferExprType(argument.name))}"
result &= &"{argument.name.token.lexeme}: {self.typeToStr(self.inferType(argument.name))}"
if i < node.arguments.len():
result &= ", "
result &= ")"
@ -479,7 +475,7 @@ proc toIntrinsic(self: Compiler, typ: Expression): Type =
of trueExpr, falseExpr, intExpr, floatExpr:
return typ.token.lexeme.toIntrinsic()
of identExpr:
let inferred = self.inferExprType(typ)
let inferred = self.inferType(typ)
if inferred != nil:
return
else:
@ -686,7 +682,7 @@ proc declareName(self: Compiler, node: Declaration) =
isPrivate: node.isPrivate,
owner: self.currentModule,
isConst: node.isConst,
valueType: Type(kind: self.inferExprType(node.value).kind, node: node),
valueType: Type(kind: self.inferType(node.value).kind, node: node),
codePos: self.chunk.code.len(),
isLet: node.isLet))
self.emitByte(StoreVar)
@ -696,8 +692,7 @@ proc declareName(self: Compiler, node: Declaration) =
# Declares the function's name in the
# current scope but no StoreVar is emitted
# because a function's name is only useful
# at compile time and has no runtime meaning
# given that we implement functions with jumps
# at compile time
self.names.add(Name(depth: self.scopeDepth,
isPrivate: node.isPrivate,
isConst: false,
@ -714,7 +709,7 @@ proc declareName(self: Compiler, node: Declaration) =
owner: self.currentModule,
isConst: false,
name: argument.name,
valueType: self.inferExprType(argument.name),
valueType: self.inferType(argument.name),
codePos: self.chunk.code.len(),
isLet: false))
self.emitByte(StoreVar)
@ -759,15 +754,15 @@ proc assignment(self: Compiler, node: ASTNode) =
## Compiles assignment expressions
case node.kind:
of assignExpr:
var node = AssignExpr(node)
let node = AssignExpr(node)
let name = IdentExpr(node.name)
let r = self.resolve(name)
if r == nil:
self.error(&"assignment to undeclared name '{node.name}'")
self.error(&"assignment to undeclared name '{name.token.lexeme}'")
elif r.isConst:
self.error(&"cannot assign to '{node.name}'")
self.error(&"cannot assign to '{name.token.lexeme}'")
elif r.isLet:
self.error(&"cannot reassign '{node.name}'")
self.error(&"cannot reassign '{name.token.lexeme}'")
self.expression(node.value)
let t = self.getStackPos(name)
let index = t.pos
@ -800,11 +795,7 @@ proc assignment(self: Compiler, node: ASTNode) =
# what values is set to a given
# offset in a dynamic array, so we only
# need to perform the operation as usual
# and then store it. We could combine
# everything into a single opcode, but
# that would require variants of each
# one for regular stack variables as
# well as closed-over ones
# and then store it again
if index != -1:
if not t.closedOver:
self.emitByte(StoreVar)
@ -814,7 +805,7 @@ proc assignment(self: Compiler, node: ASTNode) =
else:
self.error(&"reference to undeclared name '{node.token.lexeme}'")
of setItemExpr:
discard
let typ = self.inferType(SetItemExpr(node))
# TODO
else:
self.error(&"invalid AST node of kind {node.kind} at assignment(): {node} (This is an internal error and most likely a bug)")
@ -843,7 +834,7 @@ proc endScope(self: Compiler) =
# we can emit a PopN instruction. This is true for
# 99.99999% of the use cases of the language (who the
# hell is going to use 65 THOUSAND local variables?), but
# if you'll ever use more then JAPL will emit a PopN instruction
# if you'll ever use more then Peon will emit a PopN instruction
# for the first 65 thousand and change local variables and then
# emit another batch of plain ol' Pop instructions for the rest
if popped <= uint16.high().int():
@ -922,9 +913,9 @@ proc whileStmt(self: Compiler, node: WhileStmt) =
self.emitLoop(start)
proc expression(self: Compiler, node: ASTNode) =
proc expression(self: Compiler, node: Expression) =
## Compiles all expressions
if self.inferExprType(node) == nil:
if self.inferType(node) == nil:
if node.kind != identExpr:
# So we can raise a more appropriate
# error in self.identifier()
@ -989,8 +980,8 @@ proc deferStmt(self: Compiler, node: DeferStmt) =
proc returnStmt(self: Compiler, node: ReturnStmt) =
## Compiles return statements. An empty return
## implicitly returns nil
let returnType = self.inferExprType(node.value)
let typ = self.inferDeclType(self.currentFunction)
let returnType = self.inferType(node.value)
let typ = self.inferType(self.currentFunction)
if returnType == nil and self.currentFunction.returnType != nil:
self.error(&"expected return value of type '{self.currentFunction.returnType.token.lexeme}', but expression has no type")
elif self.currentFunction.returnType == nil:
@ -1057,7 +1048,7 @@ proc assertStmt(self: Compiler, node: AssertStmt) =
self.emitByte(OpCode.Assert)
proc statement(self: Compiler, node: ASTNode) =
proc statement(self: Compiler, node: Statement) =
## Compiles all statements
case node.kind:
of exprStmt:
@ -1100,13 +1091,13 @@ proc statement(self: Compiler, node: ASTNode) =
of NodeKind.tryStmt:
discard
else:
self.expression(node)
self.expression(Expression(node))
proc varDecl(self: Compiler, node: VarDecl) =
## Compiles variable declarations
let kind = self.toIntrinsic(node.valueType)
let typ = self.inferExprType(node.value)
let typ = self.inferType(node.value)
if kind == nil and typ == nil:
self.error(&"cannot determine the type of '{node.name.token.lexeme}'")
elif typ != kind and kind != nil:
@ -1161,7 +1152,7 @@ proc funDecl(self: Compiler, node: FunDecl) =
proc declaration(self: Compiler, node: ASTNode) =
proc declaration(self: Compiler, node: Declaration) =
## Compiles all declarations
case node.kind:
of NodeKind.varDecl:
@ -1169,7 +1160,7 @@ proc declaration(self: Compiler, node: ASTNode) =
of NodeKind.funDecl:
self.funDecl(FunDecl(node))
else:
self.statement(node)
self.statement(Statement(node))
proc compile*(self: Compiler, ast: seq[ASTNode], file: string): Chunk =
@ -1184,7 +1175,7 @@ proc compile*(self: Compiler, ast: seq[ASTNode], file: string): Chunk =
self.currentModule = self.file
self.current = 0
while not self.done():
self.declaration(self.step())
self.declaration(Declaration(self.step()))
if self.ast.len() > 0:
# *Technically* an empty program is a valid program
self.endScope()