8 signature NITPICK = |
8 signature NITPICK = |
9 sig |
9 sig |
10 type styp = Nitpick_Util.styp |
10 type styp = Nitpick_Util.styp |
11 type term_postprocessor = Nitpick_Model.term_postprocessor |
11 type term_postprocessor = Nitpick_Model.term_postprocessor |
12 |
12 |
13 datatype mode = Auto_Try | Try | Normal |
13 datatype mode = Auto_Try | Try | Normal | TPTP |
14 |
14 |
15 type params = |
15 type params = |
16 {cards_assigns: (typ option * int list) list, |
16 {cards_assigns: (typ option * int list) list, |
17 maxes_assigns: (styp option * int list) list, |
17 maxes_assigns: (styp option * int list) list, |
18 iters_assigns: (styp option * int list) list, |
18 iters_assigns: (styp option * int list) list, |
91 open Nitpick_Kodkod |
91 open Nitpick_Kodkod |
92 open Nitpick_Model |
92 open Nitpick_Model |
93 |
93 |
94 structure KK = Kodkod |
94 structure KK = Kodkod |
95 |
95 |
96 datatype mode = Auto_Try | Try | Normal |
96 datatype mode = Auto_Try | Try | Normal | TPTP |
|
97 |
|
98 fun is_mode_nt mode = (mode = Normal orelse mode = TPTP) |
97 |
99 |
98 type params = |
100 type params = |
99 {cards_assigns: (typ option * int list) list, |
101 {cards_assigns: (typ option * int list) list, |
100 maxes_assigns: (styp option * int list) list, |
102 maxes_assigns: (styp option * int list) list, |
101 iters_assigns: (styp option * int list) list, |
103 iters_assigns: (styp option * int list) list, |
241 o Pretty.chunks o cons (Pretty.str "") o single |
243 o Pretty.chunks o cons (Pretty.str "") o single |
242 o Pretty.mark Isabelle_Markup.hilite |
244 o Pretty.mark Isabelle_Markup.hilite |
243 else |
245 else |
244 print o Pretty.string_of |
246 print o Pretty.string_of |
245 val pprint_a = pprint Output.urgent_message |
247 val pprint_a = pprint Output.urgent_message |
246 fun pprint_n f = () |> mode = Normal ? pprint Output.urgent_message o f |
248 fun pprint_nt f = () |> is_mode_nt mode ? pprint Output.urgent_message o f |
247 fun pprint_v f = () |> verbose ? pprint Output.urgent_message o f |
249 fun pprint_v f = () |> verbose ? pprint Output.urgent_message o f |
248 fun pprint_d f = () |> debug ? pprint tracing o f |
250 fun pprint_d f = () |> debug ? pprint tracing o f |
249 val print = pprint Output.urgent_message o curry Pretty.blk 0 o pstrs |
251 val print = pprint Output.urgent_message o curry Pretty.blk 0 o pstrs |
|
252 fun print_t f = () |> mode = TPTP ? print o f |
250 (* |
253 (* |
251 val print_g = pprint tracing o Pretty.str |
254 val print_g = pprint tracing o Pretty.str |
252 *) |
255 *) |
253 val print_n = pprint_n o K o plazy |
256 val print_nt = pprint_nt o K o plazy |
254 val print_v = pprint_v o K o plazy |
257 val print_v = pprint_v o K o plazy |
255 |
258 |
256 fun check_deadline () = |
259 fun check_deadline () = |
257 if passed_deadline deadline then raise TimeLimit.TimeOut else () |
260 if passed_deadline deadline then raise TimeLimit.TimeOut else () |
258 |
261 |
259 val assm_ts = if assms orelse mode <> Normal then assm_ts else [] |
262 val assm_ts = if assms orelse mode <> Normal then assm_ts else [] |
260 val _ = |
263 val _ = |
261 if step = 0 then |
264 if step = 0 then |
262 print_n (fn () => "Nitpicking formula...") |
265 print_nt (fn () => "Nitpicking formula...") |
263 else |
266 else |
264 pprint_n (fn () => Pretty.chunks ( |
267 pprint_nt (fn () => Pretty.chunks ( |
265 pretties_for_formulas ctxt ("Nitpicking " ^ |
268 pretties_for_formulas ctxt ("Nitpicking " ^ |
266 (if i <> 1 orelse n <> 1 then |
269 (if i <> 1 orelse n <> 1 then |
267 "subgoal " ^ string_of_int i ^ " of " ^ string_of_int n |
270 "subgoal " ^ string_of_int i ^ " of " ^ string_of_int n |
268 else |
271 else |
269 "goal")) [Logic.list_implies (assm_ts, orig_t)])) |
272 "goal")) [Logic.list_implies (assm_ts, orig_t)])) |
321 preprocess_formulas hol_ctxt assm_ts neg_t |
324 preprocess_formulas hol_ctxt assm_ts neg_t |
322 val got_all_user_axioms = |
325 val got_all_user_axioms = |
323 got_all_mono_user_axioms andalso no_poly_user_axioms |
326 got_all_mono_user_axioms andalso no_poly_user_axioms |
324 |
327 |
325 fun print_wf (x, (gfp, wf)) = |
328 fun print_wf (x, (gfp, wf)) = |
326 pprint_n (fn () => Pretty.blk (0, |
329 pprint_nt (fn () => Pretty.blk (0, |
327 pstrs ("The " ^ (if gfp then "co" else "") ^ "inductive predicate \"") |
330 pstrs ("The " ^ (if gfp then "co" else "") ^ "inductive predicate \"") |
328 @ Syntax.pretty_term ctxt (Const x) :: |
331 @ Syntax.pretty_term ctxt (Const x) :: |
329 pstrs (if wf then |
332 pstrs (if wf then |
330 "\" was proved well-founded. Nitpick can compute it \ |
333 "\" was proved well-founded. Nitpick can compute it \ |
331 \efficiently." |
334 \efficiently." |
412 () |
415 () |
413 val _ = |
416 val _ = |
414 if mode = Normal andalso |
417 if mode = Normal andalso |
415 exists (fn Type (@{type_name Datatype.node}, _) => true | _ => false) |
418 exists (fn Type (@{type_name Datatype.node}, _) => true | _ => false) |
416 all_Ts then |
419 all_Ts then |
417 print_n (K ("Warning: The problem involves directly or indirectly the \ |
420 print_nt (K ("Warning: The problem involves directly or indirectly the \ |
418 \internal type " ^ quote @{type_name Datatype.node} ^ |
421 \internal type " ^ quote @{type_name Datatype.node} ^ |
419 ". This type is very Nitpick-unfriendly, and its presence \ |
422 ". This type is very Nitpick-unfriendly, and its presence \ |
420 \usually indicates either a failure of abstraction or a \ |
423 \usually indicates either a failure of abstraction or a \ |
421 \quirk in Nitpick.")) |
424 \quirk in Nitpick.")) |
422 else |
425 else |
423 () |
426 () |
424 val (mono_Ts, nonmono_Ts) = List.partition is_type_monotonic all_Ts |
427 val (mono_Ts, nonmono_Ts) = List.partition is_type_monotonic all_Ts |
425 val _ = |
428 val _ = |
426 if verbose andalso not unique_scope then |
429 if verbose andalso not unique_scope then |
453 exists (exists (curry (op =) name o shortest_name o fst) |
456 exists (exists (curry (op =) name o shortest_name o fst) |
454 o datatype_constrs hol_ctxt) deep_dataTs |
457 o datatype_constrs hol_ctxt) deep_dataTs |
455 val likely_in_struct_induct_step = |
458 val likely_in_struct_induct_step = |
456 exists is_struct_induct_step (Proof_Context.cases_of ctxt) |
459 exists is_struct_induct_step (Proof_Context.cases_of ctxt) |
457 val _ = if standard andalso likely_in_struct_induct_step then |
460 val _ = if standard andalso likely_in_struct_induct_step then |
458 pprint_n (fn () => Pretty.blk (0, |
461 pprint_nt (fn () => Pretty.blk (0, |
459 pstrs "Hint: To check that the induction hypothesis is \ |
462 pstrs "Hint: To check that the induction hypothesis is \ |
460 \general enough, try this command: " @ |
463 \general enough, try this command: " @ |
461 [Pretty.mark Isabelle_Markup.sendback (Pretty.blk (0, |
464 [Pretty.mark Isabelle_Markup.sendback (Pretty.blk (0, |
462 pstrs ("nitpick [non_std, show_all]")))] @ pstrs ".")) |
465 pstrs ("nitpick [non_std, show_all]")))] @ pstrs ".")) |
463 else |
466 else |
473 val actual_sat_solver = |
476 val actual_sat_solver = |
474 if sat_solver <> "smart" then |
477 if sat_solver <> "smart" then |
475 if incremental andalso |
478 if incremental andalso |
476 not (member (op =) (Kodkod_SAT.configured_sat_solvers true) |
479 not (member (op =) (Kodkod_SAT.configured_sat_solvers true) |
477 sat_solver) then |
480 sat_solver) then |
478 (print_n (K ("An incremental SAT solver is required: \"SAT4J\" will \ |
481 (print_nt (K ("An incremental SAT solver is required: \"SAT4J\" will \ |
479 \be used instead of " ^ quote sat_solver ^ ".")); |
482 \be used instead of " ^ quote sat_solver ^ ".")); |
480 "SAT4J") |
483 "SAT4J") |
481 else |
484 else |
482 sat_solver |
485 sat_solver |
483 else |
486 else |
484 Kodkod_SAT.smart_sat_solver_name incremental |
487 Kodkod_SAT.smart_sat_solver_name incremental |
651 |
654 |
652 fun update_checked_problems problems = |
655 fun update_checked_problems problems = |
653 List.app (Unsynchronized.change checked_problems o Option.map o cons |
656 List.app (Unsynchronized.change checked_problems o Option.map o cons |
654 o nth problems) |
657 o nth problems) |
655 fun show_kodkod_warning "" = () |
658 fun show_kodkod_warning "" = () |
656 | show_kodkod_warning s = print_n (fn () => "Kodkod warning: " ^ s ^ ".") |
659 | show_kodkod_warning s = print_nt (fn () => "Kodkod warning: " ^ s ^ ".") |
657 |
660 |
658 fun print_and_check_model genuine bounds |
661 fun print_and_check_model genuine bounds |
659 ({free_names, sel_names, nonsel_names, rel_table, scope, ...} |
662 ({free_names, sel_names, nonsel_names, rel_table, scope, ...} |
660 : problem_extension) = |
663 : problem_extension) = |
661 let |
664 let |
669 got_all_user_axioms andalso none_true wfs andalso |
672 got_all_user_axioms andalso none_true wfs andalso |
670 sound_finitizes andalso total_consts <> SOME true andalso |
673 sound_finitizes andalso total_consts <> SOME true andalso |
671 codatatypes_ok |
674 codatatypes_ok |
672 fun assms_prop () = Logic.mk_conjunction_list (neg_t :: assm_ts) |
675 fun assms_prop () = Logic.mk_conjunction_list (neg_t :: assm_ts) |
673 in |
676 in |
674 (pprint_a (Pretty.chunks |
677 (print_t (fn () => |
|
678 "% SZS status " ^ |
|
679 (if genuine then |
|
680 if falsify then "CounterSatisfiable" else "Satisfiable" |
|
681 else |
|
682 "Unknown") ^ "\n" ^ |
|
683 "% SZS output start FiniteModel\n"); |
|
684 pprint_a (Pretty.chunks |
675 [Pretty.blk (0, |
685 [Pretty.blk (0, |
676 (pstrs ((if mode = Auto_Try then "Auto " else "") ^ |
686 (pstrs ((if mode = Auto_Try then "Auto " else "") ^ |
677 "Nitpick found a" ^ |
687 "Nitpick found a" ^ |
678 (if not genuine then " potentially spurious " |
688 (if not genuine then " potentially spurious " |
679 else if genuine_means_genuine then " " |
689 else if genuine_means_genuine then " " |
681 (case pretties_for_scope scope verbose of |
691 (case pretties_for_scope scope verbose of |
682 [] => [] |
692 [] => [] |
683 | pretties => pstrs " for " @ pretties) @ |
693 | pretties => pstrs " for " @ pretties) @ |
684 [Pretty.str ":\n"])), |
694 [Pretty.str ":\n"])), |
685 Pretty.indent indent_size reconstructed_model]); |
695 Pretty.indent indent_size reconstructed_model]); |
|
696 print_t (fn () => "% SZS output stop\n"); |
686 if genuine then |
697 if genuine then |
687 (if check_genuine andalso standard then |
698 (if check_genuine andalso standard then |
688 case prove_hol_model scope tac_timeout free_names sel_names |
699 case prove_hol_model scope tac_timeout free_names sel_names |
689 rel_table bounds (assms_prop ()) of |
700 rel_table bounds (assms_prop ()) of |
690 SOME true => |
701 SOME true => |
783 (found_really_genuine, 0, 0, donno) |
794 (found_really_genuine, 0, 0, donno) |
784 else |
795 else |
785 case KK.solve_any_problem debug overlord deadline max_threads |
796 case KK.solve_any_problem debug overlord deadline max_threads |
786 max_solutions (map fst problems) of |
797 max_solutions (map fst problems) of |
787 KK.JavaNotInstalled => |
798 KK.JavaNotInstalled => |
788 (print_n install_java_message; |
799 (print_nt install_java_message; |
789 (found_really_genuine, max_potential, max_genuine, donno + 1)) |
800 (found_really_genuine, max_potential, max_genuine, donno + 1)) |
790 | KK.JavaTooOld => |
801 | KK.JavaTooOld => |
791 (print_n install_java_message; |
802 (print_nt install_java_message; |
792 (found_really_genuine, max_potential, max_genuine, donno + 1)) |
803 (found_really_genuine, max_potential, max_genuine, donno + 1)) |
793 | KK.KodkodiNotInstalled => |
804 | KK.KodkodiNotInstalled => |
794 (print_n install_kodkodi_message; |
805 (print_nt install_kodkodi_message; |
795 (found_really_genuine, max_potential, max_genuine, donno + 1)) |
806 (found_really_genuine, max_potential, max_genuine, donno + 1)) |
796 | KK.Normal ([], unsat_js, s) => |
807 | KK.Normal ([], unsat_js, s) => |
797 (update_checked_problems problems unsat_js; show_kodkod_warning s; |
808 (update_checked_problems problems unsat_js; show_kodkod_warning s; |
798 (found_really_genuine, max_potential, max_genuine, donno)) |
809 (found_really_genuine, max_potential, max_genuine, donno)) |
799 | KK.Normal (sat_ps, unsat_js, s) => |
810 | KK.Normal (sat_ps, unsat_js, s) => |
876 fun run_batch j n scopes (found_really_genuine, max_potential, max_genuine, |
887 fun run_batch j n scopes (found_really_genuine, max_potential, max_genuine, |
877 donno) = |
888 donno) = |
878 let |
889 let |
879 val _ = |
890 val _ = |
880 if null scopes then |
891 if null scopes then |
881 print_n (K "The scope specification is inconsistent.") |
892 print_nt (K "The scope specification is inconsistent.") |
882 else if verbose then |
893 else if verbose then |
883 pprint_n (fn () => Pretty.chunks |
894 pprint_nt (fn () => Pretty.chunks |
884 [Pretty.blk (0, |
895 [Pretty.blk (0, |
885 pstrs ((if n > 1 then |
896 pstrs ((if n > 1 then |
886 "Batch " ^ string_of_int (j + 1) ^ " of " ^ |
897 "Batch " ^ string_of_int (j + 1) ^ " of " ^ |
887 signed_string_of_int n ^ ": " |
898 signed_string_of_int n ^ ": " |
888 else |
899 else |
924 List.partition (#unsound o snd) (!generated_problems) |
935 List.partition (#unsound o snd) (!generated_problems) |
925 in |
936 in |
926 if not (null sound_problems) andalso |
937 if not (null sound_problems) andalso |
927 forall (KK.is_problem_trivially_false o fst) |
938 forall (KK.is_problem_trivially_false o fst) |
928 sound_problems then |
939 sound_problems then |
929 print_n (fn () => |
940 print_nt (fn () => |
930 "Warning: The conjecture " ^ |
941 "Warning: The conjecture " ^ |
931 (if falsify then "either trivially holds" |
942 (if falsify then "either trivially holds" |
932 else "is either trivially unsatisfiable") ^ |
943 else "is either trivially unsatisfiable") ^ |
933 " for the given scopes or lies outside Nitpick's supported \ |
944 " for the given scopes or lies outside Nitpick's supported \ |
934 \fragment." ^ |
945 \fragment." ^ |
963 | n => |
974 | n => |
964 scope_count (do_filter (these (!checked_problems))) |
975 scope_count (do_filter (these (!checked_problems))) |
965 scope = n |
976 scope = n |
966 ? Integer.add 1) (!generated_scopes) 0 |
977 ? Integer.add 1) (!generated_scopes) 0 |
967 in |
978 in |
|
979 (if mode = TPTP then "% SZS status Unknown\n" else "") ^ |
968 "Nitpick " ^ did_so_and_so ^ |
980 "Nitpick " ^ did_so_and_so ^ |
969 (if is_some (!checked_problems) andalso total > 0 then |
981 (if is_some (!checked_problems) andalso total > 0 then |
970 " " ^ string_of_int unsat ^ " of " ^ string_of_int total ^ " scope" |
982 " " ^ string_of_int unsat ^ " of " ^ string_of_int total ^ " scope" |
971 ^ plural_s total |
983 ^ plural_s total |
972 else |
984 else |
976 val (skipped, the_scopes) = |
988 val (skipped, the_scopes) = |
977 all_scopes hol_ctxt binarize cards_assigns maxes_assigns iters_assigns |
989 all_scopes hol_ctxt binarize cards_assigns maxes_assigns iters_assigns |
978 bitss bisim_depths mono_Ts nonmono_Ts deep_dataTs |
990 bitss bisim_depths mono_Ts nonmono_Ts deep_dataTs |
979 finitizable_dataTs |
991 finitizable_dataTs |
980 val _ = if skipped > 0 then |
992 val _ = if skipped > 0 then |
981 print_n (fn () => "Too many scopes. Skipping " ^ |
993 print_nt (fn () => "Too many scopes. Skipping " ^ |
982 string_of_int skipped ^ " scope" ^ |
994 string_of_int skipped ^ " scope" ^ |
983 plural_s skipped ^ |
995 plural_s skipped ^ |
984 ". (Consider using \"mono\" or \ |
996 ". (Consider using \"mono\" or \ |
985 \\"merge_type_vars\" to prevent this.)") |
997 \\"merge_type_vars\" to prevent this.)") |
986 else |
998 else |
987 () |
999 () |
988 val _ = scopes := the_scopes |
1000 val _ = scopes := the_scopes |
989 |
1001 |
990 fun run_batches _ _ [] |
1002 fun run_batches _ _ [] |
991 (found_really_genuine, max_potential, max_genuine, donno) = |
1003 (found_really_genuine, max_potential, max_genuine, donno) = |
992 if donno > 0 andalso max_genuine > 0 then |
1004 if donno > 0 andalso max_genuine > 0 then |
993 (print_n (fn () => excipit "checked"); unknownN) |
1005 (print_nt (fn () => excipit "checked"); unknownN) |
994 else if max_genuine = original_max_genuine then |
1006 else if max_genuine = original_max_genuine then |
995 if max_potential = original_max_potential then |
1007 if max_potential = original_max_potential then |
996 (print_n (fn () => |
1008 (print_t (K "% SZS status Unknown\n"); |
|
1009 print_nt (fn () => |
997 "Nitpick found no " ^ das_wort_model ^ "." ^ |
1010 "Nitpick found no " ^ das_wort_model ^ "." ^ |
998 (if not standard andalso likely_in_struct_induct_step then |
1011 (if not standard andalso likely_in_struct_induct_step then |
999 " This suggests that the induction hypothesis might be \ |
1012 " This suggests that the induction hypothesis might be \ |
1000 \general enough to prove this subgoal." |
1013 \general enough to prove this subgoal." |
1001 else |
1014 else |
1002 "")); if skipped > 0 then unknownN else noneN) |
1015 "")); if skipped > 0 then unknownN else noneN) |
1003 else |
1016 else |
1004 (print_n (fn () => |
1017 (print_nt (fn () => |
1005 excipit ("could not find a" ^ |
1018 excipit ("could not find a" ^ |
1006 (if max_genuine = 1 then |
1019 (if max_genuine = 1 then |
1007 " better " ^ das_wort_model ^ "." |
1020 " better " ^ das_wort_model ^ "." |
1008 else |
1021 else |
1009 "ny better " ^ das_wort_model ^ "s.") ^ |
1022 "ny better " ^ das_wort_model ^ "s.") ^ |
1021 val batches = batch_list batch_size (!scopes) |
1034 val batches = batch_list batch_size (!scopes) |
1022 val outcome_code = |
1035 val outcome_code = |
1023 run_batches 0 (length batches) batches |
1036 run_batches 0 (length batches) batches |
1024 (false, max_potential, max_genuine, 0) |
1037 (false, max_potential, max_genuine, 0) |
1025 handle TimeLimit.TimeOut => |
1038 handle TimeLimit.TimeOut => |
1026 (print_n (fn () => excipit "ran out of time after checking"); |
1039 (print_nt (fn () => excipit "ran out of time after checking"); |
1027 if !met_potential > 0 then potentialN else unknownN) |
1040 if !met_potential > 0 then potentialN else unknownN) |
1028 val _ = print_v (fn () => |
1041 val _ = print_v (fn () => |
1029 "Total time: " ^ string_from_time (Timer.checkRealTimer timer) ^ |
1042 "Total time: " ^ string_from_time (Timer.checkRealTimer timer) ^ |
1030 ".") |
1043 ".") |
1031 in (outcome_code, !state_ref) end |
1044 in (outcome_code, !state_ref) end |
1033 (* Give the inner timeout a chance. *) |
1046 (* Give the inner timeout a chance. *) |
1034 val timeout_bonus = seconds 1.0 |
1047 val timeout_bonus = seconds 1.0 |
1035 |
1048 |
1036 fun pick_nits_in_term state (params as {debug, timeout, expect, ...}) mode i n |
1049 fun pick_nits_in_term state (params as {debug, timeout, expect, ...}) mode i n |
1037 step subst assm_ts orig_t = |
1050 step subst assm_ts orig_t = |
1038 let val print_n = if mode = Normal then Output.urgent_message else K () in |
1051 let val print_nt = if is_mode_nt mode then Output.urgent_message else K () in |
1039 if getenv "KODKODI" = "" then |
1052 if getenv "KODKODI" = "" then |
1040 (* The "expect" argument is deliberately ignored if Kodkodi is missing so |
1053 (* The "expect" argument is deliberately ignored if Kodkodi is missing so |
1041 that the "Nitpick_Examples" can be processed on any machine. *) |
1054 that the "Nitpick_Examples" can be processed on any machine. *) |
1042 (print_n (Pretty.string_of (plazy install_kodkodi_message)); |
1055 (print_nt (Pretty.string_of (plazy install_kodkodi_message)); |
1043 ("no_kodkodi", state)) |
1056 ("no_kodkodi", state)) |
1044 else |
1057 else |
1045 let |
1058 let |
1046 val unknown_outcome = (unknownN, state) |
1059 val unknown_outcome = (unknownN, state) |
1047 val deadline = Option.map (curry Time.+ (Time.now ())) timeout |
1060 val deadline = Option.map (curry Time.+ (Time.now ())) timeout |
1049 time_limit (if debug orelse is_none timeout then NONE |
1062 time_limit (if debug orelse is_none timeout then NONE |
1050 else SOME (Time.+ (the timeout, timeout_bonus))) |
1063 else SOME (Time.+ (the timeout, timeout_bonus))) |
1051 (pick_them_nits_in_term deadline state params mode i n step subst |
1064 (pick_them_nits_in_term deadline state params mode i n step subst |
1052 assm_ts) orig_t |
1065 assm_ts) orig_t |
1053 handle TOO_LARGE (_, details) => |
1066 handle TOO_LARGE (_, details) => |
1054 (print_n ("Limit reached: " ^ details ^ "."); unknown_outcome) |
1067 (print_nt ("Limit reached: " ^ details ^ "."); unknown_outcome) |
1055 | TOO_SMALL (_, details) => |
1068 | TOO_SMALL (_, details) => |
1056 (print_n ("Limit reached: " ^ details ^ "."); unknown_outcome) |
1069 (print_nt ("Limit reached: " ^ details ^ "."); unknown_outcome) |
1057 | Kodkod.SYNTAX (_, details) => |
1070 | Kodkod.SYNTAX (_, details) => |
1058 (print_n ("Malformed Kodkodi output: " ^ details ^ "."); |
1071 (print_nt ("Malformed Kodkodi output: " ^ details ^ "."); |
1059 unknown_outcome) |
1072 unknown_outcome) |
1060 | TimeLimit.TimeOut => |
1073 | TimeLimit.TimeOut => |
1061 (print_n "Nitpick ran out of time."; unknown_outcome) |
1074 (print_nt "Nitpick ran out of time."; unknown_outcome) |
1062 in |
1075 in |
1063 if expect = "" orelse outcome_code = expect then outcome |
1076 if expect = "" orelse outcome_code = expect then outcome |
1064 else error ("Unexpected outcome: " ^ quote outcome_code ^ ".") |
1077 else error ("Unexpected outcome: " ^ quote outcome_code ^ ".") |
1065 end |
1078 end |
1066 end |
1079 end |