nondescript/tests/closures.nds

266 lines
3.9 KiB
Plaintext

// cascade
var f1 = proc() {
var x = 1;
var y = 5;
proc() {
var z = 8;
print (x);
x = x + 1;
proc() {
print (x);
x = x + 1;
proc() {
print (x);
print (y);
print (z);
x = x + 1;
proc() {
print (x);
x = x + 1;
}
}
}
}
};
f1()()()()();
//expect:1.0
//expect:2.0
//expect:3.0
//expect:5.0
//expect:8.0
//expect:4.0
// capturing closures in lists:
var f = proc() {
var y = 5;
var x = @[
proc() print (y),
proc() y = y + 1
];
x
};
var inst = f();
//expect:5.0
inst[0]();
inst[1]();
//expect:6.0
inst[0]();
// multiple different labels
var f2 = proc() { @result
var x = { @a @b
// this captures the internal value, not whatever it returns is assigned to
:result = @{
get = proc() print (:a),
["set"] = proc(n) :b = n,
};
};
x = 5;
};
var inst2 = f2();
inst2["get"]();
//expect:nil
inst2["set"](5.2);
inst2["get"]();
//expect:5.2
// capturing args
var argcap = proc(n)
proc() print(n)
;
//expect:8.1
argcap(8.1)();
// oop: constructors, getters, setters
var newAnimal = proc(species, color) { @result
var species = species; // copy it so that it's mutable, if args ever get immutable
var animal = @{
["getSpecies"] = proc() species,
["setSpecies"] = proc(newSpecies) species = newSpecies,
["getColor"] = proc() color, // this captures an argument directly
};
:result = animal;
};
var horse1 = newAnimal("horse", "brown");
var horse2 = newAnimal("horse", "white");
var turtle = newAnimal("turtle", "brown");
//expect:horse
print (horse1["getSpecies"]());
horse1["setSpecies"]("zebra");
//expect:zebra
print (horse1["getSpecies"]());
//expect:brown
print (horse1["getColor"]());
//expect:horse
print (horse2["getSpecies"]());
//expect:white
print (horse2["getColor"]());
//expect:turtle
print (turtle["getSpecies"]());
// closure examples from craftinginterpreters
// 1:
var makeClosure = proc(value) { @result
var closure = proc() {
print (value);
};
:result = closure;
};
var doughnut = makeClosure("doughnut");
var bagel = makeClosure("bagel");
//expect:doughnut
doughnut();
//expect:bagel
bagel();
// 2: (multi level closures)
var outer = proc() { @result
var x = "value";
var middle = proc() { @result
var inner = proc() {
print (x);
};
print ("create inner closure");
:result = inner;
};
print ("return from outer");
:result = middle;
};
//expect:return from outer
var mid = outer();
//expect:create inner closure
var in = mid();
//expect:value
in();
// 3: (mixed multi level closures)
outer = proc() { @result
var a = 1;
var b = 2;
var result;
var middle = proc() {
var c = 3;
var d = 4;
var inner = proc() {
print (a + c + b + d);
};
result = inner;
};
middle();
:result = proc() result;
};
//expect:10.0
outer()()();
// 4: manipulation of vals from closures
outer = proc() {
var x = "before";
var inner = proc() {
x = "assigned";
};
inner();
print (x);
};
//expect:assigned
outer();
// 5: get/setters using globals
var globalSet;
var globalGet;
var main5 = proc() {
var a = "initial";
var set = proc() { a = "updated"; };
var get = proc() { print (a); };
globalSet = set;
globalGet = get;
};
main5();
globalGet();
//expect:initial
globalSet();
globalGet();
//expect:updated
// 6: multiple upvalues in a simple scope
{
var a = 1;
var f = proc() {
print (a);
};
var b = 2;
var g = proc() {
print (b);
};
var c = 3;
var h = proc() {
print (c);
};
f();
g();
h();
//expect:1.0
//expect:2.0
//expect:3.0
};
// bonus: the last one with a list twist
var bonus = proc() { @result
var a = 1;
var f = proc() {
print (a);
};
var b = 2;
var g = proc() {
print (b);
};
var c = 3;
var h = proc() {
print (c);
};
:result = @[f, g, h];
};
bonus = bonus();
bonus[2]();
bonus[0]();
bonus[1]();
//expect:3.0
//expect:1.0
//expect:2.0