Skip to content

Commit

Permalink
[ruby/prism] Invalid pinned locals in pattern matching
Browse files Browse the repository at this point in the history
  • Loading branch information
kddnewton authored and matzbot committed Dec 15, 2023
1 parent 1cd4b59 commit fe9b42f
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 11 deletions.
1 change: 1 addition & 0 deletions prism/diagnostic.c
Expand Up @@ -192,6 +192,7 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = {
[PM_ERR_MODULE_TERM] = "expected an `end` to close the `module` statement",
[PM_ERR_MULTI_ASSIGN_MULTI_SPLATS] = "multiple splats in multiple assignment",
[PM_ERR_NOT_EXPRESSION] = "expected an expression after `not`",
[PM_ERR_NO_LOCAL_VARIABLE] = "%.*s: no such local variable",
[PM_ERR_NUMBER_LITERAL_UNDERSCORE] = "number literal ending with a `_`",
[PM_ERR_NUMBERED_PARAMETER_NOT_ALLOWED] = "numbered parameters are not allowed when an ordinary parameter is defined",
[PM_ERR_NUMBERED_PARAMETER_OUTER_SCOPE] = "numbered parameter is already used in outer scope",
Expand Down
1 change: 1 addition & 0 deletions prism/diagnostic.h
Expand Up @@ -184,6 +184,7 @@ typedef enum {
PM_ERR_MODULE_TERM,
PM_ERR_MULTI_ASSIGN_MULTI_SPLATS,
PM_ERR_NOT_EXPRESSION,
PM_ERR_NO_LOCAL_VARIABLE,
PM_ERR_NUMBER_LITERAL_UNDERSCORE,
PM_ERR_NUMBERED_PARAMETER_NOT_ALLOWED,
PM_ERR_NUMBERED_PARAMETER_OUTER_SCOPE,
Expand Down
9 changes: 8 additions & 1 deletion prism/prism.c
Expand Up @@ -13352,8 +13352,15 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
// expression to determine if it's a variable or an expression.
switch (parser->current.type) {
case PM_TOKEN_IDENTIFIER: {
int depth = pm_parser_local_depth(parser, &parser->current);

if (depth == -1) {
depth = 0;
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_NO_LOCAL_VARIABLE, (int) (parser->current.end - parser->current.start), parser->current.start);
}

pm_node_t *variable = (pm_node_t *) pm_local_variable_read_node_create(parser, &parser->current, (uint32_t) depth);
parser_lex(parser);
pm_node_t *variable = (pm_node_t *) pm_local_variable_read_node_create(parser, &parser->previous, 0);

return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
}
Expand Down
2 changes: 1 addition & 1 deletion test/prism/fixtures/patterns.txt
Expand Up @@ -51,7 +51,7 @@ foo => __LINE__ .. __LINE__
foo => __ENCODING__ .. __ENCODING__
foo => -> { bar } .. -> { bar }

foo => ^bar
bar = 1; foo => ^bar
foo => ^@bar
foo => ^@@bar
foo => ^$bar
Expand Down
2 changes: 1 addition & 1 deletion test/prism/location_test.rb
Expand Up @@ -673,7 +673,7 @@ def test_PinnedExpressionNode
end

def test_PinnedVariableNode
assert_location(PinnedVariableNode, "foo in ^bar", 7...11, &:pattern)
assert_location(PinnedVariableNode, "bar = 1; foo in ^bar", 16...20, &:pattern)
end

def test_PostExecutionNode
Expand Down
24 changes: 16 additions & 8 deletions test/prism/snapshots/patterns.txt
Expand Up @@ -2,7 +2,7 @@
├── locals: [:bar, :baz, :qux, :b, :a, :foo, :x]
└── statements:
@ StatementsNode (location: (1,0)-(202,19))
└── body: (length: 175)
└── body: (length: 176)
├── @ MatchRequiredNode (location: (1,0)-(1,10))
│ ├── value:
│ │ @ CallNode (location: (1,0)-(1,3))
Expand Down Expand Up @@ -1235,26 +1235,34 @@
│ │ │ └── depth: 1
│ │ └── operator_loc: (52,18)-(52,20) = ".."
│ └── operator_loc: (52,4)-(52,6) = "=>"
├── @ MatchRequiredNode (location: (54,0)-(54,11))
├── @ LocalVariableWriteNode (location: (54,0)-(54,7))
│ ├── name: :bar
│ ├── depth: 0
│ ├── name_loc: (54,0)-(54,3) = "bar"
│ ├── value:
│ │ @ CallNode (location: (54,0)-(54,3))
│ │ @ IntegerNode (location: (54,6)-(54,7))
│ │ └── flags: decimal
│ └── operator_loc: (54,4)-(54,5) = "="
├── @ MatchRequiredNode (location: (54,9)-(54,20))
│ ├── value:
│ │ @ CallNode (location: (54,9)-(54,12))
│ │ ├── flags: variable_call
│ │ ├── receiver: ∅
│ │ ├── call_operator_loc: ∅
│ │ ├── name: :foo
│ │ ├── message_loc: (54,0)-(54,3) = "foo"
│ │ ├── message_loc: (54,9)-(54,12) = "foo"
│ │ ├── opening_loc: ∅
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── pattern:
│ │ @ PinnedVariableNode (location: (54,7)-(54,11))
│ │ @ PinnedVariableNode (location: (54,16)-(54,20))
│ │ ├── variable:
│ │ │ @ LocalVariableReadNode (location: (54,8)-(54,11))
│ │ │ @ LocalVariableReadNode (location: (54,17)-(54,20))
│ │ │ ├── name: :bar
│ │ │ └── depth: 0
│ │ └── operator_loc: (54,7)-(54,8) = "^"
│ └── operator_loc: (54,4)-(54,6) = "=>"
│ │ └── operator_loc: (54,16)-(54,17) = "^"
│ └── operator_loc: (54,13)-(54,15) = "=>"
├── @ MatchRequiredNode (location: (55,0)-(55,12))
│ ├── value:
│ │ @ CallNode (location: (55,0)-(55,3))
Expand Down

0 comments on commit fe9b42f

Please sign in to comment.