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