-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGenericGen.sml
333 lines (323 loc) · 12.1 KB
/
GenericGen.sml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
signature CONVERT_VALUE =
sig
type t
val unit: t
val const: Token.token -> t
val app: Token.token -> t -> t
val parens: t -> t
end
functor ConvertFn(Value: CONVERT_VALUE) =
struct
open BuildAst Tokens
fun ins ([], {arg = SOME _, ...}) = Value.const quesTok
| ins ([], _) = Value.unit
| ins (i :: is, constr: constr) =
let
val head =
case constr of
{arg = SOME _, ...} => Value.const quesTok
| _ => Value.unit
val head = Value.app i head
in
List.foldl (fn (i, acc) => Value.app i (Value.parens acc)) head is
end
fun constr ({arg = SOME _, id, ...}: constr) =
Value.app id (Value.const quesTok)
| constr {id, ...} = Value.const id
end
structure GenericGen =
struct
open Ast Ast.Exp TokenUtils Tokens BuildAst Utils MutRecTy
structure ExpValue: CONVERT_VALUE =
struct
type t = exp
val unit = unitExp
val const = Const
val app = fn tok => fn a => App {left = Const tok, right = a}
val parens = parensExp
end
structure PatValue: CONVERT_VALUE =
struct
open Ast.Pat
type t = pat
val unit = unitPat
val const = Const
val app = fn tok =>
fn a => Con {opp = NONE, id = MaybeLongToken.make tok, atpat = a}
val parens = parensPat
end
structure ConvertExp = ConvertFn(ExpValue)
structure ConvertPat = ConvertFn(PatValue)
fun tyVarFnExp [] exp = exp
| tyVarFnExp [v] exp =
singleFnExp (Pat.Const (mkTyVar v)) exp
| tyVarFnExp vars exp =
singleFnExp (destructTuplePat (List.map (Pat.Const o mkTyVar) vars)) exp
fun genTy env ty =
let
val recordTok = mkToken "record'"
in
case ty of
Ty.Var tok => Const (mkTyVar tok)
| Ty.Record {elems, ...} =>
let
val rTok = mkToken "R'"
val elems = Seq.toList elems
val labels = List.map #lab elems
val labelExps =
List.map
(fn {lab, ty, ...} =>
appExp
[ Const rTok
, Const (stringTok lab)
, parensExp (genTy env ty)
]) elems
val exp = parensExp (infixLExp prodTok labelExps)
val to = singleFnExp (destructRecordPat labels) (infixLExp andTok
(List.map Const labels))
val from =
singleFnExp (destructInfixLPat andTok (List.map Pat.Const labels))
(recordExp (List.map (fn l => (l, Const l)) labels))
in
appExp [Const recordTok, exp, tupleExp [to, from]]
end
| Ty.Tuple {elems, ...} =>
let
val elems = Seq.toList elems
val len = List.length elems
val tTok = mkToken "T"
val freshToks = List.tabulate (len, fn i =>
mkToken ("t" ^ Int.toString i))
in
if len <= 4 then
App
{ left = Const (mkToken ("tuple" ^ Int.toString len))
, right = tupleExp (List.map (genTy env) elems)
}
else
appExp
[ Const (mkToken "tuple'")
, parensExp (infixLExp prodTok
(List.map
(fn t => appExp [Const tTok, parensExp (genTy env t)])
elems))
, tupleExp
[ singleFnExp
(destructTuplePat (List.map Pat.Const freshToks))
(infixLExp andTok (List.map Const freshToks))
, singleFnExp
(destructInfixLPat andTok (List.map Pat.Const freshToks))
(tupleExp (List.map Const freshToks))
]
]
end
| Ty.Con {id, args} =>
let
val id = MaybeLongToken.getToken id
val id = if Token.toString id = "ref" then mkToken "refc" else id
in
case generatedFixNameForTy env ty of
SOME ty => Const ty
| NONE =>
(case args of
SyntaxSeq.Empty => Const id
| SyntaxSeq.One ty =>
App {left = Const id, right = parensExp (genTy env ty)}
| SyntaxSeq.Many {elems, ...} =>
App
{ left = Const id
, right = tupleExp
(List.map (genTy env) (Seq.toList elems))
})
end
| Ty.Arrow {from, to, ...} =>
Infix
{ left = parensExp (genTy env from)
, id = mkToken "-->"
, right = parensExp (genTy env to)
}
| Ty.Parens {ty, ...} => genTy env ty
end
fun genConstrs (_, []) = unitExp
| genConstrs (env, constrs) =
let
val c0tok = mkToken "C0'"
val c1tok = mkToken "C1'"
val constrs' =
List.map
(fn {arg = SOME {ty, ...}, id, ...} =>
appExp
[Const c1tok, Const (stringTok id), parensExp (genTy env ty)]
| {id, ...} =>
App {left = Const c0tok, right = Const (stringTok id)}) constrs
val plusTok = mkToken "+`"
val dataExp =
List.foldl
(fn (e, acc) => Infix {left = acc, id = plusTok, right = e})
(List.hd constrs') (List.tl constrs')
val inrTok = mkToken "INR"
val inlTok = mkToken "INL"
fun buildINs 0 [_] = [[]]
| buildINs n [_] =
[inlTok :: List.tabulate (n - 1, fn _ => inlTok)]
| buildINs 0 (_ :: cs) =
[inrTok] :: buildINs 1 cs
| buildINs n (_ :: cs) =
(inrTok :: List.tabulate (n, fn _ => inlTok))
:: buildINs (n + 1) cs
| buildINs _ [] = []
val revConstrs = List.rev constrs
val ins = buildINs 0 revConstrs
val toINs =
List.map
(fn (is, constr) =>
(ConvertPat.constr constr, ConvertExp.ins (is, constr)))
(ListPair.zip (ins, revConstrs))
val fromINs =
List.map
(fn (is, constr) =>
(ConvertPat.ins (is, constr), ConvertExp.constr constr))
(ListPair.zip (ins, revConstrs))
in
App
{ left = App
{left = Const (mkToken "data'"), right = parensExp dataExp}
, right = tupleExp [multFnExp toINs, multFnExp fromINs]
}
end
fun genTypebind ({elems, ...}: typbind) =
let
val decs =
List.map
(fn {tycon, ty, tyvars, ...} =>
let
val tyvars = syntaxSeqToList tyvars
val env = envWithVars tyvars (mkEnv (! Options.defaultTableSize))
in
valDec (Pat.Const tycon)
(tyVarFnExp tyvars (singleLetExp genericDec (genTy env ty)))
end) (Seq.toList elems)
in
multDec decs
end
fun genSimpleDatabind (env, ty, vars, Databind constrs) =
valDec (identPat ty)
(tyVarFnExp vars (singleLetExp genericDec (genConstrs
(envWithVars vars env, constrs))))
| genSimpleDatabind (_, tyTok, vars, Typebind ty) =
genSingleTypebind genTypebind (tyTok, vars, ty)
fun genRecursiveDatabind (env, tycons, tys, vars) =
let
val yTok = mkToken "Y"
val yDec = valDec (Pat.Const yTok) (Const (mkToken "Generic.Y"))
val varExps = List.map Ty.Var vars
val patToks =
case vars of
[] => tycons
| _ => List.map #1 (generatedFixesAndArgs env)
val fullPat = destructInfixLPat andTok (List.map identPat patToks)
val exp =
case vars of
[] =>
let
val env = envWithVars vars env
val exps =
List.map
(fn tycon =>
let
val tycon = Token.toString tycon
val substMap = buildSubstMap env tycon varExps
in
case tyconData env (Atom.atom tycon) of
Databind constrs =>
genConstrs
(env, List.map (substConstr substMap) constrs)
| Typebind ty => genTy env (subst substMap ty)
end) tycons
in
singleLetExp genericDec (infixLExp andTok exps)
end
| _ =>
let
val dups: IntRedBlackSet.set AtomTable.hash_table =
AtomTable.mkTable (List.length tycons, LibBase.NotFound)
val decs =
List.map
(fn (tycon, ty) =>
let
val tyconA = Atom.atom (Token.toString tycon)
val args =
List.map
(fn Ty.Con {id, ...} => MaybeLongToken.getToken id
| Ty.Var v => mkTyVar v
| _ => raise Fail "Invalid arg")
(generatedArgsForTy env ty)
val argDups = findDuplicates args
val () = AtomTable.insert dups (tyconA, argDups)
val substMap =
buildSubstMap env (Token.toString tycon) varExps
in
singleFunDec tycon
[destructTuplePat
(applyDuplicates (argDups, Pat.Const, args))]
(case tyconData env tyconA of
Databind constrs =>
genConstrs
(env, List.map (substConstr substMap) constrs)
| Typebind ty => genTy env (subst substMap ty))
end) (ListPair.zip (tycons, tys))
val exps =
List.map
(fn (tycon, args) =>
let
val tycon = baseTyName (Token.toString tycon)
val argDups = AtomTable.lookup dups (Atom.atom tycon)
val tycon = mkToken tycon
in
case applyDuplicates (argDups, genTy env, args) of
[] => Const tycon
| args => appExp [Const tycon, tupleExp args]
end) (generatedFixesAndArgs env)
in
singleLetExp (multDec (genericDec :: decs))
(infixLExp andTok exps)
end
val lam = singleFnExp fullPat exp
val ys =
let
val ys = List.tabulate (List.length patToks, fn _ => Const yTok)
in
(if List.length ys = 1 then fn e => e else parensExp)
(infixLExp prodTok ys)
end
fun header exp =
case vars of
[] => valDec fullPat (singleLetExp (multDec [tieDec, yDec]) exp)
| _ =>
let
val concatTys = mkToken (String.concatWith "_"
(List.map Token.toString tycons))
val tyToks =
List.map (Option.valOf o generatedFixNameForTy env) tys
val tyFixes = List.map Const tyToks
val hiddenPat = destructInfixLPat andTok
(List.map
(fn tok =>
if List.exists (fn t => Token.same (tok, t)) tyToks then
identPat tok
else
wildPat) patToks)
val unpacked = unpackingDecs
(env, vars, concatTys, tycons, fn a => a, "Generic.unit")
in
multDec
(valDec (Pat.Const concatTys) (tyVarFnExp vars
(singleLetExp (multDec [tieDec, yDec, valDec hiddenPat exp])
(tupleExp tyFixes))) :: unpacked)
end
in
header (appExp [Const (mkToken "fix"), ys, parensExp lam])
end
val genDatabind = genDatabindHelper (genSimpleDatabind, genRecursiveDatabind)
val gen = {genTypebind = genTypebind, genDatabind = genDatabind}
end