|  | // 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"; | 
|  | } |