summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2023-12-15 08:48:39 -0500
committergit <svn-admin@ruby-lang.org>2023-12-15 15:03:49 +0000
commitfe9b42f024eb3724b0853c914916ea7a97fd30a6 (patch)
tree1afc6f0c6309c3e23d1b2a5b27795e294ae4f028
parent1cd4b59e8cf56850a87a56194e7096db63f40204 (diff)
[ruby/prism] Invalid pinned locals in pattern matching
https://github.com/ruby/prism/commit/3a67b37a56
-rw-r--r--prism/diagnostic.c1
-rw-r--r--prism/diagnostic.h1
-rw-r--r--prism/prism.c9
-rw-r--r--test/prism/fixtures/patterns.txt2
-rw-r--r--test/prism/location_test.rb2
-rw-r--r--test/prism/snapshots/patterns.txt24
6 files changed, 28 insertions, 11 deletions
diff --git a/prism/diagnostic.c b/prism/diagnostic.c
index b3a8282cda..fd5dce5a04 100644
--- a/prism/diagnostic.c
+++ b/prism/diagnostic.c
@@ -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",
diff --git a/prism/diagnostic.h b/prism/diagnostic.h
index c88a704488..08a3284abf 100644
--- a/prism/diagnostic.h
+++ b/prism/diagnostic.h
@@ -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,
diff --git a/prism/prism.c b/prism/prism.c
index ec51bf06fa..5746399ff7 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -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);
}
diff --git a/test/prism/fixtures/patterns.txt b/test/prism/fixtures/patterns.txt
index d73c8d025e..dcd6786d4b 100644
--- a/test/prism/fixtures/patterns.txt
+++ b/test/prism/fixtures/patterns.txt
@@ -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
diff --git a/test/prism/location_test.rb b/test/prism/location_test.rb
index 809c1bd8ae..e5b7546925 100644
--- a/test/prism/location_test.rb
+++ b/test/prism/location_test.rb
@@ -673,7 +673,7 @@ module Prism
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
diff --git a/test/prism/snapshots/patterns.txt b/test/prism/snapshots/patterns.txt
index aacdbb250e..13179be338 100644
--- a/test/prism/snapshots/patterns.txt
+++ b/test/prism/snapshots/patterns.txt
@@ -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))
@@ -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))