From aa8dfbd49843a8bbb5339e1598a691fc1d856c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Reuh=20Fildadut?= Date: Sun, 31 Dec 2023 14:25:37 +0100 Subject: [PATCH] Fix interleaved text and choices --- anselme/state/event_manager.lua | 63 ++++++++++++++---------- anselme/stdlib/text.lua | 2 +- test/results/choice text interleaved.ans | 19 +++++++ test/tests/choice text interleaved.ans | 14 ++++++ 4 files changed, 70 insertions(+), 28 deletions(-) create mode 100644 test/results/choice text interleaved.ans create mode 100644 test/tests/choice text interleaved.ans diff --git a/anselme/state/event_manager.lua b/anselme/state/event_manager.lua index 7b828b5..54a22d2 100644 --- a/anselme/state/event_manager.lua +++ b/anselme/state/event_manager.lua @@ -1,7 +1,7 @@ local class = require("anselme.lib.class") local ast = require("anselme.ast") -local Nil, String, List, Identifier, Boolean = ast.Nil, ast.String, ast.List, ast.Identifier, ast.Boolean +local Nil, String, List, Identifier = ast.Nil, ast.String, ast.List, ast.Identifier -- list of event data local event_buffer_identifier = Identifier:new("_event_buffer") @@ -11,9 +11,9 @@ local event_buffer_symbol = event_buffer_identifier:to_symbol{ confined_to_branc local last_event_type_identifier = Identifier:new("_last_event_type") local last_event_type_symbol = last_event_type_identifier:to_symbol{ confined_to_branch = true } --- indicate if the next flush should be ignored for the current buffered event -local discard_next_flush_identifier = Identifier:new("_discard_next_flush") -local discard_next_flush_symbol = discard_next_flush_identifier:to_symbol{ confined_to_branch = true } +-- (per-scope) indicate if we should discard write to an event type +local discard_next_events_identifier = Identifier:new("_discard_next_events") +local discard_next_events_symbol = discard_next_events_identifier:to_symbol{ confined_to_branch = true } return class { init = false, @@ -21,48 +21,57 @@ return class { setup = function(self, state) state.scope:define(event_buffer_symbol, List:new(state)) state.scope:define(last_event_type_symbol, Nil:new()) - state.scope:define(discard_next_flush_symbol, Nil:new()) end, reset = function(self, state) state.scope:set(event_buffer_identifier, List:new(state)) state.scope:set(last_event_type_identifier, Nil:new()) - state.scope:set(discard_next_flush_identifier, Nil:new()) end, -- write an event into the event buffer -- will flush if an event of a different type is present in the buffer write = function(self, state, event) - local current_type = state.scope:get(last_event_type_identifier):to_lua(state) - if current_type ~= nil and current_type ~= event.type then - self:flush(state) + -- discard if requested + if state.scope:defined_in_current(discard_next_events_symbol) then + local discard_type = state.scope:get(discard_next_events_identifier):to_lua() + if discard_type == event.type then + return + elseif discard_type ~= nil then + state.scope:set(discard_next_events_identifier, Nil:new()) -- fake flush the discarded events + end end + -- flush until no event or same type + repeat + local current_type = state.scope:get(last_event_type_identifier):to_lua(state) + if current_type ~= nil and current_type ~= event.type then + self:flush(state) + end + until current_type == nil or current_type == event.type + -- write state.scope:set(last_event_type_identifier, String:new(event.type)) state.scope:get(event_buffer_identifier):insert(state, event) end, - -- same as :write, but the buffer will be discarded instead of yielded on the next flush - write_and_discard_on_flush = function(self, state, event) - self:write(state, event) - state.scope:set(discard_next_flush_identifier, Boolean:new(true)) + -- same as :write, but will not actually write the event, instead discarding all immediately following event of the same type in the same scope + write_and_discard_following = function(self, state, event) + if not state.scope:defined_in_current(discard_next_events_symbol) then + state.scope:define(discard_next_events_symbol, String:new(event.type)) + else + state.scope:set(discard_next_events_identifier, String:new(event.type)) + end end, -- flush the event buffer: build the event data and yield it flush = function(self, state) local last_type = state.scope:get(last_event_type_identifier):to_lua(state) if last_type then - local discard_next_flush = state.scope:get(discard_next_flush_identifier):truthy() - if discard_next_flush then - self:reset(state) - else - local last_buffer = state.scope:get(event_buffer_identifier) - local event_president = last_buffer:get(state, 1) -- elected representative of all concerned events - -- yield event data - local data = event_president:build_event_data(state, last_buffer) - coroutine.yield(last_type, data) - -- clear room for the future - self:reset(state) - -- post callback - if event_president.post_flush_callback then event_president:post_flush_callback(state, last_buffer, data) end - end + local last_buffer = state.scope:get(event_buffer_identifier) + local event_president = last_buffer:get(state, 1) -- elected representative of all concerned events + -- yield event data + local data = event_president:build_event_data(state, last_buffer) + coroutine.yield(last_type, data) + -- clear room for the future + self:reset(state) + -- post callback + if event_president.post_flush_callback then event_president:post_flush_callback(state, last_buffer, data) end end end, -- keep flushing until nothing is left (a flush may re-fill the buffer during its execution) diff --git a/anselme/stdlib/text.lua b/anselme/stdlib/text.lua index 5627232..d5d6a6e 100644 --- a/anselme/stdlib/text.lua +++ b/anselme/stdlib/text.lua @@ -21,7 +21,7 @@ return { function(state, text, func) if func:contains_current_resume_target(state) then func:call(state, ArgumentTuple:new()) - event_manager:write_and_discard_on_flush(state, Choice:new(text, func)) + event_manager:write_and_discard_following(state, Choice:new(text, func)) else event_manager:write(state, Choice:new(text, func)) end diff --git a/test/results/choice text interleaved.ans b/test/results/choice text interleaved.ans new file mode 100644 index 0000000..8716c90 --- /dev/null +++ b/test/results/choice text interleaved.ans @@ -0,0 +1,19 @@ +--# run #-- +--- choice --- +=> | {}"a" | +--- text --- +| {}"-> a" | +--- choice --- +=> | {}"aa" | + > | {}"ab" | +--- text --- +| {}"-> aa" | +| {}"x" | +--- choice --- +=> | {}"b" | +--- text --- +| {}"-> b" | +--- return --- +() +--# saved #-- +{} \ No newline at end of file diff --git a/test/tests/choice text interleaved.ans b/test/tests/choice text interleaved.ans new file mode 100644 index 0000000..76bc753 --- /dev/null +++ b/test/tests/choice text interleaved.ans @@ -0,0 +1,14 @@ +:@choice = 1 + +:f = $_ + | a |> + |-> a + | aa |> + |-> aa + | ab |> + |-> ab + | x + | b |> + |-> b + +f! \ No newline at end of file