Get closures working!

In the process, I had to change the grammar. There is now a strong
separation between statements and expressions. The code was just wrong
before when it popped locals at the end of a block scope because there
could be temporaries on the stack if the block was in expression
position. This fixes that.

Still need to implement closing over `this`.
This commit is contained in:
Bob Nystrom
2013-12-04 07:43:50 -08:00
parent c14b115c02
commit 157944aa27
32 changed files with 1063 additions and 416 deletions
+25
View File
@@ -0,0 +1,25 @@
var f = null
var g = null
{
var local = "local"
f = fn {
io.write(local)
local = "after f"
io.write(local)
}
g = fn {
io.write(local)
local = "after g"
io.write(local)
}
}
f.call
// expect: local
// expect: after f
g.call
// expect: after f
// expect: after g
@@ -0,0 +1,9 @@
var f = null
fn(param) {
f = fn {
io.write(param)
}
}.call("param")
f.call // expect: param
@@ -0,0 +1,12 @@
var f = null
class Foo {
method(param) {
f = fn {
io.write(param)
}
}
}
Foo.new.method("param")
f.call // expect: param
@@ -0,0 +1,10 @@
var f = null
{
var local = "local"
f = fn {
io.write(local)
}
}
f.call // expect: local
@@ -0,0 +1,14 @@
var foo = null
{
var local = "local"
class Foo {
method {
io.write(local)
}
}
foo = Foo.new
}
foo.method // expect: local
+21
View File
@@ -0,0 +1,21 @@
var f = null
fn {
var a = "a"
fn {
var b = "b"
fn {
var c = "c"
f = fn {
io.write(a)
io.write(b)
io.write(c)
}
}.call
}.call
}.call
f.call
// expect: a
// expect: b
// expect: c
@@ -0,0 +1,6 @@
{
var local = "local"
fn {
io.write(local) // expect: local
}.call
}
+10
View File
@@ -0,0 +1,10 @@
{
var local = "local"
class Foo {
method {
io.write(local)
}
}
Foo.new.method // expect: local
}
@@ -0,0 +1,13 @@
var f = null
{
var a = "a"
f = fn {
io.write(a)
io.write(a)
}
}
f.call
// expect: a
// expect: a
+19
View File
@@ -0,0 +1,19 @@
{
var f = null
{
var a = "a"
f = fn io.write(a)
}
{
// Since a is out of scope, the local slot will be reused by b. Make sure
// that f still closes over a.
var b = "b"
f.call // expect: a
}
}
// TODO(bob): Closing over this.
// TODO(bob): Close over fn/method parameter.
// TODO(bob): Maximum number of closed-over variables (directly and/or indirect).
+6
View File
@@ -0,0 +1,6 @@
var global = "global"
// TODO(bob): Forward reference to global declared after use.
fn {
io.write(global) // expect: global
}.call
+15
View File
@@ -0,0 +1,15 @@
var global = "global"
// TODO(bob): Forward reference to global declared after use.
class Foo {
method {
io.write(global)
}
static classMethod {
io.write(global)
}
}
Foo.new.method // expect: global
Foo.classMethod // expect: global