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
|
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()
|
||||||
|
|
Loading…
Reference in New Issue