//! Submodule with parsing related errors. use crate::{ast::AstSpan, lexer::TokenPosition}; /// Internal parse error kinds. /// /// Used by the parser as a compact signal for later construction of user-facing /// diagnostics. /// /// Naming convention: /// - Prefix identifies the syntactic construct /// (`Expression`, `For`, `Switch`, etc.). /// - Suffix describes the exact problem (`MissingClosingParenthesis`, /// `UnexpectedToken`, `MultipleDefaults`, etc.). #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub enum ParseErrorKind { // ================== New errors that are 100% used! ================== // headline: empty parenthesized expression // primary label on ): expected an expression before this \)'` // secondary label on (: parenthesized expression starts here // Remove the parentheses or put an expression inside them. ParenthesizedExpressionEmpty { left_parenthesis_position: TokenPosition, }, // headline: missing type argument in \class<...>`` // primary label on > or insertion site: expected a type name here // secondary label on < or on class: type argument list starts here // help: Write a type name, for example \class`.` ClassTypeMissingTypeArgument { left_angle_bracket_position: TokenPosition, }, // headline: missing closing \>` in `class<...>`` // primary label on offending following token or EOF: expected \>` before this token` or at EOF: expected \>` here` // secondary label on <: this \<` starts the type argument` // help: Add \>` to close the class type expression.` ClassTypeMissingClosingAngleBracket { left_angle_bracket_position: TokenPosition, }, // headline: missing closing \)'` // primary label on the point where ) was expected: expected \)' here` or, if you have a real token there, expected \)' before this token` // secondary label on the opening (: this \(` starts the parenthesized expression` // help: Add \)' to close the expression.` ParenthesizedExpressionMissingClosingParenthesis { left_parenthesis_position: TokenPosition, }, // headline: expected expression // primary label: this token cannot start an expression // optional help: Expressions can start with literals, identifiers, \(`, `{`, or expression keywords.` ExpressionExpected, // headline: invalid type argument in \class<...>`` // primary label on the bad token inside the angle brackets: expected a qualified type name here // secondary label on class or <: while parsing this class type expression // note: Only a type name is accepted between \<` and `>` here.` ClassTypeInvalidTypeArgument { left_angle_bracket_position: TokenPosition, }, // headline: too many arguments in \new(...)`` // primary label on the fourth argument, or on the comma before it if that is easier: unexpected extra argument // secondary label on the opening (: this argument list accepts at most three arguments // note: The three slots are \outer`, `name`, and `flags`.` // help: Remove the extra argument. NewTooManyArguments { left_parenthesis_position: TokenPosition, }, // headline: missing closing \)' in `new(...)`` // primary label: expected \)' here` // secondary label on the opening (: this argument list starts here // help: Add \)' to close the argument list.` NewMissingClosingParenthesis { left_parenthesis_position: TokenPosition, }, // missing class specifier in \new` expression` // Primary label on the first token where a class specifier should have started: expected a class specifier here // Secondary label on new: \new` expression starts here` If there was an argument list, an additional secondary on ( is also reasonable: optional \new(...)` arguments end here` // Help: Add the class or expression to instantiate after \new` or `new(...)`.` NewMissingClassSpecifier { new_keyword_position: TokenPosition, }, // ================== Old errors to be thrown away! ================== /// Expression inside `(...)` could not be parsed and no closing `)` /// was found. FunctionCallMissingClosingParenthesis, /// A `do` block was not followed by a matching `until`. DoMissingUntil, /// Found an unexpected token while parsing an expression. ExpressionUnexpectedToken, DeclEmptyVariableDeclarations, DeclNoSeparatorBetweenVariableDeclarations, DeclExpectedRightBracketAfterArraySize, DeclExpectedCommaAfterVariableDeclarator, TypeSpecExpectedType, TypeSpecInvalidNamedTypeName, TypeSpecArrayMissingOpeningAngle, TypeSpecArrayMissingInnerType, TypeSpecArrayMissingClosingAngle, TypeSpecClassMissingInnerType, TypeSpecClassMissingClosingAngle, /// A `for` loop is missing its opening `(`. ForMissingOpeningParenthesis, /// The first `;` in `for (init; cond; step)` is missing. ForMissingInitializationSemicolon, /// The second `;` in `for (init; cond; step)` is missing. ForMissingConditionSemicolon, /// The closing `)` of a `for` loop is missing. ForMissingClosingParenthesis, /// An expression inside a block is not terminated with `;`. BlockMissingSemicolonAfterExpression, /// A statement inside a block is not terminated with `;`. BlockMissingSemicolonAfterStatement, BlockMissingClosingBrace, /// `switch` has no body (missing matching braces). SwitchMissingBody, /// The first top-level item in a `switch` body is not a `case`. SwitchTopLevelItemNotCase, /// A `case` arm is missing the trailing `:`. SwitchCaseMissingColon, /// Found more than one `default` branch. SwitchDuplicateDefault, /// Found `case` arms after a `default` branch. SwitchCasesAfterDefault, SwitchMissingClosingBrace, /// A `goto` was not followed by a label. GotoMissingLabel, /// Unexpected end of input while parsing. UnexpectedEndOfFile, /// Token looked like a numeric literal but could not be parsed as one. InvalidNumericLiteral, /// A bare expression appeared in a `switch` arm but was not the final arm. /// /// Such an expression must be terminated with `;` or be the final arm. SwitchBareExpressionBeforeNextArm, /// A `local` declaration is missing its first identifier. /// /// At least one variable name must follow the type. LocalMissingIdentifier, /// A `local` declaration was followed by a token that cannot serve /// as a type name. LocalInvalidTypeName, /// Invalid variable name identifier in `local` variable definition. LocalBadVariableIdentifier, /// An initializer appears in a `local` variable declaration. LocalInitializerNotAllowed, /// A non-`local` variable declaration is missing its first identifier. /// /// At least one variable name must follow the type. DeclMissingIdentifier, /// Invalid variable name identifier in non-`local` variable definition. DeclBadVariableIdentifier, /// Found an unexpected token while parsing a declaration literal. /// /// Expected one of: integer, float, string, `true`, `false`, `none` /// or an identifier. DeclarationLiteralUnexpectedToken, /// A class name was expected, but the current token is not an identifier. /// /// Emitted when parsing `class Foo` and the token after `class` is not an /// identifier (so its string value cannot be extracted). ClassNameNotIdentifier, /// A parent class name after `extends` was expected, but the token is not /// an identifier. /// /// Emitted when parsing `class Foo extends Bar` and the token after /// `extends` is not an identifier. ClassParentNameNotIdentifier, /// A class declaration was not terminated with `;`. /// /// Emitted when the parser reaches the end of a class definition but /// does not encounter the required semicolon. ClassMissingSemicolon, /// An identifier was expected inside optional parentheses, but the token /// is not an identifier. /// /// Emitted by helpers that parse either `()` or bare ``. ParenthesisedIdentifierNameNotIdentifier, /// A `(` was seen before an identifier, but the matching `)` was not found. /// /// Emitted when parsing a parenthesised identifier like `(Foo)`. ParenthesisedIdentifierMissingClosingParenthesis, /// `HideCategories` is missing the opening `(` before the category list. /// /// Expected syntax: `HideCategories(CategoryA, CategoryB, ...)`. HideCategoriesMissingOpeningParenthesis, /// `HideCategories` is missing the closing `)` after the category list. HideCategoriesMissingClosingParenthesis, /// `HideCategories` is missing the opening `(` before the category list. /// /// Expected syntax: `HideCategories(CategoryA, CategoryB, ...)`. ShowCategoriesMissingOpeningParenthesis, /// `HideCategories` is missing the closing `)` after the category list. ShowCategoriesMissingClosingParenthesis, /// `Within` must be followed by a class or package name identifier. /// /// Example: `Within(MyOuterClass)`. WithinNameNotIdentifier, /// `operator` modifier is missing the opening `(` before /// the precedence rank. /// /// Expected syntax: `operator()`. OperatorMissingOpeningParenthesis, /// `operator(<...>)` must contain an integer literal precedence rank. /// /// Emitted when the token inside parentheses is not an integer literal. OperatorPrecedenceNotIntegerLiteral, /// `operator(` is missing the closing `)`. OperatorMissingClosingParenthesis, ParamInvalidTypeName, ParamMissingIdentifier, FunctionReturnTypeNotTypeName, FunctionNameNotIdentifier, FunctionParamsMissingOpeningParenthesis, FunctionParamsMissingClosingParenthesis, ClassUnexpectedItem, EnumMissingLeftBrace, EnumBadVariant, StructFieldMissingName, StructFieldMissingSemicolon, StructMissingRightBrace, // Named enum/struct typedefs EnumMissingKeyword, // class member: expected `enum` EnumExpectedNameOrBrace, // after `enum`, expected identifier EnumNoClosingBrace, EnumEmptyVariants, EnumNoSeparatorBetweenVariants, EnumMissingLBrace, StructMissingKeyword, // class member: expected `struct` StructExpectedNameOrBrace, // after `struct`, expected identifier StructExpectedExtendsOrBrace, StructMissingLeftBrace, StructExpectedBaseName, StructBodyUnexpectedItem, CppDirectiveMissingCppBlock, // var(...) field decls VarMissingKeyword, // class member: expected `var` VarSpecsMissingOpeningParenthesis, // after `var`, expected '(' VarSpecNotIdentifier, // inside var(...), expected identifier VarSpecsMissingClosingParenthesis, // var(...) missing ')' // Generic decl end DeclMissingSemicolon, // class-level declaration missing `;` // --- Replication --- ReplicationMissingReliability, ReplicationIfMissingOpeningParenthesis, ReplicationIfMissingClosingParenthesis, ReplicationMemberNotIdentifier, ReplicationMemberMissingClosingParenthesis, ReplicationRuleMissingSemicolon, ReplicationMissingKeyword, ReplicationMissingLBrace, ReplicationMissingRBrace, // --- DefaultProperties --- DefaultPropPathExpectedIdentifier, DefaultPropIndexNotIntegerLiteral, DefaultPropIndexMissingClosingParenthesis, DefaultPropAssignMissingEq, DefaultPropsMissingKeyword, DefaultPropsMissingLBrace, DefaultPropsMissingRBrace, // --- Begin/End Object headers --- ObjectBeginMissingKeyword, ObjectMissingKeyword, ObjectHeaderKeyNotIdentifier, ObjectHeaderMissingEq, // --- State / ignores --- IgnoresItemNotIdentifier, IgnoresMissingSemicolon, StateMissingKeyword, StateNameNotIdentifier, StateParentNameNotIdentifier, StateMissingLBrace, StateMissingRBrace, ClassMissingKeyword, TypeMissingLT, TypeMissingGT, StateParensMissingRParen, BadTypeInClassTypeDeclaration, IdentifierExpected, // --- Generic list diagnostics (comma-separated, closed by `)`) --- /// Saw `)` immediately after `(`, or closed the list without any items. /// Use when a construct requires at least one item: e.g. `HideCategories(...)`. ListEmpty, /// Parser was positioned where an item was required but found neither an /// item nor a terminator. Typical triggers: /// - Leading comma: `(, Foo)` /// - Double comma: `(Foo,, Bar)` /// - Garbage in place of an item: `(@@, Foo)` /// /// Recovery: skip to next comma or `)`. ListMissingIdentifierBeforeSeparator, /// Parser was positioned where an item was required but found neither an /// item nor a terminator. Typical triggers: /// - Leading comma: `(, Foo)` /// - Double comma: `(Foo,, Bar)` /// - Garbage in place of an item: `(@@, Foo)` /// /// Recovery: skip to next comma or `)`. ListInvalidIdentifier, /// Two items without a comma (or some token after an item where a comma /// was required). Typical triggers: /// - Adjacent identifiers: `(Foo Bar)` /// - Token after an item where only `,` or `)` are valid. /// /// Recovery: behave as if a comma were present; continue with the next item. ListMissingSeparator, /// Comma directly before `)`: `(Foo, )`. /// Treat as a soft error or warning, depending on your policy. ListTrailingSeparator, FunctionArgumentMissingComma, // Expression was required, but none started MissingExpression, MissingBranchBody, CallableExpectedHeader, CallableExpectedKind, CallableOperatorInvalidPrecedence, CallableMissingBodyOrSemicolon, CallableNameNotIdentifier, CallablePrefixOperatorInvalidSymbol, CallableInfixOperatorInvalidSymbol, CallablePostfixOperatorInvalidSymbol, CallableParamsMissingOpeningParenthesis, CallableParamsMissingClosingParenthesis, NativeModifierIdNotIntegerLiteral, } /// Enumerates all specific kinds of parsing errors that the parser can emit. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] #[must_use] pub struct ParseError { /// The specific kind of parse error that occurred. pub kind: ParseErrorKind, pub anchor: TokenPosition, /// Where the user should look first. pub blame_span: AstSpan, /// The source span in which the error was detected. pub covered_span: AstSpan, pub related_span: Option, } pub type ParseResult<'src, 'arena, T> = Result; impl crate::parser::Parser<'_, '_> { pub(crate) fn make_error_here(&self, error_kind: ParseErrorKind) -> ParseError { self.make_error_at(error_kind, self.last_consumed_position_or_start()) } pub(crate) fn make_error_at( &self, error_kind: ParseErrorKind, position: TokenPosition, ) -> ParseError { ParseError { kind: error_kind, anchor: position, blame_span: AstSpan::new(position), covered_span: AstSpan::new(position), related_span: None, } } }