| Index: pkg/compiler/lib/src/io/code_output.dart
|
| diff --git a/pkg/compiler/lib/src/io/code_output.dart b/pkg/compiler/lib/src/io/code_output.dart
|
| index f7f1c9b0a3aba69b84e6a05b4002a4ef77951faa..bd97af021575b6eaff1e5e8ef9958979be88fd77 100644
|
| --- a/pkg/compiler/lib/src/io/code_output.dart
|
| +++ b/pkg/compiler/lib/src/io/code_output.dart
|
| @@ -6,8 +6,6 @@ library dart2js.code_output;
|
|
|
| import 'dart:async';
|
|
|
| -import '../source_file.dart';
|
| -
|
| import 'source_map_builder.dart';
|
|
|
| class CodeOutputMarker {
|
| @@ -17,27 +15,55 @@ class CodeOutputMarker {
|
| CodeOutputMarker(this.offsetDelta, this.sourcePosition);
|
| }
|
|
|
| +abstract class CodeOutputListener {
|
| + void onText(String text);
|
| + void onDone(int length);
|
| +}
|
| +
|
| abstract class CodeOutput {
|
| - List<CodeOutputMarker> markers = new List<CodeOutputMarker>();
|
| + /// Write [text] to this output.
|
| + ///
|
| + /// If the output is closed, a [StateError] is thrown.
|
| + void add(String text);
|
| +
|
| + /// Adds the content of [buffer] to the output and adds its markers to
|
| + /// [markers].
|
| + ///
|
| + /// If the output is closed, a [StateError] is thrown.
|
| + void addBuffer(CodeBuffer buffer);
|
| +
|
| + /// Returns the number of characters currently write to this output.
|
| + int get length;
|
| +
|
| + /// Returns `true` if this output has been closed.
|
| + bool get isClosed;
|
| +
|
| + /// Closes the output. Further writes will cause a [StateError].
|
| + void close();
|
| +
|
| + /// Applies [f] to every marker in this output.
|
| + void forEachSourceLocation(void f(int targetOffset,
|
| + SourceFileLocation sourceLocation));
|
| +}
|
|
|
| +abstract class AbstractCodeOutput extends CodeOutput {
|
| + List<CodeOutputMarker> markers = new List<CodeOutputMarker>();
|
| int lastBufferOffset = 0;
|
| int mappedRangeCounter = 0;
|
| + bool isClosed = false;
|
|
|
| - int get length;
|
| -
|
| - void _writeInternal(String text);
|
| + void _addInternal(String text);
|
|
|
| - /// Converts [object] to a string and adds it to the buffer. If [object] is a
|
| - /// [CodeBuffer], adds its markers to [markers].
|
| - void write(var object) {
|
| - if (object is CodeBuffer) {
|
| - addBuffer(object);
|
| - return;
|
| + @override
|
| + void add(String text) {
|
| + if (isClosed) {
|
| + throw new StateError("Code output is closed. Trying to write '$text'.");
|
| }
|
| if (mappedRangeCounter == 0) setSourceLocation(null);
|
| - _writeInternal(object);
|
| + _addInternal(text);
|
| }
|
|
|
| + @override
|
| void addBuffer(CodeBuffer other) {
|
| if (other.markers.length > 0) {
|
| CodeOutputMarker firstMarker = other.markers[0];
|
| @@ -50,7 +76,10 @@ abstract class CodeOutput {
|
| }
|
| lastBufferOffset = length + other.lastBufferOffset;
|
| }
|
| - _writeInternal(other.getText());
|
| + if (!other.isClosed) {
|
| + other.close();
|
| + }
|
| + _addInternal(other.getText());
|
| }
|
|
|
| void beginMappedRange() {
|
| @@ -78,141 +107,58 @@ abstract class CodeOutput {
|
| f(targetOffset, marker.sourcePosition);
|
| });
|
| }
|
| +
|
| + void close() {
|
| + if (isClosed) {
|
| + throw new StateError("Code output is already closed.");
|
| + }
|
| + isClosed = true;
|
| + }
|
| }
|
|
|
| /// [CodeOutput] using a [StringBuffer] as backend.
|
| -class CodeBuffer extends CodeOutput implements StringBuffer {
|
| +class CodeBuffer extends AbstractCodeOutput {
|
| StringBuffer buffer = new StringBuffer();
|
|
|
| @override
|
| - void _writeInternal(String text) {
|
| + void _addInternal(String text) {
|
| buffer.write(text);
|
| }
|
|
|
| @override
|
| int get length => buffer.length;
|
|
|
| - @override
|
| - bool get isEmpty => buffer.isEmpty;
|
| -
|
| - @override
|
| - bool get isNotEmpty => buffer.isNotEmpty;
|
| -
|
| - @override
|
| - void writeAll(Iterable<Object> objects, [String separator = ""]) {
|
| - Iterator iterator = objects.iterator;
|
| - if (!iterator.moveNext()) return;
|
| - if (separator.isEmpty) {
|
| - do {
|
| - write(iterator.current);
|
| - } while (iterator.moveNext());
|
| - } else {
|
| - write(iterator.current);
|
| - while (iterator.moveNext()) {
|
| - write(separator);
|
| - write(iterator.current);
|
| - }
|
| - }
|
| - }
|
| -
|
| - @override
|
| - void writeln([var object = ""]) {
|
| - write(object);
|
| - write("\n");
|
| - }
|
| -
|
| - @override
|
| - void writeCharCode(int charCode) {
|
| - buffer.writeCharCode(charCode);
|
| - }
|
| -
|
| - @override
|
| - void clear() {
|
| - buffer = new StringBuffer();
|
| - markers.clear();
|
| - lastBufferOffset = 0;
|
| + String getText() {
|
| + return buffer.toString();
|
| }
|
|
|
| String toString() {
|
| throw "Don't use CodeBuffer.toString() since it drops sourcemap data.";
|
| }
|
| -
|
| - String getText() {
|
| - return buffer.toString();
|
| - }
|
| }
|
|
|
| /// [CodeOutput] using a [CompilationOutput] as backend.
|
| -class StreamCodeOutput extends CodeOutput {
|
| +class StreamCodeOutput extends AbstractCodeOutput {
|
| int length = 0;
|
| final EventSink<String> output;
|
| + final List<CodeOutputListener> _listeners;
|
|
|
| - StreamCodeOutput(this.output);
|
| + StreamCodeOutput(this.output, [this._listeners]);
|
|
|
| @override
|
| - void _writeInternal(String text) {
|
| + void _addInternal(String text) {
|
| output.add(text);
|
| length += text.length;
|
| - }
|
| -
|
| - void close() {
|
| - output.close();
|
| - }
|
| -}
|
| -
|
| -/// [StreamCodeSink] that collects line information.
|
| -class LineColumnCodeOutput extends StreamCodeOutput
|
| - implements LineColumnProvider {
|
| - int lastLineStart = 0;
|
| - List<int> lineStarts = <int>[0];
|
| -
|
| - LineColumnCodeOutput(EventSink<String> output) : super(output);
|
| -
|
| - @override
|
| - void _writeInternal(String text) {
|
| - int offset = lastLineStart;
|
| - int index = 0;
|
| - while (index < text.length) {
|
| - // Unix uses '\n' and Windows uses '\r\n', so this algorithm works for
|
| - // both platforms.
|
| - index = text.indexOf('\n', index) + 1;
|
| - if (index <= 0) break;
|
| - lastLineStart = offset + index;
|
| - lineStarts.add(lastLineStart);
|
| + if (_listeners != null) {
|
| + _listeners.forEach((listener) => listener.onText(text));
|
| }
|
| - super._writeInternal(text);
|
| }
|
|
|
| - @override
|
| - int getLine(int offset) {
|
| - List<int> starts = lineStarts;
|
| - if (offset < 0|| starts.last <= offset) {
|
| - throw 'bad position #$offset in buffer with length ${length}.';
|
| - }
|
| - int first = 0;
|
| - int count = starts.length;
|
| - while (count > 1) {
|
| - int step = count ~/ 2;
|
| - int middle = first + step;
|
| - int lineStart = starts[middle];
|
| - if (offset < lineStart) {
|
| - count = step;
|
| - } else {
|
| - first = middle;
|
| - count -= step;
|
| - }
|
| - }
|
| - return first;
|
| - }
|
| -
|
| - @override
|
| - int getColumn(int line, int offset) {
|
| - return offset - lineStarts[line];
|
| - }
|
| -
|
| - @override
|
| void close() {
|
| - lineStarts.add(length);
|
| + output.close();
|
| super.close();
|
| + if (_listeners != null) {
|
| + _listeners.forEach((listener) => listener.onDone(length));
|
| + }
|
| }
|
| }
|
|
|