Huge dump of refactored code. Still in the middle of the changes that are to be squashed later in a one huge monster commit, because there is no value in anything atomic here.
371 lines
15 KiB
Rust
371 lines
15 KiB
Rust
//! 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<Pawn>`.`
|
|
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 `(<Ident>)` or bare `<Ident>`.
|
|
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(<integer>)`.
|
|
OperatorMissingOpeningParenthesis,
|
|
/// `operator(<...>)` must contain an integer literal precedence rank.
|
|
///
|
|
/// Emitted when the token inside parentheses is not an integer literal.
|
|
OperatorPrecedenceNotIntegerLiteral,
|
|
/// `operator(<integer>` 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<AstSpan>,
|
|
}
|
|
|
|
pub type ParseResult<'src, 'arena, T> = Result<T, ParseError>;
|
|
|
|
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,
|
|
}
|
|
}
|
|
}
|