From 5c3e9d2c5db5cf0b6463fe85d0b7b6a09915865f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Reuh=20Fildadut?= Date: Mon, 12 Apr 2021 01:58:10 +0200 Subject: [PATCH] Preserve tags in choices children --- anselme.lua | 13 +++--- interpreter/interpreter.lua | 37 ++++++++++------ test/run.lua | 29 +++++++----- test/tests/choice preserve tags.ans | 16 +++++++ test/tests/choice preserve tags.lua | 69 +++++++++++++++++++++++++++++ 5 files changed, 134 insertions(+), 30 deletions(-) create mode 100644 test/tests/choice preserve tags.ans create mode 100644 test/tests/choice preserve tags.lua diff --git a/anselme.lua b/anselme.lua index 787804f..6f1729c 100644 --- a/anselme.lua +++ b/anselme.lua @@ -337,21 +337,22 @@ local vm_mt = { functions = self.state.functions, variables = setmetatable({}, { __index = self.state.variables }), interpreter = { + -- constant global_state = self.state, coroutine = coroutine.create(function() return "return", interpreter:run(expr, namespace) end), + -- status + running_line = nil, -- events event_type = nil, event_buffer = nil, - -- skip next choices until next event change (to skip currently running choice block when resuming from a paragraph) - skip_choices_until_flush = nil, - -- status - running_line = nil, - -- choice + -- choice event choice_selected = nil, choice_available = {}, + -- skip next choices until next event change (to skip currently running choice block when resuming from a paragraph) + skip_choices_until_flush = nil, -- interrupt interrupt = nil, - -- tags + -- tag stack tags = tags or {}, } }, diff --git a/interpreter/interpreter.lua b/interpreter/interpreter.lua index 5634c13..5b10103 100644 --- a/interpreter/interpreter.lua +++ b/interpreter/interpreter.lua @@ -1,17 +1,6 @@ local eval local truthy, flush_state, to_lua, eval_text -local function write_event(state, type, data) - if state.interpreter.event_buffer and state.interpreter.event_type ~= type then - error(("previous event of type %q has not been flushed, can't write new %q event"):format(state.interpreter.event_type, type)) - end - if not state.interpreter.event_buffer then - state.interpreter.event_type = type - state.interpreter.event_buffer = {} - end - table.insert(state.interpreter.event_buffer, { data = data, tags = state.interpreter.tags[#state.interpreter.tags] or {} }) -end - local tags = { push = function(self, state, val) local new = {} @@ -26,9 +15,26 @@ local tags = { end, pop = function(self, state) table.remove(state.interpreter.tags) + end, + current = function(self, state) + return state.interpreter.tags[#state.interpreter.tags] or {} + end, + push_ignore_past = function(self, state, tags) + table.insert(state.interpreter.tags, tags) end } +local function write_event(state, type, data) + if state.interpreter.event_buffer and state.interpreter.event_type ~= type then + error(("previous event of type %q has not been flushed, can't write new %q event"):format(state.interpreter.event_type, type)) + end + if not state.interpreter.event_buffer then + state.interpreter.event_type = type + state.interpreter.event_buffer = {} + end + table.insert(state.interpreter.event_buffer, { data = data, tags = tags:current(state) }) +end + local run_block -- returns var in case of success and there is a return @@ -82,7 +88,10 @@ local function run_line(state, line) elseif line.type == "choice" then local t, er = eval_text(state, line.text) if not t then return t, er end - table.insert(state.interpreter.choice_available, line.child) + table.insert(state.interpreter.choice_available, { + tags = tags:current(state), + block = line.child + }) write_event(state, "choice", t) elseif line.type == "tag" then if line.expression then @@ -118,7 +127,9 @@ local function run_line(state, line) else local choice = state.interpreter.choice_available[sel] state.interpreter.choice_available = {} - local v, e = run_block(state, choice) + tags:push_ignore_past(state, choice.tags) + local v, e = run_block(state, choice.block) + tags:pop(state) if e then return v, e end if v then return v end end diff --git a/test/run.lua b/test/run.lua index 2c7f68f..b6ff1ba 100644 --- a/test/run.lua +++ b/test/run.lua @@ -9,7 +9,7 @@ local function format_text(t, prefix) for _, l in ipairs(t) do r = r .. prefix local tags = "" - for k, v in ipairs(l.tags) do + for k, v in pairs(l.tags) do tags = tags .. ("[%q]=%q"):format(k, v) end if tags ~= "" then @@ -39,6 +39,17 @@ local function compare(a, b) end end +local function write_result(filebase, result) + local o = assert(io.open(filebase..".lua", "w")) + o:write(ser(result)) + o:write("\n--[[\n") + for _, v in ipairs(result) do + o:write(inspect(v).."\n") + end + o:write("]]--") + o:close() +end + -- parse args local args = {} local i=1 @@ -163,15 +174,8 @@ else table.insert(result, { "error", err }) end - if args.write then - local o = assert(io.open(filebase..".lua", "w")) - o:write(ser(result)) - o:write("\n--[[\n") - for _, v in ipairs(result) do - o:write(inspect(v).."\n") - end - o:write("]]--") - o:close() + if args["write-all"] then + write_result(filebase, result) else local o, e = loadfile(filebase..".lua") if o then @@ -188,7 +192,10 @@ else success = success + 1 end else - if not args.silent then + if args["write-new"] and e:match("No such file") then + write_result(filebase, result) + print("Written result file for "..filebase) + elseif not args.silent then print("> "..namespace) print(e) print("result was:") diff --git a/test/tests/choice preserve tags.ans b/test/tests/choice preserve tags.ans new file mode 100644 index 0000000..2db0ed6 --- /dev/null +++ b/test/tests/choice preserve tags.ans @@ -0,0 +1,16 @@ +$ f + # 42 + > a + b + +~ f +> c +~ choose(1) + +# "k":"v" + ~ f + > d + ~ choose(1) + e + +f diff --git a/test/tests/choice preserve tags.lua b/test/tests/choice preserve tags.lua new file mode 100644 index 0000000..040d8cb --- /dev/null +++ b/test/tests/choice preserve tags.lua @@ -0,0 +1,69 @@ +local _={} +_[26]={} +_[25]={k="v"} +_[24]={42,k="v"} +_[23]={} +_[22]={42} +_[21]={tags=_[26],data="f"} +_[20]={tags=_[25],data="e"} +_[19]={tags=_[24],data="b"} +_[18]={tags=_[25],data="d"} +_[17]={tags=_[24],data="a"} +_[16]={tags=_[22],data="b"} +_[15]={tags=_[23],data="c"} +_[14]={tags=_[22],data="a"} +_[13]={_[21]} +_[12]={_[20]} +_[11]={_[19]} +_[10]={_[17],_[18]} +_[9]={_[16]} +_[8]={_[14],_[15]} +_[7]={"return"} +_[6]={"text",_[13]} +_[5]={"text",_[12]} +_[4]={"text",_[11]} +_[3]={"choice",_[10]} +_[2]={"text",_[9]} +_[1]={"choice",_[8]} +return {_[1],_[2],_[3],_[4],_[5],_[6],_[7]} +--[[ +{ "choice", { { + data = "a", + tags = { 42 } + }, { + data = "c", + tags = {} + } } } +{ "text", { { + data = "b", + tags = { 42 } + } } } +{ "choice", { { + data = "a", + tags = { 42, + k = "v" + } + }, { + data = "d", + tags = { + k = "v" + } + } } } +{ "text", { { + data = "b", + tags = { 42, + k = "v" + } + } } } +{ "text", { { + data = "e", + tags = { + k = "v" + } + } } } +{ "text", { { + data = "f", + tags = {} + } } } +{ "return" } +]]-- \ No newline at end of file