blob: 3aa48c6c003e85f2cb170ee4aaeaa30a82b085b3 [file] [log] [blame]
// 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]) => new _ExceptionImplementation(message);
}
/** Default implementation of [Exception] which carries a message. */
class _ExceptionImplementation implements Exception {
final message;
_ExceptionImplementation([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 source that 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.
*
* May also be `null` if omitted.
*/
final source;
/**
* The position in source where the error was detected.
*
* May be omitted. If present, [source] should also be present.
*/
final int position;
/**
* Creates a new FormatException with an optional error [message].
*
* Optionally also supply the [source] that had the incorrect format, and
* even the [position] in the format where this was detected.
*/
const FormatException([this.message = "", this.source, this.position]);
/**
* Returns a description of the format exception.
*
* The description always contains the [message].
* If [source] was provided, the description will contain (at least a part of)
* the source.
* If [position] is also provided, the part of the source included will
* contain that position, and the position will be marked.
*
* If the source contains a line break before position, only the line
* containing position 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 position = this.position;
if (source is! String) {
if (position != null) {
report += " (at position $position)";
}
return report;
}
if (position != null && (position < 0 || position > source.length)) {
position = null;
}
// Source is string and position is null or valid.
if (position == null) {
String source = this.source;
if (source.length > 78) {
source = source.substring(0, 75) + "...";
}
return "$report\n$source";
}
int lineNum = 1;
int lineStart = 0;
bool lastWasCR;
for (int i = 0; i < position; i++) {
int char = source.codeUnitAt(i);
if (char == 0x0a) {
if (lineStart != i || !lastWasCR) {
lineNum++;
}
lineStart = i + 1;
lastWasCR = false;
} else if (char == 0x0d) {
lineNum++;
lineStart = i + 1;
lastWasCR = true;
}
}
if (lineNum > 1) {
report += " (at line $lineNum, character ${position - lineStart + 1})\n";
} else {
report += " (at character ${position + 1})\n";
}
int lineEnd = source.length;
for (int i = position; 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 = position - lineStart;
if (index < 75) {
end = start + 75;
postfix = "...";
} else if (end - position < 75) {
start = end - 75;
prefix = "...";
} else {
// Neither end is near, just pick an area around the position.
start = position - 36;
end = position + 36;
prefix = postfix = "...";
}
}
String slice = source.substring(start, end);
int markOffset = position - start + prefix.length;
return "$report$prefix$slice$postfix\n${" " * markOffset}^\n";
}
}
class IntegerDivisionByZeroException implements Exception {
const IntegerDivisionByZeroException();
String toString() => "IntegerDivisionByZeroException";
}