Initial work on inferring types
This commit is contained in:
parent
025f8b463b
commit
e02f159514
|
@ -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
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
|
@ -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():
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue