1 use crate::ast::SrcSpan;
2 use heck::CamelCase;
3 use heck::SnakeCase;
4 
5 #[derive(Debug, PartialEq, Clone)]
6 pub struct LexicalError {
7     pub error: LexicalErrorType,
8     pub location: SrcSpan,
9 }
10 
11 #[derive(Debug, PartialEq, Clone)]
12 pub enum LexicalErrorType {
13     BadStringEscape,       // string contains an unescaped slash
14     DigitOutOfRadix,       // 0x012 , 2 is out of radix
15     NumTrailingUnderscore, // 1_000_ is not allowed
16     RadixIntNoValue,       // 0x, 0b, 0o without a value
17     UnexpectedStringEnd,   // Unterminated string literal
18     UnrecognizedToken { tok: char },
19     BadName { name: String },
20     BadDiscardName { name: String },
21     BadUpname { name: String },
22 }
23 
24 #[derive(Debug, PartialEq)]
25 pub struct ParseError {
26     pub error: ParseErrorType,
27     pub location: SrcSpan,
28 }
29 
30 #[derive(Debug, PartialEq)]
31 pub enum ParseErrorType {
32     ExpectedExpr,            // after "->" in a case clause
33     ExpectedName,            // any token used when a Name was expected
34     ExpectedPattern,         // after ':' where a pattern is expected
35     ExpectedType,            // after ':' or '->' where a type annotation is expected
36     ExpectedUpName,          // any token used when a UpName was expected
37     ExpectedValue,           // no value after "="
38     ExprLparStart,           // it seems "(" was used to start an expression
39     ExprThenlessTry,         // a try in the tail position of an expression sequence
40     ExtraSeparator,          // #(1,,) <- the 2nd comma is an extra separator
41     IncorrectName,           // UpName or DiscardName used when Name was expected
42     IncorrectUpName,         // Name or DiscardName used when UpName was expected
43     InvalidBitStringSegment, // <<7:hello>> `hello` is an invalid bitstring segment
44     InvalidBitStringUnit,    // in <<1:unit(x)>> x must be 1 <= x <= 256
45     InvalidTailPattern,      // only name and _name are allowed after ".." in list pattern
46     InvalidTupleAccess,      // only positive int literals for tuple access
47     LexError { error: LexicalError },
48     NestedBitStringPattern,    // <<<<1>>, 2>>, <<1>> is not allowed in there
49     NoConstructors,            // A type "A {}" must have at least one constructor
50     NoCaseClause,              // a case with no claueses
51     NoExpression, // between "{" and "}" in expression position, there must be an expression
52     NoValueAfterEqual, // = <something other than a value>
53     NotConstType, // :fn(), name, _  are not valid const types
54     OpNakedRight, // Operator with no value to the right
55     OpaqueTypeAlias, // Type aliases cannot be opaque
56     TooManyArgHoles, // a function call can have at most 1 arg hole
57     ListSpreadWithoutElements, // Pointless spread: `[..xs]`
58     UnexpectedEof,
59     UnexpectedReservedWord, // reserved word used when a name was expected
60     UnexpectedToken { expected: Vec<String> },
61 }
62 
63 impl LexicalError {
to_parse_error_info(&self) -> (&str, Vec<String>)64     pub fn to_parse_error_info(&self) -> (&str, Vec<String>) {
65         match &self.error {
66             LexicalErrorType::BadStringEscape => (
67                 "I don't understand this escape code",
68                 vec![
69                     "Hint: Add another backslash before it.".to_string(),
70                     "See: https://gleam.run/book/tour/strings.html#escape-sequences".to_string(),
71                 ],
72             ),
73             LexicalErrorType::DigitOutOfRadix => {
74                 ("This digit is too big for the specified radix.", vec![])
75             }
76             LexicalErrorType::NumTrailingUnderscore => (
77                 "Numbers cannot have a trailing underscore.",
78                 vec!["Hint: remove it.".to_string()],
79             ),
80             LexicalErrorType::RadixIntNoValue => ("This integer has no value.", vec![]),
81             LexicalErrorType::UnexpectedStringEnd => {
82                 ("The string starting here was left open.", vec![])
83             }
84             LexicalErrorType::UnrecognizedToken { .. } => (
85                 "I can't figure out what to do with this character.",
86                 vec!["Hint: Is it a typo?".to_string()],
87             ),
88             LexicalErrorType::BadName { name } => (
89                 "This is not a valid name.",
90                 vec![
91                     "Hint: Names start with a lowercase letter and contain a-z, 0-9, or _."
92                         .to_string(),
93                     format!("Try: {}", name.to_snake_case()),
94                 ],
95             ),
96             LexicalErrorType::BadDiscardName { name } => (
97                 "This is not a valid discard name.",
98                 vec![
99                     "Hint: Discard names start with _ and contain a-z, 0-9, or _.".to_string(),
100                     format!("Try: _{}", name.to_snake_case()),
101                 ],
102             ),
103             LexicalErrorType::BadUpname { name } => (
104                 "This is not a valid upname.",
105                 vec![
106                     "Hint: Upnames start with an uppercase letter and contain".to_string(),
107                     "only lowercase letters, numbers, and uppercase letters.".to_string(),
108                     format!("Try: {}", name.to_camel_case()),
109                 ],
110             ),
111         }
112     }
113 }
114