Author: housel
Date: Wed Oct 19 23:50:36 2005
New Revision: 10279
Modified:
trunk/src/common/stream-ext/indenting-streams.dylan
Log:
Bug: 7099 7266
Re-implement <indenting-stream> to improve its efficiency and correctness.
* indenting-streams.dylan
(<indenting-stream>): Add new input-tab-width: and output-tab-width: keywords
for controlling the tab width of the input and output to the wrapper stream.
An output-tab-width: value of #f disables the use of tabs on output.
(write-indent): New function for efficiently writing indenting spaces.
(write-element): Re-implement to properly keep track of the current
indentation space column and to use write-indent.
(write): Re-implement to properly keep track of the current indentation
space column, and to make a minimum number of calls to write() on the
inner stream.
Modified: trunk/src/common/stream-ext/indenting-streams.dylan
==============================================================================
--- trunk/src/common/stream-ext/indenting-streams.dylan (original)
+++ trunk/src/common/stream-ext/indenting-streams.dylan Wed Oct 19 23:50:36 2005
@@ -1,10 +1,10 @@
module: indenting-streams
-author: William Lott
+author: William Lott, Peter S. Housel
//======================================================================
//
// Copyright (c) 1996 Carnegie Mellon University
-// Copyright (c) 1998, 1999, 2000 Gwydion Dylan Maintainers
+// Copyright (c) 1998, 1999, 2000, 2004, 2005 Gwydion Dylan Maintainers
// All rights reserved.
//
// Use and copying of this software and preparation of derivative
@@ -44,62 +44,138 @@
define sealed class <indenting-stream> (<wrapper-stream>)
- slot is-after-newline? :: <boolean> = #t;
- slot is-column :: <integer> = 0;
+ slot is-space-column :: false-or(<integer>) = 0;
slot is-indentation :: <integer> = 0, init-keyword: indentation:;
+ slot is-input-tab-width :: <integer> = 8, init-keyword: input-tab-width:;
+ slot is-output-tab-width :: false-or(<integer>) = 8,
+ init-keyword: output-tab-width:;
end;
define sealed domain make(singleton(<indenting-stream>));
define sealed domain initialize(<indenting-stream>);
-define method write-element
- (stream :: <indenting-stream>, elt :: <character>) => ()
- if (stream.is-after-newline?)
- for (i from 0 below stream.is-indentation)
- write-element(stream.inner-stream, ' ');
- end;
- stream.is-after-newline? := #f;
- end if;
- write-element(stream.inner-stream, elt);
- if (elt == '\t')
- stream.is-column := stream.is-column + 8 - truncate/(stream.is-column, 8);
+define constant $spaces :: <byte-string>
+ = " "; // 64
+define constant $tabs :: <byte-string>
+ = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; // 32
+
+define function write-indent
+ (istream :: <indenting-stream>, count :: <integer>)
+ => ();
+ let stream = istream.inner-stream;
+
+ local
+ method write-spaces (count :: <integer>) => ();
+ if (count > size($spaces))
+ write(stream, $spaces);
+ write-spaces(count - size($spaces));
+ else
+ write(stream, $spaces, end: count);
+ end if;
+ end,
+ method write-tabs (count :: <integer>) => ();
+ if (count > size($tabs))
+ write(stream, $tabs);
+ write-tabs(count - size($tabs));
+ else
+ write(stream, $tabs, end: count);
+ end if;
+ end method;
+
+ let tab-width = istream.is-output-tab-width;
+ if (tab-width & tab-width >= count)
+ let (tabs, spaces) = truncate/(count, tab-width);
+ write-tabs(tabs);
+ write-spaces(spaces);
else
- stream.is-column := stream.is-column + 1;
- end;
+ write-spaces(count);
+ end if;
+end function;
+
+define method write-element
+ (stream :: <indenting-stream>, elt :: <character>)
+ => ()
+ select(elt)
+ ' ' =>
+ if (stream.is-space-column)
+ stream.is-space-column := stream.is-space-column + 1;
+ else
+ write-element(stream.inner-stream, elt);
+ end if;
+ '\t' =>
+ if (stream.is-space-column)
+ let tab-width = stream.is-input-tab-width;
+ stream.is-space-column
+ := stream.is-space-column
+ + tab-width
+ - remainder(stream.is-space-column, tab-width);
+ else
+ write-element(stream.inner-stream, elt);
+ end if;
+ '\n', '\r' =>
+ stream.is-space-column := 0;
+ write-element(stream.inner-stream, elt);
+ otherwise =>
+ if (stream.is-space-column)
+ write-indent(stream, stream.is-indentation + stream.is-space-column);
+ end if;
+ stream.is-space-column := #f;
+ write-element(stream.inner-stream, elt);
+ end select;
end method write-element;
define method write
(stream :: <indenting-stream>, elements :: <sequence>,
- #key start: _start = 0, end: _end = elements.size) => ()
- if (stream.is-after-newline?)
- for (i from 0 below stream.is-indentation)
- write-element(stream.inner-stream, ' ');
- end;
- stream.is-after-newline? := #f;
- end if;
- write(stream.inner-stream, elements, start: _start, end: _end);
- for (i from _start below _end,
- col = stream.is-column
- then if (elements[i] = '\t')
- col + 8 - truncate/(col, 8)
- else
- col + 1
- end)
- finally
- stream.is-column := col;
- end;
+ #key start: _start = 0, end: _end = elements.size)
+ => ();
+ let inner = stream.inner-stream;
+ let tab-width = stream.is-input-tab-width;
+
+ iterate loop (index :: <integer> = _start,
+ start :: <integer> = _start,
+ space-column :: false-or(<integer>) = stream.is-space-column)
+ if (index < _end)
+ let elt = elements[index];
+ select (elt)
+ ' ' =>
+ if (space-column)
+ loop(index + 1, index + 1, space-column + 1);
+ else
+ loop(index + 1, start, #f);
+ end if;
+ '\t' =>
+ if (space-column)
+ loop(index + 1, index + 1,
+ space-column + tab-width - remainder(space-column,
tab-width));
+ else
+ loop(index + 1, start, #f);
+ end if;
+ '\n', '\r' =>
+ write(inner, elements, start: start, end: index + 1);
+ loop(index + 1, index + 1, 0);
+ otherwise =>
+ if (space-column)
+ write-indent(stream, stream.is-indentation + space-column);
+ end if;
+ loop(index + 1, start, #f);
+ end select;
+ else
+ if (start ~= index)
+ write(inner, elements, start: start, end: index);
+ end if;
+ stream.is-space-column := space-column;
+ end if;
+ end iterate;
end method write;
define method new-line (stream :: <indenting-stream>) => ()
- stream.is-after-newline? := #t;
- stream.is-column := 0;
+ stream.is-space-column := 0;
new-line(stream.inner-stream)
end method new-line;
define method discard-output
(stream :: <indenting-stream>) => ()
- stream.is-after-newline? := #t;
- stream.is-column := 0;
+ stream.is-space-column := 0;
discard-output(stream.inner-stream)
end method discard-output;
--
Gd-chatter mailing list
Gd-chatter@xxxxxxxxxxxxxxxx
https://gauss.gwydiondylan.org/mailman/listinfo/gd-chatter
|