| // Copyright (c) 2012, 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. |
| |
| part of dart.core; |
| |
| // Exceptions are thrown either by the VM or from Dart code. |
| |
| /// A marker interface implemented by all core library exceptions. |
| /// |
| /// An [Exception] is intended to convey information to the user about a failure, |
| /// so that the error can be addressed programmatically. It is intended to be |
| /// caught, and it should contain useful data fields. |
| /// |
| /// Creating instances of [Exception] directly with `Exception("message")` |
| /// is discouraged in library code since it doesn't give users a precise |
| /// type they can catch. It may be reasonable to use instances of this |
| /// class in tests or during development. |
| abstract class Exception { |
| factory Exception([var message]) => _Exception(message); |
| } |
| |
| /// Default implementation of [Exception] which carries a message. |
| class _Exception implements Exception { |
| final dynamic message; |
| |
| _Exception([this.message]); |
| |
| String toString() { |
| Object? message = this.message; |
| if (message == null) return "Exception"; |
| return "Exception: $message"; |
| } |
| } |
| |
| /// Exception thrown when a string or some other data does not have an expected |
| /// format and cannot be parsed or processed. |
| class FormatException implements Exception { |
| /// A message describing the format error. |
| final String message; |
| |
| /// The actual source input which caused the error. |
| /// |
| /// This is usually a [String], but can be other types too. |
| /// If it is a string, parts of it may be included in the [toString] message. |
| /// |
| /// The source is `null` if omitted or unknown. |
| final dynamic source; |
| |
| /// The offset in [source] where the error was detected. |
| /// |
| /// A zero-based offset into the source that marks the format error causing |
| /// this exception to be created. If `source` is a string, this should be a |
| /// string index in the range `0 <= offset <= source.length`. |
| /// |
| /// If input is a string, the [toString] method may represent this offset as |
| /// a line and character position. The offset should be inside the string, |
| /// or at the end of the string. |
| /// |
| /// May be omitted. If present, [source] should also be present if possible. |
| final int? offset; |
| |
| /// Creates a new `FormatException` with an optional error [message]. |
| /// |
| /// Optionally also supply the actual [source] with the incorrect format, |
| /// and the [offset] in the format where a problem was detected. |
| @pragma("vm:entry-point") |
| const FormatException([this.message = "", this.source, this.offset]); |
| |
| /// Returns a description of the format exception. |
| /// |
| /// The description always contains the [message]. |
| /// |
| /// If [source] is present and is a string, the description will contain |
| /// (at least a part of) the source. |
| /// If [offset] is also provided, the part of the source included will |
| /// contain that offset, and the offset will be marked. |
| /// |
| /// If the source is a string and it contains a line break before offset, |
| /// only the line containing offset will be included, and its line number |
| /// will also be part of the description. Line and character offsets are |
| /// 1-based. |
| String toString() { |
| String report = "FormatException"; |
| Object? message = this.message; |
| if (message != null && "" != message) { |
| report = "$report: $message"; |
| } |
| int? offset = this.offset; |
| Object? source = this.source; |
| if (source is String) { |
| if (offset != null && (offset < 0 || offset > source.length)) { |
| offset = null; |
| } |
| // Source is string and offset is null or valid. |
| if (offset == null) { |
| if (source.length > 78) { |
| source = source.substring(0, 75) + "..."; |
| } |
| return "$report\n$source"; |
| } |
| int lineNum = 1; |
| int lineStart = 0; |
| bool previousCharWasCR = false; |
| for (int i = 0; i < offset; i++) { |
| int char = source.codeUnitAt(i); |
| if (char == 0x0a) { |
| if (lineStart != i || !previousCharWasCR) { |
| lineNum++; |
| } |
| lineStart = i + 1; |
| previousCharWasCR = false; |
| } else if (char == 0x0d) { |
| lineNum++; |
| lineStart = i + 1; |
| previousCharWasCR = true; |
| } |
| } |
| if (lineNum > 1) { |
| report += " (at line $lineNum, character ${offset - lineStart + 1})\n"; |
| } else { |
| report += " (at character ${offset + 1})\n"; |
| } |
| int lineEnd = source.length; |
| for (int i = offset; i < source.length; i++) { |
| int char = source.codeUnitAt(i); |
| if (char == 0x0a || char == 0x0d) { |
| lineEnd = i; |
| break; |
| } |
| } |
| int length = lineEnd - lineStart; |
| int start = lineStart; |
| int end = lineEnd; |
| String prefix = ""; |
| String postfix = ""; |
| if (length > 78) { |
| // Can't show entire line. Try to anchor at the nearest end, if |
| // one is within reach. |
| int index = offset - lineStart; |
| if (index < 75) { |
| end = start + 75; |
| postfix = "..."; |
| } else if (end - offset < 75) { |
| start = end - 75; |
| prefix = "..."; |
| } else { |
| // Neither end is near, just pick an area around the offset. |
| start = offset - 36; |
| end = offset + 36; |
| prefix = postfix = "..."; |
| } |
| } |
| String slice = source.substring(start, end); |
| int markOffset = offset - start + prefix.length; |
| return "$report$prefix$slice$postfix\n${" " * markOffset}^\n"; |
| } else { |
| // The source is not a string. |
| if (offset != null) { |
| report += " (at offset $offset)"; |
| } |
| return report; |
| } |
| } |
| } |
| |
| // Exception thrown when doing integer division with a zero divisor. |
| // TODO(30743): Should be removed, and division by zero should just throw an |
| // [ArgumentError]. |
| class IntegerDivisionByZeroException implements Exception { |
| @pragma("vm:entry-point") |
| const IntegerDivisionByZeroException(); |
| String toString() => "IntegerDivisionByZeroException"; |
| } |