1 {-# LANGUAGE PatternSynonyms #-} -- For aliased combinators
2 {-# LANGUAGE TemplateHaskell #-} -- For optimizeCombNode
3 {-# LANGUAGE ViewPatterns #-} -- For optimizeCombNode
4 {-# OPTIONS_GHC -fno-warn-orphans #-} -- For MakeLetName TH.Name
5 module Symantic.Parser.Grammar.Optimize where
7 import Data.Bool (Bool(..))
8 import Data.Char (Char)
9 import Data.Either (Either(..), either)
10 import Data.Eq (Eq(..))
11 import Data.Foldable (all, foldr)
12 import Data.Function ((.))
13 import qualified Data.Functor as Functor
14 import qualified Data.List as List
15 import qualified Language.Haskell.TH.Syntax as TH
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 Symantic.Parser.Staging as Hask
23 -- import Debug.Trace (trace)
26 -- | Pattern-matchable 'Comb'inators of the grammar.
27 -- @(repr)@ is not strictly necessary since it's only a phantom type
28 -- (no constructor use it as a value), but having it:
30 -- 1. emphasizes that those 'Comb'inators will be 'trans'formed again
31 -- (eg. in 'DumpComb' or 'Instr'uctions).
33 -- 2. Avoid overlapping instances between
34 -- @('Trans' ('Comb' repr) repr)@ and
35 -- @('Trans' ('Comb' repr) ('OptimizeComb' letName repr))@
36 data Comb (repr :: * -> *) a where
37 Pure :: Hask.Haskell a -> Comb repr a
38 Satisfy :: Hask.Haskell (Char -> Bool) -> Comb repr Char
39 Item :: Comb repr Char
40 Try :: Comb repr a -> Comb repr a
41 Look :: Comb repr a -> Comb repr a
42 NegLook :: Comb repr a -> Comb repr ()
43 (:<*>) :: Comb repr (a -> b) -> Comb repr a -> Comb repr b
44 (:<|>) :: Comb repr a -> Comb repr a -> Comb repr a
46 Branch :: Comb repr (Either a b) -> Comb repr (a -> c) -> Comb repr (b -> c) -> Comb repr c
47 Match :: Eq a => [Hask.Haskell (a -> Bool)] -> [Comb repr b] -> Comb repr a -> Comb repr b -> Comb repr b
48 ChainPre :: Comb repr (a -> a) -> Comb repr a -> Comb repr a
49 ChainPost :: Comb repr a -> Comb repr (a -> a) -> Comb repr a
50 Def :: TH.Name -> Comb repr a -> Comb repr a
51 Ref :: Bool -> TH.Name -> Comb repr a
53 pattern (:<$>) :: Hask.Haskell (a -> b) -> Comb repr a -> Comb repr b
54 pattern (:$>) :: Comb repr a -> Hask.Haskell b -> Comb repr b
55 pattern (:<$) :: Hask.Haskell a -> Comb repr b -> Comb repr a
56 pattern (:*>) :: Comb repr a -> Comb repr b -> Comb repr b
57 pattern (:<*) :: Comb repr a -> Comb repr b -> Comb repr a
58 pattern x :<$> p = Pure x :<*> p
59 pattern p :$> x = p :*> Pure x
60 pattern x :<$ p = Pure x :<* p
61 pattern x :<* p = Hask.Const :<$> x :<*> p
62 pattern p :*> x = Hask.Id :<$ p :<*> x
65 infixl 4 :<*>, :<*, :*>
66 infixl 4 :<$>, :<$, :$>
68 instance Applicable (Comb repr) where
71 instance Alternable (Comb repr) where
75 instance Selectable (Comb repr) where
77 instance Matchable (Comb repr) where
79 instance Foldable (Comb repr) where
82 instance Charable (Comb repr) where
84 instance Lookable (Comb repr) where
87 instance Letable TH.Name (Comb repr) where
90 instance MakeLetName TH.Name where
91 makeLetName _ = TH.qNewName "let"
93 -- Pattern-matchable 'Comb'inators keep enough structure
94 -- to have some of the symantics producing them interpreted again
95 -- (eg. after being modified by 'optimizeComb').
96 type instance Output (Comb repr) = repr
105 , Letable TH.Name repr
106 ) => Trans (Comb repr) repr where
109 Satisfy p -> satisfy p
111 Try x -> try (trans x)
112 Look x -> look (trans x)
113 NegLook x -> negLook (trans x)
114 x :<*> y -> trans x <*> trans y
115 x :<|> y -> trans x <|> trans y
117 Branch lr l r -> branch (trans lr) (trans l) (trans r)
118 Match ps bs a b -> conditional ps (trans Functor.<$> bs) (trans a) (trans b)
119 ChainPre x y -> chainPre (trans x) (trans y)
120 ChainPost x y -> chainPost (trans x) (trans y)
121 Def n x -> def n (trans x)
124 -- * Type 'OptimizeComb'
125 -- Bottom-up application of 'optimizeCombNode'.
126 newtype OptimizeComb letName repr a = OptimizeComb { unOptimizeComb :: Comb repr a }
129 Trans (OptimizeComb TH.Name repr) repr =>
130 OptimizeComb TH.Name repr a -> repr a
133 Trans (Comb repr) repr =>
134 Trans (OptimizeComb letName repr) repr where
135 trans = trans . unOptimizeComb
137 type instance Output (OptimizeComb letName repr) = Comb repr
138 instance Trans (OptimizeComb letName repr) (Comb repr) where
139 trans = unOptimizeComb
140 instance Trans (Comb repr) (OptimizeComb letName repr) where
141 trans = OptimizeComb . optimizeCombNode
142 instance Trans1 (Comb repr) (OptimizeComb letName repr)
143 instance Trans2 (Comb repr) (OptimizeComb letName repr)
144 instance Trans3 (Comb repr) (OptimizeComb letName repr)
147 Letable letName (Comb repr) =>
148 Letable letName (OptimizeComb letName repr) where
149 -- Disable useless calls to 'optimizeCombNode'
150 -- because 'Def' or 'Ref' have no matching in it.
151 def n = OptimizeComb . def n . unOptimizeComb
152 ref r n = OptimizeComb (ref r n)
153 instance Comb.Applicable (OptimizeComb letName repr)
154 instance Comb.Alternable (OptimizeComb letName repr)
155 instance Comb.Charable (OptimizeComb letName repr)
156 instance Comb.Selectable (OptimizeComb letName repr)
157 instance Comb.Matchable (OptimizeComb letName repr)
158 instance Comb.Lookable (OptimizeComb letName repr)
159 instance Comb.Foldable (OptimizeComb letName repr)
161 optimizeCombNode :: Comb repr a -> Comb repr a
162 optimizeCombNode = \case
163 -- Functor Identity Law
165 -- trace "Functor Identity Law" $
167 -- Functor Commutativity Law
169 -- trace "Functor Commutativity Law" $
170 optimizeCombNode (u :$> x)
171 -- Functor Flip Const Law
172 Hask.Flip Hask.:@ Hask.Const :<$> u ->
173 -- trace "Functor Flip Const Law" $
174 optimizeCombNode (u :*> Pure Hask.Id)
175 -- Functor Homomorphism Law
177 -- trace "Functor Homomorphism Law" $
180 -- App Right Absorption Law
182 -- trace "App Right Absorption Law" $
185 -- In Parsley: this is only a weakening to u :*> Empty
186 -- but here :*> is an alias to :<*>
187 -- hence it would loop on itself forever.
188 -- trace "App Left Absorption Law" $
190 -- App Composition Law
192 -- trace "App Composition Law" $
193 optimizeCombNode (optimizeCombNode (optimizeCombNode ((Hask.:.) :<$> u) :<*> v) :<*> w)
194 -- App Interchange Law
196 -- trace "App Interchange Law" $
197 optimizeCombNode (Hask.Flip Hask.:@ (Hask.:$) Hask.:@ x :<$> u)
198 -- App Left Absorption Law
200 -- trace "App Left Absorption Law" $
202 -- App Right Absorption Law
204 -- trace "App Right Absorption Law" $
206 -- App Pure Left Identity Law
208 -- trace "App Pure Left Identity Law" $
210 -- App Functor Left Identity Law
212 -- trace "App Functor Left Identity Law" $
214 -- App Pure Right Identity Law
216 -- trace "App Pure Right Identity Law" $
218 -- App Functor Right Identity Law
220 -- trace "App Functor Right Identity Law" $
221 optimizeCombNode (u :<* v)
222 -- App Left Associativity Law
224 -- trace "App Left Associativity Law" $
225 optimizeCombNode (u :<* optimizeCombNode (v :<* w))
227 -- Alt Left Catch Law
229 -- trace "Alt Left Catch Law" $
231 -- Alt Left Neutral Law
233 -- trace "Alt Left Neutral Law" $
235 -- All Right Neutral Law
237 -- trace "Alt Right Neutral Law" $
239 -- Alt Associativity Law
241 -- trace "Alt Associativity Law" $
242 u :<|> optimizeCombNode (v :<|> w)
246 -- trace "Look Pure Law" $
250 -- trace "Look Empty Law" $
254 -- trace "NegLook Pure Law" $
258 -- trace "NegLook Dead Law" $
260 -- NegLook Double Negation Law
261 NegLook (NegLook p) ->
262 -- trace "NegLook Double Negation Law" $
263 optimizeCombNode (Look (Try p) :*> Pure Hask.unit)
264 -- NegLook Zero Consumption Law
266 -- trace "NegLook Zero Consumption Law" $
267 optimizeCombNode (NegLook p)
270 -- trace "Look Idempotence Law" $
272 -- Look Right Identity Law
274 -- trace "Look Right Identity Law" $
275 optimizeCombNode (NegLook p)
276 -- Look Left Identity Law
278 -- trace "Look Left Identity Law" $
280 -- NegLook Transparency Law
281 NegLook (Try p :<|> q) ->
282 -- trace "NegLook Transparency Law" $
283 optimizeCombNode (optimizeCombNode (NegLook p) :*> optimizeCombNode (NegLook q))
284 -- Look Distributivity Law
285 Look p :<|> Look q ->
286 -- trace "Look Distributivity Law" $
287 optimizeCombNode (Look (optimizeCombNode (Try p :<|> q)))
288 -- Look Interchange Law
290 -- trace "Look Interchange Law" $
291 optimizeCombNode (f :<$> optimizeCombNode (Look p))
292 -- NegLook Absorption Law
294 -- trace "Neglook Absorption Law" $
295 optimizeCombNode (optimizeCombNode (p :<*> Pure Hask.unit) :<* NegLook q)
296 -- NegLook Idempotence Right Law
297 NegLook (_ :<$> p) ->
298 -- trace "NegLook Idempotence Law" $
299 optimizeCombNode (NegLook p)
300 -- Try Interchange Law
302 -- trace "Try Interchange Law" $
303 optimizeCombNode (f :<$> optimizeCombNode (Try p))
305 -- Branch Absorption Law
307 -- trace "Branch Absorption Law" $
309 -- Branch Weakening Law
310 Branch b Empty Empty ->
311 -- trace "Branch Weakening Law" $
312 optimizeCombNode (b :*> Empty)
313 -- Branch Pure Left/Right Laws
314 Branch (Pure (trans -> lr)) l r ->
315 -- trace "Branch Pure Left/Right Law" $
317 Left v -> optimizeCombNode (l :<*> Pure (Hask.Haskell (ValueCode (Value v) c)))
318 where c = Code [|| case $$(getCode lr) of Left x -> x ||]
319 Right v -> optimizeCombNode (r :<*> Pure (Hask.Haskell (ValueCode (Value v) c)))
320 where c = Code [|| case $$(getCode lr) of Right x -> x ||]
321 -- Branch Generalised Identity Law
322 Branch b (Pure (trans -> l)) (Pure (trans -> r)) ->
323 -- trace "Branch Generalised Identity Law" $
324 optimizeCombNode (Hask.Haskell (ValueCode v c) :<$> b)
326 v = Value (either (getValue l) (getValue r))
327 c = Code [|| either $$(getCode l) $$(getCode r) ||]
328 -- Branch Interchange Law
329 Branch (x :*> y) p q ->
330 -- trace "Branch Interchange Law" $
331 optimizeCombNode (x :*> optimizeCombNode (Branch y p q))
332 -- Branch Empty Right Law
334 -- trace " Branch Empty Right Law" $
335 Branch (Pure (Hask.Haskell (ValueCode v c)) :<*> b) Empty l
337 v = Value (either Right Left)
338 c = Code [||either Right Left||]
340 Branch (Branch b Empty (Pure (trans -> lr))) Empty br ->
341 -- trace "Branch Fusion Law" $
342 optimizeCombNode (Branch (optimizeCombNode (Pure (Hask.Haskell (ValueCode (Value v) c)) :<*> b)) Empty br)
345 v (Right r) = case getValue lr r of
348 c = Code [|| \case Left{} -> Left ()
349 Right r -> case $$(getCode lr) r of
351 Right rr -> Right rr ||]
352 -- Branch Distributivity Law
353 f :<$> Branch b l r ->
354 -- trace "Branch Distributivity Law" $
355 optimizeCombNode (Branch b (optimizeCombNode ((Hask..@) (Hask..) f :<$> l)) (optimizeCombNode ((Hask..@) (Hask..) f :<$> r)))
357 -- Match Absorption Law
359 -- trace "Match Absorption Law" $
361 -- Match Weakening Law
363 | all (\case {Empty -> True; _ -> False}) bs ->
364 -- trace "Match Weakening Law" $
365 optimizeCombNode (a :*> Empty)
367 Match ps bs (Pure (trans -> a)) d ->
368 -- trace "Match Pure Law" $
369 foldr (\(trans -> p, b) next -> if getValue p (getValue a) then b else next) d (List.zip ps bs)
370 -- Match Distributivity Law
371 f :<$> Match ps bs a d ->
372 -- trace "Match Distributivity Law" $
373 Match ps (optimizeCombNode . (f :<$>) Functor.<$> bs) a (optimizeCombNode (f :<$> d))
375 {- Possibly useless laws to be tested
378 -- App Definition of *> Law
379 Hask.Flip Hask.:@ Hask.Const :<$> p :<*> q ->
380 -- trace "EXTRALAW: App Definition of *> Law" $
382 -- App Definition of <* Law
383 Hask.Const :<$> p :<*> q ->
384 -- trace "EXTRALAW: App Definition of <* Law" $
387 -- Functor Composition Law
388 -- (a shortcut that could also have been be caught
389 -- by the Composition Law and Homomorphism Law)
391 -- trace "EXTRALAW: Functor Composition Law" $
392 optimizeCombNode ((Hask.:.) Hask.:@ f Hask.:@ g :<$> p)
393 -- Applicable Failure Weakening Law
395 -- trace "EXTRALAW: App Failure Weakening Law" $
396 optimizeCombNode (u :*> Empty)
398 -- trace "EXTRALAW: Try Interchange Right Law" $
399 optimizeCombNode (optimizeCombNode (Try p) :$> x)
400 -- App Reassociation Law 1
402 -- trace "EXTRALAW: App Reassociation Law 1" $
403 optimizeCombNode (u :*> optimizeCombNode (v :<*> w))
404 -- App Reassociation Law 2
406 -- trace "EXTRALAW: App Reassociation Law 2" $
407 optimizeCombNode (optimizeCombNode (u :<*> v) :<* w)
408 -- App Right Associativity Law
410 -- trace "EXTRALAW: App Right Associativity Law" $
411 optimizeCombNode (optimizeCombNode (u :*> v) :*> w)
412 -- App Reassociation Law 3
414 -- trace "EXTRALAW: App Reassociation Law 3" $
415 optimizeCombNode (optimizeCombNode (u :<*> Pure x) :<* v)
418 optimizeCombNode (optimizeCombNode (Look p) :$> x)
419 NegLook (p :$> _) -> optimizeCombNode (NegLook p)
421 -- Pure merge optimisation
422 -- Pure x :<*> Pure y -> Pure (x Hask.:@ y)