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:
parent
d1818d10b1
commit
f372a32b48
4 changed files with 26 additions and 15 deletions
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue