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:
parent
a85e7ab0af
commit
15f29e3bce
31 changed files with 70 additions and 163 deletions
|
|
@ -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
|
||||||
|
if symbol.undefine then
|
||||||
|
self.undefine[name] = true
|
||||||
|
else
|
||||||
self.variables:set(state, symbol:to_identifier(), VariableMetadata:new(state, symbol, exp))
|
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,10 +149,11 @@ 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,
|
||||||
-- return bool if variable is defined in the current environment only - won't search in parent env for exported & partial names
|
-- return bool if variable is defined in the current environment only - won't search in parent env for exported & partial names
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
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)
|
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
|
||||||
|
local r = env:get(state, block_identifier)
|
||||||
|
if keep_return:truthy() then
|
||||||
return Function:new(ParameterTuple:new(), r.expression):eval(state)
|
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
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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=()))
|
||||||
|
if(on resume)
|
||||||
fn.current checkpoint = anchor
|
fn.current checkpoint = anchor
|
||||||
if(resumed from != anchor)
|
if(resumed from == anchor | resuming(4))
|
||||||
fn.reached(anchor) = (fn.reached(anchor) | 0) + 1
|
|
||||||
merge branch!
|
|
||||||
fn.:checkpoint = $(anchor::anchor, on resume::function)
|
|
||||||
fn.current checkpoint = anchor
|
|
||||||
if(resumed from == anchor | resuming(2))
|
|
||||||
on resume!
|
on resume!
|
||||||
else!
|
else!
|
||||||
fn.reached(anchor) = (fn.reached(anchor) | 0) + 1
|
fn.reached(anchor) = (fn.reached(anchor) | 0) + 1
|
||||||
merge branch!
|
merge branch!
|
||||||
|
else!
|
||||||
|
fn.current checkpoint = anchor
|
||||||
|
if(resumed from != anchor)
|
||||||
|
fn.reached(anchor) = (fn.reached(anchor) | 0) + 1
|
||||||
|
merge branch!
|
||||||
|
|
||||||
:f = $
|
:f = $
|
||||||
if(fn.current checkpoint)
|
if(fn.current checkpoint)
|
||||||
|
|
|
||||||
3
ideas.md
3
ideas.md
|
|
@ -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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 ---
|
||||||
[0m[31m[0m[31mcancel merge[0m
|
[0m[31m[0m[31mcancel merge[0m
|
||||||
↳ from [4mtest/tests/checkpoint merging mutable value.ans:24:6[0m in call: [2merror("cancel merge")[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:l = *[1, 2]…[0m
|
|
||||||
--# post run check #--
|
--# post run check #--
|
||||||
--- text ---
|
--- text ---
|
||||||
| {}"1,2,3,4: " {}"*[1, 2, 3, 4]" {}"" |
|
| {}"1,2,3,4: " {}"*[1, 2, 3, 4]" {}"" |
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,6 @@
|
||||||
| {}"4: " {}"4" {}"" |
|
| {}"4: " {}"4" {}"" |
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31mcancel merge[0m
|
[0m[31m[0m[31mcancel merge[0m
|
||||||
↳ from [4mtest/tests/checkpoint merging variable.ans:24:6[0m in call: [2merror("cancel merge")[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:l = 1…[0m
|
|
||||||
--# post run check #--
|
--# post run check #--
|
||||||
--- text ---
|
--- text ---
|
||||||
| {}"3: " {}"3" {}"" |
|
| {}"3: " {}"3" {}"" |
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,5 @@
|
||||||
| {}"" {}"42" {}"" |
|
| {}"" {}"42" {}"" |
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31m[0m[31m[0m[31mno variable "y" defined in closure[0m
|
[0m[31m[0m[31m[0m[31m[0m[31mno variable "y" defined in closure[0m
|
||||||
↳ from [4mtest/tests/closure define nested.ans:12:4[0m in call: [2mf . "y"[0m[0m
|
|
||||||
↳ from [4mtest/tests/closure define nested.ans:12:1[0m in text interpolation: [2m| {f . "y"} |[0m[0m
|
|
||||||
↳ from [4mtest/tests/closure define nested.ans:12:1[0m in translatable: [2m| {f . "y"} |[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:f = ($() _)…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
--# run #--
|
--# run #--
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31mtrying to change the value of constant a[0m
|
[0m[31m[0m[31mtrying to change the value of constant a[0m
|
||||||
↳ from [4mtest/tests/constant variable.ans:5:3[0m in assignment: [2ma = 52[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m::a = 3…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -5,7 +5,5 @@
|
||||||
| {}"" {}"type(\"kg\", 12)" {}"" |
|
| {}"" {}"type(\"kg\", 12)" {}"" |
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31mtype check failure for weigh; 32 does not satisfy $(x) type(x) == t[0m
|
[0m[31m[0m[31mtype check failure for weigh; 32 does not satisfy $(x) type(x) == t[0m
|
||||||
↳ from [4mtest/tests/constrained variable assignement.ans:9:7[0m in assignment: [2mweigh = 32[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:weigh::is("kg") = type(5, "kg")…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
--# run #--
|
--# run #--
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31ma is already defined in the current scope[0m
|
[0m[31m[0m[31ma is already defined in the current scope[0m
|
||||||
↳ from [4mtest/tests/define override function.ans:4:4[0m in definition: [2m:a = 2[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:a = ($() _)…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
--# run #--
|
--# run #--
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31m[0m[31mcan't add an overload variant to non-overloadable variable a defined in the same scope[0m
|
[0m[31m[0m[31m[0m[31mcan't add an overload variant to non-overloadable variable a defined in the same scope[0m
|
||||||
↳ from [4mtest/tests/define override variable.ans:3:1[0m in definition: [2m:a = ($() _)[0m[0m
|
|
||||||
↳ from [4mtest/tests/define override variable.ans:3:1[0m in partial scope: [2m:a = ($() _)…[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:a = 2…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
--# run #--
|
--# run #--
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31ma is already defined in the current scope[0m
|
[0m[31m[0m[31ma is already defined in the current scope[0m
|
||||||
↳ from [4mtest/tests/define override.ans:3:4[0m in definition: [2m:a = 2[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:a = 5…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -6,9 +6,5 @@
|
||||||
| {}"" {}"42" {}"" |
|
| {}"" {}"42" {}"" |
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31m[0m[31m[0m[31midentifier "z" is undefined in branch cf017f8a-7c86-4871-109af-6658231331e6[0m
|
[0m[31m[0m[31m[0m[31m[0m[31midentifier "z" is undefined in branch cf017f8a-7c86-4871-109af-6658231331e6[0m
|
||||||
↳ from [4mtest/tests/exported variable nested.ans:12:3[0m in identifier: [2mz[0m[0m
|
|
||||||
↳ from [4mtest/tests/exported variable nested.ans:12:1[0m in text interpolation: [2m| {z} |[0m[0m
|
|
||||||
↳ from [4mtest/tests/exported variable nested.ans:12:1[0m in translatable: [2m| {z} |[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:f = ($() _)…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
--# run #--
|
--# run #--
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31mcan't call function $(a, b) _: expected 2 arguments, received 1[0m
|
[0m[31m[0m[31mcan't call function $(a, b) _: expected 2 arguments, received 1[0m
|
||||||
↳ from [4mtest/tests/function args arity check fail.ans:4:2[0m in call: [2mf("ok")[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:f = ($(a, b) _)…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
--# run #--
|
--# run #--
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31ma function with parameters (a, b) is already defined in the overload[0m
|
[0m[31m[0m[31ma function with parameters (a, b) is already defined in the overload[0m
|
||||||
↳ from [4mtest/tests/function conflict.ans:5:1[0m in definition: [2m:f = ($(a, b) 0)[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:f = ($(a, b) 0)…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -7,7 +7,5 @@
|
||||||
[0m[31m[0m[31mcan't call overload overload<($(name::($(x) type(x) == t)) _), ($(name::($(x) type(x) == t)) _)>: no function match (type("nope", 5)), possible functions were:
|
[0m[31m[0m[31mcan'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))[0m
|
• (name::($(x) type(x) == t)): type check failure for parameter name in function (name::($(x) type(x) == t))[0m
|
||||||
↳ from [4mtest/tests/function custom type dispatch error.ans:14:2[0m in call: [2ma(type(5, "nope"))[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:french name = "french name"…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -1,9 +1,5 @@
|
||||||
--# run #--
|
--# run #--
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31m[0m[31m[0m[31midentifier "b" is undefined in branch cf017f8a-7c86-4871-109af-6658231331e6[0m
|
[0m[31m[0m[31m[0m[31m[0m[31midentifier "b" is undefined in branch cf017f8a-7c86-4871-109af-6658231331e6[0m
|
||||||
↳ from [4mtest/tests/function scope wrong.ans:4:7[0m in identifier: [2mb[0m[0m
|
|
||||||
↳ from [4mtest/tests/function scope wrong.ans:4:1[0m in text interpolation: [2m| a: {b} |[0m[0m
|
|
||||||
↳ from [4mtest/tests/function scope wrong.ans:4:1[0m in translatable: [2m| a: {b} |[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:a = ($() _)…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -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>))[0m
|
• (c::($(x) <lua function>), s::($(x) <lua function>)): type check failure for parameter c in function (c::($(x) <lua function>), s::($(x) <lua function>))[0m
|
||||||
↳ from [4mtest/tests/function separate variable from variants.ans:10:4[0m in call: [2mf . "a"[0m[0m
|
|
||||||
↳ from [4mtest/tests/function separate variable from variants.ans:10:1[0m in text interpolation: [2m| {f . "a"} = 2 |[0m[0m
|
|
||||||
↳ from [4mtest/tests/function separate variable from variants.ans:10:1[0m in translatable: [2m| {f . "a"} = 2 |[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:f = ($() _)…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -3,7 +3,5 @@
|
||||||
[0m[31m[0m[31mcan'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):
|
[0m[31m[0m[31mcan'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>))[0m
|
• (a::($(x) <lua function>))[0m
|
||||||
↳ from [4mtest/tests/function type dispatch ambigous.ans:7:3[0m in call: [2mfn(5)[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:fn = ($(x::number) _)…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -11,7 +11,5 @@
|
||||||
| {}"" {}"*[3, 12, 99]" {}"" |
|
| {}"" {}"*[3, 12, 99]" {}"" |
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31mlist index out of bounds[0m
|
[0m[31m[0m[31mlist index out of bounds[0m
|
||||||
↳ from [4mtest/tests/list assignement.ans:21:6[0m in call: [2mx(5) = 0[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:x = *[1, 2]…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -9,9 +9,5 @@
|
||||||
| {}"" {}"3" {}" == " {}"3" {}"" |
|
| {}"" {}"3" {}" == " {}"3" {}"" |
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31m[0m[31m[0m[31mtuple index out of bounds[0m
|
[0m[31m[0m[31m[0m[31m[0m[31mtuple index out of bounds[0m
|
||||||
↳ from [4mtest/tests/list index.ans:11:4[0m in call: [2mx(-4)[0m[0m
|
|
||||||
↳ from [4mtest/tests/list index.ans:11:1[0m in text interpolation: [2m| {x(-4)} |[0m[0m
|
|
||||||
↳ from [4mtest/tests/list index.ans:11:1[0m in translatable: [2m| {x(-4)} |[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:x = [1, 2, 3]…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -1,23 +1,6 @@
|
||||||
--# run #--
|
--# run #--
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31mabort[0m
|
[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31mabort[0m
|
||||||
↳ from [4mtest/tests/merge nested mutable error bis.ans:14:7[0m in call: [2merror("abort")[0m[0m
|
|
||||||
↳ from [4mtest/tests/merge nested mutable error bis.ans:3:1[0m in block: [2minsert(a, b)…[0m[0m
|
|
||||||
↳ from [4mtest/tests/merge nested mutable error bis.ans:3:18[0m in call: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/merge nested mutable error bis.ans:3:17[0m in return boundary: [2m_[0m[0m
|
|
||||||
↳ from [4mscript.ans:29:6[0m in call: [2mfn![0m[0m
|
|
||||||
↳ from [4mscript.ans:27:3[0m in block: [2mresumed from = ()…[0m[0m
|
|
||||||
↳ from [4mscript.ans:27:7[0m in call: [2melse![0m[0m
|
|
||||||
↳ from [4mscript.ans:27:3[0m in partial scope: [2melse!…[0m[0m
|
|
||||||
↳ from [4mscript.ans:23:2[0m in block: [2mif(fn . "current checkpoint")…[0m[0m
|
|
||||||
↳ from [4mscript.ans:23:9[0m in call: [2m_[0m[0m
|
|
||||||
↳ from [4mscript.ans:23:7[0m in return boundary: [2m_[0m[0m
|
|
||||||
↳ from [4mscript.ans:37:9[0m in call: [2mvalue(s)![0m[0m
|
|
||||||
↳ from [4mscript.ans:36:1[0m in block: [2mvalue(s)![0m[0m
|
|
||||||
↳ from [4mscript.ans:36:20[0m in call: [2m_[0m[0m
|
|
||||||
↳ from [4mscript.ans:36:1[0m in return boundary: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/merge nested mutable error bis.ans:19:2[0m in call: [2mf![0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:a = *[1]…[0m
|
|
||||||
--# post run check #--
|
--# post run check #--
|
||||||
--- text ---
|
--- text ---
|
||||||
| {}"[1,[2,3]]: " {}"*[1, *[2, 3]]" {}"" |
|
| {}"[1,[2,3]]: " {}"*[1, *[2, 3]]" {}"" |
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,6 @@
|
||||||
--# run #--
|
--# run #--
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31mabort[0m
|
[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31mabort[0m
|
||||||
↳ from [4mtest/tests/merge nested mutable error.ans:14:7[0m in call: [2merror("abort")[0m[0m
|
|
||||||
↳ from [4mtest/tests/merge nested mutable error.ans:3:1[0m in block: [2minsert(a, b)…[0m[0m
|
|
||||||
↳ from [4mtest/tests/merge nested mutable error.ans:3:18[0m in call: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/merge nested mutable error.ans:3:17[0m in return boundary: [2m_[0m[0m
|
|
||||||
↳ from [4mscript.ans:29:6[0m in call: [2mfn![0m[0m
|
|
||||||
↳ from [4mscript.ans:27:3[0m in block: [2mresumed from = ()…[0m[0m
|
|
||||||
↳ from [4mscript.ans:27:7[0m in call: [2melse![0m[0m
|
|
||||||
↳ from [4mscript.ans:27:3[0m in partial scope: [2melse!…[0m[0m
|
|
||||||
↳ from [4mscript.ans:23:2[0m in block: [2mif(fn . "current checkpoint")…[0m[0m
|
|
||||||
↳ from [4mscript.ans:23:9[0m in call: [2m_[0m[0m
|
|
||||||
↳ from [4mscript.ans:23:7[0m in return boundary: [2m_[0m[0m
|
|
||||||
↳ from [4mscript.ans:37:9[0m in call: [2mvalue(s)![0m[0m
|
|
||||||
↳ from [4mscript.ans:36:1[0m in block: [2mvalue(s)![0m[0m
|
|
||||||
↳ from [4mscript.ans:36:20[0m in call: [2m_[0m[0m
|
|
||||||
↳ from [4mscript.ans:36:1[0m in return boundary: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/merge nested mutable error.ans:19:2[0m in call: [2mf![0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:a = *[1]…[0m
|
|
||||||
--# post run check #--
|
--# post run check #--
|
||||||
--- text ---
|
--- text ---
|
||||||
| {}"[1,[2,3]]: " {}"*[1, *[2, 3]]" {}"" |
|
| {}"[1,[2,3]]: " {}"*[1, *[2, 3]]" {}"" |
|
||||||
|
|
|
||||||
|
|
@ -14,20 +14,7 @@
|
||||||
--- text ---
|
--- text ---
|
||||||
| {}"CHECK 2" |
|
| {}"CHECK 2" |
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31mt[0m
|
[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31mt[0m
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable bis error.ans:32:7[0m in call: [2merror("t")[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable bis error.ans:7:1[0m in block: [2minsert(t, len(l) + 1)…[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable bis error.ans:7:8[0m in call: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable bis error.ans:7:1[0m in return boundary: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable bis error.ans:19:4[0m in call: [2mf(t)[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable bis error.ans:15:2[0m in block: [2m| REC |…[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable bis error.ans:15:4[0m in call: [2mif(n < 1)[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable bis error.ans:15:2[0m in partial scope: [2mif(n < 1)…[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable bis error.ans:7:1[0m in block: [2minsert(t, len(l) + 1)…[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable bis error.ans:7:8[0m in call: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable bis error.ans:7:1[0m in return boundary: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable bis error.ans:41:2[0m in call: [2mf(l)[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:x = *[99]…[0m
|
|
||||||
--# post run check #--
|
--# post run check #--
|
||||||
--- text ---
|
--- text ---
|
||||||
| {}"AFTER ERROR" |
|
| {}"AFTER ERROR" |
|
||||||
|
|
|
||||||
|
|
@ -10,20 +10,7 @@
|
||||||
--- text ---
|
--- text ---
|
||||||
| {}"CHECK" |
|
| {}"CHECK" |
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31mt[0m
|
[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31mt[0m
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable error.ans:23:7[0m in call: [2merror("t")[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable error.ans:5:1[0m in block: [2minsert(t, len(l) + 1)…[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable error.ans:5:8[0m in call: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable error.ans:5:1[0m in return boundary: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable error.ans:17:4[0m in call: [2mf(t)[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable error.ans:13:2[0m in block: [2m| REC |…[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable error.ans:13:4[0m in call: [2mif(n < 1)[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable error.ans:13:2[0m in partial scope: [2mif(n < 1)…[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable error.ans:5:1[0m in block: [2minsert(t, len(l) + 1)…[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable error.ans:5:8[0m in call: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable error.ans:5:1[0m in return boundary: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable error.ans:32:2[0m in call: [2mf(l)[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:l = *[1]…[0m
|
|
||||||
--# post run check #--
|
--# post run check #--
|
||||||
--- text ---
|
--- text ---
|
||||||
| {}"AFTER ERROR" |
|
| {}"AFTER ERROR" |
|
||||||
|
|
|
||||||
|
|
@ -14,20 +14,7 @@
|
||||||
--- text ---
|
--- text ---
|
||||||
| {}"CHECK 2" |
|
| {}"CHECK 2" |
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31mt[0m
|
[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31mt[0m
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable ter error.ans:34:7[0m in call: [2merror("t")[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable ter error.ans:7:1[0m in block: [2minsert(t, len(l) + 1)…[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable ter error.ans:7:8[0m in call: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable ter error.ans:7:1[0m in return boundary: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable ter error.ans:19:4[0m in call: [2mf(t)[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable ter error.ans:15:2[0m in block: [2m| REC |…[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable ter error.ans:15:4[0m in call: [2mif(n < 1)[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable ter error.ans:15:2[0m in partial scope: [2mif(n < 1)…[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable ter error.ans:7:1[0m in block: [2minsert(t, len(l) + 1)…[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable ter error.ans:7:8[0m in call: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable ter error.ans:7:1[0m in return boundary: [2m_[0m[0m
|
|
||||||
↳ from [4mtest/tests/scope checkpoint mutable ter error.ans:43:2[0m in call: [2mf(l)[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:x = *[99]…[0m
|
|
||||||
--# post run check #--
|
--# post run check #--
|
||||||
--- text ---
|
--- text ---
|
||||||
| {}"AFTER ERROR" |
|
| {}"AFTER ERROR" |
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,5 @@
|
||||||
| {}"d=" {}"2" {}" (2)" |
|
| {}"d=" {}"2" {}" (2)" |
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31mtrying to change the value of constant d[0m
|
[0m[31m[0m[31mtrying to change the value of constant d[0m
|
||||||
↳ from [4mtest/tests/symbol alias constant.ans:12:3[0m in assignment: [2md = 5[0m[0m
|
|
||||||
↳ from [4m?[0m in block: [2m:l = *[1, 2, 3]…[0m
|
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue