| 20353 |      1 | (*  Title:      Pure/Tools/codegen_names.ML
 | 
|  |      2 |     ID:         $Id$
 | 
|  |      3 |     Author:     Florian Haftmann, TU Muenchen
 | 
|  |      4 | 
 | 
| 20386 |      5 | Name policies for code generation: prefixing any name by corresponding theory name,
 | 
|  |      6 | conversion to alphanumeric representation. Mappings are incrementally cached.
 | 
| 20353 |      7 | *)
 | 
|  |      8 | 
 | 
|  |      9 | signature CODEGEN_NAMES =
 | 
|  |     10 | sig
 | 
| 20386 |     11 |   type tyco = string
 | 
|  |     12 |   type const = string
 | 
| 20353 |     13 |   val class: theory -> class -> class
 | 
|  |     14 |   val class_rev: theory -> class -> class
 | 
|  |     15 |   val tyco: theory -> tyco -> tyco
 | 
|  |     16 |   val tyco_rev: theory -> tyco -> tyco
 | 
| 20386 |     17 |   val tyco_force: tyco * string -> theory -> theory
 | 
| 20353 |     18 |   val instance: theory -> class * tyco -> string
 | 
|  |     19 |   val instance_rev: theory -> string -> class * tyco
 | 
|  |     20 |   val const: theory -> string * typ -> const
 | 
|  |     21 |   val const_rev: theory -> const -> string * typ
 | 
| 20386 |     22 |   val const_force: (string * typ) * const -> theory -> theory
 | 
| 20353 |     23 |   val purify_var: string -> string
 | 
|  |     24 | end;
 | 
|  |     25 | 
 | 
|  |     26 | structure CodegenNames: CODEGEN_NAMES =
 | 
|  |     27 | struct
 | 
|  |     28 | 
 | 
|  |     29 | 
 | 
|  |     30 | (* theory data *)
 | 
|  |     31 | 
 | 
|  |     32 | type tyco = string;
 | 
|  |     33 | type const = string;
 | 
|  |     34 | val inst_ord = prod_ord fast_string_ord fast_string_ord;
 | 
|  |     35 | val eq_inst = is_equal o inst_ord;
 | 
| 20386 |     36 | structure Consttab = CodegenConsts.Consttab;
 | 
| 20353 |     37 | 
 | 
|  |     38 | structure Insttab =
 | 
|  |     39 |   TableFun(
 | 
|  |     40 |     type key = class * tyco;
 | 
|  |     41 |     val ord = inst_ord;
 | 
|  |     42 |   );
 | 
|  |     43 | 
 | 
|  |     44 | datatype names = Names of {
 | 
|  |     45 |   class: class Symtab.table * class Symtab.table,
 | 
|  |     46 |   tyco: tyco Symtab.table * tyco Symtab.table,
 | 
|  |     47 |   instance: string Insttab.table * (class * tyco) Symtab.table,
 | 
|  |     48 |   const: const Consttab.table * (string * typ list) Symtab.table
 | 
|  |     49 | }
 | 
|  |     50 | 
 | 
|  |     51 | val empty_names = Names {
 | 
|  |     52 |   class = (Symtab.empty, Symtab.empty),
 | 
|  |     53 |   tyco = (Symtab.empty, Symtab.empty),
 | 
|  |     54 |   instance = (Insttab.empty, Symtab.empty),
 | 
|  |     55 |   const = (Consttab.empty, Symtab.empty)
 | 
|  |     56 | };
 | 
|  |     57 | 
 | 
|  |     58 | local
 | 
|  |     59 |   fun mk_names (class, tyco, instance, const) =
 | 
|  |     60 |     Names { class = class, tyco = tyco, instance = instance, const = const};
 | 
|  |     61 |   fun map_names f (Names { class, tyco, instance, const }) =
 | 
|  |     62 |     mk_names (f (class, tyco, instance, const));
 | 
|  |     63 |   val eq_string = op = : string * string -> bool;
 | 
|  |     64 | in
 | 
|  |     65 |   fun merge_names (Names { class = (class1, classrev1), tyco = (tyco1, tycorev1),
 | 
|  |     66 |       instance = (instance1, instancerev1), const = (const1, constrev1) },
 | 
|  |     67 |     Names { class = (class2, classrev2), tyco = (tyco2, tycorev2),
 | 
|  |     68 |       instance = (instance2, instancerev2), const = (const2, constrev2) }) =
 | 
|  |     69 |     mk_names ((Symtab.merge eq_string (class1, class2), Symtab.merge eq_string (classrev1, classrev2)),
 | 
|  |     70 |       (Symtab.merge eq_string (tyco1, tyco2), Symtab.merge eq_string (tycorev1, tycorev2)),
 | 
|  |     71 |       (Insttab.merge eq_string (instance1, instance2), Symtab.merge eq_inst (instancerev1, instancerev2)),
 | 
| 20386 |     72 |       (Consttab.merge eq_string (const1, const2), Symtab.merge CodegenConsts.eq_const (constrev1, constrev2)));
 | 
| 20353 |     73 |   fun map_class f = map_names
 | 
|  |     74 |     (fn (class, tyco, inst, const) => (f class, tyco, inst, const));
 | 
|  |     75 |   fun map_tyco f = map_names
 | 
|  |     76 |     (fn (class, tyco, inst, const) => (class, f tyco, inst, const));
 | 
|  |     77 |   fun map_inst f = map_names
 | 
|  |     78 |     (fn (class, tyco, inst, const) => (class, tyco, f inst, const));
 | 
|  |     79 |   fun map_const f = map_names
 | 
|  |     80 |     (fn (class, tyco, inst, const) => (class, tyco, inst, f const));
 | 
|  |     81 | 
 | 
|  |     82 | end; (*local*)
 | 
|  |     83 | 
 | 
|  |     84 | structure CodegenNamesData = TheoryDataFun
 | 
|  |     85 | (struct
 | 
|  |     86 |   val name = "Pure/codegen_names";
 | 
|  |     87 |   type T = names ref;
 | 
|  |     88 |   val empty = ref empty_names;
 | 
|  |     89 |   fun copy (ref names) = ref names;
 | 
|  |     90 |   val extend = copy;
 | 
|  |     91 |   fun merge _ (ref names1, ref names2) = ref (merge_names (names1, names2));
 | 
|  |     92 |   fun print _ _ = ();
 | 
|  |     93 | end);
 | 
|  |     94 | 
 | 
|  |     95 | val _ = Context.add_setup CodegenNamesData.init;
 | 
|  |     96 | 
 | 
|  |     97 | 
 | 
|  |     98 | (* forward lookup with cache update *)
 | 
|  |     99 | 
 | 
|  |    100 | fun get thy get_tabs get upd_names upd policy x =
 | 
|  |    101 |   let
 | 
|  |    102 |     val names_ref = CodegenNamesData.get thy
 | 
|  |    103 |     val (Names names) = ! names_ref;
 | 
|  |    104 |     fun mk_unique used name =
 | 
|  |    105 |       let
 | 
|  |    106 |         fun mk_name 0 = name
 | 
|  |    107 |           | mk_name i = name ^ "_" ^ string_of_int i
 | 
|  |    108 |         fun find_name i =
 | 
|  |    109 |           let
 | 
|  |    110 |             val name = mk_name i
 | 
|  |    111 |           in
 | 
|  |    112 |             if used name
 | 
|  |    113 |             then find_name (i+1)
 | 
|  |    114 |             else name
 | 
|  |    115 |           end;
 | 
|  |    116 |         val name = find_name 0;
 | 
|  |    117 |       in name end;
 | 
|  |    118 |     val tabs = get_tabs names;
 | 
|  |    119 |     fun declare name =
 | 
|  |    120 |       let
 | 
|  |    121 |         val names' = upd_names (K (upd (x, name) (fst tabs),
 | 
|  |    122 |           Symtab.update_new (name, x) (snd tabs))) (Names names)
 | 
|  |    123 |       in (names_ref := names'; name) end;
 | 
|  |    124 |   in case get (fst tabs) x
 | 
|  |    125 |    of SOME name => name
 | 
|  |    126 |     | NONE => let
 | 
|  |    127 |         val used = Symtab.defined (snd tabs);
 | 
|  |    128 |         val raw_name = policy thy x;
 | 
|  |    129 |         val name = mk_unique used raw_name;
 | 
|  |    130 |       in declare name end
 | 
|  |    131 |   end;
 | 
|  |    132 | 
 | 
|  |    133 | 
 | 
|  |    134 | (* backward lookup *)
 | 
|  |    135 | 
 | 
|  |    136 | fun rev thy get_tabs errname name =
 | 
|  |    137 |   let
 | 
|  |    138 |     val names_ref = CodegenNamesData.get thy
 | 
|  |    139 |     val (Names names) = ! names_ref;
 | 
|  |    140 |     val tab = (snd o get_tabs) names;
 | 
|  |    141 |   in case Symtab.lookup tab name
 | 
|  |    142 |    of SOME x => x
 | 
| 20389 |    143 |     | NONE => error ("No such " ^ errname ^ ": " ^ quote name)
 | 
| 20353 |    144 |   end;
 | 
|  |    145 | 
 | 
|  |    146 | 
 | 
|  |    147 | (* theory name lookup *)
 | 
|  |    148 | 
 | 
|  |    149 | fun thyname_of thy f errmsg x =
 | 
|  |    150 |   let
 | 
|  |    151 |     fun thy_of thy =
 | 
|  |    152 |       if f thy x then case get_first thy_of (Theory.parents_of thy)
 | 
|  |    153 |         of NONE => SOME thy
 | 
|  |    154 |          | thy => thy
 | 
|  |    155 |       else NONE;
 | 
|  |    156 |   in case thy_of thy
 | 
|  |    157 |    of SOME thy => Context.theory_name thy
 | 
|  |    158 |     | NONE => error (errmsg x) end;
 | 
|  |    159 | 
 | 
|  |    160 | fun thyname_of_class thy =
 | 
|  |    161 |   thyname_of thy (fn thy => member (op =) (Sign.classes thy))
 | 
|  |    162 |     (fn class => "thyname_of_class: no such class: " ^ quote class);
 | 
|  |    163 | 
 | 
|  |    164 | fun thyname_of_tyco thy =
 | 
|  |    165 |   thyname_of thy Sign.declared_tyname
 | 
|  |    166 |     (fn tyco => "thyname_of_tyco: no such type constructor: " ^ quote tyco);
 | 
|  |    167 | 
 | 
|  |    168 | fun thyname_of_instance thy =
 | 
|  |    169 |   let
 | 
|  |    170 |     fun test_instance thy (class, tyco) =
 | 
|  |    171 |       can (Sorts.mg_domain (Sign.classes_of thy) tyco) [class]
 | 
|  |    172 |   in thyname_of thy test_instance
 | 
|  |    173 |     (fn (class, tyco) => "thyname_of_instance: no such instance: " ^ quote class ^ ", " ^ quote tyco)
 | 
|  |    174 |   end;
 | 
|  |    175 | 
 | 
|  |    176 | fun thyname_of_const thy =
 | 
|  |    177 |   thyname_of thy Sign.declared_const
 | 
|  |    178 |     (fn c => "thyname_of_const: no such constant: " ^ quote c);
 | 
|  |    179 | 
 | 
|  |    180 | 
 | 
|  |    181 | (* purification of identifiers *)
 | 
|  |    182 | 
 | 
|  |    183 | val purify_name =
 | 
|  |    184 |   let
 | 
|  |    185 |     fun is_valid s = Symbol.is_ascii_letter s orelse Symbol.is_ascii_digit s orelse s = "'";
 | 
|  |    186 |     val is_junk = not o is_valid andf Symbol.not_eof;
 | 
|  |    187 |     val junk = Scan.any is_junk;
 | 
|  |    188 |     val scan_valids = Symbol.scanner "Malformed input"
 | 
|  |    189 |       ((junk |--
 | 
|  |    190 |         (Scan.optional (Scan.one Symbol.is_ascii_letter) "x" ^^ (Scan.any is_valid >> implode)
 | 
|  |    191 |         --| junk))
 | 
|  |    192 |       -- Scan.repeat ((Scan.any1 is_valid >> implode) --| junk) >> op ::);
 | 
|  |    193 |   in explode #> scan_valids #> space_implode "_" end;
 | 
|  |    194 | 
 | 
|  |    195 | fun purify_op "0" = "zero"
 | 
|  |    196 |   | purify_op "1" = "one"
 | 
|  |    197 |   | purify_op s =
 | 
|  |    198 |       let
 | 
|  |    199 |         fun rep_op "+" = SOME "sum"
 | 
|  |    200 |           | rep_op "-" = SOME "diff"
 | 
|  |    201 |           | rep_op "*" = SOME "prod"
 | 
|  |    202 |           | rep_op "/" = SOME "quotient"
 | 
|  |    203 |           | rep_op "&" = SOME "conj"
 | 
|  |    204 |           | rep_op "|" = SOME "disj"
 | 
|  |    205 |           | rep_op "=" = SOME "eq"
 | 
|  |    206 |           | rep_op "~" = SOME "inv"
 | 
|  |    207 |           | rep_op "@" = SOME "append"
 | 
|  |    208 |           | rep_op s = NONE;
 | 
|  |    209 |         val scan_valids = Symbol.scanner "Malformed input"
 | 
| 20386 |    210 |            (Scan.repeat (Scan.some rep_op || Scan.one Symbol.not_eof));
 | 
| 20353 |    211 |       in (explode #> scan_valids #> implode) s end;
 | 
|  |    212 | 
 | 
|  |    213 | val purify_lower = explode #> nth_map 0 Symbol.to_ascii_lower #> implode;
 | 
|  |    214 | val purify_upper = explode #> nth_map 0 Symbol.to_ascii_upper #> implode;
 | 
|  |    215 | 
 | 
| 20389 |    216 | fun purify_var "" = "x"
 | 
|  |    217 |   | purify_var v =
 | 
|  |    218 |       if nth (explode v) 0 = "'"
 | 
|  |    219 |       then (unprefix "'" #> purify_name #> purify_lower #> prefix "'") v
 | 
|  |    220 |       else (purify_name #> purify_lower) v;
 | 
| 20353 |    221 | 
 | 
|  |    222 | val purify_idf = purify_op #> purify_name;
 | 
|  |    223 | val purify_prefix = map (purify_idf #> purify_upper);
 | 
|  |    224 | val purify_base = purify_idf #> purify_lower;
 | 
|  |    225 | 
 | 
|  |    226 | 
 | 
| 20386 |    227 | (* explicit given names with cache update *)
 | 
| 20353 |    228 | 
 | 
| 20386 |    229 | fun tyco_force (tyco, name) thy =
 | 
|  |    230 |   let
 | 
|  |    231 |     val names = NameSpace.unpack name;
 | 
|  |    232 |     val (prefix, base) = split_last (NameSpace.unpack name);
 | 
|  |    233 |     val prefix' = purify_prefix prefix;
 | 
|  |    234 |     val base' = purify_base base;
 | 
|  |    235 |     val _ = if (base' = base) andalso forall (op =) (prefix' ~~ prefix)
 | 
|  |    236 |       then ()
 | 
|  |    237 |       else
 | 
| 20389 |    238 |         error ("Name violates naming conventions: " ^ quote name
 | 
| 20386 |    239 |           ^ "; perhaps try with " ^ quote (NameSpace.pack (prefix' @ [base'])))
 | 
|  |    240 |     val names_ref = CodegenNamesData.get thy;
 | 
|  |    241 |     val (Names names) = ! names_ref;
 | 
|  |    242 |     val (tycotab, tycorev) = #tyco names;
 | 
|  |    243 |     val _ = if Symtab.defined tycotab tyco
 | 
| 20389 |    244 |       then error ("Type constructor already named: " ^ quote tyco)
 | 
| 20386 |    245 |       else ();
 | 
|  |    246 |     val _ = if Symtab.defined tycorev name
 | 
| 20389 |    247 |       then error ("Name already given to type constructor: " ^ quote name)
 | 
| 20386 |    248 |       else ();
 | 
|  |    249 |     val _ = names_ref := map_tyco (K (Symtab.update_new (tyco, name) tycotab,
 | 
|  |    250 |           Symtab.update_new (name, tyco) tycorev)) (Names names);
 | 
|  |    251 |   in
 | 
|  |    252 |     thy
 | 
|  |    253 |   end;
 | 
|  |    254 | 
 | 
|  |    255 | fun const_force (c_ty, name) thy =
 | 
| 20353 |    256 |   let
 | 
|  |    257 |     val names = NameSpace.unpack name;
 | 
|  |    258 |     val (prefix, base) = split_last (NameSpace.unpack name);
 | 
|  |    259 |     val prefix' = purify_prefix prefix;
 | 
|  |    260 |     val base' = purify_base base;
 | 
|  |    261 |     val _ = if (base' = base) andalso forall (op =) (prefix' ~~ prefix)
 | 
|  |    262 |       then ()
 | 
|  |    263 |       else
 | 
| 20389 |    264 |         error ("Name violates naming conventions: " ^ quote name
 | 
| 20353 |    265 |           ^ "; perhaps try with " ^ quote (NameSpace.pack (prefix' @ [base'])))
 | 
|  |    266 |     val names_ref = CodegenNamesData.get thy;
 | 
|  |    267 |     val (Names names) = ! names_ref;
 | 
|  |    268 |     val (const, constrev) = #const names;
 | 
| 20386 |    269 |     val c_tys as (c, _) = CodegenConsts.norminst_of_typ thy c_ty;
 | 
| 20353 |    270 |     val _ = if Consttab.defined const c_tys
 | 
| 20389 |    271 |       then error ("Constant already named: " ^ quote (CodegenConsts.string_of_const thy c_tys))
 | 
| 20353 |    272 |       else ();
 | 
|  |    273 |     val _ = if Symtab.defined constrev name
 | 
| 20389 |    274 |       then error ("Name already given to constant: " ^ quote name)
 | 
| 20353 |    275 |       else ();
 | 
|  |    276 |     val _ = names_ref := map_const (K (Consttab.update_new (c_tys, name) const,
 | 
|  |    277 |           Symtab.update_new (name, c_tys) constrev)) (Names names);
 | 
|  |    278 |   in
 | 
|  |    279 |     thy
 | 
|  |    280 |   end;
 | 
|  |    281 | 
 | 
|  |    282 | 
 | 
|  |    283 | (* naming policies *)
 | 
|  |    284 | 
 | 
|  |    285 | fun policy thy get_basename get_thyname name =
 | 
|  |    286 |   let
 | 
|  |    287 |     val prefix = (purify_prefix o NameSpace.unpack o get_thyname thy) name;
 | 
|  |    288 |     val base = (purify_base o get_basename) name;
 | 
|  |    289 |   in NameSpace.pack (prefix @ [base]) end;
 | 
|  |    290 | 
 | 
|  |    291 | fun class_policy thy = policy thy NameSpace.base thyname_of_class;
 | 
|  |    292 | fun tyco_policy thy = policy thy NameSpace.base thyname_of_tyco;
 | 
|  |    293 | fun instance_policy thy = policy thy (fn (class, tyco) => 
 | 
|  |    294 |   NameSpace.base class ^ "_" ^ NameSpace.base tyco) thyname_of_instance;
 | 
|  |    295 | 
 | 
| 20386 |    296 | fun force_thyname thy ("op =", [Type (tyco, _)]) =
 | 
| 20389 |    297 |       (*will disappear finally*)
 | 
| 20386 |    298 |       SOME (thyname_of_tyco thy tyco)
 | 
|  |    299 |   | force_thyname thy (c, tys) =
 | 
| 20389 |    300 |       case AxClass.class_of_param thy c
 | 
|  |    301 |        of SOME class => (case tys
 | 
|  |    302 |            of [Type (tyco, _)] => SOME (thyname_of_instance thy (class, tyco))
 | 
|  |    303 |             | _ => NONE)
 | 
|  |    304 |         | NONE => (case CodegenConsts.find_def thy (c, tys)
 | 
|  |    305 |        of SOME ((thyname, _), tys) => SOME thyname
 | 
|  |    306 |         | NONE => NONE);
 | 
| 20386 |    307 | 
 | 
| 20353 |    308 | fun const_policy thy (c, tys) =
 | 
| 20386 |    309 |   case force_thyname thy (c, tys)
 | 
| 20353 |    310 |    of NONE => policy thy NameSpace.base thyname_of_const c
 | 
|  |    311 |     | SOME thyname => let
 | 
|  |    312 |         val prefix = (purify_prefix o NameSpace.unpack) thyname;
 | 
|  |    313 |         val tycos = map_filter (fn Type (tyco, _) => SOME tyco | _ => NONE) tys;
 | 
| 20386 |    314 |         val base = map (purify_base o NameSpace.base) (c :: tycos);
 | 
|  |    315 |       in NameSpace.pack (prefix @ [space_implode "_" base]) end;
 | 
| 20353 |    316 | 
 | 
|  |    317 | 
 | 
|  |    318 | (* external interfaces *)
 | 
|  |    319 | 
 | 
|  |    320 | fun class thy =
 | 
|  |    321 |   get thy #class Symtab.lookup map_class Symtab.update class_policy;
 | 
|  |    322 | fun tyco thy =
 | 
|  |    323 |   get thy #tyco Symtab.lookup map_tyco Symtab.update tyco_policy;
 | 
|  |    324 | fun instance thy =
 | 
|  |    325 |   get thy #instance Insttab.lookup map_inst Insttab.update instance_policy;
 | 
|  |    326 | fun const thy =
 | 
|  |    327 |   get thy #const Consttab.lookup map_const Consttab.update const_policy
 | 
| 20386 |    328 |     o CodegenConsts.norminst_of_typ thy;
 | 
| 20353 |    329 | 
 | 
|  |    330 | fun class_rev thy = rev thy #class "class";
 | 
|  |    331 | fun tyco_rev thy = rev thy #tyco "type constructor";
 | 
|  |    332 | fun instance_rev thy = rev thy #instance "instance";
 | 
| 20386 |    333 | fun const_rev thy = rev thy #const "constant" #> CodegenConsts.typ_of_typinst thy;
 | 
| 20353 |    334 | 
 | 
|  |    335 | 
 | 
|  |    336 | (* outer syntax *)
 | 
|  |    337 | 
 | 
|  |    338 | local
 | 
|  |    339 | 
 | 
|  |    340 | structure P = OuterParse
 | 
|  |    341 | and K = OuterKeyword
 | 
|  |    342 | 
 | 
| 20386 |    343 | fun const_force_e (raw_c, name) thy =
 | 
| 20389 |    344 |   const_force (CodegenConsts.read_const_typ thy raw_c, name) thy;
 | 
| 20353 |    345 | 
 | 
| 20386 |    346 | fun tyco_force_e (raw_tyco, name) thy =
 | 
|  |    347 |   tyco_force (Sign.intern_type thy raw_tyco, name) thy;
 | 
|  |    348 | 
 | 
|  |    349 | val (constnameK, typenameK) = ("code_constname", "code_typename");
 | 
| 20353 |    350 | 
 | 
|  |    351 | val constnameP =
 | 
|  |    352 |   OuterSyntax.command constnameK "declare code name for constant" K.thy_decl (
 | 
| 20386 |    353 |     Scan.repeat1 (P.term -- P.name)
 | 
|  |    354 |     >> (fn aliasses =>
 | 
|  |    355 |           Toplevel.theory (fold const_force_e aliasses))
 | 
|  |    356 |   );
 | 
|  |    357 | 
 | 
|  |    358 | val typenameP =
 | 
|  |    359 |   OuterSyntax.command typenameK "declare code name for type constructor" K.thy_decl (
 | 
|  |    360 |     Scan.repeat1 (P.name -- P.name)
 | 
|  |    361 |     >> (fn aliasses =>
 | 
|  |    362 |           Toplevel.theory (fold tyco_force_e aliasses))
 | 
| 20353 |    363 |   );
 | 
|  |    364 | 
 | 
|  |    365 | in
 | 
|  |    366 | 
 | 
| 20386 |    367 | val _ = OuterSyntax.add_parsers [constnameP, typenameP];
 | 
| 20353 |    368 | 
 | 
|  |    369 | 
 | 
|  |    370 | end; (*local*)
 | 
|  |    371 | 
 | 
|  |    372 | end;
 |