1(* ===================================================================== *)
2(* FILE          : Portable.sml                                          *)
3(* DESCRIPTION   : Structure for SML System dependent functions.         *)
4(* AUTHOR        : Ken Larsen, University of Cambridge (or DTU)          *)
5(*                 based on code by                                      *)
6(*                 Elsa L. Gunter, AT&T Bell Laboratories                *)
7(* DATE          : 19 September, 1997                                    *)
8(* ===================================================================== *)
9
10(* Copyright 1993 by AT&T Bell Laboratories *)
11(* Copyright 1997 by University of Cambridge *)
12
13(* Share and Enjoy *)
14
15structure Portable :> Portable =
16struct
17
18structure Process = OS.Process
19structure FileSys = OS.FileSys
20
21exception Div = General.Div
22exception Mod = General.Div
23
24fun assert_exn P x e = if P x then x else raise e
25fun with_exn f x e = f x handle Interrupt => raise Interrupt | _ => raise e
26fun finally finish f x =
27    let
28      val result = Exn.capture f x
29    in
30      finish();
31      Exn.release result
32    end
33
34val int_to_string = Int.toString
35
36(*---------------------------------------------------------------------------*
37 * Combinators                                                               *
38 *---------------------------------------------------------------------------*)
39
40fun curry f x y = f (x, y)
41fun uncurry f (x, y) = f x y
42infix 3 ##
43fun (f ## g) (x, y) = (f x, g y)
44fun apfst f (x, y) = (f x, y)
45fun apsnd f (x, y) = (x, f y)
46infix |> ||> |>> ||->
47fun x |> f = f x
48fun (x,y) |>> f = (f x, y)
49fun (x,y) ||> f = (x, f y)
50fun (x,y) ||-> f = f x y
51infixr $ ?
52fun f $ x = f x
53fun (b ? f) x = if b then f x else x
54fun B2 f g x y = f (g x y)
55fun C f x y = f y x
56fun I x = x
57fun K x y = x
58fun S f g x = f x (g x)
59fun W f x = f x x
60
61(*---------------------------------------------------------------------------*
62 * Curried versions of infixes.                                              *
63 *---------------------------------------------------------------------------*)
64
65fun append l1 l2 = l1 @ l2
66fun equal x y = x = y
67val strcat = curry (op ^)
68fun cons a L = a :: L
69fun pair x y = (x, y)
70
71fun rpair x y = (y, x)
72fun swap (x, y) = (y, x)
73fun fst (x, _) = x
74fun snd (_, y) = y
75
76fun triple x y z = (x, y, z)
77fun quadruple x1 x2 x3 x4 = (x1, x2, x3, x4)
78
79(*---------------------------------------------------------------------------*
80 * Success and failure. Interrupt has a special status in Standard ML.       *
81 *---------------------------------------------------------------------------*)
82
83fun can f x = (f x; true) handle Interrupt => raise Interrupt | _ => false
84
85fun total f x = SOME (f x) handle Interrupt => raise Interrupt | _ => NONE
86
87fun partial e f x = case f x of SOME y => y | NONE => raise e
88
89fun these (SOME x) = x
90  | these NONE = []
91
92(* ----------------------------------------------------------------------
93    Lists
94   ---------------------------------------------------------------------- *)
95
96fun list_of_singleton a = [a]
97fun single a = [a]
98fun the_single [x] = x
99  | the_single _ = raise List.Empty;
100fun singleton f x = the_single (f [x])
101
102fun list_of_pair (a, b) = [a, b]
103fun list_of_triple (a, b, c) = [a, b, c]
104fun list_of_quadruple (a, b, c, d) = [a, b, c, d]
105
106fun the_list NONE = []
107  | the_list (SOME x) = [x]
108fun the_default d NONE = d
109  | the_default _ (SOME x) = x
110
111val all = List.all
112val exists = List.exists
113
114fun first_opt f =
115   let
116      fun fo n [] = NONE
117        | fo n (a :: rst) =
118            let
119               val vo = f n a handle Interrupt => raise Interrupt | _ => NONE
120            in
121               if isSome vo then vo else fo (n + 1) rst
122            end
123   in
124      fo 0
125   end
126
127fun itlist f L base_value = List.foldr (uncurry f) base_value L
128val foldr' = itlist
129
130fun rev_itlist f L base_value = List.foldl (uncurry f) base_value L
131val foldl' = rev_itlist
132
133fun foldl_map _ (acc, []) = (acc, [])
134  | foldl_map f (acc, x :: xs) =
135      let
136         val (acc', y) = f (acc, x)
137         val (acc'', ys) = foldl_map f (acc', xs)
138      in
139         (acc'', y :: ys)
140      end
141
142fun foldl2' _ [] [] z = z
143  | foldl2' f (x::xs) (y::ys) z = foldl2' f xs ys (f x y z)
144  | foldl2' _ _ _ _ = raise ListPair.UnequalLengths
145fun foldr2' _ [] [] z = z
146  | foldr2' f (x::xs) (y::ys) z = f x y (foldr2' f xs ys z)
147  | foldr2' _ _ _ _ = raise ListPair.UnequalLengths
148
149fun zip3 ([], [], []) = []
150  | zip3 (h1::t1, h2::t2, h3::t3) = (h1,h2,h3) :: zip3 (t1,t2,t3)
151  | zip3 _ = raise ListPair.UnequalLengths
152
153(* separate s [x1, x2, ..., xn] ===> [x1, s, x2, s, ..., s, xn] *)
154
155fun separate s (x :: (xs as _ :: _)) = x :: s :: separate s xs
156  | separate _ xs = xs
157
158val filter = List.filter
159fun filter_out P = filter (not o P)
160
161val partition = List.partition
162
163fun pull_prefix ps l =
164  case ps of
165      [] => l
166    | p :: rest =>
167      let
168        val (s, l0) = List.partition p l
169      in
170        s @ pull_prefix rest l0
171      end
172
173val unzip = ListPair.unzip
174val split = unzip
175
176fun mapfilter f = List.mapPartial (total f)
177
178val flatten = List.concat
179fun front_last l =
180  let
181     fun fl _ [] = raise List.Empty
182       | fl acc [x] = (List.rev acc, x)
183       | fl acc (h :: t) = fl (h :: acc) t
184  in
185     fl [] l
186  end
187
188
189
190fun trypluck' f list =
191   let
192     fun recurse acc l =
193        case l of
194           [] => (NONE, list)
195         | h :: t => (case f h of
196                         NONE => recurse (h :: acc) t
197                       | SOME v => (SOME v, List.revAppend (acc, t)))
198   in
199      recurse [] list
200   end
201
202fun funpow n f x =
203   let
204      fun iter (0, res) = res
205        | iter (n, res) = iter (n - 1, f res)
206   in
207      if n < 0 then x else iter (n, x)
208   end
209
210fun repeat f =
211   let
212      exception LAST of 'a
213      fun loop x =
214         let
215            val y = (f x handle Interrupt => raise Interrupt
216                              | otherwise => raise (LAST x))
217         in
218            loop y
219         end
220   in
221      fn x => loop x handle (LAST y) => y
222   end
223
224fun enumerate i [] = []
225  | enumerate i (h :: t) = (i, h) :: enumerate (i + 1) t
226
227fun upto b t =
228   let
229      fun up i A = if i > t then A else up (i + 1) (i :: A)
230   in
231      List.rev (up b [])
232   end
233
234fun appi f =
235   let
236      fun recurse n lst =
237         case lst of
238            [] => ()
239          | h :: t => (f n h; recurse (n + 1) t)
240   in
241      recurse 0
242   end
243
244fun mapi f lst =
245   let
246      fun recurse n acc lst =
247         case lst of
248            [] => acc
249          | h :: t => recurse (n + 1) (f n h :: acc) t
250   in
251      List.rev (recurse 0 [] lst)
252   end
253
254fun assoc1 item =
255   let
256      fun assc ((e as (key, _)) :: rst) =
257            if item = key then SOME e else assc rst
258        | assc [] = NONE
259   in
260      assc
261   end
262
263fun assoc2 item =
264   let
265      fun assc ((e as (_, key)) :: rst) =
266            if item = key then SOME e else assc rst
267        | assc [] = NONE
268   in
269      assc
270   end
271
272type 'a cmp = 'a * 'a -> order
273
274fun flip_order LESS = GREATER
275  | flip_order EQUAL = EQUAL
276  | flip_order GREATER = LESS
277
278fun flip_cmp cmp = flip_order o cmp
279
280fun bool_compare (true, true) = EQUAL
281  | bool_compare (true, false) = GREATER
282  | bool_compare (false, true) = LESS
283  | bool_compare (false, false) = EQUAL
284
285fun option_compare cmp optp =
286  case optp of
287      (NONE, NONE) => EQUAL
288    | (NONE, SOME _) => LESS
289    | (SOME _, NONE) => GREATER
290    | (SOME x, SOME y) => cmp(x,y)
291
292fun list_compare cfn =
293   let
294      fun comp ([], []) = EQUAL
295        | comp ([], _) = LESS
296        | comp (_, []) = GREATER
297        | comp (h1 :: t1, h2 :: t2) =
298            case cfn (h1, h2) of EQUAL => comp (t1, t2) | x => x
299   in
300      comp
301   end
302
303fun pair_compare (acmp, bcmp) ((a1, b1), (a2, b2)) =
304   case acmp (a1, a2) of
305      EQUAL => bcmp (b1, b2)
306    | x => x
307
308fun measure_cmp f (x, y) = Int.compare (f x, f y)
309fun inv_img_cmp f c (x, y) = c (f x, f y)
310
311(* streamlined combination of inv_img_cmp and pair_compare *)
312fun lex_cmp (c1, c2) (f1, f2) (x1, x2) =
313   case c1 (f1 x1, f1 x2) of
314      EQUAL => c2 (f2 x1, f2 x2)
315    | x => x
316
317(*---------------------------------------------------------------------------*
318 * For loops                                                                 *
319 *---------------------------------------------------------------------------*)
320
321fun for base top f =
322   let fun For i = if i > top then [] else f i :: For (i + 1) in For base end
323
324fun for_se base top f =
325   let fun For i = if i > top then () else (f i; For (i + 1)) in For base end
326
327(*---------------------------------------------------------------------------*
328 * A naive merge sort.                                                       *
329 *---------------------------------------------------------------------------*)
330
331fun sort P =
332   let
333      fun merge [] a = a
334        | merge a [] = a
335        | merge (A as (a :: t1)) (B as (b :: t2)) =
336             if P a b then a :: merge t1 B
337                      else b :: merge A t2
338      fun srt [] = []
339        | srt [a] = a
340        | srt (h1 :: h2 :: t) = srt (merge h1 h2 :: t)
341   in
342      srt o (map (fn x => [x]))
343   end
344
345val int_sort = sort (curry (op <= : int * int -> bool))
346
347(* linear time version of topsort (in Lib)
348   only works when nodes are integers 0 up to some n
349   deps = vector of adjacency lists *)
350
351fun vector_topsort deps =
352   let
353      open Array
354      val n = Vector.length deps
355      val a = tabulate (n, SOME o (curry Vector.sub deps))
356      fun visit (n, ls) =
357         case sub (a, n) of
358            NONE => ls
359          | SOME dl => let
360                          val _ = update (a, n, NONE)
361                          val ls = List.foldl visit ls dl
362                       in
363                          n :: ls
364                       end
365      fun v (0, ls) = ls
366        | v (n, ls) = v (n - 1, visit (n - 1, ls))
367   in
368      v (n, [])
369   end
370
371(*---------------------------------------------------------------------------*
372 * Substitutions.                                                            *
373 *---------------------------------------------------------------------------*)
374
375type ('a, 'b) subst = {redex: 'a, residue: 'b} list
376
377fun subst_assoc test =
378   let
379      fun assc [] = NONE
380        | assc ({redex, residue} :: rst) =
381            if test redex then SOME residue else assc rst
382   in
383      assc
384   end
385
386infix 5 |->
387fun (r1 |-> r2) = {redex = r1, residue = r2}
388
389(*---------------------------------------------------------------------------*
390 * Sets as lists                                                             *
391 *---------------------------------------------------------------------------*)
392
393fun mem i = List.exists (equal i)
394
395fun insert i L = if mem i L then L else i :: L
396
397fun mk_set [] = []
398  | mk_set (a :: rst) = insert a (mk_set rst)
399
400fun union [] S = S
401  | union S [] = S
402  | union (a :: rst) S2 = union rst (insert a S2)
403
404(* Union of a family of sets *)
405
406fun U set_o_sets = itlist union set_o_sets []
407
408(* All the elements in the first set that are not also in the second set. *)
409
410fun set_diff a b = filter (not o C mem b) a
411val subtract = set_diff
412
413fun intersect [] _ = []
414  | intersect _ [] = []
415  | intersect S1 S2 = mk_set (filter (C mem S2) S1)
416
417fun null_intersection _ [] = true
418  | null_intersection [] _ = true
419  | null_intersection (a :: rst) S =
420      not (mem a S) andalso null_intersection rst S
421
422fun set_eq S1 S2 = set_diff S1 S2 = [] andalso set_diff S2 S1 = []
423
424(*---------------------------------------------------------------------------*
425 * Opaque type set operations                                                *
426 *---------------------------------------------------------------------------*)
427
428(* functions for lifting equality functions over standard type operators *)
429type 'a eqf = 'a -> 'a -> bool
430fun pair_eq eq1 eq2 (x1,y1) (x2,y2) = eq1 x1 x2 andalso eq2 y1 y2
431fun fst_eq eq (x1,y1) (x2,y2) = eq x1 x2
432fun option_eq eq NONE NONE = true
433  | option_eq eq (SOME x) (SOME y) = eq x y
434  | option_eq _ _ _ = false
435fun inv_img_eq f (eq:'b eqf) a1 a2 = eq (f a1) (f a2)
436fun list_eq eq l1 l2 = ListPair.allEq (fn (x,y) => eq x y) (l1, l2)
437fun redres_eq eq1 eq2 {residue=res1,redex=red1} {residue=res2,redex=red2} =
438  eq1 red1 red2 andalso eq2 res1 res2
439
440fun op_assoc1 eq_func k alist =
441  case alist of
442      [] => NONE
443    | (k',v) :: rest => if eq_func k k' then SOME v
444                        else op_assoc1 eq_func k rest
445
446fun op_mem eq_func i = List.exists (eq_func i)
447
448fun op_insert eq_func =
449   let
450      val mem = op_mem eq_func
451   in
452      fn i => fn L => if (mem i L) then L else i :: L
453   end
454
455fun op_mk_set eqf =
456   let
457      val insert = op_insert eqf
458      fun mkset [] = []
459        | mkset (a :: rst) = insert a (mkset rst)
460   in
461      mkset
462   end
463
464fun op_union eq_func =
465   let
466      val mem = op_mem eq_func
467      val insert = op_insert eq_func
468      fun un [] [] = []
469        | un a [] = a
470        | un [] a = a
471        | un (a :: b) c = un b (insert a c)
472   in
473      un
474   end
475
476(* Union of a family of sets *)
477
478fun op_U eq_func set_o_sets = itlist (op_union eq_func) set_o_sets []
479
480fun op_intersect eq_func a b =
481   let
482      val mem = op_mem eq_func
483      val in_b = C mem b
484      val mk_set = op_mk_set eq_func
485   in
486      mk_set (filter in_b a)
487   end
488
489(* All the elements in the first set that are not also in the second set. *)
490
491fun op_set_diff eq_func S1 S2 =
492   let
493      val memb = op_mem eq_func
494   in
495      filter (fn x => not (memb x S2)) S1
496   end
497
498fun op_remove eq x list =
499  if op_mem eq x list then
500    filter (fn y => not (eq x y)) list
501  else list
502
503fun op_update eq x xs = cons x (op_remove eq x xs)
504
505(*---------------------------------------------------------------------------
506   quote puts double quotes around a string. mlquote does this as well,
507   but also quotes all of the characters in the string so that the
508   resulting string could be printed out in a way that would make it a
509   valid ML lexeme  (e.g., newlines turn into \n)
510 ---------------------------------------------------------------------------*)
511
512fun mlquote s = String.concat ["\"", String.toString s, "\""]
513
514fun quote s = String.concat ["\"", s, "\""]
515
516val is_substring = String.isSubstring
517
518fun prime s = s ^ "'"
519
520val commafy = separate ", "
521
522fun enclose ld rd s = ld ^ s ^ rd
523
524val str_all = CharVector.all
525
526(*---------------------------------------------------------------------------*
527 * A hash function used for various tasks in the system. It works fairly     *
528 * well for our applications, but is not industrial strength. The size       *
529 * argument should be a prime. The function then takes a string and          *
530 * a pair (i,A) and returns a number < size. "i" is the index in the         *
531 * string to start hashing from, and A is an accumulator.  In simple         *
532 * cases i=0 and A=0.                                                        *
533 *---------------------------------------------------------------------------*)
534
535local
536   open Char String
537in
538   fun hash size =
539      fn s =>
540         let
541            fun hsh (i, A) =
542               hsh (i + 1, (A * 4 + ord (sub (s, i))) mod size)
543               handle Subscript => A
544         in
545            hsh
546         end
547end
548
549(*---------------------------------------------------------------------------
550      Refs
551 ---------------------------------------------------------------------------*)
552
553fun inc r = (r := !r + 1)
554fun dec r = (r := !r - 1)
555
556(*---------------------------------------------------------------------------
557   SML/NJ v.93 style string operations
558 ---------------------------------------------------------------------------*)
559
560fun ordof (string, place) = Char.ord (String.sub (string, place))
561val implode = String.concat
562val explode = map Char.toString o String.explode
563
564fun words2 sep string =
565   snd (itlist (fn ch => fn (chs, tokl) =>
566                   if ch = sep
567                      then if null chs
568                              then ([], tokl)
569                           else ([], implode chs :: tokl)
570                   else (ch :: chs, tokl))
571               (sep :: explode string) ([], []))
572
573fun replace_string {from, to} =
574  let
575    val next = Substring.position from
576    val drop = Substring.triml (String.size from)
577    val to = Substring.full to
578    fun f acc s =
579      let
580        val (prefix,s) = next s
581        val acc = prefix::acc
582      in
583        if Substring.isEmpty s then
584          Substring.concat(List.rev acc)
585        else
586          f (to::acc) (drop s)
587      end
588  in
589    f [] o Substring.full
590  end
591
592(*---------------------------------------------------------------------------
593    System
594 ---------------------------------------------------------------------------*)
595
596val getEnv   = Process.getEnv
597val cd       = FileSys.chDir
598val pwd      = FileSys.getDir
599fun system s = if Process.isSuccess (Process.system s) then 0 else 1
600val getArgs  = CommandLine.arguments
601val argv     = getArgs
602fun exit()   = Process.exit Process.success
603
604(*---------------------------------------------------------------------------
605    IO
606 ---------------------------------------------------------------------------*)
607
608exception Io of string;
609type instream      = TextIO.instream
610type outstream     = TextIO.outstream
611val std_out        = TextIO.stdOut
612val stdin          = TextIO.stdIn
613fun open_in file   = TextIO.openIn file
614                     handle IO.Io{cause=SysErr(s,_),...} => raise (Io s)
615                                   (* handle OS.SysErr (s,_) => raise Io s; *)
616fun open_out file  = TextIO.openOut file
617                     handle IO.Io{cause=SysErr(s,_),...} => raise (Io s)
618                                   (* handle OS.SysErr (s,_) => raise Io s; *)
619val output         = TextIO.output
620fun outputc strm s = output(strm,s)
621val close_in       = TextIO.closeIn
622val close_out      = TextIO.closeOut
623val flush_out      = TextIO.flushOut
624fun input_line is  = case TextIO.inputLine is of NONE => "" | SOME s => s
625val end_of_stream  = TextIO.endOfStream
626
627(*---------------------------------------------------------------------------*)
628(* Yet another variant of the sum type, used for the failure monad           *)
629(*---------------------------------------------------------------------------*)
630
631datatype ('a, 'b) verdict = PASS of 'a | FAIL of 'b
632
633fun verdict f c x = PASS (f x) handle e => FAIL (c x, e)
634
635fun ?>(PASS x, f) = f x
636  | ?>(FAIL y, f) = FAIL y
637
638(*---------------------------------------------------------------------------
639    Time
640 ---------------------------------------------------------------------------*)
641
642type time = Time.time
643
644local
645   open Time
646in
647   val timestamp: unit -> time = now
648   val time_to_string: time -> string = toString
649   fun dest_time t =
650      let
651         val r = toReal t
652         val sec = Arbnum.floor (toReal t)
653         val sec_million = Arbnum.* (sec, Arbnum.fromInt 1000000)
654         val r_million = r * 1000000.0
655         val usec = Arbnum.- (Arbnum.floor r_million, sec_million)
656      in
657         {sec = sec, usec = usec}
658      end
659   fun mk_time {sec, usec} =
660      fromReal (Real.+ (Arbnum.toReal sec, Arbnum.toReal usec / 1000000.0))
661   fun time_eq (t1:time) t2 = (t1 = t2)
662   fun time_lt (t1:time) t2 = Time.<(t1,t2)
663   fun time_max (t1,t2) = if time_lt t1 t2 then t2 else t1
664   fun time_maxl l =
665     case l of
666         [] => Time.zeroTime
667       | h::t => List.foldl time_max h t
668   fun realtime f x =
669     let
670       val timer = Timer.startRealTimer()
671       val result = verdict f (fn x => x) x
672       val t = Timer.checkRealTimer timer
673     in
674       print ("clock time: " ^ Time.toString t ^ "s\n");
675       case result of
676           PASS y => y
677         | FAIL (_, e) => raise e
678     end
679end
680
681(*---------------------------------------------------------------------------*
682 * Invoking a function with a flag temporarily assigned to the given value.  *
683 *---------------------------------------------------------------------------*)
684
685fun with_flag (flag, b) f x =
686   let
687      val fval = !flag
688      val () = flag := b
689      val res = f x handle e => (flag := fval; raise e)
690   in
691      flag := fval; res
692   end
693
694(*---------------------------------------------------------------------------*
695 * An abstract type of imperative streams.                                   *
696 *---------------------------------------------------------------------------*)
697
698abstype ('a, 'b) istream = STRM of {mutator: 'a -> 'a,
699                                    project: 'a -> 'b,
700                                    state: 'a ref,
701                                    init: 'a}
702with
703   fun mk_istream f i g =
704      STRM {mutator = f, project = g, state = ref i, init = i}
705   fun next (strm as STRM{mutator, state, ...}) =
706      (state := mutator (!state); strm)
707   fun state (STRM {project, state, ...}) = project (!state)
708   fun reset (strm as STRM {state, init, ...}) = (state := init; strm)
709end
710
711(*---------------------------------------------------------------------------
712    A type that can be used for sharing, and some functions for lifting
713    to various type operators (just lists and pairs currently).
714 ---------------------------------------------------------------------------*)
715
716datatype 'a delta = SAME | DIFF of 'a
717
718fun delta_apply f x = case f x of SAME => x | DIFF y => y
719
720fun delta_map f =
721   let
722      fun map [] = SAME
723        | map (h :: t) =
724            case (f h, map t) of
725               (SAME, SAME) => SAME
726             | (SAME, DIFF t') => DIFF (h  :: t')
727             | (DIFF h', SAME) => DIFF (h' :: t)
728             | (DIFF h', DIFF t') => DIFF (h' :: t')
729   in
730      map
731   end
732
733fun delta_pair f g (x, y) =
734  case (f x, g y) of
735     (SAME, SAME) => SAME
736   | (SAME, DIFF y') => DIFF (x, y')
737   | (DIFF x', SAME) => DIFF (x', y)
738   | (DIFF x', DIFF y') => DIFF (x', y')
739
740(*---------------------------------------------------------------------------
741    A function that strips leading (nested) comments and whitespace
742    from a string.
743 ---------------------------------------------------------------------------*)
744
745fun deinitcomment0 ss n =
746   case Substring.getc ss of
747      NONE => ss
748    | SOME (c, ss') =>
749        if Char.isSpace c
750           then deinitcomment0 ss' n
751        else if c = #"("
752           then case Substring.getc ss' of
753                   NONE => ss
754                 | SOME (c, ss'') =>
755                      if c = #"*"
756                         then deinitcomment0 ss'' (n + 1)
757                      else if n = 0
758                         then ss
759                      else deinitcomment0 ss'' n
760        else if n > 0 andalso c = #"*"
761           then case Substring.getc ss' of
762                   NONE => ss
763                 | SOME (c, ss'') =>
764                      if c = #")"
765                         then deinitcomment0 ss'' (n - 1)
766                      else deinitcomment0 ss'' n
767        else if n = 0
768           then ss
769        else deinitcomment0 ss' n
770
771fun deinitcommentss ss = deinitcomment0 ss 0
772fun deinitcomment s = Substring.string (deinitcomment0 (Substring.full s) 0)
773
774(*---------------------------------------------------------------------------
775    Pretty Printing
776 ---------------------------------------------------------------------------*)
777
778(*---------------------------------------------------------------------------
779 * Simple and heavily used.
780 * pfun = item printing function
781 * dfun = delimiter printing function
782 * bfun = break printer function
783 *---------------------------------------------------------------------------*)
784
785fun with_ppstream ppstrm =
786  let
787    open OldPP
788  in
789    {add_string     = add_string ppstrm,
790     add_break      = add_break ppstrm,
791     begin_block    = begin_block ppstrm,
792     end_block      = fn () => end_block ppstrm,
793     add_newline    = fn () => add_newline ppstrm,
794     clear_ppstream = fn () => clear_ppstream ppstrm,
795     flush_ppstream = fn () => flush_ppstream ppstrm}
796  end
797
798(*---------------------------------------------------------------------------
799      MoscowML returns lists of QUOTE'd strings when a quote is spread
800      over more than one line. "norm_quote" concatenates all adjacent
801      QUOTE elements in this list.
802 ---------------------------------------------------------------------------*)
803
804type 'a quotation = 'a HOLPP.quotation
805open HOLPP
806
807fun pprint f x = prettyPrint(TextIO.print, 72) (f x)
808
809fun norm_quote [] = []
810  | norm_quote [x] = [x]
811  | norm_quote (QUOTE s1 :: QUOTE s2 :: rst) =
812      norm_quote (QUOTE (s1 ^ s2) :: rst)
813  | norm_quote (h :: rst) = h :: norm_quote rst
814
815local
816  fun strip_comments (d, a) s =
817    if Substring.size s = 0
818      then a
819    else let
820           val (l, r) = Substring.splitl (fn c => c <> #"(" andalso c <> #"*") s
821           val a' = if 0 < d then a else a @ [l]
822         in
823           if Substring.isPrefix "(*#loc " r
824             then strip_comments (d + 1, a @ [Substring.trimr 1 l])
825                    (Substring.triml 7 r)
826           else if Substring.isPrefix "(*" r
827             then strip_comments (d + 1, a') (Substring.triml 2 r)
828           else if Substring.isPrefix "*)" r
829             then strip_comments (d - 1, a') (Substring.triml 2 r)
830           else if Substring.size r = 0
831             then a'
832           else let
833                  val (r1, r2) = Substring.splitAt (r, 1)
834                in
835                  strip_comments (d, if 0 < d then a' else a' @ [r1]) r2
836                end
837         end
838  val finish = Substring.concat o strip_comments (0, []) o Substring.full o
839               String.concat o List.rev
840in
841  fun quote_to_string (f : 'a -> string) =
842    let
843      fun quote_to_strings a =
844        fn [] => finish a
845         | QUOTE s :: r => quote_to_strings (s :: a) r
846         | ANTIQUOTE s :: r => quote_to_strings (f s :: a) r
847    in
848      quote_to_strings []
849    end
850  val quote_to_string_list =
851    String.tokens (fn c => c = #"\n") o quote_to_string (fn x => x)
852end
853
854(* suck in implementation specific stuff *)
855
856open MLSYSPortable
857structure HOLSusp = MLSYSPortable.HOLSusp
858
859(* rebinding the exception seems to be necessary in Moscow ML 2.01 *)
860
861exception Interrupt = MLSYSPortable.Interrupt
862
863end (* Portable *)
864