Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1167)

Side by Side Diff: pkg/kernel/lib/ast.dart

Issue 2788373002: Add Source.getTextLine and use it to display source snippets in error messages. (Closed)
Patch Set: Remove getLine, getColumn, and getLineText. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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 RangeError.checkValueInInterval(
4229 line,
4230 1,
4231 lineStarts.length,
4232 "line",
4233 "The value of 'line' ($line) must be between 1 and "
4234 "${lineStarts.length}.");
4235 if (source == null) return null;
4236
4237 cachedText ??= UTF8.decode(source, allowMalformed: true);
4238 // -1 as line numbers start at 1.
4239 int index = line - 1;
4240 if (index + 1 == lineStarts.length) {
4241 // Last line.
4242 return cachedText.substring(lineStarts[index]);
4243 } else if (index < lineStarts.length) {
4244 // We subtract 1 from the next line for two reasons:
4245 // 1. If the file isn't terminated by a newline, that index is invalid.
4246 // 2. To remove the newline at the end of the line.
4247 int endOfLine = lineStarts[index + 1] - 1;
4248 if (endOfLine > index && cachedText[endOfLine - 1] == "\r") {
4249 --endOfLine; // Windows line endings.
4250 }
4251 return cachedText.substring(lineStarts[index], endOfLine);
4252 }
4253 // This shouldn't happen: should have been caught by the range check above.
4254 throw "Internal error";
4255 }
4256
4257 /// Translates an offset to line and column numbers in the given file.
4258 Location getLocation(String file, int offset) {
4259 RangeError.checkValueInInterval(
4260 offset,
4261 0,
4262 lineStarts.last,
4263 "offset",
4264 "The value of 'offset' ($offset) must be between 0 and "
4265 "${lineStarts.length}.");
asgerf 2017/04/04 08:53:05 length -> last
ahe 2017/04/05 11:34:23 Done.
4266
4267 int low = 0, high = lineStarts.length - 1;
4268 while (low < high) {
4269 int mid = high - ((high - low) >> 1); // Get middle, rounding up.
4270 int pivot = lineStarts[mid];
4271 if (pivot <= offset) {
4272 low = mid;
4273 } else {
4274 high = mid - 1;
4275 }
4276 }
4277 int lineIndex = low;
4278 int lineStart = lineStarts[lineIndex];
4279 int lineNumber = 1 + lineIndex;
4280 int columnNumber = 1 + offset - lineStart;
4281 return new Location(file, lineNumber, columnNumber);
4282 }
4234 } 4283 }
4235 4284
4236 /// Returns the [Reference] object for the given member. 4285 /// Returns the [Reference] object for the given member.
4237 /// 4286 ///
4238 /// Returns `null` if the member is `null`. 4287 /// Returns `null` if the member is `null`.
4239 Reference getMemberReference(Member member) { 4288 Reference getMemberReference(Member member) {
4240 return member?.reference; 4289 return member?.reference;
4241 } 4290 }
4242 4291
4243 /// Returns the [Reference] object for the given class. 4292 /// Returns the [Reference] object for the given class.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
4275 /// library has not been assigned a canonical name yet. 4324 /// library has not been assigned a canonical name yet.
4276 /// 4325 ///
4277 /// Returns `null` if the library is `null`. 4326 /// Returns `null` if the library is `null`.
4278 CanonicalName getCanonicalNameOfLibrary(Library library) { 4327 CanonicalName getCanonicalNameOfLibrary(Library library) {
4279 if (library == null) return null; 4328 if (library == null) return null;
4280 if (library.canonicalName == null) { 4329 if (library.canonicalName == null) {
4281 throw '$library has no canonical name'; 4330 throw '$library has no canonical name';
4282 } 4331 }
4283 return library.canonicalName; 4332 return library.canonicalName;
4284 } 4333 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698