diff options
| author | TSUYUSATO Kitsune <make.just.on@gmail.com> | 2023-11-14 15:40:08 +0900 |
|---|---|---|
| committer | git <svn-admin@ruby-lang.org> | 2023-11-14 14:34:47 +0000 |
| commit | 3439f1e62e60db0f154ffdb53a1217378b4c9038 (patch) | |
| tree | 066720acee37332ef0822b58c89cf990a88af2dc | |
| parent | 52a0f1d14b76e4b095fc61323f669b1a1d6be960 (diff) | |
[ruby/prism] Add parse_value_expression
https://github.com/ruby/prism/commit/37fad74134
| -rw-r--r-- | prism/prism.c | 32 | ||||
| -rw-r--r-- | test/prism/errors_test.rb | 72 |
2 files changed, 93 insertions, 11 deletions
diff --git a/prism/prism.c b/prism/prism.c index b42c02be18..dab43b0b10 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -10140,6 +10140,16 @@ static pm_node_t * parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id); /** + * This is a wrapper of parse_expression, which also checks whether the resulting node is value expression. + */ +static pm_node_t * +parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id) { + pm_node_t *node = parse_expression(parser, binding_power, diag_id); + pm_assert_value_expression(parser, node); + return node; +} + +/** * 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 * an expression is optional. @@ -11769,7 +11779,7 @@ static inline pm_node_t * parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context) { context_push(parser, PM_CONTEXT_PREDICATE); pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE; - pm_node_t *predicate = parse_expression(parser, binding_power, error_id); + pm_node_t *predicate = parse_value_expression(parser, binding_power, error_id); // Predicates are closed by a term, a "then", or a term and then a "then". bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); @@ -12889,7 +12899,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) { pm_token_t lparen = parser->current; parser_lex(parser); - pm_node_t *expression = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN); + pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN); parser->pattern_matching_newlines = previous_pattern_matching_newlines; accept1(parser, PM_TOKEN_NEWLINE); @@ -13919,7 +13929,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { } else if (!token_begins_expression_p(parser->current.type)) { predicate = NULL; } else { - predicate = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CASE_EXPRESSION_AFTER_CASE); + predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CASE_EXPRESSION_AFTER_CASE); while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)); } @@ -14209,7 +14219,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { parser->command_start = true; parser_lex(parser); - superclass = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CLASS_SUPERCLASS); + superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CLASS_SUPERCLASS); } else { inheritance_operator = not_provided(parser); superclass = NULL; @@ -14584,7 +14594,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN); pm_token_t in_keyword = parser->previous; - pm_node_t *collection = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_FOR_COLLECTION); + pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_FOR_COLLECTION); pm_do_loop_stack_pop(parser); pm_token_t do_keyword; @@ -14746,7 +14756,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { parser_lex(parser); pm_token_t keyword = parser->previous; - pm_node_t *predicate = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CONDITIONAL_UNTIL_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CONDITIONAL_UNTIL_PREDICATE); pm_do_loop_stack_pop(parser); expect3(parser, PM_TOKEN_KEYWORD_DO_LOOP, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE); @@ -14767,7 +14777,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { parser_lex(parser); pm_token_t keyword = parser->previous; - pm_node_t *predicate = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CONDITIONAL_WHILE_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CONDITIONAL_WHILE_PREDICATE); pm_do_loop_stack_pop(parser); expect3(parser, PM_TOKEN_KEYWORD_DO_LOOP, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE); @@ -16079,14 +16089,14 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_token_t keyword = parser->current; parser_lex(parser); - pm_node_t *predicate = parse_expression(parser, binding_power, PM_ERR_CONDITIONAL_IF_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_IF_PREDICATE); return (pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate); } case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: { pm_token_t keyword = parser->current; parser_lex(parser); - pm_node_t *predicate = parse_expression(parser, binding_power, PM_ERR_CONDITIONAL_UNLESS_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_UNLESS_PREDICATE); return (pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate); } case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: { @@ -16094,7 +16104,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_statements_node_t *statements = pm_statements_node_create(parser); pm_statements_node_body_append(statements, node); - pm_node_t *predicate = parse_expression(parser, binding_power, PM_ERR_CONDITIONAL_UNTIL_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_UNTIL_PREDICATE); return (pm_node_t *) pm_until_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0); } case PM_TOKEN_KEYWORD_WHILE_MODIFIER: { @@ -16102,7 +16112,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_statements_node_t *statements = pm_statements_node_create(parser); pm_statements_node_body_append(statements, node); - pm_node_t *predicate = parse_expression(parser, binding_power, PM_ERR_CONDITIONAL_WHILE_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_WHILE_PREDICATE); return (pm_node_t *) pm_while_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0); } case PM_TOKEN_QUESTION_MARK: { diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb index a3631fe45b..0eb0f5bb58 100644 --- a/test/prism/errors_test.rb +++ b/test/prism/errors_test.rb @@ -1455,6 +1455,78 @@ module Prism ] end + def test_check_value_expression + source = <<~RUBY + 1 => ^(return) + while true + 1 => ^(break) + 1 => ^(next) + 1 => ^(redo) + 1 => ^(retry) + 1 => ^(2 => a) + end + 1 => ^(if 1; (return) else (return) end) + 1 => ^(unless 1; (return) else (return) end) + RUBY + message = 'Unexpected void value expression' + assert_errors expression(source), source, [ + [message, 7..13], + [message, 35..40], + [message, 51..55], + [message, 66..70], + [message, 81..86], + [message, 97..103], + [message, 123..129], + [message, 168..174], + ], compare_ripper: false # Ripper does not check 'void value expression'. + end + + def test_void_value_expression_in_statement + source = <<~RUBY + if (return) + end + unless (return) + end + while (return) + end + until (return) + end + case (return) + when 1 + end + class A < (return) + end + for x in (return) + end + RUBY + message = 'Unexpected void value expression' + assert_errors expression(source), source, [ + [message, 4..10], + [message, 24..30], + [message, 43..49], + [message, 62..68], + [message, 80..86], + [message, 110..116], + [message, 132..138], + ], compare_ripper: false # Ripper does not check 'void value expression'. + end + + def test_void_value_expression_in_modifier + source = <<~RUBY + 1 if (return) + 1 unless (return) + 1 while (return) + 1 until (return) + RUBY + message = 'Unexpected void value expression' + assert_errors expression(source), source, [ + [message, 6..12], + [message, 24..30], + [message, 41..47], + [message, 58..64], + ], compare_ripper: false # Ripper does not check 'void value expression'. + end + private def assert_errors(expected, source, errors, compare_ripper: RUBY_ENGINE == "ruby") |
