1 {-# LANGUAGE PatternSynonyms #-}
2 {-# LANGUAGE TemplateHaskell #-}
3 {-# LANGUAGE NoPolyKinds #-}
4 {-# LANGUAGE ViewPatterns #-}
5 {-# LANGUAGE UndecidableInstances #-}
6 {-# OPTIONS_GHC -fno-warn-orphans #-}
7 module Symantic.Parser.Grammar.Optimize where
9 import Data.Bool (Bool(..))
10 import Data.Char (Char)
11 import Data.Either (Either(..), either)
12 import Data.Eq (Eq(..))
13 import Data.Foldable (all, foldr)
14 import Data.Function ((.))
15 import qualified Data.Functor as Functor
16 import qualified Data.List as List
18 import Symantic.Parser.Grammar.Combinators as Comb
19 import Symantic.Parser.Staging (ValueCode(..), Value(..), Code(..), getValue, getCode)
20 import Symantic.Univariant.Letable
21 import Symantic.Univariant.Trans
22 import qualified Language.Haskell.TH.Syntax as TH
23 import qualified Symantic.Parser.Staging as Hask
25 -- import Debug.Trace (trace)
28 -- | Pattern-matchable 'Comb'inators of the grammar.
29 -- @(repr)@ is not strictly necessary since it's only a phantom type
30 -- (no constructor use it as a value), but having it:
32 -- 1. emphasizes that those 'Comb'inators will be 'trans'formed again
33 -- (eg. in 'DumpComb' or 'Instr'uctions).
35 -- 2. Avoid overlapping instances between
36 -- @('Trans' ('Comb' repr) repr)@ and
37 -- @('Trans' ('Comb' repr) ('OptimizeComb' letName repr))@
38 data Comb (repr :: * -> *) a where
39 Pure :: Hask.Haskell a -> Comb repr a
40 Satisfy :: Hask.Haskell (Char -> Bool) -> Comb repr Char
41 Item :: Comb repr Char
42 Try :: Comb repr a -> Comb repr a
43 Look :: Comb repr a -> Comb repr a
44 NegLook :: Comb repr a -> Comb repr ()
45 (:<*>) :: Comb repr (a -> b) -> Comb repr a -> Comb repr b
46 (:<|>) :: Comb repr a -> Comb repr a -> Comb repr a
48 Branch :: Comb repr (Either a b) -> Comb repr (a -> c) -> Comb repr (b -> c) -> Comb repr c
49 Match :: Eq a => [Hask.Haskell (a -> Bool)] -> [Comb repr b] -> Comb repr a -> Comb repr b -> Comb repr b
50 ChainPre :: Comb repr (a -> a) -> Comb repr a -> Comb repr a
51 ChainPost :: Comb repr a -> Comb repr (a -> a) -> Comb repr a
52 Def :: TH.Name -> Comb repr a -> Comb repr a
53 Ref :: Bool -> TH.Name -> Comb repr a
55 pattern (:<$>) :: Hask.Haskell (a -> b) -> Comb repr a -> Comb repr b
56 pattern (:$>) :: Comb repr a -> Hask.Haskell b -> Comb repr b
57 pattern (:<$) :: Hask.Haskell a -> Comb repr b -> Comb repr a
58 pattern (:*>) :: Comb repr a -> Comb repr b -> Comb repr b
59 pattern (:<*) :: Comb repr a -> Comb repr b -> Comb repr a
60 pattern x :<$> p = Pure x :<*> p
61 pattern p :$> x = p :*> Pure x
62 pattern x :<$ p = Pure x :<* p
63 pattern x :<* p = Hask.Const :<$> x :<*> p
64 pattern p :*> x = Hask.Id :<$ p :<*> x
67 infixl 4 :<*>, :<*, :*>
68 infixl 4 :<$>, :<$, :$>
70 instance Applicable (Comb repr) where
73 instance Alternable (Comb repr) where
77 instance Selectable (Comb repr) where
79 instance Matchable (Comb repr) where
81 instance Foldable (Comb repr) where
84 instance Charable (Comb repr) where
86 instance Lookable (Comb repr) where
89 instance Letable TH.Name (Comb repr) where
92 instance MakeLetName TH.Name where
93 makeLetName _ = TH.qNewName "let"
95 -- Pattern-matchable 'Comb'inators keep enough structure
96 -- to have the symantics producing them interpreted again
97 -- (eg. after being modified by 'optimizeComb').
98 type instance Output (Comb repr) = repr
107 , Letable TH.Name repr
108 ) => Trans (Comb repr) repr where
111 Satisfy p -> satisfy p
113 Try x -> try (trans x)
114 Look x -> look (trans x)
115 NegLook x -> negLook (trans x)
116 x :<*> y -> trans x <*> trans y
117 x :<|> y -> trans x <|> trans y
119 Branch lr l r -> branch (trans lr) (trans l) (trans r)
120 Match ps bs a b -> conditional ps (trans Functor.<$> bs) (trans a) (trans b)
121 ChainPre x y -> chainPre (trans x) (trans y)
122 ChainPost x y -> chainPost (trans x) (trans y)
123 Def n x -> def n (trans x)
126 -- * Type 'OptimizeComb'
127 -- Bottom-up application of 'optimizeCombNode'.
128 newtype OptimizeComb letName repr a = OptimizeComb { unOptimizeComb :: Comb repr a }
131 Trans (OptimizeComb TH.Name repr) repr =>
132 OptimizeComb TH.Name repr a -> repr a
135 Trans (Comb repr) repr =>
136 Trans (OptimizeComb letName repr) repr where
137 trans = trans . unOptimizeComb
139 type instance Output (OptimizeComb letName repr) = Comb repr
140 instance Trans (OptimizeComb letName repr) (Comb repr) where
141 trans = unOptimizeComb
142 instance Trans (Comb repr) (OptimizeComb letName repr) where
143 trans = OptimizeComb . optimizeCombNode
144 instance Trans1 (Comb repr) (OptimizeComb letName repr)
145 instance Trans2 (Comb repr) (OptimizeComb letName repr)
146 instance Trans3 (Comb repr) (OptimizeComb letName repr)
149 Letable letName (Comb repr) =>
150 Letable letName (OptimizeComb letName repr) where
151 -- Disable useless calls to 'optimizeCombNode'
152 -- because 'Def' or 'Ref' have no matching in it.
153 def n = OptimizeComb . def n . unOptimizeComb
154 ref r n = OptimizeComb (ref r n)
155 instance Comb.Applicable (OptimizeComb letName repr)
156 instance Comb.Alternable (OptimizeComb letName repr)
157 instance Comb.Charable (OptimizeComb letName repr)
158 instance Comb.Selectable (OptimizeComb letName repr)
159 instance Comb.Matchable (OptimizeComb letName repr)
160 instance Comb.Lookable (OptimizeComb letName repr)
161 instance Comb.Foldable (OptimizeComb letName repr)
163 optimizeCombNode :: Comb repr a -> Comb repr a
164 optimizeCombNode = \case
165 -- Functor Identity Law
167 -- trace "Functor Identity Law" $
169 -- Functor Commutativity Law
171 -- trace "Functor Commutativity Law" $
172 optimizeCombNode (u :$> x)
173 -- Functor Flip Const Law
174 Hask.Flip Hask.:@ Hask.Const :<$> u ->
175 -- trace "Functor Flip Const Law" $
176 optimizeCombNode (u :*> Pure Hask.Id)
177 -- Functor Homomorphism Law
179 -- trace "Functor Homomorphism Law" $
182 -- App Right Absorption Law
184 -- trace "App Right Absorption Law" $
187 -- In Parsley: this is only a weakening to u :*> Empty
188 -- but here :*> is an alias to :<*>
189 -- hence it would loop on itself forever.
190 -- trace "App Left Absorption Law" $
192 -- App Composition Law
194 -- trace "App Composition Law" $
195 optimizeCombNode (optimizeCombNode (optimizeCombNode ((Hask.:.) :<$> u) :<*> v) :<*> w)
196 -- App Interchange Law
198 -- trace "App Interchange Law" $
199 optimizeCombNode (Hask.Flip Hask.:@ (Hask.:$) Hask.:@ x :<$> u)
200 -- App Left Absorption Law
202 -- trace "App Left Absorption Law" $
204 -- App Right Absorption Law
206 -- trace "App Right Absorption Law" $
208 -- App Pure Left Identity Law
210 -- trace "App Pure Left Identity Law" $
212 -- App Functor Left Identity Law
214 -- trace "App Functor Left Identity Law" $
216 -- App Pure Right Identity Law
218 -- trace "App Pure Right Identity Law" $
220 -- App Functor Right Identity Law
222 -- trace "App Functor Right Identity Law" $
223 optimizeCombNode (u :<* v)
224 -- App Left Associativity Law
226 -- trace "App Left Associativity Law" $
227 optimizeCombNode (u :<* optimizeCombNode (v :<* w))
229 -- Alt Left Catch Law
231 -- trace "Alt Left Catch Law" $
233 -- Alt Left Neutral Law
235 -- trace "Alt Left Neutral Law" $
237 -- All Right Neutral Law
239 -- trace "Alt Right Neutral Law" $
241 -- Alt Associativity Law
243 -- trace "Alt Associativity Law" $
244 u :<|> optimizeCombNode (v :<|> w)
248 -- trace "Look Pure Law" $
252 -- trace "Look Empty Law" $
256 -- trace "NegLook Pure Law" $
260 -- trace "NegLook Dead Law" $
262 -- NegLook Double Negation Law
263 NegLook (NegLook p) ->
264 -- trace "NegLook Double Negation Law" $
265 optimizeCombNode (Look (Try p) :*> Pure Hask.unit)
266 -- NegLook Zero Consumption Law
268 -- trace "NegLook Zero Consumption Law" $
269 optimizeCombNode (NegLook p)
272 -- trace "Look Idempotence Law" $
274 -- Look Right Identity Law
276 -- trace "Look Right Identity Law" $
277 optimizeCombNode (NegLook p)
278 -- Look Left Identity Law
280 -- trace "Look Left Identity Law" $
282 -- NegLook Transparency Law
283 NegLook (Try p :<|> q) ->
284 -- trace "NegLook Transparency Law" $
285 optimizeCombNode (optimizeCombNode (NegLook p) :*> optimizeCombNode (NegLook q))
286 -- Look Distributivity Law
287 Look p :<|> Look q ->
288 -- trace "Look Distributivity Law" $
289 optimizeCombNode (Look (optimizeCombNode (Try p :<|> q)))
290 -- Look Interchange Law
292 -- trace "Look Interchange Law" $
293 optimizeCombNode (f :<$> optimizeCombNode (Look p))
294 -- NegLook Absorption Law
296 -- trace "Neglook Absorption Law" $
297 optimizeCombNode (optimizeCombNode (p :<*> Pure Hask.unit) :<* NegLook q)
298 -- NegLook Idempotence Right Law
299 NegLook (_ :<$> p) ->
300 -- trace "NegLook Idempotence Law" $
301 optimizeCombNode (NegLook p)
302 -- Try Interchange Law
304 -- trace "Try Interchange Law" $
305 optimizeCombNode (f :<$> optimizeCombNode (Try p))
307 -- Branch Absorption Law
309 -- trace "Branch Absorption Law" $
311 -- Branch Weakening Law
312 Branch b Empty Empty ->
313 -- trace "Branch Weakening Law" $
314 optimizeCombNode (b :*> Empty)
315 -- Branch Pure Left/Right Laws
316 Branch (Pure (trans -> lr)) l r ->
317 -- trace "Branch Pure Left/Right Law" $
319 Left v -> optimizeCombNode (l :<*> Pure (Hask.Haskell (ValueCode (Value v) c)))
320 where c = Code [|| case $$(getCode lr) of Left x -> x ||]
321 Right v -> optimizeCombNode (r :<*> Pure (Hask.Haskell (ValueCode (Value v) c)))
322 where c = Code [|| case $$(getCode lr) of Right x -> x ||]
323 -- Branch Generalised Identity Law
324 Branch b (Pure (trans -> l)) (Pure (trans -> r)) ->
325 -- trace "Branch Generalised Identity Law" $
326 optimizeCombNode (Hask.Haskell (ValueCode v c) :<$> b)
328 v = Value (either (getValue l) (getValue r))
329 c = Code [|| either $$(getCode l) $$(getCode r) ||]
330 -- Branch Interchange Law
331 Branch (x :*> y) p q ->
332 -- trace "Branch Interchange Law" $
333 optimizeCombNode (x :*> optimizeCombNode (Branch y p q))
334 -- Branch Empty Right Law
336 -- trace " Branch Empty Right Law" $
337 Branch (Pure (Hask.Haskell (ValueCode v c)) :<*> b) Empty l
339 v = Value (either Right Left)
340 c = Code [||either Right Left||]
342 Branch (Branch b Empty (Pure (trans -> lr))) Empty br ->
343 -- trace "Branch Fusion Law" $
344 optimizeCombNode (Branch (optimizeCombNode (Pure (Hask.Haskell (ValueCode (Value v) c)) :<*> b)) Empty br)
347 v (Right r) = case getValue lr r of
350 c = Code [|| \case Left{} -> Left ()
351 Right r -> case $$(getCode lr) r of
353 Right rr -> Right rr ||]
354 -- Branch Distributivity Law
355 f :<$> Branch b l r ->
356 -- trace "Branch Distributivity Law" $
357 optimizeCombNode (Branch b (optimizeCombNode ((Hask..@) (Hask..) f :<$> l)) (optimizeCombNode ((Hask..@) (Hask..) f :<$> r)))
359 -- Match Absorption Law
361 -- trace "Match Absorption Law" $
363 -- Match Weakening Law
365 | all (\case {Empty -> True; _ -> False}) bs ->
366 -- trace "Match Weakening Law" $
367 optimizeCombNode (a :*> Empty)
369 Match ps bs (Pure (trans -> a)) d ->
370 -- trace "Match Pure Law" $
371 foldr (\(trans -> p, b) next -> if getValue p (getValue a) then b else next) d (List.zip ps bs)
372 -- Match Distributivity Law
373 f :<$> Match ps bs a d ->
374 -- trace "Match Distributivity Law" $
375 Match ps (optimizeCombNode . (f :<$>) Functor.<$> bs) a (optimizeCombNode (f :<$> d))
377 {- Possibly useless laws to be tested
380 -- App Definition of *> Law
381 Hask.Flip Hask.:@ Hask.Const :<$> p :<*> q ->
382 -- trace "EXTRALAW: App Definition of *> Law" $
384 -- App Definition of <* Law
385 Hask.Const :<$> p :<*> q ->
386 -- trace "EXTRALAW: App Definition of <* Law" $
389 -- Functor Composition Law
390 -- (a shortcut that could also have been be caught
391 -- by the Composition Law and Homomorphism Law)
393 -- trace "EXTRALAW: Functor Composition Law" $
394 optimizeCombNode ((Hask.:.) Hask.:@ f Hask.:@ g :<$> p)
395 -- Applicable Failure Weakening Law
397 -- trace "EXTRALAW: App Failure Weakening Law" $
398 optimizeCombNode (u :*> Empty)
400 -- trace "EXTRALAW: Try Interchange Right Law" $
401 optimizeCombNode (optimizeCombNode (Try p) :$> x)
402 -- App Reassociation Law 1
404 -- trace "EXTRALAW: App Reassociation Law 1" $
405 optimizeCombNode (u :*> optimizeCombNode (v :<*> w))
406 -- App Reassociation Law 2
408 -- trace "EXTRALAW: App Reassociation Law 2" $
409 optimizeCombNode (optimizeCombNode (u :<*> v) :<* w)
410 -- App Right Associativity Law
412 -- trace "EXTRALAW: App Right Associativity Law" $
413 optimizeCombNode (optimizeCombNode (u :*> v) :*> w)
414 -- App Reassociation Law 3
416 -- trace "EXTRALAW: App Reassociation Law 3" $
417 optimizeCombNode (optimizeCombNode (u :<*> Pure x) :<* v)
420 optimizeCombNode (optimizeCombNode (Look p) :$> x)
421 NegLook (p :$> _) -> optimizeCombNode (NegLook p)
423 -- Pure merge optimisation
424 -- Pure x :<*> Pure y -> Pure (x Hask.:@ y)