-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
exceptions.dart
181 lines (169 loc) · 6.34 KB
/
exceptions.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// 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.
///
/// For failures that are not intended to be caught, use [Error]
/// and its subclasses.
@pragma('flutter:keep-to-string-in-subtypes')
abstract interface 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
// [UnsupportedError].
@Deprecated("Use UnsupportedError instead")
class IntegerDivisionByZeroException implements Exception, UnsupportedError {
String? get message => "Division resulted in non-finite value";
StackTrace? get stackTrace => null;
@pragma("vm:entry-point")
const IntegerDivisionByZeroException();
String toString() => "IntegerDivisionByZeroException";
}