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.Haskell (ValueCode(..), Value(..), getValue, code)
19 import Symantic.Univariant.Letable
20 import Symantic.Univariant.Trans
21 import qualified Symantic.Parser.Haskell 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.Haskell a -> Comb repr a
39 Satisfiable repr tok =>
41 H.Haskell (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.Haskell (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.Haskell (a -> b) -> Comb repr a -> Comb repr b
62 pattern (:$>) :: Comb repr a -> H.Haskell b -> Comb repr b
63 pattern (:<$) :: H.Haskell 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" $
196 -- In Parsley: this is only a weakening to u :*> Empty
197 -- but here :*> is an alias to :<*>
198 -- hence it would loop on itself forever.
199 -- trace "App Left Absorption Law" $
201 -- App Composition Law
203 -- trace "App Composition Law" $
204 optimizeCombNode (optimizeCombNode (optimizeCombNode ((H.:.) :<$> u) :<*> v) :<*> w)
205 -- App Interchange Law
207 -- trace "App Interchange Law" $
208 optimizeCombNode (H.Flip H..@ (H.:$) H..@ x :<$> u)
209 -- App Left Absorption Law
211 -- trace "App Left Absorption Law" $
213 -- App Right Absorption Law
215 -- trace "App Right Absorption Law" $
217 -- App Pure Left Identity Law
219 -- trace "App Pure Left Identity Law" $
221 -- App Functor Left Identity Law
223 -- trace "App Functor Left Identity Law" $
225 -- App Pure Right Identity Law
227 -- trace "App Pure Right Identity Law" $
229 -- App Functor Right Identity Law
231 -- trace "App Functor Right Identity Law" $
232 optimizeCombNode (u :<* v)
233 -- App Left Associativity Law
235 -- trace "App Left Associativity Law" $
236 optimizeCombNode (u :<* optimizeCombNode (v :<* w))
238 -- Alt Left CatchFail Law
240 -- trace "Alt Left CatchFail Law" $
242 -- Alt Left Neutral Law
244 -- trace "Alt Left Neutral Law" $
246 -- All Right Neutral Law
248 -- trace "Alt Right Neutral Law" $
250 -- Alt Associativity Law
252 -- trace "Alt Associativity Law" $
253 u :<|> optimizeCombNode (v :<|> w)
257 -- trace "Look Pure Law" $
261 -- trace "Look Empty Law" $
265 -- trace "NegLook Pure Law" $
269 -- trace "NegLook Dead Law" $
271 -- NegLook Double Negation Law
272 NegLook (NegLook p) ->
273 -- trace "NegLook Double Negation Law" $
274 optimizeCombNode (Look (Try p) :*> Pure H.unit)
275 -- NegLook Zero Consumption Law
277 -- trace "NegLook Zero Consumption Law" $
278 optimizeCombNode (NegLook p)
281 -- trace "Look Idempotence Law" $
283 -- Look Right Identity Law
285 -- trace "Look Right Identity Law" $
286 optimizeCombNode (NegLook p)
287 -- Look Left Identity Law
289 -- trace "Look Left Identity Law" $
291 -- NegLook Transparency Law
292 NegLook (Try p :<|> q) ->
293 -- trace "NegLook Transparency Law" $
294 optimizeCombNode (optimizeCombNode (NegLook p) :*> optimizeCombNode (NegLook q))
295 -- Look Distributivity Law
296 Look p :<|> Look q ->
297 -- trace "Look Distributivity Law" $
298 optimizeCombNode (Look (optimizeCombNode (Try p :<|> q)))
299 -- Look Interchange Law
301 -- trace "Look Interchange Law" $
302 optimizeCombNode (f :<$> optimizeCombNode (Look p))
303 -- NegLook Idempotence Right Law
304 NegLook (_ :<$> p) ->
305 -- trace "NegLook Idempotence Law" $
306 optimizeCombNode (NegLook p)
307 -- Try Interchange Law
309 -- trace "Try Interchange Law" $
310 optimizeCombNode (f :<$> optimizeCombNode (Try p))
312 -- Branch Absorption Law
314 -- trace "Branch Absorption Law" $
316 -- Branch Weakening Law
317 Branch b Empty Empty ->
318 -- trace "Branch Weakening Law" $
319 optimizeCombNode (b :*> Empty)
320 -- Branch Pure Left/Right Laws
321 Branch (Pure (trans -> lr)) l r ->
322 -- trace "Branch Pure Left/Right Law" $
324 Left v -> optimizeCombNode (l :<*> Pure (H.Haskell (ValueCode (Value v) c)))
325 where c = [|| case $$(code lr) of Left x -> x ||]
326 Right v -> optimizeCombNode (r :<*> Pure (H.Haskell (ValueCode (Value v) c)))
327 where c = [|| case $$(code lr) of Right x -> x ||]
328 -- Branch Generalised Identity Law
329 Branch b (Pure (trans -> l)) (Pure (trans -> r)) ->
330 -- trace "Branch Generalised Identity Law" $
331 optimizeCombNode (H.Haskell (ValueCode v c) :<$> b)
333 v = Value (either (getValue l) (getValue r))
334 c = [|| either $$(code l) $$(code r) ||]
335 -- Branch Interchange Law
336 Branch (x :*> y) p q ->
337 -- trace "Branch Interchange Law" $
338 optimizeCombNode (x :*> optimizeCombNode (Branch y p q))
339 -- Branch Empty Right Law
341 -- trace " Branch Empty Right Law" $
342 Branch (Pure (H.Haskell (ValueCode v c)) :<*> b) Empty l
344 v = Value (either Right Left)
345 c = [||either Right Left||]
347 Branch (Branch b Empty (Pure (trans -> lr))) Empty br ->
348 -- trace "Branch Fusion Law" $
349 optimizeCombNode (Branch (optimizeCombNode (Pure (H.Haskell (ValueCode (Value v) c)) :<*> b))
353 v (Right r) = case getValue lr r of
356 c = [|| \case Left{} -> Left ()
357 Right r -> case $$(code lr) r of
359 Right rr -> Right rr ||]
360 -- Branch Distributivity Law
361 f :<$> Branch b l r ->
362 -- trace "Branch Distributivity Law" $
363 optimizeCombNode (Branch b (optimizeCombNode ((H..@) (H..) f :<$> l))
364 (optimizeCombNode ((H..@) (H..) f :<$> r)))
366 -- Match Absorption Law
368 -- trace "Match Absorption Law" $
370 -- Match Weakening Law
372 | all (\case {Empty -> True; _ -> False}) bs ->
373 -- trace "Match Weakening Law" $
374 optimizeCombNode (a :*> Empty)
376 Match ps bs (Pure (trans -> a)) d ->
377 -- trace "Match Pure Law" $
378 foldr (\(trans -> p, b) next ->
379 if getValue p (getValue a) then b else next
381 -- Match Distributivity Law
382 f :<$> Match ps bs a d ->
383 -- trace "Match Distributivity Law" $
384 Match ps (optimizeCombNode . (f :<$>) Functor.<$> bs) a
385 (optimizeCombNode (f :<$> d))
387 {- Possibly useless laws to be tested
390 -- App Definition of *> Law
391 H.Flip H..@ H.Const :<$> p :<*> q ->
392 -- -- trace "EXTRALAW: App Definition of *> Law" $
394 -- App Definition of <* Law
395 H.Const :<$> p :<*> q ->
396 -- -- trace "EXTRALAW: App Definition of <* Law" $
399 -- Functor Composition Law
400 -- (a shortcut that could also have been be caught
401 -- by the Composition Law and Homomorphism Law)
403 -- -- trace "EXTRALAW: Functor Composition Law" $
404 optimizeCombNode ((H.:.) H..@ f H..@ g :<$> p)
405 -- Applicable Failure Weakening Law
407 -- -- trace "EXTRALAW: App Failure Weakening Law" $
408 optimizeCombNode (u :*> Empty)
410 -- -- trace "EXTRALAW: Try Interchange Right Law" $
411 optimizeCombNode (optimizeCombNode (Try p) :$> x)
412 -- App Reassociation Law 1
414 -- -- trace "EXTRALAW: App Reassociation Law 1" $
415 optimizeCombNode (u :*> optimizeCombNode (v :<*> w))
416 -- App Reassociation Law 2
418 -- -- trace "EXTRALAW: App Reassociation Law 2" $
419 optimizeCombNode (optimizeCombNode (u :<*> v) :<* w)
420 -- App Right Associativity Law
422 -- -- trace "EXTRALAW: App Right Associativity Law" $
423 optimizeCombNode (optimizeCombNode (u :*> v) :*> w)
424 -- App Reassociation Law 3
426 -- -- trace "EXTRALAW: App Reassociation Law 3" $
427 optimizeCombNode (optimizeCombNode (u :<*> Pure x) :<* v)
430 optimizeCombNode (optimizeCombNode (Look p) :$> x)
431 NegLook (p :$> _) -> optimizeCombNode (NegLook p)
433 -- NegLook Absorption Law
435 -- trace "EXTRALAW: Neglook Absorption Law" $
436 optimizeCombNode (optimizeCombNode (p :<*> Pure H.unit) :<* NegLook q)
437 -- Infinite loop, because :<* expands to :<*>