src/HOL/Library/code_test.ML
changeset 64578 7b20f9f94f4e
parent 64577 0288a566c966
child 64579 38a1d8b41189
equal deleted inserted replaced
64577:0288a566c966 64578:7b20f9f94f4e
    15   val successN: string
    15   val successN: string
    16   val failureN: string
    16   val failureN: string
    17   val start_markerN: string
    17   val start_markerN: string
    18   val end_markerN: string
    18   val end_markerN: string
    19   val test_terms: Proof.context -> term list -> string -> unit
    19   val test_terms: Proof.context -> term list -> string -> unit
    20   val test_targets: Proof.context -> term list -> string list -> unit list
    20   val test_targets: Proof.context -> term list -> string list -> unit
    21   val test_code_cmd: string list -> string list -> Toplevel.state -> unit
    21   val test_code_cmd: string list -> string list -> Toplevel.state -> unit
    22 
    22 
    23   val eval_term: string -> Proof.context -> term -> term
    23   val eval_term: string -> Proof.context -> term -> term
    24 
    24 
    25   val gen_driver:
    25   val gen_driver:
    66   | mk_tuples (t :: ts) = HOLogic.mk_prod (t, mk_tuples ts)
    66   | mk_tuples (t :: ts) = HOLogic.mk_prod (t, mk_tuples ts)
    67 
    67 
    68 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
    69   | dest_tuples t = [t]
    69   | dest_tuples t = [t]
    70 
    70 
    71 
       
    72 fun map_option _ NONE = NONE
       
    73   | map_option f (SOME x) = SOME (f x)
       
    74 
    71 
    75 fun last_field sep str =
    72 fun last_field sep str =
    76   let
    73   let
    77     val n = size sep
    74     val n = size sep
    78     val len = size str
    75     val len = size str
   189     val with_dir = if debug then with_overlord_dir else Isabelle_System.with_tmp_dir
   186     val with_dir = if debug then with_overlord_dir else Isabelle_System.with_tmp_dir
   190     fun evaluate f = with_dir "Code_Test" (driver ctxt f) |> parse_result compiler
   187     fun evaluate f = with_dir "Code_Test" (driver ctxt f) |> parse_result compiler
   191     fun evaluator program _ vs_ty deps =
   188     fun evaluator program _ vs_ty deps =
   192       Exn.interruptible_capture evaluate
   189       Exn.interruptible_capture evaluate
   193         (Code_Target.computation_text ctxt target program deps true vs_ty)
   190         (Code_Target.computation_text ctxt target program deps true vs_ty)
   194     fun postproc f = map (apsnd (map_option (map f)))
   191     fun postproc f = map (apsnd (Option.map (map f)))
   195   in Exn.release (Code_Thingol.dynamic_value ctxt (Exn.map_res o postproc) evaluator t) end
   192   in Exn.release (Code_Thingol.dynamic_value ctxt (Exn.map_res o postproc) evaluator t) end
   196 
   193 
   197 
   194 
   198 (* term preprocessing *)
   195 (* term preprocessing *)
   199 
   196 
   231     fun ensure_bool t =
   228     fun ensure_bool t =
   232       (case fastype_of t of
   229       (case fastype_of t of
   233         @{typ bool} => ()
   230         @{typ bool} => ()
   234       | _ => error ("Test case not of type bool: " ^ Pretty.string_of (Syntax.pretty_term ctxt t)))
   231       | _ => error ("Test case not of type bool: " ^ Pretty.string_of (Syntax.pretty_term ctxt t)))
   235 
   232 
   236     val _ = map ensure_bool ts
   233     val _ = List.app ensure_bool ts
   237 
   234 
   238     val evals = map (fn t => filter term_of (add_eval t [])) ts
   235     val evals = map (fn t => filter term_of (add_eval t [])) ts
   239     val eval = map mk_term_of evals
   236     val eval = map mk_term_of evals
   240 
   237 
   241     val T =
   238     val t =
   242       HOLogic.mk_prodT (@{typ bool},
   239       HOLogic.mk_list @{typ "bool \<times> (unit \<Rightarrow> yxml_of_term) option"}
   243         Type (@{type_name option}, [@{typ unit} --> @{typ yxml_of_term}]))
   240         (map HOLogic.mk_prod (ts ~~ eval))
   244     val t = HOLogic.mk_list T (map HOLogic.mk_prod (ts ~~ eval))
       
   245 
   241 
   246     val result = dynamic_value_strict ctxt t target
   242     val result = dynamic_value_strict ctxt t target
   247 
   243 
   248     val failed =
   244     val failed =
   249       filter_out (fst o fst o fst) (result ~~ ts ~~ evals)
   245       filter_out (fst o fst o fst) (result ~~ ts ~~ evals)
   250       handle ListPair.UnequalLengths =>
   246       handle ListPair.UnequalLengths =>
   251         error ("Evaluation failed!\nWrong number of test results: " ^ Int.toString (length result))
   247         error ("Evaluation failed!\nWrong number of test results: " ^ Int.toString (length result))
   252     val _ = case failed of [] => ()
   248   in
   253       | _ => error (Pretty.string_of (pretty_failures ctxt target failed))
   249     (case failed of [] =>
   254   in
   250       ()
   255     ()
   251     | _ => error (Pretty.string_of (pretty_failures ctxt target failed)))
   256   end
   252   end
   257 
   253 
   258 fun test_targets ctxt = map o test_terms ctxt
   254 fun test_targets ctxt = List.app o test_terms ctxt
   259 
   255 
   260 fun test_code_cmd raw_ts targets state =
   256 fun test_code_cmd raw_ts targets state =
   261   let
   257   let
   262     val ctxt = Toplevel.context_of state
   258     val ctxt = Toplevel.context_of state
   263     val ts = Syntax.read_terms ctxt raw_ts
   259     val ts = Syntax.read_terms ctxt raw_ts
   264     val frees = fold Term.add_free_names ts []
   260     val frees = fold Term.add_free_names ts []
   265     val _ = if frees = [] then () else
   261     val _ =
   266       error ("Terms contain free variables: " ^
   262       if null frees then ()
   267       Pretty.string_of (Pretty.block (Pretty.commas (map Pretty.str frees))))
   263       else error ("Terms contain free variables: " ^
   268   in
   264         Pretty.string_of (Pretty.block (Pretty.commas (map Pretty.str frees))))
   269     test_targets ctxt ts targets; ()
   265   in test_targets ctxt ts targets end
   270   end
       
   271 
   266 
   272 fun eval_term target ctxt t =
   267 fun eval_term target ctxt t =
   273   let
   268   let
   274     val frees = Term.add_free_names t []
   269     val frees = Term.add_free_names t []
   275     val _ = if frees = [] then () else
   270     val _ =
   276       error ("Term contains free variables: " ^
   271       if null frees then ()
   277       Pretty.string_of (Pretty.block (Pretty.commas (map Pretty.str frees))))
   272       else error ("Term contains free variables: " ^
       
   273         Pretty.string_of (Pretty.block (Pretty.commas (map Pretty.str frees))))
   278 
   274 
   279     val thy = Proof_Context.theory_of ctxt
   275     val thy = Proof_Context.theory_of ctxt
   280 
   276 
   281     val T_t = fastype_of t
   277     val T_t = fastype_of t
   282     val _ = if Sign.of_sort thy (T_t, @{sort term_of}) then () else error
   278     val _ =
   283       ("Type " ^ Pretty.string_of (Syntax.pretty_typ ctxt T_t) ^
   279       if Sign.of_sort thy (T_t, @{sort term_of}) then ()
       
   280       else error ("Type " ^ Pretty.string_of (Syntax.pretty_typ ctxt T_t) ^
   284        " of term not of sort " ^ Pretty.string_of (Syntax.pretty_sort ctxt @{sort term_of}))
   281        " of term not of sort " ^ Pretty.string_of (Syntax.pretty_sort ctxt @{sort term_of}))
   285 
   282 
   286     val T = HOLogic.mk_prodT (@{typ bool}, Type (@{type_name option}, [@{typ unit} --> @{typ yxml_of_term}]))
   283     val t' =
   287     val t' = HOLogic.mk_list T [HOLogic.mk_prod (@{term "False"}, mk_term_of [t])]
   284       HOLogic.mk_list @{typ "bool \<times> (unit \<Rightarrow> yxml_of_term) option"}
       
   285         [HOLogic.mk_prod (@{term "False"}, mk_term_of [t])]
   288 
   286 
   289     val result = dynamic_value_strict ctxt t' target
   287     val result = dynamic_value_strict ctxt t' target
   290   in (case result of [(_, SOME [t])] => t | _ => error "Evaluation failed") end
   288   in (case result of [(_, SOME [t])] => t | _ => error "Evaluation failed") end
   291 
   289 
   292 
   290 
   296   let
   294   let
   297     val compiler = getenv env_var
   295     val compiler = getenv env_var
   298     val _ =
   296     val _ =
   299       if compiler <> "" then ()
   297       if compiler <> "" then ()
   300       else error (Pretty.string_of (Pretty.para
   298       else error (Pretty.string_of (Pretty.para
   301          ("Environment variable " ^ env_var ^ " is not set. To test code generation with " ^
   299         ("Environment variable " ^ env_var ^ " is not set. To test code generation with " ^
   302          compilerN ^ ", set this variable to your " ^ env_var_dest ^ " in the settings file.")))
   300           compilerN ^ ", set this variable to your " ^ env_var_dest ^ " in the settings file.")))
   303 
   301 
   304     fun compile NONE = ()
   302     fun compile NONE = ()
   305       | compile (SOME cmd) =
   303       | compile (SOME cmd) =
   306           let
   304           let
   307             val (out, ret) = Isabelle_System.bash_output cmd
   305             val (out, ret) = Isabelle_System.bash_output cmd
   308           in
   306           in
   309             if ret = 0 then () else error
   307             if ret = 0 then ()
   310               ("Compilation with " ^ compilerN ^ " failed:\n" ^ cmd ^ "\n" ^ out)
   308             else error ("Compilation with " ^ compilerN ^ " failed:\n" ^ cmd ^ "\n" ^ out)
   311           end
   309           end
   312 
   310 
   313     fun run path =
   311     fun run path =
   314       let
   312       let
   315         val modules = map fst code_files
   313         val modules = map fst code_files
   316         val {files, compile_cmd, run_cmd, mk_code_file} = mk_driver ctxt path modules value_name
   314         val {files, compile_cmd, run_cmd, mk_code_file} = mk_driver ctxt path modules value_name
   317 
   315 
   318         val _ = map (fn (name, code) => File.write (mk_code_file name) code) code_files
   316         val _ = List.app (fn (name, code) => File.write (mk_code_file name) code) code_files
   319         val _ = map (fn (name, content) => File.write name content) files
   317         val _ = List.app (fn (name, content) => File.write name content) files
   320 
   318 
   321         val _ = compile compile_cmd
   319         val _ = compile compile_cmd
   322 
   320 
   323         val (out, res) = Isabelle_System.bash_output run_cmd
   321         val (out, res) = Isabelle_System.bash_output run_cmd
   324         val _ = if res = 0 then () else error
   322         val _ =
   325           ("Evaluation for " ^ compilerN ^ " terminated with error code " ^ Int.toString res ^
   323           if res = 0 then ()
   326            "\nBash output:\n" ^ out)
   324           else error ("Evaluation for " ^ compilerN ^ " terminated with error code " ^
       
   325             Int.toString res ^ "\nBash output:\n" ^ out)
   327       in out end
   326       in out end
   328   in run end
   327   in run end
   329 
   328 
   330 
   329 
   331 (* driver for PolyML *)
   330 (* driver for PolyML *)