2019-01-28 20:03:56 +00:00
|
|
|
mod block;
|
2019-04-05 22:34:45 +02:00
|
|
|
mod field_expr;
|
2018-11-08 15:42:00 +01:00
|
|
|
|
2019-07-24 11:47:28 +03:00
|
|
|
use ra_rustc_lexer::unescape;
|
|
|
|
|
2019-01-07 16:15:47 +03:00
|
|
|
use crate::{
|
|
|
|
algo::visit::{visitor_ctx, VisitorCtx},
|
2019-07-24 11:47:28 +03:00
|
|
|
ast, SyntaxError, SyntaxErrorKind,
|
2019-07-04 23:05:17 +03:00
|
|
|
SyntaxKind::{BYTE, BYTE_STRING, CHAR, STRING},
|
|
|
|
SyntaxNode, TextUnit, T,
|
2019-01-07 16:15:47 +03:00
|
|
|
};
|
|
|
|
|
2019-07-24 11:47:28 +03:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
pub enum EscapeError {
|
|
|
|
ZeroChars,
|
|
|
|
MoreThanOneChar,
|
|
|
|
LoneSlash,
|
|
|
|
InvalidEscape,
|
|
|
|
BareCarriageReturn,
|
|
|
|
EscapeOnlyChar,
|
|
|
|
TooShortHexEscape,
|
|
|
|
InvalidCharInHexEscape,
|
|
|
|
OutOfRangeHexEscape,
|
|
|
|
NoBraceInUnicodeEscape,
|
|
|
|
InvalidCharInUnicodeEscape,
|
|
|
|
EmptyUnicodeEscape,
|
|
|
|
UnclosedUnicodeEscape,
|
|
|
|
LeadingUnderscoreUnicodeEscape,
|
|
|
|
OverlongUnicodeEscape,
|
|
|
|
LoneSurrogateUnicodeEscape,
|
|
|
|
OutOfRangeUnicodeEscape,
|
|
|
|
UnicodeEscapeInByte,
|
|
|
|
NonAsciiCharInByte,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ra_rustc_lexer::unescape::EscapeError> for EscapeError {
|
|
|
|
fn from(err: ra_rustc_lexer::unescape::EscapeError) -> Self {
|
|
|
|
match err {
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::ZeroChars => EscapeError::ZeroChars,
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::MoreThanOneChar => EscapeError::MoreThanOneChar,
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::LoneSlash => EscapeError::LoneSlash,
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::InvalidEscape => EscapeError::InvalidEscape,
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::BareCarriageReturn
|
|
|
|
| ra_rustc_lexer::unescape::EscapeError::BareCarriageReturnInRawString => {
|
|
|
|
EscapeError::BareCarriageReturn
|
|
|
|
}
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::EscapeOnlyChar => EscapeError::EscapeOnlyChar,
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::TooShortHexEscape => {
|
|
|
|
EscapeError::TooShortHexEscape
|
|
|
|
}
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::InvalidCharInHexEscape => {
|
|
|
|
EscapeError::InvalidCharInHexEscape
|
|
|
|
}
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::OutOfRangeHexEscape => {
|
|
|
|
EscapeError::OutOfRangeHexEscape
|
|
|
|
}
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::NoBraceInUnicodeEscape => {
|
|
|
|
EscapeError::NoBraceInUnicodeEscape
|
|
|
|
}
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::InvalidCharInUnicodeEscape => {
|
|
|
|
EscapeError::InvalidCharInUnicodeEscape
|
|
|
|
}
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::EmptyUnicodeEscape => {
|
|
|
|
EscapeError::EmptyUnicodeEscape
|
|
|
|
}
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::UnclosedUnicodeEscape => {
|
|
|
|
EscapeError::UnclosedUnicodeEscape
|
|
|
|
}
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::LeadingUnderscoreUnicodeEscape => {
|
|
|
|
EscapeError::LeadingUnderscoreUnicodeEscape
|
|
|
|
}
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::OverlongUnicodeEscape => {
|
|
|
|
EscapeError::OverlongUnicodeEscape
|
|
|
|
}
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::LoneSurrogateUnicodeEscape => {
|
|
|
|
EscapeError::LoneSurrogateUnicodeEscape
|
|
|
|
}
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::OutOfRangeUnicodeEscape => {
|
|
|
|
EscapeError::OutOfRangeUnicodeEscape
|
|
|
|
}
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::UnicodeEscapeInByte => {
|
|
|
|
EscapeError::UnicodeEscapeInByte
|
|
|
|
}
|
|
|
|
ra_rustc_lexer::unescape::EscapeError::NonAsciiCharInByte
|
|
|
|
| ra_rustc_lexer::unescape::EscapeError::NonAsciiCharInByteString => {
|
|
|
|
EscapeError::NonAsciiCharInByte
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ra_rustc_lexer::unescape::EscapeError> for SyntaxErrorKind {
|
|
|
|
fn from(err: ra_rustc_lexer::unescape::EscapeError) -> Self {
|
|
|
|
SyntaxErrorKind::EscapeError(err.into())
|
|
|
|
}
|
|
|
|
}
|
2019-05-07 19:38:26 +03:00
|
|
|
|
2019-07-21 13:34:15 +03:00
|
|
|
pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
|
2018-11-08 15:42:00 +01:00
|
|
|
let mut errors = Vec::new();
|
2019-07-21 13:34:15 +03:00
|
|
|
for node in root.descendants() {
|
2018-11-08 15:42:00 +01:00
|
|
|
let _ = visitor_ctx(&mut errors)
|
2019-03-30 13:25:53 +03:00
|
|
|
.visit::<ast::Literal, _>(validate_literal)
|
2019-02-21 15:51:22 +03:00
|
|
|
.visit::<ast::Block, _>(block::validate_block_node)
|
2019-04-05 22:34:45 +02:00
|
|
|
.visit::<ast::FieldExpr, _>(field_expr::validate_field_expr_node)
|
2019-07-18 19:23:05 +03:00
|
|
|
.accept(&node);
|
2018-11-08 15:42:00 +01:00
|
|
|
}
|
|
|
|
errors
|
|
|
|
}
|
2019-02-21 15:51:22 +03:00
|
|
|
|
2019-03-30 13:25:53 +03:00
|
|
|
// FIXME: kill duplication
|
2019-07-18 19:23:05 +03:00
|
|
|
fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
|
2019-05-07 19:38:26 +03:00
|
|
|
let token = literal.token();
|
|
|
|
let text = token.text().as_str();
|
|
|
|
match token.kind() {
|
|
|
|
BYTE => {
|
|
|
|
if let Some(end) = text.rfind('\'') {
|
|
|
|
if let Some(without_quotes) = text.get(2..end) {
|
|
|
|
if let Err((off, err)) = unescape::unescape_byte(without_quotes) {
|
2019-07-20 12:58:27 +03:00
|
|
|
let off = token.text_range().start() + TextUnit::from_usize(off + 2);
|
2019-05-07 19:38:26 +03:00
|
|
|
acc.push(SyntaxError::new(err.into(), off))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CHAR => {
|
|
|
|
if let Some(end) = text.rfind('\'') {
|
|
|
|
if let Some(without_quotes) = text.get(1..end) {
|
|
|
|
if let Err((off, err)) = unescape::unescape_char(without_quotes) {
|
2019-07-20 12:58:27 +03:00
|
|
|
let off = token.text_range().start() + TextUnit::from_usize(off + 1);
|
2019-05-07 19:38:26 +03:00
|
|
|
acc.push(SyntaxError::new(err.into(), off))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BYTE_STRING => {
|
|
|
|
if let Some(end) = text.rfind('\"') {
|
|
|
|
if let Some(without_quotes) = text.get(2..end) {
|
|
|
|
unescape::unescape_byte_str(without_quotes, &mut |range, char| {
|
|
|
|
if let Err(err) = char {
|
|
|
|
let off = range.start;
|
2019-07-20 12:58:27 +03:00
|
|
|
let off = token.text_range().start() + TextUnit::from_usize(off + 2);
|
2019-05-07 19:38:26 +03:00
|
|
|
acc.push(SyntaxError::new(err.into(), off))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
STRING => {
|
|
|
|
if let Some(end) = text.rfind('\"') {
|
|
|
|
if let Some(without_quotes) = text.get(1..end) {
|
|
|
|
unescape::unescape_str(without_quotes, &mut |range, char| {
|
|
|
|
if let Err(err) = char {
|
|
|
|
let off = range.start;
|
2019-07-20 12:58:27 +03:00
|
|
|
let off = token.text_range().start() + TextUnit::from_usize(off + 1);
|
2019-05-07 19:38:26 +03:00
|
|
|
acc.push(SyntaxError::new(err.into(), off))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-03-30 13:25:53 +03:00
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-21 15:51:22 +03:00
|
|
|
pub(crate) fn validate_block_structure(root: &SyntaxNode) {
|
|
|
|
let mut stack = Vec::new();
|
|
|
|
for node in root.descendants() {
|
|
|
|
match node.kind() {
|
2019-05-15 15:35:47 +03:00
|
|
|
T!['{'] => stack.push(node),
|
|
|
|
T!['}'] => {
|
2019-02-21 15:51:22 +03:00
|
|
|
if let Some(pair) = stack.pop() {
|
|
|
|
assert_eq!(
|
|
|
|
node.parent(),
|
|
|
|
pair.parent(),
|
2019-07-20 12:48:24 +03:00
|
|
|
"\nunpaired curleys:\n{}\n{:#?}\n",
|
2019-02-21 15:51:22 +03:00
|
|
|
root.text(),
|
2019-07-20 12:48:24 +03:00
|
|
|
root,
|
2019-02-21 15:51:22 +03:00
|
|
|
);
|
|
|
|
assert!(
|
|
|
|
node.next_sibling().is_none() && pair.prev_sibling().is_none(),
|
|
|
|
"\nfloating curlys at {:?}\nfile:\n{}\nerror:\n{}\n",
|
|
|
|
node,
|
|
|
|
root.text(),
|
|
|
|
node.text(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|