From 51ad18c5a4133ccdc0c4de7b6d5ae6935387689d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Reuh=20Fildadut?= Date: Sun, 7 Jan 2024 20:31:28 +0100 Subject: [PATCH] LuaFunction cleanup: replace by LuaCall --- anselme/ast/Function.lua | 76 ++++++++++------- anselme/ast/Identifier.lua | 7 ++ anselme/ast/LuaCall.lua | 60 ++++++++++++++ anselme/ast/LuaFunction.lua | 83 ------------------- anselme/ast/String.lua | 7 +- anselme/ast/Translatable.lua | 2 + anselme/ast/abstract/Node.lua | 29 ++++++- anselme/state/ScopeStack.lua | 6 +- anselme/stdlib/attached block.lua | 4 +- anselme/stdlib/resume.lua | 8 +- anselme/stdlib/script.lua | 3 +- anselme/stdlib/structures.lua | 4 +- test/results/exported variable nested.ans | 2 +- test/results/for invalid iterator.ans | 2 +- .../function custom type dispatch error.ans | 2 +- test/results/function random.ans | 8 +- test/results/function scope wrong.ans | 2 +- ...nction separate variable from variants.ans | 14 +++- .../merge nested mutable error bis.ans | 16 ++-- test/results/merge nested mutable error.ans | 16 ++-- test/tests/serialize function env.ans | 1 + ...t line interpolation with choice event.ans | 2 +- 22 files changed, 192 insertions(+), 162 deletions(-) create mode 100644 anselme/ast/LuaCall.lua delete mode 100644 anselme/ast/LuaFunction.lua diff --git a/anselme/ast/Function.lua b/anselme/ast/Function.lua index b72cbc8..e186c49 100644 --- a/anselme/ast/Function.lua +++ b/anselme/ast/Function.lua @@ -1,30 +1,20 @@ -- note: functions only appear in non-evaluated nodes! once evaluated, they always become closures local ast = require("anselme.ast") -local Overloadable = ast.abstract.Overloadable -local ReturnBoundary, Environment, Identifier, Symbol +local ReturnBoundary, Environment, Identifier local operator_priority = require("anselme.common").operator_priority local resume_manager, calling_environment_manager -local function list_cache_upvalues(v, state, list, scope) - if Identifier:is(v) then - list[v.name] = scope:precache(state, v) - elseif Symbol:is(v) then - list[v.string] = scope:precache(state, v:to_identifier()) - end - v:traverse(list_cache_upvalues, state, list, scope) -end - local Function -Function = Overloadable { +Function = ast.abstract.Overloadable { type = "function", parameters = nil, -- ParameterTuple expression = nil, -- function content scope = nil, -- Environment; captured scope for closure (evaluated functions); not set when not evaluated - upvalues = nil, -- {[name]=variable metadata}; not set when not evaluated. Contain _at least_ all the upvalues explicitely defined in the function code. + upvalues = nil, -- {variable metadata, ...}; not set when not evaluated. Contain _at least_ all the upvalues explicitely defined in the function code. init = function(self, parameters, expression, scope, upvalues) self.parameters = parameters @@ -64,10 +54,15 @@ Function = Overloadable { state.scope:pop() -- list & cache upvalues so they aren't affected by future redefinition in a parent scope - local upvalues = {} - self.expression:traverse(list_cache_upvalues, state, upvalues, scope) + local used_identifiers = {} + self.parameters:list_used_identifiers(used_identifiers) + self.expression:list_used_identifiers(used_identifiers) if scope:defined(state, Identifier:new("_")) then - scope:get(state, Identifier:new("_")):traverse(list_cache_upvalues, state, upvalues, scope) + scope:get(state, Identifier:new("_")):list_used_identifiers(used_identifiers) + end + local upvalues = {} + for _, identifier in ipairs(used_identifiers) do + table.insert(upvalues, scope:precache(state, identifier)) end return Function:new(self.parameters:eval(state), self.expression, scope, upvalues) @@ -83,7 +78,7 @@ Function = Overloadable { return self.parameters:hash() end, call_dispatched = function(self, state, args) - assert(self.scope, "can't call unevaluated function") + assert(self._evaluated, "can't call unevaluated function") -- push captured closure scope local calling_environment = state.scope:capture() @@ -102,7 +97,7 @@ Function = Overloadable { end, resume = function(self, state, target) if self.parameters.min_arity > 0 then error("can't resume function with parameters") end - assert(self.scope, "can't resume unevaluated function") + assert(self._evaluated, "can't resume unevaluated function") -- push captured closure scope local calling_environment = state.scope:capture() @@ -126,28 +121,45 @@ Function = Overloadable { -- Only the upvalues that explicitely appear in the function body and variables directly defined in the function scope will be saved, so we don't have to keep a full copy of the whole environment. _serialize = function(self) local state = require("anselme.serializer_state") - return { parameters = self.parameters, expression = self.expression, upvalues = self.upvalues, scope = self.scope.variables:to_struct(state) } + return self.parameters, self.expression, self.scope.variables:to_struct(state), self.upvalues end, - _deserialize = function(self) - local state = require("anselme.serializer_state") - local scope - if self.upvalues then - -- rebuild scope: exported + normal layer so any upvalue that happen to be exported stay there - -- (and link again to current scope to allow internal vars that are not serialized to still work, like _translations) - scope = Environment:new(state, Environment:new(state, state.scope:capture(), nil, true)) - for _, var in pairs(self.upvalues) do - scope:define(state, var:get_symbol(), var:get(state)) + _deserialize = function(parameters, expression, variables, upvalues) + local r = Function:new(parameters, expression):set_source("saved") + r._deserialize_data = { variables = variables, upvalues = upvalues } + return r + end, + -- we need variables to be fully deserialized before rebuild the function scope + _post_deserialize = function(self, state, cache) + if self._deserialize_data then + local upvalues, variables = self._deserialize_data.upvalues, self._deserialize_data.variables + self._deserialize_data = nil + -- rebuild upvalues: exported + normal layer so any upvalue that happen to be exported stay there + -- (and link again to global scope to allow internal vars that are not serialized to still work, like _translations) + state.scope:push_global() + state.scope:push_export() + state.scope:push() + self.upvalues = {} + for _, var in ipairs(upvalues) do + state.scope:define(var:get_symbol(), var:get(state)) + table.insert(self.upvalues, state.scope.current:precache(state, var:get_symbol():to_identifier())) end - for _, var in self.scope:iter() do - scope:define(state, var:get_symbol(), var:get(state)) + -- rebuild function variables + state.scope:push() + self.scope = state.scope:capture() + for _, var in variables:iter() do + self.scope:define(state, var:get_symbol(), var:get(state)) end + state.scope:pop() + state.scope:pop() + state.scope:pop() + state.scope:pop() + self._evaluated = true end - return Function:new(self.parameters, self.expression, Environment:new(state, scope), self.upvalues):set_source("saved") end } package.loaded[...] = Function -ReturnBoundary, Environment, Identifier, Symbol = ast.ReturnBoundary, ast.Environment, ast.Identifier, ast.Symbol +ReturnBoundary, Environment, Identifier = ast.ReturnBoundary, ast.Environment, ast.Identifier resume_manager = require("anselme.state.resume_manager") calling_environment_manager = require("anselme.state.calling_environment_manager") diff --git a/anselme/ast/Identifier.lua b/anselme/ast/Identifier.lua index 4308ae2..436b973 100644 --- a/anselme/ast/Identifier.lua +++ b/anselme/ast/Identifier.lua @@ -23,6 +23,13 @@ Identifier = ast.abstract.Node { return state.scope:get(self) end, + list_used_identifiers = function(self, t) + if not t[self.name] then + t[self.name] = true + table.insert(t, self) + end + end, + to_string = function(self) return String:new(self.name) end, diff --git a/anselme/ast/LuaCall.lua b/anselme/ast/LuaCall.lua new file mode 100644 index 0000000..59e23e6 --- /dev/null +++ b/anselme/ast/LuaCall.lua @@ -0,0 +1,60 @@ +local ast = require("anselme.ast") +local unpack = table.unpack or unpack +local calling_environment_manager + +local LuaCall +LuaCall = ast.abstract.Runtime { + type = "lua call", + hide_in_stacktrace = true, + _evaluated = false, + + parameters = nil, -- ParameterTuple, may be unevaluated + func = nil, -- lua function + + init = function(self, parameters, func) + self.parameters = parameters + self.func = func + end, + + make_function = function(self, state, parameters, func) + local fn = ast.Function:new(parameters, LuaCall:new(parameters, func)) + return fn:eval(state) + end, + + traverse = function(self, fn, ...) + fn(self.parameters, ...) + end, + + _hash = function(self) + return ("%s<%s;%s>"):format(self.type, self.parameters:hash(), tostring(self.func)) + end, + + _format = function(self, ...) + return "" + end, + + _eval = function(self, state) + -- get arguments + local lua_args = { state } + for _, param in ipairs(self.parameters.list) do + table.insert(lua_args, state.scope:get(param.identifier)) + end + + -- run function, in calling environment + state.scope:push(calling_environment_manager:get_level(state, 1)) + local r = self.func(unpack(lua_args)) + assert(r, "lua function returned no value") + state.scope:pop() + + return r + end, + + to_lua = function(self, state) + return self.func + end, +} + +package.loaded[...] = LuaCall +calling_environment_manager = require("anselme.state.calling_environment_manager") + +return LuaCall diff --git a/anselme/ast/LuaFunction.lua b/anselme/ast/LuaFunction.lua deleted file mode 100644 index 5ee4046..0000000 --- a/anselme/ast/LuaFunction.lua +++ /dev/null @@ -1,83 +0,0 @@ -local ast = require("anselme.ast") -local Overloadable = ast.abstract.Overloadable - -local operator_priority = require("anselme.common").operator_priority -local unpack = table.unpack or unpack - -local calling_environment_manager - -local LuaFunction -LuaFunction = ast.abstract.Runtime(Overloadable) { - type = "lua function", - - parameters = nil, -- ParameterTuple - func = nil, -- lua function - - init = function(self, parameters, func) - self.parameters = parameters - self.func = func - end, - - traverse = function(self, fn, ...) - fn(self.parameters, ...) - end, - - _hash = function(self) - return ("%s<%s;%s>"):format(self.type, self.parameters:hash(), tostring(self.func)) - end, - - _format = function(self, ...) - if self.parameters.assignment then - return "$"..self.parameters:format(...).."; " - else - return "$"..self.parameters:format(...).." " - end - end, - _format_priority = function(self) - return operator_priority["$_"] - end, - - compatible_with_arguments = function(self, state, args) - return args:match_parameter_tuple(state, self.parameters) - end, - format_signature = function(self, state) - return "$"..self.parameters:format_short(state) - end, - hash_signature = function(self) - return self.parameters:hash() - end, - call_dispatched = function(self, state, args) - local calling_environment = state.scope:capture() - calling_environment_manager:push(state, calling_environment) - - local lua_args = { state } - - state.scope:push() - - args:bind_parameter_tuple(state, self.parameters) - for _, param in ipairs(self.parameters.list) do - table.insert(lua_args, state.scope:get(param.identifier)) - end - - state.scope:pop() - - local r = self.func(unpack(lua_args)) - assert(r, "lua function returned no value") - - calling_environment_manager:pop(state) - return r - end, - - _eval = function(self, state) - return LuaFunction:new(self.parameters:eval(state), self.func) - end, - - to_lua = function(self, state) - return self.func - end, -} - -package.loaded[...] = LuaFunction -calling_environment_manager = require("anselme.state.calling_environment_manager") - -return LuaFunction diff --git a/anselme/ast/String.lua b/anselme/ast/String.lua index c195438..2190098 100644 --- a/anselme/ast/String.lua +++ b/anselme/ast/String.lua @@ -1,5 +1,5 @@ local ast = require("anselme.ast") -local Identifier +local Identifier, Symbol local String = ast.abstract.Node { type = "string", @@ -25,10 +25,13 @@ local String = ast.abstract.Node { to_identifier = function(self) return Identifier:new(self.string) + end, + to_symbol = function(self) + return Symbol:new(self.string) end } package.loaded[...] = String -Identifier = ast.Identifier +Identifier, Symbol = ast.Identifier, ast.Symbol return String diff --git a/anselme/ast/Translatable.lua b/anselme/ast/Translatable.lua index eca852c..c1f4487 100644 --- a/anselme/ast/Translatable.lua +++ b/anselme/ast/Translatable.lua @@ -44,7 +44,9 @@ local Translatable = ast.abstract.Node { end, list_translatable = function(self, t) + t = t or {} table.insert(t, self) + return t end } diff --git a/anselme/ast/abstract/Node.lua b/anselme/ast/abstract/Node.lua index 4fd10d6..2b26c89 100644 --- a/anselme/ast/abstract/Node.lua +++ b/anselme/ast/abstract/Node.lua @@ -45,6 +45,9 @@ traverse = { merge = function(self, state, cache) self:merge(state, cache) end, + post_deserialize = function(self, state, cache) + self:post_deserialize(state, cache) + end, hash = function(self, t) table.insert(t, self:hash()) end, @@ -55,6 +58,9 @@ traverse = { for hash, target in pairs(self:list_resume_targets()) do add_to_node._list_resume_targets_cache[hash] = target end + end, + list_used_identifiers = function(self, t) + self:list_used_identifiers(t) end } @@ -134,7 +140,7 @@ Node = class { end, -- generate a list of translatable nodes that appear in this node - -- should only be called on non-evaluated nodes + -- should only be called on non-evaluated nodes (non-evaluated nodes don't contain cycles) -- if a node is translatable, redefine this to add it to the table - note that it shouldn't call :traverse or :list_translatable on its children, as nested translations should not be needed list_translatable = function(self, t) t = t or {} @@ -142,6 +148,14 @@ Node = class { return t end, + -- generate a list of identifiers that are used in this node + -- should only be called on non-evaluated nodes + -- the list contains at least all used nodes; some unused nodes may be present + -- redefine on identifier nodes to add an identifier to the table + list_used_identifiers = function(self, t) + self:traverse(traverse.list_used_identifiers, t) + end, + -- generate anselme code that can be used as a base for a translation file -- will include every translatable element found in this node and its children generate_translation_template = function(self) @@ -388,8 +402,21 @@ Node = class { package.loaded["anselme.serializer_state"] = state local r = binser.deserializeN(str, 1, index) package.loaded["anselme.serializer_state"] = nil + r:post_deserialize(state, {}) return r end, + -- call :_post_deserialize on all children nodes + -- automatically called after a sucesfull deserialization, intended to perform finishing touches for deserialization + -- notably, there is no guarantee that children nodes are already deserialized when _deserialize is called on a node + -- anything that require such a guarantee should be done here + post_deserialize = function(self, state, cache) + if not cache[self] then + cache[self] = true + self:_post_deserialize(state, cache) + self:traverse(traverse.post_deserialize, state, cache) + end + end, + _post_deserialize = function(self, state, cache) end, __tostring = function(self) return self:format() end, diff --git a/anselme/state/ScopeStack.lua b/anselme/state/ScopeStack.lua index ec16ce3..7018012 100644 --- a/anselme/state/ScopeStack.lua +++ b/anselme/state/ScopeStack.lua @@ -6,7 +6,7 @@ local ast = require("anselme.ast") local to_anselme = require("anselme.common.to_anselme") local unpack = table.unpack or unpack -local LuaFunction, Environment, Node +local LuaCall, Environment, Node local parameter_tuple = require("anselme.parser.expression.contextual.parameter_tuple") local symbol = require("anselme.parser.expression.primary.symbol") @@ -64,7 +64,7 @@ local ScopeStack = class { return to_anselme(original_func(unpack(lua_args))) end end - self:define_overloadable(sym, LuaFunction:new(parameters, func):eval(self.state)) + self:define_overloadable(sym, LuaCall:make_function(self.state, parameters, func)) elseif Node:issub(value) then self:define(sym, value) else @@ -150,6 +150,6 @@ local ScopeStack = class { } package.loaded[...] = ScopeStack -LuaFunction, Environment, Node = ast.LuaFunction, ast.Environment, ast.abstract.Node +LuaCall, Environment, Node = ast.LuaCall, ast.Environment, ast.abstract.Node return ScopeStack diff --git a/anselme/stdlib/attached block.lua b/anselme/stdlib/attached block.lua index de13040..e423cdc 100644 --- a/anselme/stdlib/attached block.lua +++ b/anselme/stdlib/attached block.lua @@ -10,7 +10,7 @@ return { "attached block", "(level::is number=1, keep return=false)", function(state, level, keep_return) -- level 2: env of the function that called the function that called attached block - local env = calling_environment_manager:get_level(state, level:to_lua(state)+1) + local env = calling_environment_manager:get_level(state, level:to_lua(state)) local block = env:get(state, block_identifier).expression local fn if keep_return:truthy() then @@ -28,7 +28,7 @@ return { "attached block", "(level::is number=1, keep return=false, default)", function(state, level, keep_return, default) -- level 2: env of the function that called the function that called attached block - local env = calling_environment_manager:get_level(state, level:to_lua(state)+1) + local env = calling_environment_manager:get_level(state, level:to_lua(state)) if env:defined(state, block_identifier) then local block = env:get(state, block_identifier).expression local fn diff --git a/anselme/stdlib/resume.lua b/anselme/stdlib/resume.lua index 3710b9b..c16a799 100644 --- a/anselme/stdlib/resume.lua +++ b/anselme/stdlib/resume.lua @@ -17,16 +17,10 @@ return { return func:call(state, ArgumentTuple:new()) end }, - { - "resuming", "()", - function(state) - return Boolean:new(resume_manager:resuming(state)) - end - }, { "resuming", "(level::is number=0)", function(state, level) - local env = calling_environment_manager:get_level(state, level:to_lua(state)+1) + local env = calling_environment_manager:get_level(state, level:to_lua(state)) state.scope:push(env) local r = Boolean:new(resume_manager:resuming(state)) state.scope:pop() diff --git a/anselme/stdlib/script.lua b/anselme/stdlib/script.lua index 6b7d033..216ef21 100644 --- a/anselme/stdlib/script.lua +++ b/anselme/stdlib/script.lua @@ -9,9 +9,10 @@ return [[ fn.:check = $(anchor::is anchor) fn.reached(anchor) = (fn.reached(anchor) | 0) + 1 fn.:checkpoint = $(anchor::is anchor, on resume=attached block(default=())) + :resuming = resuming(1) /* calling function is resuming */ if(on resume) fn.current checkpoint = anchor - if(resume target == anchor | resuming(4)) + if(resume target == anchor | resuming) on resume! else! fn.reached(anchor) = (fn.reached(anchor) | 0) + 1 diff --git a/anselme/stdlib/structures.lua b/anselme/stdlib/structures.lua index 4aa0776..bede562 100644 --- a/anselme/stdlib/structures.lua +++ b/anselme/stdlib/structures.lua @@ -1,5 +1,5 @@ local ast = require("anselme.ast") -local Nil, List, Table, Number, LuaFunction, ParameterTuple, Boolean = ast.Nil, ast.List, ast.Table, ast.Number, ast.LuaFunction, ast.ParameterTuple, ast.Boolean +local Nil, List, Table, Number, LuaCall, ParameterTuple, Boolean = ast.Nil, ast.List, ast.Table, ast.Number, ast.LuaCall, ast.ParameterTuple, ast.Boolean return { -- tuple @@ -122,7 +122,7 @@ return { "iter", "(s::is struct)", function(state, struct) local iter = struct:iter() - return LuaFunction:new(ParameterTuple:new(), function() + return LuaCall:make_function(state, ParameterTuple:new(), function() local k = iter() if k == nil then return Nil:new() else return k end diff --git a/test/results/exported variable nested.ans b/test/results/exported variable nested.ans index 8f7dcea..1063c24 100644 --- a/test/results/exported variable nested.ans +++ b/test/results/exported variable nested.ans @@ -5,7 +5,7 @@ --- text --- | {}"" {}"42" {}"" | --- error --- -identifier "z" is undefined in branch 46991f07-7340-4104-9f35-c1fb62e95088 +identifier "z" is undefined in branch 1c25ebb8-5027-4ccf-105b9-370d83e78fd7 ↳ from test/tests/exported variable nested.ans:12:3 in identifier: z ↳ from test/tests/exported variable nested.ans:12:1 in text interpolation: | {z} | ↳ from ? in block: :f = ($() _)… diff --git a/test/results/for invalid iterator.ans b/test/results/for invalid iterator.ans index edf81d0..fac8276 100644 --- a/test/results/for invalid iterator.ans +++ b/test/results/for invalid iterator.ans @@ -1,6 +1,6 @@ --# run #-- --- error --- -can't call overload iter: no function match arguments (42), possible functions were: +can't call overload iter: no function match arguments (value), possible functions were: • $(table::is table) (from stdlib/for.ans:46:1): type check failure for parameter table • $(tuple::is sequence) (from stdlib/for.ans:37:1): diff --git a/test/results/function custom type dispatch error.ans b/test/results/function custom type dispatch error.ans index 7124d50..249c64f 100644 --- a/test/results/function custom type dispatch error.ans +++ b/test/results/function custom type dispatch error.ans @@ -4,7 +4,7 @@ --- text --- | {}"" {}"idk" {}" is esperanto" | --- error --- -can't call overload a: no function match arguments (type(5, "nope")), possible functions were: +can't call overload a: no function match arguments (value), possible functions were: • $(name::($(x) type(x) == t)) (from test/tests/function custom type dispatch error.ans:7:1): type check failure for parameter name • $(name::($(x) type(x) == t)) (from test/tests/function custom type dispatch error.ans:4:1): diff --git a/test/results/function random.ans b/test/results/function random.ans index 7cc973b..0e30d56 100644 --- a/test/results/function random.ans +++ b/test/results/function random.ans @@ -2,14 +2,14 @@ --- text --- | {}"a" | --- text --- +| {}"c" | +--- text --- | {}"b" | --- text --- | {}"c" | --- text --- -| {}"a" | ---- text --- -| {}"b" | +| {}"c" | --- return --- () --# saved #-- -{"a.checkpoint":false, "a.run":2, "b.checkpoint":false, "b.run":2, "c.checkpoint":false, "c.run":1} \ No newline at end of file +{"a.checkpoint":false, "a.run":1, "b.checkpoint":false, "b.run":1, "c.checkpoint":false, "c.run":3} \ No newline at end of file diff --git a/test/results/function scope wrong.ans b/test/results/function scope wrong.ans index f716317..58ae1b4 100644 --- a/test/results/function scope wrong.ans +++ b/test/results/function scope wrong.ans @@ -1,6 +1,6 @@ --# run #-- --- error --- -identifier "b" is undefined in branch 46991f07-7340-4104-9f35-c1fb62e95088 +identifier "b" is undefined in branch 1c25ebb8-5027-4ccf-105b9-370d83e78fd7 ↳ from test/tests/function scope wrong.ans:4:7 in identifier: b ↳ from test/tests/function scope wrong.ans:4:1 in text interpolation: | a: {b} | ↳ from ? in block: :a = ($() _)… diff --git a/test/results/function separate variable from variants.ans b/test/results/function separate variable from variants.ans index a22c3bd..d7a5d7b 100644 --- a/test/results/function separate variable from variants.ans +++ b/test/results/function separate variable from variants.ans @@ -1,17 +1,23 @@ --# run #-- --- error --- -can't call overload _._: no function match arguments (overload([($(b) _), ($(x) _), ($() _)]), "a"), possible functions were: - • $(s::is script, k::is symbol) = val (from stdlib/script.ans:44:1): +can't call overload _._: no function match arguments (value, "a"), possible functions were: + • $(s::is script, k::is symbol) = val (from stdlib/script.ans:45:1): expected 3 arguments, received 2 - • $(s::is script, k::is string) = val (from stdlib/script.ans:42:1): + • $(s::is script, k::is string) = val (from stdlib/script.ans:43:1): expected 3 arguments, received 2 - • $(s::is script, k::is string) (from stdlib/script.ans:40:1): + • $(s::is script, k::is string) (from stdlib/script.ans:41:1): type check failure for parameter s • $(c::is function, s::is symbol) = v (from test/tests/function separate variable from variants.ans:10:4): expected 3 arguments, received 2 • $(c::is function, s::is string) = v (from test/tests/function separate variable from variants.ans:10:4): expected 3 arguments, received 2 • $(c::is function, s::is string) (from test/tests/function separate variable from variants.ans:10:4): + type check failure for parameter c + • $(c::is environment, s::is symbol) = v (from test/tests/function separate variable from variants.ans:10:4): + expected 3 arguments, received 2 + • $(c::is environment, s::is string) = v (from test/tests/function separate variable from variants.ans:10:4): + expected 3 arguments, received 2 + • $(c::is environment, s::is string) (from test/tests/function separate variable from variants.ans:10:4): type check failure for parameter c ↳ from test/tests/function separate variable from variants.ans:10:4 in call: f . "a" ↳ from test/tests/function separate variable from variants.ans:10:1 in text interpolation: | {f . "a"} = 2 | diff --git a/test/results/merge nested mutable error bis.ans b/test/results/merge nested mutable error bis.ans index 2bbed04..521f996 100644 --- a/test/results/merge nested mutable error bis.ans +++ b/test/results/merge nested mutable error bis.ans @@ -4,14 +4,14 @@ ↳ from test/tests/merge nested mutable error bis.ans:14:7 in call: error("abort") ↳ from test/tests/merge nested mutable error bis.ans:3:1 in block: insert(a, b)… ↳ from test/tests/merge nested mutable error bis.ans:3:18 in call: _ - ↳ from stdlib/script.ans:30:6 in call: fn! - ↳ from stdlib/script.ans:28:3 in block: resume target = ()… - ↳ from stdlib/script.ans:28:7 in call: else! - ↳ from stdlib/script.ans:24:2 in block: if(fn . "current checkpoint")… - ↳ from stdlib/script.ans:24:9 in call: _ - ↳ from stdlib/script.ans:38:9 in call: value(s)! - ↳ from stdlib/script.ans:37:1 in block: value(s)! - ↳ from stdlib/script.ans:37:20 in call: _ + ↳ from stdlib/script.ans:31:6 in call: fn! + ↳ from stdlib/script.ans:29:3 in block: resume target = ()… + ↳ from stdlib/script.ans:29:7 in call: else! + ↳ from stdlib/script.ans:25:2 in block: if(fn . "current checkpoint")… + ↳ from stdlib/script.ans:25:9 in call: _ + ↳ from stdlib/script.ans:39:9 in call: value(s)! + ↳ from stdlib/script.ans:38:1 in block: value(s)! + ↳ from stdlib/script.ans:38:20 in call: _ ↳ from test/tests/merge nested mutable error bis.ans:19:2 in call: f! ↳ from ? in block: :a = *[1]… --# post run check #-- diff --git a/test/results/merge nested mutable error.ans b/test/results/merge nested mutable error.ans index 467b0e0..918b68a 100644 --- a/test/results/merge nested mutable error.ans +++ b/test/results/merge nested mutable error.ans @@ -4,14 +4,14 @@ ↳ from test/tests/merge nested mutable error.ans:14:7 in call: error("abort") ↳ from test/tests/merge nested mutable error.ans:3:1 in block: insert(a, b)… ↳ from test/tests/merge nested mutable error.ans:3:18 in call: _ - ↳ from stdlib/script.ans:30:6 in call: fn! - ↳ from stdlib/script.ans:28:3 in block: resume target = ()… - ↳ from stdlib/script.ans:28:7 in call: else! - ↳ from stdlib/script.ans:24:2 in block: if(fn . "current checkpoint")… - ↳ from stdlib/script.ans:24:9 in call: _ - ↳ from stdlib/script.ans:38:9 in call: value(s)! - ↳ from stdlib/script.ans:37:1 in block: value(s)! - ↳ from stdlib/script.ans:37:20 in call: _ + ↳ from stdlib/script.ans:31:6 in call: fn! + ↳ from stdlib/script.ans:29:3 in block: resume target = ()… + ↳ from stdlib/script.ans:29:7 in call: else! + ↳ from stdlib/script.ans:25:2 in block: if(fn . "current checkpoint")… + ↳ from stdlib/script.ans:25:9 in call: _ + ↳ from stdlib/script.ans:39:9 in call: value(s)! + ↳ from stdlib/script.ans:38:1 in block: value(s)! + ↳ from stdlib/script.ans:38:20 in call: _ ↳ from test/tests/merge nested mutable error.ans:19:2 in call: f! ↳ from ? in block: :a = *[1]… --# post run check #-- diff --git a/test/tests/serialize function env.ans b/test/tests/serialize function env.ans index 9e3c5b0..0ad343e 100644 --- a/test/tests/serialize function env.ans +++ b/test/tests/serialize function env.ans @@ -1,3 +1,4 @@ +:z = 1 :x = $ 2+z x.:z = 3 diff --git a/test/tests/text line interpolation with choice event.ans b/test/tests/text line interpolation with choice event.ans index 5e95110..b8ab7c9 100644 --- a/test/tests/text line interpolation with choice event.ans +++ b/test/tests/text line interpolation with choice event.ans @@ -1,4 +1,4 @@ -:choice = 1 +:@choice = 1 :$ jump button 1 # | A