src/Pure/Syntax/pretty.ML
changeset 118 96d2c0fc2cd5
parent 18 c9ec452ff08f
child 236 d33cd0011e48
equal deleted inserted replaced
117:6b26ccac50fc 118:96d2c0fc2cd5
    65 type text = {tx: string, nl: int, pos: int};
    65 type text = {tx: string, nl: int, pos: int};
    66 
    66 
    67 val emptytext = {tx="", nl=0, pos=0};
    67 val emptytext = {tx="", nl=0, pos=0};
    68 
    68 
    69 fun blanks wd {tx,nl,pos} =
    69 fun blanks wd {tx,nl,pos} =
    70     {tx  = tx ^ repstring" "wd,
    70     {tx  = tx ^ repstring " " wd,
    71      nl  = nl,
    71      nl  = nl,
    72      pos = pos+wd};
    72      pos = pos+wd};
    73 
    73 
    74 fun newline {tx,nl,pos} =
    74 fun newline {tx,nl,pos} =
    75     {tx  = tx ^ "\n",
    75     {tx  = tx ^ "\n",
    90 fun setmargin m =
    90 fun setmargin m =
    91     (margin     := m;
    91     (margin     := m;
    92      breakgain  := !margin div 20;
    92      breakgain  := !margin div 20;
    93      emergencypos := !margin div 2);
    93      emergencypos := !margin div 2);
    94 
    94 
       
    95 (*Search for the next break (at this or higher levels) and force it to occur*)
    95 fun forcenext [] = []
    96 fun forcenext [] = []
    96   | forcenext (Break(_,wd) :: es) = Break(true,0) :: es
    97   | forcenext (Break(_,wd) :: es) = Break(true,0) :: es
    97   | forcenext (e :: es) = e :: forcenext es;
    98   | forcenext (e :: es) = e :: forcenext es;
    98 
    99 
       
   100 (*es is list of expressions to print;
       
   101   blockin is the indentation of the current block;
       
   102   after is the width of the following context until next break. *)
    99 fun format ([], _, _) text = text
   103 fun format ([], _, _) text = text
   100   | format (e::es, blockin, after) (text as {pos,nl,...}) =
   104   | format (e::es, blockin, after) (text as {pos,nl,...}) =
   101     (case e of
   105     (case e of
   102        Block(bes,indent,wd) =>
   106        Block(bes,indent,wd) =>
   103          let val blockin' = (pos + indent) mod !emergencypos
   107          let val blockin' = (pos + indent) mod !emergencypos
   104              val btext = format(bes, blockin', breakdist(es,after)) text
   108              val btext = format(bes, blockin', breakdist(es,after)) text
   105              val es2 = if nl < #nl(btext) then forcenext es
   109              (*If this block was broken then force the next break.*)
   106                        else es
   110 	     val es2 = if nl < #nl(btext) then forcenext es else es
   107          in  format (es2,blockin,after) btext  end
   111          in  format (es2,blockin,after) btext  end
   108      | String s => format (es,blockin,after) (string s text)
   112      | String s => format (es,blockin,after) (string s text)
   109      | Break(force,wd) => (* no break if text fits on this line
   113      | Break(force,wd) => (*no break if text to next break fits on this line
   110                       or if breaking would add only breakgain to space *)
   114 			    or if breaking would add only breakgain to space *)
   111            format (es,blockin,after)
   115            format (es,blockin,after)
   112                (if not force andalso
   116                (if not force andalso
   113                    pos+wd <= max[!margin - breakdist(es,after),
   117                    pos+wd <= max[!margin - breakdist(es,after),
   114                                  blockin + !breakgain]
   118                                  blockin + !breakgain]
   115                 then blanks wd text
   119                 then blanks wd text  (*just insert wd blanks*)
   116                 else blanks blockin (newline text)));
   120                 else blanks blockin (newline text)));
   117 
   121 
   118 (*** Exported functions to create formatting expressions ***)
   122 (*** Exported functions to create formatting expressions ***)
   119 
   123 
   120 fun length (Block(_,_,len)) = len
   124 fun length (Block(_,_,len)) = len
   129 fun blk (indent,es) =
   133 fun blk (indent,es) =
   130   let fun sum([], k) = k
   134   let fun sum([], k) = k
   131         | sum(e::es, k) = sum(es, length e + k)
   135         | sum(e::es, k) = sum(es, length e + k)
   132   in  Block(es,indent, sum(es,0))  end;
   136   in  Block(es,indent, sum(es,0))  end;
   133 
   137 
       
   138 (*Join the elements of es as a comma-separated list, bracketted by lp and rp*)
   134 fun lst(lp,rp) es =
   139 fun lst(lp,rp) es =
   135   let fun add(e,es) = str"," :: brk 1 :: e :: es;
   140   let fun add(e,es) = str"," :: brk 1 :: e :: es;
   136       fun list(e :: (es as _::_)) = str lp :: e :: foldr add (es,[str rp])
   141       fun list(e :: (es as _::_)) = str lp :: e :: foldr add (es,[str rp])
   137         | list(e::[]) = [str lp, e, str rp]
   142         | list(e::[]) = [str lp, e, str rp]
   138         | list([]) = []
   143         | list([]) = []
   139   in blk(size lp, list es) end;
   144   in blk(size lp, list es) end;
   140 
   145 
       
   146 (*Put quotation marks around the given expression*)
   141 fun quote prt = blk (1, [str "\"", prt, str "\""]);
   147 fun quote prt = blk (1, [str "\"", prt, str "\""]);
   142 
   148 
   143 
   149 
   144 (*** Pretty printing with depth limitation ***)
   150 (*** Pretty printing with depth limitation ***)
   145 
   151 
   146 val depth       = ref 0;        (*maximum depth; 0 means no limit*)
   152 val depth       = ref 0;        (*maximum depth; 0 means no limit*)
   147 
   153 
   148 fun setdepth dp = (depth := dp);
   154 fun setdepth dp = (depth := dp);
   149 
   155 
   150 
   156 (*Recursively prune blocks, discarding all text exceeding depth dp*)
   151 fun pruning dp (Block(bes,indent,wd)) =
   157 fun pruning dp (Block(bes,indent,wd)) =
   152       if dp>0 then blk(indent, map (pruning(dp-1)) bes)
   158       if dp>0 then blk(indent, map (pruning(dp-1)) bes)
   153               else String"..."
   159               else String"..."
   154   | pruning dp e = e;
   160   | pruning dp e = e;
   155 
   161 
   156 fun prune dp e = if dp>0 then pruning dp e else e;
   162 fun prune dp e = if dp>0 then pruning dp e else e;
   157 
   163 
   158 
   164 
   159 fun string_of e = #tx (format ([prune (!depth) e],0,0) emptytext);
   165 fun string_of e = #tx (format ([prune (!depth) e], 0, 0) emptytext);
   160 
   166 
   161 
   167 
       
   168 (*Create a single flat string: no line breaking*)
   162 fun str_of prt =
   169 fun str_of prt =
   163   let
   170   let
   164     fun s_of (Block (prts, _, _)) = implode (map s_of prts)
   171     fun s_of (Block (prts, _, _)) = implode (map s_of prts)
   165       | s_of (String s) = s
   172       | s_of (String s) = s
   166       | s_of (Break (false, wd)) = repstring " " wd
   173       | s_of (Break (false, wd)) = repstring " " wd
   167       | s_of (Break (true, _)) = " ";
   174       | s_of (Break (true, _)) = " ";
   168   in
   175   in
   169     s_of (prune (! depth) prt)
   176     s_of (prune (! depth) prt)
   170   end;
   177   end;
   171 
   178 
   172 
   179 (*Part of the interface to the Poly/ML and New Jersey ML pretty printers*)
   173 fun pprint prt (put_str, begin_blk, put_brk, put_fbrk, end_blk) =
   180 fun pprint prt (put_str, begin_blk, put_brk, put_fbrk, end_blk) =
   174   let
   181   let
   175     fun pp (Block (prts, ind, _)) = (begin_blk ind; pp_lst prts; end_blk ())
   182     fun pp (Block (prts, ind, _)) = (begin_blk ind; pp_lst prts; end_blk ())
   176       | pp (String s) = put_str s
   183       | pp (String s) = put_str s
   177       | pp (Break (false, wd)) = put_brk wd
   184       | pp (Break (false, wd)) = put_brk wd