| 4403 |      1 | (*  Title:      Pure/ML-Systems/smlnj.ML
 | 
|  |      2 |     ID:         $Id$
 | 
|  |      3 |     Author:     Carsten Clasohm and Markus Wenzel, TU Muenchen
 | 
|  |      4 | 
 | 
| 5708 |      5 | Compatibility file for Standard ML of New Jersey 110 or later.
 | 
| 4403 |      6 | *)
 | 
|  |      7 | 
 | 
|  |      8 | (** ML system related **)
 | 
|  |      9 | 
 | 
|  |     10 | (* restore old-style character / string functions *)
 | 
|  |     11 | 
 | 
|  |     12 | fun ord s = Char.ord (String.sub (s, 0));
 | 
|  |     13 | val chr = str o Char.chr;
 | 
|  |     14 | val explode = (map str) o String.explode;
 | 
|  |     15 | val implode = String.concat;
 | 
|  |     16 | 
 | 
|  |     17 | 
 | 
|  |     18 | (* New Jersey ML parameters *)
 | 
|  |     19 | 
 | 
|  |     20 | val _ =
 | 
|  |     21 |  (Compiler.Control.Print.printLength := 1000;
 | 
|  |     22 |   Compiler.Control.Print.printDepth := 350;
 | 
|  |     23 |   Compiler.Control.Print.stringDepth := 250;
 | 
|  |     24 |   Compiler.Control.Print.signatures := 2);
 | 
|  |     25 | 
 | 
|  |     26 | 
 | 
|  |     27 | (* Poly/ML emulation *)
 | 
|  |     28 | 
 | 
|  |     29 | fun quit () = exit 0;
 | 
|  |     30 | 
 | 
|  |     31 | (*limit the printing depth -- divided by 2 for comparibility with Poly/ML*)
 | 
|  |     32 | fun print_depth n =
 | 
|  |     33 |  (Compiler.Control.Print.printDepth := n div 2;
 | 
|  |     34 |   Compiler.Control.Print.printLength := n);
 | 
|  |     35 | 
 | 
|  |     36 | 
 | 
| 5816 |     37 | (* compiler-independent timing functions *)
 | 
| 4403 |     38 | 
 | 
|  |     39 | (*Note start point for timing*)
 | 
| 5816 |     40 | fun startTiming() =
 | 
| 4403 |     41 |   let val CPUtimer = Timer.startCPUTimer();
 | 
|  |     42 |       val time = Timer.checkCPUTimer(CPUtimer)
 | 
|  |     43 |   in  (CPUtimer,time)  end;
 | 
|  |     44 | 
 | 
|  |     45 | (*Finish timing and return string*)
 | 
|  |     46 | fun endTiming (CPUtimer, {gc,sys,usr}) =
 | 
|  |     47 |   let open Time  (*...for Time.toString, Time.+ and Time.- *)
 | 
|  |     48 |       val {gc=gc2,sys=sys2,usr=usr2} = Timer.checkCPUTimer(CPUtimer)
 | 
|  |     49 |   in  "User " ^ toString (usr2-usr) ^
 | 
|  |     50 |       "  GC " ^ toString (gc2-gc) ^
 | 
|  |     51 |       "  All "^ toString (sys2-sys + usr2-usr + gc2-gc) ^
 | 
|  |     52 |       " secs"
 | 
|  |     53 |       handle Time => ""
 | 
|  |     54 |   end;
 | 
|  |     55 | 
 | 
|  |     56 | 
 | 
| 4977 |     57 | (* prompts *)
 | 
|  |     58 | 
 | 
|  |     59 | fun ml_prompts p1 p2 =
 | 
|  |     60 |   (Compiler.Control.primaryPrompt := p1; Compiler.Control.secondaryPrompt := p2);
 | 
|  |     61 | 
 | 
|  |     62 | 
 | 
| 4403 |     63 | (* toplevel pretty printing (see also Pure/install_pp.ML) *)
 | 
|  |     64 | 
 | 
|  |     65 | fun make_pp path pprint =
 | 
|  |     66 |   let
 | 
|  |     67 |     open Compiler.PrettyPrint;
 | 
|  |     68 | 
 | 
|  |     69 |     fun pp pps obj =
 | 
|  |     70 |       pprint obj
 | 
|  |     71 |         (add_string pps, begin_block pps INCONSISTENT,
 | 
|  |     72 |           fn wd => add_break pps (wd, 0), fn () => add_newline pps,
 | 
|  |     73 |           fn () => end_block pps);
 | 
|  |     74 |   in
 | 
|  |     75 |     (path, pp)
 | 
|  |     76 |   end;
 | 
|  |     77 | 
 | 
|  |     78 | fun install_pp (path, pp) = Compiler.PPTable.install_pp path pp;
 | 
|  |     79 | 
 | 
|  |     80 | 
 | 
|  |     81 | (* ML command execution *)
 | 
|  |     82 | 
 | 
| 7855 |     83 | fun use_text print verbose txt =
 | 
| 5090 |     84 |   let
 | 
|  |     85 |     val ref out_orig = Compiler.Control.Print.out;
 | 
|  |     86 | 
 | 
|  |     87 |     val out_buffer = ref ([]: string list);
 | 
|  |     88 |     val out = {say = (fn s => out_buffer := s :: ! out_buffer), flush = (fn () => ())};
 | 
|  |     89 | 
 | 
| 7890 |     90 |     fun show_output () =
 | 
|  |     91 |       let val str = implode (rev (! out_buffer))
 | 
|  |     92 |       in print (String.substring (str, 0, Int.max (0, size str - 1))) end;
 | 
| 5090 |     93 |   in
 | 
|  |     94 |     Compiler.Control.Print.out := out;
 | 
|  |     95 |     Compiler.Interact.useStream (TextIO.openString txt) handle exn =>
 | 
|  |     96 |       (Compiler.Control.Print.out := out_orig; show_output (); raise exn);
 | 
|  |     97 |     Compiler.Control.Print.out := out_orig;
 | 
|  |     98 |     if verbose then show_output () else ()
 | 
|  |     99 |   end;
 | 
| 4403 |    100 | 
 | 
|  |    101 | 
 | 
|  |    102 | 
 | 
| 5816 |    103 | (** interrupts **)
 | 
|  |    104 | 
 | 
|  |    105 | local
 | 
|  |    106 | 
 | 
|  |    107 | datatype 'a result =
 | 
|  |    108 |   Result of 'a |
 | 
|  |    109 |   Exn of exn;
 | 
|  |    110 | 
 | 
|  |    111 | fun capture f x = Result (f x) handle exn => Exn exn;
 | 
|  |    112 | 
 | 
|  |    113 | fun release (Result x) = x
 | 
|  |    114 |   | release (Exn exn) = raise exn;
 | 
|  |    115 | 
 | 
|  |    116 | 
 | 
|  |    117 | val sig_int = Signals.sigINT;
 | 
|  |    118 | val sig_int_mask = Signals.MASK [Signals.sigINT];
 | 
|  |    119 | 
 | 
|  |    120 | fun interruptible () =
 | 
|  |    121 |   (case Signals.masked () of
 | 
|  |    122 |     Signals.MASKALL => false
 | 
|  |    123 |   | Signals.MASK sigs => List.all (fn s => s <> sig_int) sigs);
 | 
|  |    124 | 
 | 
|  |    125 | val mask_signals = Signals.maskSignals;
 | 
|  |    126 | val unmask_signals = Signals.unmaskSignals;
 | 
|  |    127 | 
 | 
|  |    128 | fun change_mask ok change unchange f x =
 | 
|  |    129 |   if ok () then f x
 | 
|  |    130 |   else
 | 
|  |    131 |     let
 | 
|  |    132 |       val _ = change sig_int_mask;
 | 
|  |    133 |       val result = capture f x;
 | 
|  |    134 |       val _ = unchange sig_int_mask;
 | 
|  |    135 |     in release result end;
 | 
|  |    136 | 
 | 
|  |    137 | in
 | 
|  |    138 | 
 | 
|  |    139 | 
 | 
|  |    140 | (* mask / unmask interrupt *)
 | 
|  |    141 | 
 | 
|  |    142 | fun mask_interrupt f = change_mask (not o interruptible) mask_signals unmask_signals f;
 | 
|  |    143 | fun unmask_interrupt f = change_mask interruptible unmask_signals mask_signals f;
 | 
|  |    144 | 
 | 
|  |    145 | 
 | 
|  |    146 | (* exhibit interrupt (via exception) *)
 | 
|  |    147 | 
 | 
|  |    148 | exception Interrupt;
 | 
|  |    149 | 
 | 
|  |    150 | fun exhibit_interrupt f x =
 | 
|  |    151 |   let
 | 
|  |    152 |     val orig_handler = Signals.inqHandler sig_int;
 | 
|  |    153 |     fun reset_handler () = (Signals.setHandler (sig_int, orig_handler); ());
 | 
|  |    154 | 
 | 
|  |    155 |     val interrupted = ref false;
 | 
|  |    156 | 
 | 
|  |    157 |     fun set_handler cont =
 | 
|  |    158 |       Signals.setHandler (sig_int, Signals.HANDLER (fn _ => (interrupted := true; cont)));
 | 
|  |    159 | 
 | 
|  |    160 |     fun proceed cont =
 | 
|  |    161 |       let
 | 
|  |    162 |         val _ = set_handler cont;
 | 
|  |    163 |         val result = unmask_interrupt (capture f) x;
 | 
|  |    164 |         val _ = reset_handler ();
 | 
|  |    165 |       in release result end;
 | 
|  |    166 |   in
 | 
|  |    167 |     SMLofNJ.Cont.callcc proceed;
 | 
|  |    168 |     reset_handler ();
 | 
|  |    169 |     if ! interrupted then raise Interrupt else ()
 | 
|  |    170 |    end;
 | 
|  |    171 | 
 | 
|  |    172 | end;
 | 
|  |    173 | 
 | 
|  |    174 | 
 | 
|  |    175 | 
 | 
| 4403 |    176 | (** OS related **)
 | 
|  |    177 | 
 | 
|  |    178 | (* system command execution *)
 | 
|  |    179 | 
 | 
|  |    180 | (*execute Unix command which doesn't take any input from stdin and
 | 
|  |    181 |   sends its output to stdout; could be done more easily by Unix.execute,
 | 
|  |    182 |   but that function doesn't use the PATH*)
 | 
|  |    183 | fun execute command =
 | 
|  |    184 |   let
 | 
|  |    185 |     val tmp_name = OS.FileSys.tmpName ();
 | 
|  |    186 |     val is = (OS.Process.system (command ^ " > " ^ tmp_name); TextIO.openIn tmp_name);
 | 
|  |    187 |     val result = TextIO.inputAll is;
 | 
|  |    188 |   in
 | 
|  |    189 |     TextIO.closeIn is;
 | 
|  |    190 |     OS.FileSys.remove tmp_name;
 | 
|  |    191 |     result
 | 
|  |    192 |   end;
 | 
|  |    193 | 
 | 
| 7855 |    194 | (*plain version; with return code*)
 | 
|  |    195 | val system = OS.Process.system: string -> int; 
 | 
|  |    196 | 
 | 
| 4403 |    197 | 
 | 
|  |    198 | (* file handling *)
 | 
|  |    199 | 
 | 
| 6227 |    200 | (*get time of last modification*)
 | 
|  |    201 | fun file_info name = Time.toString (OS.FileSys.modTime name) handle _ => "";
 | 
| 4403 |    202 | 
 | 
|  |    203 | 
 | 
|  |    204 | (* getenv *)
 | 
|  |    205 | 
 | 
|  |    206 | fun getenv var =
 | 
|  |    207 |   (case OS.Process.getEnv var of
 | 
|  |    208 |     NONE => ""
 | 
|  |    209 |   | SOME txt => txt);
 | 
|  |    210 | 
 | 
|  |    211 | 
 | 
| 4428 |    212 | (* non-ASCII input (see also Thy/use.ML) *)
 | 
| 4403 |    213 | 
 | 
|  |    214 | val needs_filtered_use = false;
 |