Added hasExplicitReturn field to function and lambda declarations to fix some errors with compiling them. Fixed minor issues with function and lambda parsing, the parser is now able to skip whitespace/tab tokens trasparently, made parser.done() inline, removed invalid state error from funDecl
This commit is contained in:
parent
e4c2ba2ce2
commit
7cf69cf0cf
|
@ -601,6 +601,7 @@ proc inferType(self: Compiler, node: Declaration): Type =
|
||||||
var node = FunDecl(node)
|
var node = FunDecl(node)
|
||||||
let resolved = self.resolve(node.name)
|
let resolved = self.resolve(node.name)
|
||||||
if resolved != nil:
|
if resolved != nil:
|
||||||
|
echo resolved[]
|
||||||
return resolved.valueType
|
return resolved.valueType
|
||||||
of NodeKind.varDecl:
|
of NodeKind.varDecl:
|
||||||
var node = VarDecl(node)
|
var node = VarDecl(node)
|
||||||
|
@ -699,9 +700,8 @@ proc literal(self: Compiler, node: ASTNode) =
|
||||||
proc unary(self: Compiler, node: UnaryExpr) =
|
proc unary(self: Compiler, node: UnaryExpr) =
|
||||||
## Compiles unary expressions such as decimal
|
## Compiles unary expressions such as decimal
|
||||||
## and bitwise negation
|
## and bitwise negation
|
||||||
self.expression(node.a) # Pushes the operand onto the stack
|
self.expression(node.a) # Pushes the operand onto the stack
|
||||||
# TODO: Find implementation of
|
|
||||||
# the given operator and call it
|
|
||||||
|
|
||||||
|
|
||||||
proc binary(self: Compiler, node: BinaryExpr) =
|
proc binary(self: Compiler, node: BinaryExpr) =
|
||||||
|
@ -1055,7 +1055,7 @@ proc returnStmt(self: Compiler, node: ReturnStmt) =
|
||||||
let typ = self.inferType(self.currentFunction)
|
let typ = self.inferType(self.currentFunction)
|
||||||
## Having the return type
|
## Having the return type
|
||||||
if typ.returnType == nil and returnType != nil:
|
if typ.returnType == nil and returnType != nil:
|
||||||
self.error("non-empty return statement is not allowed in functions without an explicit return type")
|
self.error("non-empty return statement is not allowed in functions with an explicit return type")
|
||||||
elif returnType == nil and typ.returnType != nil:
|
elif returnType == nil and typ.returnType != nil:
|
||||||
self.error(&"expected return value of type '{self.typeToStr(typ.returnType)}', but expression has no type")
|
self.error(&"expected return value of type '{self.typeToStr(typ.returnType)}', but expression has no type")
|
||||||
elif not self.compareTypes(returnType, typ.returnType):
|
elif not self.compareTypes(returnType, typ.returnType):
|
||||||
|
@ -1228,8 +1228,20 @@ proc funDecl(self: Compiler, node: FunDecl) =
|
||||||
# are resolved properly). There's a need for a bit
|
# are resolved properly). There's a need for a bit
|
||||||
# of boilerplate code to make closures work, but
|
# of boilerplate code to make closures work, but
|
||||||
# that's about it
|
# that's about it
|
||||||
self.emitBytes(LoadNil, OpCode.Return)
|
case self.currentFunction.kind:
|
||||||
|
of NodeKind.funDecl:
|
||||||
|
if not self.currentFunction.hasExplicitReturn:
|
||||||
|
let typ = self.inferType(self.currentFunction)
|
||||||
|
if self.currentFunction.returnType == nil and typ != nil:
|
||||||
|
self.error("non-empty return statement is not allowed in functions without an explicit return type")
|
||||||
|
if self.currentFunction.returnType != nil:
|
||||||
|
self.error("function has an explicit return type, but no explicit return statement was found")
|
||||||
|
self.emitByte(OpCode.Return)
|
||||||
|
of NodeKind.lambdaExpr:
|
||||||
|
if not LambdaExpr(Declaration(self.currentFunction)).hasExplicitReturn:
|
||||||
|
self.emitByte(OpCode.Return)
|
||||||
|
else:
|
||||||
|
discard # Unreachable
|
||||||
# Currently defer is not functional so we
|
# Currently defer is not functional so we
|
||||||
# just pop the instructions
|
# just pop the instructions
|
||||||
for i in countup(deferStart, self.deferred.len() - 1, 1):
|
for i in countup(deferStart, self.deferred.len() - 1, 1):
|
||||||
|
|
|
@ -176,6 +176,8 @@ type
|
||||||
isAsync*: bool
|
isAsync*: bool
|
||||||
isPure*: bool
|
isPure*: bool
|
||||||
returnType*: Expression
|
returnType*: Expression
|
||||||
|
hasExplicitReturn*: bool
|
||||||
|
|
||||||
|
|
||||||
SliceExpr* = ref object of Expression
|
SliceExpr* = ref object of Expression
|
||||||
expression*: Expression
|
expression*: Expression
|
||||||
|
@ -258,6 +260,7 @@ type
|
||||||
isPrivate*: bool
|
isPrivate*: bool
|
||||||
isPure*: bool
|
isPure*: bool
|
||||||
returnType*: Expression
|
returnType*: Expression
|
||||||
|
hasExplicitReturn*: bool
|
||||||
Pragma* = ref object of Expression
|
Pragma* = ref object of Expression
|
||||||
name*: IdentExpr
|
name*: IdentExpr
|
||||||
args*: seq[LiteralExpr]
|
args*: seq[LiteralExpr]
|
||||||
|
|
|
@ -167,9 +167,13 @@ proc peek(self: Parser, distance: int = 0): Token =
|
||||||
result = endOfFile
|
result = endOfFile
|
||||||
else:
|
else:
|
||||||
result = self.tokens[self.current + distance]
|
result = self.tokens[self.current + distance]
|
||||||
|
## Hack to ignore whitespace/tab
|
||||||
|
if result.kind in {TokenType.Whitespace, Tab}:
|
||||||
|
# self.current += 1
|
||||||
|
result = self.peek(distance + 1)
|
||||||
|
|
||||||
|
|
||||||
proc done(self: Parser): bool =
|
proc done(self: Parser): bool {.inline.} =
|
||||||
## Returns true if we're at the
|
## Returns true if we're at the
|
||||||
## end of the file. Note that the
|
## end of the file. Note that the
|
||||||
## parser expects an explicit
|
## parser expects an explicit
|
||||||
|
@ -190,8 +194,12 @@ proc step(self: Parser, n: int = 1): Token =
|
||||||
|
|
||||||
proc error(self: Parser, message: string) {.raises: [ParseError, ValueError].} =
|
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.peek().lexeme
|
||||||
var errorMessage = &"A fatal error occurred while parsing '{self.file}', line {self.peek().line} at '{lexeme}' -> {message}"
|
var fn = ""
|
||||||
|
if self.currentFunction != nil:
|
||||||
|
if self.currentFunction.kind == NodeKind.funDecl:
|
||||||
|
fn = &"inside function '{FunDecl(self.currentFunction).name.token.lexeme}'"
|
||||||
|
var errorMessage = &"A fatal error occurred while parsing '{self.file}', {fn} line {self.peek().line} at '{lexeme}' -> {message}"
|
||||||
raise newException(ParseError, errorMessage)
|
raise newException(ParseError, errorMessage)
|
||||||
|
|
||||||
|
|
||||||
|
@ -594,6 +602,11 @@ proc returnStmt(self: Parser): Statement =
|
||||||
value = self.expression()
|
value = self.expression()
|
||||||
endOfLine("missing semicolon after return statement")
|
endOfLine("missing semicolon after return statement")
|
||||||
result = newReturnStmt(value, tok)
|
result = newReturnStmt(value, tok)
|
||||||
|
case self.currentFunction.kind:
|
||||||
|
of NodeKind.funDecl:
|
||||||
|
FunDecl(self.currentFunction).hasExplicitReturn = true
|
||||||
|
else:
|
||||||
|
LambdaExpr(self.currentFunction).hasExplicitReturn = true
|
||||||
|
|
||||||
|
|
||||||
proc yieldStmt(self: Parser): Statement =
|
proc yieldStmt(self: Parser): Statement =
|
||||||
|
@ -903,15 +916,14 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false,
|
||||||
# go all the way up to primary(), which will
|
# go all the way up to primary(), which will
|
||||||
# call us back with isLambda=true, allowing us
|
# call us back with isLambda=true, allowing us
|
||||||
# to actually parse the function as an expression
|
# to actually parse the function as an expression
|
||||||
dec(self.current)
|
while not self.check(tok.kind):
|
||||||
|
dec(self.current)
|
||||||
result = Declaration(self.expressionStatement())
|
result = Declaration(self.expressionStatement())
|
||||||
self.currentFunction = enclosingFunction
|
self.currentFunction = enclosingFunction
|
||||||
return result
|
return result
|
||||||
elif isLambda:
|
elif isLambda:
|
||||||
self.currentFunction = newLambdaExpr(arguments, defaults, newBlockStmt(@[], Token()), isGenerator = isGenerator, isAsync = isAsync, token = tok,
|
self.currentFunction = newLambdaExpr(arguments, defaults, newBlockStmt(@[], Token()), isGenerator = isGenerator, isAsync = isAsync, token = tok,
|
||||||
returnType = nil, pragmas = (@[]))
|
returnType = nil, pragmas = (@[]))
|
||||||
elif not isOperator:
|
|
||||||
self.error("funDecl: invalid state")
|
|
||||||
if self.match(":"):
|
if self.match(":"):
|
||||||
# Function has explicit return type
|
# Function has explicit return type
|
||||||
if self.match([Function, Coroutine, Generator]):
|
if self.match([Function, Coroutine, Generator]):
|
||||||
|
|
Loading…
Reference in New Issue