2018-11-04 09:45:22 -06:00
|
|
|
use std::fmt;
|
|
|
|
|
2019-02-21 04:37:32 -06:00
|
|
|
use ra_parser::ParseError;
|
|
|
|
|
2019-05-07 11:38:26 -05:00
|
|
|
use crate::{
|
|
|
|
TextRange, TextUnit,
|
|
|
|
validation::EscapeError,
|
|
|
|
};
|
2018-11-04 09:45:22 -06:00
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
pub struct SyntaxError {
|
2018-11-05 11:38:34 -06:00
|
|
|
kind: SyntaxErrorKind,
|
|
|
|
location: Location,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
pub enum Location {
|
|
|
|
Offset(TextUnit),
|
|
|
|
Range(TextRange),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Into<Location> for TextUnit {
|
|
|
|
fn into(self) -> Location {
|
|
|
|
Location::Offset(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Into<Location> for TextRange {
|
|
|
|
fn into(self) -> Location {
|
|
|
|
Location::Range(self)
|
|
|
|
}
|
2018-11-04 09:45:22 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl SyntaxError {
|
2018-11-05 11:38:34 -06:00
|
|
|
pub fn new<L: Into<Location>>(kind: SyntaxErrorKind, loc: L) -> SyntaxError {
|
2019-02-08 05:49:43 -06:00
|
|
|
SyntaxError { kind, location: loc.into() }
|
2018-11-05 11:38:34 -06:00
|
|
|
}
|
|
|
|
|
2018-11-07 04:35:33 -06:00
|
|
|
pub fn kind(&self) -> SyntaxErrorKind {
|
|
|
|
self.kind.clone()
|
|
|
|
}
|
|
|
|
|
2018-11-05 11:38:34 -06:00
|
|
|
pub fn location(&self) -> Location {
|
|
|
|
self.location.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn offset(&self) -> TextUnit {
|
|
|
|
match self.location {
|
|
|
|
Location::Offset(offset) => offset,
|
|
|
|
Location::Range(range) => range.start(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-21 12:22:06 -05:00
|
|
|
pub fn add_offset(mut self, plus_offset: TextUnit, minus_offset: TextUnit) -> SyntaxError {
|
2018-11-05 11:38:34 -06:00
|
|
|
self.location = match self.location {
|
2019-03-21 12:22:06 -05:00
|
|
|
Location::Range(range) => Location::Range(range + plus_offset - minus_offset),
|
|
|
|
Location::Offset(offset) => Location::Offset(offset + plus_offset - minus_offset),
|
2018-11-05 11:38:34 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for SyntaxError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
self.kind.fmt(f)
|
2018-11-04 09:45:22 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
pub enum SyntaxErrorKind {
|
|
|
|
ParseError(ParseError),
|
2019-05-07 11:38:26 -05:00
|
|
|
EscapeError(EscapeError),
|
2019-01-28 14:03:56 -06:00
|
|
|
InvalidBlockAttr,
|
2019-02-17 11:08:34 -06:00
|
|
|
InvalidMatchInnerAttr,
|
2019-04-05 15:34:45 -05:00
|
|
|
InvalidTupleIndexFormat,
|
2018-11-04 09:45:22 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for SyntaxErrorKind {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
use self::SyntaxErrorKind::*;
|
|
|
|
match self {
|
2019-01-28 14:03:56 -06:00
|
|
|
InvalidBlockAttr => {
|
|
|
|
write!(f, "A block in this position cannot accept inner attributes")
|
|
|
|
}
|
2019-02-17 11:08:34 -06:00
|
|
|
InvalidMatchInnerAttr => {
|
|
|
|
write!(f, "Inner attributes are only allowed directly after the opening brace of the match expression")
|
|
|
|
}
|
2019-04-05 15:34:45 -05:00
|
|
|
InvalidTupleIndexFormat => {
|
|
|
|
write!(f, "Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix")
|
|
|
|
}
|
2018-11-04 09:45:22 -06:00
|
|
|
ParseError(msg) => write!(f, "{}", msg.0),
|
2019-05-07 11:38:26 -05:00
|
|
|
EscapeError(err) => write!(f, "{}", err),
|
2018-11-04 09:45:22 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-05-07 11:38:26 -05:00
|
|
|
|
|
|
|
impl fmt::Display for EscapeError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
let msg = match self {
|
|
|
|
EscapeError::ZeroChars => "Empty literal",
|
|
|
|
EscapeError::MoreThanOneChar => "Literal should be one character long",
|
|
|
|
EscapeError::LoneSlash => "Character must be escaped: '\\'",
|
|
|
|
EscapeError::InvalidEscape => "Invalid escape sequence",
|
|
|
|
EscapeError::BareCarriageReturn => "Character must be escaped: '\r'",
|
|
|
|
EscapeError::EscapeOnlyChar => "Character must be escaped",
|
|
|
|
EscapeError::TooShortHexEscape => "Escape sequence should have two digits",
|
|
|
|
EscapeError::InvalidCharInHexEscape => "Escape sequence should be a hexadecimal number",
|
|
|
|
EscapeError::OutOfRangeHexEscape => "Escape sequence should be ASCII",
|
|
|
|
EscapeError::NoBraceInUnicodeEscape => "Invalid escape sequence",
|
|
|
|
EscapeError::InvalidCharInUnicodeEscape => "Invalid escape sequence",
|
|
|
|
EscapeError::EmptyUnicodeEscape => "Invalid escape sequence",
|
|
|
|
EscapeError::UnclosedUnicodeEscape => "Missing '}'",
|
|
|
|
EscapeError::LeadingUnderscoreUnicodeEscape => "Invalid escape sequence",
|
|
|
|
EscapeError::OverlongUnicodeEscape => {
|
|
|
|
"Unicode escape sequence should have at most 6 digits"
|
|
|
|
}
|
|
|
|
EscapeError::LoneSurrogateUnicodeEscape => {
|
|
|
|
"Unicode escape code should not be a surrogate"
|
|
|
|
}
|
|
|
|
EscapeError::OutOfRangeUnicodeEscape => {
|
|
|
|
"Unicode escape code should be at most 0x10FFFF"
|
|
|
|
}
|
|
|
|
EscapeError::UnicodeEscapeInByte => "Unicode escapes are not allowed in bytes",
|
|
|
|
EscapeError::NonAsciiCharInByte => "Non ASCII characters are not allowed in bytes",
|
|
|
|
};
|
|
|
|
write!(f, "{}", msg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<EscapeError> for SyntaxErrorKind {
|
|
|
|
fn from(err: EscapeError) -> Self {
|
|
|
|
SyntaxErrorKind::EscapeError(err)
|
|
|
|
}
|
|
|
|
}
|