1 {-# LANGUAGE AllowAmbiguousTypes #-}
2 {-# LANGUAGE ExistentialQuantification #-}
3 {-# LANGUAGE MagicHash #-}
4 {-# LANGUAGE MultiParamTypeClasses #-}
5 module Symantic.Parser.Grammar.Observations where
7 import Control.Monad (Monad(..), mapM_, when)
8 import Data.Eq (Eq(..))
9 import Data.Function (($), id)
10 import Data.Functor (Functor(..))
11 import Data.HashMap.Strict (HashMap)
12 import Data.HashSet (HashSet)
13 import Data.Hashable (Hashable, hashWithSalt, hash)
14 import Data.Maybe (Maybe(..), isNothing, maybe)
15 import Data.Monoid (Monoid(..))
16 import Data.Ord (Ord(..))
17 import GHC.Exts (Int(..))
18 import GHC.Prim (StableName#, unsafeCoerce#)
19 import GHC.StableName (StableName(..), makeStableName, hashStableName, eqStableName)
20 import Numeric (showHex)
23 import Text.Show (Show(..))
24 import qualified Control.Monad.Trans.Class as T
25 import qualified Control.Monad.Trans.Reader as R
26 import qualified Control.Monad.Trans.State as S
28 import qualified Data.HashMap.Strict as HM
29 import qualified Data.HashSet as HS
31 import Symantic.Base.Univariant
32 import qualified Symantic.Parser.Grammar.Combinators as P
33 --import qualified Symantic.Parser.Staging as P
35 -- * Type 'ParserName'
36 data ParserName = forall a. ParserName (StableName# a)
37 -- Force evaluation of p to ensure that the StableName is correct first time
38 makeParserName :: repr a -> IO ParserName
39 makeParserName !p = fmap (\(StableName name) -> ParserName name) (makeStableName p)
40 instance Eq ParserName where
41 (ParserName n) == (ParserName m) =
42 eqStableName (StableName n) (StableName m)
43 instance Hashable ParserName where
44 hash (ParserName n) = hashStableName (StableName n)
45 hashWithSalt salt (ParserName n) =
46 hashWithSalt salt (StableName n)
48 instance Show ParserName where showsPrec _ (ParserName n) = showHex (I# (unsafeCoerce# n))
51 -- | Combinator interpreter detecting (Haskell embedded) @let@ definitions and recursive points in order to replace them with the 'Let' combinator.
52 -- See [Type-safe observable sharing in Haskell](https://doi.org/10.1145/1596638.1596653)
53 newtype Lets a = Lets { unLets :: R.ReaderT (HashSet ParserName) (S.StateT LetsState IO) () }
55 lets :: Lets a -> IO (HashSet ParserName, HashSet ParserName)
57 st <- S.execStateT (R.runReaderT m mempty) emptyLetsState
59 ( HM.keysSet (HM.filter (> 1) (lets_preds st))
63 letsNode :: Lets a -> Lets a
64 letsNode (Lets m) = Lets $ do
65 name <- T.lift (T.lift (makeParserName m))
67 let (before, preds) = HM.alterF (\v -> (v, Just (maybe 1 (+ 1) v))) name (lets_preds st)
69 if --trace (ind<>"at: "<>show name) $
71 then --trace (ind<>"skipR: "<>show name) $
74 , lets_recs = HS.insert name (lets_recs st)
77 T.lift $ S.put st{ lets_preds = preds }
78 when (isNothing before) $
79 R.local (HS.insert name) m
81 if trace (ind<>"b?: "<>show name) $ before /= Nothing
82 then trace (ind<>"SKIPB: "<>show name) $ return ()
83 else trace (ind<>"first: "<>show name) $
84 R.local (\(m,i) -> (HS.insert name m, ind<>" ")) r
87 -- | This is an uncommon 'Unlift' definition which unlifts nothing,
88 -- but it enables to leverage default definitions.
89 type instance Unlift Lets = Lets
90 instance Liftable Lets where
91 lift _x = letsNode (Lets (return ()))
92 lift1 _f x = letsNode (Lets (unLets x))
93 lift2 _f x y = letsNode (Lets (unLets x >> unLets y))
94 lift3 _f x y z = letsNode (Lets (unLets x >> unLets y >> unLets z))
95 instance Unliftable Lets where
97 instance P.Applicable Lets
98 instance P.Alternable Lets
99 instance P.Selectable Lets
100 instance P.Matchable Lets where
101 -- Here the default definition does not fit since there is no lift* for its type and thus handles 'bs' itself, which is not the transformation wanted.
102 conditional _cs bs a b =
103 letsNode (Lets (mapM_ unLets bs >> unLets a >> unLets b))
104 instance P.Foldable Lets
105 instance P.Charable Lets
106 instance P.Lookable Lets
108 -- ** Type 'LetsState'
109 data LetsState = LetsState
110 { lets_preds :: HashMap ParserName Int
111 , lets_recs :: HashSet ParserName
114 emptyLetsState :: LetsState
115 emptyLetsState = LetsState
116 { lets_preds = HM.empty
117 , lets_recs = HS.empty
123 newtype IMVar = IMVar Word64 deriving newtype (Ord, Eq, Num, Enum, Show, Ix)
124 newtype MVar (a :: Type) = MVar IMVar
125 instance Show (MVar a) where show (MVar m) = "m" <> show m
127 instance GEq MVar where
128 geq (MVar u) (MVar v)
129 | u == v = Just (unsafeCoerce Refl)
130 | otherwise = Nothing
131 instance GCompare MVar where
132 gcompare m1@(MVar u) m2@(MVar v) =
135 EQ -> case geq m1 m2 of Just Refl -> GEQ
139 type Binding o a x = Fix4 (Instr o) '[] One x a
140 data LetBinding o a x = forall rs. LetBinding (Binding o a x) (Regs rs)
141 deriving instance Show (LetBinding o a x)
143 makeLetBinding :: Binding o a x -> Set IΣVar -> LetBinding o a x
144 makeLetBinding m rs = LetBinding m (unsafeMakeRegs rs)
146 data Regs (rs :: [Type]) where
148 FreeReg :: ΣVar r -> Regs rs -> Regs (r : rs)
149 deriving instance Show (Regs rs)
151 unsafeMakeRegs :: Set IΣVar -> Regs rs
152 unsafeMakeRegs = foldr (\σ rs -> unsafeCoerce (FreeReg (ΣVar σ) rs)) (unsafeCoerce NoRegs)
154 compile :: forall compiled a. Parser a -> (forall x. Maybe (MVar x) -> Fix Combinator x -> Set IΣVar -> IMVar -> IΣVar -> compiled x) -> (compiled a, DMap MVar compiled)
155 compile (Parser p) codeGen = trace ("COMPILING NEW PARSER WITH " ++ show (DMap.size μs') ++ " LET BINDINGS") $ (codeGen' Nothing p', DMap.mapWithKey (codeGen' . Just) μs')
157 (p', μs, maxV) = preprocess p
158 (μs', frs, maxΣ) = dependencyAnalysis p' μs
160 freeRegs :: Maybe (MVar x) -> Set IΣVar
161 freeRegs = maybe Set.empty (\(MVar v) -> frs Map.! v)
163 codeGen' :: Maybe (MVar x) -> Fix Combinator x -> compiled x
164 codeGen' letBound p = codeGen letBound (analyse (emptyFlags {letBound = isJust letBound}) p) (freeRegs letBound) (maxV + 1) (maxΣ + 1)
166 preprocess :: Fix (Combinator :+: ScopeRegister) a -> (Fix Combinator a, DMap MVar (Fix Combinator), IMVar)
169 (lets, recs) = findLets q
170 (p', μs, maxV) = letInsertion lets recs q
173 data Tag t f (k :: Type -> Type) a = Tag {tag :: t, tagged :: f k a}
175 tagParser :: Fix (Combinator :+: ScopeRegister) a -> Fix (Tag ParserName Combinator) a
176 tagParser p = cata' tagAlg p
178 tagAlg p = In . Tag (makeParserName p) . (id \/ descope)
179 descope (ScopeRegister p f) = freshReg regMaker (\(reg@(Reg σ)) -> MakeRegister σ p (f reg))
180 regMaker :: IORef IΣVar
181 regMaker = newRegMaker p
184 newtype LetInserter a =
186 doLetInserter :: HFreshT IMVar
187 (State ( HashMap ParserName IMVar
188 , DMap MVar (Fix Combinator)))
191 letInsertion :: HashSet ParserName -> HashSet ParserName -> Fix (Tag ParserName Combinator) a -> (Fix Combinator a, DMap MVar (Fix Combinator), IMVar)
192 letInsertion lets recs p = (p', μs, μMax)
195 ((p', μMax), (_, μs)) = runState (runFreshT (doLetInserter m) 0) (HashMap.empty, DMap.empty)
196 alg :: Tag ParserName Combinator LetInserter a -> LetInserter a
197 alg p = LetInserter $ do
201 let bound = HashSet.member name lets
202 let recu = HashSet.member name recs
203 if bound || recu then case HashMap.lookup name vs of
204 Just v -> let μ = MVar v in return $! optimise (Let recu μ (μs DMap.! μ))
208 put (HashMap.insert name v vs, DMap.insert μ q' μs)
209 q' <- doLetInserter (postprocess q)
210 return $! optimise (Let recu μ q')
211 else do doLetInserter (postprocess q)
213 postprocess :: Combinator LetInserter a -> LetInserter a
214 postprocess = LetInserter . fmap optimise . traverseCombinator doLetInserter
216 getBefore :: MonadState LetsState m => m (HashSet ParserName)
217 getBefore = gets before
226 makeParserName :: Fix (Combinator :+: ScopeRegister) a -> ParserName
227 -- Force evaluation of p to ensure that the stableName is correct first time
228 makeParserName !p = unsafePerformIO (fmap (\(StableName name) -> ParserName name) (makeStableName p))
230 -- The argument here stops GHC from floating it out, it should be provided something from the scope
231 {-# NOINLINE newRegMaker #-}
232 newRegMaker :: a -> IORef IΣVar
233 newRegMaker x = x `seq` unsafePerformIO (newIORef 0)
235 {-# NOINLINE freshReg #-}
236 freshReg :: IORef IΣVar -> (forall r. Reg r a -> x) -> x
237 freshReg maker scope = scope $ unsafePerformIO $ do
239 writeIORef maker (x + 1)
240 return $! Reg (ΣVar x)
242 instance IFunctor f => IFunctor (Tag t f) where
243 imap f (Tag t k) = Tag t (imap f k)
245 instance Eq ParserName where
246 (ParserName n) == (ParserName m) = eqStableName (StableName n) (StableName m)
247 instance Hashable ParserName where
248 hash (ParserName n) = hashStableName (StableName n)
249 hashWithSalt salt (ParserName n) = hashWithSalt salt (StableName n)
251 -- There is great evil in this world, and I'm probably responsible for half of it
252 instance Show ParserName where showsPrec _ (ParserName n) = showHex (I# (unsafeCoerce# n))