mirror of
https://github.com/oxalica/nil.git
synced 2024-11-23 12:03:30 +03:00
Refactor error structs
This commit is contained in:
parent
17fc5fdfec
commit
e30c6aa654
@ -2,26 +2,16 @@ use super::{
|
||||
AstPtr, Attrpath, BindingKey, BindingValue, Bindings, Expr, ExprId, Literal, Module,
|
||||
ModuleSourceMap, NameDef, NameDefId, Pat, Path, PathAnchor,
|
||||
};
|
||||
use crate::{Diagnostic, FileId, FileRange, InFile};
|
||||
use crate::{Diagnostic, DiagnosticKind, FileId, InFile};
|
||||
use indexmap::IndexMap;
|
||||
use la_arena::Arena;
|
||||
use rowan::ast::AstNode;
|
||||
use rowan::TextRange;
|
||||
use smol_str::SmolStr;
|
||||
use std::str;
|
||||
use syntax::ast::{self, HasBindings, HasStringParts, LiteralKind};
|
||||
use syntax::Parse;
|
||||
use syntax::{Parse, TextRange};
|
||||
|
||||
pub(super) fn lower(parse: InFile<Parse>) -> (Module, ModuleSourceMap) {
|
||||
let diagnostics = parse
|
||||
.value
|
||||
.errors()
|
||||
.iter()
|
||||
.map(|&(err, pos)| {
|
||||
Diagnostic::SyntaxError(InFile::new(parse.file_id, TextRange::empty(pos)), err)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut ctx = LowerCtx {
|
||||
file_id: parse.file_id,
|
||||
module: Module {
|
||||
@ -29,7 +19,7 @@ pub(super) fn lower(parse: InFile<Parse>) -> (Module, ModuleSourceMap) {
|
||||
name_defs: Arena::new(),
|
||||
// Placeholder.
|
||||
entry_expr: ExprId::from_raw(0.into()),
|
||||
diagnostics,
|
||||
diagnostics: Vec::new(),
|
||||
},
|
||||
source_map: ModuleSourceMap::default(),
|
||||
};
|
||||
@ -61,12 +51,8 @@ impl LowerCtx {
|
||||
id
|
||||
}
|
||||
|
||||
fn file_range(&self, ptr: &AstPtr) -> FileRange {
|
||||
InFile::new(self.file_id, ptr.text_range())
|
||||
}
|
||||
|
||||
fn push_diagnostic(&mut self, diag: Diagnostic) {
|
||||
self.module.diagnostics.push(diag);
|
||||
fn diagnostic(&mut self, range: TextRange, kind: DiagnosticKind) {
|
||||
self.module.diagnostics.push(Diagnostic { range, kind });
|
||||
}
|
||||
|
||||
fn lower_name(&mut self, node: ast::Name) -> NameDefId {
|
||||
@ -175,8 +161,7 @@ impl LowerCtx {
|
||||
for (key, _) in bindings.entries.iter() {
|
||||
if let BindingKey::Dynamic(expr) = key {
|
||||
if let Some(ptr) = self.source_map.expr_node(*expr) {
|
||||
let range = self.file_range(&ptr);
|
||||
self.push_diagnostic(Diagnostic::InvalidDynamic(range));
|
||||
self.diagnostic(ptr.text_range(), DiagnosticKind::InvalidDynamic);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -413,7 +398,7 @@ impl MergingSet {
|
||||
let key = match ctx.lower_key(self.is_rec, attr) {
|
||||
// `inherit ${expr}` or `inherit (expr) ${expr}` is invalid.
|
||||
BindingKey::Dynamic(expr) => {
|
||||
ctx.push_diagnostic(Diagnostic::InvalidDynamic(ctx.file_range(&ptr)));
|
||||
ctx.diagnostic(ptr.text_range(), DiagnosticKind::InvalidDynamic);
|
||||
self.recover_error(ctx, expr, ptr.clone());
|
||||
continue;
|
||||
}
|
||||
@ -537,22 +522,20 @@ impl MergingValue {
|
||||
}
|
||||
|
||||
fn emit_duplicated_key(&self, ctx: &mut LowerCtx, ptr: &AstPtr) {
|
||||
let cur_range = ctx.file_range(ptr);
|
||||
ctx.diagnostic(ptr.text_range(), DiagnosticKind::DuplicatedKey);
|
||||
let prev_range = match self {
|
||||
Self::Placeholder => unreachable!(),
|
||||
Self::Attrset(set) => ctx.file_range(&set.ptr),
|
||||
Self::Attrset(set) => set.ptr.text_range(),
|
||||
Self::Final(BindingValue::Inherit(prev_expr) | BindingValue::Expr(prev_expr)) => {
|
||||
match ctx.source_map.expr_node(*prev_expr) {
|
||||
Some(ptr) => ctx.file_range(&ptr),
|
||||
Some(ptr) => ptr.text_range(),
|
||||
None => return,
|
||||
}
|
||||
}
|
||||
Self::Final(BindingValue::InheritFrom(_)) => {
|
||||
// FIXME: Cannot get inherit from attrs.
|
||||
cur_range
|
||||
}
|
||||
// FIXME: Cannot get inherit from attrs.
|
||||
Self::Final(BindingValue::InheritFrom(_)) => return,
|
||||
};
|
||||
ctx.push_diagnostic(Diagnostic::DuplicatedKey(prev_range, cur_range));
|
||||
ctx.diagnostic(prev_range, DiagnosticKind::DuplicatedKey);
|
||||
}
|
||||
|
||||
fn finish(self, ctx: &mut LowerCtx) -> BindingValue {
|
||||
@ -987,19 +970,19 @@ mod tests {
|
||||
check_error(
|
||||
"let ${a} = 1; in 1",
|
||||
expect![[r#"
|
||||
InvalidDynamic(InFile { file_id: FileId(0), value: 6..7 })
|
||||
Diagnostic { range: 6..7, kind: InvalidDynamic }
|
||||
"#]],
|
||||
);
|
||||
check_error(
|
||||
"{ inherit ${a}; }",
|
||||
expect![[r#"
|
||||
InvalidDynamic(InFile { file_id: FileId(0), value: 10..14 })
|
||||
Diagnostic { range: 10..14, kind: InvalidDynamic }
|
||||
"#]],
|
||||
);
|
||||
check_error(
|
||||
"{ inherit (a) ${a}; }",
|
||||
expect![[r#"
|
||||
InvalidDynamic(InFile { file_id: FileId(0), value: 14..18 })
|
||||
Diagnostic { range: 14..18, kind: InvalidDynamic }
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -1011,28 +994,46 @@ mod tests {
|
||||
check_error(
|
||||
"{ a = 1; a = 2; }",
|
||||
expect![[r#"
|
||||
DuplicatedKey(InFile { file_id: FileId(0), value: 6..7 }, InFile { file_id: FileId(0), value: 13..14 })
|
||||
Diagnostic { range: 13..14, kind: DuplicatedKey }
|
||||
Diagnostic { range: 6..7, kind: DuplicatedKey }
|
||||
"#]],
|
||||
);
|
||||
// Set and value.
|
||||
check_error(
|
||||
"{ a.b = 1; a = 2; }",
|
||||
expect![[r#"
|
||||
DuplicatedKey(InFile { file_id: FileId(0), value: 4..5 }, InFile { file_id: FileId(0), value: 15..16 })
|
||||
Diagnostic { range: 15..16, kind: DuplicatedKey }
|
||||
Diagnostic { range: 4..5, kind: DuplicatedKey }
|
||||
"#]],
|
||||
);
|
||||
// Value and set.
|
||||
check_error(
|
||||
"{ a = 1; a.b = 2; }",
|
||||
expect![[r#"
|
||||
DuplicatedKey(InFile { file_id: FileId(0), value: 6..7 }, InFile { file_id: FileId(0), value: 11..12 })
|
||||
Diagnostic { range: 11..12, kind: DuplicatedKey }
|
||||
Diagnostic { range: 6..7, kind: DuplicatedKey }
|
||||
"#]],
|
||||
);
|
||||
// Inherit and value.
|
||||
check_error(
|
||||
"{ inherit a; a = 1; }",
|
||||
expect![[r#"
|
||||
DuplicatedKey(InFile { file_id: FileId(0), value: 10..11 }, InFile { file_id: FileId(0), value: 17..18 })
|
||||
Diagnostic { range: 17..18, kind: DuplicatedKey }
|
||||
Diagnostic { range: 10..11, kind: DuplicatedKey }
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
// FIXME: Errors are duplicated.
|
||||
fn attrset_many_duplicated_error() {
|
||||
check_error(
|
||||
"{ a = 1; a = 2; a = 3; }",
|
||||
expect![[r#"
|
||||
Diagnostic { range: 13..14, kind: DuplicatedKey }
|
||||
Diagnostic { range: 6..7, kind: DuplicatedKey }
|
||||
Diagnostic { range: 20..21, kind: DuplicatedKey }
|
||||
Diagnostic { range: 6..7, kind: DuplicatedKey }
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1,8 +1,55 @@
|
||||
use crate::FileRange;
|
||||
use syntax::{ErrorKind as SynErrorKind, TextRange};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Diagnostic {
|
||||
SyntaxError(FileRange, syntax::Error),
|
||||
InvalidDynamic(FileRange),
|
||||
DuplicatedKey(FileRange, FileRange),
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Diagnostic {
|
||||
pub range: TextRange,
|
||||
pub kind: DiagnosticKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DiagnosticKind {
|
||||
SyntaxError(SynErrorKind),
|
||||
InvalidDynamic,
|
||||
DuplicatedKey,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Severity {
|
||||
Error,
|
||||
IncompleteSyntax,
|
||||
}
|
||||
|
||||
impl Diagnostic {
|
||||
pub fn severity(&self) -> Severity {
|
||||
match self.kind {
|
||||
DiagnosticKind::SyntaxError(kind) => match kind {
|
||||
SynErrorKind::MultipleRoots
|
||||
| SynErrorKind::PathTrailingSlash
|
||||
| SynErrorKind::PathDuplicatedSlashes
|
||||
| SynErrorKind::MultipleNoAssoc => Severity::Error,
|
||||
SynErrorKind::UnexpectedToken
|
||||
| SynErrorKind::MissingToken(_)
|
||||
| SynErrorKind::MissingExpr
|
||||
| SynErrorKind::MissingAttr => Severity::IncompleteSyntax,
|
||||
},
|
||||
DiagnosticKind::InvalidDynamic | DiagnosticKind::DuplicatedKey => Severity::Error,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn message(&self) -> String {
|
||||
match self.kind {
|
||||
DiagnosticKind::SyntaxError(kind) => kind.to_string(),
|
||||
DiagnosticKind::InvalidDynamic => "Invalid location of dynamic attribute".into(),
|
||||
DiagnosticKind::DuplicatedKey => "Duplicated name definition".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<syntax::Error> for Diagnostic {
|
||||
fn from(err: syntax::Error) -> Self {
|
||||
Self {
|
||||
range: err.range,
|
||||
kind: DiagnosticKind::SyntaxError(err.kind),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ mod ide;
|
||||
mod tests;
|
||||
|
||||
pub use base::{Change, FileId, FilePos, FileRange, InFile};
|
||||
pub use diagnostic::Diagnostic;
|
||||
pub use diagnostic::{Diagnostic, DiagnosticKind};
|
||||
pub use ide::{
|
||||
Analysis, AnalysisHost, CompletionItem, CompletionItemKind, NavigationTarget, RootDatabase,
|
||||
};
|
||||
|
@ -16,7 +16,13 @@ pub use self::kind::SyntaxKind;
|
||||
pub use self::parser::{parse_file, Parse};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Error {
|
||||
pub struct Error {
|
||||
pub range: TextRange,
|
||||
pub kind: ErrorKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ErrorKind {
|
||||
MultipleRoots,
|
||||
UnexpectedToken,
|
||||
MultipleNoAssoc,
|
||||
@ -27,7 +33,7 @@ pub enum Error {
|
||||
PathDuplicatedSlashes,
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
impl fmt::Display for ErrorKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::MultipleRoots => "Multiple root expressions",
|
||||
@ -43,7 +49,19 @@ impl fmt::Display for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{} at {}..{}",
|
||||
self.kind,
|
||||
u32::from(self.range.start()),
|
||||
u32::from(self.range.end()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ErrorKind {}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum NixLanguage {}
|
||||
|
@ -1,13 +1,13 @@
|
||||
use crate::ast::SourceFile;
|
||||
use crate::SyntaxKind::{self, *};
|
||||
use crate::{lexer, Error, SyntaxNode};
|
||||
use crate::{lexer, Error, ErrorKind, SyntaxNode};
|
||||
use rowan::ast::AstNode;
|
||||
use rowan::{Checkpoint, GreenNode, GreenNodeBuilder, TextSize};
|
||||
use rowan::{Checkpoint, GreenNode, GreenNodeBuilder, TextRange, TextSize};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Parse {
|
||||
green: GreenNode,
|
||||
errors: Vec<(Error, TextSize)>,
|
||||
errors: Vec<Error>,
|
||||
}
|
||||
|
||||
impl Parse {
|
||||
@ -23,7 +23,7 @@ impl Parse {
|
||||
SyntaxNode::new_root(self.green.clone())
|
||||
}
|
||||
|
||||
pub fn errors(&self) -> &[(Error, TextSize)] {
|
||||
pub fn errors(&self) -> &[Error] {
|
||||
&self.errors
|
||||
}
|
||||
}
|
||||
@ -44,7 +44,7 @@ pub fn parse_file(src: &str) -> Parse {
|
||||
struct Parser<'i> {
|
||||
tokens: lexer::LexTokens,
|
||||
builder: GreenNodeBuilder<'static>,
|
||||
errors: Vec<(Error, TextSize)>,
|
||||
errors: Vec<Error>,
|
||||
src: &'i str,
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ impl<'i> Parser<'i> {
|
||||
self.expr_function_opt();
|
||||
while self.peek_non_ws().is_some() {
|
||||
// Tolerate multiple exprs and just emit errors.
|
||||
self.error(Error::MultipleRoots);
|
||||
self.error(ErrorKind::MultipleRoots);
|
||||
|
||||
let prev = self.tokens.len();
|
||||
self.expr_function_opt();
|
||||
@ -72,13 +72,13 @@ impl<'i> Parser<'i> {
|
||||
}
|
||||
}
|
||||
|
||||
fn error(&mut self, err: Error) {
|
||||
let loc = self
|
||||
fn error(&mut self, kind: ErrorKind) {
|
||||
let range = self
|
||||
.tokens
|
||||
.last()
|
||||
.map(|(_, range)| range.start())
|
||||
.unwrap_or_else(|| (self.src.len() as u32).into());
|
||||
self.errors.push((err, loc));
|
||||
.map(|&(_, range)| range)
|
||||
.unwrap_or_else(|| TextRange::empty(TextSize::from(self.src.len() as u32)));
|
||||
self.errors.push(Error { range, kind });
|
||||
}
|
||||
|
||||
fn checkpoint(&mut self) -> Checkpoint {
|
||||
@ -135,7 +135,7 @@ impl<'i> Parser<'i> {
|
||||
if self.peek_non_ws() == Some(expect) {
|
||||
self.bump();
|
||||
} else {
|
||||
self.error(Error::MissingToken(expect));
|
||||
self.error(ErrorKind::MissingToken(expect));
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,11 +148,11 @@ impl<'i> Parser<'i> {
|
||||
break;
|
||||
}
|
||||
Some(_) => {
|
||||
self.error(Error::UnexpectedToken);
|
||||
self.error(ErrorKind::UnexpectedToken);
|
||||
self.bump();
|
||||
}
|
||||
None => {
|
||||
self.error(Error::MissingToken(expect));
|
||||
self.error(ErrorKind::MissingToken(expect));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -194,7 +194,7 @@ impl<'i> Parser<'i> {
|
||||
if matches!(self.iter_non_ws().nth(1), Some(T!['{'])) {
|
||||
self.expr_operator_opt()
|
||||
} else {
|
||||
self.error(Error::UnexpectedToken);
|
||||
self.error(ErrorKind::UnexpectedToken);
|
||||
self.bump();
|
||||
}
|
||||
}
|
||||
@ -269,7 +269,7 @@ impl<'i> Parser<'i> {
|
||||
if self.peek_non_ws() == Some(T!['{']) {
|
||||
self.pat();
|
||||
} else {
|
||||
self.error(Error::MissingToken(T!['{']));
|
||||
self.error(ErrorKind::MissingToken(T!['{']));
|
||||
}
|
||||
}
|
||||
self.finish_node();
|
||||
@ -326,7 +326,7 @@ impl<'i> Parser<'i> {
|
||||
|
||||
// Tolerate incorrect usage of no associative operators, and just mark them.
|
||||
while matches!(self.peek_non_ws(), Some(k) if ops.contains(&k)) {
|
||||
self.error(Error::MultipleNoAssoc);
|
||||
self.error(ErrorKind::MultipleNoAssoc);
|
||||
self.bump();
|
||||
next(self);
|
||||
}
|
||||
@ -468,7 +468,7 @@ impl<'i> Parser<'i> {
|
||||
self.finish_node();
|
||||
// Otherwise, simply skip one token to help better recovery.
|
||||
} else {
|
||||
self.error(Error::UnexpectedToken);
|
||||
self.error(ErrorKind::UnexpectedToken);
|
||||
}
|
||||
}
|
||||
Some(T!['{']) => {
|
||||
@ -492,11 +492,11 @@ impl<'i> Parser<'i> {
|
||||
continue;
|
||||
}
|
||||
Some(_) => {
|
||||
self.error(Error::UnexpectedToken);
|
||||
self.error(ErrorKind::UnexpectedToken);
|
||||
self.bump();
|
||||
}
|
||||
None => {
|
||||
self.error(Error::MissingToken(T![']']));
|
||||
self.error(ErrorKind::MissingToken(T![']']));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -504,7 +504,7 @@ impl<'i> Parser<'i> {
|
||||
self.finish_node();
|
||||
}
|
||||
_ => {
|
||||
self.error(Error::UnexpectedToken);
|
||||
self.error(ErrorKind::UnexpectedToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -539,18 +539,24 @@ impl<'i> Parser<'i> {
|
||||
Some((PATH_FRAGMENT | PATH, range)) => *range,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let mut last_is_slash = false;
|
||||
for (ch, i) in self.src[range].chars().zip(0u32..) {
|
||||
let cur_is_slash = ch == '/';
|
||||
if last_is_slash && cur_is_slash {
|
||||
let pos = range.start() + TextSize::from(i);
|
||||
self.errors.push((Error::PathDuplicatedSlashes, pos));
|
||||
}
|
||||
last_is_slash = cur_is_slash;
|
||||
}
|
||||
if !allow_trailing_slash && last_is_slash {
|
||||
let pos = range.end() - TextSize::from(1);
|
||||
self.errors.push((Error::PathTrailingSlash, pos));
|
||||
// N.B. Path tokens are ASCII-only, which are verified by the lexer.
|
||||
self.src[range]
|
||||
.as_bytes()
|
||||
.windows(2)
|
||||
.zip(1u32..)
|
||||
.filter(|(w, _)| w == b"//")
|
||||
.for_each(|(_, i)| {
|
||||
self.errors.push(Error {
|
||||
range: TextRange::at(range.start() + TextSize::from(i), 1.into()),
|
||||
kind: ErrorKind::PathDuplicatedSlashes,
|
||||
});
|
||||
});
|
||||
let last_char = TextRange::at(range.end() - TextSize::from(1), 1.into());
|
||||
if !allow_trailing_slash && &self.src[last_char] == "/" {
|
||||
self.errors.push(Error {
|
||||
range: last_char,
|
||||
kind: ErrorKind::PathTrailingSlash,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -565,7 +571,7 @@ impl<'i> Parser<'i> {
|
||||
if expect_delimiter {
|
||||
self.bump();
|
||||
} else {
|
||||
self.error(Error::UnexpectedToken);
|
||||
self.error(ErrorKind::UnexpectedToken);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -582,7 +588,7 @@ impl<'i> Parser<'i> {
|
||||
self.bump();
|
||||
break;
|
||||
}
|
||||
self.error(Error::UnexpectedToken);
|
||||
self.error(ErrorKind::UnexpectedToken);
|
||||
expect_delimiter = false;
|
||||
}
|
||||
Some(IDENT) => {
|
||||
@ -598,7 +604,7 @@ impl<'i> Parser<'i> {
|
||||
expect_delimiter = true;
|
||||
}
|
||||
Some(_) => {
|
||||
self.error(Error::UnexpectedToken);
|
||||
self.error(ErrorKind::UnexpectedToken);
|
||||
self.bump();
|
||||
expect_delimiter = false;
|
||||
}
|
||||
@ -613,7 +619,7 @@ impl<'i> Parser<'i> {
|
||||
loop {
|
||||
match self.peek_non_ws() {
|
||||
None => {
|
||||
self.error(Error::MissingToken(guard));
|
||||
self.error(ErrorKind::MissingToken(guard));
|
||||
break;
|
||||
}
|
||||
Some(k) if k == guard => {
|
||||
@ -649,7 +655,7 @@ impl<'i> Parser<'i> {
|
||||
// Consume one token if it cannot start an AttrPath and is not the guard.
|
||||
// This can happen for some extra tokens (eg. unfinished exprs) in AttrSet or LetIn.
|
||||
Some(_) => {
|
||||
self.error(Error::UnexpectedToken);
|
||||
self.error(ErrorKind::UnexpectedToken);
|
||||
self.bump();
|
||||
}
|
||||
}
|
||||
@ -678,7 +684,7 @@ impl<'i> Parser<'i> {
|
||||
}
|
||||
Some(T!["${"]) => self.dynamic(),
|
||||
Some(T!['"']) => self.string(STRING),
|
||||
_ => self.error(Error::MissingAttr),
|
||||
_ => self.error(ErrorKind::MissingAttr),
|
||||
}
|
||||
}
|
||||
|
||||
@ -701,7 +707,7 @@ impl<'i> Parser<'i> {
|
||||
// No skipping whitespace.
|
||||
match self.peek() {
|
||||
None => {
|
||||
self.error(Error::MissingToken(if node == STRING {
|
||||
self.error(ErrorKind::MissingToken(if node == STRING {
|
||||
T!['"']
|
||||
} else {
|
||||
T!["''"]
|
||||
|
@ -26,8 +26,8 @@ fn run_test(dir: &Path, ok: bool) {
|
||||
|
||||
let ast = parse_file(&src);
|
||||
let mut got = String::new();
|
||||
for (err, loc) in ast.errors() {
|
||||
writeln!(got, "{} at {}", err, u32::from(*loc)).unwrap();
|
||||
for err in ast.errors() {
|
||||
writeln!(got, "{}", err).unwrap();
|
||||
}
|
||||
write!(got, "{:#?}", ast.syntax_node()).unwrap();
|
||||
|
||||
@ -37,7 +37,6 @@ fn run_test(dir: &Path, ok: bool) {
|
||||
}
|
||||
|
||||
let expect_path = path.with_extension("ast");
|
||||
println!("{:?}", expect_path);
|
||||
expect_file![expect_path].assert_eq(&got);
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
Unexpected token at 0
|
||||
Unexpected token at 0..0
|
||||
SOURCE_FILE@0..0
|
||||
|
@ -1,6 +1,6 @@
|
||||
Unexpected token at 2
|
||||
Unexpected token at 9
|
||||
Unexpected token at 14
|
||||
Unexpected token at 2..4
|
||||
Unexpected token at 9..11
|
||||
Unexpected token at 14..16
|
||||
SOURCE_FILE@0..21
|
||||
BINARY_OP@0..21
|
||||
BINARY_OP@0..12
|
||||
|
@ -1,4 +1,4 @@
|
||||
Multiple root expressions at 12
|
||||
Multiple root expressions at 12..18
|
||||
SOURCE_FILE@0..24
|
||||
ASSERT@0..12
|
||||
KW_ASSERT@0..6 "assert"
|
||||
|
@ -1,5 +1,5 @@
|
||||
Path has duplicated slashes at 7
|
||||
Path has duplicated slashes at 20
|
||||
Path has duplicated slashes at 7..8
|
||||
Path has duplicated slashes at 20..21
|
||||
SOURCE_FILE@0..25
|
||||
LIST@0..24
|
||||
L_BRACK@0..1 "["
|
||||
|
@ -1,6 +1,6 @@
|
||||
Path has trailing slash at 6
|
||||
Path has trailing slash at 13
|
||||
Path has trailing slash at 29
|
||||
Path has trailing slash at 6..7
|
||||
Path has trailing slash at 13..14
|
||||
Path has trailing slash at 29..30
|
||||
SOURCE_FILE@0..33
|
||||
LIST@0..32
|
||||
L_BRACK@0..1 "["
|
||||
|
Loading…
Reference in New Issue
Block a user