[ruby/yarp] 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 https://github.com/ruby/yarp/pull/1379, and makes progress on #941.

  [1] Strunk & White rule 19

https://github.com/ruby/yarp/commit/0b6dd85bf1
This commit is contained in:
Mike Dalessio 2023-09-03 21:27:43 -04:00 коммит произвёл git
Родитель 2d37b44603
Коммит 4efcaf956e
5 изменённых файлов: 885 добавлений и 434 удалений

Просмотреть файл

@ -8,8 +8,8 @@ module YARP
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 @@ module YARP
)
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 @@ module YARP
)
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 @@ module YARP
)
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 @@ module YARP
)
assert_errors expected, "BEGIN 1 }", [
["Expected '{' after 'BEGIN'.", 5..5]
["Expected a `{` after `BEGIN`", 5..5]
]
end
@ -98,37 +98,37 @@ module YARP
)
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 @@ module YARP
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 @@ module YARP
)
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 @@ module YARP
)
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 @@ module YARP
)
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 @@ module YARP
)
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 @@ module YARP
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 @@ module YARP
)
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 @@ module YARP
)
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 @@ module YARP
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 @@ module YARP
)
assert_errors expected, "def foo(a,b,c,);end", [
["Unexpected ','.", 13..14]
["Unexpected `,` in parameters", 13..14]
]
end
@ -596,7 +596,7 @@ module YARP
nil
)
assert_errors expected, "-> (a, b, ) {}", [
["Unexpected ','.", 8..9]
["Unexpected `,` in parameters", 8..9]
]
end
@ -604,13 +604,13 @@ module YARP
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 @@ module YARP
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 @@ module YARP
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 @@ module YARP
)
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 @@ module YARP
)
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 @@ module YARP
)
assert_errors expected, "->(...) {}", [
["Unexpected ...", 3..6]
["Unexpected `...` when the parent method is not forwarding", 3..6]
]
end
@ -983,7 +983,7 @@ module YARP
)
assert_errors expected, "a {|...|}", [
["Unexpected ...", 4..7]
["Unexpected `...` when the parent method is not forwarding", 4..7]
]
end
@ -1000,7 +1000,7 @@ module YARP
)
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 @@ module YARP
)
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 @@ module YARP
)
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 @@ module YARP
)
assert_errors expected, "def foo(a,b,a);end", [
["Duplicated parameter name.", 12..13]
["Repeated parameter name", 12..13]
]
end
@ -1078,7 +1078,7 @@ module YARP
)
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 @@ module YARP
)
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 @@ module YARP
)
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 @@ module YARP
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

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -6,6 +6,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
// 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);

Просмотреть файл

@ -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;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу