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

Variable must now be explicitly marked as persistent

This commit is contained in:
Étienne Fildadut 2022-09-27 18:41:40 +09:00
parent e9606cdee0
commit 2c6d66c222
11 changed files with 384 additions and 106 deletions

View file

@ -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)

View file

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

View file

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