From d57486cb100d6814423c0e22556266e67000d101 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Thu, 22 Aug 2024 10:22:51 -0400 Subject: [PATCH] [ruby/prism] Turn off extended mode when parsing extended group https://github.com/ruby/prism/commit/098b3f08bc --- prism/regexp.c | 30 +++++-- test/prism/fixtures/regex.txt | 2 + test/prism/snapshots/regex.txt | 138 +++++++++++++++++---------------- 3 files changed, 97 insertions(+), 73 deletions(-) diff --git a/prism/regexp.c b/prism/regexp.c index 9c24e952e8..e4bf74c142 100644 --- a/prism/regexp.c +++ b/prism/regexp.c @@ -427,11 +427,11 @@ pm_regexp_options_remove(pm_regexp_options_t *options, uint8_t key) { /** * True if the given key is set in the options. */ -static bool -pm_regexp_options_added_p(pm_regexp_options_t *options, uint8_t key) { +static uint8_t +pm_regexp_options_state(pm_regexp_options_t *options, uint8_t key) { if (key >= PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM && key <= PRISM_REGEXP_OPTION_STATE_SLOT_MAXIMUM) { key = (uint8_t) (key - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM); - return options->values[key] == PM_REGEXP_OPTION_STATE_ADDED; + return options->values[key]; } return false; @@ -583,7 +583,10 @@ pm_regexp_parse_group(pm_regexp_parser_t *parser, uint16_t depth) { // subexpression, then we are going to be setting the options // for the parent group. In this case we are safe to return now. if (*parser->cursor == ')') { - if (pm_regexp_options_added_p(&options, 'x')) parser->extended_mode = true; + if (pm_regexp_options_state(&options, 'x') == PM_REGEXP_OPTION_STATE_ADDED) { + parser->extended_mode = true; + } + parser->cursor++; return true; } @@ -610,7 +613,15 @@ pm_regexp_parse_group(pm_regexp_parser_t *parser, uint16_t depth) { // subexpression, then we are going to be setting the options // for the parent group. In this case we are safe to return now. if (*parser->cursor == ')') { - if (pm_regexp_options_added_p(&options, 'x')) parser->extended_mode = true; + switch (pm_regexp_options_state(&options, 'x')) { + case PM_REGEXP_OPTION_STATE_ADDED: + parser->extended_mode = true; + break; + case PM_REGEXP_OPTION_STATE_REMOVED: + parser->extended_mode = false; + break; + } + parser->cursor++; return true; } @@ -624,8 +635,13 @@ pm_regexp_parse_group(pm_regexp_parser_t *parser, uint16_t depth) { } bool extended_mode = parser->extended_mode; - if (pm_regexp_options_added_p(&options, 'x')) { - parser->extended_mode = true; + switch (pm_regexp_options_state(&options, 'x')) { + case PM_REGEXP_OPTION_STATE_ADDED: + parser->extended_mode = true; + break; + case PM_REGEXP_OPTION_STATE_REMOVED: + parser->extended_mode = false; + break; } // Now, parse the expressions within this group. diff --git a/test/prism/fixtures/regex.txt b/test/prism/fixtures/regex.txt index 84b5ca0600..4623733f58 100644 --- a/test/prism/fixtures/regex.txt +++ b/test/prism/fixtures/regex.txt @@ -44,3 +44,5 @@ tap { /(?)/ =~ to_s } /(?)/ =~ "" def foo(nil:) = /(?)/ =~ "" + +/(?-x:#)/x diff --git a/test/prism/snapshots/regex.txt b/test/prism/snapshots/regex.txt index 17f12e1825..c90e689760 100644 --- a/test/prism/snapshots/regex.txt +++ b/test/prism/snapshots/regex.txt @@ -1,10 +1,10 @@ -@ ProgramNode (location: (1,0)-(46,32)) +@ ProgramNode (location: (1,0)-(48,10)) ├── flags: ∅ ├── locals: [:foo, :ab, :abc, :a] └── statements: - @ StatementsNode (location: (1,0)-(46,32)) + @ StatementsNode (location: (1,0)-(48,10)) ├── flags: ∅ - └── body: (length: 25) + └── body: (length: 26) ├── @ CallNode (location: (1,0)-(1,9)) │ ├── flags: newline, ignore_visibility │ ├── receiver: ∅ @@ -474,66 +474,72 @@ │ │ └── unescaped: "" │ ├── closing_loc: ∅ │ └── block: ∅ - └── @ DefNode (location: (46,0)-(46,32)) - ├── flags: newline - ├── name: :foo - ├── name_loc: (46,4)-(46,7) = "foo" - ├── receiver: ∅ - ├── parameters: - │ @ ParametersNode (location: (46,8)-(46,12)) - │ ├── flags: ∅ - │ ├── requireds: (length: 0) - │ ├── optionals: (length: 0) - │ ├── rest: ∅ - │ ├── posts: (length: 0) - │ ├── keywords: (length: 1) - │ │ └── @ RequiredKeywordParameterNode (location: (46,8)-(46,12)) - │ │ ├── flags: ∅ - │ │ ├── name: :nil - │ │ └── name_loc: (46,8)-(46,12) = "nil:" - │ ├── keyword_rest: ∅ - │ └── block: ∅ - ├── body: - │ @ StatementsNode (location: (46,16)-(46,32)) - │ ├── flags: ∅ - │ └── body: (length: 1) - │ └── @ MatchWriteNode (location: (46,16)-(46,32)) - │ ├── flags: ∅ - │ ├── call: - │ │ @ CallNode (location: (46,16)-(46,32)) - │ │ ├── flags: ∅ - │ │ ├── receiver: - │ │ │ @ RegularExpressionNode (location: (46,16)-(46,26)) - │ │ │ ├── flags: static_literal, forced_us_ascii_encoding - │ │ │ ├── opening_loc: (46,16)-(46,17) = "/" - │ │ │ ├── content_loc: (46,17)-(46,25) = "(?)" - │ │ │ ├── closing_loc: (46,25)-(46,26) = "/" - │ │ │ └── unescaped: "(?)" - │ │ ├── call_operator_loc: ∅ - │ │ ├── name: :=~ - │ │ ├── message_loc: (46,27)-(46,29) = "=~" - │ │ ├── opening_loc: ∅ - │ │ ├── arguments: - │ │ │ @ ArgumentsNode (location: (46,30)-(46,32)) - │ │ │ ├── flags: ∅ - │ │ │ └── arguments: (length: 1) - │ │ │ └── @ StringNode (location: (46,30)-(46,32)) - │ │ │ ├── flags: ∅ - │ │ │ ├── opening_loc: (46,30)-(46,31) = "\"" - │ │ │ ├── content_loc: (46,31)-(46,31) = "" - │ │ │ ├── closing_loc: (46,31)-(46,32) = "\"" - │ │ │ └── unescaped: "" - │ │ ├── closing_loc: ∅ - │ │ └── block: ∅ - │ └── targets: (length: 1) - │ └── @ LocalVariableTargetNode (location: (46,20)-(46,23)) - │ ├── flags: ∅ - │ ├── name: :nil - │ └── depth: 0 - ├── locals: [:nil] - ├── def_keyword_loc: (46,0)-(46,3) = "def" - ├── operator_loc: ∅ - ├── lparen_loc: (46,7)-(46,8) = "(" - ├── rparen_loc: (46,12)-(46,13) = ")" - ├── equal_loc: (46,14)-(46,15) = "=" - └── end_keyword_loc: ∅ + ├── @ DefNode (location: (46,0)-(46,32)) + │ ├── flags: newline + │ ├── name: :foo + │ ├── name_loc: (46,4)-(46,7) = "foo" + │ ├── receiver: ∅ + │ ├── parameters: + │ │ @ ParametersNode (location: (46,8)-(46,12)) + │ │ ├── flags: ∅ + │ │ ├── requireds: (length: 0) + │ │ ├── optionals: (length: 0) + │ │ ├── rest: ∅ + │ │ ├── posts: (length: 0) + │ │ ├── keywords: (length: 1) + │ │ │ └── @ RequiredKeywordParameterNode (location: (46,8)-(46,12)) + │ │ │ ├── flags: ∅ + │ │ │ ├── name: :nil + │ │ │ └── name_loc: (46,8)-(46,12) = "nil:" + │ │ ├── keyword_rest: ∅ + │ │ └── block: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (46,16)-(46,32)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 1) + │ │ └── @ MatchWriteNode (location: (46,16)-(46,32)) + │ │ ├── flags: ∅ + │ │ ├── call: + │ │ │ @ CallNode (location: (46,16)-(46,32)) + │ │ │ ├── flags: ∅ + │ │ │ ├── receiver: + │ │ │ │ @ RegularExpressionNode (location: (46,16)-(46,26)) + │ │ │ │ ├── flags: static_literal, forced_us_ascii_encoding + │ │ │ │ ├── opening_loc: (46,16)-(46,17) = "/" + │ │ │ │ ├── content_loc: (46,17)-(46,25) = "(?)" + │ │ │ │ ├── closing_loc: (46,25)-(46,26) = "/" + │ │ │ │ └── unescaped: "(?)" + │ │ │ ├── call_operator_loc: ∅ + │ │ │ ├── name: :=~ + │ │ │ ├── message_loc: (46,27)-(46,29) = "=~" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: + │ │ │ │ @ ArgumentsNode (location: (46,30)-(46,32)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ └── arguments: (length: 1) + │ │ │ │ └── @ StringNode (location: (46,30)-(46,32)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ ├── opening_loc: (46,30)-(46,31) = "\"" + │ │ │ │ ├── content_loc: (46,31)-(46,31) = "" + │ │ │ │ ├── closing_loc: (46,31)-(46,32) = "\"" + │ │ │ │ └── unescaped: "" + │ │ │ ├── closing_loc: ∅ + │ │ │ └── block: ∅ + │ │ └── targets: (length: 1) + │ │ └── @ LocalVariableTargetNode (location: (46,20)-(46,23)) + │ │ ├── flags: ∅ + │ │ ├── name: :nil + │ │ └── depth: 0 + │ ├── locals: [:nil] + │ ├── def_keyword_loc: (46,0)-(46,3) = "def" + │ ├── operator_loc: ∅ + │ ├── lparen_loc: (46,7)-(46,8) = "(" + │ ├── rparen_loc: (46,12)-(46,13) = ")" + │ ├── equal_loc: (46,14)-(46,15) = "=" + │ └── end_keyword_loc: ∅ + └── @ RegularExpressionNode (location: (48,0)-(48,10)) + ├── flags: newline, static_literal, extended, forced_us_ascii_encoding + ├── opening_loc: (48,0)-(48,1) = "/" + ├── content_loc: (48,1)-(48,8) = "(?-x:#)" + ├── closing_loc: (48,8)-(48,10) = "/x" + └── unescaped: "(?-x:#)"