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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
//! Runtime parse errors.
use core::fmt;
#[cfg(feature = "error-trace")]
use alloc::vec::Vec;
use vstd::prelude::*;
verus! {
/// A minimal runtime parser failure.
///
/// Vest parsers work on progressively sliced inputs, so a globally meaningful byte offset is not
/// available unless the caller explicitly threads that information through the parser stack.
/// Instead, this error carries a coarse-grained failure kind plus the name of the innermost
/// DSL-defined format that failed. With the `error-trace` feature it also retains the full
/// named-format call stack (at the cost of heap allocation).
#[derive(Debug, PartialEq, Eq)]
pub struct ParseError {
/// The kind of failure that occurred.
pub kind: ParseErrorKind,
/// The innermost named format known to have failed.
pub failed_format: Option<&'static str>,
/// The named-format call stack that led to the failure, stored innermost-first.
#[cfg(feature = "error-trace")]
pub format_stack: Vec<&'static str>,
}
impl Clone for ParseError {
fn clone(&self) -> Self {
Self {
kind: self.kind.clone(),
failed_format: self.failed_format,
#[cfg(feature = "error-trace")]
format_stack: self.format_stack.clone(),
}
}
}
impl ParseError {
/// Creates a new parse error.
pub fn new(kind: ParseErrorKind) -> (e: Self)
ensures
e.kind == kind,
{
Self {
kind,
failed_format: None,
#[cfg(feature = "error-trace")]
format_stack: Vec::new(),
}
}
/// Pushes one named format onto the failing format stack.
///
/// The first pushed format becomes `current_format`, so `current_format` continues to refer to
/// the innermost failing named format even as outer formats append themselves during
/// propagation.
pub fn push_format(self, current_format: &'static str) -> Self {
let mut err = self;
if err.failed_format.is_none() {
err.failed_format = Some(current_format);
}
#[cfg(feature = "error-trace")]
{
err.format_stack.push(current_format);
}
err
}
/// Returns the recorded format stack as an innermost-first slice.
pub fn format_trace(&self) -> &[&'static str] {
#[cfg(feature = "error-trace")]
{ self.format_stack.as_slice() }
#[cfg(not(feature = "error-trace"))]
{ &[] }
}
}
impl ParseError {
/// Creates an unexpected end-of-input error.
pub fn unexpected_eof() -> (e: Self)
ensures
e.kind == ParseErrorKind::UnexpectedEof,
{
Self::new(ParseErrorKind::UnexpectedEof)
}
/// Creates an expecting end-of-input error.
pub fn expecting_eof() -> Self {
Self::new(ParseErrorKind::ExpectingEof)
}
/// Creates an invalid-tag error.
pub fn invalid_tag() -> Self {
Self::new(ParseErrorKind::InvalidTag)
}
/// Creates an invalid-choice error.
pub fn invalid_choice() -> Self {
Self::new(ParseErrorKind::InvalidChoice)
}
/// Creates an invalid-length error.
pub fn invalid_length() -> Self {
Self::new(ParseErrorKind::InvalidLength)
}
/// Creates a length-mismatch error.
pub fn length_mismatch() -> Self {
Self::new(ParseErrorKind::LengthMismatch)
}
/// Creates a predicate-failed error.
pub fn predicate_failed() -> Self {
Self::new(ParseErrorKind::PredicateFailed)
}
/// Creates a condition-rejected error.
pub fn cond_rejected() -> Self {
Self::new(ParseErrorKind::CondRejected)
}
/// Creates a non-canonical-encoding error.
pub fn non_canonical() -> Self {
Self::new(ParseErrorKind::NonCanonical)
}
/// Creates an overflow error.
pub fn overflow() -> (e: Self)
ensures
e.kind == ParseErrorKind::Overflow,
{
Self::new(ParseErrorKind::Overflow)
}
/// Creates a recursion-limit-exceeded error.
pub fn recursion_limit_exceeded() -> Self {
Self::new(ParseErrorKind::RecursionLimitExceeded)
}
/// Creates a custom error with the given message.
pub fn custom(msg: &'static str) -> Self {
Self::new(ParseErrorKind::Custom(msg))
}
}
} // verus!
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let format_trace = self.format_trace();
if !format_trace.is_empty() {
write!(f, "{} while parsing format stack ", self.kind)?;
for (i, format_name) in format_trace.iter().rev().enumerate() {
if i > 0 {
f.write_str(" -> ")?;
}
write!(f, "`{}`", format_name)?;
}
Ok(())
} else {
match self.failed_format {
Some(current_format) => {
write!(f, "{} while parsing format `{}`", self.kind, current_format)
}
None => write!(f, "{}", self.kind),
}
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParseError {}
verus! {
/// The coarse-grained kind of parse failure.
#[derive(Debug, Copy, PartialEq, Eq)]
pub enum ParseErrorKind {
/// The parser needed more input bytes.
UnexpectedEof,
/// The parser expected the end of input, but more bytes were present.
ExpectingEof,
/// A tag or discriminant byte sequence was invalid.
InvalidTag,
/// Input did not match any branch of a choice-like format.
InvalidChoice,
/// A parsed length field was invalid.
InvalidLength,
/// A computed length disagreed with the enclosing format.
LengthMismatch,
/// A refinement predicate or semantic check failed.
PredicateFailed,
/// A branch was rejected after partial inspection.
CondRejected,
/// A non-canonical representation was observed.
NonCanonical,
/// An integer or size computation overflowed.
Overflow,
/// Recursion limit exceeded.
RecursionLimitExceeded,
/// A custom error message.
Custom(&'static str),
}
impl Clone for ParseErrorKind {
fn clone(&self) -> Self {
*self
}
}
} // verus!
impl fmt::Display for ParseErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ParseErrorKind::UnexpectedEof => {
f.write_str("input ended before the format could finish parsing")
}
ParseErrorKind::ExpectingEof => f.write_str("unexpected trailing input"),
ParseErrorKind::InvalidTag => {
f.write_str("tag or discriminant did not match the format")
}
ParseErrorKind::InvalidChoice => f.write_str("input did not match any choice branch"),
ParseErrorKind::InvalidLength => {
f.write_str("length field is outside the format's valid range")
}
ParseErrorKind::LengthMismatch => {
f.write_str("a length-delimited parser did not consume the declared length")
}
ParseErrorKind::PredicateFailed => {
f.write_str("parsed value failed a refinement predicate")
}
ParseErrorKind::CondRejected => f.write_str("conditional format rejected this branch"),
ParseErrorKind::NonCanonical => f.write_str("non-canonical encoding"),
ParseErrorKind::Overflow => f.write_str("integer or size computation overflowed"),
ParseErrorKind::RecursionLimitExceeded => f.write_str("recursion limit exceeded"),
ParseErrorKind::Custom(s) => f.write_str(s),
}
}
}