Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

handle syntax errors more gracefully #34

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,21 @@ pub enum ParseError {
UnexpectedEOF,
/// UnexpectedWanted is used when specific tokens are expected, but the end of file is reached
UnexpectedEOFWanted(Box<[SyntaxKind]>),
Expected(TextRange, String),
}

impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ParseError::Expected(range, description) => {
write!(
f,
"expected {} at {}..{}",
description,
usize::from(range.start()),
usize::from(range.end())
)
}
ParseError::Unexpected(range) => {
write!(f, "error node at {}..{}", usize::from(range.start()), usize::from(range.end()))
}
Expand Down Expand Up @@ -291,7 +301,15 @@ where
match self.peek() {
Some(TOKEN_DYNAMIC_START) => self.parse_dynamic(),
Some(TOKEN_STRING_START) => self.parse_string(),
_ => self.expect_ident(),
Some(TOKEN_IDENT) => self.expect_ident(),
_ => {
let start = self.start_error_node();
let end = self.finish_error_node();
self.errors.push(ParseError::Expected(
TextRange::new(start, end),
"attribute".to_string(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we should reflect here that strings etc. are also OK.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should be the exact message used? Maybe attribute or string? Although I guess a string does represent an attribute here? Please correct me if I'm wrong

));
}
}
}
fn parse_attr(&mut self) {
Expand Down Expand Up @@ -391,7 +409,9 @@ where
self.parse_attr();
self.expect(TOKEN_ASSIGN);
self.parse_expr();
self.expect(TOKEN_SEMICOLON);
if let Some(TOKEN_SEMICOLON) = self.peek() {
self.bump();
}
self.finish_node();
}
}
Expand Down Expand Up @@ -696,6 +716,16 @@ where
self.finish_node();
checkpoint
}
Some(TOKEN_SEMICOLON) => {
let checkpoint = self.checkpoint();
let start = self.start_error_node();
let end = self.finish_error_node();
self.errors.push(ParseError::Expected(
TextRange::new(start, end),
"expression".to_string(),
));
checkpoint
}
_ => self.parse_math(),
}
}
Expand Down
2 changes: 0 additions & 2 deletions test_data/general/error.expect
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ error: unexpected TOKEN_STRING_START at 78..98, wanted any of [TOKEN_ASSIGN]
error: unexpected TOKEN_CURLY_B_CLOSE at 162..166, wanted any of [TOKEN_ASSIGN]
error: unexpected end of file, wanted any of [TOKEN_ASSIGN]
error: unexpected end of file
error: unexpected end of file, wanted any of [TOKEN_SEMICOLON]
error: unexpected end of file
error: unexpected end of file, wanted any of [TOKEN_SEMICOLON]
error: unexpected end of file
NODE_ROOT 0..166 {
NODE_ATTR_SET 0..166 {
Expand Down
4 changes: 3 additions & 1 deletion test_data/parser/invalid_syntax/1.expect
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
error: unexpected TOKEN_SQUARE_B_CLOSE at 0..1, wanted any of [TOKEN_PAREN_OPEN, TOKEN_REC, TOKEN_CURLY_B_OPEN, TOKEN_SQUARE_B_OPEN, TOKEN_DYNAMIC_START, TOKEN_STRING_START, TOKEN_IDENT]
error: unexpected end of file, wanted any of [TOKEN_IDENT]
error: expected attribute at 2..2
NODE_ROOT 0..2 {
NODE_SELECT 0..2 {
NODE_ERROR 0..1 {
TOKEN_SQUARE_B_CLOSE("]") 0..1
}
TOKEN_DOT(".") 1..2
NODE_ERROR 2..2 {
}
}
}
47 changes: 47 additions & 0 deletions test_data/parser/invalid_syntax/4.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
error: expected expression at 12..12
NODE_ROOT 0..40 {
NODE_BIN_OP 0..40 {
NODE_ATTR_SET 0..28 {
TOKEN_CURLY_B_OPEN("{") 0..1
TOKEN_WHITESPACE("\n ") 1..6
NODE_KEY_VALUE 6..13 {
NODE_KEY 6..9 {
NODE_IDENT 6..9 {
TOKEN_IDENT("foo") 6..9
}
}
TOKEN_WHITESPACE(" ") 9..10
TOKEN_ASSIGN("=") 10..11
TOKEN_WHITESPACE(" ") 11..12
NODE_ERROR 12..12 {
}
TOKEN_SEMICOLON(";") 12..13
}
TOKEN_WHITESPACE("\n ") 13..18
NODE_KEY_VALUE 18..26 {
NODE_KEY 18..21 {
NODE_IDENT 18..21 {
TOKEN_IDENT("bar") 18..21
}
}
TOKEN_WHITESPACE(" ") 21..22
TOKEN_ASSIGN("=") 22..23
TOKEN_WHITESPACE(" ") 23..24
NODE_LITERAL 24..25 {
TOKEN_INTEGER("1") 24..25
}
TOKEN_SEMICOLON(";") 25..26
}
TOKEN_WHITESPACE("\n") 26..27
TOKEN_CURLY_B_CLOSE("}") 27..28
}
TOKEN_WHITESPACE(" ") 28..29
TOKEN_UPDATE("//") 29..31
TOKEN_WHITESPACE(" ") 31..32
NODE_ATTR_SET 32..40 {
TOKEN_CURLY_B_OPEN("{") 32..33
TOKEN_WHITESPACE("\n \n") 33..39
TOKEN_CURLY_B_CLOSE("}") 39..40
}
}
}
6 changes: 6 additions & 0 deletions test_data/parser/invalid_syntax/4.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
foo = ;
bar = 1;
} // {

}
64 changes: 64 additions & 0 deletions test_data/parser/invalid_syntax/5.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
error: expected attribute at 37..37
NODE_ROOT 0..57 {
NODE_ATTR_SET 0..57 {
TOKEN_REC("rec") 0..3
TOKEN_WHITESPACE(" ") 3..4
TOKEN_CURLY_B_OPEN("{") 4..5
TOKEN_WHITESPACE("\n ") 5..10
NODE_KEY_VALUE 10..22 {
NODE_KEY 10..17 {
NODE_IDENT 10..13 {
TOKEN_IDENT("bar") 10..13
}
TOKEN_DOT(".") 13..14
NODE_IDENT 14..17 {
TOKEN_IDENT("xyz") 14..17
}
}
TOKEN_WHITESPACE(" ") 17..18
TOKEN_ASSIGN("=") 18..19
TOKEN_WHITESPACE(" ") 19..20
NODE_LITERAL 20..21 {
TOKEN_INTEGER("1") 20..21
}
TOKEN_SEMICOLON(";") 21..22
}
TOKEN_WHITESPACE("\n ") 22..27
NODE_KEY_VALUE 27..38 {
NODE_KEY 27..30 {
NODE_IDENT 27..30 {
TOKEN_IDENT("foo") 27..30
}
}
TOKEN_WHITESPACE(" ") 30..31
TOKEN_ASSIGN("=") 31..32
TOKEN_WHITESPACE(" ") 32..33
NODE_SELECT 33..37 {
NODE_IDENT 33..36 {
TOKEN_IDENT("bar") 33..36
}
TOKEN_DOT(".") 36..37
NODE_ERROR 37..37 {
}
}
TOKEN_SEMICOLON(";") 37..38
}
TOKEN_WHITESPACE("\n ") 38..43
NODE_KEY_VALUE 43..55 {
NODE_KEY 43..46 {
NODE_IDENT 43..46 {
TOKEN_IDENT("abc") 43..46
}
}
TOKEN_WHITESPACE(" ") 46..47
TOKEN_ASSIGN("=") 47..48
TOKEN_WHITESPACE(" ") 48..49
NODE_LITERAL 49..54 {
TOKEN_INTEGER("12345") 49..54
}
TOKEN_SEMICOLON(";") 54..55
}
TOKEN_WHITESPACE("\n") 55..56
TOKEN_CURLY_B_CLOSE("}") 56..57
}
}
5 changes: 5 additions & 0 deletions test_data/parser/invalid_syntax/5.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
rec {
bar.xyz = 1;
foo = bar.;
abc = 12345;
}
64 changes: 64 additions & 0 deletions test_data/parser/invalid_syntax/6.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
error: expected attribute at 37..37
NODE_ROOT 0..57 {
NODE_ATTR_SET 0..57 {
TOKEN_REC("rec") 0..3
TOKEN_WHITESPACE(" ") 3..4
TOKEN_CURLY_B_OPEN("{") 4..5
TOKEN_WHITESPACE("\n ") 5..10
NODE_KEY_VALUE 10..22 {
NODE_KEY 10..17 {
NODE_IDENT 10..13 {
TOKEN_IDENT("bar") 10..13
}
TOKEN_DOT(".") 13..14
NODE_IDENT 14..17 {
TOKEN_IDENT("xyz") 14..17
}
}
TOKEN_WHITESPACE(" ") 17..18
TOKEN_ASSIGN("=") 18..19
TOKEN_WHITESPACE(" ") 19..20
NODE_LITERAL 20..21 {
TOKEN_INTEGER("1") 20..21
}
TOKEN_SEMICOLON(";") 21..22
}
TOKEN_WHITESPACE("\n ") 22..27
NODE_KEY_VALUE 27..38 {
NODE_KEY 27..30 {
NODE_IDENT 27..30 {
TOKEN_IDENT("foo") 27..30
}
}
TOKEN_WHITESPACE(" ") 30..31
TOKEN_ASSIGN("=") 31..32
TOKEN_WHITESPACE(" ") 32..33
NODE_SELECT 33..37 {
NODE_IDENT 33..36 {
TOKEN_IDENT("bar") 33..36
}
TOKEN_DOT(".") 36..37
NODE_ERROR 37..37 {
}
}
TOKEN_SEMICOLON(";") 37..38
}
TOKEN_WHITESPACE("\n ") 38..43
NODE_KEY_VALUE 43..55 {
NODE_KEY 43..46 {
NODE_IDENT 43..46 {
TOKEN_IDENT("abc") 43..46
}
}
TOKEN_WHITESPACE(" ") 46..47
TOKEN_ASSIGN("=") 47..48
TOKEN_WHITESPACE(" ") 48..49
NODE_LITERAL 49..54 {
TOKEN_INTEGER("12345") 49..54
}
TOKEN_SEMICOLON(";") 54..55
}
TOKEN_WHITESPACE("\n") 55..56
TOKEN_CURLY_B_CLOSE("}") 56..57
}
}
5 changes: 5 additions & 0 deletions test_data/parser/invalid_syntax/6.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
rec {
bar.xyz = 1;
foo = bar.;
abc = 12345;
}