blob: c0e6e0a80d5f316b95036be267b685d710a6dc01 [file] [log] [blame]
// Copyright (c) 2015, 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.
library dart2js.source_information;
import '../dart2jslib.dart' show SourceSpan;
import '../elements/elements.dart' show AstElement;
import '../scanner/scannerlib.dart' show Token;
import '../tree/tree.dart' show Node;
import '../js/js.dart' show JavaScriptNodeSourceInformation;
import 'code_output.dart';
import 'source_file.dart';
/// Interface for passing source information, for instance for use in source
/// maps, through the backend.
abstract class SourceInformation extends JavaScriptNodeSourceInformation {
SourceSpan get sourceSpan;
void beginMapping(CodeOutput output);
void endMapping(CodeOutput output);
}
/// Source information that contains start source position and optionally an
/// end source position.
class StartEndSourceInformation implements SourceInformation {
final SourceFileLocation startPosition;
final SourceFileLocation endPosition;
StartEndSourceInformation(this.startPosition, [this.endPosition]);
SourceSpan get sourceSpan {
Uri uri = Uri.parse(startPosition.sourceFile.filename);
int begin = startPosition.offset;
int end = endPosition == null ? begin : endPosition.offset;
return new SourceSpan(uri, begin, end);
}
void beginMapping(CodeBuffer output) {
output.beginMappedRange();
output.setSourceLocation(startPosition);
}
void endMapping(CodeBuffer output) {
if (endPosition != null) {
output.setSourceLocation(endPosition);
}
output.endMappedRange();
}
int get hashCode {
return (startPosition.hashCode * 17 +
endPosition.hashCode * 19)
& 0x7FFFFFFF;
}
bool operator ==(other) {
if (identical(this, other)) return true;
if (other is! StartEndSourceInformation) return false;
return startPosition == other.startPosition &&
endPosition == other.endPosition;
}
// TODO(johnniwinther): Remove this method. Source information should be
// computed based on the element by provided from statements and expressions.
static StartEndSourceInformation computeSourceInformation(
AstElement element) {
AstElement implementation = element.implementation;
SourceFile sourceFile = implementation.compilationUnit.script.file;
String name = element.name;
Node node = implementation.node;
Token beginToken;
Token endToken;
if (node == null) {
// Synthesized node. Use the enclosing element for the location.
beginToken = endToken = element.position;
} else {
beginToken = node.getBeginToken();
endToken = node.getEndToken();
}
// TODO(podivilov): find the right sourceFile here and remove offset
// checks below.
SourceFileLocation sourcePosition, endSourcePosition;
if (beginToken.charOffset < sourceFile.length) {
sourcePosition =
new TokenSourceFileLocation(sourceFile, beginToken, name);
}
if (endToken.charOffset < sourceFile.length) {
endSourcePosition =
new TokenSourceFileLocation(sourceFile, endToken, name);
}
return new StartEndSourceInformation(sourcePosition, endSourcePosition);
}
String toString() {
StringBuffer sb = new StringBuffer();
sb.write('${startPosition.getSourceUrl()}:');
sb.write('[${startPosition.getLine()},${startPosition.getColumn()}]');
if (endPosition != null) {
sb.write('-[${endPosition.getLine()},${endPosition.getColumn()}]');
}
return sb.toString();
}
}
// TODO(johnniwinther): Refactor this class to use getters.
abstract class SourceFileLocation {
SourceFile sourceFile;
SourceFileLocation(this.sourceFile) {
assert(isValid());
}
int line;
int get offset;
String getSourceUrl() => sourceFile.filename;
int getLine() {
if (line == null) line = sourceFile.getLine(offset);
return line;
}
int getColumn() => sourceFile.getColumn(getLine(), offset);
String getSourceName();
bool isValid() => offset < sourceFile.length;
int get hashCode {
return getSourceUrl().hashCode * 17 +
offset.hashCode * 17 +
getSourceName().hashCode * 23;
}
bool operator ==(other) {
if (identical(this, other)) return true;
if (other is! SourceFileLocation) return false;
return getSourceUrl() == other.getSourceUrl() &&
offset == other.offset &&
getSourceName() == other.getSourceName();
}
String toString() => '${getSourceUrl()}:[${getLine()},${getColumn()}]';
}
class TokenSourceFileLocation extends SourceFileLocation {
final Token token;
final String name;
TokenSourceFileLocation(SourceFile sourceFile, this.token, this.name)
: super(sourceFile);
int get offset => token.charOffset;
String getSourceName() {
return name;
}
String toString() {
return '${super.toString()}:$name';
}
}