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

Improve resuming from nested choices

This commit is contained in:
Étienne Fildadut 2024-01-03 16:45:53 +01:00
parent d1818d10b1
commit f372a32b48
4 changed files with 26 additions and 15 deletions

View file

@ -66,7 +66,7 @@ Function = Overloadable {
local upvalues = {}
self.expression:traverse(list_upvalues, upvalues)
if scope:defined(state, ast.Identifier:new("_")) then
scope:get(state, ast.Identifier:new("_")):traverse(list_upvalues)
scope:get(state, ast.Identifier:new("_")):traverse(list_upvalues, upvalues)
end
-- cache upvalues so they aren't affected by future redefinition in a parent scope
@ -113,14 +113,12 @@ Function = Overloadable {
state.scope:push(self.scope)
calling_environment_manager:push(state, calling_environment)
resume_manager:push(state, target)
-- push function scope
state.scope:push()
resume_manager:push(state, target)
local exp = self.expression:eval(state)
state.scope:pop()
resume_manager:pop(state)
state.scope:pop()
calling_environment_manager:pop(state)
state.scope:pop()

View file

@ -31,7 +31,7 @@ return class {
-- will flush if an event of a different type is present in the buffer
write = function(self, state, event)
-- discard if requested
if state.scope:defined_in_current(discard_next_events_symbol) then
if state.scope:defined(discard_next_events_identifier) then
local discard_type = state.scope:get(discard_next_events_identifier):to_lua()
if discard_type == event.type then
return
@ -50,12 +50,12 @@ return class {
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 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))
-- same as :write, but will not actually write the event, instead discarding all immediately following event of the same type in the same scope and children
write_and_discard_following = function(self, state, event, scope)
if not scope:defined_in_current(state, discard_next_events_symbol) then
scope:define(state, discard_next_events_symbol, String:new(event.type))
else
state.scope:set(discard_next_events_identifier, String:new(event.type))
scope:set(state, discard_next_events_identifier, String:new(event.type))
end
end,

View file

@ -4,7 +4,9 @@ local ast = require("anselme.ast")
local Nil, Identifier, ResumeTarget, Boolean
-- stack of resumable contexts
local resume_target_identifier, resume_target_symbol, resume_no_continue_identifier, resume_no_continue_symbol
local resume_target_identifier, resume_target_symbol
local resume_no_continue_identifier, resume_no_continue_symbol
local resume_environment_identifier, resume_environment_symbol
local resume_manager = class {
init = false,
@ -12,18 +14,20 @@ local resume_manager = class {
-- push a new resume context: all run code between this and the next push will try to resume to target
push = function(self, state, target)
assert(ResumeTarget:issub(target), "can only resume to a resume target")
state.scope:push_partial(resume_target_identifier, resume_no_continue_identifier)
state.scope:push_partial(resume_target_identifier, resume_no_continue_identifier, resume_environment_identifier)
state.scope:define(resume_target_symbol, target)
state.scope:define(resume_no_continue_symbol, Boolean:new(false))
state.scope:define(resume_environment_symbol, state.scope:capture())
end,
-- same as :push, but the resume will stop immediately after reaching the target or a node containing the target
-- (we will stop even if the node is not directly reached - this is used to run a specific line containing a node,
-- notably for Definition of exported variables)
push_no_continue = function(self, state, target)
assert(ResumeTarget:issub(target), "can only resume to a resume target")
state.scope:push_partial(resume_target_identifier, resume_no_continue_identifier)
state.scope:push_partial(resume_target_identifier, resume_no_continue_identifier, resume_environment_identifier)
state.scope:define(resume_target_symbol, target)
state.scope:define(resume_no_continue_symbol, Boolean:new(true))
state.scope:define(resume_environment_symbol, state.scope:capture())
end,
-- pop the current resume context
pop = function(self, state)
@ -48,6 +52,11 @@ local resume_manager = class {
-- (assumes that we are currently :resuming)
no_continue = function(self, state)
return state.scope:get(resume_no_continue_identifier):to_lua(state)
end,
-- returns the environment that was on top of the stack when the resume started
-- (assumes that we are currently :resuming)
resuming_environment = function(self, state)
return state.scope:get(resume_environment_identifier)
end
}
@ -58,6 +67,9 @@ Nil, Identifier, ResumeTarget, Boolean = ast.Nil, ast.Identifier, ast.abstract.R
resume_target_identifier = Identifier:new("_resume_target")
resume_target_symbol = resume_target_identifier:to_symbol()
resume_environment_identifier = Identifier:new("_resume_environment")
resume_environment_symbol = resume_environment_identifier:to_symbol()
resume_no_continue_identifier = Identifier:new("_resume_no_continue")
resume_no_continue_symbol = resume_no_continue_identifier:to_symbol()

View file

@ -4,6 +4,7 @@ local Nil, Choice, PartialScope, ArgumentTuple = ast.Nil, ast.Choice, ast.Partia
local event_manager = require("anselme.state.event_manager")
local translation_manager = require("anselme.state.translation_manager")
local tag_manager = require("anselme.state.tag_manager")
local resume_manager = require("anselme.state.resume_manager")
return {
-- text
@ -21,7 +22,7 @@ return {
function(state, text, func)
if func:contains_current_resume_target(state) then
func:call(state, ArgumentTuple:new())
event_manager:write_and_discard_following(state, Choice:new(text, func))
event_manager:write_and_discard_following(state, Choice:new(text, func), resume_manager:resuming_environment(state))
else
event_manager:write(state, Choice:new(text, func))
end