Initial work on inferring types

This commit is contained in:
Mattia Giambirtone 2022-04-12 12:18:25 +02:00
parent 025f8b463b
commit e02f159514
4 changed files with 76 additions and 24 deletions

View File

@ -522,11 +522,7 @@ proc declareName(self: Compiler, node: ASTNode) =
else:
discard # TODO: Classes
proc varDecl(self: Compiler, node: VarDecl) =
## Compiles variable declarations
self.expression(node.value)
self.declareName(node)
proc varDecl(self: Compiler, node: VarDecl)
proc resolveStatic(self: Compiler, name: IdentExpr,
@ -919,9 +915,54 @@ proc statement(self: Compiler, node: ASTNode) =
self.expression(node)
proc inferValueType(self: Compiler, node: ASTNode): ASTNode =
## Infers the type of a given literal expression
case node.kind:
of listExpr:
return ListExpr(node).valueType
of dictExpr:
# It's not important that we don't use
# valueType here, we just need to return
# a non-nil value so we don't error out
return DictExpr(node).keyType
else:
discard # TODO
proc inferExprType(self: Compiler, node: Expression): ASTNode =
## Infers the type of a given expression and
## returns it
# TODO
proc inferDeclType(self: Compiler, node: Declaration): ASTNode =
## Infers the type of a given declaration if it's
## not already defined and returns it
case node.kind:
of funDecl:
var node = FunDecl(node)
if node.returnType != nil:
return node.returnType
of NodeKind.varDecl:
var node = VarDecl(node)
if node.valueType != nil:
return node.valueType
else:
return # Unreachable
proc varDecl(self: Compiler, node: VarDecl) =
## Compiles variable declarations
if self.inferDeclType(node) == nil:
self.error(&"Cannot determine the type of '{node.name.token.lexeme}'")
self.expression(node.value)
self.declareName(node)
proc funDecl(self: Compiler, node: FunDecl) =
## Compiles function declarations
if self.inferDeclType(node) == nil:
self.error(&"Cannot determine the return type of '{node.name.token.lexeme}'")
# We store the current function
var function = self.currentFunction
self.currentFunction = node

View File

@ -115,17 +115,13 @@ type
FloatExpr* = ref object of LiteralExpr
StrExpr* = ref object of LiteralExpr
# There are technically keywords, not literals!
TrueExpr* = ref object of ASTNode
FalseExpr* = ref object of ASTNode
NilExpr* = ref object of ASTNode
NanExpr* = ref object of ASTNode
InfExpr* = ref object of ASTNode
TrueExpr* = ref object of LiteralExpr
FalseExpr* = ref object of LiteralExpr
NilExpr* = ref object of LiteralExpr
NanExpr* = ref object of LiteralExpr
InfExpr* = ref object of LiteralExpr
# Although this is *technically* a literal, Nim doesn't
# allow us to redefine fields from supertypes so it's
# a tough luck for us
ListExpr* = ref object of ASTNode
ListExpr* = ref object of LiteralExpr
members*: seq[ASTNode]
valueType*: IdentExpr
@ -310,8 +306,12 @@ proc isConst*(self: ASTNode): bool =
return false
# TODO: Fix (not all literals are constants)
proc isLiteral*(self: ASTNode): bool {.inline.} = self.isConst()
proc isLiteral*(self: ASTNode): bool {.inline.} =
self.kind in {intExpr, hexExpr, binExpr, octExpr,
strExpr, falseExpr, trueExpr, infExpr,
nanExpr, floatExpr, nilExpr, listExpr,
dictExpr, setExpr, tupleExpr
}
proc newIntExpr*(literal: Token): IntExpr =
@ -344,11 +344,11 @@ proc newFloatExpr*(literal: Token): FloatExpr =
result.token = literal
proc newTrueExpr*(token: Token): LiteralExpr = LiteralExpr(kind: trueExpr, token: token)
proc newFalseExpr*(token: Token): LiteralExpr = LiteralExpr(kind: falseExpr, token: token)
proc newNaNExpr*(token: Token): LiteralExpr = LiteralExpr(kind: nanExpr, token: token)
proc newNilExpr*(token: Token): LiteralExpr = LiteralExpr(kind: nilExpr, token: token)
proc newInfExpr*(token: Token): LiteralExpr = LiteralExpr(kind: infExpr, token: token)
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 newNilExpr*(token: Token): LiteralExpr = LiteralExpr(kind: nilExpr, token: token, literal: token)
proc newInfExpr*(token: Token): LiteralExpr = LiteralExpr(kind: infExpr, token: token, literal: token)
proc newStrExpr*(literal: Token): StrExpr =
@ -391,18 +391,21 @@ proc newListExpr*(members: seq[ASTNode], token: Token): ListExpr =
result = ListExpr(kind: listExpr)
result.members = members
result.token = token
result.literal = result.token
proc newSetExpr*(members: seq[ASTNode], token: Token): SetExpr =
result = SetExpr(kind: setExpr)
result.members = members
result.token = token
result.literal = result.token
proc newTupleExpr*(members: seq[ASTNode], token: Token): TupleExpr =
result = TupleExpr(kind: tupleExpr)
result.members = members
result.token = token
result.literal = result.token
proc newDictExpr*(keys, values: seq[ASTNode], token: Token): DictExpr =

View File

@ -821,7 +821,7 @@ proc varDecl(self: Parser, isLet: bool = false, isConst: bool = false): ASTNode
# the compiler may be able to infer
# the type later!
self.expect(Identifier, "expecting type name after ':'")
valueType = newIdentExpr(self.peek(-1))
valueType = newIdentExpr(self.peek(-1))
if self.match(Equal):
value = self.expression()
if isConst and not value.isConst():

View File

@ -143,6 +143,14 @@ when isMainModule:
echo getCurrentExceptionMsg()
echo &"Source line: {line}"
echo " ".repeat(relPos.start + len("Source line: ")) & "^".repeat(relPos.stop - parser.getCurrentToken().lexeme.len())
except CompileError:
let lineNo = compiler.getCurrentNode().token.line
let relPos = tokenizer.getRelPos(lineNo)
let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
echo getCurrentExceptionMsg()
echo &"Source line: {line}"
echo " ".repeat(relPos.start + len("Source line: ")) & "^".repeat(relPos.stop - compiler.getCurrentNode().token.lexeme.len())
quit(0)