// 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