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