src/Pure/Syntax/printer.ML
author wenzelm
Fri Sep 03 15:54:03 2010 +0200 (2010-09-03)
changeset 39115 a00da1674c1c
parent 38980 af73cf0dc31f
child 39116 f14735a88886
permissions -rw-r--r--
turned show_no_free_types into proper configuration option show_free_types, with flipped polarity;
     1 (*  Title:      Pure/Syntax/printer.ML
     2     Author:     Tobias Nipkow and Markus Wenzel, TU Muenchen
     3 
     4 Pretty printing of asts, terms, types and print (ast) translation.
     5 *)
     6 
     7 signature PRINTER0 =
     8 sig
     9   val show_brackets: bool Unsynchronized.ref
    10   val show_sorts: bool Unsynchronized.ref
    11   val show_types: bool Unsynchronized.ref
    12   val show_free_types_default: bool Unsynchronized.ref
    13   val show_free_types_value: Config.value Config.T
    14   val show_free_types: bool Config.T
    15   val show_all_types: bool Unsynchronized.ref
    16   val show_structs: bool Unsynchronized.ref
    17   val show_question_marks_default: bool Unsynchronized.ref
    18   val show_question_marks_value: Config.value Config.T
    19   val show_question_marks: bool Config.T
    20   val pp_show_brackets: Pretty.pp -> Pretty.pp
    21 end;
    22 
    23 signature PRINTER =
    24 sig
    25   include PRINTER0
    26   val sort_to_ast: Proof.context ->
    27     (string -> (Proof.context -> bool -> typ -> term list -> term) list) -> sort -> Ast.ast
    28   val typ_to_ast: Proof.context ->
    29     (string -> (Proof.context -> bool -> typ -> term list -> term) list) -> typ -> Ast.ast
    30   val term_to_ast: {structs: string list, fixes: string list} -> string list -> Proof.context ->
    31     (string -> (Proof.context -> bool -> typ -> term list -> term) list) -> term -> Ast.ast
    32   type prtabs
    33   val empty_prtabs: prtabs
    34   val update_prtabs: string -> Syn_Ext.xprod list -> prtabs -> prtabs
    35   val remove_prtabs: string -> Syn_Ext.xprod list -> prtabs -> prtabs
    36   val merge_prtabs: prtabs -> prtabs -> prtabs
    37   val pretty_term_ast: {extern_class: string -> xstring, extern_type: string -> xstring,
    38       extern_const: string -> xstring} -> Proof.context -> bool -> prtabs ->
    39     (string -> (Proof.context -> Ast.ast list -> Ast.ast) list) ->
    40     (string -> (Proof.context -> string -> Pretty.T) option) -> Ast.ast -> Pretty.T list
    41   val pretty_typ_ast: {extern_class: string -> xstring, extern_type: string -> xstring} ->
    42     Proof.context -> bool -> prtabs ->
    43     (string -> (Proof.context -> Ast.ast list -> Ast.ast) list) ->
    44     (string -> (Proof.context -> string -> Pretty.T) option) -> Ast.ast -> Pretty.T list
    45 end;
    46 
    47 structure Printer: PRINTER =
    48 struct
    49 
    50 
    51 (** options for printing **)
    52 
    53 val show_types = Unsynchronized.ref false;
    54 val show_sorts = Unsynchronized.ref false;
    55 val show_brackets = Unsynchronized.ref false;
    56 val show_all_types = Unsynchronized.ref false;
    57 val show_structs = Unsynchronized.ref false;
    58 
    59 val show_free_types_default = Unsynchronized.ref true;
    60 val show_free_types_value =
    61   Config.declare false "show_free_types" (fn _ => Config.Bool (! show_free_types_default));
    62 val show_free_types = Config.bool show_free_types_value;
    63 
    64 val show_question_marks_default = Unsynchronized.ref true;
    65 val show_question_marks_value =
    66   Config.declare false "show_question_marks" (fn _ => Config.Bool (! show_question_marks_default));
    67 val show_question_marks = Config.bool show_question_marks_value;
    68 
    69 fun pp_show_brackets pp = Pretty.pp (setmp_CRITICAL show_brackets true (Pretty.term pp),
    70   Pretty.typ pp, Pretty.sort pp, Pretty.classrel pp, Pretty.arity pp);
    71 
    72 
    73 
    74 (** misc utils **)
    75 
    76 (* apply print (ast) translation function *)
    77 
    78 fun apply_trans ctxt fns args =
    79   let
    80     fun app_first [] = raise Match
    81       | app_first (f :: fs) = f ctxt args handle Match => app_first fs;
    82   in app_first fns end;
    83 
    84 fun apply_typed x y fs = map (fn f => fn ctxt => f ctxt x y) fs;
    85 
    86 
    87 (* simple_ast_of *)
    88 
    89 fun simple_ast_of ctxt =
    90   let
    91     val tune_var = if Config.get ctxt show_question_marks then I else unprefix "?";
    92     fun ast_of (Const (c, _)) = Ast.Constant c
    93       | ast_of (Free (x, _)) = Ast.Variable x
    94       | ast_of (Var (xi, _)) = Ast.Variable (tune_var (Term.string_of_vname xi))
    95       | ast_of (t as _ $ _) =
    96           let val (f, args) = strip_comb t
    97           in Ast.mk_appl (ast_of f) (map ast_of args) end
    98       | ast_of (Bound i) = Ast.Variable ("B." ^ string_of_int i)
    99       | ast_of (Abs _) = raise Fail "simple_ast_of: Abs";
   100   in ast_of end;
   101 
   102 
   103 
   104 (** sort_to_ast, typ_to_ast **)
   105 
   106 fun ast_of_termT ctxt trf tm =
   107   let
   108     fun ast_of (t as Const ("_tfree", _) $ Free _) = simple_ast_of ctxt t
   109       | ast_of (t as Const ("_tvar", _) $ Var _) = simple_ast_of ctxt t
   110       | ast_of (Const (a, _)) = trans a []
   111       | ast_of (t as _ $ _) =
   112           (case strip_comb t of
   113             (Const (a, _), args) => trans a args
   114           | (f, args) => Ast.Appl (map ast_of (f :: args)))
   115       | ast_of t = simple_ast_of ctxt t
   116     and trans a args =
   117       ast_of (apply_trans ctxt (apply_typed false dummyT (trf a)) args)
   118         handle Match => Ast.mk_appl (Ast.Constant a) (map ast_of args);
   119   in ast_of tm end;
   120 
   121 fun sort_to_ast ctxt trf S = ast_of_termT ctxt trf (Type_Ext.term_of_sort S);
   122 fun typ_to_ast ctxt trf T = ast_of_termT ctxt trf (Type_Ext.term_of_typ (! show_sorts) T);
   123 
   124 
   125 
   126 (** term_to_ast **)
   127 
   128 fun ast_of_term idents consts ctxt trf
   129     show_all_types show_types show_sorts show_structs tm =
   130   let
   131     val show_free_types = Config.get ctxt show_free_types;
   132     val {structs, fixes} = idents;
   133 
   134     fun mark_atoms ((t as Const (c, T)) $ u) =
   135           if member (op =) Syn_Ext.standard_token_markers c
   136           then t $ u else mark_atoms t $ mark_atoms u
   137       | mark_atoms (t $ u) = mark_atoms t $ mark_atoms u
   138       | mark_atoms (Abs (x, T, t)) = Abs (x, T, mark_atoms t)
   139       | mark_atoms (t as Const (c, T)) =
   140           if member (op =) consts c then t
   141           else Const (Lexicon.mark_const c, T)
   142       | mark_atoms (t as Free (x, T)) =
   143           let val i = find_index (fn s => s = x) structs + 1 in
   144             if i = 0 andalso member (op =) fixes x then
   145               Const (Lexicon.mark_fixed x, T)
   146             else if i = 1 andalso not show_structs then
   147               Lexicon.const "_struct" $ Lexicon.const "_indexdefault"
   148             else Lexicon.const "_free" $ t
   149           end
   150       | mark_atoms (t as Var (xi, T)) =
   151           if xi = Syn_Ext.dddot_indexname then Const ("_DDDOT", T)
   152           else Lexicon.const "_var" $ t
   153       | mark_atoms a = a;
   154 
   155     fun prune_typs (t_seen as (Const _, _)) = t_seen
   156       | prune_typs (t as Free (x, ty), seen) =
   157           if ty = dummyT then (t, seen)
   158           else if not show_free_types orelse member (op aconv) seen t then (Lexicon.free x, seen)
   159           else (t, t :: seen)
   160       | prune_typs (t as Var (xi, ty), seen) =
   161           if ty = dummyT then (t, seen)
   162           else if not show_free_types orelse member (op aconv) seen t then (Lexicon.var xi, seen)
   163           else (t, t :: seen)
   164       | prune_typs (t_seen as (Bound _, _)) = t_seen
   165       | prune_typs (Abs (x, ty, t), seen) =
   166           let val (t', seen') = prune_typs (t, seen);
   167           in (Abs (x, ty, t'), seen') end
   168       | prune_typs (t1 $ t2, seen) =
   169           let
   170             val (t1', seen') = prune_typs (t1, seen);
   171             val (t2', seen'') = prune_typs (t2, seen');
   172           in (t1' $ t2', seen'') end;
   173 
   174     fun ast_of tm =
   175       (case strip_comb tm of
   176         (t as Abs _, ts) => Ast.mk_appl (ast_of (Syn_Trans.abs_tr' t)) (map ast_of ts)
   177       | ((c as Const ("_free", _)), Free (x, T) :: ts) =>
   178           Ast.mk_appl (constrain (c $ Lexicon.free x) T) (map ast_of ts)
   179       | ((c as Const ("_var", _)), Var (xi, T) :: ts) =>
   180           Ast.mk_appl (constrain (c $ Lexicon.var xi) T) (map ast_of ts)
   181       | ((c as Const ("_bound", _)), Free (x, T) :: ts) =>
   182           Ast.mk_appl (constrain (c $ Lexicon.free x) T) (map ast_of ts)
   183       | (Const ("_idtdummy", T), ts) =>
   184           Ast.mk_appl (constrain (Lexicon.const "_idtdummy") T) (map ast_of ts)
   185       | (const as Const (c, T), ts) =>
   186           if show_all_types
   187           then Ast.mk_appl (constrain const T) (map ast_of ts)
   188           else trans c T ts
   189       | (t, ts) => Ast.mk_appl (simple_ast_of ctxt t) (map ast_of ts))
   190 
   191     and trans a T args =
   192       ast_of (apply_trans ctxt (apply_typed show_sorts T (trf a)) args)
   193         handle Match => Ast.mk_appl (Ast.Constant a) (map ast_of args)
   194 
   195     and constrain t T =
   196       if show_types andalso T <> dummyT then
   197         Ast.Appl [Ast.Constant Syn_Ext.constrainC, simple_ast_of ctxt t,
   198           ast_of_termT ctxt trf (Type_Ext.term_of_typ show_sorts T)]
   199       else simple_ast_of ctxt t;
   200   in
   201     tm
   202     |> Syn_Trans.prop_tr'
   203     |> show_types ? (#1 o prune_typs o rpair [])
   204     |> mark_atoms
   205     |> ast_of
   206   end;
   207 
   208 fun term_to_ast idents consts ctxt trf tm =
   209   ast_of_term idents consts ctxt trf (! show_all_types)
   210     (! show_types orelse ! show_sorts orelse ! show_all_types) (! show_sorts) (! show_structs) tm;
   211 
   212 
   213 
   214 (** type prtabs **)
   215 
   216 datatype symb =
   217   Arg of int |
   218   TypArg of int |
   219   String of string |
   220   Space of string |
   221   Break of int |
   222   Block of int * symb list;
   223 
   224 type prtabs = (string * ((symb list * int * int) list) Symtab.table) list;
   225 
   226 fun mode_tab prtabs mode = the_default Symtab.empty (AList.lookup (op =) prtabs mode);
   227 fun mode_tabs prtabs modes = map_filter (AList.lookup (op =) prtabs) (modes @ [""]);
   228 
   229 
   230 (* xprod_to_fmt *)
   231 
   232 fun xprod_to_fmt (Syn_Ext.XProd (_, _, "", _)) = NONE
   233   | xprod_to_fmt (Syn_Ext.XProd (_, xsymbs, const, pri)) =
   234       let
   235         fun arg (s, p) =
   236           (if s = "type" then TypArg else Arg)
   237           (if Lexicon.is_terminal s then Syn_Ext.max_pri else p);
   238 
   239         fun xsyms_to_syms (Syn_Ext.Delim s :: xsyms) =
   240               apfst (cons (String s)) (xsyms_to_syms xsyms)
   241           | xsyms_to_syms (Syn_Ext.Argument s_p :: xsyms) =
   242               apfst (cons (arg s_p)) (xsyms_to_syms xsyms)
   243           | xsyms_to_syms (Syn_Ext.Space s :: xsyms) =
   244               apfst (cons (Space s)) (xsyms_to_syms xsyms)
   245           | xsyms_to_syms (Syn_Ext.Bg i :: xsyms) =
   246               let
   247                 val (bsyms, xsyms') = xsyms_to_syms xsyms;
   248                 val (syms, xsyms'') = xsyms_to_syms xsyms';
   249               in
   250                 (Block (i, bsyms) :: syms, xsyms'')
   251               end
   252           | xsyms_to_syms (Syn_Ext.Brk i :: xsyms) =
   253               apfst (cons (Break i)) (xsyms_to_syms xsyms)
   254           | xsyms_to_syms (Syn_Ext.En :: xsyms) = ([], xsyms)
   255           | xsyms_to_syms [] = ([], []);
   256 
   257         fun nargs (Arg _ :: syms) = nargs syms + 1
   258           | nargs (TypArg _ :: syms) = nargs syms + 1
   259           | nargs (String _ :: syms) = nargs syms
   260           | nargs (Space _ :: syms) = nargs syms
   261           | nargs (Break _ :: syms) = nargs syms
   262           | nargs (Block (_, bsyms) :: syms) = nargs syms + nargs bsyms
   263           | nargs [] = 0;
   264       in
   265         (case xsyms_to_syms xsymbs of
   266           (symbs, []) => SOME (const, (symbs, nargs symbs, pri))
   267         | _ => raise Fail "Unbalanced pretty-printing blocks")
   268       end;
   269 
   270 
   271 (* empty, extend, merge prtabs *)
   272 
   273 val empty_prtabs = [];
   274 
   275 fun update_prtabs mode xprods prtabs =
   276   let
   277     val fmts = map_filter xprod_to_fmt xprods;
   278     val tab' = fold (Symtab.update_list (op =)) fmts (mode_tab prtabs mode);
   279   in AList.update (op =) (mode, tab') prtabs end;
   280 
   281 fun remove_prtabs mode xprods prtabs =
   282   let
   283     val tab = mode_tab prtabs mode;
   284     val fmts = map_filter (fn xprod as Syn_Ext.XProd (_, _, c, _) =>
   285       if null (Symtab.lookup_list tab c) then NONE
   286       else xprod_to_fmt xprod) xprods;
   287     val tab' = fold (Symtab.remove_list (op =)) fmts tab;
   288   in AList.update (op =) (mode, tab') prtabs end;
   289 
   290 fun merge_prtabs prtabs1 prtabs2 =
   291   let
   292     val modes = distinct (op =) (map fst (prtabs1 @ prtabs2));
   293     fun merge m = (m, Symtab.merge_list (op =) (mode_tab prtabs1 m, mode_tab prtabs2 m));
   294   in map merge modes end;
   295 
   296 
   297 
   298 (** pretty term or typ asts **)
   299 
   300 fun is_chain [Block (_, pr)] = is_chain pr
   301   | is_chain [Arg _] = true
   302   | is_chain _  = false;
   303 
   304 fun pretty extern ctxt tabs trf tokentrf type_mode curried ast0 p0 =
   305   let
   306     val {extern_class, extern_type, extern_const} = extern;
   307 
   308     fun token_trans a x =
   309       (case tokentrf a of
   310         NONE =>
   311           if member (op =) Syn_Ext.standard_token_classes a
   312           then SOME (Pretty.str x) else NONE
   313       | SOME f => SOME (f ctxt x));
   314 
   315     (*default applications: prefix / postfix*)
   316     val appT =
   317       if type_mode then Type_Ext.tappl_ast_tr'
   318       else if curried then Syn_Trans.applC_ast_tr'
   319       else Syn_Trans.appl_ast_tr';
   320 
   321     fun synT _ ([], args) = ([], args)
   322       | synT markup (Arg p :: symbs, t :: args) =
   323           let val (Ts, args') = synT markup (symbs, args);
   324           in (astT (t, p) @ Ts, args') end
   325       | synT markup (TypArg p :: symbs, t :: args) =
   326           let
   327             val (Ts, args') = synT markup (symbs, args);
   328           in
   329             if type_mode then (astT (t, p) @ Ts, args')
   330             else (pretty extern ctxt tabs trf tokentrf true curried t p @ Ts, args')
   331           end
   332       | synT markup (String s :: symbs, args) =
   333           let val (Ts, args') = synT markup (symbs, args);
   334           in (markup (Pretty.str s) :: Ts, args') end
   335       | synT markup (Space s :: symbs, args) =
   336           let val (Ts, args') = synT markup (symbs, args);
   337           in (Pretty.str s :: Ts, args') end
   338       | synT markup (Block (i, bsymbs) :: symbs, args) =
   339           let
   340             val (bTs, args') = synT markup (bsymbs, args);
   341             val (Ts, args'') = synT markup (symbs, args');
   342             val T =
   343               if i < 0 then Pretty.unbreakable (Pretty.block bTs)
   344               else Pretty.blk (i, bTs);
   345           in (T :: Ts, args'') end
   346       | synT markup (Break i :: symbs, args) =
   347           let
   348             val (Ts, args') = synT markup (symbs, args);
   349             val T = if i < 0 then Pretty.fbrk else Pretty.brk i;
   350           in (T :: Ts, args') end
   351 
   352     and parT markup (pr, args, p, p': int) = #1 (synT markup
   353           (if p > p' orelse
   354             (! show_brackets andalso p' <> Syn_Ext.max_pri andalso not (is_chain pr))
   355             then [Block (1, Space "(" :: pr @ [Space ")"])]
   356             else pr, args))
   357 
   358     and atomT a = a |> Lexicon.unmark
   359      {case_class = fn c => Pretty.mark (Markup.tclass c) (Pretty.str (extern_class c)),
   360       case_type = fn c => Pretty.mark (Markup.tycon c) (Pretty.str (extern_type c)),
   361       case_const = fn c => Pretty.mark (Markup.const c) (Pretty.str (extern_const c)),
   362       case_fixed = fn x => the (token_trans "_free" x),
   363       case_default = Pretty.str}
   364 
   365     and prefixT (_, a, [], _) = [atomT a]
   366       | prefixT (c, _, args, p) = astT (appT (c, args), p)
   367 
   368     and splitT 0 ([x], ys) = (x, ys)
   369       | splitT 0 (rev_xs, ys) = (Ast.Appl (rev rev_xs), ys)
   370       | splitT n (rev_xs, y :: ys) = splitT (n - 1) (y :: rev_xs, ys)
   371 
   372     and combT (tup as (c, a, args, p)) =
   373       let
   374         val nargs = length args;
   375         val markup = a |> Lexicon.unmark
   376          {case_class = Pretty.mark o Markup.tclass,
   377           case_type = Pretty.mark o Markup.tycon,
   378           case_const = Pretty.mark o Markup.const,
   379           case_fixed = Pretty.mark o Markup.fixed,
   380           case_default = K I};
   381 
   382         (*find matching table entry, or print as prefix / postfix*)
   383         fun prnt ([], []) = prefixT tup
   384           | prnt ([], tb :: tbs) = prnt (Symtab.lookup_list tb a, tbs)
   385           | prnt ((pr, n, p') :: prnps, tbs) =
   386               if nargs = n then parT markup (pr, args, p, p')
   387               else if nargs > n andalso not type_mode then
   388                 astT (appT (splitT n ([c], args)), p)
   389               else prnt (prnps, tbs);
   390       in
   391         (case tokentrT a args of
   392           SOME prt => [prt]
   393         | NONE => astT (apply_trans ctxt (trf a) args, p) handle Match => prnt ([], tabs))
   394       end
   395 
   396     and tokentrT a [Ast.Variable x] = token_trans a x
   397       | tokentrT _ _ = NONE
   398 
   399     and astT (c as Ast.Constant a, p) = combT (c, a, [], p)
   400       | astT (Ast.Variable x, _) = [Pretty.str x]
   401       | astT (Ast.Appl ((c as Ast.Constant a) :: (args as _ :: _)), p) = combT (c, a, args, p)
   402       | astT (Ast.Appl (f :: (args as _ :: _)), p) = astT (appT (f, args), p)
   403       | astT (ast as Ast.Appl _, _) = raise Ast.AST ("pretty: malformed ast", [ast]);
   404   in astT (ast0, p0) end;
   405 
   406 
   407 (* pretty_term_ast *)
   408 
   409 fun pretty_term_ast extern ctxt curried prtabs trf tokentrf ast =
   410   pretty extern ctxt (mode_tabs prtabs (print_mode_value ()))
   411     trf tokentrf false curried ast 0;
   412 
   413 
   414 (* pretty_typ_ast *)
   415 
   416 fun pretty_typ_ast {extern_class, extern_type} ctxt _ prtabs trf tokentrf ast =
   417   pretty {extern_class = extern_class, extern_type = extern_type, extern_const = I}
   418     ctxt (mode_tabs prtabs (print_mode_value ()))
   419     trf tokentrf true false ast 0;
   420 
   421 end;