{-# OPTIONS -fglasgow-exts #-}

-- A module defining sequences of control segments and prompts
-- The control segments are some sort of continuations but we don't
--   care about their exact nature here. 
-- We can append two sequences and split a sequence at the first
--   occurrence of a given prompt

module Pugs.Cont.SeqTR (
  Seq (..), 
  splitSeq, appendSeq
) where

import qualified Pugs.Cont.PromptTR as Prompt

------------------------------------------------------------------------

data Seq s r a b = EmptyS (a -> b)
                 | PushP (Prompt.Prompt r a) (Seq s r a b)
                 | forall c. PushSeg (s r a c) (Seq s r c b)
                 | forall c. PushCO (a -> c) (Seq s r c b)

splitSeq :: Prompt.Prompt r b -> Seq s r a ans -> (Seq s r a b, Seq s r b ans)
splitSeq _ (EmptyS _) = error ("Prompt was not found on the stack")
splitSeq p (PushP p' sk) = 
  case Prompt.eqPrompt p' p of 
    Nothing -> let (subk,sk') = splitSeq p sk
               in (PushP p' subk, sk')
    Just (a2b,b2a) -> (EmptyS a2b, PushCO b2a sk)
splitSeq p (PushSeg seg sk) = 
    let (subk,sk') = splitSeq p sk
    in (PushSeg seg subk, sk')
splitSeq p (PushCO f sk) = 
    let (subk,sk') = splitSeq p sk
    in (PushCO f subk, sk')

appendSeq :: Seq s r a b -> Seq s r b ans -> Seq s r a ans
appendSeq (EmptyS f) sk = PushCO f sk
appendSeq (PushP p subk) sk = PushP p (appendSeq subk sk)
appendSeq (PushSeg seg subk) sk = PushSeg seg (appendSeq subk sk)
appendSeq (PushCO f subk) sk = PushCO f (appendSeq subk sk)

----------------------------------------------------------------------

