mirror of
https://github.com/Reuh/anselme.git
synced 2025-12-14 12:19:09 +00:00
Variable must now be explicitly marked as persistent
This commit is contained in:
parent
e9606cdee0
commit
2c6d66c222
11 changed files with 384 additions and 106 deletions
|
|
@ -66,7 +66,7 @@ common = {
|
|||
-- returns depth, or math.huge if no constraint
|
||||
-- returns nil, err
|
||||
check_constraint = function(state, fqm, val)
|
||||
local constraint = state.variable_constraints[fqm]
|
||||
local constraint = state.variable_metadata[fqm].constraint
|
||||
if constraint then
|
||||
if not constraint.value then
|
||||
local v, e = eval(state, constraint.pending)
|
||||
|
|
@ -87,7 +87,7 @@ common = {
|
|||
-- returns true
|
||||
-- returns nil, mutation illegal message
|
||||
check_mutable = function(state, fqm)
|
||||
if state.variable_constants[fqm] then
|
||||
if state.variable_metadata[fqm].constant then
|
||||
return nil, ("can't change the value of a constant %q"):format(fqm)
|
||||
end
|
||||
return true
|
||||
|
|
@ -114,12 +114,12 @@ common = {
|
|||
return nil, ("%s; while evaluating default value for variable %q defined at %s"):format(e, fqm, var.value.source)
|
||||
end
|
||||
-- make constant if variable is constant
|
||||
if state.variable_constants[fqm] then
|
||||
if state.variable_metadata[fqm].constant then
|
||||
v = copy(v)
|
||||
common.mark_constant(v)
|
||||
end
|
||||
-- set variable
|
||||
local s, err = common.set_variable(state, fqm, v, state.variable_constants[fqm])
|
||||
local s, err = common.set_variable(state, fqm, v, state.variable_metadata[fqm].constant)
|
||||
if not s then return nil, err end
|
||||
return v
|
||||
else
|
||||
|
|
@ -218,9 +218,10 @@ common = {
|
|||
table.insert(modified, v)
|
||||
end,
|
||||
--- returns true if a variable should be persisted on save
|
||||
-- will exclude: undefined variables, variables in scoped functions, constants, internal anselme variables
|
||||
-- will exclude: variable that have not been evaluated yet and non-persistent variable
|
||||
-- this will by consequence excludes variable in scoped variables (can be neither persistent not evaluated into global state), constants (can not be persistent), internal anselme variables (not marked persistent), etc.
|
||||
should_keep_variable = function(state, name, value)
|
||||
return value.type ~= "undefined argument" and value.type ~= "pending definition" and name:match("^"..identifier_pattern.."$") and not name:match("^anselme%.") and not state.variable_constants[name]
|
||||
return value.type ~= "pending definition" and state.variable_metadata[name].persistent
|
||||
end,
|
||||
--- check truthyness of an anselme value
|
||||
truthy = function(val)
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ local function eval(state, exp)
|
|||
local depth, err = check_constraint(state, param.full_name, val)
|
||||
if not depth then
|
||||
ok = false
|
||||
local v = state.variable_constraints[param.full_name].value
|
||||
local v = state.variable_metadata[param.full_name].constraint.value
|
||||
table.insert(tried_function_error_messages, ("%s: argument %s is not of expected type %s"):format(fn.pretty_signature, param.name, format(v) or v))
|
||||
break
|
||||
end
|
||||
|
|
@ -347,7 +347,7 @@ local function eval(state, exp)
|
|||
local depth, err = check_constraint(state, param.full_name, assignment)
|
||||
if not depth then
|
||||
ok = false
|
||||
local v = state.variable_constraints[param.full_name].value
|
||||
local v = state.variable_metadata[param.full_name].constraint.value
|
||||
table.insert(tried_function_error_messages, ("%s: argument %s is not of expected type %s"):format(fn.pretty_signature, param.name, format(v) or v))
|
||||
end
|
||||
depths.assignment = depth
|
||||
|
|
@ -418,8 +418,11 @@ local function eval(state, exp)
|
|||
if not s then return nil, e end
|
||||
end
|
||||
-- get function vars
|
||||
local checkpoint, checkpointe = get_variable(state, fn.namespace.."🔖")
|
||||
if not checkpoint then return nil, checkpointe end
|
||||
local checkpoint, checkpointe
|
||||
if fn.resumable then
|
||||
checkpoint, checkpointe = get_variable(state, fn.namespace.."🔖")
|
||||
if not checkpoint then return nil, checkpointe end
|
||||
end
|
||||
local seen, seene = get_variable(state, fn.namespace.."👁️")
|
||||
if not seen then return nil, seene end
|
||||
-- execute lua functions
|
||||
|
|
@ -488,7 +491,7 @@ local function eval(state, exp)
|
|||
else
|
||||
local e
|
||||
-- eval function from start
|
||||
if paren_call or checkpoint.type == "nil" then
|
||||
if paren_call or not fn.resumable or checkpoint.type == "nil" then
|
||||
ret, e = run(state, fn.child)
|
||||
-- resume at last checkpoint
|
||||
else
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ run_line = function(state, line)
|
|||
value = reached.value + 1
|
||||
})
|
||||
if not s then return nil, e end
|
||||
s, e = set_variable(state, line.parent_function.namespace.."🔖", {
|
||||
s, e = set_variable(state, line.parent_resumable.namespace.."🔖", {
|
||||
type = "function reference",
|
||||
value = { line.name }
|
||||
})
|
||||
|
|
@ -160,7 +160,7 @@ run_block = function(state, block, resume_from_there, i, j)
|
|||
if not reached then return nil, reachede end
|
||||
local seen, seene = get_variable(state, parent_line.namespace.."👁️")
|
||||
if not seen then return nil, seene end
|
||||
local checkpoint, checkpointe = get_variable(state, parent_line.parent_function.namespace.."🔖")
|
||||
local checkpoint, checkpointe = get_variable(state, parent_line.parent_resumable.namespace.."🔖")
|
||||
if not checkpoint then return nil, checkpointe end
|
||||
local s, e = set_variable(state, parent_line.namespace.."👁️", {
|
||||
type = "number",
|
||||
|
|
@ -175,7 +175,7 @@ run_block = function(state, block, resume_from_there, i, j)
|
|||
-- don't update checkpoint if an already more precise checkpoint is set
|
||||
-- (since we will go up the whole checkpoint hierarchy when resuming from a nested checkpoint)
|
||||
if checkpoint.type == "nil" or not checkpoint.value[1]:match("^"..escape(parent_line.name)) then
|
||||
s, e = set_variable(state, parent_line.parent_function.namespace.."🔖", {
|
||||
s, e = set_variable(state, parent_line.parent_resumable.namespace.."🔖", {
|
||||
type = "function reference",
|
||||
value = { parent_line.name }
|
||||
})
|
||||
|
|
@ -184,11 +184,11 @@ run_block = function(state, block, resume_from_there, i, j)
|
|||
merge_state(state)
|
||||
end
|
||||
-- go up hierarchy if asked to resume
|
||||
-- will stop at function boundary
|
||||
-- will stop at resumable function boundary
|
||||
-- if parent is a choice, will ignore choices that belong to the same block (like the whole block was executed naturally from a higher parent)
|
||||
-- if parent if a condition, will mark it as a success (skipping following else-conditions) (for the same reasons as for choices)
|
||||
-- if parent pushed a tag, will pop it (tags from parents are added to the stack in run())
|
||||
if resume_from_there and block.parent_line and not block.parent_line.resume_boundary then
|
||||
if resume_from_there and block.parent_line and not block.parent_line.resumable then
|
||||
local parent_line = block.parent_line
|
||||
if parent_line.type == "choice" then
|
||||
state.interpreter.skip_choices_until_flush = true
|
||||
|
|
@ -212,9 +212,9 @@ local function run(state, block, resume_from_there, i, j)
|
|||
local tags_len = tags:len(state)
|
||||
if resume_from_there then
|
||||
local tags_to_add = {}
|
||||
-- go up in hierarchy in ascending order until function boundary
|
||||
-- go up in hierarchy in ascending order until resumable function boundary
|
||||
local parent_line = block.parent_line
|
||||
while parent_line and not parent_line.resume_boundary do
|
||||
while parent_line and not parent_line.resumable do
|
||||
if parent_line.type == "tag" then
|
||||
local v, e = eval(state, parent_line.expression)
|
||||
if not v then return v, ("%s; at %s"):format(e, parent_line.source) end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue