The parser can now correctly recognize returning functions from other functions

This commit is contained in:
Nocturn9x 2022-05-02 11:13:04 +02:00
parent 8ca5caabb7
commit 69a585b117
2 changed files with 60 additions and 23 deletions

View File

@ -856,7 +856,7 @@ proc varDecl(self: Parser, isLet: bool = false, isConst: bool = false): Declarat
of Let:
result = newVarDecl(name, value, isPrivate=isPrivate, token=tok, isLet=isLet, valueType=valueType, pragmas=(@[]))
else:
discard # Unreachable
discard # Unreachable
proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false, isLambda: bool = false, isOperator: bool = false): Declaration =
@ -902,7 +902,10 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false, isL
# Function has explicit return type
if self.match([Function, Coroutine, Generator]):
# The function's return type is another
# function or callable object
# function. We specialize this case because
# the type declaration for a function lacks
# the braces that would qualify it as an
# expression
var arguments: seq[tuple[name: IdentExpr, valueType: Expression]] = @[]
var defaults: seq[Expression] = @[]
returnType = newLambdaExpr(arguments, defaults, nil, isGenerator=self.peek(-1).kind == Generator,
@ -910,21 +913,19 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false, isL
token=self.peek(-1), returnType=nil)
var parameter: tuple[name: IdentExpr, valueType: Expression]
if self.match(LeftParen):
var hasType = false
var j = 0
while not self.check(RightParen):
if arguments.len > 255:
self.error("cannot have more than 255 arguments in function declaration")
self.expect(Identifier, "expecting parameter name")
parameter.name = newIdentExpr(self.peek(-1))
if self.match(Colon):
hasType = true
parameter.valueType = self.expression()
for i in j..arguments.high():
for i in countdown(arguments.high(), 0):
if arguments[i].valueType != nil:
break
arguments[i].valueType = parameter.valueType
else:
hasType = false
j = arguments.high()
parameter.valueType = nil
if parameter in arguments:
self.error("duplicate parameter name in function declaration")
arguments.add(parameter)
@ -935,28 +936,27 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false, isL
if not self.match(Comma):
break
self.expect(RightParen)
if not hasType:
self.error("cannot omit type declaration for function parameters")
for argument in arguments:
if argument.valueType == nil:
self.error(&"missing type declaration for '{argument.name.token.lexeme}' in function declaration")
if self.match(Colon):
LambdaExpr(returnType).returnType = self.expression()
if not self.match(LeftBrace):
var parameter: tuple[name: IdentExpr, valueType: Expression]
self.expect(LeftParen)
var parameter: tuple[name: IdentExpr, valueType: Expression]
while not self.check(RightParen):
var hasType = false
var j = 0
if arguments.len > 255:
self.error("cannot have more than 255 arguments in function declaration")
self.expect(Identifier, "expecting parameter name")
parameter.name = newIdentExpr(self.peek(-1))
if self.match(Colon):
hasType = true
parameter.valueType = self.expression()
for i in j..arguments.high():
for i in countdown(arguments.high(), 0):
if arguments[i].valueType != nil:
break
arguments[i].valueType = parameter.valueType
else:
hasType = false
j = arguments.high()
parameter.valueType = nil
if parameter in arguments:
self.error("duplicate parameter name in function declaration")
arguments.add(parameter)
@ -969,7 +969,44 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false, isL
self.expect(RightParen)
if self.match(Colon):
# Function's return type
returnType = self.expression()
if self.match([Function, Coroutine, Generator]):
var arguments: seq[tuple[name: IdentExpr, valueType: Expression]] = @[]
var defaults: seq[Expression] = @[]
returnType = newLambdaExpr(arguments, defaults, nil, isGenerator=self.peek(-1).kind == Generator,
isAsync=self.peek(-1).kind == Coroutine,
token=self.peek(-1), returnType=nil)
var parameter: tuple[name: IdentExpr, valueType: Expression]
if self.match(LeftParen):
while not self.check(RightParen):
if arguments.len > 255:
self.error("cannot have more than 255 arguments in function declaration")
self.expect(Identifier, "expecting parameter name")
parameter.name = newIdentExpr(self.peek(-1))
if self.match(Colon):
parameter.valueType = self.expression()
for i in countdown(arguments.high(), 0):
if arguments[i].valueType != nil:
break
arguments[i].valueType = parameter.valueType
else:
parameter.valueType = nil
if parameter in arguments:
self.error("duplicate parameter name in function declaration")
arguments.add(parameter)
if self.match(Equal):
defaults.add(self.expression())
elif defaults.len() > 0:
self.error("positional argument cannot follow default argument in function declaration")
if not self.match(Comma):
break
self.expect(RightParen)
for argument in arguments:
if argument.valueType == nil:
self.error(&"missing type declaration for '{argument.name.token.lexeme}' in function declaration")
if self.match(Colon):
LambdaExpr(returnType).returnType = self.expression()
else:
returnType = self.expression()
self.expect(LeftBrace)
if self.currentFunction.kind == funDecl:
if not self.match(Semicolon):
@ -989,15 +1026,15 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false, isL
LambdaExpr(Expression(self.currentFunction)).returnType = returnType
result = self.currentFunction
if isOperator:
# isOperator is only true for functions
# with a name (since nameless operators
# don't make much sense)
if arguments.len() == 0:
self.error("cannot declare argument-less operator")
elif arguments.len() > 2:
self.error("cannot declare operator with more than 2 arguments")
elif FunDecl(result).returnType == nil:
self.error("operator cannot have void return type")
for argument in arguments:
if argument.valueType == nil:
self.error(&"missing type declaration for '{argument.name.token.lexeme}' in function declaration")
self.currentFunction = enclosingFunction

View File

@ -30,9 +30,9 @@ proc getLineEditor: LineEditor
# Handy dandy compile-time constants
const debugLexer = false
const debugParser = true
const debugCompiler = true
const debugCompiler = false
const debugOptimizer = false
const debugSerializer = true
const debugSerializer = false
when isMainModule: