Renamed all infer* functions to inferType, minor changes to signatures of declaration() and statement()
This commit is contained in:
parent
a1c5430773
commit
c7500f610e
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue