From e02f1595142a5ac0aae42c41bb003e5f87960d6e Mon Sep 17 00:00:00 2001 From: Mattia Giambirtone Date: Tue, 12 Apr 2022 12:18:25 +0200 Subject: [PATCH] Initial work on inferring types --- src/frontend/compiler.nim | 53 ++++++++++++++++++++++++++++++++++----- src/frontend/meta/ast.nim | 37 ++++++++++++++------------- src/frontend/parser.nim | 2 +- src/test.nim | 8 ++++++ 4 files changed, 76 insertions(+), 24 deletions(-) diff --git a/src/frontend/compiler.nim b/src/frontend/compiler.nim index a15a483..e1bb2af 100644 --- a/src/frontend/compiler.nim +++ b/src/frontend/compiler.nim @@ -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 diff --git a/src/frontend/meta/ast.nim b/src/frontend/meta/ast.nim index fbe5787..cd62f4d 100644 --- a/src/frontend/meta/ast.nim +++ b/src/frontend/meta/ast.nim @@ -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 = diff --git a/src/frontend/parser.nim b/src/frontend/parser.nim index b9f521e..55ceb39 100644 --- a/src/frontend/parser.nim +++ b/src/frontend/parser.nim @@ -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(): diff --git a/src/test.nim b/src/test.nim index f95e8fe..b599c70 100644 --- a/src/test.nim +++ b/src/test.nim @@ -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)