···11use crate::ast::{SrcSpan, TypeAst};
22-use crate::error::wrap;
32use crate::parse::Token;
43use ecow::EcoString;
54···3635 pub location: SrcSpan,
3736}
38373939-impl ParseError {
4040- pub fn details(&self) -> (&'static str, Vec<String>) {
4141- match &self.error {
4242- ParseErrorType::ExpectedEqual => ("I was expecting a '=' after this", vec![]),
4343- ParseErrorType::ExpectedExpr => ("I was expecting an expression after this", vec![]),
4444- ParseErrorType::ExpectedName => ("I was expecting a name here", vec![]),
4545- ParseErrorType::ExpectedPattern => ("I was expecting a pattern after this", vec![]),
4646- ParseErrorType::ExpectedType => (
4747- "I was expecting a type after this",
4848- vec!["See: https://tour.gleam.run/basics/assignments/".into()],
4949- ),
5050- ParseErrorType::ExpectedUpName => ("I was expecting a type name here", vec![]),
5151- ParseErrorType::ExpectedValue => ("I was expecting a value after this", vec![]),
5252- ParseErrorType::ExpectedDefinition => {
5353- ("I was expecting a definition after this", vec![])
5454- }
5555- ParseErrorType::ExpectedDeprecationMessage => (
5656- "A deprecation attribute must have a string message.",
5757- vec![],
5858- ),
5959- ParseErrorType::ExpectedFunctionDefinition => {
6060- ("I was expecting a function definition after this", vec![])
6161- }
6262- ParseErrorType::ExpectedTargetName => (
6363- "I was expecting a target name after this",
6464- vec!["Try `erlang`, `javascript`.".into()],
6565- ),
6666- ParseErrorType::ExtraSeparator => (
6767- "This is an extra delimiter",
6868- vec!["Hint: Try removing it?".into()],
6969- ),
7070- ParseErrorType::ExprLparStart => (
7171- "This parenthesis cannot be understood here",
7272- vec![
7373- "Hint: To group expressions in Gleam, use \"{\" and \"}\"; tuples are created with `#(` and `)`.".into(),
7474- ]
7575- ),
7676- ParseErrorType::IncorrectName => (
7777- "I'm expecting a lowercase name here",
7878- vec![wrap(
7979- "Hint: Variable and module names start with a lowercase letter, \
8080-and can contain a-z, 0-9, or _.",
8181- )],
8282- ),
8383- ParseErrorType::IncorrectUpName => (
8484- "I'm expecting a type name here",
8585- vec![wrap(
8686- "Hint: Type names start with a uppercase letter, and can \
8787-contain a-z, A-Z, or 0-9.",
8888- )],
8989- ),
9090- ParseErrorType::InvalidBitArraySegment => (
9191- "This is not a valid BitArray segment option",
9292- vec![
9393- "Hint: Valid BitArray segment options are:".into(),
9494- wrap(
9595- "bits, bytes, int, float, utf8, utf16, utf32, utf8_codepoint, \
9696-utf16_codepoint, utf32_codepoint, signed, unsigned, big, little, native, size, unit.",
9797- ),
9898- "See: https://tour.gleam.run/data-types/bit-arrays/".into(),
9999- ],
100100- ),
101101- ParseErrorType::InvalidBitArrayUnit => (
102102- "This is not a valid BitArray unit value",
103103- vec![
104104- "Hint: unit must be an integer literal >= 1 and <= 256.".into(),
105105- "See: https://tour.gleam.run/data-types/bit-arrays/".into(),
106106- ],
107107- ),
108108- ParseErrorType::InvalidTailPattern => (
109109- "This part of a list pattern can only be a name or a discard",
110110- vec![],
111111- ),
112112- ParseErrorType::InvalidTupleAccess => (
113113- "This integer is not valid for tuple access",
114114- vec![
115115- "Hint: Only non negative integer literals like 0, or 1_000 can be used."
116116- .to_string(),
117117- ],
118118- ),
119119- ParseErrorType::LexError { error: lex_err } => lex_err.to_parse_error_info(),
120120- ParseErrorType::NestedBitArrayPattern => ("BitArray patterns cannot be nested", vec![]),
121121- ParseErrorType::NotConstType => (
122122- "This type is not allowed in module constants",
123123- vec!["See: https://tour.gleam.run/basics/constants/".into()],
124124- ),
125125- ParseErrorType::NoLetBinding => (
126126- "There must be a 'let' to bind variable to value",
127127- vec![
128128- "Hint: Use let for binding.".into(),
129129- "See: https://tour.gleam.run/basics/assignments/".into(),
130130- ],
131131- ),
132132- ParseErrorType::NoValueAfterEqual => (
133133- "I was expecting to see a value after this equals sign",
134134- vec![],
135135- ),
136136- ParseErrorType::OpaqueTypeAlias => (
137137- "Type Aliases cannot be opaque",
138138- vec!["See: https://tour.gleam.run/basics/type-aliases/".into()],
139139- ),
140140- ParseErrorType::OpNakedRight => (
141141- "This operator has no value on its right side",
142142- vec!["Hint: Remove it or put a value after it.".into()],
143143- ),
144144- ParseErrorType::TooManyArgHoles => (
145145- "There is more than 1 argument hole in this function call",
146146- vec![
147147- "Hint: Function calls can have at most one argument hole.".into(),
148148- "See: https://tour.gleam.run/functions/functions/".into(),
149149- ],
150150- ),
151151- ParseErrorType::UnexpectedEof => ("The module ended unexpectedly", vec![]),
152152- ParseErrorType::ListSpreadWithoutElements => (
153153- "This spread does nothing",
154154- vec![
155155- "Hint: Try prepending some elements [1, 2, ..list].".into(),
156156- "See: https://tour.gleam.run/basics/lists/".into(),
157157- ],
158158- ),
159159- ParseErrorType::ListSpreadWithAnotherSpread => (
160160- "I wasn't expecting a spread here",
161161- vec![
162162- "Lists are immutable and singly-linked, so to join two or more lists".into(),
163163- "all the elements of the lists would need to be copied into a new list.".into(),
164164- "This would be slow, so there is no built-in syntax for it.".into(),
165165- ],
166166- ),
167167- ParseErrorType::ListSpreadFollowedByElements => (
168168- "I wasn't expecting elements after this",
169169- vec![
170170- "Lists are immutable and singly-linked, so to append items to them".into(),
171171- "all the elements of a list would need to be copied into a new list.".into(),
172172- "This would be slow, so there is no built-in syntax for it.".into(),
173173- "".into(),
174174- "Hint: prepend items to the list and then reverse it once you are done.".into(),
175175- ],
176176- ),
177177- ParseErrorType::ListPatternSpreadFollowedByElements => (
178178- "I wasn't expecting elements after this",
179179- vec![
180180- "Lists are immutable and singly-linked, so to match on the end".into(),
181181- "of a list would require the whole list to be traversed. This".into(),
182182- "would be slow, so there is no built-in syntax for it. Pattern".into(),
183183- "match on the start of the list instead.".into(),
184184- ],
185185- ),
186186- ParseErrorType::UnexpectedReservedWord => (
187187- "This is a reserved word",
188188- vec!["Hint: I was expecting to see a name here.".into()],
189189- ),
190190- ParseErrorType::LowcaseBooleanPattern => (
191191- "Did you want a Bool instead of a variable?",
192192- vec![
193193- "Hint: In Gleam boolean literals are `True` and `False`.".into(),
194194- "See: https://tour.gleam.run/basics/bools/".into(),
195195- ],
196196- ),
197197- ParseErrorType::UnexpectedLabel => (
198198- "Argument labels are not allowed for anonymous functions",
199199- vec!["Please remove the argument label.".into()],
200200- ),
201201- ParseErrorType::UnexpectedToken {
202202- token,
203203- expected,
204204- hint,
205205- } => {
206206- let found = match token {
207207- Token::Int { .. } => "an Int".to_string(),
208208- Token::Float { .. } => "a Float".to_string(),
209209- Token::String { .. } => "a String".to_string(),
210210- Token::CommentDoc { .. } => "a comment".to_string(),
211211- Token::DiscardName { .. } => "a discard name".to_string(),
212212- Token::Name { .. } | Token::UpName { .. } => "a name".to_string(),
213213- _ if token.is_reserved_word() => format!("the keyword {token}"),
214214- _ => token.to_string(),
215215- };
216216-217217- let messages = std::iter::once(format!("Found {found}, expected one of: "))
218218- .chain(expected.iter().map(|s| format!("- {s}")));
219219-220220- let messages = match hint {
221221- Some(hint_text) => messages
222222- .chain(std::iter::once(format!("Hint: {hint_text}")))
223223- .collect(),
224224- _ => messages.collect(),
225225- };
226226-227227- ("I was not expecting this", messages)
228228- }
229229- ParseErrorType::ConcatPatternVariableLeftHandSide => (
230230- "This must be a string literal",
231231- vec![
232232- "We can't tell what size this prefix should be so we don't know".into(),
233233- "how to handle this pattern.".into(),
234234- "".into(),
235235- "If you want to match one character consider using `pop_grapheme`".into(),
236236- "from the stdlib's `gleam/string` module.".into(),
237237- ],
238238- ),
239239- ParseErrorType::UnexpectedFunction => (
240240- "Functions can only be called within other functions",
241241- vec![],
242242- ),
243243- ParseErrorType::ListSpreadWithoutTail => (
244244- "I was expecting a value after this spread",
245245- vec!["If a list expression has a spread then a tail must also be given.".into()],
246246- ),
247247- ParseErrorType::UnknownAttribute => (
248248- "I don't recognise this attribute",
249249- vec!["Try `deprecated`, `external` or `target` instead.".into()],
250250- ),
251251- ParseErrorType::DuplicateAttribute => (
252252- "Duplicate attribute",
253253- vec!["This attribute has already been given.".into()],
254254- ),
255255- ParseErrorType::UnknownTarget => (
256256- "I don't recognise this target",
257257- vec!["Try `erlang`, `javascript`.".into()],
258258- ),
259259- ParseErrorType::ExpectedFunctionBody => ("This function does not have a body", vec![]),
260260- ParseErrorType::RedundantInternalAttribute => (
261261- "Redundant internal attribute",
262262- vec![
263263- format!("Only a public definition can be annotated as internal."),
264264- "Hint: remove the `@internal` annotation.".into(),
265265- ],
266266- ),
267267- ParseErrorType::InvalidModuleTypePattern => (
268268- "Invalid pattern",
269269- vec![
270270- "I'm expecting a pattern here".into(),
271271- "Hint: A pattern can be a constructor name, a literal value".into(),
272272- "or a variable to bind a value to, etc.".into(),
273273- "See: https://tour.gleam.run/flow-control/case-expressions/".into(),
274274- ],
275275- ),
276276- ParseErrorType::ExpectedRecordConstructor {
277277- name,
278278- public,
279279- opaque,
280280- field,
281281- field_type,
282282- } => {
283283- let (accessor, opaque) = match *public {
284284- true if *opaque => ("pub ", "opaque "),
285285- true => ("pub ", ""),
286286- false => ("", ""),
287287- };
288288-289289- let mut annotation = EcoString::new();
290290- match field_type {
291291- Some(t) => t.print(&mut annotation),
292292- None => annotation.push_str("Type"),
293293- };
294294-295295- (
296296- "I was not expecting this",
297297- vec![
298298- "Each custom type variant must have a constructor:\n".into(),
299299- format!("{accessor}{opaque}type {name} {{"),
300300- format!(" {name}("),
301301- format!(" {field}: {annotation},"),
302302- " )".into(),
303303- "}".into(),
304304- ],
305305- )
306306- }
307307- ParseErrorType::CallInClauseGuard => (
308308- "Unsupported expression",
309309- vec!["Functions cannot be called in clause guards.".into()],
310310- ),
311311- ParseErrorType::IfExpression => (
312312- "Gleam doesn't have if expressions",
313313- vec![
314314- "If you want to write a conditional expression you can use a `case`:".into(),
315315- "".into(),
316316- " case condition {".into(),
317317- " True -> todo".into(),
318318- " False -> todo".into(),
319319- " }".into(),
320320- "".into(),
321321- "See: https://tour.gleam.run/flow-control/case-expressions/".into(),
322322- ],
323323- ),
324324- ParseErrorType::ConstantRecordConstructorNoArguments => (
325325- "I was expecting arguments here",
326326- vec!["A record must be passed arguments when constructed.".into()],
327327- ),
328328- ParseErrorType::TypeConstructorNoArguments => (
329329- "I was expecting arguments here",
330330- vec!["A type constructor must be passed arguments.".into()],
331331- ),
332332- ParseErrorType::TypeDefinitionNoArguments => (
333333- "I was expecting generic parameters here",
334334- vec![
335335- "A generic type must have at least a generic parameter.".into(),
336336- "Hint: If a type is not generic you should omit the `()`.".into(),
337337- ],
338338- ),
339339- ParseErrorType::UnknownAttributeRecordVariant => (
340340- "This attribute cannot be used on a variant.",
341341- vec!["Hint: Did you mean `@deprecated`?".into()],
342342- ),
343343- ParseErrorType::IncorrectImportModuleSeparator { module, item } => (
344344- "I was expecting either `/` or `.{` here.",
345345- vec![
346346- "Perhaps you meant one of:".into(),
347347- "".into(),
348348- format!(" import {module}/{item}"),
349349- format!(" import {module}.{{item}}"),
350350- ]
351351- )
352352- }
353353- }
354354-}
355355-35638#[derive(Debug, Clone, PartialEq, Eq)]
35739pub enum ParseErrorType {
35840 ExpectedEqual, // expect "="
···38971 UnknownTarget, // an unknown target was used
39072 ListSpreadWithoutElements, // Pointless spread: `[..xs]`
39173 ListSpreadFollowedByElements, // trying to append something after the spread: `[..xs, x]`
392392- ListSpreadWithAnotherSpread, // trying to use multiple spreads: `[..xs, ..ys]`
7474+ ListSpreadWithAnotherSpread {
7575+ first_spread_location: SrcSpan,
7676+ second_spread_location: SrcSpan,
7777+ }, // trying to use multiple spreads: `[..xs, ..ys]`
39378 LowcaseBooleanPattern, // most likely user meant True or False in patterns
39479 UnexpectedLabel, // argument labels were provided, but are not supported in this context
39580 UnexpectedEof,
···15153 │ let val = _func_starting_with_underscore(1)
1616 │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ I'm expecting a lowercase name here
17171818-Hint: Variable and module names start with a lowercase letter, and can
1919-contain a-z, 0-9, or _.
1818+Hint: Variable and module names start with a lowercase letter, and can contain
1919+a-z, 0-9, or _.
···17174 │ 1 -> _with_underscore(1)
1818 │ ^^^^^^^^^^^^^^^^ I'm expecting a lowercase name here
19192020-Hint: Variable and module names start with a lowercase letter, and can
2121-contain a-z, 0-9, or _.
2020+Hint: Variable and module names start with a lowercase letter, and can contain
2121+a-z, 0-9, or _.
···2121all the elements of a list would need to be copied into a new list.
2222This would be slow, so there is no built-in syntax for it.
23232424-Hint: prepend items to the list and then reverse it once you are done.
2424+Hint: Prepend items to the list and then reverse it once you are done.
···2121all the elements of a list would need to be copied into a new list.
2222This would be slow, so there is no built-in syntax for it.
23232424-Hint: prepend items to the list and then reverse it once you are done.
2424+Hint: Prepend items to the list and then reverse it once you are done.
···12121 │ wibble = 4
1313 │ ^ There must be a 'let' to bind variable to value
14141515-Hint: Use let for binding.
1615See: https://tour.gleam.run/basics/assignments/
1616+Hint: Use let for binding.
···12121 │ wibble:Int = 4
1313 │ ^ There must be a 'let' to bind variable to value
14141515-Hint: Use let for binding.
1615See: https://tour.gleam.run/basics/assignments/
1616+Hint: Use let for binding.
···13132 │ wobble = 42
1414 │ ^ There must be a 'let' to bind variable to value
15151616-Hint: Use let for binding.
1716See: https://tour.gleam.run/basics/assignments/
1717+Hint: Use let for binding.
···1616 │ ^^^^^^^^^ Redundant internal attribute
17171818Only a public definition can be annotated as internal.
1919-Hint: remove the `@internal` annotation.
1919+Hint: Remove the `@internal` annotation.
···1616 │ ^^^^^^^^^ Redundant internal attribute
17171818Only a public definition can be annotated as internal.
1919-Hint: remove the `@internal` annotation.
1919+Hint: Remove the `@internal` annotation.
···1818 │ ^^^^^^^^^ Redundant internal attribute
19192020Only a public definition can be annotated as internal.
2121-Hint: remove the `@internal` annotation.
2121+Hint: Remove the `@internal` annotation.
···1616 │ ^^^^^^^^^ Redundant internal attribute
17171818Only a public definition can be annotated as internal.
1919-Hint: remove the `@internal` annotation.
1919+Hint: Remove the `@internal` annotation.