src/Tools/Metis/src/Print.sml
changeset 45778 df6e210fb44c
parent 43269 3535f16d9714
child 72004 913162a47d9f
equal deleted inserted replaced
45777:c36637603821 45778:df6e210fb44c
    24     | x :: xs => revAppend xs (K (Stream.Cons (x,s)));
    24     | x :: xs => revAppend xs (K (Stream.Cons (x,s)));
    25 
    25 
    26 fun revConcat strm =
    26 fun revConcat strm =
    27     case strm of
    27     case strm of
    28       Stream.Nil => Stream.Nil
    28       Stream.Nil => Stream.Nil
    29     | Stream.Cons (h,t) => revAppend h (revConcat o t);
    29     | Stream.Cons (h,t) => revAppend h (fn () => revConcat (t ()));
    30 
    30 
    31 local
    31 local
    32   fun calcSpaces n = nChars #" " n;
    32   fun calcSpaces n = nChars #" " n;
    33 
    33 
    34   val cacheSize = 2 * initialLineLength;
    34   val cacheSize = 2 * initialLineLength;
    60     in
    60     in
    61       String.translate escapeChar
    61       String.translate escapeChar
    62     end;
    62     end;
    63 
    63 
    64 (* ------------------------------------------------------------------------- *)
    64 (* ------------------------------------------------------------------------- *)
    65 (* A type of strings annotated with their size.                              *)
    65 (* Pretty-printing blocks.                                                   *)
    66 (* ------------------------------------------------------------------------- *)
    66 (* ------------------------------------------------------------------------- *)
    67 
    67 
    68 type stringSize = string * int;
    68 datatype style = Consistent | Inconsistent;
    69 
    69 
    70 fun mkStringSize s = (s, size s);
    70 datatype block =
    71 
    71     Block of
    72 val emptyStringSize = mkStringSize "";
    72       {style : style,
    73 
    73        indent : int};
    74 (* ------------------------------------------------------------------------- *)
    74 
    75 (* A type of pretty-printers.                                                *)
    75 fun toStringStyle style =
    76 (* ------------------------------------------------------------------------- *)
       
    77 
       
    78 datatype breakStyle = Consistent | Inconsistent;
       
    79 
       
    80 datatype step =
       
    81     BeginBlock of breakStyle * int
       
    82   | EndBlock
       
    83   | AddString of stringSize
       
    84   | AddBreak of int
       
    85   | AddNewline;
       
    86 
       
    87 type ppstream = step Stream.stream;
       
    88 
       
    89 fun breakStyleToString style =
       
    90     case style of
    76     case style of
    91       Consistent => "Consistent"
    77       Consistent => "Consistent"
    92     | Inconsistent => "Inconsistent";
    78     | Inconsistent => "Inconsistent";
    93 
    79 
    94 fun stepToString step =
    80 fun isConsistentStyle style =
       
    81     case style of
       
    82       Consistent => true
       
    83     | Inconsistent => false;
       
    84 
       
    85 fun isInconsistentStyle style =
       
    86     case style of
       
    87       Inconsistent => true
       
    88     | Consistent => false;
       
    89 
       
    90 fun mkBlock style indent =
       
    91     Block
       
    92       {style = style,
       
    93        indent = indent};
       
    94 
       
    95 val mkConsistentBlock = mkBlock Consistent;
       
    96 
       
    97 val mkInconsistentBlock = mkBlock Inconsistent;
       
    98 
       
    99 fun styleBlock (Block {style = x, ...}) = x;
       
   100 
       
   101 fun indentBlock (Block {indent = x, ...}) = x;
       
   102 
       
   103 fun isConsistentBlock block = isConsistentStyle (styleBlock block);
       
   104 
       
   105 fun isInconsistentBlock block = isInconsistentStyle (styleBlock block);
       
   106 
       
   107 (* ------------------------------------------------------------------------- *)
       
   108 (* Words are unbreakable strings annotated with their effective size.        *)
       
   109 (* ------------------------------------------------------------------------- *)
       
   110 
       
   111 datatype word = Word of {word : string, size : int};
       
   112 
       
   113 fun mkWord s = Word {word = s, size = String.size s};
       
   114 
       
   115 val emptyWord = mkWord "";
       
   116 
       
   117 fun charWord c = mkWord (str c);
       
   118 
       
   119 fun spacesWord i = Word {word = nSpaces i, size = i};
       
   120 
       
   121 fun sizeWord (Word {size = x, ...}) = x;
       
   122 
       
   123 fun renderWord (Word {word = x, ...}) = x;
       
   124 
       
   125 (* ------------------------------------------------------------------------- *)
       
   126 (* Possible line breaks.                                                     *)
       
   127 (* ------------------------------------------------------------------------- *)
       
   128 
       
   129 datatype break = Break of {size : int, extraIndent : int};
       
   130 
       
   131 fun mkBreak n = Break {size = n, extraIndent = 0};
       
   132 
       
   133 fun sizeBreak (Break {size = x, ...}) = x;
       
   134 
       
   135 fun extraIndentBreak (Break {extraIndent = x, ...}) = x;
       
   136 
       
   137 fun renderBreak b = nSpaces (sizeBreak b);
       
   138 
       
   139 fun updateSizeBreak size break =
       
   140     let
       
   141       val Break {size = _, extraIndent} = break
       
   142     in
       
   143       Break
       
   144         {size = size,
       
   145          extraIndent = extraIndent}
       
   146     end;
       
   147 
       
   148 fun appendBreak break1 break2 =
       
   149     let
       
   150 (*BasicDebug
       
   151       val () = warn "merging consecutive pretty-printing breaks"
       
   152 *)
       
   153       val Break {size = size1, extraIndent = extraIndent1} = break1
       
   154       and Break {size = size2, extraIndent = extraIndent2} = break2
       
   155 
       
   156       val size = size1 + size2
       
   157       and extraIndent = Int.max (extraIndent1,extraIndent2)
       
   158     in
       
   159       Break
       
   160         {size = size,
       
   161          extraIndent = extraIndent}
       
   162     end;
       
   163 
       
   164 (* ------------------------------------------------------------------------- *)
       
   165 (* A type of pretty-printers.                                                *)
       
   166 (* ------------------------------------------------------------------------- *)
       
   167 
       
   168 datatype step =
       
   169     BeginBlock of block
       
   170   | EndBlock
       
   171   | AddWord of word
       
   172   | AddBreak of break
       
   173   | AddNewline;
       
   174 
       
   175 type ppstream = step Stream.stream;
       
   176 
       
   177 type 'a pp = 'a -> ppstream;
       
   178 
       
   179 fun toStringStep step =
    95     case step of
   180     case step of
    96       BeginBlock _ => "BeginBlock"
   181       BeginBlock _ => "BeginBlock"
    97     | EndBlock => "EndBlock"
   182     | EndBlock => "EndBlock"
    98     | AddString _ => "AddString"
   183     | AddWord _ => "Word"
    99     | AddBreak _ => "AddBreak"
   184     | AddBreak _ => "Break"
   100     | AddNewline => "AddNewline";
   185     | AddNewline => "Newline";
   101 
       
   102 (* ------------------------------------------------------------------------- *)
       
   103 (* Pretty-printer primitives.                                                *)
       
   104 (* ------------------------------------------------------------------------- *)
       
   105 
       
   106 fun beginBlock style indent = Stream.singleton (BeginBlock (style,indent));
       
   107 
       
   108 val endBlock = Stream.singleton EndBlock;
       
   109 
       
   110 fun addString s = Stream.singleton (AddString s);
       
   111 
       
   112 fun addBreak spaces = Stream.singleton (AddBreak spaces);
       
   113 
       
   114 val addNewline = Stream.singleton AddNewline;
       
   115 
   186 
   116 val skip : ppstream = Stream.Nil;
   187 val skip : ppstream = Stream.Nil;
   117 
   188 
   118 fun sequence pp1 pp2 : ppstream = Stream.append pp1 (K pp2);
   189 fun sequence pp1 pp2 : ppstream = Stream.append pp1 (K pp2);
   119 
   190 
   120 local
   191 local
   121   fun dup pp n () = if n = 1 then pp else Stream.append pp (dup pp (n - 1));
   192   fun dup pp n () = if n = 1 then pp else Stream.append pp (dup pp (n - 1));
   122 in
   193 in
   123   fun duplicate n pp = if n = 0 then skip else dup pp n ();
   194   fun duplicate n pp : ppstream =
       
   195       let
       
   196 (*BasicDebug
       
   197         val () = if 0 <= n then () else raise Bug "Print.duplicate"
       
   198 *)
       
   199       in
       
   200         if n = 0 then skip else dup pp n ()
       
   201       end;
   124 end;
   202 end;
   125 
   203 
   126 val program : ppstream list -> ppstream = Stream.concatList;
   204 val program : ppstream list -> ppstream = Stream.concatList;
   127 
   205 
   128 val stream : ppstream Stream.stream -> ppstream = Stream.concat;
   206 val stream : ppstream Stream.stream -> ppstream = Stream.concat;
   129 
   207 
   130 fun block style indent pp = program [beginBlock style indent, pp, endBlock];
   208 (* ------------------------------------------------------------------------- *)
   131 
   209 (* Pretty-printing blocks.                                                   *)
   132 fun blockProgram style indent pps = block style indent (program pps);
   210 (* ------------------------------------------------------------------------- *)
   133 
   211 
   134 (* ------------------------------------------------------------------------- *)
   212 local
   135 (* Executing pretty-printers to generate lines.                              *)
   213   fun beginBlock b = Stream.singleton (BeginBlock b);
   136 (* ------------------------------------------------------------------------- *)
   214 
   137 
   215   val endBlock = Stream.singleton EndBlock;
   138 datatype blockBreakStyle =
   216 in
   139     InconsistentBlock
   217   fun block b pp = program [beginBlock b, pp, endBlock];
   140   | ConsistentBlock
   218 end;
   141   | BreakingBlock;
   219 
   142 
   220 fun consistentBlock i pps = block (mkConsistentBlock i) (program pps);
   143 datatype block =
   221 
   144     Block of
   222 fun inconsistentBlock i pps = block (mkInconsistentBlock i) (program pps);
   145       {indent : int,
   223 
   146        style : blockBreakStyle,
   224 (* ------------------------------------------------------------------------- *)
   147        size : int,
   225 (* Words are unbreakable strings annotated with their effective size.        *)
   148        chunks : chunk list}
   226 (* ------------------------------------------------------------------------- *)
   149 
   227 
   150 and chunk =
   228 fun ppWord w = Stream.singleton (AddWord w);
   151     StringChunk of {size : int, string : string}
   229 
   152   | BreakChunk of int
   230 val space = ppWord (mkWord " ");
   153   | BlockChunk of block;
   231 
   154 
   232 fun spaces i = ppWord (spacesWord i);
   155 datatype state =
   233 
   156     State of
   234 (* ------------------------------------------------------------------------- *)
   157       {blocks : block list,
   235 (* Possible line breaks.                                                     *)
   158        lineIndent : int,
   236 (* ------------------------------------------------------------------------- *)
   159        lineSize : int};
   237 
   160 
   238 fun ppBreak b = Stream.singleton (AddBreak b);
   161 val initialIndent = 0;
   239 
   162 
   240 fun breaks i = ppBreak (mkBreak i);
   163 val initialStyle = Inconsistent;
   241 
   164 
   242 val break = breaks 1;
   165 fun liftStyle style =
   243 
   166     case style of
   244 (* ------------------------------------------------------------------------- *)
   167       Inconsistent => InconsistentBlock
   245 (* Forced line breaks.                                                       *)
   168     | Consistent => ConsistentBlock;
   246 (* ------------------------------------------------------------------------- *)
   169 
   247 
   170 fun breakStyle style =
   248 val newline = Stream.singleton AddNewline;
   171     case style of
   249 
   172       ConsistentBlock => BreakingBlock
   250 fun newlines i = duplicate i newline;
   173     | _ => style;
   251 
   174 
   252 (* ------------------------------------------------------------------------- *)
   175 fun sizeBlock (Block {size,...}) = size;
   253 (* Pretty-printer combinators.                                               *)
   176 
   254 (* ------------------------------------------------------------------------- *)
   177 fun sizeChunk chunk =
   255 
   178     case chunk of
   256 fun ppMap f ppB a : ppstream = ppB (f a);
   179       StringChunk {size,...} => size
   257 
   180     | BreakChunk spaces => spaces
   258 fun ppBracket' l r ppA a =
   181     | BlockChunk block => sizeBlock block;
   259     let
   182 
   260       val n = sizeWord l
   183 val splitChunks =
   261     in
   184     let
   262       inconsistentBlock n
   185       fun split _ [] = NONE
   263         [ppWord l,
   186         | split acc (chunk :: chunks) =
   264          ppA a,
   187           case chunk of
   265          ppWord r]
   188             BreakChunk _ => SOME (rev acc, chunks)
       
   189           | _ => split (chunk :: acc) chunks
       
   190     in
       
   191       split []
       
   192     end;
   266     end;
   193 
   267 
   194 val sizeChunks = List.foldl (fn (c,z) => sizeChunk c + z) 0;
   268 fun ppOp' w = sequence (ppWord w) break;
   195 
       
   196 local
       
   197   fun flatten acc chunks =
       
   198       case chunks of
       
   199         [] => rev acc
       
   200       | chunk :: chunks =>
       
   201         case chunk of
       
   202           StringChunk {string = s, ...} => flatten (s :: acc) chunks
       
   203         | BreakChunk n => flatten (nSpaces n :: acc) chunks
       
   204         | BlockChunk (Block {chunks = l, ...}) =>
       
   205           flatten acc (List.revAppend (l,chunks));
       
   206 in
       
   207   fun renderChunks indent chunks =
       
   208       {indent = indent,
       
   209        line = String.concat (flatten [] (rev chunks))};
       
   210 end;
       
   211 
       
   212 fun renderChunk indent chunk = renderChunks indent [chunk];
       
   213 
       
   214 fun isEmptyBlock block =
       
   215     let
       
   216       val Block {indent = _, style = _, size, chunks} = block
       
   217 
       
   218       val empty = List.null chunks
       
   219 
       
   220 (*BasicDebug
       
   221       val _ = not empty orelse size = 0 orelse
       
   222               raise Bug "Print.isEmptyBlock: bad size"
       
   223 *)
       
   224     in
       
   225       empty
       
   226     end;
       
   227 
       
   228 (*BasicDebug
       
   229 fun checkBlock ind block =
       
   230     let
       
   231       val Block {indent, style = _, size, chunks} = block
       
   232       val _ = indent >= ind orelse raise Bug "Print.checkBlock: bad indents"
       
   233       val size' = checkChunks indent chunks
       
   234       val _ = size = size' orelse raise Bug "Print.checkBlock: wrong size"
       
   235     in
       
   236       size
       
   237     end
       
   238 
       
   239 and checkChunks ind chunks =
       
   240     case chunks of
       
   241       [] => 0
       
   242     | chunk :: chunks => checkChunk ind chunk + checkChunks ind chunks
       
   243 
       
   244 and checkChunk ind chunk =
       
   245     case chunk of
       
   246       StringChunk {size,...} => size
       
   247     | BreakChunk spaces => spaces
       
   248     | BlockChunk block => checkBlock ind block;
       
   249 
       
   250 val checkBlocks =
       
   251     let
       
   252       fun check ind blocks =
       
   253           case blocks of
       
   254             [] => 0
       
   255           | block :: blocks =>
       
   256             let
       
   257               val Block {indent,...} = block
       
   258             in
       
   259               checkBlock ind block + check indent blocks
       
   260             end
       
   261     in
       
   262       check initialIndent o rev
       
   263     end;
       
   264 *)
       
   265 
       
   266 val initialBlock =
       
   267     let
       
   268       val indent = initialIndent
       
   269       val style = liftStyle initialStyle
       
   270       val size = 0
       
   271       val chunks = []
       
   272     in
       
   273       Block
       
   274         {indent = indent,
       
   275          style = style,
       
   276          size = size,
       
   277          chunks = chunks}
       
   278     end;
       
   279 
       
   280 val initialState =
       
   281     let
       
   282       val blocks = [initialBlock]
       
   283       val lineIndent = initialIndent
       
   284       val lineSize = 0
       
   285     in
       
   286       State
       
   287         {blocks = blocks,
       
   288          lineIndent = lineIndent,
       
   289          lineSize = lineSize}
       
   290     end;
       
   291 
       
   292 (*BasicDebug
       
   293 fun checkState state =
       
   294     (let
       
   295        val State {blocks, lineIndent = _, lineSize} = state
       
   296        val lineSize' = checkBlocks blocks
       
   297        val _ = lineSize = lineSize' orelse
       
   298                raise Error "wrong lineSize"
       
   299      in
       
   300        ()
       
   301      end
       
   302      handle Error err => raise Bug err)
       
   303     handle Bug bug => raise Bug ("Print.checkState: " ^ bug);
       
   304 *)
       
   305 
       
   306 fun isFinalState state =
       
   307     let
       
   308       val State {blocks,lineIndent,lineSize} = state
       
   309     in
       
   310       case blocks of
       
   311         [] => raise Bug "Print.isFinalState: no block"
       
   312       | [block] => isEmptyBlock block
       
   313       | _ :: _ :: _ => false
       
   314     end;
       
   315 
       
   316 local
       
   317   fun renderBreak lineIndent (chunks,lines) =
       
   318       let
       
   319         val line = renderChunks lineIndent chunks
       
   320 
       
   321         val lines = line :: lines
       
   322       in
       
   323         lines
       
   324       end;
       
   325 
       
   326   fun renderBreaks lineIndent lineIndent' breaks lines =
       
   327       case rev breaks of
       
   328         [] => raise Bug "Print.renderBreaks"
       
   329       | c :: cs =>
       
   330         let
       
   331           val lines = renderBreak lineIndent (c,lines)
       
   332         in
       
   333           List.foldl (renderBreak lineIndent') lines cs
       
   334         end;
       
   335 
       
   336   fun splitAllChunks cumulatingChunks =
       
   337       let
       
   338         fun split chunks =
       
   339             case splitChunks chunks of
       
   340               SOME (prefix,chunks) => prefix :: split chunks
       
   341             | NONE => [List.concat (chunks :: cumulatingChunks)]
       
   342       in
       
   343         split
       
   344       end;
       
   345 
       
   346   fun mkBreak style cumulatingChunks chunks =
       
   347       case splitChunks chunks of
       
   348         NONE => NONE
       
   349       | SOME (chunks,broken) =>
       
   350         let
       
   351           val breaks =
       
   352               case style of
       
   353                 InconsistentBlock =>
       
   354                 [List.concat (broken :: cumulatingChunks)]
       
   355               | _ => splitAllChunks cumulatingChunks broken
       
   356         in
       
   357           SOME (breaks,chunks)
       
   358         end;
       
   359 
       
   360   fun naturalBreak blocks =
       
   361       case blocks of
       
   362         [] => Right ([],[])
       
   363       | block :: blocks =>
       
   364         case naturalBreak blocks of
       
   365           Left (breaks,blocks,lineIndent,lineSize) =>
       
   366           let
       
   367             val Block {size,...} = block
       
   368 
       
   369             val blocks = block :: blocks
       
   370 
       
   371             val lineSize = lineSize + size
       
   372           in
       
   373             Left (breaks,blocks,lineIndent,lineSize)
       
   374           end
       
   375         | Right (cumulatingChunks,blocks) =>
       
   376           let
       
   377             val Block {indent,style,size,chunks} = block
       
   378 
       
   379             val style = breakStyle style
       
   380           in
       
   381             case mkBreak style cumulatingChunks chunks of
       
   382               SOME (breaks,chunks) =>
       
   383               let
       
   384                 val size = sizeChunks chunks
       
   385 
       
   386                 val block =
       
   387                     Block
       
   388                       {indent = indent,
       
   389                        style = style,
       
   390                        size = size,
       
   391                        chunks = chunks}
       
   392 
       
   393                 val blocks = block :: blocks
       
   394 
       
   395                 val lineIndent = indent
       
   396 
       
   397                 val lineSize = size
       
   398               in
       
   399                 Left (breaks,blocks,lineIndent,lineSize)
       
   400               end
       
   401             | NONE =>
       
   402               let
       
   403                 val cumulatingChunks = chunks :: cumulatingChunks
       
   404 
       
   405                 val size = 0
       
   406 
       
   407                 val chunks = []
       
   408 
       
   409                 val block =
       
   410                     Block
       
   411                       {indent = indent,
       
   412                        style = style,
       
   413                        size = size,
       
   414                        chunks = chunks}
       
   415 
       
   416                 val blocks = block :: blocks
       
   417               in
       
   418                 Right (cumulatingChunks,blocks)
       
   419               end
       
   420           end;
       
   421 
       
   422   fun forceBreakBlock cumulatingChunks block =
       
   423       let
       
   424         val Block {indent, style, size = _, chunks} = block
       
   425 
       
   426         val style = breakStyle style
       
   427 
       
   428         val break =
       
   429             case mkBreak style cumulatingChunks chunks of
       
   430               SOME (breaks,chunks) =>
       
   431               let
       
   432                 val lineSize = sizeChunks chunks
       
   433                 val lineIndent = indent
       
   434               in
       
   435                 SOME (breaks,chunks,lineIndent,lineSize)
       
   436               end
       
   437             | NONE => forceBreakChunks cumulatingChunks chunks
       
   438       in
       
   439         case break of
       
   440           SOME (breaks,chunks,lineIndent,lineSize) =>
       
   441           let
       
   442             val size = lineSize
       
   443 
       
   444             val block =
       
   445                 Block
       
   446                   {indent = indent,
       
   447                    style = style,
       
   448                    size = size,
       
   449                    chunks = chunks}
       
   450           in
       
   451             SOME (breaks,block,lineIndent,lineSize)
       
   452           end
       
   453         | NONE => NONE
       
   454       end
       
   455 
       
   456   and forceBreakChunks cumulatingChunks chunks =
       
   457       case chunks of
       
   458         [] => NONE
       
   459       | chunk :: chunks =>
       
   460         case forceBreakChunk (chunks :: cumulatingChunks) chunk of
       
   461           SOME (breaks,chunk,lineIndent,lineSize) =>
       
   462           let
       
   463             val chunks = [chunk]
       
   464           in
       
   465             SOME (breaks,chunks,lineIndent,lineSize)
       
   466           end
       
   467         | NONE =>
       
   468           case forceBreakChunks cumulatingChunks chunks of
       
   469             SOME (breaks,chunks,lineIndent,lineSize) =>
       
   470             let
       
   471               val chunks = chunk :: chunks
       
   472 
       
   473               val lineSize = lineSize + sizeChunk chunk
       
   474             in
       
   475               SOME (breaks,chunks,lineIndent,lineSize)
       
   476             end
       
   477           | NONE => NONE
       
   478 
       
   479   and forceBreakChunk cumulatingChunks chunk =
       
   480       case chunk of
       
   481         StringChunk _ => NONE
       
   482       | BreakChunk _ => raise Bug "Print.forceBreakChunk: BreakChunk"
       
   483       | BlockChunk block =>
       
   484         case forceBreakBlock cumulatingChunks block of
       
   485           SOME (breaks,block,lineIndent,lineSize) =>
       
   486           let
       
   487             val chunk = BlockChunk block
       
   488           in
       
   489             SOME (breaks,chunk,lineIndent,lineSize)
       
   490           end
       
   491         | NONE => NONE;
       
   492 
       
   493   fun forceBreak cumulatingChunks blocks' blocks =
       
   494       case blocks of
       
   495         [] => NONE
       
   496       | block :: blocks =>
       
   497         let
       
   498           val cumulatingChunks =
       
   499               case cumulatingChunks of
       
   500                 [] => raise Bug "Print.forceBreak: null cumulatingChunks"
       
   501               | _ :: cumulatingChunks => cumulatingChunks
       
   502 
       
   503           val blocks' =
       
   504               case blocks' of
       
   505                 [] => raise Bug "Print.forceBreak: null blocks'"
       
   506               | _ :: blocks' => blocks'
       
   507         in
       
   508           case forceBreakBlock cumulatingChunks block of
       
   509             SOME (breaks,block,lineIndent,lineSize) =>
       
   510             let
       
   511               val blocks = block :: blocks'
       
   512             in
       
   513               SOME (breaks,blocks,lineIndent,lineSize)
       
   514             end
       
   515           | NONE =>
       
   516             case forceBreak cumulatingChunks blocks' blocks of
       
   517               SOME (breaks,blocks,lineIndent,lineSize) =>
       
   518               let
       
   519                 val blocks = block :: blocks
       
   520 
       
   521                 val Block {size,...} = block
       
   522 
       
   523                 val lineSize = lineSize + size
       
   524               in
       
   525                 SOME (breaks,blocks,lineIndent,lineSize)
       
   526               end
       
   527             | NONE => NONE
       
   528         end;
       
   529 
       
   530   fun normalize lineLength lines state =
       
   531       let
       
   532         val State {blocks,lineIndent,lineSize} = state
       
   533       in
       
   534         if lineIndent + lineSize <= lineLength then (lines,state)
       
   535         else
       
   536           let
       
   537             val break =
       
   538                 case naturalBreak blocks of
       
   539                   Left break => SOME break
       
   540                 | Right (c,b) => forceBreak c b blocks
       
   541           in
       
   542             case break of
       
   543               SOME (breaks,blocks,lineIndent',lineSize) =>
       
   544               let
       
   545                 val lines = renderBreaks lineIndent lineIndent' breaks lines
       
   546 
       
   547                 val state =
       
   548                     State
       
   549                       {blocks = blocks,
       
   550                        lineIndent = lineIndent',
       
   551                        lineSize = lineSize}
       
   552               in
       
   553                 normalize lineLength lines state
       
   554               end
       
   555             | NONE => (lines,state)
       
   556           end
       
   557       end;
       
   558 
       
   559 (*BasicDebug
       
   560   val normalize = fn lineLength => fn lines => fn state =>
       
   561       let
       
   562         val () = checkState state
       
   563       in
       
   564         normalize lineLength lines state
       
   565       end
       
   566       handle Bug bug =>
       
   567         raise Bug ("Print.normalize: before normalize:\n" ^ bug)
       
   568 *)
       
   569 
       
   570   fun executeBeginBlock (style,ind) lines state =
       
   571       let
       
   572         val State {blocks,lineIndent,lineSize} = state
       
   573 
       
   574         val Block {indent,...} =
       
   575             case blocks of
       
   576               [] => raise Bug "Print.executeBeginBlock: no block"
       
   577             | block :: _ => block
       
   578 
       
   579         val indent = indent + ind
       
   580 
       
   581         val style = liftStyle style
       
   582 
       
   583         val size = 0
       
   584 
       
   585         val chunks = []
       
   586 
       
   587         val block =
       
   588             Block
       
   589               {indent = indent,
       
   590                style = style,
       
   591                size = size,
       
   592                chunks = chunks}
       
   593 
       
   594         val blocks = block :: blocks
       
   595 
       
   596         val state =
       
   597             State
       
   598               {blocks = blocks,
       
   599                lineIndent = lineIndent,
       
   600                lineSize = lineSize}
       
   601       in
       
   602         (lines,state)
       
   603       end;
       
   604 
       
   605   fun executeEndBlock lines state =
       
   606       let
       
   607         val State {blocks,lineIndent,lineSize} = state
       
   608 
       
   609         val (lineSize,blocks) =
       
   610             case blocks of
       
   611               [] => raise Bug "Print.executeEndBlock: no block"
       
   612             | topBlock :: blocks =>
       
   613               let
       
   614                 val Block
       
   615                       {indent = topIndent,
       
   616                        style = topStyle,
       
   617                        size = topSize,
       
   618                        chunks = topChunks} = topBlock
       
   619               in
       
   620                 case topChunks of
       
   621                   [] => (lineSize,blocks)
       
   622                 | headTopChunks :: tailTopChunks =>
       
   623                   let
       
   624                     val (lineSize,topSize,topChunks) =
       
   625                         case headTopChunks of
       
   626                           BreakChunk spaces =>
       
   627                           let
       
   628                             val lineSize = lineSize - spaces
       
   629                             and topSize = topSize - spaces
       
   630                             and topChunks = tailTopChunks
       
   631                           in
       
   632                             (lineSize,topSize,topChunks)
       
   633                           end
       
   634                         | _ => (lineSize,topSize,topChunks)
       
   635 
       
   636                     val topBlock =
       
   637                         Block
       
   638                           {indent = topIndent,
       
   639                            style = topStyle,
       
   640                            size = topSize,
       
   641                            chunks = topChunks}
       
   642                   in
       
   643                     case blocks of
       
   644                       [] => raise Error "Print.executeEndBlock: no block"
       
   645                     | block :: blocks =>
       
   646                       let
       
   647                         val Block {indent,style,size,chunks} = block
       
   648 
       
   649                         val size = size + topSize
       
   650 
       
   651                         val chunks = BlockChunk topBlock :: chunks
       
   652 
       
   653                         val block =
       
   654                             Block
       
   655                               {indent = indent,
       
   656                                style = style,
       
   657                                size = size,
       
   658                                chunks = chunks}
       
   659 
       
   660                         val blocks = block :: blocks
       
   661                       in
       
   662                         (lineSize,blocks)
       
   663                       end
       
   664                   end
       
   665               end
       
   666 
       
   667         val state =
       
   668             State
       
   669               {blocks = blocks,
       
   670                lineIndent = lineIndent,
       
   671                lineSize = lineSize}
       
   672       in
       
   673         (lines,state)
       
   674       end;
       
   675 
       
   676   fun executeAddString lineLength (s,n) lines state =
       
   677       let
       
   678         val State {blocks,lineIndent,lineSize} = state
       
   679 
       
   680         val blocks =
       
   681             case blocks of
       
   682               [] => raise Bug "Print.executeAddString: no block"
       
   683             | Block {indent,style,size,chunks} :: blocks =>
       
   684               let
       
   685                 val size = size + n
       
   686 
       
   687                 val chunk = StringChunk {size = n, string = s}
       
   688 
       
   689                 val chunks = chunk :: chunks
       
   690 
       
   691                 val block =
       
   692                     Block
       
   693                       {indent = indent,
       
   694                        style = style,
       
   695                        size = size,
       
   696                        chunks = chunks}
       
   697 
       
   698                 val blocks = block :: blocks
       
   699               in
       
   700                 blocks
       
   701               end
       
   702 
       
   703         val lineSize = lineSize + n
       
   704 
       
   705         val state =
       
   706             State
       
   707               {blocks = blocks,
       
   708                lineIndent = lineIndent,
       
   709                lineSize = lineSize}
       
   710       in
       
   711         normalize lineLength lines state
       
   712       end;
       
   713 
       
   714   fun executeAddBreak lineLength spaces lines state =
       
   715       let
       
   716         val State {blocks,lineIndent,lineSize} = state
       
   717 
       
   718         val (blocks,lineSize) =
       
   719             case blocks of
       
   720               [] => raise Bug "Print.executeAddBreak: no block"
       
   721             | Block {indent,style,size,chunks} :: blocks' =>
       
   722               case chunks of
       
   723                 [] => (blocks,lineSize)
       
   724               | chunk :: chunks' =>
       
   725                 let
       
   726                   val spaces =
       
   727                       case style of
       
   728                         BreakingBlock => lineLength + 1
       
   729                       | _ => spaces
       
   730 
       
   731                   val size = size + spaces
       
   732 
       
   733                   val chunks =
       
   734                       case chunk of
       
   735                         BreakChunk k => BreakChunk (k + spaces) :: chunks'
       
   736                       | _ => BreakChunk spaces :: chunks
       
   737 
       
   738                   val block =
       
   739                       Block
       
   740                         {indent = indent,
       
   741                          style = style,
       
   742                          size = size,
       
   743                          chunks = chunks}
       
   744 
       
   745                   val blocks = block :: blocks'
       
   746 
       
   747                   val lineSize = lineSize + spaces
       
   748                 in
       
   749                   (blocks,lineSize)
       
   750                 end
       
   751 
       
   752         val state =
       
   753             State
       
   754               {blocks = blocks,
       
   755                lineIndent = lineIndent,
       
   756                lineSize = lineSize}
       
   757       in
       
   758         normalize lineLength lines state
       
   759       end;
       
   760 
       
   761   fun executeBigBreak lineLength lines state =
       
   762       executeAddBreak lineLength (lineLength + 1) lines state;
       
   763 
       
   764   fun executeAddNewline lineLength lines state =
       
   765       let
       
   766         val (lines,state) =
       
   767             executeAddString lineLength emptyStringSize lines state
       
   768 
       
   769         val (lines,state) =
       
   770             executeBigBreak lineLength lines state
       
   771       in
       
   772         executeAddString lineLength emptyStringSize lines state
       
   773       end;
       
   774 
       
   775   fun final lineLength lines state =
       
   776       let
       
   777         val lines =
       
   778             if isFinalState state then lines
       
   779             else
       
   780               let
       
   781                 val (lines,state) = executeBigBreak lineLength lines state
       
   782 
       
   783 (*BasicDebug
       
   784                 val _ = isFinalState state orelse raise Bug "Print.final"
       
   785 *)
       
   786               in
       
   787                 lines
       
   788               end
       
   789       in
       
   790         if List.null lines then Stream.Nil else Stream.singleton lines
       
   791       end;
       
   792 in
       
   793   fun execute {lineLength} =
       
   794       let
       
   795         fun advance step state =
       
   796             let
       
   797               val lines = []
       
   798             in
       
   799               case step of
       
   800                 BeginBlock style_ind => executeBeginBlock style_ind lines state
       
   801               | EndBlock => executeEndBlock lines state
       
   802               | AddString s => executeAddString lineLength s lines state
       
   803               | AddBreak spaces => executeAddBreak lineLength spaces lines state
       
   804               | AddNewline => executeAddNewline lineLength lines state
       
   805             end
       
   806 
       
   807 (*BasicDebug
       
   808         val advance = fn step => fn state =>
       
   809             let
       
   810               val (lines,state) = advance step state
       
   811               val () = checkState state
       
   812             in
       
   813               (lines,state)
       
   814             end
       
   815             handle Bug bug =>
       
   816               raise Bug ("Print.advance: after " ^ stepToString step ^
       
   817                          " command:\n" ^ bug)
       
   818 *)
       
   819       in
       
   820         revConcat o Stream.maps advance (final lineLength []) initialState
       
   821       end;
       
   822 end;
       
   823 
       
   824 (* ------------------------------------------------------------------------- *)
       
   825 (* Pretty-printer combinators.                                               *)
       
   826 (* ------------------------------------------------------------------------- *)
       
   827 
       
   828 type 'a pp = 'a -> ppstream;
       
   829 
       
   830 fun ppMap f ppB a : ppstream = ppB (f a);
       
   831 
       
   832 fun ppBracket' l r ppA a =
       
   833     let
       
   834       val (_,n) = l
       
   835     in
       
   836       blockProgram Inconsistent n
       
   837         [addString l,
       
   838          ppA a,
       
   839          addString r]
       
   840     end;
       
   841 
       
   842 fun ppOp' s = sequence (addString s) (addBreak 1);
       
   843 
   269 
   844 fun ppOp2' ab ppA ppB (a,b) =
   270 fun ppOp2' ab ppA ppB (a,b) =
   845     blockProgram Inconsistent 0
   271     inconsistentBlock 0
   846       [ppA a,
   272       [ppA a,
   847        ppOp' ab,
   273        ppOp' ab,
   848        ppB b];
   274        ppB b];
   849 
   275 
   850 fun ppOp3' ab bc ppA ppB ppC (a,b,c) =
   276 fun ppOp3' ab bc ppA ppB ppC (a,b,c) =
   851     blockProgram Inconsistent 0
   277     inconsistentBlock 0
   852       [ppA a,
   278       [ppA a,
   853        ppOp' ab,
   279        ppOp' ab,
   854        ppB b,
   280        ppB b,
   855        ppOp' bc,
   281        ppOp' bc,
   856        ppC c];
   282        ppC c];
   858 fun ppOpList' s ppA =
   284 fun ppOpList' s ppA =
   859     let
   285     let
   860       fun ppOpA a = sequence (ppOp' s) (ppA a)
   286       fun ppOpA a = sequence (ppOp' s) (ppA a)
   861     in
   287     in
   862       fn [] => skip
   288       fn [] => skip
   863        | h :: t => blockProgram Inconsistent 0 (ppA h :: List.map ppOpA t)
   289        | h :: t => inconsistentBlock 0 (ppA h :: List.map ppOpA t)
   864     end;
   290     end;
   865 
   291 
   866 fun ppOpStream' s ppA =
   292 fun ppOpStream' s ppA =
   867     let
   293     let
   868       fun ppOpA a = sequence (ppOp' s) (ppA a)
   294       fun ppOpA a = sequence (ppOp' s) (ppA a)
   869     in
   295     in
   870       fn Stream.Nil => skip
   296       fn Stream.Nil => skip
   871        | Stream.Cons (h,t) =>
   297        | Stream.Cons (h,t) =>
   872          blockProgram Inconsistent 0
   298          inconsistentBlock 0
   873            [ppA h,
   299            [ppA h,
   874             Stream.concat (Stream.map ppOpA (t ()))]
   300             Stream.concat (Stream.map ppOpA (t ()))]
   875     end;
   301     end;
   876 
   302 
   877 fun ppBracket l r = ppBracket' (mkStringSize l) (mkStringSize r);
   303 fun ppBracket l r = ppBracket' (mkWord l) (mkWord r);
   878 
   304 
   879 fun ppOp s = ppOp' (mkStringSize s);
   305 fun ppOp s = ppOp' (mkWord s);
   880 
   306 
   881 fun ppOp2 ab = ppOp2' (mkStringSize ab);
   307 fun ppOp2 ab = ppOp2' (mkWord ab);
   882 
   308 
   883 fun ppOp3 ab bc = ppOp3' (mkStringSize ab) (mkStringSize bc);
   309 fun ppOp3 ab bc = ppOp3' (mkWord ab) (mkWord bc);
   884 
   310 
   885 fun ppOpList s = ppOpList' (mkStringSize s);
   311 fun ppOpList s = ppOpList' (mkWord s);
   886 
   312 
   887 fun ppOpStream s = ppOpStream' (mkStringSize s);
   313 fun ppOpStream s = ppOpStream' (mkWord s);
   888 
   314 
   889 (* ------------------------------------------------------------------------- *)
   315 (* ------------------------------------------------------------------------- *)
   890 (* Pretty-printers for common types.                                         *)
   316 (* Pretty-printers for common types.                                         *)
   891 (* ------------------------------------------------------------------------- *)
   317 (* ------------------------------------------------------------------------- *)
   892 
   318 
   893 fun ppChar c = addString (str c, 1);
   319 fun ppChar c = ppWord (charWord c);
   894 
   320 
   895 fun ppString s = addString (mkStringSize s);
   321 fun ppString s = ppWord (mkWord s);
   896 
   322 
   897 fun ppEscapeString escape = ppMap (escapeString escape) ppString;
   323 fun ppEscapeString escape = ppMap (escapeString escape) ppString;
   898 
   324 
   899 local
   325 local
   900   val pp = ppString "()";
   326   val pp = ppString "()";
   947       | EQUAL => ppEqual
   373       | EQUAL => ppEqual
   948       | GREATER => ppGreater;
   374       | GREATER => ppGreater;
   949 end;
   375 end;
   950 
   376 
   951 local
   377 local
   952   val left = mkStringSize "["
   378   val left = mkWord "["
   953   and right = mkStringSize "]"
   379   and right = mkWord "]"
   954   and sep = mkStringSize ",";
   380   and sep = mkWord ",";
   955 in
   381 in
   956   fun ppList ppX xs = ppBracket' left right (ppOpList' sep ppX) xs;
   382   fun ppList ppX xs = ppBracket' left right (ppOpList' sep ppX) xs;
   957 
   383 
   958   fun ppStream ppX xs = ppBracket' left right (ppOpStream' sep ppX) xs;
   384   fun ppStream ppX xs = ppBracket' left right (ppOpStream' sep ppX) xs;
   959 end;
   385 end;
   966         SOME x => ppX x
   392         SOME x => ppX x
   967       | NONE => ppNone;
   393       | NONE => ppNone;
   968 end;
   394 end;
   969 
   395 
   970 local
   396 local
   971   val left = mkStringSize "("
   397   val left = mkWord "("
   972   and right = mkStringSize ")"
   398   and right = mkWord ")"
   973   and sep = mkStringSize ",";
   399   and sep = mkWord ",";
   974 in
   400 in
   975   fun ppPair ppA ppB =
   401   fun ppPair ppA ppB =
   976       ppBracket' left right (ppOp2' sep ppA ppB);
   402       ppBracket' left right (ppOp2' sep ppA ppB);
   977 
   403 
   978   fun ppTriple ppA ppB ppC =
   404   fun ppTriple ppA ppB ppC =
   979       ppBracket' left right (ppOp3' sep sep ppA ppB ppC);
   405       ppBracket' left right (ppOp3' sep sep ppA ppB ppC);
   980 end;
   406 end;
   981 
   407 
   982 val ppBreakStyle = ppMap breakStyleToString ppString;
       
   983 
       
   984 val ppStep = ppMap stepToString ppString;
       
   985 
       
   986 val ppStringSize =
       
   987     let
       
   988       val left = mkStringSize "\""
       
   989       and right = mkStringSize "\""
       
   990       and escape = {escape = [#"\""]}
       
   991 
       
   992       val pp = ppBracket' left right (ppEscapeString escape)
       
   993     in
       
   994       fn (s,n) => if size s = n then pp s else ppPair pp ppInt (s,n)
       
   995     end;
       
   996 
       
   997 fun ppStep step =
       
   998     blockProgram Inconsistent 2
       
   999       (ppStep step ::
       
  1000        (case step of
       
  1001           BeginBlock style_indent =>
       
  1002             [addBreak 1,
       
  1003              ppPair ppBreakStyle ppInt style_indent]
       
  1004         | EndBlock => []
       
  1005         | AddString s =>
       
  1006             [addBreak 1,
       
  1007              ppStringSize s]
       
  1008         | AddBreak n =>
       
  1009             [addBreak 1,
       
  1010              ppInt n]
       
  1011         | AddNewline => []));
       
  1012 
       
  1013 val ppPpstream = ppStream ppStep;
       
  1014 
       
  1015 fun ppException e = ppString (exnMessage e);
   408 fun ppException e = ppString (exnMessage e);
       
   409 
       
   410 (* ------------------------------------------------------------------------- *)
       
   411 (* A type of pretty-printers.                                                *)
       
   412 (* ------------------------------------------------------------------------- *)
       
   413 
       
   414 local
       
   415   val ppStepType = ppMap toStringStep ppString;
       
   416 
       
   417   val ppStyle = ppMap toStringStyle ppString;
       
   418 
       
   419   val ppBlockInfo =
       
   420       let
       
   421         val sep = mkWord " "
       
   422       in
       
   423         fn Block {style = s, indent = i} =>
       
   424            program [ppStyle s, ppWord sep, ppInt i]
       
   425       end;
       
   426 
       
   427   val ppWordInfo =
       
   428       let
       
   429         val left = mkWord "\""
       
   430         and right = mkWord "\""
       
   431         and escape = {escape = [#"\""]}
       
   432 
       
   433         val pp = ppBracket' left right (ppEscapeString escape)
       
   434       in
       
   435         fn Word {word = s, size = n} =>
       
   436            if size s = n then pp s else ppPair pp ppInt (s,n)
       
   437       end;
       
   438 
       
   439   val ppBreakInfo =
       
   440       let
       
   441         val sep = mkWord "+"
       
   442       in
       
   443         fn Break {size = n, extraIndent = k} =>
       
   444            if k = 0 then ppInt n else program [ppInt n, ppWord sep, ppInt k]
       
   445       end;
       
   446 
       
   447   fun ppStep step =
       
   448       inconsistentBlock 2
       
   449         (ppStepType step ::
       
   450          (case step of
       
   451             BeginBlock b =>
       
   452               [break,
       
   453                ppBlockInfo b]
       
   454           | EndBlock => []
       
   455           | AddWord w =>
       
   456               [break,
       
   457                ppWordInfo w]
       
   458           | AddBreak b =>
       
   459               [break,
       
   460                ppBreakInfo b]
       
   461           | AddNewline => []));
       
   462 in
       
   463   val ppPpstream = ppStream ppStep;
       
   464 end;
  1016 
   465 
  1017 (* ------------------------------------------------------------------------- *)
   466 (* ------------------------------------------------------------------------- *)
  1018 (* Pretty-printing infix operators.                                          *)
   467 (* Pretty-printing infix operators.                                          *)
  1019 (* ------------------------------------------------------------------------- *)
   468 (* ------------------------------------------------------------------------- *)
  1020 
   469 
  1118           in
   567           in
  1119             ppTerm aligned tm_r
   568             ppTerm aligned tm_r
  1120           end
   569           end
  1121     in
   570     in
  1122       fn tm_t_a_b_r as (_,t,_,_,_) =>
   571       fn tm_t_a_b_r as (_,t,_,_,_) =>
  1123          if isLayer t then block Inconsistent 0 (ppLayer tm_t_a_b_r)
   572          if isLayer t then inconsistentBlock 0 [ppLayer tm_t_a_b_r]
  1124          else ppLower tm_t_a_b_r
   573          else ppLower tm_t_a_b_r
  1125     end;
   574     end;
  1126 
   575 
  1127 local
   576 local
  1128   val leftBrack = mkStringSize "("
   577   val leftBrack = mkWord "("
  1129   and rightBrack = mkStringSize ")";
   578   and rightBrack = mkWord ")";
  1130 in
   579 in
  1131   fun ppInfixes ops =
   580   fun ppInfixes ops =
  1132       let
   581       let
  1133         val layers = layerInfixes ops
   582         val layers = layerInfixes ops
  1134 
   583 
  1158            end
   607            end
  1159       end;
   608       end;
  1160 end;
   609 end;
  1161 
   610 
  1162 (* ------------------------------------------------------------------------- *)
   611 (* ------------------------------------------------------------------------- *)
  1163 (* Executing pretty-printers with a global line length.                      *)
   612 (* A type of output lines.                                                   *)
  1164 (* ------------------------------------------------------------------------- *)
   613 (* ------------------------------------------------------------------------- *)
  1165 
   614 
  1166 val lineLength = ref initialLineLength;
   615 type line = {indent : int, line : string};
       
   616 
       
   617 val emptyLine =
       
   618     let
       
   619       val indent = 0
       
   620       and line = ""
       
   621     in
       
   622       {indent = indent,
       
   623        line = line}
       
   624     end;
       
   625 
       
   626 fun addEmptyLine lines = emptyLine :: lines;
       
   627 
       
   628 fun addLine lines indent line = {indent = indent, line = line} :: lines;
       
   629 
       
   630 (* ------------------------------------------------------------------------- *)
       
   631 (* Pretty-printer rendering.                                                 *)
       
   632 (* ------------------------------------------------------------------------- *)
       
   633 
       
   634 datatype chunk =
       
   635     WordChunk of word
       
   636   | BreakChunk of break
       
   637   | FrameChunk of frame
       
   638 
       
   639 and frame =
       
   640     Frame of
       
   641       {block : block,
       
   642        broken : bool,
       
   643        indent : int,
       
   644        size : int,
       
   645        chunks : chunk list};
       
   646 
       
   647 datatype state =
       
   648     State of
       
   649       {lineIndent : int,
       
   650        lineSize : int,
       
   651        stack : frame list};
       
   652 
       
   653 fun blockFrame (Frame {block = x, ...}) = x;
       
   654 
       
   655 fun brokenFrame (Frame {broken = x, ...}) = x;
       
   656 
       
   657 fun indentFrame (Frame {indent = x, ...}) = x;
       
   658 
       
   659 fun sizeFrame (Frame {size = x, ...}) = x;
       
   660 
       
   661 fun chunksFrame (Frame {chunks = x, ...}) = x;
       
   662 
       
   663 fun styleFrame frame = styleBlock (blockFrame frame);
       
   664 
       
   665 fun isConsistentFrame frame = isConsistentBlock (blockFrame frame);
       
   666 
       
   667 fun breakingFrame frame = isConsistentFrame frame andalso brokenFrame frame;
       
   668 
       
   669 fun sizeChunk chunk =
       
   670     case chunk of
       
   671       WordChunk w => sizeWord w
       
   672     | BreakChunk b => sizeBreak b
       
   673     | FrameChunk f => sizeFrame f;
       
   674 
       
   675 local
       
   676   fun add (c,acc) = sizeChunk c + acc;
       
   677 in
       
   678   fun sizeChunks cs = List.foldl add 0 cs;
       
   679 end;
       
   680 
       
   681 local
       
   682   fun flattenChunks acc chunks =
       
   683       case chunks of
       
   684         [] => acc
       
   685       | chunk :: chunks => flattenChunk acc chunk chunks
       
   686 
       
   687   and flattenChunk acc chunk chunks =
       
   688       case chunk of
       
   689         WordChunk w => flattenChunks (renderWord w :: acc) chunks
       
   690       | BreakChunk b => flattenChunks (renderBreak b :: acc) chunks
       
   691       | FrameChunk f => flattenFrame acc f chunks
       
   692 
       
   693   and flattenFrame acc frame chunks =
       
   694       flattenChunks acc (chunksFrame frame @ chunks);
       
   695 in
       
   696   fun renderChunks chunks = String.concat (flattenChunks [] chunks);
       
   697 end;
       
   698 
       
   699 fun addChunksLine lines indent chunks =
       
   700     addLine lines indent (renderChunks chunks);
       
   701 
       
   702 local
       
   703   fun add baseIndent ((extraIndent,chunks),lines) =
       
   704       addChunksLine lines (baseIndent + extraIndent) chunks;
       
   705 in
       
   706   fun addIndentChunksLines lines baseIndent indent_chunks =
       
   707       List.foldl (add baseIndent) lines indent_chunks;
       
   708 end;
       
   709 
       
   710 fun isEmptyFrame frame =
       
   711     let
       
   712       val chunks = chunksFrame frame
       
   713 
       
   714       val empty = List.null chunks
       
   715 
       
   716 (*BasicDebug
       
   717       val () =
       
   718           if not empty orelse sizeFrame frame = 0 then ()
       
   719           else raise Bug "Print.isEmptyFrame: bad size"
       
   720 *)
       
   721     in
       
   722       empty
       
   723     end;
       
   724 
       
   725 local
       
   726   fun breakInconsistent blockIndent =
       
   727       let
       
   728         fun break chunks =
       
   729             case chunks of
       
   730               [] => NONE
       
   731             | chunk :: chunks =>
       
   732               case chunk of
       
   733                 BreakChunk b =>
       
   734                 let
       
   735                   val pre = chunks
       
   736                   and indent = blockIndent + extraIndentBreak b
       
   737                   and post = []
       
   738                 in
       
   739                   SOME (pre,indent,post)
       
   740                 end
       
   741               | _ =>
       
   742                 case break chunks of
       
   743                   SOME (pre,indent,post) =>
       
   744                   let
       
   745                     val post = chunk :: post
       
   746                   in
       
   747                     SOME (pre,indent,post)
       
   748                   end
       
   749                 | NONE => NONE
       
   750       in
       
   751         break
       
   752       end;
       
   753 
       
   754   fun breakConsistent blockIndent =
       
   755       let
       
   756         fun break indent_chunks chunks =
       
   757             case breakInconsistent blockIndent chunks of
       
   758               NONE => (chunks,indent_chunks)
       
   759             | SOME (pre,indent,post) =>
       
   760               break ((indent,post) :: indent_chunks) pre
       
   761       in
       
   762         break []
       
   763       end;
       
   764 in
       
   765   fun breakFrame frame =
       
   766       let
       
   767         val Frame
       
   768               {block,
       
   769                broken = _,
       
   770                indent = _,
       
   771                size = _,
       
   772                chunks} = frame
       
   773 
       
   774         val blockIndent = indentBlock block
       
   775       in
       
   776         case breakInconsistent blockIndent chunks of
       
   777           NONE => NONE
       
   778         | SOME (pre,indent,post) =>
       
   779           let
       
   780             val broken = true
       
   781             and size = sizeChunks post
       
   782 
       
   783             val frame =
       
   784                 Frame
       
   785                   {block = block,
       
   786                    broken = broken,
       
   787                    indent = indent,
       
   788                    size = size,
       
   789                    chunks = post}
       
   790           in
       
   791             case styleBlock block of
       
   792               Inconsistent =>
       
   793               let
       
   794                 val indent_chunks = []
       
   795               in
       
   796                 SOME (pre,indent_chunks,frame)
       
   797               end
       
   798             | Consistent =>
       
   799               let
       
   800                 val (pre,indent_chunks) = breakConsistent blockIndent pre
       
   801               in
       
   802                 SOME (pre,indent_chunks,frame)
       
   803               end
       
   804           end
       
   805       end;
       
   806 end;
       
   807 
       
   808 fun removeChunksFrame frame =
       
   809     let
       
   810       val Frame
       
   811             {block,
       
   812              broken,
       
   813              indent,
       
   814              size = _,
       
   815              chunks} = frame
       
   816     in
       
   817       if broken andalso List.null chunks then NONE
       
   818       else
       
   819         let
       
   820           val frame =
       
   821               Frame
       
   822                 {block = block,
       
   823                  broken = true,
       
   824                  indent = indent,
       
   825                  size = 0,
       
   826                  chunks = []}
       
   827         in
       
   828           SOME (chunks,frame)
       
   829         end
       
   830     end;
       
   831 
       
   832 val removeChunksFrames =
       
   833     let
       
   834       fun remove frames =
       
   835           case frames of
       
   836             [] =>
       
   837             let
       
   838               val chunks = []
       
   839               and frames = NONE
       
   840               and indent = 0
       
   841             in
       
   842               (chunks,frames,indent)
       
   843             end
       
   844           | top :: rest =>
       
   845             let
       
   846               val (chunks,rest',indent) = remove rest
       
   847 
       
   848               val indent = indent + indentFrame top
       
   849 
       
   850               val (chunks,top') =
       
   851                   case removeChunksFrame top of
       
   852                     NONE => (chunks,NONE)
       
   853                   | SOME (topChunks,top) => (topChunks @ chunks, SOME top)
       
   854 
       
   855               val frames' =
       
   856                   case (top',rest') of
       
   857                     (NONE,NONE) => NONE
       
   858                   | (SOME top, NONE) => SOME (top :: rest)
       
   859                   | (NONE, SOME rest) => SOME (top :: rest)
       
   860                   | (SOME top, SOME rest) => SOME (top :: rest)
       
   861             in
       
   862               (chunks,frames',indent)
       
   863             end
       
   864     in
       
   865       fn frames =>
       
   866          let
       
   867            val (chunks,frames',indent) = remove frames
       
   868 
       
   869            val frames = Option.getOpt (frames',frames)
       
   870          in
       
   871            (chunks,frames,indent)
       
   872          end
       
   873     end;
       
   874 
       
   875 local
       
   876   fun breakUp lines lineIndent frames =
       
   877       case frames of
       
   878         [] => NONE
       
   879       | frame :: frames =>
       
   880         case breakUp lines lineIndent frames of
       
   881           SOME (lines_indent,lineSize,frames) =>
       
   882           let
       
   883             val lineSize = lineSize + sizeFrame frame
       
   884             and frames = frame :: frames
       
   885           in
       
   886             SOME (lines_indent,lineSize,frames)
       
   887           end
       
   888         | NONE =>
       
   889           case breakFrame frame of
       
   890             NONE => NONE
       
   891           | SOME (frameChunks,indent_chunks,frame) =>
       
   892             let
       
   893               val (chunks,frames,indent) = removeChunksFrames frames
       
   894 
       
   895               val chunks = frameChunks @ chunks
       
   896 
       
   897               val lines = addChunksLine lines lineIndent chunks
       
   898 
       
   899               val lines = addIndentChunksLines lines indent indent_chunks
       
   900 
       
   901               val lineIndent = indent + indentFrame frame
       
   902 
       
   903               val lineSize = sizeFrame frame
       
   904 
       
   905               val frames = frame :: frames
       
   906             in
       
   907               SOME ((lines,lineIndent),lineSize,frames)
       
   908             end;
       
   909 
       
   910   fun breakInsideChunk chunk =
       
   911       case chunk of
       
   912         WordChunk _ => NONE
       
   913       | BreakChunk _ => raise Bug "Print.breakInsideChunk"
       
   914       | FrameChunk frame =>
       
   915         case breakFrame frame of
       
   916           SOME (pathChunks,indent_chunks,frame) =>
       
   917           let
       
   918             val pathIndent = 0
       
   919             and breakIndent = indentFrame frame
       
   920           in
       
   921             SOME (pathChunks,pathIndent,indent_chunks,breakIndent,frame)
       
   922           end
       
   923         | NONE => breakInsideFrame frame
       
   924 
       
   925   and breakInsideChunks chunks =
       
   926       case chunks of
       
   927         [] => NONE
       
   928       | chunk :: chunks =>
       
   929         case breakInsideChunk chunk of
       
   930           SOME (pathChunks,pathIndent,indent_chunks,breakIndent,frame) =>
       
   931           let
       
   932             val pathChunks = pathChunks @ chunks
       
   933             and chunks = [FrameChunk frame]
       
   934           in
       
   935             SOME (pathChunks,pathIndent,indent_chunks,breakIndent,chunks)
       
   936           end
       
   937         | NONE =>
       
   938           case breakInsideChunks chunks of
       
   939             SOME (pathChunks,pathIndent,indent_chunks,breakIndent,chunks) =>
       
   940             let
       
   941               val chunks = chunk :: chunks
       
   942             in
       
   943               SOME (pathChunks,pathIndent,indent_chunks,breakIndent,chunks)
       
   944             end
       
   945           | NONE => NONE
       
   946 
       
   947   and breakInsideFrame frame =
       
   948       let
       
   949         val Frame
       
   950               {block,
       
   951                broken = _,
       
   952                indent,
       
   953                size = _,
       
   954                chunks} = frame
       
   955       in
       
   956         case breakInsideChunks chunks of
       
   957           SOME (pathChunks,pathIndent,indent_chunks,breakIndent,chunks) =>
       
   958           let
       
   959             val pathIndent = pathIndent + indent
       
   960             and broken = true
       
   961             and size = sizeChunks chunks
       
   962 
       
   963             val frame =
       
   964                 Frame
       
   965                   {block = block,
       
   966                    broken = broken,
       
   967                    indent = indent,
       
   968                    size = size,
       
   969                    chunks = chunks}
       
   970           in
       
   971             SOME (pathChunks,pathIndent,indent_chunks,breakIndent,frame)
       
   972           end
       
   973         | NONE => NONE
       
   974       end;
       
   975 
       
   976   fun breakInside lines lineIndent frames =
       
   977       case frames of
       
   978         [] => NONE
       
   979       | frame :: frames =>
       
   980         case breakInsideFrame frame of
       
   981           SOME (pathChunks,pathIndent,indent_chunks,breakIndent,frame) =>
       
   982           let
       
   983             val (chunks,frames,indent) = removeChunksFrames frames
       
   984 
       
   985             val chunks = pathChunks @ chunks
       
   986             and indent = indent + pathIndent
       
   987 
       
   988             val lines = addChunksLine lines lineIndent chunks
       
   989 
       
   990             val lines = addIndentChunksLines lines indent indent_chunks
       
   991 
       
   992             val lineIndent = indent + breakIndent
       
   993 
       
   994             val lineSize = sizeFrame frame
       
   995 
       
   996             val frames = frame :: frames
       
   997           in
       
   998             SOME ((lines,lineIndent),lineSize,frames)
       
   999           end
       
  1000         | NONE =>
       
  1001           case breakInside lines lineIndent frames of
       
  1002             SOME (lines_indent,lineSize,frames) =>
       
  1003             let
       
  1004               val lineSize = lineSize + sizeFrame frame
       
  1005               and frames = frame :: frames
       
  1006             in
       
  1007               SOME (lines_indent,lineSize,frames)
       
  1008             end
       
  1009           | NONE => NONE;
       
  1010 in
       
  1011   fun breakFrames lines lineIndent frames =
       
  1012       case breakUp lines lineIndent frames of
       
  1013         SOME ((lines,lineIndent),lineSize,frames) =>
       
  1014         SOME (lines,lineIndent,lineSize,frames)
       
  1015       | NONE =>
       
  1016         case breakInside lines lineIndent frames of
       
  1017           SOME ((lines,lineIndent),lineSize,frames) =>
       
  1018           SOME (lines,lineIndent,lineSize,frames)
       
  1019         | NONE => NONE;
       
  1020 end;
       
  1021 
       
  1022 (*BasicDebug
       
  1023 fun checkChunk chunk =
       
  1024     case chunk of
       
  1025       WordChunk t => (false, sizeWord t)
       
  1026     | BreakChunk b => (false, sizeBreak b)
       
  1027     | FrameChunk b => checkFrame b
       
  1028 
       
  1029 and checkChunks chunks =
       
  1030     case chunks of
       
  1031       [] => (false,0)
       
  1032     | chunk :: chunks =>
       
  1033       let
       
  1034         val (bk,sz) = checkChunk chunk
       
  1035 
       
  1036         val (bk',sz') = checkChunks chunks
       
  1037       in
       
  1038         (bk orelse bk', sz + sz')
       
  1039       end
       
  1040 
       
  1041 and checkFrame frame =
       
  1042     let
       
  1043       val Frame
       
  1044             {block = _,
       
  1045              broken,
       
  1046              indent = _,
       
  1047              size,
       
  1048              chunks} = frame
       
  1049 
       
  1050       val (bk,sz) = checkChunks chunks
       
  1051 
       
  1052       val () =
       
  1053           if size = sz then ()
       
  1054           else raise Bug "Print.checkFrame: wrong size"
       
  1055 
       
  1056       val () =
       
  1057           if broken orelse not bk then ()
       
  1058           else raise Bug "Print.checkFrame: deep broken frame"
       
  1059     in
       
  1060       (broken,size)
       
  1061     end;
       
  1062 
       
  1063 fun checkFrames frames =
       
  1064     case frames of
       
  1065       [] => (true,0)
       
  1066     | frame :: frames =>
       
  1067       let
       
  1068         val (bk,sz) = checkFrame frame
       
  1069 
       
  1070         val (bk',sz') = checkFrames frames
       
  1071 
       
  1072         val () =
       
  1073             if bk' orelse not bk then ()
       
  1074             else raise Bug "Print.checkFrame: broken stack frame"
       
  1075       in
       
  1076         (bk, sz + sz')
       
  1077       end;
       
  1078 *)
       
  1079 
       
  1080 (*BasicDebug
       
  1081 fun checkState state =
       
  1082     (let
       
  1083        val State {lineIndent,lineSize,stack} = state
       
  1084 
       
  1085        val () =
       
  1086            if not (List.null stack) then ()
       
  1087            else raise Error "no stack"
       
  1088 
       
  1089        val (_,sz) = checkFrames stack
       
  1090 
       
  1091        val () =
       
  1092            if lineSize = sz then ()
       
  1093            else raise Error "wrong lineSize"
       
  1094      in
       
  1095        ()
       
  1096      end
       
  1097      handle Error err => raise Bug err)
       
  1098     handle Bug bug => raise Bug ("Print.checkState: " ^ bug);
       
  1099 *)
       
  1100 
       
  1101 fun isEmptyState state =
       
  1102     let
       
  1103       val State {lineSize,stack,...} = state
       
  1104     in
       
  1105       lineSize = 0 andalso List.all isEmptyFrame stack
       
  1106     end;
       
  1107 
       
  1108 fun isFinalState state =
       
  1109     let
       
  1110       val State {stack,...} = state
       
  1111     in
       
  1112       case stack of
       
  1113         [] => raise Bug "Print.isFinalState: empty stack"
       
  1114       | [frame] => isEmptyFrame frame
       
  1115       | _ :: _ :: _ => false
       
  1116     end;
       
  1117 
       
  1118 local
       
  1119   val initialBlock =
       
  1120       let
       
  1121         val indent = 0
       
  1122         and style = Inconsistent
       
  1123       in
       
  1124         Block
       
  1125           {indent = indent,
       
  1126            style = style}
       
  1127       end;
       
  1128 
       
  1129   val initialFrame =
       
  1130       let
       
  1131         val block = initialBlock
       
  1132         and broken = false
       
  1133         and indent = 0
       
  1134         and size = 0
       
  1135         and chunks = []
       
  1136       in
       
  1137         Frame
       
  1138           {block = block,
       
  1139            broken = broken,
       
  1140            indent = indent,
       
  1141            size = size,
       
  1142            chunks = chunks}
       
  1143       end;
       
  1144 in
       
  1145   val initialState =
       
  1146       let
       
  1147         val lineIndent = 0
       
  1148         and lineSize = 0
       
  1149         and stack = [initialFrame]
       
  1150       in
       
  1151         State
       
  1152           {lineIndent = lineIndent,
       
  1153            lineSize = lineSize,
       
  1154            stack = stack}
       
  1155       end;
       
  1156 end;
       
  1157 
       
  1158 fun normalizeState lineLength lines state =
       
  1159     let
       
  1160       val State {lineIndent,lineSize,stack} = state
       
  1161 
       
  1162       val within =
       
  1163           case lineLength of
       
  1164             NONE => true
       
  1165           | SOME len => lineIndent + lineSize <= len
       
  1166     in
       
  1167       if within then (lines,state)
       
  1168       else
       
  1169         case breakFrames lines lineIndent stack of
       
  1170           NONE => (lines,state)
       
  1171         | SOME (lines,lineIndent,lineSize,stack) =>
       
  1172           let
       
  1173 (*BasicDebug
       
  1174             val () = checkState state
       
  1175 *)
       
  1176             val state =
       
  1177                 State
       
  1178                   {lineIndent = lineIndent,
       
  1179                    lineSize = lineSize,
       
  1180                    stack = stack}
       
  1181           in
       
  1182             normalizeState lineLength lines state
       
  1183           end
       
  1184     end
       
  1185 (*BasicDebug
       
  1186     handle Bug bug => raise Bug ("Print.normalizeState:\n" ^ bug)
       
  1187 *)
       
  1188 
       
  1189 local
       
  1190   fun executeBeginBlock block lines state =
       
  1191       let
       
  1192         val State {lineIndent,lineSize,stack} = state
       
  1193 
       
  1194         val broken = false
       
  1195         and indent = indentBlock block
       
  1196         and size = 0
       
  1197         and chunks = []
       
  1198 
       
  1199         val frame =
       
  1200             Frame
       
  1201               {block = block,
       
  1202                broken = broken,
       
  1203                indent = indent,
       
  1204                size = size,
       
  1205                chunks = chunks}
       
  1206 
       
  1207         val stack = frame :: stack
       
  1208 
       
  1209         val state =
       
  1210             State
       
  1211               {lineIndent = lineIndent,
       
  1212                lineSize = lineSize,
       
  1213                stack = stack}
       
  1214       in
       
  1215         (lines,state)
       
  1216       end;
       
  1217 
       
  1218   fun executeEndBlock lines state =
       
  1219       let
       
  1220         val State {lineIndent,lineSize,stack} = state
       
  1221 
       
  1222         val (lineSize,stack) =
       
  1223             case stack of
       
  1224               [] => raise Bug "Print.executeEndBlock: empty stack"
       
  1225             | topFrame :: stack =>
       
  1226               let
       
  1227                 val Frame
       
  1228                       {block = topBlock,
       
  1229                        broken = topBroken,
       
  1230                        indent = topIndent,
       
  1231                        size = topSize,
       
  1232                        chunks = topChunks} = topFrame
       
  1233 
       
  1234                 val (lineSize,topSize,topChunks,topFrame) =
       
  1235                     case topChunks of
       
  1236                       BreakChunk break :: chunks =>
       
  1237                       let
       
  1238 (*BasicDebug
       
  1239                         val () =
       
  1240                             let
       
  1241                               val mesg =
       
  1242                                   "ignoring a break at the end of a " ^
       
  1243                                   "pretty-printing block"
       
  1244                             in
       
  1245                               warn mesg
       
  1246                             end
       
  1247 *)
       
  1248                         val n = sizeBreak break
       
  1249 
       
  1250                         val lineSize = lineSize - n
       
  1251                         and topSize = topSize - n
       
  1252                         and topChunks = chunks
       
  1253 
       
  1254                         val topFrame =
       
  1255                             Frame
       
  1256                               {block = topBlock,
       
  1257                                broken = topBroken,
       
  1258                                indent = topIndent,
       
  1259                                size = topSize,
       
  1260                                chunks = topChunks}
       
  1261                       in
       
  1262                         (lineSize,topSize,topChunks,topFrame)
       
  1263                       end
       
  1264                     | _ => (lineSize,topSize,topChunks,topFrame)
       
  1265               in
       
  1266                 if List.null topChunks then (lineSize,stack)
       
  1267                 else
       
  1268                   case stack of
       
  1269                     [] => raise Error "Print.execute: too many end blocks"
       
  1270                   | frame :: stack =>
       
  1271                     let
       
  1272                       val Frame
       
  1273                             {block,
       
  1274                              broken,
       
  1275                              indent,
       
  1276                              size,
       
  1277                              chunks} = frame
       
  1278 
       
  1279                       val size = size + topSize
       
  1280 
       
  1281                       val chunk = FrameChunk topFrame
       
  1282 
       
  1283                       val chunks = chunk :: chunks
       
  1284 
       
  1285                       val frame =
       
  1286                           Frame
       
  1287                             {block = block,
       
  1288                              broken = broken,
       
  1289                              indent = indent,
       
  1290                              size = size,
       
  1291                              chunks = chunks}
       
  1292 
       
  1293                       val stack = frame :: stack
       
  1294                     in
       
  1295                       (lineSize,stack)
       
  1296                     end
       
  1297               end
       
  1298 
       
  1299         val state =
       
  1300             State
       
  1301               {lineIndent = lineIndent,
       
  1302                lineSize = lineSize,
       
  1303                stack = stack}
       
  1304       in
       
  1305         (lines,state)
       
  1306       end;
       
  1307 
       
  1308   fun executeAddWord lineLength word lines state =
       
  1309       let
       
  1310         val State {lineIndent,lineSize,stack} = state
       
  1311 
       
  1312         val n = sizeWord word
       
  1313 
       
  1314         val lineSize = lineSize + n
       
  1315 
       
  1316         val stack =
       
  1317             case stack of
       
  1318               [] => raise Bug "Print.executeAddWord: empty stack"
       
  1319             | frame :: stack =>
       
  1320               let
       
  1321                 val Frame
       
  1322                       {block,
       
  1323                        broken,
       
  1324                        indent,
       
  1325                        size,
       
  1326                        chunks} = frame
       
  1327 
       
  1328                 val size = size + n
       
  1329 
       
  1330                 val chunk = WordChunk word
       
  1331 
       
  1332                 val chunks = chunk :: chunks
       
  1333 
       
  1334                 val frame =
       
  1335                     Frame
       
  1336                       {block = block,
       
  1337                        broken = broken,
       
  1338                        indent = indent,
       
  1339                        size = size,
       
  1340                        chunks = chunks}
       
  1341 
       
  1342                 val stack = frame :: stack
       
  1343               in
       
  1344                 stack
       
  1345               end
       
  1346 
       
  1347         val state =
       
  1348             State
       
  1349               {lineIndent = lineIndent,
       
  1350                lineSize = lineSize,
       
  1351                stack = stack}
       
  1352       in
       
  1353         normalizeState lineLength lines state
       
  1354       end;
       
  1355 
       
  1356   fun executeAddBreak lineLength break lines state =
       
  1357       let
       
  1358         val State {lineIndent,lineSize,stack} = state
       
  1359 
       
  1360         val (topFrame,restFrames) =
       
  1361             case stack of
       
  1362               [] => raise Bug "Print.executeAddBreak: empty stack"
       
  1363             | topFrame :: restFrames => (topFrame,restFrames)
       
  1364 
       
  1365         val Frame
       
  1366               {block = topBlock,
       
  1367                broken = topBroken,
       
  1368                indent = topIndent,
       
  1369                size = topSize,
       
  1370                chunks = topChunks} = topFrame
       
  1371       in
       
  1372         case topChunks of
       
  1373           [] => (lines,state)
       
  1374         | topChunk :: restTopChunks =>
       
  1375           let
       
  1376             val (topChunks,n) =
       
  1377                 case topChunk of
       
  1378                   BreakChunk break' =>
       
  1379                   let
       
  1380                     val break = appendBreak break' break
       
  1381 
       
  1382                     val chunk = BreakChunk break
       
  1383 
       
  1384                     val topChunks = chunk :: restTopChunks
       
  1385                     and n = sizeBreak break - sizeBreak break'
       
  1386                   in
       
  1387                     (topChunks,n)
       
  1388                   end
       
  1389                 | _ =>
       
  1390                   let
       
  1391                     val chunk = BreakChunk break
       
  1392 
       
  1393                     val topChunks = chunk :: topChunks
       
  1394                     and n = sizeBreak break
       
  1395                   in
       
  1396                     (topChunks,n)
       
  1397                   end
       
  1398 
       
  1399             val lineSize = lineSize + n
       
  1400 
       
  1401             val topSize = topSize + n
       
  1402 
       
  1403             val topFrame =
       
  1404                 Frame
       
  1405                   {block = topBlock,
       
  1406                    broken = topBroken,
       
  1407                    indent = topIndent,
       
  1408                    size = topSize,
       
  1409                    chunks = topChunks}
       
  1410 
       
  1411             val stack = topFrame :: restFrames
       
  1412 
       
  1413             val state =
       
  1414                 State
       
  1415                   {lineIndent = lineIndent,
       
  1416                    lineSize = lineSize,
       
  1417                    stack = stack}
       
  1418 
       
  1419             val lineLength =
       
  1420                 if breakingFrame topFrame then SOME ~1 else lineLength
       
  1421           in
       
  1422             normalizeState lineLength lines state
       
  1423           end
       
  1424       end;
       
  1425 
       
  1426   fun executeBigBreak lines state =
       
  1427       let
       
  1428         val lineLength = SOME ~1
       
  1429         and break = mkBreak 0
       
  1430       in
       
  1431         executeAddBreak lineLength break lines state
       
  1432       end;
       
  1433 
       
  1434   fun executeAddNewline lineLength lines state =
       
  1435       if isEmptyState state then (addEmptyLine lines, state)
       
  1436       else executeBigBreak lines state;
       
  1437 
       
  1438   fun executeEof lineLength lines state =
       
  1439       if isFinalState state then (lines,state)
       
  1440       else
       
  1441         let
       
  1442           val (lines,state) = executeBigBreak lines state
       
  1443 
       
  1444 (*BasicDebug
       
  1445           val () =
       
  1446               if isFinalState state then ()
       
  1447               else raise Bug "Print.executeEof: not a final state"
       
  1448 *)
       
  1449         in
       
  1450           (lines,state)
       
  1451         end;
       
  1452 in
       
  1453   fun render {lineLength} =
       
  1454       let
       
  1455         fun execute step state =
       
  1456             let
       
  1457               val lines = []
       
  1458             in
       
  1459               case step of
       
  1460                 BeginBlock block => executeBeginBlock block lines state
       
  1461               | EndBlock => executeEndBlock lines state
       
  1462               | AddWord word => executeAddWord lineLength word lines state
       
  1463               | AddBreak break => executeAddBreak lineLength break lines state
       
  1464               | AddNewline => executeAddNewline lineLength lines state
       
  1465             end
       
  1466 
       
  1467 (*BasicDebug
       
  1468         val execute = fn step => fn state =>
       
  1469             let
       
  1470               val (lines,state) = execute step state
       
  1471 
       
  1472               val () = checkState state
       
  1473             in
       
  1474               (lines,state)
       
  1475             end
       
  1476             handle Bug bug =>
       
  1477               raise Bug ("Print.execute: after " ^ toStringStep step ^
       
  1478                          " command:\n" ^ bug)
       
  1479 *)
       
  1480 
       
  1481         fun final state =
       
  1482             let
       
  1483               val lines = []
       
  1484 
       
  1485               val (lines,state) = executeEof lineLength lines state
       
  1486 
       
  1487 (*BasicDebug
       
  1488               val () = checkState state
       
  1489 *)
       
  1490             in
       
  1491               if List.null lines then Stream.Nil else Stream.singleton lines
       
  1492             end
       
  1493 (*BasicDebug
       
  1494             handle Bug bug => raise Bug ("Print.final: " ^ bug)
       
  1495 *)
       
  1496       in
       
  1497         fn pps =>
       
  1498            let
       
  1499              val lines = Stream.maps execute final initialState pps
       
  1500            in
       
  1501              revConcat lines
       
  1502            end
       
  1503       end;
       
  1504 end;
  1167 
  1505 
  1168 local
  1506 local
  1169   fun inc {indent,line} acc = line :: nSpaces indent :: acc;
  1507   fun inc {indent,line} acc = line :: nSpaces indent :: acc;
  1170 
  1508 
  1171   fun incn (indent_line,acc) = inc indent_line ("\n" :: acc);
  1509   fun incn (indent_line,acc) = inc indent_line ("\n" :: acc);
  1172 in
  1510 in
  1173   fun toLines len ppA a =
  1511   fun toStringWithLineLength len ppA a =
  1174       case execute {lineLength = len} (ppA a) of
  1512       case render len (ppA a) of
  1175         Stream.Nil => ""
  1513         Stream.Nil => ""
  1176       | Stream.Cons (h,t) =>
  1514       | Stream.Cons (h,t) =>
  1177         let
  1515         let
  1178           val lines = Stream.foldl incn (inc h []) (t ())
  1516           val lines = Stream.foldl incn (inc h []) (t ())
  1179         in
  1517         in
  1180           String.concat (rev lines)
  1518           String.concat (List.rev lines)
  1181         end;
  1519         end;
  1182 end;
  1520 end;
  1183 
  1521 
  1184 fun toString ppA a = toLines (!lineLength) ppA a;
  1522 local
  1185 
  1523   fun renderLine {indent,line} = nSpaces indent ^ line ^ "\n";
  1186 fun toLine ppA a = toLines 100000 ppA a;
  1524 in
       
  1525   fun toStreamWithLineLength len ppA a =
       
  1526       Stream.map renderLine (render len (ppA a));
       
  1527 end;
       
  1528 
       
  1529 fun toLine ppA a = toStringWithLineLength {lineLength = NONE} ppA a;
       
  1530 
       
  1531 (* ------------------------------------------------------------------------- *)
       
  1532 (* Pretty-printer rendering with a global line length.                       *)
       
  1533 (* ------------------------------------------------------------------------- *)
       
  1534 
       
  1535 val lineLength = ref initialLineLength;
       
  1536 
       
  1537 fun toString ppA a =
       
  1538     let
       
  1539       val len = {lineLength = SOME (!lineLength)}
       
  1540     in
       
  1541       toStringWithLineLength len ppA a
       
  1542     end;
  1187 
  1543 
  1188 fun toStream ppA a =
  1544 fun toStream ppA a =
  1189     Stream.map (fn {indent,line} => nSpaces indent ^ line ^ "\n")
  1545     let
  1190       (execute {lineLength = !lineLength} (ppA a));
  1546       val len = {lineLength = SOME (!lineLength)}
  1191 
  1547     in
  1192 local
  1548       toStreamWithLineLength len ppA a
  1193   val sep = mkStringSize " =";
  1549     end;
       
  1550 
       
  1551 local
       
  1552   val sep = mkWord " =";
  1194 in
  1553 in
  1195   fun trace ppX nameX x =
  1554   fun trace ppX nameX x =
  1196       Useful.trace (toString (ppOp2' sep ppString ppX) (nameX,x) ^ "\n");
  1555       Useful.trace (toString (ppOp2' sep ppString ppX) (nameX,x) ^ "\n");
  1197 end;
  1556 end;
  1198 
  1557