diff options
author | TSUYUSATO Kitsune <make.just.on@gmail.com> | 2023-11-29 10:32:26 +0900 |
---|---|---|
committer | git <svn-admin@ruby-lang.org> | 2023-11-29 02:03:06 +0000 |
commit | a908cef53f4c647c7fe7c9e808b501c3bb3cc70f (patch) | |
tree | 5bcade9747f23bde3587ee114c4611800f82cecc /prism | |
parent | fcabe2df39b892458cb1f67437852c4acbb245a6 (diff) | |
download | ruby-a908cef53f4c647c7fe7c9e808b501c3bb3cc70f.tar.gz |
[ruby/prism] Reject class/module defs in method params/rescue/ensure/else
Fix https://github.com/ruby/prism/pull/1936
https://github.com/ruby/prism/commit/232e77a003
Diffstat (limited to 'prism')
-rw-r--r-- | prism/diagnostic.c | 4 | ||||
-rw-r--r-- | prism/parser.h | 9 | ||||
-rw-r--r-- | prism/prism.c | 43 |
3 files changed, 41 insertions, 15 deletions
diff --git a/prism/diagnostic.c b/prism/diagnostic.c index e2181151c2..443ad35c6a 100644 --- a/prism/diagnostic.c +++ b/prism/diagnostic.c @@ -90,7 +90,7 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = { [PM_ERR_CASE_MATCH_MISSING_PREDICATE] = "expected a predicate for a case matching statement", [PM_ERR_CASE_MISSING_CONDITIONS] = "expected a `when` or `in` clause after `case`", [PM_ERR_CASE_TERM] = "expected an `end` to close the `case` statement", - [PM_ERR_CLASS_IN_METHOD] = "unexpected class definition in a method body", + [PM_ERR_CLASS_IN_METHOD] = "unexpected class definition in a method definition", [PM_ERR_CLASS_NAME] = "expected a constant name after `class`", [PM_ERR_CLASS_SUPERCLASS] = "expected a superclass after `<`", [PM_ERR_CLASS_TERM] = "expected an `end` to close the `class` statement", @@ -185,7 +185,7 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = { [PM_ERR_LIST_W_UPPER_ELEMENT] = "expected a string in a `%W` list", [PM_ERR_LIST_W_UPPER_TERM] = "expected a closing delimiter for the `%W` list", [PM_ERR_MALLOC_FAILED] = "failed to allocate memory", - [PM_ERR_MODULE_IN_METHOD] = "unexpected module definition in a method body", + [PM_ERR_MODULE_IN_METHOD] = "unexpected module definition in a method definition", [PM_ERR_MODULE_NAME] = "expected a constant name after `module`", [PM_ERR_MODULE_TERM] = "expected an `end` to close the `module` statement", [PM_ERR_MULTI_ASSIGN_MULTI_SPLATS] = "multiple splats in multiple assignment", diff --git a/prism/parser.h b/prism/parser.h index fec1036229..c1f9e0f663 100644 --- a/prism/parser.h +++ b/prism/parser.h @@ -297,6 +297,9 @@ typedef enum { /** an ensure statement */ PM_CONTEXT_ENSURE, + /** an ensure statement within a method definition */ + PM_CONTEXT_ENSURE_DEF, + /** a for loop */ PM_CONTEXT_FOR, @@ -333,9 +336,15 @@ typedef enum { /** a rescue else statement */ PM_CONTEXT_RESCUE_ELSE, + /** a rescue else statement within a method definition */ + PM_CONTEXT_RESCUE_ELSE_DEF, + /** a rescue statement */ PM_CONTEXT_RESCUE, + /** a rescue statement within a method definition */ + PM_CONTEXT_RESCUE_DEF, + /** a singleton class definition */ PM_CONTEXT_SCLASS, diff --git a/prism/prism.c b/prism/prism.c index 03b6204a78..41ed44e9c1 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -6603,6 +6603,7 @@ context_terminator(pm_context_t context, pm_token_t *token) { case PM_CONTEXT_ELSE: case PM_CONTEXT_FOR: case PM_CONTEXT_ENSURE: + case PM_CONTEXT_ENSURE_DEF: return token->type == PM_TOKEN_KEYWORD_END; case PM_CONTEXT_FOR_INDEX: return token->type == PM_TOKEN_KEYWORD_IN; @@ -6623,8 +6624,10 @@ context_terminator(pm_context_t context, pm_token_t *token) { return token->type == PM_TOKEN_PARENTHESIS_RIGHT; case PM_CONTEXT_BEGIN: case PM_CONTEXT_RESCUE: + case PM_CONTEXT_RESCUE_DEF: return token->type == PM_TOKEN_KEYWORD_ENSURE || token->type == PM_TOKEN_KEYWORD_RESCUE || token->type == PM_TOKEN_KEYWORD_ELSE || token->type == PM_TOKEN_KEYWORD_END; case PM_CONTEXT_RESCUE_ELSE: + case PM_CONTEXT_RESCUE_ELSE_DEF: return token->type == PM_TOKEN_KEYWORD_ENSURE || token->type == PM_TOKEN_KEYWORD_END; case PM_CONTEXT_LAMBDA_BRACES: return token->type == PM_TOKEN_BRACE_RIGHT; @@ -6690,6 +6693,10 @@ context_def_p(pm_parser_t *parser) { while (context_node != NULL) { switch (context_node->context) { case PM_CONTEXT_DEF: + case PM_CONTEXT_DEF_PARAMS: + case PM_CONTEXT_ENSURE_DEF: + case PM_CONTEXT_RESCUE_DEF: + case PM_CONTEXT_RESCUE_ELSE_DEF: return true; case PM_CONTEXT_CLASS: case PM_CONTEXT_MODULE: @@ -11837,7 +11844,7 @@ parse_parameters( * nodes pointing to each other from the top. */ static inline void -parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node) { +parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, bool def_p) { pm_rescue_node_t *current = NULL; while (accept1(parser, PM_TOKEN_KEYWORD_RESCUE)) { @@ -11900,7 +11907,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node) { if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) { pm_accepts_block_stack_push(parser, true); - pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_RESCUE); + pm_statements_node_t *statements = parse_statements(parser, def_p ? PM_CONTEXT_RESCUE_DEF : PM_CONTEXT_RESCUE); if (statements) { pm_rescue_node_statements_set(rescue, statements); } @@ -11936,7 +11943,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node) { pm_statements_node_t *else_statements = NULL; if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) { pm_accepts_block_stack_push(parser, true); - else_statements = parse_statements(parser, PM_CONTEXT_RESCUE_ELSE); + else_statements = parse_statements(parser, def_p ? PM_CONTEXT_RESCUE_ELSE_DEF : PM_CONTEXT_RESCUE_ELSE); pm_accepts_block_stack_pop(parser); accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); } @@ -11952,7 +11959,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node) { pm_statements_node_t *ensure_statements = NULL; if (!match1(parser, PM_TOKEN_KEYWORD_END)) { pm_accepts_block_stack_push(parser, true); - ensure_statements = parse_statements(parser, PM_CONTEXT_ENSURE); + ensure_statements = parse_statements(parser, def_p ? PM_CONTEXT_ENSURE_DEF : PM_CONTEXT_ENSURE); pm_accepts_block_stack_pop(parser); accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); } @@ -11970,10 +11977,10 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node) { } static inline pm_begin_node_t * -parse_rescues_as_begin(pm_parser_t *parser, pm_statements_node_t *statements) { +parse_rescues_as_begin(pm_parser_t *parser, pm_statements_node_t *statements, bool def_p) { pm_token_t no_begin_token = not_provided(parser); pm_begin_node_t *begin_node = pm_begin_node_create(parser, &no_begin_token, statements); - parse_rescues(parser, begin_node); + parse_rescues(parser, begin_node, def_p); // All nodes within a begin node are optional, so we look // for the earliest possible node that we can use to set @@ -12078,7 +12085,7 @@ parse_block(pm_parser_t *parser) { if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) { assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE)); - statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements); + statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false); } } @@ -14547,7 +14554,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { } pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements); - parse_rescues(parser, begin_node); + parse_rescues(parser, begin_node, false); expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM); begin_node->base.location.end = parser->previous.end; @@ -14665,7 +14672,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) { assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE)); - statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements); + statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false); } expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM); @@ -14717,7 +14724,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) { assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE)); - statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements); + statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false); } expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM); @@ -14744,6 +14751,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_token_t operator = not_provided(parser); pm_token_t name = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = def_keyword.end, .end = def_keyword.end }; + // This context is necessary for lexing `...` in a bare params correctly. + // It must be pushed before lexing the first param, so it is here. context_push(parser, PM_CONTEXT_DEF_PARAMS); parser_lex(parser); pm_constant_id_t old_param_name = parser->current_param_name; @@ -14844,7 +14853,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { break; } case PM_TOKEN_PARENTHESIS_LEFT: { + // The current context is `PM_CONTEXT_DEF_PARAMS`, however the inner expression + // of this parenthesis should not be processed under this context. + // Thus, the context is popped here. + context_pop(parser); parser_lex(parser); + pm_token_t lparen = parser->previous; pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_DEF_RECEIVER); @@ -14859,6 +14873,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_parser_scope_push(parser, true); parser->current_param_name = 0; + + // To push `PM_CONTEXT_DEF_PARAMS` again is for the same reason as described the above. + context_push(parser, PM_CONTEXT_DEF_PARAMS); name = parse_method_definition_name(parser); break; } @@ -14967,7 +14984,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) { assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE)); - statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements); + statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, true); } pm_accepts_block_stack_pop(parser); @@ -15222,7 +15239,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) { assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE)); - statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements); + statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false); } pm_constant_id_list_t locals = parser->current_scope->locals; @@ -15893,7 +15910,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) { assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE)); - body = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) body); + body = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) body, false); } expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END); |