1 (* Title: Pure/Tools/codegen_serializer.ML
3 Author: Florian Haftmann, TU Muenchen
5 Serializer from intermediate language ("Thin-gol") to
6 target languages (like SML or Haskell).
9 signature CODEGEN_SERIALIZER =
11 include BASIC_CODEGEN_THINGOL;
13 val add_pretty_list: string -> string -> string -> (Pretty.T list -> Pretty.T)
14 -> ((string -> string) * (string -> string)) option -> int * string
16 val add_pretty_ml_string: string -> string -> string -> string
17 -> (string -> string) -> (string -> string) -> string -> theory -> theory;
18 val add_undefined: string -> string -> string -> theory -> theory;
21 val add_serializer : string * serializer -> theory -> theory;
22 val ml_from_thingol: serializer;
23 val hs_from_thingol: serializer;
24 val get_serializer: theory -> string * Args.T list
25 -> string list option -> CodegenThingol.code -> unit;
27 val const_has_serialization: theory -> string list -> string -> bool;
28 val tyco_has_serialization: theory -> string list -> string -> bool;
30 val eval_verbose: bool ref;
31 val eval_term: theory ->
32 (string * 'a option ref) * CodegenThingol.iterm -> CodegenThingol.code
36 structure CodegenSerializer: CODEGEN_SERIALIZER =
39 open BasicCodegenThingol;
40 val tracing = CodegenThingol.tracing;
46 datatype lrx = L | R | X;
51 | INFX of (int * lrx);
53 type 'a pretty_syntax = int * (fixity -> (fixity -> 'a -> Pretty.T)
54 -> 'a list -> Pretty.T);
56 fun eval_lrx L L = false
57 | eval_lrx R R = false
58 | eval_lrx _ _ = true;
60 fun eval_fxy NOBR _ = false
61 | eval_fxy _ BR = true
62 | eval_fxy _ NOBR = false
63 | eval_fxy (INFX (pr, lr)) (INFX (pr_ctxt, lr_ctxt)) =
66 andalso eval_lrx lr lr_ctxt
67 | eval_fxy _ (INFX _) = false;
69 fun gen_brackify _ [p] = p
70 | gen_brackify true (ps as _::_) = Pretty.enclose "(" ")" ps
71 | gen_brackify false (ps as _::_) = Pretty.block ps;
73 fun brackify fxy_ctxt ps =
74 gen_brackify (eval_fxy BR fxy_ctxt) (Pretty.breaks ps);
76 fun brackify_infix infx fxy_ctxt ps =
77 gen_brackify (eval_fxy (INFX infx) fxy_ctxt) (Pretty.breaks ps);
79 fun mk_app mk_app' from_expr const_syntax fxy (const as (c, (_, ty)), es) =
81 of NONE => brackify fxy (mk_app' c es)
84 val k = if i < 0 then (length o fst o CodegenThingol.unfold_fun) ty else i
86 then case chop i es of (es1, es2) =>
87 brackify fxy (pr fxy from_expr es1 :: map (from_expr BR) es2)
88 else from_expr fxy (CodegenThingol.eta_expand (const, es) i)
91 val first_upper = implode o nth_map 0 Symbol.to_ascii_upper o explode;
94 (* user-defined syntax *)
96 val str = setmp print_mode [] Pretty.str;
98 val (atomK, infixK, infixlK, infixrK) =
99 ("target_atom", "infix", "infixl", "infixr");
100 val _ = OuterSyntax.add_keywords [atomK, infixK, infixlK, infixrK];
104 | Pretty of Pretty.T;
106 fun fillin_mixfix fxy_this ms fxy_ctxt pr args =
110 | fillin (Arg fxy :: ms) (a :: args) =
111 pr fxy a :: fillin ms args
112 | fillin (Pretty p :: ms) args =
115 error ("Inconsistent mixfix: too many arguments")
117 error ("Inconsistent mixfix: too less arguments");
118 in gen_brackify (eval_fxy fxy_this fxy_ctxt) (fillin ms args) end;
120 fun parse_infix (fixity as INFX (i, x)) s =
122 val l = case x of L => fixity
124 val r = case x of R => fixity
127 [Arg l, (Pretty o Pretty.brk) 1, (Pretty o str) s, (Pretty o Pretty.brk) 1, Arg r]
132 val sym_any = Scan.one Symbol.not_eof;
133 val parse = Scan.repeat (
134 ($$ "_" -- $$ "_" >> K (Arg NOBR))
135 || ($$ "_" >> K (Arg BR))
136 || ($$ "/" |-- Scan.repeat ($$ " ") >> (Pretty o Pretty.brk o length))
139 || Scan.unless ($$ "_" || $$ "/")
140 sym_any) >> (Pretty o str o implode)));
141 in case Scan.finite Symbol.stopper parse (Symbol.explode s)
143 | _ => error ("Malformed mixfix annotation: " ^ quote s)
146 fun parse_syntax num_args =
148 fun is_arg (Arg _) = true
150 fun parse_nonatomic s =
153 error ("Mixfix contains just one pretty element; either declare as "
154 ^ quote atomK ^ " or consider adding a break")
156 fun mk fixity mfx ctxt =
158 val i = (length o List.filter is_arg) mfx;
159 val _ = if i > num_args ctxt then error "Too many arguments in code syntax" else ();
160 in (i, fillin_mixfix fixity mfx) end;
162 OuterParse.$$$ infixK |-- OuterParse.nat
163 >> (fn i => (parse_infix (INFX (i, X)), INFX (i, X)))
164 || OuterParse.$$$ infixlK |-- OuterParse.nat
165 >> (fn i => (parse_infix (INFX (i, L)), INFX (i, L)))
166 || OuterParse.$$$ infixrK |-- OuterParse.nat
167 >> (fn i => (parse_infix (INFX (i, R)), INFX (i, R)))
168 || OuterParse.$$$ atomK |-- pair (parse_mixfix, NOBR)
169 || pair (parse_nonatomic, BR)
170 ) -- OuterParse.string >> (fn ((p, fxy), s) => (p s, fxy));
172 parse #-> (fn (mfx, fixity) => pair (mk fixity mfx))
176 (* list and string serializer *)
178 fun implode_list c_nil c_cons e =
180 fun dest_cons (IConst (c, _) `$ e1 `$ e2) =
184 | dest_cons _ = NONE;
185 val (es, e') = CodegenThingol.unfoldr dest_cons e;
187 of IConst (c, _) => if c = c_nil then SOME es else NONE
191 fun implode_string mk_char mk_string es =
192 if forall (fn IChar _ => true | _ => false) es
193 then (SOME o str o mk_string o implode o map (fn IChar (c, _) => mk_char c)) es
196 fun pretty_ml_string c_nil c_cons mk_char mk_string target_implode =
198 fun pretty fxy pr [e] =
199 case implode_list c_nil c_cons e
200 of SOME es => (case implode_string mk_char mk_string es
202 | NONE => Pretty.block [str target_implode, Pretty.brk 1, pr BR e])
203 | NONE => Pretty.block [str target_implode, Pretty.brk 1, pr BR e]
206 fun pretty_list c_nil c_cons mk_list mk_char_string (target_fxy, target_cons) =
208 fun default fxy pr e1 e2 =
209 brackify_infix (target_fxy, R) fxy [
210 pr (INFX (target_fxy, X)) e1,
212 pr (INFX (target_fxy, R)) e2
214 fun pretty fxy pr [e1, e2] =
215 case Option.map (cons e1) (implode_list c_nil c_cons e2)
218 of SOME (mk_char, mk_string) =>
219 (case implode_string mk_char mk_string es
221 | NONE => mk_list (map (pr NOBR) es))
222 | NONE => mk_list (map (pr NOBR) es))
223 | NONE => default fxy pr e1 e2;
227 (* variable name contexts *)
229 (*FIXME could name.ML do th whole job?*)
230 fun make_vars names = (fold (fn name => Symtab.update_new (name, name)) names Symtab.empty,
231 Name.make_context names);
233 fun intro_vars names (namemap, namectxt) =
235 val (names', namectxt') = Name.variants names namectxt;
236 val namemap' = fold2 (curry Symtab.update) names names' namemap;
237 in (namemap', namectxt') end;
239 fun lookup_var (namemap, _) name = case Symtab.lookup namemap name
240 of SOME name' => name'
241 | NONE => error ("invalid name in context: " ^ quote name);
243 fun constructive_fun (name, (eqs, ty)) =
245 val is_cons = CodegenNames.has_nsp CodegenNames.nsp_dtco;
246 fun is_pat (IConst (c, _)) = is_cons c
247 | is_pat (IVar _) = true
248 | is_pat (t1 `$ t2) =
249 is_pat t1 andalso is_pat t2
250 | is_pat (INum _) = true
251 | is_pat (IChar _) = true
253 fun check_eq (eq as (lhs, rhs)) =
256 else (warning ("In function " ^ quote name ^ ", throwing away one "
257 ^ "non-executable function clause"); NONE)
258 in case map_filter check_eq eqs
259 of [] => error ("In function " ^ quote name ^ ", no "
260 ^ "executable function clauses found")
261 | eqs => (name, (eqs, ty))
265 (** SML serializer **)
268 MLFuns of (string * ((iterm list * iterm) list * typscheme)) list
269 | MLDatas of (string * ((vname * sort) list * (string * itype list) list)) list
270 | MLClass of string * (class list * (vname * (string * itype) list))
271 | MLClassinst of string * ((class * (string * (vname * sort) list))
272 * ((class * (string * inst list list)) list
273 * (string * iterm) list));
275 fun pr_sml_def tyco_syntax const_syntax keyword_vars deresolv ml_def =
277 val is_cons = CodegenNames.has_nsp CodegenNames.nsp_dtco;
280 val label = translate_string (fn "." => "__" | c => c)
281 o NameSpace.pack o op @ o apsnd single o apfst (fst o split_last) o split_last o NameSpace.unpack;
282 fun pr_tyvar (v, []) =
284 | pr_tyvar (v, sort) =
287 str ("'" ^ v ^ " " ^ deresolv class);
294 of [class] => pr_class class
295 | _ => Pretty.enum " *" "" "" (map pr_class sort),
299 fun pr_insts fxy iys =
301 fun pr_proj s = str ("#" ^ s);
306 | pr_lookup (ps as _ :: _) p =
307 brackify BR [Pretty.enum " o" "(" ")" ps, p];
308 fun pr_inst fxy (Instance (inst, iss)) =
310 (str o deresolv) inst
311 :: map (pr_insts BR) iss
313 | pr_inst fxy (Context (classes, (v, i))) =
314 pr_lookup (map (pr_proj o label) classes
315 @ (if i = ~1 then [] else [(pr_proj o string_of_int) (i+1)])
316 ) ((str o dictvar) v);
319 | [iy] => pr_inst fxy iy
320 | _ :: _ => (Pretty.list "(" ")" o map (pr_inst NOBR)) iys
322 fun pr_tycoexpr fxy (tyco, tys) =
324 val tyco' = (str o deresolv) tyco
325 in case map (pr_typ BR) tys
327 | [p] => Pretty.block [p, Pretty.brk 1, tyco']
328 | (ps as _::_) => Pretty.block [Pretty.list "(" ")" ps, Pretty.brk 1, tyco']
330 and pr_typ fxy (tyco `%% tys) =
331 (case tyco_syntax tyco
332 of NONE => pr_tycoexpr fxy (tyco, tys)
334 if not (i = length tys)
335 then error ("Number of argument mismatch in customary serialization: "
336 ^ (string_of_int o length) tys ^ " given, "
337 ^ string_of_int i ^ " expected")
338 else pr fxy pr_typ tys)
339 | pr_typ fxy (t1 `-> t2) =
340 (gen_brackify (case fxy of BR => false | _ => eval_fxy (INFX (1, R)) fxy)
342 pr_typ (INFX (1, X)) t1,
344 pr_typ (INFX (1, R)) t2
346 | pr_typ fxy (ITyVar v) =
348 fun pr_term vars fxy (IConst c) =
349 pr_app vars fxy (c, [])
350 | pr_term vars fxy (IVar v) =
351 str (lookup_var vars v)
352 | pr_term vars fxy (t as t1 `$ t2) =
353 (case CodegenThingol.unfold_const_app t
354 of SOME c_ts => pr_app vars fxy c_ts
356 brackify fxy [pr_term vars NOBR t1, pr_term vars BR t2 ])
357 | pr_term vars fxy (t as _ `|-> _) =
359 val (ts, t') = CodegenThingol.unfold_abs t;
360 val vs = fold (CodegenThingol.fold_varnames (insert (op =)) o fst) ts [];
361 val vars' = intro_vars vs vars;
362 fun mk_abs (t, ty) = (Pretty.block o Pretty.breaks)
363 [str "fn", pr_term vars' NOBR t, str "=>"];
364 in brackify BR (map mk_abs ts @ [pr_term vars' NOBR t']) end
365 | pr_term vars fxy (INum (n, _)) =
366 brackify BR [(str o IntInf.toString) n, str ":", str "IntInf.int"]
367 | pr_term vars _ (IChar (c, _)) =
368 (str o prefix "#" o quote)
371 then prefix "\\" (string_of_int i)
374 | pr_term vars fxy (t as ICase ((_, [_]), _)) =
376 val (ts, t) = CodegenThingol.unfold_let t;
377 fun mk ((p, _), t) vars =
379 val vs = CodegenThingol.fold_varnames (insert (op =)) p [];
380 val vars' = intro_vars vs vars;
383 (Pretty.block o Pretty.breaks) [
385 pr_term vars' NOBR p,
392 val (binds, vars') = fold_map mk ts vars;
395 [str ("let"), Pretty.fbrk, binds |> Pretty.chunks] |> Pretty.block,
396 [str ("in"), Pretty.fbrk, pr_term vars' NOBR t] |> Pretty.block,
399 | pr_term vars fxy (ICase (((td, ty), b::bs), _)) =
401 fun pr definer (p, t) =
403 val vs = CodegenThingol.fold_varnames (insert (op =)) p [];
404 val vars' = intro_vars vs vars;
406 (Pretty.block o Pretty.breaks) [
408 pr_term vars' NOBR p,
414 (Pretty.enclose "(" ")" o single o brackify fxy) (
416 :: pr_term vars NOBR td
421 and pr_app' vars c ts =
423 val p = (str o deresolv) c;
424 val ps = map (pr_term vars BR) ts;
425 in if is_cons c andalso length ts > 1 then
426 [p, Pretty.enum "," "(" ")" ps]
430 and pr_app vars fxy (app as ((c, (iss, ty)), ts)) =
431 case if is_cons c then [] else (map (pr_insts BR) o filter_out null) iss
433 mk_app (pr_app' vars) (pr_term vars) const_syntax fxy app
435 if (is_none o const_syntax) c then
436 brackify fxy ((str o deresolv) c :: (ps @ map (pr_term vars BR) ts))
438 error ("Cannot apply user defined serialization for function expecting dictionaries: " ^ quote c)
439 fun eta_expand_poly_fun (funn as (_, (_::_, _))) =
441 | eta_expand_poly_fun (funn as (_, ([_], ([], _)))) =
443 | eta_expand_poly_fun (funn as (_, ([(_::_, _)], _))) =
445 | eta_expand_poly_fun (funn as (_, ([(_, _ `|-> _)], _))) =
447 | eta_expand_poly_fun (funn as (name, ([([], t)], tysm as (vs, ty)))) =
448 if (null o fst o CodegenThingol.unfold_fun) ty
449 orelse (not o null o filter_out (null o snd)) vs
451 else (name, ([([IVar "x"], t `$ IVar "x")], tysm));
452 fun pr_def (MLFuns raw_funns) =
454 val funns as (funn :: funns') = map (eta_expand_poly_fun o constructive_fun) raw_funns;
458 | mk (_::_) _ = "fun"
459 | mk [] vs = if (null o filter_out (null o snd)) vs then "val" else "fun";
460 fun chk (_, ((ts, _) :: _, (vs, _))) NONE = SOME (mk ts vs)
461 | chk (_, ((ts, _) :: _, (vs, _))) (SOME defi) =
462 if defi = mk ts vs then SOME defi
463 else error ("Mixing simultaneous vals and funs not implemented");
464 in the (fold chk funns NONE) end;
465 fun pr_funn definer (name, (eqs as eq::eqs', (raw_vs, ty))) =
467 val vs = filter_out (null o snd) raw_vs;
468 val shift = if null eqs' then I else
469 map (Pretty.block o single o Pretty.block o single);
470 fun pr_eq definer (ts, t) =
472 val consts = map_filter
473 (fn c => if (is_some o const_syntax) c
474 then NONE else (SOME o NameSpace.base o deresolv) c)
475 ((fold o CodegenThingol.fold_constnames) (insert (op =)) (t :: ts) []);
476 val vars = keyword_vars
478 |> intro_vars ((fold o CodegenThingol.fold_unbound_varnames) (insert (op =)) (t :: ts) []);
480 (Pretty.block o Pretty.breaks) (
481 [str definer, (str o deresolv) name]
482 @ (if null ts andalso null vs
483 andalso not (ty = ITyVar "_")(*for evaluation*)
484 then [str ":", pr_typ NOBR ty]
487 @ map (pr_term vars BR) ts)
488 @ [str "=", pr_term vars NOBR t]
492 (Pretty.block o Pretty.fbreaks o shift) (
494 :: map (pr_eq "|") eqs'
497 val (ps, p) = split_last (pr_funn definer funn :: map (pr_funn "and") funns');
498 in Pretty.chunks (ps @ [Pretty.block ([p, str ";"])]) end
499 | pr_def (MLDatas (datas as (data :: datas'))) =
504 (Pretty.block o Pretty.breaks) [
507 Pretty.enum " *" "" "" (map (pr_typ (INFX (2, L))) tys)
509 fun pr_data definer (tyco, (vs, cos)) =
510 (Pretty.block o Pretty.breaks) (
512 :: pr_tycoexpr NOBR (tyco, map (ITyVar o fst) vs)
514 :: separate (str "|") (map pr_co cos)
516 val (ps, p) = split_last (pr_data "datatype" data :: map (pr_data "and") datas');
517 in Pretty.chunks (ps @ [Pretty.block ([p, str ";"])]) end
518 | pr_def (MLClass (class, (superclasses, (v, classops)))) =
521 fun pr_superclass class =
522 (Pretty.block o Pretty.breaks o map str) [
523 label class, ":", "'" ^ v, deresolv class
525 fun pr_classop (classop, ty) =
526 (Pretty.block o Pretty.breaks) [
527 (str o suffix "_" o NameSpace.base) classop, str ":", pr_typ NOBR ty
529 fun pr_classop_fun (classop, _) =
530 (Pretty.block o Pretty.breaks) [
532 (str o deresolv) classop,
533 Pretty.enclose "(" ")" [str (w ^ ":'" ^ v ^ " " ^ deresolv class)],
535 str ("#" ^ (suffix "_" o NameSpace.base) classop),
540 (Pretty.block o Pretty.breaks) [
542 (str o deresolv) class,
544 Pretty.enum "," "{" "};" (
545 map pr_superclass superclasses @ map pr_classop classops
548 :: map pr_classop_fun classops
551 | pr_def (MLClassinst (inst, ((class, (tyco, arity)), (superarities, classop_defs)))) =
553 fun pr_superclass (superclass, superinst_iss) =
554 (Pretty.block o Pretty.breaks) [
555 (str o label) superclass,
557 pr_insts NOBR [Instance superinst_iss]
559 fun pr_classop_def (classop, t) =
561 val consts = map_filter
562 (fn c => if (is_some o const_syntax) c
563 then NONE else (SOME o NameSpace.base o deresolv) c)
564 (CodegenThingol.fold_constnames (insert (op =)) t []);
565 val vars = keyword_vars
566 |> intro_vars consts;
568 (Pretty.block o Pretty.breaks) [
569 (str o suffix "_" o NameSpace.base) classop,
575 (Pretty.block o Pretty.breaks) ([
576 str (if null arity then "val" else "fun"),
577 (str o deresolv) inst ] @
578 map pr_tyvar arity @ [
580 Pretty.enum "," "{" "}" (map pr_superclass superarities @ map pr_classop_def classop_defs),
582 pr_tycoexpr NOBR (class, [tyco `%% map (ITyVar o fst) arity])
585 in pr_def ml_def end;
589 (** Haskell serializer **)
591 fun pr_haskell class_syntax tyco_syntax const_syntax keyword_vars deresolv_here deresolv def =
593 val is_cons = CodegenNames.has_nsp CodegenNames.nsp_dtco;
594 fun class_name class = case class_syntax class
595 of NONE => deresolv class
596 | SOME (class, _) => class;
597 fun classop_name class classop = case class_syntax class
598 of NONE => NameSpace.base classop
599 | SOME (_, classop_syntax) => case classop_syntax classop
600 of NONE => NameSpace.base classop
601 | SOME classop => classop
602 fun pr_typparms tyvars vs =
603 case maps (fn (v, sort) => map (pair v) sort) vs
605 | xs => Pretty.block [
606 Pretty.enum "," "(" ")" (
607 map (fn (v, class) => str
608 (class_name class ^ " " ^ lookup_var tyvars v)) xs
612 fun pr_tycoexpr tyvars fxy (tyco, tys) =
613 brackify fxy (str tyco :: map (pr_typ tyvars BR) tys)
614 and pr_typ tyvars fxy (tycoexpr as tyco `%% tys) =
615 (case tyco_syntax tyco
617 pr_tycoexpr tyvars fxy (deresolv tyco, tys)
619 if not (i = length tys)
620 then error ("Number of argument mismatch in customary serialization: "
621 ^ (string_of_int o length) tys ^ " given, "
622 ^ string_of_int i ^ " expected")
623 else pr fxy (pr_typ tyvars) tys)
624 | pr_typ tyvars fxy (t1 `-> t2) =
625 brackify_infix (1, R) fxy [
626 pr_typ tyvars (INFX (1, X)) t1,
628 pr_typ tyvars (INFX (1, R)) t2
630 | pr_typ tyvars fxy (ITyVar v) =
631 (str o lookup_var tyvars) v;
632 fun pr_typscheme_expr tyvars (vs, tycoexpr) =
633 Pretty.block [pr_typparms tyvars vs, pr_tycoexpr tyvars NOBR tycoexpr];
634 fun pr_typscheme tyvars (vs, ty) =
635 Pretty.block [pr_typparms tyvars vs, pr_typ tyvars NOBR ty];
636 fun pr_term vars fxy (IConst c) =
637 pr_app vars fxy (c, [])
638 | pr_term vars fxy (t as (t1 `$ t2)) =
639 (case CodegenThingol.unfold_const_app t
640 of SOME app => pr_app vars fxy app
643 pr_term vars NOBR t1,
646 | pr_term vars fxy (IVar v) =
647 (str o lookup_var vars) v
648 | pr_term vars fxy (t as _ `|-> _) =
650 val (ts, t') = CodegenThingol.unfold_abs t;
651 val vs = fold (CodegenThingol.fold_varnames (insert (op =)) o fst) ts [];
652 val vars' = intro_vars vs vars;
656 :: map (pr_term vars' BR o fst) ts @ [
658 pr_term vars' NOBR t'
661 | pr_term vars fxy (INum (n, _)) =
663 (str o IntInf.toString) n
665 brackify BR [(str o Library.prefix "-" o IntInf.toString o IntInf.~) n]
666 | pr_term vars fxy (IChar (c, _)) =
667 (str o enclose "'" "'")
668 (let val i = (Char.ord o the o Char.fromString) c
670 then Library.prefix "\\" (string_of_int i)
673 | pr_term vars fxy (t as ICase ((_, [_]), _)) =
675 val (ts, t) = CodegenThingol.unfold_let t;
676 fun pr ((p, _), t) vars =
678 val vs = CodegenThingol.fold_varnames (insert (op =)) p [];
679 val vars' = intro_vars vs vars;
681 ((Pretty.block o Pretty.breaks) [
687 val (binds, vars') = fold_map pr ts vars;
689 [str ("let"), Pretty.fbrk, binds |> Pretty.chunks] |> Pretty.block,
690 [str ("in "), pr_term vars' NOBR t] |> Pretty.block
692 | pr_term vars fxy (ICase (((td, _), bs), _)) =
696 val vs = CodegenThingol.fold_varnames (insert (op =)) p [];
697 val vars' = intro_vars vs vars;
699 (Pretty.block o Pretty.breaks) [
700 pr_term vars' NOBR p,
706 (Pretty.enclose "(" ")" o Pretty.breaks) [
708 pr_term vars NOBR td,
710 (Pretty.chunks o map pr) bs
713 and pr_app' vars c ts =
714 (str o deresolv) c :: map (pr_term vars BR) ts
715 and pr_app vars fxy =
716 mk_app (pr_app' vars) (pr_term vars) const_syntax fxy;
717 fun pr_def (name, CodegenThingol.Fun (funn as (eqs, (vs, ty)))) =
719 val tyvars = intro_vars (map fst vs) keyword_vars;
722 val consts = map_filter
723 (fn c => if (is_some o const_syntax) c
724 then NONE else (SOME o NameSpace.base o deresolv) c)
725 ((fold o CodegenThingol.fold_constnames) (insert (op =)) (t :: ts) []);
726 val vars = keyword_vars
728 |> intro_vars ((fold o CodegenThingol.fold_unbound_varnames) (insert (op =)) (t :: ts) []);
730 (Pretty.block o Pretty.breaks) (
731 (str o deresolv_here) name
732 :: map (pr_term vars BR) ts
733 @ [str "=", pr_term vars NOBR t]
739 (str o suffix " ::" o deresolv_here) name,
741 pr_typscheme tyvars (vs, ty)
743 :: (map pr_eq o fst o snd o constructive_fun) (name, funn)
746 | pr_def (name, CodegenThingol.Datatype (vs, [(co, [ty])])) =
748 val tyvars = intro_vars (map fst vs) keyword_vars;
750 (Pretty.block o Pretty.breaks) [
752 pr_typscheme_expr tyvars (vs, (deresolv_here name, map (ITyVar o fst) vs)),
754 (str o deresolv_here) co,
758 | pr_def (name, CodegenThingol.Datatype (vs, co :: cos)) =
760 val tyvars = intro_vars (map fst vs) keyword_vars;
761 fun pr_co (co, tys) =
762 (Pretty.block o Pretty.breaks) (
763 (str o deresolv_here) co
764 :: map (pr_typ tyvars BR) tys
767 (Pretty.block o Pretty.breaks) (
769 :: pr_typscheme_expr tyvars (vs, (deresolv_here name, map (ITyVar o fst) vs))
772 :: map ((fn p => Pretty.block [str "| ", p]) o pr_co) cos
775 | pr_def (_, CodegenThingol.Datatypecons _) =
777 | pr_def (name, CodegenThingol.Class (superclasss, (v, classops))) =
779 val tyvars = intro_vars [v] keyword_vars;
780 fun pr_classop (classop, ty) =
782 str (deresolv_here classop ^ " ::"),
784 pr_typ tyvars NOBR ty
789 pr_typparms tyvars [(v, superclasss)],
790 str (deresolv_here name ^ " " ^ v),
793 Pretty.chunks (map pr_classop classops)
796 | pr_def (_, CodegenThingol.Classmember _) =
798 | pr_def (_, CodegenThingol.Classinst ((class, (tyco, vs)), (_, classop_defs))) =
800 val tyvars = intro_vars (map fst vs) keyword_vars;
804 pr_typparms tyvars vs,
805 str (class_name class ^ " "),
806 pr_typ tyvars BR (tyco `%% map (ITyVar o fst) vs),
809 Pretty.chunks (map (fn (classop, t) =>
811 val consts = map_filter
812 (fn c => if (is_some o const_syntax) c
813 then NONE else (SOME o NameSpace.base o deresolv) c)
814 (CodegenThingol.fold_constnames (insert (op =)) t []);
815 val vars = keyword_vars
816 |> intro_vars consts;
818 (Pretty.block o Pretty.breaks) [
819 (str o classop_name class) classop,
827 in Pretty.setmp_margin 999999 pr_def def end;
830 (** generic abstract serializer **)
832 structure NameMangler = NameManglerFun (
833 type ctxt = (string * string -> string) * (string -> string option);
834 type src = string * string;
835 val ord = prod_ord string_ord string_ord;
836 fun mk (postprocess, validate) ((shallow, name), 0) =
838 val name' = postprocess (shallow, name);
839 in case validate name'
841 | _ => mk (postprocess, validate) ((shallow, name), 1)
843 | mk (postprocess, validate) (("", name), i) =
844 postprocess ("", name ^ replicate_string i "'")
846 | mk (postprocess, validate) ((shallow, name), 1) =
847 postprocess (shallow, shallow ^ "_" ^ name)
849 | mk (postprocess, validate) ((shallow, name), i) =
850 postprocess (shallow, name ^ replicate_string i "'")
852 fun is_valid _ _ = true;
853 fun maybe_unique _ _ = NONE;
854 fun re_mangle _ dst = error ("No such definition name: " ^ quote dst);
857 (*FIXME refactor this properly*)
858 fun code_serialize seri_defs seri_module validate postprocess nsp_conn name_root
859 (code : CodegenThingol.code) =
861 datatype node = Def of CodegenThingol.def | Module of node Graph.T;
862 fun dest_modl (Module m) = m;
865 val (names, name_base) = (split_last o NameSpace.unpack) name;
866 val (names_mod, name_shallow) = split_last names;
867 in (names_mod, NameSpace.pack [name_shallow, name_base]) end;
868 fun mk_deresolver module nsp_conn postprocess validate =
870 datatype tabnode = N of string * tabnode Symtab.table option;
871 fun mk module manglers tab =
874 case NameSpace.unpack name
877 fun in_conn (shallow, conn) =
878 member (op = : string * string -> bool) conn shallow;
881 val n as (shallow, _) = mk_name name;
883 AList.map_entry_yield in_conn shallow (
884 NameMangler.declare (postprocess, validate) n
885 #-> (fn n' => pair (name, n'))
888 val (renamings, manglers') =
889 fold_map add_name (Graph.keys module) manglers;
890 fun extend_tab (n, n') =
891 if (length o NameSpace.unpack) n = 1
894 (n, N (n', SOME (mk ((dest_modl o Graph.get_node module) n) manglers' Symtab.empty)))
896 Symtab.update_new (n, N (n', NONE));
897 in fold extend_tab renamings tab end;
898 fun get_path_name [] tab =
900 | get_path_name [p] tab =
902 val SOME (N (p', tab')) = Symtab.lookup tab p
904 | get_path_name [p1, p2] tab =
905 (case Symtab.lookup tab p1
906 of SOME (N (p', SOME tab')) =>
908 val (ps', tab'') = get_path_name [p2] tab'
909 in (p' :: ps', tab'') end
912 val SOME (N (p', NONE)) = Symtab.lookup tab (NameSpace.pack [p1, p2])
914 | get_path_name (p::ps) tab =
916 val SOME (N (p', SOME tab')) = Symtab.lookup tab p
917 val (ps', tab'') = get_path_name ps tab'
918 in (p' :: ps', tab'') end;
919 fun deresolv tab prefix name =
921 val (common, (_, rem)) = chop_prefix (op =) (prefix, NameSpace.unpack name);
922 val (_, SOME tab') = get_path_name common tab;
923 val (name', _) = get_path_name rem tab';
924 in NameSpace.pack name' end handle BIND => (error ("Missing name: " ^ quote name ^ ", in " ^ quote (NameSpace.pack prefix)));
925 in deresolv (mk module (AList.make (K NameMangler.empty) nsp_conn) Symtab.empty) end;
926 fun allimports_of modl =
928 fun imps_of prfx (Module modl) imps tab =
930 val this = NameSpace.pack prfx;
931 val name_con = (rev o Graph.strong_conn) modl;
935 |> fold (fn names => fn (imps', tab) =>
937 |> fold_map (fn name =>
938 imps_of (prfx @ [name]) (Graph.get_node modl name) (imps' @ imps)) names
939 |-> (fn imps'' => pair (flat imps'' @ imps'))) name_con
941 Symtab.update_new (this, imps' @ imps)
942 #> pair (this :: imps'))
944 | imps_of prfx (Def _) imps tab =
946 in snd (imps_of [] (Module modl) [] Symtab.empty) end;
947 fun add_def ((names_mod, name_id), def) =
950 Graph.new_node (name_id, Def def)
952 Graph.default_node (m, Module Graph.empty)
953 #> Graph.map_node m (Module o add ms o dest_modl)
954 in add names_mod end;
955 fun add_dep (name1, name2) =
956 if name1 = name2 then I
959 val m1 = dest_name name1 |> apsnd single |> (op @);
960 val m2 = dest_name name2 |> apsnd single |> (op @);
961 val (ms, (r1, r2)) = chop_prefix (op =) (m1, m2);
962 val (ms, (s1::r1, s2::r2)) = chop_prefix (op =) (m1, m2);
964 if null r1 andalso null r2
966 else fn edge => fn gr => (Graph.add_edge_acyclic edge gr
967 handle Graph.CYCLES _ =>
968 error ("Module dependency "
969 ^ quote name1 ^ " -> " ^ quote name2 ^ " would result in module dependency cycle"))
975 |> Graph.map_node m (Module o add ms o dest_modl);
979 |> Graph.fold (fn (name, (def, _)) => add_def (dest_name name, def)) code
980 |> Graph.fold (fn (name, (_, (_, deps))) =>
981 fold (curry add_dep name) deps) code;
982 val names = map fst (Graph.dest root_module);
983 val imptab = allimports_of root_module;
984 val resolver = mk_deresolver root_module nsp_conn postprocess validate;
985 fun sresolver s = (resolver o NameSpace.unpack) s
986 fun mk_name prfx name =
988 val name_qual = NameSpace.pack (prfx @ [name])
989 in (name_qual, resolver prfx name_qual) end;
990 fun is_bot (_, (Def Bot)) = true
992 fun mk_contents prfx module =
993 map_filter (seri prfx)
994 ((map (AList.make (Graph.get_node module)) o rev o Graph.strong_conn) module)
995 and seri prfx [(name, Module modl)] =
996 seri_module (resolver []) (map (resolver []) ((the o Symtab.lookup imptab) (NameSpace.pack (prfx @ [name]))))
997 (mk_name prfx name, mk_contents (prfx @ [name]) modl)
999 seri_defs sresolver (NameSpace.pack prfx)
1000 (map (fn (name, Def def) => (fst (mk_name prfx name), def)) ds)
1002 seri_module (resolver []) (map (resolver []) ((the o Symtab.lookup imptab) ""))
1003 (("", name_root), (mk_contents [] root_module))
1006 fun abstract_serializer (target, nspgrp) name_root (from_defs, from_module, validator, postproc)
1007 postprocess (class_syntax, tyco_syntax, const_syntax)
1008 (drop, select) code =
1010 fun project NONE code = code
1011 | project (SOME names) code =
1013 fun check name = if member (op =) drop name
1014 then error ("shadowed definition " ^ quote name ^ " selected for serialization")
1015 else if can (Graph.get_node code) name
1017 else error ("dropped definition " ^ quote name ^ " selected for serialization")
1018 val names' = (map o tap) check names;
1019 in CodegenThingol.project_code names code end;
1020 fun from_module' resolv imps ((name_qual, name), defs) =
1021 from_module resolv imps ((name_qual, name), defs)
1022 |> postprocess (resolv name_qual);
1025 |> tracing (fn _ => "dropping shadowed definitions...")
1026 |> CodegenThingol.delete_garbage drop
1027 |> tracing (fn _ => "projecting...")
1029 |> tracing (fn _ => "serializing...")
1030 |> code_serialize (from_defs (class_syntax, tyco_syntax, const_syntax))
1031 from_module' validator postproc nspgrp name_root
1035 fun abstract_validator keywords name =
1037 fun replace_invalid c = (*FIXME*)
1038 if Symbol.is_ascii_letter c orelse Symbol.is_ascii_digit c orelse c = "'"
1039 andalso not (NameSpace.separator = c)
1044 |> member (op =) keywords ? suffix "'"
1045 |> (fn name' => if name = name' then name else suffix_it name')
1048 |> translate_string replace_invalid
1050 |> (fn name' => if name = name' then NONE else SOME name')
1053 fun write_file mkdir path p = (
1056 File.mkdir (Path.dir path)
1058 File.write path (Pretty.output p ^ "\n");
1062 fun mk_module_file postprocess_module ext path name p =
1064 val prfx = Path.dir path;
1065 val name' = case name
1066 of "" => Path.base path
1067 | _ => (Path.ext ext o Path.unpack o implode o separate "/" o NameSpace.unpack) name;
1070 |> write_file true (Path.append prfx name')
1071 |> postprocess_module name
1074 fun parse_args f args =
1077 | (_, _) => error "bad serializer arguments";
1079 fun parse_single_file serializer =
1080 parse_args (Args.name
1081 >> (fn path => serializer
1082 (fn "" => write_file false (Path.unpack path) #> K NONE
1085 fun parse_multi_file postprocess_module ext serializer =
1086 parse_args (Args.name
1087 >> (fn path => (serializer o mk_module_file postprocess_module ext) (Path.unpack path)));
1089 fun parse_internal serializer =
1090 parse_args (Args.name
1091 >> (fn "-" => serializer
1092 (fn "" => (fn p => (use_text Output.ml_output false (Pretty.output p); NONE))
1094 | _ => Scan.fail ()));
1096 fun parse_stdout serializer =
1097 parse_args (Args.name
1098 >> (fn "_" => serializer
1099 (fn "" => (fn p => (Pretty.writeln p; NONE))
1101 | _ => Scan.fail ()));
1103 val nsp_module = CodegenNames.nsp_module;
1104 val nsp_class = CodegenNames.nsp_class;
1105 val nsp_tyco = CodegenNames.nsp_tyco;
1106 val nsp_inst = CodegenNames.nsp_inst;
1107 val nsp_fun = CodegenNames.nsp_fun;
1108 val nsp_classop = CodegenNames.nsp_classop;
1109 val nsp_dtco = CodegenNames.nsp_dtco;
1110 val nsp_eval = CodegenNames.nsp_eval;
1113 (** ML serializer **)
1117 val reserved_ml' = [
1118 "bool", "int", "list", "unit", "option", "true", "false", "not",
1119 "NONE", "SOME", "o", "string", "char", "String", "Term"
1122 fun ml_from_defs (_, tyco_syntax, const_syntax) deresolver prefx defs =
1124 val seri = pr_sml_def tyco_syntax const_syntax
1125 (make_vars (ThmDatabase.ml_reserved @ reserved_ml'))
1126 (deresolver prefx) #> SOME;
1129 (fn (name, CodegenThingol.Fun info) => (name, info)
1130 | (name, def) => error ("Function block containing illegal def: " ^ quote name)
1133 val filter_datatype =
1135 (fn (name, CodegenThingol.Datatype info) => SOME (name, info)
1136 | (name, CodegenThingol.Datatypecons _) => NONE
1137 | (name, def) => error ("Datatype block containing illegal def: " ^ quote name)
1140 fun filter_class defs =
1142 (fn (name, CodegenThingol.Class info) => SOME (name, info)
1143 | (name, CodegenThingol.Classmember _) => NONE
1144 | (name, def) => error ("Class block containing illegal def: " ^ quote name)
1146 of [class] => MLClass class
1147 | _ => error ("Class block without class: " ^ (commas o map (quote o fst)) defs)
1149 of (_, CodegenThingol.Fun _)::_ => (seri o filter_funs) defs
1150 | (_, CodegenThingol.Datatypecons _)::_ => (seri o filter_datatype) defs
1151 | (_, CodegenThingol.Datatype _)::_ => (seri o filter_datatype) defs
1152 | (_, CodegenThingol.Class _)::_ => (seri o filter_class) defs
1153 | (_, CodegenThingol.Classmember _)::_ => (seri o filter_class) defs
1154 | [(inst, CodegenThingol.Classinst info)] => seri (MLClassinst (inst, info))
1155 | defs => error ("Illegal mutual dependencies: " ^ (commas o map fst) defs)
1158 fun ml_serializer root_name target nspgrp =
1160 fun ml_from_module resolv _ ((_, name), ps) =
1162 str ("structure " ^ name ^ " = "),
1165 ] @ separate (str "") ps @ [
1167 str ("end; (* struct " ^ name ^ " *)")
1169 fun postproc (shallow, n) =
1171 fun ch_first f = String.implode o nth_map 0 f o String.explode;
1172 in if shallow = CodegenNames.nsp_dtco
1173 then ch_first Char.toUpper n
1176 in abstract_serializer (target, nspgrp)
1177 root_name (ml_from_defs, ml_from_module,
1178 abstract_validator (ThmDatabase.ml_reserved @ reserved_ml'), postproc) end;
1182 fun ml_from_thingol target args =
1184 val serializer = ml_serializer "ROOT" target [[nsp_module], [nsp_class, nsp_tyco],
1185 [nsp_fun, nsp_dtco, nsp_class, nsp_classop, nsp_inst]]
1190 (K o SOME o str o suffix ";" o prefix "val _ = use "
1191 o quote o suffix ".ML" o translate_string (fn "." => "/" | s => s)) "ML" serializer
1192 | _ => Scan.fail ());
1195 || parse_internal serializer
1196 || parse_stdout serializer
1197 || parse_single_file serializer) args
1200 val eval_verbose = ref false;
1202 fun eval_term_proto thy data hidden ((ref_name, reff), e) code =
1204 val (val_name, code') = CodegenThingol.add_eval_def (nsp_eval, e) code;
1205 val struct_name = "EVAL";
1206 fun output p = if !eval_verbose then (Pretty.writeln p; Pretty.output p)
1207 else Pretty.output p;
1208 val serializer = ml_serializer struct_name "SML" [[nsp_module], [nsp_class, nsp_tyco],
1209 [nsp_fun, nsp_dtco, nsp_class, nsp_classop, nsp_inst], [nsp_eval]]
1210 (fn "" => (fn p => (use_text Output.ml_output (!eval_verbose) (output p); NONE))
1212 (hidden, SOME [NameSpace.pack [nsp_eval, val_name]]);
1213 val _ = serializer code';
1214 val val_name_struct = NameSpace.append struct_name val_name;
1215 val _ = reff := NONE;
1216 val _ = use_text Output.ml_output (!eval_verbose) ("val _ = (" ^ ref_name ^ " := SOME (" ^ val_name_struct ^ "))");
1218 of NONE => error ("Could not retrieve value of ML reference " ^ quote ref_name
1219 ^ " (reference probably has been shadowed)")
1220 | SOME value => value
1223 structure NameMangler = NameManglerFun (
1224 type ctxt = string list;
1226 val ord = string_ord;
1227 fun mk reserved_ml (name, i) =
1228 (Symbol.alphanum o NameSpace.base) name ^ replicate_string i "'";
1229 fun is_valid (reserved_ml : string list) = not o member (op =) reserved_ml;
1230 fun maybe_unique _ _ = NONE;
1231 fun re_mangle _ dst = error ("No such definition name: " ^ quote dst);
1234 fun mk_flat_ml_resolver names =
1238 |> fold_map (NameMangler.declare (ThmDatabase.ml_reserved @ reserved_ml')) names
1240 in NameMangler.get (ThmDatabase.ml_reserved @ reserved_ml') mangler end;
1245 (** haskell serializer **)
1247 fun hs_from_thingol target args =
1249 fun hs_from_defs keyword_vars (class_syntax, tyco_syntax, const_syntax) deresolver prefix defs =
1251 val deresolv = deresolver "";
1252 val deresolv_here = deresolver prefix;
1253 val hs_from_def = pr_haskell class_syntax tyco_syntax const_syntax
1254 keyword_vars deresolv_here deresolv;
1255 in case map_filter hs_from_def defs
1257 | ps => (SOME o Pretty.chunks o separate (str "")) ps
1260 "hiding", "deriving", "where", "case", "of", "infix", "infixl", "infixr",
1261 "import", "default", "forall", "let", "in", "class", "qualified", "data",
1262 "newtype", "instance", "if", "then", "else", "type", "as", "do", "module"
1264 "Bool", "Integer", "Maybe", "True", "False", "Nothing", "Just", "not", "negate",
1267 fun hs_from_module resolv imps ((_, name), ps) =
1269 str ("module " ^ name ^ " where")
1270 :: map (str o prefix "import qualified ") imps @ (
1272 :: separate (str "") ps
1274 fun postproc (shallow, n) =
1276 fun ch_first f = String.implode o nth_map 0 f o String.explode;
1277 in if member (op =) [nsp_module, nsp_class, nsp_tyco, nsp_dtco] shallow
1278 then ch_first Char.toUpper n
1279 else ch_first Char.toLower n
1281 val serializer = abstract_serializer (target, [[nsp_module],
1282 [nsp_class], [nsp_tyco], [nsp_fun, nsp_classop], [nsp_dtco], [nsp_inst]])
1283 "Main" (hs_from_defs (make_vars reserved_hs), hs_from_module, abstract_validator reserved_hs, postproc);
1285 (parse_multi_file ((K o K) NONE) "hs" serializer) args
1292 datatype syntax_expr = SyntaxExpr of {
1293 class: ((string * (string -> string option)) * serial) Symtab.table,
1294 inst: unit Symtab.table,
1295 tyco: (itype pretty_syntax * serial) Symtab.table,
1296 const: (iterm pretty_syntax * serial) Symtab.table
1299 fun mk_syntax_expr ((class, inst), (tyco, const)) =
1300 SyntaxExpr { class = class, inst = inst, tyco = tyco, const = const };
1301 fun map_syntax_expr f (SyntaxExpr { class, inst, tyco, const }) =
1302 mk_syntax_expr (f ((class, inst), (tyco, const)));
1303 fun merge_syntax_expr (SyntaxExpr { class = class1, inst = inst1, tyco = tyco1, const = const1 },
1304 SyntaxExpr { class = class2, inst = inst2, tyco = tyco2, const = const2 }) =
1306 (Symtab.merge (eq_snd (op =)) (class1, class2),
1307 Symtab.merge (op =) (inst1, inst2)),
1308 (Symtab.merge (eq_snd (op =)) (tyco1, tyco2),
1309 Symtab.merge (eq_snd (op =)) (const1, const2))
1312 datatype syntax_modl = SyntaxModl of {
1313 merge: string Symtab.table,
1314 prolog: Pretty.T Symtab.table
1317 fun mk_syntax_modl (merge, prolog) =
1318 SyntaxModl { merge = merge, prolog = prolog };
1319 fun map_syntax_modl f (SyntaxModl { merge, prolog }) =
1320 mk_syntax_modl (f (merge, prolog));
1321 fun merge_syntax_modl (SyntaxModl { merge = merge1, prolog = prolog1 },
1322 SyntaxModl { merge = merge2, prolog = prolog2 }) =
1324 Symtab.merge (op =) (merge1, merge2),
1325 Symtab.merge (op =) (prolog1, prolog2)
1328 type serializer = string -> Args.T list
1329 -> (string -> (string * (string -> string option)) option)
1334 -> itype -> Pretty.T)
1335 -> itype list -> Pretty.T))
1341 -> iterm -> Pretty.T)
1342 -> iterm list -> Pretty.T))
1344 -> string list * string list option
1345 -> CodegenThingol.code -> unit;
1347 datatype target = Target of {
1349 serializer: serializer,
1350 syntax_expr: syntax_expr,
1351 syntax_modl: syntax_modl
1354 fun mk_target (serial, (serializer, (syntax_expr, syntax_modl))) =
1355 Target { serial = serial, serializer = serializer, syntax_expr = syntax_expr, syntax_modl = syntax_modl };
1356 fun map_target f ( Target { serial, serializer, syntax_expr, syntax_modl } ) =
1357 mk_target (f (serial, (serializer, (syntax_expr, syntax_modl))));
1358 fun merge_target target (Target { serial = serial1, serializer = serializer, syntax_expr = syntax_expr1, syntax_modl = syntax_modl1 },
1359 Target { serial = serial2, serializer = _, syntax_expr = syntax_expr2, syntax_modl = syntax_modl2 }) =
1360 if serial1 = serial2 then
1361 mk_target (serial1, (serializer,
1362 (merge_syntax_expr (syntax_expr1, syntax_expr2),
1363 merge_syntax_modl (syntax_modl1, syntax_modl2))
1366 error ("Incompatible serializers: " ^ quote target);
1368 structure CodegenSerializerData = TheoryDataFun
1370 val name = "Pure/codegen_serializer";
1371 type T = target Symtab.table;
1372 val empty = Symtab.empty;
1375 fun merge _ = Symtab.join merge_target;
1379 fun the_serializer (Target { serializer, ... }) = serializer;
1380 fun the_syntax_expr (Target { syntax_expr = SyntaxExpr x, ... }) = x;
1381 fun the_syntax_modl (Target { syntax_modl = SyntaxModl x, ... }) = x;
1383 fun add_serializer (target, seri) thy =
1385 val _ = case Symtab.lookup (CodegenSerializerData.get thy) target
1386 of SOME _ => warning ("overwriting existing serializer " ^ quote target)
1390 |> (CodegenSerializerData.map oo Symtab.map_default)
1391 (target, mk_target (serial (), (seri,
1392 (mk_syntax_expr ((Symtab.empty, Symtab.empty), (Symtab.empty, Symtab.empty)),
1393 mk_syntax_modl (Symtab.empty, Symtab.empty)))))
1394 (map_target (fn (serial, (_, syntax)) => (serial, (seri, syntax))))
1397 val _ = Context.add_setup (
1398 CodegenSerializerData.init
1399 #> add_serializer ("SML", ml_from_thingol)
1400 #> add_serializer ("Haskell", hs_from_thingol)
1403 fun get_serializer thy (target, args) cs =
1405 val data = case Symtab.lookup (CodegenSerializerData.get thy) target
1406 of SOME data => data
1407 | NONE => error ("Unknown code target language: " ^ quote target);
1408 val seri = the_serializer data;
1409 val { class, inst, tyco, const } = the_syntax_expr data;
1410 fun fun_of sys = (Option.map fst oo Symtab.lookup) sys;
1412 seri target args (fun_of class, fun_of tyco, fun_of const)
1413 (Symtab.keys class @ Symtab.keys inst @ Symtab.keys tyco @ Symtab.keys const, cs)
1416 fun has_serialization f thy targets name =
1418 is_some o (fn tab => Symtab.lookup tab name) o f o the_syntax_expr o the
1419 o (Symtab.lookup ((CodegenSerializerData.get) thy))
1422 val tyco_has_serialization = has_serialization #tyco;
1423 val const_has_serialization = has_serialization #const;
1428 val data = case Symtab.lookup (CodegenSerializerData.get thy) target
1429 of SOME data => data
1430 | NONE => error ("Unknown code target language: " ^ quote target);
1431 val { class, inst, tyco, const } = the_syntax_expr data;
1432 fun fun_of sys = (Option.map fst oo Symtab.lookup) sys;
1434 eval_term_proto thy (fun_of class, fun_of tyco, fun_of const)
1435 (Symtab.keys class @ Symtab.keys inst @ Symtab.keys tyco @ Symtab.keys const)
1440 (** ML and toplevel interface **)
1444 fun map_syntax_exprs target f thy =
1446 val _ = if is_some (Symtab.lookup (CodegenSerializerData.get thy) target)
1448 else error ("Unknown code target language: " ^ quote target);
1451 |> (CodegenSerializerData.map o Symtab.map_entry target o map_target
1452 o apsnd o apsnd o apfst o map_syntax_expr) f
1455 fun gen_add_syntax_class prep_class prep_const target raw_class (syntax, raw_ops) thy =
1457 val cls = prep_class thy raw_class
1458 val class = CodegenNames.class thy cls;
1459 fun mk_classop (const as (c, _)) = case AxClass.class_of_param thy c
1460 of SOME class' => if cls = class' then CodegenNames.const thy const
1461 else error ("Not a class operation for class " ^ quote class ^ ": " ^ quote c)
1462 | NONE => error ("Not a class operation: " ^ quote c)
1463 val ops = (map o apfst) (mk_classop o prep_const thy) raw_ops;
1464 val syntax_ops = AList.lookup (op =) ops;
1467 |> (map_syntax_exprs target o apfst o apfst)
1468 (Symtab.update (class, ((syntax, syntax_ops), serial ())))
1471 fun gen_add_syntax_inst prep_class prep_tyco target (raw_tyco, raw_class) thy =
1473 val inst = CodegenNames.instance thy (prep_class thy raw_class, prep_tyco thy raw_tyco);
1476 |> (map_syntax_exprs target o apfst o apsnd)
1477 (Symtab.update (inst, ()))
1480 fun gen_add_syntax_tyco prep_tyco raw_tyco target syntax thy =
1482 val tyco = (CodegenNames.tyco thy o prep_tyco thy) raw_tyco;
1485 |> (map_syntax_exprs target o apsnd o apfst)
1486 (Symtab.update (tyco, (syntax, serial ())))
1489 fun gen_add_syntax_const prep_const raw_c target syntax thy =
1491 val c' = prep_const thy raw_c;
1492 val c'' = CodegenNames.const thy c';
1495 |> (map_syntax_exprs target o apsnd o apsnd)
1496 (Symtab.update (c'', (syntax, serial ())))
1499 fun read_type thy raw_tyco =
1501 val tyco = Sign.intern_type thy raw_tyco;
1502 val _ = if Sign.declared_tyname thy tyco then ()
1503 else error ("No such type constructor: " ^ quote raw_tyco);
1506 fun idfs_of_const_names thy cs =
1508 val cs' = AList.make (fn c => Sign.the_const_type thy c) cs;
1509 val cs'' = map (CodegenConsts.norm_of_typ thy) cs';
1510 in AList.make (CodegenNames.const thy) cs'' end;
1512 fun parse_quote num_of consts_of target get_init adder =
1513 parse_syntax num_of #-> (fn mfx => pair (fn thy => adder target (mfx thy) thy));
1515 fun zip_list (x::xs) f g =
1516 f x #-> (fn y => fold_map (fn x => g |-- f x >> pair x) xs
1517 #-> (fn xys => pair ((x, y) :: xys)));
1519 structure P = OuterParse
1520 and K = OuterKeyword
1522 fun parse_multi_syntax parse_thing parse_syntax =
1523 P.and_list1 parse_thing
1524 #-> (fn things => Scan.repeat1 (P.$$$ "(" |-- P.name :--
1525 (fn target => zip_list things (parse_syntax target)
1526 (P.$$$ "and")) --| P.$$$ ")"))
1528 val add_syntax_class = gen_add_syntax_class ClassPackage.read_class CodegenConsts.read_const;
1529 val add_syntax_inst = gen_add_syntax_inst ClassPackage.read_class read_type;
1531 fun parse_syntax_tyco target raw_tyco =
1533 fun intern thy = read_type thy raw_tyco;
1534 fun num_of thy = Sign.arity_number thy (intern thy);
1535 fun idf_of thy = CodegenNames.tyco thy (intern thy);
1537 Sign.read_typ (thy, K NONE);
1539 parse_quote num_of ((K o K) ([], [])) target idf_of
1540 (gen_add_syntax_tyco read_type raw_tyco)
1543 fun parse_syntax_const target raw_const =
1545 fun intern thy = CodegenConsts.read_const thy raw_const;
1546 fun num_of thy = (length o fst o strip_type o Sign.the_const_type thy o fst o intern) thy;
1547 fun idf_of thy = (CodegenNames.const thy o intern) thy;
1549 parse_quote num_of CodegenConsts.consts_of target idf_of
1550 (gen_add_syntax_const CodegenConsts.read_const raw_const)
1553 val (code_classK, code_instanceK, code_typeK, code_constK) =
1554 ("code_class", "code_instance", "code_type", "code_const");
1559 OuterSyntax.command code_classK "define code syntax for class" K.thy_decl (
1560 parse_multi_syntax P.xname
1561 (fn _ => fn _ => P.string -- Scan.optional (P.$$$ "where" |-- Scan.repeat1
1562 (P.term --| (P.$$$ "\\<equiv>" || P.$$$ "==") -- P.string)) [])
1563 >> (Toplevel.theory oo fold) (fn (target, syns) =>
1564 fold (fn (raw_class, syn) => add_syntax_class target raw_class syn) syns)
1567 val code_instanceP =
1568 OuterSyntax.command code_instanceK "define code syntax for instance" K.thy_decl (
1569 parse_multi_syntax (P.xname --| P.$$$ "::" -- P.xname)
1570 (fn _ => fn _ => P.name #->
1571 (fn "-" => Scan.succeed () | _ => Scan.fail_with (fn _ => "\"-\" expected") ()))
1572 >> (Toplevel.theory oo fold) (fn (target, syns) =>
1573 fold (fn (raw_inst, ()) => add_syntax_inst target raw_inst) syns)
1577 OuterSyntax.command code_typeK "define code syntax for type constructor" K.thy_decl (
1579 parse_multi_syntax P.xname parse_syntax_tyco
1581 >> (Toplevel.theory o (fold o fold) (fold snd o snd))
1585 OuterSyntax.command code_constK "define code syntax for constant" K.thy_decl (
1587 parse_multi_syntax P.term parse_syntax_const
1589 >> (Toplevel.theory o (fold o fold) (fold snd o snd))
1592 val _ = OuterSyntax.add_parsers [code_classP, code_instanceP, code_typeP, code_constP];
1594 fun add_pretty_list target nill cons mk_list mk_char_string target_cons thy =
1596 val [(_, nil''), (cons', cons'')] = idfs_of_const_names thy [nill, cons];
1597 val pr = pretty_list nil'' cons'' mk_list mk_char_string target_cons;
1600 |> gen_add_syntax_const (K I) cons' target pr
1603 fun add_pretty_ml_string target nill cons str mk_char mk_string target_implode thy =
1605 val [(_, nil''), (_, cons''), (str', _)] = idfs_of_const_names thy [nill, cons, str];
1606 val pr = pretty_ml_string nil'' cons'' mk_char mk_string target_implode;
1609 |> gen_add_syntax_const (K I) str' target pr
1612 fun add_undefined target undef target_undefined thy =
1614 val [(undef', _)] = idfs_of_const_names thy [undef];
1615 fun pretty _ _ _ = str target_undefined;
1618 |> gen_add_syntax_const (K I) undef' target (~1, pretty)