mirror of
https://github.com/Reuh/anselme.git
synced 2025-10-28 17:19: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 = {}
|
local upvalues = {}
|
||||||
self.expression:traverse(list_upvalues, upvalues)
|
self.expression:traverse(list_upvalues, upvalues)
|
||||||
if scope:defined(state, ast.Identifier:new("_")) then
|
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
|
end
|
||||||
|
|
||||||
-- cache upvalues so they aren't affected by future redefinition in a parent scope
|
-- 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)
|
state.scope:push(self.scope)
|
||||||
calling_environment_manager:push(state, calling_environment)
|
calling_environment_manager:push(state, calling_environment)
|
||||||
|
|
||||||
resume_manager:push(state, target)
|
|
||||||
|
|
||||||
-- push function scope
|
-- push function scope
|
||||||
state.scope:push()
|
state.scope:push()
|
||||||
|
resume_manager:push(state, target)
|
||||||
local exp = self.expression:eval(state)
|
local exp = self.expression:eval(state)
|
||||||
state.scope:pop()
|
|
||||||
|
|
||||||
resume_manager:pop(state)
|
resume_manager:pop(state)
|
||||||
|
state.scope:pop()
|
||||||
|
|
||||||
calling_environment_manager:pop(state)
|
calling_environment_manager:pop(state)
|
||||||
state.scope:pop()
|
state.scope:pop()
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ return class {
|
||||||
-- 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)
|
||||||
-- discard if requested
|
-- 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()
|
local discard_type = state.scope:get(discard_next_events_identifier):to_lua()
|
||||||
if discard_type == event.type then
|
if discard_type == event.type then
|
||||||
return
|
return
|
||||||
|
|
@ -50,12 +50,12 @@ return class {
|
||||||
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 will not actually write the event, instead discarding all immediately following event of the same type in the same scope
|
-- 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)
|
write_and_discard_following = function(self, state, event, scope)
|
||||||
if not state.scope:defined_in_current(discard_next_events_symbol) then
|
if not scope:defined_in_current(state, discard_next_events_symbol) then
|
||||||
state.scope:define(discard_next_events_symbol, String:new(event.type))
|
scope:define(state, discard_next_events_symbol, String:new(event.type))
|
||||||
else
|
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
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ local ast = require("anselme.ast")
|
||||||
local Nil, Identifier, ResumeTarget, Boolean
|
local Nil, Identifier, ResumeTarget, Boolean
|
||||||
|
|
||||||
-- stack of resumable contexts
|
-- 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 {
|
local resume_manager = class {
|
||||||
init = false,
|
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 a new resume context: all run code between this and the next push will try to resume to target
|
||||||
push = function(self, state, target)
|
push = function(self, state, target)
|
||||||
assert(ResumeTarget:issub(target), "can only resume to a resume 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_target_symbol, target)
|
||||||
state.scope:define(resume_no_continue_symbol, Boolean:new(false))
|
state.scope:define(resume_no_continue_symbol, Boolean:new(false))
|
||||||
|
state.scope:define(resume_environment_symbol, state.scope:capture())
|
||||||
end,
|
end,
|
||||||
-- same as :push, but the resume will stop immediately after reaching the target or a node containing the target
|
-- 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,
|
-- (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)
|
-- notably for Definition of exported variables)
|
||||||
push_no_continue = function(self, state, target)
|
push_no_continue = function(self, state, target)
|
||||||
assert(ResumeTarget:issub(target), "can only resume to a resume 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_target_symbol, target)
|
||||||
state.scope:define(resume_no_continue_symbol, Boolean:new(true))
|
state.scope:define(resume_no_continue_symbol, Boolean:new(true))
|
||||||
|
state.scope:define(resume_environment_symbol, state.scope:capture())
|
||||||
end,
|
end,
|
||||||
-- pop the current resume context
|
-- pop the current resume context
|
||||||
pop = function(self, state)
|
pop = function(self, state)
|
||||||
|
|
@ -48,6 +52,11 @@ local resume_manager = class {
|
||||||
-- (assumes that we are currently :resuming)
|
-- (assumes that we are currently :resuming)
|
||||||
no_continue = function(self, state)
|
no_continue = function(self, state)
|
||||||
return state.scope:get(resume_no_continue_identifier):to_lua(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
|
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_identifier = Identifier:new("_resume_target")
|
||||||
resume_target_symbol = resume_target_identifier:to_symbol()
|
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_identifier = Identifier:new("_resume_no_continue")
|
||||||
resume_no_continue_symbol = resume_no_continue_identifier:to_symbol()
|
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 event_manager = require("anselme.state.event_manager")
|
||||||
local translation_manager = require("anselme.state.translation_manager")
|
local translation_manager = require("anselme.state.translation_manager")
|
||||||
local tag_manager = require("anselme.state.tag_manager")
|
local tag_manager = require("anselme.state.tag_manager")
|
||||||
|
local resume_manager = require("anselme.state.resume_manager")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
-- text
|
-- text
|
||||||
|
|
@ -21,7 +22,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_following(state, Choice:new(text, func))
|
event_manager:write_and_discard_following(state, Choice:new(text, func), resume_manager:resuming_environment(state))
|
||||||
else
|
else
|
||||||
event_manager:write(state, Choice:new(text, func))
|
event_manager:write(state, Choice:new(text, func))
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue