forked from myst-lang/myst
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[interpreter,spec] (myst-lang#109) Fix
self
and scope resolution fo…
…r blocks on static methods. `Invocation` was incorrectly determining the value of `self` to use when calling a function. Before myst-lang#131, it was only checking if the Call had a receiver, and would use that value if it did. After myst-lang#131, if the Call did _not_ have a receiver, it would then check if the functor was a closure, and use the closed value of `self` if it was. Now, Invocations _always_ perform both checks, with closures taking higher precedence than Call receivers (though, both will be pushed to the stack if the conditions are met). Before this commit, I was very confused why static methods weren't working while non-static methods were. I assumed it was an issue with `scope` vs `instance_scope` on Types or something like that, but had no idea. Now, though, I'm even more confused how _any_ case was working previously, as the Call receiver was _always_ being pushed as the value of `self`. At least with this version of the code, the value of `self` that will be present is more explicit and well-specified. ¯\_(ツ)_/¯
- Loading branch information
1 parent
fe72e5a
commit c8eb378
Showing
5 changed files
with
235 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,217 @@ | ||
require "../../spec_helper.cr" | ||
require "../../support/nodes.cr" | ||
require "../../support/interpret.cr" | ||
|
||
describe "Interpreter - Closures" do | ||
describe "on blocks" do | ||
it "captures the value of `self` as part of the closure" do | ||
itr = parse_and_interpret %q( | ||
@sum = 0 | ||
[1, 2, 3].each{ |e| @sum += e } | ||
@sum | ||
) | ||
|
||
itr.stack.last.should eq(val(6)) | ||
end | ||
|
||
it "can access variables from blocks on static methods (see #109)" do | ||
itr = parse_and_interpret %q( | ||
deftype Test | ||
defstatic hello(&block) | ||
block() | ||
end | ||
end | ||
i = 0 | ||
Test.hello do | ||
i += 6 | ||
end | ||
i | ||
) | ||
|
||
itr.stack.last.should eq(val(6)) | ||
end | ||
|
||
it "can access variables from within nested blocks" do | ||
itr = parse_and_interpret %q( | ||
defmodule Test | ||
def hello(&block) | ||
block() | ||
end | ||
end | ||
i = 0 | ||
Test.hello do | ||
[1, 2, 3].each{ |e| i += e } | ||
end | ||
i | ||
) | ||
|
||
itr.stack.last.should eq(val(6)) | ||
end | ||
|
||
it "can access variables from within nested blocks on static methods (see #109)" do | ||
itr = parse_and_interpret %q( | ||
deftype Test | ||
defstatic hello(&block) | ||
block() | ||
end | ||
end | ||
i = 0 | ||
Test.hello do | ||
[1, 2, 3].each{ |e| i += e } | ||
end | ||
i | ||
) | ||
|
||
itr.stack.last.should eq(val(6)) | ||
end | ||
|
||
it "maintains the top level value of `self` from within nested blocks" do | ||
itr = parse_and_interpret %q( | ||
deftype Test | ||
defstatic hello(&block) | ||
block() | ||
end | ||
end | ||
@sum = 0 | ||
Test.hello do | ||
[1, 2, 3].each{ |e| @sum += e } | ||
end | ||
@sum | ||
) | ||
|
||
itr.stack.last.should eq(val(6)) | ||
end | ||
|
||
it "can access variables from a block within an anonymous function" do | ||
itr = parse_and_interpret %q( | ||
defmodule Test | ||
def hello(&block) | ||
block() | ||
end | ||
end | ||
i = 0 | ||
func = fn | ||
->() { [1, 2, 3].each{ |e| i += e }; i } | ||
end | ||
Test.hello(&func) | ||
) | ||
|
||
itr.stack.last.should eq(val(6)) | ||
end | ||
|
||
it "can access variables from a block within an anonymous function on static methods (see #109)" do | ||
itr = parse_and_interpret %q( | ||
deftype Test | ||
defstatic hello(&block) | ||
block() | ||
end | ||
end | ||
i = 0 | ||
func = fn | ||
->() { [1, 2, 3].each{ |e| i += e }; i } | ||
end | ||
Test.hello(&func) | ||
) | ||
|
||
itr.stack.last.should eq(val(6)) | ||
end | ||
end | ||
|
||
|
||
describe "on anonymous functions" do | ||
it "captures the value of `self` as part of the closure" do | ||
itr = parse_and_interpret %q( | ||
@sum = 0 | ||
func = fn | ||
->(a) { @sum += a } | ||
end | ||
func(6) | ||
@sum | ||
) | ||
|
||
itr.stack.last.should eq(val(6)) | ||
end | ||
|
||
it "can access variables from anonymous functions on static methods (see #109)" do | ||
itr = parse_and_interpret %q( | ||
deftype Test | ||
defstatic hello(&block) | ||
block() | ||
end | ||
end | ||
i = 0 | ||
Test.hello(&fn ->() { i += 6 } end) | ||
i | ||
) | ||
|
||
itr.stack.last.should eq(val(6)) | ||
end | ||
|
||
it "can access variables from within a nested block" do | ||
itr = parse_and_interpret %q( | ||
defmodule Test | ||
def hello(&block) | ||
block() | ||
end | ||
end | ||
i = 0 | ||
Test.hello do | ||
func = fn ->(e) { i += e } end | ||
[1, 2, 3].each(&func) | ||
end | ||
i | ||
) | ||
|
||
itr.stack.last.should eq(val(6)) | ||
end | ||
|
||
it "can access variables from within a nested block on static methods (see #109)" do | ||
itr = parse_and_interpret %q( | ||
deftype Test | ||
defstatic hello(&block) | ||
block() | ||
end | ||
end | ||
i = 0 | ||
Test.hello do | ||
func = fn ->(e) { i += e } end | ||
[1, 2, 3].each(&func) | ||
end | ||
i | ||
) | ||
|
||
itr.stack.last.should eq(val(6)) | ||
end | ||
|
||
it "maintains the top level value of `self` from within a nested block" do | ||
itr = parse_and_interpret %q( | ||
deftype Test | ||
defstatic hello(&block) | ||
block() | ||
end | ||
end | ||
@sum = 0 | ||
Test.hello do | ||
func = fn ->(e) { @sum += e } end | ||
[1, 2, 3].each(&func) | ||
end | ||
@sum | ||
) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
deftype Test | ||
defstatic hello(&block) | ||
block() | ||
end | ||
end | ||
|
||
i = 0 | ||
|
||
func = fn | ||
->() { 10.times{ i += 1 } } | ||
end | ||
|
||
Test.hello(&func) |