packages feed

WidgetRattus 0.2 → 0.3

raw patch · 50 files changed

+4878/−4215 lines, 50 filesdep +monomerdep ~ghcdep ~ghc-bootdep ~template-haskellbinary-addedPVP ok

version bump matches the API change (PVP)

Dependencies added: monomer

Dependency ranges changed: ghc, ghc-boot, template-haskell, text

API changes (from Hackage documentation)

- AsyncRattus: AllowLazyData :: AsyncRattus
- AsyncRattus: AllowRecursion :: AsyncRattus
- AsyncRattus: continuous :: Name -> Q [Dec]
- AsyncRattus: data AsyncRattus
- AsyncRattus: mapO :: Box (a -> b) -> O a -> O b
- AsyncRattus.Channels: C :: IO a -> C a
- AsyncRattus.Channels: [unC] :: C a -> IO a
- AsyncRattus.Channels: chan :: C (Chan a)
- AsyncRattus.Channels: class Producer p a | p -> a
- AsyncRattus.Channels: data Chan a
- AsyncRattus.Channels: delayC :: O (C a) -> C (O a)
- AsyncRattus.Channels: getCurrent :: Producer p a => p -> Maybe' a
- AsyncRattus.Channels: getInput :: IO (Box (O a) :* (a -> IO ()))
- AsyncRattus.Channels: getNext :: Producer p a => p -> (forall q. Producer q a => O q -> b) -> b
- AsyncRattus.Channels: instance AsyncRattus.Channels.Producer p a => AsyncRattus.Channels.Producer (AsyncRattus.InternalPrimitives.Box p) a
- AsyncRattus.Channels: instance AsyncRattus.Channels.Producer p a => AsyncRattus.Channels.Producer (AsyncRattus.InternalPrimitives.O p) a
- AsyncRattus.Channels: instance GHC.Base.Applicative AsyncRattus.Channels.C
- AsyncRattus.Channels: instance GHC.Base.Functor AsyncRattus.Channels.C
- AsyncRattus.Channels: instance GHC.Base.Monad AsyncRattus.Channels.C
- AsyncRattus.Channels: mkInput :: Producer p a => p -> IO (Box (O a))
- AsyncRattus.Channels: newtype C a
- AsyncRattus.Channels: setOutput :: Producer p a => p -> (a -> IO ()) -> IO ()
- AsyncRattus.Channels: startEventLoop :: IO ()
- AsyncRattus.Channels: timer :: Int -> Box (O ())
- AsyncRattus.Channels: wait :: Chan a -> O a
- AsyncRattus.Future: (:>:) :: !a -> !O (F (SigF a)) -> SigF a
- AsyncRattus.Future: Now :: !a -> F a
- AsyncRattus.Future: Wait :: !O (F a) -> F a
- AsyncRattus.Future: bindF :: F a -> Box (a -> F b) -> F b
- AsyncRattus.Future: current :: SigF a -> a
- AsyncRattus.Future: data F a
- AsyncRattus.Future: data SigF a
- AsyncRattus.Future: filter :: Box (a -> Bool) -> SigF a -> F (SigF a)
- AsyncRattus.Future: filterAwait :: Box (a -> Bool) -> F (SigF a) -> F (SigF a)
- AsyncRattus.Future: filterMap :: Box (a -> Maybe' b) -> SigF a -> F (SigF b)
- AsyncRattus.Future: filterMapAwait :: Box (a -> Maybe' b) -> F (SigF a) -> F (SigF b)
- AsyncRattus.Future: fromSig :: Sig a -> SigF a
- AsyncRattus.Future: future :: SigF a -> O (F (SigF a))
- AsyncRattus.Future: instance AsyncRattus.Channels.Producer (AsyncRattus.Future.OneShot a) a
- AsyncRattus.Future: instance AsyncRattus.Channels.Producer (AsyncRattus.Future.SigF a) a
- AsyncRattus.Future: instance AsyncRattus.Channels.Producer p a => AsyncRattus.Channels.Producer (AsyncRattus.Future.F p) a
- AsyncRattus.Future: map :: Box (a -> b) -> SigF a -> SigF b
- AsyncRattus.Future: mapAwait :: Box (a -> b) -> F (SigF a) -> F (SigF b)
- AsyncRattus.Future: mapF :: Box (a -> b) -> F a -> F b
- AsyncRattus.Future: mkSigF :: Box (O a) -> F (SigF a)
- AsyncRattus.Future: mkSigF' :: Box (O a) -> O (F (SigF a))
- AsyncRattus.Future: scan :: Stable b => Box (b -> a -> b) -> b -> SigF a -> SigF b
- AsyncRattus.Future: scanAwait :: Stable b => Box (b -> a -> b) -> b -> F (SigF a) -> F (SigF b)
- AsyncRattus.Future: switch :: SigF a -> F (SigF a) -> SigF a
- AsyncRattus.Future: switchAwait :: F (SigF a) -> F (SigF a) -> F (SigF a)
- AsyncRattus.Future: switchS :: Stable a => SigF a -> F (a -> SigF a) -> SigF a
- AsyncRattus.Future: sync :: O (F a) -> O (F b) -> O (F a :* F b)
- AsyncRattus.Future: syncF :: (Stable a, Stable b) => F a -> F b -> F (a :* b)
- AsyncRattus.Future: trigger :: Stable b => Box (a -> b -> c) -> SigF a -> SigF b -> SigF c
- AsyncRattus.Future: triggerAwait :: Stable b => Box (a -> b -> c) -> F (SigF a) -> SigF b -> F (SigF c)
- AsyncRattus.Future: zipWith :: (Stable a, Stable b) => Box (a -> b -> c) -> SigF a -> SigF b -> SigF c
- AsyncRattus.Future: zipWithAwait :: (Stable a, Stable b) => Box (a -> b -> c) -> a -> b -> F (SigF a) -> F (SigF b) -> F (SigF c)
- AsyncRattus.InternalPrimitives: Both :: !a -> !b -> Select a b
- AsyncRattus.InternalPrimitives: Box :: a -> Box a
- AsyncRattus.InternalPrimitives: Chan :: InputChannelIdentifier -> Chan a
- AsyncRattus.InternalPrimitives: Delay :: !Clock -> (InputValue -> a) -> O a
- AsyncRattus.InternalPrimitives: Fst :: !a -> !O b -> Select a b
- AsyncRattus.InternalPrimitives: Snd :: !O a -> !b -> Select a b
- AsyncRattus.InternalPrimitives: [ContinuousData] :: Continuous a => !Weak (IORef a) -> ContinuousData
- AsyncRattus.InternalPrimitives: [MoreInputs] :: !InputChannelIdentifier -> !a -> !InputValue -> InputValue
- AsyncRattus.InternalPrimitives: [OneInput] :: !InputChannelIdentifier -> !a -> InputValue
- AsyncRattus.InternalPrimitives: adv :: O a -> a
- AsyncRattus.InternalPrimitives: adv' :: O a -> InputValue -> a
- AsyncRattus.InternalPrimitives: asyncRattusError :: [Char] -> a
- AsyncRattus.InternalPrimitives: box :: a -> Box a
- AsyncRattus.InternalPrimitives: channelMember :: InputChannelIdentifier -> Clock -> Bool
- AsyncRattus.InternalPrimitives: class Continuous p
- AsyncRattus.InternalPrimitives: class Stable a
- AsyncRattus.InternalPrimitives: clockUnion :: Clock -> Clock -> Clock
- AsyncRattus.InternalPrimitives: data Box a
- AsyncRattus.InternalPrimitives: data ContinuousData
- AsyncRattus.InternalPrimitives: data InputValue
- AsyncRattus.InternalPrimitives: data O a
- AsyncRattus.InternalPrimitives: data Select a b
- AsyncRattus.InternalPrimitives: defaultPromote :: Continuous a => a -> Box a
- AsyncRattus.InternalPrimitives: delay :: a -> O a
- AsyncRattus.InternalPrimitives: emptyClock :: Clock
- AsyncRattus.InternalPrimitives: extractClock :: O a -> Clock
- AsyncRattus.InternalPrimitives: inputInClock :: InputValue -> Clock -> Bool
- AsyncRattus.InternalPrimitives: instance AsyncRattus.InternalPrimitives.Stable a => AsyncRattus.InternalPrimitives.Continuous a
- AsyncRattus.InternalPrimitives: never :: O a
- AsyncRattus.InternalPrimitives: newtype Chan a
- AsyncRattus.InternalPrimitives: nextProgress :: Continuous p => p -> Clock
- AsyncRattus.InternalPrimitives: progressAndNext :: Continuous p => InputValue -> p -> (p, Clock)
- AsyncRattus.InternalPrimitives: progressInternal :: Continuous p => InputValue -> p -> p
- AsyncRattus.InternalPrimitives: progressPromoteStore :: InputValue -> IO ()
- AsyncRattus.InternalPrimitives: progressPromoteStoreAtomic :: InputValue -> IO ()
- AsyncRattus.InternalPrimitives: progressPromoteStoreMutex :: MVar ()
- AsyncRattus.InternalPrimitives: promote :: Continuous a => a -> Box a
- AsyncRattus.InternalPrimitives: promoteInternal :: Continuous p => p -> Box p
- AsyncRattus.InternalPrimitives: promoteStore :: IORef [ContinuousData]
- AsyncRattus.InternalPrimitives: select :: O a -> O b -> Select a b
- AsyncRattus.InternalPrimitives: select' :: O a -> O b -> InputValue -> Select a b
- AsyncRattus.InternalPrimitives: singletonClock :: InputChannelIdentifier -> Clock
- AsyncRattus.InternalPrimitives: type Clock = IntSet
- AsyncRattus.InternalPrimitives: type InputChannelIdentifier = Int
- AsyncRattus.InternalPrimitives: unbox :: Box a -> a
- AsyncRattus.Plugin: AllowLazyData :: AsyncRattus
- AsyncRattus.Plugin: AllowRecursion :: AsyncRattus
- AsyncRattus.Plugin: data AsyncRattus
- AsyncRattus.Plugin: plugin :: Plugin
- AsyncRattus.Plugin.Annotation: AllowLazyData :: AsyncRattus
- AsyncRattus.Plugin.Annotation: AllowRecursion :: AsyncRattus
- AsyncRattus.Plugin.Annotation: ExpectError :: InternalAnn
- AsyncRattus.Plugin.Annotation: ExpectWarning :: InternalAnn
- AsyncRattus.Plugin.Annotation: data AsyncRattus
- AsyncRattus.Plugin.Annotation: data InternalAnn
- AsyncRattus.Plugin.Annotation: instance Data.Data.Data AsyncRattus.Plugin.Annotation.AsyncRattus
- AsyncRattus.Plugin.Annotation: instance Data.Data.Data AsyncRattus.Plugin.Annotation.InternalAnn
- AsyncRattus.Plugin.Annotation: instance GHC.Classes.Eq AsyncRattus.Plugin.Annotation.AsyncRattus
- AsyncRattus.Plugin.Annotation: instance GHC.Classes.Eq AsyncRattus.Plugin.Annotation.InternalAnn
- AsyncRattus.Plugin.Annotation: instance GHC.Classes.Ord AsyncRattus.Plugin.Annotation.AsyncRattus
- AsyncRattus.Plugin.Annotation: instance GHC.Classes.Ord AsyncRattus.Plugin.Annotation.InternalAnn
- AsyncRattus.Plugin.Annotation: instance GHC.Show.Show AsyncRattus.Plugin.Annotation.AsyncRattus
- AsyncRattus.Plugin.Annotation: instance GHC.Show.Show AsyncRattus.Plugin.Annotation.InternalAnn
- AsyncRattus.Primitives: Both :: !a -> !b -> Select a b
- AsyncRattus.Primitives: Fst :: !a -> !O b -> Select a b
- AsyncRattus.Primitives: Snd :: !O a -> !b -> Select a b
- AsyncRattus.Primitives: adv :: O a -> a
- AsyncRattus.Primitives: box :: a -> Box a
- AsyncRattus.Primitives: class Continuous p
- AsyncRattus.Primitives: class Stable a
- AsyncRattus.Primitives: data Box a
- AsyncRattus.Primitives: data O a
- AsyncRattus.Primitives: data Select a b
- AsyncRattus.Primitives: delay :: a -> O a
- AsyncRattus.Primitives: never :: O a
- AsyncRattus.Primitives: promote :: Continuous a => a -> Box a
- AsyncRattus.Primitives: select :: O a -> O b -> Select a b
- AsyncRattus.Primitives: unbox :: Box a -> a
- AsyncRattus.Signal: (:::) :: !a -> !O (Sig a) -> Sig a
- AsyncRattus.Signal: cond :: Stable a => Sig Bool -> Sig a -> Sig a -> Sig a
- AsyncRattus.Signal: const :: a -> Sig a
- AsyncRattus.Signal: current :: Sig a -> a
- AsyncRattus.Signal: data Sig a
- AsyncRattus.Signal: derivative :: forall a v. (VectorSpace v a, Eq v, Fractional a, Stable v, Stable a) => Sig v -> Sig v
- AsyncRattus.Signal: filter :: Box (a -> Bool) -> Sig a -> IO (Box (O (Sig a)))
- AsyncRattus.Signal: filterAwait :: Box (a -> Bool) -> O (Sig a) -> IO (Box (O (Sig a)))
- AsyncRattus.Signal: filterMap :: Box (a -> Maybe' b) -> Sig a -> IO (Box (O (Sig b)))
- AsyncRattus.Signal: filterMapAwait :: Box (a -> Maybe' b) -> O (Sig a) -> IO (Box (O (Sig b)))
- AsyncRattus.Signal: future :: Sig a -> O (Sig a)
- AsyncRattus.Signal: getInputSig :: IO (Box (O (Sig a)) :* (a -> IO ()))
- AsyncRattus.Signal: infixr 5 :::
- AsyncRattus.Signal: instance AsyncRattus.Channels.Producer (AsyncRattus.Signal.Sig a) a
- AsyncRattus.Signal: instance AsyncRattus.Channels.Producer (AsyncRattus.Signal.SigMaybe a) a
- AsyncRattus.Signal: instance AsyncRattus.InternalPrimitives.Continuous a => AsyncRattus.InternalPrimitives.Continuous (AsyncRattus.Signal.Sig a)
- AsyncRattus.Signal: integral :: forall a v. (VectorSpace v a, Eq v, Fractional a, Stable v, Stable a) => v -> Sig v -> Sig v
- AsyncRattus.Signal: interleave :: Box (a -> a -> a) -> O (Sig a) -> O (Sig a) -> O (Sig a)
- AsyncRattus.Signal: map :: Box (a -> b) -> Sig a -> Sig b
- AsyncRattus.Signal: mapAwait :: Box (a -> b) -> O (Sig a) -> O (Sig b)
- AsyncRattus.Signal: mkBoxSig :: Box (O a) -> Box (O (Sig a))
- AsyncRattus.Signal: mkInputSig :: Producer p a => p -> IO (Box (O (Sig a)))
- AsyncRattus.Signal: mkSig :: Box (O a) -> O (Sig a)
- AsyncRattus.Signal: scan :: Continuous b => Box (b -> a -> b) -> b -> Sig a -> Sig b
- AsyncRattus.Signal: scanAwait :: Continuous b => Box (b -> a -> b) -> b -> O (Sig a) -> Sig b
- AsyncRattus.Signal: scanAwaitC :: Continuous b => Box (b -> a -> C b) -> b -> O (Sig a) -> C (Sig b)
- AsyncRattus.Signal: scanC :: Continuous b => Box (b -> a -> C b) -> b -> Sig a -> C (Sig b)
- AsyncRattus.Signal: scanMap :: Continuous b => Box (b -> a -> b) -> Box (b -> c) -> b -> Sig a -> Sig c
- AsyncRattus.Signal: switch :: Sig a -> O (Sig a) -> Sig a
- AsyncRattus.Signal: switchAwait :: O (Sig a) -> O (Sig a) -> O (Sig a)
- AsyncRattus.Signal: switchS :: Continuous a => Sig a -> O (a -> Sig a) -> Sig a
- AsyncRattus.Signal: trigger :: (Stable a, Stable b) => Box (a -> b -> c) -> Sig a -> Sig b -> IO (Box (Sig c))
- AsyncRattus.Signal: triggerAwait :: Stable b => Box (a -> b -> c) -> O (Sig a) -> Sig b -> IO (Box (O (Sig c)))
- AsyncRattus.Signal: update :: Continuous a => Sig a -> O (Sig (a -> a)) -> Sig a
- AsyncRattus.Signal: zip :: (Stable a, Stable b) => Sig a -> Sig b -> Sig (a :* b)
- AsyncRattus.Signal: zipWith :: (Stable a, Stable b) => Box (a -> b -> c) -> Sig a -> Sig b -> Sig c
- AsyncRattus.Signal: zipWith3 :: forall a b c d. (Stable a, Stable b, Stable c) => Box (a -> b -> c -> d) -> Sig a -> Sig b -> Sig c -> Sig d
- AsyncRattus.Strict: (+++) :: List a -> List a -> List a
- AsyncRattus.Strict: (:!) :: !a -> !List a -> List a
- AsyncRattus.Strict: (:*) :: !a -> !b -> (:*) a b
- AsyncRattus.Strict: -- structure <tt>l</tt>.
- AsyncRattus.Strict: -- | The <a>Item</a> type function returns the type of items of the
- AsyncRattus.Strict: Just' :: !a -> Maybe' a
- AsyncRattus.Strict: Nil :: List a
- AsyncRattus.Strict: Nothing' :: Maybe' a
- AsyncRattus.Strict: class () => IsList l where {
- AsyncRattus.Strict: curry' :: ((a :* b) -> c) -> a -> b -> c
- AsyncRattus.Strict: data List a
- AsyncRattus.Strict: data Maybe' a
- AsyncRattus.Strict: data a :* b
- AsyncRattus.Strict: delete' :: Eq a => a -> List a -> List a
- AsyncRattus.Strict: deleteBy' :: (a -> a -> Bool) -> a -> List a -> List a
- AsyncRattus.Strict: filter' :: (a -> Bool) -> List a -> List a
- AsyncRattus.Strict: fromList :: IsList l => [Item l] -> l
- AsyncRattus.Strict: fromListN :: IsList l => Int -> [Item l] -> l
- AsyncRattus.Strict: fromMaybe' :: a -> Maybe' a -> a
- AsyncRattus.Strict: fst' :: (a :* b) -> a
- AsyncRattus.Strict: infixr 2 :*
- AsyncRattus.Strict: infixr 8 :!
- AsyncRattus.Strict: init' :: List a -> List a
- AsyncRattus.Strict: instance (AsyncRattus.InternalPrimitives.Continuous a, AsyncRattus.InternalPrimitives.Continuous b) => AsyncRattus.InternalPrimitives.Continuous (a AsyncRattus.Strict.:* b)
- AsyncRattus.Strict: instance (Data.VectorSpace.VectorSpace v a, Data.VectorSpace.VectorSpace w a, GHC.Float.Floating a, GHC.Classes.Eq a) => Data.VectorSpace.VectorSpace (v AsyncRattus.Strict.:* w) a
- AsyncRattus.Strict: instance (GHC.Classes.Eq a, GHC.Classes.Eq b) => GHC.Classes.Eq (a AsyncRattus.Strict.:* b)
- AsyncRattus.Strict: instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (a AsyncRattus.Strict.:* b)
- AsyncRattus.Strict: instance AsyncRattus.InternalPrimitives.Continuous a => AsyncRattus.InternalPrimitives.Continuous (AsyncRattus.Strict.List a)
- AsyncRattus.Strict: instance AsyncRattus.InternalPrimitives.Continuous a => AsyncRattus.InternalPrimitives.Continuous (AsyncRattus.Strict.Maybe' a)
- AsyncRattus.Strict: instance Data.Foldable.Foldable AsyncRattus.Strict.List
- AsyncRattus.Strict: instance Data.Traversable.Traversable AsyncRattus.Strict.List
- AsyncRattus.Strict: instance GHC.Base.Functor ((AsyncRattus.Strict.:*) a)
- AsyncRattus.Strict: instance GHC.Base.Functor AsyncRattus.Strict.List
- AsyncRattus.Strict: instance GHC.Classes.Eq a => GHC.Classes.Eq (AsyncRattus.Strict.List a)
- AsyncRattus.Strict: instance GHC.Classes.Eq a => GHC.Classes.Eq (AsyncRattus.Strict.Maybe' a)
- AsyncRattus.Strict: instance GHC.IsList.IsList (AsyncRattus.Strict.List a)
- AsyncRattus.Strict: instance GHC.Show.Show a => GHC.Show.Show (AsyncRattus.Strict.List a)
- AsyncRattus.Strict: instance GHC.Show.Show a => GHC.Show.Show (AsyncRattus.Strict.Maybe' a)
- AsyncRattus.Strict: listToMaybe' :: List a -> Maybe' a
- AsyncRattus.Strict: map' :: (a -> b) -> List a -> List b
- AsyncRattus.Strict: mapMaybe' :: (a -> Maybe' b) -> List a -> List b
- AsyncRattus.Strict: maybe' :: b -> (a -> b) -> Maybe' a -> b
- AsyncRattus.Strict: nub' :: Eq a => List a -> List a
- AsyncRattus.Strict: nubBy' :: (a -> a -> Bool) -> List a -> List a
- AsyncRattus.Strict: reverse' :: List a -> List a
- AsyncRattus.Strict: singleton :: a -> List a
- AsyncRattus.Strict: snd' :: (a :* b) -> b
- AsyncRattus.Strict: toList :: IsList l => l -> [Item l]
- AsyncRattus.Strict: type family Item l;
- AsyncRattus.Strict: uncurry' :: (a -> b -> c) -> (a :* b) -> c
- AsyncRattus.Strict: union' :: Eq a => List a -> List a -> List a
- AsyncRattus.Strict: unionBy' :: (a -> a -> Bool) -> List a -> List a -> List a
- AsyncRattus.Strict: zip' :: List a -> List b -> List (a :* b)
- AsyncRattus.Strict: zipWith' :: (a -> b -> c) -> List a -> List b -> List c
- AsyncRattus.Strict: }
+ WidgetRattus: AllowLazyData :: WidgetRattus
+ WidgetRattus: AllowRecursion :: WidgetRattus
+ WidgetRattus: continuous :: Name -> Q [Dec]
+ WidgetRattus: data WidgetRattus
+ WidgetRattus: mapO :: Box (a -> b) -> O a -> O b
+ WidgetRattus.Channels: C :: IO a -> C a
+ WidgetRattus.Channels: [unC] :: C a -> IO a
+ WidgetRattus.Channels: chan :: C (Chan a)
+ WidgetRattus.Channels: class Producer p a | p -> a
+ WidgetRattus.Channels: data Chan a
+ WidgetRattus.Channels: delayC :: O (C a) -> C (O a)
+ WidgetRattus.Channels: getCurrent :: Producer p a => p -> Maybe' a
+ WidgetRattus.Channels: getNext :: Producer p a => p -> (forall q. Producer q a => O q -> b) -> b
+ WidgetRattus.Channels: instance GHC.Base.Applicative WidgetRattus.Channels.C
+ WidgetRattus.Channels: instance GHC.Base.Functor WidgetRattus.Channels.C
+ WidgetRattus.Channels: instance GHC.Base.Monad WidgetRattus.Channels.C
+ WidgetRattus.Channels: instance WidgetRattus.Channels.Producer p a => WidgetRattus.Channels.Producer (WidgetRattus.InternalPrimitives.Box p) a
+ WidgetRattus.Channels: instance WidgetRattus.Channels.Producer p a => WidgetRattus.Channels.Producer (WidgetRattus.InternalPrimitives.O p) a
+ WidgetRattus.Channels: newtype C a
+ WidgetRattus.Channels: timer :: Int -> Box (O ())
+ WidgetRattus.Channels: wait :: Chan a -> O a
+ WidgetRattus.Future: (:>:) :: !a -> !O (F (SigF a)) -> SigF a
+ WidgetRattus.Future: Now :: !a -> F a
+ WidgetRattus.Future: Wait :: !O (F a) -> F a
+ WidgetRattus.Future: bindF :: F a -> Box (a -> F b) -> F b
+ WidgetRattus.Future: current :: SigF a -> a
+ WidgetRattus.Future: data F a
+ WidgetRattus.Future: data SigF a
+ WidgetRattus.Future: filter :: Box (a -> Bool) -> SigF a -> F (SigF a)
+ WidgetRattus.Future: filterAwait :: Box (a -> Bool) -> F (SigF a) -> F (SigF a)
+ WidgetRattus.Future: filterMap :: Box (a -> Maybe' b) -> SigF a -> F (SigF b)
+ WidgetRattus.Future: filterMapAwait :: Box (a -> Maybe' b) -> F (SigF a) -> F (SigF b)
+ WidgetRattus.Future: fromSig :: Sig a -> SigF a
+ WidgetRattus.Future: future :: SigF a -> O (F (SigF a))
+ WidgetRattus.Future: instance WidgetRattus.Channels.Producer (WidgetRattus.Future.OneShot a) a
+ WidgetRattus.Future: instance WidgetRattus.Channels.Producer (WidgetRattus.Future.SigF a) a
+ WidgetRattus.Future: instance WidgetRattus.Channels.Producer p a => WidgetRattus.Channels.Producer (WidgetRattus.Future.F p) a
+ WidgetRattus.Future: map :: Box (a -> b) -> SigF a -> SigF b
+ WidgetRattus.Future: mapAwait :: Box (a -> b) -> F (SigF a) -> F (SigF b)
+ WidgetRattus.Future: mapF :: Box (a -> b) -> F a -> F b
+ WidgetRattus.Future: mkSigF :: Box (O a) -> F (SigF a)
+ WidgetRattus.Future: mkSigF' :: Box (O a) -> O (F (SigF a))
+ WidgetRattus.Future: scan :: Stable b => Box (b -> a -> b) -> b -> SigF a -> SigF b
+ WidgetRattus.Future: scanAwait :: Stable b => Box (b -> a -> b) -> b -> F (SigF a) -> F (SigF b)
+ WidgetRattus.Future: switch :: SigF a -> F (SigF a) -> SigF a
+ WidgetRattus.Future: switchAwait :: F (SigF a) -> F (SigF a) -> F (SigF a)
+ WidgetRattus.Future: switchS :: Stable a => SigF a -> F (a -> SigF a) -> SigF a
+ WidgetRattus.Future: sync :: O (F a) -> O (F b) -> O (F a :* F b)
+ WidgetRattus.Future: syncF :: (Stable a, Stable b) => F a -> F b -> F (a :* b)
+ WidgetRattus.Future: trigger :: Stable b => Box (a -> b -> c) -> SigF a -> SigF b -> SigF c
+ WidgetRattus.Future: triggerAwait :: Stable b => Box (a -> b -> c) -> F (SigF a) -> SigF b -> F (SigF c)
+ WidgetRattus.Future: zipWith :: (Stable a, Stable b) => Box (a -> b -> c) -> SigF a -> SigF b -> SigF c
+ WidgetRattus.Future: zipWithAwait :: (Stable a, Stable b) => Box (a -> b -> c) -> a -> b -> F (SigF a) -> F (SigF b) -> F (SigF c)
+ WidgetRattus.InternalPrimitives: Both :: !a -> !b -> Select a b
+ WidgetRattus.InternalPrimitives: Box :: a -> Box a
+ WidgetRattus.InternalPrimitives: Chan :: InputChannelIdentifier -> Chan a
+ WidgetRattus.InternalPrimitives: Delay :: !Clock -> (InputValue -> a) -> O a
+ WidgetRattus.InternalPrimitives: Fst :: !a -> !O b -> Select a b
+ WidgetRattus.InternalPrimitives: Snd :: !O a -> !b -> Select a b
+ WidgetRattus.InternalPrimitives: [ContinuousData] :: Continuous a => !Weak (IORef a) -> ContinuousData
+ WidgetRattus.InternalPrimitives: [MoreInputs] :: !InputChannelIdentifier -> !a -> !InputValue -> InputValue
+ WidgetRattus.InternalPrimitives: [OneInput] :: !InputChannelIdentifier -> !a -> InputValue
+ WidgetRattus.InternalPrimitives: adv :: O a -> a
+ WidgetRattus.InternalPrimitives: adv' :: O a -> InputValue -> a
+ WidgetRattus.InternalPrimitives: box :: a -> Box a
+ WidgetRattus.InternalPrimitives: channelMember :: InputChannelIdentifier -> Clock -> Bool
+ WidgetRattus.InternalPrimitives: class Continuous p
+ WidgetRattus.InternalPrimitives: class Stable a
+ WidgetRattus.InternalPrimitives: clockUnion :: Clock -> Clock -> Clock
+ WidgetRattus.InternalPrimitives: data Box a
+ WidgetRattus.InternalPrimitives: data ContinuousData
+ WidgetRattus.InternalPrimitives: data InputValue
+ WidgetRattus.InternalPrimitives: data O a
+ WidgetRattus.InternalPrimitives: data Select a b
+ WidgetRattus.InternalPrimitives: defaultPromote :: Continuous a => a -> Box a
+ WidgetRattus.InternalPrimitives: delay :: a -> O a
+ WidgetRattus.InternalPrimitives: emptyClock :: Clock
+ WidgetRattus.InternalPrimitives: extractClock :: O a -> Clock
+ WidgetRattus.InternalPrimitives: inputInClock :: InputValue -> Clock -> Bool
+ WidgetRattus.InternalPrimitives: instance WidgetRattus.InternalPrimitives.Stable a => WidgetRattus.InternalPrimitives.Continuous a
+ WidgetRattus.InternalPrimitives: never :: O a
+ WidgetRattus.InternalPrimitives: newtype Chan a
+ WidgetRattus.InternalPrimitives: nextProgress :: Continuous p => p -> Clock
+ WidgetRattus.InternalPrimitives: progressAndNext :: Continuous p => InputValue -> p -> (p, Clock)
+ WidgetRattus.InternalPrimitives: progressInternal :: Continuous p => InputValue -> p -> p
+ WidgetRattus.InternalPrimitives: progressPromoteStore :: InputValue -> IO ()
+ WidgetRattus.InternalPrimitives: progressPromoteStoreAtomic :: InputValue -> IO ()
+ WidgetRattus.InternalPrimitives: progressPromoteStoreMutex :: MVar ()
+ WidgetRattus.InternalPrimitives: promote :: Continuous a => a -> Box a
+ WidgetRattus.InternalPrimitives: promoteInternal :: Continuous p => p -> Box p
+ WidgetRattus.InternalPrimitives: promoteStore :: IORef [ContinuousData]
+ WidgetRattus.InternalPrimitives: rattusError :: [Char] -> a
+ WidgetRattus.InternalPrimitives: select :: O a -> O b -> Select a b
+ WidgetRattus.InternalPrimitives: select' :: O a -> O b -> InputValue -> Select a b
+ WidgetRattus.InternalPrimitives: singletonClock :: InputChannelIdentifier -> Clock
+ WidgetRattus.InternalPrimitives: type Clock = IntSet
+ WidgetRattus.InternalPrimitives: type InputChannelIdentifier = Int
+ WidgetRattus.InternalPrimitives: unbox :: Box a -> a
+ WidgetRattus.Plugin: AllowLazyData :: WidgetRattus
+ WidgetRattus.Plugin: AllowRecursion :: WidgetRattus
+ WidgetRattus.Plugin: data WidgetRattus
+ WidgetRattus.Plugin: plugin :: Plugin
+ WidgetRattus.Plugin.Annotation: AllowLazyData :: WidgetRattus
+ WidgetRattus.Plugin.Annotation: AllowRecursion :: WidgetRattus
+ WidgetRattus.Plugin.Annotation: ExpectError :: InternalAnn
+ WidgetRattus.Plugin.Annotation: ExpectWarning :: InternalAnn
+ WidgetRattus.Plugin.Annotation: data InternalAnn
+ WidgetRattus.Plugin.Annotation: data WidgetRattus
+ WidgetRattus.Plugin.Annotation: instance Data.Data.Data WidgetRattus.Plugin.Annotation.InternalAnn
+ WidgetRattus.Plugin.Annotation: instance Data.Data.Data WidgetRattus.Plugin.Annotation.WidgetRattus
+ WidgetRattus.Plugin.Annotation: instance GHC.Classes.Eq WidgetRattus.Plugin.Annotation.InternalAnn
+ WidgetRattus.Plugin.Annotation: instance GHC.Classes.Eq WidgetRattus.Plugin.Annotation.WidgetRattus
+ WidgetRattus.Plugin.Annotation: instance GHC.Classes.Ord WidgetRattus.Plugin.Annotation.InternalAnn
+ WidgetRattus.Plugin.Annotation: instance GHC.Classes.Ord WidgetRattus.Plugin.Annotation.WidgetRattus
+ WidgetRattus.Plugin.Annotation: instance GHC.Show.Show WidgetRattus.Plugin.Annotation.InternalAnn
+ WidgetRattus.Plugin.Annotation: instance GHC.Show.Show WidgetRattus.Plugin.Annotation.WidgetRattus
+ WidgetRattus.Primitives: Both :: !a -> !b -> Select a b
+ WidgetRattus.Primitives: Fst :: !a -> !O b -> Select a b
+ WidgetRattus.Primitives: Snd :: !O a -> !b -> Select a b
+ WidgetRattus.Primitives: adv :: O a -> a
+ WidgetRattus.Primitives: box :: a -> Box a
+ WidgetRattus.Primitives: class Continuous p
+ WidgetRattus.Primitives: class Stable a
+ WidgetRattus.Primitives: data Box a
+ WidgetRattus.Primitives: data O a
+ WidgetRattus.Primitives: data Select a b
+ WidgetRattus.Primitives: delay :: a -> O a
+ WidgetRattus.Primitives: never :: O a
+ WidgetRattus.Primitives: promote :: Continuous a => a -> Box a
+ WidgetRattus.Primitives: select :: O a -> O b -> Select a b
+ WidgetRattus.Primitives: unbox :: Box a -> a
+ WidgetRattus.Signal: (:::) :: !a -> !O (Sig a) -> Sig a
+ WidgetRattus.Signal: buffer :: Stable a => a -> Sig a -> Sig a
+ WidgetRattus.Signal: bufferAwait :: Stable a => a -> O (Sig a) -> O (Sig a)
+ WidgetRattus.Signal: cond :: Stable a => Sig Bool -> Sig a -> Sig a -> Sig a
+ WidgetRattus.Signal: const :: a -> Sig a
+ WidgetRattus.Signal: current :: Sig a -> a
+ WidgetRattus.Signal: data Sig a
+ WidgetRattus.Signal: derivative :: forall a v. (VectorSpace v a, Eq v, Fractional a, Stable v, Stable a) => Sig v -> Sig v
+ WidgetRattus.Signal: future :: Sig a -> O (Sig a)
+ WidgetRattus.Signal: infixr 5 :::
+ WidgetRattus.Signal: instance WidgetRattus.Channels.Producer (WidgetRattus.Signal.Sig a) a
+ WidgetRattus.Signal: instance WidgetRattus.Channels.Producer (WidgetRattus.Signal.SigMaybe a) a
+ WidgetRattus.Signal: instance WidgetRattus.InternalPrimitives.Continuous a => WidgetRattus.InternalPrimitives.Continuous (WidgetRattus.Signal.Sig a)
+ WidgetRattus.Signal: integral :: forall a v. (VectorSpace v a, Eq v, Fractional a, Stable v, Stable a) => v -> Sig v -> Sig v
+ WidgetRattus.Signal: interleave :: Box (a -> a -> a) -> O (Sig a) -> O (Sig a) -> O (Sig a)
+ WidgetRattus.Signal: interleaveAll :: Box (a -> a -> a) -> List (O (Sig a)) -> O (Sig a)
+ WidgetRattus.Signal: jump :: Box (a -> Maybe' (Sig a)) -> Sig a -> Sig a
+ WidgetRattus.Signal: jumping :: Box (a -> Maybe' (Sig a)) -> Sig a -> Sig a
+ WidgetRattus.Signal: map :: Box (a -> b) -> Sig a -> Sig b
+ WidgetRattus.Signal: mapAwait :: Box (a -> b) -> O (Sig a) -> O (Sig b)
+ WidgetRattus.Signal: mapInterleave :: Box (a -> a) -> Box (a -> a -> a) -> O (Sig a) -> O (Sig a) -> O (Sig a)
+ WidgetRattus.Signal: mkBoxSig :: Box (O a) -> Box (O (Sig a))
+ WidgetRattus.Signal: mkSig :: Box (O a) -> O (Sig a)
+ WidgetRattus.Signal: scan :: Stable b => Box (b -> a -> b) -> b -> Sig a -> Sig b
+ WidgetRattus.Signal: scanAwait :: Stable b => Box (b -> a -> b) -> b -> O (Sig a) -> Sig b
+ WidgetRattus.Signal: scanAwaitC :: Stable b => Box (b -> a -> C b) -> b -> O (Sig a) -> C (Sig b)
+ WidgetRattus.Signal: scanC :: Stable b => Box (b -> a -> C b) -> b -> Sig a -> C (Sig b)
+ WidgetRattus.Signal: scanMap :: Stable b => Box (b -> a -> b) -> Box (b -> c) -> b -> Sig a -> Sig c
+ WidgetRattus.Signal: stop :: Box (a -> Bool) -> Sig a -> Sig a
+ WidgetRattus.Signal: switch :: Sig a -> O (Sig a) -> Sig a
+ WidgetRattus.Signal: switchAwait :: O (Sig a) -> O (Sig a) -> O (Sig a)
+ WidgetRattus.Signal: switchR :: Stable a => Sig a -> O (Sig (a -> Sig a)) -> Sig a
+ WidgetRattus.Signal: switchS :: Stable a => Sig a -> O (a -> Sig a) -> Sig a
+ WidgetRattus.Signal: trigger :: (Stable b, Stable c) => Box (a -> b -> c) -> Sig a -> Sig b -> Sig c
+ WidgetRattus.Signal: triggerAwait :: (Stable b, Stable c) => Box (a -> b -> c) -> c -> O (Sig a) -> Sig b -> Sig c
+ WidgetRattus.Signal: triggerAwaitM :: Stable b => Box (a -> b -> Maybe' c) -> O (Sig a) -> Sig b -> O (Sig (Maybe' c))
+ WidgetRattus.Signal: triggerM :: Stable b => Box (a -> b -> Maybe' c) -> Sig a -> Sig b -> Sig (Maybe' c)
+ WidgetRattus.Signal: update :: Stable a => Sig a -> O (Sig (a -> a)) -> Sig a
+ WidgetRattus.Signal: zip :: (Stable a, Stable b) => Sig a -> Sig b -> Sig (a :* b)
+ WidgetRattus.Signal: zipWith :: (Stable a, Stable b) => Box (a -> b -> c) -> Sig a -> Sig b -> Sig c
+ WidgetRattus.Signal: zipWith3 :: forall a b c d. (Stable a, Stable b, Stable c) => Box (a -> b -> c -> d) -> Sig a -> Sig b -> Sig c -> Sig d
+ WidgetRattus.Strict: (+++) :: List a -> List a -> List a
+ WidgetRattus.Strict: (:!) :: !a -> !List a -> List a
+ WidgetRattus.Strict: (:*) :: !a -> !b -> (:*) a b
+ WidgetRattus.Strict: -- structure <tt>l</tt>.
+ WidgetRattus.Strict: -- | The <a>Item</a> type function returns the type of items of the
+ WidgetRattus.Strict: Just' :: !a -> Maybe' a
+ WidgetRattus.Strict: Nil :: List a
+ WidgetRattus.Strict: Nothing' :: Maybe' a
+ WidgetRattus.Strict: class () => IsList l where {
+ WidgetRattus.Strict: concatMap' :: (a -> List b) -> List a -> List b
+ WidgetRattus.Strict: curry' :: ((a :* b) -> c) -> a -> b -> c
+ WidgetRattus.Strict: data List a
+ WidgetRattus.Strict: data Maybe' a
+ WidgetRattus.Strict: data a :* b
+ WidgetRattus.Strict: delete' :: Eq a => a -> List a -> List a
+ WidgetRattus.Strict: deleteBy' :: (a -> a -> Bool) -> a -> List a -> List a
+ WidgetRattus.Strict: filter' :: (a -> Bool) -> List a -> List a
+ WidgetRattus.Strict: fromList :: IsList l => [Item l] -> l
+ WidgetRattus.Strict: fromListN :: IsList l => Int -> [Item l] -> l
+ WidgetRattus.Strict: fromMaybe' :: a -> Maybe' a -> a
+ WidgetRattus.Strict: fst' :: (a :* b) -> a
+ WidgetRattus.Strict: infixr 2 :*
+ WidgetRattus.Strict: infixr 8 :!
+ WidgetRattus.Strict: init' :: List a -> List a
+ WidgetRattus.Strict: instance (Data.VectorSpace.VectorSpace v a, Data.VectorSpace.VectorSpace w a, GHC.Float.Floating a, GHC.Classes.Eq a) => Data.VectorSpace.VectorSpace (v WidgetRattus.Strict.:* w) a
+ WidgetRattus.Strict: instance (GHC.Classes.Eq a, GHC.Classes.Eq b) => GHC.Classes.Eq (a WidgetRattus.Strict.:* b)
+ WidgetRattus.Strict: instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (a WidgetRattus.Strict.:* b)
+ WidgetRattus.Strict: instance (WidgetRattus.InternalPrimitives.Continuous a, WidgetRattus.InternalPrimitives.Continuous b) => WidgetRattus.InternalPrimitives.Continuous (a WidgetRattus.Strict.:* b)
+ WidgetRattus.Strict: instance Data.Foldable.Foldable WidgetRattus.Strict.List
+ WidgetRattus.Strict: instance Data.Traversable.Traversable WidgetRattus.Strict.List
+ WidgetRattus.Strict: instance GHC.Base.Functor ((WidgetRattus.Strict.:*) a)
+ WidgetRattus.Strict: instance GHC.Base.Functor WidgetRattus.Strict.List
+ WidgetRattus.Strict: instance GHC.Classes.Eq a => GHC.Classes.Eq (WidgetRattus.Strict.List a)
+ WidgetRattus.Strict: instance GHC.Classes.Eq a => GHC.Classes.Eq (WidgetRattus.Strict.Maybe' a)
+ WidgetRattus.Strict: instance GHC.Classes.Ord a => GHC.Classes.Ord (WidgetRattus.Strict.Maybe' a)
+ WidgetRattus.Strict: instance GHC.IsList.IsList (WidgetRattus.Strict.List a)
+ WidgetRattus.Strict: instance GHC.Show.Show a => GHC.Show.Show (WidgetRattus.Strict.List a)
+ WidgetRattus.Strict: instance GHC.Show.Show a => GHC.Show.Show (WidgetRattus.Strict.Maybe' a)
+ WidgetRattus.Strict: instance WidgetRattus.InternalPrimitives.Continuous a => WidgetRattus.InternalPrimitives.Continuous (WidgetRattus.Strict.List a)
+ WidgetRattus.Strict: instance WidgetRattus.InternalPrimitives.Continuous a => WidgetRattus.InternalPrimitives.Continuous (WidgetRattus.Strict.Maybe' a)
+ WidgetRattus.Strict: isJust' :: Maybe' a -> Bool
+ WidgetRattus.Strict: listToMaybe' :: List a -> Maybe' a
+ WidgetRattus.Strict: map' :: (a -> b) -> List a -> List b
+ WidgetRattus.Strict: mapMaybe' :: (a -> Maybe' b) -> List a -> List b
+ WidgetRattus.Strict: maybe' :: b -> (a -> b) -> Maybe' a -> b
+ WidgetRattus.Strict: nub' :: Eq a => List a -> List a
+ WidgetRattus.Strict: nubBy' :: (a -> a -> Bool) -> List a -> List a
+ WidgetRattus.Strict: readMaybe' :: Read a => Text -> Maybe' a
+ WidgetRattus.Strict: reverse' :: List a -> List a
+ WidgetRattus.Strict: singleton :: a -> List a
+ WidgetRattus.Strict: snd' :: (a :* b) -> b
+ WidgetRattus.Strict: splitOn' :: Text -> Text -> List Text
+ WidgetRattus.Strict: toList :: IsList l => l -> [Item l]
+ WidgetRattus.Strict: toText :: Show a => a -> Text
+ WidgetRattus.Strict: type family Item l;
+ WidgetRattus.Strict: uncurry' :: (a -> b -> c) -> (a :* b) -> c
+ WidgetRattus.Strict: union' :: Eq a => List a -> List a -> List a
+ WidgetRattus.Strict: unionBy' :: (a -> a -> Bool) -> List a -> List a -> List a
+ WidgetRattus.Strict: zip' :: List a -> List b -> List (a :* b)
+ WidgetRattus.Strict: zipWith' :: (a -> b -> c) -> List a -> List b -> List c
+ WidgetRattus.Strict: }
+ WidgetRattus.Widgets: addInputSigTF :: TextField -> O (Sig Text) -> TextField
+ WidgetRattus.Widgets: btnClick :: Button -> Chan ()
+ WidgetRattus.Widgets: btnContent :: Button -> Sig a
+ WidgetRattus.Widgets: btnOnClick :: Button -> Box (O ())
+ WidgetRattus.Widgets: btnOnClickSig :: Button -> O (Sig ())
+ WidgetRattus.Widgets: class Stable a => Displayable a
+ WidgetRattus.Widgets: class Continuous a => IsWidget a
+ WidgetRattus.Widgets: class Widgets ws
+ WidgetRattus.Widgets: data Button
+ WidgetRattus.Widgets: data HStack
+ WidgetRattus.Widgets: data Label
+ WidgetRattus.Widgets: data Popup
+ WidgetRattus.Widgets: data Slider
+ WidgetRattus.Widgets: data TextDropdown
+ WidgetRattus.Widgets: data TextField
+ WidgetRattus.Widgets: data VStack
+ WidgetRattus.Widgets: data Widget
+ WidgetRattus.Widgets: display :: Displayable a => a -> Text
+ WidgetRattus.Widgets: instance (WidgetRattus.Widgets.Widgets w, WidgetRattus.Widgets.Widgets v) => WidgetRattus.Widgets.Widgets (w WidgetRattus.Strict.:* v)
+ WidgetRattus.Widgets: instance WidgetRattus.Widgets.InternalTypes.Displayable Data.Text.Internal.Text
+ WidgetRattus.Widgets: instance WidgetRattus.Widgets.InternalTypes.Displayable GHC.Types.Int
+ WidgetRattus.Widgets: instance WidgetRattus.Widgets.InternalTypes.IsWidget w => WidgetRattus.Widgets.Widgets w
+ WidgetRattus.Widgets: instance WidgetRattus.Widgets.Widgets w => WidgetRattus.Widgets.Widgets (WidgetRattus.Strict.List w)
+ WidgetRattus.Widgets: labText :: Label -> Sig a
+ WidgetRattus.Widgets: mkButton :: Displayable a => Sig a -> C Button
+ WidgetRattus.Widgets: mkConstHStack :: Widgets ws => ws -> C HStack
+ WidgetRattus.Widgets: mkConstVStack :: Widgets ws => ws -> C VStack
+ WidgetRattus.Widgets: mkHStack :: IsWidget a => Sig (List a) -> C HStack
+ WidgetRattus.Widgets: mkLabel :: Displayable a => Sig a -> C Label
+ WidgetRattus.Widgets: mkPopup :: Sig Bool -> Sig Widget -> C Popup
+ WidgetRattus.Widgets: mkProgressBar :: Sig Int -> Sig Int -> Sig Int -> C Slider
+ WidgetRattus.Widgets: mkSlider :: Int -> Sig Int -> Sig Int -> C Slider
+ WidgetRattus.Widgets: mkTextDropdown :: Sig (List Text) -> Text -> C TextDropdown
+ WidgetRattus.Widgets: mkTextField :: Text -> C TextField
+ WidgetRattus.Widgets: mkVStack :: IsWidget a => Sig (List a) -> C VStack
+ WidgetRattus.Widgets: mkWidget :: IsWidget a => a -> Widget
+ WidgetRattus.Widgets: mkWidgetNode :: IsWidget a => a -> WidgetNode AppModel AppEvent
+ WidgetRattus.Widgets: popChild :: Popup -> Sig Widget
+ WidgetRattus.Widgets: popCurr :: Popup -> Sig Bool
+ WidgetRattus.Widgets: popEvent :: Popup -> Chan Bool
+ WidgetRattus.Widgets: runApplication :: IsWidget a => C a -> IO ()
+ WidgetRattus.Widgets: setEnabled :: IsWidget a => a -> Sig Bool -> Widget
+ WidgetRattus.Widgets: setInputSigTF :: TextField -> Sig Text -> TextField
+ WidgetRattus.Widgets: sldCurr :: Slider -> Sig Int
+ WidgetRattus.Widgets: sldEvent :: Slider -> Chan Int
+ WidgetRattus.Widgets: sldMax :: Slider -> Sig Int
+ WidgetRattus.Widgets: sldMin :: Slider -> Sig Int
+ WidgetRattus.Widgets: tddCurr :: TextDropdown -> Sig Text
+ WidgetRattus.Widgets: tddEvent :: TextDropdown -> Chan Text
+ WidgetRattus.Widgets: tddList :: TextDropdown -> Sig (List Text)
+ WidgetRattus.Widgets: textFieldOnInput :: TextField -> Box (O Text)
+ WidgetRattus.Widgets: textFieldOnInputSig :: TextField -> O (Sig Text)
+ WidgetRattus.Widgets: tfContent :: TextField -> Sig Text
+ WidgetRattus.Widgets: tfInput :: TextField -> Chan Text
+ WidgetRattus.Widgets: toWidgetList :: Widgets ws => ws -> List Widget

Files

CHANGELOG.md view
@@ -1,3 +1,8 @@+# 0.3++- Include the Widgets library.+- Replace module names from AsyncRattus to WidgetRattus+ # 0.2  Extend continuous types so that they can track their channel
WidgetRattus.cabal view
@@ -1,27 +1,37 @@ cabal-version:       1.18 name:                WidgetRattus-version:             0.2+version:             0.3 category:            FRP-synopsis:            An asynchronous modal FRP language+synopsis:            An asynchronous modal FRP language for GUI programming description:              This library implements an experimental variant of the Async Rattus             programming language that features extensions for implementing GUIs.+            A comprehensive introduction can be found in this +            <src/docs/paper.pdf paper>.++            .++            Several example GUIs implemented using Widget Rattus can be found+            <https://github.com/pa-ba/AsyncRattus/tree/WidgetRattus/examples/gui here>.               -homepage:            https://github.com/pa-ba/AsyncRattus/+homepage:            https://github.com/pa-ba/AsyncRattus/tree/WidgetRattus bug-reports:         https://github.com/pa-ba/AsyncRattus/issues License:             BSD3 License-file:        LICENSE-copyright:           Copyright (C) 2023 Emil Houlborg, Gregers Rørdam, Patrick Bahr-Author:              Emil Houlborg, Gregers Rørdam, Patrick Bahr+copyright:           Copyright (C) 2024 Emil Houlborg, Gregers Rørdam, Patrick Bahr, Jean-Claude Sebastian Disch, Asger Lademark Heegaard+Author:              Emil Houlborg, Gregers Rørdam, Patrick Bahr, Jean-Claude Sebastian Disch, Asger Lademark Heegaard maintainer:          Patrick Bahr <paba@itu.dk> stability:           experimental  build-type:          Custom  extra-source-files:  CHANGELOG.md+                     examples/gui/src/*.hs+extra-doc-files:     docs/paper.pdf+                       custom-setup   setup-depends:@@ -30,34 +40,38 @@   library-  exposed-modules:     AsyncRattus-                       AsyncRattus.Signal-                       AsyncRattus.Future-                       AsyncRattus.Strict-                       AsyncRattus.Plugin-                       AsyncRattus.Primitives-                       AsyncRattus.InternalPrimitives-                       AsyncRattus.Channels-                       AsyncRattus.Plugin.Annotation+  exposed-modules:     WidgetRattus+                       WidgetRattus.Signal+                       WidgetRattus.Future+                       WidgetRattus.Strict+                       WidgetRattus.Plugin+                       WidgetRattus.Primitives+                       WidgetRattus.InternalPrimitives+                       WidgetRattus.Channels+                       WidgetRattus.Plugin.Annotation+                       WidgetRattus.Widgets                                               -  other-modules:       AsyncRattus.Plugin.ScopeCheck-                       AsyncRattus.Plugin.SingleTick-                       AsyncRattus.Plugin.CheckClockCompatibility-                       AsyncRattus.Plugin.Strictify-                       AsyncRattus.Plugin.Utils-                       AsyncRattus.Plugin.Dependency-                       AsyncRattus.Plugin.StableSolver-                       AsyncRattus.Plugin.Transform-                       AsyncRattus.Plugin.PrimExpr-                       AsyncRattus.Derive+  other-modules:       WidgetRattus.Plugin.ScopeCheck+                       WidgetRattus.Plugin.SingleTick+                       WidgetRattus.Plugin.CheckClockCompatibility+                       WidgetRattus.Plugin.Strictify+                       WidgetRattus.Plugin.Utils+                       WidgetRattus.Plugin.Dependency+                       WidgetRattus.Plugin.StableSolver+                       WidgetRattus.Plugin.Transform+                       WidgetRattus.Plugin.PrimExpr+                       WidgetRattus.Widgets.InternalTypes+                       WidgetRattus.Derive   build-depends:       base >=4.16 && <5,                        containers >= 0.6.5 && < 0.8,-                       ghc >= 9.2 && < 9.9,-                       ghc-boot >= 9.2 && < 9.9,+                       ghc >= 9.2 && < 9.7,+                       ghc-boot >= 9.2 && < 9.7,                        hashtables >= 1.3.1 && < 1.4,                        simple-affine-space >= 0.2.1 && < 0.3,                        transformers >= 0.5.6 && < 0.7,-                       template-haskell >= 2.17 && < 2.22+                       template-haskell >= 2.17 && < 2.23,+                       text >= 1.2 && < 3,+                       monomer >= 1.4 && < 2   hs-source-dirs:      src   default-language:    Haskell2010   ghc-options:         -W@@ -69,7 +83,7 @@   main-is:             test/IllTyped.hs   default-language:    Haskell2010   build-depends:       WidgetRattus, base-  ghc-options:         -fplugin=AsyncRattus.Plugin+  ghc-options:         -fplugin=WidgetRattus.Plugin   Test-Suite well-typed@@ -78,5 +92,5 @@   hs-source-dirs:      test   default-language:    Haskell2010   build-depends:       WidgetRattus, base, containers, text-  ghc-options:         -fplugin=AsyncRattus.Plugin+  ghc-options:         -fplugin=WidgetRattus.Plugin 
+ docs/paper.pdf view

binary file changed (absent → 592894 bytes)

+ examples/gui/src/Calculator.hs view
@@ -0,0 +1,99 @@+{-# OPTIONS -fplugin=WidgetRattus.Plugin #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators #-}++import WidgetRattus+import WidgetRattus.Signal+import WidgetRattus.Widgets+import Prelude hiding (map, const, zipWith, zip, filter, getLine, putStrLn,null)+import Data.Text (Text)++nums :: List Int+nums = [0..9]++data Op = Plus | Minus | Equals | Reset++compute :: (Int :* Op :* Bool -> Maybe' (Int :* Op) -> Int :* Op :* Bool)+compute (n :* op     :* _) Nothing'          = (n :* op :* False)+compute _                  (Just' (_ :* Reset)) = (0 :* Reset :* True)+compute (n :* Plus   :* _) (Just' (m :* op)) = (n + m) :* op :* True+compute (n :* Minus  :* _) (Just' (m :* op)) = (n - m) :* op :* True+compute (_ :* Equals :* _) (Just' (m :* op)) = m :* op :* True+compute (_ :* Reset  :* _) (Just' (m :* op)) = m :* op :* True+++window :: C VStack+window = do++    -- construct number buttons+    numBtns :: List Button  +        <- mapM (mkButton . const) nums+    let [b0, b1, b2, b3, b4, b5, b6, b7, b8, b9] = numBtns+    -- construct operator buttons+    resetBut <- mkButton (const ("C"::Text))+    addBut   <- mkButton (const ("+"::Text))+    subBut   <- mkButton (const ("-"::Text))+    eqBut    <- mkButton (const ("="::Text))++    -- signal to construct numbers+    let numClicks :: List (O (Sig (Int -> Int))) +          = zipWith' (\b n -> mapAwait (box (\ _ x -> x * 10 + n)) (btnOnClickSig b)) numBtns nums+          +++    -- signal to reset the current number to 0, after clicking an+    -- operator button+    let resetSig :: O (Sig (Int -> Int))+          = mapAwait (box (\ _ _ -> 0))+            $ interleaveAll (box (\ a _ -> a))+            $ map' btnOnClickSig [addBut, subBut, eqBut,resetBut]++    -- combine signals to construct the number signal+    let sigList = resetSig :! numClicks :: List (O (Sig (Int -> Int)))+    let combinedSig = interleaveAll (box (\ a _ -> a)) sigList++    -- number signal (i.e. the multidigit number that has been+    -- constructed)+    let numberSig :: Sig Int+         = scanAwait (box (\ a f-> f a)) 0 combinedSig+    -- operator signal+    let opSig :: O (Sig Op)+         = interleaveAll (box (\ a _ -> a))+          $ map' (\ (op :* btn) -> mapAwait (box (\ _ -> op)) (btnOnClickSig btn) )+            [(Plus :* addBut), (Minus :* subBut), (Equals :* eqBut), (Reset :* resetBut)]++    -- signal consisting of an operand (i.e. a number) @n@ and an+    -- operator @op@. @n@ is the value of @numberSig@ just before+    -- clicking an operator button, and op is taken from opSig+    let operand :: Sig (Maybe' (Int :* Op))+         = Nothing' ::: triggerAwaitM (box (\op n -> Just' (n :* op))) opSig (buffer 0 numberSig)++    -- The result signal consisting of a number n that is the result+    -- of the current computation, an operator op that still needs to+    -- applied to n and a Boolean b that indicates whether we have+    -- just calculated n (and thus n should be displayed)+    let resSig :: Sig (Int :* Op :* Bool)+         = scan (box compute) (0 :* Plus :* True) operand+    -- The signal that should be displayed+    let displaySig :: Sig Int+         = zipWith (box (\ (n :* _ :* b) m -> if b then n else m)) resSig numberSig+    +    -- label to display the result (and operands)+    result <- mkLabel displaySig+    +    -- lay out widgets+    operators <- mkConstVStack (resetBut :* addBut :* subBut :* eqBut)+    row1 <- mkConstHStack (b7 :* b8 :* b9)+    row2 <- mkConstHStack (b4 :* b5 :* b6)+    row3 <- mkConstHStack (b1 :* b2 :* b3)++    numbers <- mkConstVStack (row1 :* row2 :* row3 :* b0)++    input <- mkConstHStack (numbers :* operators)++    mkConstVStack (result :* input)++main :: IO ()+main = runApplication window
+ examples/gui/src/Counter.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedLists #-}+{-# OPTIONS -fplugin=WidgetRattus.Plugin #-}+{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}+{-# HLINT ignore "Evaluate" #-}+{-# HLINT ignore "Use const" #-}+{-# LANGUAGE ScopedTypeVariables #-}++import WidgetRattus+import WidgetRattus.Signal+import WidgetRattus.Widgets++import Prelude hiding (map, const, zipWith, zip, filter, getLine, putStrLn,null)+import Data.Text hiding (filter, map, all)++window :: C VStack+window = do +    btn <- mkButton (const ("Increment" :: Text))+    let sig = btnOnClickSig btn+    let sig' = scanAwait (box (\ n _ -> n+1 :: Int)) 0 sig +    lbl <- mkLabel sig'+    mkConstVStack (lbl :* btn)+    ++main :: IO ()+main = runApplication window
+ examples/gui/src/FlightBooker.hs view
@@ -0,0 +1,88 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedLists #-}+{-# OPTIONS -fplugin=WidgetRattus.Plugin #-}+{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}+{-# HLINT ignore "Evaluate" #-}+{-# HLINT ignore "Use const" #-}++import WidgetRattus+import WidgetRattus.Signal+import WidgetRattus.Widgets+import Prelude hiding (map, const, zipWith, zipWith3, zip, filter, getLine, putStrLn,null)+import Data.Text (Text)++-- Benchmark 3+isDate :: Text -> Bool+isDate txt = case splitOn' "-" txt of+  [dayStr, monthStr, yearStr] ->+    let day = readMaybe' dayStr+        month = readMaybe' monthStr+        year = readMaybe' yearStr+    in isValid day month year+  _ -> False+  where+    isValid :: Maybe' Int -> Maybe' Int -> Maybe' Int -> Bool+    isValid (Just' d) (Just' m) (Just' y)+      | m < 1 || m > 12 = False+      | d < 1 || d > daysInMonth m y = False+      | otherwise = True+    isValid _ _ _ = False++    daysInMonth :: Int -> Int -> Int+    daysInMonth m y+        | m `elem` ([4, 6, 9, 11] :: List Int) = 30+        | m == 2 = if isLeapYear y then 29 else 28+        | otherwise = 31++    isLeapYear :: Int -> Bool+    isLeapYear y = y `mod` 4 == 0 && (y `mod` 100 /= 0 || y `mod` 400 == 0)++isLater :: Text -> Text -> Bool+isLater dep ret = case (splitOn' "-" dep, splitOn' "-" ret) of+  ([depDayStr, depMonthStr, depYearStr], [retDayStr, retMonthStr, retYearStr]) ->+    let depDay = readMaybe' depDayStr+        depMonth = readMaybe' depMonthStr+        depYear = readMaybe' depYearStr+        retDay = readMaybe' retDayStr+        retMonth = readMaybe' retMonthStr+        retYear = readMaybe' retYearStr+    in all isJust' ([depDay, depMonth, depYear, retDay, retMonth, retYear] :: List (Maybe' Int)) &&+       (depYear < retYear ||+       (depYear == retYear && (depMonth < retMonth ||+       (depMonth == retMonth && depDay < retDay))))+  _ -> False++bookingToText :: Bool -> Text -> Text -> Text+bookingToText oneWay dep ret =+  "You have booked a " <> if oneWay then "one-way flight on " <> dep+  else "return flight from " <> dep <> " to " <> ret++window :: C VStack+window = do+    dropDown <- mkTextDropdown (const ["One-Way", "Return-Flight"]) "One-Way"+    tf1 <- mkTextField "01-01-2021"+    tf2 <- mkTextField "01-02-2021"+    button <- mkButton (const  ("Book" :: Text))++    let isRF = map (box (== "Return-Flight")) (tddCurr dropDown)+    let isOW = map (box (== "One-Way")) (tddCurr dropDown)+    +    let labelSig = zipWith3 (box bookingToText) isOW (tfContent tf1) (tfContent tf2)++    let sig = scanAwait (box (\ _ _ -> True )) False (btnOnClickSig button)++    label <- mkLabel labelSig+    +    popup <- mkPopup sig (const (mkWidget label))++    let tf1IsDate = map (box isDate) (tfContent tf1)+    let tf1IsLater = zipWith (box isLater) (tfContent tf1) (tfContent tf2)++    let oneWayAndDate = zipWith (box (&&)) isOW tf1IsDate+    let returnFlightAndIsLater = zipWith (box (&&)) isRF tf1IsLater+    let validBooking = zipWith (box (||)) oneWayAndDate returnFlightAndIsLater++    mkConstVStack (popup :* dropDown :* tf1 :* setEnabled tf2 isRF :* setEnabled button validBooking)++main :: IO ()+main = runApplication window
+ examples/gui/src/TemperatureConverter.hs view
@@ -0,0 +1,50 @@+{-# OPTIONS -fplugin=WidgetRattus.Plugin #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedLists #-}+{-# OPTIONS -fplugin=WidgetRattus.Plugin #-}+{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}+{-# HLINT ignore "Evaluate" #-}+{-# HLINT ignore "Use const" #-}+++import WidgetRattus+import WidgetRattus.Signal+import WidgetRattus.Widgets+import Prelude hiding (map, const, zipWith, zip, filter, getLine, putStrLn,null)+import Data.Text hiding (filter, map, all)+import Data.Text.Read++-- Benchmark 2+celsiusToFahrenheit :: Text -> Text+celsiusToFahrenheit t =+        case signed decimal t of+            Right (t', _) -> toText (t' * 9 `div` 5 + 32)+            Left _ -> "Invalid input"++fahrenheitToCelsius :: Text -> Text+fahrenheitToCelsius t =+    case signed decimal t of+        Right (t', _) -> toText ((t' - 32) * 5 `div` 9)+        Left _ -> "Invalid input"++window :: C HStack+window = do+    tfF1 <- mkTextField "32"+    tfC1 <- mkTextField "0"++    let convertFtoC = map (box fahrenheitToCelsius) (tfContent tfF1)+    let convertCtoF = map (box celsiusToFahrenheit) (tfContent tfC1)++    let tfF2 = addInputSigTF tfF1 (future convertCtoF)+    let tfC2 = addInputSigTF tfC1 (future convertFtoC)++    fLabel <- mkLabel (const ("Fahrenheit" :: Text))+    cLabel <- mkLabel (const ("Celsius" :: Text))++    fStack <- mkConstVStack (tfF2 :* fLabel)+    cStack <- mkConstVStack (tfC2 :* cLabel)  +    mkConstHStack (fStack :* cStack)+ ++main :: IO ()+main = runApplication window
+ examples/gui/src/Timer.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedLists #-}+{-# OPTIONS -fplugin=WidgetRattus.Plugin #-}++{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ScopedTypeVariables #-}+++import WidgetRattus+import WidgetRattus.Signal+import WidgetRattus.Widgets+import Prelude hiding (map, const, zipWith, zip, filter, getLine, putStrLn,null)+import Data.Text hiding (filter, map, all)+++everySecond :: Box (O())+everySecond = timer 1000000++everySecondSig :: O (Sig ())+everySecondSig = mkSig everySecond++nats :: (Int :* Int) -> Sig (Int :* Int)+nats (n :* max) = stop +    (box (\ (n :* max) -> n >= max)) +    (scanAwait (box (\ (n :* max) _ -> (n + 1) :* max)) (n :* max) everySecondSig)+++reset :: (Int :* Int) -> (Int :* Int)+reset (_ :* max) = (0 :* max)++setMax :: Int -> (Int :* Int) -> (Int :* Int)+setMax max' (n :* _) = ((min n max') :* max')++window :: C VStack+window = do+    slider <- mkSlider 50 (const 1) (const 100)+    resetBtn <- mkButton (const ("Reset" :: Text))++    let resSig :: O (Sig ()) +         = mkSig (btnOnClick resetBtn)+    let resetSig :: O (Sig (Int :* Int -> Int :* Int))+         = mapAwait (box (\ _ -> reset)) resSig++    let currentMax :: Int+         = current (sldCurr slider)+    let setMaxSig :: O (Sig (Int :* Int -> Int :* Int)) +         = mapAwait (box setMax) (future (sldCurr slider))+ +    let inputSig :: O (Sig (Int :* Int -> Int :* Int))+         = interleave (box (.)) resetSig setMaxSig++    let inputSig' :: O (Sig (Int :* Int -> Sig (Int :* Int)))+         = mapAwait (box (nats .)) inputSig++    let counterSig :: Sig (Int :* Int)+         = switchR (nats (0 :* currentMax)) inputSig'+    +    let currentSig = map (box fst') counterSig+    let maxSig = map (box snd') counterSig++    label <- mkLabel currentSig+    pb <- mkProgressBar (const 0) maxSig currentSig++    mkConstVStack (slider :* resetBtn :* label :* pb)++main :: IO ()+main = runApplication window
− src/AsyncRattus.hs
@@ -1,27 +0,0 @@-{-# OPTIONS -fplugin=AsyncRattus.Plugin #-}----- | The bare-bones Asynchronous Rattus language. To program with streams,--- you can use "AsyncRattus.Stream".--module AsyncRattus (-  -- * Asynchronous Rattus language primitives-  module AsyncRattus.Primitives,-  -- * Strict data types-  module AsyncRattus.Strict,-  -- * Derive class instance declarations-  module AsyncRattus.Derive,-  -- * Annotation-  AsyncRattus(..),-  -- * other-  mapO-  )-  where--import AsyncRattus.Plugin-import AsyncRattus.Strict-import AsyncRattus.Primitives-import AsyncRattus.Derive--mapO :: Box (a -> b) -> O a -> O b-mapO f later = delay (unbox f (adv later))
− src/AsyncRattus/Channels.hs
@@ -1,211 +0,0 @@-{-# OPTIONS -fplugin=AsyncRattus.Plugin #-}--{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}---- | This module is meant for library authors that want to build APIs--- for interacting with asynchronous resources, e.g. a GUI framework. --module AsyncRattus.Channels (-  getInput,-  setOutput,-  mkInput,-  startEventLoop,-  timer,-  Producer (..),-  chan,-  C (..),-  delayC,-  wait,-  Chan-) where-import AsyncRattus.InternalPrimitives--import AsyncRattus.Plugin.Annotation-import AsyncRattus.Strict-import Control.Monad-import System.IO.Unsafe-import Data.IORef-import Unsafe.Coerce-import qualified Data.HashTable.IO as H-import Data.HashTable.IO (BasicHashTable)-import qualified Data.IntSet as IntSet-import Control.Concurrent hiding (Chan)---- | A type @p@ satisfying @Producer p a@ is essentially a signal that--- produces values of type @a@ but it might not produce such values at--- each tick.-class Producer p a | p -> a where-  -- | Get the current value of the producer if any.-  getCurrent :: p -> Maybe' a-  -- | Get the next state of the producer. Morally, the type of this-  -- method should be-  ---  -- > getNext :: p -> (exists q. Producer q a => O q)-  ---  -- We encode the existential type using continuation-passing style.-  getNext :: p -> (forall q. Producer q a => O q -> b) -> b--instance Producer p a => Producer (O p) a where-  getCurrent _ = Nothing'-  getNext p cb = cb p--instance Producer p a => Producer (Box p) a where-  getCurrent p = getCurrent (unbox p)-  getNext p cb = getNext (unbox p) cb--newtype C a = C {unC :: IO a} deriving (Functor, Applicative, Monad)--chan :: C (Chan a)-chan = C (Chan <$> atomicModifyIORef nextFreshChannel (\ x -> (x - 1, x)))--delayC :: O (C a) -> C (O a)-delayC d = return (delay (unsafePerformIO (unC (adv d))))--{-# ANN wait AllowRecursion #-}-wait :: Chan a -> O a-wait (Chan ch) = Delay (singletonClock ch) (lookupInp ch) --{-# NOINLINE nextFreshChannel #-}-nextFreshChannel :: IORef InputChannelIdentifier-nextFreshChannel = unsafePerformIO (newIORef (-1))---{-# NOINLINE inputValue #-}-inputValue :: MVar (Maybe' InputValue)-inputValue = unsafePerformIO (newMVar Nothing')--{-# NOINLINE inputSem #-}-inputSem :: MVar ()-inputSem = unsafePerformIO newEmptyMVar--data OutputChannel where-  OutputChannel :: Producer p a => !(O p) -> !(a -> IO ()) -> OutputChannel---{-# NOINLINE output #-}-output :: BasicHashTable InputChannelIdentifier (List (IORef (Maybe' OutputChannel)))-output = unsafePerformIO (H.new)--{-# NOINLINE eventLoopStarted #-}-eventLoopStarted :: IORef Bool-eventLoopStarted = unsafePerformIO (newIORef False)----- | This function can be used to implement input signals. It returns--- a boxed delayed computation @s@ and a callback function @cb@. The--- signal @mkSig s@ will produce a new value @v@ whenever the callback--- function @cb@ is called with argument @v@.-getInput :: IO (Box (O a) :* (a -> IO ()))-getInput = do ch <- atomicModifyIORef nextFreshChannel (\ x -> (x - 1, x))-              return ((box (Delay (singletonClock ch) (lookupInp ch)))-                       :* \ x -> newInput ch x)---newInput :: InputChannelIdentifier -> a -> IO ()-newInput ch x = do iv <- takeMVar inputValue-                   case iv of -                    Nothing' -> putMVar inputValue (Just' (OneInput ch x)) >> putMVar inputSem ()-                    Just' more -> putMVar inputValue (Just' (MoreInputs ch x more))--{-# ANN lookupInp AllowRecursion #-}-lookupInp :: InputChannelIdentifier -> InputValue -> a-lookupInp _ (OneInput _ v) = unsafeCoerce v-lookupInp ch (MoreInputs ch' v more) = if ch' == ch then unsafeCoerce v else lookupInp ch more--{-# ANN setOutput' AllowLazyData #-}-setOutput' :: Producer p a => (a -> IO ()) -> O p -> IO ()-setOutput' cb !sig = do-  ref <- newIORef (Just' (OutputChannel sig cb))-  let upd Nothing = (Just (ref :! Nil),())-      upd (Just ls) = (Just (ref :! ls),())-  let upd' ch Nothing = do-        forkIO (threadDelay ch >> newInput ch ())-        return (Just (ref :! Nil),())-      upd' _ (Just ls) = return (Just (ref :! ls),())-  let run pre ch =-        if ch > 0 then-          pre >> H.mutateIO output ch (upd' ch)-        else -          pre >> H.mutate output ch upd-  IntSet.foldl' run (return ()) (extractClock sig)----- | This function can be used to produces outputs. Given a signal @s@--- and function @f@, the call @setOutput s f@ registers @f@ as a--- callback function that is called with argument @v@ whenever the--- signal produces a new value @v@. For this function to work,--- 'startEventLoop' must be called.-setOutput :: Producer p a => p -> (a -> IO ()) -> IO ()-setOutput !sig cb = do-  case getCurrent sig of-    Just' cur' -> cb cur'-    Nothing' -> return ()-  getNext sig (setOutput' cb)---- | This function is essentially the composition of 'getInput' and--- 'setOutput'. It turns any producer into a signal.-mkInput :: Producer p a => p -> IO (Box (O a))-mkInput p = do (out :* cb) <- getInput-               setOutput p cb-               return out---- | @timer n@ produces a delayed computation that ticks every @n@--- milliseconds. In particular @mkSig (timer n)@ is a signal that--- produces a new value every #n# milliseconds.-timer :: Int -> Box (O ())-timer d = Box (Delay (singletonClock (d `max` 10)) (\ _ -> ()))---update :: InputValue -> IORef (Maybe' OutputChannel) -> IO ()-update inp ref = do-  mout <- readIORef ref-  case mout of-    Nothing' -> return ()-    Just' (OutputChannel (Delay _ sigf) cb) -> do-      writeIORef ref Nothing'-      let new = sigf inp-      case getCurrent new of-        Just' w' -> cb w'-        Nothing' -> return ()-      getNext new (setOutput' cb)---{-# ANN getOutputsForInputs AllowRecursion #-}-{-# ANN getOutputsForInputs AllowLazyData #-}-getOutputsForInputs :: List (IORef (Maybe' OutputChannel)) -> InputValue -> IO (List (IORef (Maybe' OutputChannel)))-getOutputsForInputs acc (OneInput ch _) = do res <- H.lookup output ch-                                             case res of -                                              Nothing -> return acc-                                              Just ls -> H.delete output ch >> return (acc `union'` ls)-getOutputsForInputs acc (MoreInputs ch _ more) = do res <- H.lookup output ch-                                                    case res of -                                                      Nothing -> getOutputsForInputs acc more-                                                      Just ls -> H.delete output ch >> getOutputsForInputs (acc `union'` ls) more--{-# ANN eventLoop AllowRecursion #-}-{-# ANN eventLoop AllowLazyData #-}--eventLoop :: IO ()-eventLoop = do _ <- takeMVar inputSem-               minp <- takeMVar inputValue-               putMVar inputValue Nothing'-               case minp of-                 Nothing' -> error "AsyncRattus.Channels.eventLoop unexpected state"-                 Just' inp -> do-                   ls <- getOutputsForInputs Nil inp-                   mapM_ (update inp) ls-               eventLoop---- | In order for 'setOutput' to work, this IO action must be invoked.-startEventLoop :: IO ()-startEventLoop = do-  started <- atomicModifyIORef eventLoopStarted (\b -> (True,b))-  when (not started) eventLoop
− src/AsyncRattus/Derive.hs
@@ -1,117 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE ExistentialQuantification #-}---module AsyncRattus.Derive (continuous) where--import AsyncRattus.InternalPrimitives-import Language.Haskell.TH-import Language.Haskell.TH.Syntax-import Control.Monad---data DataInfo = forall flag . DataInfo Cxt Name [TyVarBndr flag] [Con] [DerivClause] --{-|-  This function provides a list (of the given length) of new names based-  on the given string.--}-newNames :: Int -> String -> Q [Name]-newNames n name = replicateM n (newName name)---{-|-  This is the @Q@-lifted version of 'abstractNewtype.--}-abstractNewtypeQ :: Q Info -> Q (Maybe DataInfo)-abstractNewtypeQ = liftM abstractNewtype---{-| Apply a class name to type arguments to construct a type class-    constraint.--}--mkClassP :: Name -> [Type] -> Type-mkClassP name = foldl AppT (ConT name)---{-| This function provides the name and the arity of the given data-constructor, and if it is a GADT also its type.--}-normalCon :: Con -> [(Name,[StrictType], Maybe Type)]-normalCon (NormalC constr args) = [(constr, args, Nothing)]-normalCon (RecC constr args) = [(constr, map (\(_,s,t) -> (s,t)) args, Nothing)]-normalCon (InfixC a constr b) = [(constr, [a,b], Nothing)]-normalCon (ForallC _ _ constr) = normalCon constr-normalCon (GadtC (constr:_) args typ) = [(constr,args,Just typ)]-normalCon (RecGadtC (constr : _) args typ) = [(constr,map dropFst args,Just typ)]-  where dropFst (_,x,y) = (x,y)-normalCon _ = error "missing case for 'normalCon'"--normalCon' :: Con -> [(Name,[Type], Maybe Type)]-normalCon' con = map conv (normalCon con)-  where conv (n, ts, t) = (n, map snd ts, t)-  -mkInstanceD :: Cxt -> Type -> [Dec] -> Dec-mkInstanceD cxt ty decs = InstanceD Nothing cxt ty decs--{-|-  This function returns the name of a bound type variable--}-tyVarBndrName (PlainTV n _) = n-tyVarBndrName (KindedTV n _ _) = n--{-|-  This function abstracts away @newtype@ declaration, it turns them into-  @data@ declarations.--}-abstractNewtype :: Info -> Maybe DataInfo-abstractNewtype (TyConI (NewtypeD cxt name args _ constr derive))-    = Just (DataInfo cxt name args [constr] derive)-abstractNewtype (TyConI (DataD cxt name args _ constrs derive))-    = Just (DataInfo cxt name args constrs derive)-abstractNewtype _ = Nothing--continuous :: Name -> Q [Dec]-continuous fname = do-  Just (DataInfo _cxt name args constrs _deriving) <- abstractNewtypeQ $ reify fname-  let argNames = map (VarT . tyVarBndrName) args-      complType = foldl AppT (ConT name) argNames-      preCond = map (mkClassP ''Continuous . (: [])) argNames-      classType = AppT (ConT ''Continuous) complType-  let constrs' = concatMap normalCon' constrs-  progressAndNextDecl <- funD 'progressAndNext (map genProgressAndNext constrs')-  progressInternalDecl <- funD 'progressInternal (map genProgressInternal constrs')-  nextProgressDecl <- funD 'nextProgress (map genNextProgress constrs')-  return [mkInstanceD preCond classType [progressAndNextDecl,progressInternalDecl,nextProgressDecl]]-      where genProgressAndNext (constr, args,_) = do-              let n = length args-              varNs <- newNames n "x"-              varNsR <- newNames n "y"-              varNsS <- newNames n "z"-              varIn <- newName "_inp"-              let pat = ConP constr [] $ map VarP varNs--              progressInternalExp <- [|progressAndNext|]-              let lets = zipWith3 (\ x y z -> ValD (TupP [VarP y, VarP z]) (NormalB (progressInternalExp `AppE` VarE varIn `AppE` VarE x)) []) varNs varNsR varNsS-              clockUnionExp <- [|clockUnion|]-              result <- appsE ( conE constr : (map varE varNsR))-              clock <- if n == 0 then [|emptyClock|] else return (foldl1 (\ x y -> (clockUnionExp `AppE` x) `AppE` y)  (map VarE varNsS))-              let body = LetE lets (TupE [Just result, Just clock])-              return $ Clause [VarP varIn, pat] (NormalB body) []-            genProgressInternal (constr, args,_) = do-              let n = length args-              varNs <- newNames n "x"-              varIn <- newName "_inp"-              let pat = ConP constr [] $ map VarP varNs-                  allVars = map varE varNs-                  inpVar = varE varIn-              body <- appsE ( conE constr : (map (\ x -> [|progressInternal $inpVar $x|]) allVars))-              return $ Clause [VarP varIn, pat] (NormalB body) []-            genNextProgress (constr, args,_) = do-              let n = length args-              varNs <- newNames n "x"-              let pat = ConP constr [] $ map VarP varNs-                  allVars = map varE varNs-              body <- if n == 0 then [|emptyClock|] else foldl1 (\ x y -> [|clockUnion $x $y|]) ((map (\ x -> [|nextProgress $x|]) allVars))-              return $ Clause [pat] (NormalB body) []
− src/AsyncRattus/Future.hs
@@ -1,219 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE TypeOperators #-}-{-# OPTIONS -fplugin=AsyncRattus.Plugin #-}----- | Programming with futures.--module AsyncRattus.Future-  ( F(..)-  , SigF(..)-  , mkSigF-  , mkSigF'-  , current-  , future-  , bindF-  , mapF-  , sync-  , syncF-  , switchAwait-  , switch-  , switchS-  , filterMap-  , filterMapAwait-  , filterAwait-  , filter-  , trigger-  , triggerAwait-  , map-  , mapAwait-  , zipWith-  , zipWithAwait-  , fromSig-  , scan-  , scanAwait-  )--where--import AsyncRattus-import AsyncRattus.Signal (Sig(..))-import Prelude hiding (map, filter, zipWith)-import AsyncRattus.Channels--newtype OneShot a = OneShot (F a)--instance Producer (OneShot a) a where-  getCurrent (OneShot (Now x)) = Just' x-  getCurrent (OneShot (Wait _)) = Nothing'--  getNext (OneShot (Now _)) cb = cb (never :: O (OneShot a))-  getNext (OneShot (Wait x)) cb = cb (delay (OneShot (adv x)))--instance Producer p a => Producer (F p) a where-  getCurrent (Now x) = getCurrent x-  getCurrent (Wait _) = Nothing'-  -  getNext (Now x) cb = getNext x cb-  getNext (Wait x) cb = cb x--instance Producer (SigF a) a where-  getCurrent (x :>: _) = Just' x-  getNext (_ :>: xs) cb = cb xs------ | @F a@ will produces a value of type @a@ after zero or more ticks--- of some clocks-data F a = Now !a | Wait !(O (F a))----bindF :: F a -> Box (a -> F b) -> F b-bindF (Now x) f = unbox f x-bindF (Wait x) f = Wait (delay (bindF (adv x) f))--mapF :: Box (a -> b) -> F a -> F b-mapF f d = d `bindF` (box (\ x -> Now (unbox f x)))---sync :: O (F a) -> O (F b) -> O (F a :* F b)-sync x y = delay (case select x y of-                     Fst x' y' -> (x' :* Wait y')-                     Snd x' y' -> (Wait x' :* y')-                     Both x' y' -> (x' :* y'))--syncF :: (Stable a, Stable b) => F a -> F b -> F (a :* b)-syncF (Now x) (Now y) = Now (x :* y)-syncF (Wait x) (Now y) = Wait (delay (syncA (adv x) y))-syncF (Now x) (Wait y) = Wait (delay (syncB x (adv y)))-syncF (Wait x) (Wait y) = Wait (delay (case select x y of-                                         Fst x' y' -> syncF x' (Wait y')-                                         Snd x' y' -> syncF (Wait x') y'-                                         Both x' y' -> syncF x' y'-                                      )) --syncA :: (Stable b) => F a -> b -> F (a :* b)-syncA (Now x) y = Now (x :* y)-syncA (Wait x) y = Wait (delay (syncA (adv x) y))---syncB :: (Stable a) => a -> F b -> F (a :* b)-syncB x (Now y) = Now (x :* y)-syncB x (Wait y) = Wait (delay (syncB x (adv y)))----- | @SigF a@ is a signal of values of type @a@. In contrast to 'Sig',--- 'SigF' supports the 'filter' and 'filterMap' functions.-data SigF a = !a :>: !(O (F (SigF a)))----- | Get the current value of a signal.-current :: SigF a -> a-current (x :>: _) = x----- | Get the future the signal.-future :: SigF a -> O (F (SigF a))-future (_ :>: xs) = xs---mkSigF :: Box (O a) -> F (SigF a)-mkSigF b = Wait (mkSigF' b) where--mkSigF' :: Box (O a) -> O (F (SigF a))-mkSigF' b = delay (Now (adv (unbox b) :>: mkSigF' b))---fromSig :: Sig a -> SigF a-fromSig (x ::: xs) = x :>: delay (Now (fromSig (adv xs)))--  -switchAwait :: F (SigF a) -> F (SigF a) -> F(SigF a)-switchAwait _ (Now ys) = Now ys-switchAwait (Now (x :>: xs)) (Wait ys) = Now (x :>: delay (uncurry' switchAwait (adv (sync xs ys)) ))-switchAwait (Wait xs) (Wait ys) = Wait (delay (uncurry' switchAwait (adv (sync xs ys)) ))--switch :: SigF a -> F (SigF a) -> SigF a-switch _ (Now ys) = ys-switch (x :>: xs) (Wait ys) = x :>: delay (uncurry' switchAwait (adv (sync xs ys)))--switchS :: Stable a => SigF a -> F (a -> SigF a) -> SigF a-switchS (x :>: _) (Now f) = f x-switchS (x :>: xs) (Wait ys) = x :>: delay (uncurry' (switchAwaitS x) (adv (sync xs ys)))--switchAwaitS :: Stable a => a -> F (SigF a) -> F (a -> SigF a) -> F (SigF a)-switchAwaitS _ (Now (x :>: _)) (Now f) = Now (f x)-switchAwaitS _ (Now (x :>: xs)) (Wait ys) =-  Now (x :>: delay (uncurry' (switchAwaitS x) (adv (sync xs ys))))-switchAwaitS x (Wait _) (Now f) = Now (f x)-switchAwaitS x (Wait xs) (Wait ys) = Wait (delay (uncurry' (switchAwaitS x) (adv (sync xs ys))))----filterMapAwait :: Box (a -> Maybe' b) -> F(SigF a) -> F (SigF b)-filterMapAwait f (Wait xs) = Wait (delay (filterMapAwait f (adv xs)))-filterMapAwait f (Now (x :>: xs)) = case unbox f x of-                                     Just' y  -> Now (y :>: delay (filterMapAwait f (adv xs)))-                                     Nothing' -> Wait (delay (filterMapAwait f (adv xs)))--filterMap :: Box (a -> Maybe' b) -> SigF a -> F (SigF b)-filterMap f xs = filterMapAwait f (Now xs)---filterAwait :: Box (a -> Bool) -> F( SigF a) -> F (SigF a)-filterAwait p = filterMapAwait (box (\ x -> if unbox p x then Just' x else Nothing'))--filter :: Box (a -> Bool) -> SigF a -> F (SigF a)-filter p = filterMap (box (\ x -> if unbox p x then Just' x else Nothing'))--trigger :: Stable b => Box (a -> b -> c) -> SigF a -> SigF b -> SigF c-trigger f (a :>: as) (b :>: bs) =-  unbox f a b :>:-  delay (uncurry' (trigger' b f) (adv (sync as bs)))--triggerAwait :: Stable b => Box (a -> b -> c) -> F (SigF a) -> SigF b -> F (SigF c)-triggerAwait f (Now (a :>: as)) (b :>: bs)-  = Now (unbox f a b :>: delay (uncurry' (trigger' b f) (adv (sync as bs))))-triggerAwait f (Wait as) (b :>: bs)-  = Wait (delay (uncurry' (trigger' b f) (adv (sync as bs))))--trigger' :: Stable b => b -> Box (a -> b -> c) -> F (SigF a) -> F (SigF b) -> F (SigF c)-trigger' b f (Now (a :>: as)) (Wait bs) =-  Now (unbox f a b :>: delay (uncurry' (trigger' b f) (adv (sync as bs))))-trigger' _ f (Now (a :>: as)) (Now (b :>: bs)) =-  Now (unbox f a b :>: delay (uncurry' (trigger' b f) (adv (sync as bs))))-trigger' b f (Wait as) (Wait bs) =-  Wait (delay (uncurry' (trigger' b f) (adv (sync as bs))))-trigger' _ f (Wait as) (Now (b :>: bs)) =-  Wait (delay (uncurry' (trigger' b f) (adv (sync as bs))))---mapAwait :: Box (a -> b) -> F (SigF a) -> F (SigF b)-mapAwait f (Now (x :>: xs)) = Now (unbox f x :>: delay (mapAwait f (adv xs)))-mapAwait f (Wait xs) = Wait (delay (mapAwait f (adv xs)))--map :: Box (a -> b) -> SigF a -> SigF b-map f (x :>: xs) = unbox f x :>: delay (mapAwait f (adv xs))----zipWith :: (Stable a, Stable b) => Box(a -> b -> c) -> SigF a -> SigF b -> SigF c-zipWith f (a :>: as) (b :>: bs) = unbox f a b :>: delay (uncurry' (zipWithAwait f a b) (adv (sync as bs)))--zipWithAwait :: (Stable a, Stable b) => Box(a -> b -> c) -> a -> b -> F (SigF a) -> F (SigF b) -> F (SigF c)-zipWithAwait f _ _ (Now (a :>: as)) (Now (b :>: bs)) = Now (unbox f a b :>: delay (uncurry' (zipWithAwait f a b) (adv (sync as bs))))-zipWithAwait f _ b (Now (a :>: as)) (Wait bs) = Now (unbox f a b :>: delay (uncurry' (zipWithAwait f a b) (adv (sync as bs))))-zipWithAwait f a _ (Wait as) (Now (b :>: bs)) = Now (unbox f a b :>: delay (uncurry' (zipWithAwait f a b) (adv (sync as bs))))-zipWithAwait f a b (Wait as) (Wait bs) = Wait (delay (uncurry' (zipWithAwait f a b) (adv (sync as bs))))--scan :: (Stable b) => Box(b -> a -> b) -> b -> SigF a -> SigF b-scan f acc (a :>: as) = acc' :>: delay (scanAwait f acc' (adv as))-  where acc' = unbox f acc a--scanAwait :: (Stable b) => Box (b -> a -> b) -> b -> F (SigF a) -> F (SigF b)-scanAwait f acc (Now (a :>: as)) = Now (acc' :>: delay (scanAwait f acc' (adv as)))-  where acc' = unbox f acc a-scanAwait f acc (Wait as) = Wait (delay (scanAwait f acc (adv as)))
− src/AsyncRattus/InternalPrimitives.hs
@@ -1,263 +0,0 @@-{-# LANGUAGE GADTs #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE UndecidableInstances #-}--module AsyncRattus.InternalPrimitives where--import Prelude hiding (Left, Right)-import Data.IntSet (IntSet)-import qualified Data.IntSet as IntSet-import Data.IORef-import Control.Concurrent.MVar-import System.IO.Unsafe-import System.Mem.Weak-import Control.Monad---- An input channel is identified by an integer. The programmer should not know about it.-type InputChannelIdentifier = Int--type Clock = IntSet--singletonClock :: InputChannelIdentifier -> Clock-singletonClock = IntSet.singleton--emptyClock :: Clock-emptyClock = IntSet.empty--clockUnion :: Clock -> Clock -> Clock-clockUnion = IntSet.union--channelMember :: InputChannelIdentifier -> Clock -> Bool-channelMember = IntSet.member--data InputValue where-  OneInput :: !InputChannelIdentifier -> !a -> InputValue-  MoreInputs :: !InputChannelIdentifier -> !a -> !InputValue -> InputValue--inputInClock :: InputValue -> Clock -> Bool-inputInClock (OneInput ch _) cl = channelMember ch cl-inputInClock (MoreInputs ch _ more) cl = channelMember ch cl || inputInClock more cl----- | The "later" type modality. A value @v@ of type @O 𝜏@ consists of--- two components: Its clock, denoted @cl(v)@, and a delayed--- computation that will produce a value of type @𝜏@ as soon as the--- clock @cl(v)@ ticks. The clock @cl(v)@ is only used for type--- checking and is not directly accessible, whereas the delayed--- computation is accessible via 'adv' and 'select'.--data O a = Delay !Clock (InputValue -> a)---- | The return type of the 'select' primitive.-data Select a b = Fst !a !(O b) | Snd !(O a) !b | Both !a !b--asyncRattusError pr = error (pr ++ ": Did you forget to mark this as Async Rattus code?")---- | This is the constructor for the "later" modality 'O':------ >     Γ ✓θ ⊢ t :: 𝜏--- > ----------------------- >  Γ ⊢ delay t :: O 𝜏------ The typing rule requires that its argument @t@ typecheck with an--- additional tick @✓θ@ of some clock @θ@.-{-# INLINE [1] delay #-}-delay :: a -> O a-delay _ = asyncRattusError "delay"--extractClock :: O a -> Clock-extractClock (Delay cl _) = cl--{-# INLINE [1] adv' #-}-adv' :: O a -> InputValue -> a-adv' (Delay _ f) inp = f inp----- | This is the eliminator for the "later" modality 'O':------ >   Γ ⊢ t :: O 𝜏     Γ' tick-free--- > ------------------------------------ >     Γ ✓cl(t) Γ' ⊢ adv t :: 𝜏------ It requires that a tick @✓θ@ is in the context whose clock matches--- exactly the clock of @t@, i.e. @θ = cl(t)@.--{-# INLINE [1] adv #-}-adv :: O a -> a-adv _ = asyncRattusError "adv"---- | If we want to eliminate more than one delayed computation, i.e.\--- two @s :: O σ@ and @t :: O 𝜏@, we need to use 'select' instead of--- just 'adv'.------ >   Γ ⊢ s :: O σ     Γ ⊢ t :: O 𝜏     Γ' tick-free--- > ----------------------------------------------------- >    Γ ✓cl(s)⊔cl(t) Γ' ⊢ select s t :: Select σ 𝜏------ It requires that we have a tick @✓θ@ in the context whose clock--- matches the union of the clocks of @s@ and @t@, i.e. @θ =--- cl(s)⊔cl(t)@. The union of two clocks ticks whenever either of the--- two clocks ticks, i.e. @cl(s)⊔cl(t)@, whenever @cl(s)@ or @cl(t)@--- ticks.------ That means there are three possible outcomes, which are reflected--- in the result type of @select s t@. A value of @Select σ 𝜏@ is--- either------   * a value of type @σ@ and a delayed computation of type @O 𝜏@, if---     @cl(s)@ ticks before @cl(t)@,------   * a value of type @𝜏@ and a delayed computation of type @O σ@, if---     @cl(t)@ ticks before @cl(s)@, or------   * a value of type @σ@ and a value of type @𝜏@, if @cl(s)@ and---   * @cl(s)@ tick simultaneously.---{-# INLINE [1] select #-}-select :: O a -> O b -> Select a b-select _ _ = asyncRattusError "select"--select' :: O a -> O b -> InputValue -> Select a b-select' a@(Delay clA inpFA) b@(Delay clB inpFB) inp-  = if inputInClock inp clA then-      if inputInClock inp clB then Both (inpFA inp) (inpFB inp)-      else Fst (inpFA inp) b-    else Snd a (inpFB inp)------ | The clock of @never :: O 𝜏@ will never tick, i.e. it will never--- produce a value of type @𝜏@. With 'never' we can for example--- implement the constant signal @x ::: never@ of type @Sig a@ for any @x ::--- a@.-never :: O a-never = Delay emptyClock (error "Trying to adv on the 'never' delayed computation")---- | A type is @Stable@ if it is a strict type and the later modality--- @O@ and function types only occur under @Box@.------ For example, these types are stable: @Int@, @Box (a -> b)@, @Box (O--- Int)@, @Box (Sig a -> Sig b)@.------ But these types are not stable: @[Int]@ (because the list type is--- not strict), @Int -> Int@, (function type is not stable), @O--- Int@, @Sig Int@.--class  Stable a  where------ | The "stable" type modality. A value of type @Box a@ is a--- time-independent computation that produces a value of type @a@.--- Use 'box' and 'unbox' to construct and consume 'Box'-types.-data Box a = Box a----- | This is the constructor for the "stable" modality 'Box':------ >     Γ☐ ⊢ t :: 𝜏--- > ----------------------- >  Γ ⊢ box t :: Box 𝜏------ where Γ☐ is obtained from Γ by removing all ticks and all variables--- @x :: 𝜏@, where 𝜏 is not a stable type.--{-# INLINE [1] box #-}-box :: a -> Box a-box x = Box x----- | This is the eliminator for the "stable" modality  'Box':------ >   Γ ⊢ t :: Box 𝜏--- > --------------------- >  Γ ⊢ unbox t :: 𝜏-{-# INLINE [1] unbox #-}-unbox :: Box a -> a-unbox (Box d) = d---defaultPromote :: Continuous a => a -> Box a-defaultPromote x = unsafePerformIO $ -    do r <- newIORef x-       r' <- mkWeakIORef r (return ()) -       modifyIORef promoteStore (ContinuousData r' :)-       return (Box (unsafePerformIO $ readIORef r))---class Continuous p where-  -- | Computes the same as 'progressInternal' and 'nextProgress'. In-  -- particular @progressAndNext inp v = (progressInternal inp v,-  -- nextProgress (progressInternal inp v))@.-  progressAndNext :: InputValue -> p -> (p , Clock)--  -- | Progresses the continuous value, given the input value from-  -- some channel-  progressInternal :: InputValue -> p -> p-  -- | Computes the set of channels that the continuous value is-  -- depending on. That is if @nextProgress v = cl@ and a new input-  -- @inp@ on channel @ch@ arrives, then @progressInternal inp v = v@.-  nextProgress :: p -> Clock -  promoteInternal :: p -> Box p-  promoteInternal = defaultPromote---- For stable types we can circumvent the "promote store".-instance {-# OVERLAPPABLE #-} Stable a => Continuous a where-    progressAndNext _ x = (x , emptyClock) -    progressInternal _ x = x-    nextProgress _ = emptyClock-    promoteInternal = Box--data ContinuousData where-   ContinuousData :: Continuous a => !(Weak (IORef a)) -> ContinuousData---- TODO: The list type needs to be replaced by a more efficient--- mutable data structure.-{-# NOINLINE promoteStore #-}-promoteStore :: IORef [ContinuousData]-promoteStore = unsafePerformIO (newIORef [])--{-# NOINLINE progressPromoteStoreMutex #-}-progressPromoteStoreMutex :: MVar ()-progressPromoteStoreMutex = unsafePerformIO (newMVar ())----- | Atomic version of 'progressPromoteStore'.--progressPromoteStoreAtomic :: InputValue -> IO ()-progressPromoteStoreAtomic inp = do-    takeMVar progressPromoteStoreMutex-    progressPromoteStore inp-    putMVar progressPromoteStoreMutex ()----- | For promote to work, its argument must be stored in the "promote--- store", and whenenver an input is received on some channel, all--- values in the "promote store" must be advanced (using--- 'progressInternal').--progressPromoteStore :: InputValue -> IO ()-progressPromoteStore inp = do -    xs <- atomicModifyIORef promoteStore (\x -> ([],x))-    xs' <- filterM run xs-    atomicModifyIORef promoteStore (\x -> (x ++ xs',()))-  where run (ContinuousData x) = do-          d <- deRefWeak x-          case d of-            Nothing -> return False-            Just x -> modifyIORef' x (progressInternal inp) >> return True--promote :: Continuous a => a -> Box a-promote x = promoteInternal x--newtype Chan a = Chan InputChannelIdentifier--{-# RULES-  "unbox/box"    forall x. unbox (box x) = x-    #-}---{-# RULES-  "box/unbox"    forall x. box (unbox x) = x-    #-}
− src/AsyncRattus/Plugin.hs
@@ -1,162 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE CPP #-}----- | The plugin to make it all work.--module AsyncRattus.Plugin (plugin, AsyncRattus(..)) where-import AsyncRattus.Plugin.StableSolver-import AsyncRattus.Plugin.ScopeCheck-import AsyncRattus.Plugin.Strictify-import AsyncRattus.Plugin.SingleTick-import AsyncRattus.Plugin.CheckClockCompatibility-import AsyncRattus.Plugin.Utils-import AsyncRattus.Plugin.Annotation-import AsyncRattus.Plugin.Transform--import Prelude hiding ((<>))--import Control.Monad-import Data.Maybe-import Data.List-import Data.Data hiding (tyConName)-import qualified Data.Set as Set-import Data.Set (Set)--import qualified GHC.LanguageExtensions as LangExt--import GHC.Plugins-import GHC.Tc.Types---- | Use this to enable Asynchronous Rattus' plugin, either by supplying the option--- @-fplugin=AsyncRattus.Plugin@ directly to GHC, or by including the--- following pragma in each source file:--- --- > {-# OPTIONS -fplugin=AsyncRattus.Plugin #-}-plugin :: Plugin-plugin = defaultPlugin {-  installCoreToDos = install,-  pluginRecompile = purePlugin,-  typeCheckResultAction = typechecked,-  tcPlugin = tcStable,-  driverPlugin = updateEnv-  }---data Options = Options {debugMode :: Bool}----- | Enable the @Strict@ language extension.-updateEnv :: [CommandLineOption] -> HscEnv -> IO HscEnv-updateEnv _ env = return env {hsc_dflags = update (hsc_dflags env) } -  where update fls = xopt_set fls LangExt.Strict--typechecked :: [CommandLineOption] -> ModSummary -> TcGblEnv -> TcM TcGblEnv-typechecked _ _ env = checkAll env >> return env--install :: [CommandLineOption] -> [CoreToDo] -> CoreM [CoreToDo]-install opts todo = case find findSamePass todo of       -- check that we don't run the transformation twice-                      Nothing -> return (strPass : todo) -- (e.g. if the "-fplugin" option is used twice)-                      _ -> return todo-    where name = "Async Rattus strictify"-          strPass = CoreDoPluginPass name (strictifyProgram Options{debugMode = dmode})-          dmode = "debug" `elem` opts-          findSamePass (CoreDoPluginPass s _) = s == name-          findSamePass _ = False-          ---- | Apply the following operations to all Asynchronous Rattus definitions in the--- program:------ * Transform into single tick form (see SingleTick module)--- * Check whether lazy data types are used (see Strictify module)--- * Transform into call-by-value form (see Strictify module)--strictifyProgram :: Options -> ModGuts -> CoreM ModGuts-strictifyProgram opts guts = do-  newBinds <- mapM (strictify opts guts) (mg_binds guts)-  return guts { mg_binds = newBinds }--strictify :: Options -> ModGuts -> CoreBind -> CoreM CoreBind-strictify opts guts b@(Rec bs) = do-  let debug = debugMode opts-  tr <- liftM or (mapM (shouldProcessCore guts . fst) bs)-  if tr then do-    let vs = map fst bs-    es' <- mapM (\ (v,e) -> do-      processCore <- shouldProcessCore guts v-      if not processCore-      then do-        when debug $ putMsg $ text "Skipping binding: " <> ppr v-        return e-      else checkAndTransform guts (Set.fromList vs) debug v e-      ) bs-    when debug $ putMsg $ "Plugin | result of transformation: " <> ppr es'-    return (Rec (zip vs es'))-  else return b-strictify opts guts b@(NonRec v e) = do-    let debug = debugMode opts-    when debug $ putMsg $ text "Processing binding: " <> ppr v <> text " | Non-recursive binding"-    when debug $ putMsg $ text "Expr: " <> ppr e-    processCore <- shouldProcessCore guts v-    if not processCore then do-      when debug $ putMsg $ text "Skipping binding: " <> ppr v-      return b-    else do-      transformed <- checkAndTransform guts Set.empty debug v e-      when debug $ putMsg $ "Plugin | result of transformation: " <> ppr transformed-      return $ NonRec v transformed--checkAndTransform :: ModGuts -> Set Var -> Bool -> Var -> CoreExpr -> CoreM CoreExpr-checkAndTransform guts recursiveSet debug v e = do-  when debug $ putMsg $ text "Processing binding: " <> ppr v-  when debug $ putMsg $ text "Expr: " <> ppr e-  allowRec <- allowRecursion guts v-  singleTick <- toSingleTick e-  when debug $ putMsg $ text "Single-tick: " <> ppr singleTick-  lazy <- allowLazyData guts v-  when (not lazy) $ checkStrictData (SCxt (nameSrcSpan $ getName v)) singleTick-  when debug $ putMsg $ text "Strict single-tick: " <> ppr singleTick-  checkExpr CheckExpr{ recursiveSet = recursiveSet, oldExpr = e,-                        verbose = debug,-                        allowRecExp = allowRec} singleTick-  transform singleTick--getModuleAnnotations :: Data a => ModGuts -> [a]-getModuleAnnotations guts = anns'-  where anns = filter (\a-> case ann_target a of-                         ModuleTarget m -> m == (mg_module guts)-                         _ -> False) (mg_anns guts)-        anns' = mapMaybe (fromSerialized deserializeWithData . ann_value) anns-----allowLazyData :: ModGuts -> CoreBndr -> CoreM Bool-allowLazyData guts bndr = do-  l <- annotationsOn guts bndr :: CoreM [AsyncRattus]-  return (AllowLazyData `elem` l)--allowRecursion :: ModGuts -> CoreBndr -> CoreM Bool-allowRecursion guts bndr = do-  l <- annotationsOn guts bndr :: CoreM [AsyncRattus]-  return (AllowRecursion `elem` l)--expectError :: ModGuts -> CoreBndr -> CoreM Bool-expectError guts bndr = do-  l <- annotationsOn guts bndr :: CoreM [InternalAnn]-  return $ ExpectError `elem` l---shouldProcessCore :: ModGuts -> CoreBndr -> CoreM Bool-shouldProcessCore guts bndr = do-  expectScopeError <- expectError guts bndr-  return (userFunction bndr && not expectScopeError)--annotationsOn :: (Data a) => ModGuts -> CoreBndr -> CoreM [a]-annotationsOn guts bndr = do-  (_,anns)  <- getAnnotations deserializeWithData guts-  return $-    lookupWithDefaultUFM anns [] (varName bndr) ++-    getModuleAnnotations guts
− src/AsyncRattus/Plugin/Annotation.hs
@@ -1,30 +0,0 @@-{-# LANGUAGE DeriveDataTypeable #-}-module AsyncRattus.Plugin.Annotation (AsyncRattus(..), InternalAnn (..)) where--import Data.Data---- | By default all Async Rattus functions are checked for use of lazy--- data types, since these may cause memory leaks. If any lazy data--- types are used, a warning is issued. These warnings can be disabled--- by annotating the module or the function with 'AllowLazyData'------ > {-# ANN myFunction AllowLazyData #-}--- >--- > {-# ANN module AllowLazyData #-}------ Async Rattus only allows guarded recursion, i.e. recursive calls--- must occur in the scope of a tick. Structural recursion over strict--- data types is safe as well, but is currently not checked. To--- disable the guarded recursion check, annotate the module or--- function with 'AllowRecursion'.--- --- > {-# ANN myFunction AllowRecursion #-}--- >--- > {-# ANN module AllowRecursion #-}---data AsyncRattus = AllowLazyData | AllowRecursion deriving (Typeable, Data, Show, Ord, Eq)----- | This annotation type is for internal use only.-data InternalAnn = ExpectError | ExpectWarning deriving (Typeable, Data, Show, Eq, Ord)
− src/AsyncRattus/Plugin/CheckClockCompatibility.hs
@@ -1,261 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE CPP #-}---- | This module implements the check that the transformed code is--- typable in the single tick calculus.--module AsyncRattus.Plugin.CheckClockCompatibility-  (checkExpr, CheckExpr (..)) where--import GHC.Types.Tickish-import GHC.Plugins--import AsyncRattus.Plugin.Utils-import qualified AsyncRattus.Plugin.PrimExpr as Prim-import Prelude hiding ((<>))-import Data.Set (Set)-import qualified Data.Set as Set-import Data.Map (Map)-import qualified Data.Map as Map-import Data.Maybe (isJust)-import Control.Monad (foldM, when)-import Control.Applicative ((<|>))-import System.Exit (exitFailure)--type LCtx = Set Var-data HiddenReason = BoxApp | AdvApp | NestedRec Var | FunDef | DelayApp-type Hidden = Map Var HiddenReason--data TypeError = TypeError SrcSpan SDoc---data Ctx = Ctx-  { current :: LCtx,-    hidden :: Hidden,-    earlier :: Maybe LCtx,-    srcLoc :: SrcSpan,-    recDef :: Set Var, -- ^ recursively defined variables -    stableTypes :: Set Var,-    allowRecursion :: Bool,-    allowGuardedRec :: Bool-    }--hasTick :: Ctx -> Bool-hasTick = isJust . earlier--stabilize :: HiddenReason -> Ctx -> Ctx-stabilize hr c = c-  {current = Set.empty,-   earlier = Nothing,-   hidden = hidden c `Map.union` Map.fromSet (const hr) ctxHid,-   allowGuardedRec = False-  }-  where ctxHid = maybe (current c) (Set.union (current c)) (earlier c)--data Scope = Hidden SDoc | Visible--getScope  :: Ctx -> Var -> Scope-getScope c v =-    if v `Set.member` recDef c then-      if allowGuardedRec c || allowRecursion c || typeClassFunction v then Visible-      else Hidden ("(Mutually) recursive call to " <> ppr v <> " must occur under delay")-    else case Map.lookup v (hidden c) of-      Just reason ->-        if (isStable (stableTypes c) (varType v)) then Visible-        else case reason of-          NestedRec rv ->-            if allowRecursion c then Visible-            else Hidden ("Variable " <> ppr v <> " is no longer in scope:"-                         $$ "It appears in a local recursive definition (namely of " <> ppr rv <> ")"-                         $$ "and is of type " <> ppr (varType v) <> ", which is not stable.")-          BoxApp -> Hidden ("Variable " <> ppr v <> " is no longer in scope:" $$-                       "It occurs under " <> keyword "box" $$ "and is of type " <> ppr (varType v) <> ", which is not stable.")-          AdvApp -> Hidden ("Variable " <> ppr v <> " is no longer in scope: It occurs under adv.")--          FunDef -> Hidden ("Variable " <> ppr v <> " is no longer in scope: It occurs in a function that is defined under a delay, is a of a non-stable type " <> ppr (varType v) <> ", and is bound outside delay")-          DelayApp -> Hidden ("Variable " <> ppr v <> " is no longer in scope: It occurs under two occurrences of delay and is a of a non-stable type " <> ppr (varType v))-      Nothing-          | maybe False (Set.member v) (earlier c) ->-            if isStable (stableTypes c) (varType v) then Visible-            else Hidden ("Variable " <> ppr v <> " is no longer in scope:" $$-                         "It occurs under delay" $$ "and is of type " <> ppr (varType v) <> ", which is not stable.")-          | Set.member v (current c) -> Visible-          | otherwise -> Visible----pickFirst :: SrcSpan -> SrcSpan -> SrcSpan-pickFirst s@RealSrcSpan{} _ = s-pickFirst _ s = s--typeError :: Ctx -> Var -> SDoc -> TypeError-typeError ctx var = TypeError (pickFirst (srcLoc ctx) (nameSrcSpan (varName var)))--instance Outputable TypeError where-  ppr (TypeError srcLoc sdoc) = text "TypeError at " <> ppr srcLoc <> text ": " <> ppr sdoc--emptyCtx :: CheckExpr -> Ctx-emptyCtx c =-  Ctx { current =  Set.empty,-        earlier = Nothing,-        hidden = Map.empty,-        srcLoc = noLocationInfo,-        recDef = recursiveSet c,-        stableTypes = Set.empty,-        allowRecursion = allowRecExp c,-        allowGuardedRec = False-        }--stabilizeLater :: Ctx -> Ctx-stabilizeLater c =-  case earlier c of-    Just earl -> c {earlier = Nothing,-                    hidden = hidden c `Map.union` Map.fromSet (const FunDef) earl}-    Nothing -> c--isStableConstr :: Type -> CoreM (Maybe Var)-isStableConstr t =-  case splitTyConApp_maybe t of-    Just (con,[args]) ->-      case getNameModule con of-        Just (name, mod) ->-          if isRattModule mod && name == "Stable"-          then return (getTyVar_maybe args)-          else return Nothing-        _ -> return Nothing-    _ ->  return Nothing---- should be equatable-type SymbolicClock = Set Var--mkClock1 :: Var -> SymbolicClock-mkClock1 = Set.singleton--mkClock2 :: Var -> Var -> SymbolicClock-mkClock2 v1 v2 = Set.fromList [v1, v2]--newtype CheckResult = CheckResult{-  -- if present, contains the variable of the primitive applied so we can report its position-  -- in case of an error, and the clock for the primitive-  prim :: Maybe (Var, SymbolicClock)-}--instance Outputable CheckResult where-  ppr (CheckResult prim) = text "CheckResult {prim = " <> ppr prim <> text "}"--emptyCheckResult :: CheckResult-emptyCheckResult = CheckResult {prim = Nothing}--data CheckExpr = CheckExpr{-  recursiveSet :: Set Var,-  oldExpr :: Expr Var,-  verbose :: Bool,-  allowRecExp :: Bool-  }--checkExpr :: CheckExpr -> Expr Var -> CoreM ()-checkExpr c e = do-  when (verbose c) $ putMsg $ text "checkExpr: " <> ppr e-  res <- checkExpr' (emptyCtx c) e-  case res of-    Right _ -> do when (verbose c) $ putMsgS "checkExpr succeeded."-    Left (TypeError src doc) ->-      let printErrMsg = if verbose c-          then do-            printMessage SevError src ("Internal error in Async Rattus Plugin: single tick transformation did not preserve typing." $$ doc)-            putMsgS "-------- old --------"-            putMsg $ ppr (oldExpr c)-            putMsgS "-------- new --------"-            putMsg (ppr e)-            -          else do-            printMessage SevError noSrcSpan ("Internal error in Async Rattus Plugin: single tick transformation did not preserve typing." $$-                                  "Compile with flags \"-fplugin-opt AsyncRattus.Plugin:debug\" and \"-g2\" for detailed information")-      in do-        printErrMsg-        liftIO exitFailure---checkExpr' :: Ctx -> Expr Var -> CoreM (Either TypeError CheckResult)-checkExpr' c (App e e') | isType e' || (not $ tcIsLiftedTypeKind $ typeKind $ exprType e')-  = checkExpr' c e-checkExpr' c@Ctx{current = cur, earlier = earl} expr@(App e e') =-  case Prim.isPrimExpr expr of-    Just (Prim.BoxApp _) ->-      checkExpr' (stabilize BoxApp c) e'-    Just (Prim.DelayApp f _) -> do-      let c' = case earl of-                 Nothing -> c{current = Set.empty, earlier = Just cur, allowGuardedRec = True}-                 Just earl' -> c{ current = Set.empty, earlier = Just cur, allowGuardedRec = True,-                                  hidden = hidden c `Map.union` Map.fromSet (const DelayApp) earl'}-      eRes <- checkExpr' c' e'-      case eRes of-        Left err -> return $ Left err-        Right (CheckResult {prim = Nothing}) -> return $ Left $ typeError c f (text "Each delay must contain an adv or select")-        Right _ -> return $ Right emptyCheckResult-    Just (Prim.AdvApp f _) | not (hasTick c) -> return $ Left $ typeError c f (text "can only use adv under delay")-    Just (Prim.AdvApp f (arg, _)) -> return $ Right $ CheckResult {prim = Just (f, mkClock1 arg)}-    Just (Prim.SelectApp f _ _) | not (hasTick c) -> return $ Left $ typeError c f (text "can only use select under delay")-    Just (Prim.SelectApp f (arg1, _) (arg2, _))-> return $ Right $ CheckResult {prim = Just (f, mkClock2 arg1 arg2)}-    Nothing -> checkBoth c e e'-checkExpr' c (Case e v _ alts) = do-    res <- checkExpr' c' e-    resAll <- mapM (\(Alt _ _ altE) -> checkExpr' c altE) alts-    foldM (fmap return . combine c) res resAll-  where c' = addVars [v] c-checkExpr' c (Lam v e)-  | isTyVar v || (not $ tcIsLiftedTypeKind $ typeKind $ varType v) = do-      is <- isStableConstr (varType v)-      let c' = case is of-            Nothing -> c-            Just t -> c{stableTypes = Set.insert t (stableTypes c)}-      checkExpr' c' e-  | otherwise = checkExpr' (addVars [v] (stabilizeLater c)) e-checkExpr' _ (Type _)  = return $ Right emptyCheckResult-checkExpr' _ (Lit _)  = return $ Right emptyCheckResult-checkExpr' _ (Coercion _)  = return $ Right emptyCheckResult-checkExpr' c (Tick (SourceNote span _name) e) =-  checkExpr' c{srcLoc = fromRealSrcSpan span} e-checkExpr' c (Tick _ e) = checkExpr' c e-checkExpr' c (Cast e _) = checkExpr' c e-checkExpr' c (Let (NonRec _ e1) e2) = do-  res1 <- checkExpr' c e1-  res2 <- checkExpr' c e2-  return $ combine c res1 res2-checkExpr' c (Let (Rec binds) e2) = do-    resAll <- mapM (\ (v,e) -> checkExpr' (c' v) e) binds-    res <- checkExpr' (addVars vs c) e2-    foldM (fmap return . combine c) res resAll-  where vs = map fst binds-        ctxHid = maybe (current c) (Set.union (current c)) (earlier c)-        c' v = c {current = Set.empty,-                  earlier = Nothing,-                  hidden =  hidden c `Map.union`-                   Map.fromSet (const (NestedRec v)) ctxHid,-                  recDef = recDef c `Set.union` Set.fromList vs }-checkExpr' c  (Var v)-  | tcIsLiftedTypeKind $ typeKind $ varType v =  case getScope c v of-             Hidden reason -> return $ Left $ typeError c v reason-             Visible -> return $ Right emptyCheckResult-  | otherwise = return $ Right emptyCheckResult--addVars :: [Var] -> Ctx -> Ctx-addVars v c = c{current = Set.fromList v `Set.union` current c }--checkBoth :: Ctx -> CoreExpr -> CoreExpr -> CoreM (Either TypeError CheckResult)-checkBoth c e e' = do-  c1 <- checkExpr' c e-  c2 <- checkExpr' c e'-  return $ combine c c1 c2---- Combines two CheckResults such that the clocks therein are compatible.--- If both CheckResults have PrimVars, one is picked arbitrarily.-combine :: Ctx -> Either TypeError CheckResult -> Either TypeError CheckResult -> Either TypeError CheckResult-combine c eRes1 eRes2 = do-  res1 <- eRes1-  res2 <- eRes2-  case (res1, res2) of-    (CheckResult (Just (_, cl1)), CheckResult (Just (_, cl2))) | cl1 == cl2 -> Right res2-    (CheckResult (Just _), CheckResult (Just (p, _))) -> Left $ typeError c p "Only one adv/select allowed in a delay"-    (CheckResult maybeP, CheckResult maybeP') -> Right $ CheckResult {prim = maybeP <|> maybeP'}
− src/AsyncRattus/Plugin/Dependency.hs
@@ -1,385 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE GADTs #-}---- | This module is used to perform a dependency analysis of top-level--- function definitions, i.e. to find out which defintions are--- (mutual) recursive. To this end, this module also provides--- functions to compute, bound variables and variable occurrences.--module AsyncRattus.Plugin.Dependency (dependency, HasBV (..),printBinds) where---import GHC.Plugins-import GHC.Data.Bag-import GHC.Hs.Type---import GHC.Hs.Extension-import GHC.Hs.Expr-import GHC.Hs.Pat-import GHC.Hs.Binds--#if __GLASGOW_HASKELL__ >= 904-import GHC.Parser.Annotation-#else-import Language.Haskell.Syntax.Extension-import GHC.Parser.Annotation-#endif---import Data.Set (Set)-import qualified Data.Set as Set-import Data.Graph-import Data.Maybe-import Data.Either-import Prelude hiding ((<>))------ | Compute the dependencies of a bag of bindings, returning a list--- of the strongly-connected components.-dependency :: Bag (LHsBindLR GhcTc GhcTc) -> [SCC (LHsBindLR GhcTc GhcTc, Set Var)]-dependency binds = map AcyclicSCC noDeps ++ catMaybes (map filterJust (stronglyConnComp (concat deps)))-  where (deps,noDeps) = partitionEithers $ map mkDep $ bagToList binds-        mkDep :: GenLocated l (HsBindLR GhcTc GhcTc) ->-                 Either [(Maybe (GenLocated l (HsBindLR GhcTc GhcTc), Set Var), Name, [Name])]-                 (GenLocated l (HsBindLR GhcTc GhcTc), Set Var)-        mkDep b =-          let dep = map varName $ Set.toList (getFV b)-              vars = getBV b in-          case Set.toList vars of-            (v:vs) -> Left ((Just (b,vars), varName v , dep) : map (\ v' -> (Nothing, varName v' , dep)) vs)-            [] -> Right (b,vars)-        filterJust (AcyclicSCC Nothing) = Nothing -- this should not happen-        filterJust (AcyclicSCC (Just b)) = Just (AcyclicSCC b)-        filterJust (CyclicSCC bs) = Just (CyclicSCC (catMaybes bs))---printBinds (AcyclicSCC bind) = liftIO (putStr "acyclic bind: ") >> printBind (fst bind) >> liftIO (putStrLn "") -printBinds (CyclicSCC binds) = liftIO (putStr "cyclic binds: ") >> mapM_ (printBind . fst) binds >> liftIO (putStrLn "") ---printBind (L _ FunBind{fun_id = L _ name}) = -  liftIO $ putStr $ (getOccString name ++ " ")-printBind (L _ (VarBind {var_id = name})) =   liftIO $ putStr $ (getOccString name ++ " ")-#if __GLASGOW_HASKELL__ < 904-printBind (L _ (AbsBinds {abs_exports = exp})) = -#else-printBind (L _ (XHsBindsLR (AbsBinds {abs_exports = exp}))) = -#endif-  mapM_ (\ e -> liftIO $ putStr $ ((getOccString $ abe_poly e)  ++ " ")) exp-printBind _ = return ()----- | Computes the variables that are bound by a given piece of syntax.--class HasBV a where-  getBV :: a -> Set Var--instance HasBV (HsBindLR GhcTc GhcTc) where-  getBV (FunBind{fun_id = L _ v}) = Set.singleton v-  getBV (PatBind {pat_lhs = pat}) = getBV pat-  getBV (VarBind {var_id = v}) = Set.singleton v-  getBV PatSynBind{} = Set.empty-#if __GLASGOW_HASKELL__ < 904-  getBV (AbsBinds {abs_exports = es}) = Set.fromList (map abe_poly es)-#else-  getBV (XHsBindsLR (AbsBinds {abs_exports = es})) = Set.fromList (map abe_poly es)-#endif-  -instance HasBV a => HasBV (GenLocated b a) where-  getBV (L _ e) = getBV e--instance HasBV a => HasBV [a] where-  getBV ps = foldl (\s p -> getBV p `Set.union` s) Set.empty ps--#if __GLASGOW_HASKELL__ >= 904-getRecFieldRhs = hfbRHS-#else-getRecFieldRhs = hsRecFieldArg-#endif--getConBV (PrefixCon _ ps) = getBV ps-getConBV (InfixCon p p') = getBV p `Set.union` getBV p'-getConBV (RecCon (HsRecFields {rec_flds = fs})) = foldl run Set.empty fs-      where run s (L _ f) = getBV (getRecFieldRhs f) `Set.union` s--#if __GLASGOW_HASKELL__ < 904-instance HasBV CoPat where-  getBV CoPat {co_pat_inner = p} = getBV p-#else-instance HasBV XXPatGhcTc where-  getBV CoPat {co_pat_inner = p} = getBV p-  getBV (ExpansionPat _ p) = getBV p-#endif--instance HasBV (Pat GhcTc) where-  getBV (VarPat _ (L _ v)) = Set.singleton v-  getBV (LazyPat _ p) = getBV p-#if __GLASGOW_HASKELL__ >= 906-  getBV (AsPat _ (L _ v) _ p) = Set.insert v (getBV p)-#else-  getBV (AsPat _ (L _ v) p) = Set.insert v (getBV p)-#endif-  getBV (BangPat _ p) = getBV p-  getBV (ListPat _ ps) = getBV ps-  getBV (TuplePat _ ps _) = getBV ps-  getBV (SumPat _ p _ _) = getBV p-  getBV (ViewPat _ _ p) = getBV p--  getBV (SplicePat _ sp) =-    case sp of-#if __GLASGOW_HASKELL__ < 906-      HsTypedSplice _ _ v _ -> Set.singleton v-      HsSpliced _ _ (HsSplicedPat p) -> getBV p-      HsUntypedSplice _ _ v _ ->  Set.singleton v-      HsQuasiQuote _ p p' _ _ -> Set.fromList [p,p']-      _ -> Set.empty-#else-      HsUntypedSpliceExpr _ e -> getFV e-      HsQuasiQuote _ v _  -> Set.singleton v-#endif--  getBV (NPlusKPat _ (L _ v) _ _ _ _) = Set.singleton v-  getBV (NPat {}) = Set.empty-  getBV (XPat p) = getBV p-  getBV (WildPat {}) = Set.empty-  getBV (LitPat {}) = Set.empty-#if __GLASGOW_HASKELL__ >= 904  -  getBV (ParPat _ _ p _) = getBV p-#else-  getBV (ParPat _ p) = getBV p-#endif-  getBV (ConPat {pat_args = con}) = getConBV con-  getBV (SigPat _ p _) = getBV p--#if __GLASGOW_HASKELL__ < 904-instance HasBV NoExtCon where-  getBV _ = Set.empty-#endif---- | Syntax that may contain variables.-class HasFV a where-  -- | Compute the set of variables occurring in the given piece of-  -- syntax.  The name falsely suggests that returns free variables,-  -- but in fact it returns all variable occurrences, no matter-  -- whether they are free or bound.-  getFV :: a -> Set Var --instance HasFV a => HasFV (GenLocated b a) where-  getFV (L _ e) = getFV e-  -instance HasFV a => HasFV [a] where-  getFV es = foldMap getFV es--instance HasFV a => HasFV (Bag a) where-  getFV es = foldMap getFV es--instance HasFV Var where-  getFV v = Set.singleton v--instance HasFV a => HasFV (MatchGroup GhcTc a) where-  getFV MG {mg_alts = alts} = getFV alts-  -instance HasFV a => HasFV (Match GhcTc a) where-  getFV Match {m_grhss = rhss} = getFV rhss--instance HasFV (HsTupArg GhcTc) where-  getFV (Present _ e) = getFV e-  getFV Missing {} = Set.empty--instance HasFV a => HasFV (GRHS GhcTc a) where-  getFV (GRHS _ g b) = getFV g `Set.union` getFV b--instance HasFV a => HasFV (GRHSs GhcTc a) where-  getFV GRHSs {grhssGRHSs = rhs, grhssLocalBinds = lbs} =-    getFV rhs `Set.union` getFV lbs---instance HasFV (HsLocalBindsLR GhcTc GhcTc) where-  getFV (HsValBinds _ bs) = getFV bs-  getFV (HsIPBinds _ bs) = getFV bs-  getFV EmptyLocalBinds {} = Set.empty-  -instance HasFV (HsValBindsLR GhcTc GhcTc) where-  getFV (ValBinds _ b _) = getFV b-  getFV (XValBindsLR b) = getFV b--instance HasFV (NHsValBindsLR GhcTc) where-  getFV (NValBinds bs _) = foldMap (getFV . snd) bs--instance HasFV (HsBindLR GhcTc GhcTc) where-  getFV FunBind {fun_matches = ms} = getFV ms-  getFV PatBind {pat_rhs = rhs} = getFV rhs-  getFV VarBind {var_rhs = rhs} = getFV rhs-  getFV PatSynBind {} = Set.empty-#if __GLASGOW_HASKELL__ < 904-  getFV AbsBinds {abs_binds = bs} = getFV bs-#else-  getFV (XHsBindsLR AbsBinds {abs_binds = bs}) = getFV bs-#endif--instance HasFV (IPBind GhcTc) where-  getFV (IPBind _ _ e) = getFV e--instance HasFV (HsIPBinds GhcTc) where-  getFV (IPBinds _ bs) = getFV bs-  -instance HasFV (ApplicativeArg GhcTc) where-  getFV ApplicativeArgOne { arg_expr = e }     = getFV e-  getFV ApplicativeArgMany {app_stmts = es, final_expr = e} = getFV es `Set.union` getFV e--instance HasFV (ParStmtBlock GhcTc GhcTc) where-  getFV (ParStmtBlock _ es _ _) = getFV es-  -instance HasFV a => HasFV (StmtLR GhcTc GhcTc a) where-  getFV (LastStmt _ e _ _) = getFV e-  getFV (BindStmt _ _ e) = getFV e-  getFV (ApplicativeStmt _ args _) = foldMap (getFV . snd) args-  getFV (BodyStmt _ e _ _) = getFV e-  getFV (LetStmt _ bs) = getFV bs-  getFV (ParStmt _ stms e _) = getFV stms `Set.union` getFV e-  getFV TransStmt{} = Set.empty -- TODO-  getFV RecStmt{} = Set.empty -- TODO---instance HasFV (HsRecFields GhcTc (GenLocated SrcSpanAnnA (HsExpr GhcTc))) where-  getFV HsRecFields{rec_flds = fs} = getFV fs--#if __GLASGOW_HASKELL__ >= 904-instance HasFV (HsFieldBind o (GenLocated SrcSpanAnnA (HsExpr GhcTc))) where-#else-instance HasFV (HsRecField' o (GenLocated SrcSpanAnnA (HsExpr GhcTc))) where-#endif-  getFV rf  = getFV (getRecFieldRhs rf)--instance HasFV (ArithSeqInfo GhcTc) where-  getFV (From e) = getFV e-  getFV (FromThen e1 e2) = getFV e1 `Set.union` getFV e2-  getFV (FromTo e1 e2) = getFV e1 `Set.union` getFV e2-  getFV (FromThenTo e1 e2 e3) = getFV e1 `Set.union` getFV e2 `Set.union` getFV e3-  -#if __GLASGOW_HASKELL__ >= 904-instance HasFV (HsQuote GhcTc) where-#else-instance HasFV (HsBracket GhcTc) where-#endif-  getFV (ExpBr _ e) = getFV e-  getFV (VarBr _ _ e) = getFV e-  getFV _ = Set.empty--instance HasFV (HsCmd GhcTc) where-  getFV (HsCmdArrApp _ e1 e2 _ _) = getFV e1 `Set.union` getFV e2-  getFV (HsCmdArrForm _ e _ _ cmd) = getFV e `Set.union` getFV cmd-  getFV (HsCmdApp _ e1 e2) = getFV e1 `Set.union` getFV e2-  getFV (HsCmdLam _ l) = getFV l-  getFV (HsCmdCase _ _ mg) = getFV mg-  getFV (HsCmdIf _ _ e1 e2 e3) = getFV e1 `Set.union` getFV e2 `Set.union` getFV e3-  getFV (HsCmdDo _ cmd) = getFV cmd-#if __GLASGOW_HASKELL__ >= 904-  getFV (HsCmdPar _ _ cmd _) = getFV cmd-  getFV (HsCmdLet _ _ bs _ _) = getFV bs-#else-  getFV (HsCmdPar _ cmd) = getFV cmd-  getFV (HsCmdLet _ bs _) = getFV bs-#endif-#if __GLASGOW_HASKELL__ >= 904-  getFV (HsCmdLamCase _ _ mg) = getFV mg-#else-  getFV (HsCmdLamCase _ mg) = getFV mg-#endif-  getFV (XCmd e) = getFV e---instance (HasFV a, HasFV b) => HasFV (Either a b) where-  getFV (Left x) = getFV x-  getFV (Right x) = getFV x--#if __GLASGOW_HASKELL__ >= 908-instance HasFV (LHsRecUpdFields GhcTc) where-  getFV RegularRecUpdFields {recUpdFields = x} = getFV x-  getFV OverloadedRecUpdFields {olRecUpdFields = x} = getFV x-#endif--instance HasFV (HsCmdTop GhcTc) where-  getFV (HsCmdTop _ cmd) = getFV cmd--instance HasFV (HsExpr GhcTc) where-  getFV (HsVar _ v) = getFV v-  getFV HsUnboundVar {} = Set.empty-  getFV HsOverLabel {} = Set.empty-  getFV HsIPVar {} = Set.empty-  getFV HsOverLit {} = Set.empty-  getFV HsLit {} = Set.empty-  getFV (HsLam _ mg) = getFV mg-  getFV (HsApp _ e1 e2) = getFV e1 `Set.union` getFV e2      -  getFV (OpApp _ e1 e2 e3) = getFV e1 `Set.union` getFV e2 `Set.union` getFV e3-  getFV (NegApp _ e _) = getFV e-  getFV (SectionL _ e1 e2) = getFV e1 `Set.union` getFV e2-  getFV (SectionR _ e1 e2) = getFV e1 `Set.union` getFV e2-  getFV (ExplicitTuple _ es _) = getFV es-  getFV (ExplicitSum _ _ _ e) = getFV e-  getFV (HsCase _ e mg) = getFV e  `Set.union` getFV mg-  getFV (HsMultiIf _ es) = getFV es-  getFV (HsDo _ _ e) = getFV e-  getFV HsProjection {} = Set.empty-  getFV HsGetField {gf_expr = e} = getFV e-  getFV (ExplicitList _ es) = getFV es-  getFV (RecordUpd {rupd_expr = e, rupd_flds = fs}) = getFV e `Set.union` getFV fs-  getFV (RecordCon {rcon_flds = fs}) = getFV fs-  getFV (ArithSeq _ _ e) = getFV e-#if __GLASGOW_HASKELL__ >= 906-  getFV HsTypedSplice{} = Set.empty-  getFV HsUntypedSplice{} = Set.empty-#else-  getFV HsSpliceE{} = Set.empty-#endif-  getFV (HsProc _ _ e) = getFV e-  getFV (HsStatic _ e) = getFV e-  getFV (XExpr e) = getFV e-#if __GLASGOW_HASKELL__ >= 904-  getFV (HsPar _ _ e _) = getFV e  -  getFV (HsLamCase _ _ mg) = getFV mg-  getFV (HsLet _ _ bs _ e) = getFV bs `Set.union` getFV e-  getFV HsRecSel {} = Set.empty-  getFV (HsTypedBracket _ e) = getFV e-  getFV (HsUntypedBracket _ e) = getFV e-#else  -  getFV (HsBinTick _ _ _ e) = getFV e-  getFV (HsTick _ _ e) = getFV e-  getFV (HsLet _ bs e) = getFV bs `Set.union` getFV e-  getFV (HsPar _ e) = getFV e-  getFV (HsLamCase _ mg) = getFV mg-  getFV HsConLikeOut {} = Set.empty-  getFV HsRecFld {} = Set.empty-  getFV (HsBracket _ e) = getFV e-  getFV HsRnBracketOut {} = Set.empty-  getFV HsTcBracketOut {} = Set.empty-#endif--#if __GLASGOW_HASKELL__ >= 906-  getFV (HsAppType _ e _ _) = getFV e-  getFV (ExprWithTySig _ e _) = getFV e  -#else-  getFV (HsAppType _ e _) = getFV e-  getFV (ExprWithTySig _ e _) = getFV e  -#endif-  getFV (HsIf _ e1 e2 e3) = getFV e1 `Set.union` getFV e2 `Set.union` getFV e3-  getFV (HsPragE _ _ e) = getFV e---instance HasFV XXExprGhcTc where-  getFV (WrapExpr e) = getFV e-  getFV (ExpansionExpr (HsExpanded _e1 e2)) = getFV e2-#if __GLASGOW_HASKELL__ >= 904  -  getFV (HsTick _ e) = getFV e-  getFV (HsBinTick _ _ e) = getFV e-  getFV ConLikeTc{} = Set.empty-#endif---instance HasFV (e GhcTc) => HasFV (HsWrap e) where-  getFV (HsWrap _ e) = getFV e
− src/AsyncRattus/Plugin/PrimExpr.hs
@@ -1,109 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module AsyncRattus.Plugin.PrimExpr (-    Prim (..),-    PrimInfo (..),-    function,-    prim,-    isPrimExpr-) where--import Data.Map (Map)-import qualified Data.Map as Map-import GHC.Plugins-import AsyncRattus.Plugin.Utils-import Prelude hiding ((<>))--data Prim = Delay | Adv | Box | Select---- DelayApp has the following fields: Var = delay f, T1 = value type, T2 = later type (O v a)--- AdvApp has the following fields: Var = adv f, TypedArg = var and type for arg-data PrimInfo = DelayApp Var Type | AdvApp Var TypedArg | BoxApp Var | SelectApp Var TypedArg TypedArg--type TypedArg = (Var, Type)--data PartialPrimInfo = PartialPrimInfo {-  primPart :: Prim,-  functionPart :: Var,-  args :: [Var],-  typeArgs :: [Type]-}--instance Outputable PartialPrimInfo where-  ppr (PartialPrimInfo Delay f _ typeArgs) = text "PartialPrimInfo { prim = Delay, function = " <> ppr f <> text "args = (not printing since it should be undefined) , typeArgs = " <> ppr typeArgs -  ppr (PartialPrimInfo prim f args typeArgs) = text "PartialPrimInfo { prim = " <> ppr prim <> text ", function = " <> ppr f <> text ", args = " <> ppr args <> text ", typeArgs = " <> ppr typeArgs--instance Outputable Prim where-  ppr Delay = "delay"-  ppr Adv = "adv"-  ppr Select = "select"-  ppr Box = "box"--instance Outputable PrimInfo where-  ppr (DelayApp f _) = text "DelayApp - function " <> ppr f -  ppr (BoxApp f) = text "BoxApp - function " <> ppr f-  ppr (AdvApp f arg) = text "AdvApp - function " <> ppr f <> text " | arg " <> ppr arg-  ppr (SelectApp f arg arg2) = text "SelectApp - function " <> ppr f <> text " | arg " <> ppr arg <> text " | arg2 " <> ppr arg2-  -primMap :: Map FastString Prim-primMap = Map.fromList-  [("delay", Delay),-   ("adv", Adv),-   ("select", Select),-   ("box", Box)-   ]---isPrim :: Var -> Maybe Prim-isPrim v = case getNameModule v of-    Just (name, mod) | isRattModule mod -> Map.lookup name primMap-    _ -> Nothing--createPartialPrimInfo :: Prim -> Var -> PartialPrimInfo-createPartialPrimInfo prim function =-  PartialPrimInfo {-    primPart = prim,-    functionPart = function,-    args = [],-    typeArgs = []-  }--function :: PrimInfo -> Var-function (DelayApp f _) = f-function (BoxApp f) = f-function (AdvApp f _) = f-function (SelectApp f _ _) = f--prim :: PrimInfo -> Prim-prim (DelayApp {}) = Delay-prim (BoxApp _) = Box-prim (AdvApp {}) = Adv-prim (SelectApp {}) = Select--validatePartialPrimInfo :: PartialPrimInfo -> Maybe PrimInfo-validatePartialPrimInfo (PartialPrimInfo Select f [arg2V, argV] [arg2T, argT]) = Just $ SelectApp f (argV, argT) (arg2V, arg2T)-validatePartialPrimInfo (PartialPrimInfo Delay f [_] [argT]) = Just $ DelayApp f argT-validatePartialPrimInfo (PartialPrimInfo {primPart = Box, functionPart = f}) = Just $ BoxApp f-validatePartialPrimInfo (PartialPrimInfo Adv f [argV] [argT]) = Just $ AdvApp f (argV, argT)-validatePartialPrimInfo _ = Nothing--isPrimExpr :: Expr Var -> Maybe PrimInfo-isPrimExpr expr = isPrimExpr' expr >>= validatePartialPrimInfo--isPrimExpr' :: Expr Var -> Maybe PartialPrimInfo-isPrimExpr' (App e (Type t)) = case mPPI of-  Just pPI@(PartialPrimInfo {typeArgs = tArgs}) -> Just pPI {typeArgs = t : tArgs}-  Nothing -> Nothing-  where mPPI = isPrimExpr' e-isPrimExpr' (App e e') =-  case isPrimExpr' e of-    Just partPrimInfo@(PartialPrimInfo { primPart = Delay, args = args}) -> Just partPrimInfo {args = undefined : args}-    Just partPrimInfo@(PartialPrimInfo { args = args}) -> Just partPrimInfo {args = maybe args (:args) (getMaybeVar e')}-    _ -> Nothing-isPrimExpr' (Var v) = case isPrim v of-  Just p ->  Just $ createPartialPrimInfo p v-  Nothing -> Nothing-isPrimExpr' (Tick _ e) = isPrimExpr' e-isPrimExpr' (Lam v e)-  | isTyVar v || (not $ tcIsLiftedTypeKind $ typeKind $ varType v) = isPrimExpr' e-isPrimExpr' _ = Nothing
− src/AsyncRattus/Plugin/ScopeCheck.hs
@@ -1,812 +0,0 @@-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ImplicitParams #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE CPP #-}------ | This module implements the source plugin that checks the variable--- scope of of Async Rattus programs.--module AsyncRattus.Plugin.ScopeCheck (checkAll) where--import AsyncRattus.Plugin.Utils-import AsyncRattus.Plugin.Dependency-import AsyncRattus.Plugin.Annotation--import Control.Monad.Trans.State.Strict-import Data.IORef--import Prelude hiding ((<>))--import GHC.Parser.Annotation-import GHC.Plugins-import GHC.Tc.Types-import GHC.Data.Bag-import GHC.Tc.Types.Evidence-import GHC.Hs.Extension-import GHC.Hs.Expr-import GHC.Hs.Pat-import GHC.Hs.Binds--import Data.Graph-import qualified Data.Set as Set-import qualified Data.Map as Map-import Data.Set (Set)-import Data.Map (Map)-import Data.List-import Data.List.NonEmpty (NonEmpty(..),(<|),nonEmpty)-import System.Exit-import Data.Either-import Data.Maybe--import Data.Data hiding (tyConName)--import Control.Monad--type ErrorMsg = (Severity,SrcSpan,SDoc)-type ErrorMsgsRef = IORef [ErrorMsg]---- | The current context for scope checking-data Ctxt = Ctxt-  {-    errorMsgs :: ErrorMsgsRef,-    -- | Variables that are in scope now (i.e. occurring in the typing-    -- context but not to the left of a tick)-    current :: LCtxt,-    -- | Variables that are in the typing context, but to the left of a-    -- tick-    earlier :: Either NoTickReason (NonEmpty LCtxt),-    -- | Variables that have fallen out of scope. The map contains the-    -- reason why they have fallen out of scope.-    hidden :: Hidden,-    -- -- | Same as 'hidden' but for recursive variables.-    -- hiddenRec :: Hidden,-    -- | The current location information.-    srcLoc :: SrcSpan,-    -- | If we are in the body of a recursively defined function, this-    -- field contains the variables that are defined recursively-    -- (could be more than one due to mutual recursion or because of a-    -- recursive pattern definition) and the location of the recursive-    -- definition.-    recDef :: Maybe RecDef,-    -- | Type variables with a 'Stable' constraint attached to them.-    stableTypes :: Set Var,-    -- | A mapping from variables to the primitives that they are-    -- defined equal to. For example, a program could contain @let-    -- mydel = delay in mydel 1@, in which case @mydel@ is mapped to-    -- 'Delay'.-    primAlias :: Map Var Prim,-    -- | Allow general recursion.-    allowRecursion :: Bool}------ | The starting context for checking a top-level definition. For--- non-recursive definitions, the argument is @Nothing@. Otherwise, it--- contains the recursively defined variables along with the location--- of the recursive definition.-emptyCtxt :: ErrorMsgsRef -> Maybe (Set Var,SrcSpan) -> Bool -> Ctxt-emptyCtxt em mvar allowRec =-  Ctxt { errorMsgs = em,-         current =  Set.empty,-         earlier = Left NoDelay,-         hidden = Map.empty,-         srcLoc = noLocationInfo,-         recDef = mvar,-         primAlias = Map.empty,-         stableTypes = Set.empty,-         allowRecursion = allowRec}---- | A local context, consisting of a set of variables.-type LCtxt = Set Var---- | The recursively defined variables + the position where the--- recursive definition starts-type RecDef = (Set Var, SrcSpan)-----data StableReason = StableRec SrcSpan | StableBox deriving Show---- | Indicates, why a variable has fallen out of scope.-data HiddenReason = Stabilize StableReason | FunDef | DelayApp | AdvApp | SelectApp deriving Show---- | Indicates, why there is no tick-data NoTickReason = NoDelay | TickHidden HiddenReason deriving Show---- | Hidden context, containing variables that have fallen out of--- context along with the reason why they have.-type Hidden = Map Var HiddenReason---- | The 5 primitive Asynchronous Rattus operations.-data Prim = Delay | Adv | Select | Box | Unbox deriving Show---- | This constraint is used to pass along the context implicitly via--- an implicit parameter.-type GetCtxt = ?ctxt :: Ctxt---type CheckM = StateT ([Maybe (Prim, SrcSpan)]) TcM---- | This type class is implemented for each AST type @a@ for which we--- can check whether it adheres to the scoping rules of Asynchronous Rattus.-class Scope a where-  -- | Check whether the argument is a scope correct piece of syntax-  -- in the given context.-  check :: GetCtxt => a -> CheckM Bool---- | This is a variant of 'Scope' for syntax that can also bind--- variables.-class ScopeBind a where-  -- | 'checkBind' checks whether its argument is scope-correct and in-  -- addition returns the the set of variables bound by it.-  checkBind :: GetCtxt => a -> CheckM (Bool,Set Var)----- | set the current context.-setCtxt :: Ctxt -> (GetCtxt => a) -> a -setCtxt c a = let ?ctxt = c in a----- | modify the current context.-modifyCtxt :: (Ctxt -> Ctxt) -> (GetCtxt => a) -> (GetCtxt => a)-modifyCtxt f a =-  let newc = f ?ctxt in-  let ?ctxt = newc in a-----getLocAnn' :: SrcSpanAnn' b -> SrcSpan-getLocAnn' = locA---updateLoc :: SrcSpanAnn' b -> (GetCtxt => a) -> (GetCtxt => a)-updateLoc src = modifyCtxt (\c -> c {srcLoc = getLocAnn' src})----- | Check all definitions in the given module. If Scope errors are--- found, the current execution is halted with 'exitFailure'.-checkAll :: TcGblEnv -> TcM ()-checkAll env = do-  let bindDep = dependency (tcg_binds env)-  result <- mapM (checkSCC' (tcg_mod env) (tcg_ann_env env)) bindDep-  let (res,msgs) = foldl' (\(b,l) (b',l') -> (b && b', l ++ l')) (True,[]) result-  printAccErrMsgs msgs-  if res then return () else liftIO exitFailure---printAccErrMsgs :: [ErrorMsg] -> TcM ()-printAccErrMsgs msgs = mapM_ printMsg (sortOn (\(_,l,_)->l) msgs)-  where printMsg (sev,loc,doc) = printMessage sev loc doc-----instance Scope a => Scope (GenLocated SrcSpan a) where-  check (L l x) =  (\c -> c {srcLoc = l}) `modifyCtxt` check x--instance Scope a => Scope (GenLocated (SrcSpanAnn' b) a) where-  check (L l x) =  updateLoc l $ check x-  -instance Scope a => Scope (Bag a) where-  check bs = fmap and (mapM check (bagToList bs))--instance Scope a => Scope [a] where-  check ls = fmap and (mapM check ls)---instance Scope (Match GhcTc (GenLocated SrcAnno (HsExpr GhcTc))) where-  check Match{m_pats=ps,m_grhss=rhs} = addVars (getBV ps) `modifyCtxt` check rhs--instance Scope (Match GhcTc (GenLocated SrcAnno (HsCmd GhcTc))) where-  check Match{m_pats=ps,m_grhss=rhs} = addVars (getBV ps) `modifyCtxt` check rhs---instance Scope (MatchGroup GhcTc (GenLocated SrcAnno (HsExpr GhcTc))) where-  check MG {mg_alts = alts} = check alts---instance Scope (MatchGroup GhcTc (GenLocated SrcAnno (HsCmd GhcTc))) where-  check MG {mg_alts = alts} = check alts---instance Scope a => ScopeBind (StmtLR GhcTc GhcTc a) where-  checkBind (LastStmt _ b _ _) =  ( , Set.empty) <$> check b-  checkBind (BindStmt _ p b) = do-    let vs = getBV p-    let c' = addVars vs ?ctxt-    r <- setCtxt c' (check b)-    return (r,vs)-  checkBind (BodyStmt _ b _ _) = ( , Set.empty) <$> check b-  checkBind (LetStmt _ bs) = checkBind bs-  checkBind ParStmt{} = notSupported "monad comprehensions"-  checkBind TransStmt{} = notSupported "monad comprehensions"-  checkBind ApplicativeStmt{} = notSupported "applicative do notation"-  checkBind RecStmt{} = notSupported "recursive do notation"--instance ScopeBind a => ScopeBind [a] where-  checkBind [] = return (True,Set.empty)-  checkBind (x:xs) = do-    (r,vs) <- checkBind x-    (r',vs') <- addVars vs `modifyCtxt` (checkBind xs)-    return (r && r',vs `Set.union` vs')--instance ScopeBind a => ScopeBind (GenLocated SrcSpan a) where-  checkBind (L l x) =  (\c -> c {srcLoc = l}) `modifyCtxt` checkBind x--instance ScopeBind a => ScopeBind (GenLocated (SrcSpanAnn' b) a) where-  checkBind (L l x) =  updateLoc l $ checkBind x--instance Scope a => Scope (GRHS GhcTc a) where-  check (GRHS _ gs b) = do-    (r, vs) <- checkBind gs-    r' <- addVars vs `modifyCtxt`  (check b)-    return (r && r')--checkRec :: GetCtxt => LHsBindLR GhcTc GhcTc -> CheckM Bool-checkRec b =  liftM2 (&&) (checkPatBind b) (check b)--checkPatBind :: GetCtxt => LHsBindLR GhcTc GhcTc -> CheckM Bool-checkPatBind (L l b) = updateLoc l $ checkPatBind' b--checkPatBind' :: GetCtxt => HsBindLR GhcTc GhcTc -> CheckM Bool-checkPatBind' PatBind{} = do-  printMessage' SevError ("(Mutual) recursive pattern binding definitions are not supported in Asynchronous Rattus")-  return False-#if __GLASGOW_HASKELL__ < 904-checkPatBind' AbsBinds {abs_binds = binds} = -#else-checkPatBind' (XHsBindsLR AbsBinds {abs_binds = binds}) = -#endif-  liftM and (mapM checkPatBind (bagToList binds))--checkPatBind' _ = return True----- | Check the scope of a list of (mutual) recursive bindings. The--- second argument is the set of variables defined by the (mutual)--- recursive bindings-checkRecursiveBinds :: GetCtxt => [LHsBindLR GhcTc GhcTc] -> Set Var -> CheckM (Bool, Set Var)-checkRecursiveBinds bs vs = do-    res <- fmap and (mapM check' bs)-    return (res, vs)-    where check' b@(L l _) = fc (getLocAnn' l) `modifyCtxt` checkRec b-          fc l c = let-            ctxHid = either (const $ current c) (Set.union (current c) . Set.unions) (earlier c)-            in c {current = Set.empty,-                  earlier = Left (TickHidden $ Stabilize $ StableRec l),-                  hidden =  hidden c `Map.union`-                            (Map.fromSet (const (Stabilize (StableRec l))) ctxHid),-                  recDef = maybe (Just (vs,l)) (\(vs',_) -> Just (Set.union vs' vs,l)) (recDef c)-                   -- TODO fix location info of recDef (needs one location for each var)-                   }          ---instance ScopeBind (SCC (GenLocated SrcSpanAnnA (HsBindLR  GhcTc GhcTc), Set Var)) where-  checkBind (AcyclicSCC (b,vs)) = (, vs) <$> check b-  checkBind (CyclicSCC bs) = checkRecursiveBinds (map fst bs) (foldMap snd bs)-  -instance ScopeBind (HsValBindsLR GhcTc GhcTc) where-  checkBind (ValBinds _ bs _) = checkBind (dependency bs)-  -  checkBind (XValBindsLR (NValBinds binds _)) = checkBind binds---instance ScopeBind (HsBindLR GhcTc GhcTc) where-  checkBind b = (, getBV b) <$> check b----- | Compute the set of variables defined by the given Haskell binder.-getAllBV :: GenLocated l (HsBindLR GhcTc GhcTc) -> Set Var-getAllBV (L _ b) = getAllBV' b where-  getAllBV' (FunBind{fun_id = L _ v}) = Set.singleton v-#if __GLASGOW_HASKELL__ < 904-  getAllBV' (AbsBinds {abs_exports = es, abs_binds = bs}) = Set.fromList (map abe_poly es) `Set.union` foldMap getBV bs-  getAllBV' XHsBindsLR{} = Set.empty-#else-  getAllBV' (XHsBindsLR (AbsBinds {abs_exports = es, abs_binds = bs})) = Set.fromList (map abe_poly es) `Set.union` foldMap getBV bs-#endif-  getAllBV' (PatBind {pat_lhs = pat}) = getBV pat-  getAllBV' (VarBind {var_id = v}) = Set.singleton v-  getAllBV' PatSynBind{} = Set.empty----- Check nested bindings-instance ScopeBind (RecFlag, Bag (GenLocated SrcSpanAnnA (HsBindLR GhcTc GhcTc))) where-  checkBind (NonRecursive, bs)  = checkBind $ bagToList bs-  checkBind (Recursive, bs) = checkRecursiveBinds bs' (foldMap getAllBV bs')-    where bs' = bagToList bs---instance ScopeBind (HsLocalBindsLR GhcTc GhcTc) where-  checkBind (HsValBinds _ bs) = checkBind bs-  checkBind HsIPBinds {} = notSupported "implicit parameters"-  checkBind EmptyLocalBinds{} = return (True,Set.empty)--type SrcAnno = SrcSpanAnnA-  -instance Scope (GRHSs GhcTc (GenLocated SrcAnno (HsExpr GhcTc))) where-  check GRHSs{grhssGRHSs = rhs, grhssLocalBinds = lbinds} = do-    (l,vs) <- checkBind lbinds-    r <- addVars vs `modifyCtxt` (check rhs)-    return (r && l)--instance Scope (GRHSs GhcTc (GenLocated SrcAnno (HsCmd GhcTc))) where-  check GRHSs{grhssGRHSs = rhs, grhssLocalBinds = lbinds} = do-    (l,vs) <- checkBind lbinds-    r <- addVars vs `modifyCtxt` (check rhs)-    return (r && l)--instance Show Var where-  show v = getOccString v---tickHidden :: HiddenReason -> SDoc-tickHidden FunDef = "a function definition"-tickHidden DelayApp = "a nested application of delay"-tickHidden AdvApp = "an application of adv"-tickHidden SelectApp = "an application of select"-tickHidden (Stabilize StableBox) = "an application of box"-tickHidden (Stabilize (StableRec src)) = "a nested recursive definition (at " <> ppr src <> ")"--isSelect :: GetCtxt => LHsExpr GhcTc -> Bool-isSelect e =-  case isPrimExpr e of-    Just (Select, _) -> True-    _ -> False--instance Scope (HsExpr GhcTc) where-  check (HsVar _ (L _ v))-    | Just p <- isPrim v =-        case p of-          Unbox -> return True-          _ -> printMessageCheck SevError ("Defining an alias for " <> ppr v <> " is not allowed")-    | otherwise = case getScope v of-             Hidden reason -> printMessageCheck SevError reason-             Visible -> return True-             ImplUnboxed -> return True-               -- printMessageCheck SevWarning-               --  (ppr v <> text " is an external temporal function used under delay, which may cause time leaks.")-  check (HsApp _ (L _ (HsApp _ f arg)) arg2) | isSelect f =-    case earlier ?ctxt of-      Right (er :| ers) -> do-        res <- get-        case res of-            Just _ : _ -> printMessageCheck SevError ("only one adv or select may be used in the scope of a delay.")-            Nothing : pre -> do put pre-                                b1 <- mod `modifyCtxt` check arg-                                b2 <- mod `modifyCtxt` check arg2-                                modify (Just (Select, srcLoc ?ctxt) :)-                                return $ b1 && b2-            _ -> error "Asynchronous Rattus: internal error"-        where mod c =  c{earlier = case nonEmpty ers of-                                    Nothing -> Left $ TickHidden SelectApp-                                    Just ers' -> Right ers',-                        current = er,-                        hidden = hidden ?ctxt `Map.union`-                        Map.fromSet (const SelectApp) (current ?ctxt)}-      Left NoDelay -> printMessageCheck SevError "select may only be used in the scope of a delay."-      Left (TickHidden hr) -> printMessageCheck SevError ("select may only be used in the scope of a delay. "-                        <> " There is a delay, but its scope is interrupted by " <> tickHidden hr <> ".")-  check (HsApp _ e1 e2) =-    case isPrimExpr e1 of-    Just (p,_) -> case p of-      Box -> do-        ch <- stabilize StableBox `modifyCtxt` check e2-        return ch-      Unbox -> check e2-      Delay -> do modify (Nothing :)-                  b <- (\c -> c{current = Set.empty,-                           earlier = case earlier c of-                                      Left _ -> Right (current c :| [])-                                      Right cs -> Right (current c <| cs)})-                     `modifyCtxt` check e2-                  res <- get-                  case res of-                    Nothing : _ -> printMessageCheck SevError "No adv or select found in the scope of this occurrence of delay"-                    _ : pre -> put pre >> return b-                    _ -> error "Asynchronous Rattus: internal error"-      Adv -> case earlier ?ctxt of-        Right (er :| ers) -> do-          res <- get-          case res of-            Just _ : _ -> printMessageCheck SevError ("only one adv or select may be used in the scope of a delay.")-            Nothing : pre -> do put pre-                                b <- mod `modifyCtxt` check e2-                                modify (Just (Adv,srcLoc ?ctxt) :)-                                return b-            _ -> error "Asynchronous Rattus: internal error"-          where mod c =  c{earlier = case nonEmpty ers of-                                       Nothing -> Left $ TickHidden AdvApp-                                       Just ers' -> Right ers',-                           current = er,-                           hidden = hidden ?ctxt `Map.union`-                            Map.fromSet (const AdvApp) (current ?ctxt)}-        Left NoDelay -> printMessageCheck SevError ("adv may only be used in the scope of a delay.")-        Left (TickHidden hr) -> printMessageCheck SevError ("adv may only be used in the scope of a delay. "-                            <> " There is a delay, but its scope is interrupted by " <> tickHidden hr <> ".")-      Select -> printMessageCheck SevError ("select must be fully applied")-    _ -> liftM2 (&&) (check e1)  (check e2)-  check HsUnboundVar{}  = return True-#if __GLASGOW_HASKELL__ >= 904-  check (HsPar _ _ e _) = check e-  check (HsLamCase _ _ mg) = check mg-  check HsRecSel{} = return True-  check HsTypedBracket{} = notSupported "MetaHaskell"-  check HsUntypedBracket{} = notSupported "MetaHaskell"-#else-  check HsConLikeOut{} = return True-  check HsRecFld{} = return True-  check (HsPar _ e) = check e-  check (HsLamCase _ mg) = check mg-  check HsBracket{} = notSupported "MetaHaskell"-  check (HsTick _ _ e) = check e-  check (HsBinTick _ _ _ e) = check e-  check HsRnBracketOut{} = notSupported "MetaHaskell"-  check HsTcBracketOut{} = notSupported "MetaHaskell"-#endif-#if __GLASGOW_HASKELL__ >= 904-  check (HsLet _ _ bs _ e) = do-#else-  check (HsLet _ bs e) = do-#endif-    (l,vs) <- checkBind bs-    r <- addVars vs `modifyCtxt` (check e)-    return (r && l)-         -  check HsOverLabel{} = return True-  check HsIPVar{} = notSupported "implicit parameters"-  check HsOverLit{} = return True  -  check HsLit{} = return True-  check (OpApp _ e1 e2 e3) = and <$> mapM check [e1,e2,e3]-  check (HsLam _ mg) = check mg-  check (HsCase _ e1 e2) = (&&) <$> check e1 <*> check e2-  check (SectionL _ e1 e2) = (&&) <$> check e1 <*> check e2-  check (SectionR _ e1 e2) = (&&) <$> check e1 <*> check e2-  check (ExplicitTuple _ e _) = check e-  check (NegApp _ e _) = check e-  check (ExplicitSum _ _ _ e) = check e-  check (HsMultiIf _ e) = check e-  check (ExplicitList _ e) = check e-  check HsProjection {} = return True-  check HsGetField {gf_expr = e} = check e-  check RecordUpd { rupd_expr = e, rupd_flds = fs} = (&&) <$> check e <*> check fs-  check RecordCon { rcon_flds = f} = check f-  check (ArithSeq _ _ e) = check e-#if __GLASGOW_HASKELL__ >= 906-  check HsTypedSplice{} = notSupported "Template Haskell"-  check HsUntypedSplice{} = notSupported "Template Haskell"-#else-  check HsSpliceE{} = notSupported "Template Haskell"-#endif-  check (HsProc _ _ e) = check e-  check (HsStatic _ e) = check e-  check (HsDo _ _ e) = fst <$> checkBind e-  check (XExpr e) = check e-#if __GLASGOW_HASKELL__ >= 906-  check (HsAppType _ e _ _) = check e-  check (ExprWithTySig _ e _) = check e-#else-  check (HsAppType _ e _) = check e-  check (ExprWithTySig _ e _) = check e-#endif-  check (HsPragE _ _ e) = check e-  check (HsIf _ e1 e2 e3) = and <$> mapM check [e1,e2,e3]---instance (Scope a, Scope b) => Scope (Either a b) where-  check (Left x) = check x-  check (Right x) = check x---#if __GLASGOW_HASKELL__ >= 908-instance Scope (LHsRecUpdFields GhcTc) where-  check RegularRecUpdFields {recUpdFields = x} = check x-  check OverloadedRecUpdFields {olRecUpdFields = x} = check x-#endif---instance Scope XXExprGhcTc where-  check (WrapExpr (HsWrap _ e)) = check e-  check (ExpansionExpr (HsExpanded _ e)) = check e-#if __GLASGOW_HASKELL__ >= 904-  check ConLikeTc{} = return True-  check (HsTick _ e) = check e-  check (HsBinTick _ _ e) = check e-#endif--instance Scope (HsCmdTop GhcTc) where-  check (HsCmdTop _ e) = check e-  -instance Scope (HsCmd GhcTc) where-  check (HsCmdArrApp _ e1 e2 _ _) = (&&) <$> check e1 <*> check e2-  check (HsCmdDo _ e) = fst <$> checkBind e-  check (HsCmdArrForm _ e1 _ _ e2) = (&&) <$> check e1 <*> check e2-  check (HsCmdApp _ e1 e2) = (&&) <$> check e1 <*> check e2-  check (HsCmdLam _ e) = check e-#if __GLASGOW_HASKELL__ >= 904-  check (HsCmdPar _ _ e _) = check e-  check (HsCmdLamCase _ _ e) = check e  -  check (HsCmdLet _ _ bs _ e) = do-#else-  check (HsCmdPar _ e) = check e-  check (HsCmdLamCase _ e) = check e-  check (HsCmdLet _ bs e) = do-#endif-    (l,vs) <- checkBind bs-    r <- addVars vs `modifyCtxt` (check e)-    return (r && l)--  check (HsCmdCase _ e1 e2) = (&&) <$> check e1 <*> check e2-  check (HsCmdIf _ _ e1 e2 e3) = (&&) <$> ((&&) <$> check e1 <*> check e2) <*> check e3-  check (XCmd (HsWrap _ e)) = check e---instance Scope (ArithSeqInfo GhcTc) where-  check (From e) = check e-  check (FromThen e1 e2) = (&&) <$> check e1 <*> check e2-  check (FromTo e1 e2) = (&&) <$> check e1 <*> check e2-  check (FromThenTo e1 e2 e3) = (&&) <$> ((&&) <$> check e1 <*> check e2) <*> check e3--instance Scope a => Scope (HsRecFields GhcTc a) where-  check HsRecFields {rec_flds = fs} = check fs----#if __GLASGOW_HASKELL__ >= 904-instance Scope b => Scope (HsFieldBind a b) where-  check HsFieldBind{hfbRHS = a} = check a-#else-instance Scope b => Scope (HsRecField' a b) where-  check HsRecField{hsRecFieldArg = a} = check a-#endif--instance Scope (HsTupArg GhcTc) where-  check (Present _ e) = check e-  check Missing{} = return True--instance Scope (HsBindLR GhcTc GhcTc) where-#if __GLASGOW_HASKELL__ >= 904-  check (XHsBindsLR AbsBinds {abs_binds = binds, abs_ev_vars  = ev})-#else-  check AbsBinds {abs_binds = binds, abs_ev_vars  = ev}-#endif-    = mod `modifyCtxt` check binds-      where mod c = c { stableTypes= stableTypes c `Set.union`-                        Set.fromList (mapMaybe (isStableConstr . varType) ev)}-  check FunBind{fun_matches= matches, fun_id = L _ v,-                fun_ext = wrapper} =-      mod `modifyCtxt` check matches-    where mod c = c { stableTypes= stableTypes c `Set.union`-                      Set.fromList (stableConstrFromWrapper' wrapper)  `Set.union`-                      Set.fromList (extractStableConstr (varType v))}-  check PatBind{pat_lhs = lhs, pat_rhs=rhs} = addVars (getBV lhs) `modifyCtxt` check rhs-  check VarBind{var_rhs = rhs} = check rhs-  check PatSynBind {} = return True -- pattern synonyms are not supported----- | Checks whether the given type is a type constraint of the form--- @Stable a@ for some type variable @a@. In that case it returns the--- type variable @a@.-isStableConstr :: Type -> Maybe TyVar-isStableConstr t = -  case splitTyConApp_maybe t of-    Just (con,[args]) ->-      case getNameModule con of-        Just (name, mod) ->-          if isRattModule mod && name == "Stable"-          then (getTyVar_maybe args)-          else Nothing-        _ -> Nothing                           -    _ ->  Nothing----#if __GLASGOW_HASKELL__ >= 906-stableConstrFromWrapper' :: (HsWrapper , a) -> [TyVar]-stableConstrFromWrapper' (x , _) = stableConstrFromWrapper x-#else-stableConstrFromWrapper' :: HsWrapper -> [TyVar]-stableConstrFromWrapper' = stableConstrFromWrapper-#endif--stableConstrFromWrapper :: HsWrapper -> [TyVar]-stableConstrFromWrapper (WpCompose v w) = stableConstrFromWrapper v ++ stableConstrFromWrapper w-stableConstrFromWrapper (WpEvLam v) = maybeToList $ isStableConstr (varType v)-stableConstrFromWrapper _ = []----- | Given a type @(C1, ... Cn) => t@, this function returns the list--- of type variables @[a1,...,am]@ for which there is a constraint--- @Stable ai@ among @C1, ... Cn@.-extractStableConstr :: Type -> [TyVar]-extractStableConstr  = mapMaybe isStableConstr . map irrelevantMult . fst . splitFunTys . snd . splitForAllTys'---getSCCLoc :: SCC (LHsBindLR  GhcTc GhcTc, Set Var) -> SrcSpan-getSCCLoc (AcyclicSCC (L l _ ,_)) = getLocAnn' l-getSCCLoc (CyclicSCC ((L l _,_ ) : _)) = getLocAnn' l-getSCCLoc _ = noLocationInfo--checkSCC' ::  Module -> AnnEnv -> SCC (LHsBindLR  GhcTc GhcTc, Set Var) -> TcM (Bool, [ErrorMsg])-checkSCC' mod anEnv scc = do-  err <- liftIO (newIORef [])-  let allowRec = AllowRecursion `Set.member` getAnn mod anEnv scc-  res <- checkSCC allowRec err scc-  msgs <- liftIO (readIORef err)-  let anns = getAnn mod anEnv scc-  if ExpectWarning `Set.member` anns -    then if ExpectError `Set.member` anns-         then return (False,[(SevError, getSCCLoc scc, "Annotation to expect both warning and error is not allowed.")])-         else if any (\(s,_,_) -> case s of SevWarning -> True; _ -> False) msgs-              then return (res, filter (\(s,_,_) -> case s of SevWarning -> False; _ -> True) msgs)-              else return (False,[(SevError, getSCCLoc scc, "Warning was expected, but typechecking produced no warning.")])-    else if ExpectError `Set.member` anns-         then if res-              then return (False,[(SevError, getSCCLoc scc, "Error was expected, but typechecking produced no error.")])-              else return (True,[])-         else return (res, msgs)-getAnn :: forall a . (Data a, Ord a) => Module -> AnnEnv -> SCC (LHsBindLR  GhcTc GhcTc, Set Var) -> Set a-getAnn mod anEnv scc =-  case scc of-    (AcyclicSCC (_,vs)) -> Set.unions $ Set.map checkVar vs-    (CyclicSCC bs) -> Set.unions $ map (Set.unions . Set.map checkVar . snd) bs-  where checkVar :: Var -> Set a-        checkVar v =-          let anns = findAnns deserializeWithData anEnv (NamedTarget name) :: [a]-              annsMod = findAnns deserializeWithData anEnv (ModuleTarget mod) :: [a]-              name :: Name-              name = varName v-          in Set.fromList anns `Set.union` Set.fromList annsMod------ | Checks a top-level definition group, which is either a single--- non-recursive definition or a group of (mutual) recursive--- definitions.--checkSCC :: Bool -> ErrorMsgsRef -> SCC (LHsBindLR  GhcTc GhcTc, Set Var) -> TcM Bool-checkSCC allowRec errm (AcyclicSCC (b,_)) = setCtxt (emptyCtxt errm Nothing allowRec) (evalStateT (check b) [])--checkSCC allowRec errm (CyclicSCC bs) = (fmap and (mapM check' bs'))-  where bs' = map fst bs-        vs = foldMap snd bs-        check' b@(L l _) = setCtxt (emptyCtxt errm (Just (vs,getLocAnn' l)) allowRec) (evalStateT (checkRec b) [])---- | Stabilizes the given context, i.e. remove all non-stable types--- and any tick. This is performed on checking 'box', and--- guarded recursive definitions. To provide better error messages a--- reason has to be given as well.-stabilize :: StableReason -> Ctxt -> Ctxt-stabilize sr c = c-  {current = Set.empty,-   earlier = Left $ TickHidden hr,-   hidden = hidden c `Map.union` Map.fromSet (const hr) ctxHid}-  where ctxHid = either (const $ current c) (foldl' Set.union (current c)) (earlier c)-        hr = Stabilize sr--data VarScope = Hidden SDoc | Visible | ImplUnboxed----- | This function checks whether the given variable is in scope.-getScope  :: GetCtxt => Var -> VarScope-getScope v =-  case ?ctxt of-    Ctxt{recDef = Just (vs,_), earlier = e, allowRecursion = allowRec} | v `Set.member` vs ->-     if allowRec then Visible else-        case e of-          Right _ -> Visible-          Left NoDelay -> Hidden ("The (mutually) recursive call to " <> ppr v <> " must occur in the scope of a delay")-          Left (TickHidden hr) -> Hidden ("The (mutually) recursive call to " <> ppr v <> " must occur in the scope of a delay. "-                            <> "There is a delay, but its scope is interrupted by " <> tickHidden hr <> ".")-    _ ->  case Map.lookup v (hidden ?ctxt) of-            Just (Stabilize (StableRec rv)) ->-              if (isStable (stableTypes ?ctxt) (varType v)) || allowRecursion ?ctxt then Visible-              else Hidden ("Variable " <> ppr v <> " is no longer in scope:" $$-                       "It appears in a local recursive definition (at " <> ppr rv <> ")"-                       $$ "and is of type " <> ppr (varType v) <> ", which is not stable.")-            Just (Stabilize StableBox) ->-              if (isStable (stableTypes ?ctxt) (varType v)) then Visible-              else Hidden ("Variable " <> ppr v <> " is no longer in scope:" $$-                       "It occurs under " <> keyword "box" $$ "and is of type " <> ppr (varType v) <> ", which is not stable.")-            Just AdvApp -> Hidden ("Variable " <> ppr v <> " is no longer in scope: It occurs under adv.")-            Just SelectApp -> Hidden ("Variable " <> ppr v <> " is no longer in scope: It occurs under select.")-            Just DelayApp -> Hidden ("Variable " <> ppr v <> " is no longer in scope due to repeated application of delay")-            Just FunDef -> if (isStable (stableTypes ?ctxt) (varType v)) then Visible-              else Hidden ("Variable " <> ppr v <> " is no longer in scope: It occurs in a function that is defined under a delay, is a of a non-stable type " <> ppr (varType v) <> ", and is bound outside delay")-            Nothing-              | either (const False) (any (Set.member v)) (earlier ?ctxt) ->-                if isStable (stableTypes ?ctxt) (varType v) then Visible-                else Hidden ("Variable " <> ppr v <> " is no longer in scope:" $$-                         "It occurs under delay" $$ "and is of type " <> ppr (varType v) <> ", which is not stable.")-              | Set.member v (current ?ctxt) -> Visible-              | isTemporal (varType v) && isRight (earlier ?ctxt) && userFunction v-                -> ImplUnboxed-              | otherwise -> Visible---- | A map from the syntax of a primitive of Asynchronous Rattus to 'Prim'.-primMap :: Map FastString Prim-primMap = Map.fromList-  [("Delay", Delay),-   ("delay", Delay),-   ("adv", Adv),-   ("select", Select),-   ("box", Box),-   ("unbox", Unbox)]----- | Checks whether a given variable is in fact an Asynchronous Rattus primitive.-isPrim :: GetCtxt => Var -> Maybe Prim-isPrim v-  | Just p <- Map.lookup v (primAlias ?ctxt) = Just p-  | otherwise = do-  (name,mod) <- getNameModule v-  if isRattModule mod then Map.lookup name primMap-  else Nothing----- | Checks whether a given expression is in fact a Asynchronous Rattus primitive.-isPrimExpr :: GetCtxt => LHsExpr GhcTc -> Maybe (Prim,Var)-isPrimExpr (L _ e) = isPrimExpr' e where-  isPrimExpr' :: GetCtxt => HsExpr GhcTc -> Maybe (Prim,Var)-  isPrimExpr' (HsVar _ (L _ v)) = fmap (,v) (isPrim v)-#if __GLASGOW_HASKELL__ >= 906-  isPrimExpr' (HsAppType _ e _ _) = isPrimExpr e-#else-  isPrimExpr' (HsAppType _ e _) = isPrimExpr e-#endif--  isPrimExpr' (XExpr (WrapExpr (HsWrap _ e))) = isPrimExpr' e-  isPrimExpr' (XExpr (ExpansionExpr (HsExpanded _ e))) = isPrimExpr' e-  isPrimExpr' (HsPragE _ _ e) = isPrimExpr e-#if __GLASGOW_HASKELL__ < 904-  isPrimExpr' (HsTick _ _ e) = isPrimExpr e-  isPrimExpr' (HsBinTick _ _ _ e) = isPrimExpr e-  isPrimExpr' (HsPar _ e) = isPrimExpr e-#else-  isPrimExpr' (XExpr (HsTick _ e)) = isPrimExpr e-  isPrimExpr' (XExpr (HsBinTick _ _ e)) = isPrimExpr e-  isPrimExpr' (HsPar _ _ e _) = isPrimExpr e-#endif--  isPrimExpr' _ = Nothing----- | This type class provides default implementations for 'check' and--- 'checkBind' for Haskell syntax that is not supported. These default--- implementations simply print an error message.-class NotSupported a where-  notSupported :: GetCtxt => SDoc -> CheckM a--instance NotSupported Bool where-  notSupported doc = printMessageCheck SevError ("Asynchronous Rattus does not support " <> doc)--instance NotSupported (Bool,Set Var) where-  notSupported doc = (,Set.empty) <$> notSupported doc----- | Add variables to the current context.-addVars :: Set Var -> Ctxt -> Ctxt-addVars vs c = c{current = vs `Set.union` current c }---- | Print a message with the current location.-printMessage' :: GetCtxt => Severity -> SDoc ->  CheckM ()-printMessage' sev doc =-  liftIO (modifyIORef (errorMsgs ?ctxt) ((sev ,srcLoc ?ctxt, doc) :))---- | Print a message with the current location. Returns 'False', if--- the severity is 'SevError' and otherwise 'True.-printMessageCheck :: GetCtxt =>  Severity -> SDoc -> CheckM Bool-printMessageCheck sev doc = printMessage' sev doc >>-  case sev of-    SevError -> return False-    _ -> return True
− src/AsyncRattus/Plugin/SingleTick.hs
@@ -1,226 +0,0 @@--- | This module implements the translation from the multi-tick--- calculus to the single tick calculus.--{-# LANGUAGE CPP #-}--module AsyncRattus.Plugin.SingleTick-  (toSingleTick) where--#if __GLASGOW_HASKELL__ >= 900-import GHC.Plugins-#else-import GhcPlugins-#endif--  -import AsyncRattus.Plugin.Utils-import Prelude hiding ((<>))-import Control.Monad.Trans.Writer.Strict-import Control.Monad.Trans.Class-import Data.List---- | Transform the given expression from the multi-tick calculus into--- the single tick calculus form.-toSingleTick :: CoreExpr -> CoreM CoreExpr-toSingleTick (Let (Rec bs) e) = do-  e' <- toSingleTick e-  bs' <- mapM (mapM toSingleTick) bs-  return (Let (Rec bs') e')-toSingleTick (Let (NonRec b e1) e2) = do-  e1' <- toSingleTick e1-  e2' <- toSingleTick e2-  return (Let (NonRec b e1') e2')-toSingleTick (Case e b ty alts) = do-  e' <- toSingleTick e-  alts' <- mapM ((\ (c,bs,f) -> fmap (\ x -> mkAlt c bs x) (toSingleTick f)) . getAlt) alts-  return (Case e' b ty alts')-toSingleTick (Cast e c) = do-  e' <- toSingleTick e-  return (Cast e' c)-toSingleTick (Tick t e) = do-  e' <- toSingleTick e-  return (Tick t e')-toSingleTick (Lam x e) = do-  (e', advs) <- runWriterT (extractAdv' e)-  advs' <- mapM (\ (x,a,b) -> fmap (\b' -> (x,a,b')) (toSingleTick b)) advs-  return (foldLets' advs' (Lam x e'))-toSingleTick (App e1 e2)-  | isDelayApp e1 = do-      (e2', advs) <- runWriterT (extractAdv e2)-      advs' <- mapM (mapM toSingleTick) advs-      return (foldLets advs' (App e1 e2'))-  | otherwise = do-      e1' <- toSingleTick e1-      e2' <- toSingleTick e2-      return (App e1' e2')--toSingleTick e@Type{} = return e-toSingleTick e@Var{} = return e-toSingleTick e@Lit{} = return e-toSingleTick e@Coercion{} = return e--foldLets :: [(Id,CoreExpr)] -> CoreExpr -> CoreExpr-foldLets ls e = foldl' (\e' (x,b) -> Let (NonRec x b) e') e ls--foldLets' :: [(Id,CoreExpr,CoreExpr)] -> CoreExpr -> CoreExpr-foldLets' ls e = foldl' (\e' (x,a,b) -> Let (NonRec x (App a b)) e') e ls--extractAdvApp :: CoreExpr -> CoreExpr -> WriterT [(Id,CoreExpr)] CoreM CoreExpr-extractAdvApp e1 e2-  | isVar e2 = return (App e1 e2)-  | otherwise = do-  x <- lift (mkSysLocalFromExpr (fsLit "adv") e2)-  tell [(x,e2)]-  return (App e1 (Var x))---- removes casts and ticks from a tree-filterTree :: CoreExpr -> CoreExpr-filterTree (Cast e _) = filterTree e-filterTree (Tick _ e) = filterTree e-filterTree e = e---extractSelectApp :: CoreExpr -> CoreExpr -> WriterT [(Id,CoreExpr)] CoreM CoreExpr-extractSelectApp e1 e2-  | isVar e' && isVar e2 = return (App e1 e2)-  | isVar e2 = do-    x <- lift (mkSysLocalFromExpr (fsLit "selectFreshVar") e')-    tell [(x, e')]-    return (App (App e (Var x)) e2)-  | isVar e' = do-    x <- lift (mkSysLocalFromExpr (fsLit "selectFreshVar") e2)-    tell [(x, e2)]-    return (App e1 (Var x))-  | otherwise = do-    x <- lift (mkSysLocalFromExpr (fsLit "selectFreshVar") e')-    y <- lift (mkSysLocalFromExpr (fsLit "selectFreshVar") e2)-    tell [(x, e')]-    tell [(y, e2)]-    return (App (App e (Var x)) (Var y))-  where (App e e') = filterTree e1----- This is used to pull adv out of delayed terms. The writer monad--- returns mappings from fresh variables to terms that occur as--- argument of adv.--- --- That is, occurrences of @adv t@ are replaced with @adv x@ (for some--- fresh variable @x@) and the pair @(x,t)@ is returned in the--- writer monad.-extractAdv :: CoreExpr -> WriterT [(Id,CoreExpr)] CoreM CoreExpr-extractAdv (App expr@(App e _) e2) | isSelectApp e = extractSelectApp expr e2-extractAdv e@(App e1 e2)-  | isAdvApp e1 = extractAdvApp e1 e2-  | isSelectApp e1 = extractSelectApp e1 e2-  | isDelayApp e1 = do-      (e2', advs) <- lift $ runWriterT (extractAdv e2)-      advs' <- mapM (mapM extractAdv) advs-      return (foldLets advs' (App e1 e2'))-  | isBoxApp e1 = lift $ toSingleTick e-  | otherwise = do-      e1' <- extractAdv e1-      e2' <- extractAdv e2-      return (App e1' e2')-extractAdv (Lam x e) = do-  (e', advs) <- lift $ runWriterT (extractAdv' e)-  advs' <- mapM (\ (x,a,b) -> fmap (\b' -> (x,b')) (extractAdvApp a b)) advs-  return (foldLets advs' (Lam x e'))-extractAdv (Case e b ty alts) = do-  e' <- extractAdv e-  alts' <- mapM ((\ (c,bs,f) -> fmap (\ x -> mkAlt c bs x) (extractAdv f)) . getAlt) alts-  return (Case e' b ty alts')-extractAdv (Cast e c) = do-  e' <- extractAdv e-  return (Cast e' c)-extractAdv (Tick t e) = do-  e' <- extractAdv e-  return (Tick t e')-extractAdv e@(Let Rec{} _) = lift $ toSingleTick e-extractAdv (Let (NonRec b e1) e2) = do-  e1' <- extractAdv e1-  e2' <- extractAdv e2-  return (Let (NonRec b e1') e2')-extractAdv e@Type{} = return e-extractAdv e@Var{} = return e-extractAdv e@Lit{} = return e-extractAdv e@Coercion{} = return e---- This is used to pull adv out of lambdas. The writer monad returns--- mappings from fresh variables to occurrences of adv and the term it--- is applied to.--- --- That is occurrences of @adv t@ are replaced with a fresh variable--- @x@ and the triple @(x,adv,t)@ is returned in the writer monad.--- For select a b, the triple @(x, select a, b) is returned in the writer monad.-extractAdv' :: CoreExpr -> WriterT [(Id,CoreExpr,CoreExpr)] CoreM CoreExpr-extractAdv' e@(App e1 e2)-  | isAdvApp e1 = do-       x <- lift (mkSysLocalFromExpr (fsLit "adv") e)-       tell [(x,e1,e2)]-       return (Var x)-  | isSelectApp e1 = do-      x <- lift (mkSysLocalFromExpr (fsLit "select") e)-      tell [(x,e1,e2)]-      return (Var x)-  | isDelayApp e1 = do-      (e2', advs) <- lift $ runWriterT (extractAdv e2)-      advs' <- mapM (mapM extractAdv') advs-      return (foldLets advs' (App e1 e2'))-  | isBoxApp e1 = lift $ toSingleTick e-  | otherwise = do-      e1' <- extractAdv' e1-      e2' <- extractAdv' e2-      return (App e1' e2')-extractAdv' (Lam x e) = do-  e' <- extractAdv' e-  return (Lam x e')-extractAdv' (Case e b ty alts) = do-  e' <- extractAdv' e-  alts' <- mapM ((\ (c,bs,f) -> fmap (\ x -> mkAlt c bs x) (extractAdv' f)) . getAlt) alts-  return (Case e' b ty alts')-extractAdv' (Cast e c) = do-  e' <- extractAdv' e-  return (Cast e' c)-extractAdv' (Tick t e) = do-  e' <- extractAdv' e-  return (Tick t e')-extractAdv' e@(Let Rec{} _) = lift $ toSingleTick e-extractAdv' (Let (NonRec b e1) e2) = do-  e1' <- extractAdv' e1-  e2' <- extractAdv' e2-  return (Let (NonRec b e1') e2')-extractAdv' e@Type{} = return e-extractAdv' e@Var{} = return e-extractAdv' e@Lit{} = return e-extractAdv' e@Coercion{} = return e----isDelayApp :: CoreExpr -> Bool-isDelayApp = isPrimApp (== "delay")--isBoxApp :: CoreExpr -> Bool-isBoxApp = isPrimApp (\occ -> occ == "Box" || occ == "box")--isAdvApp :: CoreExpr -> Bool-isAdvApp = isPrimApp (== "adv")--isSelectApp :: CoreExpr -> Bool-isSelectApp = isPrimApp (== "select")--isPrimApp :: (String -> Bool) -> CoreExpr -> Bool-isPrimApp p (App e e')-  | isType e' || not  (tcIsLiftedTypeKind(typeKind (exprType e'))) = isPrimApp p e-  | otherwise = False-isPrimApp p (Cast e _) = isPrimApp p e-isPrimApp p (Tick _ e) = isPrimApp p e-isPrimApp p (Var v) = isPrimVar p v-isPrimApp _ _ = False--isPrimVar :: (String -> Bool) -> Var -> Bool-isPrimVar p v = maybe False id $ do-  let name = varName v-  mod <- nameModule_maybe name-  let occ = getOccString name-  return (p occ-          && moduleNameString (moduleName mod) == "AsyncRattus.InternalPrimitives")
− src/AsyncRattus/Plugin/StableSolver.hs
@@ -1,83 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE CPP #-}----- | This module implements a constraint solver plugin for the--- 'Stable' type class.--module AsyncRattus.Plugin.StableSolver (tcStable) where--import AsyncRattus.Plugin.Utils-    ( getNameModule, isRattModule, isStable )--import Prelude hiding ((<>))--import GHC.Plugins-  (Type, Var, CommandLineOption,tyConSingleDataCon,-   mkCoreConApps,getTyVar_maybe)-import GHC.Core-import GHC.Tc.Types.Evidence-import GHC.Core.Class-import GHC.Tc.Types-import GHC.Tc.Types.Constraint--import Data.Set (Set)-import qualified Data.Set as Set-#if __GLASGOW_HASKELL__ >= 904-import GHC.Types.Unique.FM-#endif------ | Constraint solver plugin for the 'Stable' type class.-tcStable :: [CommandLineOption] -> Maybe TcPlugin-tcStable _ = Just $ TcPlugin-  { tcPluginInit = return ()-  , tcPluginSolve = \ () -> stableSolver-  , tcPluginStop = \ () -> return ()-#if __GLASGOW_HASKELL__ >= 904-  , tcPluginRewrite = \ () -> emptyUFM-#endif-  }---wrap :: Class -> Type -> EvTerm-wrap cls ty = EvExpr appDc-  where-    tyCon = classTyCon cls-    dc = tyConSingleDataCon tyCon-    appDc = mkCoreConApps dc [Type ty]--solveStable :: Set Var -> (Type, (Ct,Class)) -> Maybe (EvTerm, Ct)-solveStable c (ty,(ct,cl))-  | isStable c ty = Just (wrap cl ty, ct)-  | otherwise = Nothing--#if __GLASGOW_HASKELL__ >= 904-stableSolver :: EvBindsVar -> [Ct] -> [Ct] -> TcPluginM TcPluginSolveResult-stableSolver _ given wanted = do-#else-stableSolver :: [Ct] -> [Ct] -> [Ct] -> TcPluginM TcPluginResult-stableSolver given _derived wanted = do-#endif--  let chSt = concatMap filterCt wanted-  let haveSt = Set.fromList $ concatMap (filterTypeVar . fst) $ concatMap filterCt given-  case mapM (solveStable haveSt) chSt of-    Just evs -> return $ TcPluginOk evs []-    Nothing -> return $ TcPluginOk [] []--  where-#if __GLASGOW_HASKELL__ >= 908-        filterCt ct@(CDictCan (DictCt {di_cls = cl, di_tys = [ty]}))-#else-        filterCt ct@(CDictCan {cc_class = cl, cc_tyargs = [ty]})-#endif-          = case getNameModule cl of-                Just (name,mod)-                  | isRattModule mod && name == "Stable" -> [(ty,(ct,cl))]-                _ -> []-        filterCt _ = []-        filterTypeVar ty = case getTyVar_maybe ty of-          Just v -> [v]-          Nothing -> []
− src/AsyncRattus/Plugin/Strictify.hs
@@ -1,64 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE CPP #-}-module AsyncRattus.Plugin.Strictify-  (checkStrictData, SCxt (..)) where-import Prelude hiding ((<>))-import Control.Monad-import AsyncRattus.Plugin.Utils--import GHC.Plugins-import GHC.Types.Tickish--data SCxt = SCxt {srcSpan :: SrcSpan}---- | Checks whether the given expression uses non-strict data types--- and issues a warning if it finds any such use.-checkStrictData :: SCxt -> CoreExpr -> CoreM ()-checkStrictData ss (Let (NonRec _ e1) e2) = -  checkStrictData ss e1 >> checkStrictData ss e2-checkStrictData ss (Case e _ _ alts) = do-  checkStrictData ss e-  mapM_ ((\(_,_,e) ->  checkStrictData ss e) . getAlt) alts-checkStrictData ss (Let (Rec es) e) = do-  mapM_ (\ (_,e) -> checkStrictData ss e) es-  checkStrictData ss e-checkStrictData ss (Lam _ e) = checkStrictData ss e-checkStrictData ss (Cast e _) = checkStrictData ss e-checkStrictData ss (Tick (SourceNote span _) e) = -  checkStrictData (ss{srcSpan = fromRealSrcSpan span}) e-checkStrictData ss (App e1 e2)-  | ignoreArgument e1 = return ()-  | otherwise = do -    when (not (isType e2) && tcIsLiftedTypeKind(typeKind (exprType e2))-        && not (isStrict (exprType e2)) && not (isDeepseqForce e2) && not (isLit e2))-          (printMessage SevWarning (srcSpan ss)-               (text "The use of lazy type " <> ppr (exprType e2) <> " may lead to memory leaks. Use Control.DeepSeq.force on lazy types."))-    checkStrictData ss e1-    checkStrictData ss e2-checkStrictData _ss _ = return ()--isLit :: CoreExpr -> Bool-isLit Lit{} = True-isLit (App (Var v) Lit{}) -  | Just (name,mod) <- getNameModule v = mod == "GHC.CString" && name == "unpackCString#"-isLit _ = False---ignoreArgument :: CoreExpr -> Bool-ignoreArgument (Var v) =-  case getNameModule v of-    Just (name, mod) -> -      ((mod == "GHC.Exts" || mod == "GHC.IsList") && (name == "fromList" || name == "fromListN")) ||-      (mod == "Data.String" && name == "fromString") ||-      (mod == "GHC.Stack.Types" && name == "pushCallStack") ||-      (mod == "Data.Text.Internal" && name == "pack")-    _ -> False-ignoreArgument (App x _) = ignoreArgument x-ignoreArgument _ = False--isDeepseqForce :: CoreExpr -> Bool-isDeepseqForce (App (App (App (Var v) _) _) _) =-  case getNameModule v of-    Just (name, mod) -> mod == "Control.DeepSeq" && name == "force"-    _ -> False-isDeepseqForce _ = False
− src/AsyncRattus/Plugin/Transform.hs
@@ -1,143 +0,0 @@-{-# LANGUAGE TupleSections #-}-module AsyncRattus.Plugin.Transform (-    transform-) where--import GHC.Core.Opt.Monad-import GHC.Plugins-import AsyncRattus.Plugin.PrimExpr-import AsyncRattus.Plugin.Utils-import Data.Maybe (fromJust)-import Prelude hiding ((<>))-import Data.Functor ((<&>))-import Control.Applicative ((<|>))-import Data.Tuple (swap)--data Ctx = Ctx {-    fresh :: Maybe Var-}--emptyCtx :: Ctx-emptyCtx = Ctx {-    fresh = Nothing-}--replaceVar :: Var -> Var -> Expr Var ->  Expr Var-replaceVar match rep (Var v) = if v == match then Var rep else Var v-replaceVar match rep (App e e') = App (replaceVar match rep e) (replaceVar match rep e')-replaceVar match rep (Tick _ e) = replaceVar match rep e-replaceVar match rep (Lam v e) = Lam (if v == match then rep else v) (replaceVar match rep e)-replaceVar match rep (Let (NonRec b e') e) =-  Let (NonRec newB (replaceVar  match rep e')) (replaceVar match rep e)-  where newB = if b == match then rep else b-replaceVar match rep (Cast e _) = replaceVar match rep e-replaceVar match rep (Case e b t alts) =-  Case newExpr newB t (map (\(Alt con binds expr) -> Alt con (map (\v -> if v == match then rep else v) binds) (replaceVar match rep expr)) alts)-  where newExpr = replaceVar match rep e-        newB = if b == match then rep else b-replaceVar _ _ e = e--transformPrim :: Ctx -> Expr Var -> CoreM (Expr Var, PrimInfo)-transformPrim ctx expr@(App e e') = case isPrimExpr expr of-  Just primInfo@(AdvApp f _) -> do-    varAdv' <- adv'Var-    let newE = replaceVar f varAdv' e-    return (App (App newE e') (Var (fromJust $ fresh ctx)), primInfo)-  Just primInfo@(SelectApp f _ _) -> do-    varSelect' <- select'Var-    let newE = replaceVar f varSelect' e-    return (App (App newE e') (Var (fromJust $ fresh ctx)), primInfo)-  Just (DelayApp _ t) -> do-    bigDelayVar <- bigDelay-    inputValueV <- inputValueVar-    let inputValueType = mkTyConTy inputValueV -    inpVar <- mkSysLocalM (fsLit "inpV") inputValueType inputValueType-    let ctx' = ctx {fresh = Just inpVar}-    (newExpr, maybePrimInfo) <- transform' ctx' e'-    let primInfo = fromJust maybePrimInfo-    let lambdaExpr = Lam inpVar newExpr-    clockCode <- constructClockExtractionCode primInfo-    return (App (App (App (Var bigDelayVar) (Type t)) clockCode) lambdaExpr, primInfo)-  Just primInfo -> do-        error $ showSDocUnsafe $ text "transformPrim: Cannot transform " <> ppr (prim primInfo)-  Nothing -> error "Cannot transform non-prim applications"-transformPrim _ _ = do-  error "Cannot transform anything else than prim applications"---transform :: CoreExpr -> CoreM CoreExpr-transform expr = fst <$> transform' emptyCtx expr--transform' :: Ctx -> CoreExpr -> CoreM (CoreExpr, Maybe PrimInfo)-transform' ctx expr@(App e e') = case isPrimExpr expr of-    Just (BoxApp _) -> do-        (newExpr, primInfo) <- transform' ctx e'-        return (App e newExpr, primInfo)-    (Just _) -> do-        (newExpr, primInfo) <- transformPrim ctx expr-        return (newExpr, Just primInfo)-    Nothing -> do-        (newExpr, primInfo) <- transform' ctx e-        (newExpr', primInfo') <- transform' ctx e'-        return (App newExpr newExpr', primInfo <|> primInfo')-transform' ctx (Lam b rhs) = do-    (newExpr, primInfo) <- transform' ctx rhs-    return (Lam b newExpr, primInfo)-transform' ctx (Let (NonRec b rhs) e) = do-    (newRhs, primInfo) <- transform' ctx rhs-    (newExpr, primInfo') <- transform' ctx e-    return (Let (NonRec b newRhs) newExpr, primInfo <|> primInfo')-transform' ctx (Let (Rec binds) e) = do-    transformedBinds <- mapM (\(b, bindE) -> fmap (b,) (transform' ctx bindE)) binds-    (e', mPi) <- transform' ctx e-    let primInfos = map (\(_, (_, p)) -> p) transformedBinds-    let firstPrimInfo = foldl (<|>) mPi primInfos-    newBinds <- mapM (\(b, (e, _)) -> return (b, e)) transformedBinds-    return (Let (Rec newBinds) e', firstPrimInfo)-transform' ctx (Case e b t alts) = do-    -- The checking pass has ensured that there are not advances on different-    -- clocks. Thus we can just pick the first PrimInfo we find.-    (expr, primInfo) <- transform' ctx e--    -- For each alternative, transform it and save the maybePrimInfo-value-    transformed <- mapM (\(Alt con binds expr) -> transform' ctx expr <&> fmap (Alt con binds) . swap) alts--    -- Of all the primInfos we have, pick the first one. This is safe because-    -- the checking pass has ensured that the clocks of all primitives.-    let firstPrimInfo = foldl (\acc (p, _) -> acc <|> p) primInfo transformed-    let alts' = map snd transformed-    return (Case expr b t alts', firstPrimInfo)-transform' ctx (Cast e c) = do (e' , p) <- transform' ctx e; return (Cast e' c, p)-transform' ctx (Tick t e) = do (e' , p) <- transform' ctx e; return (Tick t e', p)-transform' _ e = return (e, Nothing)--constructClockExtractionCode :: PrimInfo -> CoreM CoreExpr-constructClockExtractionCode (AdvApp _ arg) = createClockCode arg-constructClockExtractionCode (SelectApp _ arg arg2) = clockUnion arg arg2-constructClockExtractionCode primInfo = error $ "Cannot construct clock for prim " ++ showSDocUnsafe (ppr (prim primInfo))---createClockCode :: (Var, Type) -> CoreM CoreExpr-createClockCode (argV, argT) = do-    extractClock <- extractClockVar-    return $ App (App (Var extractClock) (Type argT)) (Var argV)---- Generate code for union of two clocks.--- clockUnion (aVar, aType) (bVar, bType) returns the AST for:---  Set.union (extractClock aVar) (extractClock bVar)--clockUnion :: (Var,Type) -> (Var, Type) -> CoreM CoreExpr-clockUnion arg arg2 = do-    clock1Code <- createClockCode arg-    clock2Code <- createClockCode arg2-    unionVar' <- unionVar-    return $-        App-        (-            App-            (-                   (Var unionVar')-            )-            clock1Code-        )-        clock2Code
− src/AsyncRattus/Plugin/Utils.hs
@@ -1,380 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE CPP #-}--module AsyncRattus.Plugin.Utils (-  printMessage,-  Severity(..),-  isRattModule,-  adv'Var,-  select'Var,-  bigDelay,-  inputValueVar,-  extractClockVar,-  unionVar,-  isGhcModule,-  getNameModule,-  isStable,-  isStrict,-  isTemporal,-  userFunction,-  typeClassFunction,-  getVar,-  getMaybeVar,-  getModuleFS,-  isVar,-  isType,-  mkSysLocalFromVar,-  mkSysLocalFromExpr,-  fromRealSrcSpan,-  noLocationInfo,-  mkAlt,-  getAlt,-  splitForAllTys')-  where--#if __GLASGOW_HASKELL__ >= 908-import GHC.Types.Error (ResolvedDiagnosticReason (..))-#endif--#if __GLASGOW_HASKELL__ >= 906-import GHC.Builtin.Types.Prim-import GHC.Tc.Utils.TcType-#endif-#if __GLASGOW_HASKELL__ >= 904-import qualified GHC.Data.Strict as Strict-import Control.Concurrent.MVar (readMVar)-#else-import Data.IORef (readIORef)-#endif  -import GHC.Utils.Logger-import GHC.Plugins-import GHC.Utils.Error hiding (errorMsg)-import GHC.Utils.Monad---import GHC.Types.Name.Cache (NameCache(nsNames), lookupOrigNameCache, OrigNameCache)-import qualified GHC.Types.Name.Occurrence as Occurrence-import GHC.Types.TyThing--import Prelude hiding ((<>))-import Data.Set (Set)-import qualified Data.Set as Set-import Data.Char-import Data.Maybe---getMaybeVar :: CoreExpr -> Maybe Var-getMaybeVar (App e e')-  | isType e' || not  (tcIsLiftedTypeKind (typeKind (exprType e'))) = getMaybeVar e-  | otherwise = Nothing-getMaybeVar (Cast e _) = getMaybeVar e-getMaybeVar (Tick _ e) = getMaybeVar e-getMaybeVar (Var v) = Just v-getMaybeVar _ = Nothing--getVar :: CoreExpr -> Var-getVar = fromJust . getMaybeVar--isVar :: CoreExpr -> Bool-isVar = isJust . getMaybeVar--isType Type {} = True-isType (App e _) = isType e-isType (Cast e _) = isType e-isType (Tick _ e) = isType e-isType _ = False--#if __GLASGOW_HASKELL__ >= 906-isFunTyCon = isArrowTyCon-repSplitAppTys = splitAppTysNoView-#endif- --printMessage :: (HasDynFlags m, MonadIO m, HasLogger m) =>-                Severity -> SrcSpan -> SDoc -> m ()-printMessage sev loc doc = do-#if __GLASGOW_HASKELL__ >= 908-  logger <- getLogger-  liftIO $ putLogMsg logger (logFlags logger)-    (MCDiagnostic sev (if sev == SevError then ResolvedDiagnosticReason ErrorWithoutFlag else ResolvedDiagnosticReason WarningWithoutFlag) Nothing) loc doc-#elif __GLASGOW_HASKELL__ >= 906-  logger <- getLogger-  liftIO $ putLogMsg logger (logFlags logger)-    (MCDiagnostic sev (if sev == SevError then ErrorWithoutFlag else WarningWithoutFlag) Nothing) loc doc-#elif __GLASGOW_HASKELL__ >= 904-  logger <- getLogger-  liftIO $ putLogMsg logger (logFlags logger)-    (MCDiagnostic sev (if sev == SevError then ErrorWithoutFlag else WarningWithoutFlag)) loc doc-#else-   dflags <- getDynFlags-   logger <- getLogger-   liftIO $ putLogMsg logger dflags NoReason sev loc doc-#endif--instance Ord FastString where-   compare = uniqCompareFS--{--******************************************************-*             Extracting variables                   *-******************************************************--}---origNameCache :: CoreM OrigNameCache-origNameCache = do-  hscEnv <- getHscEnv-#if __GLASGOW_HASKELL__ >= 904-  let nameCache = hsc_NC hscEnv-  liftIO $ readMVar (nsNames nameCache)-#else-  nameCache <- liftIO $ readIORef (hsc_NC hscEnv)-  return $ nsNames nameCache-#endif---getNamedThingFromModuleAndOccName :: String -> OccName -> CoreM TyThing-getNamedThingFromModuleAndOccName moduleName occName = do-  origNameCache <- origNameCache-  case filter ((moduleName ==) . unpackFS . getModuleFS) (moduleEnvKeys origNameCache) of-    mod : _ -> lookupThing $ fromJust $ lookupOrigNameCache origNameCache mod occName-    _ -> error ( ("internal error: cannot find module " ++ moduleName ++ "; " ++ show (map (unpackFS . getModuleFS) $ moduleEnvKeys origNameCache)))--getVarFromModule :: String -> String -> CoreM Var-getVarFromModule moduleName = fmap tyThingId . getNamedThingFromModuleAndOccName moduleName . mkOccName Occurrence.varName--getTyConFromModule :: String -> String -> CoreM TyCon-getTyConFromModule moduleName = fmap tyThingTyCon . getNamedThingFromModuleAndOccName moduleName . mkOccName Occurrence.tcName--adv'Var :: CoreM Var-adv'Var = getVarFromModule "AsyncRattus.InternalPrimitives" "adv'"--select'Var :: CoreM Var-select'Var = getVarFromModule "AsyncRattus.InternalPrimitives" "select'"--bigDelay :: CoreM Var-bigDelay = getVarFromModule "AsyncRattus.InternalPrimitives" "Delay"--inputValueVar :: CoreM TyCon-inputValueVar = getTyConFromModule "AsyncRattus.InternalPrimitives" "InputValue"--extractClockVar :: CoreM Var-extractClockVar = getVarFromModule "AsyncRattus.InternalPrimitives" "extractClock"--unionVar :: CoreM Var-unionVar = getVarFromModule "AsyncRattus.InternalPrimitives" "clockUnion"--rattModules :: Set FastString-rattModules = Set.fromList ["AsyncRattus.InternalPrimitives","AsyncRattus.Channels"]--getModuleFS :: Module -> FastString-getModuleFS = moduleNameFS . moduleName--isRattModule :: FastString -> Bool-isRattModule = (`Set.member` rattModules)--isGhcModule :: FastString -> Bool-isGhcModule = (== "GHC.Types")--getNameModule :: NamedThing a => a -> Maybe (FastString, FastString)-getNameModule v = do-  let name = getName v-  mod <- nameModule_maybe name-  return (getOccFS name,moduleNameFS (moduleName mod))----- | The set of stable built-in types.-ghcStableTypes :: Set FastString-ghcStableTypes = Set.fromList ["Word","Int","Bool","Float","Double","Char", "IO"]--isGhcStableType :: FastString -> Bool-isGhcStableType = (`Set.member` ghcStableTypes)---newtype TypeCmp = TC Type--instance Eq TypeCmp where-  (TC t1) == (TC t2) = eqType t1 t2--instance Ord TypeCmp where-  compare (TC t1) (TC t2) = nonDetCmpType t1 t2--isTemporal :: Type -> Bool-isTemporal t = isTemporalRec 0 Set.empty t---isTemporalRec :: Int -> Set TypeCmp -> Type -> Bool-isTemporalRec d _ _ | d == 100 = False-isTemporalRec _ pr t | Set.member (TC t) pr = False-isTemporalRec d pr t = do-  let pr' = Set.insert (TC t) pr-  case splitTyConApp_maybe t of-    Nothing -> False-    Just (con,args) ->-      case getNameModule con of-        Nothing -> False-        Just (name,mod)-          -- If it's a Rattus type constructor check if it's a box-          | isRattModule mod && (name == "Box" || name == "O") -> True-          | isFunTyCon con -> or (map (isTemporalRec (d+1) pr') args)-          | isAlgTyCon con ->-            case algTyConRhs con of-              DataTyCon {data_cons = cons} -> or (map check cons)-                where check con = case dataConInstSig con args of-                        (_, _,tys) -> or (map (isTemporalRec (d+1) pr') tys)-              _ -> or (map (isTemporalRec (d+1) pr') args)-        _ -> False----- | Check whether the given type is stable. This check may use--- 'Stable' constraints from the context.--isStable :: Set Var -> Type -> Bool-isStable c t = isStableRec c 0 Set.empty t---- | Check whether the given type is stable. This check may use--- 'Stable' constraints from the context.--isStableRec :: Set Var -> Int -> Set TypeCmp -> Type -> Bool--- To prevent infinite recursion (when checking recursive types) we--- keep track of previously checked types. This, however, is not--- enough for non-regular data types. Hence we also have a counter.-isStableRec _ d _ _ | d == 100 = True-isStableRec _ _ pr t | Set.member (TC t) pr = True-isStableRec c d pr t = do-  let pr' = Set.insert (TC t) pr-  case splitTyConApp_maybe t of-    Nothing -> case getTyVar_maybe t of-      Just v -> -- if it's a type variable, check the context-        v `Set.member` c-      Nothing -> False-    Just (con,args) ->-      case getNameModule con of-        Nothing -> False-        Just (name,mod)-          | mod == "GHC.Num.Integer" && name == "Integer" -> True-          | mod == "Data.Text.Internal" && name == "Text" -> True-          -- If it's a Rattus type constructor check if it's a box-          | isRattModule mod && (name == "Box" || name == "Chan") -> True-            -- If its a built-in type check the set of stable built-in types-          | isGhcModule mod -> isGhcStableType name-          {- deal with type synonyms (does not seem to be necessary (??))-           | Just (subst,ty,[]) <- expandSynTyCon_maybe con args ->-             isStableRec c (d+1) pr' (substTy (extendTvSubstList emptySubst subst) ty) -}-          | isAlgTyCon con ->-            case algTyConRhs con of-              DataTyCon {data_cons = cons, is_enum = enum}-                | enum -> True-                | all hasStrictArgs cons ->-                  and  (map check cons)-                | otherwise -> False-                where check con = case dataConInstSig con args of-                        (_, _,tys) -> and (map (isStableRec c (d+1) pr') tys)-              TupleTyCon {} -> null args-              _ -> False-        _ -> False----isStrict :: Type -> Bool-isStrict t = isStrictRec 0 Set.empty t--splitForAllTys' :: Type -> ([TyCoVar], Type)-splitForAllTys' = splitForAllTyCoVars---- | Check whether the given type is stable. This check may use--- 'Stable' constraints from the context.--isStrictRec :: Int -> Set TypeCmp -> Type -> Bool--- To prevent infinite recursion (when checking recursive types) we--- keep track of previously checked types. This, however, is not--- enough for non-regular data types. Hence we also have a counter.-isStrictRec d _ _ | d == 100 = True-isStrictRec _ pr t | Set.member (TC t) pr = True-isStrictRec d pr t = do-  let pr' = Set.insert (TC t) pr-  let (_,t') = splitForAllTys' t-  let (c, tys) = repSplitAppTys t'-  if isJust (getTyVar_maybe c) then and (map (isStrictRec (d+1) pr') tys)-  else  case splitTyConApp_maybe t' of-    Nothing -> isJust (getTyVar_maybe t)-    Just (con,args) ->-      case getNameModule con of-        Nothing -> False-        Just (name,mod)-          | mod == "GHC.Num.Integer" && name == "Integer" -> True-          | mod == "Data.Text.Internal" && name == "Text" -> True-          | mod == "GHC.IORef" && name == "IORef" -> True-          | mod == "GHC.MVar" && name == "MVar" -> True-          -- If it's a Rattus type constructor check if it's a box-          | isRattModule mod && (name == "Box" || name == "Chan" || name == "O" || name == "Output") -> True-            -- If its a built-in type check the set of stable built-in types-          | isGhcModule mod -> isGhcStableType name-          {- deal with type synonyms (does not seem to be necessary (??))-           | Just (subst,ty,[]) <- expandSynTyCon_maybe con args ->-             isStrictRec c (d+1) pr' (substTy (extendTvSubstList emptySubst subst) ty) -}-          | isFunTyCon con -> True-          | isAlgTyCon con ->-            case algTyConRhs con of-              DataTyCon {data_cons = cons, is_enum = enum}-                | enum -> True-                | all hasStrictArgs cons ->-                  and  (map check cons)-                | otherwise -> False-                where check con = case dataConInstSig con args of-                        (_, _,tys) -> and (map (isStrictRec (d+1) pr') tys)-              TupleTyCon {} -> null args-              NewTyCon {nt_rhs = ty} -> isStrictRec (d+1) pr' ty-              _ -> False-          | otherwise -> False------hasStrictArgs :: DataCon -> Bool-hasStrictArgs con = all isBanged (dataConImplBangs con)--userFunction :: Var -> Bool-userFunction v-  | typeClassFunction v = True-  | otherwise = -    case getOccString (getName v) of-      (c : _)-        | isUpper c || c == '$' || c == ':' -> False-        | otherwise -> True-      _ -> False--typeClassFunction :: Var -> Bool-typeClassFunction v =-  case getOccString (getName v) of-    ('$' : 'c' : _) -> True-    ('$' : 'f' : _) -> True-    _ -> False--mkSysLocalFromVar :: MonadUnique m => FastString -> Var -> m Id-mkSysLocalFromVar lit v = mkSysLocalM lit (varMult v) (varType v)- -mkSysLocalFromExpr :: MonadUnique m => FastString -> CoreExpr -> m Id-mkSysLocalFromExpr lit e = mkSysLocalM lit oneDataConTy (exprType e)- - -fromRealSrcSpan :: RealSrcSpan -> SrcSpan-#if __GLASGOW_HASKELL__ >= 904-fromRealSrcSpan span = RealSrcSpan span Strict.Nothing-#else-fromRealSrcSpan span = RealSrcSpan span Nothing-#endif--instance Ord SrcSpan where-  compare (RealSrcSpan s _) (RealSrcSpan t _) = compare s t-  compare RealSrcSpan{} _ = LT-  compare _ _ = GT--noLocationInfo :: SrcSpan-noLocationInfo = UnhelpfulSpan UnhelpfulNoLocationInfo--mkAlt c args e = Alt c args e-getAlt (Alt c args e) = (c, args, e)
− src/AsyncRattus/Primitives.hs
@@ -1,21 +0,0 @@--- | The language primitives of Async Rattus. Note that the typing---  rules for 'delay', 'adv','select' and 'box' are more restrictive---  than the Haskell types that are indicated. The stricter Async---  Rattus typing rules for these primitives are given below.--{-# LANGUAGE TypeOperators #-}-module AsyncRattus.Primitives-  (O-  ,Box-  ,Select(..)-  ,delay-  ,adv-  ,promote-  ,box-  ,unbox-  ,select-  ,never-  ,Stable-  ,Continuous-  ) where-import AsyncRattus.InternalPrimitives
− src/AsyncRattus/Signal.hs
@@ -1,412 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies #-}-{-# OPTIONS -fplugin=AsyncRattus.Plugin #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE CPP #-}----- | Programming with signals.--module AsyncRattus.Signal-  ( map-  , mkInputSig-  , getInputSig-  , filterMap-  , filterMapAwait-  , filter-  , filterAwait-  , trigger-  , triggerAwait-  , mapAwait-  , switch-  , switchS-  , switchAwait-  , interleave-  , mkSig-  , mkBoxSig-  , current-  , future-  , const-  , scan-  , scanC-  , scanAwait-  , scanAwaitC-  , scanMap-  , Sig(..)-  , zipWith-  , zipWith3-  , zip-  , cond-  , update-  , integral-  , derivative-  )--where--import AsyncRattus-import AsyncRattus.Channels-import Prelude hiding (map, const, zipWith, zipWith3, zip, filter)-import Data.VectorSpace-import Data.Ratio ((%))--- TODO: InternalPrimitives is only used to implment instance of--- Continuous. Replace this manual instance declaration with Template--- Haskell.-import AsyncRattus.InternalPrimitives--infixr 5 :::---- | @Sig a@ is a stream of values of type @a@.-data Sig a = !a ::: !(O (Sig a))--instance Producer (Sig a) a where-  getCurrent p = Just' (current p)-  getNext p cb = cb (future p)--newtype SigMaybe a = SigMaybe (Sig (Maybe' a))--instance Producer (SigMaybe a) a where-  getCurrent (SigMaybe p) = current p-  getNext (SigMaybe p) cb = cb (delay (SigMaybe (adv (future p))))---- | Get the current value of a signal.-current :: Sig a -> a-current (x ::: _) = x----- | Get the future the signal.-future :: Sig a -> O (Sig a)-future (_ ::: xs) = xs---- | Apply a function to the value of a signal.-map :: Box (a -> b) -> Sig a -> Sig b-map f (x ::: xs) = unbox f x ::: delay (map f (adv xs))---- | Variant of 'getInput' that returns a signal instead of a boxed--- delayed computation.-getInputSig :: IO (Box (O (Sig a)) :* (a -> IO ()))-getInputSig = do (s :* cb) <- getInput-                 return (mkBoxSig s :* cb)---- | Turn a producer into a signal. This is a variant of 'mkInput'--- that returns a signal instead of a boxed delayed computation.-mkInputSig :: Producer p a => p -> IO (Box (O (Sig a)))-mkInputSig p = mkBoxSig <$> mkInput p----- | This function is essentially the composition of 'filter' with--- 'map'. The signal produced by @filterMap f s@ has the value @v@--- whenever @s@ has the value @u@ such that @unbox f u = Just' v@.-filterMap :: Box (a -> Maybe' b) -> Sig a -> IO (Box (O (Sig b)))-filterMap f s = mkInputSig (SigMaybe (map f s))---- | This function is similar to 'filterMap' but takes a delayed--- signal (type @O (Sig a)@) as an argument instead of a signal (@Sig--- a@).-filterMapAwait :: Box (a -> Maybe' b) -> O (Sig a) -> IO (Box (O (Sig b)))-filterMapAwait f s = mkInputSig (delay (SigMaybe (map f (adv s))))---- | Filter the given signal using a predicate. The signal produced by--- @filter p s@ contains only values from @s@ that satisfy the--- predicate @p@.-filter :: Box (a -> Bool) -> Sig a -> IO (Box (O (Sig a)))-filter p = filterMap (box (\ x -> if unbox p x then Just' x else Nothing'))---- | This function is similar to 'filter' but takes a delayed signal--- (type @O (Sig a)@) as an argument instead of a signal (@Sig a@).-filterAwait :: Box (a -> Bool) -> O (Sig a) -> IO (Box (O (Sig a)))-filterAwait p = filterMapAwait (box (\ x -> if unbox p x then Just' x else Nothing'))----- | This function is a variant of 'zipWith'. Whereas @zipWith f xs--- ys@ produces a new value whenever @xs@ or @ys@ produce a new value,--- @trigger f xs ys@ only produces a new value when xs produces a new--- value.------ Example:------ >                      xs:  1 2 3     2--- >                      ys:  1     0 5 2--- >--- > zipWith (box (+)) xs ys:  2 3 4 3 8 4--- > trigger (box (+)) xy ys:  2     3 8 4--trigger :: (Stable a, Stable b) => Box (a -> b -> c) -> Sig a -> Sig b -> IO (Box (Sig c))-trigger f (a ::: as) bs@(b:::_) = do s <- triggerAwait f as bs-                                     return (box (unbox f a b ::: unbox s))--- | This function is similar to 'trigger' but takes a delayed signal--- (type @O (Sig a)@) as an argument instead of a signal (@Sig a@).-triggerAwait :: Stable b => Box (a -> b -> c) -> O (Sig a) -> Sig b -> IO (Box (O (Sig c)))-triggerAwait f as bs = mkBoxSig <$> mkInput (box SigMaybe `mapO` (trig f as bs)) where-  trig :: Stable b => Box (a -> b -> c) -> O (Sig a) -> Sig b -> O (Sig (Maybe' c))-  trig f as (b ::: bs) =-    delay (case select as bs of-            Fst (a' ::: as') bs' -> Just' (unbox f a' b) ::: trig f as' (b ::: bs')-            Snd as' bs' -> Nothing' ::: trig f as' bs'-            Both (a' ::: as') (b' ::: bs') -> Just' (unbox f a' b') ::: trig f as' (b' ::: bs')-          )---- | A version of @map@ for delayed signals.-mapAwait :: Box (a -> b) -> O (Sig a) -> O (Sig b)-mapAwait f d = delay (map f (adv d))---- | Turns a boxed delayed computation into a delayed signal.-mkSig :: Box (O a) -> O (Sig a)-mkSig b = delay (adv (unbox b) ::: mkSig b)---- | Variant of 'mkSig' that returns a boxed delayed signal-mkBoxSig :: Box (O a) -> Box (O (Sig a))-mkBoxSig b = box (mkSig b)----- | Construct a constant signal that never updates.-const :: a -> Sig a-const x = x ::: never---- | Similar to Haskell's 'scanl'.------ > scan (box f) x (v1 ::: v2 ::: v3 ::: ... ) == (x `f` v1) ::: ((x `f` v1) `f` v2) ::: ...------ Note: Unlike 'scanl', 'scan' starts with @x `f` v1@, not @x@.--scan :: (Continuous b) => Box(b -> a -> b) -> b -> Sig a -> Sig b-scan f acc (a ::: as) = acc' ::: delay (scan f (unbox accBox) (adv as))-  where acc' = unbox f acc a-        accBox = promote acc'--scanC :: (Continuous b) => Box(b -> a -> C b) -> b -> Sig a -> C (Sig b)-scanC f acc (a ::: as) = do-    acc' <- unbox f acc a-    let accBox = promote acc'-    fut <- delayC $ delay (scanC f (unbox accBox) (adv as))-    return (acc' ::: fut)-  where -        --- | Like 'scan', but uses a delayed signal.-scanAwait :: (Continuous b) => Box (b -> a -> b) -> b -> O (Sig a) -> Sig b-scanAwait f acc as = acc ::: delay (scan f (unbox accBox) (adv as))-  where accBox = promote acc --scanAwaitC :: (Continuous b) => Box (b -> a -> C b) -> b -> O (Sig a) -> C (Sig b)-scanAwaitC f acc as = do -    fut <- delayC $ delay (scanC f (unbox accBox) (adv as))-    return (acc ::: fut)-  where accBox = promote acc ---- | 'scanMap' is a composition of 'map' and 'scan':------ > scanMap f g x === map g . scan f x-scanMap :: (Continuous b) => Box (b -> a -> b) -> Box (b -> c) -> b -> Sig a -> Sig c-scanMap f p acc (a ::: as) =  unbox p acc' ::: delay (scanMap f p (unbox accBox) (adv as))-  where acc' = unbox f acc a-        accBox = promote acc'---- | This function allows to switch from one signal to another one--- dynamically. The signal defined by @switch xs ys@ first behaves--- like @xs@, but as soon as @ys@ produces a new value, @switch xs ys@--- behaves like @ys@.------ Example:------ >           xs: 1 2 3 4 5   6 7 8   9--- >           ys:         1 2   3 4 5 6--- >--- > switch xs ys: 1 2 3 1 2 4   3 4 5 6-switch :: Sig a -> O (Sig a) -> Sig a-switch (x ::: xs) d = x ::: delay (case select xs d of-                                     Fst   xs'  d'  -> switch xs' d'-                                     Snd   _    d'  -> d'-                                     Both  _    d'  -> d')---- | This function is similar to 'switch', but the (future) second--- signal may depend on the last value of the first signal.-switchS :: Continuous a => Sig a -> O (a -> Sig a) -> Sig a-switchS (x ::: xs) d = x ::: delay (case select xs d of-                                     Fst   xs'  d'  -> switchS xs' d'-                                     Snd   _    f  -> f (unbox xBox)-                                     Both  _    f  -> f (unbox xBox))-  where xBox = promote x---- | This function is similar to 'switch' but works on delayed signals--- instead of signals.-switchAwait :: O (Sig a) -> O (Sig a) -> O (Sig a)-switchAwait xs ys = delay (case select xs ys of-                                  Fst  xs'  d'  -> switch xs' d'-                                  Snd  _    d'  -> d'-                                  Both _    d'  -> d')---- | This function interleaves two signals producing a new value @v@--- whenever either input stream produces a new value @v@. In case the--- input signals produce a new value simultaneously, the function--- argument is used break ties, i.e. to compute the new output value based--- on the two new input values------ Example:------ >                         xs: 1 3   5 3 1 3--- >                         ys:   0 2   4--- >--- > interleave (box (+)) xs ys: 1 3 2 5 7 1 3-interleave :: Box (a -> a -> a) -> O (Sig a) -> O (Sig a) -> O (Sig a)-interleave f xs ys = delay (case select xs ys of-                              Fst (x ::: xs') ys' -> x ::: interleave f xs' ys'-                              Snd xs' (y ::: ys') -> y ::: interleave f xs' ys'-                              Both (x ::: xs') (y ::: ys') -> unbox f x y ::: interleave f xs' ys')----- | Takes two signals and updates the first signal using the--- functions produced by the second signal:------ Law:------ (xs `update` fs) `update` gs = (xs `update` (interleave (box (.)) gs fs))-update :: (Continuous a) => Sig a -> O (Sig (a -> a)) -> Sig a-update (x ::: xs) fs = x ::: delay -    (case select xs fs of-      Fst xs' ys' -> update xs' ys'-      Snd xs' (f ::: fs') -> update (f (unbox xBox) ::: xs') fs'-      Both (x' ::: xs') (f ::: fs') -> update (f x' ::: xs') fs')-  where xBox = promote x----- | This function is a variant of combines the values of two signals--- using the function argument. @zipWith f xs ys@ produces a new value--- @unbox f x y@ whenever @xs@ or @ys@ produce a new value, where @x@--- and @y@ are the current values of @xs@ and @ys@, respectively.------ Example:------ >                      xs:  1 2 3     2--- >                      ys:  1     0 5 2--- >--- > zipWith (box (+)) xs ys:  2 3 4 3 8 4--zipWith :: (Stable a, Stable b) => Box(a -> b -> c) -> Sig a -> Sig b -> Sig c-zipWith f (a ::: as) (b ::: bs) = unbox f a b ::: delay (-    case select as bs of-      Fst as' lbs -> zipWith f as' (b ::: lbs)-      Snd las bs' -> zipWith f (a ::: las) bs'-      Both as' bs' -> zipWith f as' bs'-  )---- | Variant of 'zipWith' with three signals.-zipWith3 :: forall a b c d. (Stable a, Stable b, Stable c) => Box(a -> b -> c -> d) -> Sig a -> Sig b -> Sig c -> Sig d-zipWith3 f as bs cs = zipWith (box (\f x -> unbox f x)) cds cs-  where cds :: Sig (Box (c -> d))-        cds = zipWith (box (\a b -> box (\ c -> unbox f a b c))) as bs---- | If-then-else lifted to signals. @cond bs xs ys@ produces a stream--- whose value is taken from @xs@ whenever @bs@ is true and from @ys@--- otherwise.-cond :: Stable a => Sig Bool -> Sig a -> Sig a -> Sig a-cond = zipWith3 (box (\b x y -> if b then x else y))----- | This is a special case of 'zipWith' using the tupling--- function. That is,------ > zip = zipWith (box (:*))-zip :: (Stable a, Stable b) => Sig a -> Sig b -> Sig (a:*b)-zip = zipWith (box (:*))---- | Sampling interval (in microseconds) for the 'integral' and--- 'derivative' functions.--dt :: Int-dt = 20000---- | @integral x xs@ computes the integral of the signal @xs@ with the--- constant @x@. For example, if @xs@ is the velocity of an object,--- the signal @integral 0 xs@ describes the distance travelled by that--- object.-integral :: forall a v . (VectorSpace v a, Eq v, Fractional a, Stable v, Stable a)-  => v -> Sig v -> Sig v-integral = int -  where int cur (x ::: xs)-          | x == zeroVector = cur ::: delay (int cur (adv xs))-          | otherwise = cur ::: delay (-              case select xs (unbox (timer dt)) of-                Fst xs' _ -> int cur xs'-                Snd xs' _ -> int (dtf *^ (cur ^+^ x)) (x ::: xs')-                Both (x' ::: xs') _ ->  int (dtf *^ (cur ^+^ x')) (x'::: xs'))-         -- sampling interval in seconds-        dtf :: a-        dtf = fromRational (fromIntegral dt % 1000000)-                --- | Compute the derivative of a signal. For example, if @xs@ is the--- velocity of an object, the signal @derivative xs@ describes the--- acceleration travelled by that object.-derivative :: forall a v . (VectorSpace v a, Eq v, Fractional a, Stable v, Stable a)-  => Sig v -> Sig v-derivative xs = der zeroVector (current xs) xs where-  -- inverse sampling interval in seconds-  dtf :: a-  dtf = fromIntegral dt * 0.000001--  der :: v -> v -> Sig v -> Sig v-  der d last (x:::xs)-    | d == zeroVector = zeroVector ::: delay-                        (let x' ::: xs' = adv xs-                         in der ((x' ^-^ x) ^/ dtf) x (x' ::: xs'))-    | otherwise = d ::: delay (-        case select xs (unbox (timer dt)) of-          Fst xs' _ -> der d last xs'-          Snd xs' _ -> der ((x ^-^ last) ^/ dtf) x (x ::: xs')-          Both (x' ::: xs') _ ->  der ((x' ^-^ last) ^/ dtf) x' (x' ::: xs'))---instance Continuous a => Continuous (Sig a) where-    progressInternal inp (x ::: xs@(Delay cl _)) = -        if inputInClock inp cl then (adv' xs inp)-        else progressInternal inp x ::: xs-    progressAndNext inp (x ::: xs@(Delay cl _)) = -        if inputInClock inp cl then let n = adv' xs inp in (n, nextProgress n)-        else let (n , cl') = progressAndNext inp x in (n ::: xs , cl `clockUnion` cl')-    nextProgress (x ::: (Delay cl _)) = nextProgress x `clockUnion` cl---- Prevent functions from being inlined too early for the rewrite--- rules to fire.--{-# NOINLINE [1] map #-}-{-# NOINLINE [1] const #-}-{-# NOINLINE [1] scan #-}-{-# NOINLINE [1] scanMap #-}-{-# NOINLINE [1] zip #-}-{-# NOINLINE [1] update #-}-{-# NOINLINE [1] switch #-}---{-# RULES--  "const/switch" forall x xs.-  switch (const x) xs = x ::: xs;--  "update/update" forall xs fs gs.-    update (update xs fs) gs = update xs (interleave (box (.)) gs fs) ;--  "const/map" forall (f :: Stable b => Box (a -> b))  x.-    map f (const x) = let x' = unbox f x in const x' ;--  "map/map" forall f g xs.-    map f (map g xs) = map (box (unbox f . unbox g)) xs ;--  "map/scan" forall f p acc as.-    map p (scan f acc as) = scanMap f p acc as ;--  "zip/map" forall xs ys f.-    map f (zip xs ys) = let f' = unbox f in zipWith (box (\ x y -> f' (x :* y))) xs ys;--  "scan/scan" forall f g b c as.-    scan g c (scan f b as) =-      let f' = unbox f; g' = unbox g in-      scanMap (box (\ (b:*c) a -> let b' = f' b a in (b':* g' c b'))) (box snd') (b:*c) as ;--  "scan/scanMap" forall f g p b c as.-    scan g c (scanMap f p b as) =-      let f' = unbox f; g' = unbox g; p' = unbox p in-      scanMap (box (\ (b:*c) a -> let b' = f' (p' b) a in (b':* g' c b'))) (box snd') (b:*c) as ;--#-}-
− src/AsyncRattus/Strict.hs
@@ -1,255 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE TemplateHaskell #-}----- | This module contains strict versions of some standard data--- structures.----module AsyncRattus.Strict-  ( List(..),-    singleton,-    IsList(..),-    init',-    reverse',-    union',-    unionBy',-    nub',-    nubBy',-    filter',-    delete',-    deleteBy',-    (+++),-    listToMaybe',-    map',-    zip',-    zipWith',-    mapMaybe',-    (:*)(..),-    Maybe'(..),-    maybe',-    fromMaybe',-    fst',-    snd',-    curry',-    uncurry'-  )where--import Prelude hiding (map)-import Data.VectorSpace-import AsyncRattus.Derive-import GHC.Exts (IsList(..))--infixr 2 :*--- | Strict pair type.-data a :* b = !a :* !b--continuous ''(:*)---- | First projection function.-fst' :: (a :* b) -> a-fst' (a:*_) = a---- | Second projection function.-snd' :: (a :* b) -> b-snd' (_:*b) = b--curry' :: ((a :* b) -> c) -> a -> b -> c-curry' f x y = f (x :* y)--uncurry' :: (a -> b -> c) -> (a :* b) -> c-uncurry' f (x :* y) = f x y---instance Functor ((:*) a) where-  fmap f (x:*y) = (x :* f y)-  -instance (Show a, Show b) => Show (a:*b) where-  show (a :* b) = "(" ++ show a ++ " :* " ++ show b ++ ")"--instance (Eq a, Eq b) => Eq (a :* b) where-  (x1 :* y1) == (x2 :* y2) = x1 == x2 && y1 == y2---instance (VectorSpace v a, VectorSpace w a, Floating a, Eq a) => VectorSpace (v :* w) a where-  zeroVector = zeroVector :* zeroVector--  a *^ (x :* y) = (a *^ x) :* (a *^ y)--  (x :* y) ^/ a = (x ^/ a) :* (y ^/ a)--  negateVector (x :* y) = (negateVector x) :* (negateVector y)--  (x1 :* y1) ^+^ (x2 :* y2) = (x1 ^+^ x2) :* (y1 ^+^ y2)--  (x1 :* y1) ^-^ (x2 :* y2) = (x1 ^-^ x2) :* (y1 ^-^ y2)--  (x1 :* y1) `dot` (x2 :* y2) = (x1 `dot` x2) + (y1 `dot` y2)--infixr 8 :!---- | Strict list type.-data List a = Nil | !a :! !(List a)--continuous ''List---singleton :: a -> List a-singleton x = x :! Nil--instance Traversable List where-  traverse _ Nil = pure Nil-  traverse f (x :! xs) = (:!) <$> (f x) <*> (traverse f xs)--instance IsList (List a) where-  type Item (List a) = a--  fromList [] = Nil-  fromList (x : xs) = x :! fromList xs--  toList Nil = []-  toList (x :! xs) = x : toList xs----- | Remove the last element from a list if there is one, otherwise--- return 'Nil'.-init' :: List a -> List a-init' Nil = Nil-init' (_ :! Nil) = Nil-init' (x :! xs) = x :! init' xs---- | Reverse a list.-reverse' :: List a -> List a-reverse' l =  rev l Nil-  where-    rev Nil     a = a-    rev (x:!xs) a = rev xs (x:!a)-    --- | Returns @'Nothing''@ on an empty list or @'Just'' a@ where @a@ is the--- first element of the list.-listToMaybe' :: List a -> Maybe' a-listToMaybe' Nil = Nothing'-listToMaybe' (x :! _) = Just' x---- | Append two lists.-(+++) :: List a -> List a -> List a-(+++) Nil     ys = ys-(+++) (x:!xs) ys = x :! xs +++ ys---map' :: (a -> b) -> List a -> List b-map' _ Nil = Nil-map' f (x :! xs) = f x :! map' f xs--zip' :: List a -> List b -> List (a :* b)-zip' Nil _ = Nil-zip' _ Nil = Nil-zip' (x :! xs) (y :! ys) = (x :* y) :! zip' xs ys--zipWith' :: (a -> b -> c) -> List a -> List b -> List c-zipWith' _ Nil _ = Nil-zipWith' _ _ Nil = Nil-zipWith' f (x :! xs) (y :! ys) = f x y :! zipWith' f xs ys----- | A version of 'map' which can throw out elements.  In particular,--- the function argument returns something of type @'Maybe'' b@.  If--- this is 'Nothing'', no element is added on to the result list.  If--- it is @'Just'' b@, then @b@ is included in the result list.-mapMaybe'          :: (a -> Maybe' b) -> List a -> List b-mapMaybe' _ Nil     = Nil-mapMaybe' f (x:!xs) =- let rs = mapMaybe' f xs in- case f x of-  Nothing' -> rs-  Just' r  -> r:!rs--union' :: (Eq a) => List a -> List a -> List a-union' = unionBy' (==)--unionBy' :: (a -> a -> Bool) -> List a -> List a -> List a-unionBy' eq xs ys =  xs +++ foldl (flip (deleteBy' eq)) (nubBy' eq ys) xs--delete' :: (Eq a) => a -> List a -> List a-delete' =  deleteBy' (==)--deleteBy' :: (a -> a -> Bool) -> a -> List a -> List a-deleteBy' _  _ Nil        = Nil-deleteBy' eq x (y :! ys)    = if x `eq` y then ys else y :! deleteBy' eq x ys---nub' :: (Eq a) => List a -> List a-nub' =  nubBy' (==)--nubBy' :: (a -> a -> Bool) -> List a -> List a-nubBy' _ Nil             =  Nil-nubBy' eq (x:!xs)         =  x :! nubBy' eq (filter' (\ y -> not (eq x y)) xs)--filter' :: (a -> Bool) -> List a -> List a-filter' _ Nil    = Nil-filter' pred (x :! xs)-  | pred x         = x :! filter' pred xs-  | otherwise      = filter' pred xs--instance Foldable List where-  -  foldMap f = run where-    run Nil = mempty-    run (x :! xs) = f x <> run xs-  foldr f = run where-    run b Nil = b-    run b (a :! as) = (run $! (f a b)) as-  foldl f = run where-    run a Nil = a-    run a (b :! bs) = (run $! (f a b)) bs-  elem a = run where-    run Nil = False-    run (x :! xs)-      | a == x = True-      | otherwise = run xs-    -  -instance Functor List where-  fmap = map'--instance Eq a => Eq (List a) where-  Nil == Nil = True-  Nil == _ = False-  _ == Nil = False-  (x :! xs) == (y :! ys) = if x == y then xs == ys else False--instance Show a => Show (List a) where-  show Nil = "Nil"-  show (x :! xs) = show x ++ " :! " ++ show xs---- | Strict variant of 'Maybe'.-data Maybe' a = Just' !a | Nothing'--continuous ''Maybe'--instance Eq a => Eq (Maybe' a) where-  Nothing' == Nothing' = True-  Just' x == Just' y = x == y-  _ == _ = False--instance Show a => Show (Maybe' a) where-  show Nothing' = "Nothing'"-  show (Just' x) = "Just' " ++ show x---- | takes a default value, a function, and a 'Maybe'' value.  If the--- 'Maybe'' value is 'Nothing'', the function returns the default--- value.  Otherwise, it applies the function to the value inside the--- 'Just'' and returns the result.-maybe' :: b -> (a -> b) -> Maybe' a -> b-maybe' n _ Nothing'  = n-maybe' _ f (Just' x) = f x--fromMaybe' :: a -> Maybe' a -> a-fromMaybe' _ (Just' x) = x-fromMaybe' d Nothing' = d-
+ src/WidgetRattus.hs view
@@ -0,0 +1,30 @@+{-# OPTIONS -fplugin=WidgetRattus.Plugin #-}+++-- | The bare-bones Asynchronous Rattus language. To program with streams,+-- you can use "WidgetRattus.Stream".++module WidgetRattus (+  -- * Asynchronous Rattus language primitives+  module WidgetRattus.Primitives,+  -- * Channels API+  module WidgetRattus.Channels,+  -- * Strict data types+  module WidgetRattus.Strict,+  -- * Derive class instance declarations+  module WidgetRattus.Derive,+  -- * Annotation+  WidgetRattus(..),+  -- * other+  mapO+  )+  where++import WidgetRattus.Plugin+import WidgetRattus.Strict+import WidgetRattus.Primitives+import WidgetRattus.Derive+import WidgetRattus.Channels++mapO :: Box (a -> b) -> O a -> O b+mapO f later = delay (unbox f (adv later))
+ src/WidgetRattus/Channels.hs view
@@ -0,0 +1,79 @@+{-# OPTIONS -fplugin=WidgetRattus.Plugin #-}++{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module WidgetRattus.Channels (+  timer,+  Producer (..),+  chan,+  C (..),+  delayC,+  wait,+  Chan+) where+import WidgetRattus.InternalPrimitives++import WidgetRattus.Plugin.Annotation+import WidgetRattus.Strict+import System.IO.Unsafe+import Data.IORef+import Unsafe.Coerce++-- | A type @p@ satisfying @Producer p a@ is essentially a signal that+-- produces values of type @a@ but it might not produce such values at+-- each tick.+class Producer p a | p -> a where+  -- | Get the current value of the producer if any.+  getCurrent :: p -> Maybe' a+  -- | Get the next state of the producer. Morally, the type of this+  -- method should be+  --+  -- > getNext :: p -> (exists q. Producer q a => O q)+  --+  -- We encode the existential type using continuation-passing style.+  getNext :: p -> (forall q. Producer q a => O q -> b) -> b++instance Producer p a => Producer (O p) a where+  getCurrent _ = Nothing'+  getNext p cb = cb p++instance Producer p a => Producer (Box p) a where+  getCurrent p = getCurrent (unbox p)+  getNext p cb = getNext (unbox p) cb++newtype C a = C {unC :: IO a} deriving (Functor, Applicative, Monad)++chan :: C (Chan a)+chan = C (Chan <$> atomicModifyIORef nextFreshChannel (\ x -> (x - 1, x)))++delayC :: O (C a) -> C (O a)+delayC d = return (delay (unsafePerformIO (unC (adv d))))++{-# ANN wait AllowRecursion #-}+wait :: Chan a -> O a+wait (Chan ch) = Delay (singletonClock ch) (lookupInp ch) ++{-# NOINLINE nextFreshChannel #-}+nextFreshChannel :: IORef InputChannelIdentifier+nextFreshChannel = unsafePerformIO (newIORef (-1))++++{-# ANN lookupInp AllowRecursion #-}+lookupInp :: InputChannelIdentifier -> InputValue -> a+lookupInp _ (OneInput _ v) = unsafeCoerce v+lookupInp ch (MoreInputs ch' v more) = if ch' == ch then unsafeCoerce v else lookupInp ch more++-- | @timer n@ produces a delayed computation that ticks every @n@+-- milliseconds. In particular @mkSig (timer n)@ is a signal that+-- produces a new value every #n# milliseconds.+timer :: Int -> Box (O ())+timer d = Box (Delay (singletonClock (d `max` 10)) (\ _ -> ()))
+ src/WidgetRattus/Derive.hs view
@@ -0,0 +1,117 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE ExistentialQuantification #-}+++module WidgetRattus.Derive (continuous) where++import WidgetRattus.InternalPrimitives+import Language.Haskell.TH+import Language.Haskell.TH.Syntax+import Control.Monad+++data DataInfo = forall flag . DataInfo Cxt Name [TyVarBndr flag] [Con] [DerivClause] ++{-|+  This function provides a list (of the given length) of new names based+  on the given string.+-}+newNames :: Int -> String -> Q [Name]+newNames n name = replicateM n (newName name)+++{-|+  This is the @Q@-lifted version of 'abstractNewtype.+-}+abstractNewtypeQ :: Q Info -> Q (Maybe DataInfo)+abstractNewtypeQ = liftM abstractNewtype+++{-| Apply a class name to type arguments to construct a type class+    constraint.+-}++mkClassP :: Name -> [Type] -> Type+mkClassP name = foldl AppT (ConT name)+++{-| This function provides the name and the arity of the given data+constructor, and if it is a GADT also its type.+-}+normalCon :: Con -> [(Name,[StrictType], Maybe Type)]+normalCon (NormalC constr args) = [(constr, args, Nothing)]+normalCon (RecC constr args) = [(constr, map (\(_,s,t) -> (s,t)) args, Nothing)]+normalCon (InfixC a constr b) = [(constr, [a,b], Nothing)]+normalCon (ForallC _ _ constr) = normalCon constr+normalCon (GadtC (constr:_) args typ) = [(constr,args,Just typ)]+normalCon (RecGadtC (constr : _) args typ) = [(constr,map dropFst args,Just typ)]+  where dropFst (_,x,y) = (x,y)+normalCon _ = error "missing case for 'normalCon'"++normalCon' :: Con -> [(Name,[Type], Maybe Type)]+normalCon' con = map conv (normalCon con)+  where conv (n, ts, t) = (n, map snd ts, t)+  +mkInstanceD :: Cxt -> Type -> [Dec] -> Dec+mkInstanceD cxt ty decs = InstanceD Nothing cxt ty decs++{-|+  This function returns the name of a bound type variable+-}+tyVarBndrName (PlainTV n _) = n+tyVarBndrName (KindedTV n _ _) = n++{-|+  This function abstracts away @newtype@ declaration, it turns them into+  @data@ declarations.+-}+abstractNewtype :: Info -> Maybe DataInfo+abstractNewtype (TyConI (NewtypeD cxt name args _ constr derive))+    = Just (DataInfo cxt name args [constr] derive)+abstractNewtype (TyConI (DataD cxt name args _ constrs derive))+    = Just (DataInfo cxt name args constrs derive)+abstractNewtype _ = Nothing++continuous :: Name -> Q [Dec]+continuous fname = do+  Just (DataInfo _cxt name args constrs _deriving) <- abstractNewtypeQ $ reify fname+  let argNames = map (VarT . tyVarBndrName) args+      complType = foldl AppT (ConT name) argNames+      preCond = map (mkClassP ''Continuous . (: [])) argNames+      classType = AppT (ConT ''Continuous) complType+  let constrs' = concatMap normalCon' constrs+  progressAndNextDecl <- funD 'progressAndNext (map genProgressAndNext constrs')+  progressInternalDecl <- funD 'progressInternal (map genProgressInternal constrs')+  nextProgressDecl <- funD 'nextProgress (map genNextProgress constrs')+  return [mkInstanceD preCond classType [progressAndNextDecl,progressInternalDecl,nextProgressDecl]]+      where genProgressAndNext (constr, args,_) = do+              let n = length args+              varNs <- newNames n "x"+              varNsR <- newNames n "y"+              varNsS <- newNames n "z"+              varIn <- newName "_inp"+              let pat = ConP constr [] $ map VarP varNs++              progressInternalExp <- [|progressAndNext|]+              let lets = zipWith3 (\ x y z -> ValD (TupP [VarP y, VarP z]) (NormalB (progressInternalExp `AppE` VarE varIn `AppE` VarE x)) []) varNs varNsR varNsS+              clockUnionExp <- [|clockUnion|]+              result <- appsE ( conE constr : (map varE varNsR))+              clock <- if n == 0 then [|emptyClock|] else return (foldl1 (\ x y -> (clockUnionExp `AppE` x) `AppE` y)  (map VarE varNsS))+              let body = LetE lets (TupE [Just result, Just clock])+              return $ Clause [VarP varIn, pat] (NormalB body) []+            genProgressInternal (constr, args,_) = do+              let n = length args+              varNs <- newNames n "x"+              varIn <- newName "_inp"+              let pat = ConP constr [] $ map VarP varNs+                  allVars = map varE varNs+                  inpVar = varE varIn+              body <- appsE ( conE constr : (map (\ x -> [|progressInternal $inpVar $x|]) allVars))+              return $ Clause [VarP varIn, pat] (NormalB body) []+            genNextProgress (constr, args,_) = do+              let n = length args+              varNs <- newNames n "x"+              let pat = ConP constr [] $ map VarP varNs+                  allVars = map varE varNs+              body <- if n == 0 then [|emptyClock|] else foldl1 (\ x y -> [|clockUnion $x $y|]) ((map (\ x -> [|nextProgress $x|]) allVars))+              return $ Clause [pat] (NormalB body) []
+ src/WidgetRattus/Future.hs view
@@ -0,0 +1,218 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE TypeOperators #-}+{-# OPTIONS -fplugin=WidgetRattus.Plugin #-}+++-- | Programming with futures.++module WidgetRattus.Future+  ( F(..)+  , SigF(..)+  , mkSigF+  , mkSigF'+  , current+  , future+  , bindF+  , mapF+  , sync+  , syncF+  , switchAwait+  , switch+  , switchS+  , filterMap+  , filterMapAwait+  , filterAwait+  , filter+  , trigger+  , triggerAwait+  , map+  , mapAwait+  , zipWith+  , zipWithAwait+  , fromSig+  , scan+  , scanAwait+  )++where++import WidgetRattus+import WidgetRattus.Signal (Sig(..))+import Prelude hiding (map, filter, zipWith)++newtype OneShot a = OneShot (F a)++instance Producer (OneShot a) a where+  getCurrent (OneShot (Now x)) = Just' x+  getCurrent (OneShot (Wait _)) = Nothing'++  getNext (OneShot (Now _)) cb = cb (never :: O (OneShot a))+  getNext (OneShot (Wait x)) cb = cb (delay (OneShot (adv x)))++instance Producer p a => Producer (F p) a where+  getCurrent (Now x) = getCurrent x+  getCurrent (Wait _) = Nothing'+  +  getNext (Now x) cb = getNext x cb+  getNext (Wait x) cb = cb x++instance Producer (SigF a) a where+  getCurrent (x :>: _) = Just' x+  getNext (_ :>: xs) cb = cb xs++++-- | @F a@ will produces a value of type @a@ after zero or more ticks+-- of some clocks+data F a = Now !a | Wait !(O (F a))++++bindF :: F a -> Box (a -> F b) -> F b+bindF (Now x) f = unbox f x+bindF (Wait x) f = Wait (delay (bindF (adv x) f))++mapF :: Box (a -> b) -> F a -> F b+mapF f d = d `bindF` (box (\ x -> Now (unbox f x)))+++sync :: O (F a) -> O (F b) -> O (F a :* F b)+sync x y = delay (case select x y of+                     Fst x' y' -> (x' :* Wait y')+                     Snd x' y' -> (Wait x' :* y')+                     Both x' y' -> (x' :* y'))++syncF :: (Stable a, Stable b) => F a -> F b -> F (a :* b)+syncF (Now x) (Now y) = Now (x :* y)+syncF (Wait x) (Now y) = Wait (delay (syncA (adv x) y))+syncF (Now x) (Wait y) = Wait (delay (syncB x (adv y)))+syncF (Wait x) (Wait y) = Wait (delay (case select x y of+                                         Fst x' y' -> syncF x' (Wait y')+                                         Snd x' y' -> syncF (Wait x') y'+                                         Both x' y' -> syncF x' y'+                                      )) ++syncA :: (Stable b) => F a -> b -> F (a :* b)+syncA (Now x) y = Now (x :* y)+syncA (Wait x) y = Wait (delay (syncA (adv x) y))+++syncB :: (Stable a) => a -> F b -> F (a :* b)+syncB x (Now y) = Now (x :* y)+syncB x (Wait y) = Wait (delay (syncB x (adv y)))+++-- | @SigF a@ is a signal of values of type @a@. In contrast to 'Sig',+-- 'SigF' supports the 'filter' and 'filterMap' functions.+data SigF a = !a :>: !(O (F (SigF a)))+++-- | Get the current value of a signal.+current :: SigF a -> a+current (x :>: _) = x+++-- | Get the future the signal.+future :: SigF a -> O (F (SigF a))+future (_ :>: xs) = xs+++mkSigF :: Box (O a) -> F (SigF a)+mkSigF b = Wait (mkSigF' b) where++mkSigF' :: Box (O a) -> O (F (SigF a))+mkSigF' b = delay (Now (adv (unbox b) :>: mkSigF' b))+++fromSig :: Sig a -> SigF a+fromSig (x ::: xs) = x :>: delay (Now (fromSig (adv xs)))++  +switchAwait :: F (SigF a) -> F (SigF a) -> F(SigF a)+switchAwait _ (Now ys) = Now ys+switchAwait (Now (x :>: xs)) (Wait ys) = Now (x :>: delay (uncurry' switchAwait (adv (sync xs ys)) ))+switchAwait (Wait xs) (Wait ys) = Wait (delay (uncurry' switchAwait (adv (sync xs ys)) ))++switch :: SigF a -> F (SigF a) -> SigF a+switch _ (Now ys) = ys+switch (x :>: xs) (Wait ys) = x :>: delay (uncurry' switchAwait (adv (sync xs ys)))++switchS :: Stable a => SigF a -> F (a -> SigF a) -> SigF a+switchS (x :>: _) (Now f) = f x+switchS (x :>: xs) (Wait ys) = x :>: delay (uncurry' (switchAwaitS x) (adv (sync xs ys)))++switchAwaitS :: Stable a => a -> F (SigF a) -> F (a -> SigF a) -> F (SigF a)+switchAwaitS _ (Now (x :>: _)) (Now f) = Now (f x)+switchAwaitS _ (Now (x :>: xs)) (Wait ys) =+  Now (x :>: delay (uncurry' (switchAwaitS x) (adv (sync xs ys))))+switchAwaitS x (Wait _) (Now f) = Now (f x)+switchAwaitS x (Wait xs) (Wait ys) = Wait (delay (uncurry' (switchAwaitS x) (adv (sync xs ys))))++++filterMapAwait :: Box (a -> Maybe' b) -> F(SigF a) -> F (SigF b)+filterMapAwait f (Wait xs) = Wait (delay (filterMapAwait f (adv xs)))+filterMapAwait f (Now (x :>: xs)) = case unbox f x of+                                     Just' y  -> Now (y :>: delay (filterMapAwait f (adv xs)))+                                     Nothing' -> Wait (delay (filterMapAwait f (adv xs)))++filterMap :: Box (a -> Maybe' b) -> SigF a -> F (SigF b)+filterMap f xs = filterMapAwait f (Now xs)+++filterAwait :: Box (a -> Bool) -> F( SigF a) -> F (SigF a)+filterAwait p = filterMapAwait (box (\ x -> if unbox p x then Just' x else Nothing'))++filter :: Box (a -> Bool) -> SigF a -> F (SigF a)+filter p = filterMap (box (\ x -> if unbox p x then Just' x else Nothing'))++trigger :: Stable b => Box (a -> b -> c) -> SigF a -> SigF b -> SigF c+trigger f (a :>: as) (b :>: bs) =+  unbox f a b :>:+  delay (uncurry' (trigger' b f) (adv (sync as bs)))++triggerAwait :: Stable b => Box (a -> b -> c) -> F (SigF a) -> SigF b -> F (SigF c)+triggerAwait f (Now (a :>: as)) (b :>: bs)+  = Now (unbox f a b :>: delay (uncurry' (trigger' b f) (adv (sync as bs))))+triggerAwait f (Wait as) (b :>: bs)+  = Wait (delay (uncurry' (trigger' b f) (adv (sync as bs))))++trigger' :: Stable b => b -> Box (a -> b -> c) -> F (SigF a) -> F (SigF b) -> F (SigF c)+trigger' b f (Now (a :>: as)) (Wait bs) =+  Now (unbox f a b :>: delay (uncurry' (trigger' b f) (adv (sync as bs))))+trigger' _ f (Now (a :>: as)) (Now (b :>: bs)) =+  Now (unbox f a b :>: delay (uncurry' (trigger' b f) (adv (sync as bs))))+trigger' b f (Wait as) (Wait bs) =+  Wait (delay (uncurry' (trigger' b f) (adv (sync as bs))))+trigger' _ f (Wait as) (Now (b :>: bs)) =+  Wait (delay (uncurry' (trigger' b f) (adv (sync as bs))))+++mapAwait :: Box (a -> b) -> F (SigF a) -> F (SigF b)+mapAwait f (Now (x :>: xs)) = Now (unbox f x :>: delay (mapAwait f (adv xs)))+mapAwait f (Wait xs) = Wait (delay (mapAwait f (adv xs)))++map :: Box (a -> b) -> SigF a -> SigF b+map f (x :>: xs) = unbox f x :>: delay (mapAwait f (adv xs))++++zipWith :: (Stable a, Stable b) => Box(a -> b -> c) -> SigF a -> SigF b -> SigF c+zipWith f (a :>: as) (b :>: bs) = unbox f a b :>: delay (uncurry' (zipWithAwait f a b) (adv (sync as bs)))++zipWithAwait :: (Stable a, Stable b) => Box(a -> b -> c) -> a -> b -> F (SigF a) -> F (SigF b) -> F (SigF c)+zipWithAwait f _ _ (Now (a :>: as)) (Now (b :>: bs)) = Now (unbox f a b :>: delay (uncurry' (zipWithAwait f a b) (adv (sync as bs))))+zipWithAwait f _ b (Now (a :>: as)) (Wait bs) = Now (unbox f a b :>: delay (uncurry' (zipWithAwait f a b) (adv (sync as bs))))+zipWithAwait f a _ (Wait as) (Now (b :>: bs)) = Now (unbox f a b :>: delay (uncurry' (zipWithAwait f a b) (adv (sync as bs))))+zipWithAwait f a b (Wait as) (Wait bs) = Wait (delay (uncurry' (zipWithAwait f a b) (adv (sync as bs))))++scan :: (Stable b) => Box(b -> a -> b) -> b -> SigF a -> SigF b+scan f acc (a :>: as) = acc' :>: delay (scanAwait f acc' (adv as))+  where acc' = unbox f acc a++scanAwait :: (Stable b) => Box (b -> a -> b) -> b -> F (SigF a) -> F (SigF b)+scanAwait f acc (Now (a :>: as)) = Now (acc' :>: delay (scanAwait f acc' (adv as)))+  where acc' = unbox f acc a+scanAwait f acc (Wait as) = Wait (delay (scanAwait f acc (adv as)))
+ src/WidgetRattus/InternalPrimitives.hs view
@@ -0,0 +1,264 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-}++module WidgetRattus.InternalPrimitives where++import Prelude hiding (Left, Right)+import Data.IntSet (IntSet)+import qualified Data.IntSet as IntSet+import Data.IORef+import Control.Concurrent.MVar+import System.IO.Unsafe+import System.Mem.Weak+import Control.Monad++-- An input channel is identified by an integer. The programmer should not know about it.+type InputChannelIdentifier = Int++type Clock = IntSet++singletonClock :: InputChannelIdentifier -> Clock+singletonClock = IntSet.singleton++emptyClock :: Clock+emptyClock = IntSet.empty++clockUnion :: Clock -> Clock -> Clock+clockUnion = IntSet.union++channelMember :: InputChannelIdentifier -> Clock -> Bool+channelMember = IntSet.member++data InputValue where+  OneInput :: !InputChannelIdentifier -> !a -> InputValue+  MoreInputs :: !InputChannelIdentifier -> !a -> !InputValue -> InputValue++inputInClock :: InputValue -> Clock -> Bool+inputInClock (OneInput ch _) cl = channelMember ch cl+inputInClock (MoreInputs ch _ more) cl = channelMember ch cl || inputInClock more cl+++-- | The "later" type modality. A value @v@ of type @O 𝜏@ consists of+-- two components: Its clock, denoted @cl(v)@, and a delayed+-- computation that will produce a value of type @𝜏@ as soon as the+-- clock @cl(v)@ ticks. The clock @cl(v)@ is only used for type+-- checking and is not directly accessible, whereas the delayed+-- computation is accessible via 'adv' and 'select'.++data O a = Delay !Clock (InputValue -> a)++-- | The return type of the 'select' primitive.+data Select a b = Fst !a !(O b) | Snd !(O a) !b | Both !a !b++rattusError pr = error (pr ++ ": Did you forget to mark this as Async Rattus code?")++-- | This is the constructor for the "later" modality 'O':+--+-- >     Γ ✓θ ⊢ t :: 𝜏+-- > --------------------+-- >  Γ ⊢ delay t :: O 𝜏+--+-- The typing rule requires that its argument @t@ typecheck with an+-- additional tick @✓θ@ of some clock @θ@.+{-# INLINE [1] delay #-}+delay :: a -> O a+delay _ = rattusError "delay"++extractClock :: O a -> Clock+extractClock (Delay cl _) = cl++{-# INLINE [1] adv' #-}+adv' :: O a -> InputValue -> a+adv' (Delay _ f) inp = f inp+++-- | This is the eliminator for the "later" modality 'O':+--+-- >   Γ ⊢ t :: O 𝜏     Γ' tick-free+-- > ---------------------------------+-- >     Γ ✓cl(t) Γ' ⊢ adv t :: 𝜏+--+-- It requires that a tick @✓θ@ is in the context whose clock matches+-- exactly the clock of @t@, i.e. @θ = cl(t)@.++{-# INLINE [1] adv #-}+adv :: O a -> a+adv _ = rattusError "adv"++-- | If we want to eliminate more than one delayed computation, i.e.\+-- two @s :: O σ@ and @t :: O 𝜏@, we need to use 'select' instead of+-- just 'adv'.+--+-- >   Γ ⊢ s :: O σ     Γ ⊢ t :: O 𝜏     Γ' tick-free+-- > --------------------------------------------------+-- >    Γ ✓cl(s)⊔cl(t) Γ' ⊢ select s t :: Select σ 𝜏+--+-- It requires that we have a tick @✓θ@ in the context whose clock+-- matches the union of the clocks of @s@ and @t@, i.e. @θ =+-- cl(s)⊔cl(t)@. The union of two clocks ticks whenever either of the+-- two clocks ticks, i.e. @cl(s)⊔cl(t)@, whenever @cl(s)@ or @cl(t)@+-- ticks.+--+-- That means there are three possible outcomes, which are reflected+-- in the result type of @select s t@. A value of @Select σ 𝜏@ is+-- either+--+--   * a value of type @σ@ and a delayed computation of type @O 𝜏@, if+--     @cl(s)@ ticks before @cl(t)@,+--+--   * a value of type @𝜏@ and a delayed computation of type @O σ@, if+--     @cl(t)@ ticks before @cl(s)@, or+--+--   * a value of type @σ@ and a value of type @𝜏@, if @cl(s)@ and+--   * @cl(s)@ tick simultaneously.+++{-# INLINE [1] select #-}+select :: O a -> O b -> Select a b+select _ _ = rattusError "select"++select' :: O a -> O b -> InputValue -> Select a b+select' a@(Delay clA inpFA) b@(Delay clB inpFB) inp+  = if inputInClock inp clA then+      if inputInClock inp clB then Both (inpFA inp) (inpFB inp)+      else Fst (inpFA inp) b+    else Snd a (inpFB inp)++++-- | The clock of @never :: O 𝜏@ will never tick, i.e. it will never+-- produce a value of type @𝜏@. With 'never' we can for example+-- implement the constant signal @x ::: never@ of type @Sig a@ for any @x ::+-- a@.+never :: O a+never = Delay emptyClock (error "Trying to adv on the 'never' delayed computation")++-- | A type is @Stable@ if it is a strict type and the later modality+-- @O@ and function types only occur under @Box@.+--+-- For example, these types are stable: @Int@, @Box (a -> b)@, @Box (O+-- Int)@, @Box (Sig a -> Sig b)@.+--+-- But these types are not stable: @[Int]@ (because the list type is+-- not strict), @Int -> Int@, (function type is not stable), @O+-- Int@, @Sig Int@.++class  Stable a  where++++-- | The "stable" type modality. A value of type @Box a@ is a+-- time-independent computation that produces a value of type @a@.+-- Use 'box' and 'unbox' to construct and consume 'Box'-types.+data Box a = Box a+++-- | This is the constructor for the "stable" modality 'Box':+--+-- >     Γ☐ ⊢ t :: 𝜏+-- > --------------------+-- >  Γ ⊢ box t :: Box 𝜏+--+-- where Γ☐ is obtained from Γ by removing all ticks and all variables+-- @x :: 𝜏@, where 𝜏 is not a stable type.++{-# INLINE [1] box #-}+box :: a -> Box a+box x = Box x+++-- | This is the eliminator for the "stable" modality  'Box':+--+-- >   Γ ⊢ t :: Box 𝜏+-- > ------------------+-- >  Γ ⊢ unbox t :: 𝜏+{-# INLINE [1] unbox #-}+unbox :: Box a -> a+unbox (Box d) = d+++defaultPromote :: Continuous a => a -> Box a+defaultPromote x = unsafePerformIO $ +    do r <- newIORef x+       r' <- mkWeakIORef r (return ()) +       modifyIORef promoteStore (ContinuousData r' :)+       return (Box (unsafePerformIO $ readIORef r))+++class Continuous p where+  -- | Computes the same as 'progressInternal' and 'nextProgress'. In+  -- particular @progressAndNext inp v = (progressInternal inp v,+  -- nextProgress (progressInternal inp v))@.+  progressAndNext :: InputValue -> p -> (p , Clock)++  -- | Progresses the continuous value, given the input value from+  -- some channel+  progressInternal :: InputValue -> p -> p+  -- | Computes the set of channels that the continuous value is+  -- depending on. That is if @nextProgress v = cl@ and a new input+  -- @inp@ on channel @ch@ arrives, then @progressInternal inp v = v@+  -- if @not (ch `channelMember` cl)@.+  nextProgress :: p -> Clock +  promoteInternal :: p -> Box p+  promoteInternal = defaultPromote++-- For stable types we can circumvent the "promote store".+instance {-# OVERLAPPABLE #-} Stable a => Continuous a where+    progressAndNext _ x = (x , emptyClock) +    progressInternal _ x = x+    nextProgress _ = emptyClock+    promoteInternal = Box++data ContinuousData where+   ContinuousData :: Continuous a => !(Weak (IORef a)) -> ContinuousData++-- TODO: The list type needs to be replaced by a more efficient+-- mutable data structure.+{-# NOINLINE promoteStore #-}+promoteStore :: IORef [ContinuousData]+promoteStore = unsafePerformIO (newIORef [])++{-# NOINLINE progressPromoteStoreMutex #-}+progressPromoteStoreMutex :: MVar ()+progressPromoteStoreMutex = unsafePerformIO (newMVar ())+++-- | Atomic version of 'progressPromoteStore'.++progressPromoteStoreAtomic :: InputValue -> IO ()+progressPromoteStoreAtomic inp = do+    takeMVar progressPromoteStoreMutex+    progressPromoteStore inp+    putMVar progressPromoteStoreMutex ()+++-- | For promote to work, its argument must be stored in the "promote+-- store", and whenenver an input is received on some channel, all+-- values in the "promote store" must be advanced (using+-- 'progressInternal').++progressPromoteStore :: InputValue -> IO ()+progressPromoteStore inp = do +    xs <- atomicModifyIORef promoteStore (\x -> ([],x))+    xs' <- filterM run xs+    atomicModifyIORef promoteStore (\x -> (x ++ xs',()))+  where run (ContinuousData x) = do+          d <- deRefWeak x+          case d of+            Nothing -> return False+            Just x -> modifyIORef' x (progressInternal inp) >> return True++promote :: Continuous a => a -> Box a+promote x = promoteInternal x++newtype Chan a = Chan InputChannelIdentifier++{-# RULES+  "unbox/box"    forall x. unbox (box x) = x+    #-}+++{-# RULES+  "box/unbox"    forall x. box (unbox x) = x+    #-}
+ src/WidgetRattus/Plugin.hs view
@@ -0,0 +1,162 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE CPP #-}+++-- | The plugin to make it all work.++module WidgetRattus.Plugin (plugin, WidgetRattus(..)) where+import WidgetRattus.Plugin.StableSolver+import WidgetRattus.Plugin.ScopeCheck+import WidgetRattus.Plugin.Strictify+import WidgetRattus.Plugin.SingleTick+import WidgetRattus.Plugin.CheckClockCompatibility+import WidgetRattus.Plugin.Utils+import WidgetRattus.Plugin.Annotation+import WidgetRattus.Plugin.Transform++import Prelude hiding ((<>))++import Control.Monad+import Data.Maybe+import Data.List+import Data.Data hiding (tyConName)+import qualified Data.Set as Set+import Data.Set (Set)++import qualified GHC.LanguageExtensions as LangExt++import GHC.Plugins+import GHC.Tc.Types++-- | Use this to enable Asynchronous Rattus' plugin, either by supplying the option+-- @-fplugin=WidgetRattus.Plugin@ directly to GHC, or by including the+-- following pragma in each source file:+-- +-- > {-# OPTIONS -fplugin=WidgetRattus.Plugin #-}+plugin :: Plugin+plugin = defaultPlugin {+  installCoreToDos = install,+  pluginRecompile = purePlugin,+  typeCheckResultAction = typechecked,+  tcPlugin = tcStable,+  driverPlugin = updateEnv+  }+++data Options = Options {debugMode :: Bool}+++-- | Enable the @Strict@ language extension.+updateEnv :: [CommandLineOption] -> HscEnv -> IO HscEnv+updateEnv _ env = return env {hsc_dflags = update (hsc_dflags env) } +  where update fls = xopt_set fls LangExt.Strict++typechecked :: [CommandLineOption] -> ModSummary -> TcGblEnv -> TcM TcGblEnv+typechecked _ _ env = checkAll env >> return env++install :: [CommandLineOption] -> [CoreToDo] -> CoreM [CoreToDo]+install opts todo = case find findSamePass todo of       -- check that we don't run the transformation twice+                      Nothing -> return (strPass : todo) -- (e.g. if the "-fplugin" option is used twice)+                      _ -> return todo+    where name = "Async Rattus strictify"+          strPass = CoreDoPluginPass name (strictifyProgram Options{debugMode = dmode})+          dmode = "debug" `elem` opts+          findSamePass (CoreDoPluginPass s _) = s == name+          findSamePass _ = False+          ++-- | Apply the following operations to all Asynchronous Rattus definitions in the+-- program:+--+-- * Transform into single tick form (see SingleTick module)+-- * Check whether lazy data types are used (see Strictify module)+-- * Transform into call-by-value form (see Strictify module)++strictifyProgram :: Options -> ModGuts -> CoreM ModGuts+strictifyProgram opts guts = do+  newBinds <- mapM (strictify opts guts) (mg_binds guts)+  return guts { mg_binds = newBinds }++strictify :: Options -> ModGuts -> CoreBind -> CoreM CoreBind+strictify opts guts b@(Rec bs) = do+  let debug = debugMode opts+  tr <- liftM or (mapM (shouldProcessCore guts . fst) bs)+  if tr then do+    let vs = map fst bs+    es' <- mapM (\ (v,e) -> do+      processCore <- shouldProcessCore guts v+      if not processCore+      then do+        when debug $ putMsg $ text "Skipping binding: " <> ppr v+        return e+      else checkAndTransform guts (Set.fromList vs) debug v e+      ) bs+    when debug $ putMsg $ "Plugin | result of transformation: " <> ppr es'+    return (Rec (zip vs es'))+  else return b+strictify opts guts b@(NonRec v e) = do+    let debug = debugMode opts+    when debug $ putMsg $ text "Processing binding: " <> ppr v <> text " | Non-recursive binding"+    when debug $ putMsg $ text "Expr: " <> ppr e+    processCore <- shouldProcessCore guts v+    if not processCore then do+      when debug $ putMsg $ text "Skipping binding: " <> ppr v+      return b+    else do+      transformed <- checkAndTransform guts Set.empty debug v e+      when debug $ putMsg $ "Plugin | result of transformation: " <> ppr transformed+      return $ NonRec v transformed++checkAndTransform :: ModGuts -> Set Var -> Bool -> Var -> CoreExpr -> CoreM CoreExpr+checkAndTransform guts recursiveSet debug v e = do+  when debug $ putMsg $ text "Processing binding: " <> ppr v+  when debug $ putMsg $ text "Expr: " <> ppr e+  allowRec <- allowRecursion guts v+  singleTick <- toSingleTick e+  when debug $ putMsg $ text "Single-tick: " <> ppr singleTick+  lazy <- allowLazyData guts v+  when (not lazy) $ checkStrictData (SCxt (nameSrcSpan $ getName v)) singleTick+  when debug $ putMsg $ text "Strict single-tick: " <> ppr singleTick+  checkExpr CheckExpr{ recursiveSet = recursiveSet, oldExpr = e,+                        verbose = debug,+                        allowRecExp = allowRec} singleTick+  transform singleTick++getModuleAnnotations :: Data a => ModGuts -> [a]+getModuleAnnotations guts = anns'+  where anns = filter (\a-> case ann_target a of+                         ModuleTarget m -> m == (mg_module guts)+                         _ -> False) (mg_anns guts)+        anns' = mapMaybe (fromSerialized deserializeWithData . ann_value) anns+++++allowLazyData :: ModGuts -> CoreBndr -> CoreM Bool+allowLazyData guts bndr = do+  l <- annotationsOn guts bndr :: CoreM [WidgetRattus]+  return (AllowLazyData `elem` l)++allowRecursion :: ModGuts -> CoreBndr -> CoreM Bool+allowRecursion guts bndr = do+  l <- annotationsOn guts bndr :: CoreM [WidgetRattus]+  return (AllowRecursion `elem` l)++expectError :: ModGuts -> CoreBndr -> CoreM Bool+expectError guts bndr = do+  l <- annotationsOn guts bndr :: CoreM [InternalAnn]+  return $ ExpectError `elem` l+++shouldProcessCore :: ModGuts -> CoreBndr -> CoreM Bool+shouldProcessCore guts bndr = do+  expectScopeError <- expectError guts bndr+  return (userFunction bndr && not expectScopeError)++annotationsOn :: (Data a) => ModGuts -> CoreBndr -> CoreM [a]+annotationsOn guts bndr = do+  (_,anns)  <- getAnnotations deserializeWithData guts+  return $+    lookupWithDefaultUFM anns [] (varName bndr) +++    getModuleAnnotations guts
+ src/WidgetRattus/Plugin/Annotation.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE DeriveDataTypeable #-}+module WidgetRattus.Plugin.Annotation (WidgetRattus(..), InternalAnn (..)) where++import Data.Data++-- | By default all Async Rattus functions are checked for use of lazy+-- data types, since these may cause memory leaks. If any lazy data+-- types are used, a warning is issued. These warnings can be disabled+-- by annotating the module or the function with 'AllowLazyData'+--+-- > {-# ANN myFunction AllowLazyData #-}+-- >+-- > {-# ANN module AllowLazyData #-}+--+-- Async Rattus only allows guarded recursion, i.e. recursive calls+-- must occur in the scope of a tick. Structural recursion over strict+-- data types is safe as well, but is currently not checked. To+-- disable the guarded recursion check, annotate the module or+-- function with 'AllowRecursion'.+-- +-- > {-# ANN myFunction AllowRecursion #-}+-- >+-- > {-# ANN module AllowRecursion #-}+++data WidgetRattus = AllowLazyData | AllowRecursion deriving (Typeable, Data, Show, Ord, Eq)+++-- | This annotation type is for internal use only.+data InternalAnn = ExpectError | ExpectWarning deriving (Typeable, Data, Show, Eq, Ord)
+ src/WidgetRattus/Plugin/CheckClockCompatibility.hs view
@@ -0,0 +1,261 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE CPP #-}++-- | This module implements the check that the transformed code is+-- typable in the single tick calculus.++module WidgetRattus.Plugin.CheckClockCompatibility+  (checkExpr, CheckExpr (..)) where++import GHC.Types.Tickish+import GHC.Plugins++import WidgetRattus.Plugin.Utils+import qualified WidgetRattus.Plugin.PrimExpr as Prim+import Prelude hiding ((<>))+import Data.Set (Set)+import qualified Data.Set as Set+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Maybe (isJust)+import Control.Monad (foldM, when)+import Control.Applicative ((<|>))+import System.Exit (exitFailure)++type LCtx = Set Var+data HiddenReason = BoxApp | AdvApp | NestedRec Var | FunDef | DelayApp+type Hidden = Map Var HiddenReason++data TypeError = TypeError SrcSpan SDoc+++data Ctx = Ctx+  { current :: LCtx,+    hidden :: Hidden,+    earlier :: Maybe LCtx,+    srcLoc :: SrcSpan,+    recDef :: Set Var, -- ^ recursively defined variables +    stableTypes :: Set Var,+    allowRecursion :: Bool,+    allowGuardedRec :: Bool+    }++hasTick :: Ctx -> Bool+hasTick = isJust . earlier++stabilize :: HiddenReason -> Ctx -> Ctx+stabilize hr c = c+  {current = Set.empty,+   earlier = Nothing,+   hidden = hidden c `Map.union` Map.fromSet (const hr) ctxHid,+   allowGuardedRec = False+  }+  where ctxHid = maybe (current c) (Set.union (current c)) (earlier c)++data Scope = Hidden SDoc | Visible++getScope  :: Ctx -> Var -> Scope+getScope c v =+    if v `Set.member` recDef c then+      if allowGuardedRec c || allowRecursion c || typeClassFunction v then Visible+      else Hidden ("(Mutually) recursive call to " <> ppr v <> " must occur under delay")+    else case Map.lookup v (hidden c) of+      Just reason ->+        if (isStable (stableTypes c) (varType v)) then Visible+        else case reason of+          NestedRec rv ->+            if allowRecursion c then Visible+            else Hidden ("Variable " <> ppr v <> " is no longer in scope:"+                         $$ "It appears in a local recursive definition (namely of " <> ppr rv <> ")"+                         $$ "and is of type " <> ppr (varType v) <> ", which is not stable.")+          BoxApp -> Hidden ("Variable " <> ppr v <> " is no longer in scope:" $$+                       "It occurs under " <> keyword "box" $$ "and is of type " <> ppr (varType v) <> ", which is not stable.")+          AdvApp -> Hidden ("Variable " <> ppr v <> " is no longer in scope: It occurs under adv.")++          FunDef -> Hidden ("Variable " <> ppr v <> " is no longer in scope: It occurs in a function that is defined under a delay, is a of a non-stable type " <> ppr (varType v) <> ", and is bound outside delay")+          DelayApp -> Hidden ("Variable " <> ppr v <> " is no longer in scope: It occurs under two occurrences of delay and is a of a non-stable type " <> ppr (varType v))+      Nothing+          | maybe False (Set.member v) (earlier c) ->+            if isStable (stableTypes c) (varType v) then Visible+            else Hidden ("Variable " <> ppr v <> " is no longer in scope:" $$+                         "It occurs under delay" $$ "and is of type " <> ppr (varType v) <> ", which is not stable.")+          | Set.member v (current c) -> Visible+          | otherwise -> Visible++++pickFirst :: SrcSpan -> SrcSpan -> SrcSpan+pickFirst s@RealSrcSpan{} _ = s+pickFirst _ s = s++typeError :: Ctx -> Var -> SDoc -> TypeError+typeError ctx var = TypeError (pickFirst (srcLoc ctx) (nameSrcSpan (varName var)))++instance Outputable TypeError where+  ppr (TypeError srcLoc sdoc) = text "TypeError at " <> ppr srcLoc <> text ": " <> ppr sdoc++emptyCtx :: CheckExpr -> Ctx+emptyCtx c =+  Ctx { current =  Set.empty,+        earlier = Nothing,+        hidden = Map.empty,+        srcLoc = noLocationInfo,+        recDef = recursiveSet c,+        stableTypes = Set.empty,+        allowRecursion = allowRecExp c,+        allowGuardedRec = False+        }++stabilizeLater :: Ctx -> Ctx+stabilizeLater c =+  case earlier c of+    Just earl -> c {earlier = Nothing,+                    hidden = hidden c `Map.union` Map.fromSet (const FunDef) earl}+    Nothing -> c++isStableConstr :: Type -> CoreM (Maybe Var)+isStableConstr t =+  case splitTyConApp_maybe t of+    Just (con,[args]) ->+      case getNameModule con of+        Just (name, mod) ->+          if isRattModule mod && name == "Stable"+          then return (getTyVar_maybe args)+          else return Nothing+        _ -> return Nothing+    _ ->  return Nothing++-- should be equatable+type SymbolicClock = Set Var++mkClock1 :: Var -> SymbolicClock+mkClock1 = Set.singleton++mkClock2 :: Var -> Var -> SymbolicClock+mkClock2 v1 v2 = Set.fromList [v1, v2]++newtype CheckResult = CheckResult{+  -- if present, contains the variable of the primitive applied so we can report its position+  -- in case of an error, and the clock for the primitive+  prim :: Maybe (Var, SymbolicClock)+}++instance Outputable CheckResult where+  ppr (CheckResult prim) = text "CheckResult {prim = " <> ppr prim <> text "}"++emptyCheckResult :: CheckResult+emptyCheckResult = CheckResult {prim = Nothing}++data CheckExpr = CheckExpr{+  recursiveSet :: Set Var,+  oldExpr :: Expr Var,+  verbose :: Bool,+  allowRecExp :: Bool+  }++checkExpr :: CheckExpr -> Expr Var -> CoreM ()+checkExpr c e = do+  when (verbose c) $ putMsg $ text "checkExpr: " <> ppr e+  res <- checkExpr' (emptyCtx c) e+  case res of+    Right _ -> do when (verbose c) $ putMsgS "checkExpr succeeded."+    Left (TypeError src doc) ->+      let printErrMsg = if verbose c+          then do+            printMessage SevError src ("Internal error in Async Rattus Plugin: single tick transformation did not preserve typing." $$ doc)+            putMsgS "-------- old --------"+            putMsg $ ppr (oldExpr c)+            putMsgS "-------- new --------"+            putMsg (ppr e)+            +          else do+            printMessage SevError noSrcSpan ("Internal error in Async Rattus Plugin: single tick transformation did not preserve typing." $$+                                  "Compile with flags \"-fplugin-opt WidgetRattus.Plugin:debug\" and \"-g2\" for detailed information")+      in do+        printErrMsg+        liftIO exitFailure+++checkExpr' :: Ctx -> Expr Var -> CoreM (Either TypeError CheckResult)+checkExpr' c (App e e') | isType e' || (not $ tcIsLiftedTypeKind $ typeKind $ exprType e')+  = checkExpr' c e+checkExpr' c@Ctx{current = cur, earlier = earl} expr@(App e e') =+  case Prim.isPrimExpr expr of+    Just (Prim.BoxApp _) ->+      checkExpr' (stabilize BoxApp c) e'+    Just (Prim.DelayApp f _) -> do+      let c' = case earl of+                 Nothing -> c{current = Set.empty, earlier = Just cur, allowGuardedRec = True}+                 Just earl' -> c{ current = Set.empty, earlier = Just cur, allowGuardedRec = True,+                                  hidden = hidden c `Map.union` Map.fromSet (const DelayApp) earl'}+      eRes <- checkExpr' c' e'+      case eRes of+        Left err -> return $ Left err+        Right (CheckResult {prim = Nothing}) -> return $ Left $ typeError c f (text "Each delay must contain an adv or select")+        Right _ -> return $ Right emptyCheckResult+    Just (Prim.AdvApp f _) | not (hasTick c) -> return $ Left $ typeError c f (text "can only use adv under delay")+    Just (Prim.AdvApp f (arg, _)) -> return $ Right $ CheckResult {prim = Just (f, mkClock1 arg)}+    Just (Prim.SelectApp f _ _) | not (hasTick c) -> return $ Left $ typeError c f (text "can only use select under delay")+    Just (Prim.SelectApp f (arg1, _) (arg2, _))-> return $ Right $ CheckResult {prim = Just (f, mkClock2 arg1 arg2)}+    Nothing -> checkBoth c e e'+checkExpr' c (Case e v _ alts) = do+    res <- checkExpr' c' e+    resAll <- mapM (\(Alt _ _ altE) -> checkExpr' c altE) alts+    foldM (fmap return . combine c) res resAll+  where c' = addVars [v] c+checkExpr' c (Lam v e)+  | isTyVar v || (not $ tcIsLiftedTypeKind $ typeKind $ varType v) = do+      is <- isStableConstr (varType v)+      let c' = case is of+            Nothing -> c+            Just t -> c{stableTypes = Set.insert t (stableTypes c)}+      checkExpr' c' e+  | otherwise = checkExpr' (addVars [v] (stabilizeLater c)) e+checkExpr' _ (Type _)  = return $ Right emptyCheckResult+checkExpr' _ (Lit _)  = return $ Right emptyCheckResult+checkExpr' _ (Coercion _)  = return $ Right emptyCheckResult+checkExpr' c (Tick (SourceNote span _name) e) =+  checkExpr' c{srcLoc = fromRealSrcSpan span} e+checkExpr' c (Tick _ e) = checkExpr' c e+checkExpr' c (Cast e _) = checkExpr' c e+checkExpr' c (Let (NonRec _ e1) e2) = do+  res1 <- checkExpr' c e1+  res2 <- checkExpr' c e2+  return $ combine c res1 res2+checkExpr' c (Let (Rec binds) e2) = do+    resAll <- mapM (\ (v,e) -> checkExpr' (c' v) e) binds+    res <- checkExpr' (addVars vs c) e2+    foldM (fmap return . combine c) res resAll+  where vs = map fst binds+        ctxHid = maybe (current c) (Set.union (current c)) (earlier c)+        c' v = c {current = Set.empty,+                  earlier = Nothing,+                  hidden =  hidden c `Map.union`+                   Map.fromSet (const (NestedRec v)) ctxHid,+                  recDef = recDef c `Set.union` Set.fromList vs }+checkExpr' c  (Var v)+  | tcIsLiftedTypeKind $ typeKind $ varType v =  case getScope c v of+             Hidden reason -> return $ Left $ typeError c v reason+             Visible -> return $ Right emptyCheckResult+  | otherwise = return $ Right emptyCheckResult++addVars :: [Var] -> Ctx -> Ctx+addVars v c = c{current = Set.fromList v `Set.union` current c }++checkBoth :: Ctx -> CoreExpr -> CoreExpr -> CoreM (Either TypeError CheckResult)+checkBoth c e e' = do+  c1 <- checkExpr' c e+  c2 <- checkExpr' c e'+  return $ combine c c1 c2++-- Combines two CheckResults such that the clocks therein are compatible.+-- If both CheckResults have PrimVars, one is picked arbitrarily.+combine :: Ctx -> Either TypeError CheckResult -> Either TypeError CheckResult -> Either TypeError CheckResult+combine c eRes1 eRes2 = do+  res1 <- eRes1+  res2 <- eRes2+  case (res1, res2) of+    (CheckResult (Just (_, cl1)), CheckResult (Just (_, cl2))) | cl1 == cl2 -> Right res2+    (CheckResult (Just _), CheckResult (Just (p, _))) -> Left $ typeError c p "Only one adv/select allowed in a delay"+    (CheckResult maybeP, CheckResult maybeP') -> Right $ CheckResult {prim = maybeP <|> maybeP'}
+ src/WidgetRattus/Plugin/Dependency.hs view
@@ -0,0 +1,385 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE GADTs #-}++-- | This module is used to perform a dependency analysis of top-level+-- function definitions, i.e. to find out which defintions are+-- (mutual) recursive. To this end, this module also provides+-- functions to compute, bound variables and variable occurrences.++module WidgetRattus.Plugin.Dependency (dependency, HasBV (..),printBinds) where+++import GHC.Plugins+import GHC.Data.Bag+import GHC.Hs.Type+++import GHC.Hs.Extension+import GHC.Hs.Expr+import GHC.Hs.Pat+import GHC.Hs.Binds++#if __GLASGOW_HASKELL__ >= 904+import GHC.Parser.Annotation+#else+import Language.Haskell.Syntax.Extension+import GHC.Parser.Annotation+#endif+++import Data.Set (Set)+import qualified Data.Set as Set+import Data.Graph+import Data.Maybe+import Data.Either+import Prelude hiding ((<>))++++-- | Compute the dependencies of a bag of bindings, returning a list+-- of the strongly-connected components.+dependency :: Bag (LHsBindLR GhcTc GhcTc) -> [SCC (LHsBindLR GhcTc GhcTc, Set Var)]+dependency binds = map AcyclicSCC noDeps ++ catMaybes (map filterJust (stronglyConnComp (concat deps)))+  where (deps,noDeps) = partitionEithers $ map mkDep $ bagToList binds+        mkDep :: GenLocated l (HsBindLR GhcTc GhcTc) ->+                 Either [(Maybe (GenLocated l (HsBindLR GhcTc GhcTc), Set Var), Name, [Name])]+                 (GenLocated l (HsBindLR GhcTc GhcTc), Set Var)+        mkDep b =+          let dep = map varName $ Set.toList (getFV b)+              vars = getBV b in+          case Set.toList vars of+            (v:vs) -> Left ((Just (b,vars), varName v , dep) : map (\ v' -> (Nothing, varName v' , dep)) vs)+            [] -> Right (b,vars)+        filterJust (AcyclicSCC Nothing) = Nothing -- this should not happen+        filterJust (AcyclicSCC (Just b)) = Just (AcyclicSCC b)+        filterJust (CyclicSCC bs) = Just (CyclicSCC (catMaybes bs))+++printBinds (AcyclicSCC bind) = liftIO (putStr "acyclic bind: ") >> printBind (fst bind) >> liftIO (putStrLn "") +printBinds (CyclicSCC binds) = liftIO (putStr "cyclic binds: ") >> mapM_ (printBind . fst) binds >> liftIO (putStrLn "") +++printBind (L _ FunBind{fun_id = L _ name}) = +  liftIO $ putStr $ (getOccString name ++ " ")+printBind (L _ (VarBind {var_id = name})) =   liftIO $ putStr $ (getOccString name ++ " ")+#if __GLASGOW_HASKELL__ < 904+printBind (L _ (AbsBinds {abs_exports = exp})) = +#else+printBind (L _ (XHsBindsLR (AbsBinds {abs_exports = exp}))) = +#endif+  mapM_ (\ e -> liftIO $ putStr $ ((getOccString $ abe_poly e)  ++ " ")) exp+printBind _ = return ()+++-- | Computes the variables that are bound by a given piece of syntax.++class HasBV a where+  getBV :: a -> Set Var++instance HasBV (HsBindLR GhcTc GhcTc) where+  getBV (FunBind{fun_id = L _ v}) = Set.singleton v+  getBV (PatBind {pat_lhs = pat}) = getBV pat+  getBV (VarBind {var_id = v}) = Set.singleton v+  getBV PatSynBind{} = Set.empty+#if __GLASGOW_HASKELL__ < 904+  getBV (AbsBinds {abs_exports = es}) = Set.fromList (map abe_poly es)+#else+  getBV (XHsBindsLR (AbsBinds {abs_exports = es})) = Set.fromList (map abe_poly es)+#endif+  +instance HasBV a => HasBV (GenLocated b a) where+  getBV (L _ e) = getBV e++instance HasBV a => HasBV [a] where+  getBV ps = foldl (\s p -> getBV p `Set.union` s) Set.empty ps++#if __GLASGOW_HASKELL__ >= 904+getRecFieldRhs = hfbRHS+#else+getRecFieldRhs = hsRecFieldArg+#endif++getConBV (PrefixCon _ ps) = getBV ps+getConBV (InfixCon p p') = getBV p `Set.union` getBV p'+getConBV (RecCon (HsRecFields {rec_flds = fs})) = foldl run Set.empty fs+      where run s (L _ f) = getBV (getRecFieldRhs f) `Set.union` s++#if __GLASGOW_HASKELL__ < 904+instance HasBV CoPat where+  getBV CoPat {co_pat_inner = p} = getBV p+#else+instance HasBV XXPatGhcTc where+  getBV CoPat {co_pat_inner = p} = getBV p+  getBV (ExpansionPat _ p) = getBV p+#endif++instance HasBV (Pat GhcTc) where+  getBV (VarPat _ (L _ v)) = Set.singleton v+  getBV (LazyPat _ p) = getBV p+#if __GLASGOW_HASKELL__ >= 906+  getBV (AsPat _ (L _ v) _ p) = Set.insert v (getBV p)+#else+  getBV (AsPat _ (L _ v) p) = Set.insert v (getBV p)+#endif+  getBV (BangPat _ p) = getBV p+  getBV (ListPat _ ps) = getBV ps+  getBV (TuplePat _ ps _) = getBV ps+  getBV (SumPat _ p _ _) = getBV p+  getBV (ViewPat _ _ p) = getBV p++  getBV (SplicePat _ sp) =+    case sp of+#if __GLASGOW_HASKELL__ < 906+      HsTypedSplice _ _ v _ -> Set.singleton v+      HsSpliced _ _ (HsSplicedPat p) -> getBV p+      HsUntypedSplice _ _ v _ ->  Set.singleton v+      HsQuasiQuote _ p p' _ _ -> Set.fromList [p,p']+      _ -> Set.empty+#else+      HsUntypedSpliceExpr _ e -> getFV e+      HsQuasiQuote _ v _  -> Set.singleton v+#endif++  getBV (NPlusKPat _ (L _ v) _ _ _ _) = Set.singleton v+  getBV (NPat {}) = Set.empty+  getBV (XPat p) = getBV p+  getBV (WildPat {}) = Set.empty+  getBV (LitPat {}) = Set.empty+#if __GLASGOW_HASKELL__ >= 904  +  getBV (ParPat _ _ p _) = getBV p+#else+  getBV (ParPat _ p) = getBV p+#endif+  getBV (ConPat {pat_args = con}) = getConBV con+  getBV (SigPat _ p _) = getBV p++#if __GLASGOW_HASKELL__ < 904+instance HasBV NoExtCon where+  getBV _ = Set.empty+#endif++-- | Syntax that may contain variables.+class HasFV a where+  -- | Compute the set of variables occurring in the given piece of+  -- syntax.  The name falsely suggests that returns free variables,+  -- but in fact it returns all variable occurrences, no matter+  -- whether they are free or bound.+  getFV :: a -> Set Var ++instance HasFV a => HasFV (GenLocated b a) where+  getFV (L _ e) = getFV e+  +instance HasFV a => HasFV [a] where+  getFV es = foldMap getFV es++instance HasFV a => HasFV (Bag a) where+  getFV es = foldMap getFV es++instance HasFV Var where+  getFV v = Set.singleton v++instance HasFV a => HasFV (MatchGroup GhcTc a) where+  getFV MG {mg_alts = alts} = getFV alts+  +instance HasFV a => HasFV (Match GhcTc a) where+  getFV Match {m_grhss = rhss} = getFV rhss++instance HasFV (HsTupArg GhcTc) where+  getFV (Present _ e) = getFV e+  getFV Missing {} = Set.empty++instance HasFV a => HasFV (GRHS GhcTc a) where+  getFV (GRHS _ g b) = getFV g `Set.union` getFV b++instance HasFV a => HasFV (GRHSs GhcTc a) where+  getFV GRHSs {grhssGRHSs = rhs, grhssLocalBinds = lbs} =+    getFV rhs `Set.union` getFV lbs+++instance HasFV (HsLocalBindsLR GhcTc GhcTc) where+  getFV (HsValBinds _ bs) = getFV bs+  getFV (HsIPBinds _ bs) = getFV bs+  getFV EmptyLocalBinds {} = Set.empty+  +instance HasFV (HsValBindsLR GhcTc GhcTc) where+  getFV (ValBinds _ b _) = getFV b+  getFV (XValBindsLR b) = getFV b++instance HasFV (NHsValBindsLR GhcTc) where+  getFV (NValBinds bs _) = foldMap (getFV . snd) bs++instance HasFV (HsBindLR GhcTc GhcTc) where+  getFV FunBind {fun_matches = ms} = getFV ms+  getFV PatBind {pat_rhs = rhs} = getFV rhs+  getFV VarBind {var_rhs = rhs} = getFV rhs+  getFV PatSynBind {} = Set.empty+#if __GLASGOW_HASKELL__ < 904+  getFV AbsBinds {abs_binds = bs} = getFV bs+#else+  getFV (XHsBindsLR AbsBinds {abs_binds = bs}) = getFV bs+#endif++instance HasFV (IPBind GhcTc) where+  getFV (IPBind _ _ e) = getFV e++instance HasFV (HsIPBinds GhcTc) where+  getFV (IPBinds _ bs) = getFV bs+  +instance HasFV (ApplicativeArg GhcTc) where+  getFV ApplicativeArgOne { arg_expr = e }     = getFV e+  getFV ApplicativeArgMany {app_stmts = es, final_expr = e} = getFV es `Set.union` getFV e++instance HasFV (ParStmtBlock GhcTc GhcTc) where+  getFV (ParStmtBlock _ es _ _) = getFV es+  +instance HasFV a => HasFV (StmtLR GhcTc GhcTc a) where+  getFV (LastStmt _ e _ _) = getFV e+  getFV (BindStmt _ _ e) = getFV e+  getFV (ApplicativeStmt _ args _) = foldMap (getFV . snd) args+  getFV (BodyStmt _ e _ _) = getFV e+  getFV (LetStmt _ bs) = getFV bs+  getFV (ParStmt _ stms e _) = getFV stms `Set.union` getFV e+  getFV TransStmt{} = Set.empty -- TODO+  getFV RecStmt{} = Set.empty -- TODO+++instance HasFV (HsRecFields GhcTc (GenLocated SrcSpanAnnA (HsExpr GhcTc))) where+  getFV HsRecFields{rec_flds = fs} = getFV fs++#if __GLASGOW_HASKELL__ >= 904+instance HasFV (HsFieldBind o (GenLocated SrcSpanAnnA (HsExpr GhcTc))) where+#else+instance HasFV (HsRecField' o (GenLocated SrcSpanAnnA (HsExpr GhcTc))) where+#endif+  getFV rf  = getFV (getRecFieldRhs rf)++instance HasFV (ArithSeqInfo GhcTc) where+  getFV (From e) = getFV e+  getFV (FromThen e1 e2) = getFV e1 `Set.union` getFV e2+  getFV (FromTo e1 e2) = getFV e1 `Set.union` getFV e2+  getFV (FromThenTo e1 e2 e3) = getFV e1 `Set.union` getFV e2 `Set.union` getFV e3+  +#if __GLASGOW_HASKELL__ >= 904+instance HasFV (HsQuote GhcTc) where+#else+instance HasFV (HsBracket GhcTc) where+#endif+  getFV (ExpBr _ e) = getFV e+  getFV (VarBr _ _ e) = getFV e+  getFV _ = Set.empty++instance HasFV (HsCmd GhcTc) where+  getFV (HsCmdArrApp _ e1 e2 _ _) = getFV e1 `Set.union` getFV e2+  getFV (HsCmdArrForm _ e _ _ cmd) = getFV e `Set.union` getFV cmd+  getFV (HsCmdApp _ e1 e2) = getFV e1 `Set.union` getFV e2+  getFV (HsCmdLam _ l) = getFV l+  getFV (HsCmdCase _ _ mg) = getFV mg+  getFV (HsCmdIf _ _ e1 e2 e3) = getFV e1 `Set.union` getFV e2 `Set.union` getFV e3+  getFV (HsCmdDo _ cmd) = getFV cmd+#if __GLASGOW_HASKELL__ >= 904+  getFV (HsCmdPar _ _ cmd _) = getFV cmd+  getFV (HsCmdLet _ _ bs _ _) = getFV bs+#else+  getFV (HsCmdPar _ cmd) = getFV cmd+  getFV (HsCmdLet _ bs _) = getFV bs+#endif+#if __GLASGOW_HASKELL__ >= 904+  getFV (HsCmdLamCase _ _ mg) = getFV mg+#else+  getFV (HsCmdLamCase _ mg) = getFV mg+#endif+  getFV (XCmd e) = getFV e+++instance (HasFV a, HasFV b) => HasFV (Either a b) where+  getFV (Left x) = getFV x+  getFV (Right x) = getFV x++#if __GLASGOW_HASKELL__ >= 908+instance HasFV (LHsRecUpdFields GhcTc) where+  getFV RegularRecUpdFields {recUpdFields = x} = getFV x+  getFV OverloadedRecUpdFields {olRecUpdFields = x} = getFV x+#endif++instance HasFV (HsCmdTop GhcTc) where+  getFV (HsCmdTop _ cmd) = getFV cmd++instance HasFV (HsExpr GhcTc) where+  getFV (HsVar _ v) = getFV v+  getFV HsUnboundVar {} = Set.empty+  getFV HsOverLabel {} = Set.empty+  getFV HsIPVar {} = Set.empty+  getFV HsOverLit {} = Set.empty+  getFV HsLit {} = Set.empty+  getFV (HsLam _ mg) = getFV mg+  getFV (HsApp _ e1 e2) = getFV e1 `Set.union` getFV e2      +  getFV (OpApp _ e1 e2 e3) = getFV e1 `Set.union` getFV e2 `Set.union` getFV e3+  getFV (NegApp _ e _) = getFV e+  getFV (SectionL _ e1 e2) = getFV e1 `Set.union` getFV e2+  getFV (SectionR _ e1 e2) = getFV e1 `Set.union` getFV e2+  getFV (ExplicitTuple _ es _) = getFV es+  getFV (ExplicitSum _ _ _ e) = getFV e+  getFV (HsCase _ e mg) = getFV e  `Set.union` getFV mg+  getFV (HsMultiIf _ es) = getFV es+  getFV (HsDo _ _ e) = getFV e+  getFV HsProjection {} = Set.empty+  getFV HsGetField {gf_expr = e} = getFV e+  getFV (ExplicitList _ es) = getFV es+  getFV (RecordUpd {rupd_expr = e, rupd_flds = fs}) = getFV e `Set.union` getFV fs+  getFV (RecordCon {rcon_flds = fs}) = getFV fs+  getFV (ArithSeq _ _ e) = getFV e+#if __GLASGOW_HASKELL__ >= 906+  getFV HsTypedSplice{} = Set.empty+  getFV HsUntypedSplice{} = Set.empty+#else+  getFV HsSpliceE{} = Set.empty+#endif+  getFV (HsProc _ _ e) = getFV e+  getFV (HsStatic _ e) = getFV e+  getFV (XExpr e) = getFV e+#if __GLASGOW_HASKELL__ >= 904+  getFV (HsPar _ _ e _) = getFV e  +  getFV (HsLamCase _ _ mg) = getFV mg+  getFV (HsLet _ _ bs _ e) = getFV bs `Set.union` getFV e+  getFV HsRecSel {} = Set.empty+  getFV (HsTypedBracket _ e) = getFV e+  getFV (HsUntypedBracket _ e) = getFV e+#else  +  getFV (HsBinTick _ _ _ e) = getFV e+  getFV (HsTick _ _ e) = getFV e+  getFV (HsLet _ bs e) = getFV bs `Set.union` getFV e+  getFV (HsPar _ e) = getFV e+  getFV (HsLamCase _ mg) = getFV mg+  getFV HsConLikeOut {} = Set.empty+  getFV HsRecFld {} = Set.empty+  getFV (HsBracket _ e) = getFV e+  getFV HsRnBracketOut {} = Set.empty+  getFV HsTcBracketOut {} = Set.empty+#endif++#if __GLASGOW_HASKELL__ >= 906+  getFV (HsAppType _ e _ _) = getFV e+  getFV (ExprWithTySig _ e _) = getFV e  +#else+  getFV (HsAppType _ e _) = getFV e+  getFV (ExprWithTySig _ e _) = getFV e  +#endif+  getFV (HsIf _ e1 e2 e3) = getFV e1 `Set.union` getFV e2 `Set.union` getFV e3+  getFV (HsPragE _ _ e) = getFV e+++instance HasFV XXExprGhcTc where+  getFV (WrapExpr e) = getFV e+  getFV (ExpansionExpr (HsExpanded _e1 e2)) = getFV e2+#if __GLASGOW_HASKELL__ >= 904  +  getFV (HsTick _ e) = getFV e+  getFV (HsBinTick _ _ e) = getFV e+  getFV ConLikeTc{} = Set.empty+#endif+++instance HasFV (e GhcTc) => HasFV (HsWrap e) where+  getFV (HsWrap _ e) = getFV e
+ src/WidgetRattus/Plugin/PrimExpr.hs view
@@ -0,0 +1,109 @@+{-# LANGUAGE OverloadedStrings #-}++module WidgetRattus.Plugin.PrimExpr (+    Prim (..),+    PrimInfo (..),+    function,+    prim,+    isPrimExpr+) where++import Data.Map (Map)+import qualified Data.Map as Map+import GHC.Plugins+import WidgetRattus.Plugin.Utils+import Prelude hiding ((<>))++data Prim = Delay | Adv | Box | Select++-- DelayApp has the following fields: Var = delay f, T1 = value type, T2 = later type (O v a)+-- AdvApp has the following fields: Var = adv f, TypedArg = var and type for arg+data PrimInfo = DelayApp Var Type | AdvApp Var TypedArg | BoxApp Var | SelectApp Var TypedArg TypedArg++type TypedArg = (Var, Type)++data PartialPrimInfo = PartialPrimInfo {+  primPart :: Prim,+  functionPart :: Var,+  args :: [Var],+  typeArgs :: [Type]+}++instance Outputable PartialPrimInfo where+  ppr (PartialPrimInfo Delay f _ typeArgs) = text "PartialPrimInfo { prim = Delay, function = " <> ppr f <> text "args = (not printing since it should be undefined) , typeArgs = " <> ppr typeArgs +  ppr (PartialPrimInfo prim f args typeArgs) = text "PartialPrimInfo { prim = " <> ppr prim <> text ", function = " <> ppr f <> text ", args = " <> ppr args <> text ", typeArgs = " <> ppr typeArgs++instance Outputable Prim where+  ppr Delay = "delay"+  ppr Adv = "adv"+  ppr Select = "select"+  ppr Box = "box"++instance Outputable PrimInfo where+  ppr (DelayApp f _) = text "DelayApp - function " <> ppr f +  ppr (BoxApp f) = text "BoxApp - function " <> ppr f+  ppr (AdvApp f arg) = text "AdvApp - function " <> ppr f <> text " | arg " <> ppr arg+  ppr (SelectApp f arg arg2) = text "SelectApp - function " <> ppr f <> text " | arg " <> ppr arg <> text " | arg2 " <> ppr arg2+  +primMap :: Map FastString Prim+primMap = Map.fromList+  [("delay", Delay),+   ("adv", Adv),+   ("select", Select),+   ("box", Box)+   ]+++isPrim :: Var -> Maybe Prim+isPrim v = case getNameModule v of+    Just (name, mod) | isRattModule mod -> Map.lookup name primMap+    _ -> Nothing++createPartialPrimInfo :: Prim -> Var -> PartialPrimInfo+createPartialPrimInfo prim function =+  PartialPrimInfo {+    primPart = prim,+    functionPart = function,+    args = [],+    typeArgs = []+  }++function :: PrimInfo -> Var+function (DelayApp f _) = f+function (BoxApp f) = f+function (AdvApp f _) = f+function (SelectApp f _ _) = f++prim :: PrimInfo -> Prim+prim (DelayApp {}) = Delay+prim (BoxApp _) = Box+prim (AdvApp {}) = Adv+prim (SelectApp {}) = Select++validatePartialPrimInfo :: PartialPrimInfo -> Maybe PrimInfo+validatePartialPrimInfo (PartialPrimInfo Select f [arg2V, argV] [arg2T, argT]) = Just $ SelectApp f (argV, argT) (arg2V, arg2T)+validatePartialPrimInfo (PartialPrimInfo Delay f [_] [argT]) = Just $ DelayApp f argT+validatePartialPrimInfo (PartialPrimInfo {primPart = Box, functionPart = f}) = Just $ BoxApp f+validatePartialPrimInfo (PartialPrimInfo Adv f [argV] [argT]) = Just $ AdvApp f (argV, argT)+validatePartialPrimInfo _ = Nothing++isPrimExpr :: Expr Var -> Maybe PrimInfo+isPrimExpr expr = isPrimExpr' expr >>= validatePartialPrimInfo++isPrimExpr' :: Expr Var -> Maybe PartialPrimInfo+isPrimExpr' (App e (Type t)) = case mPPI of+  Just pPI@(PartialPrimInfo {typeArgs = tArgs}) -> Just pPI {typeArgs = t : tArgs}+  Nothing -> Nothing+  where mPPI = isPrimExpr' e+isPrimExpr' (App e e') =+  case isPrimExpr' e of+    Just partPrimInfo@(PartialPrimInfo { primPart = Delay, args = args}) -> Just partPrimInfo {args = undefined : args}+    Just partPrimInfo@(PartialPrimInfo { args = args}) -> Just partPrimInfo {args = maybe args (:args) (getMaybeVar e')}+    _ -> Nothing+isPrimExpr' (Var v) = case isPrim v of+  Just p ->  Just $ createPartialPrimInfo p v+  Nothing -> Nothing+isPrimExpr' (Tick _ e) = isPrimExpr' e+isPrimExpr' (Lam v e)+  | isTyVar v || (not $ tcIsLiftedTypeKind $ typeKind $ varType v) = isPrimExpr' e+isPrimExpr' _ = Nothing
+ src/WidgetRattus/Plugin/ScopeCheck.hs view
@@ -0,0 +1,812 @@+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ImplicitParams #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE CPP #-}++++-- | This module implements the source plugin that checks the variable+-- scope of of Async Rattus programs.++module WidgetRattus.Plugin.ScopeCheck (checkAll) where++import WidgetRattus.Plugin.Utils+import WidgetRattus.Plugin.Dependency+import WidgetRattus.Plugin.Annotation++import Control.Monad.Trans.State.Strict+import Data.IORef++import Prelude hiding ((<>))++import GHC.Parser.Annotation+import GHC.Plugins+import GHC.Tc.Types+import GHC.Data.Bag+import GHC.Tc.Types.Evidence+import GHC.Hs.Extension+import GHC.Hs.Expr+import GHC.Hs.Pat+import GHC.Hs.Binds++import Data.Graph+import qualified Data.Set as Set+import qualified Data.Map as Map+import Data.Set (Set)+import Data.Map (Map)+import Data.List+import Data.List.NonEmpty (NonEmpty(..),(<|),nonEmpty)+import System.Exit+import Data.Either+import Data.Maybe++import Data.Data hiding (tyConName)++import Control.Monad++type ErrorMsg = (Severity,SrcSpan,SDoc)+type ErrorMsgsRef = IORef [ErrorMsg]++-- | The current context for scope checking+data Ctxt = Ctxt+  {+    errorMsgs :: ErrorMsgsRef,+    -- | Variables that are in scope now (i.e. occurring in the typing+    -- context but not to the left of a tick)+    current :: LCtxt,+    -- | Variables that are in the typing context, but to the left of a+    -- tick+    earlier :: Either NoTickReason (NonEmpty LCtxt),+    -- | Variables that have fallen out of scope. The map contains the+    -- reason why they have fallen out of scope.+    hidden :: Hidden,+    -- -- | Same as 'hidden' but for recursive variables.+    -- hiddenRec :: Hidden,+    -- | The current location information.+    srcLoc :: SrcSpan,+    -- | If we are in the body of a recursively defined function, this+    -- field contains the variables that are defined recursively+    -- (could be more than one due to mutual recursion or because of a+    -- recursive pattern definition) and the location of the recursive+    -- definition.+    recDef :: Maybe RecDef,+    -- | Type variables with a 'Stable' constraint attached to them.+    stableTypes :: Set Var,+    -- | A mapping from variables to the primitives that they are+    -- defined equal to. For example, a program could contain @let+    -- mydel = delay in mydel 1@, in which case @mydel@ is mapped to+    -- 'Delay'.+    primAlias :: Map Var Prim,+    -- | Allow general recursion.+    allowRecursion :: Bool}++++-- | The starting context for checking a top-level definition. For+-- non-recursive definitions, the argument is @Nothing@. Otherwise, it+-- contains the recursively defined variables along with the location+-- of the recursive definition.+emptyCtxt :: ErrorMsgsRef -> Maybe (Set Var,SrcSpan) -> Bool -> Ctxt+emptyCtxt em mvar allowRec =+  Ctxt { errorMsgs = em,+         current =  Set.empty,+         earlier = Left NoDelay,+         hidden = Map.empty,+         srcLoc = noLocationInfo,+         recDef = mvar,+         primAlias = Map.empty,+         stableTypes = Set.empty,+         allowRecursion = allowRec}++-- | A local context, consisting of a set of variables.+type LCtxt = Set Var++-- | The recursively defined variables + the position where the+-- recursive definition starts+type RecDef = (Set Var, SrcSpan)+++++data StableReason = StableRec SrcSpan | StableBox deriving Show++-- | Indicates, why a variable has fallen out of scope.+data HiddenReason = Stabilize StableReason | FunDef | DelayApp | AdvApp | SelectApp deriving Show++-- | Indicates, why there is no tick+data NoTickReason = NoDelay | TickHidden HiddenReason deriving Show++-- | Hidden context, containing variables that have fallen out of+-- context along with the reason why they have.+type Hidden = Map Var HiddenReason++-- | The 5 primitive Asynchronous Rattus operations.+data Prim = Delay | Adv | Select | Box | Unbox deriving Show++-- | This constraint is used to pass along the context implicitly via+-- an implicit parameter.+type GetCtxt = ?ctxt :: Ctxt+++type CheckM = StateT ([Maybe (Prim, SrcSpan)]) TcM++-- | This type class is implemented for each AST type @a@ for which we+-- can check whether it adheres to the scoping rules of Asynchronous Rattus.+class Scope a where+  -- | Check whether the argument is a scope correct piece of syntax+  -- in the given context.+  check :: GetCtxt => a -> CheckM Bool++-- | This is a variant of 'Scope' for syntax that can also bind+-- variables.+class ScopeBind a where+  -- | 'checkBind' checks whether its argument is scope-correct and in+  -- addition returns the the set of variables bound by it.+  checkBind :: GetCtxt => a -> CheckM (Bool,Set Var)+++-- | set the current context.+setCtxt :: Ctxt -> (GetCtxt => a) -> a +setCtxt c a = let ?ctxt = c in a+++-- | modify the current context.+modifyCtxt :: (Ctxt -> Ctxt) -> (GetCtxt => a) -> (GetCtxt => a)+modifyCtxt f a =+  let newc = f ?ctxt in+  let ?ctxt = newc in a+++++getLocAnn' :: SrcSpanAnn' b -> SrcSpan+getLocAnn' = locA+++updateLoc :: SrcSpanAnn' b -> (GetCtxt => a) -> (GetCtxt => a)+updateLoc src = modifyCtxt (\c -> c {srcLoc = getLocAnn' src})+++-- | Check all definitions in the given module. If Scope errors are+-- found, the current execution is halted with 'exitFailure'.+checkAll :: TcGblEnv -> TcM ()+checkAll env = do+  let bindDep = dependency (tcg_binds env)+  result <- mapM (checkSCC' (tcg_mod env) (tcg_ann_env env)) bindDep+  let (res,msgs) = foldl' (\(b,l) (b',l') -> (b && b', l ++ l')) (True,[]) result+  printAccErrMsgs msgs+  if res then return () else liftIO exitFailure+++printAccErrMsgs :: [ErrorMsg] -> TcM ()+printAccErrMsgs msgs = mapM_ printMsg (sortOn (\(_,l,_)->l) msgs)+  where printMsg (sev,loc,doc) = printMessage sev loc doc+++++instance Scope a => Scope (GenLocated SrcSpan a) where+  check (L l x) =  (\c -> c {srcLoc = l}) `modifyCtxt` check x++instance Scope a => Scope (GenLocated (SrcSpanAnn' b) a) where+  check (L l x) =  updateLoc l $ check x+  +instance Scope a => Scope (Bag a) where+  check bs = fmap and (mapM check (bagToList bs))++instance Scope a => Scope [a] where+  check ls = fmap and (mapM check ls)+++instance Scope (Match GhcTc (GenLocated SrcAnno (HsExpr GhcTc))) where+  check Match{m_pats=ps,m_grhss=rhs} = addVars (getBV ps) `modifyCtxt` check rhs++instance Scope (Match GhcTc (GenLocated SrcAnno (HsCmd GhcTc))) where+  check Match{m_pats=ps,m_grhss=rhs} = addVars (getBV ps) `modifyCtxt` check rhs+++instance Scope (MatchGroup GhcTc (GenLocated SrcAnno (HsExpr GhcTc))) where+  check MG {mg_alts = alts} = check alts+++instance Scope (MatchGroup GhcTc (GenLocated SrcAnno (HsCmd GhcTc))) where+  check MG {mg_alts = alts} = check alts+++instance Scope a => ScopeBind (StmtLR GhcTc GhcTc a) where+  checkBind (LastStmt _ b _ _) =  ( , Set.empty) <$> check b+  checkBind (BindStmt _ p b) = do+    let vs = getBV p+    let c' = addVars vs ?ctxt+    r <- setCtxt c' (check b)+    return (r,vs)+  checkBind (BodyStmt _ b _ _) = ( , Set.empty) <$> check b+  checkBind (LetStmt _ bs) = checkBind bs+  checkBind ParStmt{} = notSupported "monad comprehensions"+  checkBind TransStmt{} = notSupported "monad comprehensions"+  checkBind ApplicativeStmt{} = notSupported "applicative do notation"+  checkBind RecStmt{} = notSupported "recursive do notation"++instance ScopeBind a => ScopeBind [a] where+  checkBind [] = return (True,Set.empty)+  checkBind (x:xs) = do+    (r,vs) <- checkBind x+    (r',vs') <- addVars vs `modifyCtxt` (checkBind xs)+    return (r && r',vs `Set.union` vs')++instance ScopeBind a => ScopeBind (GenLocated SrcSpan a) where+  checkBind (L l x) =  (\c -> c {srcLoc = l}) `modifyCtxt` checkBind x++instance ScopeBind a => ScopeBind (GenLocated (SrcSpanAnn' b) a) where+  checkBind (L l x) =  updateLoc l $ checkBind x++instance Scope a => Scope (GRHS GhcTc a) where+  check (GRHS _ gs b) = do+    (r, vs) <- checkBind gs+    r' <- addVars vs `modifyCtxt`  (check b)+    return (r && r')++checkRec :: GetCtxt => LHsBindLR GhcTc GhcTc -> CheckM Bool+checkRec b =  liftM2 (&&) (checkPatBind b) (check b)++checkPatBind :: GetCtxt => LHsBindLR GhcTc GhcTc -> CheckM Bool+checkPatBind (L l b) = updateLoc l $ checkPatBind' b++checkPatBind' :: GetCtxt => HsBindLR GhcTc GhcTc -> CheckM Bool+checkPatBind' PatBind{} = do+  printMessage' SevError ("(Mutual) recursive pattern binding definitions are not supported in Asynchronous Rattus")+  return False+#if __GLASGOW_HASKELL__ < 904+checkPatBind' AbsBinds {abs_binds = binds} = +#else+checkPatBind' (XHsBindsLR AbsBinds {abs_binds = binds}) = +#endif+  liftM and (mapM checkPatBind (bagToList binds))++checkPatBind' _ = return True+++-- | Check the scope of a list of (mutual) recursive bindings. The+-- second argument is the set of variables defined by the (mutual)+-- recursive bindings+checkRecursiveBinds :: GetCtxt => [LHsBindLR GhcTc GhcTc] -> Set Var -> CheckM (Bool, Set Var)+checkRecursiveBinds bs vs = do+    res <- fmap and (mapM check' bs)+    return (res, vs)+    where check' b@(L l _) = fc (getLocAnn' l) `modifyCtxt` checkRec b+          fc l c = let+            ctxHid = either (const $ current c) (Set.union (current c) . Set.unions) (earlier c)+            in c {current = Set.empty,+                  earlier = Left (TickHidden $ Stabilize $ StableRec l),+                  hidden =  hidden c `Map.union`+                            (Map.fromSet (const (Stabilize (StableRec l))) ctxHid),+                  recDef = maybe (Just (vs,l)) (\(vs',_) -> Just (Set.union vs' vs,l)) (recDef c)+                   -- TODO fix location info of recDef (needs one location for each var)+                   }          +++instance ScopeBind (SCC (GenLocated SrcSpanAnnA (HsBindLR  GhcTc GhcTc), Set Var)) where+  checkBind (AcyclicSCC (b,vs)) = (, vs) <$> check b+  checkBind (CyclicSCC bs) = checkRecursiveBinds (map fst bs) (foldMap snd bs)+  +instance ScopeBind (HsValBindsLR GhcTc GhcTc) where+  checkBind (ValBinds _ bs _) = checkBind (dependency bs)+  +  checkBind (XValBindsLR (NValBinds binds _)) = checkBind binds+++instance ScopeBind (HsBindLR GhcTc GhcTc) where+  checkBind b = (, getBV b) <$> check b+++-- | Compute the set of variables defined by the given Haskell binder.+getAllBV :: GenLocated l (HsBindLR GhcTc GhcTc) -> Set Var+getAllBV (L _ b) = getAllBV' b where+  getAllBV' (FunBind{fun_id = L _ v}) = Set.singleton v+#if __GLASGOW_HASKELL__ < 904+  getAllBV' (AbsBinds {abs_exports = es, abs_binds = bs}) = Set.fromList (map abe_poly es) `Set.union` foldMap getBV bs+  getAllBV' XHsBindsLR{} = Set.empty+#else+  getAllBV' (XHsBindsLR (AbsBinds {abs_exports = es, abs_binds = bs})) = Set.fromList (map abe_poly es) `Set.union` foldMap getBV bs+#endif+  getAllBV' (PatBind {pat_lhs = pat}) = getBV pat+  getAllBV' (VarBind {var_id = v}) = Set.singleton v+  getAllBV' PatSynBind{} = Set.empty+++-- Check nested bindings+instance ScopeBind (RecFlag, Bag (GenLocated SrcSpanAnnA (HsBindLR GhcTc GhcTc))) where+  checkBind (NonRecursive, bs)  = checkBind $ bagToList bs+  checkBind (Recursive, bs) = checkRecursiveBinds bs' (foldMap getAllBV bs')+    where bs' = bagToList bs+++instance ScopeBind (HsLocalBindsLR GhcTc GhcTc) where+  checkBind (HsValBinds _ bs) = checkBind bs+  checkBind HsIPBinds {} = notSupported "implicit parameters"+  checkBind EmptyLocalBinds{} = return (True,Set.empty)++type SrcAnno = SrcSpanAnnA+  +instance Scope (GRHSs GhcTc (GenLocated SrcAnno (HsExpr GhcTc))) where+  check GRHSs{grhssGRHSs = rhs, grhssLocalBinds = lbinds} = do+    (l,vs) <- checkBind lbinds+    r <- addVars vs `modifyCtxt` (check rhs)+    return (r && l)++instance Scope (GRHSs GhcTc (GenLocated SrcAnno (HsCmd GhcTc))) where+  check GRHSs{grhssGRHSs = rhs, grhssLocalBinds = lbinds} = do+    (l,vs) <- checkBind lbinds+    r <- addVars vs `modifyCtxt` (check rhs)+    return (r && l)++instance Show Var where+  show v = getOccString v+++tickHidden :: HiddenReason -> SDoc+tickHidden FunDef = "a function definition"+tickHidden DelayApp = "a nested application of delay"+tickHidden AdvApp = "an application of adv"+tickHidden SelectApp = "an application of select"+tickHidden (Stabilize StableBox) = "an application of box"+tickHidden (Stabilize (StableRec src)) = "a nested recursive definition (at " <> ppr src <> ")"++isSelect :: GetCtxt => LHsExpr GhcTc -> Bool+isSelect e =+  case isPrimExpr e of+    Just (Select, _) -> True+    _ -> False++instance Scope (HsExpr GhcTc) where+  check (HsVar _ (L _ v))+    | Just p <- isPrim v =+        case p of+          Unbox -> return True+          _ -> printMessageCheck SevError ("Defining an alias for " <> ppr v <> " is not allowed")+    | otherwise = case getScope v of+             Hidden reason -> printMessageCheck SevError reason+             Visible -> return True+             ImplUnboxed -> return True+               -- printMessageCheck SevWarning+               --  (ppr v <> text " is an external temporal function used under delay, which may cause time leaks.")+  check (HsApp _ (L _ (HsApp _ f arg)) arg2) | isSelect f =+    case earlier ?ctxt of+      Right (er :| ers) -> do+        res <- get+        case res of+            Just _ : _ -> printMessageCheck SevError ("only one adv or select may be used in the scope of a delay.")+            Nothing : pre -> do put pre+                                b1 <- mod `modifyCtxt` check arg+                                b2 <- mod `modifyCtxt` check arg2+                                modify (Just (Select, srcLoc ?ctxt) :)+                                return $ b1 && b2+            _ -> error "Asynchronous Rattus: internal error"+        where mod c =  c{earlier = case nonEmpty ers of+                                    Nothing -> Left $ TickHidden SelectApp+                                    Just ers' -> Right ers',+                        current = er,+                        hidden = hidden ?ctxt `Map.union`+                        Map.fromSet (const SelectApp) (current ?ctxt)}+      Left NoDelay -> printMessageCheck SevError "select may only be used in the scope of a delay."+      Left (TickHidden hr) -> printMessageCheck SevError ("select may only be used in the scope of a delay. "+                        <> " There is a delay, but its scope is interrupted by " <> tickHidden hr <> ".")+  check (HsApp _ e1 e2) =+    case isPrimExpr e1 of+    Just (p,_) -> case p of+      Box -> do+        ch <- stabilize StableBox `modifyCtxt` check e2+        return ch+      Unbox -> check e2+      Delay -> do modify (Nothing :)+                  b <- (\c -> c{current = Set.empty,+                           earlier = case earlier c of+                                      Left _ -> Right (current c :| [])+                                      Right cs -> Right (current c <| cs)})+                     `modifyCtxt` check e2+                  res <- get+                  case res of+                    Nothing : _ -> printMessageCheck SevError "No adv or select found in the scope of this occurrence of delay"+                    _ : pre -> put pre >> return b+                    _ -> error "Asynchronous Rattus: internal error"+      Adv -> case earlier ?ctxt of+        Right (er :| ers) -> do+          res <- get+          case res of+            Just _ : _ -> printMessageCheck SevError ("only one adv or select may be used in the scope of a delay.")+            Nothing : pre -> do put pre+                                b <- mod `modifyCtxt` check e2+                                modify (Just (Adv,srcLoc ?ctxt) :)+                                return b+            _ -> error "Asynchronous Rattus: internal error"+          where mod c =  c{earlier = case nonEmpty ers of+                                       Nothing -> Left $ TickHidden AdvApp+                                       Just ers' -> Right ers',+                           current = er,+                           hidden = hidden ?ctxt `Map.union`+                            Map.fromSet (const AdvApp) (current ?ctxt)}+        Left NoDelay -> printMessageCheck SevError ("adv may only be used in the scope of a delay.")+        Left (TickHidden hr) -> printMessageCheck SevError ("adv may only be used in the scope of a delay. "+                            <> " There is a delay, but its scope is interrupted by " <> tickHidden hr <> ".")+      Select -> printMessageCheck SevError ("select must be fully applied")+    _ -> liftM2 (&&) (check e1)  (check e2)+  check HsUnboundVar{}  = return True+#if __GLASGOW_HASKELL__ >= 904+  check (HsPar _ _ e _) = check e+  check (HsLamCase _ _ mg) = check mg+  check HsRecSel{} = return True+  check HsTypedBracket{} = notSupported "MetaHaskell"+  check HsUntypedBracket{} = notSupported "MetaHaskell"+#else+  check HsConLikeOut{} = return True+  check HsRecFld{} = return True+  check (HsPar _ e) = check e+  check (HsLamCase _ mg) = check mg+  check HsBracket{} = notSupported "MetaHaskell"+  check (HsTick _ _ e) = check e+  check (HsBinTick _ _ _ e) = check e+  check HsRnBracketOut{} = notSupported "MetaHaskell"+  check HsTcBracketOut{} = notSupported "MetaHaskell"+#endif+#if __GLASGOW_HASKELL__ >= 904+  check (HsLet _ _ bs _ e) = do+#else+  check (HsLet _ bs e) = do+#endif+    (l,vs) <- checkBind bs+    r <- addVars vs `modifyCtxt` (check e)+    return (r && l)+         +  check HsOverLabel{} = return True+  check HsIPVar{} = notSupported "implicit parameters"+  check HsOverLit{} = return True  +  check HsLit{} = return True+  check (OpApp _ e1 e2 e3) = and <$> mapM check [e1,e2,e3]+  check (HsLam _ mg) = check mg+  check (HsCase _ e1 e2) = (&&) <$> check e1 <*> check e2+  check (SectionL _ e1 e2) = (&&) <$> check e1 <*> check e2+  check (SectionR _ e1 e2) = (&&) <$> check e1 <*> check e2+  check (ExplicitTuple _ e _) = check e+  check (NegApp _ e _) = check e+  check (ExplicitSum _ _ _ e) = check e+  check (HsMultiIf _ e) = check e+  check (ExplicitList _ e) = check e+  check HsProjection {} = return True+  check HsGetField {gf_expr = e} = check e+  check RecordUpd { rupd_expr = e, rupd_flds = fs} = (&&) <$> check e <*> check fs+  check RecordCon { rcon_flds = f} = check f+  check (ArithSeq _ _ e) = check e+#if __GLASGOW_HASKELL__ >= 906+  check HsTypedSplice{} = notSupported "Template Haskell"+  check HsUntypedSplice{} = notSupported "Template Haskell"+#else+  check HsSpliceE{} = notSupported "Template Haskell"+#endif+  check (HsProc _ _ e) = check e+  check (HsStatic _ e) = check e+  check (HsDo _ _ e) = fst <$> checkBind e+  check (XExpr e) = check e+#if __GLASGOW_HASKELL__ >= 906+  check (HsAppType _ e _ _) = check e+  check (ExprWithTySig _ e _) = check e+#else+  check (HsAppType _ e _) = check e+  check (ExprWithTySig _ e _) = check e+#endif+  check (HsPragE _ _ e) = check e+  check (HsIf _ e1 e2 e3) = and <$> mapM check [e1,e2,e3]+++instance (Scope a, Scope b) => Scope (Either a b) where+  check (Left x) = check x+  check (Right x) = check x+++#if __GLASGOW_HASKELL__ >= 908+instance Scope (LHsRecUpdFields GhcTc) where+  check RegularRecUpdFields {recUpdFields = x} = check x+  check OverloadedRecUpdFields {olRecUpdFields = x} = check x+#endif+++instance Scope XXExprGhcTc where+  check (WrapExpr (HsWrap _ e)) = check e+  check (ExpansionExpr (HsExpanded _ e)) = check e+#if __GLASGOW_HASKELL__ >= 904+  check ConLikeTc{} = return True+  check (HsTick _ e) = check e+  check (HsBinTick _ _ e) = check e+#endif++instance Scope (HsCmdTop GhcTc) where+  check (HsCmdTop _ e) = check e+  +instance Scope (HsCmd GhcTc) where+  check (HsCmdArrApp _ e1 e2 _ _) = (&&) <$> check e1 <*> check e2+  check (HsCmdDo _ e) = fst <$> checkBind e+  check (HsCmdArrForm _ e1 _ _ e2) = (&&) <$> check e1 <*> check e2+  check (HsCmdApp _ e1 e2) = (&&) <$> check e1 <*> check e2+  check (HsCmdLam _ e) = check e+#if __GLASGOW_HASKELL__ >= 904+  check (HsCmdPar _ _ e _) = check e+  check (HsCmdLamCase _ _ e) = check e  +  check (HsCmdLet _ _ bs _ e) = do+#else+  check (HsCmdPar _ e) = check e+  check (HsCmdLamCase _ e) = check e+  check (HsCmdLet _ bs e) = do+#endif+    (l,vs) <- checkBind bs+    r <- addVars vs `modifyCtxt` (check e)+    return (r && l)++  check (HsCmdCase _ e1 e2) = (&&) <$> check e1 <*> check e2+  check (HsCmdIf _ _ e1 e2 e3) = (&&) <$> ((&&) <$> check e1 <*> check e2) <*> check e3+  check (XCmd (HsWrap _ e)) = check e+++instance Scope (ArithSeqInfo GhcTc) where+  check (From e) = check e+  check (FromThen e1 e2) = (&&) <$> check e1 <*> check e2+  check (FromTo e1 e2) = (&&) <$> check e1 <*> check e2+  check (FromThenTo e1 e2 e3) = (&&) <$> ((&&) <$> check e1 <*> check e2) <*> check e3++instance Scope a => Scope (HsRecFields GhcTc a) where+  check HsRecFields {rec_flds = fs} = check fs++++#if __GLASGOW_HASKELL__ >= 904+instance Scope b => Scope (HsFieldBind a b) where+  check HsFieldBind{hfbRHS = a} = check a+#else+instance Scope b => Scope (HsRecField' a b) where+  check HsRecField{hsRecFieldArg = a} = check a+#endif++instance Scope (HsTupArg GhcTc) where+  check (Present _ e) = check e+  check Missing{} = return True++instance Scope (HsBindLR GhcTc GhcTc) where+#if __GLASGOW_HASKELL__ >= 904+  check (XHsBindsLR AbsBinds {abs_binds = binds, abs_ev_vars  = ev})+#else+  check AbsBinds {abs_binds = binds, abs_ev_vars  = ev}+#endif+    = mod `modifyCtxt` check binds+      where mod c = c { stableTypes= stableTypes c `Set.union`+                        Set.fromList (mapMaybe (isStableConstr . varType) ev)}+  check FunBind{fun_matches= matches, fun_id = L _ v,+                fun_ext = wrapper} =+      mod `modifyCtxt` check matches+    where mod c = c { stableTypes= stableTypes c `Set.union`+                      Set.fromList (stableConstrFromWrapper' wrapper)  `Set.union`+                      Set.fromList (extractStableConstr (varType v))}+  check PatBind{pat_lhs = lhs, pat_rhs=rhs} = addVars (getBV lhs) `modifyCtxt` check rhs+  check VarBind{var_rhs = rhs} = check rhs+  check PatSynBind {} = return True -- pattern synonyms are not supported+++-- | Checks whether the given type is a type constraint of the form+-- @Stable a@ for some type variable @a@. In that case it returns the+-- type variable @a@.+isStableConstr :: Type -> Maybe TyVar+isStableConstr t = +  case splitTyConApp_maybe t of+    Just (con,[args]) ->+      case getNameModule con of+        Just (name, mod) ->+          if isRattModule mod && name == "Stable"+          then (getTyVar_maybe args)+          else Nothing+        _ -> Nothing                           +    _ ->  Nothing++++#if __GLASGOW_HASKELL__ >= 906+stableConstrFromWrapper' :: (HsWrapper , a) -> [TyVar]+stableConstrFromWrapper' (x , _) = stableConstrFromWrapper x+#else+stableConstrFromWrapper' :: HsWrapper -> [TyVar]+stableConstrFromWrapper' = stableConstrFromWrapper+#endif++stableConstrFromWrapper :: HsWrapper -> [TyVar]+stableConstrFromWrapper (WpCompose v w) = stableConstrFromWrapper v ++ stableConstrFromWrapper w+stableConstrFromWrapper (WpEvLam v) = maybeToList $ isStableConstr (varType v)+stableConstrFromWrapper _ = []+++-- | Given a type @(C1, ... Cn) => t@, this function returns the list+-- of type variables @[a1,...,am]@ for which there is a constraint+-- @Stable ai@ among @C1, ... Cn@.+extractStableConstr :: Type -> [TyVar]+extractStableConstr  = mapMaybe isStableConstr . map irrelevantMult . fst . splitFunTys . snd . splitForAllTys'+++getSCCLoc :: SCC (LHsBindLR  GhcTc GhcTc, Set Var) -> SrcSpan+getSCCLoc (AcyclicSCC (L l _ ,_)) = getLocAnn' l+getSCCLoc (CyclicSCC ((L l _,_ ) : _)) = getLocAnn' l+getSCCLoc _ = noLocationInfo++checkSCC' ::  Module -> AnnEnv -> SCC (LHsBindLR  GhcTc GhcTc, Set Var) -> TcM (Bool, [ErrorMsg])+checkSCC' mod anEnv scc = do+  err <- liftIO (newIORef [])+  let allowRec = AllowRecursion `Set.member` getAnn mod anEnv scc+  res <- checkSCC allowRec err scc+  msgs <- liftIO (readIORef err)+  let anns = getAnn mod anEnv scc+  if ExpectWarning `Set.member` anns +    then if ExpectError `Set.member` anns+         then return (False,[(SevError, getSCCLoc scc, "Annotation to expect both warning and error is not allowed.")])+         else if any (\(s,_,_) -> case s of SevWarning -> True; _ -> False) msgs+              then return (res, filter (\(s,_,_) -> case s of SevWarning -> False; _ -> True) msgs)+              else return (False,[(SevError, getSCCLoc scc, "Warning was expected, but typechecking produced no warning.")])+    else if ExpectError `Set.member` anns+         then if res+              then return (False,[(SevError, getSCCLoc scc, "Error was expected, but typechecking produced no error.")])+              else return (True,[])+         else return (res, msgs)+getAnn :: forall a . (Data a, Ord a) => Module -> AnnEnv -> SCC (LHsBindLR  GhcTc GhcTc, Set Var) -> Set a+getAnn mod anEnv scc =+  case scc of+    (AcyclicSCC (_,vs)) -> Set.unions $ Set.map checkVar vs+    (CyclicSCC bs) -> Set.unions $ map (Set.unions . Set.map checkVar . snd) bs+  where checkVar :: Var -> Set a+        checkVar v =+          let anns = findAnns deserializeWithData anEnv (NamedTarget name) :: [a]+              annsMod = findAnns deserializeWithData anEnv (ModuleTarget mod) :: [a]+              name :: Name+              name = varName v+          in Set.fromList anns `Set.union` Set.fromList annsMod++++-- | Checks a top-level definition group, which is either a single+-- non-recursive definition or a group of (mutual) recursive+-- definitions.++checkSCC :: Bool -> ErrorMsgsRef -> SCC (LHsBindLR  GhcTc GhcTc, Set Var) -> TcM Bool+checkSCC allowRec errm (AcyclicSCC (b,_)) = setCtxt (emptyCtxt errm Nothing allowRec) (evalStateT (check b) [])++checkSCC allowRec errm (CyclicSCC bs) = (fmap and (mapM check' bs'))+  where bs' = map fst bs+        vs = foldMap snd bs+        check' b@(L l _) = setCtxt (emptyCtxt errm (Just (vs,getLocAnn' l)) allowRec) (evalStateT (checkRec b) [])++-- | Stabilizes the given context, i.e. remove all non-stable types+-- and any tick. This is performed on checking 'box', and+-- guarded recursive definitions. To provide better error messages a+-- reason has to be given as well.+stabilize :: StableReason -> Ctxt -> Ctxt+stabilize sr c = c+  {current = Set.empty,+   earlier = Left $ TickHidden hr,+   hidden = hidden c `Map.union` Map.fromSet (const hr) ctxHid}+  where ctxHid = either (const $ current c) (foldl' Set.union (current c)) (earlier c)+        hr = Stabilize sr++data VarScope = Hidden SDoc | Visible | ImplUnboxed+++-- | This function checks whether the given variable is in scope.+getScope  :: GetCtxt => Var -> VarScope+getScope v =+  case ?ctxt of+    Ctxt{recDef = Just (vs,_), earlier = e, allowRecursion = allowRec} | v `Set.member` vs ->+     if allowRec then Visible else+        case e of+          Right _ -> Visible+          Left NoDelay -> Hidden ("The (mutually) recursive call to " <> ppr v <> " must occur in the scope of a delay")+          Left (TickHidden hr) -> Hidden ("The (mutually) recursive call to " <> ppr v <> " must occur in the scope of a delay. "+                            <> "There is a delay, but its scope is interrupted by " <> tickHidden hr <> ".")+    _ ->  case Map.lookup v (hidden ?ctxt) of+            Just (Stabilize (StableRec rv)) ->+              if (isStable (stableTypes ?ctxt) (varType v)) || allowRecursion ?ctxt then Visible+              else Hidden ("Variable " <> ppr v <> " is no longer in scope:" $$+                       "It appears in a local recursive definition (at " <> ppr rv <> ")"+                       $$ "and is of type " <> ppr (varType v) <> ", which is not stable.")+            Just (Stabilize StableBox) ->+              if (isStable (stableTypes ?ctxt) (varType v)) then Visible+              else Hidden ("Variable " <> ppr v <> " is no longer in scope:" $$+                       "It occurs under " <> keyword "box" $$ "and is of type " <> ppr (varType v) <> ", which is not stable.")+            Just AdvApp -> Hidden ("Variable " <> ppr v <> " is no longer in scope: It occurs under adv.")+            Just SelectApp -> Hidden ("Variable " <> ppr v <> " is no longer in scope: It occurs under select.")+            Just DelayApp -> Hidden ("Variable " <> ppr v <> " is no longer in scope due to repeated application of delay")+            Just FunDef -> if (isStable (stableTypes ?ctxt) (varType v)) then Visible+              else Hidden ("Variable " <> ppr v <> " is no longer in scope: It occurs in a function that is defined under a delay, is a of a non-stable type " <> ppr (varType v) <> ", and is bound outside delay")+            Nothing+              | either (const False) (any (Set.member v)) (earlier ?ctxt) ->+                if isStable (stableTypes ?ctxt) (varType v) then Visible+                else Hidden ("Variable " <> ppr v <> " is no longer in scope:" $$+                         "It occurs under delay" $$ "and is of type " <> ppr (varType v) <> ", which is not stable.")+              | Set.member v (current ?ctxt) -> Visible+              | isTemporal (varType v) && isRight (earlier ?ctxt) && userFunction v+                -> ImplUnboxed+              | otherwise -> Visible++-- | A map from the syntax of a primitive of Asynchronous Rattus to 'Prim'.+primMap :: Map FastString Prim+primMap = Map.fromList+  [("Delay", Delay),+   ("delay", Delay),+   ("adv", Adv),+   ("select", Select),+   ("box", Box),+   ("unbox", Unbox)]+++-- | Checks whether a given variable is in fact an Asynchronous Rattus primitive.+isPrim :: GetCtxt => Var -> Maybe Prim+isPrim v+  | Just p <- Map.lookup v (primAlias ?ctxt) = Just p+  | otherwise = do+  (name,mod) <- getNameModule v+  if isRattModule mod then Map.lookup name primMap+  else Nothing+++-- | Checks whether a given expression is in fact a Asynchronous Rattus primitive.+isPrimExpr :: GetCtxt => LHsExpr GhcTc -> Maybe (Prim,Var)+isPrimExpr (L _ e) = isPrimExpr' e where+  isPrimExpr' :: GetCtxt => HsExpr GhcTc -> Maybe (Prim,Var)+  isPrimExpr' (HsVar _ (L _ v)) = fmap (,v) (isPrim v)+#if __GLASGOW_HASKELL__ >= 906+  isPrimExpr' (HsAppType _ e _ _) = isPrimExpr e+#else+  isPrimExpr' (HsAppType _ e _) = isPrimExpr e+#endif++  isPrimExpr' (XExpr (WrapExpr (HsWrap _ e))) = isPrimExpr' e+  isPrimExpr' (XExpr (ExpansionExpr (HsExpanded _ e))) = isPrimExpr' e+  isPrimExpr' (HsPragE _ _ e) = isPrimExpr e+#if __GLASGOW_HASKELL__ < 904+  isPrimExpr' (HsTick _ _ e) = isPrimExpr e+  isPrimExpr' (HsBinTick _ _ _ e) = isPrimExpr e+  isPrimExpr' (HsPar _ e) = isPrimExpr e+#else+  isPrimExpr' (XExpr (HsTick _ e)) = isPrimExpr e+  isPrimExpr' (XExpr (HsBinTick _ _ e)) = isPrimExpr e+  isPrimExpr' (HsPar _ _ e _) = isPrimExpr e+#endif++  isPrimExpr' _ = Nothing+++-- | This type class provides default implementations for 'check' and+-- 'checkBind' for Haskell syntax that is not supported. These default+-- implementations simply print an error message.+class NotSupported a where+  notSupported :: GetCtxt => SDoc -> CheckM a++instance NotSupported Bool where+  notSupported doc = printMessageCheck SevError ("Asynchronous Rattus does not support " <> doc)++instance NotSupported (Bool,Set Var) where+  notSupported doc = (,Set.empty) <$> notSupported doc+++-- | Add variables to the current context.+addVars :: Set Var -> Ctxt -> Ctxt+addVars vs c = c{current = vs `Set.union` current c }++-- | Print a message with the current location.+printMessage' :: GetCtxt => Severity -> SDoc ->  CheckM ()+printMessage' sev doc =+  liftIO (modifyIORef (errorMsgs ?ctxt) ((sev ,srcLoc ?ctxt, doc) :))++-- | Print a message with the current location. Returns 'False', if+-- the severity is 'SevError' and otherwise 'True.+printMessageCheck :: GetCtxt =>  Severity -> SDoc -> CheckM Bool+printMessageCheck sev doc = printMessage' sev doc >>+  case sev of+    SevError -> return False+    _ -> return True
+ src/WidgetRattus/Plugin/SingleTick.hs view
@@ -0,0 +1,226 @@+-- | This module implements the translation from the multi-tick+-- calculus to the single tick calculus.++{-# LANGUAGE CPP #-}++module WidgetRattus.Plugin.SingleTick+  (toSingleTick) where++#if __GLASGOW_HASKELL__ >= 900+import GHC.Plugins+#else+import GhcPlugins+#endif++  +import WidgetRattus.Plugin.Utils+import Prelude hiding ((<>))+import Control.Monad.Trans.Writer.Strict+import Control.Monad.Trans.Class+import Data.List++-- | Transform the given expression from the multi-tick calculus into+-- the single tick calculus form.+toSingleTick :: CoreExpr -> CoreM CoreExpr+toSingleTick (Let (Rec bs) e) = do+  e' <- toSingleTick e+  bs' <- mapM (mapM toSingleTick) bs+  return (Let (Rec bs') e')+toSingleTick (Let (NonRec b e1) e2) = do+  e1' <- toSingleTick e1+  e2' <- toSingleTick e2+  return (Let (NonRec b e1') e2')+toSingleTick (Case e b ty alts) = do+  e' <- toSingleTick e+  alts' <- mapM ((\ (c,bs,f) -> fmap (\ x -> mkAlt c bs x) (toSingleTick f)) . getAlt) alts+  return (Case e' b ty alts')+toSingleTick (Cast e c) = do+  e' <- toSingleTick e+  return (Cast e' c)+toSingleTick (Tick t e) = do+  e' <- toSingleTick e+  return (Tick t e')+toSingleTick (Lam x e) = do+  (e', advs) <- runWriterT (extractAdv' e)+  advs' <- mapM (\ (x,a,b) -> fmap (\b' -> (x,a,b')) (toSingleTick b)) advs+  return (foldLets' advs' (Lam x e'))+toSingleTick (App e1 e2)+  | isDelayApp e1 = do+      (e2', advs) <- runWriterT (extractAdv e2)+      advs' <- mapM (mapM toSingleTick) advs+      return (foldLets advs' (App e1 e2'))+  | otherwise = do+      e1' <- toSingleTick e1+      e2' <- toSingleTick e2+      return (App e1' e2')++toSingleTick e@Type{} = return e+toSingleTick e@Var{} = return e+toSingleTick e@Lit{} = return e+toSingleTick e@Coercion{} = return e++foldLets :: [(Id,CoreExpr)] -> CoreExpr -> CoreExpr+foldLets ls e = foldl' (\e' (x,b) -> Let (NonRec x b) e') e ls++foldLets' :: [(Id,CoreExpr,CoreExpr)] -> CoreExpr -> CoreExpr+foldLets' ls e = foldl' (\e' (x,a,b) -> Let (NonRec x (App a b)) e') e ls++extractAdvApp :: CoreExpr -> CoreExpr -> WriterT [(Id,CoreExpr)] CoreM CoreExpr+extractAdvApp e1 e2+  | isVar e2 = return (App e1 e2)+  | otherwise = do+  x <- lift (mkSysLocalFromExpr (fsLit "adv") e2)+  tell [(x,e2)]+  return (App e1 (Var x))++-- removes casts and ticks from a tree+filterTree :: CoreExpr -> CoreExpr+filterTree (Cast e _) = filterTree e+filterTree (Tick _ e) = filterTree e+filterTree e = e+++extractSelectApp :: CoreExpr -> CoreExpr -> WriterT [(Id,CoreExpr)] CoreM CoreExpr+extractSelectApp e1 e2+  | isVar e' && isVar e2 = return (App e1 e2)+  | isVar e2 = do+    x <- lift (mkSysLocalFromExpr (fsLit "selectFreshVar") e')+    tell [(x, e')]+    return (App (App e (Var x)) e2)+  | isVar e' = do+    x <- lift (mkSysLocalFromExpr (fsLit "selectFreshVar") e2)+    tell [(x, e2)]+    return (App e1 (Var x))+  | otherwise = do+    x <- lift (mkSysLocalFromExpr (fsLit "selectFreshVar") e')+    y <- lift (mkSysLocalFromExpr (fsLit "selectFreshVar") e2)+    tell [(x, e')]+    tell [(y, e2)]+    return (App (App e (Var x)) (Var y))+  where (App e e') = filterTree e1+++-- This is used to pull adv out of delayed terms. The writer monad+-- returns mappings from fresh variables to terms that occur as+-- argument of adv.+-- +-- That is, occurrences of @adv t@ are replaced with @adv x@ (for some+-- fresh variable @x@) and the pair @(x,t)@ is returned in the+-- writer monad.+extractAdv :: CoreExpr -> WriterT [(Id,CoreExpr)] CoreM CoreExpr+extractAdv (App expr@(App e _) e2) | isSelectApp e = extractSelectApp expr e2+extractAdv e@(App e1 e2)+  | isAdvApp e1 = extractAdvApp e1 e2+  | isSelectApp e1 = extractSelectApp e1 e2+  | isDelayApp e1 = do+      (e2', advs) <- lift $ runWriterT (extractAdv e2)+      advs' <- mapM (mapM extractAdv) advs+      return (foldLets advs' (App e1 e2'))+  | isBoxApp e1 = lift $ toSingleTick e+  | otherwise = do+      e1' <- extractAdv e1+      e2' <- extractAdv e2+      return (App e1' e2')+extractAdv (Lam x e) = do+  (e', advs) <- lift $ runWriterT (extractAdv' e)+  advs' <- mapM (\ (x,a,b) -> fmap (\b' -> (x,b')) (extractAdvApp a b)) advs+  return (foldLets advs' (Lam x e'))+extractAdv (Case e b ty alts) = do+  e' <- extractAdv e+  alts' <- mapM ((\ (c,bs,f) -> fmap (\ x -> mkAlt c bs x) (extractAdv f)) . getAlt) alts+  return (Case e' b ty alts')+extractAdv (Cast e c) = do+  e' <- extractAdv e+  return (Cast e' c)+extractAdv (Tick t e) = do+  e' <- extractAdv e+  return (Tick t e')+extractAdv e@(Let Rec{} _) = lift $ toSingleTick e+extractAdv (Let (NonRec b e1) e2) = do+  e1' <- extractAdv e1+  e2' <- extractAdv e2+  return (Let (NonRec b e1') e2')+extractAdv e@Type{} = return e+extractAdv e@Var{} = return e+extractAdv e@Lit{} = return e+extractAdv e@Coercion{} = return e++-- This is used to pull adv out of lambdas. The writer monad returns+-- mappings from fresh variables to occurrences of adv and the term it+-- is applied to.+-- +-- That is occurrences of @adv t@ are replaced with a fresh variable+-- @x@ and the triple @(x,adv,t)@ is returned in the writer monad.+-- For select a b, the triple @(x, select a, b) is returned in the writer monad.+extractAdv' :: CoreExpr -> WriterT [(Id,CoreExpr,CoreExpr)] CoreM CoreExpr+extractAdv' e@(App e1 e2)+  | isAdvApp e1 = do+       x <- lift (mkSysLocalFromExpr (fsLit "adv") e)+       tell [(x,e1,e2)]+       return (Var x)+  | isSelectApp e1 = do+      x <- lift (mkSysLocalFromExpr (fsLit "select") e)+      tell [(x,e1,e2)]+      return (Var x)+  | isDelayApp e1 = do+      (e2', advs) <- lift $ runWriterT (extractAdv e2)+      advs' <- mapM (mapM extractAdv') advs+      return (foldLets advs' (App e1 e2'))+  | isBoxApp e1 = lift $ toSingleTick e+  | otherwise = do+      e1' <- extractAdv' e1+      e2' <- extractAdv' e2+      return (App e1' e2')+extractAdv' (Lam x e) = do+  e' <- extractAdv' e+  return (Lam x e')+extractAdv' (Case e b ty alts) = do+  e' <- extractAdv' e+  alts' <- mapM ((\ (c,bs,f) -> fmap (\ x -> mkAlt c bs x) (extractAdv' f)) . getAlt) alts+  return (Case e' b ty alts')+extractAdv' (Cast e c) = do+  e' <- extractAdv' e+  return (Cast e' c)+extractAdv' (Tick t e) = do+  e' <- extractAdv' e+  return (Tick t e')+extractAdv' e@(Let Rec{} _) = lift $ toSingleTick e+extractAdv' (Let (NonRec b e1) e2) = do+  e1' <- extractAdv' e1+  e2' <- extractAdv' e2+  return (Let (NonRec b e1') e2')+extractAdv' e@Type{} = return e+extractAdv' e@Var{} = return e+extractAdv' e@Lit{} = return e+extractAdv' e@Coercion{} = return e++++isDelayApp :: CoreExpr -> Bool+isDelayApp = isPrimApp (== "delay")++isBoxApp :: CoreExpr -> Bool+isBoxApp = isPrimApp (\occ -> occ == "Box" || occ == "box")++isAdvApp :: CoreExpr -> Bool+isAdvApp = isPrimApp (== "adv")++isSelectApp :: CoreExpr -> Bool+isSelectApp = isPrimApp (== "select")++isPrimApp :: (String -> Bool) -> CoreExpr -> Bool+isPrimApp p (App e e')+  | isType e' || not  (tcIsLiftedTypeKind(typeKind (exprType e'))) = isPrimApp p e+  | otherwise = False+isPrimApp p (Cast e _) = isPrimApp p e+isPrimApp p (Tick _ e) = isPrimApp p e+isPrimApp p (Var v) = isPrimVar p v+isPrimApp _ _ = False++isPrimVar :: (String -> Bool) -> Var -> Bool+isPrimVar p v = maybe False id $ do+  let name = varName v+  mod <- nameModule_maybe name+  let occ = getOccString name+  return (p occ+          && moduleNameString (moduleName mod) == "WidgetRattus.InternalPrimitives")
+ src/WidgetRattus/Plugin/StableSolver.hs view
@@ -0,0 +1,83 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+++-- | This module implements a constraint solver plugin for the+-- 'Stable' type class.++module WidgetRattus.Plugin.StableSolver (tcStable) where++import WidgetRattus.Plugin.Utils+    ( getNameModule, isRattModule, isStable )++import Prelude hiding ((<>))++import GHC.Plugins+  (Type, Var, CommandLineOption,tyConSingleDataCon,+   mkCoreConApps,getTyVar_maybe)+import GHC.Core+import GHC.Tc.Types.Evidence+import GHC.Core.Class+import GHC.Tc.Types+import GHC.Tc.Types.Constraint++import Data.Set (Set)+import qualified Data.Set as Set+#if __GLASGOW_HASKELL__ >= 904+import GHC.Types.Unique.FM+#endif++++-- | Constraint solver plugin for the 'Stable' type class.+tcStable :: [CommandLineOption] -> Maybe TcPlugin+tcStable _ = Just $ TcPlugin+  { tcPluginInit = return ()+  , tcPluginSolve = \ () -> stableSolver+  , tcPluginStop = \ () -> return ()+#if __GLASGOW_HASKELL__ >= 904+  , tcPluginRewrite = \ () -> emptyUFM+#endif+  }+++wrap :: Class -> Type -> EvTerm+wrap cls ty = EvExpr appDc+  where+    tyCon = classTyCon cls+    dc = tyConSingleDataCon tyCon+    appDc = mkCoreConApps dc [Type ty]++solveStable :: Set Var -> (Type, (Ct,Class)) -> Maybe (EvTerm, Ct)+solveStable c (ty,(ct,cl))+  | isStable c ty = Just (wrap cl ty, ct)+  | otherwise = Nothing++#if __GLASGOW_HASKELL__ >= 904+stableSolver :: EvBindsVar -> [Ct] -> [Ct] -> TcPluginM TcPluginSolveResult+stableSolver _ given wanted = do+#else+stableSolver :: [Ct] -> [Ct] -> [Ct] -> TcPluginM TcPluginResult+stableSolver given _derived wanted = do+#endif++  let chSt = concatMap filterCt wanted+  let haveSt = Set.fromList $ concatMap (filterTypeVar . fst) $ concatMap filterCt given+  case mapM (solveStable haveSt) chSt of+    Just evs -> return $ TcPluginOk evs []+    Nothing -> return $ TcPluginOk [] []++  where+#if __GLASGOW_HASKELL__ >= 908+        filterCt ct@(CDictCan (DictCt {di_cls = cl, di_tys = [ty]}))+#else+        filterCt ct@(CDictCan {cc_class = cl, cc_tyargs = [ty]})+#endif+          = case getNameModule cl of+                Just (name,mod)+                  | isRattModule mod && name == "Stable" -> [(ty,(ct,cl))]+                _ -> []+        filterCt _ = []+        filterTypeVar ty = case getTyVar_maybe ty of+          Just v -> [v]+          Nothing -> []
+ src/WidgetRattus/Plugin/Strictify.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+module WidgetRattus.Plugin.Strictify+  (checkStrictData, SCxt (..)) where+import Prelude hiding ((<>))+import Control.Monad+import WidgetRattus.Plugin.Utils++import GHC.Plugins+import GHC.Types.Tickish++data SCxt = SCxt {srcSpan :: SrcSpan}++-- | Checks whether the given expression uses non-strict data types+-- and issues a warning if it finds any such use.+checkStrictData :: SCxt -> CoreExpr -> CoreM ()+checkStrictData ss (Let (NonRec _ e1) e2) = +  checkStrictData ss e1 >> checkStrictData ss e2+checkStrictData ss (Case e _ _ alts) = do+  checkStrictData ss e+  mapM_ ((\(_,_,e) ->  checkStrictData ss e) . getAlt) alts+checkStrictData ss (Let (Rec es) e) = do+  mapM_ (\ (_,e) -> checkStrictData ss e) es+  checkStrictData ss e+checkStrictData ss (Lam _ e) = checkStrictData ss e+checkStrictData ss (Cast e _) = checkStrictData ss e+checkStrictData ss (Tick (SourceNote span _) e) = +  checkStrictData (ss{srcSpan = fromRealSrcSpan span}) e+checkStrictData ss (App e1 e2)+  | ignoreArgument e1 = return ()+  | otherwise = do +    when (not (isType e2) && tcIsLiftedTypeKind(typeKind (exprType e2))+        && not (isStrict (exprType e2)) && not (isDeepseqForce e2) && not (isLit e2))+          (printMessage SevWarning (srcSpan ss)+               (text "The use of lazy type " <> ppr (exprType e2) <> " may lead to memory leaks. Use Control.DeepSeq.force on lazy types."))+    checkStrictData ss e1+    checkStrictData ss e2+checkStrictData _ss _ = return ()++isLit :: CoreExpr -> Bool+isLit Lit{} = True+isLit (App (Var v) Lit{}) +  | Just (name,mod) <- getNameModule v = mod == "GHC.CString" && name == "unpackCString#"+isLit _ = False+++ignoreArgument :: CoreExpr -> Bool+ignoreArgument (Var v) =+  case getNameModule v of+    Just (name, mod) -> +      ((mod == "GHC.Exts" || mod == "GHC.IsList") && (name == "fromList" || name == "fromListN")) ||+      (mod == "Data.String" && name == "fromString") ||+      (mod == "GHC.Stack.Types" && name == "pushCallStack") ||+      (mod == "Data.Text.Internal" && name == "pack")+    _ -> False+ignoreArgument (App x _) = ignoreArgument x+ignoreArgument _ = False++isDeepseqForce :: CoreExpr -> Bool+isDeepseqForce (App (App (App (Var v) _) _) _) =+  case getNameModule v of+    Just (name, mod) -> mod == "Control.DeepSeq" && name == "force"+    _ -> False+isDeepseqForce _ = False
+ src/WidgetRattus/Plugin/Transform.hs view
@@ -0,0 +1,143 @@+{-# LANGUAGE TupleSections #-}+module WidgetRattus.Plugin.Transform (+    transform+) where++import GHC.Core.Opt.Monad+import GHC.Plugins+import WidgetRattus.Plugin.PrimExpr+import WidgetRattus.Plugin.Utils+import Data.Maybe (fromJust)+import Prelude hiding ((<>))+import Data.Functor ((<&>))+import Control.Applicative ((<|>))+import Data.Tuple (swap)++data Ctx = Ctx {+    fresh :: Maybe Var+}++emptyCtx :: Ctx+emptyCtx = Ctx {+    fresh = Nothing+}++replaceVar :: Var -> Var -> Expr Var ->  Expr Var+replaceVar match rep (Var v) = if v == match then Var rep else Var v+replaceVar match rep (App e e') = App (replaceVar match rep e) (replaceVar match rep e')+replaceVar match rep (Tick _ e) = replaceVar match rep e+replaceVar match rep (Lam v e) = Lam (if v == match then rep else v) (replaceVar match rep e)+replaceVar match rep (Let (NonRec b e') e) =+  Let (NonRec newB (replaceVar  match rep e')) (replaceVar match rep e)+  where newB = if b == match then rep else b+replaceVar match rep (Cast e _) = replaceVar match rep e+replaceVar match rep (Case e b t alts) =+  Case newExpr newB t (map (\(Alt con binds expr) -> Alt con (map (\v -> if v == match then rep else v) binds) (replaceVar match rep expr)) alts)+  where newExpr = replaceVar match rep e+        newB = if b == match then rep else b+replaceVar _ _ e = e++transformPrim :: Ctx -> Expr Var -> CoreM (Expr Var, PrimInfo)+transformPrim ctx expr@(App e e') = case isPrimExpr expr of+  Just primInfo@(AdvApp f _) -> do+    varAdv' <- adv'Var+    let newE = replaceVar f varAdv' e+    return (App (App newE e') (Var (fromJust $ fresh ctx)), primInfo)+  Just primInfo@(SelectApp f _ _) -> do+    varSelect' <- select'Var+    let newE = replaceVar f varSelect' e+    return (App (App newE e') (Var (fromJust $ fresh ctx)), primInfo)+  Just (DelayApp _ t) -> do+    bigDelayVar <- bigDelay+    inputValueV <- inputValueVar+    let inputValueType = mkTyConTy inputValueV +    inpVar <- mkSysLocalM (fsLit "inpV") inputValueType inputValueType+    let ctx' = ctx {fresh = Just inpVar}+    (newExpr, maybePrimInfo) <- transform' ctx' e'+    let primInfo = fromJust maybePrimInfo+    let lambdaExpr = Lam inpVar newExpr+    clockCode <- constructClockExtractionCode primInfo+    return (App (App (App (Var bigDelayVar) (Type t)) clockCode) lambdaExpr, primInfo)+  Just primInfo -> do+        error $ showSDocUnsafe $ text "transformPrim: Cannot transform " <> ppr (prim primInfo)+  Nothing -> error "Cannot transform non-prim applications"+transformPrim _ _ = do+  error "Cannot transform anything else than prim applications"+++transform :: CoreExpr -> CoreM CoreExpr+transform expr = fst <$> transform' emptyCtx expr++transform' :: Ctx -> CoreExpr -> CoreM (CoreExpr, Maybe PrimInfo)+transform' ctx expr@(App e e') = case isPrimExpr expr of+    Just (BoxApp _) -> do+        (newExpr, primInfo) <- transform' ctx e'+        return (App e newExpr, primInfo)+    (Just _) -> do+        (newExpr, primInfo) <- transformPrim ctx expr+        return (newExpr, Just primInfo)+    Nothing -> do+        (newExpr, primInfo) <- transform' ctx e+        (newExpr', primInfo') <- transform' ctx e'+        return (App newExpr newExpr', primInfo <|> primInfo')+transform' ctx (Lam b rhs) = do+    (newExpr, primInfo) <- transform' ctx rhs+    return (Lam b newExpr, primInfo)+transform' ctx (Let (NonRec b rhs) e) = do+    (newRhs, primInfo) <- transform' ctx rhs+    (newExpr, primInfo') <- transform' ctx e+    return (Let (NonRec b newRhs) newExpr, primInfo <|> primInfo')+transform' ctx (Let (Rec binds) e) = do+    transformedBinds <- mapM (\(b, bindE) -> fmap (b,) (transform' ctx bindE)) binds+    (e', mPi) <- transform' ctx e+    let primInfos = map (\(_, (_, p)) -> p) transformedBinds+    let firstPrimInfo = foldl (<|>) mPi primInfos+    newBinds <- mapM (\(b, (e, _)) -> return (b, e)) transformedBinds+    return (Let (Rec newBinds) e', firstPrimInfo)+transform' ctx (Case e b t alts) = do+    -- The checking pass has ensured that there are not advances on different+    -- clocks. Thus we can just pick the first PrimInfo we find.+    (expr, primInfo) <- transform' ctx e++    -- For each alternative, transform it and save the maybePrimInfo-value+    transformed <- mapM (\(Alt con binds expr) -> transform' ctx expr <&> fmap (Alt con binds) . swap) alts++    -- Of all the primInfos we have, pick the first one. This is safe because+    -- the checking pass has ensured that the clocks of all primitives.+    let firstPrimInfo = foldl (\acc (p, _) -> acc <|> p) primInfo transformed+    let alts' = map snd transformed+    return (Case expr b t alts', firstPrimInfo)+transform' ctx (Cast e c) = do (e' , p) <- transform' ctx e; return (Cast e' c, p)+transform' ctx (Tick t e) = do (e' , p) <- transform' ctx e; return (Tick t e', p)+transform' _ e = return (e, Nothing)++constructClockExtractionCode :: PrimInfo -> CoreM CoreExpr+constructClockExtractionCode (AdvApp _ arg) = createClockCode arg+constructClockExtractionCode (SelectApp _ arg arg2) = clockUnion arg arg2+constructClockExtractionCode primInfo = error $ "Cannot construct clock for prim " ++ showSDocUnsafe (ppr (prim primInfo))+++createClockCode :: (Var, Type) -> CoreM CoreExpr+createClockCode (argV, argT) = do+    extractClock <- extractClockVar+    return $ App (App (Var extractClock) (Type argT)) (Var argV)++-- Generate code for union of two clocks.+-- clockUnion (aVar, aType) (bVar, bType) returns the AST for:+--  Set.union (extractClock aVar) (extractClock bVar)++clockUnion :: (Var,Type) -> (Var, Type) -> CoreM CoreExpr+clockUnion arg arg2 = do+    clock1Code <- createClockCode arg+    clock2Code <- createClockCode arg2+    unionVar' <- unionVar+    return $+        App+        (+            App+            (+                   (Var unionVar')+            )+            clock1Code+        )+        clock2Code
+ src/WidgetRattus/Plugin/Utils.hs view
@@ -0,0 +1,384 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE CPP #-}++module WidgetRattus.Plugin.Utils (+  printMessage,+  Severity(..),+  isRattModule,+  adv'Var,+  select'Var,+  bigDelay,+  inputValueVar,+  extractClockVar,+  unionVar,+  isGhcModule,+  getNameModule,+  isStable,+  isStrict,+  isTemporal,+  userFunction,+  typeClassFunction,+  getVar,+  getMaybeVar,+  getModuleFS,+  isVar,+  isType,+  mkSysLocalFromVar,+  mkSysLocalFromExpr,+  fromRealSrcSpan,+  noLocationInfo,+  mkAlt,+  getAlt,+  splitForAllTys')+  where++#if __GLASGOW_HASKELL__ >= 908+import GHC.Types.Error (ResolvedDiagnosticReason (..))+#endif++#if __GLASGOW_HASKELL__ >= 906+import GHC.Builtin.Types.Prim+import GHC.Tc.Utils.TcType+#endif+#if __GLASGOW_HASKELL__ >= 904+import qualified GHC.Data.Strict as Strict+import Control.Concurrent.MVar (readMVar)+#else+import Data.IORef (readIORef)+#endif  +import GHC.Utils.Logger+import GHC.Plugins+import GHC.Utils.Error hiding (errorMsg)+import GHC.Utils.Monad+++import GHC.Types.Name.Cache (NameCache(nsNames), lookupOrigNameCache, OrigNameCache)+import qualified GHC.Types.Name.Occurrence as Occurrence+import GHC.Types.TyThing++import Prelude hiding ((<>))+import Data.Set (Set)+import qualified Data.Set as Set+import Data.Char+import Data.Maybe+++getMaybeVar :: CoreExpr -> Maybe Var+getMaybeVar (App e e')+  | isType e' || not  (tcIsLiftedTypeKind (typeKind (exprType e'))) = getMaybeVar e+  | otherwise = Nothing+getMaybeVar (Cast e _) = getMaybeVar e+getMaybeVar (Tick _ e) = getMaybeVar e+getMaybeVar (Var v) = Just v+getMaybeVar _ = Nothing++getVar :: CoreExpr -> Var+getVar = fromJust . getMaybeVar++isVar :: CoreExpr -> Bool+isVar = isJust . getMaybeVar++isType Type {} = True+isType (App e _) = isType e+isType (Cast e _) = isType e+isType (Tick _ e) = isType e+isType _ = False++#if __GLASGOW_HASKELL__ >= 906+isFunTyCon = isArrowTyCon+repSplitAppTys = splitAppTysNoView+#endif+ ++printMessage :: (HasDynFlags m, MonadIO m, HasLogger m) =>+                Severity -> SrcSpan -> SDoc -> m ()+printMessage sev loc doc = do+#if __GLASGOW_HASKELL__ >= 908+  logger <- getLogger+  liftIO $ putLogMsg logger (logFlags logger)+    (MCDiagnostic sev (if sev == SevError then ResolvedDiagnosticReason ErrorWithoutFlag else ResolvedDiagnosticReason WarningWithoutFlag) Nothing) loc doc+#elif __GLASGOW_HASKELL__ >= 906+  logger <- getLogger+  liftIO $ putLogMsg logger (logFlags logger)+    (MCDiagnostic sev (if sev == SevError then ErrorWithoutFlag else WarningWithoutFlag) Nothing) loc doc+#elif __GLASGOW_HASKELL__ >= 904+  logger <- getLogger+  liftIO $ putLogMsg logger (logFlags logger)+    (MCDiagnostic sev (if sev == SevError then ErrorWithoutFlag else WarningWithoutFlag)) loc doc+#else+   dflags <- getDynFlags+   logger <- getLogger+   liftIO $ putLogMsg logger dflags NoReason sev loc doc+#endif++instance Ord FastString where+   compare = uniqCompareFS++{-+******************************************************+*             Extracting variables                   *+******************************************************+-}+++origNameCache :: CoreM OrigNameCache+origNameCache = do+  hscEnv <- getHscEnv+#if __GLASGOW_HASKELL__ >= 904+  let nameCache = hsc_NC hscEnv+  liftIO $ readMVar (nsNames nameCache)+#else+  nameCache <- liftIO $ readIORef (hsc_NC hscEnv)+  return $ nsNames nameCache+#endif+++getNamedThingFromModuleAndOccName :: String -> OccName -> CoreM TyThing+getNamedThingFromModuleAndOccName moduleName occName = do+  origNameCache <- origNameCache+  case filter ((moduleName ==) . unpackFS . getModuleFS) (moduleEnvKeys origNameCache) of+    mod : _ -> lookupThing $ fromJust $ lookupOrigNameCache origNameCache mod occName+    _ -> error ( ("internal error: cannot find module " ++ moduleName ++ "; " ++ show (map (unpackFS . getModuleFS) $ moduleEnvKeys origNameCache)))++getVarFromModule :: String -> String -> CoreM Var+getVarFromModule moduleName = fmap tyThingId . getNamedThingFromModuleAndOccName moduleName . mkOccName Occurrence.varName++getTyConFromModule :: String -> String -> CoreM TyCon+getTyConFromModule moduleName = fmap tyThingTyCon . getNamedThingFromModuleAndOccName moduleName . mkOccName Occurrence.tcName++adv'Var :: CoreM Var+adv'Var = getVarFromModule "WidgetRattus.InternalPrimitives" "adv'"++select'Var :: CoreM Var+select'Var = getVarFromModule "WidgetRattus.InternalPrimitives" "select'"++bigDelay :: CoreM Var+bigDelay = getVarFromModule "WidgetRattus.InternalPrimitives" "Delay"++inputValueVar :: CoreM TyCon+inputValueVar = getTyConFromModule "WidgetRattus.InternalPrimitives" "InputValue"++extractClockVar :: CoreM Var+extractClockVar = getVarFromModule "WidgetRattus.InternalPrimitives" "extractClock"++unionVar :: CoreM Var+unionVar = getVarFromModule "WidgetRattus.InternalPrimitives" "clockUnion"++rattModules :: Set FastString+rattModules = Set.fromList ["WidgetRattus.InternalPrimitives","WidgetRattus.Channels"]++getModuleFS :: Module -> FastString+getModuleFS = moduleNameFS . moduleName++isRattModule :: FastString -> Bool+isRattModule = (`Set.member` rattModules)++ghcModules :: Set FastString+ghcModules = Set.fromList ["GHC.Types","GHC.Word","GHC.Int"]++isGhcModule :: FastString -> Bool+isGhcModule = (`Set.member` ghcModules)++getNameModule :: NamedThing a => a -> Maybe (FastString, FastString)+getNameModule v = do+  let name = getName v+  mod <- nameModule_maybe name+  return (getOccFS name,moduleNameFS (moduleName mod))+++-- | The set of stable built-in types.+ghcStableTypes :: Set FastString+ghcStableTypes = Set.fromList ["Word", "Word8", "Word16","Word32", "Word64","Int","Int8","Int16","Int32","Int64","Bool","Float","Double","Char", "IO"]++isGhcStableType :: FastString -> Bool+isGhcStableType = (`Set.member` ghcStableTypes)+++newtype TypeCmp = TC Type++instance Eq TypeCmp where+  (TC t1) == (TC t2) = eqType t1 t2++instance Ord TypeCmp where+  compare (TC t1) (TC t2) = nonDetCmpType t1 t2++isTemporal :: Type -> Bool+isTemporal t = isTemporalRec 0 Set.empty t+++isTemporalRec :: Int -> Set TypeCmp -> Type -> Bool+isTemporalRec d _ _ | d == 100 = False+isTemporalRec _ pr t | Set.member (TC t) pr = False+isTemporalRec d pr t = do+  let pr' = Set.insert (TC t) pr+  case splitTyConApp_maybe t of+    Nothing -> False+    Just (con,args) ->+      case getNameModule con of+        Nothing -> False+        Just (name,mod)+          -- If it's a Rattus type constructor check if it's a box+          | isRattModule mod && (name == "Box" || name == "O") -> True+          | isFunTyCon con -> or (map (isTemporalRec (d+1) pr') args)+          | isAlgTyCon con ->+            case algTyConRhs con of+              DataTyCon {data_cons = cons} -> or (map check cons)+                where check con = case dataConInstSig con args of+                        (_, _,tys) -> or (map (isTemporalRec (d+1) pr') tys)+              _ -> or (map (isTemporalRec (d+1) pr') args)+        _ -> False+++-- | Check whether the given type is stable. This check may use+-- 'Stable' constraints from the context.++isStable :: Set Var -> Type -> Bool+isStable c t = isStableRec c 0 Set.empty t++-- | Check whether the given type is stable. This check may use+-- 'Stable' constraints from the context.++isStableRec :: Set Var -> Int -> Set TypeCmp -> Type -> Bool+-- To prevent infinite recursion (when checking recursive types) we+-- keep track of previously checked types. This, however, is not+-- enough for non-regular data types. Hence we also have a counter.+isStableRec _ d _ _ | d == 100 = True+isStableRec _ _ pr t | Set.member (TC t) pr = True+isStableRec c d pr t = do+  let pr' = Set.insert (TC t) pr+  case splitTyConApp_maybe t of+    Nothing -> case getTyVar_maybe t of+      Just v -> -- if it's a type variable, check the context+        v `Set.member` c+      Nothing -> False+    Just (con,args) ->+      case getNameModule con of+        Nothing -> False+        Just (name,mod)+          | mod == "GHC.Num.Integer" && name == "Integer" -> True+          | mod == "Data.Text.Internal" && name == "Text" -> True+          -- If it's a Rattus type constructor check if it's a box+          | isRattModule mod && (name == "Box" || name == "Chan") -> True+            -- If its a built-in type check the set of stable built-in types+          | isGhcModule mod -> isGhcStableType name+          {- deal with type synonyms (does not seem to be necessary (??))+           | Just (subst,ty,[]) <- expandSynTyCon_maybe con args ->+             isStableRec c (d+1) pr' (substTy (extendTvSubstList emptySubst subst) ty) -}+          | isAlgTyCon con ->+            case algTyConRhs con of+              DataTyCon {data_cons = cons, is_enum = enum}+                | enum -> True+                | all hasStrictArgs cons ->+                  and  (map check cons)+                | otherwise -> False+                where check con = case dataConInstSig con args of+                        (_, _,tys) -> and (map (isStableRec c (d+1) pr') tys)+              TupleTyCon {} -> null args+              _ -> False+        _ -> False++++isStrict :: Type -> Bool+isStrict t = isStrictRec 0 Set.empty t++splitForAllTys' :: Type -> ([TyCoVar], Type)+splitForAllTys' = splitForAllTyCoVars++-- | Check whether the given type is stable. This check may use+-- 'Stable' constraints from the context.++isStrictRec :: Int -> Set TypeCmp -> Type -> Bool+-- To prevent infinite recursion (when checking recursive types) we+-- keep track of previously checked types. This, however, is not+-- enough for non-regular data types. Hence we also have a counter.+isStrictRec d _ _ | d == 100 = True+isStrictRec _ pr t | Set.member (TC t) pr = True+isStrictRec d pr t = do+  let pr' = Set.insert (TC t) pr+  let (_,t') = splitForAllTys' t+  let (c, tys) = repSplitAppTys t'+  if isJust (getTyVar_maybe c) then all (isStrictRec (d+1) pr') tys+  else  case splitTyConApp_maybe t' of+    Nothing -> isJust (getTyVar_maybe t)+    Just (con,args) ->+      case getNameModule con of+        Nothing -> False+        Just (name,mod)+          | (mod == "GHC.Internal.IsList" || mod == "GHC.IsList" || mod == "GHC.Exts") && name == "Item" -> all (isStrictRec (d+1) pr') args+          | mod == "GHC.Num.Integer" && name == "Integer" -> True+          | mod == "Data.Text.Internal" && name == "Text" -> True+          | mod == "GHC.IORef" && name == "IORef" -> True+          | mod == "GHC.MVar" && name == "MVar" -> True+          -- If it's a Rattus type constructor check if it's a box+          | isRattModule mod && (name == "Box" || name == "Chan" || name == "O" || name == "Output") -> True+            -- If its a built-in type check the set of stable built-in types+          | isGhcModule mod -> isGhcStableType name+          {- deal with type synonyms (does not seem to be necessary (??))+           | Just (subst,ty,[]) <- expandSynTyCon_maybe con args ->+             isStrictRec c (d+1) pr' (substTy (extendTvSubstList emptySubst subst) ty) -}+          | isFunTyCon con -> True+          | isAlgTyCon con ->+            case algTyConRhs con of+              DataTyCon {data_cons = cons, is_enum = enum}+                | enum -> True+                | all hasStrictArgs cons ->+                  all check cons+                | otherwise -> False+                where check con = case dataConInstSig con args of+                        (_, _,tys) -> all (isStrictRec (d+1) pr') tys+              TupleTyCon {} -> null args+              NewTyCon {nt_rhs = ty} -> isStrictRec (d+1) pr' ty+              _ -> False+          | otherwise -> False++++++hasStrictArgs :: DataCon -> Bool+hasStrictArgs con = all isBanged (dataConImplBangs con)++userFunction :: Var -> Bool+userFunction v+  | typeClassFunction v = True+  | otherwise = +    case getOccString (getName v) of+      (c : _)+        | isUpper c || c == '$' || c == ':' -> False+        | otherwise -> True+      _ -> False++typeClassFunction :: Var -> Bool+typeClassFunction v =+  case getOccString (getName v) of+    ('$' : 'c' : _) -> True+    ('$' : 'f' : _) -> True+    _ -> False++mkSysLocalFromVar :: MonadUnique m => FastString -> Var -> m Id+mkSysLocalFromVar lit v = mkSysLocalM lit (varMult v) (varType v)+ +mkSysLocalFromExpr :: MonadUnique m => FastString -> CoreExpr -> m Id+mkSysLocalFromExpr lit e = mkSysLocalM lit oneDataConTy (exprType e)+ + +fromRealSrcSpan :: RealSrcSpan -> SrcSpan+#if __GLASGOW_HASKELL__ >= 904+fromRealSrcSpan span = RealSrcSpan span Strict.Nothing+#else+fromRealSrcSpan span = RealSrcSpan span Nothing+#endif++instance Ord SrcSpan where+  compare (RealSrcSpan s _) (RealSrcSpan t _) = compare s t+  compare RealSrcSpan{} _ = LT+  compare _ _ = GT++noLocationInfo :: SrcSpan+noLocationInfo = UnhelpfulSpan UnhelpfulNoLocationInfo++mkAlt c args e = Alt c args e+getAlt (Alt c args e) = (c, args, e)
+ src/WidgetRattus/Primitives.hs view
@@ -0,0 +1,21 @@+-- | The language primitives of Async Rattus. Note that the typing+--  rules for 'delay', 'adv','select' and 'box' are more restrictive+--  than the Haskell types that are indicated. The stricter Async+--  Rattus typing rules for these primitives are given below.++{-# LANGUAGE TypeOperators #-}+module WidgetRattus.Primitives+  (O+  ,Box+  ,Select(..)+  ,delay+  ,adv+  ,promote+  ,box+  ,unbox+  ,select+  ,never+  ,Stable+  ,Continuous+  ) where+import WidgetRattus.InternalPrimitives
+ src/WidgetRattus/Signal.hs view
@@ -0,0 +1,492 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeFamilies #-}+{-# OPTIONS -fplugin=WidgetRattus.Plugin #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedLists #-}+++-- | Programming with signals.++module WidgetRattus.Signal+  ( map+  , mapAwait+  , switch+  , switchS+  , switchR+  , trigger+  , triggerAwait+  , triggerM+  , triggerAwaitM+  , buffer+  , bufferAwait+  , switchAwait+  , interleave+  , mapInterleave+  , interleaveAll+  , mkSig+  , mkBoxSig+  , current+  , future+  , const+  , jump+  , jumping+  , stop+  , scan+  , scanC+  , scanAwait+  , scanAwaitC+  , scanMap+  , Sig(..)+  , zipWith+  , zipWith3+  , zip+  , cond+  , update+  , integral+  , derivative+  )++where++import WidgetRattus+import Prelude hiding (map, const, zipWith, zipWith3, zip, filter)+import Data.VectorSpace+import Data.Ratio ((%))+-- TODO: InternalPrimitives is only used to implment instance of+-- Continuous. Replace this manual instance declaration with Template+-- Haskell.+import WidgetRattus.InternalPrimitives++infixr 5 :::++-- | @Sig a@ is a stream of values of type @a@.+data Sig a = !a ::: !(O (Sig a))++instance Producer (Sig a) a where+  getCurrent p = Just' (current p)+  getNext p cb = cb (future p)++newtype SigMaybe a = SigMaybe (Sig (Maybe' a))++instance Producer (SigMaybe a) a where+  getCurrent (SigMaybe p) = current p+  getNext (SigMaybe p) cb = cb (delay (SigMaybe (adv (future p))))++-- | Get the current value of a signal.+current :: Sig a -> a+current (x ::: _) = x+++-- | Get the future the signal.+future :: Sig a -> O (Sig a)+future (_ ::: xs) = xs++-- | Apply a function to the value of a signal.+map :: Box (a -> b) -> Sig a -> Sig b+map f (x ::: xs) = unbox f x ::: delay (map f (adv xs))++-- | A version of @map@ for delayed signals.+mapAwait :: Box (a -> b) -> O (Sig a) -> O (Sig b)+mapAwait f d = delay (map f (adv d))++-- | Turns a boxed delayed computation into a delayed signal.+mkSig :: Box (O a) -> O (Sig a)+mkSig b = delay (adv (unbox b) ::: mkSig b)++-- | Variant of 'mkSig' that returns a boxed delayed signal+mkBoxSig :: Box (O a) -> Box (O (Sig a))+mkBoxSig b = box (mkSig b)+++-- | Construct a constant signal that never updates.+const :: a -> Sig a+const x = x ::: never++-- | Similar to Haskell's 'scanl'.+--+-- > scan (box f) x (v1 ::: v2 ::: v3 ::: ... ) == (x `f` v1) ::: ((x `f` v1) `f` v2) ::: ...+--+-- Note: Unlike 'scanl', 'scan' starts with @x `f` v1@, not @x@.++scan :: (Stable b) => Box(b -> a -> b) -> b -> Sig a -> Sig b+scan f acc (a ::: as) = acc' ::: delay (scan f acc' (adv as))+  where acc' = unbox f acc a++-- | A variant of 'scan' that works with the 'C' monad.++scanC :: (Stable b) => Box(b -> a -> C b) -> b -> Sig a -> C (Sig b)+scanC f acc (a ::: as) = do+    acc' <- unbox f acc a+    fut <- delayC $ delay (scanC f acc' (adv as))+    return (acc' ::: fut)+  where +        +-- | Like 'scan', but uses a delayed signal.+scanAwait :: (Stable b) => Box (b -> a -> b) -> b -> O (Sig a) -> Sig b+scanAwait f acc as = acc ::: delay (scan f acc (adv as))++-- | A variant of 'scanAwait' that works with the 'C' monad.++scanAwaitC :: (Stable b) => Box (b -> a -> C b) -> b -> O (Sig a) -> C (Sig b)+scanAwaitC f acc as = do +    fut <- delayC $ delay (scanC f acc (adv as))+    return (acc ::: fut)++-- | 'scanMap' is a composition of 'map' and 'scan':+--+-- > scanMap f g x === map g . scan f x+scanMap :: (Stable b) => Box (b -> a -> b) -> Box (b -> c) -> b -> Sig a -> Sig c+scanMap f p acc (a ::: as) =  unbox p acc' ::: delay (scanMap f p acc' (adv as))+  where acc' = unbox f acc a++-- | @jump (box f) xs@ first behaves like @xs@, but as soon as @f x =+-- Just xs'@ for a (current or future) value @x@ of @xs@, it behaves+-- like @xs'@.++jump :: Box (a -> Maybe' (Sig a)) -> Sig a -> Sig a+jump f (x ::: xs) = case unbox f x of+                        Just' xs' -> xs'+                        Nothing' -> x ::: delay (jump f (adv xs))+++-- | Similar to 'jump', but it can jump repeatedly. That is, @jumping+-- (box f) xs@ first behaves like @xs@, but every time @f x = Just+-- xs'@ for a (current or future) value @x@ of @jumping (box f) xs@,+-- it behaves like @xs'@.++jumping :: Box (a -> Maybe' (Sig a)) -> Sig a -> Sig a+jumping f (x ::: xs) = case unbox f x of+                         Just' (x' ::: xs') -> x' ::: delay (jumping f (adv xs'))+                         Nothing'           -> x  ::: delay (jumping f (adv xs))++-- | Stops as soon as the the predicate becomes true for the current+-- value. That is, @stop (box p) xs@ first behaves as @xs@, but as+-- soon as @f x = True@ for some (current or future) value @x@ of+-- @xs@, then it behaves as @const x@.+stop :: Box (a -> Bool) -> Sig a ->  Sig a+stop p = jump (box (\ x -> if unbox p x then Just' (const x) else Nothing'))++-- | This function allows to switch from one signal to another one+-- dynamically. The signal defined by @switch xs ys@ first behaves+-- like @xs@, but as soon as @ys@ produces a new value, @switch xs ys@+-- behaves like @ys@.+--+-- Example:+--+-- >           xs: 1 2 3 4 5   6 7 8   9+-- >           ys:         1 2   3 4 5 6+-- >+-- > switch xs ys: 1 2 3 1 2 4   3 4 5 6+switch :: Sig a -> O (Sig a) -> Sig a+switch (x ::: xs) d = x ::: delay (case select xs d of+                                     Fst   xs'  d'  -> switch xs' d'+                                     Snd   _    d'  -> d'+                                     Both  _    d'  -> d')++-- | This function is similar to 'switch', but the (future) second+-- signal may depend on the last value of the first signal.+switchS :: Stable a => Sig a -> O (a -> Sig a) -> Sig a+switchS (x ::: xs) d = x ::: delay (case select xs d of+                                     Fst   xs'  d'  -> switchS xs' d'+                                     Snd   _    f  -> f x+                                     Both  _    f  -> f x)++-- | This function is similar to 'switch' but works on delayed signals+-- instead of signals.+switchAwait :: O (Sig a) -> O (Sig a) -> O (Sig a)+switchAwait xs ys = delay (case select xs ys of+                                  Fst  xs'  d'  -> switch xs' d'+                                  Snd  _    d'  -> d'+                                  Both _    d'  -> d')++-- | Variant of 'switchS' that repeatedly switches. The output signal+-- @switch xs ys@ first behaves like @xs@, but whenever @ys@ produces+-- a value @f@, the signal switches to @f v@ where @v@ is the previous+-- value of the output signal. +--+-- 'switchS' can be considered a special case of 'switchR' that only+-- makes a single switch. That is we have the following:+--+-- > switchS xs ys = switchR (delay (const (adv xs))) ys+switchR :: Stable a => Sig a -> O (Sig (a -> Sig a)) -> Sig a+switchR sig steps = switchS sig+      (delay (let step ::: steps' = adv steps in \ x -> switchR (step x) steps'))++-- | This function interleaves two signals producing a new value @v@+-- whenever either input stream produces a new value @v@. In case the+-- input signals produce a new value simultaneously, the function+-- argument is used break ties, i.e. to compute the new output value based+-- on the two new input values+--+-- Example:+--+-- >                         xs: 1 3   5 3 1 3+-- >                         ys:   0 2   4+-- >+-- > interleave (box (+)) xs ys: 1 3 2 5 7 1 3+interleave :: Box (a -> a -> a) -> O (Sig a) -> O (Sig a) -> O (Sig a)+interleave f xs ys = delay (case select xs ys of+                              Fst (x ::: xs') ys' -> x ::: interleave f xs' ys'+                              Snd xs' (y ::: ys') -> y ::: interleave f xs' ys'+                              Both (x ::: xs') (y ::: ys') -> unbox f x y ::: interleave f xs' ys')+++-- | This is the composition of 'mapAwait' and 'interleave'. That is,+-- +-- > mapInterleave f g xs ys = mapAwait f (interleave xs ys)+mapInterleave :: Box (a -> a) -> Box (a -> a -> a) -> O (Sig a) -> O (Sig a) -> O (Sig a)+mapInterleave g f xs ys = delay (case select xs ys of+                              Fst (x ::: xs') ys' -> unbox g x ::: mapInterleave g f xs' ys'+                              Snd xs' (y ::: ys') -> unbox g y ::: mapInterleave g f xs' ys'+                              Both (x ::: xs') (y ::: ys') -> unbox g (unbox f x y) ::: mapInterleave g f xs' ys')+++{-# ANN interleaveAll AllowRecursion #-}+interleaveAll :: Box (a -> a -> a) -> List (O (Sig a)) -> O (Sig a)+interleaveAll _ Nil = error "interleaveAll: List must be nonempty"+interleaveAll _ [s] = s+interleaveAll f (x :! xs) = interleave f x (interleaveAll f xs)+++-- | Takes two signals and updates the first signal using the+-- functions produced by the second signal:+--+-- Law:+--+-- > (xs `update` fs) `update` gs = (xs `update` (interleave (box (.)) gs fs))+update :: (Stable a) => Sig a -> O (Sig (a -> a)) -> Sig a+update (x ::: xs) fs = x ::: delay +    (case select xs fs of+      Fst xs' ys' -> update xs' ys'+      Snd xs' (f ::: fs') -> update (f x ::: xs') fs'+      Both (x' ::: xs') (f ::: fs') -> update (f x' ::: xs') fs')+++-- | This function is a variant of combines the values of two signals+-- using the function argument. @zipWith f xs ys@ produces a new value+-- @unbox f x y@ whenever @xs@ or @ys@ produce a new value, where @x@+-- and @y@ are the current values of @xs@ and @ys@, respectively.+--+-- Example:+--+-- >                      xs:  1 2 3     2+-- >                      ys:  1     0 5 2+-- >+-- > zipWith (box (+)) xs ys:  2 3 4 3 8 4++zipWith :: (Stable a, Stable b) => Box(a -> b -> c) -> Sig a -> Sig b -> Sig c+zipWith f (a ::: as) (b ::: bs) = unbox f a b ::: delay (+    case select as bs of+      Fst as' lbs -> zipWith f as' (b ::: lbs)+      Snd las bs' -> zipWith f (a ::: las) bs'+      Both as' bs' -> zipWith f as' bs'+  )++-- | Variant of 'zipWith' with three signals.+zipWith3 :: forall a b c d. (Stable a, Stable b, Stable c) => Box(a -> b -> c -> d) -> Sig a -> Sig b -> Sig c -> Sig d+zipWith3 f as bs cs = zipWith (box (\f x -> unbox f x)) cds cs+  where cds :: Sig (Box (c -> d))+        cds = zipWith (box (\a b -> box (\ c -> unbox f a b c))) as bs++-- | If-then-else lifted to signals. @cond bs xs ys@ produces a stream+-- whose value is taken from @xs@ whenever @bs@ is true and from @ys@+-- otherwise.+cond :: Stable a => Sig Bool -> Sig a -> Sig a -> Sig a+cond = zipWith3 (box (\b x y -> if b then x else y))+++-- | This is a special case of 'zipWith' using the tupling+-- function. That is,+--+-- > zip = zipWith (box (:*))+zip :: (Stable a, Stable b) => Sig a -> Sig b -> Sig (a:*b)+zip = zipWith (box (:*))++-- | This function is a variant of 'trigger' that works on a delayed+-- input signal. To this end, 'triggerAwait' takes an additional+-- argument that is the initial value of output signal.+--+-- Example:+--+-- >                             xs:    1     0 5 2+-- >                             ys:  5 1 2 3     2+-- >+-- > triggerAwait (box (+)) 0 xy ys:  0 2 2 2 3 8 4++triggerAwait :: (Stable b, Stable c) => Box (a -> b -> c) -> c -> O (Sig a) -> Sig b -> Sig c+triggerAwait f c as (b ::: bs) = c :::+    delay (case select as bs of+            Fst (a' ::: as') bs' -> triggerAwait f (unbox f a' b) as' (b ::: bs')+            Snd as' bs' -> triggerAwait f c as' bs'+            Both (a' ::: as') (b' ::: bs') -> triggerAwait f (unbox f a' b') as' (b' ::: bs'))+++-- | This function is a variant of 'triggerAwait' that only produces a+-- value when the first signal ticks; otherwise it produces+-- @Nothing'@.+--+-- Example:+--+-- >                             xs:    1     0 5 2+-- >                             ys:  5 1 2 3     2+-- >+-- > triggerAwaitM (box plus) xy ys:    2 N N 3 8 4 where plus x y =+-- Just' (x+y)++triggerAwaitM :: Stable b => Box (a -> b -> Maybe' c) -> O (Sig a) -> Sig b -> O (Sig (Maybe' c))+triggerAwaitM f as (b ::: bs) = +    delay (case select as bs of+            Fst (a' ::: as') bs' -> unbox f a' b ::: triggerAwaitM f as' (b ::: bs')+            Snd as' bs' -> Nothing' ::: triggerAwaitM f as' bs'+            Both (a' ::: as') (b' ::: bs') -> unbox f a' b' ::: triggerAwaitM f as' (b' ::: bs'))++-- | This function is a variant of 'zipWith'. Whereas @zipWith f xs+-- ys@ produces a new value whenever @xs@ or @ys@ produce a new value,+-- @trigger f xs ys@ only produces a new value when xs produces a new+-- value, otherwise it just repeats the previous value.+--+-- Example:+--+-- >                      xs:  1     0 5 2+-- >                      ys:  1 2 3     2+-- >+-- > zipWith (box (+)) xs ys:  2 3 4 3 8 4+-- > trigger (box (+)) xy ys:  2 2 2 3 8 4++trigger :: (Stable b, Stable c) => Box (a -> b -> c) -> Sig a -> Sig b -> Sig c+trigger f (a:::as) bs@(b ::: _) = triggerAwait f (unbox f a b) as bs++-- | This function is a variant of 'trigger' that only produces a+-- value when the first signal ticks; otherwise it produces+-- @Nothing'@.+--+-- Example:+--+-- >                      xs:  1     0 5 2+-- >                      ys:  1 2 3     2+-- >+-- > zipWith (box plus) xs ys:  2 3 4 3 8 4+-- > trigger (box plus) xy ys:  2 N N 3 8 4+-- where+-- > plus x y = Just' (x+y)++triggerM :: Stable b => Box (a -> b -> Maybe' c) -> Sig a -> Sig b -> Sig (Maybe' c)+triggerM f (a:::as) bs@(b ::: _) = unbox f a b ::: triggerAwaitM f as bs+++-- Buffer takes an initial value and a signal as input and returns a signal that+-- is always one tick behind the input signal.+buffer :: Stable a => a -> Sig a -> Sig a+buffer x (y ::: ys) = x ::: delay (buffer y (adv ys))++-- Like buffer but works for delayed signals+bufferAwait :: Stable a => a -> O (Sig a) -> O (Sig a)+bufferAwait x xs = delay (buffer x (adv xs))++-- | Sampling interval (in microseconds) for the 'integral' and+-- 'derivative' functions.++dt :: Int+dt = 20000++-- | @integral x xs@ computes the integral of the signal @xs@ with the+-- constant @x@. For example, if @xs@ is the velocity of an object,+-- the signal @integral 0 xs@ describes the distance travelled by that+-- object.+integral :: forall a v . (VectorSpace v a, Eq v, Fractional a, Stable v, Stable a)+  => v -> Sig v -> Sig v+integral = int +  where int cur (x ::: xs)+          | x == zeroVector = cur ::: delay (int cur (adv xs))+          | otherwise = cur ::: delay (+              case select xs (unbox (timer dt)) of+                Fst xs' _ -> int cur xs'+                Snd xs' _ -> int (dtf *^ (cur ^+^ x)) (x ::: xs')+                Both (x' ::: xs') _ ->  int (dtf *^ (cur ^+^ x')) (x'::: xs'))+         -- sampling interval in seconds+        dtf :: a+        dtf = fromRational (fromIntegral dt % 1000000)+                +-- | Compute the derivative of a signal. For example, if @xs@ is the+-- velocity of an object, the signal @derivative xs@ describes the+-- acceleration travelled by that object.+derivative :: forall a v . (VectorSpace v a, Eq v, Fractional a, Stable v, Stable a)+  => Sig v -> Sig v+derivative xs = der zeroVector (current xs) xs where+  -- inverse sampling interval in seconds+  dtf :: a+  dtf = fromIntegral dt * 0.000001++  der :: v -> v -> Sig v -> Sig v+  der d last (x:::xs)+    | d == zeroVector = zeroVector ::: delay+                        (let x' ::: xs' = adv xs+                         in der ((x' ^-^ x) ^/ dtf) x (x' ::: xs'))+    | otherwise = d ::: delay (+        case select xs (unbox (timer dt)) of+          Fst xs' _ -> der d last xs'+          Snd xs' _ -> der ((x ^-^ last) ^/ dtf) x (x ::: xs')+          Both (x' ::: xs') _ ->  der ((x' ^-^ last) ^/ dtf) x' (x' ::: xs'))+++instance Continuous a => Continuous (Sig a) where+    progressInternal inp (x ::: xs@(Delay cl _)) = +        if inputInClock inp cl then (adv' xs inp)+        else progressInternal inp x ::: xs+    progressAndNext inp (x ::: xs@(Delay cl _)) = +        if inputInClock inp cl then let n = adv' xs inp in (n, nextProgress n)+        else let (n , cl') = progressAndNext inp x in (n ::: xs , cl `clockUnion` cl')+    nextProgress (x ::: (Delay cl _)) = nextProgress x `clockUnion` cl++-- Prevent functions from being inlined too early for the rewrite+-- rules to fire.++{-# NOINLINE [1] map #-}+{-# NOINLINE [1] const #-}+{-# NOINLINE [1] scan #-}+{-# NOINLINE [1] scanMap #-}+{-# NOINLINE [1] zip #-}+{-# NOINLINE [1] update #-}+{-# NOINLINE [1] switch #-}+{-# NOINLINE [1] interleave #-}+{-# NOINLINE [1] mapAwait #-}+++{-# RULES++  "const/switch" forall x xs.+  switch (const x) xs = x ::: xs;++  "update/update" forall xs fs gs.+    update (update xs fs) gs = update xs (interleave (box (.)) gs fs) ;++  "const/map" forall (f :: Stable b => Box (a -> b))  x.+    map f (const x) = let x' = unbox f x in const x' ;++  "map/map" forall f g xs.+    map f (map g xs) = map (box (unbox f . unbox g)) xs ;++  "map/scan" forall f p acc as.+    map p (scan f acc as) = scanMap f p acc as ;++  "mapAwait/interleave" forall f g xs ys.+    mapAwait f (interleave g xs ys) = mapInterleave f g xs ys ;++  "zip/map" forall xs ys f.+    map f (zip xs ys) = let f' = unbox f in zipWith (box (\ x y -> f' (x :* y))) xs ys;++  "scan/scan" forall f g b c as.+    scan g c (scan f b as) =+      let f' = unbox f; g' = unbox g in+      scanMap (box (\ (b:*c) a -> let b' = f' b a in (b':* g' c b'))) (box snd') (b:*c) as ;++  "scan/scanMap" forall f g p b c as.+    scan g c (scanMap f p b as) =+      let f' = unbox f; g' = unbox g; p' = unbox p in+      scanMap (box (\ (b:*c) a -> let b' = f' (p' b) a in (b':* g' c b'))) (box snd') (b:*c) as ;++#-}+
+ src/WidgetRattus/Strict.hs view
@@ -0,0 +1,275 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE TemplateHaskell #-}+++-- | This module contains strict versions of some standard data+-- structures.++++module WidgetRattus.Strict+  ( List(..),+    singleton,+    IsList(..),+    init',+    reverse',+    union',+    unionBy',+    nub',+    nubBy',+    filter',+    delete',+    deleteBy',+    (+++),+    listToMaybe',+    map',+    zip',+    zipWith',+    mapMaybe',+    concatMap',+    (:*)(..),+    Maybe'(..),+    maybe',+    fromMaybe',+    isJust',+    fst',+    snd',+    curry',+    uncurry',+    toText,+    readMaybe',+    splitOn'+  )where++import Prelude hiding (map)+import Data.VectorSpace+import WidgetRattus.Derive+import WidgetRattus.Plugin.Annotation+import GHC.Exts (IsList(..))+import Data.Text hiding (foldl, singleton)+import Text.Read (readMaybe)++infixr 2 :*+-- | Strict pair type.+data a :* b = !a :* !b++continuous ''(:*)++-- | First projection function.+fst' :: (a :* b) -> a+fst' (a:*_) = a++-- | Second projection function.+snd' :: (a :* b) -> b+snd' (_:*b) = b++curry' :: ((a :* b) -> c) -> a -> b -> c+curry' f x y = f (x :* y)++uncurry' :: (a -> b -> c) -> (a :* b) -> c+uncurry' f (x :* y) = f x y+++instance Functor ((:*) a) where+  fmap f (x:*y) = (x :* f y)+  +instance (Show a, Show b) => Show (a:*b) where+  show (a :* b) = "(" ++ show a ++ " :* " ++ show b ++ ")"++instance (Eq a, Eq b) => Eq (a :* b) where+  (x1 :* y1) == (x2 :* y2) = x1 == x2 && y1 == y2+++instance (VectorSpace v a, VectorSpace w a, Floating a, Eq a) => VectorSpace (v :* w) a where+  zeroVector = zeroVector :* zeroVector++  a *^ (x :* y) = (a *^ x) :* (a *^ y)++  (x :* y) ^/ a = (x ^/ a) :* (y ^/ a)++  negateVector (x :* y) = (negateVector x) :* (negateVector y)++  (x1 :* y1) ^+^ (x2 :* y2) = (x1 ^+^ x2) :* (y1 ^+^ y2)++  (x1 :* y1) ^-^ (x2 :* y2) = (x1 ^-^ x2) :* (y1 ^-^ y2)++  (x1 :* y1) `dot` (x2 :* y2) = (x1 `dot` x2) + (y1 `dot` y2)++infixr 8 :!++-- | Strict list type.+data List a = Nil | !a :! !(List a)++continuous ''List+++singleton :: a -> List a+singleton x = x :! Nil++instance Traversable List where+  traverse _ Nil = pure Nil+  traverse f (x :! xs) = (:!) <$> (f x) <*> (traverse f xs)++instance IsList (List a) where+  type Item (List a) = a++  fromList [] = Nil+  fromList (x : xs) = x :! fromList xs++  toList Nil = []+  toList (x :! xs) = x : toList xs+++-- | Remove the last element from a list if there is one, otherwise+-- return 'Nil'.+init' :: List a -> List a+init' Nil = Nil+init' (_ :! Nil) = Nil+init' (x :! xs) = x :! init' xs++-- | Reverse a list.+reverse' :: List a -> List a+reverse' l =  rev l Nil+  where+    rev Nil     a = a+    rev (x:!xs) a = rev xs (x:!a)+    +-- | Returns @'Nothing''@ on an empty list or @'Just'' a@ where @a@ is the+-- first element of the list.+listToMaybe' :: List a -> Maybe' a+listToMaybe' Nil = Nothing'+listToMaybe' (x :! _) = Just' x++-- | Append two lists.+(+++) :: List a -> List a -> List a+(+++) Nil     ys = ys+(+++) (x:!xs) ys = x :! xs +++ ys+++map' :: (a -> b) -> List a -> List b+map' _ Nil = Nil+map' f (x :! xs) = f x :! map' f xs++concatMap' :: (a -> List b) -> List a -> List b+concatMap' _ Nil = Nil+concatMap' f (x :! xs) = f x +++ concatMap' f xs++zip' :: List a -> List b -> List (a :* b)+zip' Nil _ = Nil+zip' _ Nil = Nil+zip' (x :! xs) (y :! ys) = (x :* y) :! zip' xs ys++zipWith' :: (a -> b -> c) -> List a -> List b -> List c+zipWith' _ Nil _ = Nil+zipWith' _ _ Nil = Nil+zipWith' f (x :! xs) (y :! ys) = f x y :! zipWith' f xs ys+++-- | A version of 'map' which can throw out elements.  In particular,+-- the function argument returns something of type @'Maybe'' b@.  If+-- this is 'Nothing'', no element is added on to the result list.  If+-- it is @'Just'' b@, then @b@ is included in the result list.+mapMaybe'          :: (a -> Maybe' b) -> List a -> List b+mapMaybe' _ Nil     = Nil+mapMaybe' f (x:!xs) =+ let rs = mapMaybe' f xs in+ case f x of+  Nothing' -> rs+  Just' r  -> r:!rs++isJust' :: Maybe' a -> Bool+isJust' (Just' _) = True+isJust' Nothing' = False++union' :: (Eq a) => List a -> List a -> List a+union' = unionBy' (==)++unionBy' :: (a -> a -> Bool) -> List a -> List a -> List a+unionBy' eq xs ys =  xs +++ foldl (flip (deleteBy' eq)) (nubBy' eq ys) xs++delete' :: (Eq a) => a -> List a -> List a+delete' =  deleteBy' (==)++deleteBy' :: (a -> a -> Bool) -> a -> List a -> List a+deleteBy' _  _ Nil        = Nil+deleteBy' eq x (y :! ys)    = if x `eq` y then ys else y :! deleteBy' eq x ys+++nub' :: (Eq a) => List a -> List a+nub' =  nubBy' (==)++nubBy' :: (a -> a -> Bool) -> List a -> List a+nubBy' _ Nil             =  Nil+nubBy' eq (x:!xs)         =  x :! nubBy' eq (filter' (\ y -> not (eq x y)) xs)++filter' :: (a -> Bool) -> List a -> List a+filter' _ Nil    = Nil+filter' pred (x :! xs)+  | pred x         = x :! filter' pred xs+  | otherwise      = filter' pred xs++instance Foldable List where+  +  foldMap f = run where+    run Nil = mempty+    run (x :! xs) = f x <> run xs+  foldr f = run where+    run b Nil = b+    run b (a :! as) = (run $! (f a b)) as+  foldl f = run where+    run a Nil = a+    run a (b :! bs) = (run $! (f a b)) bs+  elem a = run where+    run Nil = False+    run (x :! xs)+      | a == x = True+      | otherwise = run xs+    +  +instance Functor List where+  fmap = map'++instance Eq a => Eq (List a) where+  Nil == Nil = True+  Nil == _ = False+  _ == Nil = False+  (x :! xs) == (y :! ys) = if x == y then xs == ys else False++instance Show a => Show (List a) where+  show Nil = "Nil"+  show (x :! xs) = show x ++ " :! " ++ show xs++-- | Strict variant of 'Maybe'.+data Maybe' a = Just' !a | Nothing' deriving (Show, Eq, Ord)++continuous ''Maybe'++-- | takes a default value, a function, and a 'Maybe'' value.  If the+-- 'Maybe'' value is 'Nothing'', the function returns the default+-- value.  Otherwise, it applies the function to the value inside the+-- 'Just'' and returns the result.+maybe' :: b -> (a -> b) -> Maybe' a -> b+maybe' n _ Nothing'  = n+maybe' _ f (Just' x) = f x++fromMaybe' :: a -> Maybe' a -> a+fromMaybe' _ (Just' x) = x+fromMaybe' d Nothing' = d+++{-# ANN toText AllowLazyData #-}+toText :: Show a => a -> Text+toText x = pack (show x)++{-# ANN readMaybe' AllowLazyData #-}+readMaybe' :: Read a => Text -> Maybe' a+readMaybe' x = case readMaybe  (unpack x) of +                Just x -> Just' x+                Nothing -> Nothing'+                +splitOn' :: Text -> Text -> List Text+splitOn' x y = fromList (splitOn x y)
+ src/WidgetRattus/Widgets.hs view
@@ -0,0 +1,217 @@+{-# OPTIONS -fplugin=WidgetRattus.Plugin #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE TypeOperators #-}+++module WidgetRattus.Widgets +  ( Displayable (..)+  , IsWidget (..)+  , Widgets (..)+  , Widget+  , HStack+  , VStack+  , TextDropdown+  , tddCurr+  , tddEvent+  , tddList+  , Popup+  , popCurr+  , popEvent+  , popChild+  , Slider+  , sldCurr+  , sldEvent+  , sldMin+  , sldMax+  , Button+  , btnContent+  , btnClick+  , Label+  , labText+  , TextField+  , tfContent+  , tfInput+  , mkButton+  , mkTextField+  , addInputSigTF+  , mkLabel+  , mkHStack+  , mkConstHStack+  , mkVStack+  , mkConstVStack+  , mkTextDropdown+  , mkPopup+  , mkSlider+  , mkProgressBar+  , btnOnClick+  , btnOnClickSig+  , setInputSigTF+  , textFieldOnInput+  , textFieldOnInputSig+  , runApplication+      ) where++import WidgetRattus+import WidgetRattus.Widgets.InternalTypes+import WidgetRattus.Signal+import Data.Text+import WidgetRattus.InternalPrimitives+import System.IO.Unsafe+import Control.Concurrent hiding (Chan)+import Data.IntSet as IntSet+import Prelude hiding (const)++import qualified Monomer as M++-- The identity function.+instance Displayable Text where+      display x = x++-- Convert Int to Text via String.+instance Displayable Int where  +      display x = toText x+++-- Functions for constructing Async Rattus widgets. +mkButton :: (Displayable a) => Sig a -> C Button+mkButton t = do+      c <- chan+      return Button{btnContent = t, btnClick = c}++mkTextField :: Text -> C TextField+mkTextField txt = do+      c <- chan+      let sig = txt ::: mkSig (box (wait c))+      return TextField{tfContent = sig, tfInput = c}++mkLabel :: (Displayable a) => Sig a -> C Label+mkLabel t = do+      return Label{labText = t}++class Widgets ws where+      toWidgetList :: ws -> List Widget++instance {-# OVERLAPPABLE #-} IsWidget w => Widgets w where+      toWidgetList w = [ mkWidget w ]++instance {-# OVERLAPPING #-} (Widgets w, Widgets v) => Widgets (w :* v) where+      toWidgetList (w :* v) = toWidgetList w +++ toWidgetList v+++instance {-# OVERLAPPING #-} (Widgets w) => Widgets (List w) where+      toWidgetList w = concatMap' toWidgetList w+++mkHStack :: IsWidget a => Sig(List a) -> C HStack+mkHStack wl = do+      return (HStack wl)+      +mkConstHStack :: Widgets ws => ws -> C HStack+mkConstHStack w = mkHStack (const (toWidgetList w))++mkVStack :: IsWidget a => Sig(List a) -> C VStack+mkVStack wl = do+      return (VStack wl)++mkConstVStack :: Widgets ws => ws -> C VStack+mkConstVStack w = mkVStack (const (toWidgetList w))++mkTextDropdown :: Sig (List Text) -> Text -> C TextDropdown+mkTextDropdown opts init = do+      c <- chan+      let curr = init ::: mkSig (box (wait c))+      return TextDropdown{tddCurr = curr, tddEvent = c, tddList = opts}++mkPopup :: Sig Bool -> Sig Widget -> C Popup +mkPopup b w = do+      c <- chan+      let sig = current b ::: interleave (box (\x _ -> x)) (future b) (mkSig (box (wait c)))+      return Popup{popCurr = sig, popEvent = c, popChild = w}++mkSlider :: Int -> Sig Int -> Sig Int -> C Slider+mkSlider start min max = do+      c <- chan+      let curr = start ::: mkSig (box (wait c))+      return Slider{sldCurr = curr, sldEvent = c, sldMin = min, sldMax = max}++mkProgressBar :: Sig Int -> Sig Int -> Sig Int -> C Slider+mkProgressBar min max curr = do+      c <- chan+      let boundedCurrent = WidgetRattus.Signal.zipWith (box Prelude.min) curr max+      return Slider{sldCurr = boundedCurrent, sldEvent = c, sldMin = min, sldMax = max}+++-- Helper function that takes a Button and returns a boxed delayed computation.+-- The delayed computation is defined from the buttons input channel.+btnOnClick :: Button -> Box(O())+btnOnClick btn =+      let ch = btnClick btn+      in box (wait ch)++-- Function that constructs a delayed signal from a Button.+btnOnClickSig :: Button -> O (Sig ())+btnOnClickSig btn = mkSig (btnOnClick btn)++-- Creates a new textfield whose contents are determined by+-- the input signal.+-- Therefore user input will only be shown if the input signal+-- ticks in response to user input on the textfield.+-- Note: the input TF and output TF share an input channel+-- Hence if both are part of a GUI they will be written to simultaneously+setInputSigTF :: TextField -> Sig Text -> TextField+setInputSigTF tf sig = tf{tfContent = sig} ++-- Uses the input signal to create a new textfield+-- The returned textfield updates in response to the input signal+-- as well as the content signal of the original textfield.+-- Note: the input TF and output TF share an input channel+-- Hence if both are part of a GUI they will be written to simultaneously+addInputSigTF :: TextField -> O (Sig Text) -> TextField+addInputSigTF tf sig =+      let leaved = current (tfContent tf) ::: interleave (box (\x _ -> x)) (future (tfContent tf)) sig+      in tf{tfContent = leaved, tfInput = tfInput tf}++-- Helper function that takes a TextField and returns a boxed delayed computation.+-- The delayed computation is defined from the Textfields input channel.+textFieldOnInput :: TextField -> Box(O Text)+textFieldOnInput tf =+      let ch = tfInput tf+      in box (wait ch)++-- Function that constructs a delayed signal from a Textfield.+textFieldOnInputSig :: TextField -> O (Sig Text)+textFieldOnInputSig tf = mkSig (textFieldOnInput tf)+++-- Function which creates a timed event. Associated clock will be part of the AppModel.+mkTimerEvent :: Int -> (AppEvent -> IO ()) -> IO ()+mkTimerEvent n cb = (threadDelay n >> cb (AppEvent (Chan n) ())) >> return ()+++-- runApplication takes as input a widget and starts the GUI applicaiton+-- by calling Monomer's startApp function.+{-# ANN runApplication AllowLazyData #-}+runApplication :: IsWidget a => C a -> IO ()+runApplication (C w) = do+    w' <- w+    M.startApp (AppModel w' emptyClock) handler builder config+    where builder _ (AppModel w _) = mkWidgetNode w `M.styleBasic` [M.padding 3]+          handler _ _ (AppModel w cl) (AppEvent (Chan ch) d) =+            let inp = OneInput ch d in unsafePerformIO $ do+               progressPromoteStoreAtomic inp+               let (w' , cl') = progressAndNext inp w+               let activeTimers = if ch > 0 then IntSet.delete ch cl else cl+               let newTimers = IntSet.filter (> 0) cl' `IntSet.difference` activeTimers+               let timers = Prelude.map (M.Producer . mkTimerEvent) (IntSet.toList newTimers)+               return (M.Model (AppModel w' (newTimers `IntSet.union` activeTimers)) : M.Request M.RenderOnce : timers )+          config = [+                M.appWindowTitle "GUI Application",+                M.appTheme M.lightTheme,+                M.appFontDef "Regular" "./assets/fonts/Roboto-Regular.ttf",+                M.appInitEvent (AppEvent (Chan 1) ())+                ]
+ src/WidgetRattus/Widgets/InternalTypes.hs view
@@ -0,0 +1,122 @@++{-# OPTIONS -fplugin=WidgetRattus.Plugin #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE GADTs #-}+++module WidgetRattus.Widgets.InternalTypes where++import WidgetRattus+import WidgetRattus.InternalPrimitives+import WidgetRattus.Signal+import Data.Text++import qualified Monomer as M+{-# ANN module AllowLazyData #-}++-- The Displayable typeclass is used to define the display function.+-- The display function is used to convert a datatype to Text.+class Stable a => Displayable a where+      display :: a -> Text++-- The AppModel datatype used to contain the Widget passed to runApplication. +-- The associated clock is a set of timers. +-- Any timers created with mkTimerEvent will be added to the clock.+data AppModel where+    AppModel :: IsWidget a => !a -> !Clock -> AppModel++++instance (Eq AppModel) where+      _ == _ = False+++-- AppEvent data type used to convert channels into events.+data AppEvent where+      AppEvent :: !(Chan a) -> !a -> AppEvent++-- The IsWidget typeclass is used to define the mkWidgetNode function.+class Continuous a => IsWidget a where+      mkWidgetNode :: a -> M.WidgetNode AppModel AppEvent+      +      mkWidget :: a -> Widget+      mkWidget w = Widget w (WidgetRattus.Signal.const True)+++      setEnabled :: a -> Sig Bool -> Widget+      setEnabled = Widget++-- Custom data types for widgets.+data Widget where+    Widget :: IsWidget a => !a -> !(Sig Bool) -> Widget++data HStack where +      HStack :: IsWidget a => !(Sig (List a)) -> HStack++data VStack where +      VStack :: IsWidget a => !(Sig (List a)) -> VStack++data TextDropdown = TextDropdown {tddCurr :: !(Sig Text), tddEvent :: !(Chan Text), tddList :: !(Sig (List Text))}++data Popup = Popup {popCurr :: !(Sig Bool), popEvent :: !(Chan Bool), popChild :: !(Sig Widget)}++data Slider = Slider {sldCurr :: !(Sig Int), sldEvent :: !(Chan Int), sldMin :: !(Sig Int), sldMax :: !(Sig Int)}++data Button where+    Button :: (Displayable a) =>  {btnContent :: !(Sig a) , btnClick :: !(Chan ())} -> Button+++data Label where+      Label :: (Displayable a) => {labText :: !(Sig a)} -> Label++data TextField = TextField {tfContent :: !(Sig Text), tfInput :: !(Chan Text)} ++-- Template Haskell code for generating instances of Continous.+continuous ''Button+continuous ''TextField+continuous ''Label+continuous ''Widget+continuous ''HStack+continuous ''VStack+continuous ''TextDropdown+continuous ''Popup+continuous ''Slider++-- isWidget Instance declerations for Widgets.+-- Here widgget data types are passed to Monomer constructors.+instance IsWidget Button where+      mkWidgetNode Button{btnContent = txt ::: _ , btnClick = click} =+            M.button  (display txt) (AppEvent click ())++instance IsWidget TextField where+      mkWidgetNode TextField{tfContent = txt ::: _, tfInput = inp} = +            M.textFieldV txt (AppEvent inp)++instance IsWidget Label where+      mkWidgetNode Label{labText = txt ::: _} = M.label (display txt)+++instance IsWidget HStack where+      mkWidgetNode (HStack ws) = M.hstack_ [ M.childSpacing_ 2] (reverse' $ fmap mkWidgetNode (current ws))++instance IsWidget VStack where+      mkWidgetNode (VStack ws) = M.vstack_ [ M.childSpacing_ 2] (reverse' $ fmap mkWidgetNode (current ws))++instance IsWidget TextDropdown where+      mkWidgetNode TextDropdown{tddList = opts ::: _, tddCurr = curr ::: _, tddEvent = ch}+            = M.textDropdownV curr (AppEvent ch) opts++instance IsWidget Popup where+      mkWidgetNode Popup{popCurr = curr ::: _, popEvent = ch, popChild = child}+            = M.popupV curr (AppEvent ch) (mkWidgetNode (current child))++instance IsWidget Slider where+      mkWidgetNode Slider{sldCurr = curr ::: _, sldEvent = ch, sldMin = min ::: _, sldMax = max ::: _}+            = M.hsliderV curr (AppEvent ch) min max++instance IsWidget Widget where+    mkWidgetNode (Widget w (e ::: _)) = M.nodeEnabled (mkWidgetNode w) e++    mkWidget w = w++    setEnabled (Widget w _) es = Widget w es
test/IllTyped.hs view
@@ -2,10 +2,10 @@  module Main (module Main) where -import AsyncRattus-import AsyncRattus.Signal as S+import WidgetRattus+import WidgetRattus.Signal as S import Prelude-import AsyncRattus.Plugin.Annotation (InternalAnn (..))+import WidgetRattus.Plugin.Annotation (InternalAnn (..))   {-# ANN loopIndirect ExpectError #-}
test/WellTyped.hs view
@@ -1,11 +1,11 @@ {-# LANGUAGE TypeOperators #-} {-# LANGUAGE StrictData #-}-{-# OPTIONS -fplugin=AsyncRattus.Plugin #-}+{-# OPTIONS -fplugin=WidgetRattus.Plugin #-}  module Main (module Main) where -import AsyncRattus-import AsyncRattus.Signal+import WidgetRattus+import WidgetRattus.Signal import Data.Set as Set import Data.Text