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