diff --git a/prism/parser.h b/prism/parser.h index f77d8818aa..c701e595a9 100644 --- a/prism/parser.h +++ b/prism/parser.h @@ -212,6 +212,7 @@ typedef enum { PM_CONTEXT_EMBEXPR, // an interpolated expression PM_CONTEXT_ENSURE, // an ensure statement PM_CONTEXT_FOR, // a for loop + PM_CONTEXT_FOR_INDEX, // a for loop's index PM_CONTEXT_IF, // an if statement PM_CONTEXT_LAMBDA_BRACES, // a lambda expression with braces PM_CONTEXT_LAMBDA_DO_END, // a lambda expression with do..end diff --git a/prism/prism.c b/prism/prism.c index 6b9c20a4bd..5cb18a7b30 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -40,6 +40,7 @@ debug_context(pm_context_t context) { case PM_CONTEXT_BLOCK_BRACES: return "BLOCK_BRACES"; case PM_CONTEXT_BLOCK_KEYWORDS: return "BLOCK_KEYWORDS"; case PM_CONTEXT_FOR: return "FOR"; + case PM_CONTEXT_FOR_INDEX: return "FOR_INDEX"; case PM_CONTEXT_IF: return "IF"; case PM_CONTEXT_MAIN: return "MAIN"; case PM_CONTEXT_MODULE: return "MODULE"; @@ -5602,6 +5603,8 @@ context_terminator(pm_context_t context, pm_token_t *token) { case PM_CONTEXT_FOR: case PM_CONTEXT_ENSURE: return token->type == PM_TOKEN_KEYWORD_END; + case PM_CONTEXT_FOR_INDEX: + return token->type == PM_TOKEN_KEYWORD_IN; case PM_CONTEXT_CASE_WHEN: return token->type == PM_TOKEN_KEYWORD_WHEN || token->type == PM_TOKEN_KEYWORD_END || token->type == PM_TOKEN_KEYWORD_ELSE; case PM_CONTEXT_CASE_IN: @@ -9585,7 +9588,7 @@ parse_target(pm_parser_t *parser, pm_node_t *target) { } } -// Parse a write targets and validate that it is in a valid position for +// Parse a write target and validate that it is in a valid position for // assignment. static pm_node_t * parse_target_validate(pm_parser_t *parser, pm_node_t *target) { @@ -12544,10 +12547,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { multi_target->base.location.end = rparen_loc.end; if (match1(parser, PM_TOKEN_COMMA)) { - return parse_targets_validate(parser, (pm_node_t *) multi_target, PM_BINDING_POWER_INDEX); - } else { - return parse_target_validate(parser, (pm_node_t *) multi_target); + if (binding_power == PM_BINDING_POWER_STATEMENT) { + return parse_targets_validate(parser, (pm_node_t *) multi_target, PM_BINDING_POWER_INDEX); + } + return (pm_node_t *) multi_target; } + + return parse_target_validate(parser, (pm_node_t *) multi_target); } // If we have a single statement and are ending on a right parenthesis @@ -13634,7 +13640,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { parser_lex(parser); pm_token_t for_keyword = parser->previous; pm_node_t *index; + pm_parser_scope_push_transparent(parser); + context_push(parser, PM_CONTEXT_FOR_INDEX); // First, parse out the first index expression. if (accept1(parser, PM_TOKEN_USTAR)) { @@ -13660,6 +13668,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { index = parse_target(parser, index); } + context_pop(parser); pm_parser_scope_pop(parser); pm_do_loop_stack_push(parser, true); diff --git a/test/prism/fixtures/variables.txt b/test/prism/fixtures/variables.txt index 276dc3b3f1..1545c30c80 100644 --- a/test/prism/fixtures/variables.txt +++ b/test/prism/fixtures/variables.txt @@ -44,3 +44,4 @@ Foo = 1, 2 (a; b; c) +a, (b, c), d = [] diff --git a/test/prism/snapshots/variables.txt b/test/prism/snapshots/variables.txt index f0293522be..4a5507e313 100644 --- a/test/prism/snapshots/variables.txt +++ b/test/prism/snapshots/variables.txt @@ -1,8 +1,8 @@ -@ ProgramNode (location: (1,0)-(45,9)) -├── locals: [:abc, :foo, :bar, :baz] +@ ProgramNode (location: (1,0)-(47,17)) +├── locals: [:abc, :foo, :bar, :baz, :a, :b, :c, :d] └── statements: - @ StatementsNode (location: (1,0)-(45,9)) - └── body: (length: 24) + @ StatementsNode (location: (1,0)-(47,17)) + └── body: (length: 25) ├── @ ClassVariableReadNode (location: (1,0)-(1,5)) │ └── name: :@@abc ├── @ ClassVariableWriteNode (location: (3,0)-(3,9)) @@ -300,39 +300,69 @@ │ │ ├── opening_loc: ∅ │ │ └── closing_loc: ∅ │ └── operator_loc: (43,4)-(43,5) = "=" - └── @ ParenthesesNode (location: (45,0)-(45,9)) - ├── body: - │ @ StatementsNode (location: (45,1)-(45,8)) - │ └── body: (length: 3) - │ ├── @ CallNode (location: (45,1)-(45,2)) - │ │ ├── receiver: ∅ - │ │ ├── call_operator_loc: ∅ - │ │ ├── message_loc: (45,1)-(45,2) = "a" - │ │ ├── opening_loc: ∅ - │ │ ├── arguments: ∅ - │ │ ├── closing_loc: ∅ - │ │ ├── block: ∅ - │ │ ├── flags: variable_call - │ │ └── name: :a - │ ├── @ CallNode (location: (45,4)-(45,5)) - │ │ ├── receiver: ∅ - │ │ ├── call_operator_loc: ∅ - │ │ ├── message_loc: (45,4)-(45,5) = "b" - │ │ ├── opening_loc: ∅ - │ │ ├── arguments: ∅ - │ │ ├── closing_loc: ∅ - │ │ ├── block: ∅ - │ │ ├── flags: variable_call - │ │ └── name: :b - │ └── @ CallNode (location: (45,7)-(45,8)) - │ ├── receiver: ∅ - │ ├── call_operator_loc: ∅ - │ ├── message_loc: (45,7)-(45,8) = "c" - │ ├── opening_loc: ∅ - │ ├── arguments: ∅ - │ ├── closing_loc: ∅ - │ ├── block: ∅ - │ ├── flags: variable_call - │ └── name: :c - ├── opening_loc: (45,0)-(45,1) = "(" - └── closing_loc: (45,8)-(45,9) = ")" + ├── @ ParenthesesNode (location: (45,0)-(45,9)) + │ ├── body: + │ │ @ StatementsNode (location: (45,1)-(45,8)) + │ │ └── body: (length: 3) + │ │ ├── @ CallNode (location: (45,1)-(45,2)) + │ │ │ ├── receiver: ∅ + │ │ │ ├── call_operator_loc: ∅ + │ │ │ ├── message_loc: (45,1)-(45,2) = "a" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: ∅ + │ │ │ ├── closing_loc: ∅ + │ │ │ ├── block: ∅ + │ │ │ ├── flags: variable_call + │ │ │ └── name: :a + │ │ ├── @ CallNode (location: (45,4)-(45,5)) + │ │ │ ├── receiver: ∅ + │ │ │ ├── call_operator_loc: ∅ + │ │ │ ├── message_loc: (45,4)-(45,5) = "b" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: ∅ + │ │ │ ├── closing_loc: ∅ + │ │ │ ├── block: ∅ + │ │ │ ├── flags: variable_call + │ │ │ └── name: :b + │ │ └── @ CallNode (location: (45,7)-(45,8)) + │ │ ├── receiver: ∅ + │ │ ├── call_operator_loc: ∅ + │ │ ├── message_loc: (45,7)-(45,8) = "c" + │ │ ├── opening_loc: ∅ + │ │ ├── arguments: ∅ + │ │ ├── closing_loc: ∅ + │ │ ├── block: ∅ + │ │ ├── flags: variable_call + │ │ └── name: :c + │ ├── opening_loc: (45,0)-(45,1) = "(" + │ └── closing_loc: (45,8)-(45,9) = ")" + └── @ MultiWriteNode (location: (47,0)-(47,17)) + ├── requireds: (length: 3) + │ ├── @ LocalVariableTargetNode (location: (47,0)-(47,1)) + │ │ ├── name: :a + │ │ └── depth: 0 + │ ├── @ MultiTargetNode (location: (47,3)-(47,9)) + │ │ ├── requireds: (length: 2) + │ │ │ ├── @ LocalVariableTargetNode (location: (47,4)-(47,5)) + │ │ │ │ ├── name: :b + │ │ │ │ └── depth: 0 + │ │ │ └── @ LocalVariableTargetNode (location: (47,7)-(47,8)) + │ │ │ ├── name: :c + │ │ │ └── depth: 0 + │ │ ├── rest: ∅ + │ │ ├── posts: (length: 0) + │ │ ├── lparen_loc: (47,3)-(47,4) = "(" + │ │ └── rparen_loc: (47,8)-(47,9) = ")" + │ └── @ LocalVariableTargetNode (location: (47,11)-(47,12)) + │ ├── name: :d + │ └── depth: 0 + ├── rest: ∅ + ├── posts: (length: 0) + ├── lparen_loc: ∅ + ├── rparen_loc: ∅ + ├── operator_loc: (47,13)-(47,14) = "=" + └── value: + @ ArrayNode (location: (47,15)-(47,17)) + ├── elements: (length: 0) + ├── opening_loc: (47,15)-(47,16) = "[" + └── closing_loc: (47,16)-(47,17) = "]"