From da9e80e8ff1e646f41460fbb45ae2cbfb3768687 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Sun, 3 Sep 2023 21:27:43 -0400 Subject: [PATCH] Extract error messages into diagnostic.c and use canonical message IDs The parser now passes around `yp_diagnostic_id_t` for diagnostic messages instead of character strings, and we rely on the function `diagnostic_message()` to resolve that to a string. In addition, many messages were edited so that the parser expresses coordinate ideas in similar form [1] using consistent voice and typographic conventions. Closes #1379, and makes progress on #941. [1] Strunk & White rule 19 --- include/yarp/diagnostic.h | 199 ++++++++- rust/yarp-sys/tests/parser_tests.rs | 2 +- src/diagnostic.c | 256 +++++++++++- src/unescape.c | 40 +- src/yarp.c | 608 ++++++++++++++-------------- test/yarp/errors_test.rb | 216 +++++----- 6 files changed, 886 insertions(+), 435 deletions(-) diff --git a/include/yarp/diagnostic.h b/include/yarp/diagnostic.h index 58228d8493a..fd17945e0d9 100644 --- a/include/yarp/diagnostic.h +++ b/include/yarp/diagnostic.h @@ -6,6 +6,7 @@ #include #include +#include // This struct represents a diagnostic found during parsing. typedef struct { @@ -15,8 +16,204 @@ typedef struct { const char *message; } yp_diagnostic_t; +typedef enum { + YP_ERR_ALIAS_ARGUMENT, + YP_ERR_AMPAMPEQ_MULTI_ASSIGN, + YP_ERR_ARGUMENT_AFTER_BLOCK, + YP_ERR_ARGUMENT_BARE_HASH, + YP_ERR_ARGUMENT_BLOCK_MULTI, + YP_ERR_ARGUMENT_FORMAL_CLASS, + YP_ERR_ARGUMENT_FORMAL_CONSTANT, + YP_ERR_ARGUMENT_FORMAL_GLOBAL, + YP_ERR_ARGUMENT_FORMAL_IVAR, + YP_ERR_ARGUMENT_NO_FORWARDING_AMP, + YP_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES, + YP_ERR_ARGUMENT_NO_FORWARDING_STAR, + YP_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT, + YP_ERR_ARGUMENT_SPLAT_AFTER_SPLAT, + YP_ERR_ARGUMENT_TERM_PAREN, + YP_ERR_ARRAY_ELEMENT, + YP_ERR_ARRAY_EXPRESSION, + YP_ERR_ARRAY_EXPRESSION_AFTER_STAR, + YP_ERR_ARRAY_SEPARATOR, + YP_ERR_ARRAY_TERM, + YP_ERR_BEGIN_LONELY_ELSE, + YP_ERR_BEGIN_TERM, + YP_ERR_BEGIN_UPCASE_BRACE, + YP_ERR_BEGIN_UPCASE_TERM, + YP_ERR_BLOCK_PARAM_LOCAL_VARIABLE, + YP_ERR_BLOCK_PARAM_PIPE_TERM, + YP_ERR_BLOCK_TERM_BRACE, + YP_ERR_BLOCK_TERM_END, + YP_ERR_CANNOT_PARSE_EXPRESSION, + YP_ERR_CANNOT_PARSE_STRING_PART, + YP_ERR_CASE_EXPRESSION_AFTER_CASE, + YP_ERR_CASE_EXPRESSION_AFTER_WHEN, + YP_ERR_CASE_LONELY_ELSE, + YP_ERR_CASE_TERM, + YP_ERR_CLASS_IN_METHOD, + YP_ERR_CLASS_NAME, + YP_ERR_CLASS_SUPERCLASS, + YP_ERR_CLASS_TERM, + YP_ERR_CONDITIONAL_ELSIF_PREDICATE, + YP_ERR_CONDITIONAL_IF_PREDICATE, + YP_ERR_CONDITIONAL_TERM, + YP_ERR_CONDITIONAL_TERM_ELSE, + YP_ERR_CONDITIONAL_UNLESS_PREDICATE, + YP_ERR_CONDITIONAL_UNTIL_PREDICATE, + YP_ERR_CONDITIONAL_WHILE_PREDICATE, + YP_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT, + YP_ERR_DEF_ENDLESS, + YP_ERR_DEF_ENDLESS_SETTER, + YP_ERR_DEF_NAME, + YP_ERR_DEF_NAME_AFTER_RECEIVER, + YP_ERR_DEF_PARAMS_TERM, + YP_ERR_DEF_PARAMS_TERM_PAREN, + YP_ERR_DEF_RECEIVER, + YP_ERR_DEF_RECEIVER_TERM, + YP_ERR_DEF_TERM, + YP_ERR_DEFINED_EXPRESSION, + YP_ERR_EMBDOC_TERM, + YP_ERR_EMBEXPR_END, + YP_ERR_EMBVAR_INVALID, + YP_ERR_END_UPCASE_BRACE, + YP_ERR_END_UPCASE_TERM, + YP_ERR_ESCAPE_INVALID_CONTROL, + YP_ERR_ESCAPE_INVALID_CONTROL_REPEAT, + YP_ERR_ESCAPE_INVALID_HEXADECIMAL, + YP_ERR_ESCAPE_INVALID_META, + YP_ERR_ESCAPE_INVALID_META_REPEAT, + YP_ERR_ESCAPE_INVALID_UNICODE, + YP_ERR_ESCAPE_INVALID_UNICODE_CM_FLAGS, + YP_ERR_ESCAPE_INVALID_UNICODE_LITERAL, + YP_ERR_ESCAPE_INVALID_UNICODE_LONG, + YP_ERR_ESCAPE_INVALID_UNICODE_TERM, + YP_ERR_EXPECT_ARGUMENT, + YP_ERR_EXPECT_EOL_AFTER_STATEMENT, + YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, + YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, + YP_ERR_EXPECT_EXPRESSION_AFTER_COMMA, + YP_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, + YP_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS, + YP_ERR_EXPECT_EXPRESSION_AFTER_LPAREN, + YP_ERR_EXPECT_EXPRESSION_AFTER_QUESTION, + YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, + YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, + YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, + YP_ERR_EXPECT_EXPRESSION_AFTER_STAR, + YP_ERR_EXPECT_IDENT_REQ_PARAMETER, + YP_ERR_EXPECT_LPAREN_REQ_PARAMETER, + YP_ERR_EXPECT_RBRACKET, + YP_ERR_EXPECT_RPAREN, + YP_ERR_EXPECT_RPAREN_AFTER_MULTI, + YP_ERR_EXPECT_RPAREN_REQ_PARAMETER, + YP_ERR_EXPECT_STRING_CONTENT, + YP_ERR_EXPECT_WHEN_DELIMITER, + YP_ERR_EXPRESSION_BARE_HASH, + YP_ERR_FOR_COLLECTION, + YP_ERR_FOR_IN, + YP_ERR_FOR_INDEX, + YP_ERR_FOR_TERM, + YP_ERR_HASH_EXPRESSION_AFTER_LABEL, + YP_ERR_HASH_KEY, + YP_ERR_HASH_ROCKET, + YP_ERR_HASH_TERM, + YP_ERR_HASH_VALUE, + YP_ERR_HEREDOC_TERM, + YP_ERR_INCOMPLETE_QUESTION_MARK, + YP_ERR_INCOMPLETE_VARIABLE_CLASS, + YP_ERR_INCOMPLETE_VARIABLE_INSTANCE, + YP_ERR_INVALID_ENCODING_MAGIC_COMMENT, + YP_ERR_INVALID_FLOAT_EXPONENT, + YP_ERR_INVALID_NUMBER_BINARY, + YP_ERR_INVALID_NUMBER_DECIMAL, + YP_ERR_INVALID_NUMBER_HEXADECIMAL, + YP_ERR_INVALID_NUMBER_OCTAL, + YP_ERR_INVALID_PERCENT, + YP_ERR_INVALID_TOKEN, + YP_ERR_INVALID_VARIABLE_GLOBAL, + YP_ERR_LAMBDA_OPEN, + YP_ERR_LAMBDA_TERM_BRACE, + YP_ERR_LAMBDA_TERM_END, + YP_ERR_LIST_I_LOWER_ELEMENT, + YP_ERR_LIST_I_LOWER_TERM, + YP_ERR_LIST_I_UPPER_ELEMENT, + YP_ERR_LIST_I_UPPER_TERM, + YP_ERR_LIST_W_LOWER_ELEMENT, + YP_ERR_LIST_W_LOWER_TERM, + YP_ERR_LIST_W_UPPER_ELEMENT, + YP_ERR_LIST_W_UPPER_TERM, + YP_ERR_MALLOC_FAILED, + YP_ERR_MODULE_IN_METHOD, + YP_ERR_MODULE_NAME, + YP_ERR_MODULE_TERM, + YP_ERR_MULTI_ASSIGN_MULTI_SPLATS, + YP_ERR_NOT_EXPRESSION, + YP_ERR_NUMBER_LITERAL_UNDERSCORE, + YP_ERR_OPERATOR_MULTI_ASSIGN, + YP_ERR_PARAMETER_ASSOC_SPLAT_MULTI, + YP_ERR_PARAMETER_BLOCK_MULTI, + YP_ERR_PARAMETER_NAME_REPEAT, + YP_ERR_PARAMETER_NO_DEFAULT, + YP_ERR_PARAMETER_NO_DEFAULT_KW, + YP_ERR_PARAMETER_NUMBERED_RESERVED, + YP_ERR_PARAMETER_ORDER, + YP_ERR_PARAMETER_SPLAT_MULTI, + YP_ERR_PARAMETER_STAR, + YP_ERR_PARAMETER_WILD_LOOSE_COMMA, + YP_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, + YP_ERR_PATTERN_EXPRESSION_AFTER_HROCKET, + YP_ERR_PATTERN_EXPRESSION_AFTER_COMMA, + YP_ERR_PATTERN_EXPRESSION_AFTER_IN, + YP_ERR_PATTERN_EXPRESSION_AFTER_KEY, + YP_ERR_PATTERN_EXPRESSION_AFTER_PAREN, + YP_ERR_PATTERN_EXPRESSION_AFTER_PIN, + YP_ERR_PATTERN_EXPRESSION_AFTER_PIPE, + YP_ERR_PATTERN_EXPRESSION_AFTER_RANGE, + YP_ERR_PATTERN_HASH_KEY, + YP_ERR_PATTERN_HASH_KEY_LABEL, + YP_ERR_PATTERN_IDENT_AFTER_HROCKET, + YP_ERR_PATTERN_LABEL_AFTER_COMMA, + YP_ERR_PATTERN_REST, + YP_ERR_PATTERN_TERM_BRACE, + YP_ERR_PATTERN_TERM_BRACKET, + YP_ERR_PATTERN_TERM_PAREN, + YP_ERR_PIPEPIPEEQ_MULTI_ASSIGN, + YP_ERR_REGEXP_TERM, + YP_ERR_RESCUE_EXPRESSION, + YP_ERR_RESCUE_MODIFIER_VALUE, + YP_ERR_RESCUE_TERM, + YP_ERR_RESCUE_VARIABLE, + YP_ERR_RETURN_INVALID, + YP_ERR_STRING_CONCATENATION, + YP_ERR_STRING_INTERPOLATED_TERM, + YP_ERR_STRING_LITERAL_TERM, + YP_ERR_SYMBOL_INVALID, + YP_ERR_SYMBOL_TERM_DYNAMIC, + YP_ERR_SYMBOL_TERM_INTERPOLATED, + YP_ERR_TERNARY_COLON, + YP_ERR_TERNARY_EXPRESSION_FALSE, + YP_ERR_TERNARY_EXPRESSION_TRUE, + YP_ERR_UNDEF_ARGUMENT, + YP_ERR_UNARY_RECEIVER_BANG, + YP_ERR_UNARY_RECEIVER_MINUS, + YP_ERR_UNARY_RECEIVER_PLUS, + YP_ERR_UNARY_RECEIVER_TILDE, + YP_ERR_UNTIL_TERM, + YP_ERR_WHILE_TERM, + YP_ERR_WRITE_TARGET_READONLY, + YP_ERR_WRITE_TARGET_UNEXPECTED, + YP_ERR_XSTRING_TERM, + YP_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS, + YP_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS, + YP_WARN_AMBIGUOUS_PREFIX_STAR, + YP_WARN_AMBIGUOUS_SLASH, + /* This must be the last member. */ + YP_DIAGNOSTIC_ID_LEN, +} yp_diagnostic_id_t; + // Append a diagnostic to the given list of diagnostics. -bool yp_diagnostic_list_append(yp_list_t *list, const uint8_t *start, const uint8_t *end, const char *message); +bool yp_diagnostic_list_append(yp_list_t *list, const uint8_t *start, const uint8_t *end, yp_diagnostic_id_t diag_id); // Deallocate the internal state of the given diagnostic list. void yp_diagnostic_list_free(yp_list_t *list); diff --git a/rust/yarp-sys/tests/parser_tests.rs b/rust/yarp-sys/tests/parser_tests.rs index 98d79ec5af6..7e0246e4396 100644 --- a/rust/yarp-sys/tests/parser_tests.rs +++ b/rust/yarp-sys/tests/parser_tests.rs @@ -86,7 +86,7 @@ fn diagnostics_test() { let message = CStr::from_ptr((*error).message); assert_eq!( message.to_string_lossy(), - "Expected to be able to parse an expression." + "Cannot parse the expression" ); let location = { diff --git a/src/diagnostic.c b/src/diagnostic.c index b216d96a330..e92a1ee4910 100644 --- a/src/diagnostic.c +++ b/src/diagnostic.c @@ -1,12 +1,264 @@ #include "yarp/diagnostic.h" +/* + ## Message composition + + When composing an error message, use sentence fragments. + + Try describing the property of the code that caused the error, rather than the rule that is being + violated. It may help to use a fragment that completes a sentence beginning, "The parser + encountered (a) ...". If appropriate, add a description of the rule violation (or other helpful + context) after a semicolon. + + For example:, instead of "Control escape sequence cannot be doubled", prefer: + + > "Invalid control escape sequence; control cannot be repeated" + + In some cases, where the failure is more general or syntax expectations are violated, it may make + more sense to use a fragment that completes a sentence beginning, "The parser ...". + + For example: + + > "Expected an expression after `(`" + > "Cannot parse the expression" + + + ## Message style guide + + - Use articles like "a", "an", and "the" when appropriate. + - e.g., prefer "Cannot parse the expression" to "Cannot parse expression". + - Use the common name for tokens and nodes. + - e.g., prefer "keyword splat" to "assoc splat" + - e.g., prefer "embedded document" to "embdoc" + - Capitalize the initial word of the message. + - Use back ticks around token literals + - e.g., "Expected a `=>` between the hash key and value" + - Do not use `.` or other punctuation at the end of the message. + - Do not use contractions like "can't". Prefer "cannot" to "can not". + - For tokens that can have multiple meanings, reference the token and its meaning. + - e.g., "`*` splat argument" is clearer and more complete than "splat argument" or "`*` argument" + + + ## Error names (YP_ERR_*) + + - When appropriate, prefer node name to token name. + - e.g., prefer "SPLAT" to "STAR" in the context of argument parsing. + - Prefer token name to common name. + - e.g., prefer "STAR" to "ASTERISK". + - Try to order the words in the name from more general to more specific, + - e.g., "INVALID_NUMBER_DECIMAL" is better than "DECIMAL_INVALID_NUMBER". + - When in doubt, look for similar patterns and name them so that they are grouped when lexically + sorted. See YP_ERR_ARGUMENT_NO_FORWARDING_* for an example. +*/ + +static const char* const diagnostic_messages[YP_DIAGNOSTIC_ID_LEN] = { + [YP_ERR_ALIAS_ARGUMENT] = "Invalid argument being passed to `alias`; expected a bare word, symbol, constant, or global variable", + [YP_ERR_AMPAMPEQ_MULTI_ASSIGN] = "Unexpected `&&=` in a multiple assignment", + [YP_ERR_ARGUMENT_AFTER_BLOCK] = "Unexpected argument after a block argument", + [YP_ERR_ARGUMENT_BARE_HASH] = "Unexpected bare hash argument", + [YP_ERR_ARGUMENT_BLOCK_MULTI] = "Multiple block arguments; only one block is allowed", + [YP_ERR_ARGUMENT_FORMAL_CLASS] = "Invalid formal argument; formal argument cannot be a class variable", + [YP_ERR_ARGUMENT_FORMAL_CONSTANT] = "Invalid formal argument; formal argument cannot be a constant", + [YP_ERR_ARGUMENT_FORMAL_GLOBAL] = "Invalid formal argument; formal argument cannot be a global variable", + [YP_ERR_ARGUMENT_FORMAL_IVAR] = "Invalid formal argument; formal argument cannot be an instance variable", + [YP_ERR_ARGUMENT_NO_FORWARDING_AMP] = "Unexpected `&` when the parent method is not forwarding", + [YP_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES] = "Unexpected `...` when the parent method is not forwarding", + [YP_ERR_ARGUMENT_NO_FORWARDING_STAR] = "Unexpected `*` when the parent method is not forwarding", + [YP_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT] = "Unexpected `*` splat argument after a `**` keyword splat argument", + [YP_ERR_ARGUMENT_SPLAT_AFTER_SPLAT] = "Unexpected `*` splat argument after a `*` splat argument", + [YP_ERR_ARGUMENT_TERM_PAREN] = "Expected a `)` to close the arguments", + [YP_ERR_ARRAY_ELEMENT] = "Expected an element for the array", + [YP_ERR_ARRAY_EXPRESSION] = "Expected an expression for the array element", + [YP_ERR_ARRAY_EXPRESSION_AFTER_STAR] = "Expected an expression after `*` in the array", + [YP_ERR_ARRAY_SEPARATOR] = "Expected a `,` separator for the array elements", + [YP_ERR_ARRAY_TERM] = "Expected a `]` to close the array", + [YP_ERR_BEGIN_LONELY_ELSE] = "Unexpected `else` in `begin` block; a `rescue` clause must precede `else`", + [YP_ERR_BEGIN_TERM] = "Expected an `end` to close the `begin` statement", + [YP_ERR_BEGIN_UPCASE_BRACE] = "Expected a `{` after `BEGIN`", + [YP_ERR_BEGIN_UPCASE_TERM] = "Expected a `}` to close the `BEGIN` statement", + [YP_ERR_BLOCK_PARAM_LOCAL_VARIABLE] = "Expected a local variable name in the block parameters", + [YP_ERR_BLOCK_PARAM_PIPE_TERM] = "Expected the block parameters to end with `|`", + [YP_ERR_BLOCK_TERM_BRACE] = "Expected a block beginning with `{` to end with `}`", + [YP_ERR_BLOCK_TERM_END] = "Expected a block beginning with `do` to end with `end`", + [YP_ERR_CANNOT_PARSE_EXPRESSION] = "Cannot parse the expression", + [YP_ERR_CANNOT_PARSE_STRING_PART] = "Cannot parse the string part", + [YP_ERR_CASE_EXPRESSION_AFTER_CASE] = "Expected an expression after `case`", + [YP_ERR_CASE_EXPRESSION_AFTER_WHEN] = "Expected an expression after `when`", + [YP_ERR_CASE_LONELY_ELSE] = "Unexpected `else` in `case` statement; a `when` clause must precede `else`", + [YP_ERR_CASE_TERM] = "Expected an `end` to close the `case` statement", + [YP_ERR_CLASS_IN_METHOD] = "Unexpected class definition in a method body", + [YP_ERR_CLASS_NAME] = "Expected a constant name after `class`", + [YP_ERR_CLASS_SUPERCLASS] = "Expected a superclass after `<`", + [YP_ERR_CLASS_TERM] = "Expected an `end` to close the `class` statement", + [YP_ERR_CONDITIONAL_ELSIF_PREDICATE] = "Expected a predicate expression for the `elsif` statement", + [YP_ERR_CONDITIONAL_IF_PREDICATE] = "Expected a predicate expression for the `if` statement", + [YP_ERR_CONDITIONAL_TERM] = "Expected an `end` to close the conditional clause", + [YP_ERR_CONDITIONAL_TERM_ELSE] = "Expected an `end` to close the `else` clause", + [YP_ERR_CONDITIONAL_UNLESS_PREDICATE] = "Expected a predicate expression for the `unless` statement", + [YP_ERR_CONDITIONAL_UNTIL_PREDICATE] = "Expected a predicate expression for the `until` statement", + [YP_ERR_CONDITIONAL_WHILE_PREDICATE] = "Expected a predicate expression for the `while` statement", + [YP_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT] = "Expected a constant after the `::` operator", + [YP_ERR_DEF_ENDLESS] = "Could not parse the endless method body", + [YP_ERR_DEF_ENDLESS_SETTER] = "Invalid method name; a setter method cannot be defined in an endless method definition", + [YP_ERR_DEF_NAME] = "Expected a method name", + [YP_ERR_DEF_NAME_AFTER_RECEIVER] = "Expected a method name after the receiver", + [YP_ERR_DEF_PARAMS_TERM] = "Expected a delimiter to close the parameters", + [YP_ERR_DEF_PARAMS_TERM_PAREN] = "Expected a `)` to close the parameters", + [YP_ERR_DEF_RECEIVER] = "Expected a receiver for the method definition", + [YP_ERR_DEF_RECEIVER_TERM] = "Expected a `.` or `::` after the receiver in a method definition", + [YP_ERR_DEF_TERM] = "Expected an `end` to close the `def` statement", + [YP_ERR_DEFINED_EXPRESSION] = "Expected an expression after `defined?`", + [YP_ERR_EMBDOC_TERM] = "Could not find a terminator for the embedded document", + [YP_ERR_EMBEXPR_END] = "Expected a `}` to close the embedded expression", + [YP_ERR_EMBVAR_INVALID] = "Invalid embedded variable", + [YP_ERR_END_UPCASE_BRACE] = "Expected a `{` after `END`", + [YP_ERR_END_UPCASE_TERM] = "Expected a `}` to close the `END` statement", + [YP_ERR_ESCAPE_INVALID_CONTROL] = "Invalid control escape sequence", + [YP_ERR_ESCAPE_INVALID_CONTROL_REPEAT] = "Invalid control escape sequence; control cannot be repeated", + [YP_ERR_ESCAPE_INVALID_HEXADECIMAL] = "Invalid hexadecimal escape sequence", + [YP_ERR_ESCAPE_INVALID_META] = "Invalid meta escape sequence", + [YP_ERR_ESCAPE_INVALID_META_REPEAT] = "Invalid meta escape sequence; meta cannot be repeated", + [YP_ERR_ESCAPE_INVALID_UNICODE] = "Invalid Unicode escape sequence", + [YP_ERR_ESCAPE_INVALID_UNICODE_CM_FLAGS] = "Invalid Unicode escape sequence; Unicode cannot be combined with control or meta flags", + [YP_ERR_ESCAPE_INVALID_UNICODE_LITERAL] = "Invalid Unicode escape sequence; multiple codepoints are not allowed in a character literal", + [YP_ERR_ESCAPE_INVALID_UNICODE_LONG] = "Invalid Unicode escape sequence; maximum length is 6 digits", + [YP_ERR_ESCAPE_INVALID_UNICODE_TERM] = "Invalid Unicode escape sequence; needs closing `}`", + [YP_ERR_EXPECT_ARGUMENT] = "Expected an argument", + [YP_ERR_EXPECT_EOL_AFTER_STATEMENT] = "Expected a newline or semicolon after the statement", + [YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ] = "Expected an expression after `&&=`", + [YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ] = "Expected an expression after `||=`", + [YP_ERR_EXPECT_EXPRESSION_AFTER_COMMA] = "Expected an expression after `,`", + [YP_ERR_EXPECT_EXPRESSION_AFTER_EQUAL] = "Expected an expression after `=`", + [YP_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS] = "Expected an expression after `<<`", + [YP_ERR_EXPECT_EXPRESSION_AFTER_LPAREN] = "Expected an expression after `(`", + [YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR] = "Expected an expression after the operator", + [YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT] = "Expected an expression after `*` splat in an argument", + [YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH] = "Expected an expression after `**` in a hash", + [YP_ERR_EXPECT_EXPRESSION_AFTER_STAR] = "Expected an expression after `*`", + [YP_ERR_EXPECT_IDENT_REQ_PARAMETER] = "Expected an identifier for the required parameter", + [YP_ERR_EXPECT_LPAREN_REQ_PARAMETER] = "Expected a `(` to start a required parameter", + [YP_ERR_EXPECT_RBRACKET] = "Expected a matching `]`", + [YP_ERR_EXPECT_RPAREN] = "Expected a matching `)`", + [YP_ERR_EXPECT_RPAREN_AFTER_MULTI] = "Expected a `)` after multiple assignment", + [YP_ERR_EXPECT_RPAREN_REQ_PARAMETER] = "Expected a `)` to end a required parameter", + [YP_ERR_EXPECT_STRING_CONTENT] = "Expected string content after opening string delimiter", + [YP_ERR_EXPECT_WHEN_DELIMITER] = "Expected a delimiter after the predicates of a `when` clause", + [YP_ERR_EXPRESSION_BARE_HASH] = "Unexpected bare hash in expression", + [YP_ERR_FOR_COLLECTION] = "Expected a collection after the `in` in a `for` statement", + [YP_ERR_FOR_INDEX] = "Expected an index after `for`", + [YP_ERR_FOR_IN] = "Expected an `in` after the index in a `for` statement", + [YP_ERR_FOR_TERM] = "Expected an `end` to close the `for` loop", + [YP_ERR_HASH_EXPRESSION_AFTER_LABEL] = "Expected an expression after the label in a hash", + [YP_ERR_HASH_KEY] = "Expected a key in the hash literal", + [YP_ERR_HASH_ROCKET] = "Expected a `=>` between the hash key and value", + [YP_ERR_HASH_TERM] = "Expected a `}` to close the hash literal", + [YP_ERR_HASH_VALUE] = "Expected a value in the hash literal", + [YP_ERR_HEREDOC_TERM] = "Could not find a terminator for the heredoc", + [YP_ERR_INCOMPLETE_QUESTION_MARK] = "Incomplete expression at `?`", + [YP_ERR_INCOMPLETE_VARIABLE_CLASS] = "Incomplete class variable", + [YP_ERR_INCOMPLETE_VARIABLE_INSTANCE] = "Incomplete instance variable", + [YP_ERR_INVALID_ENCODING_MAGIC_COMMENT] = "Unknown or invalid encoding in the magic comment", + [YP_ERR_INVALID_FLOAT_EXPONENT] = "Invalid exponent", + [YP_ERR_INVALID_NUMBER_BINARY] = "Invalid binary number", + [YP_ERR_INVALID_NUMBER_DECIMAL] = "Invalid decimal number", + [YP_ERR_INVALID_NUMBER_HEXADECIMAL] = "Invalid hexadecimal number", + [YP_ERR_INVALID_NUMBER_OCTAL] = "Invalid octal number", + [YP_ERR_INVALID_PERCENT] = "Invalid `%` token", // TODO WHAT? + [YP_ERR_INVALID_TOKEN] = "Invalid token", // TODO WHAT? + [YP_ERR_INVALID_VARIABLE_GLOBAL] = "Invalid global variable", + [YP_ERR_LAMBDA_OPEN] = "Expected a `do` keyword or a `{` to open the lambda block", + [YP_ERR_LAMBDA_TERM_BRACE] = "Expected a lambda block beginning with `{` to end with `}`", + [YP_ERR_LAMBDA_TERM_END] = "Expected a lambda block beginning with `do` to end with `end`", + [YP_ERR_LIST_I_LOWER_ELEMENT] = "Expected a symbol in a `%i` list", + [YP_ERR_LIST_I_LOWER_TERM] = "Expected a closing delimiter for the `%i` list", + [YP_ERR_LIST_I_UPPER_ELEMENT] = "Expected a symbol in a `%I` list", + [YP_ERR_LIST_I_UPPER_TERM] = "Expected a closing delimiter for the `%I` list", + [YP_ERR_LIST_W_LOWER_ELEMENT] = "Expected a string in a `%w` list", + [YP_ERR_LIST_W_LOWER_TERM] = "Expected a closing delimiter for the `%w` list", + [YP_ERR_LIST_W_UPPER_ELEMENT] = "Expected a string in a `%W` list", + [YP_ERR_LIST_W_UPPER_TERM] = "Expected a closing delimiter for the `%W` list", + [YP_ERR_MALLOC_FAILED] = "Failed to allocate memory", + [YP_ERR_MODULE_IN_METHOD] = "Unexpected module definition in a method body", + [YP_ERR_MODULE_NAME] = "Expected a constant name after `module`", + [YP_ERR_MODULE_TERM] = "Expected an `end` to close the `module` statement", + [YP_ERR_MULTI_ASSIGN_MULTI_SPLATS] = "Multiple splats in multiple assignment", + [YP_ERR_NOT_EXPRESSION] = "Expected an expression after `not`", + [YP_ERR_NUMBER_LITERAL_UNDERSCORE] = "Number literal ending with a `_`", + [YP_ERR_OPERATOR_MULTI_ASSIGN] = "Unexpected operator for a multiple assignment", + [YP_ERR_PARAMETER_ASSOC_SPLAT_MULTI] = "Unexpected multiple `**` splat parameters", + [YP_ERR_PARAMETER_BLOCK_MULTI] = "Multiple block parameters; only one block is allowed", + [YP_ERR_PARAMETER_NAME_REPEAT] = "Repeated parameter name", + [YP_ERR_PARAMETER_NO_DEFAULT] = "Expected a default value for the parameter", + [YP_ERR_PARAMETER_NO_DEFAULT_KW] = "Expected a default value for the keyword parameter", + [YP_ERR_PARAMETER_NUMBERED_RESERVED] = "Token reserved for a numbered parameter", + [YP_ERR_PARAMETER_ORDER] = "Unexpected parameter order", + [YP_ERR_PARAMETER_SPLAT_MULTI] = "Unexpected multiple `*` splat parameters", + [YP_ERR_PARAMETER_STAR] = "Unexpected parameter `*`", + [YP_ERR_PARAMETER_WILD_LOOSE_COMMA] = "Unexpected `,` in parameters", + [YP_ERR_PATTERN_EXPRESSION_AFTER_BRACKET] = "Expected a pattern expression after the `[` operator", + [YP_ERR_PATTERN_EXPRESSION_AFTER_COMMA] = "Expected a pattern expression after `,`", + [YP_ERR_PATTERN_EXPRESSION_AFTER_HROCKET] = "Expected a pattern expression after `=>`", + [YP_ERR_PATTERN_EXPRESSION_AFTER_IN] = "Expected a pattern expression after the `in` keyword", + [YP_ERR_PATTERN_EXPRESSION_AFTER_KEY] = "Expected a pattern expression after the key", + [YP_ERR_PATTERN_EXPRESSION_AFTER_PAREN] = "Expected a pattern expression after the `(` operator", + [YP_ERR_PATTERN_EXPRESSION_AFTER_PIN] = "Expected a pattern expression after the `^` pin operator", + [YP_ERR_PATTERN_EXPRESSION_AFTER_PIPE] = "Expected a pattern expression after the `|` operator", + [YP_ERR_PATTERN_EXPRESSION_AFTER_RANGE] = "Expected a pattern expression after the range operator", + [YP_ERR_PATTERN_HASH_KEY] = "Expected a key in the hash pattern", + [YP_ERR_PATTERN_HASH_KEY_LABEL] = "Expected a label as the key in the hash pattern", // TODO // THIS // AND // ABOVE // IS WEIRD + [YP_ERR_PATTERN_IDENT_AFTER_HROCKET] = "Expected an identifier after the `=>` operator", + [YP_ERR_PATTERN_LABEL_AFTER_COMMA] = "Expected a label after the `,` in the hash pattern", + [YP_ERR_PATTERN_REST] = "Unexpected rest pattern", + [YP_ERR_PATTERN_TERM_BRACE] = "Expected a `}` to close the pattern expression", + [YP_ERR_PATTERN_TERM_BRACKET] = "Expected a `]` to close the pattern expression", + [YP_ERR_PATTERN_TERM_PAREN] = "Expected a `)` to close the pattern expression", + [YP_ERR_PIPEPIPEEQ_MULTI_ASSIGN] = "Unexpected `||=` in a multiple assignment", + [YP_ERR_REGEXP_TERM] = "Expected a closing delimiter for the regular expression", + [YP_ERR_RESCUE_EXPRESSION] = "Expected a rescued expression", + [YP_ERR_RESCUE_MODIFIER_VALUE] = "Expected a value after the `rescue` modifier", + [YP_ERR_RESCUE_TERM] = "Expected a closing delimiter for the `rescue` clause", + [YP_ERR_RESCUE_VARIABLE] = "Expected an exception variable after `=>` in a rescue statement", + [YP_ERR_RETURN_INVALID] = "Invalid `return` in a class or module body", + [YP_ERR_STRING_CONCATENATION] = "Expected a string for concatenation", + [YP_ERR_STRING_INTERPOLATED_TERM] = "Expected a closing delimiter for the interpolated string", + [YP_ERR_STRING_LITERAL_TERM] = "Expected a closing delimiter for the string literal", + [YP_ERR_SYMBOL_INVALID] = "Invalid symbol", // TODO expected symbol? yarp.c ~9719 + [YP_ERR_SYMBOL_TERM_DYNAMIC] = "Expected a closing delimiter for the dynamic symbol", + [YP_ERR_SYMBOL_TERM_INTERPOLATED] = "Expected a closing delimiter for the interpolated symbol", + [YP_ERR_TERNARY_COLON] = "Expected a `:` after the true expression of a ternary operator", + [YP_ERR_TERNARY_EXPRESSION_FALSE] = "Expected an expression after `:` in the ternary operator", + [YP_ERR_TERNARY_EXPRESSION_TRUE] = "Expected an expression after `?` in the ternary operator", + [YP_ERR_UNDEF_ARGUMENT] = "Invalid argument being passed to `undef`; expected a bare word, constant, or symbol argument", + [YP_ERR_UNARY_RECEIVER_BANG] = "Expected a receiver for unary `!`", + [YP_ERR_UNARY_RECEIVER_MINUS] = "Expected a receiver for unary `-`", + [YP_ERR_UNARY_RECEIVER_PLUS] = "Expected a receiver for unary `+`", + [YP_ERR_UNARY_RECEIVER_TILDE] = "Expected a receiver for unary `~`", + [YP_ERR_UNTIL_TERM] = "Expected an `end` to close the `until` statement", + [YP_ERR_WHILE_TERM] = "Expected an `end` to close the `while` statement", + [YP_ERR_WRITE_TARGET_READONLY] = "Immutable variable as a write target", + [YP_ERR_WRITE_TARGET_UNEXPECTED] = "Unexpected write target", + [YP_ERR_XSTRING_TERM] = "Expected a closing delimiter for the `%x` or backtick string", + [YP_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS] = "Ambiguous first argument; put parentheses or a space even after `-` operator", + [YP_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS] = "Ambiguous first argument; put parentheses or a space even after `+` operator", + [YP_WARN_AMBIGUOUS_PREFIX_STAR] = "Ambiguous `*` has been interpreted as an argument prefix", + [YP_WARN_AMBIGUOUS_SLASH] = "Ambiguous `/`; wrap regexp in parentheses or add a space after `/` operator", +}; + +static const char* +yp_diagnostic_message(yp_diagnostic_id_t diag_id) { + assert(diag_id < YP_DIAGNOSTIC_ID_LEN); + const char *message = diagnostic_messages[diag_id]; + assert(message); + return message; +} + // Append an error to the given list of diagnostic. bool -yp_diagnostic_list_append(yp_list_t *list, const uint8_t *start, const uint8_t *end, const char *message) { +yp_diagnostic_list_append(yp_list_t *list, const uint8_t *start, const uint8_t *end, yp_diagnostic_id_t diag_id) { yp_diagnostic_t *diagnostic = (yp_diagnostic_t *) malloc(sizeof(yp_diagnostic_t)); if (diagnostic == NULL) return false; - *diagnostic = (yp_diagnostic_t) { .start = start, .end = end, .message = message }; + *diagnostic = (yp_diagnostic_t) { .start = start, .end = end, .message = yp_diagnostic_message(diag_id) }; yp_list_append(list, (yp_list_node_t *) diagnostic); return true; } diff --git a/src/unescape.c b/src/unescape.c index 830c5996ae3..9da52eaea9c 100644 --- a/src/unescape.c +++ b/src/unescape.c @@ -94,7 +94,7 @@ static inline size_t unescape_hexadecimal(const uint8_t *backslash, uint8_t *value, const uint8_t *end, yp_list_t *error_list) { *value = 0; if (backslash + 2 >= end || !yp_char_is_hexadecimal_digit(backslash[2])) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, "Invalid hex escape."); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, YP_ERR_ESCAPE_INVALID_HEXADECIMAL); return 2; } *value = unescape_hexadecimal_digit(backslash[2]); @@ -157,7 +157,7 @@ unescape_unicode_write(uint8_t *dest, uint32_t value, const uint8_t *start, cons // If we get here, then the value is too big. This is an error, but we don't // want to just crash, so instead we'll add an error to the error list and put // in a replacement character instead. - if (error_list) yp_diagnostic_list_append(error_list, start, end, "Invalid Unicode escape sequence."); + if (error_list) yp_diagnostic_list_append(error_list, start, end, YP_ERR_ESCAPE_INVALID_UNICODE); dest[0] = 0xEF; dest[1] = 0xBF; dest[2] = 0xBD; @@ -235,7 +235,7 @@ unescape( // \unnnn Unicode character, where nnnn is exactly 4 hexadecimal digits ([0-9a-fA-F]) case 'u': { if ((flags & YP_UNESCAPE_FLAG_CONTROL) | (flags & YP_UNESCAPE_FLAG_META)) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, "Unicode escape sequence cannot be used with control or meta flags."); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, YP_ERR_ESCAPE_INVALID_UNICODE_CM_FLAGS); return backslash + 2; } @@ -252,11 +252,11 @@ unescape( // \u{nnnn} character literal allows only 1-6 hexadecimal digits if (hexadecimal_length > 6) { - if (error_list) yp_diagnostic_list_append(error_list, unicode_cursor, unicode_cursor + hexadecimal_length, "invalid Unicode escape."); + if (error_list) yp_diagnostic_list_append(error_list, unicode_cursor, unicode_cursor + hexadecimal_length, YP_ERR_ESCAPE_INVALID_UNICODE_LONG); } // there are not hexadecimal characters else if (hexadecimal_length == 0) { - if (error_list) yp_diagnostic_list_append(error_list, unicode_cursor, unicode_cursor + hexadecimal_length, "unterminated Unicode escape"); + if (error_list) yp_diagnostic_list_append(error_list, unicode_cursor, unicode_cursor + hexadecimal_length, YP_ERR_ESCAPE_INVALID_UNICODE); return unicode_cursor; } @@ -277,13 +277,13 @@ unescape( // ?\u{nnnn} character literal should contain only one codepoint and cannot be like ?\u{nnnn mmmm} if (flags & YP_UNESCAPE_FLAG_EXPECT_SINGLE && codepoints_count > 1) { - if (error_list) yp_diagnostic_list_append(error_list, extra_codepoints_start, unicode_cursor - 1, "Multiple codepoints at single character literal"); + if (error_list) yp_diagnostic_list_append(error_list, extra_codepoints_start, unicode_cursor - 1, YP_ERR_ESCAPE_INVALID_UNICODE_LITERAL); } if (unicode_cursor < end && *unicode_cursor == '}') { unicode_cursor++; } else { - if (error_list) yp_diagnostic_list_append(error_list, backslash, unicode_cursor, "invalid Unicode escape."); + if (error_list) yp_diagnostic_list_append(error_list, backslash, unicode_cursor, YP_ERR_ESCAPE_INVALID_UNICODE_TERM); } return unicode_cursor; @@ -298,7 +298,7 @@ unescape( return backslash + 6; } - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, "Invalid Unicode escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, YP_ERR_ESCAPE_INVALID_UNICODE); return backslash + 2; } // \c\M-x meta control character, where x is an ASCII printable character @@ -306,12 +306,12 @@ unescape( // \cx control character, where x is an ASCII printable character case 'c': if (backslash + 2 >= end) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, "Invalid control escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, YP_ERR_ESCAPE_INVALID_CONTROL); return end; } if (flags & YP_UNESCAPE_FLAG_CONTROL) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, "Control escape sequence cannot be doubled."); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, YP_ERR_ESCAPE_INVALID_CONTROL_REPEAT); return backslash + 2; } @@ -325,7 +325,7 @@ unescape( return backslash + 3; default: { if (!char_is_ascii_printable(backslash[2])) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, "Invalid control escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, YP_ERR_ESCAPE_INVALID_CONTROL); return backslash + 2; } @@ -339,17 +339,17 @@ unescape( // \C-? delete, ASCII 7Fh (DEL) case 'C': if (backslash + 3 >= end) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, "Invalid control escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, YP_ERR_ESCAPE_INVALID_CONTROL); return end; } if (flags & YP_UNESCAPE_FLAG_CONTROL) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, "Control escape sequence cannot be doubled."); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, YP_ERR_ESCAPE_INVALID_CONTROL_REPEAT); return backslash + 2; } if (backslash[2] != '-') { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, "Invalid control escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, YP_ERR_ESCAPE_INVALID_CONTROL); return backslash + 2; } @@ -363,7 +363,7 @@ unescape( return backslash + 4; default: if (!char_is_ascii_printable(backslash[3])) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, "Invalid control escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, YP_ERR_ESCAPE_INVALID_CONTROL); return backslash + 2; } @@ -377,17 +377,17 @@ unescape( // \M-x meta character, where x is an ASCII printable character case 'M': { if (backslash + 3 >= end) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, "Invalid control escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, YP_ERR_ESCAPE_INVALID_META); return end; } if (flags & YP_UNESCAPE_FLAG_META) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, "Meta escape sequence cannot be doubled."); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, YP_ERR_ESCAPE_INVALID_META_REPEAT); return backslash + 2; } if (backslash[2] != '-') { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, "Invalid meta escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, YP_ERR_ESCAPE_INVALID_META); return backslash + 2; } @@ -402,7 +402,7 @@ unescape( return backslash + 4; } - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, "Invalid meta escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, YP_ERR_ESCAPE_INVALID_META); return backslash + 3; } // \n @@ -474,7 +474,7 @@ yp_unescape_manipulate_string_or_char_literal(yp_parser_t *parser, yp_string_t * // within the string. uint8_t *allocated = malloc(string->length); if (allocated == NULL) { - yp_diagnostic_list_append(&parser->error_list, string->source, string->source + string->length, "Failed to allocate memory for unescaping."); + yp_diagnostic_list_append(&parser->error_list, string->source, string->source + string->length, YP_ERR_MALLOC_FAILED); return; } diff --git a/src/yarp.c b/src/yarp.c index cb2bf18597c..07ee4d8a8f1 100644 --- a/src/yarp.c +++ b/src/yarp.c @@ -549,7 +549,7 @@ yp_arguments_validate(yp_parser_t *parser, yp_arguments_t *arguments) { &parser->error_list, arguments->block->base.location.start, arguments->block->base.location.end, - "both block arg and actual block given" + YP_ERR_ARGUMENT_BLOCK_MULTI ); } } @@ -643,14 +643,14 @@ parse_decimal_number(yp_parser_t *parser, const uint8_t *start, const uint8_t *e unsigned long value = strtoul(digits, &endptr, 10); if ((digits == endptr) || (*endptr != '\0') || (errno == ERANGE)) { - yp_diagnostic_list_append(&parser->error_list, start, end, "invalid decimal number"); + yp_diagnostic_list_append(&parser->error_list, start, end, YP_ERR_INVALID_NUMBER_DECIMAL); value = UINT32_MAX; } free(digits); if (value > UINT32_MAX) { - yp_diagnostic_list_append(&parser->error_list, start, end, "invalid decimal number"); + yp_diagnostic_list_append(&parser->error_list, start, end, YP_ERR_INVALID_NUMBER_DECIMAL); value = UINT32_MAX; } @@ -4637,7 +4637,7 @@ yp_parser_parameter_name_check(yp_parser_t *parser, yp_token_t *name) { yp_constant_id_t constant_id = yp_parser_constant_id_token(parser, name); if (yp_constant_id_list_includes(&parser->current_scope->locals, constant_id)) { - yp_diagnostic_list_append(&parser->error_list, name->start, name->end, "Duplicated parameter name."); + yp_diagnostic_list_append(&parser->error_list, name->start, name->end, YP_ERR_PARAMETER_NAME_REPEAT); } } @@ -4980,7 +4980,7 @@ parser_lex_encoding_comment(yp_parser_t *parser) { // didn't understand the encoding that the user was trying to use. In this // case we'll keep using the default encoding but add an error to the // parser to indicate an unsuccessful parse. - yp_diagnostic_list_append(&parser->error_list, encoding_start, encoding_end, "Could not understand the encoding specified in the magic comment."); + yp_diagnostic_list_append(&parser->error_list, encoding_start, encoding_end, YP_ERR_INVALID_ENCODING_MAGIC_COMMENT); } /******************************************************************************/ @@ -5140,7 +5140,7 @@ lex_optional_float_suffix(yp_parser_t *parser) { parser->current.end += yp_strspn_decimal_number(parser->current.end, parser->end - parser->current.end); type = YP_TOKEN_FLOAT; } else { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Missing exponent."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_FLOAT_EXPONENT); type = YP_TOKEN_FLOAT; } } @@ -5161,7 +5161,7 @@ lex_numeric_prefix(yp_parser_t *parser) { if (yp_char_is_decimal_digit(peek(parser))) { parser->current.end += yp_strspn_decimal_number(parser->current.end, parser->end - parser->current.end); } else { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid decimal number."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_NUMBER_DECIMAL); } break; @@ -5173,7 +5173,7 @@ lex_numeric_prefix(yp_parser_t *parser) { if (yp_char_is_binary_digit(peek(parser))) { parser->current.end += yp_strspn_binary_number(parser->current.end, parser->end - parser->current.end); } else { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid binary number."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_NUMBER_BINARY); } break; @@ -5185,7 +5185,7 @@ lex_numeric_prefix(yp_parser_t *parser) { if (yp_char_is_octal_digit(peek(parser))) { parser->current.end += yp_strspn_octal_number(parser->current.end, parser->end - parser->current.end); } else { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid octal number."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_NUMBER_OCTAL); } break; @@ -5210,7 +5210,7 @@ lex_numeric_prefix(yp_parser_t *parser) { if (yp_char_is_hexadecimal_digit(peek(parser))) { parser->current.end += yp_strspn_hexadecimal_number(parser->current.end, parser->end - parser->current.end); } else { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid hexadecimal number."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_NUMBER_HEXADECIMAL); } break; @@ -5240,7 +5240,7 @@ lex_numeric_prefix(yp_parser_t *parser) { // If the last character that we consumed was an underscore, then this is // actually an invalid integer value, and we should return an invalid token. if (peek_offset(parser, -1) == '_') { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Number literal cannot end with a `_`."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_NUMBER_LITERAL_UNDERSCORE); } return type; @@ -5292,7 +5292,7 @@ lex_numeric(yp_parser_t *parser) { static yp_token_type_t lex_global_variable(yp_parser_t *parser) { if (parser->current.end >= parser->end) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid global variable."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_VARIABLE_GLOBAL); return YP_TOKEN_GLOBAL_VARIABLE; } @@ -5333,7 +5333,7 @@ lex_global_variable(yp_parser_t *parser) { } while (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0); // $0 isn't allowed to be followed by anything. - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid global variable."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_VARIABLE_GLOBAL); } return YP_TOKEN_GLOBAL_VARIABLE; @@ -5364,7 +5364,7 @@ lex_global_variable(yp_parser_t *parser) { } else { // If we get here, then we have a $ followed by something that isn't // recognized as a global variable. - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid global variable."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_VARIABLE_GLOBAL); } return YP_TOKEN_GLOBAL_VARIABLE; @@ -5704,7 +5704,7 @@ lex_question_mark(yp_parser_t *parser) { } if (parser->current.end >= parser->end) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Incomplete character syntax."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INCOMPLETE_QUESTION_MARK); return YP_TOKEN_CHARACTER_LITERAL; } @@ -5755,9 +5755,9 @@ lex_at_variable(yp_parser_t *parser) { parser->current.end += width; } } else if (type == YP_TOKEN_CLASS_VARIABLE) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Incomplete class variable."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INCOMPLETE_VARIABLE_CLASS); } else { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Incomplete instance variable."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INCOMPLETE_VARIABLE_INSTANCE); } // If we're lexing an embedded variable, then we need to pop back into the @@ -5856,7 +5856,7 @@ lex_embdoc(yp_parser_t *parser) { parser_lex_callback(parser); } - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unterminated embdoc"); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_EMBDOC_TERM); comment->end = parser->current.end; yp_list_append(&parser->comment_list, (yp_list_node_t *) comment); @@ -6286,7 +6286,7 @@ parser_lex(yp_parser_t *parser) { yp_token_type_t type = YP_TOKEN_STAR; if (lex_state_spcarg_p(parser, space_seen)) { - yp_diagnostic_list_append(&parser->warning_list, parser->current.start, parser->current.end, "`*' interpreted as argument prefix"); + yp_diagnostic_list_append(&parser->warning_list, parser->current.start, parser->current.end, YP_WARN_AMBIGUOUS_PREFIX_STAR); type = YP_TOKEN_USTAR; } else if (lex_state_beg_p(parser)) { type = YP_TOKEN_USTAR; @@ -6430,7 +6430,7 @@ parser_lex(yp_parser_t *parser) { // this is not a valid heredoc declaration. In this case we // will add an error, but we will still return a heredoc // start. - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unterminated heredoc."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_EMBDOC_TERM); body_start = parser->end; } else { // Otherwise, we want to indicate that the body of the @@ -6627,7 +6627,7 @@ parser_lex(yp_parser_t *parser) { &parser->warning_list, parser->current.start, parser->current.end, - "ambiguous first argument; put parentheses or a space even after `+` operator" + YP_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS ); } @@ -6676,7 +6676,7 @@ parser_lex(yp_parser_t *parser) { &parser->warning_list, parser->current.start, parser->current.end, - "ambiguous first argument; put parentheses or a space even after `-` operator" + YP_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS ); } @@ -6774,7 +6774,7 @@ parser_lex(yp_parser_t *parser) { } if (lex_state_spcarg_p(parser, space_seen)) { - yp_diagnostic_list_append(&parser->warning_list, parser->current.start, parser->current.end, "ambiguity between regexp and two divisions: wrap regexp in parentheses or add a space after `/' operator"); + yp_diagnostic_list_append(&parser->warning_list, parser->current.start, parser->current.end, YP_WARN_AMBIGUOUS_SLASH); lex_mode_push_regexp(parser, '\0', '/'); LEX(YP_TOKEN_REGEXP_BEGIN); } @@ -6813,7 +6813,7 @@ parser_lex(yp_parser_t *parser) { // going to say it's the percent operator because we don't want to move into the // string lex mode unnecessarily. if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->current.end >= parser->end)) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unexpected end of input"); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_PERCENT); LEX(YP_TOKEN_PERCENT); } @@ -6938,7 +6938,7 @@ parser_lex(yp_parser_t *parser) { // unparseable. In this case we'll just drop it from the parser // and skip past it and hope that the next token is something // that we can parse. - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid %% token"); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_PERCENT); goto lex_next_token; } } @@ -6974,7 +6974,7 @@ parser_lex(yp_parser_t *parser) { // token as we've exhausted all of the other options. We'll skip past // it and return the next token. if (!width) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid token."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_TOKEN); goto lex_next_token; } @@ -7920,17 +7920,17 @@ accept_any(yp_parser_t *parser, size_t count, ...) { // valid) and create an artificial token instead. This allows us to recover from // the fact that the token isn't present and continue parsing. static void -expect(yp_parser_t *parser, yp_token_type_t type, const char *message) { +expect(yp_parser_t *parser, yp_token_type_t type, yp_diagnostic_id_t diag_id) { if (accept(parser, type)) return; - yp_diagnostic_list_append(&parser->error_list, parser->previous.end, parser->previous.end, message); + yp_diagnostic_list_append(&parser->error_list, parser->previous.end, parser->previous.end, diag_id); parser->previous = (yp_token_t) { .type = YP_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end }; } static void -expect_any(yp_parser_t *parser, const char*message, size_t count, ...) { +expect_any(yp_parser_t *parser, yp_diagnostic_id_t diag_id, size_t count, ...) { va_list types; va_start(types, count); @@ -7943,13 +7943,13 @@ expect_any(yp_parser_t *parser, const char*message, size_t count, ...) { va_end(types); - yp_diagnostic_list_append(&parser->error_list, parser->previous.end, parser->previous.end, message); + yp_diagnostic_list_append(&parser->error_list, parser->previous.end, parser->previous.end, diag_id); parser->previous = (yp_token_t) { .type = YP_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end }; } static yp_node_t * -parse_expression(yp_parser_t *parser, yp_binding_power_t binding_power, const char *message); +parse_expression(yp_parser_t *parser, yp_binding_power_t binding_power, yp_diagnostic_id_t diag_id); // This function controls whether or not we will attempt to parse an expression // beginning at the subsequent token. It is used when we are in a context where @@ -8026,14 +8026,14 @@ token_begins_expression_p(yp_token_type_t type) { // Parse an expression with the given binding power that may be optionally // prefixed by the * operator. static yp_node_t * -parse_starred_expression(yp_parser_t *parser, yp_binding_power_t binding_power, const char *message) { +parse_starred_expression(yp_parser_t *parser, yp_binding_power_t binding_power, yp_diagnostic_id_t diag_id) { if (accept(parser, YP_TOKEN_USTAR)) { yp_token_t operator = parser->previous; - yp_node_t *expression = parse_expression(parser, binding_power, "Expected expression after `*'."); + yp_node_t *expression = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_STAR); return (yp_node_t *) yp_splat_node_create(parser, &operator, expression); } - return parse_expression(parser, binding_power, message); + return parse_expression(parser, binding_power, diag_id); } // Convert the given node into a valid target node. @@ -8059,7 +8059,7 @@ parse_target(yp_parser_t *parser, yp_node_t *target) { /* fallthrough */ case YP_NUMBERED_REFERENCE_READ_NODE: assert(sizeof(yp_global_variable_target_node_t) == sizeof(yp_numbered_reference_read_node_t)); - yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, "Can't set variable"); + yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, YP_ERR_WRITE_TARGET_READONLY); /* fallthrough */ case YP_GLOBAL_VARIABLE_READ_NODE: assert(sizeof(yp_global_variable_target_node_t) == sizeof(yp_global_variable_read_node_t)); @@ -8122,7 +8122,7 @@ parse_target(yp_parser_t *parser, yp_node_t *target) { target->type = YP_LOCAL_VARIABLE_TARGET_NODE; if (token_is_numbered_parameter(message.start, message.end)) { - yp_diagnostic_list_append(&parser->error_list, message.start, message.end, "reserved for numbered parameter"); + yp_diagnostic_list_append(&parser->error_list, message.start, message.end, YP_ERR_PARAMETER_NUMBERED_RESERVED); } return target; @@ -8166,7 +8166,7 @@ parse_target(yp_parser_t *parser, yp_node_t *target) { // In this case we have a node that we don't know how to convert // into a target. We need to treat it as an error. For now, we'll // mark it as an error and just skip right past it. - yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, "Unexpected write target."); + yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, YP_ERR_WRITE_TARGET_UNEXPECTED); return target; } } @@ -8191,7 +8191,7 @@ parse_write(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_nod } case YP_BACK_REFERENCE_READ_NODE: case YP_NUMBERED_REFERENCE_READ_NODE: - yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, "Can't set variable"); + yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, YP_ERR_WRITE_TARGET_READONLY); /* fallthrough */ case YP_GLOBAL_VARIABLE_READ_NODE: { yp_global_variable_write_node_t *node = yp_global_variable_write_node_create(parser, target, operator, value); @@ -8263,7 +8263,7 @@ parse_write(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_nod target = (yp_node_t *) yp_local_variable_write_node_create(parser, constant_id, 0, value, &message, operator); if (token_is_numbered_parameter(message.start, message.end)) { - yp_diagnostic_list_append(&parser->error_list, message.start, message.end, "reserved for numbered parameter"); + yp_diagnostic_list_append(&parser->error_list, message.start, message.end, YP_ERR_PARAMETER_NUMBERED_RESERVED); } return target; @@ -8336,7 +8336,7 @@ parse_write(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_nod // In this case we have a node that we don't know how to convert into a // target. We need to treat it as an error. For now, we'll mark it as an // error and just skip right past it. - yp_diagnostic_list_append(&parser->error_list, operator->start, operator->end, "Unexpected `='."); + yp_diagnostic_list_append(&parser->error_list, operator->start, operator->end, YP_ERR_EXPECT_EXPRESSION_AFTER_EQUAL); return target; } } @@ -8381,14 +8381,14 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b // others yet. if (has_splat) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Multiple splats in multi-assignment."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_MULTI_ASSIGN_MULTI_SPLATS); } yp_token_t star_operator = parser->previous; yp_node_t *name = NULL; if (token_begins_expression_p(parser->current.type)) { - name = parse_expression(parser, binding_power, "Expected an expression after '*'."); + name = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_STAR); name = parse_target(parser, name); } @@ -8401,10 +8401,10 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b // the node when it returns. yp_token_t lparen = parser->previous; - yp_node_t *first_child_target = parse_expression(parser, YP_BINDING_POWER_STATEMENT, "Expected an expression after '('."); + yp_node_t *first_child_target = parse_expression(parser, YP_BINDING_POWER_STATEMENT, YP_ERR_EXPECT_EXPRESSION_AFTER_LPAREN); yp_node_t *child_target = parse_targets(parser, first_child_target, YP_BINDING_POWER_STATEMENT); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected an ')' after multi-assignment."); + expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_EXPECT_RPAREN_AFTER_MULTI); yp_token_t rparen = parser->previous; if (YP_NODE_TYPE_P(child_target, YP_MULTI_WRITE_NODE) && first_target == NULL && result->targets.size == 0) { @@ -8447,7 +8447,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b // If we get here, then we weren't able to parse anything at all, so // we need to return a missing node. yp_node_destroy(parser, (yp_node_t *) result); - yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, "Expected index after for."); + yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, YP_ERR_FOR_INDEX); return (yp_node_t *) yp_missing_node_create(parser, operator.start, operator.end); } @@ -8459,7 +8459,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b return (yp_node_t *) result; } - yp_node_t *target = parse_expression(parser, binding_power, "Expected another expression after ','."); + yp_node_t *target = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_COMMA); target = parse_target(parser, target); yp_multi_write_node_targets_append(result, target); @@ -8487,7 +8487,7 @@ parse_statements(yp_parser_t *parser, yp_context_t context) { context_push(parser, context); while (true) { - yp_node_t *node = parse_expression(parser, YP_BINDING_POWER_STATEMENT, "Expected to be able to parse an expression."); + yp_node_t *node = parse_expression(parser, YP_BINDING_POWER_STATEMENT, YP_ERR_CANNOT_PARSE_EXPRESSION); yp_statements_node_body_append(statements, node); // If we're recovering from a syntax error, then we need to stop parsing the @@ -8532,7 +8532,7 @@ parse_statements(yp_parser_t *parser, yp_context_t context) { while (accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)); if (context_terminator(context, &parser->current)) break; } else { - expect(parser, YP_TOKEN_NEWLINE, "Expected a newline or semicolon after statement."); + expect(parser, YP_TOKEN_NEWLINE, YP_ERR_EXPECT_EOL_AFTER_STATEMENT); } } @@ -8555,9 +8555,9 @@ parse_assocs(yp_parser_t *parser, yp_node_t *node) { yp_node_t *value = NULL; if (token_begins_expression_p(parser->current.type)) { - value = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected an expression after ** in hash."); + value = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH); } else if (yp_parser_local_depth(parser, &operator) == -1) { - yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, "Expected an expression after ** in hash."); + yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH); } element = (yp_node_t *) yp_assoc_splat_node_create(parser, value, &operator); @@ -8571,24 +8571,24 @@ parse_assocs(yp_parser_t *parser, yp_node_t *node) { yp_node_t *value = NULL; if (token_begins_expression_p(parser->current.type)) { - value = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected an expression after the label in hash."); + value = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_HASH_EXPRESSION_AFTER_LABEL); } element = (yp_node_t *) yp_assoc_node_create(parser, key, &operator, value); break; } default: { - yp_node_t *key = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a key in the hash literal."); + yp_node_t *key = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_HASH_KEY); yp_token_t operator; if (yp_symbol_node_label_p(key)) { operator = not_provided(parser); } else { - expect(parser, YP_TOKEN_EQUAL_GREATER, "Expected a => between the key and the value in the hash."); + expect(parser, YP_TOKEN_EQUAL_GREATER, YP_ERR_HASH_ROCKET); operator = parser->previous; } - yp_node_t *value = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value in the hash literal."); + yp_node_t *value = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_HASH_VALUE); element = (yp_node_t *) yp_assoc_node_create(parser, key, &operator, value); break; } @@ -8636,7 +8636,7 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for while (!match_type_p(parser, YP_TOKEN_EOF)) { if (parsed_block_argument) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unexpected argument after block argument."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_ARGUMENT_AFTER_BLOCK); } yp_node_t *argument = NULL; @@ -8645,7 +8645,7 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for case YP_TOKEN_USTAR_STAR: case YP_TOKEN_LABEL: { if (parsed_bare_hash) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unexpected bare hash."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_ARGUMENT_BARE_HASH); } yp_keyword_hash_node_t *hash = yp_keyword_hash_node_create(parser); @@ -8664,9 +8664,9 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for yp_node_t *expression = NULL; if (token_begins_expression_p(parser->current.type)) { - expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected to be able to parse an argument."); + expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_EXPECT_ARGUMENT); } else if (yp_parser_local_depth(parser, &operator) == -1) { - yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, "unexpected & when parent method is not forwarding."); + yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, YP_ERR_ARGUMENT_NO_FORWARDING_AMP); } argument = (yp_node_t *)yp_block_argument_node_create(parser, &operator, expression); @@ -8680,15 +8680,15 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for if (match_any_type_p(parser, 2, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_COMMA)) { if (yp_parser_local_depth(parser, &parser->previous) == -1) { - yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, "unexpected * when parent method is not forwarding."); + yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, YP_ERR_ARGUMENT_NO_FORWARDING_STAR); } argument = (yp_node_t *) yp_splat_node_create(parser, &operator, NULL); } else { - yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected an expression after '*' in argument."); + yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT); if (parsed_bare_hash) { - yp_diagnostic_list_append(&parser->error_list, operator.start, expression->location.end, "Unexpected splat argument after double splat."); + yp_diagnostic_list_append(&parser->error_list, operator.start, expression->location.end, YP_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT); } argument = (yp_node_t *) yp_splat_node_create(parser, &operator, expression); @@ -8704,11 +8704,11 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for // If the token begins an expression then this ... was not actually // argument forwarding but was instead a range. yp_token_t operator = parser->previous; - yp_node_t *right = parse_expression(parser, YP_BINDING_POWER_RANGE, "Expected a value after the operator."); + yp_node_t *right = parse_expression(parser, YP_BINDING_POWER_RANGE, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); argument = (yp_node_t *) yp_range_node_create(parser, NULL, &operator, right); } else { if (yp_parser_local_depth(parser, &parser->previous) == -1) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "unexpected ... when parent method is not forwarding."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES); } argument = (yp_node_t *)yp_forwarding_arguments_node_create(parser, &parser->previous); @@ -8719,12 +8719,12 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for /* fallthrough */ default: { if (argument == NULL) { - argument = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected to be able to parse an argument."); + argument = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_EXPECT_ARGUMENT); } if (yp_symbol_node_label_p(argument) || accept(parser, YP_TOKEN_EQUAL_GREATER)) { if (parsed_bare_hash) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected bare hash argument."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_BARE_HASH); } yp_token_t operator; @@ -8737,7 +8737,7 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for yp_keyword_hash_node_t *bare_hash = yp_keyword_hash_node_create(parser); // Finish parsing the one we are part way through - yp_node_t *value = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value in the hash literal."); + yp_node_t *value = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_HASH_VALUE); argument = (yp_node_t *) yp_assoc_node_create(parser, argument, &operator, value); yp_keyword_hash_node_elements_append(bare_hash, argument); @@ -8793,7 +8793,7 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for // It can recurse infinitely down, and splats are allowed to group arguments. static yp_required_destructured_parameter_node_t * parse_required_destructured_parameter(yp_parser_t *parser) { - expect(parser, YP_TOKEN_PARENTHESIS_LEFT, "Expected '(' to start a required parameter."); + expect(parser, YP_TOKEN_PARENTHESIS_LEFT, YP_ERR_EXPECT_LPAREN_REQ_PARAMETER); yp_token_t opening = parser->previous; yp_required_destructured_parameter_node_t *node = yp_required_destructured_parameter_node_create(parser, &opening); @@ -8804,7 +8804,7 @@ parse_required_destructured_parameter(yp_parser_t *parser) { if (node->parameters.size > 0 && match_type_p(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { if (parsed_splat) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected splat after splat."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_SPLAT_AFTER_SPLAT); } param = (yp_node_t *) yp_splat_node_create(parser, &parser->previous, NULL); @@ -8816,7 +8816,7 @@ parse_required_destructured_parameter(yp_parser_t *parser) { param = (yp_node_t *) parse_required_destructured_parameter(parser); } else if (accept(parser, YP_TOKEN_USTAR)) { if (parsed_splat) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected splat after splat."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_SPLAT_AFTER_SPLAT); } yp_token_t star = parser->previous; @@ -8831,7 +8831,7 @@ parse_required_destructured_parameter(yp_parser_t *parser) { param = (yp_node_t *) yp_splat_node_create(parser, &star, value); parsed_splat = true; } else { - expect(parser, YP_TOKEN_IDENTIFIER, "Expected an identifier for a required parameter."); + expect(parser, YP_TOKEN_IDENTIFIER, YP_ERR_EXPECT_IDENT_REQ_PARAMETER); yp_token_t name = parser->previous; param = (yp_node_t *) yp_required_parameter_node_create(parser, &name); @@ -8841,7 +8841,7 @@ parse_required_destructured_parameter(yp_parser_t *parser) { yp_required_destructured_parameter_node_append_parameter(node, param); } while (accept(parser, YP_TOKEN_COMMA)); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected ')' to end a required parameter."); + expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_EXPECT_RPAREN_REQ_PARAMETER); yp_required_destructured_parameter_node_closing_set(node, &parser->previous); return node; @@ -8896,12 +8896,12 @@ update_parameter_state(yp_parser_t *parser, yp_token_t *token, yp_parameters_ord } if (token->type == YP_TOKEN_USTAR && *current == YP_PARAMETERS_ORDER_AFTER_OPTIONAL) { - yp_diagnostic_list_append(&parser->error_list, token->start, token->end, "Unexpected parameter *"); + yp_diagnostic_list_append(&parser->error_list, token->start, token->end, YP_ERR_PARAMETER_STAR); } if (*current == YP_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) { // We know what transition we failed on, so we can provide a better error here. - yp_diagnostic_list_append(&parser->error_list, token->start, token->end, "Unexpected parameter order"); + yp_diagnostic_list_append(&parser->error_list, token->start, token->end, YP_ERR_PARAMETER_ORDER); } else if (state < *current) { *current = state; } @@ -8956,7 +8956,7 @@ parse_parameters( if (params->block == NULL) { yp_parameters_node_block_set(params, param); } else { - yp_diagnostic_list_append(&parser->error_list, param->base.location.start, param->base.location.end, "Unexpected multiple block parameter"); + yp_diagnostic_list_append(&parser->error_list, param->base.location.start, param->base.location.end, YP_ERR_PARAMETER_BLOCK_MULTI); yp_parameters_node_posts_append(params, (yp_node_t *) param); } @@ -8964,7 +8964,7 @@ parse_parameters( } case YP_TOKEN_UDOT_DOT_DOT: { if (!allows_forwarding_parameter) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unexpected ..."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES); } if (order > YP_PARAMETERS_ORDER_NOTHING_AFTER) { update_parameter_state(parser, &parser->current, &order); @@ -8987,16 +8987,16 @@ parse_parameters( parser_lex(parser); switch (parser->previous.type) { case YP_TOKEN_CONSTANT: - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a constant"); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_FORMAL_CONSTANT); break; case YP_TOKEN_INSTANCE_VARIABLE: - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be an instance variable"); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_FORMAL_IVAR); break; case YP_TOKEN_GLOBAL_VARIABLE: - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a global variable"); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_FORMAL_GLOBAL); break; case YP_TOKEN_CLASS_VARIABLE: - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a class variable"); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_FORMAL_CLASS); break; default: break; } @@ -9014,7 +9014,7 @@ parse_parameters( if (accept(parser, YP_TOKEN_EQUAL)) { yp_token_t operator = parser->previous; context_push(parser, YP_CONTEXT_DEFAULT_PARAMS); - yp_node_t *value = parse_expression(parser, binding_power, "Expected to find a default value for the parameter."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_PARAMETER_NO_DEFAULT); yp_optional_parameter_node_t *param = yp_optional_parameter_node_create(parser, &name, &operator, value); yp_parameters_node_optionals_append(params, param); @@ -9072,7 +9072,7 @@ parse_parameters( yp_node_t *value = NULL; if (token_begins_expression_p(parser->current.type)) { context_push(parser, YP_CONTEXT_DEFAULT_PARAMS); - value = parse_expression(parser, binding_power, "Expected to find a default value for the keyword parameter."); + value = parse_expression(parser, binding_power, YP_ERR_PARAMETER_NO_DEFAULT_KW); context_pop(parser); } @@ -9113,7 +9113,7 @@ parse_parameters( if (params->rest == NULL) { yp_parameters_node_rest_set(params, param); } else { - yp_diagnostic_list_append(&parser->error_list, param->base.location.start, param->base.location.end, "Unexpected multiple splat parameters."); + yp_diagnostic_list_append(&parser->error_list, param->base.location.start, param->base.location.end, YP_ERR_PARAMETER_SPLAT_MULTI); yp_parameters_node_posts_append(params, (yp_node_t *) param); } @@ -9147,7 +9147,7 @@ parse_parameters( if (params->keyword_rest == NULL) { yp_parameters_node_keyword_rest_set(params, param); } else { - yp_diagnostic_list_append(&parser->error_list, param->location.start, param->location.end, "Unexpected multiple double splat parameters."); + yp_diagnostic_list_append(&parser->error_list, param->location.start, param->location.end, YP_ERR_PARAMETER_ASSOC_SPLAT_MULTI); yp_parameters_node_posts_append(params, param); } @@ -9165,11 +9165,11 @@ parse_parameters( if (params->rest == NULL) { yp_parameters_node_rest_set(params, param); } else { - yp_diagnostic_list_append(&parser->error_list, param->base.location.start, param->base.location.end, "Unexpected multiple splat parameters."); + yp_diagnostic_list_append(&parser->error_list, param->base.location.start, param->base.location.end, YP_ERR_PARAMETER_SPLAT_MULTI); yp_parameters_node_posts_append(params, (yp_node_t *) param); } } else { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected ','."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_PARAMETER_WILD_LOOSE_COMMA); } } @@ -9210,7 +9210,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) { parser_lex(parser); yp_rescue_node_operator_set(rescue, &parser->previous); - yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement."); + yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, YP_ERR_RESCUE_VARIABLE); reference = parse_target(parser, reference); yp_rescue_node_reference_set(rescue, reference); @@ -9228,7 +9228,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) { // we'll attempt to parse it here and any others delimited by commas. do { - yp_node_t *expression = parse_starred_expression(parser, YP_BINDING_POWER_DEFINED, "Expected to find a rescued expression."); + yp_node_t *expression = parse_starred_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_RESCUE_EXPRESSION); yp_rescue_node_exceptions_append(rescue, expression); // If we hit a newline, then this is the end of the rescue expression. We @@ -9240,7 +9240,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) { if (accept(parser, YP_TOKEN_EQUAL_GREATER)) { yp_rescue_node_operator_set(rescue, &parser->previous); - yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement."); + yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, YP_ERR_RESCUE_VARIABLE); reference = parse_target(parser, reference); yp_rescue_node_reference_set(rescue, reference); @@ -9254,7 +9254,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) { if (accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { accept(parser, YP_TOKEN_KEYWORD_THEN); } else { - expect(parser, YP_TOKEN_KEYWORD_THEN, "Expected a terminator after rescue clause."); + expect(parser, YP_TOKEN_KEYWORD_THEN, YP_ERR_RESCUE_TERM); } if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_ELSE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) { @@ -9374,7 +9374,7 @@ parse_block_parameters( yp_block_parameters_node_t *block_parameters = yp_block_parameters_node_create(parser, parameters, opening); if (accept(parser, YP_TOKEN_SEMICOLON)) { do { - expect(parser, YP_TOKEN_IDENTIFIER, "Expected a local variable name."); + expect(parser, YP_TOKEN_IDENTIFIER, YP_ERR_BLOCK_PARAM_LOCAL_VARIABLE); yp_parser_local_add_token(parser, &parser->previous); yp_block_local_variable_node_t *local = yp_block_local_variable_node_create(parser, &parser->previous); @@ -9406,7 +9406,7 @@ parse_block(yp_parser_t *parser) { parameters = parse_block_parameters(parser, true, &block_parameters_opening, false); accept(parser, YP_TOKEN_NEWLINE); parser->command_start = true; - expect(parser, YP_TOKEN_PIPE, "Expected block parameters to end with '|'."); + expect(parser, YP_TOKEN_PIPE, YP_ERR_BLOCK_PARAM_PIPE_TERM); } yp_block_parameters_node_closing_set(parameters, &parser->previous); @@ -9420,7 +9420,7 @@ parse_block(yp_parser_t *parser) { statements = (yp_node_t *) parse_statements(parser, YP_CONTEXT_BLOCK_BRACES); } - expect(parser, YP_TOKEN_BRACE_RIGHT, "Expected block beginning with '{' to end with '}'."); + expect(parser, YP_TOKEN_BRACE_RIGHT, YP_ERR_BLOCK_TERM_BRACE); } else { if (!match_type_p(parser, YP_TOKEN_KEYWORD_END)) { if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ELSE, YP_TOKEN_KEYWORD_ENSURE)) { @@ -9435,7 +9435,7 @@ parse_block(yp_parser_t *parser) { } } - expect(parser, YP_TOKEN_KEYWORD_END, "Expected block beginning with 'do' to end with 'end'."); + expect(parser, YP_TOKEN_KEYWORD_END, YP_ERR_BLOCK_TERM_END); } yp_constant_id_list_t locals = parser->current_scope->locals; @@ -9462,7 +9462,7 @@ parse_arguments_list(yp_parser_t *parser, yp_arguments_t *arguments, bool accept yp_accepts_block_stack_push(parser, true); parse_arguments(parser, arguments, true, YP_TOKEN_PARENTHESIS_RIGHT); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected a ')' to close the argument list."); + expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_ARGUMENT_TERM_PAREN); yp_accepts_block_stack_pop(parser); arguments->closing_loc = YP_LOCATION_TOKEN_VALUE(&parser->previous); @@ -9502,7 +9502,8 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) { yp_token_t keyword = parser->previous; context_push(parser, YP_CONTEXT_PREDICATE); - yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_MODIFIER, "Expected to find a predicate for the conditional."); + yp_diagnostic_id_t error_id = context == YP_CONTEXT_IF ? YP_ERR_CONDITIONAL_IF_PREDICATE : YP_ERR_CONDITIONAL_UNLESS_PREDICATE; + yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_MODIFIER, error_id); // Predicates are closed by a term, a "then", or a term and then a "then". accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); @@ -9540,7 +9541,7 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) { if (context == YP_CONTEXT_IF) { while (accept(parser, YP_TOKEN_KEYWORD_ELSIF)) { yp_token_t elsif_keyword = parser->previous; - yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_MODIFIER, "Expected to find a predicate for the elsif clause."); + yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_MODIFIER, YP_ERR_CONDITIONAL_ELSIF_PREDICATE); // Predicates are closed by a term, a "then", or a term and then a "then". accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); @@ -9567,7 +9568,7 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) { yp_accepts_block_stack_pop(parser); accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `else` clause."); + expect(parser, YP_TOKEN_KEYWORD_END, YP_ERR_CONDITIONAL_TERM_ELSE); yp_else_node_t *else_node = yp_else_node_create(parser, &else_keyword, else_statements, &parser->previous); @@ -9583,7 +9584,8 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) { break; } } else { - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close conditional statement."); + // We should specialize this error message to refer to 'if' or 'unless' explicitly. + expect(parser, YP_TOKEN_KEYWORD_END, YP_ERR_CONDITIONAL_TERM); } // Set the appropriate end location for all of the nodes in the subtree. @@ -9733,7 +9735,7 @@ parse_string_part(yp_parser_t *parser) { parser->brace_nesting = brace_nesting; lex_state_set(parser, state); - expect(parser, YP_TOKEN_EMBEXPR_END, "Expected a closing delimiter for an embedded expression."); + expect(parser, YP_TOKEN_EMBEXPR_END, YP_ERR_EMBEXPR_END); yp_token_t closing = parser->previous; return (yp_node_t *) yp_embedded_statements_node_create(parser, &opening, statements, &closing); @@ -9787,7 +9789,7 @@ parse_string_part(yp_parser_t *parser) { // we'll not attempt to lex this token and instead just return a // missing node. default: - expect(parser, YP_TOKEN_IDENTIFIER, "Expected a valid embedded variable."); + expect(parser, YP_TOKEN_IDENTIFIER, YP_ERR_EMBVAR_INVALID); variable = (yp_node_t *) yp_missing_node_create(parser, parser->current.start, parser->current.end); break; } @@ -9796,7 +9798,7 @@ parse_string_part(yp_parser_t *parser) { } default: parser_lex(parser); - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Could not understand string part"); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_CANNOT_PARSE_STRING_PART); return NULL; } } @@ -9827,7 +9829,7 @@ parse_symbol(yp_parser_t *parser, yp_lex_mode_t *lex_mode, yp_lex_state_t next_s symbol = parser->previous; break; default: - expect(parser, YP_TOKEN_IDENTIFIER, "Expected symbol."); + expect(parser, YP_TOKEN_IDENTIFIER, YP_ERR_SYMBOL_INVALID); symbol = parser->previous; break; } @@ -9871,7 +9873,7 @@ parse_symbol(yp_parser_t *parser, yp_lex_mode_t *lex_mode, yp_lex_state_t next_s } if (next_state != YP_LEX_STATE_NONE) lex_state_set(parser, next_state); - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for an interpolated symbol."); + expect(parser, YP_TOKEN_STRING_END, YP_ERR_SYMBOL_TERM_INTERPOLATED); return (yp_node_t *) yp_interpolated_symbol_node_create(parser, &opening, &node_list, &parser->previous); } @@ -9886,7 +9888,7 @@ parse_symbol(yp_parser_t *parser, yp_lex_mode_t *lex_mode, yp_lex_state_t next_s if (next_state != YP_LEX_STATE_NONE) { lex_state_set(parser, next_state); } - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for a dynamic symbol."); + expect(parser, YP_TOKEN_STRING_END, YP_ERR_SYMBOL_TERM_DYNAMIC); return (yp_node_t *) yp_symbol_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_ALL); } @@ -9914,7 +9916,7 @@ parse_undef_argument(yp_parser_t *parser) { return parse_symbol(parser, &lex_mode, YP_LEX_STATE_NONE); } default: - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Expected a bare word or symbol argument."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_UNDEF_ARGUMENT); return (yp_node_t *) yp_missing_node_create(parser, parser->current.start, parser->current.end); } } @@ -9956,7 +9958,7 @@ parse_alias_argument(yp_parser_t *parser, bool first) { parser_lex(parser); return (yp_node_t *) yp_global_variable_read_node_create(parser, &parser->previous); default: - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Expected a bare word, symbol or global variable argument."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_ALIAS_ARGUMENT); return (yp_node_t *) yp_missing_node_create(parser, parser->current.start, parser->current.end); } } @@ -10175,7 +10177,7 @@ parse_heredoc_dedent(yp_parser_t *parser, yp_node_t *node, yp_heredoc_quote_t qu } static yp_node_t * -parse_pattern(yp_parser_t *parser, bool top_pattern, const char *message); +parse_pattern(yp_parser_t *parser, bool top_pattern, yp_diagnostic_id_t diag_id); // Accept any number of constants joined by :: delimiters. static yp_node_t * @@ -10184,7 +10186,7 @@ parse_pattern_constant_path(yp_parser_t *parser, yp_node_t *node) { // path nodes. while (accept(parser, YP_TOKEN_COLON_COLON)) { yp_token_t delimiter = parser->previous; - expect(parser, YP_TOKEN_CONSTANT, "Expected a constant after the :: operator."); + expect(parser, YP_TOKEN_CONSTANT, YP_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT); yp_node_t *child = (yp_node_t *) yp_constant_read_node_create(parser, &parser->previous); node = (yp_node_t *)yp_constant_path_node_create(parser, node, &delimiter, child); @@ -10206,9 +10208,9 @@ parse_pattern_constant_path(yp_parser_t *parser, yp_node_t *node) { accept(parser, YP_TOKEN_NEWLINE); if (!accept(parser, YP_TOKEN_BRACKET_RIGHT)) { - inner = parse_pattern(parser, true, "Expected a pattern expression after the [ operator."); + inner = parse_pattern(parser, true, YP_ERR_PATTERN_EXPRESSION_AFTER_BRACKET); accept(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_BRACKET_RIGHT, "Expected a ] to close the pattern expression."); + expect(parser, YP_TOKEN_BRACKET_RIGHT, YP_ERR_PATTERN_TERM_BRACKET); } closing = parser->previous; @@ -10217,8 +10219,8 @@ parse_pattern_constant_path(yp_parser_t *parser, yp_node_t *node) { opening = parser->previous; if (!accept(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { - inner = parse_pattern(parser, true, "Expected a pattern expression after the ( operator."); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected a ) to close the pattern expression."); + inner = parse_pattern(parser, true, YP_ERR_PATTERN_EXPRESSION_AFTER_PAREN); + expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_PATTERN_TERM_PAREN); } closing = parser->previous; @@ -10343,7 +10345,7 @@ parse_pattern_hash(yp_parser_t *parser, yp_node_t *first_assoc) { if (!match_any_type_p(parser, 7, YP_TOKEN_COMMA, YP_TOKEN_KEYWORD_THEN, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_BRACKET_RIGHT, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { // Here we have a value for the first assoc in the list, so we will parse it // now and update the first assoc. - yp_node_t *value = parse_pattern(parser, false, "Expected a pattern expression after the key."); + yp_node_t *value = parse_pattern(parser, false, YP_ERR_PATTERN_EXPRESSION_AFTER_KEY); yp_assoc_node_t *assoc = (yp_assoc_node_t *) first_assoc; assoc->base.location.end = value->location.end; @@ -10373,12 +10375,12 @@ parse_pattern_hash(yp_parser_t *parser, yp_node_t *first_assoc) { if (match_type_p(parser, YP_TOKEN_USTAR_STAR)) { assoc = parse_pattern_keyword_rest(parser); } else { - expect(parser, YP_TOKEN_LABEL, "Expected a label after the `,'."); + expect(parser, YP_TOKEN_LABEL, YP_ERR_PATTERN_LABEL_AFTER_COMMA); yp_node_t *key = (yp_node_t *) yp_symbol_node_label_create(parser, &parser->previous); yp_node_t *value = NULL; if (!match_any_type_p(parser, 7, YP_TOKEN_COMMA, YP_TOKEN_KEYWORD_THEN, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_BRACKET_RIGHT, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { - value = parse_pattern(parser, false, "Expected a pattern expression after the key."); + value = parse_pattern(parser, false, YP_ERR_PATTERN_EXPRESSION_AFTER_KEY); } else { const yp_location_t *value_loc = &((yp_symbol_node_t *) key)->value_loc; yp_parser_local_add_location(parser, value_loc->start, value_loc->end); @@ -10399,7 +10401,7 @@ parse_pattern_hash(yp_parser_t *parser, yp_node_t *first_assoc) { // Parse a pattern expression primitive. static yp_node_t * -parse_pattern_primitive(yp_parser_t *parser, const char *message) { +parse_pattern_primitive(yp_parser_t *parser, yp_diagnostic_id_t diag_id) { switch (parser->current.type) { case YP_TOKEN_IDENTIFIER: { parser_lex(parser); @@ -10418,11 +10420,11 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { // Otherwise, we'll parse the inner pattern, then deal with it depending // on the type it returns. - yp_node_t *inner = parse_pattern(parser, true, "Expected a pattern expression after the [ operator."); + yp_node_t *inner = parse_pattern(parser, true, YP_ERR_PATTERN_EXPRESSION_AFTER_BRACKET); accept(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_BRACKET_RIGHT, "Expected a ] to close the pattern expression."); + expect(parser, YP_TOKEN_BRACKET_RIGHT, YP_ERR_PATTERN_TERM_BRACKET); yp_token_t closing = parser->previous; switch (YP_NODE_TYPE(inner)) { @@ -10486,15 +10488,15 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { key = parse_pattern_keyword_rest(parser); break; case YP_TOKEN_STRING_BEGIN: - key = parse_expression(parser, YP_BINDING_POWER_MAX, "Expected a key in the hash pattern."); + key = parse_expression(parser, YP_BINDING_POWER_MAX, YP_ERR_PATTERN_HASH_KEY); if (!yp_symbol_node_label_p(key)) { - yp_diagnostic_list_append(&parser->error_list, key->location.start, key->location.end, "Expected a label as the key in the hash pattern."); + yp_diagnostic_list_append(&parser->error_list, key->location.start, key->location.end, YP_ERR_PATTERN_HASH_KEY_LABEL); } break; default: parser_lex(parser); - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Expected a key in the hash pattern."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_PATTERN_HASH_KEY); key = (yp_node_t *) yp_missing_node_create(parser, parser->previous.start, parser->previous.end); break; } @@ -10503,7 +10505,7 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { node = parse_pattern_hash(parser, (yp_node_t *) yp_assoc_node_create(parser, key, &operator, NULL)); accept(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_BRACE_RIGHT, "Expected a } to close the pattern expression."); + expect(parser, YP_TOKEN_BRACE_RIGHT, YP_ERR_PATTERN_TERM_BRACE); yp_token_t closing = parser->previous; node->base.location.start = opening.start; @@ -10525,18 +10527,18 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { // expression as the right side of the range. switch (parser->current.type) { case YP_CASE_PRIMITIVE: { - yp_node_t *right = parse_expression(parser, YP_BINDING_POWER_MAX, "Expected an expression after the range operator."); + yp_node_t *right = parse_expression(parser, YP_BINDING_POWER_MAX, YP_ERR_PATTERN_EXPRESSION_AFTER_RANGE); return (yp_node_t *) yp_range_node_create(parser, NULL, &operator, right); } default: { - yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, "Expected an expression after the range operator."); + yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, YP_ERR_PATTERN_EXPRESSION_AFTER_RANGE); yp_node_t *right = (yp_node_t *) yp_missing_node_create(parser, operator.start, operator.end); return (yp_node_t *) yp_range_node_create(parser, NULL, &operator, right); } } } case YP_CASE_PRIMITIVE: { - yp_node_t *node = parse_expression(parser, YP_BINDING_POWER_MAX, message); + yp_node_t *node = parse_expression(parser, YP_BINDING_POWER_MAX, diag_id); // Now that we have a primitive, we need to check if it's part of a range. if (accept_any(parser, 2, YP_TOKEN_DOT_DOT, YP_TOKEN_DOT_DOT_DOT)) { @@ -10547,7 +10549,7 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { // node. Otherwise, we'll create an endless range. switch (parser->current.type) { case YP_CASE_PRIMITIVE: { - yp_node_t *right = parse_expression(parser, YP_BINDING_POWER_MAX, "Expected an expression after the range operator."); + yp_node_t *right = parse_expression(parser, YP_BINDING_POWER_MAX, YP_ERR_PATTERN_EXPRESSION_AFTER_RANGE); return (yp_node_t *) yp_range_node_create(parser, node, &operator, right); } default: @@ -10607,17 +10609,17 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { yp_token_t lparen = parser->current; parser_lex(parser); - yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_STATEMENT, "Expected an expression after the pin operator."); + yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_STATEMENT, YP_ERR_PATTERN_EXPRESSION_AFTER_PIN); parser->pattern_matching_newlines = previous_pattern_matching_newlines; accept(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected a closing parenthesis after the expression."); + expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_PATTERN_TERM_PAREN); return (yp_node_t *) yp_pinned_expression_node_create(parser, expression, &operator, &lparen, &parser->previous); } default: { // If we get here, then we have a pin operator followed by something // not understood. We'll create a missing node and return that. - yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, "Expected a variable after the pin operator."); + yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, YP_ERR_PATTERN_EXPRESSION_AFTER_PIN); yp_node_t *variable = (yp_node_t *) yp_missing_node_create(parser, operator.start, operator.end); return (yp_node_t *) yp_pinned_variable_node_create(parser, &operator, variable); } @@ -10627,7 +10629,7 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { yp_token_t delimiter = parser->current; parser_lex(parser); - expect(parser, YP_TOKEN_CONSTANT, "Expected a constant after the :: operator."); + expect(parser, YP_TOKEN_CONSTANT, YP_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT); yp_node_t *child = (yp_node_t *) yp_constant_read_node_create(parser, &parser->previous); yp_constant_path_node_t *node = yp_constant_path_node_create(parser, NULL, &delimiter, child); @@ -10641,7 +10643,7 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { return parse_pattern_constant_path(parser, node); } default: - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, message); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, diag_id); return (yp_node_t *) yp_missing_node_create(parser, parser->current.start, parser->current.end); } } @@ -10649,7 +10651,7 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { // Parse any number of primitives joined by alternation and ended optionally by // assignment. static yp_node_t * -parse_pattern_primitives(yp_parser_t *parser, const char *message) { +parse_pattern_primitives(yp_parser_t *parser, yp_diagnostic_id_t diag_id) { yp_node_t *node = NULL; do { @@ -10666,9 +10668,9 @@ parse_pattern_primitives(yp_parser_t *parser, const char *message) { case YP_TOKEN_UDOT_DOT_DOT: case YP_CASE_PRIMITIVE: { if (node == NULL) { - node = parse_pattern_primitive(parser, message); + node = parse_pattern_primitive(parser, diag_id); } else { - yp_node_t *right = parse_pattern_primitive(parser, "Expected to be able to parse a pattern after `|'."); + yp_node_t *right = parse_pattern_primitive(parser, YP_ERR_PATTERN_EXPRESSION_AFTER_PIPE); node = (yp_node_t *) yp_alternation_pattern_node_create(parser, node, right, &operator); } @@ -10679,13 +10681,13 @@ parse_pattern_primitives(yp_parser_t *parser, const char *message) { if (node != NULL) { yp_node_destroy(parser, node); } - node = parse_pattern(parser, false, "Expected a pattern after the opening parenthesis."); + node = parse_pattern(parser, false, YP_ERR_PATTERN_EXPRESSION_AFTER_PAREN); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected a closing parenthesis after the pattern."); + expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_PATTERN_TERM_PAREN); break; } default: { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, message); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, diag_id); yp_node_t *right = (yp_node_t *) yp_missing_node_create(parser, parser->current.start, parser->current.end); if (node == NULL) { @@ -10704,7 +10706,7 @@ parse_pattern_primitives(yp_parser_t *parser, const char *message) { while (accept(parser, YP_TOKEN_EQUAL_GREATER)) { yp_token_t operator = parser->previous; - expect(parser, YP_TOKEN_IDENTIFIER, "Expected an identifier after the `=>' operator."); + expect(parser, YP_TOKEN_IDENTIFIER, YP_ERR_PATTERN_IDENT_AFTER_HROCKET); yp_token_t identifier = parser->previous; yp_parser_local_add_token(parser, &identifier); @@ -10717,7 +10719,7 @@ parse_pattern_primitives(yp_parser_t *parser, const char *message) { // Parse a pattern matching expression. static yp_node_t * -parse_pattern(yp_parser_t *parser, bool top_pattern, const char *message) { +parse_pattern(yp_parser_t *parser, bool top_pattern, yp_diagnostic_id_t diag_id) { yp_node_t *node = NULL; bool leading_rest = false; @@ -10745,7 +10747,7 @@ parse_pattern(yp_parser_t *parser, bool top_pattern, const char *message) { } /* fallthrough */ default: - node = parse_pattern_primitives(parser, message); + node = parse_pattern_primitives(parser, diag_id); break; } @@ -10777,12 +10779,12 @@ parse_pattern(yp_parser_t *parser, bool top_pattern, const char *message) { // will continue to parse the rest of the patterns, but we will indicate // it as an error. if (trailing_rest) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected rest pattern."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_PATTERN_REST); } trailing_rest = true; } else { - node = parse_pattern_primitives(parser, "Expected a pattern after the comma."); + node = parse_pattern_primitives(parser, YP_ERR_PATTERN_EXPRESSION_AFTER_COMMA); } yp_node_list_append(&nodes, node); @@ -10850,7 +10852,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { } if (yp_array_node_size(array) != 0) { - expect(parser, YP_TOKEN_COMMA, "Expected a separator for the elements in an array."); + expect(parser, YP_TOKEN_COMMA, YP_ERR_ARRAY_SEPARATOR); } // If we have a right bracket immediately following a comma, this is @@ -10862,11 +10864,11 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { if (accept(parser, YP_TOKEN_USTAR)) { yp_token_t operator = parser->previous; - yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected an expression after '*' in the array."); + yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_ARRAY_EXPRESSION_AFTER_STAR); element = (yp_node_t *) yp_splat_node_create(parser, &operator, expression); } else if (match_any_type_p(parser, 2, YP_TOKEN_LABEL, YP_TOKEN_USTAR_STAR)) { if (parsed_bare_hash) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unexpected bare hash."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_EXPRESSION_BARE_HASH); } yp_keyword_hash_node_t *hash = yp_keyword_hash_node_create(parser); @@ -10878,11 +10880,11 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parsed_bare_hash = true; } else { - element = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected an element for the array."); + element = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_ARRAY_EXPRESSION); if (yp_symbol_node_label_p(element) || accept(parser, YP_TOKEN_EQUAL_GREATER)) { if (parsed_bare_hash) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected bare hash."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_EXPRESSION_BARE_HASH); } yp_keyword_hash_node_t *hash = yp_keyword_hash_node_create(parser); @@ -10894,7 +10896,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { operator = not_provided(parser); } - yp_node_t *value = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value in the hash literal."); + yp_node_t *value = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_HASH_VALUE); yp_node_t *assoc = (yp_node_t *) yp_assoc_node_create(parser, element, &operator, value); yp_keyword_hash_node_elements_append(hash, assoc); @@ -10912,7 +10914,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { } accept(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_BRACKET_RIGHT, "Expected a closing bracket for the array."); + expect(parser, YP_TOKEN_BRACKET_RIGHT, YP_ERR_ARRAY_TERM); yp_array_node_close_set(array, &parser->previous); yp_accepts_block_stack_pop(parser); @@ -10927,14 +10929,14 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { // If this is the end of the file or we match a right parenthesis, then // we have an empty parentheses node, and we can immediately return. if (match_any_type_p(parser, 2, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_EOF)) { - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected a closing parenthesis."); + expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_EXPECT_RPAREN); return (yp_node_t *) yp_parentheses_node_create(parser, &opening, NULL, &parser->previous); } // Otherwise, we're going to parse the first statement in the list of // statements within the parentheses. yp_accepts_block_stack_push(parser, true); - yp_node_t *statement = parse_expression(parser, YP_BINDING_POWER_STATEMENT, "Expected to be able to parse an expression."); + yp_node_t *statement = parse_expression(parser, YP_BINDING_POWER_STATEMENT, YP_ERR_CANNOT_PARSE_EXPRESSION); while (accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)); // If we hit a right parenthesis, then we're done parsing the parentheses @@ -10992,7 +10994,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { // Ignore semicolon without statements before them if (accept_any(parser, 2, YP_TOKEN_SEMICOLON, YP_TOKEN_NEWLINE)) continue; - yp_node_t *node = parse_expression(parser, YP_BINDING_POWER_STATEMENT, "Expected to be able to parse an expression."); + yp_node_t *node = parse_expression(parser, YP_BINDING_POWER_STATEMENT, YP_ERR_CANNOT_PARSE_EXPRESSION); yp_statements_node_body_append(statements, node); // If we're recovering from a syntax error, then we need to stop parsing the @@ -11009,7 +11011,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { context_pop(parser); yp_accepts_block_stack_pop(parser); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected a closing parenthesis."); + expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_EXPECT_RPAREN); return (yp_node_t *) yp_parentheses_node_create(parser, &opening, (yp_node_t *) statements, &parser->previous); } @@ -11024,7 +11026,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { } yp_accepts_block_stack_pop(parser); - expect(parser, YP_TOKEN_BRACE_RIGHT, "Expected a closing delimiter for a hash literal."); + expect(parser, YP_TOKEN_BRACE_RIGHT, YP_ERR_HASH_TERM); yp_hash_node_closing_loc_set(node, &parser->previous); return (yp_node_t *) node; @@ -11084,7 +11086,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t delimiter = parser->previous; - expect(parser, YP_TOKEN_CONSTANT, "Expected a constant after ::."); + expect(parser, YP_TOKEN_CONSTANT, YP_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT); yp_node_t *constant = (yp_node_t *) yp_constant_read_node_create(parser, &parser->previous); yp_node_t *node = (yp_node_t *)yp_constant_path_node_create(parser, NULL, &delimiter, constant); @@ -11100,7 +11102,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_token_t operator = parser->current; parser_lex(parser); - yp_node_t *right = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *right = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (yp_node_t *) yp_range_node_create(parser, NULL, &operator, right); } case YP_TOKEN_FLOAT: @@ -11229,7 +11231,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { } lex_state_set(parser, YP_LEX_STATE_END); - expect(parser, YP_TOKEN_HEREDOC_END, "Expected a closing delimiter for heredoc."); + expect(parser, YP_TOKEN_HEREDOC_END, YP_ERR_HEREDOC_TERM); if (quote == YP_HEREDOC_QUOTE_BACKTICK) { assert(YP_NODE_TYPE_P(node, YP_INTERPOLATED_X_STRING_NODE)); @@ -11254,7 +11256,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { return (yp_node_t *) yp_string_concat_node_create( parser, node, - parse_expression(parser, YP_BINDING_POWER_CALL, "Expected string on the right side of concatenation.") + parse_expression(parser, YP_BINDING_POWER_CALL, YP_ERR_CANNOT_PARSE_EXPRESSION) ); } else { return node; @@ -11302,7 +11304,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { case YP_SYMBOL_NODE: case YP_INTERPOLATED_SYMBOL_NODE: { if (!YP_NODE_TYPE_P(old_name, YP_SYMBOL_NODE) && !YP_NODE_TYPE_P(old_name, YP_INTERPOLATED_SYMBOL_NODE)) { - yp_diagnostic_list_append(&parser->error_list, old_name->location.start, old_name->location.end, "Expected a bare word or symbol argument."); + yp_diagnostic_list_append(&parser->error_list, old_name->location.start, old_name->location.end, YP_ERR_ALIAS_ARGUMENT); } break; } @@ -11311,10 +11313,10 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { case YP_GLOBAL_VARIABLE_READ_NODE: { if (YP_NODE_TYPE_P(old_name, YP_BACK_REFERENCE_READ_NODE) || YP_NODE_TYPE_P(old_name, YP_NUMBERED_REFERENCE_READ_NODE) || YP_NODE_TYPE_P(old_name, YP_GLOBAL_VARIABLE_READ_NODE)) { if (YP_NODE_TYPE_P(old_name, YP_NUMBERED_REFERENCE_READ_NODE)) { - yp_diagnostic_list_append(&parser->error_list, old_name->location.start, old_name->location.end, "Can't make alias for number variables."); + yp_diagnostic_list_append(&parser->error_list, old_name->location.start, old_name->location.end, YP_ERR_ALIAS_ARGUMENT); } } else { - yp_diagnostic_list_append(&parser->error_list, old_name->location.start, old_name->location.end, "Expected a global variable."); + yp_diagnostic_list_append(&parser->error_list, old_name->location.start, old_name->location.end, YP_ERR_ALIAS_ARGUMENT); } break; } @@ -11336,7 +11338,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { ) { predicate = NULL; } else { - predicate = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected a value after case keyword."); + predicate = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, YP_ERR_CASE_EXPRESSION_AFTER_CASE); while (accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)); } @@ -11360,14 +11362,14 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { do { if (accept(parser, YP_TOKEN_USTAR)) { yp_token_t operator = parser->previous; - yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value after `*' operator."); + yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_EXPECT_EXPRESSION_AFTER_STAR); yp_splat_node_t *splat_node = yp_splat_node_create(parser, &operator, expression); yp_when_node_conditions_append(when_node, (yp_node_t *) splat_node); if (YP_NODE_TYPE_P(expression, YP_MISSING_NODE)) break; } else { - yp_node_t *condition = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value after when keyword."); + yp_node_t *condition = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_CASE_EXPRESSION_AFTER_WHEN); yp_when_node_conditions_append(when_node, condition); if (YP_NODE_TYPE_P(condition, YP_MISSING_NODE)) break; @@ -11377,7 +11379,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { if (accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { accept(parser, YP_TOKEN_KEYWORD_THEN); } else { - expect(parser, YP_TOKEN_KEYWORD_THEN, "Expected a delimiter after the predicates of a `when' clause."); + expect(parser, YP_TOKEN_KEYWORD_THEN, YP_ERR_EXPECT_WHEN_DELIMITER); } if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_WHEN, YP_TOKEN_KEYWORD_ELSE, YP_TOKEN_KEYWORD_END)) { @@ -11401,18 +11403,18 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t in_keyword = parser->previous; - yp_node_t *pattern = parse_pattern(parser, true, "Expected a pattern after `in' keyword."); + yp_node_t *pattern = parse_pattern(parser, true, YP_ERR_PATTERN_EXPRESSION_AFTER_IN); parser->pattern_matching_newlines = previous_pattern_matching_newlines; // Since we're in the top-level of the case-in node we need to check // for guard clauses in the form of `if` or `unless` statements. if (accept(parser, YP_TOKEN_KEYWORD_IF_MODIFIER)) { yp_token_t keyword = parser->previous; - yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value after guard keyword."); + yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_CONDITIONAL_IF_PREDICATE); pattern = (yp_node_t *) yp_if_node_modifier_create(parser, pattern, &keyword, predicate); } else if (accept(parser, YP_TOKEN_KEYWORD_UNLESS_MODIFIER)) { yp_token_t keyword = parser->previous; - yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value after guard keyword."); + yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_CONDITIONAL_UNLESS_PREDICATE); pattern = (yp_node_t *) yp_unless_node_modifier_create(parser, pattern, &keyword, predicate); } @@ -11427,7 +11429,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { then_keyword = not_provided(parser); } } else { - expect(parser, YP_TOKEN_KEYWORD_THEN, "Expected a delimiter after the predicates of an `in' clause."); + expect(parser, YP_TOKEN_KEYWORD_THEN, YP_ERR_EXPECT_WHEN_DELIMITER); then_keyword = parser->previous; } @@ -11450,7 +11452,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); if (accept(parser, YP_TOKEN_KEYWORD_ELSE)) { if (case_node->conditions.size < 1) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected else without no when clauses in case statement."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_CASE_LONELY_ELSE); } yp_token_t else_keyword = parser->previous; @@ -11465,7 +11467,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_case_node_consequent_set(case_node, else_node); } - expect(parser, YP_TOKEN_KEYWORD_END, "Expected case statement to end with an end keyword."); + expect(parser, YP_TOKEN_KEYWORD_END, YP_ERR_CASE_TERM); yp_case_node_end_keyword_loc_set(case_node, &parser->previous); return (yp_node_t *) case_node; } @@ -11486,7 +11488,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_begin_node_t *begin_node = yp_begin_node_create(parser, &begin_keyword, begin_statements); parse_rescues(parser, begin_node); - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `begin` statement."); + expect(parser, YP_TOKEN_KEYWORD_END, YP_ERR_BEGIN_TERM); begin_node->base.location.end = parser->previous.end; yp_begin_node_end_keyword_set(begin_node, &parser->previous); @@ -11495,7 +11497,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { &parser->error_list, begin_node->else_clause->base.location.start, begin_node->else_clause->base.location.end, - "else without rescue is useless" + YP_ERR_BEGIN_LONELY_ELSE ); } @@ -11505,11 +11507,11 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t keyword = parser->previous; - expect(parser, YP_TOKEN_BRACE_LEFT, "Expected '{' after 'BEGIN'."); + expect(parser, YP_TOKEN_BRACE_LEFT, YP_ERR_BEGIN_UPCASE_BRACE); yp_token_t opening = parser->previous; yp_statements_node_t *statements = parse_statements(parser, YP_CONTEXT_PREEXE); - expect(parser, YP_TOKEN_BRACE_RIGHT, "Expected '}' after 'BEGIN' statements."); + expect(parser, YP_TOKEN_BRACE_RIGHT, YP_ERR_BEGIN_UPCASE_TERM); return (yp_node_t *) yp_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous); } case YP_TOKEN_KEYWORD_BREAK: @@ -11542,7 +11544,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { (parser->current_context->context == YP_CONTEXT_CLASS) || (parser->current_context->context == YP_CONTEXT_MODULE) ) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid return in class/module body"); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_RETURN_INVALID); } return (yp_node_t *) yp_return_node_create(parser, &keyword, arguments.arguments); } @@ -11580,7 +11582,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { if (accept(parser, YP_TOKEN_LESS_LESS)) { yp_token_t operator = parser->previous; - yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_NOT, "Expected to find an expression after `<<`."); + yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_NOT, YP_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS); yp_parser_scope_push(parser, true); accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); @@ -11597,7 +11599,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { statements = (yp_node_t *) parse_rescues_as_begin(parser, (yp_statements_node_t *) statements); } - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `class` statement."); + expect(parser, YP_TOKEN_KEYWORD_END, YP_ERR_CLASS_TERM); yp_constant_id_list_t locals = parser->current_scope->locals; yp_parser_scope_pop(parser); @@ -11605,10 +11607,10 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { return (yp_node_t *) yp_singleton_class_node_create(parser, &locals, &class_keyword, &operator, expression, statements, &parser->previous); } - yp_node_t *constant_path = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected to find a class name after `class`."); + yp_node_t *constant_path = parse_expression(parser, YP_BINDING_POWER_INDEX, YP_ERR_CLASS_NAME); yp_token_t name = parser->previous; if (name.type != YP_TOKEN_CONSTANT) { - yp_diagnostic_list_append(&parser->error_list, name.start, name.end, "Expected a constant name after `class`."); + yp_diagnostic_list_append(&parser->error_list, name.start, name.end, YP_ERR_CLASS_NAME); } yp_token_t inheritance_operator; @@ -11621,7 +11623,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser->command_start = true; parser_lex(parser); - superclass = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected to find a superclass after `<`."); + superclass = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, YP_ERR_CLASS_SUPERCLASS); } else { inheritance_operator = not_provided(parser); superclass = NULL; @@ -11642,10 +11644,10 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { statements = (yp_node_t *) parse_rescues_as_begin(parser, (yp_statements_node_t *) statements); } - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `class` statement."); + expect(parser, YP_TOKEN_KEYWORD_END, YP_ERR_CLASS_TERM); if (context_def_p(parser)) { - yp_diagnostic_list_append(&parser->error_list, class_keyword.start, class_keyword.end, "Class definition in method body"); + yp_diagnostic_list_append(&parser->error_list, class_keyword.start, class_keyword.end, YP_ERR_CLASS_IN_METHOD); } yp_constant_id_list_t locals = parser->current_scope->locals; @@ -11684,7 +11686,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { name = parse_method_definition_name(parser); if (name.type == YP_TOKEN_MISSING) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Expected a method name after receiver."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_DEF_NAME_AFTER_RECEIVER); } } else { name = parser->previous; @@ -11752,7 +11754,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { name = parse_method_definition_name(parser); if (name.type == YP_TOKEN_MISSING) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Expected a method name after receiver."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_DEF_NAME_AFTER_RECEIVER); } } else { name = identifier; @@ -11762,13 +11764,13 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { case YP_TOKEN_PARENTHESIS_LEFT: { parser_lex(parser); yp_token_t lparen = parser->previous; - yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_STATEMENT, "Expected to be able to parse receiver."); + yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_STATEMENT, YP_ERR_DEF_RECEIVER); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected closing ')' for receiver."); + expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_EXPECT_RPAREN); yp_token_t rparen = parser->previous; lex_state_set(parser, YP_LEX_STATE_FNAME); - expect_any(parser, "Expected '.' or '::' after receiver", 2, YP_TOKEN_DOT, YP_TOKEN_COLON_COLON); + expect_any(parser, YP_ERR_DEF_RECEIVER_TERM, 2, YP_TOKEN_DOT, YP_TOKEN_COLON_COLON); operator = parser->previous; receiver = (yp_node_t *) yp_parentheses_node_create(parser, &lparen, expression, &rparen); @@ -11782,7 +11784,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { name = parse_method_definition_name(parser); if (name.type == YP_TOKEN_MISSING) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Expected a method name after receiver."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_DEF_NAME); } break; } @@ -11805,7 +11807,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { lex_state_set(parser, YP_LEX_STATE_BEG); parser->command_start = true; - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected ')' after left parenthesis."); + expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_DEF_PARAMS_TERM_PAREN); rparen = parser->previous; break; } @@ -11836,18 +11838,18 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { if (accept(parser, YP_TOKEN_EQUAL)) { if (token_is_setter_name(&name)) { - yp_diagnostic_list_append(&parser->error_list, name.start, name.end, "Setter method cannot be defined in an endless method definition"); + yp_diagnostic_list_append(&parser->error_list, name.start, name.end, YP_ERR_DEF_ENDLESS_SETTER); } equal = parser->previous; context_push(parser, YP_CONTEXT_DEF); statements = (yp_node_t *) yp_statements_node_create(parser); - yp_node_t *statement = parse_expression(parser, YP_BINDING_POWER_DEFINED + 1, "Expected to be able to parse body of endless method definition."); + yp_node_t *statement = parse_expression(parser, YP_BINDING_POWER_DEFINED + 1, YP_ERR_DEF_ENDLESS); if (accept(parser, YP_TOKEN_KEYWORD_RESCUE_MODIFIER)) { yp_token_t rescue_keyword = parser->previous; - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the rescue keyword."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_RESCUE_MODIFIER_VALUE); yp_rescue_modifier_node_t *rescue_node = yp_rescue_modifier_node_create(parser, statement, &rescue_keyword, value); statement = (yp_node_t *)rescue_node; } @@ -11861,7 +11863,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { if (lparen.type == YP_TOKEN_NOT_PROVIDED) { lex_state_set(parser, YP_LEX_STATE_BEG); parser->command_start = true; - expect_any(parser, "Expected a terminator after the parameters", 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + expect_any(parser, YP_ERR_DEF_PARAMS_TERM, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); } else { accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); } @@ -11882,7 +11884,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_accepts_block_stack_pop(parser); yp_do_loop_stack_pop(parser); - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `def` statement."); + expect(parser, YP_TOKEN_KEYWORD_END, YP_ERR_DEF_TERM); end_keyword = parser->previous; } @@ -11914,18 +11916,18 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { if (accept(parser, YP_TOKEN_PARENTHESIS_LEFT)) { lparen = parser->previous; - expression = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected expression after `defined?`."); + expression = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, YP_ERR_DEFINED_EXPRESSION); if (parser->recovering) { rparen = not_provided(parser); } else { - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected ')' after 'defined?' expression."); + expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_EXPECT_RPAREN); rparen = parser->previous; } } else { lparen = not_provided(parser); rparen = not_provided(parser); - expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected expression after `defined?`."); + expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_DEFINED_EXPRESSION); } return (yp_node_t *) yp_defined_node_create( @@ -11940,11 +11942,11 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t keyword = parser->previous; - expect(parser, YP_TOKEN_BRACE_LEFT, "Expected '{' after 'END'."); + expect(parser, YP_TOKEN_BRACE_LEFT, YP_ERR_END_UPCASE_BRACE); yp_token_t opening = parser->previous; yp_statements_node_t *statements = parse_statements(parser, YP_CONTEXT_POSTEXE); - expect(parser, YP_TOKEN_BRACE_RIGHT, "Expected '}' after 'END' statements."); + expect(parser, YP_TOKEN_BRACE_RIGHT, YP_ERR_END_UPCASE_TERM); return (yp_node_t *) yp_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous); } case YP_TOKEN_KEYWORD_FALSE: @@ -11957,10 +11959,10 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_node_t *index = parse_targets(parser, NULL, YP_BINDING_POWER_INDEX); yp_do_loop_stack_push(parser, true); - expect(parser, YP_TOKEN_KEYWORD_IN, "Expected keyword in."); + expect(parser, YP_TOKEN_KEYWORD_IN, YP_ERR_FOR_IN); yp_token_t in_keyword = parser->previous; - yp_node_t *collection = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected collection."); + yp_node_t *collection = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, YP_ERR_FOR_COLLECTION); yp_do_loop_stack_pop(parser); yp_token_t do_keyword; @@ -11975,7 +11977,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { if (!accept(parser, YP_TOKEN_KEYWORD_END)) { statements = parse_statements(parser, YP_CONTEXT_FOR); - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close for loop."); + expect(parser, YP_TOKEN_KEYWORD_END, YP_ERR_FOR_TERM); } return (yp_node_t *) yp_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->previous); @@ -12024,17 +12026,17 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { if (accept(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { arguments.closing_loc = YP_LOCATION_TOKEN_VALUE(&parser->previous); } else { - receiver = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected expression after `not`."); + receiver = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, YP_ERR_NOT_EXPRESSION); yp_flip_flop(receiver); if (!parser->recovering) { accept(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected ')' after 'not' expression."); + expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_EXPECT_RPAREN); arguments.closing_loc = YP_LOCATION_TOKEN_VALUE(&parser->previous); } } } else { - receiver = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected expression after `not`."); + receiver = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_NOT_EXPRESSION); yp_flip_flop(receiver); } @@ -12047,7 +12049,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t module_keyword = parser->previous; - yp_node_t *constant_path = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected to find a module name after `module`."); + yp_node_t *constant_path = parse_expression(parser, YP_BINDING_POWER_INDEX, YP_ERR_MODULE_NAME); yp_token_t name; // If we can recover from a syntax error that occurred while parsing @@ -12060,7 +12062,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { while (accept(parser, YP_TOKEN_COLON_COLON)) { yp_token_t double_colon = parser->previous; - expect(parser, YP_TOKEN_CONSTANT, "Expected to find a module name after `::`."); + expect(parser, YP_TOKEN_CONSTANT, YP_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT); yp_node_t *constant = (yp_node_t *) yp_constant_read_node_create(parser, &parser->previous); constant_path = (yp_node_t *) yp_constant_path_node_create(parser, constant_path, &double_colon, constant); @@ -12071,7 +12073,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { // syntax error. We handle that here as well. name = parser->previous; if (name.type != YP_TOKEN_CONSTANT) { - yp_diagnostic_list_append(&parser->error_list, name.start, name.end, "Expected to find a module name after `module`."); + yp_diagnostic_list_append(&parser->error_list, name.start, name.end, YP_ERR_MODULE_NAME); } yp_parser_scope_push(parser, true); @@ -12092,10 +12094,10 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_constant_id_list_t locals = parser->current_scope->locals; yp_parser_scope_pop(parser); - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `module` statement."); + expect(parser, YP_TOKEN_KEYWORD_END, YP_ERR_MODULE_TERM); if (context_def_p(parser)) { - yp_diagnostic_list_append(&parser->error_list, module_keyword.start, module_keyword.end, "Module definition in method body"); + yp_diagnostic_list_append(&parser->error_list, module_keyword.start, module_keyword.end, YP_ERR_MODULE_IN_METHOD); } return (yp_node_t *) yp_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous); @@ -12120,7 +12122,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t keyword = parser->previous; - yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected predicate expression after `until`."); + yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, YP_ERR_CONDITIONAL_UNTIL_PREDICATE); yp_do_loop_stack_pop(parser); accept_any(parser, 3, YP_TOKEN_KEYWORD_DO_LOOP, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); @@ -12131,7 +12133,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { statements = parse_statements(parser, YP_CONTEXT_UNTIL); yp_accepts_block_stack_pop(parser); accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `until` statement."); + expect(parser, YP_TOKEN_KEYWORD_END, YP_ERR_UNTIL_TERM); } return (yp_node_t *) yp_until_node_create(parser, &keyword, &parser->previous, predicate, statements, 0); @@ -12141,7 +12143,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t keyword = parser->previous; - yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected predicate expression after `while`."); + yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, YP_ERR_CONDITIONAL_WHILE_PREDICATE); yp_do_loop_stack_pop(parser); accept_any(parser, 3, YP_TOKEN_KEYWORD_DO_LOOP, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); @@ -12152,7 +12154,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { statements = parse_statements(parser, YP_CONTEXT_WHILE); yp_accepts_block_stack_pop(parser); accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `while` statement."); + expect(parser, YP_TOKEN_KEYWORD_END, YP_ERR_WHILE_TERM); } return (yp_node_t *) yp_while_node_create(parser, &keyword, &parser->previous, predicate, statements, 0); @@ -12165,7 +12167,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { accept(parser, YP_TOKEN_WORDS_SEP); if (match_type_p(parser, YP_TOKEN_STRING_END)) break; - expect(parser, YP_TOKEN_STRING_CONTENT, "Expected a symbol in a `%i` list."); + expect(parser, YP_TOKEN_STRING_CONTENT, YP_ERR_LIST_I_LOWER_ELEMENT); yp_token_t opening = not_provided(parser); yp_token_t closing = not_provided(parser); @@ -12174,7 +12176,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_array_node_elements_append(array, symbol); } - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for a `%i` list."); + expect(parser, YP_TOKEN_STRING_END, YP_ERR_LIST_I_LOWER_TERM); yp_array_node_close_set(array, &parser->previous); return (yp_node_t *) array; @@ -12310,7 +12312,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { break; } default: - expect(parser, YP_TOKEN_STRING_CONTENT, "Expected a symbol in a `%I` list."); + expect(parser, YP_TOKEN_STRING_CONTENT, YP_ERR_LIST_I_UPPER_ELEMENT); parser_lex(parser); break; } @@ -12321,7 +12323,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_array_node_elements_append(array, current); } - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for a `%I` list."); + expect(parser, YP_TOKEN_STRING_END, YP_ERR_LIST_I_UPPER_TERM); yp_array_node_close_set(array, &parser->previous); return (yp_node_t *) array; @@ -12337,7 +12339,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { accept(parser, YP_TOKEN_WORDS_SEP); if (match_type_p(parser, YP_TOKEN_STRING_END)) break; - expect(parser, YP_TOKEN_STRING_CONTENT, "Expected a string in a `%w` list."); + expect(parser, YP_TOKEN_STRING_CONTENT, YP_ERR_LIST_W_LOWER_ELEMENT); yp_token_t opening = not_provided(parser); yp_token_t closing = not_provided(parser); @@ -12345,7 +12347,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_array_node_elements_append(array, string); } - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for a `%w` list."); + expect(parser, YP_TOKEN_STRING_END, YP_ERR_LIST_W_LOWER_TERM); yp_array_node_close_set(array, &parser->previous); return (yp_node_t *) array; @@ -12461,7 +12463,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { break; } default: - expect(parser, YP_TOKEN_STRING_CONTENT, "Expected a string in a `%W` list."); + expect(parser, YP_TOKEN_STRING_CONTENT, YP_ERR_LIST_W_UPPER_ELEMENT); parser_lex(parser); break; } @@ -12472,7 +12474,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_array_node_elements_append(array, current); } - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for a `%W` list."); + expect(parser, YP_TOKEN_STRING_END, YP_ERR_LIST_W_UPPER_TERM); yp_array_node_close_set(array, &parser->previous); return (yp_node_t *) array; @@ -12536,7 +12538,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { } } - expect(parser, YP_TOKEN_REGEXP_END, "Expected a closing delimiter for a regular expression."); + expect(parser, YP_TOKEN_REGEXP_END, YP_ERR_REGEXP_TERM); yp_interpolated_regular_expression_node_closing_set(node, &parser->previous); return (yp_node_t *) node; @@ -12600,7 +12602,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { } } - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for an xstring."); + expect(parser, YP_TOKEN_STRING_END, YP_ERR_XSTRING_TERM); yp_interpolated_xstring_node_closing_set(node, &parser->previous); return (yp_node_t *) node; } @@ -12618,7 +12620,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_node_t *name = NULL; if (token_begins_expression_p(parser->current.type)) { - name = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an expression after '*'."); + name = parse_expression(parser, YP_BINDING_POWER_INDEX, YP_ERR_EXPECT_EXPRESSION_AFTER_STAR); } yp_node_t *splat = (yp_node_t *) yp_splat_node_create(parser, &operator, name); @@ -12628,7 +12630,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t operator = parser->previous; - yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, "Expected a receiver after unary !."); + yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, YP_ERR_UNARY_RECEIVER_BANG); yp_call_node_t *node = yp_call_node_unary_create(parser, &operator, receiver, "!"); yp_flip_flop(receiver); @@ -12638,7 +12640,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t operator = parser->previous; - yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, "Expected a receiver after unary ~."); + yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, YP_ERR_UNARY_RECEIVER_TILDE); yp_call_node_t *node = yp_call_node_unary_create(parser, &operator, receiver, "~"); return (yp_node_t *) node; @@ -12647,7 +12649,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t operator = parser->previous; - yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, "Expected a receiver after unary -."); + yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, YP_ERR_UNARY_RECEIVER_MINUS); yp_call_node_t *node = yp_call_node_unary_create(parser, &operator, receiver, "-@"); return (yp_node_t *) node; @@ -12656,7 +12658,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t operator = parser->previous; - yp_node_t *node = parse_expression(parser, yp_binding_powers[parser->previous.type].right, "Expected a receiver after unary -."); + yp_node_t *node = parse_expression(parser, yp_binding_powers[parser->previous.type].right, YP_ERR_UNARY_RECEIVER_MINUS); switch (YP_NODE_TYPE(node)) { case YP_INTEGER_NODE: @@ -12695,7 +12697,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { } accept(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected ')' after left parenthesis."); + expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_EXPECT_RPAREN); yp_block_parameters_node_closing_set(params, &parser->previous); break; @@ -12722,10 +12724,10 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { if (!accept(parser, YP_TOKEN_BRACE_RIGHT)) { body = (yp_node_t *) parse_statements(parser, YP_CONTEXT_LAMBDA_BRACES); - expect(parser, YP_TOKEN_BRACE_RIGHT, "Expecting '}' to close lambda block."); + expect(parser, YP_TOKEN_BRACE_RIGHT, YP_ERR_LAMBDA_TERM_BRACE); } } else { - expect(parser, YP_TOKEN_KEYWORD_DO, "Expected a 'do' keyword or a '{' to open lambda block."); + expect(parser, YP_TOKEN_KEYWORD_DO, YP_ERR_LAMBDA_OPEN); opening = parser->previous; if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_END, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) { @@ -12739,7 +12741,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { body = (yp_node_t *) parse_rescues_as_begin(parser, (yp_statements_node_t *) body); } - expect(parser, YP_TOKEN_KEYWORD_END, "Expecting 'end' keyword to close lambda block."); + expect(parser, YP_TOKEN_KEYWORD_END, YP_ERR_LAMBDA_TERM_END); } yp_constant_id_list_t locals = parser->current_scope->locals; @@ -12751,7 +12753,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t operator = parser->previous; - yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, "Expected a receiver after unary +."); + yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, YP_ERR_UNARY_RECEIVER_PLUS); yp_call_node_t *node = yp_call_node_unary_create(parser, &operator, receiver, "+@"); return (yp_node_t *) node; @@ -12793,7 +12795,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { } else if (!lex_interpolation) { // If we don't accept interpolation then we expect the // string to start with a single string content node. - expect(parser, YP_TOKEN_STRING_CONTENT, "Expected string content after opening delimiter."); + expect(parser, YP_TOKEN_STRING_CONTENT, YP_ERR_EXPECT_STRING_CONTENT); yp_token_t content = parser->previous; // It is unfortunately possible to have multiple string @@ -12820,12 +12822,12 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_node_list_append(&parts, part); } - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for a string literal."); + expect(parser, YP_TOKEN_STRING_END, YP_ERR_STRING_LITERAL_TERM); node = (yp_node_t *) yp_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); } else if (accept(parser, YP_TOKEN_LABEL_END)) { node = (yp_node_t *) yp_symbol_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_ALL); } else { - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for a string literal."); + expect(parser, YP_TOKEN_STRING_END, YP_ERR_STRING_LITERAL_TERM); node = (yp_node_t *) yp_string_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_MINIMAL); } } else if (match_type_p(parser, YP_TOKEN_STRING_CONTENT)) { @@ -12857,7 +12859,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { if (accept(parser, YP_TOKEN_LABEL_END)) { node = (yp_node_t *) yp_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous); } else { - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for an interpolated string."); + expect(parser, YP_TOKEN_STRING_END, YP_ERR_STRING_INTERPOLATED_TERM); node = (yp_node_t *) yp_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); } } @@ -12875,7 +12877,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { if (accept(parser, YP_TOKEN_LABEL_END)) { node = (yp_node_t *) yp_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous); } else { - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for an interpolated string."); + expect(parser, YP_TOKEN_STRING_END, YP_ERR_STRING_INTERPOLATED_TERM); node = (yp_node_t *) yp_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); } } @@ -12896,7 +12898,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { // parsed. If it cannot be concatenated with the previous // node, then we'll need to add a syntax error. if (!YP_NODE_TYPE_P(node, YP_STRING_NODE) && !YP_NODE_TYPE_P(node, YP_INTERPOLATED_STRING_NODE)) { - yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Unexpected string concatenation."); + yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, YP_ERR_STRING_CONCATENATION); } // Either way we will create a concat node to hold the @@ -12923,8 +12925,8 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { } static inline yp_node_t * -parse_assignment_value(yp_parser_t *parser, yp_binding_power_t previous_binding_power, yp_binding_power_t binding_power, const char *message) { - yp_node_t *value = parse_starred_expression(parser, binding_power, message); +parse_assignment_value(yp_parser_t *parser, yp_binding_power_t previous_binding_power, yp_binding_power_t binding_power, yp_diagnostic_id_t diag_id) { + yp_node_t *value = parse_starred_expression(parser, binding_power, diag_id); if (previous_binding_power == YP_BINDING_POWER_STATEMENT && (YP_NODE_TYPE_P(value, YP_SPLAT_NODE) || match_type_p(parser, YP_TOKEN_COMMA))) { yp_token_t opening = not_provided(parser); @@ -12934,7 +12936,7 @@ parse_assignment_value(yp_parser_t *parser, yp_binding_power_t previous_binding_ value = (yp_node_t *) array; while (accept(parser, YP_TOKEN_COMMA)) { - yp_node_t *element = parse_starred_expression(parser, binding_power, "Expected an element for the array."); + yp_node_t *element = parse_starred_expression(parser, binding_power, YP_ERR_ARRAY_ELEMENT); yp_array_node_elements_append(array, element); if (YP_NODE_TYPE_P(element, YP_MISSING_NODE)) break; } @@ -12963,7 +12965,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t /* fallthrough */ case YP_CASE_WRITABLE: { parser_lex(parser); - yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =."); + yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_EQUAL); return parse_write(parser, node, &token, value); } case YP_SPLAT_NODE: { @@ -12972,7 +12974,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t switch (YP_NODE_TYPE(splat_node->expression)) { case YP_CASE_WRITABLE: parser_lex(parser); - yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =."); + yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_EQUAL); return parse_write(parser, (yp_node_t *) splat_node, &token, value); default: break; @@ -12985,7 +12987,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t // In this case we have an = sign, but we don't know what it's for. We // need to treat it as an error. For now, we'll mark it as an error // and just skip right past it. - yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Unexpected `='."); + yp_diagnostic_list_append(&parser->error_list, token.start, token.end, YP_ERR_EXPECT_EXPRESSION_AFTER_EQUAL); return node; } } @@ -12993,12 +12995,12 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t switch (YP_NODE_TYPE(node)) { case YP_BACK_REFERENCE_READ_NODE: case YP_NUMBERED_REFERENCE_READ_NODE: - yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Can't set variable"); + yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, YP_ERR_WRITE_TARGET_READONLY); /* fallthrough */ case YP_GLOBAL_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); yp_node_t *result = (yp_node_t *) yp_global_variable_and_write_node_create(parser, node, &token, value); yp_node_destroy(parser, node); @@ -13007,7 +13009,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t case YP_CLASS_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); yp_node_t *result = (yp_node_t *) yp_class_variable_and_write_node_create(parser, (yp_class_variable_read_node_t *) node, &token, value); yp_node_destroy(parser, node); @@ -13016,13 +13018,13 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t case YP_CONSTANT_PATH_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); return (yp_node_t *) yp_constant_path_and_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value); } case YP_CONSTANT_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); yp_node_t *result = (yp_node_t *) yp_constant_and_write_node_create(parser, (yp_constant_read_node_t *) node, &token, value); yp_node_destroy(parser, node); @@ -13031,7 +13033,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t case YP_INSTANCE_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); yp_node_t *result = (yp_node_t *) yp_instance_variable_and_write_node_create(parser, (yp_instance_variable_read_node_t *) node, &token, value); yp_node_destroy(parser, node); @@ -13041,7 +13043,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node; parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); yp_node_t *result = (yp_node_t *) yp_local_variable_and_write_node_create(parser, node, &token, value, cast->name, cast->depth); yp_node_destroy(parser, node); @@ -13058,11 +13060,11 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t yp_constant_id_t constant_id = yp_parser_local_add_location(parser, message_loc.start, message_loc.end); if (token_is_numbered_parameter(message_loc.start, message_loc.end)) { - yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter"); + yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, YP_ERR_PARAMETER_NUMBERED_RESERVED); } parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); yp_node_t *result = (yp_node_t *) yp_local_variable_and_write_node_create(parser, node, &token, value, constant_id, 0); yp_node_destroy(parser, node); @@ -13072,12 +13074,12 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t parser_lex(parser); node = parse_target(parser, node); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); return (yp_node_t *) yp_call_and_write_node_create(parser, (yp_call_node_t *) node, &token, value); } case YP_MULTI_WRITE_NODE: { parser_lex(parser); - yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Cannot use `&&=' on a multi-write."); + yp_diagnostic_list_append(&parser->error_list, token.start, token.end, YP_ERR_AMPAMPEQ_MULTI_ASSIGN); return node; } default: @@ -13086,7 +13088,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t // In this case we have an &&= sign, but we don't know what it's for. // We need to treat it as an error. For now, we'll mark it as an error // and just skip right past it. - yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Unexpected `&&='."); + yp_diagnostic_list_append(&parser->error_list, token.start, token.end, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); return node; } } @@ -13094,12 +13096,12 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t switch (YP_NODE_TYPE(node)) { case YP_BACK_REFERENCE_READ_NODE: case YP_NUMBERED_REFERENCE_READ_NODE: - yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Can't set variable"); + yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, YP_ERR_WRITE_TARGET_READONLY); /* fallthrough */ case YP_GLOBAL_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); yp_node_t *result = (yp_node_t *) yp_global_variable_or_write_node_create(parser, node, &token, value); yp_node_destroy(parser, node); @@ -13108,7 +13110,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t case YP_CLASS_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); yp_node_t *result = (yp_node_t *) yp_class_variable_or_write_node_create(parser, (yp_class_variable_read_node_t *) node, &token, value); yp_node_destroy(parser, node); @@ -13117,13 +13119,13 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t case YP_CONSTANT_PATH_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); return (yp_node_t *) yp_constant_path_or_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value); } case YP_CONSTANT_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); yp_node_t *result = (yp_node_t *) yp_constant_or_write_node_create(parser, (yp_constant_read_node_t *) node, &token, value); yp_node_destroy(parser, node); @@ -13132,7 +13134,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t case YP_INSTANCE_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); yp_node_t *result = (yp_node_t *) yp_instance_variable_or_write_node_create(parser, (yp_instance_variable_read_node_t *) node, &token, value); yp_node_destroy(parser, node); @@ -13142,7 +13144,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node; parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); yp_node_t *result = (yp_node_t *) yp_local_variable_or_write_node_create(parser, node, &token, value, cast->name, cast->depth); yp_node_destroy(parser, node); @@ -13159,11 +13161,11 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t yp_constant_id_t constant_id = yp_parser_local_add_location(parser, message_loc.start, message_loc.end); if (token_is_numbered_parameter(message_loc.start, message_loc.end)) { - yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter"); + yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, YP_ERR_PARAMETER_NUMBERED_RESERVED); } parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); yp_node_t *result = (yp_node_t *) yp_local_variable_or_write_node_create(parser, node, &token, value, constant_id, 0); yp_node_destroy(parser, node); @@ -13173,12 +13175,12 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t parser_lex(parser); node = parse_target(parser, node); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); return (yp_node_t *) yp_call_or_write_node_create(parser, (yp_call_node_t *) node, &token, value); } case YP_MULTI_WRITE_NODE: { parser_lex(parser); - yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Cannot use `||=' on a multi-write."); + yp_diagnostic_list_append(&parser->error_list, token.start, token.end, YP_ERR_PIPEPIPEEQ_MULTI_ASSIGN); return node; } default: @@ -13187,7 +13189,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t // In this case we have an ||= sign, but we don't know what it's for. // We need to treat it as an error. For now, we'll mark it as an error // and just skip right past it. - yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Unexpected `||='."); + yp_diagnostic_list_append(&parser->error_list, token.start, token.end, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); return node; } } @@ -13205,12 +13207,12 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t switch (YP_NODE_TYPE(node)) { case YP_BACK_REFERENCE_READ_NODE: case YP_NUMBERED_REFERENCE_READ_NODE: - yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Can't set variable"); + yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, YP_ERR_WRITE_TARGET_READONLY); /* fallthrough */ case YP_GLOBAL_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); yp_node_t *result = (yp_node_t *) yp_global_variable_operator_write_node_create(parser, node, &token, value); yp_node_destroy(parser, node); @@ -13219,7 +13221,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t case YP_CLASS_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); yp_node_t *result = (yp_node_t *) yp_class_variable_operator_write_node_create(parser, (yp_class_variable_read_node_t *) node, &token, value); yp_node_destroy(parser, node); @@ -13228,13 +13230,13 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t case YP_CONSTANT_PATH_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (yp_node_t *) yp_constant_path_operator_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value); } case YP_CONSTANT_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); yp_node_t *result = (yp_node_t *) yp_constant_operator_write_node_create(parser, (yp_constant_read_node_t *) node, &token, value); yp_node_destroy(parser, node); @@ -13243,7 +13245,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t case YP_INSTANCE_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); yp_node_t *result = (yp_node_t *) yp_instance_variable_operator_write_node_create(parser, (yp_instance_variable_read_node_t *) node, &token, value); yp_node_destroy(parser, node); @@ -13253,7 +13255,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node; parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); yp_node_t *result = (yp_node_t *) yp_local_variable_operator_write_node_create(parser, node, &token, value, cast->name, cast->depth); yp_node_destroy(parser, node); @@ -13270,11 +13272,11 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t yp_constant_id_t constant_id = yp_parser_local_add_location(parser, message_loc.start, message_loc.end); if (token_is_numbered_parameter(message_loc.start, message_loc.end)) { - yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter"); + yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, YP_ERR_PARAMETER_NUMBERED_RESERVED); } parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); yp_node_t *result = (yp_node_t *) yp_local_variable_operator_write_node_create(parser, node, &token, value, constant_id, 0); yp_node_destroy(parser, node); @@ -13284,12 +13286,12 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t node = parse_target(parser, node); parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (yp_node_t *) yp_call_operator_write_node_create(parser, (yp_call_node_t *) node, &token, value); } case YP_MULTI_WRITE_NODE: { parser_lex(parser); - yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Unexpected operator."); + yp_diagnostic_list_append(&parser->error_list, token.start, token.end, YP_ERR_OPERATOR_MULTI_ASSIGN); return node; } default: @@ -13298,7 +13300,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t // In this case we have an operator but we don't know what it's for. // We need to treat it as an error. For now, we'll mark it as an error // and just skip right past it. - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected operator."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return node; } } @@ -13306,14 +13308,14 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t case YP_TOKEN_KEYWORD_AND: { parser_lex(parser); - yp_node_t *right = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *right = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (yp_node_t *) yp_and_node_create(parser, node, &token, right); } case YP_TOKEN_KEYWORD_OR: case YP_TOKEN_PIPE_PIPE: { parser_lex(parser); - yp_node_t *right = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *right = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (yp_node_t *) yp_or_node_create(parser, node, &token, right); } case YP_TOKEN_EQUAL_TILDE: { @@ -13324,7 +13326,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t // // In this case, `foo` should be a method call and not a local yet. parser_lex(parser); - yp_node_t *argument = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *argument = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); // If the receiver of this =~ is a regular expression node, then we need // to introduce local variables for it based on its named capture groups. @@ -13375,7 +13377,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t case YP_TOKEN_STAR_STAR: { parser_lex(parser); - yp_node_t *argument = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *argument = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (yp_node_t *) yp_call_node_binary_create(parser, node, &token, argument); } case YP_TOKEN_AMPERSAND_DOT: @@ -13402,7 +13404,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t break; } default: { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Expected a valid method name"); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_DEF_NAME); message = (yp_token_t) { .type = YP_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end }; } } @@ -13427,7 +13429,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t yp_node_t *right = NULL; if (token_begins_expression_p(parser->current.type)) { - right = parse_expression(parser, binding_power, "Expected a value after the operator."); + right = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); } return (yp_node_t *) yp_range_node_create(parser, node, &token, right); @@ -13436,14 +13438,14 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t yp_token_t keyword = parser->current; parser_lex(parser); - yp_node_t *predicate = parse_expression(parser, binding_power, "Expected a predicate after `if'."); + yp_node_t *predicate = parse_expression(parser, binding_power, YP_ERR_CONDITIONAL_IF_PREDICATE); return (yp_node_t *) yp_if_node_modifier_create(parser, node, &keyword, predicate); } case YP_TOKEN_KEYWORD_UNLESS_MODIFIER: { yp_token_t keyword = parser->current; parser_lex(parser); - yp_node_t *predicate = parse_expression(parser, binding_power, "Expected a predicate after `unless'."); + yp_node_t *predicate = parse_expression(parser, binding_power, YP_ERR_CONDITIONAL_UNLESS_PREDICATE); return (yp_node_t *) yp_unless_node_modifier_create(parser, node, &keyword, predicate); } case YP_TOKEN_KEYWORD_UNTIL_MODIFIER: { @@ -13451,7 +13453,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t yp_statements_node_t *statements = yp_statements_node_create(parser); yp_statements_node_body_append(statements, node); - yp_node_t *predicate = parse_expression(parser, binding_power, "Expected a predicate after 'until'"); + yp_node_t *predicate = parse_expression(parser, binding_power, YP_ERR_CONDITIONAL_UNTIL_PREDICATE); return (yp_node_t *) yp_until_node_modifier_create(parser, &token, predicate, statements, YP_NODE_TYPE_P(node, YP_BEGIN_NODE) ? YP_LOOP_FLAGS_BEGIN_MODIFIER : 0); } case YP_TOKEN_KEYWORD_WHILE_MODIFIER: { @@ -13459,12 +13461,12 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t yp_statements_node_t *statements = yp_statements_node_create(parser); yp_statements_node_body_append(statements, node); - yp_node_t *predicate = parse_expression(parser, binding_power, "Expected a predicate after 'while'"); + yp_node_t *predicate = parse_expression(parser, binding_power, YP_ERR_CONDITIONAL_WHILE_PREDICATE); return (yp_node_t *) yp_while_node_modifier_create(parser, &token, predicate, statements, YP_NODE_TYPE_P(node, YP_BEGIN_NODE) ? YP_LOOP_FLAGS_BEGIN_MODIFIER : 0); } case YP_TOKEN_QUESTION_MARK: { parser_lex(parser); - yp_node_t *true_expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value after '?'"); + yp_node_t *true_expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_TERNARY_EXPRESSION_TRUE); if (parser->recovering) { // If parsing the true expression of this ternary resulted in a syntax @@ -13480,10 +13482,10 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t } accept(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_COLON, "Expected ':' after true expression in ternary operator."); + expect(parser, YP_TOKEN_COLON, YP_ERR_TERNARY_COLON); yp_token_t colon = parser->previous; - yp_node_t *false_expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value after ':'"); + yp_node_t *false_expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_TERNARY_EXPRESSION_FALSE); return (yp_node_t *) yp_if_node_ternary_create(parser, node, true_expression, &colon, false_expression); } @@ -13552,7 +13554,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t return (yp_node_t *) yp_call_node_shorthand_create(parser, node, &delimiter, &arguments); } default: { - yp_diagnostic_list_append(&parser->error_list, delimiter.start, delimiter.end, "Expected identifier or constant after '::'"); + yp_diagnostic_list_append(&parser->error_list, delimiter.start, delimiter.end, YP_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT); yp_node_t *child = (yp_node_t *) yp_missing_node_create(parser, delimiter.start, delimiter.end); return (yp_node_t *)yp_constant_path_node_create(parser, node, &delimiter, child); } @@ -13561,7 +13563,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t case YP_TOKEN_KEYWORD_RESCUE_MODIFIER: { parser_lex(parser); accept(parser, YP_TOKEN_NEWLINE); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the rescue keyword."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_RESCUE_MODIFIER_VALUE); return (yp_node_t *) yp_rescue_modifier_node_create(parser, node, &token, value); } @@ -13578,7 +13580,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t parse_arguments(parser, &arguments, false, YP_TOKEN_BRACKET_RIGHT); yp_accepts_block_stack_pop(parser); - expect(parser, YP_TOKEN_BRACKET_RIGHT, "Expected ']' to close the bracket expression."); + expect(parser, YP_TOKEN_BRACKET_RIGHT, YP_ERR_EXPECT_RBRACKET); } arguments.closing_loc = YP_LOCATION_TOKEN_VALUE(&parser->previous); @@ -13612,7 +13614,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t parser_lex(parser); - yp_node_t *pattern = parse_pattern(parser, true, "Expected a pattern after `in'."); + yp_node_t *pattern = parse_pattern(parser, true, YP_ERR_PATTERN_EXPRESSION_AFTER_IN); parser->pattern_matching_newlines = previous_pattern_matching_newlines; return (yp_node_t *) yp_match_predicate_node_create(parser, node, pattern, &operator); @@ -13627,7 +13629,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t parser_lex(parser); - yp_node_t *pattern = parse_pattern(parser, true, "Expected a pattern after `=>'."); + yp_node_t *pattern = parse_pattern(parser, true, YP_ERR_PATTERN_EXPRESSION_AFTER_HROCKET); parser->pattern_matching_newlines = previous_pattern_matching_newlines; return (yp_node_t *) yp_match_required_node_create(parser, node, pattern, &operator); @@ -13645,7 +13647,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t // Consumers of this function should always check parser->recovering to // determine if they need to perform additional cleanup. static yp_node_t * -parse_expression(yp_parser_t *parser, yp_binding_power_t binding_power, const char *message) { +parse_expression(yp_parser_t *parser, yp_binding_power_t binding_power, yp_diagnostic_id_t diag_id) { yp_token_t recovery = parser->previous; yp_node_t *node = parse_expression_prefix(parser, binding_power); @@ -13653,7 +13655,7 @@ parse_expression(yp_parser_t *parser, yp_binding_power_t binding_power, const ch // parse_expression_prefix is going to be a missing node. In that case we need // to add the error message to the parser's error list. if (YP_NODE_TYPE_P(node, YP_MISSING_NODE)) { - yp_diagnostic_list_append(&parser->error_list, recovery.end, recovery.end, message); + yp_diagnostic_list_append(&parser->error_list, recovery.end, recovery.end, diag_id); return node; } diff --git a/test/yarp/errors_test.rb b/test/yarp/errors_test.rb index 608af07795f..61955d612f6 100644 --- a/test/yarp/errors_test.rb +++ b/test/yarp/errors_test.rb @@ -8,8 +8,8 @@ class ErrorsTest < TestCase def test_constant_path_with_invalid_token_after assert_error_messages "A::$b", [ - "Expected identifier or constant after '::'", - "Expected a newline or semicolon after statement." + "Expected a constant after the `::` operator", + "Expected a newline or semicolon after the statement" ] end @@ -26,7 +26,7 @@ def test_module_name_recoverable ) assert_errors expected, "module Parent module end", [ - ["Expected to find a module name after `module`.", 20..20] + ["Expected a constant name after `module`", 20..20] ] end @@ -42,7 +42,7 @@ def test_for_loops_index_missing ) assert_errors expected, "for in 1..10\ni\nend", [ - ["Expected index after for.", 0..0] + ["Expected an index after `for`", 0..0] ] end @@ -58,9 +58,9 @@ def test_for_loops_only_end ) assert_errors expected, "for end", [ - ["Expected index after for.", 0..0], - ["Expected keyword in.", 3..3], - ["Expected collection.", 3..3] + ["Expected an index after `for`", 0..0], + ["Expected an `in` after the index in a `for` statement", 3..3], + ["Expected a collection after the `in` in a `for` statement", 3..3] ] end @@ -73,7 +73,7 @@ def test_pre_execution_missing_brace ) assert_errors expected, "BEGIN 1 }", [ - ["Expected '{' after 'BEGIN'.", 5..5] + ["Expected a `{` after `BEGIN`", 5..5] ] end @@ -98,37 +98,37 @@ def test_pre_execution_context ) assert_errors expected, "BEGIN { 1 + }", [ - ["Expected a value after the operator.", 11..11] + ["Expected an expression after the operator", 11..11] ] end def test_unterminated_embdoc assert_errors expression("1"), "1\n=begin\n", [ - ["Unterminated embdoc", 2..9] + ["Could not find a terminator for the embedded document", 2..9] ] end def test_unterminated_i_list assert_errors expression("%i["), "%i[", [ - ["Expected a closing delimiter for a `%i` list.", 3..3] + ["Expected a closing delimiter for the `%i` list", 3..3] ] end def test_unterminated_w_list assert_errors expression("%w["), "%w[", [ - ["Expected a closing delimiter for a `%w` list.", 3..3] + ["Expected a closing delimiter for the `%w` list", 3..3] ] end def test_unterminated_W_list assert_errors expression("%W["), "%W[", [ - ["Expected a closing delimiter for a `%W` list.", 3..3] + ["Expected a closing delimiter for the `%W` list", 3..3] ] end def test_unterminated_regular_expression assert_errors expression("/hello"), "/hello", [ - ["Expected a closing delimiter for a regular expression.", 1..1] + ["Expected a closing delimiter for the regular expression", 1..1] ] end @@ -136,178 +136,178 @@ def test_unterminated_regular_expression_with_heredoc source = "<<-END + /b\nEND\n" assert_errors expression(source), source, [ - ["Expected a closing delimiter for a regular expression.", 10..10] + ["Expected a closing delimiter for the regular expression", 10..10] ] end def test_unterminated_xstring assert_errors expression("`hello"), "`hello", [ - ["Expected a closing delimiter for an xstring.", 1..1] + ["Expected a closing delimiter for the `%x` or backtick string", 1..1] ] end def test_unterminated_string assert_errors expression('"hello'), '"hello', [ - ["Expected a closing delimiter for an interpolated string.", 1..1] + ["Expected a closing delimiter for the interpolated string", 1..1] ] end def test_unterminated_s_symbol assert_errors expression("%s[abc"), "%s[abc", [ - ["Expected a closing delimiter for a dynamic symbol.", 3..3] + ["Expected a closing delimiter for the dynamic symbol", 3..3] ] end def test_unterminated_parenthesized_expression assert_errors expression('(1 + 2'), '(1 + 2', [ - ["Expected to be able to parse an expression.", 6..6], - ["Expected a closing parenthesis.", 6..6] + ["Cannot parse the expression", 6..6], + ["Expected a matching `)`", 6..6] ] end def test_unterminated_argument_expression assert_errors expression('a %'), 'a %', [ - ["Unexpected end of input", 2..3], - ["Expected a value after the operator.", 3..3], + ["Invalid `%` token", 2..3], + ["Expected an expression after the operator", 3..3], ] end def test_cr_without_lf_in_percent_expression assert_errors expression("%\r"), "%\r", [ - ["Invalid %% token", 0..2], + ["Invalid `%` token", 0..2], ] end def test_1_2_3 assert_errors expression("(1, 2, 3)"), "(1, 2, 3)", [ - ["Expected to be able to parse an expression.", 2..2], - ["Expected a closing parenthesis.", 2..2], - ["Expected a newline or semicolon after statement.", 2..2], - ["Expected to be able to parse an expression.", 2..2], - ["Expected a newline or semicolon after statement.", 5..5], - ["Expected to be able to parse an expression.", 5..5], - ["Expected a newline or semicolon after statement.", 8..8], - ["Expected to be able to parse an expression.", 8..8], + ["Cannot parse the expression", 2..2], + ["Expected a matching `)`", 2..2], + ["Expected a newline or semicolon after the statement", 2..2], + ["Cannot parse the expression", 2..2], + ["Expected a newline or semicolon after the statement", 5..5], + ["Cannot parse the expression", 5..5], + ["Expected a newline or semicolon after the statement", 8..8], + ["Cannot parse the expression", 8..8], ] end def test_return_1_2_3 assert_error_messages "return(1, 2, 3)", [ - "Expected to be able to parse an expression.", - "Expected a closing parenthesis.", - "Expected a newline or semicolon after statement.", - "Expected to be able to parse an expression." + "Cannot parse the expression", + "Expected a matching `)`", + "Expected a newline or semicolon after the statement", + "Cannot parse the expression", ] end def test_return_1 assert_errors expression("return 1,;"), "return 1,;", [ - ["Expected to be able to parse an argument.", 9..9] + ["Expected an argument", 9..9] ] end def test_next_1_2_3 assert_errors expression("next(1, 2, 3)"), "next(1, 2, 3)", [ - ["Expected to be able to parse an expression.", 6..6], - ["Expected a closing parenthesis.", 6..6], - ["Expected a newline or semicolon after statement.", 12..12], - ["Expected to be able to parse an expression.", 12..12] + ["Cannot parse the expression", 6..6], + ["Expected a matching `)`", 6..6], + ["Expected a newline or semicolon after the statement", 12..12], + ["Cannot parse the expression", 12..12], ] end def test_next_1 assert_errors expression("next 1,;"), "next 1,;", [ - ["Expected to be able to parse an argument.", 7..7] + ["Expected an argument", 7..7] ] end def test_break_1_2_3 assert_errors expression("break(1, 2, 3)"), "break(1, 2, 3)", [ - ["Expected to be able to parse an expression.", 7..7], - ["Expected a closing parenthesis.", 7..7], - ["Expected a newline or semicolon after statement.", 13..13], - ["Expected to be able to parse an expression.", 13..13], + ["Cannot parse the expression", 7..7], + ["Expected a matching `)`", 7..7], + ["Expected a newline or semicolon after the statement", 13..13], + ["Cannot parse the expression", 13..13], ] end def test_break_1 assert_errors expression("break 1,;"), "break 1,;", [ - ["Expected to be able to parse an argument.", 8..8] + ["Expected an argument", 8..8] ] end def test_argument_forwarding_when_parent_is_not_forwarding assert_errors expression('def a(x, y, z); b(...); end'), 'def a(x, y, z); b(...); end', [ - ["unexpected ... when parent method is not forwarding.", 18..21] + ["Unexpected `...` when the parent method is not forwarding", 18..21] ] end def test_argument_forwarding_only_effects_its_own_internals assert_errors expression('def a(...); b(...); end; def c(x, y, z); b(...); end'), 'def a(...); b(...); end; def c(x, y, z); b(...); end', [ - ["unexpected ... when parent method is not forwarding.", 43..46] + ["Unexpected `...` when the parent method is not forwarding", 43..46] ] end def test_top_level_constant_with_downcased_identifier assert_error_messages "::foo", [ - "Expected a constant after ::.", - "Expected a newline or semicolon after statement." + "Expected a constant after the `::` operator", + "Expected a newline or semicolon after the statement" ] end def test_top_level_constant_starting_with_downcased_identifier assert_error_messages "::foo::A", [ - "Expected a constant after ::.", - "Expected a newline or semicolon after statement." + "Expected a constant after the `::` operator", + "Expected a newline or semicolon after the statement" ] end def test_aliasing_global_variable_with_non_global_variable assert_errors expression("alias $a b"), "alias $a b", [ - ["Expected a global variable.", 9..10] + ["Invalid argument being passed to `alias`; expected a bare word, symbol, constant, or global variable", 9..10] ] end def test_aliasing_non_global_variable_with_global_variable assert_errors expression("alias a $b"), "alias a $b", [ - ["Expected a bare word or symbol argument.", 8..10] + ["Invalid argument being passed to `alias`; expected a bare word, symbol, constant, or global variable", 8..10] ] end def test_aliasing_global_variable_with_global_number_variable assert_errors expression("alias $a $1"), "alias $a $1", [ - ["Can't make alias for number variables.", 9..11] + ["Invalid argument being passed to `alias`; expected a bare word, symbol, constant, or global variable", 9..11] ] end def test_def_with_expression_receiver_and_no_identifier assert_errors expression("def (a); end"), "def (a); end", [ - ["Expected '.' or '::' after receiver", 7..7] + ["Expected a `.` or `::` after the receiver in a method definition", 7..7] ] end def test_def_with_multiple_statements_receiver assert_errors expression("def (\na\nb\n).c; end"), "def (\na\nb\n).c; end", [ - ["Expected closing ')' for receiver.", 7..7], - ["Expected '.' or '::' after receiver", 7..7], - ["Expected to be able to parse an expression.", 10..10], - ["Expected to be able to parse an expression.", 11..11] + ["Expected a matching `)`", 7..7], + ["Expected a `.` or `::` after the receiver in a method definition", 7..7], + ["Cannot parse the expression", 10..10], + ["Cannot parse the expression", 11..11] ] end def test_def_with_empty_expression_receiver assert_errors expression("def ().a; end"), "def ().a; end", [ - ["Expected to be able to parse receiver.", 5..5] + ["Expected a receiver for the method definition", 5..5] ] end def test_block_beginning_with_brace_and_ending_with_end assert_error_messages "x.each { x end", [ - "Expected a newline or semicolon after statement.", - "Expected to be able to parse an expression.", - "Expected to be able to parse an expression.", - "Expected block beginning with '{' to end with '}'." + "Expected a newline or semicolon after the statement", + "Cannot parse the expression", + "Cannot parse the expression", + "Expected a block beginning with `{` to end with `}`" ] end @@ -328,7 +328,7 @@ def test_double_splat_followed_by_splat_argument ) assert_errors expected, "a(**kwargs, *args)", [ - ["Unexpected splat argument after double splat.", 12..17] + ["Unexpected `*` splat argument after a `**` keyword splat argument", 12..17] ] end @@ -349,15 +349,15 @@ def test_arguments_after_block ) assert_errors expected, "a(&block, foo)", [ - ["Unexpected argument after block argument.", 10..13] + ["Unexpected argument after a block argument", 10..13] ] end def test_arguments_binding_power_for_and assert_error_messages "foo(*bar and baz)", [ - "Expected a ')' to close the argument list.", - "Expected a newline or semicolon after statement.", - "Expected to be able to parse an expression." + "Expected a `)` to close the arguments", + "Expected a newline or semicolon after the statement", + "Cannot parse the expression" ] end @@ -384,7 +384,7 @@ def test_splat_argument_after_keyword_argument ) assert_errors expected, "a(foo: bar, *args)", [ - ["Unexpected splat argument after double splat.", 12..17] + ["Unexpected `*` splat argument after a `**` keyword splat argument", 12..17] ] end @@ -405,7 +405,7 @@ def test_module_definition_in_method_body ) assert_errors expected, "def foo;module A;end;end", [ - ["Module definition in method body", 8..14] + ["Unexpected module definition in a method body", 8..14] ] end @@ -443,7 +443,7 @@ def test_module_definition_in_method_body_within_block Location() ) - assert_errors expected, <<~RUBY, [["Module definition in method body", 21..27]] + assert_errors expected, <<~RUBY, [["Unexpected module definition in a method body", 21..27]] def foo bar do module Foo;end @@ -480,7 +480,7 @@ def test_class_definition_in_method_body ) assert_errors expected, "def foo;class A;end;end", [ - ["Class definition in method body", 8..13] + ["Unexpected class definition in a method body", 8..13] ] end @@ -506,10 +506,10 @@ def test_bad_arguments ) assert_errors expected, "def foo(A, @a, $A, @@a);end", [ - ["Formal argument cannot be a constant", 8..9], - ["Formal argument cannot be an instance variable", 11..13], - ["Formal argument cannot be a global variable", 15..17], - ["Formal argument cannot be a class variable", 19..22], + ["Invalid formal argument; formal argument cannot be a constant", 8..9], + ["Invalid formal argument; formal argument cannot be an instance variable", 11..13], + ["Invalid formal argument; formal argument cannot be a global variable", 15..17], + ["Invalid formal argument; formal argument cannot be a class variable", 19..22], ] end @@ -540,15 +540,15 @@ def test_cannot_assign_to_a_reserved_numbered_parameter end RUBY assert_errors expected, source, [ - ["reserved for numbered parameter", 8..10], - ["reserved for numbered parameter", 14..16], - ["reserved for numbered parameter", 20..22], - ["reserved for numbered parameter", 26..28], - ["reserved for numbered parameter", 32..34], - ["reserved for numbered parameter", 40..42], - ["reserved for numbered parameter", 46..48], - ["reserved for numbered parameter", 52..54], - ["reserved for numbered parameter", 58..60], + ["Token reserved for a numbered parameter", 8..10], + ["Token reserved for a numbered parameter", 14..16], + ["Token reserved for a numbered parameter", 20..22], + ["Token reserved for a numbered parameter", 26..28], + ["Token reserved for a numbered parameter", 32..34], + ["Token reserved for a numbered parameter", 40..42], + ["Token reserved for a numbered parameter", 46..48], + ["Token reserved for a numbered parameter", 52..54], + ["Token reserved for a numbered parameter", 58..60], ] end @@ -577,7 +577,7 @@ def test_do_not_allow_trailing_commas_in_method_parameters ) assert_errors expected, "def foo(a,b,c,);end", [ - ["Unexpected ','.", 13..14] + ["Unexpected `,` in parameters", 13..14] ] end @@ -596,7 +596,7 @@ def test_do_not_allow_trailing_commas_in_lambda_parameters nil ) assert_errors expected, "-> (a, b, ) {}", [ - ["Unexpected ','.", 8..9] + ["Unexpected `,` in parameters", 8..9] ] end @@ -604,13 +604,13 @@ def test_do_not_allow_multiple_codepoints_in_a_single_character_literal expected = StringNode(Location(), Location(), nil, "\u0001\u0002") assert_errors expected, '?\u{0001 0002}', [ - ["Multiple codepoints at single character literal", 9..12] + ["Invalid Unicode escape sequence; multiple codepoints are not allowed in a character literal", 9..12] ] end def test_invalid_hex_escape assert_errors expression('"\\xx"'), '"\\xx"', [ - ["Invalid hex escape.", 1..3], + ["Invalid hexadecimal escape sequence", 1..3], ] end @@ -618,7 +618,7 @@ def test_do_not_allow_more_than_6_hexadecimal_digits_in_u_Unicode_character_nota expected = StringNode(Location(), Location(), Location(), "\u0001") assert_errors expected, '"\u{0000001}"', [ - ["invalid Unicode escape.", 4..11], + ["Invalid Unicode escape sequence; maximum length is 6 digits", 4..11], ] end @@ -626,13 +626,13 @@ def test_do_not_allow_characters_other_than_0_9_a_f_and_A_F_in_u_Unicode_charact expected = StringNode(Location(), Location(), Location(), "\u0000z}") assert_errors expected, '"\u{000z}"', [ - ["unterminated Unicode escape", 7..7], + ["Invalid Unicode escape sequence", 7..7], ] end def test_unterminated_unicode_brackets_should_be_a_syntax_error assert_errors expression('?\\u{3'), '?\\u{3', [ - ["invalid Unicode escape.", 1..5], + ["Invalid Unicode escape sequence; needs closing `}`", 1..5], ] end @@ -923,7 +923,7 @@ def test_case_without_when_clauses_errors_on_else_clause ) assert_errors expected, "case :a\nelse\nend", [ - ["Unexpected else without no when clauses in case statement.", 8..12] + ["Unexpected `else` in `case` statement; a `when` clause must precede `else`", 8..12] ] end @@ -944,7 +944,7 @@ def test_setter_method_cannot_be_defined_in_an_endless_method_definition ) assert_errors expected, "def a=() = 42", [ - ["Setter method cannot be defined in an endless method definition", 4..6] + ["Invalid method name; a setter method cannot be defined in an endless method definition", 4..6] ] end @@ -959,7 +959,7 @@ def test_do_not_allow_forward_arguments_in_lambda_literals ) assert_errors expected, "->(...) {}", [ - ["Unexpected ...", 3..6] + ["Unexpected `...` when the parent method is not forwarding", 3..6] ] end @@ -983,7 +983,7 @@ def test_do_not_allow_forward_arguments_in_blocks ) assert_errors expected, "a {|...|}", [ - ["Unexpected ...", 4..7] + ["Unexpected `...` when the parent method is not forwarding", 4..7] ] end @@ -1000,7 +1000,7 @@ def test_dont_allow_return_inside_class_body ) assert_errors expected, "class A; return; end", [ - ["Invalid return in class/module body", 15..16] + ["Invalid `return` in a class or module body", 15..16] ] end @@ -1015,7 +1015,7 @@ def test_dont_allow_return_inside_module_body ) assert_errors expected, "module A; return; end", [ - ["Invalid return in class/module body", 16..17] + ["Invalid `return` in a class or module body", 16..17] ] end @@ -1033,8 +1033,8 @@ def test_dont_allow_setting_to_back_and_nth_reference ) assert_errors expected, "begin\n$+ = nil\n$1466 = nil\nend", [ - ["Can't set variable", 6..8], - ["Can't set variable", 15..20] + ["Immutable variable as a write target", 6..8], + ["Immutable variable as a write target", 15..20] ] end @@ -1058,7 +1058,7 @@ def test_duplicated_parameter_names ) assert_errors expected, "def foo(a,b,a);end", [ - ["Duplicated parameter name.", 12..13] + ["Repeated parameter name", 12..13] ] end @@ -1078,7 +1078,7 @@ def test_duplicated_parameter_names ) assert_errors expected, "def foo(a,b,*a);end", [ - ["Duplicated parameter name.", 13..14] + ["Repeated parameter name", 13..14] ] expected = DefNode( @@ -1097,7 +1097,7 @@ def test_duplicated_parameter_names ) assert_errors expected, "def foo(a,b,**a);end", [ - ["Duplicated parameter name.", 14..15] + ["Repeated parameter name", 14..15] ] expected = DefNode( @@ -1116,7 +1116,7 @@ def test_duplicated_parameter_names ) assert_errors expected, "def foo(a,b,&a);end", [ - ["Duplicated parameter name.", 13..14] + ["Repeated parameter name", 13..14] ] expected = DefNode( @@ -1134,12 +1134,12 @@ def test_duplicated_parameter_names Location() ) - assert_errors expected, "def foo(a = 1,b,*c);end", [["Unexpected parameter *", 16..17]] + assert_errors expected, "def foo(a = 1,b,*c);end", [["Unexpected parameter `*`", 16..17]] end def test_unterminated_global_variable assert_errors expression("$"), "$", [ - ["Invalid global variable.", 0..1] + ["Invalid global variable", 0..1] ] end