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: else:
discard # TODO: Classes discard # TODO: Classes
proc varDecl(self: Compiler, node: VarDecl)
proc varDecl(self: Compiler, node: VarDecl) =
## Compiles variable declarations
self.expression(node.value)
self.declareName(node)
proc resolveStatic(self: Compiler, name: IdentExpr, proc resolveStatic(self: Compiler, name: IdentExpr,
@ -919,9 +915,54 @@ proc statement(self: Compiler, node: ASTNode) =
self.expression(node) 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) = proc funDecl(self: Compiler, node: FunDecl) =
## Compiles function declarations ## 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 # We store the current function
var function = self.currentFunction var function = self.currentFunction
self.currentFunction = node self.currentFunction = node

View File

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

View File

@ -143,6 +143,14 @@ when isMainModule:
echo getCurrentExceptionMsg() echo getCurrentExceptionMsg()
echo &"Source line: {line}" echo &"Source line: {line}"
echo " ".repeat(relPos.start + len("Source line: ")) & "^".repeat(relPos.stop - parser.getCurrentToken().lexeme.len()) 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) quit(0)