derete the fil #2
|
@ -151,7 +151,7 @@ proc done(self: Compiler): bool =
|
|||
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
|
||||
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}")
|
||||
|
@ -246,8 +246,8 @@ proc patchJump(self: Compiler, offset: int) =
|
|||
self.chunk.code[offset] = JumpIfFalseOrPop.uint8()
|
||||
else:
|
||||
discard
|
||||
self.chunk.code.delete(offset + 1) # Discards the 24 bit integer
|
||||
let offsetArray = jump.toDouble()
|
||||
self.chunk.code.delete(offset + 1) # Discards the first 8 bits of the jump offset (which are empty)
|
||||
let offsetArray = (jump - 1).toDouble() # -1 since we got rid of 1 byte!
|
||||
self.chunk.code[offset + 1] = offsetArray[0]
|
||||
self.chunk.code[offset + 2] = offsetArray[1]
|
||||
else:
|
||||
|
@ -562,7 +562,7 @@ proc identifier(self: Compiler, node: IdentExpr) =
|
|||
let t = self.getStaticIndex(node)
|
||||
let index = t.pos
|
||||
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.emitBytes(index.toTriple())
|
||||
else:
|
||||
|
@ -765,11 +765,13 @@ proc inferValueType(self: Compiler, node: ASTNode): ASTNode =
|
|||
size[1] = &"int{size[1]}"
|
||||
elif size[1].startsWith("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]))
|
||||
else:
|
||||
self.error(&"invalid type specifier '{size[1]}' for '{size[0]}'")
|
||||
return newIdentExpr(Token(lexeme: "int"))
|
||||
of nilExpr:
|
||||
return newIdentExpr(Token(lexeme: "nil"))
|
||||
else:
|
||||
discard # TODO
|
||||
|
||||
|
@ -887,10 +889,14 @@ proc returnStmt(self: Compiler, node: ReturnStmt) =
|
|||
## Compiles return statements. An empty return
|
||||
## implicitly returns nil
|
||||
let returnType = self.inferExprType(node.value)
|
||||
if returnType == nil:
|
||||
self.error("expression has no type")
|
||||
elif returnType.token.lexeme != self.currentFunction.returnType.token.lexeme:
|
||||
self.error(&"expected value of type '{self.currentFunction.returnType.token.lexeme}', got '{returnType.token.lexeme}'")
|
||||
if returnType == nil and self.currentFunction.returnType != nil:
|
||||
self.error(&"expected return value of type '{self.currentFunction.returnType.token.lexeme}', but expression has no type")
|
||||
elif self.currentFunction.returnType == nil:
|
||||
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.emitByte(OpCode.Return)
|
||||
|
||||
|
@ -997,16 +1003,16 @@ proc statement(self: Compiler, node: ASTNode) =
|
|||
|
||||
proc varDecl(self: Compiler, node: VarDecl) =
|
||||
## 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.expression(node.value)
|
||||
self.declareName(node, IdentExpr(node.valueType))
|
||||
self.declareName(node, IdentExpr(kind))
|
||||
|
||||
|
||||
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
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
## A recursive-descent top-down parser implementation
|
||||
|
||||
import strformat
|
||||
import strutils
|
||||
|
||||
|
||||
import meta/token
|
||||
|
@ -120,7 +121,7 @@ proc step(self: Parser, n: int = 1): Token =
|
|||
self.current += 1
|
||||
|
||||
|
||||
proc error(self: Parser, message: string) =
|
||||
proc error(self: Parser, message: string) {.raises: [ParseError, ValueError].} =
|
||||
## Raises a formatted ParseError exception
|
||||
var lexeme = self.getCurrentToken().lexeme
|
||||
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)
|
||||
|
||||
|
||||
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
|
||||
proc expression(self: Parser): ASTNode
|
||||
proc expressionStatement(self: Parser): ASTNode
|
||||
|
@ -590,7 +602,7 @@ proc returnStmt(self: Parser): ASTNode =
|
|||
let tok = self.peek(-1)
|
||||
if self.currentFunction == nil:
|
||||
self.error("'return' cannot be used outside functions")
|
||||
var value: ASTNode
|
||||
var value: ASTNode = newNilExpr(Token(lexeme: "nil"))
|
||||
if not self.check(Semicolon):
|
||||
# Since return can be used on its own too
|
||||
# (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
|
||||
# return type is the same as a void
|
||||
# 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))
|
||||
if not self.match(LeftBrace):
|
||||
# Argument-less function
|
||||
|
@ -1031,7 +1043,7 @@ proc declaration(self: Parser): ASTNode =
|
|||
of Operator:
|
||||
discard self.step()
|
||||
result = self.funDecl(isOperator=true)
|
||||
of Type, Comment, Whitespace, Tab:
|
||||
of Type, Comment, TokenType.Whitespace, TokenType.Tab:
|
||||
discard self.step() # TODO
|
||||
else:
|
||||
result = self.statement()
|
||||
|
|
Loading…
Reference in New Issue