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.Either (Either(..), either)
9 import Data.Eq (Eq(..))
10 import Data.Foldable (all, foldr)
11 import Data.Function ((.))
12 import Data.Kind (Type)
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.Grammar.Pure (ValueCode(..), Value(..), getValue, getCode)
19 import Symantic.Univariant.Letable
20 import Symantic.Univariant.Trans
21 import qualified Symantic.Parser.Grammar.Pure as H
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 :: Type -> Type) a where
37 Pure :: H.CombPure a -> Comb repr a
39 Satisfiable repr tok =>
41 H.CombPure (tok -> Bool) -> Comb repr tok
42 Item :: Satisfiable repr tok => Comb repr tok
43 Try :: Comb repr a -> Comb repr a
44 Look :: Comb repr a -> Comb repr a
45 NegLook :: Comb repr a -> Comb repr ()
47 (:<*>) :: Comb repr (a -> b) -> Comb repr a -> Comb repr b
48 (:<|>) :: Comb repr a -> Comb repr a -> Comb repr a
51 Comb repr (Either a b) ->
52 Comb repr (a -> c) -> Comb repr (b -> c) -> Comb repr c
54 [H.CombPure (a -> Bool)] ->
55 [Comb repr b] -> Comb repr a -> Comb repr b -> Comb repr b
56 ChainPre :: Comb repr (a -> a) -> Comb repr a -> Comb repr a
57 ChainPost :: Comb repr a -> Comb repr (a -> a) -> Comb repr a
58 Def :: TH.Name -> Comb repr a -> Comb repr a
59 Ref :: Bool -> TH.Name -> Comb repr a
61 pattern (:<$>) :: H.CombPure (a -> b) -> Comb repr a -> Comb repr b
62 pattern (:$>) :: Comb repr a -> H.CombPure b -> Comb repr b
63 pattern (:<$) :: H.CombPure a -> Comb repr b -> Comb repr a
64 pattern (:*>) :: Comb repr a -> Comb repr b -> Comb repr b
65 pattern (:<*) :: Comb repr a -> Comb repr b -> Comb repr a
66 pattern x :<$> p = Pure x :<*> p
67 pattern p :$> x = p :*> Pure x
68 pattern x :<$ p = Pure x :<* p
69 pattern x :<* p = H.Const :<$> x :<*> p
70 pattern p :*> x = H.Id :<$ p :<*> x
73 infixl 4 :<*>, :<*, :*>
74 infixl 4 :<$>, :<$, :$>
76 instance Applicable (Comb repr) where
79 instance Alternable (Comb repr) where
83 instance Selectable (Comb repr) where
85 instance Matchable (Comb repr) where
87 instance Foldable (Comb repr) where
90 instance Satisfiable repr tok => Satisfiable (Comb repr) tok where
92 instance Lookable (Comb repr) where
96 instance Letable TH.Name (Comb repr) where
99 instance MakeLetName TH.Name where
100 makeLetName _ = TH.qNewName "name"
102 -- Pattern-matchable 'Comb'inators keep enough structure
103 -- to have some of the symantics producing them interpreted again
104 -- (eg. after being modified by 'optimizeComb').
105 type instance Output (Comb repr) = repr
113 , Letable TH.Name repr
114 ) => Trans (Comb repr) repr where
117 Satisfy es p -> satisfy es p
119 Try x -> try (trans x)
120 Look x -> look (trans x)
121 NegLook x -> negLook (trans x)
123 x :<*> y -> trans x <*> trans y
124 x :<|> y -> trans x <|> trans y
126 Branch lr l r -> branch (trans lr) (trans l) (trans r)
127 Match ps bs a b -> conditional ps (trans Functor.<$> bs) (trans a) (trans b)
128 ChainPre x y -> chainPre (trans x) (trans y)
129 ChainPost x y -> chainPost (trans x) (trans y)
130 Def n x -> def n (trans x)
133 -- * Type 'OptimizeComb'
134 -- Bottom-up application of 'optimizeCombNode'.
135 newtype OptimizeComb letName repr a =
136 OptimizeComb { unOptimizeComb :: Comb repr a }
139 Trans (OptimizeComb TH.Name repr) repr =>
140 OptimizeComb TH.Name repr a -> repr a
143 Trans (Comb repr) repr =>
144 Trans (OptimizeComb letName repr) repr where
145 trans = trans . unOptimizeComb
147 type instance Output (OptimizeComb _letName repr) = Comb repr
148 instance Trans (OptimizeComb letName repr) (Comb repr) where
149 trans = unOptimizeComb
150 instance Trans (Comb repr) (OptimizeComb letName repr) where
151 trans = OptimizeComb . optimizeCombNode
152 instance Trans1 (Comb repr) (OptimizeComb letName repr)
153 instance Trans2 (Comb repr) (OptimizeComb letName repr)
154 instance Trans3 (Comb repr) (OptimizeComb letName repr)
157 Letable letName (Comb repr) =>
158 Letable letName (OptimizeComb letName repr) where
159 -- Disable useless calls to 'optimizeCombNode'
160 -- because 'Def' or 'Ref' have no matching in it.
161 def n = OptimizeComb . def n . unOptimizeComb
162 ref r n = OptimizeComb (ref r n)
163 instance Comb.Applicable (OptimizeComb letName repr)
164 instance Comb.Alternable (OptimizeComb letName repr)
165 instance Comb.Satisfiable repr tok =>
166 Comb.Satisfiable (OptimizeComb letName repr) tok
167 instance Comb.Selectable (OptimizeComb letName repr)
168 instance Comb.Matchable (OptimizeComb letName repr)
169 instance Comb.Lookable (OptimizeComb letName repr)
170 instance Comb.Foldable (OptimizeComb letName repr)
172 optimizeCombNode :: Comb repr a -> Comb repr a
173 optimizeCombNode = \case
174 -- Functor Identity Law
176 -- trace "Functor Identity Law" $
178 -- Functor Commutativity Law
180 -- trace "Functor Commutativity Law" $
181 optimizeCombNode (u :$> x)
182 -- Functor Flip Const Law
183 H.Flip H.:@ H.Const :<$> u ->
184 -- trace "Functor Flip Const Law" $
185 optimizeCombNode (u :*> Pure H.Id)
186 -- Functor Homomorphism Law
188 -- trace "Functor Homomorphism Law" $
191 -- App Right Absorption Law
193 -- trace "App Right Absorption Law" $
195 -- App Left Absorption Law
197 -- In Parsley: this is only a weakening to u :*> Empty
198 -- but here :*> is an alias to :<*>
199 -- hence it would loop on itself forever.
200 -- trace "App Left Absorption Law" $
202 -- App Composition Law
204 -- trace "App Composition Law" $
205 optimizeCombNode (optimizeCombNode (optimizeCombNode ((H.:.) :<$> u) :<*> v) :<*> w)
206 -- App Interchange Law
208 -- trace "App Interchange Law" $
209 optimizeCombNode (H.Flip H..@ (H.:$) H..@ x :<$> u)
210 -- App Left Absorption Law
212 -- trace "App Left Absorption Law" $
214 -- App Right Absorption Law
216 -- trace "App Right Absorption Law" $
218 -- App Pure Left Identity Law
220 -- trace "App Pure Left Identity Law" $
222 -- App Functor Left Identity Law
224 -- trace "App Functor Left Identity Law" $
226 -- App Pure Right Identity Law
228 -- trace "App Pure Right Identity Law" $
230 -- App Functor Right Identity Law
232 -- trace "App Functor Right Identity Law" $
233 optimizeCombNode (u :<* v)
234 -- App Left Associativity Law
236 -- trace "App Left Associativity Law" $
237 optimizeCombNode (u :<* optimizeCombNode (v :<* w))
239 -- Alt Left CatchFail Law
241 -- trace "Alt Left CatchFail Law" $
243 -- Alt Left Neutral Law
245 -- trace "Alt Left Neutral Law" $
247 -- All Right Neutral Law
249 -- trace "Alt Right Neutral Law" $
251 -- Alt Associativity Law
253 -- trace "Alt Associativity Law" $
254 u :<|> optimizeCombNode (v :<|> w)
258 -- trace "Look Pure Law" $
262 -- trace "Look Empty Law" $
266 -- trace "NegLook Pure Law" $
270 -- trace "NegLook Dead Law" $
272 -- NegLook Double Negation Law
273 NegLook (NegLook p) ->
274 -- trace "NegLook Double Negation Law" $
275 optimizeCombNode (Look (Try p) :*> Pure H.unit)
276 -- NegLook Zero Consumption Law
278 -- trace "NegLook Zero Consumption Law" $
279 optimizeCombNode (NegLook p)
282 -- trace "Look Idempotence Law" $
284 -- Look Right Identity Law
286 -- trace "Look Right Identity Law" $
287 optimizeCombNode (NegLook p)
288 -- Look Left Identity Law
290 -- trace "Look Left Identity Law" $
292 -- NegLook Transparency Law
293 NegLook (Try p :<|> q) ->
294 -- trace "NegLook Transparency Law" $
295 optimizeCombNode (optimizeCombNode (NegLook p) :*> optimizeCombNode (NegLook q))
296 -- Look Distributivity Law
297 Look p :<|> Look q ->
298 -- trace "Look Distributivity Law" $
299 optimizeCombNode (Look (optimizeCombNode (Try p :<|> q)))
300 -- Look Interchange Law
302 -- trace "Look Interchange Law" $
303 optimizeCombNode (f :<$> optimizeCombNode (Look p))
304 -- NegLook Idempotence Right Law
305 NegLook (_ :<$> p) ->
306 -- trace "NegLook Idempotence Law" $
307 optimizeCombNode (NegLook p)
308 -- Try Interchange Law
310 -- trace "Try Interchange Law" $
311 optimizeCombNode (f :<$> optimizeCombNode (Try p))
313 -- Branch Absorption Law
315 -- trace "Branch Absorption Law" $
317 -- Branch Weakening Law
318 Branch b Empty Empty ->
319 -- trace "Branch Weakening Law" $
320 optimizeCombNode (b :*> Empty)
321 -- Branch Pure Left/Right Laws
322 Branch (Pure (trans -> lr)) l r ->
323 -- trace "Branch Pure Left/Right Law" $
325 Left v -> optimizeCombNode (l :<*> Pure (H.CombPure (ValueCode (Value v) c)))
326 where c = [|| case $$(getCode lr) of Left x -> x ||]
327 Right v -> optimizeCombNode (r :<*> Pure (H.CombPure (ValueCode (Value v) c)))
328 where c = [|| case $$(getCode lr) of Right x -> x ||]
329 -- Branch Generalised Identity Law
330 Branch b (Pure (trans -> l)) (Pure (trans -> r)) ->
331 -- trace "Branch Generalised Identity Law" $
332 optimizeCombNode (H.CombPure (ValueCode v c) :<$> b)
334 v = Value (either (getValue l) (getValue r))
335 c = [|| either $$(getCode l) $$(getCode r) ||]
336 -- Branch Interchange Law
337 Branch (x :*> y) p q ->
338 -- trace "Branch Interchange Law" $
339 optimizeCombNode (x :*> optimizeCombNode (Branch y p q))
340 -- Branch Empty Right Law
342 -- trace " Branch Empty Right Law" $
343 Branch (Pure (H.CombPure (ValueCode v c)) :<*> b) Empty l
345 v = Value (either Right Left)
346 c = [||either Right Left||]
348 Branch (Branch b Empty (Pure (trans -> lr))) Empty br ->
349 -- trace "Branch Fusion Law" $
350 optimizeCombNode (Branch (optimizeCombNode (Pure (H.CombPure (ValueCode (Value v) c)) :<*> b))
354 v (Right r) = case getValue lr r of
357 c = [|| \case Left{} -> Left ()
358 Right r -> case $$(getCode lr) r of
360 Right rr -> Right rr ||]
361 -- Branch Distributivity Law
362 f :<$> Branch b l r ->
363 -- trace "Branch Distributivity Law" $
364 optimizeCombNode (Branch b (optimizeCombNode ((H..@) (H..) f :<$> l))
365 (optimizeCombNode ((H..@) (H..) f :<$> r)))
367 -- Match Absorption Law
369 -- trace "Match Absorption Law" $
371 -- Match Weakening Law
373 | all (\case {Empty -> True; _ -> False}) bs ->
374 -- trace "Match Weakening Law" $
375 optimizeCombNode (a :*> Empty)
377 Match ps bs (Pure (trans -> a)) d ->
378 -- trace "Match Pure Law" $
379 foldr (\(trans -> p, b) next ->
380 if getValue p (getValue a) then b else next
382 -- Match Distributivity Law
383 f :<$> Match ps bs a d ->
384 -- trace "Match Distributivity Law" $
385 Match ps (optimizeCombNode . (f :<$>) Functor.<$> bs) a
386 (optimizeCombNode (f :<$> d))
388 {- Possibly useless laws to be tested
391 -- App Definition of *> Law
392 H.Flip H..@ H.Const :<$> p :<*> q ->
393 -- -- trace "EXTRALAW: App Definition of *> Law" $
395 -- App Definition of <* Law
396 H.Const :<$> p :<*> q ->
397 -- -- trace "EXTRALAW: App Definition of <* Law" $
400 -- Functor Composition Law
401 -- (a shortcut that could also have been be caught
402 -- by the Composition Law and Homomorphism Law)
404 -- -- trace "EXTRALAW: Functor Composition Law" $
405 optimizeCombNode ((H.:.) H..@ f H..@ g :<$> p)
406 -- Applicable Failure Weakening Law
408 -- -- trace "EXTRALAW: App Failure Weakening Law" $
409 optimizeCombNode (u :*> Empty)
411 -- -- trace "EXTRALAW: Try Interchange Right Law" $
412 optimizeCombNode (optimizeCombNode (Try p) :$> x)
413 -- App Reassociation Law 1
415 -- -- trace "EXTRALAW: App Reassociation Law 1" $
416 optimizeCombNode (u :*> optimizeCombNode (v :<*> w))
417 -- App Reassociation Law 2
419 -- -- trace "EXTRALAW: App Reassociation Law 2" $
420 optimizeCombNode (optimizeCombNode (u :<*> v) :<* w)
421 -- App Right Associativity Law
423 -- -- trace "EXTRALAW: App Right Associativity Law" $
424 optimizeCombNode (optimizeCombNode (u :*> v) :*> w)
425 -- App Reassociation Law 3
427 -- -- trace "EXTRALAW: App Reassociation Law 3" $
428 optimizeCombNode (optimizeCombNode (u :<*> Pure x) :<* v)
431 optimizeCombNode (optimizeCombNode (Look p) :$> x)
432 NegLook (p :$> _) -> optimizeCombNode (NegLook p)
434 -- NegLook Absorption Law
436 -- trace "EXTRALAW: Neglook Absorption Law" $
437 optimizeCombNode (optimizeCombNode (p :<*> Pure H.unit) :<* NegLook q)
438 -- Infinite loop, because :<* expands to :<*>