1 {-# LANGUAGE PatternSynonyms #-}
2 {-# LANGUAGE TemplateHaskell #-}
3 {-# LANGUAGE ViewPatterns #-}
4 {-# LANGUAGE UndecidableInstances #-}
5 {-# OPTIONS_GHC -fno-warn-orphans #-}
6 module Symantic.Parser.Grammar.Optimize where
8 import Data.Bool (Bool(..))
9 import Data.Char (Char)
10 import Data.Either (Either(..), either)
11 import Data.Eq (Eq(..))
12 import Data.Foldable (all, foldr)
13 import Data.Function ((.))
14 import qualified Data.Functor as Functor
15 import qualified Data.List as List
17 import Symantic.Parser.Grammar.Combinators as Comb
18 import Symantic.Parser.Staging (ValueCode(..), Value(..), Code(..), getValue, getCode)
19 import Symantic.Univariant.Letable
20 import Symantic.Univariant.Trans
21 import qualified Language.Haskell.TH.Syntax as TH
22 import qualified Symantic.Parser.Staging as Hask
26 Pure :: Hask.Haskell a -> Grammar a
27 Satisfy :: Hask.Haskell (Char -> Bool) -> Grammar Char
29 Try :: Grammar a -> Grammar a
30 Look :: Grammar a -> Grammar a
31 NegLook :: Grammar a -> Grammar ()
32 (:<*>) :: Grammar (a -> b) -> Grammar a -> Grammar b
33 (:<|>) :: Grammar a -> Grammar a -> Grammar a
35 Branch :: Grammar (Either a b) -> Grammar (a -> c) -> Grammar (b -> c) -> Grammar c
36 Match :: Eq a => [Hask.Haskell (a -> Bool)] -> [Grammar b] -> Grammar a -> Grammar b -> Grammar b
37 ChainPre :: Grammar (a -> a) -> Grammar a -> Grammar a
38 ChainPost :: Grammar a -> Grammar (a -> a) -> Grammar a
39 Def :: TH.Name -> Grammar a -> Grammar a
40 Ref :: Bool -> TH.Name -> Grammar a
42 pattern (:<$>) :: Hask.Haskell (a -> b) -> Grammar a -> Grammar b
43 pattern (:$>) :: Grammar a -> Hask.Haskell b -> Grammar b
44 pattern (:<$) :: Hask.Haskell a -> Grammar b -> Grammar a
45 pattern (:*>) :: Grammar a -> Grammar b -> Grammar b
46 pattern (:<*) :: Grammar a -> Grammar b -> Grammar a
47 pattern x :<$> p = Pure x :<*> p
48 pattern p :$> x = p :*> Pure x
49 pattern x :<$ p = Pure x :<* p
50 pattern x :<* p = Hask.Const :<$> x :<*> p
51 pattern p :*> x = Hask.Id :<$ p :<*> x
54 infixl 4 :<*>, :<*, :*>
55 infixl 4 :<$>, :<$, :$>
57 instance Applicable Grammar where
60 instance Alternable Grammar where
64 instance Selectable Grammar where
66 instance Matchable Grammar where
68 instance Foldable Grammar where
71 instance Charable Grammar where
73 instance Lookable Grammar where
76 instance Letable TH.Name Grammar where
79 instance MakeLetName TH.Name where
80 makeLetName _ = TH.qNewName "let"
82 instance Letable letName repr =>
83 Letable letName (Any repr)
92 , Letable TH.Name repr
94 Trans Grammar (Any repr) where
97 Satisfy p -> satisfy p
99 Try x -> try (trans x)
100 Look x -> look (trans x)
101 NegLook x -> negLook (trans x)
102 x :<*> y -> trans x <*> trans y
103 x :<|> y -> trans x <|> trans y
105 Branch lr l r -> branch (trans lr) (trans l) (trans r)
106 Match ps bs a b -> conditional ps (trans Functor.<$> bs) (trans a) (trans b)
107 ChainPre x y -> chainPre (trans x) (trans y)
108 ChainPost x y -> chainPost (trans x) (trans y)
109 Def n x -> def n (trans x)
112 -- * Type 'OptimizeGrammar'
113 -- Bottom-up application of 'optimizeGrammarNode'.
114 newtype OptimizeGrammar letName a = OptimizeGrammar { unOptimizeGrammar ::
117 optimizeGrammar :: OptimizeGrammar TH.Name a -> Grammar a
118 optimizeGrammar = unOptimizeGrammar
120 type instance Output (OptimizeGrammar letName) = Grammar
121 instance Trans Grammar (OptimizeGrammar letName) where
122 trans = OptimizeGrammar . optimizeGrammarNode
123 instance Trans1 Grammar (OptimizeGrammar letName)
124 instance Trans2 Grammar (OptimizeGrammar letName)
125 instance Trans3 Grammar (OptimizeGrammar letName)
126 instance Trans (OptimizeGrammar letName) Grammar where
127 trans = unOptimizeGrammar
130 Letable letName Grammar =>
131 Letable letName (OptimizeGrammar letName) where
132 -- Disable useless calls to 'optimizeGrammarNode'
133 -- because 'Def' or 'Ref' have no matching in it.
134 def n = OptimizeGrammar . def n . unOptimizeGrammar
135 ref r n = OptimizeGrammar (ref r n)
136 instance Comb.Applicable (OptimizeGrammar letName)
137 instance Comb.Alternable (OptimizeGrammar letName)
138 instance Comb.Charable (OptimizeGrammar letName)
139 instance Comb.Selectable (OptimizeGrammar letName)
140 instance Comb.Matchable (OptimizeGrammar letName)
141 instance Comb.Lookable (OptimizeGrammar letName)
142 instance Comb.Foldable (OptimizeGrammar letName)
144 optimizeGrammarNode :: Grammar a -> Grammar a
145 optimizeGrammarNode = \case
146 -- Applicable Right Absorption Law
147 Empty :<*> _ -> Empty
150 -- Applicable Failure Weakening Law
151 u :<*> Empty -> optimizeGrammarNode (u :*> Empty)
152 u :<* Empty -> optimizeGrammarNode (u :*> Empty)
153 -- Branch Absorption Law
154 Branch Empty _ _ -> empty
155 -- Branch Weakening Law
156 Branch b Empty Empty -> optimizeGrammarNode (b :*> Empty)
157 -- Match Absorbtion Law
158 Match _ _ Empty d -> d
159 -- Match Weakening Law
161 | all (\case {Empty -> True; _ -> False}) bs -> optimizeGrammarNode (a :*> Empty)
163 Match ps bs (Pure (trans -> a)) d -> foldr (\(trans -> p, b) next -> if getValue p (getValue a) then b else next) d (List.zip ps bs)
165 -- Pure merge optimisation
166 -- TODO: use trace to see why it's already handled by other laws
167 -- Pure x :<*> Pure y -> Pure (x Hask.:@ y)
168 -- Applicable Identity Law
170 -- Flip const optimisation
171 Hask.Flip Hask.:@ Hask.Const :<$> u -> optimizeGrammarNode (u :*> Pure Hask.Id)
173 f :<$> Pure x -> Pure (f Hask.:@ x)
174 -- Functor Composition Law
175 -- (a shortcut that could also have been be caught
176 -- by the Composition Law and Homomorphism Law)
177 f :<$> (g :<$> p) -> optimizeGrammarNode ((Hask.:.) Hask.:@ f Hask.:@ g :<$> p)
179 u :<*> (v :<*> w) -> optimizeGrammarNode (optimizeGrammarNode (optimizeGrammarNode ((Hask.:.) :<$> u) :<*> v) :<*> w)
181 Hask.Flip Hask.:@ Hask.Const :<$> p :<*> q -> p :*> q
183 Hask.Const :<$> p :<*> q -> p :<* q
184 -- Reassociation Law 1
185 (u :*> v) :<*> w -> optimizeGrammarNode (u :*> optimizeGrammarNode (v :<*> w))
187 u :<*> Pure x -> optimizeGrammarNode (Hask.Flip Hask.:@ (Hask.:$) Hask.:@ x :<$> u)
188 -- Right Absorption Law
189 (_ :<$> p) :*> q -> p :*> q
190 -- Left Absorption Law
191 p :<* (_ :<$> q) -> p :<* q
192 -- Reassociation Law 2
193 u :<*> (v :<* w) -> optimizeGrammarNode (optimizeGrammarNode (u :<*> v) :<* w)
194 -- Reassociation Law 3
195 u :<*> (v :$> x) -> optimizeGrammarNode (optimizeGrammarNode (u :<*> Pure x) :<* v)
204 (u :<|> v) :<|> w -> u :<|> optimizeGrammarNode (v :<|> w)
206 -- Pure Left Identity Law
208 -- Functor Left Identity Law
209 (u :$> _) :*> v -> u :*> v
211 u :*> (v :*> w) -> optimizeGrammarNode (optimizeGrammarNode (u :*> v) :*> w)
212 -- Pure Right Identity Law
214 -- Functor Right Identity Law
215 u :<* (v :$> _) -> optimizeGrammarNode (u :<* v)
217 x :<$ u -> optimizeGrammarNode (u :$> x)
219 (u :<* v) :<* w -> optimizeGrammarNode (u :<* optimizeGrammarNode (v :<* w))
225 -- Pure negative-lookahead
226 NegLook Pure{} -> Empty
228 -- Dead negative-lookahead
229 NegLook Empty -> Pure Hask.unit
230 -- Double Negation Law
231 NegLook (NegLook p) -> optimizeGrammarNode (Look (Try p) :*> Pure Hask.unit)
232 -- Zero Consumption Law
233 NegLook (Try p) -> optimizeGrammarNode (NegLook p)
235 Look (Look p) -> Look p
236 -- Right Identity Law
237 NegLook (Look p) -> optimizeGrammarNode (NegLook p)
240 Look (NegLook p) -> NegLook p
242 NegLook (Try p :<|> q) -> optimizeGrammarNode (optimizeGrammarNode (NegLook p) :*> optimizeGrammarNode (NegLook q))
243 -- Distributivity Law
244 Look p :<|> Look q -> optimizeGrammarNode (Look (optimizeGrammarNode (Try p :<|> q)))
246 Look (p :$> x) -> optimizeGrammarNode (optimizeGrammarNode (Look p) :$> x)
248 Look (f :<$> p) -> optimizeGrammarNode (f :<$> optimizeGrammarNode (Look p))
250 p :<*> NegLook q -> optimizeGrammarNode (optimizeGrammarNode (p :<*> Pure Hask.unit) :<* NegLook q)
252 NegLook (p :$> _) -> optimizeGrammarNode (NegLook p)
254 NegLook (_ :<$> p) -> optimizeGrammarNode (NegLook p)
256 Try (p :$> x) -> optimizeGrammarNode (optimizeGrammarNode (Try p) :$> x)
258 Try (f :<$> p) -> optimizeGrammarNode (f :<$> optimizeGrammarNode (Try p))
260 -- Pure Left/Right Laws
261 Branch (Pure (trans -> lr)) l r ->
263 Left v -> optimizeGrammarNode (l :<*> Pure (Hask.Haskell (ValueCode (Value v) c)))
264 where c = Code [|| case $$(getCode lr) of Left x -> x ||]
265 Right v -> optimizeGrammarNode (r :<*> Pure (Hask.Haskell (ValueCode (Value v) c)))
266 where c = Code [|| case $$(getCode lr) of Right x -> x ||]
267 -- Generalised Identity Law
268 Branch b (Pure (trans -> l)) (Pure (trans -> r)) ->
269 optimizeGrammarNode (Hask.Haskell (ValueCode v c) :<$> b)
271 v = Value (either (getValue l) (getValue r))
272 c = Code [|| either $$(getCode l) $$(getCode r) ||]
274 Branch (x :*> y) p q ->
275 optimizeGrammarNode (x :*> optimizeGrammarNode (Branch y p q))
276 -- Negated Branch Law
278 Branch (Pure (Hask.Haskell (ValueCode v c)) :<*> b) Empty l
280 v = Value (either Right Left)
281 c = Code [||either Right Left||]
283 Branch (Branch b Empty (Pure (trans -> lr))) Empty br ->
284 optimizeGrammarNode (Branch (optimizeGrammarNode (Pure (Hask.Haskell (ValueCode (Value v) c)) :<*> b)) Empty br)
287 v (Right r) = case getValue lr r of
290 c = Code [|| \case Left{} -> Left ()
291 Right r -> case $$(getCode lr) r of
293 Right rr -> Right rr ||]
294 -- Branch Distributivity Law
295 f :<$> Branch b l r -> optimizeGrammarNode (Branch b (optimizeGrammarNode ((Hask..@) (Hask..) f :<$> l))
296 (optimizeGrammarNode ((Hask..@) (Hask..) f :<$> r)))
297 -- Match Distributivity Law
298 f :<$> Match ps bs a d -> Match ps (optimizeGrammarNode . (f :<$>) Functor.<$> bs) a (optimizeGrammarNode (f :<$> d))