String quoting for SQL queries
[bpt/mlt.git] / src / mlt.sml
CommitLineData
c0a3b488
AC
1(*
2 * Dynamic web page generation with Standard ML
3 * Copyright (C) 2003 Adam Chlipala
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *)
19
20(* Translation of templates into SML source *)
21
22structure Mlt :> MLT =
23struct
24 open Tree
25
26 exception Skip
27
28 fun error (pos, msg) = (ErrorMsg.error pos msg;
29 raise Skip)
30
31 type varid = int
32
33 datatype var = VAR of Types.ty | REF of Types.ty
34
35 val errorTy = Types.WILDCARDty
36
37 val ppstream = PrettyPrint.mk_ppstream {consumer = TextIO.print, flush = fn () => TextIO.flushOut TextIO.stdOut,
38 linewidth = 80}
39
40 (* States to thread throughout translation *)
41 local
42 datatype state = STATE of {env: StaticEnv.staticEnv,
43 vars : var StringMap.map,
44 config : Config.config,
45 templates : StringSet.set}
46
47 datatype strct = STRCT of {elements: Modules.elements,
48 eenv: EntityEnv.entityEnv}
49
50 fun getElements (Modules.SIG {elements, ...}) = elements
51 | getElements _ = raise Fail "Unexpected Signature in getElements"
52
53 val bogusStamp = Stamps.special "<bogus>"
54 val errorStrct = STRCT {elements = [], eenv = EntityEnv.empty}
55 in
56 fun mkState (config, env, templates) =
57 STATE {config = config,
58 env = env,
59 vars = StringMap.empty,
60 templates = templates}
61
62 fun addVar (STATE {config, env, vars, templates}, v, ty) =
63 STATE {config = config, env = env, vars = StringMap.insert (vars, v, ty), templates = templates}
64 fun addVars (state, vars) = StringMap.foldli (fn (v, ty, state) => addVar (state, v, ty)) state vars
65
66 fun getVar (STATE {vars, ...}, v, pos) = StringMap.find (vars, v)
67 fun lookVal (STATE {env, ...}, v, pos) =
68 (case StaticEnv.look (env, Symbol.varSymbol v) of
69 Bindings.VALbind var =>
70 (case var of
71 VarCon.VALvar {typ, ...} => #1 (TypesUtil.instantiatePoly (!typ))
72 | _ => raise Fail "Unexpected var in lookVal")
73 | Bindings.CONbind (Types.DATACON {typ, ...}) => #1 (TypesUtil.instantiatePoly typ)
74 | _ => raise Fail "Unexpected binding in lookVal")
75 handle StaticEnv.Unbound => (error (SOME pos, "Unbound variable " ^ v);
76 errorTy)
77
78 fun lookCon' (STATE {env, ...}, v) =
79 (case StaticEnv.look (env, Symbol.varSymbol v) of
80 Bindings.CONbind (Types.DATACON {typ, ...}) => #1 (TypesUtil.instantiatePoly typ)
81 | _ => raise Fail "Unexpected binding in lookVal")
82 fun lookCon (env, v, pos) = (lookCon' (env, v))
83 handle ModuleUtil.Unbound _ => (error (SOME pos, "Unbound constructor " ^ v);
84 errorTy)
85 fun lookStr (STATE {env, ...}, v, pos) =
86 (case StaticEnv.look (env, Symbol.strSymbol v) of
87 Bindings.STRbind modl =>
88 (case modl of
89 Modules.STR {rlzn = {entities, ...}, sign, ...} => STRCT {elements = getElements sign,
90 eenv = entities}
91 | _=> raise Fail "Unexpected module in lookStr")
92 | _ => raise Fail "Unexpected binding in lookStr")
93 handle StaticEnv.Unbound => (error (SOME pos, "Unbound structure " ^ v);
94 errorStrct)
95
96 fun getStr (STRCT {elements, eenv, ...}, v, pos) =
97 (case ModuleUtil.getStr (elements, eenv, Symbol.strSymbol v, Access.nullAcc, II.Null) of
98 (Modules.STR {rlzn = {entities, ...}, sign = Modules.SIG {elements, ...}, ...}, _) =>
99 STRCT {elements = elements, eenv = entities}
100 | _ => raise Fail "Unexpected spec in getStr")
101 handle ModuleUtil.Unbound _ => (error (SOME pos, "Unbound structure " ^ v);
102 errorStrct)
103 fun getVal (STRCT {elements, ...}, v, pos) =
104 (case ModuleUtil.getSpec (elements, Symbol.varSymbol v) of
105 Modules.VALspec {spec, ...} => #1 (TypesUtil.instantiatePoly spec)
106 | _ => raise Fail "Unexpected spec in getVal")
107 handle ModuleUtil.Unbound _ => (case ModuleUtil.getSpec (elements, Symbol.tycSymbol v) of
108 Modules.CONspec {spec = Types.DATACON {typ, ...}, ...} => #1 (TypesUtil.instantiatePoly typ)
109 | _ => raise Fail "Unexpected spec in getVal")
110 handle ModuleUtil.Unbound _ => (error (SOME pos, "Unbound variable " ^ v);
111 errorTy)
112 fun getCon (STRCT {elements, ...}, v, pos) =
113 (case ModuleUtil.getSpec (elements, Symbol.varSymbol v) of
114 Modules.CONspec {spec = Types.DATACON {typ, ...}, ...} => #1 (TypesUtil.instantiatePoly typ)
115 | _ => raise Fail "Unexpected spec in getVal")
116 handle ModuleUtil.Unbound _ => (error (SOME pos, "Unbound constructor " ^ v);
117 errorTy)
118
119 fun unify (STATE {env, ...}) (pos, t1, t2) =
120 (*let
121 val t1 = ModuleUtil.transType eenv t1
122 val t2 = ModuleUtil.transType eenv t2
123 in*)
124 Unify.unifyTy (t1, t2)
125 (*end*)
126 handle Unify.Unify msg =>
127 (PrettyPrint.begin_block ppstream PrettyPrint.CONSISTENT 0;
8291a2b9
AC
128 PrettyPrint.add_string ppstream "Error unifying";
129 PrettyPrint.add_break ppstream (1, 0);
c0a3b488
AC
130 PrettyPrint.begin_block ppstream PrettyPrint.CONSISTENT 5;
131 PPType.ppType env ppstream t1;
132 PrettyPrint.end_block ppstream;
8291a2b9
AC
133 PrettyPrint.add_break ppstream (1, 0);
134 PrettyPrint.add_string ppstream "and";
135 PrettyPrint.add_break ppstream (1, 0);
c0a3b488
AC
136 PrettyPrint.begin_block ppstream PrettyPrint.CONSISTENT 5;
137 PPType.ppType env ppstream t2;
138 PrettyPrint.end_block ppstream;
c0a3b488 139 PrettyPrint.end_block ppstream;
8291a2b9 140 PrettyPrint.add_break ppstream (1, 0);
c0a3b488
AC
141 PrettyPrint.flush_ppstream ppstream;
142 error (SOME pos, Unify.failMessage msg))
143
144 fun resolvePath (getter, transer) (pos, state, path) =
145 let
146 fun traverse ([], _, _) = raise Fail "Impossible empty variable path in pat traverse"
147 | traverse ([v], str as STRCT {eenv, ...}, path) =
148 let
149 val ty = getter (str, v, pos)
150 val ty = transer eenv ty
151 fun folder (STRCT {eenv, ...}, ty) = transer eenv ty
152 in
153 foldl folder ty path
154 end
155 | traverse (s::rest, str, path) = traverse (rest, getStr (str, s, pos), str::path)
156 in
157 case path of
158 [] => raise Fail "Empty path to resolvePath"
159 | [_] => raise Fail "Singleton path to resolvePath"
160 | (first::rest) => traverse (rest, lookStr (state, first, pos), [])
161 end
162
163 fun resolveStructure (pos, state, path) =
164 let
165 fun look (STATE {env, ...}, v, pos) =
166 (case StaticEnv.look (env, Symbol.strSymbol v) of
167 Bindings.STRbind modl =>
168 (case modl of
169 Modules.STR {rlzn = {entities, ...}, sign, ...} => (getElements sign, entities, modl)
170 | _=> raise Fail "Unexpected module in lookStr")
171 | _ => raise Fail "Unexpected binding in lookStr")
172 handle ModuleUtil.Unbound _ => (error (SOME pos, "Unbound structure " ^ v);
173 ([], EntityEnv.empty, Modules.ERRORstr))
174
175 fun get (elements, eenv, v) =
176 let
177 val sym = Symbol.strSymbol v
178 in
179 (case ModuleUtil.getStr (elements, eenv, sym, Access.nullAcc, II.Null) of
180 (str as Modules.STR {rlzn = {entities, ...}, sign = Modules.SIG {elements, ...}, ...}, _) =>
181 (elements, entities, str)
182 | _ => raise Fail "Unexpected spec in resolveStructure")
183 handle ModuleUtil.Unbound _ => (error (SOME pos, "Unbound structure " ^ v);
184 ([], EntityEnv.empty, Modules.ERRORstr))
185 end
186
187 fun traverse ([], (_, _, str)) = str
188 | traverse ([v], (elements, eenv, _)) = #3 (get (elements, eenv, v))
189 | traverse (s::rest, (elements, eenv, _)) = traverse (rest, get (elements, eenv, s))
190 in
191 case path of
192 [] => raise Fail "Empty path to resolveStructure"
193 | (first::rest) => traverse (rest, look (state, first, pos))
194 end
195
196 fun openStructure (pos, state as STATE {config, env, vars, templates}, path) =
197 let
198 val str = resolveStructure (pos, state, path)
199 val env = ModuleUtil.openStructure (env, str)
200 in
201 STATE {config = config, env = env, vars = vars, templates = templates}
202 end
203
204 fun tyToString (STATE {env, ...}) ty =
205 PrettyPrint.pp_to_string 65535 (PPType.ppType env) ty
206
207 fun printFn (state as STATE {config, env, ...}) ty =
208 let
209 val tyname = tyToString state ty
210 in
211 Config.printFn config tyname
212 end
213
214 fun isTemplate (STATE {templates, ...}) s = StringSet.member (templates, s)
215 end
216
217 fun twiddleType f ty =
218 (case TypesUtil.headReduceType ty of
219 Types.WILDCARDty => ty
220 | _ => f ty)
221
222 val domain = twiddleType BasicTypes.domain
223 val range = twiddleType BasicTypes.range
224
225 (*val _ = (Unify.debugging := true;
226 EntityEnv.debugging := true;
227 ModuleUtil.debugging := true)*)
228
229 fun newTyvar eq = Types.VARty (Types.mkTyvar (Types.OPEN {depth = 0, eq = eq, kind = Types.META}))
230 fun newFlex elms = Types.VARty (Types.mkTyvar (Types.OPEN {depth = 0, eq = false, kind = Types.FLEX elms}))
231
232 val resolveVal = resolvePath (getVal, ModuleUtil.transType)
233 val resolveCon = resolvePath (getCon, ModuleUtil.transType)
234
235 fun escapeString s =
236 let
237 val chars = String.explode s
238 val escd = map (fn #"\"" => "\\\""
239 | #"\n" => "\\n"
240 | #"\r" => ""
241 | #"\t" => "\\t"
242 | x => str x) chars
243 in
244 String.concat escd
245 end
246
247 val mkTuple = BasicTypes.tupleTy
248
249 val templateTy = BasicTypes.--> (Types.CONty (BasicTypes.listTycon,
250 [mkTuple [BasicTypes.stringTy,
251 BasicTypes.stringTy]]), BasicTypes.unitTy)
252
253 fun xexp state (EXP (e, pos)) =
254 (case e of
255 Int_e n =>
256 (BasicTypes.intTy, Int.toString n)
8291a2b9
AC
257 | Real_e n =>
258 (BasicTypes.realTy, Real.toString n)
c0a3b488
AC
259 | String_e s =>
260 (BasicTypes.stringTy, "\"" ^ s ^ "\"")
261 | Char_e s =>
262 (BasicTypes.charTy, "#\"" ^ s ^ "\"")
263 | Cons_e (e1, e2) =>
264 let
265 val (ty1, es1) = xexp state e1
266 val (ty2, es2) = xexp state e2
267
268 val parm = newTyvar false
269 val ran = Types.CONty (BasicTypes.listTycon, [parm])
270 val dom = mkTuple [parm, ran]
271
272 val xt = mkTuple [ty1, ty2]
273 in
274 unify state (pos, dom, xt);
275 (ran, "(" ^ es1 ^ ") :: (" ^ es2 ^ ")")
276 end
277 | StrCat_e (e1, e2) =>
278 let
279 val (ty1, es1) = xexp state e1
280 val (ty2, es2) = xexp state e2
281 in
282 unify state (pos, ty1, BasicTypes.stringTy);
283 unify state (pos, ty2, BasicTypes.stringTy);
284 (BasicTypes.stringTy, "(" ^ es1 ^ ") ^ (" ^ es2 ^ ")")
285 end
286 | Orelse_e (e1, e2) =>
287 let
288 val (ty1, es1) = xexp state e1
289 val (ty2, es2) = xexp state e2
290 in
291 unify state (pos, ty1, BasicTypes.boolTy);
292 unify state (pos, ty2, BasicTypes.boolTy);
293 (BasicTypes.boolTy, "(" ^ es1 ^ ") orelse (" ^ es2 ^ ")")
294 end
295 | Andalso_e (e1, e2) =>
296 let
297 val (ty1, es1) = xexp state e1
298 val (ty2, es2) = xexp state e2
299 in
300 unify state (pos, ty1, BasicTypes.boolTy);
301 unify state (pos, ty2, BasicTypes.boolTy);
302 (BasicTypes.boolTy, "(" ^ es1 ^ ") andalso (" ^ es2 ^ ")")
303 end
304 | Plus_e (e1, e2) =>
305 let
306 val (ty1, es1) = xexp state e1
307 val (ty2, es2) = xexp state e2
308 in
309 unify state (pos, ty1, BasicTypes.intTy);
310 unify state (pos, ty2, BasicTypes.intTy);
311 (BasicTypes.intTy, "(" ^ es1 ^ ") + (" ^ es2 ^ ")")
312 end
313 | Minus_e (e1, e2) =>
314 let
315 val (ty1, es1) = xexp state e1
316 val (ty2, es2) = xexp state e2
317 in
318 unify state (pos, ty1, BasicTypes.intTy);
319 unify state (pos, ty2, BasicTypes.intTy);
320 (BasicTypes.intTy, "(" ^ es1 ^ ") - (" ^ es2 ^ ")")
321 end
322 | Times_e (e1, e2) =>
323 let
324 val (ty1, es1) = xexp state e1
325 val (ty2, es2) = xexp state e2
326 in
327 unify state (pos, ty1, BasicTypes.intTy);
328 unify state (pos, ty2, BasicTypes.intTy);
329 (BasicTypes.intTy, "(" ^ es1 ^ ") * (" ^ es2 ^ ")")
330 end
331 | Divide_e (e1, e2) =>
332 let
333 val (ty1, es1) = xexp state e1
334 val (ty2, es2) = xexp state e2
335 in
336 unify state (pos, ty1, BasicTypes.intTy);
337 unify state (pos, ty2, BasicTypes.intTy);
338 (BasicTypes.intTy, "(" ^ es1 ^ ") div (" ^ es2 ^ ")")
339 end
340 | Mod_e (e1, e2) =>
341 let
342 val (ty1, es1) = xexp state e1
343 val (ty2, es2) = xexp state e2
344 in
345 unify state (pos, ty1, BasicTypes.intTy);
346 unify state (pos, ty2, BasicTypes.intTy);
347 (BasicTypes.intTy, "(" ^ es1 ^ ") mod (" ^ es2 ^ ")")
348 end
349 | Lt_e (e1, e2) =>
350 let
351 val (ty1, es1) = xexp state e1
352 val (ty2, es2) = xexp state e2
353 in
354 unify state (pos, ty1, BasicTypes.intTy);
355 unify state (pos, ty2, BasicTypes.intTy);
356 (BasicTypes.boolTy, "(" ^ es1 ^ ") < (" ^ es2 ^ ")")
357 end
358 | Lte_e (e1, e2) =>
359 let
360 val (ty1, es1) = xexp state e1
361 val (ty2, es2) = xexp state e2
362 in
363 unify state (pos, ty1, BasicTypes.intTy);
364 unify state (pos, ty2, BasicTypes.intTy);
365 (BasicTypes.boolTy, "(" ^ es1 ^ ") <= (" ^ es2 ^ ")")
366 end
367 | Gt_e (e1, e2) =>
368 let
369 val (ty1, es1) = xexp state e1
370 val (ty2, es2) = xexp state e2
371 in
372 unify state (pos, ty1, BasicTypes.intTy);
373 unify state (pos, ty2, BasicTypes.intTy);
374 (BasicTypes.boolTy, "(" ^ es1 ^ ") > (" ^ es2 ^ ")")
375 end
376 | Gte_e (e1, e2) =>
377 let
378 val (ty1, es1) = xexp state e1
379 val (ty2, es2) = xexp state e2
380 in
381 unify state (pos, ty1, BasicTypes.intTy);
382 unify state (pos, ty2, BasicTypes.intTy);
383 (BasicTypes.boolTy, "(" ^ es1 ^ ") >= (" ^ es2 ^ ")")
384 end
385 | Param_e => (BasicTypes.--> (BasicTypes.stringTy, BasicTypes.stringTy), "Web.getParam")
386 | Neg_e => (BasicTypes.--> (BasicTypes.intTy, BasicTypes.intTy), "~")
387 | Template_e name =>
388 if isTemplate state name then
389 let
390 fun toUpper ch = chr (ord ch + ord #"A" - ord #"a")
391 val name = str (toUpper (String.sub (name, 0))) ^ String.extract (name, 1, NONE)
392 in
393 (templateTy, "(Web.withParams " ^ name ^ ".exec)")
394 end
395 else
396 (error (SOME pos, "Unknown template " ^ name);
397 (errorTy, "<errorTemplate>"))
398 | Proj_e field =>
399 let
400 val carried = newTyvar false
401 in
402 (BasicTypes.--> (newFlex [(Symbol.labSymbol field, carried)], carried), "#" ^ field)
403 end
404 | Eq_e (e1, e2) =>
405 let
406 val (ty1, s1) = xexp state e1
407 val (ty2, s2) = xexp state e2
408 in
409 unify state (pos, ty1, ty2);
410 unify state (pos, ty1, newTyvar true);
411 (BasicTypes.boolTy, "(" ^ s1 ^ ") = (" ^ s2 ^ ")")
412 end
413 | Neq_e (e1, e2) =>
414 let
415 val (ty1, s1) = xexp state e1
416 val (ty2, s2) = xexp state e2
417 in
418 unify state (pos, ty1, ty2);
419 unify state (pos, ty1, newTyvar true);
420 (BasicTypes.boolTy, "(" ^ s1 ^ ") <> (" ^ s2 ^ ")")
421 end
422 | Ident_e [] => raise Fail "Impossible empty variable path"
423 | Ident_e [id] =>
424 (case getVar (state, id, SOME pos) of
425 NONE => (lookVal (state, id, pos), id)
426 | SOME (VAR ty) => (ty, id)
427 | SOME (REF ty) => (ty, "!" ^ id))
428 | Ident_e (path as (s::rest)) =>
429 (resolveVal (pos, state, path), foldl (fn (v, st) => st ^ "." ^ v) s rest)
430 | App_e (f, x) =>
431 let
432 val (ft, fs) = xexp state f
433 val (xt, xs) = xexp state x
434
435 (*val (ft, _) = TypesUtil.instantiatePoly ft*)
436 val dom = domain ft
437 val ran = range ft
438 in
439 unify state (pos, dom, xt);
440 (ran, "(" ^ fs ^ ") (" ^ xs ^ ")")
441 end
8291a2b9
AC
442 | Case_e (e, matches) =>
443 let
444 val (ty, s) = xexp state e
445
446 fun folder ((p, e'), (first, str, bodyTy)) =
447 let
448 val (pty, vars', ps) = xpat state p
449
450 val _ = unify state (pos, ty, pty)
451
452 val (ty', str') = xexp (addVars (state, vars')) e'
453 in
454 unify state (pos, ty', bodyTy);
455 (false,
456 str ^ (if first then " " else " | ") ^ "(" ^ ps ^ ") => " ^
457 str' ^ "\n",
458 bodyTy)
459 end
460 val bodyTy = newTyvar false
461 val (_, str, _) =
462 foldl folder (true, "(case (" ^ s ^ ") of\n", bodyTy) matches
463 val str = str ^ ")\n"
464 in
465 (bodyTy, str)
466 end
c0a3b488
AC
467 | Record_e (ist, cs) =>
468 let
469 val (cs, str) = foldl (fn ((id, e), (cs, str)) =>
470 let
471 val idSym = Symbol.labSymbol id
472 val _ = List.all (fn (id', _) => idSym <> id') cs
473 orelse error (SOME pos, "Duplicate label " ^ id ^ " in record")
474 val (ty, s) = xexp state e
475 in
476 ((idSym, ty) :: cs, str ^ ", " ^ id ^ " = " ^ s)
477 end) ([], "") cs
478 val cs = rev cs
479 val str =
480 case str of
481 "" => str
482 | _ => String.extract(str, 2, NONE)
483 val str = "{" ^ str ^ "}"
484 in
485 (BasicTypes.recordTy cs, str)
486 end
8291a2b9
AC
487 | Fn_e matches =>
488 let
489 val dom = newTyvar false
490 val ran = newTyvar false
491
492 fun folder ((p, e'), (first, str)) =
493 let
494 val (pty, vars', ps) = xpat state p
495
496 val _ = unify state (pos, dom, pty)
497
498 val (ty', str') = xexp (addVars (state, vars')) e'
499 in
500 unify state (pos, ty', ran);
501 (false,
502 str ^ (if first then " " else " | ") ^ "(" ^ ps ^ ") => " ^
503 str' ^ "\n")
504 end
505 val (_, str) =
506 foldl folder (true, "(fn \n") matches
507 val str = str ^ ")\n"
508 in
509 (BasicTypes.--> (dom, ran), str)
510 end
511 | Raise_e e =>
512 let
513 val (ty, es) = xexp state e
514 in
515 unify state (pos, ty, BasicTypes.exnTy);
516 (newTyvar false, "(raise (" ^ es ^ "))")
517 end
c0a3b488
AC
518 | RecordUpd_e (e, cs) =>
519 let
520 val (ty, es) = xexp state e
521
522 val cs' =
523 case TypesUtil.headReduceType ty of
524 Types.CONty (Types.RECORDtyc labs, tys) => ListPair.zip (labs, tys)
525 | _ => error (SOME pos, "Record update on non-record")
526
527 val (n, str) = foldl (fn ((id, ty), (n, str)) =>
528 case List.find (fn (id', _) => id = Symbol.labSymbol id') cs of
529 NONE => (n, str ^ ", " ^ Symbol.name id ^ " = #" ^
530 Symbol.name id ^ " " ^ "UPD'")
531 | SOME (_, e) =>
532 let
533 val (ty', s) = xexp state e
534 in
535 unify state (pos, ty, ty');
536 (n + 1, str ^ ", " ^ Symbol.name id ^ " = " ^ s)
537 end) (0, "") cs'
538
539 val _ = n = length cs
540 orelse error (SOME pos, "Updated fields in record update not found in starting expression")
541
542 val str =
543 case str of
544 "" => str
545 | _ => String.extract(str, 2, NONE)
546 val str = "let val UPD' = " ^ es ^ " in {" ^ str ^ "} end"
547 in
548 (ty, str)
549 end)
550 handle Skip => (errorTy, "<error>")
551
8291a2b9 552 and mergePatVars pos (vars1, vars2) =
c0a3b488
AC
553 StringMap.foldli (fn (v, ty, vars) =>
554 (case StringMap.find (vars, v) of
555 NONE => StringMap.insert (vars, v, ty)
556 | SOME _ => error (SOME pos, "Duplicate variable " ^ v ^ " in pattern"))) vars1 vars2
557
8291a2b9 558 and xpat state (PAT (p, pos)) =
c0a3b488
AC
559 (case p of
560 Ident_p [] => raise Fail "Impossible empty Ident_p"
561 | Ident_p [id] =>
562 ((lookCon' (state, id), StringMap.empty, id)
563 handle StaticEnv.Unbound =>
564 let
565 val ty = newTyvar false
566 in
567 (ty, StringMap.insert (StringMap.empty, id, VAR ty), id)
568 end)
569 | Ident_p (path as (s::rest)) =>
570 (resolveCon (pos, state, path), StringMap.empty, foldl (fn (v, st) => st ^ "." ^ v) s rest)
571 | Wild_p => (newTyvar false, StringMap.empty, "_")
572 | Int_p n => (BasicTypes.intTy, StringMap.empty, Int.toString n)
8291a2b9 573 | Real_p n => (BasicTypes.realTy, StringMap.empty, Real.toString n)
c0a3b488 574 | String_p s => (BasicTypes.stringTy, StringMap.empty, "\"" ^ s ^ "\"")
8291a2b9 575 | Char_p s => (BasicTypes.charTy, StringMap.empty, "#\"" ^ s ^ "\"")
c0a3b488
AC
576 | App_p ([], _) => raise Fail "Impossible App_p"
577 | App_p ([id], p) =>
578 let
579 val (ty, vars, s) = xpat state p
580 val tyc = lookCon (state, id, pos)
581 val dom = domain tyc
582 in
583 unify state (pos, dom, ty);
584 (range tyc, vars, id ^ " (" ^ s ^ ")")
585 end
586 | App_p (path as (fst::rest), p) =>
587 let
588 val (ty, vars, s) = xpat state p
589 val tyc = resolveCon (pos, state, path)
590 val dom = domain tyc
591 in
592 unify state (pos, dom, ty);
593 (range tyc, vars, foldl (fn (n, st) => st ^ "." ^ n) fst rest ^ " (" ^ s ^ ")")
594 end
595 | Cons_p (p1, p2) =>
596 let
597 val (ty1, vars', s1) = xpat state p1
598 val (ty2, vars'', s2) = xpat state p2
599
600 val resty = Types.CONty (BasicTypes.listTycon, [ty1])
601 in
602 unify state (pos, ty2, resty);
603 (resty, mergePatVars pos (vars', vars''), "(" ^ s1 ^ ")::(" ^ s2 ^ ")")
604 end
605 | As_p (id, p) =>
606 let
607 val (ty, vars, s) = xpat state p
608 in
609 not (Option.isSome (StringMap.find(vars, id)))
610 orelse error (SOME pos, "Duplicate variable " ^ id ^ " in pattern");
611 (ty, StringMap.insert (vars, id, VAR ty), id ^ " as (" ^ s ^ ")")
612 end
613 | Record_p (ist, cs) =>
614 let
615 val (cs, vars, str) = foldl (fn ((id, p), (cs, vars, str)) =>
616 let
617 val (ty, vars', s) = xpat state p
618 in
619 ((Symbol.labSymbol id, ty)::cs, mergePatVars pos (vars, vars'),
620 str ^ ", " ^ id ^ " = " ^ s)
621 end) ([], StringMap.empty, "") cs
622 val cs = rev cs
623 val str =
624 if String.size str >= 2 then
625 String.extract(str, 2, NONE)
626 else
627 str
628 val str = "{" ^ str ^ "}"
629 in
630 (BasicTypes.recordTy cs, vars, str)
631 end
632 | FlexRecord_p cs =>
633 let
634 val (cs, vars, str) = foldl (fn ((id, p), (cs, vars, str)) =>
635 let
636 val (ty, vars', s) = xpat state p
637 in
638 ((Symbol.labSymbol id, ty)::cs, mergePatVars pos (vars, vars'),
639 str ^ ", " ^ id ^ " = " ^ s)
640 end) ([], StringMap.empty, "") cs
641 val cs = rev cs
642 val str =
643 if String.size str >= 2 then
644 String.extract(str, 2, NONE)
645 else
646 str
647 val str = "{" ^ str ^ ", ...}"
648 in
649 (newFlex cs, vars, str)
650 end
651 (*| _ =>
652 error (SOME pos, "Not done yet!!!")*))
653 handle Skip => (errorTy, StringMap.empty, "<error>")
654
655 fun xblock state (BLOCK (blocks, pos)) =
656 let
657 fun folder (BITEM (bi, pos), (state, str)) =
658 (case bi of
659 Html_i s =>
660 (state, str ^ "val _ = Web.print (\"" ^ escapeString s ^ "\")\n")
661 | Ref_i rs =>
662 let
663 fun folder ((id, e), (state, str)) =
664 let
665 val (ty, es) = xexp state e
666
667 val state = addVar (state, id, REF ty)
668 in
669 (state, str ^ "val " ^ id ^ " = ref (" ^ es ^ ")\n")
670 end
671 in
672 foldl folder (state, str) rs
673 end
674 | Assn_i (id, e) =>
675 let
676 val vty =
677 case getVar (state, id, SOME pos) of
678 NONE => error (SOME pos, "Unbound variable " ^ id)
679 | SOME (REF vty) => vty
680 | _ => error (SOME pos, "Can't assign to non-ref variable " ^ id)
681
682 val (ty, es) = xexp state e
683 in
684 unify state (pos, ty, vty);
685 (state, str ^ "val _ = " ^ id ^ " := (" ^ es ^ ")\n")
686 end
687 | Val_i (p, e) =>
688 let
689 val (pty, vars, ps) = xpat state p
690 val state' = addVars (state, vars)
691 val (ty, es) = xexp state e
692 in
693 unify state (pos, pty, ty);
694 (state', str ^ "val " ^ ps ^ " = (" ^ es ^ ")\n")
695 end
696 | Exp_i e =>
697 let
698 val (ty, s) = xexp state e
699 val ty = TypesUtil.headReduceType ty
700 val printFn =
701 case printFn state ty of
702 NONE => (if tyToString state ty = "_" then
703 ()
704 else
705 error (SOME pos, "Unable to convert value of type " ^
706 tyToString state ty ^ " to string");
707 "<errorPrint>")
708 | SOME v => v
709 in
710 (state, str ^ "val _ = " ^ printFn ^ " (" ^ s ^ ")\n")
711 end
8291a2b9 712 | Ifthenelse_i (e, b, els) =>
c0a3b488
AC
713 let
714 val str = str ^ "val _ = "
8291a2b9
AC
715 val (ty, s) = xexp state e
716 val (_, str') = xblock state b
717 val _ = unify state (pos, ty, BasicTypes.boolTy)
718 val str = str ^ "if (" ^ s ^ ") then let\n" ^
719 str' ^
720 "in () end\n"
c0a3b488
AC
721 val str =
722 case els of
723 NONE =>
724 str ^ "else ()\n"
725 | SOME els =>
726 let
727 val (_, str') = xblock state els
728 in
729 str ^ "else let\n" ^
730 str' ^
731 "in () end\n"
732 end
733 in
734 (state, str)
735 end
736 | Foreach_i (id, e, b) =>
737 let
738 val parm = newTyvar false
739
740 val (ty, es) = xexp state e
741
742 val _ = unify state (pos, ty, Types.CONty (BasicTypes.listTycon, [parm]))
743
744 (*val _ = print ("... to " ^ tyToString (context, ivmap, pty) ^ "\n")*)
745
746 val state = addVar (state, id, VAR parm)
747 val (_, bs) = xblock state b
748 in
8291a2b9
AC
749 (state, str ^ "fun foreach (" ^ id ^ " : " ^
750 tyToString state parm ^ ") = let\n" ^
c0a3b488
AC
751 bs ^
752 "in () end\n" ^
753 "val _ = app foreach (" ^ es ^ ")\n")
754 end
755 | For_i (id, eFrom, eTo, b) =>
756 let
757 val (ty1, es1) = xexp state eFrom
758 val _ = unify state (pos, ty1, BasicTypes.intTy)
759
760 val (ty2, es2) = xexp state eTo
761 val _ = unify state (pos, ty2, BasicTypes.intTy)
762
763 val state = addVar (state, id, VAR BasicTypes.intTy)
764 val (_, bs) = xblock state b
765 in
766 (state, str ^ "fun forFunc " ^ id ^ " = let\n" ^
767 bs ^
768 "in () end\n" ^
8291a2b9 769 "val _ = Web.for forFunc (" ^ es1 ^ ", " ^ es2 ^ ")\n")
c0a3b488
AC
770 end
771 | Case_i (e, matches) =>
772 let
773 val (ty, s) = xexp state e
774
775 fun folder ((p, b), (first, str)) =
776 let
777 val (pty, vars', ps) = xpat state p
778
779 val _ = unify state (pos, ty, pty)
780
781 val (_, str') = xblock (addVars (state, vars')) b
782
783 (*val _ = print ("Pattern type: " ^ tyToString (context, ivmap, pty) ^ " vs. " ^ tyToString (context, ivmap, ty) ^ "\n")*)
784 in
785 (false,
786 str ^ (if first then " " else " | ") ^ "(" ^ ps ^ ") => let\n" ^
787 str' ^
788 "in () end\n")
789 end
790 val (_, str) =
791 foldl folder (true, str ^ "val _ = (case (" ^ s ^ ") of\n") matches
792 val str = str ^ ") handle Match => ()\n"
793 in
794 (state, str)
795 end
796 | TryCatch_i (b, matches) =>
797 let
798 val (_, bs) = xblock state b
799
800 fun folder ((p, b), (first, str)) =
801 let
802 val (pty, vars, ps) = xpat state p
803 val state = addVars (state, vars)
804 val (_, str') = xblock state b
805 in
806 unify state (pos, BasicTypes.exnTy, pty);
807 (false,
808 str ^ (if first then " " else " | ") ^ "(" ^ ps ^ ") => let\n" ^
809 str' ^
810 "in () end\n")
811 end
812 val (_, str) =
813 foldl folder (true,
814 str ^ "val _ = (let\n" ^
815 bs ^
816 "in () end handle\n") matches
817 val str = str ^ ")\n"
818 in
819 (state, str)
820 end
821 | Open_i paths =>
822 let
823 fun folder (path, state) = openStructure (pos, state, path)
824
825 val str = foldl (fn (path, str) => str ^ " " ^ Tree.pathString path) (str ^ "open") paths
826 val str = str ^ "\n"
827 in
828 (foldl folder state paths, str)
829 end)
830 handle Skip => (state, str)
831 in
832 foldl folder (state, "") blocks
833 end
834
835 fun trans (config, env, templates, name, block) =
836 let
837 val state = mkState (config, env, templates)
838 val (_, str) = xblock state block
839 in
840 "(* This file generated automatically by something or other *)\n" ^
841 "\n" ^
842 "structure " ^ name ^ " :> TEMPLATE =\n" ^
843 "struct\n" ^
844 "fun exec () = let\n" ^
845 str ^
846 "in () end\n" ^
847 "end\n"
848 end
849end
850
851