1 (* Title: HOL/Library/code_test.ML |
1 (* Title: HOL/Library/code_test.ML |
2 Author: Andreas Lochbihler, ETH Zurich |
2 Author: Andreas Lochbihler, ETH Zürich |
3 |
3 |
4 Test infrastructure for the code generator |
4 Test infrastructure for the code generator. |
5 *) |
5 *) |
6 |
6 |
7 signature CODE_TEST = sig |
7 signature CODE_TEST = |
8 val add_driver : string * ((Proof.context -> (string * string) list * string -> Path.T -> string) * string) -> theory -> theory |
8 sig |
9 val get_driver : theory -> string -> ((Proof.context -> (string * string) list * string -> Path.T -> string) * string) option |
9 val add_driver: |
10 val overlord : bool Config.T |
10 string * ((Proof.context -> (string * string) list * string -> Path.T -> string) * string) -> |
11 val successN : string |
11 theory -> theory |
12 val failureN : string |
12 val get_driver: theory -> string -> |
13 val start_markerN : string |
13 ((Proof.context -> (string * string) list * string -> Path.T -> string) * string) option |
14 val end_markerN : string |
14 val overlord: bool Config.T |
15 val test_terms : Proof.context -> term list -> string -> unit |
15 val successN: string |
16 val test_targets : Proof.context -> term list -> string list -> unit list |
16 val failureN: string |
17 val test_code_cmd : string list -> string list -> Toplevel.state -> unit |
17 val start_markerN: string |
18 |
18 val end_markerN: string |
19 val eval_term : string -> Proof.context -> term -> term |
19 val test_terms: Proof.context -> term list -> string -> unit |
20 |
20 val test_targets: Proof.context -> term list -> string list -> unit list |
21 val gen_driver : |
21 val test_code_cmd: string list -> string list -> Toplevel.state -> unit |
|
22 |
|
23 val eval_term: string -> Proof.context -> term -> term |
|
24 |
|
25 val gen_driver: |
22 (theory -> Path.T -> string list -> string -> |
26 (theory -> Path.T -> string list -> string -> |
23 {files : (Path.T * string) list, |
27 {files: (Path.T * string) list, |
24 compile_cmd : string option, run_cmd : string, mk_code_file : string -> Path.T}) |
28 compile_cmd: string option, |
25 -> string -> string -> string |
29 run_cmd: string, |
26 -> theory -> (string * string) list * string -> Path.T -> string |
30 mk_code_file: string -> Path.T}) -> |
27 |
31 string -> string -> string -> theory -> (string * string) list * string -> Path.T -> string |
28 val ISABELLE_POLYML : string |
32 |
29 val polymlN : string |
33 val ISABELLE_POLYML: string |
30 val evaluate_in_polyml : Proof.context -> (string * string) list * string -> Path.T -> string |
34 val polymlN: string |
31 |
35 val evaluate_in_polyml: Proof.context -> (string * string) list * string -> Path.T -> string |
32 val mltonN : string |
36 |
33 val ISABELLE_MLTON : string |
37 val mltonN: string |
34 val evaluate_in_mlton : Proof.context -> (string * string) list * string -> Path.T -> string |
38 val ISABELLE_MLTON: string |
35 |
39 val evaluate_in_mlton: Proof.context -> (string * string) list * string -> Path.T -> string |
36 val smlnjN : string |
40 |
37 val ISABELLE_SMLNJ : string |
41 val smlnjN: string |
38 val evaluate_in_smlnj : Proof.context -> (string * string) list * string -> Path.T -> string |
42 val ISABELLE_SMLNJ: string |
39 |
43 val evaluate_in_smlnj: Proof.context -> (string * string) list * string -> Path.T -> string |
40 val ocamlN : string |
44 |
41 val ISABELLE_OCAMLC : string |
45 val ocamlN: string |
42 val evaluate_in_ocaml : Proof.context -> (string * string) list * string -> Path.T -> string |
46 val ISABELLE_OCAMLC: string |
43 |
47 val evaluate_in_ocaml: Proof.context -> (string * string) list * string -> Path.T -> string |
44 val ghcN : string |
48 |
45 val ISABELLE_GHC : string |
49 val ghcN: string |
46 val ghc_options : string Config.T |
50 val ISABELLE_GHC: string |
47 val evaluate_in_ghc : Proof.context -> (string * string) list * string -> Path.T -> string |
51 val ghc_options: string Config.T |
48 |
52 val evaluate_in_ghc: Proof.context -> (string * string) list * string -> Path.T -> string |
49 val scalaN : string |
53 |
50 val ISABELLE_SCALA : string |
54 val scalaN: string |
51 val evaluate_in_scala : Proof.context -> (string * string) list * string -> Path.T -> string |
55 val ISABELLE_SCALA: string |
|
56 val evaluate_in_scala: Proof.context -> (string * string) list * string -> Path.T -> string |
52 end |
57 end |
53 |
58 |
54 structure Code_Test : CODE_TEST = struct |
59 structure Code_Test: CODE_TEST = |
|
60 struct |
55 |
61 |
56 (* convert a list of terms into nested tuples and back *) |
62 (* convert a list of terms into nested tuples and back *) |
|
63 |
57 fun mk_tuples [] = @{term "()"} |
64 fun mk_tuples [] = @{term "()"} |
58 | mk_tuples [t] = t |
65 | mk_tuples [t] = t |
59 | mk_tuples (t :: ts) = HOLogic.mk_prod (t, mk_tuples ts) |
66 | mk_tuples (t :: ts) = HOLogic.mk_prod (t, mk_tuples ts) |
60 |
67 |
61 fun dest_tuples (Const (@{const_name Pair}, _) $ l $ r) = l :: dest_tuples r |
68 fun dest_tuples (Const (@{const_name Pair}, _) $ l $ r) = l :: dest_tuples r |
65 fun map_option _ NONE = NONE |
72 fun map_option _ NONE = NONE |
66 | map_option f (SOME x) = SOME (f x) |
73 | map_option f (SOME x) = SOME (f x) |
67 |
74 |
68 fun last_field sep str = |
75 fun last_field sep str = |
69 let |
76 let |
70 val n = size sep; |
77 val n = size sep |
71 val len = size str; |
78 val len = size str |
72 fun find i = |
79 fun find i = |
73 if i < 0 then NONE |
80 if i < 0 then NONE |
74 else if String.substring (str, i, n) = sep then SOME i |
81 else if String.substring (str, i, n) = sep then SOME i |
75 else find (i - 1); |
82 else find (i - 1) |
76 in |
83 in |
77 (case find (len - n) of |
84 (case find (len - n) of |
78 NONE => NONE |
85 NONE => NONE |
79 | SOME i => SOME (String.substring (str, 0, i), String.extract (str, i + n, NONE))) |
86 | SOME i => SOME (String.substring (str, 0, i), String.extract (str, i + n, NONE))) |
80 end; |
87 end |
81 |
88 |
82 fun split_first_last start stop s = |
89 fun split_first_last start stop s = |
83 case first_field start s |
90 (case first_field start s of |
84 of NONE => NONE |
91 NONE => NONE |
85 | SOME (initial, rest) => |
92 | SOME (initial, rest) => |
86 case last_field stop rest |
93 (case last_field stop rest of |
87 of NONE => NONE |
94 NONE => NONE |
88 | SOME (middle, tail) => SOME (initial, middle, tail); |
95 | SOME (middle, tail) => SOME (initial, middle, tail))) |
89 |
96 |
90 (* Data slot for drivers *) |
97 |
|
98 (* data slot for drivers *) |
91 |
99 |
92 structure Drivers = Theory_Data |
100 structure Drivers = Theory_Data |
93 ( |
101 ( |
94 type T = (string * ((Proof.context -> (string * string) list * string -> Path.T -> string) * string)) list; |
102 type T = |
95 val empty = []; |
103 (string * ((Proof.context -> (string * string) list * string -> Path.T -> string) * string)) list |
96 val extend = I; |
104 val empty = [] |
97 fun merge data : T = AList.merge (op =) (K true) data; |
105 val extend = I |
|
106 fun merge data : T = AList.merge (op =) (K true) data |
98 ) |
107 ) |
99 |
108 |
100 val add_driver = Drivers.map o AList.update (op =); |
109 val add_driver = Drivers.map o AList.update (op =) |
101 val get_driver = AList.lookup (op =) o Drivers.get; |
110 val get_driver = AList.lookup (op =) o Drivers.get |
102 |
111 |
103 (* |
112 (* |
104 Test drivers must produce output of the following format: |
113 Test drivers must produce output of the following format: |
105 |
114 |
106 The start of the relevant data is marked with start_markerN, |
115 The start of the relevant data is marked with start_markerN, |
107 its end with end_markerN. |
116 its end with end_markerN. |
108 |
117 |
109 Between these two markers, every line corresponds to one test. |
118 Between these two markers, every line corresponds to one test. |
110 Lines of successful tests start with successN, failures start with failureN. |
119 Lines of successful tests start with successN, failures start with failureN. |
111 The failure failureN may continue with the YXML encoding of the evaluated term. |
120 The failure failureN may continue with the YXML encoding of the evaluated term. |
112 There must not be any additional whitespace in between. |
121 There must not be any additional whitespace in between. |
113 *) |
122 *) |
114 |
123 |
115 (* Parsing of results *) |
124 |
|
125 (* parsing of results *) |
116 |
126 |
117 val successN = "True" |
127 val successN = "True" |
118 val failureN = "False" |
128 val failureN = "False" |
119 val start_markerN = "*@*Isabelle/Code_Test-start*@*" |
129 val start_markerN = "*@*Isabelle/Code_Test-start*@*" |
120 val end_markerN = "*@*Isabelle/Code_Test-end*@*" |
130 val end_markerN = "*@*Isabelle/Code_Test-end*@*" |
121 |
131 |
122 fun parse_line line = |
132 fun parse_line line = |
123 if String.isPrefix successN line then (true, NONE) |
133 if String.isPrefix successN line then (true, NONE) |
124 else if String.isPrefix failureN line then (false, |
134 else if String.isPrefix failureN line then (false, |
125 if size line > size failureN then |
135 if size line > size failureN then |
126 String.extract (line, size failureN, NONE) |
136 String.extract (line, size failureN, NONE) |
127 |> YXML.parse_body |
137 |> YXML.parse_body |
128 |> Term_XML.Decode.term |
138 |> Term_XML.Decode.term |
129 |> dest_tuples |
139 |> dest_tuples |
130 |> SOME |
140 |> SOME |
131 else NONE) |
141 else NONE) |
132 else raise Fail ("Cannot parse result of evaluation:\n" ^ line) |
142 else raise Fail ("Cannot parse result of evaluation:\n" ^ line) |
133 |
143 |
134 fun parse_result target out = |
144 fun parse_result target out = |
135 case split_first_last start_markerN end_markerN out |
145 (case split_first_last start_markerN end_markerN out of |
136 of NONE => error ("Evaluation failed for " ^ target ^ "!\nBash output:\n" ^ out) |
146 NONE => error ("Evaluation failed for " ^ target ^ "!\nBash output:\n" ^ out) |
137 | SOME (_, middle, _) => middle |> trim_line |> split_lines |> map parse_line |
147 | SOME (_, middle, _) => middle |> trim_line |> split_lines |> map parse_line) |
138 |
148 |
139 (* Pretty printing of test results *) |
149 |
|
150 (* pretty printing of test results *) |
140 |
151 |
141 fun pretty_eval _ NONE _ = [] |
152 fun pretty_eval _ NONE _ = [] |
142 | pretty_eval ctxt (SOME evals) ts = |
153 | pretty_eval ctxt (SOME evals) ts = |
143 [Pretty.fbrk, |
154 [Pretty.fbrk, |
144 Pretty.big_list "Evaluated terms" |
155 Pretty.big_list "Evaluated terms" |
145 (map (fn (t, eval) => Pretty.block |
156 (map (fn (t, eval) => Pretty.block |
146 [Syntax.pretty_term ctxt t, Pretty.brk 1, Pretty.str "=", Pretty.brk 1, |
157 [Syntax.pretty_term ctxt t, Pretty.brk 1, Pretty.str "=", Pretty.brk 1, |
147 Syntax.pretty_term ctxt eval]) |
158 Syntax.pretty_term ctxt eval]) |
148 (ts ~~ evals))] |
159 (ts ~~ evals))] |
149 |
160 |
150 fun pretty_failure ctxt target (((_, evals), query), eval_ts) = |
161 fun pretty_failure ctxt target (((_, evals), query), eval_ts) = |
151 Pretty.block (Pretty.text ("Test in " ^ target ^ " failed for") |
162 Pretty.block (Pretty.text ("Test in " ^ target ^ " failed for") |
152 @ [Pretty.brk 1, Pretty.quote (Syntax.pretty_term ctxt query)] |
163 @ [Pretty.brk 1, Pretty.quote (Syntax.pretty_term ctxt query)] |
153 @ pretty_eval ctxt evals eval_ts) |
164 @ pretty_eval ctxt evals eval_ts) |
154 |
165 |
155 fun pretty_failures ctxt target failures = |
166 fun pretty_failures ctxt target failures = |
156 Pretty.blk (0, Pretty.fbreaks (map (pretty_failure ctxt target) failures)) |
167 Pretty.blk (0, Pretty.fbreaks (map (pretty_failure ctxt target) failures)) |
157 |
168 |
158 (* Driver invocation *) |
169 |
159 |
170 (* driver invocation *) |
160 val overlord = Attrib.setup_config_bool @{binding "code_test_overlord"} (K false); |
171 |
|
172 val overlord = Attrib.setup_config_bool @{binding "code_test_overlord"} (K false) |
161 |
173 |
162 fun with_overlord_dir name f = |
174 fun with_overlord_dir name f = |
163 let |
175 let |
164 val path = Path.append (Path.explode "$ISABELLE_HOME_USER") (Path.basic (name ^ serial_string ())) |
176 val path = |
165 val _ = Isabelle_System.mkdirs path; |
177 Path.append (Path.explode "$ISABELLE_HOME_USER") (Path.basic (name ^ serial_string ())) |
166 in |
178 val _ = Isabelle_System.mkdirs path |
167 Exn.release (Exn.capture f path) |
179 in Exn.release (Exn.capture f path) end |
168 end; |
|
169 |
180 |
170 fun dynamic_value_strict ctxt t compiler = |
181 fun dynamic_value_strict ctxt t compiler = |
171 let |
182 let |
172 val thy = Proof_Context.theory_of ctxt |
183 val thy = Proof_Context.theory_of ctxt |
173 val (driver, target) = case get_driver thy compiler |
184 val (driver, target) = |
174 of NONE => error ("No driver for target " ^ compiler) |
185 (case get_driver thy compiler of |
175 | SOME f => f; |
186 NONE => error ("No driver for target " ^ compiler) |
|
187 | SOME f => f) |
176 val debug = Config.get (Proof_Context.init_global thy) overlord |
188 val debug = Config.get (Proof_Context.init_global thy) overlord |
177 val with_dir = if debug then with_overlord_dir else Isabelle_System.with_tmp_dir |
189 val with_dir = if debug then with_overlord_dir else Isabelle_System.with_tmp_dir |
178 fun evaluate f = with_dir "Code_Test" (driver ctxt f) |> parse_result compiler |
190 fun evaluate f = with_dir "Code_Test" (driver ctxt f) |> parse_result compiler |
179 fun evaluator program _ vs_ty deps = |
191 fun evaluator program _ vs_ty deps = |
180 Exn.interruptible_capture evaluate (Code_Target.computation_text ctxt target program deps true vs_ty); |
192 Exn.interruptible_capture evaluate |
|
193 (Code_Target.computation_text ctxt target program deps true vs_ty) |
181 fun postproc f = map (apsnd (map_option (map f))) |
194 fun postproc f = map (apsnd (map_option (map f))) |
182 in |
195 in Exn.release (Code_Thingol.dynamic_value ctxt (Exn.map_res o postproc) evaluator t) end |
183 Exn.release (Code_Thingol.dynamic_value ctxt (Exn.map_res o postproc) evaluator t) |
196 |
184 end; |
197 |
185 |
198 (* term preprocessing *) |
186 (* Term preprocessing *) |
|
187 |
199 |
188 fun add_eval (Const (@{const_name Trueprop}, _) $ t) = add_eval t |
200 fun add_eval (Const (@{const_name Trueprop}, _) $ t) = add_eval t |
189 | add_eval (Const (@{const_name "HOL.eq"}, _) $ lhs $ rhs) = (fn acc => |
201 | add_eval (Const (@{const_name "HOL.eq"}, _) $ lhs $ rhs) = (fn acc => |
190 acc |
202 acc |
191 |> add_eval rhs |
203 |> add_eval rhs |
192 |> add_eval lhs |
204 |> add_eval lhs |
193 |> cons rhs |
205 |> cons rhs |
194 |> cons lhs) |
206 |> cons lhs) |
195 | add_eval (Const (@{const_name "Not"}, _) $ t) = add_eval t |
207 | add_eval (Const (@{const_name "Not"}, _) $ t) = add_eval t |
196 | add_eval (Const (@{const_name "Orderings.ord_class.less_eq"}, _) $ lhs $ rhs) = (fn acc => |
208 | add_eval (Const (@{const_name "Orderings.ord_class.less_eq"}, _) $ lhs $ rhs) = (fn acc => |
197 lhs :: rhs :: acc) |
209 lhs :: rhs :: acc) |
198 | add_eval (Const (@{const_name "Orderings.ord_class.less"}, _) $ lhs $ rhs) = (fn acc => |
210 | add_eval (Const (@{const_name "Orderings.ord_class.less"}, _) $ lhs $ rhs) = (fn acc => |
199 lhs :: rhs :: acc) |
211 lhs :: rhs :: acc) |
200 | add_eval _ = I |
212 | add_eval _ = I |
201 |
213 |
202 fun mk_term_of [] = @{term "None :: (unit \<Rightarrow> yxml_of_term) option"} |
214 fun mk_term_of [] = @{term "None :: (unit \<Rightarrow> yxml_of_term) option"} |
203 | mk_term_of ts = |
215 | mk_term_of ts = |
204 let |
216 let |
205 val tuple = mk_tuples ts |
217 val tuple = mk_tuples ts |
206 val T = fastype_of tuple |
218 val T = fastype_of tuple |
207 in |
219 in |
208 @{term "Some :: (unit \<Rightarrow> yxml_of_term) \<Rightarrow> (unit \<Rightarrow> yxml_of_term) option"} $ |
220 @{term "Some :: (unit \<Rightarrow> yxml_of_term) \<Rightarrow> (unit \<Rightarrow> yxml_of_term) option"} $ |
209 (absdummy @{typ unit} (@{const yxml_string_of_term} $ |
221 (absdummy @{typ unit} (@{const yxml_string_of_term} $ |
210 (Const (@{const_name Code_Evaluation.term_of}, T --> @{typ term}) $ tuple))) |
222 (Const (@{const_name Code_Evaluation.term_of}, T --> @{typ term}) $ tuple))) |
211 end |
223 end |
212 |
224 |
213 fun test_terms ctxt ts target = |
225 fun test_terms ctxt ts target = |
214 let |
226 let |
215 val thy = Proof_Context.theory_of ctxt |
227 val thy = Proof_Context.theory_of ctxt |
216 |
228 |
217 fun term_of t = Sign.of_sort thy (fastype_of t, @{sort term_of}) |
229 fun term_of t = Sign.of_sort thy (fastype_of t, @{sort term_of}) |
218 |
230 |
219 fun ensure_bool t = case fastype_of t of @{typ bool} => () |
231 fun ensure_bool t = |
220 | _ => error ("Test case not of type bool: " ^ Pretty.string_of (Syntax.pretty_term ctxt t)) |
232 (case fastype_of t of |
|
233 @{typ bool} => () |
|
234 | _ => error ("Test case not of type bool: " ^ Pretty.string_of (Syntax.pretty_term ctxt t))) |
221 |
235 |
222 val _ = map ensure_bool ts |
236 val _ = map ensure_bool ts |
223 |
237 |
224 val evals = map (fn t => filter term_of (add_eval t [])) ts |
238 val evals = map (fn t => filter term_of (add_eval t [])) ts |
225 val eval = map mk_term_of evals |
239 val eval = map mk_term_of evals |
226 |
240 |
227 val T = HOLogic.mk_prodT (@{typ bool}, Type (@{type_name option}, [@{typ unit} --> @{typ yxml_of_term}])) |
241 val T = |
|
242 HOLogic.mk_prodT (@{typ bool}, |
|
243 Type (@{type_name option}, [@{typ unit} --> @{typ yxml_of_term}])) |
228 val t = HOLogic.mk_list T (map HOLogic.mk_prod (ts ~~ eval)) |
244 val t = HOLogic.mk_list T (map HOLogic.mk_prod (ts ~~ eval)) |
229 |
245 |
230 val result = dynamic_value_strict ctxt t target; |
246 val result = dynamic_value_strict ctxt t target |
231 |
247 |
232 val failed = |
248 val failed = |
233 filter_out (fst o fst o fst) (result ~~ ts ~~ evals) |
249 filter_out (fst o fst o fst) (result ~~ ts ~~ evals) |
234 handle ListPair.UnequalLengths => |
250 handle ListPair.UnequalLengths => |
235 error ("Evaluation failed!\nWrong number of test results: " ^ Int.toString (length result)) |
251 error ("Evaluation failed!\nWrong number of test results: " ^ Int.toString (length result)) |
236 val _ = case failed of [] => () |
252 val _ = case failed of [] => () |
237 | _ => error (Pretty.string_of (pretty_failures ctxt target failed)) |
253 | _ => error (Pretty.string_of (pretty_failures ctxt target failed)) |
238 in |
254 in |
239 () |
255 () |
240 end |
256 end |
241 |
257 |
242 fun test_targets ctxt = map o test_terms ctxt |
258 fun test_targets ctxt = map o test_terms ctxt |
243 |
259 |
244 fun test_code_cmd raw_ts targets state = |
260 fun test_code_cmd raw_ts targets state = |
245 let |
261 let |
246 val ctxt = Toplevel.context_of state; |
262 val ctxt = Toplevel.context_of state |
247 val ts = Syntax.read_terms ctxt raw_ts; |
263 val ts = Syntax.read_terms ctxt raw_ts |
248 val frees = fold Term.add_free_names ts [] |
264 val frees = fold Term.add_free_names ts [] |
249 val _ = if frees = [] then () else |
265 val _ = if frees = [] then () else |
250 error ("Terms contain free variables: " ^ |
266 error ("Terms contain free variables: " ^ |
251 Pretty.string_of (Pretty.block (Pretty.commas (map Pretty.str frees)))) |
267 Pretty.string_of (Pretty.block (Pretty.commas (map Pretty.str frees)))) |
252 in |
268 in |
261 Pretty.string_of (Pretty.block (Pretty.commas (map Pretty.str frees)))) |
277 Pretty.string_of (Pretty.block (Pretty.commas (map Pretty.str frees)))) |
262 |
278 |
263 val thy = Proof_Context.theory_of ctxt |
279 val thy = Proof_Context.theory_of ctxt |
264 |
280 |
265 val T_t = fastype_of t |
281 val T_t = fastype_of t |
266 val _ = if Sign.of_sort thy (T_t, @{sort term_of}) then () else error |
282 val _ = if Sign.of_sort thy (T_t, @{sort term_of}) then () else error |
267 ("Type " ^ Pretty.string_of (Syntax.pretty_typ ctxt T_t) ^ |
283 ("Type " ^ Pretty.string_of (Syntax.pretty_typ ctxt T_t) ^ |
268 " of term not of sort " ^ Pretty.string_of (Syntax.pretty_sort ctxt @{sort term_of})) |
284 " of term not of sort " ^ Pretty.string_of (Syntax.pretty_sort ctxt @{sort term_of})) |
269 |
285 |
270 val T = HOLogic.mk_prodT (@{typ bool}, Type (@{type_name option}, [@{typ unit} --> @{typ yxml_of_term}])) |
286 val T = HOLogic.mk_prodT (@{typ bool}, Type (@{type_name option}, [@{typ unit} --> @{typ yxml_of_term}])) |
271 val t' = HOLogic.mk_list T [HOLogic.mk_prod (@{term "False"}, mk_term_of [t])] |
287 val t' = HOLogic.mk_list T [HOLogic.mk_prod (@{term "False"}, mk_term_of [t])] |
272 |
288 |
273 val result = dynamic_value_strict ctxt t' target; |
289 val result = dynamic_value_strict ctxt t' target |
274 in |
290 in (case result of [(_, SOME [t])] => t | _ => error "Evaluation failed") end |
275 case result of [(_, SOME [t])] => t | _ => error "Evaluation failed" |
291 |
276 end |
292 |
277 |
293 (* generic driver *) |
278 (* Generic driver *) |
|
279 |
294 |
280 fun gen_driver mk_driver env_var env_var_dest compilerN ctxt (code_files, value_name) = |
295 fun gen_driver mk_driver env_var env_var_dest compilerN ctxt (code_files, value_name) = |
281 let |
296 let |
282 val compiler = getenv env_var |
297 val compiler = getenv env_var |
283 val _ = if compiler <> "" then () else error (Pretty.string_of (Pretty.para |
298 val _ = |
|
299 if compiler <> "" then () |
|
300 else error (Pretty.string_of (Pretty.para |
284 ("Environment variable " ^ env_var ^ " is not set. To test code generation with " ^ |
301 ("Environment variable " ^ env_var ^ " is not set. To test code generation with " ^ |
285 compilerN ^ ", set this variable to your " ^ env_var_dest ^ " in the settings file."))) |
302 compilerN ^ ", set this variable to your " ^ env_var_dest ^ " in the settings file."))) |
286 |
303 |
287 fun compile NONE = () |
304 fun compile NONE = () |
288 | compile (SOME cmd) = |
305 | compile (SOME cmd) = |
289 let |
306 let |
290 val (out, ret) = Isabelle_System.bash_output cmd |
307 val (out, ret) = Isabelle_System.bash_output cmd |
291 in |
308 in |
292 if ret = 0 then () else error |
309 if ret = 0 then () else error |
293 ("Compilation with " ^ compilerN ^ " failed:\n" ^ cmd ^ "\n" ^ out) |
310 ("Compilation with " ^ compilerN ^ " failed:\n" ^ cmd ^ "\n" ^ out) |
294 end |
311 end |
295 |
312 |
296 fun run (path : Path.T)= |
313 fun run path = |
297 let |
314 let |
298 val modules = map fst code_files |
315 val modules = map fst code_files |
299 val {files, compile_cmd, run_cmd, mk_code_file} |
316 val {files, compile_cmd, run_cmd, mk_code_file} = mk_driver ctxt path modules value_name |
300 = mk_driver ctxt path modules value_name |
|
301 |
317 |
302 val _ = map (fn (name, code) => File.write (mk_code_file name) code) code_files |
318 val _ = map (fn (name, code) => File.write (mk_code_file name) code) code_files |
303 val _ = map (fn (name, content) => File.write name content) files |
319 val _ = map (fn (name, content) => File.write name content) files |
304 |
320 |
305 val _ = compile compile_cmd |
321 val _ = compile compile_cmd |
306 |
322 |
307 val (out, res) = Isabelle_System.bash_output run_cmd |
323 val (out, res) = Isabelle_System.bash_output run_cmd |
308 val _ = if res = 0 then () else error |
324 val _ = if res = 0 then () else error |
309 ("Evaluation for " ^ compilerN ^ " terminated with error code " ^ Int.toString res ^ |
325 ("Evaluation for " ^ compilerN ^ " terminated with error code " ^ Int.toString res ^ |
310 "\nBash output:\n" ^ out) |
326 "\nBash output:\n" ^ out) |
311 in |
327 in out end |
312 out |
328 in run end |
313 end |
329 |
314 in |
330 |
315 run |
331 (* driver for PolyML *) |
316 end |
|
317 |
|
318 (* Driver for PolyML *) |
|
319 |
332 |
320 val ISABELLE_POLYML = "ISABELLE_POLYML" |
333 val ISABELLE_POLYML = "ISABELLE_POLYML" |
321 val polymlN = "PolyML"; |
334 val polymlN = "PolyML" |
322 |
335 |
323 fun mk_driver_polyml _ path _ value_name = |
336 fun mk_driver_polyml _ path _ value_name = |
324 let |
337 let |
325 val generatedN = "generated.sml" |
338 val generatedN = "generated.sml" |
326 val driverN = "driver.sml" |
339 val driverN = "driver.sml" |
327 |
340 |
328 val code_path = Path.append path (Path.basic generatedN) |
341 val code_path = Path.append path (Path.basic generatedN) |
329 val driver_path = Path.append path (Path.basic driverN) |
342 val driver_path = Path.append path (Path.basic driverN) |
330 val driver = |
343 val driver = |
331 "fun main prog_name = \n" ^ |
344 "fun main prog_name = \n" ^ |
332 " let\n" ^ |
345 " let\n" ^ |
333 " fun format_term NONE = \"\"\n" ^ |
346 " fun format_term NONE = \"\"\n" ^ |
334 " | format_term (SOME t) = t ();\n" ^ |
347 " | format_term (SOME t) = t ();\n" ^ |
335 " fun format (true, _) = \"" ^ successN ^ "\\n\"\n" ^ |
348 " fun format (true, _) = \"" ^ successN ^ "\\n\"\n" ^ |
336 " | format (false, to) = \"" ^ failureN ^ "\" ^ format_term to ^ \"\\n\";\n" ^ |
349 " | format (false, to) = \"" ^ failureN ^ "\" ^ format_term to ^ \"\\n\";\n" ^ |
337 " val result = " ^ value_name ^ " ();\n" ^ |
350 " val result = " ^ value_name ^ " ();\n" ^ |
338 " val _ = print \"" ^ start_markerN ^ "\";\n" ^ |
351 " val _ = print \"" ^ start_markerN ^ "\";\n" ^ |