OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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.source_information; | 5 library dart2js.source_information; |
6 | 6 |
7 import '../dart2jslib.dart' show SourceSpan; | 7 import '../dart2jslib.dart' show SourceSpan, MessageKind; |
8 import '../elements/elements.dart' show AstElement; | 8 import '../elements/elements.dart' show AstElement; |
9 import '../scanner/scannerlib.dart' show Token; | 9 import '../scanner/scannerlib.dart' show Token; |
10 import '../tree/tree.dart' show Node; | 10 import '../tree/tree.dart' show Node; |
11 import '../js/js.dart' show JavaScriptNodeSourceInformation; | 11 import '../js/js.dart' show JavaScriptNodeSourceInformation; |
12 import 'source_file.dart'; | 12 import 'source_file.dart'; |
13 | 13 |
14 /// Interface for passing source information, for instance for use in source | 14 /// Interface for passing source information, for instance for use in source |
15 /// maps, through the backend. | 15 /// maps, through the backend. |
16 abstract class SourceInformation extends JavaScriptNodeSourceInformation { | 16 abstract class SourceInformation extends JavaScriptNodeSourceInformation { |
17 SourceSpan get sourceSpan; | 17 SourceSpan get sourceSpan; |
18 | 18 |
19 /// The source location associated with the start of the JS node. | 19 /// The source location associated with the start of the JS node. |
20 SourceLocation get startPosition; | 20 SourceLocation get startPosition => null; |
21 | |
22 /// The source location associated with the closing of the JS node. | |
23 SourceLocation get closingPosition => null; | |
21 | 24 |
22 /// The source location associated with the end of the JS node. | 25 /// The source location associated with the end of the JS node. |
23 SourceLocation get endPosition; | 26 SourceLocation get endPosition => null; |
27 } | |
28 | |
29 /// Factory for creating [SourceInformationBuilder]s. | |
30 class SourceInformationFactory { | |
31 const SourceInformationFactory(); | |
32 | |
33 /// Create a [SourceInformationBuilder] for [element]. | |
34 SourceInformationBuilder forContext(AstElement element) { | |
35 return const SourceInformationBuilder(); | |
36 } | |
37 } | |
38 | |
39 /// Interface for generating [SourceInformation]. | |
40 class SourceInformationBuilder { | |
41 const SourceInformationBuilder(); | |
42 | |
43 /// Create a [SourceInformationBuilder] for [element]. | |
44 SourceInformationBuilder forContext(AstElement element) { | |
45 return this; | |
46 } | |
47 | |
48 /// Generate [SourceInformation] the declaration of [element]. | |
49 SourceInformation buildDeclaration(AstElement element) => null; | |
50 | |
51 /// Generate [SourceInformation] for the generic [node]. | |
52 @deprecated | |
53 SourceInformation buildGeneric(Node node) => null; | |
54 | |
55 /// Generate [SourceInformation] for the return [node]. | |
56 SourceInformation buildReturn(Node node) => null; | |
57 | |
58 /// Generate [SourceInformation] for the loop [node]. | |
59 SourceInformation buildLoop(Node node) => null; | |
60 | |
61 /// Generate [SourceInformation] for the read access in [node]. | |
62 SourceInformation buildGet(Node node) => null; | |
63 | |
64 /// Generate [SourceInformation] for the invocation in [node]. | |
65 SourceInformation buildCall(Node node) => null; | |
24 } | 66 } |
25 | 67 |
26 /// Source information that contains start source position and optionally an | 68 /// Source information that contains start source position and optionally an |
27 /// end source position. | 69 /// end source position. |
28 class StartEndSourceInformation implements SourceInformation { | 70 class StartEndSourceInformation extends SourceInformation { |
71 @override | |
29 final SourceLocation startPosition; | 72 final SourceLocation startPosition; |
73 | |
74 @override | |
30 final SourceLocation endPosition; | 75 final SourceLocation endPosition; |
31 | 76 |
32 StartEndSourceInformation(this.startPosition, [this.endPosition]); | 77 StartEndSourceInformation(this.startPosition, [this.endPosition]); |
33 | 78 |
79 @override | |
34 SourceSpan get sourceSpan { | 80 SourceSpan get sourceSpan { |
35 Uri uri = startPosition.sourceUri; | 81 Uri uri = startPosition.sourceUri; |
36 int begin = startPosition.offset; | 82 int begin = startPosition.offset; |
37 int end = endPosition == null ? begin : endPosition.offset; | 83 int end = endPosition == null ? begin : endPosition.offset; |
38 return new SourceSpan(uri, begin, end); | 84 return new SourceSpan(uri, begin, end); |
39 } | 85 } |
40 | 86 |
41 int get hashCode { | 87 int get hashCode { |
42 return (startPosition.hashCode * 17 + | 88 return 0x7FFFFFFF & |
43 endPosition.hashCode * 19) | 89 (startPosition.hashCode * 17 + endPosition.hashCode * 19); |
44 & 0x7FFFFFFF; | |
45 } | 90 } |
46 | 91 |
47 bool operator ==(other) { | 92 bool operator ==(other) { |
48 if (identical(this, other)) return true; | 93 if (identical(this, other)) return true; |
49 if (other is! StartEndSourceInformation) return false; | 94 if (other is! StartEndSourceInformation) return false; |
50 return startPosition == other.startPosition && | 95 return startPosition == other.startPosition && |
51 endPosition == other.endPosition; | 96 endPosition == other.endPosition; |
52 } | 97 } |
53 | 98 |
54 // TODO(johnniwinther): Remove this method. Source information should be | 99 // TODO(johnniwinther): Remove this method. Source information should be |
(...skipping 12 matching lines...) Expand all Loading... | |
67 beginToken = endToken = element.position; | 112 beginToken = endToken = element.position; |
68 } else { | 113 } else { |
69 beginToken = node.getBeginToken(); | 114 beginToken = node.getBeginToken(); |
70 endToken = node.getEndToken(); | 115 endToken = node.getEndToken(); |
71 } | 116 } |
72 // TODO(podivilov): find the right sourceFile here and remove offset | 117 // TODO(podivilov): find the right sourceFile here and remove offset |
73 // checks below. | 118 // checks below. |
74 SourceLocation sourcePosition, endSourcePosition; | 119 SourceLocation sourcePosition, endSourcePosition; |
75 if (beginToken.charOffset < sourceFile.length) { | 120 if (beginToken.charOffset < sourceFile.length) { |
76 sourcePosition = | 121 sourcePosition = |
77 new TokenSourceLocation(sourceFile, beginToken, name); | 122 new OffsetSourceLocation(sourceFile, beginToken.charOffset, name); |
78 } | 123 } |
79 if (endToken.charOffset < sourceFile.length) { | 124 if (endToken.charOffset < sourceFile.length) { |
80 endSourcePosition = | 125 endSourcePosition = |
81 new TokenSourceLocation(sourceFile, endToken, name); | 126 new OffsetSourceLocation(sourceFile, endToken.charOffset, name); |
82 } | 127 } |
83 return new StartEndSourceInformation(sourcePosition, endSourcePosition); | 128 return new StartEndSourceInformation(sourcePosition, endSourcePosition); |
84 } | 129 } |
85 | 130 |
86 String toString() { | 131 String toString() { |
87 StringBuffer sb = new StringBuffer(); | 132 StringBuffer sb = new StringBuffer(); |
88 sb.write('${startPosition.sourceUri}:'); | 133 sb.write('${startPosition.sourceUri}:'); |
89 // Use 1-based line/column info to match usual dart tool output. | 134 // Use 1-based line/column info to match usual dart tool output. |
90 sb.write('[${startPosition.line + 1},${startPosition.column + 1}]'); | 135 sb.write('[${startPosition.line + 1},${startPosition.column + 1}]'); |
91 if (endPosition != null) { | 136 if (endPosition != null) { |
92 sb.write('-[${endPosition.line + 1},${endPosition.column + 1}]'); | 137 sb.write('-[${endPosition.line + 1},${endPosition.column + 1}]'); |
93 } | 138 } |
94 return sb.toString(); | 139 return sb.toString(); |
95 } | 140 } |
96 } | 141 } |
97 | 142 |
143 class StartEndSourceInformationFactory implements SourceInformationFactory { | |
144 const StartEndSourceInformationFactory(); | |
145 | |
146 @override | |
147 SourceInformationBuilder forContext(AstElement element) { | |
148 return new StartEndSourceInformationBuilder(element); | |
149 } | |
150 } | |
151 | |
152 /// [SourceInformationBuilder] that generates [PositionSourceInformation]. | |
153 class StartEndSourceInformationBuilder extends SourceInformationBuilder { | |
154 final SourceFile sourceFile; | |
155 final String name; | |
156 | |
157 StartEndSourceInformationBuilder(AstElement element) | |
158 : sourceFile = element.compilationUnit.script.file, | |
159 name = element.name; | |
160 | |
161 SourceInformation buildDeclaration(AstElement element) { | |
162 return StartEndSourceInformation.computeSourceInformation(element); | |
163 } | |
164 | |
165 SourceLocation sourceFileLocationForToken(Token token) { | |
166 SourceLocation location = | |
167 new OffsetSourceLocation(sourceFile, token.charOffset, name); | |
168 checkValidSourceFileLocation(location, sourceFile, token.charOffset); | |
169 return location; | |
170 } | |
171 | |
172 void checkValidSourceFileLocation( | |
173 SourceLocation location, SourceFile sourceFile, int offset) { | |
174 if (!location.isValid) { | |
175 throw MessageKind.INVALID_SOURCE_FILE_LOCATION.message( | |
176 {'offset': offset, | |
177 'fileName': sourceFile.filename, | |
178 'length': sourceFile.length}); | |
179 } | |
180 } | |
181 | |
182 @override | |
183 SourceInformation buildLoop(Node node) { | |
184 return new StartEndSourceInformation( | |
185 sourceFileLocationForToken(node.getBeginToken()), | |
186 sourceFileLocationForToken(node.getEndToken())); | |
187 } | |
188 | |
189 @override | |
190 SourceInformation buildGeneric(Node node) { | |
191 return new StartEndSourceInformation( | |
192 sourceFileLocationForToken(node.getBeginToken())); | |
193 } | |
194 | |
195 @override | |
196 SourceInformation buildReturn(Node node) => buildGeneric(node); | |
197 | |
198 @override | |
199 SourceInformation buildGet(Node node) => buildGeneric(node); | |
200 | |
201 @override | |
202 SourceInformation buildCall(Node node) => buildGeneric(node); | |
203 | |
204 @override | |
205 SourceInformationBuilder forContext( | |
206 AstElement element, {SourceInformation sourceInformation}) { | |
207 return new StartEndSourceInformationBuilder(element); | |
208 } | |
209 } | |
210 | |
98 /// [SourceInformation] that consists of an offset position into the source | 211 /// [SourceInformation] that consists of an offset position into the source |
99 /// code. | 212 /// code. |
100 class PositionSourceInformation implements SourceInformation { | 213 class PositionSourceInformation extends SourceInformation { |
101 final SourceLocation sourcePosition; | 214 @override |
215 final SourceLocation startPosition; | |
102 | 216 |
103 PositionSourceInformation(this.sourcePosition); | 217 @override |
218 final SourceLocation closingPosition; | |
104 | 219 |
105 SourceLocation get startPosition => sourcePosition; | 220 PositionSourceInformation(this.startPosition, |
106 SourceLocation get endPosition => null; | 221 [this.closingPosition]); |
107 | 222 |
223 @override | |
108 SourceSpan get sourceSpan { | 224 SourceSpan get sourceSpan { |
109 Uri uri = sourcePosition.sourceUri; | 225 SourceLocation location = |
110 int offset = sourcePosition.offset; | 226 startPosition != null ? startPosition : closingPosition; |
227 Uri uri = location.sourceUri; | |
228 int offset = location.offset; | |
111 return new SourceSpan(uri, offset, offset); | 229 return new SourceSpan(uri, offset, offset); |
112 } | 230 } |
113 | 231 |
114 int get hashCode { | 232 int get hashCode { |
115 return sourcePosition.hashCode * 17 & 0x7FFFFFFF; | 233 return 0x7FFFFFFF & |
234 (startPosition.hashCode * 17 + closingPosition.hashCode * 19); | |
116 } | 235 } |
117 | 236 |
118 bool operator ==(other) { | 237 bool operator ==(other) { |
119 if (identical(this, other)) return true; | 238 if (identical(this, other)) return true; |
120 if (other is! PositionSourceInformation) return false; | 239 if (other is! PositionSourceInformation) return false; |
121 return sourcePosition == other.sourcePosition; | 240 return startPosition == other.startPosition && |
241 closingPosition == other.closingPosition; | |
122 } | 242 } |
123 | 243 |
124 String toString() { | 244 String toString() { |
125 StringBuffer sb = new StringBuffer(); | 245 StringBuffer sb = new StringBuffer(); |
126 sb.write('${sourcePosition.sourceUri}:'); | 246 if (startPosition != null) { |
247 sb.write('${startPosition.sourceUri}:'); | |
248 } else { | |
249 sb.write('${closingPosition.sourceUri}:'); | |
250 } | |
127 // Use 1-based line/column info to match usual dart tool output. | 251 // Use 1-based line/column info to match usual dart tool output. |
128 sb.write('[${sourcePosition.line + 1},${sourcePosition.column + 1}]'); | 252 if (startPosition != null) { |
253 sb.write('[${startPosition.line + 1},' | |
254 '${startPosition.column + 1}]'); | |
255 } | |
256 if (closingPosition != null) { | |
257 sb.write('-[${closingPosition.line + 1},' | |
258 '${closingPosition.column + 1}]'); | |
259 } | |
129 return sb.toString(); | 260 return sb.toString(); |
130 } | 261 } |
131 } | 262 } |
132 | 263 |
133 /// A location in a source file. | 264 /// A location in a source file. |
134 abstract class SourceLocation { | 265 abstract class SourceLocation { |
135 final SourceFile _sourceFile; | 266 final SourceFile _sourceFile; |
136 int _line; | 267 int _line; |
137 | 268 |
138 SourceLocation(this._sourceFile) { | 269 SourceLocation(this._sourceFile) { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
173 offset == other.offset && | 304 offset == other.offset && |
174 sourceName == other.sourceName; | 305 sourceName == other.sourceName; |
175 } | 306 } |
176 | 307 |
177 String toString() { | 308 String toString() { |
178 // Use 1-based line/column info to match usual dart tool output. | 309 // Use 1-based line/column info to match usual dart tool output. |
179 return '${sourceUri}:[${line + 1},${column + 1}]'; | 310 return '${sourceUri}:[${line + 1},${column + 1}]'; |
180 } | 311 } |
181 } | 312 } |
182 | 313 |
183 class TokenSourceLocation extends SourceLocation { | 314 class OffsetSourceLocation extends SourceLocation { |
184 final Token token; | 315 final int offset; |
185 final String sourceName; | 316 final String sourceName; |
186 | 317 |
187 TokenSourceLocation(SourceFile sourceFile, this.token, this.sourceName) | 318 OffsetSourceLocation(SourceFile sourceFile, this.offset, this.sourceName) |
188 : super(sourceFile); | 319 : super(sourceFile); |
floitsch
2015/04/21 11:31:53
indent++
Johnni Winther
2015/04/21 12:07:01
Done.
| |
189 | 320 |
190 @override | |
191 int get offset => token.charOffset; | |
192 | 321 |
193 String toString() { | 322 String toString() { |
194 return '${super.toString()}:$sourceName'; | 323 return '${super.toString()}:$sourceName'; |
195 } | 324 } |
196 } | 325 } |
326 | |
327 class PositionSourceInformationFactory implements SourceInformationFactory { | |
328 const PositionSourceInformationFactory(); | |
329 | |
330 @override | |
331 SourceInformationBuilder forContext(AstElement element) { | |
332 return new PositionSourceInformationBuilder(element); | |
333 } | |
334 } | |
335 | |
336 /// [SourceInformationBuilder] that generates [PositionSourceInformation]. | |
337 class PositionSourceInformationBuilder implements SourceInformationBuilder { | |
338 final SourceFile sourceFile; | |
339 final String name; | |
340 | |
341 PositionSourceInformationBuilder(AstElement element) | |
342 : sourceFile = element.implementation.compilationUnit.script.file, | |
343 name = element.name; | |
344 | |
345 SourceInformation buildDeclaration(AstElement element) { | |
346 if (element.isSynthesized) { | |
347 return new PositionSourceInformation( | |
348 new OffsetSourceLocation( | |
349 sourceFile, element.position.charOffset, name)); | |
350 } else { | |
351 return new PositionSourceInformation( | |
352 null, | |
353 new OffsetSourceLocation(sourceFile, | |
354 element.resolvedAst.node.getEndToken().charOffset, name)); | |
355 } | |
356 } | |
357 | |
358 SourceInformation buildBegin(Node node) { | |
359 return new PositionSourceInformation(new OffsetSourceLocation( | |
360 sourceFile, node.getBeginToken().charOffset, name)); | |
361 } | |
362 | |
363 @override | |
364 SourceInformation buildGeneric(Node node) => buildBegin(node); | |
365 | |
366 @override | |
367 SourceInformation buildReturn(Node node) => buildBegin(node); | |
368 | |
369 @override | |
370 SourceInformation buildLoop(Node node) => buildBegin(node); | |
371 | |
372 @override | |
373 SourceInformation buildGet(Node node) => buildBegin(node); | |
374 | |
375 @override | |
376 SourceInformation buildCall(Node node) => buildBegin(node); | |
377 | |
378 @override | |
379 SourceInformationBuilder forContext(AstElement element) { | |
380 return new PositionSourceInformationBuilder(element); | |
381 } | |
382 } | |
OLD | NEW |