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
use crate::PhpVersion;
use php_ast::Span;
use std::borrow::Cow;
use thiserror::Error;
/// A parse error or diagnostic emitted during parsing.
///
/// The parser recovers from all errors and always produces a complete AST,
/// so errors are informational rather than fatal. Each variant carries a
/// [`Span`] identifying the source location.
#[derive(Debug, Clone, Error)]
#[non_exhaustive]
pub enum ParseError {
/// A specific token was expected but a different one was found.
#[error("expected {expected}, found {found}")]
#[non_exhaustive]
Expected {
/// Description of the expected token.
expected: Cow<'static, str>,
/// Description of the token actually found, e.g. `"';'"` or
/// `"identifier"`. A description rather than the lexer's token kind,
/// so that new tokens are not a breaking change for this type.
found: Cow<'static, str>,
/// Source range of the error.
span: Span,
},
/// An expression was expected but not found (e.g. empty parentheses).
#[error("expected expression")]
#[non_exhaustive]
ExpectedExpression {
/// Source range of the error.
span: Span,
},
/// A statement was expected but not found.
#[error("expected statement")]
#[non_exhaustive]
ExpectedStatement {
/// Source range of the error.
span: Span,
},
/// PHP source must start with `<?php` or `<?`.
#[error("expected opening PHP tag")]
#[non_exhaustive]
ExpectedOpenTag {
/// Source range of the error.
span: Span,
},
/// A string literal was opened but never closed.
#[error("unterminated string literal")]
#[non_exhaustive]
UnterminatedString {
/// Source range of the error.
span: Span,
},
/// A required token was missing after another construct.
#[error("expected {expected} after {after}")]
#[non_exhaustive]
ExpectedAfter {
/// Description of the expected token.
expected: Cow<'static, str>,
/// Construct the token should follow.
after: Cow<'static, str>,
/// Source range of the error.
span: Span,
},
/// A delimiter (parenthesis, bracket, brace) was opened but never closed.
#[error("expected {delimiter} to close the delimiter opened at byte {}", opened_at.start)]
#[non_exhaustive]
UnclosedDelimiter {
/// The expected closing delimiter, e.g. `"')'"`.
delimiter: Cow<'static, str>,
/// Where the delimiter was opened.
opened_at: Span,
/// Source range of the error.
span: Span,
},
/// A construct that is syntactically valid but semantically forbidden
/// (e.g. `(unset)` cast, deprecated syntax). Equivalent to a PHP fatal.
#[error("{message}")]
#[non_exhaustive]
Forbidden {
/// Error message.
message: Cow<'static, str>,
/// Source range of the error.
span: Span,
},
/// Statements, expressions or string interpolations are nested deeper than
/// the parser's recursion budget. The innermost construct is replaced by an
/// error node so that parsing stays within a bounded stack.
#[error("maximum nesting depth exceeded")]
#[non_exhaustive]
NestingTooDeep {
/// Source range of the error.
span: Span,
},
/// The source is larger than 4 GiB, so byte offsets no longer fit in a
/// [`Span`]. Nothing is parsed and the program is empty.
#[error("source is {len} bytes; the maximum is 4 GiB")]
#[non_exhaustive]
SourceTooLarge {
/// Length of the rejected source in bytes.
len: usize,
/// Always empty (`0..0`).
span: Span,
},
/// Syntax that requires a newer PHP version than the targeted one.
/// Emitted by [`crate::parse_with`] when the source uses features
/// unavailable in the specified [`crate::PhpVersion`].
#[error("'{feature}' requires PHP {required} or higher")]
#[non_exhaustive]
VersionTooLow {
/// Name of the feature used.
feature: Cow<'static, str>,
/// Minimum PHP version required.
required: PhpVersion,
/// PHP version targeted.
used: PhpVersion,
/// Source range of the error.
span: Span,
},
}
impl ParseError {
/// Source range of the error.
pub fn span(&self) -> Span {
match self {
ParseError::Expected { span, .. }
| ParseError::ExpectedExpression { span }
| ParseError::ExpectedStatement { span }
| ParseError::ExpectedOpenTag { span }
| ParseError::UnterminatedString { span }
| ParseError::ExpectedAfter { span, .. }
| ParseError::UnclosedDelimiter { span, .. }
| ParseError::Forbidden { span, .. }
| ParseError::NestingTooDeep { span }
| ParseError::SourceTooLarge { span, .. }
| ParseError::VersionTooLow { span, .. } => *span,
}
}
}