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