| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.io.source_file; | 5 library dart2js.io.source_file; |
| 6 | 6 |
| 7 import 'dart:convert' show UTF8; | 7 import 'dart:convert' show UTF8; |
| 8 import 'dart:math'; | 8 import 'dart:math'; |
| 9 import 'dart:typed_data' show Uint8List; | 9 import 'dart:typed_data' show Uint8List; |
| 10 | 10 |
| 11 import 'package:kernel/ast.dart' as kernel show Location, Source; |
| 12 |
| 11 import 'line_column_provider.dart'; | 13 import 'line_column_provider.dart'; |
| 12 | 14 |
| 13 /** | 15 /** |
| 14 * Represents a file of source code. The content can be either a [String] or | 16 * Represents a file of source code. The content can be either a [String] or |
| 15 * a UTF-8 encoded [List<int>] of bytes. | 17 * a UTF-8 encoded [List<int>] of bytes. |
| 16 */ | 18 */ |
| 17 abstract class SourceFile implements LineColumnProvider { | 19 abstract class SourceFile implements LineColumnProvider { |
| 18 /// The absolute URI of the source file. | 20 /// The absolute URI of the source file. |
| 19 Uri get uri; | 21 Uri get uri; |
| 20 | 22 |
| 23 kernel.Source cachedKernelSource; |
| 24 |
| 25 kernel.Source get kernelSource { |
| 26 return cachedKernelSource ??= new kernel.Source( |
| 27 lineStarts, slowUtf8ZeroTerminatedBytes())..cachedText = slowText(); |
| 28 } |
| 29 |
| 21 /// The name of the file. | 30 /// The name of the file. |
| 22 /// | 31 /// |
| 23 /// This is [uri], maybe relativized to a more human-readable form. | 32 /// This is [uri], maybe relativized to a more human-readable form. |
| 24 String get filename => uri.toString(); | 33 String get filename => uri.toString(); |
| 25 | 34 |
| 26 /** The text content of the file represented as a String. */ | 35 /** The text content of the file represented as a String. */ |
| 27 String slowText(); | 36 String slowText(); |
| 28 | 37 |
| 29 /** | 38 /** |
| 30 * The content of the file represented as a UTF-8 encoded [List<int>], | 39 * The content of the file represented as a UTF-8 encoded [List<int>], |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 } | 88 } |
| 80 starts.add(text.length + 1); // One additional line start at the end. | 89 starts.add(text.length + 1); // One additional line start at the end. |
| 81 return starts; | 90 return starts; |
| 82 } | 91 } |
| 83 | 92 |
| 84 /** | 93 /** |
| 85 * Returns the line number for the offset [position] in the string | 94 * Returns the line number for the offset [position] in the string |
| 86 * representation of this source file. | 95 * representation of this source file. |
| 87 */ | 96 */ |
| 88 int getLine(int position) { | 97 int getLine(int position) { |
| 89 List<int> starts = lineStarts; | 98 new kernel.Source(lineStarts, null).getLocation(null, position).line; |
| 90 if (position < 0 || starts.last <= position) { | |
| 91 throw 'bad position #$position in file $filename with ' | |
| 92 'length ${length}.'; | |
| 93 } | |
| 94 int first = 0; | |
| 95 int count = starts.length; | |
| 96 while (count > 1) { | |
| 97 int step = count ~/ 2; | |
| 98 int middle = first + step; | |
| 99 int lineStart = starts[middle]; | |
| 100 if (position < lineStart) { | |
| 101 count = step; | |
| 102 } else { | |
| 103 first = middle; | |
| 104 count -= step; | |
| 105 } | |
| 106 } | |
| 107 return first; | |
| 108 } | 99 } |
| 109 | 100 |
| 110 /** | 101 /** |
| 111 * Returns the column number for the offset [position] in the string | 102 * Returns the column number for the offset [position] in the string |
| 112 * representation of this source file. | 103 * representation of this source file. |
| 113 */ | 104 */ |
| 114 int getColumn(int line, int position) { | 105 int getColumn(int line, int position) { |
| 115 return position - lineStarts[line]; | 106 return position - lineStarts[line]; |
| 116 } | 107 } |
| 117 | 108 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 134 String getLocationMessage(String message, int start, int end, | 125 String getLocationMessage(String message, int start, int end, |
| 135 {bool includeSourceLine: true, String colorize(String text)}) { | 126 {bool includeSourceLine: true, String colorize(String text)}) { |
| 136 if (colorize == null) { | 127 if (colorize == null) { |
| 137 colorize = (text) => text; | 128 colorize = (text) => text; |
| 138 } | 129 } |
| 139 if (end > length) { | 130 if (end > length) { |
| 140 start = length - 1; | 131 start = length - 1; |
| 141 end = length; | 132 end = length; |
| 142 } | 133 } |
| 143 | 134 |
| 144 int lineStart = getLine(start); | 135 kernel.Location startLocation = kernelSource.getLocation(null, start); |
| 145 int columnStart = getColumn(lineStart, start); | 136 kernel.Location endLocation = kernelSource.getLocation(null, end); |
| 146 int lineEnd = getLine(end); | 137 int lineStart = startLocation.line - 1; |
| 147 int columnEnd = getColumn(lineEnd, end); | 138 int columnStart = startLocation.column - 1; |
| 139 int lineEnd = startLocation.line - 1; |
| 140 int columnEnd = endLocation.column - 1; |
| 148 | 141 |
| 149 StringBuffer buf = new StringBuffer('${filename}:'); | 142 StringBuffer buf = new StringBuffer('${filename}:'); |
| 150 if (start != end || start != 0) { | 143 if (start != end || start != 0) { |
| 151 // Line/column info is relevant. | 144 // Line/column info is relevant. |
| 152 buf.write('${lineStart + 1}:${columnStart + 1}:'); | 145 buf.write('${lineStart + 1}:${columnStart + 1}:'); |
| 153 } | 146 } |
| 154 buf.write('\n$message\n'); | 147 buf.write('\n$message\n'); |
| 155 | 148 |
| 156 if (start != end && includeSourceLine) { | 149 if (start != end && includeSourceLine) { |
| 157 if (lineStart == lineEnd) { | 150 if (lineStart == lineEnd) { |
| 158 String textLine = getLineText(lineStart); | 151 String textLine = kernelSource.getTextLine(startLocation.line); |
| 159 | 152 |
| 160 int toColumn = min(columnStart + (end - start), textLine.length); | 153 int toColumn = min(columnStart + (end - start), textLine.length); |
| 161 buf.write(textLine.substring(0, columnStart)); | 154 buf.write(textLine.substring(0, columnStart)); |
| 162 buf.write(colorize(textLine.substring(columnStart, toColumn))); | 155 buf.write(colorize(textLine.substring(columnStart, toColumn))); |
| 163 buf.write(textLine.substring(toColumn)); | 156 buf.writeln(textLine.substring(toColumn)); |
| 164 | 157 |
| 165 int i = 0; | 158 int i = 0; |
| 166 for (; i < columnStart; i++) { | 159 for (; i < columnStart; i++) { |
| 167 buf.write(' '); | 160 buf.write(' '); |
| 168 } | 161 } |
| 169 | 162 |
| 170 for (; i < toColumn; i++) { | 163 for (; i < toColumn; i++) { |
| 171 buf.write(colorize('^')); | 164 buf.write(colorize('^')); |
| 172 } | 165 } |
| 173 } else { | 166 } else { |
| 174 for (int line = lineStart; line <= lineEnd; line++) { | 167 for (int line = lineStart; line <= lineEnd; line++) { |
| 175 String textLine = getLineText(line); | 168 String textLine = kernelSource.getTextLine(line + 1); |
| 176 if (line == lineStart) { | 169 if (line == lineStart) { |
| 177 buf.write(textLine.substring(0, columnStart)); | 170 buf.write(textLine.substring(0, columnStart)); |
| 178 buf.write(colorize(textLine.substring(columnStart))); | 171 buf.writeln(colorize(textLine.substring(columnStart))); |
| 179 } else if (line == lineEnd) { | 172 } else if (line == lineEnd) { |
| 180 buf.write(colorize(textLine.substring(0, columnEnd))); | 173 buf.write(colorize(textLine.substring(0, columnEnd))); |
| 181 buf.write(textLine.substring(columnEnd)); | 174 buf.writeln(textLine.substring(columnEnd)); |
| 182 } else { | 175 } else { |
| 183 buf.write(colorize(textLine)); | 176 buf.writeln(colorize(textLine)); |
| 184 } | 177 } |
| 185 } | 178 } |
| 186 } | 179 } |
| 187 } | 180 } |
| 188 | 181 |
| 189 return buf.toString(); | 182 return buf.toString(); |
| 190 } | 183 } |
| 191 | 184 |
| 192 int get lines => lineStarts.length - 1; | 185 int get lines => lineStarts.length - 1; |
| 193 | 186 |
| 194 /// Returns the text of line at the 0-based [index] within this source file. | 187 /// Returns the text of line at the 0-based [index] within this source |
| 195 String getLineText(int index) { | 188 /// file. The returned line always ends with `"\n"`. |
| 196 // +1 for 0-indexing, +1 again to avoid the last line of the file | 189 String getLineText(int index) => kernelSource.getTextLine(line) + "\n"; |
| 197 if ((index + 2) < lineStarts.length) { | |
| 198 return slowSubstring(lineStarts[index], lineStarts[index + 1]); | |
| 199 } else if ((index + 1) < lineStarts.length) { | |
| 200 return '${slowSubstring(lineStarts[index], length)}\n'; | |
| 201 } else { | |
| 202 throw new ArgumentError("Line index $index is out of bounds."); | |
| 203 } | |
| 204 } | |
| 205 } | 190 } |
| 206 | 191 |
| 207 List<int> _zeroTerminateIfNecessary(List<int> bytes) { | 192 List<int> _zeroTerminateIfNecessary(List<int> bytes) { |
| 208 if (bytes.length > 0 && bytes.last == 0) return bytes; | 193 if (bytes.length > 0 && bytes.last == 0) return bytes; |
| 209 List<int> result = new Uint8List(bytes.length + 1); | 194 List<int> result = new Uint8List(bytes.length + 1); |
| 210 result.setRange(0, bytes.length, bytes); | 195 result.setRange(0, bytes.length, bytes); |
| 211 result[result.length - 1] = 0; | 196 result[result.length - 1] = 0; |
| 212 return result; | 197 return result; |
| 213 } | 198 } |
| 214 | 199 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 set length(int v) {} | 270 set length(int v) {} |
| 286 | 271 |
| 287 String slowText() => text; | 272 String slowText() => text; |
| 288 | 273 |
| 289 List<int> slowUtf8ZeroTerminatedBytes() { | 274 List<int> slowUtf8ZeroTerminatedBytes() { |
| 290 return _zeroTerminateIfNecessary(UTF8.encode(text)); | 275 return _zeroTerminateIfNecessary(UTF8.encode(text)); |
| 291 } | 276 } |
| 292 | 277 |
| 293 String slowSubstring(int start, int end) => text.substring(start, end); | 278 String slowSubstring(int start, int end) => text.substring(start, end); |
| 294 } | 279 } |
| OLD | NEW |