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 |