91dd628bd8
Need unique name for library collision with template parser. Few more changes to work under VM. More changes for lang.dart seperation. Seperation from lang.dart (tokenizer can't access private fields of base class in another library). This was allowed in frog but not in the VM. VM is right so need to sever dependency. BUG= TEST= Review URL: https://chromiumcodereview.appspot.com//9695048 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@5544 260f80e4-7a28-3924-810f-c04153c831b5
187 lines
5.0 KiB
Dart
187 lines
5.0 KiB
Dart
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
// TODO(jimhug): This should be an interface to work better with tools.
|
|
/**
|
|
* Represents a file of source code.
|
|
*/
|
|
class SourceFile implements Comparable {
|
|
// TODO(terry): This filename for in memory buffer. May need to rework if
|
|
// filename is used for more than informational.
|
|
static String IN_MEMORY_FILE = '<buffer>';
|
|
|
|
/** The name of the file. */
|
|
final String filename;
|
|
|
|
/** The text content of the file. */
|
|
String _text;
|
|
|
|
/**
|
|
* The order of the source file in a given library. This is used while we're
|
|
* writing code for a library. A single source file can be used
|
|
*/
|
|
// TODO(jmesserly): I don't like having properties that are only valid
|
|
// sometimes. An alternative would be to store it in a Map that's used by
|
|
// WorldGenerator while it's emitting code. This seems simpler.
|
|
int orderInLibrary;
|
|
|
|
List<int> _lineStarts;
|
|
|
|
SourceFile(this.filename, this._text);
|
|
|
|
String get text() => _text;
|
|
|
|
set text(String newText) {
|
|
if (newText != _text) {
|
|
_text = newText;
|
|
_lineStarts = null;
|
|
orderInLibrary = null;
|
|
}
|
|
}
|
|
|
|
List<int> get lineStarts() {
|
|
if (_lineStarts == null) {
|
|
var starts = [0];
|
|
var index = 0;
|
|
while (index < text.length) {
|
|
index = text.indexOf('\n', index) + 1;
|
|
if (index <= 0) break;
|
|
starts.add(index);
|
|
}
|
|
starts.add(text.length + 1);
|
|
_lineStarts = starts;
|
|
}
|
|
return _lineStarts;
|
|
}
|
|
|
|
int getLine(int position) {
|
|
// TODO(jimhug): Implement as binary search.
|
|
var starts = lineStarts;
|
|
for (int i=0; i < starts.length; i++) {
|
|
if (starts[i] > position) return i-1;
|
|
}
|
|
world.internalError('bad position');
|
|
}
|
|
|
|
int getColumn(int line, int position) {
|
|
return position - lineStarts[line];
|
|
}
|
|
|
|
/**
|
|
* Create a pretty string representation from a character position
|
|
* in the file.
|
|
*/
|
|
String getLocationMessage(String message, int start,
|
|
[int end, bool includeText=false]) {
|
|
var line = getLine(start);
|
|
var column = getColumn(line, start);
|
|
|
|
var buf = new StringBuffer(
|
|
'${filename}:${line + 1}:${column + 1}: $message');
|
|
if (includeText) {
|
|
buf.add('\n');
|
|
var textLine;
|
|
// +1 for 0-indexing, +1 again to avoid the last line of the file
|
|
if ((line + 2) < _lineStarts.length) {
|
|
textLine = text.substring(_lineStarts[line], _lineStarts[line+1]);
|
|
} else {
|
|
textLine = text.substring(_lineStarts[line]) + '\n';
|
|
}
|
|
|
|
int toColumn = Math.min(column + (end-start), textLine.length);
|
|
if (options.useColors) {
|
|
buf.add(textLine.substring(0, column));
|
|
buf.add(_RED_COLOR);
|
|
buf.add(textLine.substring(column, toColumn));
|
|
buf.add(_NO_COLOR);
|
|
buf.add(textLine.substring(toColumn));
|
|
} else {
|
|
buf.add(textLine);
|
|
}
|
|
|
|
int i = 0;
|
|
for (; i < column; i++) {
|
|
buf.add(' ');
|
|
}
|
|
|
|
if (options.useColors) buf.add(_RED_COLOR);
|
|
for (; i < toColumn; i++) {
|
|
buf.add('^');
|
|
}
|
|
if (options.useColors) buf.add(_NO_COLOR);
|
|
}
|
|
|
|
return buf.toString();
|
|
}
|
|
|
|
/** Compares two source files. */
|
|
int compareTo(SourceFile other) {
|
|
if (orderInLibrary != null && other.orderInLibrary != null) {
|
|
return orderInLibrary - other.orderInLibrary;
|
|
} else {
|
|
return filename.compareTo(other.filename);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* A range of characters in a [SourceFile]. Used to represent the source
|
|
* positions of [Token]s and [Node]s for error reporting or other tooling
|
|
* work.
|
|
*/
|
|
// TODO(jmesserly): Rename to Span - but first write cool refactoring tool
|
|
class SourceSpan implements Comparable {
|
|
/** The [SourceFile] that contains this span. */
|
|
final SourceFile file;
|
|
|
|
/** The character position of the start of this span. */
|
|
final int start;
|
|
|
|
/** The character position of the end of this span. */
|
|
final int end;
|
|
|
|
SourceSpan(this.file, this.start, this.end);
|
|
|
|
/** Returns the source text corresponding to this [Span]. */
|
|
String get text() {
|
|
return file.text.substring(start, end);
|
|
}
|
|
|
|
toMessageString(String message) {
|
|
return file.getLocationMessage(message, start, end: end, includeText: true);
|
|
}
|
|
|
|
int get line() {
|
|
return file.getLine(start);
|
|
}
|
|
|
|
int get column() {
|
|
return file.getColumn(line, start);
|
|
}
|
|
|
|
int get endLine() {
|
|
return file.getLine(end);
|
|
}
|
|
|
|
int get endColumn() {
|
|
return file.getColumn(endLine, end);
|
|
}
|
|
|
|
String get locationText() {
|
|
var line = file.getLine(start);
|
|
var column = file.getColumn(line, start);
|
|
return '${file.filename}:${line + 1}:${column + 1}';
|
|
}
|
|
|
|
/** Compares two source spans by file and position. Handles nulls. */
|
|
int compareTo(SourceSpan other) {
|
|
if (file == other.file) {
|
|
int d = start - other.start;
|
|
return d == 0 ? (end - other.end) : d;
|
|
}
|
|
return file.compareTo(other.file);
|
|
}
|
|
}
|