1
0
Fork 0
mirror of https://github.com/Reuh/anselme.git synced 2025-10-28 00:59:31 +00:00

Undefine _ in attached block

This commit is contained in:
Étienne Fildadut 2024-01-02 14:35:18 +01:00
parent a85e7ab0af
commit 15f29e3bce
31 changed files with 70 additions and 163 deletions

View file

@ -68,6 +68,7 @@ local Environment = ast.abstract.Runtime {
variables = nil, -- Table of { {identifier} = variable metadata, ... } variables = nil, -- Table of { {identifier} = variable metadata, ... }
partial = nil, -- { [name string] = true, ... } partial = nil, -- { [name string] = true, ... }
undefine = nil, -- { [name string] = true, ... }
export = nil, -- bool export = nil, -- bool
init = function(self, state, parent, partial_names, is_export) init = function(self, state, parent, partial_names, is_export)
@ -75,6 +76,7 @@ local Environment = ast.abstract.Runtime {
self.parent = parent self.parent = parent
self.partial = partial_names self.partial = partial_names
self.export = is_export self.export = is_export
self.undefine = {}
end, end,
traverse = function(self, fn, ...) traverse = function(self, fn, ...)
@ -97,7 +99,11 @@ local Environment = ast.abstract.Runtime {
or (self.export ~= symbol.exported) then or (self.export ~= symbol.exported) then
return self.parent:define(state, symbol, exp) return self.parent:define(state, symbol, exp)
end end
self.variables:set(state, symbol:to_identifier(), VariableMetadata:new(state, symbol, exp)) if symbol.undefine then
self.undefine[name] = true
else
self.variables:set(state, symbol:to_identifier(), VariableMetadata:new(state, symbol, exp))
end
end, end,
-- define or redefine new overloadable variable in current environment, inheriting existing overload variants from (parent) scopes -- define or redefine new overloadable variable in current environment, inheriting existing overload variants from (parent) scopes
define_overloadable = function(self, state, symbol, exp) define_overloadable = function(self, state, symbol, exp)
@ -132,7 +138,7 @@ local Environment = ast.abstract.Runtime {
defined = function(self, state, identifier) defined = function(self, state, identifier)
if self.variables:has(state, identifier) then if self.variables:has(state, identifier) then
return true return true
elseif self.parent then elseif self.parent and not self.undefine[identifier.name] then
return self.parent:defined(state, identifier) return self.parent:defined(state, identifier)
end end
return false return false
@ -143,9 +149,10 @@ local Environment = ast.abstract.Runtime {
local name = symbol.string local name = symbol.string
if self.variables:has(state, symbol:to_identifier()) then if self.variables:has(state, symbol:to_identifier()) then
return true return true
elseif (self.partial and not self.partial[name]) elseif self.parent and not self.undefine[name] then
or (self.export ~= symbol.exported) then if (self.partial and not self.partial[name]) or (self.export ~= symbol.exported) then
return self.parent:defined_in_current(state, symbol) return self.parent:defined_in_current(state, symbol)
end
end end
return false return false
end, end,
@ -159,7 +166,7 @@ local Environment = ast.abstract.Runtime {
if self:defined(state, identifier) then if self:defined(state, identifier) then
if self.variables:has(state, identifier) then if self.variables:has(state, identifier) then
return self.variables:get(state, identifier) return self.variables:get(state, identifier)
elseif self.parent then elseif self.parent and not self.undefine[identifier.name] then
return self.parent:_get_variable(state, identifier) return self.parent:_get_variable(state, identifier)
end end
else else

View file

@ -1,7 +1,7 @@
-- create a partial layer to define temporary variables -- create a partial layer to define temporary variables
local ast = require("anselme.ast") local ast = require("anselme.ast")
local Identifier, Quote local Identifier, Quote, Nil
local attached_block_identifier, attached_block_symbol local attached_block_identifier, attached_block_symbol
local unpack = table.unpack or unpack local unpack = table.unpack or unpack
@ -11,7 +11,7 @@ PartialScope = ast.abstract.Node {
type = "partial scope", type = "partial scope",
expression = nil, expression = nil,
definitions = nil, -- {[sym]=value,...} where values are already evaluated! definitions = nil, -- {[sym]=value,...}
_identifiers = nil, -- {identifier,...} - just a cache so we don't rebuild it on every eval _identifiers = nil, -- {identifier,...} - just a cache so we don't rebuild it on every eval
init = function(self, expression) init = function(self, expression)
@ -49,7 +49,7 @@ PartialScope = ast.abstract.Node {
_eval = function(self, state) _eval = function(self, state)
state.scope:push_partial(unpack(self._identifiers)) state.scope:push_partial(unpack(self._identifiers))
for sym, val in pairs(self.definitions) do state.scope:define(sym, val) end for sym, val in pairs(self.definitions) do state.scope:define(sym:eval(state), val:eval(state)) end
local exp = self.expression:eval(state) local exp = self.expression:eval(state)
state.scope:pop() state.scope:pop()
@ -71,14 +71,16 @@ PartialScope = ast.abstract.Node {
end, end,
-- class method: return a PartialScope that define the block identifier _ to a Quote of `block` -- class method: return a PartialScope that define the block identifier _ to a Quote of `block`
attach_block = function(self, expression, block) attach_block = function(self, expression, block)
local partial = ast.PartialScope:new(expression) local partial = PartialScope:new(expression)
partial:define(attached_block_symbol, Quote:new(block)) local unpartial = PartialScope:new(block)
unpartial:define(attached_block_symbol:with{undefine=true}, Nil:new())
partial:define(attached_block_symbol, Quote:new(unpartial))
return partial return partial
end end
} }
package.loaded[...] = PartialScope package.loaded[...] = PartialScope
Identifier, Quote = ast.Identifier, ast.Quote Identifier, Quote, Nil = ast.Identifier, ast.Quote, ast.Nil
attached_block_identifier = Identifier:new("_") attached_block_identifier = Identifier:new("_")
attached_block_symbol = attached_block_identifier:to_symbol() attached_block_symbol = attached_block_identifier:to_symbol()

View file

@ -15,6 +15,7 @@ Symbol = ast.abstract.Node {
exported = nil, -- bool exported = nil, -- bool
confined_to_branch = nil, -- bool confined_to_branch = nil, -- bool
undefine = nil, -- bool
init = function(self, str, modifiers) init = function(self, str, modifiers)
modifiers = modifiers or {} modifiers = modifiers or {}
@ -24,6 +25,7 @@ Symbol = ast.abstract.Node {
self.alias = modifiers.alias self.alias = modifiers.alias
self.confined_to_branch = modifiers.confined_to_branch self.confined_to_branch = modifiers.confined_to_branch
self.exported = modifiers.exported self.exported = modifiers.exported
self.undefine = modifiers.undefine
end, end,
_eval = function(self, state) _eval = function(self, state)
@ -34,7 +36,7 @@ Symbol = ast.abstract.Node {
with = function(self, modifiers) with = function(self, modifiers)
modifiers = modifiers or {} modifiers = modifiers or {}
for _, k in ipairs{"constant", "type_check", "alias", "exported", "confined_to_branch"} do for _, k in ipairs{"constant", "type_check", "alias", "exported", "confined_to_branch", "undefine"} do
if modifiers[k] == nil then if modifiers[k] == nil then
modifiers[k] = self[k] modifiers[k] = self[k]
end end

View file

@ -4,6 +4,8 @@ local assert0 = require("anselme.common").assert0
local calling_environment_manager = require("anselme.state.calling_environment_manager") local calling_environment_manager = require("anselme.state.calling_environment_manager")
local block_identifier = Identifier:new("_")
return { return {
{ {
"defined", "(c::function, s::string)", "defined", "(c::function, s::string)",
@ -88,21 +90,33 @@ return {
end end
}, },
{ {
"attached block", "(level::number=1)", "attached block", "(level::number=1, keep return=false)",
function(state, level) function(state, level, keep_return)
-- level 2: env of the function that called the function that called attached block -- 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)+1)
local r = env:get(state, Identifier:new("_")) local r = env:get(state, block_identifier)
return Function:with_return_boundary(ParameterTuple:new(), r.expression):eval(state) if keep_return:truthy() then
return Function:new(ParameterTuple:new(), r.expression):eval(state)
else
return Function:with_return_boundary(ParameterTuple:new(), r.expression):eval(state)
end
end end
}, },
{ {
"attached block keep return", "(level::number=1)", "attached block", "(level::number=1, keep return=false, default)",
function(state, level) function(state, level, keep_return, default)
-- level 2: env of the function that called the function that called attached block -- 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)+1)
local r = env:get(state, Identifier:new("_")) if env:defined(state, block_identifier) then
return Function:new(ParameterTuple:new(), r.expression):eval(state) local r = env:get(state, block_identifier)
if keep_return:truthy() then
return Function:new(ParameterTuple:new(), r.expression):eval(state)
else
return Function:with_return_boundary(ParameterTuple:new(), r.expression):eval(state)
end
else
return default
end
end end
}, },
} }

View file

@ -18,7 +18,7 @@ end
return { return {
{ {
"if", "(condition, expression=attached block keep return!)", function(state, condition, expression) "if", "(condition, expression=attached block(keep return=true))", function(state, condition, expression)
ensure_if_variable(state) ensure_if_variable(state)
if condition:truthy() or expression:contains_current_resume_target(state) then if condition:truthy() or expression:contains_current_resume_target(state) then
set_if_variable(state, true) set_if_variable(state, true)
@ -42,7 +42,7 @@ return {
end end
}, },
{ {
"else if", "(condition, expression=attached block keep return!)", "else if", "(condition, expression=attached block(keep return=true))",
function(state, condition, expression) function(state, condition, expression)
ensure_if_variable(state) ensure_if_variable(state)
if (not last_if_success(state) and condition:truthy()) or expression:contains_current_resume_target(state) then if (not last_if_success(state) and condition:truthy()) or expression:contains_current_resume_target(state) then
@ -55,7 +55,7 @@ return {
end end
}, },
{ {
"else", "(expression=attached block keep return!)", "else", "(expression=attached block(keep return=true))",
function(state, expression) function(state, expression)
ensure_if_variable(state) ensure_if_variable(state)
if not last_if_success(state) or expression:contains_current_resume_target(state) then if not last_if_success(state) or expression:contains_current_resume_target(state) then
@ -67,7 +67,7 @@ return {
end end
}, },
{ {
"while", "(condition, expression=attached block keep return!)", "while", "(condition, expression=attached block(keep return=true))",
function(state, condition, expression) function(state, condition, expression)
ensure_if_variable(state) ensure_if_variable(state)
local cond = condition:call(state, ArgumentTuple:new()) local cond = condition:call(state, ArgumentTuple:new())

View file

@ -8,18 +8,19 @@ return [[
fn.:check = $(anchor::anchor) fn.:check = $(anchor::anchor)
fn.reached(anchor) = (fn.reached(anchor) | 0) + 1 fn.reached(anchor) = (fn.reached(anchor) | 0) + 1
fn.:checkpoint = $(anchor::anchor) fn.:checkpoint = $(anchor::anchor, on resume=attached block(default=()))
fn.current checkpoint = anchor if(on resume)
if(resumed from != anchor) fn.current checkpoint = anchor
fn.reached(anchor) = (fn.reached(anchor) | 0) + 1 if(resumed from == anchor | resuming(4))
merge branch! on resume!
fn.:checkpoint = $(anchor::anchor, on resume::function) else!
fn.current checkpoint = anchor fn.reached(anchor) = (fn.reached(anchor) | 0) + 1
if(resumed from == anchor | resuming(2)) merge branch!
on resume!
else! else!
fn.reached(anchor) = (fn.reached(anchor) | 0) + 1 fn.current checkpoint = anchor
merge branch! if(resumed from != anchor)
fn.reached(anchor) = (fn.reached(anchor) | 0) + 1
merge branch!
:f = $ :f = $
if(fn.current checkpoint) if(fn.current checkpoint)

View file

@ -34,9 +34,8 @@ Standard library.
* Text manipulation would make sense, but that would require a full UTF-8/Unicode support library like https://github.com/starwing/luautf8. * Text manipulation would make sense, but that would require a full UTF-8/Unicode support library like https://github.com/starwing/luautf8.
* Something to load other files. Maybe not load it by default to let the calling game sandbox Anselme. Probably create an export scope per file to perform some nice module loading. * Something to load other files. Maybe not load it by default to let the calling game sandbox Anselme. Probably create an export scope per file to perform some nice module loading.
* Implement the useful functions from Anselme v1. * Implement the useful functions from Anselme v1.
* Checkpoint management.
* Overloadable :format for custom types.
* Text manipulation: concatenation, retag/add tags * Text manipulation: concatenation, retag/add tags
* And in general, clean up everything.
--- ---

View file

@ -9,8 +9,6 @@
| {}"1,2,3,4,5: " {}"*[1, 2, 3, 4, 5]" {}"" | | {}"1,2,3,4,5: " {}"*[1, 2, 3, 4, 5]" {}"" |
--- error --- --- error ---
cancel merge cancel merge
↳ from test/tests/checkpoint merging mutable value.ans:24:6 in call: error("cancel merge")
↳ from ? in block: :l = *[1, 2]…
--# post run check #-- --# post run check #--
--- text --- --- text ---
| {}"1,2,3,4: " {}"*[1, 2, 3, 4]" {}"" | | {}"1,2,3,4: " {}"*[1, 2, 3, 4]" {}"" |

View file

@ -9,8 +9,6 @@
| {}"4: " {}"4" {}"" | | {}"4: " {}"4" {}"" |
--- error --- --- error ---
cancel merge cancel merge
↳ from test/tests/checkpoint merging variable.ans:24:6 in call: error("cancel merge")
↳ from ? in block: :l = 1…
--# post run check #-- --# post run check #--
--- text --- --- text ---
| {}"3: " {}"3" {}"" | | {}"3: " {}"3" {}"" |

View file

@ -3,9 +3,5 @@
| {}"" {}"42" {}"" | | {}"" {}"42" {}"" |
--- error --- --- error ---
no variable "y" defined in closure no variable "y" defined in closure
↳ from test/tests/closure define nested.ans:12:4 in call: f . "y"
↳ from test/tests/closure define nested.ans:12:1 in text interpolation: | {f . "y"} |
↳ from test/tests/closure define nested.ans:12:1 in translatable: | {f . "y"} |
↳ from ? in block: :f = ($() _)…
--# saved #-- --# saved #--
{} {}

View file

@ -1,7 +1,5 @@
--# run #-- --# run #--
--- error --- --- error ---
trying to change the value of constant a trying to change the value of constant a
↳ from test/tests/constant variable.ans:5:3 in assignment: a = 52
↳ from ? in block: ::a = 3…
--# saved #-- --# saved #--
{} {}

View file

@ -5,7 +5,5 @@
| {}"" {}"type(\"kg\", 12)" {}"" | | {}"" {}"type(\"kg\", 12)" {}"" |
--- error --- --- error ---
type check failure for weigh; 32 does not satisfy $(x) type(x) == t type check failure for weigh; 32 does not satisfy $(x) type(x) == t
↳ from test/tests/constrained variable assignement.ans:9:7 in assignment: weigh = 32
↳ from ? in block: :weigh::is("kg") = type(5, "kg")…
--# saved #-- --# saved #--
{} {}

View file

@ -1,7 +1,5 @@
--# run #-- --# run #--
--- error --- --- error ---
a is already defined in the current scope a is already defined in the current scope
↳ from test/tests/define override function.ans:4:4 in definition: :a = 2
↳ from ? in block: :a = ($() _)…
--# saved #-- --# saved #--
{} {}

View file

@ -1,8 +1,5 @@
--# run #-- --# run #--
--- error --- --- error ---
can't add an overload variant to non-overloadable variable a defined in the same scope can't add an overload variant to non-overloadable variable a defined in the same scope
↳ from test/tests/define override variable.ans:3:1 in definition: :a = ($() _)
↳ from test/tests/define override variable.ans:3:1 in partial scope: :a = ($() _)…
↳ from ? in block: :a = 2…
--# saved #-- --# saved #--
{} {}

View file

@ -1,7 +1,5 @@
--# run #-- --# run #--
--- error --- --- error ---
a is already defined in the current scope a is already defined in the current scope
↳ from test/tests/define override.ans:3:4 in definition: :a = 2
↳ from ? in block: :a = 5…
--# saved #-- --# saved #--
{} {}

View file

@ -6,9 +6,5 @@
| {}"" {}"42" {}"" | | {}"" {}"42" {}"" |
--- error --- --- error ---
identifier "z" is undefined in branch cf017f8a-7c86-4871-109af-6658231331e6 identifier "z" is undefined in branch cf017f8a-7c86-4871-109af-6658231331e6
↳ 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 test/tests/exported variable nested.ans:12:1 in translatable: | {z} |
↳ from ? in block: :f = ($() _)…
--# saved #-- --# saved #--
{} {}

View file

@ -1,7 +1,5 @@
--# run #-- --# run #--
--- error --- --- error ---
can't call function $(a, b) _: expected 2 arguments, received 1 can't call function $(a, b) _: expected 2 arguments, received 1
↳ from test/tests/function args arity check fail.ans:4:2 in call: f("ok")
↳ from ? in block: :f = ($(a, b) _)…
--# saved #-- --# saved #--
{} {}

View file

@ -1,7 +1,5 @@
--# run #-- --# run #--
--- error --- --- error ---
a function with parameters (a, b) is already defined in the overload a function with parameters (a, b) is already defined in the overload
↳ from test/tests/function conflict.ans:5:1 in definition: :f = ($(a, b) 0)
↳ from ? in block: :f = ($(a, b) 0)…
--# saved #-- --# saved #--
{} {}

View file

@ -7,7 +7,5 @@
can't call overload overload<($(name::($(x) type(x) == t)) _), ($(name::($(x) type(x) == t)) _)>: no function match (type("nope", 5)), possible functions were: can't call overload overload<($(name::($(x) type(x) == t)) _), ($(name::($(x) type(x) == t)) _)>: no function match (type("nope", 5)), possible functions were:
• (name::($(x) type(x) == t)): type check failure for parameter name in function (name::($(x) type(x) == t)) • (name::($(x) type(x) == t)): type check failure for parameter name in function (name::($(x) type(x) == t))
• (name::($(x) type(x) == t)): type check failure for parameter name in function (name::($(x) type(x) == t)) • (name::($(x) type(x) == t)): type check failure for parameter name in function (name::($(x) type(x) == t))
↳ from test/tests/function custom type dispatch error.ans:14:2 in call: a(type(5, "nope"))
↳ from ? in block: :french name = "french name"…
--# saved #-- --# saved #--
{} {}

View file

@ -1,9 +1,5 @@
--# run #-- --# run #--
--- error --- --- error ---
identifier "b" is undefined in branch cf017f8a-7c86-4871-109af-6658231331e6 identifier "b" is undefined in branch cf017f8a-7c86-4871-109af-6658231331e6
↳ 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 test/tests/function scope wrong.ans:4:1 in translatable: | a: {b} |
↳ from ? in block: :a = ($() _)…
--# saved #-- --# saved #--
{} {}

View file

@ -7,9 +7,5 @@
• (c::($(x) <lua function>), s::($(x) <lua function>)) = v: expected 3 arguments, received 2 • (c::($(x) <lua function>), s::($(x) <lua function>)) = v: expected 3 arguments, received 2
• (c::($(x) <lua function>), s::($(x) <lua function>)) = v: expected 3 arguments, received 2 • (c::($(x) <lua function>), s::($(x) <lua function>)) = v: expected 3 arguments, received 2
• (c::($(x) <lua function>), s::($(x) <lua function>)): type check failure for parameter c in function (c::($(x) <lua function>), s::($(x) <lua function>)) • (c::($(x) <lua function>), s::($(x) <lua function>)): type check failure for parameter c in function (c::($(x) <lua function>), s::($(x) <lua function>))
↳ 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 |
↳ from test/tests/function separate variable from variants.ans:10:1 in translatable: | {f . "a"} = 2 |
↳ from ? in block: :f = ($() _)…
--# saved #-- --# saved #--
{} {}

View file

@ -3,7 +3,5 @@
can't call overload overload<($(a::($(x) <lua function>)) _), ($(x::($(x) <lua function>)) _)>: more than one function match (5), matching functions were at least (specificity 1.3): can't call overload overload<($(a::($(x) <lua function>)) _), ($(x::($(x) <lua function>)) _)>: more than one function match (5), matching functions were at least (specificity 1.3):
• (x::($(x) <lua function>)) • (x::($(x) <lua function>))
• (a::($(x) <lua function>)) • (a::($(x) <lua function>))
↳ from test/tests/function type dispatch ambigous.ans:7:3 in call: fn(5)
↳ from ? in block: :fn = ($(x::number) _)…
--# saved #-- --# saved #--
{} {}

View file

@ -11,7 +11,5 @@
| {}"" {}"*[3, 12, 99]" {}"" | | {}"" {}"*[3, 12, 99]" {}"" |
--- error --- --- error ---
list index out of bounds list index out of bounds
↳ from test/tests/list assignement.ans:21:6 in call: x(5) = 0
↳ from ? in block: :x = *[1, 2]…
--# saved #-- --# saved #--
{} {}

View file

@ -9,9 +9,5 @@
| {}"" {}"3" {}" == " {}"3" {}"" | | {}"" {}"3" {}" == " {}"3" {}"" |
--- error --- --- error ---
tuple index out of bounds tuple index out of bounds
↳ from test/tests/list index.ans:11:4 in call: x(-4)
↳ from test/tests/list index.ans:11:1 in text interpolation: | {x(-4)} |
↳ from test/tests/list index.ans:11:1 in translatable: | {x(-4)} |
↳ from ? in block: :x = [1, 2, 3]…
--# saved #-- --# saved #--
{} {}

View file

@ -1,23 +1,6 @@
--# run #-- --# run #--
--- error --- --- error ---
abort abort
↳ 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 test/tests/merge nested mutable error bis.ans:3:17 in return boundary: _
↳ from script.ans:29:6 in call: fn!
↳ from script.ans:27:3 in block: resumed from = ()…
↳ from script.ans:27:7 in call: else!
↳ from script.ans:27:3 in partial scope: else!…
↳ from script.ans:23:2 in block: if(fn . "current checkpoint")…
↳ from script.ans:23:9 in call: _
↳ from script.ans:23:7 in return boundary: _
↳ from script.ans:37:9 in call: value(s)!
↳ from script.ans:36:1 in block: value(s)!
↳ from script.ans:36:20 in call: _
↳ from script.ans:36:1 in return boundary: _
↳ from test/tests/merge nested mutable error bis.ans:19:2 in call: f!
↳ from ? in block: :a = *[1]…
--# post run check #-- --# post run check #--
--- text --- --- text ---
| {}"[1,[2,3]]: " {}"*[1, *[2, 3]]" {}"" | | {}"[1,[2,3]]: " {}"*[1, *[2, 3]]" {}"" |

View file

@ -1,23 +1,6 @@
--# run #-- --# run #--
--- error --- --- error ---
abort abort
↳ 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 test/tests/merge nested mutable error.ans:3:17 in return boundary: _
↳ from script.ans:29:6 in call: fn!
↳ from script.ans:27:3 in block: resumed from = ()…
↳ from script.ans:27:7 in call: else!
↳ from script.ans:27:3 in partial scope: else!…
↳ from script.ans:23:2 in block: if(fn . "current checkpoint")…
↳ from script.ans:23:9 in call: _
↳ from script.ans:23:7 in return boundary: _
↳ from script.ans:37:9 in call: value(s)!
↳ from script.ans:36:1 in block: value(s)!
↳ from script.ans:36:20 in call: _
↳ from script.ans:36:1 in return boundary: _
↳ from test/tests/merge nested mutable error.ans:19:2 in call: f!
↳ from ? in block: :a = *[1]…
--# post run check #-- --# post run check #--
--- text --- --- text ---
| {}"[1,[2,3]]: " {}"*[1, *[2, 3]]" {}"" | | {}"[1,[2,3]]: " {}"*[1, *[2, 3]]" {}"" |

View file

@ -14,20 +14,7 @@
--- text --- --- text ---
| {}"CHECK 2" | | {}"CHECK 2" |
--- error --- --- error ---
t t
↳ from test/tests/scope checkpoint mutable bis error.ans:32:7 in call: error("t")
↳ from test/tests/scope checkpoint mutable bis error.ans:7:1 in block: insert(t, len(l) + 1)…
↳ from test/tests/scope checkpoint mutable bis error.ans:7:8 in call: _
↳ from test/tests/scope checkpoint mutable bis error.ans:7:1 in return boundary: _
↳ from test/tests/scope checkpoint mutable bis error.ans:19:4 in call: f(t)
↳ from test/tests/scope checkpoint mutable bis error.ans:15:2 in block: | REC |…
↳ from test/tests/scope checkpoint mutable bis error.ans:15:4 in call: if(n < 1)
↳ from test/tests/scope checkpoint mutable bis error.ans:15:2 in partial scope: if(n < 1)…
↳ from test/tests/scope checkpoint mutable bis error.ans:7:1 in block: insert(t, len(l) + 1)…
↳ from test/tests/scope checkpoint mutable bis error.ans:7:8 in call: _
↳ from test/tests/scope checkpoint mutable bis error.ans:7:1 in return boundary: _
↳ from test/tests/scope checkpoint mutable bis error.ans:41:2 in call: f(l)
↳ from ? in block: :x = *[99]…
--# post run check #-- --# post run check #--
--- text --- --- text ---
| {}"AFTER ERROR" | | {}"AFTER ERROR" |

View file

@ -10,20 +10,7 @@
--- text --- --- text ---
| {}"CHECK" | | {}"CHECK" |
--- error --- --- error ---
t t
↳ from test/tests/scope checkpoint mutable error.ans:23:7 in call: error("t")
↳ from test/tests/scope checkpoint mutable error.ans:5:1 in block: insert(t, len(l) + 1)…
↳ from test/tests/scope checkpoint mutable error.ans:5:8 in call: _
↳ from test/tests/scope checkpoint mutable error.ans:5:1 in return boundary: _
↳ from test/tests/scope checkpoint mutable error.ans:17:4 in call: f(t)
↳ from test/tests/scope checkpoint mutable error.ans:13:2 in block: | REC |…
↳ from test/tests/scope checkpoint mutable error.ans:13:4 in call: if(n < 1)
↳ from test/tests/scope checkpoint mutable error.ans:13:2 in partial scope: if(n < 1)…
↳ from test/tests/scope checkpoint mutable error.ans:5:1 in block: insert(t, len(l) + 1)…
↳ from test/tests/scope checkpoint mutable error.ans:5:8 in call: _
↳ from test/tests/scope checkpoint mutable error.ans:5:1 in return boundary: _
↳ from test/tests/scope checkpoint mutable error.ans:32:2 in call: f(l)
↳ from ? in block: :l = *[1]…
--# post run check #-- --# post run check #--
--- text --- --- text ---
| {}"AFTER ERROR" | | {}"AFTER ERROR" |

View file

@ -14,20 +14,7 @@
--- text --- --- text ---
| {}"CHECK 2" | | {}"CHECK 2" |
--- error --- --- error ---
t t
↳ from test/tests/scope checkpoint mutable ter error.ans:34:7 in call: error("t")
↳ from test/tests/scope checkpoint mutable ter error.ans:7:1 in block: insert(t, len(l) + 1)…
↳ from test/tests/scope checkpoint mutable ter error.ans:7:8 in call: _
↳ from test/tests/scope checkpoint mutable ter error.ans:7:1 in return boundary: _
↳ from test/tests/scope checkpoint mutable ter error.ans:19:4 in call: f(t)
↳ from test/tests/scope checkpoint mutable ter error.ans:15:2 in block: | REC |…
↳ from test/tests/scope checkpoint mutable ter error.ans:15:4 in call: if(n < 1)
↳ from test/tests/scope checkpoint mutable ter error.ans:15:2 in partial scope: if(n < 1)…
↳ from test/tests/scope checkpoint mutable ter error.ans:7:1 in block: insert(t, len(l) + 1)…
↳ from test/tests/scope checkpoint mutable ter error.ans:7:8 in call: _
↳ from test/tests/scope checkpoint mutable ter error.ans:7:1 in return boundary: _
↳ from test/tests/scope checkpoint mutable ter error.ans:43:2 in call: f(l)
↳ from ? in block: :x = *[99]…
--# post run check #-- --# post run check #--
--- text --- --- text ---
| {}"AFTER ERROR" | | {}"AFTER ERROR" |

View file

@ -6,7 +6,5 @@
| {}"d=" {}"2" {}" (2)" | | {}"d=" {}"2" {}" (2)" |
--- error --- --- error ---
trying to change the value of constant d trying to change the value of constant d
↳ from test/tests/symbol alias constant.ans:12:3 in assignment: d = 5
↳ from ? in block: :l = *[1, 2, 3]…
--# saved #-- --# saved #--
{} {}

View file

@ -47,6 +47,8 @@ local function run_loop(run_state, out)
elseif e == "return" then elseif e == "return" then
table.insert(out, data:format(run_state)) table.insert(out, data:format(run_state))
run_state:merge() run_state:merge()
elseif e == "error" then
table.insert(out, (tostring(data):gsub("\n%s*↳[^\n]*", ""))) -- traceback change every day and a half due to AST changes. TODO: only keep ast layers relevant for the user
else else
table.insert(out, tostring(data)) table.insert(out, tostring(data))
end end