Skip to content

Commit 523b220

Browse files
committed
feat(closure): allow capture in nested scopes
1 parent 12afad1 commit 523b220

File tree

4 files changed

+41
-28
lines changed

4 files changed

+41
-28
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103
- re-enabled the AST optimizer, only used for the main `arkscript` executable (not enabled when embedding arkscript, so that one can grab variables from the VM)
104104
- loops have their own scope: variables created inside a loop won't leak outside it
105105
- upgraded fmtlib to 11.1.3-13
106+
- allow capture in nested scope (before it was targeting only the current scope)
106107

107108
### Removed
108109
- removed unused `NodeType::Closure`

include/Ark/VM/VM.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,8 @@ namespace Ark
186186
// instruction helpers
187187
// ================================================
188188

189-
inline Value* loadSymbol(uint16_t id, internal::ExecutionContext& context);
190-
inline Value* loadConstAsPtr(uint16_t id) const;
189+
[[nodiscard]] inline Value* loadSymbol(uint16_t id, internal::ExecutionContext& context);
190+
[[nodiscard]] inline Value* loadConstAsPtr(uint16_t id) const;
191191
inline void store(uint16_t id, const Value* val, internal::ExecutionContext& context);
192192
inline void setVal(uint16_t id, const Value* val, internal::ExecutionContext& context);
193193

src/arkreactor/VM/VM.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ namespace Ark
556556
if (!context.saved_scope)
557557
context.saved_scope = Scope();
558558

559-
Value* ptr = (context.locals.back())[arg];
559+
Value* ptr = findNearestVariable(arg, context);
560560
if (!ptr)
561561
throwVMError(ErrorKind::Scope, fmt::format("Couldn't capture `{}' as it is currently unbound", m_state.m_symbols[arg]));
562562
else

tests/unittests/resources/LangSuite/builtins-tests.ark

+37-25
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,43 @@
55
(let closure (fun (&foo) ()))
66

77
(test:suite builtin {
8-
(test:eq (type []) "List")
9-
(test:eq (type true) "Bool")
10-
(test:eq (type false) "Bool")
11-
(test:eq (type nil) "Nil")
12-
(test:eq (type 1) "Number")
13-
(test:eq (type "hello") "String")
14-
(test:eq (type print) "CProc")
15-
(test:eq (type foo) "Function")
16-
(test:eq (type closure) "Closure")
17-
18-
(test:expect (not (io:fileExists? "test.txt")))
19-
(io:writeFile "test.txt" "hello, world!")
20-
(test:expect (io:fileExists? "test.txt"))
21-
(test:eq (io:readFile "test.txt") "hello, world!")
22-
(io:appendToFile "test.txt" "bis")
23-
(test:eq (io:readFile "test.txt") "hello, world!bis")
24-
(test:expect (> (len (io:listFiles "./")) 0))
25-
(test:expect (not (io:dir? "test.txt")))
26-
(test:expect (not (io:fileExists? "temp")))
27-
(io:makeDir "temp")
28-
(test:expect (io:fileExists? "temp"))
29-
(test:expect (io:dir? "temp"))
30-
(let old (time))
31-
(sys:sleep 1)
32-
(test:expect (< old (time)))
8+
(test:case "types" {
9+
(test:eq (type []) "List")
10+
(test:eq (type true) "Bool")
11+
(test:eq (type false) "Bool")
12+
(test:eq (type nil) "Nil")
13+
(test:eq (type 1) "Number")
14+
(test:eq (type "hello") "String")
15+
(test:eq (type print) "CProc")
16+
(test:eq (type foo) "Function")
17+
(test:eq (type closure) "Closure") })
18+
19+
(test:case "closures" {
20+
(mut keep true)
21+
(mut foo nil)
22+
(while keep {
23+
(set foo (fun (&keep) keep))
24+
(set keep false) })
25+
(test:expect foo.keep "capture inside a deeper scope works") })
26+
27+
(test:case "files" {
28+
(test:expect (not (io:fileExists? "test.txt")))
29+
(io:writeFile "test.txt" "hello, world!")
30+
(test:expect (io:fileExists? "test.txt"))
31+
(test:eq (io:readFile "test.txt") "hello, world!")
32+
(io:appendToFile "test.txt" "bis")
33+
(test:eq (io:readFile "test.txt") "hello, world!bis")
34+
(test:expect (> (len (io:listFiles "./")) 0))
35+
(test:expect (not (io:dir? "test.txt")))
36+
(test:expect (not (io:fileExists? "temp")))
37+
(io:makeDir "temp")
38+
(test:expect (io:fileExists? "temp"))
39+
(test:expect (io:dir? "temp")) })
40+
41+
(test:case "time" {
42+
(let old (time))
43+
(sys:sleep 1)
44+
(test:expect (< old (time))) })
3345

3446
(mut rands [])
3547
(mut i 0)

0 commit comments

Comments
 (0)