3 , GeneralizedNewtypeDeriving
4 , MultiParamTypeClasses
9 {-# OPTIONS_GHC -fno-warn-missing-methods #-}
10 -- |An internal module for rewriting 'Name's in Template Haskell AST.
11 module Network.HTTP.Lucu.Implant.Rewrite
28 import Control.Applicative hiding (empty)
29 import Control.Monad.State
30 import Data.Collections
31 import Data.Collections.BaseInstances ()
32 import qualified Data.Collections.Newtype.TH as C
34 import Data.Generics.Aliases hiding (GT)
35 import Data.Generics.Schemes
37 import Data.Monoid.Unicode
38 import qualified Data.Set as S (Set)
39 import Language.Haskell.TH.Syntax
41 import Prelude.Unicode
43 -- |Pattern for 'Name's. 'Just' represents a perfect matching pattern,
44 -- and 'Nothing' represensts a wildcard.
46 = NamePat !(Maybe ModName) !(Maybe OccName)
48 -- |Instruction for rewriting 'Name's.
54 -- |A 'Set' of modules and names to be imported.
55 newtype Imports = Imports (S.Set ImportOp)
57 -- |Instruction for declaring module imports.
59 = -- |> import qualified M as A
68 -- > import M (a, b, c, ...)
71 , impNames ∷ !(Maybe (S.Set (NameSpace, OccName)))
75 -- |List of 'RewriteRule's.
76 type Rules = [RewriteRule]
78 -- |Instruction for rewriting 'Name's and declaring module imports.
86 C.derive [d| instance Foldable Imports ImportOp
87 instance Collection Imports ImportOp
88 instance Map Imports ImportOp ()
89 instance Set Imports ImportOp
90 instance SortingCollection Imports ImportOp
93 -- |@'insert' imp@ merges @imp@ with an existing one if any.
94 instance Unfoldable Imports ImportOp where
95 insert qi@(QualifiedImp {}) (Imports s) = Imports $ insert qi s
96 insert ui@(UnqualifiedImp {}) (Imports s)
97 = case find sameMod s of
98 Nothing → Imports $ insert ui s
99 Just ui' → Imports $ insert (merge ui') (delete ui' s)
101 sameMod ∷ ImportOp → Bool
102 sameMod ui'@(UnqualifiedImp {})
103 = impModule ui ≡ impModule ui'
107 merge ∷ ImportOp → ImportOp
109 = case (impNames ui, impNames ui') of
112 (Just ns, Just ns') → ui { impNames = Just (ns ⊕ ns') }
114 empty = Imports empty
115 singleton = Imports ∘ singleton
117 instance Monoid Imports where
121 instance Ord ImportOp where
123 | impModule α < impModule β = LT
124 | impModule α > impModule β = GT
127 (QualifiedImp {}, QualifiedImp {})
128 → impAlias α `compare` impAlias β
129 (QualifiedImp {}, _ )
131 (UnqualifiedImp {}, UnqualifiedImp {})
132 → impNames α `compare` impNames β
133 (UnqualifiedImp {}, _ )
136 -- |@'qualifyAll' module alias@: qualify every symbols defined in
137 -- @module@ with @alias@.
138 qualifyAll ∷ String → String → RewriteRule
140 = let pat = NamePat (Just (mkModName m)) Nothing
141 rop = Qualify (mkModName a)
142 iop = QualifiedImp (mkModName m) (mkModName a)
144 RewriteRule pat rop (singleton iop)
146 -- |@'unqualify' name module@: unqualify the symbol @name@ with
147 -- importing @module@.
148 unqualify ∷ Name → String → RewriteRule
149 unqualify (Name o _) m
150 = let pat = NamePat Nothing (Just o)
151 iop = UnqualifiedImp (mkModName m) ∘ Just
152 $ singleton (VarName, o)
154 RewriteRule pat Unqualify (singleton iop)
156 -- |@'unqualifyIn' name tycl module@: unqualify a constructor, field
157 -- name, or whatever resides in the type or class @tycl@ with
158 -- importing @module@.
159 unqualifyIn ∷ Name → Name → String → RewriteRule
160 unqualifyIn (Name name _) (Name tycl _) m
161 = let pat = NamePat Nothing (Just name)
162 iop = UnqualifiedImp (mkModName m) ∘ Just
163 $ singleton (TcClsName, tycl)
165 RewriteRule pat Unqualify (singleton iop)
167 -- |@'unqualifyAll' origMod impMod@: unqualify every symbols
168 -- defined in @origMod@ with importing @impMod@.
169 unqualifyAll ∷ String → String → RewriteRule
170 unqualifyAll origMod impMod
171 = let pat = NamePat (Just (mkModName origMod)) Nothing
172 iop = UnqualifiedImp (mkModName impMod) Nothing
174 RewriteRule pat Unqualify (singleton iop)
176 -- |@'rewriteNames' rules d@ rewrites each and every 'Name's included
177 -- in @d@ according to the name-rewriting @rules@ while at the same
178 -- time building a set of modules to be imported.
179 rewriteNames ∷ Data d ⇒ Rules → d → (d, Imports)
180 rewriteNames rules = flip runState (∅) ∘ gmapM (everywhereM (mkM f))
182 f ∷ (Functor m, Monad m) ⇒ Name → StateT Imports m Name
183 f n = case findRule rules n of
184 Nothing → fail $ "No rules matches to name: " ⧺ showName n
185 Just r → applyRule r n
187 findRule ∷ Rules → Name → Maybe RewriteRule
188 findRule _ (Name _ NameS ) = Just identityRule
189 findRule rs (Name o (NameQ m)) = find (matchPat m o ∘ rrPat) rs
190 findRule _ (Name _ (NameU _ )) = Just identityRule
191 findRule rs (Name o (NameG _ _ m)) = find (matchPat m o ∘ rrPat) rs
192 findRule _ _ = Nothing
194 identityRule ∷ RewriteRule
195 identityRule = RewriteRule {
196 rrPat = NamePat Nothing Nothing
201 matchPat ∷ ModName → OccName → NamePat → Bool
202 matchPat m o (NamePat mp op)
203 = maybe True (≡ m) mp ∧ maybe True (≡ o) op
205 applyRule ∷ (Functor m, Monad m)
208 → StateT Imports m Name
209 applyRule (RewriteRule {..}) n
210 = modify (⊕ rrImps) *> pure (rewrite rrOp n)
212 rewrite ∷ RewriteOp → Name → Name
213 rewrite Identity n = n
214 rewrite Unqualify (Name o _) = Name o NameS
215 rewrite (Qualify m) (Name o _) = Name o (NameQ m)