1structure term_pp :> term_pp = 2struct 3 4open Portable HolKernel term_grammar 5 HOLtokens HOLgrammars GrammarSpecials 6 PrecAnalysis 7 8val PP_ERR = mk_HOL_ERR "term_pp"; 9 10fun PRINT s = print (s ^ "\n") 11fun LEN l = Int.toString (length l) 12 13(*--------------------------------------------------------------------------- 14 Miscellaneous syntax stuff. 15 ---------------------------------------------------------------------------*) 16 17fun ellist_size els = 18 let 19 fun recurse A els = 20 case els of 21 [] => A 22 | e::rest => 23 case e of 24 PPBlock(more_els, (sty, ind)) => recurse A (more_els @ rest) 25 | HardSpace n => recurse (A + n) rest 26 | BreakSpace (n, m) => recurse 0 rest 27 | RE (TOK s) => recurse (A + UTF8.size s) rest 28 | _ => recurse 0 rest 29 in 30 recurse 0 els 31 end 32 33val dest_pair = sdest_binop (",", "pair") (PP_ERR "dest_pair" ""); 34val is_pair = Lib.can dest_pair; 35 36fun isSuffix s1 s2 = (* s1 is a suffix of s2 *) let 37 val ss = Substring.full s2 38 val (pref, suff) = Substring.position s1 ss 39in 40 Substring.size suff = String.size s1 41end 42 43fun acc_strip_comb M rands = 44 let val (Rator,Rand) = dest_comb M 45 in acc_strip_comb Rator (Rand::rands) 46 end 47 handle HOL_ERR _ => (M,rands); 48 49fun strip_comb tm = acc_strip_comb tm []; 50 51fun string_of_nspaces n = String.concat (List.tabulate(n, (fn _ => " "))) 52val isPrefix = String.isPrefix 53 54fun lose_constrec_ty {Name,Ty,Thy} = {Name = Name, Thy = Thy} 55 56(* while f is still of functional type, dest_abs the abs term and apply the 57 f to the variable just stripped from the abs *) 58fun apply_absargs f abs = 59 if can dom_rng (type_of f) then let 60 val (v, body) = dest_abs abs 61 in 62 apply_absargs (mk_comb(f, v)) body 63 end 64 else 65 (f, abs) 66 67(*--------------------------------------------------------------------------- 68 Type antiquotations (required in term parser) 69 ---------------------------------------------------------------------------*) 70 71 72val casesplit_munger = ref (NONE: (term -> term * (term * term)list) option) 73fun init_casesplit_munger f = 74 case !casesplit_munger of 75 NONE => casesplit_munger := SOME f 76 | _ => raise PP_ERR "init_casesplit_munger" 77 "casesplit munger already initialised" 78 79exception CaseConversionFailed 80fun convert_case tm = 81 case !casesplit_munger of 82 NONE => raise CaseConversionFailed 83 | (SOME f) => let 84 val (split_on, splits) = f tm 85 handle HOL_ERR _ => raise CaseConversionFailed 86 val _ = not (null splits) orelse raise CaseConversionFailed 87 in 88 (split_on, splits) 89 end 90 91val prettyprint_cases = ref true; 92val prettyprint_cases_dt = ref false; 93val _ = register_btrace ("pp_cases", prettyprint_cases) 94val _ = register_btrace ("pp_cases_dt", prettyprint_cases_dt) 95 96fun prettyprint_cases_name () = if !prettyprint_cases_dt then "dtcase" else "case"; 97 98 99 100(* ---------------------------------------------------------------------- 101 A flag controlling whether to print escaped syntax with a dollar 102 or enclosing parentheses. Thus whether the term mk_comb(+, 3) comes 103 out as 104 $+ 3 105 or 106 (+) 3 107 The parser accepts either form. 108 ---------------------------------------------------------------------- *) 109open HOLPP smpp term_pp_types term_pp_utils 110 111val dollar_escape = ref true 112 113(* When printing with parentheses, make consecutive calls to the 114 supplied printing function (add_string) so that the "tokens" 115 aren't merged prematurely. This is important to catch possible 116 unwanted comment tokens. 117 118 In the dollar-branch, we're happy to have the dollar smashed up 119 against what follows it. *) 120fun dollarise contentpfn parenpfn s = 121 if !dollar_escape then contentpfn ("$" ^ s) 122 else parenpfn "(" >> contentpfn s >> parenpfn ")" 123 124 125val _ = Feedback.register_btrace ("pp_dollar_escapes", dollar_escape); 126 127(* ---------------------------------------------------------------------- 128 Functions for manipulating the "printing info" data that is carried 129 along by the monadic printer 130 ---------------------------------------------------------------------- *) 131 132open smpp term_pp_types term_pp_utils 133infix || ||| 134 135val start_info = dflt_pinfo 136 137fun getlaststring x = 138 (fupdate (fn x => x) >- 139 (fn (i:printing_info) => return (#last_string i))) 140 x 141 142fun setlaststring s = let 143 fun set {seen_frees,current_bvars,last_string,in_gspec} = 144 {seen_frees=seen_frees, current_bvars = current_bvars, 145 last_string = s, in_gspec = in_gspec} 146in 147 fupdate set >> return () 148end 149 150 151(* ---------------------------------------------------------------------- 152 Control symbol merging 153 ---------------------------------------------------------------------- *) 154 155(* A character is symbolic if it is listed on the first line of the 156 symbolic characters given in DESCRIPTION, section 1.1.1(ii) (page 2). 157 The function "Char.contains" is slow on the first argument, but 158 fast on its second argument. 159*) 160 161val avoid_symbol_merges = ref true 162val _ = register_btrace("pp_avoids_symbol_merges", avoid_symbol_merges) 163 164fun creates_comment(s1, s2) = let 165 val last = String.sub(s1, size s1 - 1) 166 val first = String.sub(s2, 0) 167in 168 last = #"(" andalso first = #"*" orelse 169 last = #"*" andalso first = #")" 170end 171 172 173fun avoid_symbolmerge G (add_string, add_xstring, add_break) = let 174 open term_grammar 175 val op>> = smpp.>> 176 infix >> 177 val keywords = #endbinding (specials G) :: grammar_tokens G @ 178 known_constants G 179 val split = term_tokens.user_split_ident keywords 180 fun bad_merge (s1, s2) = let 181 val combined = s1 ^ s2 182 val (x,y) = split combined 183 in 184 y <> s2 185 end handle base_tokens.LEX_ERR _ => true 186 fun new_addxstring f (xstr as {s,sz,ann}) ls = let 187 val allspaces = str_all (equal #" ") s 188 in 189 case s of 190 "" => nothing 191 | _ => (if ls = " " orelse allspaces then f xstr 192 else if not (!avoid_symbol_merges) then f xstr 193 else if String.sub(ls, size ls - 1) = #"\"" then f xstr 194 (* special case the quotation because term_tokens relies on 195 the base token technology (see base_lexer) to separate the 196 end of a string from the next character *) 197 else if creates_comment (ls, s) orelse bad_merge (ls, s) then 198 add_string " " >> f xstr 199 else 200 f xstr) >> 201 setlaststring (if allspaces then " " else s) 202 end 203 fun new_addstring f s = new_addxstring (fn{s,...}=>f s) {s=s,sz=NONE,ann=NONE} 204 fun new_add_break (p as (n,m)) = 205 (if n > 0 then setlaststring " " else nothing) >> add_break p 206in 207 ((fn s => getlaststring >- new_addstring add_string s), 208 (fn xstr => getlaststring >- new_addxstring add_xstring xstr), 209 new_add_break) 210end 211 212 213 214(* ---------------------------------------------------------------------- 215 A flag controlling printing of set comprehensions 216 ---------------------------------------------------------------------- *) 217 218val unamb_comp = ref 0 219val _ = Feedback.register_trace ("pp_unambiguous_comprehensions", unamb_comp, 2) 220 221fun grav_name (Prec(n, s)) = s | grav_name _ = "" 222fun grav_prec (Prec(n,s)) = n | grav_prec _ = ~1 223 224 225fun pneeded_by_style (rr: term_grammar.rule_record, pgrav, fname, fprec) = 226 case #paren_style rr of 227 Always => true 228 | OnlyIfNecessary => false 229 | NotEvenIfRand => false 230 | ParoundName => grav_name pgrav <> fname 231 | ParoundPrec => grav_prec pgrav <> fprec 232 233fun countP P [] = 0 234 | countP P (x::xs) = if P x then 1 + countP P xs else countP P xs 235val numTMs = countP (fn TM => true | _ => false) 236 237fun find_partial f = 238 let fun find [] = NONE 239 | find (x::xs) = 240 case f x 241 of NONE => find xs 242 | result => result 243 in find end; 244 245 246fun splitP P thelist = let 247 fun with_acc acc [] = acc 248 | with_acc (inlist, outlist) (x::xs) = let 249 in 250 if P x then with_acc (x::inlist, outlist) xs 251 else with_acc (inlist, x::outlist) xs 252 end 253in 254 with_acc ([], []) (List.rev thelist) 255end 256 257fun find_lspec els = 258 let 259 fun find_lspec1 e = 260 case e of 261 ListForm l => SOME l 262 | PPBlock(els, _) => recurse els 263 | _ => NONE 264 and recurse els = 265 case els of 266 [] => NONE 267 | e :: rest => (case find_lspec1 e of NONE => recurse rest | x => x) 268 in 269 recurse els 270 end 271 272fun grule_term_names G grule = let 273 fun lift f (rr as {term_name,timestamp,elements,...}) = 274 if term_name_is_lform term_name then 275 case find_lspec elements of 276 NONE => [] (* probably a bad rule *) 277 | SOME {nilstr,cons,...} => 278 map (fn s => (s, (timestamp, f [rr]))) [nilstr, cons] 279 else if term_name = GrammarSpecials.fnapp_special then [] 280 else 281 [(term_name, (timestamp, f [rr]))] 282 val suffix = lift (SUFFIX o STD_suffix) 283 val prefix = lift (PREFIX o STD_prefix) 284 fun mkifix a = lift (fn rrs => INFIX (STD_infix(rrs, a))) 285 val closefix = lift CLOSEFIX 286 fun bstamp LAMBDA = 0 287 | bstamp (BinderString r) = #timestamp r 288in 289 case grule of 290 PREFIX (STD_prefix list) => List.concat (map prefix list) 291 | PREFIX (BINDER list) => 292 map (fn b => (binder_to_string G b, (bstamp b, PREFIX (BINDER [b])))) list 293 (* binder_to_string is incomplete on LAMBDA, but this doesn't matter 294 here as the information generated here is not used to print 295 pure LAMBDAs *) 296 | SUFFIX (STD_suffix list) => List.concat (map suffix list) 297 | SUFFIX TYPE_annotation => [] 298 | INFIX (STD_infix(list, a)) => List.concat (map (mkifix a) list) 299 | INFIX RESQUAN_OP => [(resquan_special, (0, grule))] 300 | INFIX (FNAPP lst) => 301 (fnapp_special, (0, INFIX (FNAPP []))) :: 302 List.concat (map (mkifix LEFT) lst) 303 | INFIX VSCONS => [(vs_cons_special, (0, INFIX VSCONS))] 304 | CLOSEFIX lst => List.concat (map closefix lst) 305end 306 307exception DoneExit 308 309(* fun symbolic s = List.all HOLsym (String.explode s) *) 310 311fun symbolic s = HOLsym (String.sub(s,String.size(s)-1)); 312 313(* term tm can be seen to have name s according to grammar G *) 314fun has_name G s tm = 315 grammar_name G tm = SOME s orelse 316 (case dest_term tm of 317 VAR(s', _) => s' = s 318 | _ => false) 319 320(* term tm might be the product of parsing name s - 321 weaker than has_name *) 322fun has_name_by_parser G s tm = let 323 val oinfo = term_grammar.overload_info G 324in 325 case dest_term tm of 326 VAR(vnm, _) => vnm = s orelse 327 (case dest_fakeconst_name vnm of 328 SOME{fake,...} => fake = s 329 | NONE => false) 330 | _ => 331 (case Overload.info_for_name oinfo s of 332 NONE => false 333 | SOME {actual_ops,...} => 334 List.exists (fn t => can (match_term t) tm) actual_ops) 335end 336 337(* use of has_name_by_parser for nilstr allows for scenario where you have a 338 chain of cons-like things, and cons does indeed want to print as the cons 339 string, but the bottom nil equivalent would prefer to print some other way 340 (perhaps with Unicode). 341 In this scenario (e.g., in pred_sets, where EMPTY is the bottom of the 342 list-form, but is overloaded to the Unicode symbol for empty set as well 343 as the string "EMPTY"), you probably still want the list-form. 344*) 345fun is_list G (r as {nilstr, cons}) tm = 346 has_name_by_parser G nilstr tm orelse 347 (is_comb tm andalso 348 let 349 val (conshd, tail) = dest_comb tm 350 in 351 is_comb conshd andalso 352 has_name G cons (rator conshd) andalso 353 is_list G r tail 354 end) 355 356(* 357val is_list = fn G => fn (r as {nilstr,cons}) => fn tm => 358 let 359 val b = is_list G r tm 360 in 361 PRINT ("is_list{nilstr=\""^nilstr^"\",cons=\""^cons^"\"}" ^ 362 debugprint G tm ^ " --> " ^ Bool.toString b); 363 b 364 end 365*) 366 367fun str_unicode_ok s = CharVector.all Char.isPrint s 368 369fun oi_strip_comb' oinfo t = 370 if current_trace "PP.avoid_unicode" = 0 then Overload.oi_strip_comb oinfo t 371 else Overload.oi_strip_combP oinfo str_unicode_ok t 372 373fun overloading_of_term' oinfo t = 374 if current_trace "PP.avoid_unicode" = 0 then 375 Overload.overloading_of_term oinfo t 376 else 377 Overload.overloading_of_termP oinfo str_unicode_ok t 378 379fun pp_unicode_free ppel = 380 case ppel of 381 PPBlock(ppels, _) => List.all pp_unicode_free ppels 382 | RE (TOK s) => str_unicode_ok s 383 | ListForm {separator,...} => List.all pp_unicode_free separator 384 | _ => true 385 386fun is_unicode_ok_rule r = 387 current_trace "PP.avoid_unicode" = 0 orelse 388 (case r of 389 PREFIX (STD_prefix rrs) => 390 List.all (fn {elements,...} => List.all pp_unicode_free elements) 391 rrs 392 | PREFIX (BINDER bs) => 393 List.all (fn LAMBDA => true | BinderString {tok,...} => str_unicode_ok tok) 394 bs 395 | SUFFIX TYPE_annotation => true 396 | SUFFIX (STD_suffix rrs) => 397 List.all (fn {elements,...} => List.all pp_unicode_free elements) 398 rrs 399 | INFIX (STD_infix (rrs, _)) => 400 List.all (fn {elements,...} => List.all pp_unicode_free elements) 401 rrs 402 | INFIX (FNAPP rrs) => 403 List.all (fn {elements,...} => List.all pp_unicode_free elements) 404 rrs 405 | INFIX VSCONS => true 406 | INFIX RESQUAN_OP => true 407 | CLOSEFIX rrs => 408 List.all (fn {elements,...} => List.all pp_unicode_free elements) 409 rrs) 410 411fun rule_to_rr rule = 412 case rule of 413 INFIX (STD_infix (slist, _)) => slist 414 | PREFIX (STD_prefix slist) => slist 415 | SUFFIX (STD_suffix slist) => slist 416 | CLOSEFIX slist => slist 417 | _ => [] 418 419(* gives the "wrong" lexicographic order, but is more likely to 420 resolve differences with one comparison because types/terms with 421 the same name are rare, but it's quite reasonable for many 422 types/terms to share the same theory *) 423fun nthy_compare ({Name = n1, Thy = thy1}, {Name = n2, Thy = thy2}) = 424 case String.compare(n1, n2) of 425 EQUAL => String.compare(thy1, thy2) 426 | x => x 427 428val prettyprint_bigrecs = ref true; 429val _ = register_btrace ("pp_bigrecs", prettyprint_bigrecs) 430 431val pp_print_firstcasebar = ref false 432val _ = register_btrace ("PP.print_firstcasebar", pp_print_firstcasebar) 433 434val unfakeconst = Option.map #fake o GrammarSpecials.dest_fakeconst_name 435 436fun atom_name tm = let 437 val (vnm, _) = dest_var tm 438in 439 case unfakeconst vnm of 440 NONE => vnm 441 | SOME s => s 442end handle HOL_ERR _ => fst (dest_const tm) 443 444fun is_fakeconst tm = let 445 val (vnm, _) = dest_var tm 446in 447 String.isPrefix GrammarSpecials.fakeconst_special vnm 448end handle HOL_ERR _ => false 449 450fun is_constish tm = is_const tm orelse is_fakeconst tm 451 452fun pp_term (G : grammar) TyG backend = let 453 val G = #tm_grammar_upd (#extras backend) G 454 val TyG = #ty_grammar_upd (#extras backend) TyG 455 val block = smpp.block 456 fun tystr ty = 457 PP.pp_to_string 10000 458 (fn ty => 459 lower (type_pp.pp_type TyG PPBackEnd.raw_terminal ty) dflt_pinfo 460 |> valOf |> #1) 461 ty 462 val {restr_binders,lambda,endbinding,type_intro,res_quanop} = specials G 463 val overload_info = overload_info G 464 val spec_table = 465 HOLset.addList (HOLset.empty String.compare, grammar_tokens G) 466 val num_info = numeral_info G 467 fun insert ((nopt, grule), acc) = let 468 val keys_n_rules = grule_term_names G grule 469 val n = case nopt of SOME n => n | NONE => 0 (* doesn't matter *) 470 fun sortinsert (tstamp,r) [] = [(n,tstamp,r)] 471 | sortinsert (tstamp,r) ((h as (_,t',r')) :: rest) = 472 if tstamp < t' then h :: sortinsert (tstamp,r) rest 473 else (n,tstamp,r) :: h :: rest 474 fun val_insert (tstamp,r) NONE = [(n,tstamp,r)] 475 | val_insert (tstamp,r) (SOME l) = sortinsert (tstamp,r) l 476 fun myinsert ((k, (tstamp, r)), acc) = let 477 val existing = Binarymap.peek(acc, k) 478 val newvalue = 479 case existing of 480 NONE => [(n,tstamp,r)] 481 | SOME [] => [(n,tstamp,r)] 482 | SOME ((old as (_,t',_))::rest) => 483 if tstamp > t' then (n,tstamp,r)::old::rest 484 else old::(n,tstamp,r)::rest 485 in 486 Binarymap.insert(acc, k, newvalue) 487 end 488 in 489 (List.foldl myinsert acc keys_n_rules) 490 end 491 val rule_table = List.foldl insert 492 (Binarymap.mkDict String.compare) 493 (term_grammar.rules G) 494 fun lookup_term s = Binarymap.peek(rule_table, s) 495 val comb_prec = #1 (hd (valOf (lookup_term fnapp_special))) 496 handle Option => 497 raise PP_ERR "pp_term" "Grammar has no function application" 498 val recsel_info = (* (precedence, upd_tok) option *) 499 case lookup_term recsel_special of 500 SOME [(n, _, INFIX (STD_infix([{elements = [RE(TOK s)],...}], _)))] => 501 SOME (n, s) 502 | SOME _ => 503 raise PP_ERR "pp_term" "Invalid rule for record field select operator" 504 | NONE => NONE 505 val recupd_info = (* (precedence, upd_tok) option *) 506 case lookup_term recupd_special of 507 SOME [(n, _, INFIX (STD_infix([{elements = [RE(TOK s)],...}], _)))] => 508 SOME (Prec(n, recupd_special), s) 509 | SOME _ => 510 raise PP_ERR "pp_term" "Invalid rule for record update operator" 511 | NONE => NONE 512 val recfupd_info = (* (precedence, with_tok) option *) 513 case lookup_term recfupd_special of 514 SOME [(n, _, INFIX (STD_infix([{elements = [RE(TOK s)],...}], _)))] => 515 SOME (Prec(n, recfupd_special), s) 516 | SOME _ => 517 raise PP_ERR "pp_term" "Invalid rule for record f-update operator" 518 | NONE => NONE 519 val recwith_info = (* (precedence, with_tok) option *) 520 case (lookup_term recwith_special) of 521 SOME [(n, _, INFIX (STD_infix([{elements = [RE(TOK s)],...}], _)))] => 522 SOME (n, s) 523 | SOME _ => 524 raise PP_ERR "pp_term" 525 "Invalid form of rule for record with \"operator\"" 526 | NONE => NONE 527 val reclist_info = (* (leftdelim, rightdelim, sep) option *) 528 case lookup_term reccons_special of 529 SOME [(_, _, CLOSEFIX[{elements,...}])] => 530 let 531 fun find_listform pfx els = 532 case els of 533 [] => raise PP_ERR "pp_term" "No list-form in record literal rule" 534 | ListForm{separator,...} :: rest => 535 (List.rev pfx, rest, separator) 536 | e :: rest => find_listform (e::pfx) rest 537 in 538 SOME (find_listform [] elements) 539 end 540 | SOME _ => 541 raise PP_ERR "pp_term" 542 "Invalid form of rule for record update list" 543 | NONE => NONE 544 545 546 val resquan_op_prec = 547 case (lookup_term resquan_special) of 548 SOME [] => raise Fail "term_pp : This really shouldn't happen" 549 | SOME (x::xs) => SOME (#1 x) 550 | NONE => NONE 551 val vscons_prec = #1 (hd (valOf (lookup_term vs_cons_special))) 552 handle Option => 553 raise PP_ERR "pp_term" "Grammar has no vstruct cons" 554 val open_res_list_allowed = 555 case resquan_op_prec of 556 NONE => false 557 | SOME p => p < vscons_prec 558 559 val uprinters = user_printers G 560 val printers_exist = FCNet.size uprinters > 0 561 562 val my_dest_abs = term_pp_utils.pp_dest_abs G 563 val my_is_abs = term_pp_utils.pp_is_abs G 564 565 fun dest_vstruct bndr res t = 566 term_pp_utils.dest_vstruct G {binder = bndr, restrictor = res} t 567 568 569 570 fun strip_vstructs bndr res tm = 571 term_pp_utils.strip_vstructs G {binder = bndr, restrictor = res} tm 572 573 574 datatype comb_posn = RatorCP | RandCP | NoCP 575 576 fun pr_term binderp showtypes showtypes_v ppfns combpos (tm:term) 577 pgrav lgrav rgrav depth apps = 578 let 579 val full_pr_term = pr_term 580 val pr_term = pr_term binderp showtypes showtypes_v ppfns combpos 581 fun pr0 tm = pr_term0 binderp showtypes showtypes_v ppfns combpos tm 582 pgrav lgrav rgrav 583 depth 584 in 585 if printers_exist then 586 let 587 fun sysprint { gravs = (pg,lg,rg), binderp, depth} tm = 588 full_pr_term binderp showtypes showtypes_v ppfns combpos tm 589 pg lg rg depth 590 fun test (pat,_,_) = FCNet.can_match_term pat tm 591 val candidates = filter test (FCNet.match tm uprinters) 592 fun printwith f = f (TyG, G) 593 backend sysprint ppfns 594 (pgrav, lgrav, rgrav) 595 depth tm 596 fun runfirst [] = pr0 tm 597 | runfirst ((_,_,f)::t) = 598 (printwith f 599 handle UserPP_Failed => runfirst t) || runfirst t 600 in 601 runfirst candidates 602 end 603 else pr0 tm 604 end apps 605 and pr_term0 binderp showtypes showtypes_v ppfns combpos tm 606 pgrav lgrav rgrav depth apps = 607 let 608 val full_pr_term = pr_term 609 val pr_term = pr_term binderp showtypes showtypes_v ppfns NoCP 610 val {add_string,add_break,add_xstring,...} = ppfns 611 fun add_ann_string (s,ann) = add_xstring {s=s,ann=SOME ann,sz=NONE} 612 fun var_ann t s = let 613 val (vnm, ty) = dest_var t 614 fun k bvs = 615 add_ann_string(s, 616 ((if HOLset.member(bvs, t) then PPBackEnd.BV 617 else PPBackEnd.FV) 618 (ty, fn () => vnm ^ " :" ^ tystr ty))) 619 in 620 getbvs >- k 621 end 622 623 fun constann t s = let 624 val (Thy,Name,Ty,fake) = let 625 val {Thy,Name,Ty} = dest_thy_const t 626 in 627 (Thy,Name,Ty,Name) 628 end handle HOL_ERR _ => let 629 val (s, ty) = dest_var t 630 in 631 case GrammarSpecials.dest_fakeconst_name s of 632 SOME{original = SOME{Thy,Name},fake} => (Thy,Name,ty,fake) 633 | SOME{original = NONE, fake} => ("", fake, ty, fake) 634 | NONE => raise mk_HOL_ERR "term_pp" "constann" 635 "Called on non-const (fake or o/wise)" 636 end 637 fun isAlphaNum_ish c = Char.isAlphaNum c orelse c = #"'" orelse c = #"_" 638 val constr = if CharVector.all isAlphaNum_ish s then PPBackEnd.Const 639 else PPBackEnd.SymConst 640 in 641 add_ann_string(s, constr {Thy = Thy, Name = Name, Ty = (Ty, fn () => tystr Ty)}) 642 end 643 fun block_by_style (rr, pgrav, fname, fprec) = let 644 val needed = 645 case #1 (#block_style (rr:rule_record)) of 646 AroundSameName => grav_name pgrav <> fname 647 | AroundSamePrec => grav_prec pgrav <> fprec 648 | AroundEachPhrase => true 649 | NoPhrasing => false 650 in 651 if needed then 652 let 653 val (c, i) = #2 (#block_style rr) 654 in 655 block c i 656 end 657 else 658 I 659 end 660 fun paren b p = 661 if b then 662 block INCONSISTENT 1 ( 663 add_string "(" >> (p >- (fn r => add_string ")" >> return r)) 664 ) 665 else p 666 667 fun spacep b = if b then add_break(1, 0) else nothing 668 fun hardspace n = add_string (string_of_nspaces n) 669 fun sizedbreak n = add_break(n, 0) 670 671 fun doTy ty = 672 type_pp.pp_type_with_depth TyG backend (decdepth depth) ty 673 674 (* Prints "elements" from a concrete syntax rule. 675 676 els is the list of pp_elements; 677 args is a list of terms to be inserted in place of RE TM elements; 678 fopt is a term corresponding to the constant (if any) at the head 679 position of the term. 680 681 Returns the unused args *) 682 fun print_ellist fopt (lprec, cprec, rprec) (els, args : term list) = let 683 (* val _ = PRINT 684 ("print_ellist: "^Int.toString (length els)^" elements; "^ 685 " args = [" ^ 686 String.concatWith ", " (map (debugprint G) args) ^ "]") *) 687 fun onetok acc [] = acc 688 | onetok NONE (RE (TOK s) :: rest) = onetok (SOME s) rest 689 | onetok (SOME _) (RE (TOK s) :: rest) = NONE 690 | onetok acc (_ :: rest) = onetok acc rest 691 val tok_string = 692 case (fopt, onetok NONE els) of 693 (SOME f, SOME _) => 694 if is_constish f then constann f else var_ann f 695 | _ => add_string 696 fun recurse (els, args) = 697 case els of 698 [] => return args 699 | (e :: es) => let 700 (* val _ = PRINT ("print_ellist.recurse.cons: "^ 701 Int.toString (length args) ^ " args") *) 702 in 703 case e of 704 PPBlock(more_els, (sty, ind)) => 705 block sty ind (recurse (more_els,args)) >- 706 (fn rest => recurse (es,rest)) 707 | HardSpace n => (hardspace n >> recurse (es, args)) 708 | BreakSpace (n, m) => (add_break(n,m) >> recurse (es, args)) 709 | RE (TOK s) => (tok_string s >> recurse (es, args)) 710 | RE TM => (pr_term (hd args) Top Top Top (decdepth depth) >> 711 recurse (es, tl args)) 712 | RE (ListTM _) => raise Fail "term_pp - encountered (RE ListTM)" 713 | FirstTM => (pr_term (hd args) cprec lprec cprec (decdepth depth) >> 714 recurse (es, tl args)) 715 | LastTM => (pr_term (hd args) cprec cprec rprec (decdepth depth) >> 716 recurse (es, tl args)) 717 | EndInitialBlock _ => raise Fail "term_pp - encountered EIB" 718 | BeginFinalBlock _ => raise Fail "term_pp - encountered BFB" 719 | ListForm lspec => 720 (pr_lspec lspec (hd args) >> recurse (es, tl args)) 721 end 722 and pr_lspec (r as {nilstr, cons, block_info,...}) t = 723 let 724 (* val _ = PRINT ("pr_lspec: "^debugprint G t^" {nilstr=\""^nilstr^ 725 "\"}")*) 726 val sep = #separator r 727 (* val (consistency, breakspacing) = block_info *) 728 (* list will never be empty *) 729 fun pr_list tm = let 730 fun lrecurse depth tm = let 731 val (_, args) = strip_comb tm 732 val head = hd args 733 handle Empty => raise Fail ("pr_list empty list with t = "^ 734 debugprint G t) 735 val tail = List.nth(args, 1) 736 in 737 if depth = 0 then add_string "..." 738 else if has_name_by_parser G nilstr tail then 739 (* last element *) 740 pr_term head Top Top Top (decdepth depth) 741 else let 742 in 743 pr_term head Top Top Top (decdepth depth) >> 744 recurse (sep, []) >> 745 lrecurse (decdepth depth) tail 746 end 747 end 748 in 749 lrecurse depth t 750 end 751 in 752 if has_name_by_parser G nilstr t then return () 753 else pr_list t 754 end 755 in 756 recurse (els, args) (* before 757 PRINT "print_ellist terminated" *) >- (fn _ => return ()) 758 end 759 760 761 762 fun pr_vstruct bv = let 763 val pr_t = 764 if showtypes then full_pr_term true true showtypes_v ppfns NoCP 765 else full_pr_term true false showtypes_v ppfns NoCP 766 in 767 case bv of 768 Simple tm => let 769 in 770 if (is_pair tm orelse is_var tm) then 771 record_bvars (free_vars tm) 772 (pr_t tm Top Top Top (decdepth depth)) 773 else 774 raise PP_ERR "pr_vstruct" 775 "Can only handle pairs and vars as vstructs" 776 end 777 | Restricted{Bvar, Restrictor} => let 778 in 779 block CONSISTENT 0 780 (add_string "(" >> 781 pr_vstruct (Simple Bvar) >> 782 add_string (res_quanop) >> 783 add_break(0,2) >> 784 pr_term Restrictor Top Top Top (decdepth depth) >> 785 add_string ")") 786 end 787 end 788 789 (* this function is only called in circumstances when all of a 790 vstruct list is restricted with the same term and when the 791 relative precedences of the res_quan_op (traditionally "::") is 792 less than that of VSCONS. If this situation pertains, then we 793 can print out all of the vstruct items in a row, and then 794 finish off with a single :: <tm>. For example \x y z::Q. 795 796 The accompanying can_print_vstructl function spots when the 797 situation as described above pertains. 798 799 One final wrinkle has to be dealt with: 800 The restricting term might have an occurrence in it of 801 something that needs to be printed so that it looks like the 802 endbinding token. If this happens, then the restriction needs 803 to be parenthesised. In particular, the standard syntax has 804 "." as the endbinding token and as the infix record selection 805 operator, so that if you write 806 !x y :: (rec.fld1). body 807 the parenthesisation needs to be preserved. 808 809 So, we have one last auxiliary function which determines whether 810 or not the restrictor might print an endbinding token. *) 811 812 infix might_print nmight_print 813 fun tm nmight_print str = let 814 val {Name,...} = dest_thy_const tm 815 val actual_name0 = 816 case overloading_of_term' overload_info tm of 817 NONE => Name 818 | SOME s => s 819 fun testit s = if isPrefix s actual_name0 then SOME s else NONE 820 val actual_name = 821 case find_partial testit [recsel_special, recupd_special, 822 recfupd_special] of 823 NONE => actual_name0 824 | SOME s => s 825 val rule = lookup_term actual_name 826 in 827 case rule of 828 NONE => Name = str 829 | SOME rrlist => 830 List.exists (mem str o term_grammar.rule_tokens G o #3) rrlist 831 end 832 833 fun tm might_print str = 834 case (dest_term tm) of 835 COMB(Rator, Rand) => Rator might_print str orelse Rand might_print str 836 | LAMB(_,Body) => Body might_print str 837 | VAR(Name,Ty) => Name = str 838 | CONST x => tm nmight_print str 839 840 841 fun pr_res_vstructl restrictor res_op vsl body = let 842 val bvts = map bv2term vsl 843 val simples = map Simple bvts 844 val add_final_parens = restrictor might_print endbinding 845 in 846 block CONSISTENT 2 ( 847 block INCONSISTENT 2 (pr_list pr_vstruct (add_break(1,0)) simples) >> 848 add_string res_op >> 849 paren add_final_parens ( 850 pr_term restrictor Top Top Top (decdepth depth) 851 ) 852 ) >> 853 add_string endbinding >> add_break (1,0) >> 854 record_bvars (free_varsl bvts) 855 (block CONSISTENT 0 856 (pr_term body Top Top Top (decdepth depth))) 857 end 858 fun can_print_vstructl vsl = let 859 fun recurse acc _ [] = SOME acc 860 | recurse acc _ ((Simple _)::_) = NONE 861 | recurse acc bvs (Restricted{Restrictor = t,Bvar}::xs) = let 862 in 863 if aconv t acc andalso List.all (fn v => not (free_in v t)) bvs then 864 recurse acc (Bvar::bvs) xs 865 else NONE 866 end 867 in 868 case vsl of 869 [] => raise PP_ERR "can_print_vstructl" "Empty list!" 870 | (Simple _::xs) => NONE 871 | (Restricted{Restrictor = t,Bvar}::xs) => recurse t [Bvar] xs 872 end 873 874 (* the pr_vstructl function figures out which way to print a given 875 list of vstructs *) 876 fun pr_vstructl vsl b = 877 case can_print_vstructl vsl of 878 SOME r => pr_res_vstructl r res_quanop vsl b 879 | _ => 880 let 881 fun recurse [] = raise Fail "pr_vstructl.recurse: Empty List!" 882 | recurse [bv] = 883 pr_vstruct bv >> add_string endbinding >> add_break (1,0) >> 884 record_bvars (free_vars (bv2term bv)) 885 (block CONSISTENT 0 886 (pr_term b Top Top Top (decdepth depth))) 887 | recurse (bv::rest) = 888 pr_vstruct bv >> add_break (1,0) >> 889 record_bvars (free_vars (bv2term bv)) (recurse rest) 890 in 891 block INCONSISTENT 2 (recurse vsl) 892 end 893 894 fun pr_abs tm = let 895 val addparens = lgrav <> RealTop orelse rgrav <> RealTop 896 val restr_binder = 897 find_partial (fn (b,s) => if b = NONE then SOME s else NONE) 898 restr_binders 899 val (bvars, body) = strip_vstructs NONE restr_binder tm 900 val bvars_seen_here = List.concat (map (free_vars o bv2term) bvars) 901 val lambda' = if current_trace "PP.avoid_unicode" > 0 then 902 List.filter str_unicode_ok lambda 903 else lambda 904 val tok = case lambda' of 905 [] => raise PP_ERR "pr_abs" "No token for lambda abstraction" 906 | h::_ => h 907 in 908 paren addparens 909 (block CONSISTENT 2 (add_string tok >> pr_vstructl bvars body)) 910 end 911 912 fun can_pr_numeral stropt = List.exists (fn (k,s') => s' = stropt) num_info 913 fun pr_numeral injtermopt tm = let 914 open Overload 915 val numty = Type.mk_thy_type {Tyop="num", Thy="num", Args=[]} 916 val num2numty = numty --> numty 917 val numinfo_search_string = Option.map (fst o dest_const) injtermopt 918 val inj_t = 919 case injtermopt of 920 NONE => mk_thy_const {Name = nat_elim_term, Thy = "arithmetic", 921 Ty = numty --> numty} 922 | SOME t => t 923 val injty = type_of inj_t 924 val is_a_real_numeral = (* i.e. doesn't need a suffix *) 925 case info_for_name overload_info fromNum_str of 926 NONE => false 927 | SOME oi => op_mem aconv inj_t (#actual_ops oi) 928 val numeral_str = Arbnum.toString (Literal.dest_numeral tm) 929 val sfx = 930 if not is_a_real_numeral orelse !Globals.show_numeral_types then let 931 val (k, _) = 932 valOf (List.find (fn (_, s') => s' = numinfo_search_string) 933 num_info) 934 in 935 str k 936 end 937 else "" 938 in 939 paren showtypes ( 940 add_ann_string (numeral_str ^ sfx, 941 PPBackEnd.Literal PPBackEnd.NumLit) >> 942 (if showtypes then 943 add_string (" "^type_intro) >> add_break (0,0) >> 944 doTy (#2 (dom_rng injty)) 945 else nothing) 946 ) 947 end 948 949 exception NotReallyARecord 950 951 fun check_for_field_selection t1 t2 = let 952 fun getfldname s = 953 if isSome recsel_info then 954 if isPrefix recsel_special s then 955 SOME (String.extract(s, size recsel_special, NONE), t2) 956 else if is_substring bigrec_subdivider_string s andalso 957 !prettyprint_bigrecs 958 then let 959 open Overload 960 val brss = bigrec_subdivider_string 961 val (f, x) = dest_comb t2 962 val _ = is_const f orelse raise NotReallyARecord 963 val fname = valOf (overloading_of_term overload_info f) 964 val _ = is_substring (brss ^ "sf") fname orelse 965 raise NotReallyARecord 966 open Substring 967 val (_, brsssguff) = position brss (full s) 968 val dropguff = slice(brsssguff, String.size brss, NONE) 969 val dropdigits = dropl Char.isDigit dropguff 970 val fldname = string(slice(dropdigits, 1, NONE)) 971 in 972 SOME (fldname, x) 973 end handle HOL_ERR _ => NONE 974 | NotReallyARecord => NONE 975 | Option => NONE 976 else NONE 977 else NONE 978 in 979 if is_const t1 orelse is_fakeconst t1 then 980 case grammar_name G t1 of 981 SOME s => let 982 val fldname = getfldname s 983 in 984 case fldname of 985 SOME(fldname, t2) => let 986 val (prec0, fldtok) = valOf recsel_info 987 (* assumes that field selection is always left associative *) 988 val add_l = 989 case lgrav of 990 Prec(n, _) => n >= prec0 991 | _ => false 992 val add_r = 993 case rgrav of 994 Prec(n, _) => n > prec0 995 | _ => false 996 val prec = Prec(prec0, recsel_special) 997 val add_parens = add_l orelse add_r 998 val lprec = if add_parens then Top else lgrav 999 open PPBackEnd 1000 in 1001 block INCONSISTENT 0 ( 1002 paren add_parens ( 1003 pr_term t2 prec lprec prec (decdepth depth) >> 1004 add_string fldtok >> 1005 add_break(0,0) >> 1006 add_ann_string (fldname, Literal FldName) 1007 ) 1008 ) 1009 end 1010 | NONE => fail 1011 end 1012 | NONE => fail 1013 else fail 1014 end 1015 1016 fun check_for_record_update wholetm t1 t2 = 1017 if isSome recwith_info andalso isSome reclist_info andalso 1018 isSome recfupd_info andalso isSome recupd_info 1019 then let 1020 open Overload 1021 fun ap1 t = let val (d,_) = dom_rng (type_of t) 1022 in mk_comb(t,genvar d) end 1023 fun ap2 t = t |> ap1 |> ap1 1024 val fupdhelper = Option.map (atom_name o #1) o 1025 Overload.oi_strip_comb overload_info 1026 fun fupdstr0 wholetm_opt t = 1027 case wholetm_opt of 1028 NONE => t |> ap2 |> fupdhelper 1029 | SOME t => t |> fupdhelper 1030 fun fupdstr wholetm_opt = 1031 Option.join o Lib.total (fupdstr0 wholetm_opt) 1032 (* function to determine if t is a record update *) 1033 fun is_record_update wholetm_opt t = 1034 if is_comb t andalso is_const (rator t) then 1035 case fupdstr wholetm_opt (rator t) of 1036 SOME s => 1037 (!prettyprint_bigrecs andalso isSuffix "_fupd" s andalso 1038 is_substring (bigrec_subdivider_string ^ "sf") s) orelse 1039 isPrefix recfupd_special s 1040 | NONE => false 1041 else false 1042 (* descend the rands of a term until one that is not a record 1043 update is found. Return this and the list of rators up to 1044 this point. *) 1045 fun find_first_non_update acc t = 1046 if is_comb t andalso is_record_update NONE (rator t) then 1047 find_first_non_update ((rator t)::acc) (rand t) 1048 else 1049 (List.rev acc, t) 1050 fun categorise_bigrec_updates v = let 1051 fun bigrec_update t = 1052 if is_comb t then 1053 case fupdstr NONE (rator t) of 1054 SOME s => if is_substring bigrec_subdivider_string s then 1055 SOME (s, rand t) 1056 else NONE 1057 | NONE => NONE 1058 else NONE 1059 fun strip_o acc tlist = 1060 case tlist of 1061 [] => acc 1062 | t::ts => let 1063 val (f, args) = strip_comb t 1064 val {Name,Thy,...} = dest_thy_const f 1065 in 1066 if Name = "o" andalso Thy = "combin" then 1067 strip_o acc (hd (tl args) :: hd args :: ts) 1068 else strip_o (t::acc) ts 1069 end handle HOL_ERR _ => strip_o (t::acc) ts 1070 fun strip_bigrec_updates t = let 1071 val internal_upds = strip_o [] [t] 1072 in 1073 List.mapPartial bigrec_update internal_upds 1074 end 1075 fun categorise_bigrec_update (s, value) = let 1076 (* first strip suffix, and decide if a normal update *) 1077 val sz = size s 1078 val (s, value, value_upd) = let 1079 (* suffix will be "_fupd" *) 1080 val (f, x) = dest_comb value 1081 val {Thy, Name, ...} = dest_thy_const f 1082 in 1083 if Thy = "combin" andalso Name = "K" then 1084 (String.extract(s, 0, SOME (sz - 5)), x, true) 1085 else 1086 (String.extract(s, 0, SOME (sz - 5)), value, false) 1087 end handle HOL_ERR _ => 1088 (String.extract(s,0,SOME (sz - 5)), value, false) 1089 1090 val ss = Substring.full s 1091 val (_, ss) = (* drop initial typename *) 1092 Substring.position bigrec_subdivider_string ss 1093 val ss = (* drop bigrec_subdivider_string *) 1094 Substring.slice(ss, size bigrec_subdivider_string, NONE) 1095 val ss = (* drop subrecord number *) 1096 Substring.dropl Char.isDigit ss 1097 val ss = (* drop underscore before field name *) 1098 Substring.slice(ss, 1, NONE) 1099 in 1100 (Substring.string ss, value, value_upd) 1101 end handle Subscript => raise NotReallyARecord 1102 in 1103 map categorise_bigrec_update (strip_bigrec_updates v) 1104 end 1105 fun categorise_update t = let 1106 (* t is an update, possibly a bigrec monster. Here we generate 1107 a list of real updates (i.e., the terms corresponding to the 1108 new value in the update), each with an accompanying field 1109 string, and a boolean, which is true iff the update is a value 1110 update (not a "fupd") *) 1111 val (fld, value) = dest_comb t 1112 val rname = valOf (fupdstr NONE fld) 1113 in 1114 if isPrefix recfupd_special rname then let 1115 val (f, x) = dest_comb value 1116 val {Thy, Name,...} = dest_thy_const f 1117 val fldname = String.extract(rname,size recfupd_special, NONE) 1118 in 1119 if Thy = "combin" andalso Name = "K" then [(fldname, x, true)] 1120 else [(fldname, value, false)] 1121 end handle HOL_ERR _ => 1122 [(String.extract(rname,size recfupd_special, NONE), 1123 value, false)] 1124 else (* is a big record - examine value *) 1125 assert (not o null) (categorise_bigrec_updates value) 1126 handle HOL_ERR _ => raise NotReallyARecord 1127 end 1128 in 1129 if is_record_update (SOME wholetm) t1 then let 1130 val (updates0, base) = find_first_non_update [] t2 1131 val updates = List.concat (map categorise_update (t1::updates0)) 1132 val (with_prec, with_tok) = valOf recwith_info 1133 val (ldelim, rdelim, sep) = valOf reclist_info 1134 fun print_update depth (fld, value, normal_upd) = let 1135 val (upd_prec, updtok) = 1136 if normal_upd then valOf recupd_info 1137 else valOf recfupd_info 1138 in 1139 block INCONSISTENT 2 1140 (add_ann_string 1141 (fld, PPBackEnd.Literal PPBackEnd.FldName) >> 1142 add_string " " >> 1143 add_string updtok >> 1144 add_break(1,0) >> 1145 pr_term value upd_prec upd_prec Top (decdepth depth)) 1146 end 1147 fun print_updlist updates = let 1148 fun recurse depth upds = 1149 if depth = 0 then add_string "..." 1150 else 1151 case upds of 1152 [] => nothing (* should never happen *) 1153 | [u] => print_update (decdepth depth) u 1154 | u::us => (print_update (decdepth depth) u >> 1155 print_ellist NONE (Top,Top,Top) (sep, []) >> 1156 recurse (decdepth depth) us) 1157 val ldelim_size = ellist_size ldelim 1158 in 1159 print_ellist NONE (Top,Top,Top) (ldelim, []) >> 1160 block INCONSISTENT ldelim_size (recurse depth updates) >> 1161 print_ellist NONE (Top,Top,Top) (rdelim, []) >> 1162 nothing 1163 end 1164 in 1165 if is_const base andalso fst (dest_const base) = "ARB" then 1166 print_updlist updates 1167 else let 1168 val add_l = 1169 case lgrav of 1170 Prec(n, _) => n > with_prec 1171 | _ => false 1172 val add_r = 1173 case rgrav of 1174 Prec(n, _) => n > with_prec 1175 | _ => false 1176 val addparens = add_l orelse add_r 1177 val lprec = if addparens then Top else lgrav 1178 val with_grav = Prec(with_prec, recwith_special) 1179 in 1180 paren addparens ( 1181 block INCONSISTENT 0 ( 1182 pr_term base with_grav lprec with_grav (decdepth depth) >> 1183 add_string " " >> 1184 add_string with_tok >> 1185 add_break (1,0) >> 1186 (if length updates = 1 then print_update depth (hd updates) 1187 else print_updlist updates) 1188 ) 1189 ) 1190 end 1191 end handle NotReallyARecord => fail 1192 else fail 1193 end 1194 else fail 1195 1196 fun comb_show_type (f, args) = let 1197 val _ = (showtypes andalso combpos <> RatorCP) orelse raise PP_ERR "" "" 1198 1199 (* find out how the printer will map this constant into a string, 1200 and then see how this string maps back into constants. The 1201 base_type will encompass the simulated polymorphism of the 1202 overloading system as well as any genuine polymorphism in 1203 the underlying constant. *) 1204 val base_ty = let 1205 in 1206 if is_fakeconst f then let 1207 (* f prints to the atom-name *) 1208 val nm = atom_name f 1209 in 1210 #base_type (valOf (Overload.info_for_name overload_info nm)) 1211 end 1212 else 1213 case overloading_of_term' overload_info f of 1214 NONE => let 1215 val {Thy,Name,Ty} = dest_thy_const f 1216 in 1217 type_of (prim_mk_const {Thy = Thy, Name = Name}) 1218 end 1219 | SOME print_name => 1220 #base_type 1221 (valOf (Overload.info_for_name overload_info print_name)) 1222 end 1223 val base_ptyM = Pretype.rename_typevars [] (Pretype.fromType base_ty) 1224 open errormonad 1225 fun foldthis (tm,acc) = let 1226 open Pretype 1227 val fn_ptyM = lift (fn ty => mk_fun_ty(fromType (type_of tm), ty)) 1228 new_uvar 1229 in 1230 acc >- (fn ty1 => fn_ptyM >- (fn ty2 => unify ty1 ty2 >> chase ty1)) 1231 end 1232 val resultM = List.foldl foldthis base_ptyM args 1233 in 1234 case (resultM >- Pretype.has_unbound_uvar) Pretype.Env.empty of 1235 Error _ => false 1236 | Some (_, b) => b 1237 end handle HOL_ERR _ => false 1238 | Option => false 1239 1240 fun pr_comb tm t1 t2 = let 1241 val add_l = 1242 case lgrav of 1243 Prec (n, _) => (n >= comb_prec) 1244 | _ => false 1245 val add_r = 1246 case rgrav of 1247 Prec (n, _) => (n > comb_prec) 1248 | _ => false 1249 val addparens = add_l orelse add_r 1250 1251 val (f, args) = strip_comb tm 1252 val comb_show_type = comb_show_type(f,args) 1253 val prec = Prec(comb_prec, fnapp_special) 1254 val lprec = if addparens then Top else lgrav 1255 val rprec = if addparens then Top else rgrav 1256 in 1257 paren (addparens orelse comb_show_type) ( 1258 block INCONSISTENT 0 ( 1259 full_pr_term binderp showtypes showtypes_v ppfns RatorCP t1 1260 prec lprec prec (decdepth depth) >> 1261 add_break (1, 2) >> 1262 full_pr_term binderp showtypes showtypes_v ppfns RandCP t2 1263 prec prec rprec (decdepth depth) >> 1264 (if comb_show_type then 1265 add_string (" "^type_intro) >> add_break (0,0) >> 1266 doTy (type_of tm) 1267 else nothing) 1268 ) 1269 ) 1270 end 1271 1272 fun pr_sole_name tm n rules = let 1273 (* This function prints a solitary name n. The rules are possibly 1274 relevant rules from the grammar. If one is a list rule, and our 1275 n is the name of the nil case, then we should print that 1276 list's delimiters around nothing. 1277 Otherwise, the presence of a rule with our name n in it, is a 1278 probable indication that our name will need a $ printed out in 1279 front of it. *) 1280 (* val _ = PRINT ("pr_sole_name: "^debugprint G tm) *) 1281 fun check_rule rule = 1282 case rule of 1283 CLOSEFIX [{elements,...}] => 1284 (case find_lspec elements of 1285 NONE => NONE 1286 | SOME{nilstr,...} => if nilstr = n then SOME elements else NONE) 1287 | _ => NONE 1288 val nilrule = find_partial check_rule rules 1289 val ty = type_of tm 1290 fun add s = 1291 if is_constish tm then constann tm s 1292 else var_ann tm s 1293 in 1294 case nilrule of 1295 SOME els => (* (PRINT ("Found a nil-rule for "^n); *) 1296 print_ellist NONE (Top,Top,Top) (els, [tm]) >> return () 1297 | NONE => let 1298 (* if only rule is a list form rule and we've got to here, it 1299 will be a rule allowing this to the cons part of a list form. 1300 Such functions don't need to be dollar-ed *) 1301 in 1302 if HOLset.member(spec_table, n) then dollarise add add_string n 1303 else add n 1304 end 1305 end 1306 1307 1308 fun pr_comb_with_rule frule fterm args Rand = let 1309 val {fname,fprec,f} = fterm 1310 val comb_show_type = comb_show_type(f,args @ [Rand]) 1311 fun ptype_block p = 1312 if comb_show_type then 1313 paren true ( 1314 block CONSISTENT 0 ( 1315 p >- 1316 (fn r => add_break (1,2) >> add_string type_intro >> 1317 doTy (type_of tm) >> return r) 1318 ) 1319 ) 1320 else p 1321 fun block_up_els acc els = 1322 case els of 1323 [] => List.rev acc 1324 | (e::es) => let 1325 in 1326 case e of 1327 EndInitialBlock bi => 1328 block_up_els [PPBlock(List.rev acc, bi)] es 1329 | BeginFinalBlock bi => let 1330 val block_of_rest = block_up_els [] es 1331 in 1332 List.rev (PPBlock(block_of_rest, bi)::acc) 1333 end 1334 | x => block_up_els (x::acc) es 1335 end 1336 in 1337 case frule of 1338 INFIX(STD_infix(lst, fassoc)) => let 1339 val rr = hd lst 1340 val elements = #elements rr 1341 fun check_grav a grav = 1342 case grav of 1343 Prec(n, _) => 1344 (n > fprec) orelse (n = fprec andalso a <> fassoc) 1345 | _ => false 1346 val parens_needed_outright = 1347 check_grav RIGHT lgrav orelse check_grav LEFT rgrav 1348 val parens_needed_by_style = 1349 pneeded_by_style(rr, pgrav, fname, fprec) 1350 val addparens = parens_needed_outright orelse parens_needed_by_style 1351 val prec = Prec(fprec, fname) 1352 val lprec = if addparens then Top else lgrav 1353 val rprec = if addparens then Top else rgrav 1354 val arg_terms = args @ [Rand] 1355 val pp_elements = block_up_els [] ((FirstTM::elements) @ [LastTM]) 1356 val begblock = block_by_style(rr, pgrav, fname, fprec) 1357 in 1358 ptype_block ( 1359 paren (addparens orelse comb_show_type) ( 1360 begblock 1361 (print_ellist (SOME f) 1362 (lprec, prec, rprec) 1363 (pp_elements, arg_terms)) 1364 ) 1365 ) 1366 end 1367 | INFIX RESQUAN_OP => raise Fail "Res. quans shouldn't arise" 1368 | INFIX (FNAPP _) => raise PP_ERR "pr_term" "fn apps can't arise" 1369 | INFIX VSCONS => raise PP_ERR "pr_term" "vs cons can't arise" 1370 | SUFFIX (STD_suffix lst) => let 1371 val rr = hd lst 1372 val elements = #elements rr 1373 val parens_needed_outright = 1374 case lgrav of 1375 Prec(n, _) => n > fprec 1376 | _ => false 1377 val parens_needed_by_style = 1378 pneeded_by_style (rr, pgrav, fname, fprec) 1379 val addparens = parens_needed_outright orelse parens_needed_by_style 1380 val lprec = if addparens then Top else lgrav 1381 val prec = Prec(fprec, fname) 1382 val real_args = args @ [Rand] 1383 val pp_elements = block_up_els [] (FirstTM :: elements) 1384 val begblock = 1385 block_by_style(rr, pgrav, fname, fprec) 1386 in 1387 ptype_block ( 1388 paren (addparens orelse comb_show_type) ( 1389 begblock ( 1390 print_ellist (SOME f) 1391 (lprec, prec, Top) 1392 (pp_elements, real_args) 1393 ) 1394 ) 1395 ) 1396 end 1397 | SUFFIX TYPE_annotation => 1398 raise Fail "Type annotation shouldn't arise" 1399 | PREFIX (STD_prefix lst) => let 1400 val rr = hd lst 1401 val elements = #elements rr 1402 val parens_needed_outright = 1403 case rgrav of 1404 Prec(n, _) => n > fprec 1405 | _ => false 1406 val addparens = 1407 parens_needed_outright orelse 1408 pneeded_by_style(rr, pgrav, fname, fprec) orelse 1409 (combpos = RandCP andalso #paren_style rr <> NotEvenIfRand) 1410 val rprec = if addparens then Top else rgrav 1411 val pp_elements = block_up_els [] (elements @ [LastTM]) 1412 val real_args = args @ [Rand] 1413 val prec = Prec(fprec, fname) 1414 val begblock = block_by_style(rr, pgrav, fname, fprec) 1415 in 1416 ptype_block ( 1417 paren (addparens orelse comb_show_type) ( 1418 begblock ( 1419 print_ellist (SOME f) 1420 (Top, prec, rprec) 1421 (pp_elements, real_args) 1422 ) 1423 ) 1424 ) 1425 end 1426 | PREFIX (BINDER lst) => let 1427 val tok = case hd lst of 1428 LAMBDA => hd lambda (* should never happen *) 1429 | BinderString r => #tok r 1430 fun find (bopt, s) = if bopt = SOME fname then SOME s else NONE 1431 val restr_binder = find_partial find restr_binders 1432 val (bvs, body) = strip_vstructs (SOME fname) restr_binder tm 1433 val bvars_seen_here = List.concat (map (free_vars o bv2term) bvs) 1434 val addparens = 1435 case rgrav of 1436 Prec(n, _) => n > fprec 1437 | _ => false 1438 val addparens = addparens orelse combpos = RandCP 1439 val print_tok = if is_constish f then constann f tok 1440 else var_ann f tok 1441 in 1442 ptype_block ( 1443 paren (addparens orelse comb_show_type) ( 1444 block INCONSISTENT 2 (print_tok >> pr_vstructl bvs body) 1445 ) 1446 ) 1447 end 1448 | CLOSEFIX lst => let 1449 val rr = hd lst 1450 val elements = #elements rr 1451 in 1452 ptype_block 1453 (uncurry block (#2 (#block_style rr)) 1454 (print_ellist (SOME f) 1455 (Top, Top, Top) 1456 (elements, args @ [Rand]) >> 1457 return ())) 1458 end 1459 end 1460 1461 fun print_ty_antiq tm = let 1462 val ty = parse_type.dest_ty_antiq tm 1463 in 1464 block CONSISTENT 2 1465 (add_string "(ty_antiq(" >> 1466 add_break(0,0) >> 1467 add_string "`:" >> 1468 doTy ty >> 1469 add_string "`))") 1470 end 1471 1472 (* used to determine whether or not to print out disambiguating type 1473 information when showtypes_v is true *) 1474 fun const_is_polymorphic c = 1475 if is_const c then let 1476 val {Name,Thy,Ty} = dest_thy_const c 1477 val genconst = prim_mk_const {Name=Name,Thy=Thy} 1478 in 1479 Type.polymorphic (type_of genconst) 1480 end handle HOL_ERR _ => false 1481 (* the exception is possible if the constant is out of date *) 1482 else if is_fakeconst c then 1483 case Overload.info_for_name overload_info (atom_name c) of 1484 NONE => (* peculiar, printing but not parsing *) true 1485 | SOME {base_type,...} => Type.polymorphic base_type 1486 else false 1487 1488 fun const_has_multi_ovl tm = 1489 case overloading_of_term' overload_info tm of 1490 NONE => (* no printing form *) true 1491 | SOME s => 1492 case Overload.info_for_name overload_info s of 1493 NONE => true (* seems pretty unlikely *) 1494 | SOME {actual_ops,...} => length actual_ops > 1 1495 1496 fun const_is_ambiguous t = 1497 const_is_polymorphic t orelse const_has_multi_ovl t 1498 1499 in 1500 if depth = 0 then add_string "..." 1501 else if parse_type.is_ty_antiq tm then print_ty_antiq tm 1502 else 1503 case dest_term tm of 1504 VAR(vname, Ty) => let 1505 val (isfake, vname) = 1506 (true, valOf (unfakeconst vname)) 1507 handle Option => (false, vname) 1508 val vrule = lookup_term vname 1509 val add_type= 1510 add_string (" "^type_intro) >> add_break(0,0) >> doTy Ty 1511 fun new_freevar ({seen_frees,current_bvars,...}:printing_info) = 1512 showtypes andalso not isfake andalso 1513 not (HOLset.member(seen_frees, tm)) andalso 1514 not (HOLset.member(current_bvars, tm)) andalso not binderp 1515 fun calc_print_type nfv = 1516 showtypes_v orelse 1517 showtypes andalso not isfake andalso (binderp orelse nfv) 1518 val adds = 1519 if is_constish tm then constann tm else var_ann tm 1520 in 1521 fupdate (fn x => x) >- return o new_freevar >- 1522 (fn is_new => 1523 (if is_new then spotfv tm else nothing) >> 1524 return (calc_print_type is_new)) >- 1525 (fn print_type => 1526 block INCONSISTENT 2 ( 1527 paren print_type ( 1528 (if isSome vrule then 1529 pr_sole_name tm vname (map #3 (valOf vrule)) 1530 else 1531 if HOLset.member(spec_table, vname) then 1532 dollarise adds add_string vname 1533 else adds vname) >> 1534 (if print_type then add_type else nothing) 1535 ) 1536 ) 1537 ) 1538 end 1539 | CONST(c as {Name, Thy, Ty}) => let 1540 val add_ann_string = constann tm 1541 fun add_prim_name() = add_ann_string (Thy ^ "$" ^ Name) 1542 fun with_type action = let 1543 in 1544 if Name = "the_value" andalso Thy = "bool" then action() 1545 else 1546 paren true (action() >> add_string (" "^type_intro) >> doTy Ty) 1547 end 1548 val r = {Name = Name, Thy = Thy} 1549 fun normal_const () = let 1550 fun cope_with_rules s = let 1551 val crules = 1552 Option.map (List.filter (is_unicode_ok_rule o #3)) 1553 (lookup_term s) 1554 open PPBackEnd 1555 in 1556 if isSome crules then 1557 pr_sole_name tm s (map #3 (valOf crules)) 1558 else if s = "0" andalso can_pr_numeral NONE then 1559 pr_numeral NONE tm 1560 else if Literal.is_emptystring tm then 1561 add_xstring {s="\"\"", sz = NONE, 1562 ann = SOME (Literal StringLit)} 1563 else add_ann_string s 1564 end 1565 in 1566 if Name = "the_value" andalso Thy = "bool" then let 1567 val {Args,...} = dest_thy_type Ty 1568 in (* TODO: annotate all of this as the constant somehow *) 1569 add_string "(" >> 1570 block CONSISTENT 0 (add_string type_intro >> doTy (hd Args)) >> 1571 add_string ")" 1572 end 1573 else 1574 case overloading_of_term' overload_info tm of 1575 NONE => add_prim_name() 1576 | SOME s => 1577 (* term is overloaded *) 1578 if s = "case" then cope_with_rules Name 1579 else cope_with_rules s 1580 end 1581 in 1582 case (showtypes_v, const_is_polymorphic tm, const_has_multi_ovl tm) of 1583 (true, false, true) => add_prim_name() 1584 | (true, true, true) => with_type add_prim_name 1585 | (true, true, false) => with_type normal_const 1586 | _ => if !show_types andalso combpos <> RatorCP andalso 1587 const_is_polymorphic tm 1588 then 1589 with_type normal_const 1590 else normal_const() 1591 end 1592 | COMB(Rator, Rand) => let 1593 val (f, args) = strip_comb Rator 1594 val (oif, oiargs, overloadedp) = 1595 case oi_strip_comb' overload_info tm of 1596 NONE => (f, args @ [Rand], false) 1597 | SOME (f, args) => (f, args, true) 1598 1599 fun check_for_setcomprehensions () = 1600 if grammar_name G oif = SOME "GSPEC" andalso my_is_abs Rand 1601 then let 1602 val (vs, body) = my_dest_abs Rand 1603 val vfrees = FVL [vs] empty_tmset 1604 val bvars_seen_here = HOLset.listItems vfrees 1605 1606 val (l, r) = dest_pair body 1607 val lfrees = FVL [l] empty_tmset 1608 val rfrees = FVL [r] empty_tmset 1609 open HOLset 1610 in 1611 if ((equal(intersection(lfrees,rfrees), vfrees) orelse 1612 (isEmpty lfrees andalso equal(rfrees, vfrees)) orelse 1613 (isEmpty rfrees andalso equal(lfrees, vfrees))) 1614 andalso !unamb_comp = 0) orelse 1615 !unamb_comp = 2 1616 then 1617 block CONSISTENT 0 1618 (record_bvars bvars_seen_here 1619 (set_gspec 1620 (add_string "{" >> 1621 block CONSISTENT 0 1622 (pr_term l Top Top Top (decdepth depth) >> 1623 hardspace 1 >> add_string "|" >> spacep true >> 1624 pr_term r Top Top Top (decdepth depth)) >> 1625 add_string "}"))) 1626 else 1627 block CONSISTENT 0 1628 (record_bvars bvars_seen_here 1629 (set_gspec 1630 (add_string "{" >> 1631 block CONSISTENT 0 1632 (pr_term l Top Top Top (decdepth depth) >> 1633 hardspace 1 >> add_string "|" >> spacep true >> 1634 pr_term vs Top Top Top (decdepth depth) >> 1635 hardspace 1 >> add_string "|" >> spacep true >> 1636 pr_term r Top Top Top (decdepth depth)) >> 1637 add_string "}"))) 1638 end handle HOL_ERR _ => fail 1639 else fail 1640 1641 fun is_atom tm = is_const tm orelse is_var tm 1642 fun pr_atomf (f,args0) = let 1643 (* the tm, Rator and Rand bindings that we began with are 1644 overridden by the f and args values that may be the product of 1645 oi_strip_comb.*) 1646 val fname = atom_name f 1647 (* val _ = PRINT ("pr_atomf: "^fname^" and "^ 1648 Int.toString (length args0) ^ " args") *) 1649 val tm = list_mk_comb (f, args0) 1650 val Rator = rator tm 1651 val (args,Rand) = front_last args0 1652 val candidate_rules = 1653 Option.map (List.filter (is_unicode_ok_rule o #3)) 1654 (lookup_term fname) 1655 (* val _ = PRINT ("pr_atomf: "^debugprint G tm^", "^ 1656 (case candidate_rules of 1657 NONE => "rules = NONE" 1658 | SOME l => 1659 Int.toString (length l)^ " candidate rules")) 1660 *) 1661 1662 1663 val restr_binder = 1664 find_partial (fn (b,s) => if s=fname then SOME b else NONE) 1665 restr_binders 1666 val restr_binder_rule = 1667 if isSome restr_binder andalso length args = 1 andalso 1668 my_is_abs Rand 1669 then let 1670 val bindex = case valOf restr_binder of 1671 NONE => binder_to_string G LAMBDA 1672 | SOME s => s 1673 val optrule = Option.map (List.filter (is_unicode_ok_rule o #3)) 1674 (lookup_term bindex) 1675 fun ok_rule (_, _, r) = 1676 case r of 1677 PREFIX(BINDER b) => true 1678 | otherwise => false 1679 in 1680 case optrule of 1681 SOME (r::_) => if ok_rule r then SOME r else NONE 1682 | otherwise => NONE 1683 end 1684 else NONE 1685 fun check_rrec_args f rrec args = 1686 let 1687 val rels = f (rule_elements (#elements rrec)) 1688 (*val _ = PRINT ("check_rrec_args: rels = [" ^ 1689 String.concatWith ", " (map reltoString rels) ^ 1690 "]; args = [" ^ 1691 String.concatWith ", " (map (debugprint G) args)^ 1692 "]")*) 1693 fun recurse rels args = 1694 case (rels, args) of 1695 ([], []) => true 1696 | ([], _) => false 1697 | (TM :: rrest, _ :: arest) => recurse rrest arest 1698 | (TOK _ :: rrest, _) => recurse rrest args 1699 | (_, []) => false 1700 | (ListTM {nilstr,cons,...} :: rrest, a :: arest) => 1701 is_list G {nilstr=nilstr,cons=cons} a andalso 1702 recurse rrest arest 1703 in 1704 recurse rels args 1705 end 1706 in 1707 case candidate_rules of 1708 NONE => 1709 let 1710 in 1711 case restr_binder of 1712 NONE => pr_comb tm Rator Rand 1713 | SOME NONE => 1714 if isSome restr_binder_rule then pr_abs tm 1715 else pr_comb tm Rator Rand 1716 | SOME (SOME fname) => 1717 if isSome restr_binder_rule then 1718 pr_comb_with_rule(#3(valOf restr_binder_rule)) 1719 {fprec = #1 (valOf restr_binder_rule), 1720 fname = fname, 1721 f = f} args Rand 1722 else 1723 pr_comb tm Rator Rand 1724 end 1725 | SOME crules0 => 1726 let 1727 datatype ruletype = Norm of (int * grammar_rule) 1728 | List of pp_element list 1729 fun suitable_rule (prec, _, rule) = 1730 case rule of 1731 INFIX(STD_infix(rrlist, _)) => 1732 if check_rrec_args mkrels_infix (hd rrlist) args0 then 1733 SOME (Norm(prec, rule)) 1734 else NONE 1735 | INFIX RESQUAN_OP => raise Fail "Can't happen 90212" 1736 | PREFIX (STD_prefix list) => 1737 if check_rrec_args mkrels_prefix (hd list) args0 then 1738 SOME (Norm (prec, rule)) 1739 else NONE 1740 | PREFIX (BINDER _) => 1741 if my_is_abs Rand andalso length args = 0 then 1742 SOME (Norm(prec, rule)) 1743 else NONE 1744 | SUFFIX (STD_suffix list) => 1745 if check_rrec_args mkrels_suffix (hd list) args0 then 1746 SOME (Norm(prec, rule)) 1747 else NONE 1748 | SUFFIX Type_annotation => raise Fail "Can't happen 90210" 1749 | CLOSEFIX list => 1750 let 1751 (* val _ = PRINT "suitable_rule: closefix check" *) 1752 val r = hd list 1753 in 1754 if term_name_is_lform (#term_name r) then 1755 ((* PRINT ("rule term-name is empty - testing " ^ 1756 debugprint G tm); *) 1757 case find_lspec (#elements r) of 1758 SOME {nilstr,cons,...} => 1759 if is_list G {nilstr=nilstr,cons=cons} tm then 1760 SOME (List (#elements r)) 1761 else NONE 1762 | NONE => NONE) 1763 else if check_rrec_args mkrels_closefix r args0 then 1764 SOME (Norm(prec, rule)) 1765 else NONE 1766 end 1767 | INFIX (FNAPP _) => raise Fail "Can't happen 90211" 1768 | INFIX VSCONS => raise Fail "Can't happen 90213" 1769 in 1770 case List.mapPartial suitable_rule crules0 of 1771 Norm (prec,rule) :: _ => 1772 pr_comb_with_rule 1773 rule 1774 {fprec = prec, fname=fname, f=f} args Rand 1775 | List els :: _ => 1776 ((* PRINT "printing a List rule"; *) 1777 print_ellist NONE (Top,Top,Top) (els, [tm]) >> return ()) 1778 | [] => (*(PRINT "No suitable rules, printing with pr_comb";*) 1779 pr_comb tm Rator Rand 1780 (* before PRINT "Finished pr_comb") *) 1781 end 1782 end (* pr_atomf *) 1783 fun maybe_pr_atomf () = 1784 if grammar_name G oif = SOME "case" then 1785 pr_atomf (strip_comb tm) 1786 else if overloadedp then 1787 case oiargs of 1788 [] => (* term is a comb, but it somehow overloads to a 1789 single "constant" *) 1790 pr_term oif pgrav lgrav rgrav depth 1791 | _ => pr_atomf (oif, oiargs) 1792 else if is_var f then pr_atomf (f, args @ [Rand]) 1793 else pr_comb tm Rator Rand 1794 in 1795 (* check for various literal and special forms *) 1796 1797 (* strings *) 1798 (case total Literal.dest_string_lit tm of 1799 NONE => fail 1800 | SOME s => 1801 add_ann_string (Literal.string_literalpp s, 1802 PPBackEnd.Literal PPBackEnd.StringLit)) ||| 1803 1804 (* characters *) 1805 (fn _ => case total Literal.dest_char_lit tm of 1806 NONE => fail 1807 | SOME c => add_ann_string ("#" ^ Lib.mlquote (str c), 1808 PPBackEnd.Literal PPBackEnd.CharLit)) ||| 1809 1810 (* numerals *) 1811 (fn _ => if Literal.is_numeral tm andalso can_pr_numeral NONE then 1812 pr_numeral NONE tm 1813 else fail) ||| 1814 (fn _ => (if Literal.is_numeral Rand andalso 1815 can_pr_numeral (SOME (atom_name Rator)) 1816 then pr_numeral (SOME Rator) Rand 1817 else fail) handle HOL_ERR _ => fail) ||| 1818 1819 (* binders *) 1820 (fn _ => if my_is_abs tm then pr_abs tm else fail) ||| 1821 1822 (* record forms *) 1823 (fn _ => 1824 case oiargs of 1825 [] => fail 1826 | _ => let 1827 val (args, Rand) = front_last oiargs 1828 in 1829 check_for_field_selection (list_mk_comb(oif,args)) Rand 1830 end) ||| 1831 (fn _ => check_for_record_update tm Rator Rand) ||| 1832 1833 check_for_setcomprehensions ||| 1834 1835 (* case expressions *) 1836 (fn () => 1837 if (is_const f andalso (!prettyprint_cases)) then 1838 case grammar_name G oif of 1839 SOME "case" => 1840 (let 1841 val (split_on, splits) = convert_case tm 1842 val parens = (case rgrav of Prec _ => true | _ => false) 1843 orelse 1844 combpos = RandCP 1845 fun p body = 1846 get_gspec >- 1847 (fn b => if b orelse parens then 1848 add_string "(" >> block PP.CONSISTENT 1 body >> add_string ")" 1849 else 1850 block PP.CONSISTENT 0 body) 1851 val casebar = add_break(1,0) >> add_string "|" >> hardspace 1 1852 fun do_split rprec (l,r) = 1853 record_bvars 1854 (free_vars l) 1855 (block PP.CONSISTENT 0 1856 (pr_term l Top Top Top (decdepth depth) >> 1857 hardspace 1 >> 1858 add_string "=>" >> add_break(1,2) >> 1859 block PP.CONSISTENT 0 (pr_term r Top Top rprec (decdepth depth)))) 1860 in 1861 p (block PP.CONSISTENT 0 1862 (add_string (prettyprint_cases_name ()) >> 1863 add_break(1,2) >> 1864 pr_term split_on Top Top Top (decdepth depth) >> 1865 add_break(1,0) >> add_string "of") >> 1866 (if !pp_print_firstcasebar then 1867 casebar 1868 else 1869 add_break (1,2)) >> 1870 (if length splits > 1 then 1871 pr_list (do_split (Prec(0,"casebar"))) 1872 casebar (butlast splits) >> 1873 casebar >> 1874 do_split (if parens then Top else rgrav) 1875 (last splits) 1876 else 1877 do_split (if parens then Top else rgrav) 1878 (hd splits))) 1879 end handle CaseConversionFailed => fail) 1880 | _ => fail 1881 else fail) ||| 1882 1883 (fn _ => if showtypes_v then 1884 if const_is_ambiguous f then 1885 pr_comb tm Rator Rand 1886 else 1887 maybe_pr_atomf() 1888 else maybe_pr_atomf()) 1889 end 1890 | LAMB(Bvar, Body) => pr_abs tm 1891 end apps 1892 val avoid_merge = avoid_symbolmerge G 1893 open PPBackEnd 1894in 1895 fn t => 1896 let 1897 val {add_string,add_break,ublock,add_xstring,add_newline,ustyle,...} = 1898 backend 1899 val (add_string, add_xstring, add_break) = 1900 avoid_merge (add_string, add_xstring, add_break) 1901 val ppfns = {add_string = add_string, 1902 add_xstring = add_xstring, 1903 add_break = add_break, 1904 add_newline = add_newline, 1905 ublock = ublock, 1906 ustyle = ustyle, 1907 extras = ()} 1908 in 1909 ublock CONSISTENT 0 ( 1910 pr_term false 1911 (!Globals.show_types orelse !Globals.show_types_verbosely) 1912 (!Globals.show_types_verbosely) 1913 ppfns NoCP t RealTop RealTop RealTop 1914 (!Globals.max_print_depth) 1915 ) 1916 end 1917end 1918 1919end; (* term_pp *) 1920