From 5bf5c6d3fda58aa5343fa47d9949fb784382dc5e Mon Sep 17 00:00:00 2001 From: Mattia Giambirtone Date: Wed, 25 May 2022 12:15:45 +0200 Subject: [PATCH] Fixed variable declarations not compiling in some cases --- src/frontend/compiler.nim | 15 ++++++++------- src/frontend/parser.nim | 6 +++++- src/main.nim | 8 ++++---- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/frontend/compiler.nim b/src/frontend/compiler.nim index 5b27fa9..57584a7 100644 --- a/src/frontend/compiler.nim +++ b/src/frontend/compiler.nim @@ -562,8 +562,8 @@ proc inferType(self: Compiler, node: LiteralExpr): Type = proc toIntrinsic(self: Compiler, typ: Expression): Type = - ## Gets an expression's - ## intrinsic type, if possible + ## Gets an expression's intrinsic type, if + ## possible if typ == nil: return nil case typ.kind: @@ -590,7 +590,7 @@ proc inferType(self: Compiler, node: Expression): Type = if name != nil: return name.valueType else: - result = node.name.lexeme.toIntrinsic() + result = self.toIntrinsic(Expression(node)) if result != nil: result.node = node of unaryExpr: @@ -1307,9 +1307,10 @@ proc varDecl(self: Compiler, node: VarDecl) = let kind = self.inferType(node.valueType) let typ = self.inferType(node.value) if kind == nil and typ == nil: - self.error(&"cannot determine the type of '{node.name.token.lexeme}'") + self.error(&"'{node.name.token.lexeme}' has no type") elif not self.compareTypes(typ, kind): - self.error(&"expected value of type '{self.typeToStr(kind)}', but '{node.name.token.lexeme}' is of type '{self.typeToStr(typ)}'") + if kind != nil: + self.error(&"expected value of type '{self.typeToStr(kind)}', but '{node.name.token.lexeme}' is of type '{self.typeToStr(typ)}'") self.expression(node.value) self.declareName(node) @@ -1326,12 +1327,12 @@ proc funDecl(self: Compiler, node: FunDecl) = # TODO: Forward declarations if node.body != nil: if BlockStmt(node.body).code.len() == 0: - self.error("Cannot declare function with empty body") + self.error("cannot declare function with empty body") let fnType = self.inferType(node) let impl = self.findByType(node.name.token.lexeme, fnType) if impl.len() > 1: # Oh-oh! We found more than one implementation of - # the same function! Error! + # the same function with the same name! Error! var msg = &"multiple matching implementations of '{node.name.token.lexeme}' found:\n" for fn in reversed(impl): var node = FunDecl(fn.valueType.node) diff --git a/src/frontend/parser.nim b/src/frontend/parser.nim index 03f4c40..83116df 100644 --- a/src/frontend/parser.nim +++ b/src/frontend/parser.nim @@ -799,6 +799,7 @@ proc varDecl(self: Parser, isLet: bool = false, let isPrivate = not self.match("*") self.checkDecl(isPrivate) var valueType: IdentExpr + var hasInit = false if self.match(":"): # We don't enforce it here because # the compiler may be able to infer @@ -806,6 +807,7 @@ proc varDecl(self: Parser, isLet: bool = false, self.expect(Identifier, "expecting type name after ':'") valueType = newIdentExpr(self.peek(-1)) if self.match("="): + hasInit = true value = self.expression() if isConst and not value.isConst(): self.error("constant initializer is not a constant") @@ -813,7 +815,7 @@ proc varDecl(self: Parser, isLet: bool = false, if tok.kind != Var: self.error(&"{tok.lexeme} declaration requires an initializer") value = newNilExpr(Token(lexeme: "nil")) - self.expect(Semicolon, &"expecting semicolon after declaration") + self.expect(Semicolon, "expecting semicolon after declaration") case tok.kind: of Var: result = newVarDecl(name, value, isPrivate = isPrivate, token = tok, @@ -826,6 +828,8 @@ proc varDecl(self: Parser, isLet: bool = false, isLet = isLet, valueType = valueType, pragmas = (@[])) else: discard # Unreachable + if not hasInit and VarDecl(result).valueType == nil: + self.error("expecting initializer or type declaration, but neither was found") proc parseDeclArguments(self: Parser, arguments: var seq[tuple[name: IdentExpr, valueType: Expression, mutable: bool, isRef: bool, isPtr: bool]], diff --git a/src/main.nim b/src/main.nim index 5521c13..e9ea762 100644 --- a/src/main.nim +++ b/src/main.nim @@ -27,10 +27,10 @@ proc fillSymbolTable(tokenizer: Lexer) proc getLineEditor: LineEditor # Handy dandy compile-time constants -const debugLexer = false -const debugParser = false +const debugLexer = true +const debugParser = true const debugCompiler = true -const debugSerializer = false +const debugSerializer = true const debugRuntime = false when debugSerializer: @@ -106,7 +106,7 @@ proc repl = var hashMatches = computeSHA256(input).toHex().toLowerAscii() == serialized.fileHash styledEcho fgCyan, "Serialization step: " styledEcho fgBlue, &"\t- File hash: ", fgYellow, serialized.fileHash, fgBlue, " (", if hashMatches: fgGreen else: fgRed, if hashMatches: "OK" else: "Fail", fgBlue, ")" - styledEcho fgBlue, "\t- Peon version: ", fgYellow, &"{serialized.peonVer.major}.{serialized.peonVer.minor}.{serialized.peonVer.patch}", fgBlue, " (commit ", fgYellow, serialized.commitHash[0..8], fgBlue, ") on branch ", fgYellow, serialized.peonBranch + styledEcho fgBlue, "\t- Peon version: ", fgYellow, &"{serialized.version.major}.{serialized.version.minor}.{serialized.version.patch}", fgBlue, " (commit ", fgYellow, serialized.commit[0..8], fgBlue, ") on branch ", fgYellow, serialized.branch stdout.styledWriteLine(fgBlue, "\t- Compilation date & time: ", fgYellow, fromUnix(serialized.compileDate).format("d/M/yyyy HH:mm:ss")) stdout.styledWrite(fgBlue, &"\t- Constants segment: ") if serialized.chunk.consts == compiled.consts: