Chromium Code Reviews| Index: pkg/compiler/lib/src/io/start_end_information.dart |
| diff --git a/pkg/compiler/lib/src/io/start_end_information.dart b/pkg/compiler/lib/src/io/start_end_information.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..2ee6da965d3b90d467ad70430c4c341f94fda529 |
| --- /dev/null |
| +++ b/pkg/compiler/lib/src/io/start_end_information.dart |
| @@ -0,0 +1,230 @@ |
| +// 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. |
| + |
| +/// Source information system that maps spans of Dart AST nodes to spans of |
| +/// JavaScript nodes. |
| + |
| +library dart2js.source_information.start_end; |
| + |
| +import '../dart2jslib.dart' show |
| + MessageKind, |
| + SourceSpan; |
| +import '../elements/elements.dart' show |
| + AstElement, |
| + LocalElement; |
| +import '../js/js.dart' as js; |
| +import '../js/js_source_mapping.dart'; |
| +import '../scanner/scannerlib.dart' show Token; |
| +import '../tree/tree.dart' show Node, Send; |
| + |
| +import 'source_file.dart'; |
| +import 'source_information.dart'; |
| + |
| +/// Source information that contains start source position and optionally an |
| +/// end source position. |
| +class StartEndSourceInformation extends SourceInformation { |
| + @override |
| + final SourceLocation startPosition; |
| + |
| + @override |
| + final SourceLocation endPosition; |
| + |
| + StartEndSourceInformation(this.startPosition, [this.endPosition]); |
| + |
| + @override |
| + List<SourceLocation> get sourceLocations { |
| + if (endPosition == null) { |
| + return <SourceLocation>[startPosition]; |
| + } else { |
| + return <SourceLocation>[startPosition, endPosition]; |
| + } |
| + } |
| + |
| + @override |
| + SourceSpan get sourceSpan { |
| + Uri uri = startPosition.sourceUri; |
| + int begin = startPosition.offset; |
| + int end = endPosition == null ? begin : endPosition.offset; |
| + return new SourceSpan(uri, begin, end); |
| + } |
| + |
| + int get hashCode { |
| + return 0x7FFFFFFF & |
| + (startPosition.hashCode * 17 + endPosition.hashCode * 19); |
| + } |
| + |
| + 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. |
|
floitsch
2015/06/29 08:55:52
-by-
Johnni Winther
2015/06/29 12:36:29
TODO was stale. Replaced with the appropriate.
|
| + static StartEndSourceInformation computeSourceInformation( |
| + AstElement element) { |
| + |
| + AstElement implementation = element.implementation; |
| + SourceFile sourceFile = implementation.compilationUnit.script.file; |
| + String name = computeElementNameForSourceMaps(element); |
| + 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 |
|
floitsch
2015/06/29 08:55:52
I think we can safely reassign this TODO.
Johnni Winther
2015/06/29 12:36:29
Done.
|
| + // checks below. |
| + SourceLocation sourcePosition, endSourcePosition; |
| + if (beginToken.charOffset < sourceFile.length) { |
| + sourcePosition = |
| + new OffsetSourceLocation(sourceFile, beginToken.charOffset, name); |
| + } |
| + if (endToken.charOffset < sourceFile.length) { |
| + endSourcePosition = |
| + new OffsetSourceLocation(sourceFile, endToken.charOffset, name); |
| + } |
| + return new StartEndSourceInformation(sourcePosition, endSourcePosition); |
| + } |
| + |
| + String get shortText { |
| + StringBuffer sb = new StringBuffer(); |
| + sb.write('${startPosition.sourceUri.pathSegments.last}:'); |
| + // Use 1-based line/startPosition info to match usual dart tool output. |
| + sb.write('[${startPosition.line + 1},${startPosition.column + 1}]'); |
| + if (endPosition != null) { |
| + sb.write('-[${endPosition.line + 1},${endPosition.column + 1}]'); |
| + } |
| + return sb.toString(); |
| + } |
| + |
| + String toString() { |
| + StringBuffer sb = new StringBuffer(); |
|
floitsch
2015/06/29 08:55:52
create a helper function?
Only seems to differ in
Johnni Winther
2015/06/29 12:36:29
Done.
|
| + sb.write('${startPosition.sourceUri}:'); |
| + // Use 1-based line/column info to match usual dart tool output. |
| + sb.write('[${startPosition.line + 1},${startPosition.column + 1}]'); |
| + if (endPosition != null) { |
| + sb.write('-[${endPosition.line + 1},${endPosition.column + 1}]'); |
| + } |
| + return sb.toString(); |
| + } |
| +} |
| + |
| +class StartEndSourceInformationStrategy |
| + implements JavaScriptSourceInformationStrategy { |
| + const StartEndSourceInformationStrategy(); |
| + |
| + @override |
| + SourceInformationBuilder createBuilderForContext(AstElement element) { |
| + return new StartEndSourceInformationBuilder(element); |
| + } |
| + |
| + @override |
| + SourceInformationProcessor createProcessor(SourceMapper sourceMapper) { |
| + return new StartEndSourceInformationProcessor(sourceMapper); |
| + } |
| +} |
| + |
| +class StartEndSourceInformationProcessor extends SourceInformationProcessor { |
| + final SourceMapper sourceMapper; |
| + js.Node root; |
|
floitsch
2015/06/29 08:55:52
comments what "root" is.
unless there are subclass
Johnni Winther
2015/06/29 12:36:29
Done.
|
| + |
| + StartEndSourceInformationProcessor(this.sourceMapper); |
| + |
| + @override |
| + void onPositions(js.Node node, |
| + int startPosition, |
| + int endPosition, |
| + int closingPosition) { |
| + if (node.sourceInformation != null) { |
| + StartEndSourceInformation sourceInformation = node.sourceInformation; |
| + sourceMapper.register( |
| + node, startPosition, sourceInformation.startPosition); |
| + if (sourceInformation.endPosition != null) { |
| + sourceMapper.register(node, endPosition, sourceInformation.endPosition); |
| + } |
| + if (root == null) { |
| + sourceMapper.register(node, endPosition, null); |
| + root = node; |
| + } |
| + } |
| + } |
| +} |
| + |
| +/// [SourceInformationBuilder] that generates [PositionSourceInformation]. |
| +class StartEndSourceInformationBuilder extends SourceInformationBuilder { |
| + final SourceFile sourceFile; |
| + final String name; |
| + |
| + StartEndSourceInformationBuilder(AstElement element) |
| + : sourceFile = element.compilationUnit.script.file, |
| + name = computeElementNameForSourceMaps(element); |
| + |
| + SourceInformation buildDeclaration(AstElement element) { |
| + return StartEndSourceInformation.computeSourceInformation(element); |
| + } |
| + |
| + SourceLocation sourceFileLocationForToken(Token token) { |
| + SourceLocation location = |
| + new OffsetSourceLocation(sourceFile, token.charOffset, name); |
| + checkValidSourceFileLocation(location, sourceFile, token.charOffset); |
| + return location; |
| + } |
| + |
| + void checkValidSourceFileLocation( |
| + SourceLocation location, SourceFile sourceFile, int offset) { |
| + if (!location.isValid) { |
| + throw MessageKind.INVALID_SOURCE_FILE_LOCATION.message( |
| + {'offset': offset, |
| + 'fileName': sourceFile.filename, |
| + 'length': sourceFile.length}); |
| + } |
| + } |
| + |
| + @override |
| + SourceInformation buildLoop(Node node) { |
| + return new StartEndSourceInformation( |
| + sourceFileLocationForToken(node.getBeginToken()), |
| + sourceFileLocationForToken(node.getEndToken())); |
| + } |
| + |
| + @override |
| + SourceInformation buildGeneric(Node node) { |
| + return new StartEndSourceInformation( |
| + sourceFileLocationForToken(node.getBeginToken())); |
| + } |
| + |
| + @override |
| + SourceInformation buildReturn(Node node) { |
| + return buildGeneric(node); |
| + } |
| + |
| + @override |
| + SourceInformation buildGet(Node node) => buildGeneric(node); |
| + |
| + @override |
| + SourceInformation buildAssignment(Node node) => buildGeneric(node); |
| + |
| + @override |
| + SourceInformation buildCall(Node receiver, Node call) { |
| + return buildGeneric(receiver); |
| + } |
| + |
| + @override |
| + SourceInformation buildIf(Node node) => buildGeneric(node); |
| + |
| + @override |
| + SourceInformationBuilder forContext( |
| + AstElement element, {SourceInformation sourceInformation}) { |
| + return new StartEndSourceInformationBuilder(element); |
| + } |
| +} |
| + |
| + |
| + |