1 import Base 2 import ./system.bend as Sys 3 import ./machine.bend as M 4 # One transition engine, independent of the operational state carrier. 5 type PhaseResult is Type: 6 Complete{entries:List,world:State} 7 Failed{entries:List,world:State,error:String} 8 type Owners is Type: 9 Owners{exit:List,transition:List,enter:List} 10 type HandlerResult is Type: 11 Completed{owners:Owners,world:State} 12 Stopped{owners:Owners,world:State,phase:Phase,error:String} 13 type Prepared is Data: 14 Idle{slot:M.Slot} 15 Ready{slot:M.Slot,transition:M.Transition,skipSame:Bool} 16 def prepend(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome,~initial:Entry -> State -> V -> Entry & Sys.Outcome,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,head:Entry,tail:PhaseResult) -> PhaseResult: 17 match tail: 18 case Complete{entries,world}: Complete{head <> entries,world} 19 case Failed{entries,world,error}: Failed{head <> entries,world,error} 20 21 def entry_outcome(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome,~initial:Entry -> State -> V -> Entry & Sys.Outcome,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,entry:Entry,outcome:Sys.Outcome,next:State -> Maybe<&2,String> -> PhaseResult) -> PhaseResult: 22 match outcome: 23 case Sys.Failed{world,error}:prepend(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,entry,next(world,Some{error})) 24 case Sys.Succeeded{world,_}:prepend(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,entry,next(world,None{})) 25 def entry_result(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome,~initial:Entry -> State -> V -> Entry & Sys.Outcome,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,observed:Entry & Sys.Outcome,next:State -> Maybe<&2,String> -> PhaseResult) -> PhaseResult: 26 match observed: 27 case (entry,outcome):entry_outcome(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,entry,outcome,next) 28 def run_phase(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome,~initial:Entry -> State -> V -> Entry & Sys.Outcome,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,entries:List<&1,Entry>,world:State,+phase:Phase,+from:V,+to:V,error:Maybe<&2,String>) -> PhaseResult: 29 match entries error: 30 case entries Some{error}: Failed{entries,world,error} 31 case [] None{}: Complete{[],world} 32 case entry <> rest None{}: entry_result(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,invoke(entry,world,phase,from,to),world => error => run_phase(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,rest,world,phase,from,to,error)) 33 34 def run_initial(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome,~initial:Entry -> State -> V -> Entry & Sys.Outcome,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,entries:List<&1,Entry>,world:State,+to:V,error:Maybe<&2,String>) -> PhaseResult: 35 match entries error: 36 case entries Some{error}: Failed{entries,world,error} 37 case [] None{}: Complete{[],world} 38 case entry <> rest None{}: entry_result(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,initial(entry,world,to),world => error => run_initial(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,rest,world,to,error)) 39 40 def choose(~S:Data,~K:Data,~V:Data,skip:Bool,+current:V,+value:V,previous:Maybe<&2,V>,+skipSame:Bool) -> Prepared: 41 match skip: 42 case True{}: Idle{M.Present{current,M.NoPending{},previous,False{}}} 43 case False{}: Ready{M.Present{current,M.NoPending{},Some{current},False{}},M.Transition{current,value},skipSame} 44 45 def prepare(~S:Data,~K:Data,~V:Data,~same:V -> V -> Bool,slot:M.Slot,captured:M.Snapshot) -> Prepared: 46 match slot captured: 47 case slot M.Unscheduled{}: Idle{M.clear_changed(~S,~K,~V,slot)} 48 case M.Missing{} M.Scheduled{_,_}: Idle{M.Missing{}} 49 case M.Present{+current,_,previous,_} M.Scheduled{+value,+skipSame}: choose(~S,~K,~V,Bool.and(skipSame,same(current,value)),current,value,previous,skipSame) 50 51 def committed(~S:Data,~K:Data,~V:Data,slot:M.Slot,from:V,to:V) -> M.Slot: 52 match slot: 53 case M.Missing{}: M.Missing{} 54 case M.Present{_,pending,_,_}: M.Present{to,pending,Some{from},True{}} 55 56 def requeued(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome,~initial:Entry -> State -> V -> Entry & Sys.Outcome,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,~K:Data,~take:State -> State & M.Slot,~put:State -> M.Slot -> State,~publish:State -> M.Transition -> State,observed:State & M.Slot,to:V,skipSame:Bool) -> State: 57 (world,slot)=observed 58 put(world,M.queue(~S,~K,~V,slot,to,skipSame)) 59 60 def published(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome,~initial:Entry -> State -> V -> Entry & Sys.Outcome,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,~K:Data,~take:State -> State & M.Slot,~put:State -> M.Slot -> State,~publish:State -> M.Transition -> State,observed:State & M.Slot,+from:V,+to:V) -> State: 61 (world,slot)=observed 62 publish(put(world,committed(~S,~K,~V,slot,from,to)),M.Transition{from,to}) 63 64 def after_enter(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome,~initial:Entry -> State -> V -> Entry & Sys.Outcome,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,exit:List<&1,Entry>,transition:List<&1,Entry>,observed:PhaseResult) -> HandlerResult: 65 match observed: 66 case Complete{enter,world}: Completed{Owners{exit,transition,enter},world} 67 case Failed{enter,world,error}: Stopped{Owners{exit,transition,enter},world,enterPhase,error} 68 69 def after_transition(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome,~initial:Entry -> State -> V -> Entry & Sys.Outcome,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,~K:Data,~take:State -> State & M.Slot,~put:State -> M.Slot -> State,~publish:State -> M.Transition -> State,exit:List<&1,Entry>,enter:List<&1,Entry>,observed:PhaseResult,+from:V,+to:V,skipSame:Bool) -> HandlerResult: 70 match observed: 71 case Failed{transition,world,error}: Stopped{Owners{exit,transition,enter},requeued(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,~K,~take,~put,~publish,take(world),to,skipSame),transitionPhase,error} 72 case Complete{transition,world}: after_enter(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,exit,transition,run_phase(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,enter,published(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,~K,~take,~put,~publish,take(world),from,to),enterPhase,from,to,None{})) 73 74 def after_exit(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome,~initial:Entry -> State -> V -> Entry & Sys.Outcome,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,~K:Data,~take:State -> State & M.Slot,~put:State -> M.Slot -> State,~publish:State -> M.Transition -> State,transition:List<&1,Entry>,enter:List<&1,Entry>,observed:PhaseResult,+from:V,+to:V,skipSame:Bool) -> HandlerResult: 75 match observed: 76 case Failed{exit,world,error}: Stopped{Owners{exit,transition,enter},requeued(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,~K,~take,~put,~publish,take(world),to,skipSame),exitPhase,error} 77 case Complete{exit,world}: after_transition(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,~K,~take,~put,~publish,exit,enter,run_phase(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,transition,world,transitionPhase,from,to,None{}),from,to,skipSame) 78 79 def prepared(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome,~initial:Entry -> State -> V -> Entry & Sys.Outcome,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,~K:Data,~take:State -> State & M.Slot,~put:State -> M.Slot -> State,~publish:State -> M.Transition -> State,owners:Owners,world:State,prepared:Prepared) -> HandlerResult: 80 match owners prepared: 81 case owners Idle{slot}: Completed{owners,put(world,slot)} 82 case Owners{exit,transition,enter} Ready{slot,M.Initial{to},_}:after_enter(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,exit,transition,run_initial(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,enter,put(world,slot),to,None{})) 83 case Owners{exit,transition,enter} Ready{slot,M.Transition{+from,+to},skipSame}: after_exit(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,~K,~take,~put,~publish,transition,enter,run_phase(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,exit,put(world,slot),exitPhase,from,to,None{}),from,to,skipSame) 84 85 def taken(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome,~initial:Entry -> State -> V -> Entry & Sys.Outcome,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,~K:Data,~take:State -> State & M.Slot,~put:State -> M.Slot -> State,~publish:State -> M.Transition -> State,~same:V -> V -> Bool,owners:Owners,observed:State & M.Slot,captured:M.Snapshot) -> HandlerResult: 86 (world,slot)=observed 87 prepared(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,~K,~take,~put,~publish,owners,world,prepare(~S,~K,~V,~same,slot,captured)) 88 89 def run(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome,~initial:Entry -> State -> V -> Entry & Sys.Outcome,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,~K:Data,~take:State -> State & M.Slot,~put:State -> M.Slot -> State,~publish:State -> M.Transition -> State,~same:V -> V -> Bool,owners:Owners,world:State,captured:M.Snapshot) -> HandlerResult: 90 taken(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,~K,~take,~put,~publish,~same,owners,take(world),captured)