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

Fix interleaved text and choices

This commit is contained in:
Étienne Fildadut 2023-12-31 14:25:37 +01:00
parent 4125a4c99b
commit aa8dfbd498
4 changed files with 70 additions and 28 deletions

View file

@ -1,7 +1,7 @@
local class = require("anselme.lib.class") local class = require("anselme.lib.class")
local ast = require("anselme.ast") 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 -- list of event data
local event_buffer_identifier = Identifier:new("_event_buffer") 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_identifier = Identifier:new("_last_event_type")
local last_event_type_symbol = last_event_type_identifier:to_symbol{ confined_to_branch = true } 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 -- (per-scope) indicate if we should discard write to an event type
local discard_next_flush_identifier = Identifier:new("_discard_next_flush") local discard_next_events_identifier = Identifier:new("_discard_next_events")
local discard_next_flush_symbol = discard_next_flush_identifier:to_symbol{ confined_to_branch = true } local discard_next_events_symbol = discard_next_events_identifier:to_symbol{ confined_to_branch = true }
return class { return class {
init = false, init = false,
@ -21,48 +21,57 @@ return class {
setup = function(self, state) setup = function(self, state)
state.scope:define(event_buffer_symbol, List:new(state)) state.scope:define(event_buffer_symbol, List:new(state))
state.scope:define(last_event_type_symbol, Nil:new()) state.scope:define(last_event_type_symbol, Nil:new())
state.scope:define(discard_next_flush_symbol, Nil:new())
end, end,
reset = function(self, state) reset = function(self, state)
state.scope:set(event_buffer_identifier, List:new(state)) state.scope:set(event_buffer_identifier, List:new(state))
state.scope:set(last_event_type_identifier, Nil:new()) state.scope:set(last_event_type_identifier, Nil:new())
state.scope:set(discard_next_flush_identifier, Nil:new())
end, end,
-- write an event into the event buffer -- write an event into the event buffer
-- will flush if an event of a different type is present in the buffer -- will flush if an event of a different type is present in the buffer
write = function(self, state, event) write = function(self, state, event)
local current_type = state.scope:get(last_event_type_identifier):to_lua(state) -- discard if requested
if current_type ~= nil and current_type ~= event.type then if state.scope:defined_in_current(discard_next_events_symbol) then
self:flush(state) 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 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:set(last_event_type_identifier, String:new(event.type))
state.scope:get(event_buffer_identifier):insert(state, event) state.scope:get(event_buffer_identifier):insert(state, event)
end, end,
-- same as :write, but the buffer will be discarded instead of yielded on the next flush -- 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_on_flush = function(self, state, event) write_and_discard_following = function(self, state, event)
self:write(state, event) if not state.scope:defined_in_current(discard_next_events_symbol) then
state.scope:set(discard_next_flush_identifier, Boolean:new(true)) 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, end,
-- flush the event buffer: build the event data and yield it -- flush the event buffer: build the event data and yield it
flush = function(self, state) flush = function(self, state)
local last_type = state.scope:get(last_event_type_identifier):to_lua(state) local last_type = state.scope:get(last_event_type_identifier):to_lua(state)
if last_type then if last_type then
local discard_next_flush = state.scope:get(discard_next_flush_identifier):truthy() local last_buffer = state.scope:get(event_buffer_identifier)
if discard_next_flush then local event_president = last_buffer:get(state, 1) -- elected representative of all concerned events
self:reset(state) -- yield event data
else local data = event_president:build_event_data(state, last_buffer)
local last_buffer = state.scope:get(event_buffer_identifier) coroutine.yield(last_type, data)
local event_president = last_buffer:get(state, 1) -- elected representative of all concerned events -- clear room for the future
-- yield event data self:reset(state)
local data = event_president:build_event_data(state, last_buffer) -- post callback
coroutine.yield(last_type, data) if event_president.post_flush_callback then event_president:post_flush_callback(state, last_buffer, data) end
-- 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 end
end, end,
-- keep flushing until nothing is left (a flush may re-fill the buffer during its execution) -- keep flushing until nothing is left (a flush may re-fill the buffer during its execution)

View file

@ -21,7 +21,7 @@ return {
function(state, text, func) function(state, text, func)
if func:contains_current_resume_target(state) then if func:contains_current_resume_target(state) then
func:call(state, ArgumentTuple:new()) 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 else
event_manager:write(state, Choice:new(text, func)) event_manager:write(state, Choice:new(text, func))
end end

View file

@ -0,0 +1,19 @@
--# run #--
--- choice ---
=> | {}"a" |
--- text ---
| {}"-> a" |
--- choice ---
=> | {}"aa" |
> | {}"ab" |
--- text ---
| {}"-> aa" |
| {}"x" |
--- choice ---
=> | {}"b" |
--- text ---
| {}"-> b" |
--- return ---
()
--# saved #--
{}

View file

@ -0,0 +1,14 @@
:@choice = 1
:f = $_
| a |>
|-> a
| aa |>
|-> aa
| ab |>
|-> ab
| x
| b |>
|-> b
f!