Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 /// ----------------------------------------------------------------------- | 5 /// ----------------------------------------------------------------------- |
| 6 /// ERROR HANDLING | 6 /// ERROR HANDLING |
| 7 /// ----------------------------------------------------------------------- | 7 /// ----------------------------------------------------------------------- |
| 8 /// | 8 /// |
| 9 /// As a rule of thumb, errors that can be detected statically are handled by | 9 /// As a rule of thumb, errors that can be detected statically are handled by |
| 10 /// the frontend, typically by translating the erroneous code into a 'throw' or | 10 /// the frontend, typically by translating the erroneous code into a 'throw' or |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 43 /// | 43 /// |
| 44 /// Use [Transformer] for bulk transformations that are likely to transform lots | 44 /// Use [Transformer] for bulk transformations that are likely to transform lots |
| 45 /// of nodes, and [TreeNode.replaceWith] for sparse transformations that mutate | 45 /// of nodes, and [TreeNode.replaceWith] for sparse transformations that mutate |
| 46 /// relatively few nodes. Or use whichever is more convenient. | 46 /// relatively few nodes. Or use whichever is more convenient. |
| 47 /// | 47 /// |
| 48 /// The AST can also be mutated by direct field manipulation, but the user then | 48 /// The AST can also be mutated by direct field manipulation, but the user then |
| 49 /// has to update parent pointers manually. | 49 /// has to update parent pointers manually. |
| 50 /// | 50 /// |
| 51 library kernel.ast; | 51 library kernel.ast; |
| 52 | 52 |
| 53 import 'dart:convert' show UTF8; | |
| 54 | |
| 53 import 'visitor.dart'; | 55 import 'visitor.dart'; |
| 54 export 'visitor.dart'; | 56 export 'visitor.dart'; |
| 55 | 57 |
| 56 import 'canonical_name.dart' show CanonicalName; | 58 import 'canonical_name.dart' show CanonicalName; |
| 57 export 'canonical_name.dart' show CanonicalName; | 59 export 'canonical_name.dart' show CanonicalName; |
| 58 | 60 |
| 59 import 'transformations/flags.dart'; | 61 import 'transformations/flags.dart'; |
| 60 import 'text/ast_to_text.dart'; | 62 import 'text/ast_to_text.dart'; |
| 61 import 'type_algebra.dart'; | 63 import 'type_algebra.dart'; |
| 62 import 'type_environment.dart'; | 64 import 'type_environment.dart'; |
| (...skipping 4037 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4100 } | 4102 } |
| 4101 | 4103 |
| 4102 transformChildren(Transformer v) { | 4104 transformChildren(Transformer v) { |
| 4103 transformList(libraries, v, this); | 4105 transformList(libraries, v, this); |
| 4104 } | 4106 } |
| 4105 | 4107 |
| 4106 Program get enclosingProgram => this; | 4108 Program get enclosingProgram => this; |
| 4107 | 4109 |
| 4108 /// Translates an offset to line and column numbers in the given file. | 4110 /// Translates an offset to line and column numbers in the given file. |
| 4109 Location getLocation(String file, int offset) { | 4111 Location getLocation(String file, int offset) { |
| 4110 List<int> lines = uriToSource[file].lineStarts; | 4112 return uriToSource[file]?.getLocation(file, offset); |
| 4111 int low = 0, high = lines.length - 1; | |
| 4112 while (low < high) { | |
| 4113 int mid = high - ((high - low) >> 1); // Get middle, rounding up. | |
| 4114 int pivot = lines[mid]; | |
| 4115 if (pivot <= offset) { | |
| 4116 low = mid; | |
| 4117 } else { | |
| 4118 high = mid - 1; | |
| 4119 } | |
| 4120 } | |
| 4121 int lineIndex = low; | |
| 4122 int lineStart = lines[lineIndex]; | |
| 4123 int lineNumber = 1 + lineIndex; | |
| 4124 int columnNumber = 1 + offset - lineStart; | |
| 4125 return new Location(file, lineNumber, columnNumber); | |
| 4126 } | 4113 } |
| 4127 } | 4114 } |
| 4128 | 4115 |
| 4129 /// A tuple with file, line, and column number, for displaying human-readable | 4116 /// A tuple with file, line, and column number, for displaying human-readable |
| 4130 /// locations. | 4117 /// locations. |
| 4131 class Location { | 4118 class Location { |
| 4132 final String file; | 4119 final String file; |
| 4133 final int line; // 1-based. | 4120 final int line; // 1-based. |
| 4134 final int column; // 1-based. | 4121 final int column; // 1-based. |
| 4135 | 4122 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4221 if (node == child) { | 4208 if (node == child) { |
| 4222 return replacement; | 4209 return replacement; |
| 4223 } else { | 4210 } else { |
| 4224 return node; | 4211 return node; |
| 4225 } | 4212 } |
| 4226 } | 4213 } |
| 4227 } | 4214 } |
| 4228 | 4215 |
| 4229 class Source { | 4216 class Source { |
| 4230 final List<int> lineStarts; | 4217 final List<int> lineStarts; |
| 4218 | |
| 4231 final List<int> source; | 4219 final List<int> source; |
| 4232 | 4220 |
| 4221 String cachedText; | |
| 4222 | |
| 4233 Source(this.lineStarts, this.source); | 4223 Source(this.lineStarts, this.source); |
| 4224 | |
| 4225 /// Return the text corresponding to [line] which is a 1-based line | |
| 4226 /// number. The returned line contains no line separators. | |
| 4227 String getTextLine(int line) { | |
| 4228 _rangeCheck(line, 1, lineStarts.length, "line"); | |
| 4229 if (source == null) return null; | |
| 4230 | |
| 4231 cachedText ??= UTF8.decode(source, allowMalformed: true); | |
| 4232 // -1 as line numbers start at 1. | |
| 4233 int index = line - 1; | |
| 4234 if (index + 1 == lineStarts.length) { | |
| 4235 // Last line. | |
| 4236 return cachedText.substring(lineStarts[index]); | |
| 4237 } else if (index < lineStarts.length) { | |
| 4238 // We subtract 1 from the next line for two reasons: | |
| 4239 // 1. If the file isn't terminated by a newline, that index is invalid. | |
| 4240 // 2. To remove the newline at the end of the line. | |
| 4241 int endOfLine = lineStarts[index + 1] - 1; | |
| 4242 if (endOfLine > index && cachedText[endOfLine - 1] == "\r") { | |
| 4243 --endOfLine; // Windows line endings. | |
| 4244 } | |
| 4245 return cachedText.substring(lineStarts[index], endOfLine); | |
| 4246 } | |
| 4247 // This shouldn't happen: should have been caught by the range check above. | |
| 4248 throw "Internal error"; | |
| 4249 } | |
| 4250 | |
| 4251 /// Translates an offset to line and column numbers in the given file. | |
| 4252 Location getLocation(String file, int offset) { | |
| 4253 _rangeCheck(offset, 0, lineStarts.last, "offset"); | |
| 4254 int low = 0, high = lineStarts.length - 1; | |
| 4255 while (low < high) { | |
| 4256 int mid = high - ((high - low) >> 1); // Get middle, rounding up. | |
| 4257 int pivot = lineStarts[mid]; | |
| 4258 if (pivot <= offset) { | |
| 4259 low = mid; | |
| 4260 } else { | |
| 4261 high = mid - 1; | |
| 4262 } | |
| 4263 } | |
| 4264 int lineIndex = low; | |
| 4265 int lineStart = lineStarts[lineIndex]; | |
| 4266 int lineNumber = 1 + lineIndex; | |
| 4267 int columnNumber = 1 + offset - lineStart; | |
| 4268 return new Location(file, lineNumber, columnNumber); | |
| 4269 } | |
| 4270 } | |
| 4271 | |
| 4272 void _rangeCheck(int value, int min, int max, String name) { | |
| 4273 RangeError.checkValueInInterval(value, min, max, name, | |
| 4274 "The value of '$name' ($value) must be between $min and $max."); | |
|
sra1
2017/05/04 05:44:39
Please remove this interpolation.
It is expensive
| |
| 4234 } | 4275 } |
| 4235 | 4276 |
| 4236 /// Returns the [Reference] object for the given member. | 4277 /// Returns the [Reference] object for the given member. |
| 4237 /// | 4278 /// |
| 4238 /// Returns `null` if the member is `null`. | 4279 /// Returns `null` if the member is `null`. |
| 4239 Reference getMemberReference(Member member) { | 4280 Reference getMemberReference(Member member) { |
| 4240 return member?.reference; | 4281 return member?.reference; |
| 4241 } | 4282 } |
| 4242 | 4283 |
| 4243 /// Returns the [Reference] object for the given class. | 4284 /// Returns the [Reference] object for the given class. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4275 /// library has not been assigned a canonical name yet. | 4316 /// library has not been assigned a canonical name yet. |
| 4276 /// | 4317 /// |
| 4277 /// Returns `null` if the library is `null`. | 4318 /// Returns `null` if the library is `null`. |
| 4278 CanonicalName getCanonicalNameOfLibrary(Library library) { | 4319 CanonicalName getCanonicalNameOfLibrary(Library library) { |
| 4279 if (library == null) return null; | 4320 if (library == null) return null; |
| 4280 if (library.canonicalName == null) { | 4321 if (library.canonicalName == null) { |
| 4281 throw '$library has no canonical name'; | 4322 throw '$library has no canonical name'; |
| 4282 } | 4323 } |
| 4283 return library.canonicalName; | 4324 return library.canonicalName; |
| 4284 } | 4325 } |
| OLD | NEW |