aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/syntax_error.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/syntax_error.rs')
-rw-r--r--crates/ra_syntax/src/syntax_error.rs214
1 files changed, 26 insertions, 188 deletions
diff --git a/crates/ra_syntax/src/syntax_error.rs b/crates/ra_syntax/src/syntax_error.rs
index 7f9d36618..460552103 100644
--- a/crates/ra_syntax/src/syntax_error.rs
+++ b/crates/ra_syntax/src/syntax_error.rs
@@ -1,209 +1,47 @@
1//! FIXME: write short doc here 1//! Module that defines `SyntaxError`.
2 2
3use std::fmt; 3use std::fmt;
4 4
5use ra_parser::ParseError; 5use crate::{TextRange, TextUnit};
6
7use crate::{validation::EscapeError, TextRange, TextUnit, TokenizeError};
8 6
7/// Represents the result of unsuccessful tokenization, parsing
8/// or semmantical analyzis.
9#[derive(Debug, Clone, PartialEq, Eq, Hash)] 9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10pub struct SyntaxError { 10pub struct SyntaxError(String, TextRange);
11 kind: SyntaxErrorKind, 11
12 location: Location, 12// FIXME: there was an unused SyntaxErrorKind previously (before this enum was removed)
13} 13// It was introduced in this PR: https://github.com/rust-analyzer/rust-analyzer/pull/846/files#diff-827da9b03b8f9faa1bade5cdd44d5dafR95
14 14// but it was not removed by a mistake.
15// FIXME: Location should be just `Location(TextRange)` 15//
16// TextUnit enum member just unnecessarily compicates things, 16// So, we need to find a place where to stick validation for attributes in match clauses.
17// we should'n treat it specially, it just as a `TextRange { start: x, end: x + 1 }` 17// Code before refactor:
18// see `location_to_range()` in ra_ide/src/diagnostics 18// InvalidMatchInnerAttr => {
19#[derive(Clone, PartialEq, Eq, Hash)] 19// write!(f, "Inner attributes are only allowed directly after the opening brace of the match expression")
20pub enum Location { 20// }
21 Offset(TextUnit),
22 Range(TextRange),
23}
24
25impl From<TextUnit> for Location {
26 fn from(offset: TextUnit) -> Location {
27 Location::Offset(offset)
28 }
29}
30
31impl From<TextRange> for Location {
32 fn from(range: TextRange) -> Location {
33 Location::Range(range)
34 }
35}
36
37impl fmt::Debug for Location {
38 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39 match self {
40 Location::Offset(it) => fmt::Debug::fmt(it, f),
41 Location::Range(it) => fmt::Debug::fmt(it, f),
42 }
43 }
44}
45 21
46impl SyntaxError { 22impl SyntaxError {
47 pub fn new<L: Into<Location>>(kind: SyntaxErrorKind, loc: L) -> SyntaxError { 23 pub fn new(message: impl Into<String>, range: TextRange) -> Self {
48 SyntaxError { kind, location: loc.into() } 24 Self(message.into(), range)
49 } 25 }
50 26 pub fn new_at_offset(message: impl Into<String>, offset: TextUnit) -> Self {
51 pub fn kind(&self) -> SyntaxErrorKind { 27 Self(message.into(), TextRange::offset_len(offset, 1.into()))
52 self.kind.clone()
53 } 28 }
54 29
55 pub fn location(&self) -> Location { 30 pub fn message(&self) -> &str {
56 self.location.clone() 31 &self.0
57 } 32 }
58 33 pub fn range(&self) -> &TextRange {
59 pub fn offset(&self) -> TextUnit { 34 &self.1
60 match self.location {
61 Location::Offset(offset) => offset,
62 Location::Range(range) => range.start(),
63 }
64 } 35 }
65 36
66 pub fn add_offset(mut self, plus_offset: TextUnit, minus_offset: TextUnit) -> SyntaxError { 37 pub fn with_range(mut self, range: TextRange) -> Self {
67 self.location = match self.location { 38 self.1 = range;
68 Location::Range(range) => Location::Range(range + plus_offset - minus_offset),
69 Location::Offset(offset) => Location::Offset(offset + plus_offset - minus_offset),
70 };
71
72 self 39 self
73 } 40 }
74
75 pub fn debug_dump(&self, acc: &mut impl fmt::Write) {
76 writeln!(acc, "error {:?}: {}", self.location(), self.kind()).unwrap();
77 }
78} 41}
79 42
80impl fmt::Display for SyntaxError { 43impl fmt::Display for SyntaxError {
81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 44 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82 self.kind.fmt(f) 45 self.0.fmt(f)
83 }
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, Hash)]
87pub enum SyntaxErrorKind {
88 ParseError(ParseError),
89 EscapeError(EscapeError),
90 TokenizeError(TokenizeError),
91 // FIXME: the obvious pattern of this enum dictates that the following enum variants
92 // should be wrapped into something like `SemmanticError(SemmanticError)`
93 // or `ValidateError(ValidateError)` or `SemmanticValidateError(...)`
94 InvalidBlockAttr,
95 InvalidMatchInnerAttr,
96 InvalidTupleIndexFormat,
97 VisibilityNotAllowed,
98 InclusiveRangeMissingEnd,
99}
100
101impl fmt::Display for SyntaxErrorKind {
102 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
103 use self::SyntaxErrorKind::*;
104 match self {
105 InvalidBlockAttr => {
106 write!(f, "A block in this position cannot accept inner attributes")
107 }
108 InvalidMatchInnerAttr => {
109 write!(f, "Inner attributes are only allowed directly after the opening brace of the match expression")
110 }
111 InvalidTupleIndexFormat => {
112 write!(f, "Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix")
113 }
114 ParseError(msg) => write!(f, "{}", msg.0),
115 EscapeError(err) => write!(f, "{}", err),
116 TokenizeError(err) => write!(f, "{}", err),
117 VisibilityNotAllowed => {
118 write!(f, "unnecessary visibility qualifier")
119 }
120 InclusiveRangeMissingEnd => {
121 write!(f, "An inclusive range must have an end expression")
122 }
123 }
124 }
125}
126
127impl fmt::Display for TokenizeError {
128 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129 #[rustfmt::skip]
130 let msg = match self {
131 TokenizeError::EmptyInt => {
132 "Missing digits after the integer base prefix"
133 }
134 TokenizeError::EmptyExponent => {
135 "Missing digits after the exponent symbol"
136 }
137 TokenizeError::UnterminatedBlockComment => {
138 "Missing trailing `*/` symbols to terminate the block comment"
139 }
140 TokenizeError::UnterminatedChar => {
141 "Missing trailing `'` symbol to terminate the character literal"
142 }
143 TokenizeError::UnterminatedByte => {
144 "Missing trailing `'` symbol to terminate the byte literal"
145 }
146 TokenizeError::UnterminatedString => {
147 "Missing trailing `\"` symbol to terminate the string literal"
148 }
149 TokenizeError::UnterminatedByteString => {
150 "Missing trailing `\"` symbol to terminate the byte string literal"
151 }
152 TokenizeError::UnterminatedRawString => {
153 "Missing trailing `\"` with `#` symbols to terminate the raw string literal"
154 }
155 TokenizeError::UnterminatedRawByteString => {
156 "Missing trailing `\"` with `#` symbols to terminate the raw byte string literal"
157 }
158 TokenizeError::UnstartedRawString => {
159 "Missing `\"` symbol after `#` symbols to begin the raw string literal"
160 }
161 TokenizeError::UnstartedRawByteString => {
162 "Missing `\"` symbol after `#` symbols to begin the raw byte string literal"
163 }
164 TokenizeError::LifetimeStartsWithNumber => {
165 "Lifetime name cannot start with a number"
166 }
167 };
168 write!(f, "{}", msg)
169 }
170}
171
172impl fmt::Display for EscapeError {
173 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174 let msg = match self {
175 EscapeError::ZeroChars => "Empty literal",
176 EscapeError::MoreThanOneChar => "Literal should be one character long",
177 EscapeError::LoneSlash => "Character must be escaped: '\\'",
178 EscapeError::InvalidEscape => "Invalid escape sequence",
179 EscapeError::BareCarriageReturn => "Character must be escaped: '\r'",
180 EscapeError::EscapeOnlyChar => "Character must be escaped",
181 EscapeError::TooShortHexEscape => "Escape sequence should have two digits",
182 EscapeError::InvalidCharInHexEscape => "Escape sequence should be a hexadecimal number",
183 EscapeError::OutOfRangeHexEscape => "Escape sequence should be ASCII",
184 EscapeError::NoBraceInUnicodeEscape => "Invalid escape sequence",
185 EscapeError::InvalidCharInUnicodeEscape => "Invalid escape sequence",
186 EscapeError::EmptyUnicodeEscape => "Invalid escape sequence",
187 EscapeError::UnclosedUnicodeEscape => "Missing '}'",
188 EscapeError::LeadingUnderscoreUnicodeEscape => "Invalid escape sequence",
189 EscapeError::OverlongUnicodeEscape => {
190 "Unicode escape sequence should have at most 6 digits"
191 }
192 EscapeError::LoneSurrogateUnicodeEscape => {
193 "Unicode escape code should not be a surrogate"
194 }
195 EscapeError::OutOfRangeUnicodeEscape => {
196 "Unicode escape code should be at most 0x10FFFF"
197 }
198 EscapeError::UnicodeEscapeInByte => "Unicode escapes are not allowed in bytes",
199 EscapeError::NonAsciiCharInByte => "Non ASCII characters are not allowed in bytes",
200 };
201 write!(f, "{}", msg)
202 }
203}
204
205impl From<EscapeError> for SyntaxErrorKind {
206 fn from(err: EscapeError) -> Self {
207 SyntaxErrorKind::EscapeError(err)
208 } 46 }
209} 47}