112 Commits
Author SHA1 Message Date
Kevin Newton 19c0ec232e [ruby/prism] Fix up handling Foo::Bar {} with a comma
https://github.com/ruby/prism/commit/4893d3b94e
2026-10-15 20:43:54 +00:00
Kevin Newton 12c4506f46 [ruby/prism] Fix up not command inside endless def
https://github.com/ruby/prism/commit/c3bdf7c769
2026-10-15 20:43:44 +00:00
Kevin Newton 8c7656f5ba [ruby/prism] Split up command write checks
Previously checking for a command write was the same concept as
checking for a command call, but in reality (and since 4.0) they
are different things.

https://github.com/ruby/prism/commit/e9cdac6b98
2026-10-15 20:24:39 +00:00
Kevin Newton 16e5778e07 [ruby/prism] Handle command assignment with endless def
A very subtle issue, but one that came up with fuzzers.

https://github.com/ruby/prism/commit/b57cd1f440
2026-10-15 19:37:22 +00:00
Kevin Newton 976b89be4a [ruby/prism] Do not report regexp errors twice with captures
When named captures were present we would reprocess the regexp and
accidentally report errors twice.

https://github.com/ruby/prism/commit/e2e11ad07f
2026-10-13 17:12:17 +00:00
Kevin Newton b74b3b45e8 [ruby/prism] Add a constant id set
There are times when we don't need explicit order in a list of
constants, namely when looking at names of captures in a pattern
match and names of captures in a regular expression. In these cases
it's better to be linear with respect to the number of names, so
using a hash makes a little more sense.

https://github.com/ruby/prism/commit/d1c23d4956
2026-09-29 19:02:58 +00:00
yuki300 42bf37a41d [ruby/prism] Only report real captures inside alternation patterns
When a variable is captured anywhere in a pattern, the operands of each
alternation are visited to report captures inside them. That visitor
treated every local variable target as a capture, including
underscore-prefixed names and targets that belong to a lambda, a string
interpolation, or a pinned expression:

    case foo
    in [bar, 1 | _baz]                         # error
    in [bar, "#{case 1; in baz; end}" | 2]     # error
    end

Without `bar` both are accepted. Skip underscore-prefixed names, like
parse_pattern_capture does, and only descend into the nodes that make up
the pattern itself. Nested alternations are skipped too, their operands
were already checked when they were parsed. Before this, a capture like
`1 => [x, (1 | y) | 2]` was reported twice.

The new fixture is excluded from the tests that compare against parse.y,
which currently rejects these forms because of the capture of `bar`:
https://bugs.ruby-lang.org/issues/22310

https://github.com/ruby/prism/commit/33ef692741
2026-09-28 16:22:39 +00:00
Hiroya Fujinami 8587ce292b [ruby/prism] Avoid quadratic value-expression check on and/or chains
(https://github.com/ruby/prism/pull/4221)

Ref https://bugs.ruby-lang.org/issues/22294

pm_check_value_expression descended the left operand of every and/or
node it visited. Because pm_and_node_create and pm_or_node_create
already assert the value of their left operand when the node is built,
walking a left-associative chain such as `a && a && ... && a`
re-checked the whole left spine once per operator, which is quadratic
in the length of the chain: 16k operators took seconds.

The left operand of an existing and/or node was therefore already
checked, so stop at the node instead of descending. This makes the
check linear. The only observable change is that a void value on the
left spine of a chain is now reported once, at the innermost node
where it is created, rather than once per enclosing operator; the
errors fixture that pinned the duplicate is updated to match.

https://github.com/ruby/prism/commit/b19a0a5bc0
2026-09-05 09:18:25 +00:00
Alan Wu 19f5b1248d Reintroduce recent PRISM changes
This reverts commit 895084e65b.
IRB failures are fixed by 6612731a4f.
2026-08-05 21:56:00 +00:00
XrXr 895084e65b Revert recent PRISM changes to fix irb bundled_gems CI
This reverts commit 0017dea395,
5e36630fc0, and
f3ec056c9f.

We are trying to bump to latest IRB, which has "Accomodate new prism
tokens", but that runs into another CI failure. While we figure out a
path forward at <https://github.com/ruby/ruby/pull/18207>, let's get
back to a green CI.
2026-08-05 13:06:40 -04:00
Kevin Newton 5e36630fc0 [ruby/prism] Split up lbrace token
This also more closely matches parse.y, and makes it easier to
delineate which brace belongs to which type.

https://github.com/ruby/prism/commit/43ed8c1f80
2026-08-05 11:02:34 +00:00
Kevin Newton e67f02518a [ruby/prism] Pinned back references and pinned numbered references are not allowed
https://github.com/ruby/prism/commit/35c587b1c2
2026-07-29 20:59:02 +00:00
Kevin Newtonandkai-matsudate 0f5e45d8cf [ruby/prism] Fix pattern matching trailing comma
This was previously an allow-list of the various tokens that were
considered the start of a pattern expression. Instead, use our
existing expression checking stuff and avoid having to list out
each token.

https://github.com/ruby/prism/commit/a139586ca0

Co-authored-by: kai-matsudate <kai.matsudate@techouse.jp>
2026-07-17 19:54:47 +00:00
Kevin Newton c51b1596c0 [ruby/prism] Refactor do keyword parsing
Mirror much more closely the parse.y COND and CMDARG stacks. This
fixes a whole host of really really weird edge cases.

https://github.com/ruby/prism/commit/75bf2e7081
2026-07-07 14:04:07 +00:00
Kevin Newton 2a23415062 [ruby/prism] Pop block stack _before_ ending in parenthesized method call in command call
https://github.com/ruby/prism/commit/c5da02a516
2026-06-29 14:16:12 +00:00
Kevin Newton 11d005d6ba [ruby/prism] Pop block stack before finishing command call arguments within parenthesized call
https://github.com/ruby/prism/commit/26cfb915e8
2026-06-23 20:33:39 +00:00
Kevin Newton 6785670f7e [ruby/prism] Handle EOF in hash pattern key
https://github.com/ruby/prism/commit/43ffaad503
2026-06-22 20:52:15 +00:00
Kevin Newton 10b27fd0ff [ruby/prism] Dynamic constant writes on operator writes
https://github.com/ruby/prism/commit/6b4f0ade80
2026-06-22 19:53:09 +00:00
Kevin Newton 80c53fdae2 [ruby/prism] Match command_call/arg
A couple more deviations from the parse.y grammar with the
command_call and arg productions.

* pm_block_call_p — allow parens on chain links (meth 1 do end.fun(x))
* pm_command_call_value_p — recognize const-path brace commands (Foo::Bar { })
* super with do/end as a block_call (chaining: super 1 do end.baz)
* foo(Foo::Bar { } => v)

https://github.com/ruby/prism/commit/2c2a463021
2026-06-22 19:50:35 +00:00
Kevin Newton b5bbbe69cd [ruby/prism] Fix duplicative rest pattern in pattern matching
https://github.com/ruby/prism/commit/358d778439
2026-06-22 14:38:55 +00:00
Kevin Newton 8f3fce4e0e [ruby/prism] Handle trailing comma after ...
https://github.com/ruby/prism/commit/8eb393bf37
2026-06-22 14:38:55 +00:00
Kevin Newton 1db15766a8 [ruby/prism] Fix up non-associativity in same binding power
https://github.com/ruby/prism/commit/55548c2fd5
2026-06-22 14:38:54 +00:00
Kevin Newton 20bdc5d2fb [ruby/prism] Disallow trailing comma on parenthesized yield
https://github.com/ruby/prism/commit/b3819da252
2026-06-22 14:38:54 +00:00
Kevin Newton f71dd80fa3 [ruby/prism] Disallow trailing comma on jumps at EOF
https://github.com/ruby/prism/commit/d18d9d829b
2026-06-22 14:38:54 +00:00
Kevin Newton 6a9ee89182 [ruby/prism] Parse rescue modifier values as statements
The value of a `rescue` modifier is a full `stmt` in the grammar in
three of its six productions, but we parsed it as a plain expression
in every case. This rejected valid syntax such as `a rescue b, c = 1`
and accepted invalid syntax such as `a = 1 rescue not b`.

These are the relevant grammar rules:

      stmt            : stmt modifier_rescue stmt
                      | mlhs '=' mrhs_arg modifier_rescue stmt
      command_rhs     : command_call_value modifier_rescue stmt
      arg_rhs         : arg modifier_rescue arg
      endless_arg     : endless_arg modifier_rescue arg
      endless_command : endless_command modifier_rescue arg

parse_rescue_modifier_value will now parse either a stmt or an arg
depending on the caller.

https://github.com/ruby/prism/commit/07e63f707f
2026-06-15 15:57:16 +00:00
Earlopain 29764156f6 [ruby/prism] Fix multibyte non-alphanumeric chars for bare percent string literals
Alphanumerics are correctly handled in the check below
by simply discarding the `%`.
The same was not true for the other types, which caused some assumption to no longer hold.

https://github.com/ruby/prism/commit/69a9a36a6a
2026-06-10 12:20:27 +00:00
kai-matsudate 9e8ad9ac04 [ruby/prism] Reject modifier conditionals in if/unless predicates
Prism accepted a modifier conditional as the predicate of an `if`/`unless`
(and `elsif`), while parse.y rejects it:

    if a if b then end      # parse.y: SyntaxError, prism: accepted
    unless a unless b then end

The `if`/`unless`/`elsif` predicate was parsed with a floor of
`PM_BINDING_POWER_MODIFIER`, which is inclusive of the modifier
conditionals (`if`/`unless`/`while`/`until`, left binding power
`PM_BINDING_POWER_MODIFIER`), so they were absorbed into the predicate.
`while`/`until` predicates already use `PM_BINDING_POWER_COMPOSITION` and
reject these correctly.

Raise the floor to `PM_BINDING_POWER_MODIFIER + 1` so the predicate still
absorbs `and`/`or` (and tighter operators) but excludes the modifier
conditionals, matching parse.y and aligning `if`/`unless` with
`while`/`until`.

https://github.com/ruby/prism/commit/0fa8d8f8d8
2026-06-01 17:25:15 +00:00
Earlopain 11de89ca1a Reject END { next } as well
Followup for https://bugs.ruby-lang.org/issues/20409
2026-05-15 19:58:27 +09:00
Earlopain 558c104139 [ruby/prism] Reject END { break } for Ruby 4.0
For [Bug #20409]

https://github.com/ruby/prism/commit/4848eb344e
2026-04-27 14:01:26 +00:00
Earlopain 51a3f08477 [ruby/prism] Reject return and similar with block pass argument
Same handling as for `yield`. Fixes [Bug #21988]

https://github.com/ruby/prism/commit/2dd20183ad
2026-04-09 11:48:11 +00:00
Kevin Newton b1d6132b11 [ruby/prism] More gracefully handle interpolated keys in hpn
https://github.com/ruby/prism/commit/31c71e7a40
2026-03-24 15:44:33 +00:00
Kevin Newton c8c94edeae [ruby/prism] Fix binding for in, not, and do on/after command calls
https://github.com/ruby/prism/commit/fd0a20f8d8
2026-03-10 02:08:17 +00:00
Kevin Newton fd9448bc87 [ruby/prism] Fix not without parentheses binding power
https://github.com/ruby/prism/commit/7d21e564ac
2026-03-06 21:27:30 +00:00
Kevin Newton 6533b101e3 [ruby/prism] Fix precedence of infix operators after command
https://github.com/ruby/prism/commit/35470bb90d
2026-03-06 21:26:44 +00:00
Kevin Newton 9ecac8d469 [ruby/prism] Fix the handling of do on commands
Introduce PM_TOKEN_KEYWORD_DO_BLOCK to distinguish do-blocks on
command-style calls from regular `do` keywords. Add
parse_command_do_block to attach these blocks to call nodes. Track
in_endless_def_body to prevent do-block consumption inside endless
method definitions, allowing blocks to correctly bubble up to outer
contexts like `private def f = puts "Hello" do end`.

https://github.com/ruby/prism/commit/7d17fd254b
2026-03-06 18:45:20 +00:00
Earlopain 795619ec11 [ruby/prism] Revert "Reject infix operators on command call on
writes"
(https://github.com/ruby/prism/pull/3960)

This reverts commit https://github.com/ruby/prism/commit/4e71dbfc7bd9.

And also add a regression test. Seems like currently prism parses these the same that parse.y does.

https://github.com/ruby/prism/commit/03993421f2
2026-03-04 11:49:58 +00:00
Kevin Newton 8c7f4db893 [ruby/prism] Fix modifier rescue pattern matching
[Bug #21713]

https://github.com/ruby/prism/commit/02c944c055
2026-03-03 13:40:10 +00:00
Kevin Newton 3b6562f663 [ruby/prism] Fix up endless method definition with do/end
[Bug #21714]

https://github.com/ruby/prism/commit/0f47e18335
2026-03-02 20:41:55 +00:00
Kevin Newton 460566ab85 [ruby/prism] Reject infix operators on command call on writes
https://github.com/ruby/prism/commit/4e71dbfc7b
2026-03-02 17:35:03 +00:00
Earlopain 6af0de2379 [ruby/prism] Fix error message for block/lambda with ... argument
They currently complain that the parent method is not forwarding.
But the actual problem is that these types of arguments simply don't
accept `...`

Fixes [Bug #21927]

https://github.com/ruby/prism/commit/0aa2363331
2026-02-27 13:33:36 +00:00
Earlopain 731b6092e9 [ruby/prism] [Feature #19107] Allow trailing comma in method signature
https://github.com/ruby/prism/commit/b7e247ce6a
2026-02-22 16:38:42 +00:00
Earlopain 387faae784 [ruby/prism] Add a test for multiple &nil blocks/mixing them
https://github.com/ruby/prism/commit/e5fb0e192b
2026-02-16 20:33:32 +00:00
Kevin Newton 7135ab56c8 [ruby/prism] Only accept noblock in Ruby 4.1+
https://github.com/ruby/prism/commit/fb88c72dce
2026-02-16 20:33:32 +00:00
Earlopain bf1ac3f4af [ruby/prism] Fix lexing for unterminated strings/heredocs etc.
When we hit EOF and still have lex modes left, it means some content was unterminated.
Heredocs specifically have logic that needs to happen when the body finished lexing.
If we don't reset the mode back to how it was before, it will not continue lexing at the correct place.

Followup to https://github.com/ruby/prism/pull/3918.
We can't call into `parser_lex` since it resets token locations.

https://github.com/ruby/prism/commit/27c24fdc0d
2026-02-13 16:38:48 +00:00
Earlopain fd9dd36dfc [ruby/prism] Revert "Fix lexing for unterminated strings/heredocs etc."
This reverts commit https://github.com/ruby/prism/commit/8f35e8ef255b.

https://github.com/ruby/prism/commit/ed48f6dbfb
2026-02-12 15:53:47 +00:00
Earlopain ed113c556b [ruby/prism] Fix lexing for unterminated strings/heredocs etc.
When we hit EOF and still have lex modes left, it means some content was unterminated.
Heredocs specifically have logic that needs to happen when the body finished lexing.
If we don't reset the mode back to how it was before, it will not continue lexing at the correct place.

https://github.com/ruby/prism/commit/8f35e8ef25
2026-02-12 14:51:03 +00:00
Earlopain 3237be163c [Bug #21669] Thoroughly implement void value expression check (prism) 2026-02-03 10:49:21 -05:00
Thomas Marshall 14fbcf0e6e [ruby/prism] Report missing end errors at opening token
This commit adds an `expect1_opening` function that expects a token and
attaches the error to the opening token location rather than the current
position. This is useful for errors about missing closing tokens, where
we want to point to the line with the opening token rather than the end
of the file.

For example:

```ruby
def foo
def bar
def baz
       ^ expected an `end` to close the `def` statement
       ^ expected an `end` to close the `def` statement
       ^ expected an `end` to close the `def` statement
```

This would previously produce three identical errors at the end of the
file. After this commit, they would be reported at the opening token
location:

```ruby
def foo
^~~ expected an `end` to close the `def` statement
def bar
^~~ expected an `end` to close the `def` statement
def baz
^~~ expected an `end` to close the `def` statement
```

I considered using the end of the line where the opening token is
located, but in some cases that would be less useful than the opening
token location itself. For example:

```ruby
def foo def bar def baz
```

Here the end of the line where the opening token is located would be the
same for each of the unclosed `def` nodes.

https://github.com/ruby/prism/commit/2d7829f060
2025-12-29 14:12:20 +00:00
Thomas Marshall 8afd4fade6 [ruby/prism] Add unterminated construct tests
https://github.com/ruby/prism/commit/166764f794
2025-12-29 14:12:20 +00:00
Earlopain e2c886dd66 [ruby/prism] Reject p(p a, &block => value) and similar
Redo of https://github.com/ruby/prism/pull/3669 with more tests

https://github.com/ruby/prism/commit/48b403ea79
2025-12-18 19:58:53 -05:00