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