ra_syntax: reshape SyntaxError for the sake of removing redundancy

This commit is contained in:
Veetaha 2020-02-06 02:33:18 +02:00
parent 9053003e3b
commit 9fdf984958
55 changed files with 405 additions and 638 deletions

View file

@ -1,209 +1,47 @@
//! FIXME: write short doc here
//! Module that defines `SyntaxError`.
use std::fmt;
use ra_parser::ParseError;
use crate::{validation::EscapeError, TextRange, TextUnit, TokenizeError};
use crate::{TextRange, TextUnit};
/// Represents the result of unsuccessful tokenization, parsing
/// or semmantical analyzis.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SyntaxError {
kind: SyntaxErrorKind,
location: Location,
}
pub struct SyntaxError(String, TextRange);
// FIXME: Location should be just `Location(TextRange)`
// TextUnit enum member just unnecessarily compicates things,
// we should'n treat it specially, it just as a `TextRange { start: x, end: x + 1 }`
// see `location_to_range()` in ra_ide/src/diagnostics
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Location {
Offset(TextUnit),
Range(TextRange),
}
impl From<TextUnit> for Location {
fn from(offset: TextUnit) -> Location {
Location::Offset(offset)
}
}
impl From<TextRange> for Location {
fn from(range: TextRange) -> Location {
Location::Range(range)
}
}
impl fmt::Debug for Location {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Location::Offset(it) => fmt::Debug::fmt(it, f),
Location::Range(it) => fmt::Debug::fmt(it, f),
}
}
}
// FIXME: there was an unused SyntaxErrorKind previously (before this enum was removed)
// It was introduced in this PR: https://github.com/rust-analyzer/rust-analyzer/pull/846/files#diff-827da9b03b8f9faa1bade5cdd44d5dafR95
// but it was not removed by a mistake.
//
// So, we need to find a place where to stick validation for attributes in match clauses.
// Code before refactor:
// InvalidMatchInnerAttr => {
// write!(f, "Inner attributes are only allowed directly after the opening brace of the match expression")
// }
impl SyntaxError {
pub fn new<L: Into<Location>>(kind: SyntaxErrorKind, loc: L) -> SyntaxError {
SyntaxError { kind, location: loc.into() }
pub fn new(message: impl Into<String>, range: TextRange) -> Self {
Self(message.into(), range)
}
pub fn new_at_offset(message: impl Into<String>, offset: TextUnit) -> Self {
Self(message.into(), TextRange::offset_len(offset, 1.into()))
}
pub fn kind(&self) -> SyntaxErrorKind {
self.kind.clone()
pub fn message(&self) -> &str {
&self.0
}
pub fn range(&self) -> &TextRange {
&self.1
}
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(),
}
}
pub fn add_offset(mut self, plus_offset: TextUnit, minus_offset: TextUnit) -> SyntaxError {
self.location = match self.location {
Location::Range(range) => Location::Range(range + plus_offset - minus_offset),
Location::Offset(offset) => Location::Offset(offset + plus_offset - minus_offset),
};
pub fn with_range(mut self, range: TextRange) -> Self {
self.1 = range;
self
}
pub fn debug_dump(&self, acc: &mut impl fmt::Write) {
writeln!(acc, "error {:?}: {}", self.location(), self.kind()).unwrap();
}
}
impl fmt::Display for SyntaxError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.kind.fmt(f)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SyntaxErrorKind {
ParseError(ParseError),
EscapeError(EscapeError),
TokenizeError(TokenizeError),
// FIXME: the obvious pattern of this enum dictates that the following enum variants
// should be wrapped into something like `SemmanticError(SemmanticError)`
// or `ValidateError(ValidateError)` or `SemmanticValidateError(...)`
InvalidBlockAttr,
InvalidMatchInnerAttr,
InvalidTupleIndexFormat,
VisibilityNotAllowed,
InclusiveRangeMissingEnd,
}
impl fmt::Display for SyntaxErrorKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::SyntaxErrorKind::*;
match self {
InvalidBlockAttr => {
write!(f, "A block in this position cannot accept inner attributes")
}
InvalidMatchInnerAttr => {
write!(f, "Inner attributes are only allowed directly after the opening brace of the match expression")
}
InvalidTupleIndexFormat => {
write!(f, "Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix")
}
ParseError(msg) => write!(f, "{}", msg.0),
EscapeError(err) => write!(f, "{}", err),
TokenizeError(err) => write!(f, "{}", err),
VisibilityNotAllowed => {
write!(f, "unnecessary visibility qualifier")
}
InclusiveRangeMissingEnd => {
write!(f, "An inclusive range must have an end expression")
}
}
}
}
impl fmt::Display for TokenizeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[rustfmt::skip]
let msg = match self {
TokenizeError::EmptyInt => {
"Missing digits after the integer base prefix"
}
TokenizeError::EmptyExponent => {
"Missing digits after the exponent symbol"
}
TokenizeError::UnterminatedBlockComment => {
"Missing trailing `*/` symbols to terminate the block comment"
}
TokenizeError::UnterminatedChar => {
"Missing trailing `'` symbol to terminate the character literal"
}
TokenizeError::UnterminatedByte => {
"Missing trailing `'` symbol to terminate the byte literal"
}
TokenizeError::UnterminatedString => {
"Missing trailing `\"` symbol to terminate the string literal"
}
TokenizeError::UnterminatedByteString => {
"Missing trailing `\"` symbol to terminate the byte string literal"
}
TokenizeError::UnterminatedRawString => {
"Missing trailing `\"` with `#` symbols to terminate the raw string literal"
}
TokenizeError::UnterminatedRawByteString => {
"Missing trailing `\"` with `#` symbols to terminate the raw byte string literal"
}
TokenizeError::UnstartedRawString => {
"Missing `\"` symbol after `#` symbols to begin the raw string literal"
}
TokenizeError::UnstartedRawByteString => {
"Missing `\"` symbol after `#` symbols to begin the raw byte string literal"
}
TokenizeError::LifetimeStartsWithNumber => {
"Lifetime name cannot start with a number"
}
};
write!(f, "{}", msg)
}
}
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)
self.0.fmt(f)
}
}