| // 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 [:new Exception("message"):] |
| * is discouraged, and only included as a temporary measure during development, |
| * until the actual exceptions used by a library are done. |
| */ |
| abstract class Exception { |
| factory Exception([var message]) => _Exception(message); |
| } |
| |
| /** Default implementation of [Exception] which carries a message. */ |
| class _Exception implements Exception { |
| final message; |
| |
| _Exception([this.message]); |
| |
| String toString() { |
| 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 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"; |
| if (message != null && "" != message) { |
| report = "$report: $message"; |
| } |
| int offset = this.offset; |
| Object objectSource = this.source; |
| if (objectSource is String) { |
| String source = objectSource; |
| 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. |
| class IntegerDivisionByZeroException implements Exception { |
| @pragma("vm:entry-point") |
| const IntegerDivisionByZeroException(); |
| String toString() => "IntegerDivisionByZeroException"; |
| } |