0 | module Generics.Derive
  1 |
  2 | import Data.List1
  3 | import public Generics.SOP
  4 | import public Generics.Meta
  5 | import public Decidable.Equality
  6 |
  7 | import public Language.Reflection.Util
  8 |
  9 | import System.Clock
 10 | import System.File
 11 |
 12 | %language ElabReflection
 13 |
 14 | %default total
 15 |
 16 | --------------------------------------------------------------------------------
 17 | --          Generic
 18 | --------------------------------------------------------------------------------
 19 |
 20 | private
 21 | ConNames : Type
 22 | ConNames = (Name, List Name, List TTImp)
 23 |
 24 | ||| Name of record `Generic`'s constructor.
 25 | export
 26 | mkGeneric : Name
 27 | mkGeneric = "MkGeneric"
 28 |
 29 | -- Applies the proper n-ary sum constructor to a list
 30 | -- of arguments. `k` is the index of the data type's
 31 | -- constructor.
 32 | private
 33 | mkSOP' : (k : Nat) -> (arg : TTImp) -> TTImp
 34 | mkSOP' k arg = `(MkSOP ~(run k))
 35 |
 36 |   where
 37 |     run : (n : Nat) -> TTImp
 38 |     run 0     = `(Z ~(arg))
 39 |     run (S n) = `(S ~(run n))
 40 |
 41 | private
 42 | mkSOP : (k : Nat) -> (args : List TTImp) -> TTImp
 43 | mkSOP k args = mkSOP' k (listOf args)
 44 |
 45 | ||| Creates the syntax tree for the code of the given data type.
 46 | ||| We export this since it might be useful elsewhere.
 47 | export
 48 | mkCode : (p : ParamTypeInfo) -> TTImp
 49 | mkCode p = listOf $ map (\c => listOf $ explicits c.args) p.cons
 50 |
 51 |   where
 52 |     explicits : Vect n (ConArg p.numParams) -> List TTImp
 53 |     explicits [] = []
 54 |     explicits (CArg _ _ ExplicitArg t :: as) =
 55 |       ttimp p.paramNames t :: explicits as
 56 |     explicits (_ :: as) = explicits as
 57 |
 58 | private
 59 | fromClause : (Nat,ConNames) -> Clause
 60 | fromClause (k,(con,ns,vars)) = patClause (bindAll con ns) (mkSOP k vars)
 61 |
 62 | private
 63 | fromToIdClause : (Nat,ConNames) -> Clause
 64 | fromToIdClause (k,(con,ns,vars)) = patClause (bindAll con ns) `(Refl)
 65 |
 66 | private
 67 | toClause : (Nat,ConNames) -> Clause
 68 | toClause (k,(con,ns,vars)) =
 69 |   patClause (mkSOP k $ map bindVar ns) (appAll con vars)
 70 |
 71 | private
 72 | impossibleToClause : Nat -> Clause
 73 | impossibleToClause k = impossibleClause (mkSOP' k implicitTrue)
 74 |
 75 | private
 76 | toFromIdClause : (Nat,ConNames) -> Clause
 77 | toFromIdClause (k,(con,ns,vars)) = patClause (mkSOP k $ map bindVar ns) `(Refl)
 78 |
 79 | private
 80 | zipWithIndex : List a -> List (Nat,a)
 81 | zipWithIndex as = run 0 as
 82 |
 83 |   where
 84 |     run : Nat -> List a -> List (Nat,a)
 85 |     run _ []     = []
 86 |     run k (h::t) = (k,h) :: run (S k) t
 87 |
 88 | private
 89 | conNames : ParamCon n -> ConNames
 90 | conNames c =
 91 |   let ns   := toList $ freshNames "x" (count isExplicit c.args)
 92 |       vars := map var ns
 93 |    in (c.name, ns, vars)
 94 |
 95 | ||| Derives a `Generic` implementation for the given data type
 96 | ||| and visibility.
 97 | export
 98 | GenericVis : Visibility -> List Name -> ParamTypeInfo -> Res (List TopLevel)
 99 | GenericVis vis _ p =
100 |   let names    := zipWithIndex (map conNames p.cons)
101 |       fun      := UN . Basic $ "implGeneric" ++ camelCase p.info.name
102 |
103 |       appType  := p.applied
104 |       genType  := `(Generic ~(appType) ~(mkCode p))
105 |       funType  := piAll genType p.implicits
106 |
107 |       x        := lambdaArg {a = Name} "x"
108 |       varX     := var "x"
109 |       from     := lam x $ iCase varX implicitFalse (map fromClause names)
110 |       to       := lam x $ iCase varX implicitFalse (map toClause names)
111 |       fromToId := lam x $ iCase varX implicitFalse (map fromToIdClause names)
112 |       toFromId := lam x $ iCase varX implicitFalse (map toFromIdClause names)
113 |
114 |       impl     := appAll mkGeneric [from,to,fromToId,toFromId]
115 |
116 |    in Right
117 |        [ TL (interfaceHint vis fun funType) (def fun [patClause (var fun) impl])]
118 |
119 | ||| Alias for `GenericVis Public`.
120 | export
121 | Generic : List Name -> ParamTypeInfo -> Res (List TopLevel)
122 | Generic = GenericVis Public
123 |
124 | --------------------------------------------------------------------------------
125 | --          Meta
126 | --------------------------------------------------------------------------------
127 |
128 | -- a string constant
129 | private
130 | str : String -> TTImp
131 | str = primVal . Str
132 |
133 | -- an int constant
134 | private
135 | int : Nat -> TTImp
136 | int n = `(fromInteger ~(primVal $ BI (cast n)))
137 |
138 | -- applies a name's namespace (List String) and name value
139 | -- to a function (`con`) wrapped in a `TTImp`.
140 | private
141 | appNSName : Name -> (con,np : TTImp) -> TTImp
142 | appNSName (NS (MkNS ss) (UN $ Basic s)) con np =
143 |   let ss' := listOf $ reverse $ map str ss
144 |    in `(~(con) ~(ss') ~(str s) ~(np))
145 | appNSName n con np                          =
146 |   let s := str $ nameStr n
147 |    in `(~(con) [] ~(s) ~(np))
148 |
149 | -- creates an ArgName's TTImp from an argument's index and name
150 | private
151 | argNameTTImp : (Nat,Maybe Name) -> TTImp
152 | argNameTTImp (k, Just $ UN $ Basic n) = `(NamedArg ~(int k) ~(str n))
153 | argNameTTImp (k, _)                   = `(UnnamedArg ~(int k))
154 |
155 | -- creates a ConInfo's TTImp from a `ParamCon`.
156 | private
157 | conTTImp : ParamCon n -> TTImp
158 | conTTImp c =
159 |   let np := listOf $ map argNameTTImp (names 0 c.args)
160 |    in appNSName c.name `(MkConInfo) np
161 |
162 |   where
163 |     names : (k : Nat) -> Vect m (ConArg n) -> List (Nat, Maybe Name)
164 |     names k []                             = []
165 |     names k (CArg n _ ExplicitArg t :: as) = (k,n) :: names (S k) as
166 |     names k (_ :: as)                      = names k as
167 |
168 | private
169 | tiTTImp : ParamTypeInfo -> TTImp
170 | tiTTImp p =
171 |   let nps := map conTTImp p.cons
172 |    in appNSName p.info.name `(MkTypeInfo) (listOf nps)
173 |
174 | ||| Derives a `Meta` implementation for the given data type
175 | ||| and visibility.
176 | export
177 | MetaVis : Visibility -> List Name -> ParamTypeInfo -> Res (List TopLevel)
178 | MetaVis vis _ p =
179 |   let genType  := `(Meta ~(p.applied) ~(mkCode p))
180 |       funType  := piAll genType p.implicits
181 |       fun      := UN . Basic $ "implMeta" ++ camelCase p.info.name
182 |
183 |       impl     := `(MkMeta ~(tiTTImp p))
184 |
185 |    in Right
186 |        [TL (interfaceHint vis fun funType) (def fun [patClause (var fun) impl])]
187 |
188 | ||| Alias for `EqVis Public`.
189 | export
190 | Meta : List Name -> ParamTypeInfo -> Res (List TopLevel)
191 | Meta = MetaVis Public
192 |
193 | --------------------------------------------------------------------------------
194 | --          Eq
195 | --------------------------------------------------------------------------------
196 |
197 | ||| Derives `Eq` for the given data type.
198 | |||
199 | ||| @deprecated : This is deprecated. Use `Derive.Eq.Eq` from elab-util.
200 | export %deprecate
201 | Eq : List Name -> ParamTypeInfo -> Res (List TopLevel)
202 | Eq _ p =
203 |   let nm := implName p "Eq"
204 |       cl := patClause (var nm) `(mkEq genEq)
205 |    in Right [TL (interfaceHint Public nm (implType "Eq" p)) (def nm [cl])]
206 |
207 | --------------------------------------------------------------------------------
208 | --          Ord
209 | --------------------------------------------------------------------------------
210 |
211 | ||| Derives `Ord` for the given data type.
212 | |||
213 | ||| @deprecated : This is deprecated. Use `Derive.Ord.Ord` from elab-util.
214 | export %deprecate
215 | Ord : List Name -> ParamTypeInfo -> Res (List TopLevel)
216 | Ord _ p =
217 |   let nm := implName p "Ord"
218 |       cl := patClause (var nm) `(mkOrd genCompare)
219 |    in Right [TL (interfaceHint Public nm (implType "Ord" p)) (def nm [cl])]
220 |
221 | --------------------------------------------------------------------------------
222 | --          DecEq
223 | --------------------------------------------------------------------------------
224 |
225 | ||| Derives `DecEq` for the given data type.
226 | export
227 | DecEq : List Name -> ParamTypeInfo -> Res (List TopLevel)
228 | DecEq _ p =
229 |   let nm := implName p "DecEq"
230 |       cl := patClause (var nm) `(mkDecEq genDecEq)
231 |    in Right [TL (interfaceHint Public nm (implType "DecEq" p)) (def nm [cl])]
232 |
233 | --------------------------------------------------------------------------------
234 | --          Show
235 | --------------------------------------------------------------------------------
236 |
237 | ||| Derives `Show` for the given data type.
238 | |||
239 | ||| @deprecated : This is deprecated. Use `Derive.Show.Show` from elab-util.
240 | export %deprecate
241 | Show : List Name -> ParamTypeInfo -> Res (List TopLevel)
242 | Show _ p =
243 |   let nm := implName p "Show"
244 |       cl := patClause (var nm) `(mkShowPrec genShowPrec)
245 |    in Right [TL (interfaceHint Public nm (implType "Show" p)) (def nm [cl])]
246 |
247 | --------------------------------------------------------------------------------
248 | --          Prelude and Data Implementations
249 | --------------------------------------------------------------------------------
250 |
251 | -- Prelude
252 |
253 | %runElab derive "Nat" [Generic,Meta]
254 |
255 | %runElab derive "Maybe" [Generic,Meta]
256 |
257 |
258 | %runElab derive "Either" [Generic,Meta]
259 |
260 | %runElab derive "List" [Generic,Meta]
261 |
262 | %runElab derive "List1" [Generic,Meta]
263 |
264 | %runElab derive "Dec" [Generic,Meta]
265 |
266 | %runElab derive "Ordering" [Generic,Meta]
267 |
268 | %runElab derive "Bool" [Generic,Meta]
269 |
270 | %runElab derive "Prec" [Generic,Meta]
271 |
272 | -- System
273 |
274 | %runElab derive "System.File.Mode.Mode" [Generic,Meta]
275 |
276 | %runElab derive "FileError" [Generic,Meta]
277 |
278 | %runElab derive "File" [Generic,Meta]
279 |
280 | %runElab derive "FileMode" [Generic,Meta]
281 |
282 | %runElab derive "Permissions" [Generic,Meta]
283 |
284 | %runElab derive "ClockType" [Generic,Meta]
285 |