also derete this #3

Closed
N00nehere wants to merge 49 commits from (deleted):n00nehere-patch-2 into master
2 changed files with 35 additions and 17 deletions
Showing only changes of commit ed79385e2a - Show all commits

View File

@ -151,7 +151,7 @@ proc done(self: Compiler): bool =
result = self.current > self.ast.high() result = self.current > self.ast.high()
proc error(self: Compiler, message: string) = proc error(self: Compiler, message: string) {.raises: [CompileError, ValueError].} =
## Raises a formatted CompileError exception ## Raises a formatted CompileError exception
var tok = self.getCurrentNode().token var tok = self.getCurrentNode().token
raise newException(CompileError, &"A fatal error occurred while compiling '{self.file}', module '{self.currentModule}' line {tok.line} at '{tok.lexeme}' -> {message}") raise newException(CompileError, &"A fatal error occurred while compiling '{self.file}', module '{self.currentModule}' line {tok.line} at '{tok.lexeme}' -> {message}")
@ -246,8 +246,8 @@ proc patchJump(self: Compiler, offset: int) =
self.chunk.code[offset] = JumpIfFalseOrPop.uint8() self.chunk.code[offset] = JumpIfFalseOrPop.uint8()
else: else:
discard discard
self.chunk.code.delete(offset + 1) # Discards the 24 bit integer self.chunk.code.delete(offset + 1) # Discards the first 8 bits of the jump offset (which are empty)
let offsetArray = jump.toDouble() let offsetArray = (jump - 1).toDouble() # -1 since we got rid of 1 byte!
self.chunk.code[offset + 1] = offsetArray[0] self.chunk.code[offset + 1] = offsetArray[0]
self.chunk.code[offset + 2] = offsetArray[1] self.chunk.code[offset + 2] = offsetArray[1]
else: else:
@ -562,7 +562,7 @@ proc identifier(self: Compiler, node: IdentExpr) =
let t = self.getStaticIndex(node) let t = self.getStaticIndex(node)
let index = t.pos let index = t.pos
if index != -1: if index != -1:
if t.closedOver: if not t.closedOver:
self.emitByte(LoadVar) # Static name resolution, loads value at index in the stack. Very fast. Much wow. self.emitByte(LoadVar) # Static name resolution, loads value at index in the stack. Very fast. Much wow.
self.emitBytes(index.toTriple()) self.emitBytes(index.toTriple())
else: else:
@ -765,11 +765,13 @@ proc inferValueType(self: Compiler, node: ASTNode): ASTNode =
size[1] = &"int{size[1]}" size[1] = &"int{size[1]}"
elif size[1].startsWith("f"): elif size[1].startsWith("f"):
size[1] = size[1].strip(true, false, {'f'}) size[1] = size[1].strip(true, false, {'f'})
size[1] = &"float{size[1]}" size[1] = &"float{size[1]}"
return newIdentExpr(Token(lexeme: size[1])) return newIdentExpr(Token(lexeme: size[1]))
else: else:
self.error(&"invalid type specifier '{size[1]}' for '{size[0]}'") self.error(&"invalid type specifier '{size[1]}' for '{size[0]}'")
return newIdentExpr(Token(lexeme: "int")) return newIdentExpr(Token(lexeme: "int"))
of nilExpr:
return newIdentExpr(Token(lexeme: "nil"))
else: else:
discard # TODO discard # TODO
@ -887,10 +889,14 @@ proc returnStmt(self: Compiler, node: ReturnStmt) =
## Compiles return statements. An empty return ## Compiles return statements. An empty return
## implicitly returns nil ## implicitly returns nil
let returnType = self.inferExprType(node.value) let returnType = self.inferExprType(node.value)
if returnType == nil: if returnType == nil and self.currentFunction.returnType != nil:
self.error("expression has no type") self.error(&"expected return value of type '{self.currentFunction.returnType.token.lexeme}', but expression has no type")
elif returnType.token.lexeme != self.currentFunction.returnType.token.lexeme: elif self.currentFunction.returnType == nil:
self.error(&"expected value of type '{self.currentFunction.returnType.token.lexeme}', got '{returnType.token.lexeme}'") if node.value.kind != nilExpr:
self.error("non-nil return value is not allowed in functions without an explicit return type")
else:
if returnType.token.lexeme != self.currentFunction.returnType.token.lexeme:
self.error(&"expected return value of type '{self.currentFunction.returnType.token.lexeme}', got '{returnType.token.lexeme}' instead")
self.expression(node.value) self.expression(node.value)
self.emitByte(OpCode.Return) self.emitByte(OpCode.Return)
@ -997,16 +1003,16 @@ proc statement(self: Compiler, node: ASTNode) =
proc varDecl(self: Compiler, node: VarDecl) = proc varDecl(self: Compiler, node: VarDecl) =
## Compiles variable declarations ## Compiles variable declarations
if self.inferDeclType(node) == nil: let kind = self.inferDeclType(node)
if kind == nil:
self.error(&"Cannot determine the type of '{node.name.token.lexeme}'") self.error(&"Cannot determine the type of '{node.name.token.lexeme}'")
self.expression(node.value) self.expression(node.value)
self.declareName(node, IdentExpr(node.valueType)) self.declareName(node, IdentExpr(kind))
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

@ -15,6 +15,7 @@
## A recursive-descent top-down parser implementation ## A recursive-descent top-down parser implementation
import strformat import strformat
import strutils
import meta/token import meta/token
@ -120,7 +121,7 @@ proc step(self: Parser, n: int = 1): Token =
self.current += 1 self.current += 1
proc error(self: Parser, message: string) = proc error(self: Parser, message: string) {.raises: [ParseError, ValueError].} =
## Raises a formatted ParseError exception ## Raises a formatted ParseError exception
var lexeme = self.getCurrentToken().lexeme var lexeme = self.getCurrentToken().lexeme
var errorMessage = &"A fatal error occurred while parsing '{self.file}', line {self.peek().line} at '{lexeme}' -> {message}" var errorMessage = &"A fatal error occurred while parsing '{self.file}', line {self.peek().line} at '{lexeme}' -> {message}"
@ -181,6 +182,17 @@ proc expect(self: Parser, kind: TokenType, message: string = "") =
self.error(message) self.error(message)
proc expect(self: Parser, kinds: openarray[TokenType], message: string = "") =
## Behaves like self.expect(), except that
## an error is raised only if none of the
## given token kinds matches
for kind in kinds:
if self.match(kind):
return
if message.len() == 0:
self.error(&"""expecting any of the following tokens: {kinds.join(", ")}, but got {self.peek().kind} instead""")
# Forward declarations # Forward declarations
proc expression(self: Parser): ASTNode proc expression(self: Parser): ASTNode
proc expressionStatement(self: Parser): ASTNode proc expressionStatement(self: Parser): ASTNode
@ -590,7 +602,7 @@ proc returnStmt(self: Parser): ASTNode =
let tok = self.peek(-1) let tok = self.peek(-1)
if self.currentFunction == nil: if self.currentFunction == nil:
self.error("'return' cannot be used outside functions") self.error("'return' cannot be used outside functions")
var value: ASTNode var value: ASTNode = newNilExpr(Token(lexeme: "nil"))
if not self.check(Semicolon): if not self.check(Semicolon):
# Since return can be used on its own too # Since return can be used on its own too
# (in which case it implicitly returns nil), # (in which case it implicitly returns nil),
@ -884,7 +896,7 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false, isL
# A function without an explicit # A function without an explicit
# return type is the same as a void # return type is the same as a void
# function in C (i.e. no return type) # function in C (i.e. no return type)
self.expect(Identifier, "expecting function return type after ':'") self.expect([Identifier, Nil], "expecting function return type after ':'")
returnType = newIdentExpr(self.peek(-1)) returnType = newIdentExpr(self.peek(-1))
if not self.match(LeftBrace): if not self.match(LeftBrace):
# Argument-less function # Argument-less function
@ -1031,7 +1043,7 @@ proc declaration(self: Parser): ASTNode =
of Operator: of Operator:
discard self.step() discard self.step()
result = self.funDecl(isOperator=true) result = self.funDecl(isOperator=true)
of Type, Comment, Whitespace, Tab: of Type, Comment, TokenType.Whitespace, TokenType.Tab:
discard self.step() # TODO discard self.step() # TODO
else: else:
result = self.statement() result = self.statement()