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

Clean implementation of 👁️ and no longer increment 🏁 on checkpoint execution (redundant with 👁️)

This commit is contained in:
Étienne Fildadut 2022-10-03 18:10:47 +09:00
parent f79e2f5716
commit 2ff494d108
12 changed files with 115 additions and 77 deletions

View file

@ -359,8 +359,8 @@ Functions can return a value using a [return line](#lines-that-can-t-have-childr
Functions always have the following variables defined in its namespace by default:
`👁️`: number, number of times the function was executed before
`🔖`: function reference, last reached checkpoint. `nil` if no checkpoint reached.
`👁️`: number, number of times the function was executed/resumed before (incremented when reaching the end of the function or a return line)
`🔖`: function reference, last reached checkpoint. `()` (nil) if no checkpoint reached. (updated when reaching a checkpoint or directly executing a checkpoint)
These variables are persistent, unless the function is scoped.
@ -382,8 +382,8 @@ When executing the parent function after this checkpoint has been reached (using
Checkpoints always have the following variable defined in its namespace by default:
`👁️`: number, number of times the checkpoint was executed before
`🏁`: number, number of times the checkpoint was reached before (includes times where it was resumed from and executed)
`👁️`: number, number of times the checkpoint was executed/resumed before (incremented when reaching the end of the function or a return line)
`🏁`: number, number of times the checkpoint was reached before (incremented when reaching the checkpoint line; not incremented when resuming from/executing the checkpoint directly)
These variables are persistent.
@ -901,7 +901,7 @@ But in the cases when you want to manually set the current checkpoint, you can c
b
c
Force run the function starting from checkpoint, will write "b" and "c" and set the current checkpoint to "checkpoint":
Set the current checkpoint to "checkpoint" and force run the function starting from this checkpoint, will write "b" and "c":
~ f.checkpoint
Will correctly resumes from the last set checkpoint, and write "b" and "c":
@ -921,7 +921,7 @@ You can also only execute the checkpoints' children code only by using a paranth
b
c
Run the checkpoint only, will only write "b" and set the current checkpoint to "checkpoint":
Set the current checkpoint to "checkpoint" and run this checkpoint only, will only write "b":
~ f.checkpoint()
And will resume from the checkpoint like before:

View file

@ -247,7 +247,7 @@ local interpreter_methods = {
end
if not r then coroutine.yield("error", e) end
if self.state.interpreter.current_event then -- flush final events
local rf, re = run_line(self.state, { type = "flush_events" })
local rf, re = run_line(self.state, { type = "flush events" })
if re then coroutine.yield("error", re) end
if rf then r = rf end
end
@ -541,6 +541,8 @@ local vm_mt = {
-- * `signature`: string, full signature of the function
-- * `fn`: function (Lua function or table, see examples in `stdlib/functions.lua`)
--
-- Alternatively, can also take a table as a sole argument to load several functions: { ["signature"] = fn, ... }
--
-- Returns this VM.
loadfunction = function(self, signature, fn)
if type(signature) == "table" then

View file

@ -41,7 +41,7 @@ common = {
end
end
-- scoping: since merging means we will re-copy every variable from global state again, we need to simulate this
-- behavious for scoped variables (to have consistent references for mutables values in particular), including
-- behaviour for scoped variables (to have consistent references for mutables values in particular), including
-- scopes that aren't currently active
fix_not_modified_references(mt.scoped, copy_cache, modified_tables) -- replace not modified values in scope with original before re-copying to keep consistent references
for _, scopes in pairs(mt.scoped) do

View file

@ -397,8 +397,15 @@ local function eval(state, exp)
local fn = selected_variant.variant
if fn.type ~= "function" then
return nil, ("unknown function type %q"):format(fn.type)
-- checkpoint: no args and resume execution
-- checkpoint: no args and can resume execution
elseif fn.subtype == "checkpoint" then
-- set current checkpoint
local s, e = set_variable(state, fn.parent_resumable.namespace.."🔖", {
type = "function reference",
value = { fn.name }
})
if not s then return nil, e end
-- run checkpoint content, eventually resuming
local r, e = run(state, fn.child, not paren_call)
if not r then return nil, e end
return r
@ -423,8 +430,6 @@ local function eval(state, exp)
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
-- I guess we could technically skip getting & updating the seen and checkpoints vars since they can't be used from Anselme
-- but it's also kinda fun to known how many time a function was ran
@ -501,12 +506,6 @@ local function eval(state, exp)
end
if not ret then return nil, e end
end
-- update function vars
local s, e = set_variable(state, fn.namespace.."👁️", {
type = "number",
value = seen.value + 1
})
if not s then return nil, e end
-- for classes: build resulting object
if fn.subtype == "class" and ret and ret.type == "nil" then
ret = {

View file

@ -108,7 +108,7 @@ run_line = function(state, line)
if not iv then return nil, ("%s; at %s"):format(ie, line.source) end
end
end
elseif line.type == "flush_events" then
elseif line.type == "flush events" then
local v, e = events:flush(state)
if not v then return nil, ("%s; in event flush at %s"):format(e, line.source) end
elseif line.type == "function" and line.subtype == "checkpoint" then
@ -151,36 +151,8 @@ run_block = function(state, block, resume_from_there, i, j)
end
i = i + 1
end
-- if we are exiting a checkpoint block, mark it as ran and update checkpoint
-- (when resuming from a checkpoint, execution is resumed from inside the checkpoint, the line.subtype=="checkpoint" check in run_line is never called)
-- (and we want this to be done after executing the checkpoint block anyway)
-- if we reach the end of a checkpoint block (we are resuming execution from a checkpoint), merge state
if block.parent_line and block.parent_line.type == "function" and block.parent_line.subtype == "checkpoint" then
local parent_line = block.parent_line
local reached, reachede = get_variable(state, parent_line.namespace.."🏁")
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_resumable.namespace.."🔖")
if not checkpoint then return nil, checkpointe end
local s, e = set_variable(state, parent_line.namespace.."👁️", {
type = "number",
value = seen.value + 1
})
if not s then return nil, e end
s, e = set_variable(state, parent_line.namespace.."🏁", {
type = "number",
value = reached.value + 1
})
if not s then return nil, e end
-- 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_resumable.namespace.."🔖", {
type = "function reference",
value = { parent_line.name }
})
if not s then return nil, e end
end
merge_state(state)
end
-- go up hierarchy if asked to resume

View file

@ -83,8 +83,6 @@ TODO: fn/checkpoint/tag: maybe consider them a regular func call that takes chil
a
~ tag.pop()
TODO: perform seen/reached/etc default variable not in interpreter but using parse-time macro
TODO: make language simple enough to be able to reimplement it in, say, nim. Especially the AST interpreter (we could precompile a lot of stuff...)
TODO: test reacheability of script paths + visualization of different branches the script can take. For one of those overarching story visualization thingy.

View file

@ -105,6 +105,7 @@ local function parse_line(line, state, namespace, parent_resumable, in_scoped)
allow_params = false
allow_assign = false
keep_in_ast = true
if not parent_resumable then return nil, ("checkpoint definition line is not in a function; at %s"):format(line.source) end
r.parent_resumable = parent_resumable -- store parent resumable function and run checkpoint when line is read
else
error("unknown function line type")
@ -248,6 +249,8 @@ local function parse_line(line, state, namespace, parent_resumable, in_scoped)
-- custom code injection
inject(state, r, "start", line.children, 2)
inject(state, r, "end", line.children)
-- update 👁️ variable
table.insert(line.children, { content = "~👁️+=1", source = line.source })
-- define args
for _, param in ipairs(r.params) do
if not state.variables[param.full_name] then
@ -336,6 +339,7 @@ local function parse_line(line, state, namespace, parent_resumable, in_scoped)
r.expression = ("{%s}"):format(expr)
-- return
elseif l:match("^%@") then
if not parent_resumable then return nil, ("return line is not in a function; at %s"):format(line.source) end
r.type = "return"
r.child = true
local expr = l:match("^%@(.*)$")
@ -347,13 +351,15 @@ local function parse_line(line, state, namespace, parent_resumable, in_scoped)
-- custom code injection
if not line.children then line.children = {} end
inject(state, parent_resumable, "return", line.children)
-- update 👁️ variable
table.insert(line.children, { content = "~👁️+=1", source = line.source })
-- text
elseif l:match("[^%s]") then
r.type = "text"
r.text = l
-- flush events
else
r.type = "flush_events"
r.type = "flush events"
end
if not r.type then return nil, ("unknown line %s type"):format(line.source) end
return r

View file

@ -152,7 +152,7 @@ else
-- simple random to get the same result across lua versions
local prev = 0
local function badrandom(a, b)
prev = (15485863 * prev + 11) % 2038074743
prev = (4241 * prev + 11) % 6997
return a + prev % (b-a+1)
end
function math.random(a, b)

View file

@ -1,18 +1,22 @@
local _={}
_[29]={}
_[28]={}
_[27]={}
_[26]={}
_[25]={}
_[24]={}
_[23]={}
_[22]={}
_[21]={}
_[20]={tags=_[25],text="2"}
_[19]={tags=_[25],text="Reached: "}
_[18]={tags=_[24],text="1"}
_[17]={tags=_[24],text="Seen: "}
_[16]={tags=_[23],text="seen!"}
_[15]={tags=_[22],text="1"}
_[14]={tags=_[22],text="Reached: "}
_[13]={tags=_[21],text="0"}
_[12]={tags=_[21],text="Seen: "}
_[20]={text="1",tags=_[29]}
_[19]={text="Reached: ",tags=_[28]}
_[18]={text="1",tags=_[27]}
_[17]={text="Seen: ",tags=_[26]}
_[16]={text="seen!",tags=_[25]}
_[15]={text="1",tags=_[24]}
_[14]={text="Reached: ",tags=_[23]}
_[13]={text="0",tags=_[22]}
_[12]={text="Seen: ",tags=_[21]}
_[11]={_[19],_[20]}
_[10]={_[17],_[18]}
_[9]={_[16]}
@ -27,17 +31,17 @@ _[1]={"text",_[7]}
return {_[1],_[2],_[3],_[4],_[5],_[6]}
--[[
{ "text", { {
tags = <1>{},
tags = {},
text = "Seen: "
}, {
tags = <table 1>,
tags = {},
text = "0"
} } }
{ "text", { {
tags = <1>{},
tags = {},
text = "Reached: "
}, {
tags = <table 1>,
tags = {},
text = "1"
} } }
{ "text", { {
@ -45,18 +49,18 @@ return {_[1],_[2],_[3],_[4],_[5],_[6]}
text = "seen!"
} } }
{ "text", { {
tags = <1>{},
tags = {},
text = "Seen: "
}, {
tags = <table 1>,
tags = {},
text = "1"
} } }
{ "text", { {
tags = <1>{},
tags = {},
text = "Reached: "
}, {
tags = <table 1>,
text = "2"
tags = {},
text = "1"
} } }
{ "return" }
]]--

View file

@ -4,10 +4,10 @@ _[20]={}
_[19]={}
_[18]={}
_[17]={}
_[16]={tags=_[21],text="c"}
_[15]={tags=_[20],text="a"}
_[14]={tags=_[19],text="c"}
_[13]={tags=_[18],text="b"}
_[16]={tags=_[21],text="a"}
_[15]={tags=_[20],text="c"}
_[14]={tags=_[19],text="b"}
_[13]={tags=_[18],text="a"}
_[12]={tags=_[17],text="c"}
_[11]={_[16]}
_[10]={_[15]}
@ -26,6 +26,10 @@ return {_[1],_[2],_[3],_[4],_[5],_[6]}
tags = {},
text = "c"
} } }
{ "text", { {
tags = {},
text = "a"
} } }
{ "text", { {
tags = {},
text = "b"
@ -38,9 +42,5 @@ return {_[1],_[2],_[3],_[4],_[5],_[6]}
tags = {},
text = "a"
} } }
{ "text", { {
tags = {},
text = "c"
} } }
{ "return" }
]]--

View file

@ -0,0 +1,12 @@
:$ fn
{👁️}
:! a
a: {👁️}
~ fn.a
~ fn.a
~ fn.a

View file

@ -0,0 +1,45 @@
local _={}
_[19]={}
_[18]={}
_[17]={}
_[16]={}
_[15]={}
_[14]={}
_[13]={text="2",tags=_[19]}
_[12]={text="a: ",tags=_[18]}
_[11]={text="1",tags=_[17]}
_[10]={text="a: ",tags=_[16]}
_[9]={text="0",tags=_[15]}
_[8]={text="a: ",tags=_[14]}
_[7]={_[12],_[13]}
_[6]={_[10],_[11]}
_[5]={_[8],_[9]}
_[4]={"return"}
_[3]={"text",_[7]}
_[2]={"text",_[6]}
_[1]={"text",_[5]}
return {_[1],_[2],_[3],_[4]}
--[[
{ "text", { {
tags = {},
text = "a: "
}, {
tags = {},
text = "0"
} } }
{ "text", { {
tags = {},
text = "a: "
}, {
tags = {},
text = "1"
} } }
{ "text", { {
tags = {},
text = "a: "
}, {
tags = {},
text = "2"
} } }
{ "return" }
]]--