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