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

Add Information About Found Token in UnexpectedToken Error Type #3299

Merged
merged 24 commits into from
Jun 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1d63d74
feat: add to UnexpectedToken and include in details with info about …
Jun 20, 2024
5bfc19b
feat: move formatting logic out of parser and display keywords in de…
Jun 20, 2024
0eb33f9
chore: apply cargo fmt
Jun 20, 2024
4864247
refac: capture as an enum rather than a struct
Jun 26, 2024
ab72271
feat: move is_reserved_word to Token, re-apply the specific error mes…
Jun 26, 2024
bb84827
test: add tests for unexpected String and unexpected Int
Jun 26, 2024
570aec3
style: cargo fmt
Jun 26, 2024
c40ca3d
feat: use backticks to surround all tokens instead of dquotes in Display
Jun 26, 2024
8a7cf13
feat: display token type instead of repeating content for content-hol…
Jun 26, 2024
602447c
chore: remove to_string on Token to resolve clippy warning
Jun 26, 2024
824a324
refac: change field name in UnexpectedTokenError from found to token
Jun 27, 2024
d60c21d
chore: update changelog
Jun 30, 2024
ba9df14
feat: add to UnexpectedToken and include in details with info about …
Jun 20, 2024
cd7f308
feat: move formatting logic out of parser and display keywords in de…
Jun 20, 2024
fc7bb42
chore: apply cargo fmt
Jun 20, 2024
aab3cc3
refac: capture as an enum rather than a struct
Jun 26, 2024
600061b
feat: move is_reserved_word to Token, re-apply the specific error mes…
Jun 26, 2024
c892dc0
test: add tests for unexpected String and unexpected Int
Jun 26, 2024
176437e
style: cargo fmt
Jun 26, 2024
624b560
feat: use backticks to surround all tokens instead of dquotes in Display
Jun 26, 2024
58be22c
feat: display token type instead of repeating content for content-hol…
Jun 26, 2024
de83dce
chore: remove to_string on Token to resolve clippy warning
Jun 26, 2024
db009f2
refac: change field name in UnexpectedTokenError from found to token
Jun 27, 2024
6c46b3c
chore: update changelog
Jun 30, 2024
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
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,24 @@
- Import cycles now show the location where the import occur.
([Ameen Radwan](https://github.com/Acepie))

- Error messages resulting from unexpected tokens now include information on
the found token's type. This updated message explains how the lexer handled
the token, so as to guide the user towards providing correct syntax.

Following is an example, where the error message indicates that the name of
the provided field conflicts with a keyword:

```
3 │ A(type: String)
│ ^^^^ I was not expecting this

Found the keyword `type`, expected one of:
`)`
a constructor argument name
```

([Rahul D. Ghosal](https://github.com/rdghosal))

### Formatter

### Language Server
Expand Down
96 changes: 8 additions & 88 deletions compiler-core/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,12 @@ where
parse_result: Result<A, ParseError>,
) -> Result<A, ParseError> {
let parse_result = self.ensure_no_errors(parse_result)?;
if let Some((start, _, end)) = self.next_tok() {
if let Some((start, token, end)) = self.next_tok() {
// there are still more tokens
let expected = vec!["An import, const, type, or function.".into()];
return parse_error(
ParseErrorType::UnexpectedToken {
token,
expected,
hint: None,
},
Expand Down Expand Up @@ -2476,8 +2477,9 @@ where
})),
}
}
Some((start, _, end)) => parse_error(
Some((start, token, end)) => parse_error(
ParseErrorType::UnexpectedToken {
token,
expected: vec!["UpName".into(), "Name".into()],
hint: None,
},
Expand Down Expand Up @@ -2811,7 +2813,7 @@ where
Token::UpName { .. } => {
parse_error(ParseErrorType::IncorrectName, SrcSpan { start, end })
}
_ if is_reserved_word(tok) => parse_error(
_ if tok.is_reserved_word() => parse_error(
ParseErrorType::UnexpectedReservedWord,
SrcSpan { start, end },
),
Expand Down Expand Up @@ -2968,8 +2970,9 @@ where
fn next_tok_unexpected<A>(&mut self, expected: Vec<EcoString>) -> Result<A, ParseError> {
match self.next_tok() {
None => parse_error(ParseErrorType::UnexpectedEof, SrcSpan { start: 0, end: 0 }),
Some((start, _, end)) => parse_error(
Some((start, token, end)) => parse_error(
ParseErrorType::UnexpectedToken {
token,
expected,
hint: None,
},
Expand Down Expand Up @@ -3541,90 +3544,6 @@ fn parse_error<T>(error: ParseErrorType, location: SrcSpan) -> Result<T, ParseEr
// Misc Helpers
//

/// Returns whether the given token is a reserved word.
///
/// Useful for checking if a user tried to enter a reserved word as a name.
fn is_reserved_word(tok: Token) -> bool {
match tok {
Token::As
| Token::Assert
| Token::Case
| Token::Const
| Token::Fn
| Token::If
| Token::Import
| Token::Let
| Token::Opaque
| Token::Pub
| Token::Todo
| Token::Type
| Token::Use
| Token::Auto
| Token::Delegate
| Token::Derive
| Token::Echo
| Token::Else
| Token::Implement
| Token::Macro
| Token::Panic
| Token::Test => true,

Token::Name { .. }
| Token::UpName { .. }
| Token::DiscardName { .. }
| Token::Int { .. }
| Token::Float { .. }
| Token::String { .. }
| Token::CommentDoc { .. }
| Token::LeftParen
| Token::RightParen
| Token::LeftSquare
| Token::RightSquare
| Token::LeftBrace
| Token::RightBrace
| Token::Plus
| Token::Minus
| Token::Star
| Token::Slash
| Token::Less
| Token::Greater
| Token::LessEqual
| Token::GreaterEqual
| Token::Percent
| Token::PlusDot
| Token::MinusDot
| Token::StarDot
| Token::SlashDot
| Token::LessDot
| Token::GreaterDot
| Token::LessEqualDot
| Token::GreaterEqualDot
| Token::LtGt
| Token::Colon
| Token::Comma
| Token::Hash
| Token::Bang
| Token::Equal
| Token::EqualEqual
| Token::NotEqual
| Token::Vbar
| Token::VbarVbar
| Token::AmperAmper
| Token::LtLt
| Token::GtGt
| Token::Pipe
| Token::Dot
| Token::RArrow
| Token::LArrow
| Token::DotDot
| Token::At
| Token::EndOfFile
| Token::CommentNormal
| Token::CommentModule
| Token::NewLine => false,
}
}

// Parsing a function call into the appropriate structure
#[derive(Debug)]
pub enum ParserArg {
Expand Down Expand Up @@ -3660,6 +3579,7 @@ pub fn make_call(
if name != "_" {
return parse_error(
ParseErrorType::UnexpectedToken {
token: Token::Name { name },
expected: vec!["An expression".into(), "An underscore".into()],
hint: None,
},
Expand Down
21 changes: 19 additions & 2 deletions compiler-core/src/parse/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::ast::SrcSpan;
use crate::error::wrap;
use crate::parse::Token;
use ecow::EcoString;
use heck::{ToSnakeCase, ToUpperCamelCase};

Expand Down Expand Up @@ -187,8 +188,23 @@ utf16_codepoint, utf32_codepoint, signed, unsigned, big, little, native, size, u
"Argument labels are not allowed for anonymous functions",
vec!["Please remove the argument label.".into()],
),
ParseErrorType::UnexpectedToken { expected, hint } => {
let messages = std::iter::once("Expected one of: ".to_string())
ParseErrorType::UnexpectedToken {
token,
expected,
hint,
} => {
let found = match token {
Token::Int { .. } => "an Int".to_string(),
Token::Float { .. } => "a Float".to_string(),
Token::String { .. } => "a String".to_string(),
Token::CommentDoc { .. } => "a comment".to_string(),
Token::DiscardName { .. } => "a discard name".to_string(),
Token::Name { .. } | Token::UpName { .. } => "a name".to_string(),
_ if token.is_reserved_word() => format!("the keyword {}", token),
_ => token.to_string(),
};

let messages = std::iter::once(format!("Found {found}, expected one of: "))
.chain(expected.iter().map(|s| s.to_string()));

let messages = match hint {
Expand Down Expand Up @@ -290,6 +306,7 @@ pub enum ParseErrorType {
UnexpectedEof,
UnexpectedReservedWord, // reserved word used when a name was expected
UnexpectedToken {
token: Token,
expected: Vec<EcoString>,
hint: Option<EcoString>,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ error: Syntax error
3 │ let <<b1, pub>> = <<24, 3>>
│ ^^^ I was not expecting this

Expected one of:
">>"
Found the keyword `pub`, expected one of:
`>>`
a bit array segment pattern
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ error: Syntax error
3 │ let #(a, case, c) = #(1, 2, 3)
│ ^^^^ I was not expecting this

Expected one of:
")"
Found the keyword `case`, expected one of:
`)`
a pattern
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ error: Syntax error
3 │ <<72, 101, 108, 108, 111, 44, 32, 74, 111, 101, const>>
│ ^^^^^ I was not expecting this

Expected one of:
">>"
Found the keyword `const`, expected one of:
`>>`
a bit array segment
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ error: Syntax error
3 │ add(_name, 1)
│ ^^^^^ I was not expecting this

Expected one of:
Found a name, expected one of:
An expression
An underscore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ error: Syntax error
4 │ -> -> 0
│ ^^ I was not expecting this

Expected one of:
"}"
Found `->`, expected one of:
`}`
a case clause
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ error: Syntax error
3 │ case 1, type {
│ ^^^^ I was not expecting this

Expected one of:
"{"
Found the keyword `type`, expected one of:
`{`
an expression
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ error: Syntax error
2 │ const a = <<1, 2, <->>
│ ^^ I was not expecting this

Expected one of:
">>"
Found `<-`, expected one of:
`>>`
a bit array segment
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ error: Syntax error
2 │ const a = [1, 2, <-]
│ ^^ I was not expecting this

Expected one of:
"]"
Found `<-`, expected one of:
`]`
a constant value
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ error: Syntax error
5 │ const a = A("a", let)
│ ^^^ I was not expecting this

Expected one of:
")"
Found the keyword `let`, expected one of:
`)`
a constant record argument
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ error: Syntax error
2 │ const a = #(1, 2, <-)
│ ^^ I was not expecting this

Expected one of:
")"
Found `<-`, expected one of:
`)`
a constant value
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
source: compiler-core/src/parse/tests.rs
expression: "\nfn f(a, \"b\") -> String {\n a <> b\n}\n"
---
error: Syntax error
┌─ /src/parse/error.gleam:2:9
2 │ fn f(a, "b") -> String {
│ ^^^ I was not expecting this

Found a String, expected one of:
`)`
a function parameter
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ error: Syntax error
2 │ fn f(g: fn(Int, 1) -> Int) -> Int {
│ ^ I was not expecting this

Expected one of:
")"
Found an Int, expected one of:
`)`
a type
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ error: Syntax error
3 │ #(1, 2, const)
│ ^^^^^ I was not expecting this

Expected one of:
")"
Found the keyword `const`, expected one of:
`)`
an expression
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ error: Syntax error
4 │ type
│ ^^^^ I was not expecting this

Expected one of:
"}"
Found the keyword `type`, expected one of:
`}`
a record constructor
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ error: Syntax error
3 │ A(type: String)
│ ^^^^ I was not expecting this

Expected one of:
")"
Found the keyword `type`, expected one of:
`)`
a constructor argument name
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
source: compiler-core/src/parse/tests.rs
expression: "\ntype A {\n One\n Two\n 3\n}\n"
---
error: Syntax error
┌─ /src/parse/error.gleam:5:5
5 │ 3
│ ^ I was not expecting this

Found an Int, expected one of:
`}`
a record constructor
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ error: Syntax error
2 │ type A(a, type) {
│ ^^^^ I was not expecting this

Expected one of:
")"
Found the keyword `type`, expected one of:
`)`
a name
Loading
Loading