copyright: comply with REUSE-3.0
[haskell/symantic-parser.git] / src / Symantic / Parser / Grammar / ObserveSharing.hs
index 76c6415e769d4e4349725f7298614af47758ce51..719a622f515b5887114a60cc1effd42931fc1496 100644 (file)
@@ -1,30 +1,30 @@
+{-# LANGUAGE DefaultSignatures #-}
+{-# LANGUAGE TupleSections #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 module Symantic.Parser.Grammar.ObserveSharing
-  ( module Symantic.Univariant.Letable
+  ( module Symantic.ObserveSharing
   , module Symantic.Parser.Grammar.ObserveSharing
   ) where
 
 import Control.Monad (mapM)
 import Data.Function (($), (.))
 import Data.Hashable (Hashable, hashWithSalt)
+import System.IO.Unsafe (unsafePerformIO) -- For 'new'
 import Text.Show (Show(..))
-import qualified Control.Applicative as Functor
+import qualified Control.Applicative as F
 
 import Symantic.Parser.Grammar.Combinators
-import Symantic.Univariant.Letable hiding (observeSharing)
-import qualified Symantic.Univariant.Letable as Letable
+import Symantic.Derive
+import Symantic.ObserveSharing hiding (observeSharing)
+import qualified Symantic.ObserveSharing as ObserveSharing
 import qualified Language.Haskell.TH.Syntax as TH
-import qualified Symantic.Univariant.Trans as Sym
 
--- | Like 'Letable.observeSharing'
+-- | Like 'Observable.observeSharing'
 -- but type-binding @(letName)@ to 'TH.Name'
 -- to avoid the trouble to always set it.
-observeSharing ::
-  Letsable TH.Name repr =>
-  ObserveSharing TH.Name repr a ->
-  repr a
+observeSharing :: Letsable TH.Name repr => ObserveSharing TH.Name repr a -> repr a
 observeSharing os = lets defs body
-  where (body, defs) = Letable.observeSharing os
+  where (body, defs) = ObserveSharing.observeSharing os
 
 -- | Needed by 'observeSharing'.
 instance Hashable TH.Name where
@@ -34,62 +34,109 @@ instance MakeLetName TH.Name where
 
 -- Combinators semantics for the 'ObserveSharing' interpreter.
 instance
-  ( Letable TH.Name repr
-  , Satisfiable tok repr
-  ) => Satisfiable tok (ObserveSharing TH.Name repr)
+  ( Referenceable TH.Name repr
+  , CombAlternable repr
+  ) => CombAlternable (ObserveSharing TH.Name repr)
 instance
-  ( Letable TH.Name repr
-  , Alternable repr
-  ) => Alternable (ObserveSharing TH.Name repr)
+  ( Referenceable TH.Name repr
+  , CombApplicable repr
+  ) => CombApplicable (ObserveSharing TH.Name repr)
 instance
-  ( Letable TH.Name repr
-  , Applicable repr
-  ) => Applicable (ObserveSharing TH.Name repr)
+  ( Referenceable TH.Name repr
+  , CombFoldable repr
+  ) => CombFoldable (ObserveSharing TH.Name repr)
 instance
-  ( Letable TH.Name repr
-  , Selectable repr
-  ) => Selectable (ObserveSharing TH.Name repr)
+  ( Referenceable TH.Name repr
+  , CombLookable repr
+  ) => CombLookable (ObserveSharing TH.Name repr)
 instance
-  ( Letable TH.Name repr
-  , Matchable repr
-  ) => Matchable (ObserveSharing TH.Name repr) where
+  ( Referenceable TH.Name repr
+  , CombMatchable repr
+  ) => CombMatchable (ObserveSharing TH.Name repr) where
   -- Here the default definition does not fit
-  -- since there is no lift* for the type of 'conditional'
+  -- since there is no liftDerived* for the type of 'conditional'
   -- and its default definition does not handles 'bs'
-  -- as needed by the 'ObserveSharing' transformation.
-  conditional a cs bs b = observeSharingNode $ ObserveSharing $
-    conditional
-      Functor.<$> unObserveSharing a
-      Functor.<*> Functor.pure cs
-      Functor.<*> mapM unObserveSharing bs
-      Functor.<*> unObserveSharing b
-instance
-  ( Letable TH.Name repr
-  , Foldable repr
-  {- TODO: the following constraints are for the current Foldable,
-   - they will have to be removed when Foldable will have Sym.lift2 as defaults
-   -}
-  , Applicable repr
-  , Alternable repr
-  ) => Foldable (ObserveSharing TH.Name repr)
-instance
-  ( Letable TH.Name repr
-  , Lookable repr
-  ) => Lookable (ObserveSharing TH.Name repr)
+  -- as needed by the 'ObserveSharing' interpreter.
+  conditional a bs d = observeSharingNode $ ObserveSharing $ conditional
+    F.<$> unObserveSharing a
+    F.<*> mapM (\(p, b) -> (p,) F.<$> unObserveSharing b) bs
+    F.<*> unObserveSharing d
+instance
+  ( Referenceable TH.Name repr
+  , CombSelectable repr
+  ) => CombSelectable (ObserveSharing TH.Name repr)
+instance
+  ( Referenceable TH.Name repr
+  , CombSatisfiable tok repr
+  ) => CombSatisfiable tok (ObserveSharing TH.Name repr)
+instance
+  ( Referenceable TH.Name repr
+  , CombRegisterableUnscoped repr
+  ) => CombRegisterable (ObserveSharing TH.Name repr) where
+  new ini f =
+    -- 'unsafePerformIO' is used here because propagating 'IO'
+    -- would prevent 'observeSharing' to recognize recursive let,
+    -- causing an infinite loop on them.
+    let !regName = unsafePerformIO $ TH.newName "reg" in
+    let reg = UnscopedRegister regName in
+    newUnscoped reg ini (f (Register reg))
+  get = getUnscoped . unRegister
+  put reg x = putUnscoped (unRegister reg) x
+instance
+  ( Referenceable TH.Name repr
+  , CombRegisterableUnscoped repr
+  ) => CombRegisterableUnscoped (ObserveSharing TH.Name repr)
+
+-- * Class 'CombRegisterableUnscoped'
+-- | These combinators are used to remove the @Rank2Types@ from 'CombRegisterable'
+-- in order to be able to 'observeSharing'.
+class CombRegisterableUnscoped (repr::ReprComb) where
+  newUnscoped :: UnscopedRegister a -> repr a -> repr b -> repr b
+  getUnscoped :: UnscopedRegister a -> repr a
+  putUnscoped :: UnscopedRegister a -> repr a -> repr ()
+  default newUnscoped ::
+    FromDerived2 CombRegisterableUnscoped repr =>
+    UnscopedRegister a -> repr a -> repr b -> repr b
+  default getUnscoped ::
+    FromDerived CombRegisterableUnscoped repr =>
+    UnscopedRegister a -> repr a
+  default putUnscoped ::
+    FromDerived1 CombRegisterableUnscoped repr =>
+    UnscopedRegister a -> repr a -> repr ()
+  newUnscoped = liftDerived2 . newUnscoped
+  getUnscoped = liftDerived . getUnscoped
+  putUnscoped = liftDerived1 . putUnscoped
 
 -- Combinators semantics for the 'FinalizeSharing' interpreter.
-instance Applicable repr => Applicable (FinalizeSharing TH.Name repr)
-instance Alternable repr => Alternable (FinalizeSharing TH.Name repr)
-instance Satisfiable tok repr => Satisfiable tok (FinalizeSharing TH.Name repr)
-instance Selectable repr => Selectable (FinalizeSharing TH.Name repr)
-instance Matchable repr => Matchable (FinalizeSharing TH.Name repr) where
-  conditional a cs bs b = FinalizeSharing $
-    conditional
-      Functor.<$> unFinalizeSharing a
-      Functor.<*> Functor.pure cs
-      Functor.<*> mapM unFinalizeSharing bs
-      Functor.<*> unFinalizeSharing b
-instance Lookable repr => Lookable (FinalizeSharing TH.Name repr)
-instance Foldable repr => Foldable (FinalizeSharing TH.Name repr) where
-  chainPre = Sym.lift2 chainPre
-  chainPost = Sym.lift2 chainPost
+instance
+  ( CombApplicable repr
+  ) => CombApplicable (FinalizeSharing TH.Name repr)
+instance
+  ( CombAlternable repr
+  ) => CombAlternable (FinalizeSharing TH.Name repr)
+instance
+  ( CombFoldable repr
+  ) => CombFoldable (FinalizeSharing TH.Name repr)
+instance
+  ( CombLookable repr
+  ) => CombLookable (FinalizeSharing TH.Name repr)
+instance
+  ( CombMatchable repr
+  ) => CombMatchable (FinalizeSharing TH.Name repr) where
+  conditional a bs d = FinalizeSharing $ conditional
+    F.<$> unFinalizeSharing a
+    F.<*> mapM (\(p, b) -> (p,) F.<$> unFinalizeSharing b) bs
+    F.<*> unFinalizeSharing d
+instance
+  ( CombSatisfiable tok repr
+  ) => CombSatisfiable tok (FinalizeSharing TH.Name repr)
+instance
+  ( CombSelectable repr
+  ) => CombSelectable (FinalizeSharing TH.Name repr)
+instance
+  ( CombRegisterableUnscoped repr
+  ) => CombRegisterableUnscoped (FinalizeSharing TH.Name repr)
+
+-- | Call trace stack updated by 'call' and 'refJoin'.
+-- Used to avoid infinite loops when tying the knot with 'polyfix'.
+type CallTrace = [TH.Name]