| author | nipkow | 
| Fri, 06 Aug 2004 16:54:26 +0200 | |
| changeset 15119 | e5f167042c1d | 
| parent 15029 | a4d0ed993050 | 
| child 15261 | ba3c9fdbace3 | 
| permissions | -rw-r--r-- | 
| 11520 | 1 | (* Title: Pure/codegen.ML | 
| 2 | ID: $Id$ | |
| 11539 | 3 | Author: Stefan Berghofer, TU Muenchen | 
| 11520 | 4 | |
| 11539 | 5 | Generic code generator. | 
| 11520 | 6 | *) | 
| 7 | ||
| 8 | signature CODEGEN = | |
| 9 | sig | |
| 10 | val quiet_mode : bool ref | |
| 11 | val message : string -> unit | |
| 13753 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 12 | val mode : string list ref | 
| 13886 
0b243f6e257e
Margin for pretty-printing is now a mutable reference.
 berghofe parents: 
13753diff
changeset | 13 | val margin : int ref | 
| 11520 | 14 | |
| 12452 | 15 | datatype 'a mixfix = | 
| 11520 | 16 | Arg | 
| 17 | | Ignore | |
| 18 | | Pretty of Pretty.T | |
| 12452 | 19 | | Quote of 'a; | 
| 11520 | 20 | |
| 12452 | 21 | type 'a codegen | 
| 22 | ||
| 23 | val add_codegen: string -> term codegen -> theory -> theory | |
| 24 | val add_tycodegen: string -> typ codegen -> theory -> theory | |
| 14197 | 25 | val add_attribute: string -> (Args.T list -> theory attribute * Args.T list) -> theory -> theory | 
| 11520 | 26 | val print_codegens: theory -> unit | 
| 27 | val generate_code: theory -> (string * string) list -> string | |
| 28 | val generate_code_i: theory -> (string * term) list -> string | |
| 12452 | 29 | val assoc_consts: (xstring * string option * term mixfix list) list -> theory -> theory | 
| 30 | val assoc_consts_i: (xstring * typ option * term mixfix list) list -> theory -> theory | |
| 31 | val assoc_types: (xstring * typ mixfix list) list -> theory -> theory | |
| 32 | val get_assoc_code: theory -> string -> typ -> term mixfix list option | |
| 33 | val get_assoc_type: theory -> string -> typ mixfix list option | |
| 34 | val invoke_codegen: theory -> string -> bool -> | |
| 35 | (exn option * string) Graph.T * term -> (exn option * string) Graph.T * Pretty.T | |
| 36 | val invoke_tycodegen: theory -> string -> bool -> | |
| 37 | (exn option * string) Graph.T * typ -> (exn option * string) Graph.T * Pretty.T | |
| 14858 | 38 | val mk_id: string -> string | 
| 11520 | 39 | val mk_const_id: Sign.sg -> string -> string | 
| 40 | val mk_type_id: Sign.sg -> string -> string | |
| 41 | val rename_term: term -> term | |
| 42 | val get_defn: theory -> string -> typ -> ((term list * term) * int option) option | |
| 43 | val is_instance: theory -> typ -> typ -> bool | |
| 44 | val parens: Pretty.T -> Pretty.T | |
| 45 | val mk_app: bool -> Pretty.T -> Pretty.T list -> Pretty.T | |
| 46 | val eta_expand: term -> term list -> int -> term | |
| 14105 | 47 | val strip_tname: string -> string | 
| 13753 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 48 | val mk_type: bool -> typ -> Pretty.T | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 49 | val mk_term_of: Sign.sg -> bool -> typ -> Pretty.T | 
| 14105 | 50 | val mk_gen: Sign.sg -> bool -> string list -> string -> typ -> Pretty.T | 
| 51 | val test_fn: (int -> (string * term) list option) ref | |
| 52 | val test_term: theory -> int -> int -> term -> (string * term) list option | |
| 12452 | 53 | val parse_mixfix: (string -> 'a) -> string -> 'a mixfix list | 
| 11520 | 54 | val parsers: OuterSyntax.parser list | 
| 55 | val setup: (theory -> theory) list | |
| 56 | end; | |
| 57 | ||
| 58 | structure Codegen : CODEGEN = | |
| 59 | struct | |
| 60 | ||
| 61 | val quiet_mode = ref true; | |
| 62 | fun message s = if !quiet_mode then () else writeln s; | |
| 63 | ||
| 13753 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 64 | val mode = ref ([] : string list); | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 65 | |
| 13886 
0b243f6e257e
Margin for pretty-printing is now a mutable reference.
 berghofe parents: 
13753diff
changeset | 66 | val margin = ref 80; | 
| 
0b243f6e257e
Margin for pretty-printing is now a mutable reference.
 berghofe parents: 
13753diff
changeset | 67 | |
| 11520 | 68 | (**** Mixfix syntax ****) | 
| 69 | ||
| 12452 | 70 | datatype 'a mixfix = | 
| 11520 | 71 | Arg | 
| 72 | | Ignore | |
| 73 | | Pretty of Pretty.T | |
| 12452 | 74 | | Quote of 'a; | 
| 11520 | 75 | |
| 76 | fun is_arg Arg = true | |
| 77 | | is_arg Ignore = true | |
| 78 | | is_arg _ = false; | |
| 79 | ||
| 12452 | 80 | fun quotes_of [] = [] | 
| 81 | | quotes_of (Quote q :: ms) = q :: quotes_of ms | |
| 82 | | quotes_of (_ :: ms) = quotes_of ms; | |
| 83 | ||
| 84 | fun args_of [] xs = ([], xs) | |
| 85 | | args_of (Arg :: ms) (x :: xs) = apfst (cons x) (args_of ms xs) | |
| 86 | | args_of (Ignore :: ms) (_ :: xs) = args_of ms xs | |
| 87 | | args_of (_ :: ms) xs = args_of ms xs; | |
| 11520 | 88 | |
| 12490 | 89 | fun num_args x = length (filter is_arg x); | 
| 11520 | 90 | |
| 91 | ||
| 92 | (**** theory data ****) | |
| 93 | ||
| 14105 | 94 | (* type of code generators *) | 
| 11520 | 95 | |
| 12452 | 96 | type 'a codegen = theory -> (exn option * string) Graph.T -> | 
| 97 | string -> bool -> 'a -> ((exn option * string) Graph.T * Pretty.T) option; | |
| 98 | ||
| 14105 | 99 | (* parameters for random testing *) | 
| 100 | ||
| 101 | type test_params = | |
| 102 |   {size: int, iterations: int, default_type: typ option};
 | |
| 103 | ||
| 104 | fun merge_test_params | |
| 105 |   {size = size1, iterations = iterations1, default_type = default_type1}
 | |
| 106 |   {size = size2, iterations = iterations2, default_type = default_type2} =
 | |
| 107 |   {size = Int.max (size1, size2),
 | |
| 108 | iterations = Int.max (iterations1, iterations2), | |
| 109 | default_type = case default_type1 of | |
| 110 | None => default_type2 | |
| 111 | | _ => default_type1}; | |
| 112 | ||
| 113 | val default_test_params : test_params = | |
| 114 |   {size = 10, iterations = 100, default_type = None};
 | |
| 115 | ||
| 116 | fun set_size size ({iterations, default_type, ...} : test_params) =
 | |
| 117 |   {size = size, iterations = iterations, default_type = default_type};
 | |
| 118 | ||
| 119 | fun set_iterations iterations ({size, default_type, ...} : test_params) =
 | |
| 120 |   {size = size, iterations = iterations, default_type = default_type};
 | |
| 121 | ||
| 122 | fun set_default_type s sg ({size, iterations, ...} : test_params) =
 | |
| 123 |   {size = size, iterations = iterations,
 | |
| 124 | default_type = Some (typ_of (read_ctyp sg s))}; | |
| 125 | ||
| 126 | (* data kind 'Pure/codegen' *) | |
| 127 | ||
| 11520 | 128 | structure CodegenArgs = | 
| 129 | struct | |
| 130 | val name = "Pure/codegen"; | |
| 131 | type T = | |
| 12452 | 132 |     {codegens : (string * term codegen) list,
 | 
| 133 | tycodegens : (string * typ codegen) list, | |
| 134 | consts : ((string * typ) * term mixfix list) list, | |
| 12555 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 135 | types : (string * typ mixfix list) list, | 
| 14197 | 136 | attrs: (string * (Args.T list -> theory attribute * Args.T list)) list, | 
| 14105 | 137 | test_params: test_params}; | 
| 11520 | 138 | |
| 12555 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 139 | val empty = | 
| 14105 | 140 |     {codegens = [], tycodegens = [], consts = [], types = [], attrs = [],
 | 
| 141 | test_params = default_test_params}; | |
| 11520 | 142 | val copy = I; | 
| 143 | val prep_ext = I; | |
| 144 | ||
| 12555 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 145 | fun merge | 
| 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 146 |     ({codegens = codegens1, tycodegens = tycodegens1,
 | 
| 14105 | 147 | consts = consts1, types = types1, attrs = attrs1, | 
| 148 | test_params = test_params1}, | |
| 12555 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 149 |      {codegens = codegens2, tycodegens = tycodegens2,
 | 
| 14105 | 150 | consts = consts2, types = types2, attrs = attrs2, | 
| 151 | test_params = test_params2}) = | |
| 11520 | 152 |     {codegens = rev (merge_alists (rev codegens1) (rev codegens2)),
 | 
| 12452 | 153 | tycodegens = rev (merge_alists (rev tycodegens1) (rev tycodegens2)), | 
| 12555 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 154 | consts = merge_alists consts1 consts2, | 
| 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 155 | types = merge_alists types1 types2, | 
| 14105 | 156 | attrs = merge_alists attrs1 attrs2, | 
| 157 | test_params = merge_test_params test_params1 test_params2}; | |
| 11520 | 158 | |
| 12452 | 159 |   fun print sg ({codegens, tycodegens, ...} : T) =
 | 
| 160 | Pretty.writeln (Pretty.chunks | |
| 161 |       [Pretty.strs ("term code generators:" :: map fst codegens),
 | |
| 162 |        Pretty.strs ("type code generators:" :: map fst tycodegens)]);
 | |
| 11520 | 163 | end; | 
| 164 | ||
| 165 | structure CodegenData = TheoryDataFun(CodegenArgs); | |
| 166 | val print_codegens = CodegenData.print; | |
| 167 | ||
| 168 | ||
| 14105 | 169 | (**** access parameters for random testing ****) | 
| 170 | ||
| 171 | fun get_test_params thy = #test_params (CodegenData.get thy); | |
| 172 | ||
| 173 | fun map_test_params f thy = | |
| 174 |   let val {codegens, tycodegens, consts, types, attrs, test_params} =
 | |
| 175 | CodegenData.get thy; | |
| 176 |   in CodegenData.put {codegens = codegens, tycodegens = tycodegens,
 | |
| 177 | consts = consts, types = types, attrs = attrs, | |
| 178 | test_params = f test_params} thy | |
| 179 | end; | |
| 180 | ||
| 181 | ||
| 12452 | 182 | (**** add new code generators to theory ****) | 
| 11520 | 183 | |
| 184 | fun add_codegen name f thy = | |
| 14105 | 185 |   let val {codegens, tycodegens, consts, types, attrs, test_params} =
 | 
| 186 | CodegenData.get thy | |
| 11520 | 187 | in (case assoc (codegens, name) of | 
| 12452 | 188 |       None => CodegenData.put {codegens = (name, f) :: codegens,
 | 
| 12555 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 189 | tycodegens = tycodegens, consts = consts, types = types, | 
| 14105 | 190 | attrs = attrs, test_params = test_params} thy | 
| 12452 | 191 |     | Some _ => error ("Code generator " ^ name ^ " already declared"))
 | 
| 192 | end; | |
| 193 | ||
| 194 | fun add_tycodegen name f thy = | |
| 14105 | 195 |   let val {codegens, tycodegens, consts, types, attrs, test_params} =
 | 
| 196 | CodegenData.get thy | |
| 12452 | 197 | in (case assoc (tycodegens, name) of | 
| 198 |       None => CodegenData.put {tycodegens = (name, f) :: tycodegens,
 | |
| 12555 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 199 | codegens = codegens, consts = consts, types = types, | 
| 14105 | 200 | attrs = attrs, test_params = test_params} thy | 
| 11520 | 201 |     | Some _ => error ("Code generator " ^ name ^ " already declared"))
 | 
| 202 | end; | |
| 203 | ||
| 204 | ||
| 12555 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 205 | (**** code attribute ****) | 
| 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 206 | |
| 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 207 | fun add_attribute name att thy = | 
| 14105 | 208 |   let val {codegens, tycodegens, consts, types, attrs, test_params} =
 | 
| 209 | CodegenData.get thy | |
| 12555 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 210 | in (case assoc (attrs, name) of | 
| 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 211 |       None => CodegenData.put {tycodegens = tycodegens,
 | 
| 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 212 | codegens = codegens, consts = consts, types = types, | 
| 14105 | 213 | attrs = (name, att) :: attrs, test_params = test_params} thy | 
| 12555 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 214 |     | Some _ => error ("Code attribute " ^ name ^ " already declared"))
 | 
| 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 215 | end; | 
| 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 216 | |
| 14197 | 217 | fun mk_parser (a, p) = (if a = "" then Scan.succeed "" else Args.$$$ a) |-- p; | 
| 218 | ||
| 12555 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 219 | val code_attr = | 
| 14197 | 220 | Attrib.syntax (Scan.depend (fn thy => foldr op || (map mk_parser | 
| 221 | (#attrs (CodegenData.get thy)), Scan.fail) >> pair thy)); | |
| 12555 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 222 | |
| 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 223 | |
| 11520 | 224 | (**** associate constants with target language code ****) | 
| 225 | ||
| 226 | fun gen_assoc_consts prep_type xs thy = foldl (fn (thy, (s, tyopt, syn)) => | |
| 227 | let | |
| 228 | val sg = sign_of thy; | |
| 14105 | 229 |     val {codegens, tycodegens, consts, types, attrs, test_params} =
 | 
| 230 | CodegenData.get thy; | |
| 11520 | 231 | val cname = Sign.intern_const sg s; | 
| 232 | in | |
| 233 | (case Sign.const_type sg cname of | |
| 234 | Some T => | |
| 235 | let val T' = (case tyopt of | |
| 236 | None => T | |
| 237 | | Some ty => | |
| 238 | let val U = prep_type sg ty | |
| 14769 | 239 | in if Sign.typ_instance sg (U, T) then U | 
| 11520 | 240 |                     else error ("Illegal type constraint for constant " ^ cname)
 | 
| 241 | end) | |
| 242 | in (case assoc (consts, (cname, T')) of | |
| 243 |              None => CodegenData.put {codegens = codegens,
 | |
| 12452 | 244 | tycodegens = tycodegens, | 
| 12555 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 245 | consts = ((cname, T'), syn) :: consts, | 
| 14105 | 246 | types = types, attrs = attrs, test_params = test_params} thy | 
| 11520 | 247 |            | Some _ => error ("Constant " ^ cname ^ " already associated with code"))
 | 
| 248 | end | |
| 249 |      | _ => error ("Not a constant: " ^ s))
 | |
| 250 | end) (thy, xs); | |
| 251 | ||
| 252 | val assoc_consts_i = gen_assoc_consts (K I); | |
| 253 | val assoc_consts = gen_assoc_consts (fn sg => typ_of o read_ctyp sg); | |
| 254 | ||
| 255 | (**** associate types with target language types ****) | |
| 256 | ||
| 257 | fun assoc_types xs thy = foldl (fn (thy, (s, syn)) => | |
| 258 | let | |
| 14105 | 259 |     val {codegens, tycodegens, consts, types, attrs, test_params} =
 | 
| 260 | CodegenData.get thy; | |
| 11520 | 261 | val tc = Sign.intern_tycon (sign_of thy) s | 
| 262 | in | |
| 263 | (case assoc (types, tc) of | |
| 12452 | 264 |        None => CodegenData.put {codegens = codegens,
 | 
| 265 | tycodegens = tycodegens, consts = consts, | |
| 14105 | 266 | types = (tc, syn) :: types, attrs = attrs, | 
| 267 | test_params = test_params} thy | |
| 11520 | 268 |      | Some _ => error ("Type " ^ tc ^ " already associated with code"))
 | 
| 269 | end) (thy, xs); | |
| 270 | ||
| 12452 | 271 | fun get_assoc_type thy s = assoc (#types (CodegenData.get thy), s); | 
| 11546 | 272 | |
| 11520 | 273 | |
| 274 | (**** make valid ML identifiers ****) | |
| 275 | ||
| 14858 | 276 | fun is_ascii_letdig x = Symbol.is_ascii_letter x orelse | 
| 277 | Symbol.is_ascii_digit x orelse Symbol.is_ascii_quasi x; | |
| 278 | ||
| 279 | fun dest_sym s = (case split_last (snd (take_prefix (equal "\\") (explode s))) of | |
| 280 |     ("<" :: "^" :: xs, ">") => (true, implode xs)
 | |
| 281 |   | ("<" :: xs, ">") => (false, implode xs)
 | |
| 282 | | _ => sys_error "dest_sym"); | |
| 283 | ||
| 284 | fun mk_id s = if s = "" then "" else | |
| 11520 | 285 | let | 
| 14858 | 286 | fun check_str [] = [] | 
| 287 | | check_str xs = (case take_prefix is_ascii_letdig xs of | |
| 288 | ([], " " :: zs) => check_str zs | |
| 289 | | ([], z :: zs) => | |
| 290 | if size z = 1 then string_of_int (ord z) :: check_str zs | |
| 291 | else (case dest_sym z of | |
| 292 | (true, "isub") => check_str zs | |
| 293 | | (true, "isup") => "" :: check_str zs | |
| 294 | | (ctrl, s') => (if ctrl then "ctrl_" ^ s' else s') :: check_str zs) | |
| 295 | | (ys, zs) => implode ys :: check_str zs); | |
| 296 | val s' = space_implode "_" | |
| 297 | (flat (map (check_str o Symbol.explode) (NameSpace.unpack s))) | |
| 11520 | 298 | in | 
| 14858 | 299 | if Symbol.is_ascii_letter (hd (explode s')) then s' else "id_" ^ s' | 
| 11520 | 300 | end; | 
| 301 | ||
| 14858 | 302 | fun mk_const_id sg s = | 
| 303 | let val s' = mk_id (Sign.cond_extern sg Sign.constK s) | |
| 304 | in if s' mem ThmDatabase.ml_reserved then s' ^ "_const" else s' end; | |
| 13073 
cc9d7f403a4b
mk_const_id now checks for clashes with reserved ML identifiers.
 berghofe parents: 
13003diff
changeset | 305 | |
| 14858 | 306 | fun mk_type_id sg s = | 
| 307 | let val s' = mk_id (Sign.cond_extern sg Sign.typeK s) | |
| 308 | in if s' mem ThmDatabase.ml_reserved then s' ^ "_type" else s' end; | |
| 11520 | 309 | |
| 13731 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 310 | fun rename_terms ts = | 
| 11520 | 311 | let | 
| 13731 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 312 | val names = foldr add_term_names | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 313 | (ts, map (fst o fst) (Drule.vars_of_terms ts)); | 
| 14858 | 314 | val reserved = names inter ThmDatabase.ml_reserved; | 
| 315 | val (illegal, alt_names) = split_list (mapfilter (fn s => | |
| 316 | let val s' = mk_id s in if s = s' then None else Some (s, s') end) names) | |
| 317 | val ps = (reserved @ illegal) ~~ | |
| 318 | variantlist (map (suffix "'") reserved @ alt_names, names); | |
| 11520 | 319 | |
| 14858 | 320 | fun rename_id s = if_none (assoc (ps, s)) s; | 
| 321 | ||
| 322 | fun rename (Var ((a, i), T)) = Var ((rename_id a, i), T) | |
| 323 | | rename (Free (a, T)) = Free (rename_id a, T) | |
| 11520 | 324 | | rename (Abs (s, T, t)) = Abs (s, T, rename t) | 
| 325 | | rename (t $ u) = rename t $ rename u | |
| 326 | | rename t = t; | |
| 327 | in | |
| 13731 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 328 | map rename ts | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 329 | end; | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 330 | |
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 331 | val rename_term = hd o rename_terms o single; | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 332 | |
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 333 | |
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 334 | (**** retrieve definition of constant ****) | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 335 | |
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 336 | fun is_instance thy T1 T2 = | 
| 14769 | 337 | Sign.typ_instance (sign_of thy) (T1, Type.varifyT T2); | 
| 13731 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 338 | |
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 339 | fun get_assoc_code thy s T = apsome snd (find_first (fn ((s', T'), _) => | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 340 | s = s' andalso is_instance thy T T') (#consts (CodegenData.get thy))); | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 341 | |
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 342 | fun get_defn thy s T = | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 343 | let | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 344 | val axms = flat (map (Symtab.dest o #axioms o Theory.rep_theory) | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 345 | (thy :: Theory.ancestors_of thy)); | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 346 | val defs = mapfilter (fn (_, t) => | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 347 | (let | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 348 | val (lhs, rhs) = Logic.dest_equals t; | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 349 | val (c, args) = strip_comb lhs; | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 350 | val (s', T') = dest_Const c | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 351 | in if s=s' then Some (T', split_last (rename_terms (args @ [rhs]))) | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 352 | else None end) handle TERM _ => None) axms; | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 353 | val i = find_index (is_instance thy T o fst) defs | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 354 | in | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 355 | if i>=0 then Some (snd (nth_elem (i, defs)), | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 356 | if length defs = 1 then None else Some i) | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 357 | else None | 
| 11520 | 358 | end; | 
| 359 | ||
| 360 | ||
| 12452 | 361 | (**** invoke suitable code generator for term / type ****) | 
| 11520 | 362 | |
| 12452 | 363 | fun invoke_codegen thy dep brack (gr, t) = (case get_first | 
| 11520 | 364 | (fn (_, f) => f thy gr dep brack t) (#codegens (CodegenData.get thy)) of | 
| 365 |       None => error ("Unable to generate code for term:\n" ^
 | |
| 366 | Sign.string_of_term (sign_of thy) t ^ "\nrequired by:\n" ^ | |
| 367 | commas (Graph.all_succs gr [dep])) | |
| 12452 | 368 | | Some x => x); | 
| 369 | ||
| 370 | fun invoke_tycodegen thy dep brack (gr, T) = (case get_first | |
| 371 | (fn (_, f) => f thy gr dep brack T) (#tycodegens (CodegenData.get thy)) of | |
| 372 |       None => error ("Unable to generate code for type:\n" ^
 | |
| 373 | Sign.string_of_typ (sign_of thy) T ^ "\nrequired by:\n" ^ | |
| 374 | commas (Graph.all_succs gr [dep])) | |
| 375 | | Some x => x); | |
| 11520 | 376 | |
| 377 | ||
| 378 | (**** code generator for mixfix expressions ****) | |
| 379 | ||
| 380 | fun parens p = Pretty.block [Pretty.str "(", p, Pretty.str ")"];
 | |
| 381 | ||
| 382 | fun pretty_fn [] p = [p] | |
| 383 |   | pretty_fn (x::xs) p = Pretty.str ("fn " ^ x ^ " =>") ::
 | |
| 384 | Pretty.brk 1 :: pretty_fn xs p; | |
| 385 | ||
| 386 | fun pretty_mixfix [] [] _ = [] | |
| 387 | | pretty_mixfix (Arg :: ms) (p :: ps) qs = p :: pretty_mixfix ms ps qs | |
| 12452 | 388 | | pretty_mixfix (Ignore :: ms) ps qs = pretty_mixfix ms ps qs | 
| 11520 | 389 | | pretty_mixfix (Pretty p :: ms) ps qs = p :: pretty_mixfix ms ps qs | 
| 12452 | 390 | | pretty_mixfix (Quote _ :: ms) ps (q :: qs) = q :: pretty_mixfix ms ps qs; | 
| 11520 | 391 | |
| 392 | ||
| 12452 | 393 | (**** default code generators ****) | 
| 11520 | 394 | |
| 395 | fun eta_expand t ts i = | |
| 396 | let | |
| 397 | val (Ts, _) = strip_type (fastype_of t); | |
| 398 | val j = i - length ts | |
| 399 | in | |
| 400 |     foldr (fn (T, t) => Abs ("x", T, t))
 | |
| 401 | (take (j, Ts), list_comb (t, ts @ map Bound (j-1 downto 0))) | |
| 402 | end; | |
| 403 | ||
| 404 | fun mk_app _ p [] = p | |
| 405 | | mk_app brack p ps = if brack then | |
| 406 |        Pretty.block (Pretty.str "(" ::
 | |
| 407 | separate (Pretty.brk 1) (p :: ps) @ [Pretty.str ")"]) | |
| 408 | else Pretty.block (separate (Pretty.brk 1) (p :: ps)); | |
| 409 | ||
| 14858 | 410 | fun new_names t xs = variantlist (map mk_id xs, | 
| 11520 | 411 | map (fst o fst o dest_Var) (term_vars t) union | 
| 412 | add_term_names (t, ThmDatabase.ml_reserved)); | |
| 413 | ||
| 414 | fun new_name t x = hd (new_names t [x]); | |
| 415 | ||
| 416 | fun default_codegen thy gr dep brack t = | |
| 417 | let | |
| 418 | val (u, ts) = strip_comb t; | |
| 12452 | 419 | fun codegens brack = foldl_map (invoke_codegen thy dep brack) | 
| 11520 | 420 | in (case u of | 
| 14105 | 421 | Var ((s, i), T) => | 
| 422 | let | |
| 423 | val (gr', ps) = codegens true (gr, ts); | |
| 424 | val (gr'', _) = invoke_tycodegen thy dep false (gr', T) | |
| 425 | in Some (gr'', mk_app brack (Pretty.str (s ^ | |
| 11520 | 426 | (if i=0 then "" else string_of_int i))) ps) | 
| 427 | end | |
| 428 | ||
| 14105 | 429 | | Free (s, T) => | 
| 430 | let | |
| 431 | val (gr', ps) = codegens true (gr, ts); | |
| 432 | val (gr'', _) = invoke_tycodegen thy dep false (gr', T) | |
| 433 | in Some (gr'', mk_app brack (Pretty.str s) ps) end | |
| 11520 | 434 | |
| 435 | | Const (s, T) => | |
| 436 | (case get_assoc_code thy s T of | |
| 437 | Some ms => | |
| 438 | let val i = num_args ms | |
| 439 | in if length ts < i then | |
| 440 | default_codegen thy gr dep brack (eta_expand u ts i) | |
| 441 | else | |
| 442 | let | |
| 12452 | 443 | val (ts1, ts2) = args_of ms ts; | 
| 444 | val (gr1, ps1) = codegens false (gr, ts1); | |
| 445 | val (gr2, ps2) = codegens true (gr1, ts2); | |
| 446 | val (gr3, ps3) = codegens false (gr2, quotes_of ms); | |
| 11520 | 447 | in | 
| 448 | Some (gr3, mk_app brack (Pretty.block (pretty_mixfix ms ps1 ps3)) ps2) | |
| 449 | end | |
| 450 | end | |
| 451 | | None => (case get_defn thy s T of | |
| 452 | None => None | |
| 453 | | Some ((args, rhs), k) => | |
| 454 | let | |
| 455 | val id = mk_const_id (sign_of thy) s ^ (case k of | |
| 456 | None => "" | Some i => "_def" ^ string_of_int i); | |
| 12452 | 457 | val (gr', ps) = codegens true (gr, ts); | 
| 11520 | 458 | in | 
| 459 | Some (Graph.add_edge (id, dep) gr' handle Graph.UNDEF _ => | |
| 460 | let | |
| 461 |                    val _ = message ("expanding definition of " ^ s);
 | |
| 462 | val (Ts, _) = strip_type T; | |
| 463 | val (args', rhs') = | |
| 464 | if not (null args) orelse null Ts then (args, rhs) else | |
| 465 | let val v = Free (new_name rhs "x", hd Ts) | |
| 466 | in ([v], betapply (rhs, v)) end; | |
| 12452 | 467 | val (gr1, p) = invoke_codegen thy id false | 
| 468 | (Graph.add_edge (id, dep) | |
| 469 | (Graph.new_node (id, (None, "")) gr'), rhs'); | |
| 470 | val (gr2, xs) = codegens false (gr1, args'); | |
| 12580 
7fdc00bb2a9e
Code generator now adds type constraints to val declarations (to make
 berghofe parents: 
12555diff
changeset | 471 | val (gr3, ty) = invoke_tycodegen thy id false (gr2, T); | 
| 14980 | 472 | in Graph.map_node id (K (None, Pretty.string_of (Pretty.block | 
| 12580 
7fdc00bb2a9e
Code generator now adds type constraints to val declarations (to make
 berghofe parents: 
12555diff
changeset | 473 | (separate (Pretty.brk 1) (if null args' then | 
| 
7fdc00bb2a9e
Code generator now adds type constraints to val declarations (to make
 berghofe parents: 
12555diff
changeset | 474 |                        [Pretty.str ("val " ^ id ^ " :"), ty]
 | 
| 
7fdc00bb2a9e
Code generator now adds type constraints to val declarations (to make
 berghofe parents: 
12555diff
changeset | 475 |                      else Pretty.str ("fun " ^ id) :: xs) @
 | 
| 14980 | 476 | [Pretty.str " =", Pretty.brk 1, p, Pretty.str ";"])) ^ "\n\n")) gr3 | 
| 11520 | 477 | end, mk_app brack (Pretty.str id) ps) | 
| 478 | end)) | |
| 479 | ||
| 480 | | Abs _ => | |
| 481 | let | |
| 482 | val (bs, Ts) = ListPair.unzip (strip_abs_vars u); | |
| 483 | val t = strip_abs_body u | |
| 484 | val bs' = new_names t bs; | |
| 12452 | 485 | val (gr1, ps) = codegens true (gr, ts); | 
| 486 | val (gr2, p) = invoke_codegen thy dep false | |
| 487 | (gr1, subst_bounds (map Free (rev (bs' ~~ Ts)), t)); | |
| 11520 | 488 | in | 
| 489 |         Some (gr2, mk_app brack (Pretty.block (Pretty.str "(" :: pretty_fn bs' p @
 | |
| 490 | [Pretty.str ")"])) ps) | |
| 491 | end | |
| 492 | ||
| 493 | | _ => None) | |
| 494 | end; | |
| 495 | ||
| 12452 | 496 | fun default_tycodegen thy gr dep brack (TVar ((s, i), _)) = | 
| 497 | Some (gr, Pretty.str (s ^ (if i = 0 then "" else string_of_int i))) | |
| 498 | | default_tycodegen thy gr dep brack (TFree (s, _)) = Some (gr, Pretty.str s) | |
| 499 | | default_tycodegen thy gr dep brack (Type (s, Ts)) = | |
| 500 | (case assoc (#types (CodegenData.get thy), s) of | |
| 501 | None => None | |
| 502 | | Some ms => | |
| 503 | let | |
| 504 | val (gr', ps) = foldl_map | |
| 505 | (invoke_tycodegen thy dep false) (gr, fst (args_of ms Ts)); | |
| 506 | val (gr'', qs) = foldl_map | |
| 507 | (invoke_tycodegen thy dep false) (gr', quotes_of ms) | |
| 508 | in Some (gr'', Pretty.block (pretty_mixfix ms ps qs)) end); | |
| 509 | ||
| 11520 | 510 | |
| 511 | fun output_code gr xs = implode (map (snd o Graph.get_node gr) | |
| 512 | (rev (Graph.all_preds gr xs))); | |
| 513 | ||
| 14598 
7009f59711e3
Replaced quote by Library.quote, since quote now refers to Symbol.quote
 berghofe parents: 
14197diff
changeset | 514 | fun gen_generate_code prep_term thy = | 
| 
7009f59711e3
Replaced quote by Library.quote, since quote now refers to Symbol.quote
 berghofe parents: 
14197diff
changeset | 515 | setmp print_mode [] (Pretty.setmp_margin (!margin) (fn xs => | 
| 11520 | 516 | let | 
| 517 | val sg = sign_of thy; | |
| 518 |     val gr = Graph.new_node ("<Top>", (None, "")) Graph.empty;
 | |
| 519 | val (gr', ps) = foldl_map (fn (gr, (s, t)) => apsnd (pair s) | |
| 12452 | 520 | (invoke_codegen thy "<Top>" false (gr, t))) | 
| 521 | (gr, map (apsnd (prep_term sg)) xs) | |
| 14818 | 522 | val code = | 
| 523 | "structure Generated =\nstruct\n\n" ^ | |
| 524 | output_code gr' ["<Top>"] ^ | |
| 525 | space_implode "\n\n" (map (fn (s', p) => Pretty.string_of (Pretty.block | |
| 526 |         [Pretty.str ("val " ^ s' ^ " ="), Pretty.brk 1, p, Pretty.str ";"])) ps) ^
 | |
| 527 | "\n\nend;\n\nopen Generated;\n"; | |
| 14980 | 528 | in code end)); | 
| 11520 | 529 | |
| 530 | val generate_code_i = gen_generate_code (K I); | |
| 531 | val generate_code = gen_generate_code | |
| 532 | (fn sg => term_of o read_cterm sg o rpair TypeInfer.logicT); | |
| 533 | ||
| 12452 | 534 | |
| 13753 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 535 | (**** Reflection ****) | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 536 | |
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 537 | val strip_tname = implode o tl o explode; | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 538 | |
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 539 | fun pretty_list xs = Pretty.block (Pretty.str "[" :: | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 540 | flat (separate [Pretty.str ",", Pretty.brk 1] (map single xs)) @ | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 541 | [Pretty.str "]"]); | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 542 | |
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 543 | fun mk_type p (TVar ((s, i), _)) = Pretty.str | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 544 | (strip_tname s ^ (if i = 0 then "" else string_of_int i) ^ "T") | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 545 | | mk_type p (TFree (s, _)) = Pretty.str (strip_tname s ^ "T") | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 546 | | mk_type p (Type (s, Ts)) = (if p then parens else I) (Pretty.block | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 547 |       [Pretty.str "Type", Pretty.brk 1, Pretty.str ("(\"" ^ s ^ "\","),
 | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 548 | Pretty.brk 1, pretty_list (map (mk_type false) Ts), Pretty.str ")"]); | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 549 | |
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 550 | fun mk_term_of sg p (TVar ((s, i), _)) = Pretty.str | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 551 | (strip_tname s ^ (if i = 0 then "" else string_of_int i) ^ "F") | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 552 | | mk_term_of sg p (TFree (s, _)) = Pretty.str (strip_tname s ^ "F") | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 553 | | mk_term_of sg p (Type (s, Ts)) = (if p then parens else I) (Pretty.block | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 554 |       (separate (Pretty.brk 1) (Pretty.str ("term_of_" ^ mk_type_id sg s) ::
 | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 555 | flat (map (fn T => [mk_term_of sg true T, mk_type true T]) Ts)))); | 
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 556 | |
| 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 557 | |
| 14105 | 558 | (**** Test data generators ****) | 
| 559 | ||
| 560 | fun mk_gen sg p xs a (TVar ((s, i), _)) = Pretty.str | |
| 561 | (strip_tname s ^ (if i = 0 then "" else string_of_int i) ^ "G") | |
| 562 | | mk_gen sg p xs a (TFree (s, _)) = Pretty.str (strip_tname s ^ "G") | |
| 563 | | mk_gen sg p xs a (Type (s, Ts)) = (if p then parens else I) (Pretty.block | |
| 564 |       (separate (Pretty.brk 1) (Pretty.str ("gen_" ^ mk_type_id sg s ^
 | |
| 565 | (if s mem xs then "'" else "")) :: map (mk_gen sg true xs a) Ts @ | |
| 566 | (if s mem xs then [Pretty.str a] else [])))); | |
| 567 | ||
| 568 | val test_fn : (int -> (string * term) list option) ref = ref (fn _ => None); | |
| 569 | ||
| 15029 | 570 | fun test_term thy sz i = setmp print_mode [] (fn t => | 
| 14105 | 571 | let | 
| 572 | val _ = assert (null (term_tvars t) andalso null (term_tfrees t)) | |
| 573 | "Term to be tested contains type variables"; | |
| 574 | val _ = assert (null (term_vars t)) | |
| 575 | "Term to be tested contains schematic variables"; | |
| 576 | val sg = sign_of thy; | |
| 577 | val frees = map dest_Free (term_frees t); | |
| 14140 
ca089b9d13c4
test_term now renames variable for size of test data to avoid clashes
 berghofe parents: 
14135diff
changeset | 578 | val szname = variant (map fst frees) "i"; | 
| 14105 | 579 | val s = "structure TestTerm =\nstruct\n\n" ^ | 
| 580 | setmp mode ["term_of", "test"] (generate_code_i thy) | |
| 581 |         [("testf", list_abs_free (frees, t))] ^
 | |
| 14980 | 582 | "\n" ^ Pretty.string_of | 
| 14105 | 583 | (Pretty.block [Pretty.str "val () = Codegen.test_fn :=", | 
| 14140 
ca089b9d13c4
test_term now renames variable for size of test data to avoid clashes
 berghofe parents: 
14135diff
changeset | 584 |           Pretty.brk 1, Pretty.str ("(fn " ^ szname ^ " =>"), Pretty.brk 1,
 | 
| 14105 | 585 | Pretty.blk (0, [Pretty.str "let", Pretty.brk 1, | 
| 586 | Pretty.blk (0, separate Pretty.fbrk (map (fn (s, T) => | |
| 14886 
b792081d2399
mk_id is now also applied to identifiers in test_term.
 berghofe parents: 
14858diff
changeset | 587 |               Pretty.block [Pretty.str ("val " ^ mk_id s ^ " ="), Pretty.brk 1,
 | 
| 14105 | 588 | mk_gen sg false [] "" T, Pretty.brk 1, | 
| 14140 
ca089b9d13c4
test_term now renames variable for size of test data to avoid clashes
 berghofe parents: 
14135diff
changeset | 589 | Pretty.str (szname ^ ";")]) frees)), | 
| 14105 | 590 | Pretty.brk 1, Pretty.str "in", Pretty.brk 1, | 
| 591 | Pretty.block [Pretty.str "if ", | |
| 14886 
b792081d2399
mk_id is now also applied to identifiers in test_term.
 berghofe parents: 
14858diff
changeset | 592 | mk_app false (Pretty.str "testf") (map (Pretty.str o mk_id o fst) frees), | 
| 14110 
c45c94fa16f4
use Library.Some/None instead of just Some/None in generated quickcheck code
 kleing parents: 
14105diff
changeset | 593 | Pretty.brk 1, Pretty.str "then Library.None", | 
| 14105 | 594 | Pretty.brk 1, Pretty.str "else ", | 
| 14110 
c45c94fa16f4
use Library.Some/None instead of just Some/None in generated quickcheck code
 kleing parents: 
14105diff
changeset | 595 | Pretty.block [Pretty.str "Library.Some ", Pretty.block (Pretty.str "[" :: | 
| 14105 | 596 | flat (separate [Pretty.str ",", Pretty.brk 1] | 
| 597 | (map (fn (s, T) => [Pretty.block | |
| 14598 
7009f59711e3
Replaced quote by Library.quote, since quote now refers to Symbol.quote
 berghofe parents: 
14197diff
changeset | 598 |                     [Pretty.str ("(" ^ Library.quote s ^ ","), Pretty.brk 1,
 | 
| 14105 | 599 | mk_app false (mk_term_of sg false T) | 
| 14886 
b792081d2399
mk_id is now also applied to identifiers in test_term.
 berghofe parents: 
14858diff
changeset | 600 | [Pretty.str (mk_id s)], Pretty.str ")"]]) frees)) @ | 
| 14105 | 601 | [Pretty.str "]"])]], | 
| 14980 | 602 | Pretty.brk 1, Pretty.str "end"]), Pretty.str ");"]) ^ | 
| 14105 | 603 | "\n\nend;\n"; | 
| 604 | val _ = use_text Context.ml_output false s; | |
| 605 | fun iter f k = if k > i then None | |
| 14135 
f8a25218b423
test_term now handles Match exception raised in generated code.
 berghofe parents: 
14110diff
changeset | 606 | else (case (f () handle Match => | 
| 
f8a25218b423
test_term now handles Match exception raised in generated code.
 berghofe parents: 
14110diff
changeset | 607 | (warning "Exception Match raised in generated code"; None)) of | 
| 
f8a25218b423
test_term now handles Match exception raised in generated code.
 berghofe parents: 
14110diff
changeset | 608 | None => iter f (k+1) | Some x => Some x); | 
| 14105 | 609 | fun test k = if k > sz then None | 
| 610 |       else (priority ("Test data size: " ^ string_of_int k);
 | |
| 611 | case iter (fn () => !test_fn k) 1 of | |
| 612 | None => test (k+1) | Some x => Some x); | |
| 15029 | 613 | in test 0 end); | 
| 14105 | 614 | |
| 615 | fun test_goal ({size, iterations, default_type}, tvinsts) i st =
 | |
| 616 | let | |
| 617 | val sg = Toplevel.sign_of st; | |
| 618 |     fun strip (Const ("all", _) $ Abs (_, _, t)) = strip t
 | |
| 619 | | strip t = t; | |
| 620 | val (gi, frees) = Logic.goal_params | |
| 621 | (prop_of (snd (snd (Proof.get_goal (Toplevel.proof_of st))))) i; | |
| 622 | val gi' = ObjectLogic.atomize_term sg (map_term_types | |
| 623 | (map_type_tfree (fn p as (s, _) => if_none (assoc (tvinsts, s)) | |
| 624 | (if_none default_type (TFree p)))) (subst_bounds (frees, strip gi))); | |
| 625 | in case test_term (Toplevel.theory_of st) size iterations gi' of | |
| 626 | None => writeln "No counterexamples found." | |
| 627 |     | Some cex => writeln ("Counterexample found:\n" ^
 | |
| 628 | Pretty.string_of (Pretty.chunks (map (fn (s, t) => | |
| 629 | Pretty.block [Pretty.str (s ^ " ="), Pretty.brk 1, | |
| 630 | Sign.pretty_term sg t]) cex))) | |
| 631 | end; | |
| 632 | ||
| 633 | ||
| 12452 | 634 | (**** Interface ****) | 
| 635 | ||
| 13731 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 636 | val str = setmp print_mode [] Pretty.str; | 
| 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 637 | |
| 11520 | 638 | fun parse_mixfix rd s = | 
| 639 | (case Scan.finite Symbol.stopper (Scan.repeat | |
| 640 | ( $$ "_" >> K Arg | |
| 641 | || $$ "?" >> K Ignore | |
| 642 | || $$ "/" |-- Scan.repeat ($$ " ") >> (Pretty o Pretty.brk o length) | |
| 643 |       || $$ "{" |-- $$ "*" |-- Scan.repeat1
 | |
| 644 | ( $$ "'" |-- Scan.one Symbol.not_eof | |
| 645 | || Scan.unless ($$ "*" -- $$ "}") (Scan.one Symbol.not_eof)) --| | |
| 12452 | 646 | $$ "*" --| $$ "}" >> (Quote o rd o implode) | 
| 11520 | 647 | || Scan.repeat1 | 
| 648 | ( $$ "'" |-- Scan.one Symbol.not_eof | |
| 649 |             || Scan.unless ($$ "_" || $$ "?" || $$ "/" || $$ "{" |-- $$ "*")
 | |
| 13731 
e2d17090052b
Parameters in definitions are now renamed to avoid clashes with
 berghofe parents: 
13073diff
changeset | 650 | (Scan.one Symbol.not_eof)) >> (Pretty o str o implode))) | 
| 11520 | 651 | (Symbol.explode s) of | 
| 652 | (p, []) => p | |
| 653 |    | _ => error ("Malformed annotation: " ^ quote s));
 | |
| 654 | ||
| 11546 | 655 | structure P = OuterParse and K = OuterSyntax.Keyword; | 
| 11520 | 656 | |
| 657 | val assoc_typeP = | |
| 658 | OuterSyntax.command "types_code" | |
| 11546 | 659 | "associate types with target language types" K.thy_decl | 
| 11520 | 660 |     (Scan.repeat1 (P.xname --| P.$$$ "(" -- P.string --| P.$$$ ")") >>
 | 
| 12452 | 661 | (fn xs => Toplevel.theory (fn thy => assoc_types | 
| 662 | (map (fn (name, mfx) => (name, parse_mixfix | |
| 663 | (typ_of o read_ctyp (sign_of thy)) mfx)) xs) thy))); | |
| 11520 | 664 | |
| 665 | val assoc_constP = | |
| 666 | OuterSyntax.command "consts_code" | |
| 11546 | 667 | "associate constants with target language code" K.thy_decl | 
| 11520 | 668 | (Scan.repeat1 | 
| 13003 | 669 | (P.xname -- (Scan.option (P.$$$ "::" |-- P.typ)) --| | 
| 11520 | 670 |         P.$$$ "(" -- P.string --| P.$$$ ")") >>
 | 
| 671 | (fn xs => Toplevel.theory (fn thy => assoc_consts | |
| 672 | (map (fn ((name, optype), mfx) => (name, optype, parse_mixfix | |
| 673 | (term_of o read_cterm (sign_of thy) o rpair TypeInfer.logicT) mfx)) | |
| 674 | xs) thy))); | |
| 675 | ||
| 676 | val generate_codeP = | |
| 11546 | 677 | OuterSyntax.command "generate_code" "generates code for terms" K.thy_decl | 
| 13003 | 678 |     (Scan.option (P.$$$ "(" |-- P.name --| P.$$$ ")") --
 | 
| 13753 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 679 | Scan.optional (P.$$$ "[" |-- P.enum "," P.xname --| P.$$$ "]") (!mode) -- | 
| 13003 | 680 | Scan.repeat1 (P.name --| P.$$$ "=" -- P.term) >> | 
| 13753 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 681 | (fn ((opt_fname, mode'), xs) => Toplevel.theory (fn thy => | 
| 11520 | 682 | ((case opt_fname of | 
| 683 | None => use_text Context.ml_output false | |
| 684 | | Some fname => File.write (Path.unpack fname)) | |
| 13753 
38b76f457b9c
- Added mode reference variable (may be used to switch on and off specific
 berghofe parents: 
13731diff
changeset | 685 | (setmp mode mode' (generate_code thy) xs); thy)))); | 
| 11520 | 686 | |
| 14105 | 687 | val params = | 
| 688 |   [("size", P.nat >> (K o set_size)),
 | |
| 689 |    ("iterations", P.nat >> (K o set_iterations)),
 | |
| 690 |    ("default_type", P.typ >> set_default_type)];
 | |
| 691 | ||
| 692 | val parse_test_params = P.short_ident :-- (fn s => | |
| 693 | P.$$$ "=" |-- if_none (assoc (params, s)) Scan.fail) >> snd; | |
| 694 | ||
| 695 | fun parse_tyinst xs = | |
| 696 | (P.type_ident --| P.$$$ "=" -- P.typ >> (fn (v, s) => fn sg => | |
| 697 | fn (x, ys) => (x, (v, typ_of (read_ctyp sg s)) :: ys))) xs; | |
| 698 | ||
| 699 | fun app [] x = x | |
| 700 | | app (f :: fs) x = app fs (f x); | |
| 701 | ||
| 702 | val test_paramsP = | |
| 703 | OuterSyntax.command "quickcheck_params" "set parameters for random testing" K.thy_decl | |
| 704 | (P.$$$ "[" |-- P.list1 parse_test_params --| P.$$$ "]" >> | |
| 705 | (fn fs => Toplevel.theory (fn thy => | |
| 706 | map_test_params (app (map (fn f => f (sign_of thy)) fs)) thy))); | |
| 707 | ||
| 708 | val testP = | |
| 709 | OuterSyntax.command "quickcheck" "try to find counterexample for subgoal" K.diag | |
| 710 | (Scan.option (P.$$$ "[" |-- P.list1 | |
| 711 | ( parse_test_params >> (fn f => fn sg => apfst (f sg)) | |
| 712 | || parse_tyinst) --| P.$$$ "]") -- Scan.optional P.nat 1 >> | |
| 713 | (fn (ps, g) => Toplevel.keep (fn st => | |
| 714 | test_goal (app (if_none (apsome | |
| 715 | (map (fn f => f (Toplevel.sign_of st))) ps) []) | |
| 716 | (get_test_params (Toplevel.theory_of st), [])) g st))); | |
| 717 | ||
| 718 | val parsers = [assoc_typeP, assoc_constP, generate_codeP, test_paramsP, testP]; | |
| 11520 | 719 | |
| 12452 | 720 | val setup = | 
| 721 | [CodegenData.init, | |
| 722 | add_codegen "default" default_codegen, | |
| 723 | add_tycodegen "default" default_tycodegen, | |
| 12555 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 724 |    assoc_types [("fun", parse_mixfix (K dummyT) "(_ ->/ _)")],
 | 
| 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 725 |    Attrib.add_attributes [("code",
 | 
| 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 726 | (code_attr, K Attrib.undef_local_attribute), | 
| 
e6d7f040fdc7
"code" attribute is now managed by basic code generator module.
 berghofe parents: 
12490diff
changeset | 727 | "declare theorems for code generation")]]; | 
| 11520 | 728 | |
| 729 | end; | |
| 730 | ||
| 731 | OuterSyntax.add_parsers Codegen.parsers; |