Various fixes to closures and function objects

This commit is contained in:
Mattia Giambirtone 2022-10-06 09:57:19 +02:00
parent 9c878e5b9e
commit a4bccba6cd
6 changed files with 24 additions and 11 deletions

View File

@ -65,6 +65,7 @@ type
isClosure: bool
envLen: int
children: seq[Type]
parent: Type
of Reference, Pointer:
value: Type
of Generic:
@ -475,7 +476,6 @@ proc getStackPos(self: Compiler, name: Name): int =
if name == variable:
found = true
break
inc(result)
if not found:
return -1
@ -944,12 +944,14 @@ proc emitFunction(self: Compiler, name: Name) =
# created by previous LoadFunction instructions
# that is now bound to some variable, so we just
# load it
elif self.scopeDepth > 0 and name.depth != self.scopeDepth:
elif self.scopeDepth > 0 and not self.currentFunction.isNil() and name.depth != self.scopeDepth:
self.emitByte(LoadClosure, name.line)
self.emitBytes(self.getClosurePos(name).toTriple(), name.line)
self.emitByte(LoadVar, name.line)
self.emitBytes(self.getStackPos(name).toTriple(), name.line)
else:
self.emitByte(LoadClosure, name.line)
self.emitBytes(self.getClosurePos(name).toTriple(), name.line)
self.emitByte(LoadVar, name.line)
self.emitBytes(self.getStackPos(name).toTriple(), name.line)
proc generateCall(self: Compiler, fn: Name, args: seq[Expression], onStack: bool = false) =
@ -1441,7 +1443,13 @@ proc identifier(self: Compiler, node: IdentExpr) =
# align its semantics with the call stack. This makes closures work as expected and is
# not much slower than indexing our stack (since they're both dynamic arrays at runtime anyway)
if not s.isClosedOver:
self.currentFunction.valueType.isClosure = true
var fn = self.currentFunction.valueType
while true:
fn.isClosure = true
if fn.parent.isNil():
break
fn = fn.parent
s.isClosedOver = true
self.currentFunction.valueType.envLen += 1
self.closedOver.add(s)
let stackIdx = self.getStackPos(s).toTriple()
@ -1851,6 +1859,7 @@ proc funDecl(self: Compiler, node: FunDecl, fn: Name = nil, args: seq[Expression
var function = self.currentFunction
if not self.currentFunction.isNil():
self.currentFunction.valueType.children.add(fn.valueType)
fn.valueType.parent = function.valueType
self.currentFunction = fn
var names {.used.} = self.names[^(node.arguments.len())..^1]
if fn.valueType.isBuiltinFunction:

View File

@ -967,6 +967,8 @@ proc parseFunExpr(self: Parser): LambdaExpr =
result.returnType = self.parseFunExpr()
else:
result.returnType = self.expression()
result.arguments = arguments
result.defaults = defaults
proc parseGenerics(self: Parser, decl: Declaration) =

View File

@ -6,12 +6,12 @@ fn first(a, b, c: int): int {
}
fn second(a, b: int): int {
return b;
return first(b, a, 0);
}
fn last(a, b, c: int): int {
return c;
return second(a, c);
}

View File

@ -13,5 +13,7 @@ fn makeClosure(n: int): fn: fn: int {
}
print(makeClosure(1)()()); # 1
var closure = makeClosure(38);
var inner = closure();
print(inner()); # 38!

View File

@ -12,7 +12,7 @@ fn outer: fn (n: int): int {
fn getAdder(a, b: int): fn: int64 {
fn getAdder(a, b: int): fn (): int64 {
var x = a;
var y = b;
fn adder: int {

View File

@ -18,5 +18,5 @@ fn outerTwo(n: int): int {
}
print(outerTwo(5));
print(outer());
print(outerTwo(5)); # 5
print(outer()); # 69420