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 Data.Kind (Type)
14 import qualified Data.Functor as Functor
15 import qualified Data.List as List
16 import qualified Language.Haskell.TH.Syntax as TH
18 import Symantic.Parser.Grammar.Combinators as Comb
19 import Symantic.Parser.Staging (ValueCode(..), Value(..), getValue, code)
20 import Symantic.Univariant.Letable
21 import Symantic.Univariant.Trans
22 import qualified Symantic.Parser.Staging as H
24 -- import Debug.Trace (trace)
27 -- | Pattern-matchable 'Comb'inators of the grammar.
28 -- @(repr)@ is not strictly necessary since it's only a phantom type
29 -- (no constructor use it as a value), but having it:
31 -- 1. emphasizes that those 'Comb'inators will be 'trans'formed again
32 -- (eg. in 'DumpComb' or 'Instr'uctions).
34 -- 2. Avoid overlapping instances between
35 -- @('Trans' ('Comb' repr) repr)@ and
36 -- @('Trans' ('Comb' repr) ('OptimizeComb' letName repr))@
37 data Comb (repr :: Type -> Type) a where
38 Pure :: H.Haskell a -> Comb repr a
39 Satisfy :: H.Haskell (Char -> Bool) -> Comb repr Char
40 Item :: Comb repr Char
41 Try :: Comb repr a -> Comb repr a
42 Look :: Comb repr a -> Comb repr a
43 NegLook :: Comb repr a -> Comb repr ()
44 (:<*>) :: Comb repr (a -> b) -> Comb repr a -> Comb repr b
45 (:<|>) :: Comb repr a -> Comb repr a -> Comb repr a
47 Branch :: Comb repr (Either a b) -> Comb repr (a -> c) -> Comb repr (b -> c) -> Comb repr c
48 Match :: Eq a => [H.Haskell (a -> Bool)] -> [Comb repr b] -> Comb repr a -> Comb repr b -> Comb repr b
49 ChainPre :: Comb repr (a -> a) -> Comb repr a -> Comb repr a
50 ChainPost :: Comb repr a -> Comb repr (a -> a) -> Comb repr a
51 Def :: TH.Name -> Comb repr a -> Comb repr a
52 Ref :: Bool -> TH.Name -> Comb repr a
54 pattern (:<$>) :: H.Haskell (a -> b) -> Comb repr a -> Comb repr b
55 pattern (:$>) :: Comb repr a -> H.Haskell b -> Comb repr b
56 pattern (:<$) :: H.Haskell a -> Comb repr b -> Comb repr a
57 pattern (:*>) :: Comb repr a -> Comb repr b -> Comb repr b
58 pattern (:<*) :: Comb repr a -> Comb repr b -> Comb repr a
59 pattern x :<$> p = Pure x :<*> p
60 pattern p :$> x = p :*> Pure x
61 pattern x :<$ p = Pure x :<* p
62 pattern x :<* p = H.Const :<$> x :<*> p
63 pattern p :*> x = H.Id :<$ p :<*> x
66 infixl 4 :<*>, :<*, :*>
67 infixl 4 :<$>, :<$, :$>
69 instance Applicable (Comb repr) where
72 instance Alternable (Comb repr) where
76 instance Selectable (Comb repr) where
78 instance Matchable (Comb repr) where
80 instance Foldable (Comb repr) where
83 instance Charable (Comb repr) where
85 instance Lookable (Comb repr) where
88 instance Letable TH.Name (Comb repr) where
91 instance MakeLetName TH.Name where
92 makeLetName _ = TH.qNewName "let"
94 -- Pattern-matchable 'Comb'inators keep enough structure
95 -- to have some of the symantics producing them interpreted again
96 -- (eg. after being modified by 'optimizeComb').
97 type instance Output (Comb repr) = repr
106 , Letable TH.Name repr
107 ) => Trans (Comb repr) repr where
110 Satisfy p -> satisfy p
112 Try x -> try (trans x)
113 Look x -> look (trans x)
114 NegLook x -> negLook (trans x)
115 x :<*> y -> trans x <*> trans y
116 x :<|> y -> trans x <|> trans y
118 Branch lr l r -> branch (trans lr) (trans l) (trans r)
119 Match ps bs a b -> conditional ps (trans Functor.<$> bs) (trans a) (trans b)
120 ChainPre x y -> chainPre (trans x) (trans y)
121 ChainPost x y -> chainPost (trans x) (trans y)
122 Def n x -> def n (trans x)
125 -- * Type 'OptimizeComb'
126 -- Bottom-up application of 'optimizeCombNode'.
127 newtype OptimizeComb letName repr a = OptimizeComb { unOptimizeComb :: Comb repr a }
130 Trans (OptimizeComb TH.Name repr) repr =>
131 OptimizeComb TH.Name repr a -> repr a
134 Trans (Comb repr) repr =>
135 Trans (OptimizeComb letName repr) repr where
136 trans = trans . unOptimizeComb
138 type instance Output (OptimizeComb _letName repr) = Comb repr
139 instance Trans (OptimizeComb letName repr) (Comb repr) where
140 trans = unOptimizeComb
141 instance Trans (Comb repr) (OptimizeComb letName repr) where
142 trans = OptimizeComb . optimizeCombNode
143 instance Trans1 (Comb repr) (OptimizeComb letName repr)
144 instance Trans2 (Comb repr) (OptimizeComb letName repr)
145 instance Trans3 (Comb repr) (OptimizeComb letName repr)
148 Letable letName (Comb repr) =>
149 Letable letName (OptimizeComb letName repr) where
150 -- Disable useless calls to 'optimizeCombNode'
151 -- because 'Def' or 'Ref' have no matching in it.
152 def n = OptimizeComb . def n . unOptimizeComb
153 ref r n = OptimizeComb (ref r n)
154 instance Comb.Applicable (OptimizeComb letName repr)
155 instance Comb.Alternable (OptimizeComb letName repr)
156 instance Comb.Charable (OptimizeComb letName repr)
157 instance Comb.Selectable (OptimizeComb letName repr)
158 instance Comb.Matchable (OptimizeComb letName repr)
159 instance Comb.Lookable (OptimizeComb letName repr)
160 instance Comb.Foldable (OptimizeComb letName repr)
162 optimizeCombNode :: Comb repr a -> Comb repr a
163 optimizeCombNode = \case
164 -- Functor Identity Law
166 -- trace "Functor Identity Law" $
168 -- Functor Commutativity Law
170 -- trace "Functor Commutativity Law" $
171 optimizeCombNode (u :$> x)
172 -- Functor Flip Const Law
173 H.Flip H.:@ H.Const :<$> u ->
174 -- trace "Functor Flip Const Law" $
175 optimizeCombNode (u :*> Pure H.Id)
176 -- Functor Homomorphism Law
178 -- trace "Functor Homomorphism Law" $
181 -- App Right Absorption Law
183 -- trace "App Right Absorption Law" $
186 -- In Parsley: this is only a weakening to u :*> Empty
187 -- but here :*> is an alias to :<*>
188 -- hence it would loop on itself forever.
189 -- trace "App Left Absorption Law" $
191 -- App Composition Law
193 -- trace "App Composition Law" $
194 optimizeCombNode (optimizeCombNode (optimizeCombNode ((H.:.) :<$> u) :<*> v) :<*> w)
195 -- App Interchange Law
197 -- trace "App Interchange Law" $
198 optimizeCombNode (H.Flip H..@ (H.:$) H..@ x :<$> u)
199 -- App Left Absorption Law
201 -- trace "App Left Absorption Law" $
203 -- App Right Absorption Law
205 -- trace "App Right Absorption Law" $
207 -- App Pure Left Identity Law
209 -- trace "App Pure Left Identity Law" $
211 -- App Functor Left Identity Law
213 -- trace "App Functor Left Identity Law" $
215 -- App Pure Right Identity Law
217 -- trace "App Pure Right Identity Law" $
219 -- App Functor Right Identity Law
221 -- trace "App Functor Right Identity Law" $
222 optimizeCombNode (u :<* v)
223 -- App Left Associativity Law
225 -- trace "App Left Associativity Law" $
226 optimizeCombNode (u :<* optimizeCombNode (v :<* w))
228 -- Alt Left Catch Law
230 -- trace "Alt Left Catch Law" $
232 -- Alt Left Neutral Law
234 -- trace "Alt Left Neutral Law" $
236 -- All Right Neutral Law
238 -- trace "Alt Right Neutral Law" $
240 -- Alt Associativity Law
242 -- trace "Alt Associativity Law" $
243 u :<|> optimizeCombNode (v :<|> w)
247 -- trace "Look Pure Law" $
251 -- trace "Look Empty Law" $
255 -- trace "NegLook Pure Law" $
259 -- trace "NegLook Dead Law" $
261 -- NegLook Double Negation Law
262 NegLook (NegLook p) ->
263 -- trace "NegLook Double Negation Law" $
264 optimizeCombNode (Look (Try p) :*> Pure H.unit)
265 -- NegLook Zero Consumption Law
267 -- trace "NegLook Zero Consumption Law" $
268 optimizeCombNode (NegLook p)
271 -- trace "Look Idempotence Law" $
273 -- Look Right Identity Law
275 -- trace "Look Right Identity Law" $
276 optimizeCombNode (NegLook p)
277 -- Look Left Identity Law
279 -- trace "Look Left Identity Law" $
281 -- NegLook Transparency Law
282 NegLook (Try p :<|> q) ->
283 -- trace "NegLook Transparency Law" $
284 optimizeCombNode (optimizeCombNode (NegLook p) :*> optimizeCombNode (NegLook q))
285 -- Look Distributivity Law
286 Look p :<|> Look q ->
287 -- trace "Look Distributivity Law" $
288 optimizeCombNode (Look (optimizeCombNode (Try p :<|> q)))
289 -- Look Interchange Law
291 -- trace "Look Interchange Law" $
292 optimizeCombNode (f :<$> optimizeCombNode (Look p))
293 -- NegLook Absorption Law
295 -- trace "Neglook Absorption Law" $
296 optimizeCombNode (optimizeCombNode (p :<*> Pure H.unit) :<* NegLook q)
297 -- NegLook Idempotence Right Law
298 NegLook (_ :<$> p) ->
299 -- trace "NegLook Idempotence Law" $
300 optimizeCombNode (NegLook p)
301 -- Try Interchange Law
303 -- trace "Try Interchange Law" $
304 optimizeCombNode (f :<$> optimizeCombNode (Try p))
306 -- Branch Absorption Law
308 -- trace "Branch Absorption Law" $
310 -- Branch Weakening Law
311 Branch b Empty Empty ->
312 -- trace "Branch Weakening Law" $
313 optimizeCombNode (b :*> Empty)
314 -- Branch Pure Left/Right Laws
315 Branch (Pure (trans -> lr)) l r ->
316 -- trace "Branch Pure Left/Right Law" $
318 Left v -> optimizeCombNode (l :<*> Pure (H.Haskell (ValueCode (Value v) c)))
319 where c = [|| case $$(code lr) of Left x -> x ||]
320 Right v -> optimizeCombNode (r :<*> Pure (H.Haskell (ValueCode (Value v) c)))
321 where c = [|| case $$(code lr) of Right x -> x ||]
322 -- Branch Generalised Identity Law
323 Branch b (Pure (trans -> l)) (Pure (trans -> r)) ->
324 -- trace "Branch Generalised Identity Law" $
325 optimizeCombNode (H.Haskell (ValueCode v c) :<$> b)
327 v = Value (either (getValue l) (getValue r))
328 c = [|| either $$(code l) $$(code r) ||]
329 -- Branch Interchange Law
330 Branch (x :*> y) p q ->
331 -- trace "Branch Interchange Law" $
332 optimizeCombNode (x :*> optimizeCombNode (Branch y p q))
333 -- Branch Empty Right Law
335 -- trace " Branch Empty Right Law" $
336 Branch (Pure (H.Haskell (ValueCode v c)) :<*> b) Empty l
338 v = Value (either Right Left)
339 c = [||either Right Left||]
341 Branch (Branch b Empty (Pure (trans -> lr))) Empty br ->
342 -- trace "Branch Fusion Law" $
343 optimizeCombNode (Branch (optimizeCombNode (Pure (H.Haskell (ValueCode (Value v) c)) :<*> b))
347 v (Right r) = case getValue lr r of
350 c = [|| \case Left{} -> Left ()
351 Right r -> case $$(code 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 ((H..@) (H..) f :<$> l))
358 (optimizeCombNode ((H..@) (H..) f :<$> r)))
360 -- Match Absorption Law
362 -- trace "Match Absorption Law" $
364 -- Match Weakening Law
366 | all (\case {Empty -> True; _ -> False}) bs ->
367 -- trace "Match Weakening Law" $
368 optimizeCombNode (a :*> Empty)
370 Match ps bs (Pure (trans -> a)) d ->
371 -- trace "Match Pure Law" $
372 foldr (\(trans -> p, b) next ->
373 if getValue p (getValue a) then b else next
375 -- Match Distributivity Law
376 f :<$> Match ps bs a d ->
377 -- trace "Match Distributivity Law" $
378 Match ps (optimizeCombNode . (f :<$>) Functor.<$> bs) a
379 (optimizeCombNode (f :<$> d))
381 {- Possibly useless laws to be tested
384 -- App Definition of *> Law
385 H.Flip H..@ H.Const :<$> p :<*> q ->
386 -- trace "EXTRALAW: App Definition of *> Law" $
388 -- App Definition of <* Law
389 H.Const :<$> p :<*> q ->
390 -- trace "EXTRALAW: App Definition of <* Law" $
393 -- Functor Composition Law
394 -- (a shortcut that could also have been be caught
395 -- by the Composition Law and Homomorphism Law)
397 -- trace "EXTRALAW: Functor Composition Law" $
398 optimizeCombNode ((H.:.) H..@ f H..@ g :<$> p)
399 -- Applicable Failure Weakening Law
401 -- trace "EXTRALAW: App Failure Weakening Law" $
402 optimizeCombNode (u :*> Empty)
404 -- trace "EXTRALAW: Try Interchange Right Law" $
405 optimizeCombNode (optimizeCombNode (Try p) :$> x)
406 -- App Reassociation Law 1
408 -- trace "EXTRALAW: App Reassociation Law 1" $
409 optimizeCombNode (u :*> optimizeCombNode (v :<*> w))
410 -- App Reassociation Law 2
412 -- trace "EXTRALAW: App Reassociation Law 2" $
413 optimizeCombNode (optimizeCombNode (u :<*> v) :<* w)
414 -- App Right Associativity Law
416 -- trace "EXTRALAW: App Right Associativity Law" $
417 optimizeCombNode (optimizeCombNode (u :*> v) :*> w)
418 -- App Reassociation Law 3
420 -- trace "EXTRALAW: App Reassociation Law 3" $
421 optimizeCombNode (optimizeCombNode (u :<*> Pure x) :<* v)
424 optimizeCombNode (optimizeCombNode (Look p) :$> x)
425 NegLook (p :$> _) -> optimizeCombNode (NegLook p)