Commit graph

750 commits

Author SHA1 Message Date
Earlopain
a04555c8ab [ruby/prism] Be more defensive in the parser translator lexer
Generally I have been good about safely accessing the tokens but failed
to properly guard against no tokens in places
where it could theoretically happen through invalid syntax.

I added a test case for one occurance, other changes are theoretical only.

4a3866af19
2025-08-14 15:42:33 +00:00
S-H-GAMELINKS
a12e0c1db1 [ruby/prism] Remove uneeded test
a6b448b10f
2025-08-05 13:58:09 -04:00
S-H-GAMELINKS
02200ac81c [ruby/prism] Add it read and assignment test
659d769621
2025-08-05 13:58:09 -04:00
S-H-GAMELINKS
b482e3d7cd [ruby/prism] Make it = it assign nil to match parse.y behavior [Bug #21139]
Currently Prism returns `42` for code like this:
```ruby
42.tap { it = it; p it } # => 42
```

But parse.y returns `nil`:
```ruby
42.tap { it = it; p it } # => nil
```

In parse.y, it on the right-hand side is parsed as a local variable.
In Prism, it was parsed as the implicit block parameter it, which caused this inconsistent behavior.

This change makes the right-hand side it to be parsed as a local variable, aligning with parse.y's behavior.

Bug ticket: https://bugs.ruby-lang.org/issues/21139

cf3bbf9d2c
2025-08-05 13:58:09 -04:00
Kevin Newton
6e2b139d6a [ruby/prism] Ensure context terminators terminate expressions
915f6b3ae9
2025-08-05 13:58:09 -04:00
Kevin Newton
2e672fdee0 [ruby/prism] Bump JRuby version
27d284bbb8
2025-08-05 13:58:09 -04:00
Kevin Newton
2936da902c [ruby/prism] Handle new ractor stuff
f5ded5104d
2025-08-05 13:58:09 -04:00
ydah
087190fcd2 [ruby/prism] Improve error handling for missing parentheses after 'not' in command calls
d9151b8a82
2025-08-05 13:58:09 -04:00
Yusuke Endoh
f814a77755 [ruby/prism] Reject true && not true
A command-call-like `not true` must be rejected after `&&` and `||`.

https://bugs.ruby-lang.org/issues/21337

0513cf22ad
2025-08-05 13:58:09 -04:00
Justin Collins
c6dd3cefa1 [ruby/prism] Avoid monkey patching Sexp#== in RubyParser tests
7362b114a3
2025-08-01 16:57:18 +00:00
Justin Collins
d289eb2723 [ruby/prism] RubyParser translation for stabby lambdas with it
c2e372a8d8
2025-08-01 16:57:17 +00:00
Stan Lo
2eab962c53 [ruby/prism] Allow command calls in endless method bodies within assignments
Previously, endless method definitions in assignment contexts like
`x = def f = p 1` would fail to parse because command calls (method
calls without parentheses) were only accepted when the surrounding
binding power was less than `PM_BINDING_POWER_COMPOSITION`.

This fix specifically checks for assignment context and allows command
calls in those cases while maintaining the existing behavior for other
contexts. This ensures that:

- `x = def f = p 1` parses correctly (previously failed)
- `private def f = puts "Hello"` still produces the expected error

722af59ba3
2025-07-29 17:18:41 +00:00
Aaron Patterson
a1403fb7cb Interpolated strings must not be frozen
Strings concatenated with backslash may end up being frozen when they
shouldn't be.  This commit fixes the issue.  It required a change
upstream in Prism, but also a change to the Prism compiler in CRuby.

  https://github.com/ruby/prism/pull/3606

[Bug #21187]
2025-07-22 08:10:55 -07:00
Hiroshi SHIBATA
7dbd9c2636
Revert "[ruby/prism] Clear flags on interpolated strings"
This reverts commit a495e6a44c.

This break extension builds:

```
/Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:321:in 'String#replace': can't modify frozen String: "$(SDKROOT)$(prefix)/include" (FrozenError)
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:321:in 'RbConfig.expand'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:314:in 'block in RbConfig.expand'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:307:in 'String#gsub'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:307:in 'RbConfig.expand'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:314:in 'block in RbConfig.expand'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:307:in 'String#gsub'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:307:in 'RbConfig.expand'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:314:in 'block in RbConfig.expand'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:307:in 'String#gsub'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:307:in 'RbConfig.expand'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:325:in 'block in <module:RbConfig>'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:324:in 'Hash#each_value'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:324:in '<module:RbConfig>'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:11:in '<top (required)>'
        from ./ext/extmk.rb:42:in 'Kernel#require'
        from ./ext/extmk.rb:42:in '<main>'
make[1]: *** [ext/configure-ext.mk:70: ext/json/exts.mk] Error 1
```
2025-07-22 09:07:04 +09:00
Aaron Patterson
a495e6a44c [ruby/prism] Clear flags on interpolated strings
When inner strings aren't frozen, we need to clear the flags on
interpolated string nodes so that we don't emit wrong instructions.

The compiler is currently incorrectly emitting frozen strings because
the parser is erroneously declaring interpolated strings as "frozen".
We need to fix this behavior in the parser so we can fix the compiler in
CRuby.  This patch is a partial fix for [this bug](https://bugs.ruby-lang.org/issues/21187)

eda693f056
2025-07-21 23:04:42 +00:00
Aaron Patterson
c1c9deea83 [ruby/prism] Revert "Merge pull request #3598 from Shopify/fix-3473"
This reverts commit bc446fb979, reversing
changes made to 71432af1eb.

e5ca485f4e
2025-07-17 16:23:17 +00:00
Stan Lo
13de248f39 [ruby/prism] Allow command calls in endless method bodies regardless of context
Previously, endless method definitions like `x = def f = p 1` would fail
to parse because command calls (method calls without parentheses) were
only accepted when the surrounding binding power was less than
`PM_BINDING_POWER_COMPOSITION` (8). In assignment contexts with binding
power 18, this condition was false, causing parse errors.

This fix ensures command calls are always accepted in endless method
bodies by passing `true` for `accepts_command_call`, making the method
body parse consistently regardless of where the method is defined.

70413ed4dd
2025-07-17 16:06:34 +00:00
Earlopain
133cf95618 [ruby/prism] [Bug #21345] Fix accepting multiple rest patterns with leading match
Related:
* https://bugs.ruby-lang.org/issues/20765
* https://github.com/ruby/prism/issues/2915

de56fa4a34
2025-07-16 18:12:06 +00:00
Stan Lo
2591b93593 [ruby/prism] Fix crash when using arithmetic expressions in pattern matching
When arithmetic expressions like `-1**2` are used in pattern matching contexts,
Ruby crashes with "Unexpected node type in pattern matching expression: PM_CALL_NODE".
This happens because the Prism parser creates `PM_CALL_NODE` for arithmetic operations,
but Ruby's pattern matching compiler doesn't handle call nodes.

This fix adds validation to reject `PM_CALL_NODE` in pattern contexts with a proper
syntax error.

365049a767
2025-07-16 17:08:28 +00:00
ydah
4eb0a6cd4d [ruby/prism] Improve error handling for missing parentheses after 'not' in command calls
d9151b8a82
2025-07-16 15:48:09 +00:00
Yusuke Endoh
4cf85fe214 [ruby/prism] Reject true && not true
A command-call-like `not true` must be rejected after `&&` and `||`.

https://bugs.ruby-lang.org/issues/21337

0513cf22ad
2025-07-16 15:48:09 +00:00
Earlopain
3071c5d04c [ruby/prism] Fix parser translator with trailing backslash in %W /%I array
https://docs.ruby-lang.org/en/master/syntax/literals_rdoc.html#label-25w+and+-25W-3A+String-Array+Literals
> %W allow escape sequences described in Escape Sequences. However the continuation line <newline> is not usable because it is interpreted as the escaped newline described above.

f5c7460ad5
2025-06-30 12:32:31 +00:00
Nobuyoshi Nakada
9e5c74f219 [ruby/prism] [DOC] Fix a typo in comment
ruby/ruby#13636

e13d4f19db

Co-Authored-By: Tim Smith <tsmith84@gmail.com>
2025-06-17 11:18:05 +00:00
Earlopain
970813d982 [ruby/prism] Fix parser translator during string escaping with invalid utf-8
Instead, prefer `scan_byte` over `get_byte` since that already returns the byte as an integer, sidestepping conversion issues.

Fixes https://github.com/ruby/prism/issues/3582

7f3008b2b5
2025-06-11 18:07:43 +00:00
Koichi Sasada
ef2bb61018 Ractor::Port
* Added `Ractor::Port`
  * `Ractor::Port#receive` (support multi-threads)
  * `Rcator::Port#close`
  * `Ractor::Port#closed?`
* Added some methods
  * `Ractor#join`
  * `Ractor#value`
  * `Ractor#monitor`
  * `Ractor#unmonitor`
* Removed some methods
  * `Ractor#take`
  * `Ractor.yield`
* Change the spec
  * `Racotr.select`

You can wait for multiple sequences of messages with `Ractor::Port`.

```ruby
ports = 3.times.map{ Ractor::Port.new }
ports.map.with_index do |port, ri|
  Ractor.new port,ri do |port, ri|
    3.times{|i| port << "r#{ri}-#{i}"}
  end
end

p ports.each{|port| pp 3.times.map{port.receive}}

```

In this example, we use 3 ports, and 3 Ractors send messages to them respectively.
We can receive a series of messages from each port.

You can use `Ractor#value` to get the last value of a Ractor's block:

```ruby
result = Ractor.new do
  heavy_task()
end.value
```

You can wait for the termination of a Ractor with `Ractor#join` like this:

```ruby
Ractor.new do
  some_task()
end.join
```

`#value` and `#join` are similar to `Thread#value` and `Thread#join`.

To implement `#join`, `Ractor#monitor` (and `Ractor#unmonitor`) is introduced.

This commit changes `Ractor.select()` method.
It now only accepts ports or Ractors, and returns when a port receives a message or a Ractor terminates.

We removes `Ractor.yield` and `Ractor#take` because:
* `Ractor::Port` supports most of similar use cases in a simpler manner.
* Removing them significantly simplifies the code.

We also change the internal thread scheduler code (thread_pthread.c):
* During barrier synchronization, we keep the `ractor_sched` lock to avoid deadlocks.
  This lock is released by `rb_ractor_sched_barrier_end()`
  which is called at the end of operations that require the barrier.
* fix potential deadlock issues by checking interrupts just before setting UBF.

https://bugs.ruby-lang.org/issues/21262
2025-05-31 04:01:33 +09:00
viralpraxis
543dd77cc3 [ruby/prism] Fix parsing rescued exception via indexed assignment
Given this code

```ruby
begin
  raise '42'
rescue => A[]
end
```

Prism fails with this backtrace

```
Error: test_unparser/corpus/literal/rescue.txt(Prism::ParserTest): NoMethodError: undefined method `arguments' for nil
prism/lib/prism/translation/parser/compiler.rb:1055:in `visit_index_target_node'
prism/lib/prism/node.rb:9636:in `accept'
prism/lib/prism/compiler.rb:30:in `visit'
prism/lib/prism/translation/parser/compiler.rb:218:in `visit_begin_node'
```

Seems like

```diff
-            visit_all(node.arguments.arguments),
+            visit_all(node.arguments&.arguments || []),
```

fixes the problem.

76d01aeb6c
2025-04-12 17:43:57 +00:00
Earlopain
d543fda433 [ruby/prism] Be explicit in tests which files parser can't parse
It also updates to latest `parser`, which allows numbered
parameters in pattern matching pin,
passing `patterns.txt` and `case.txt`

bdcc8b3dc5
2025-04-02 20:53:34 +00:00
Earlopain
334c261cc9 [ruby/prism] Fix parser translator when splatting in pattern matching pin
Because it ends up treating it as a local variable, and `a.x`
is not a valid local variable name.

I'm not big on pattern matching, but conceptually it makes sense to me
to treat anything inside ^() to not be
pattern matching syntax?

80dbd85c45
2025-04-02 20:51:54 +00:00
Earlopain
d7e46543b5 [ruby/prism] Fix parser translator when pinning hash with string keys
`StringNode` and `SymbolNode` don't have the same shape
(`content` vs `value`) and that wasn't handled.

I believe the logic for the common case can be reused.
I simply left the special handling for implicit nodes in pattern matching
and fall through otherwise.

NOTE: patterns.txt is not actually tested at the moment,
because it contains syntax that `parser` mistakenly rejects.
But I checked manually that this doesn't introduce other failures.
https://github.com/whitequark/parser/pull/1060

55adfaa895
2025-03-30 17:24:05 +00:00
Kevin Newton
052794bfe1 [ruby/prism] Accept a newline after the defined? keyword
[Bug #21197]

22be955ce9
2025-03-30 13:22:41 -04:00
Kevin Newton
d49483a747 [ruby/prism] Move snapshots
This is messing up the CRuby sync, so moving them out of the test
directory will make this easier.

7ba13bfb68
2025-03-27 20:14:36 +00:00
Benoit Daloze
65bc0ec62d [ruby/prism] Fix fork check in ractor_test.rb
0073266cad
2025-03-20 21:24:19 +00:00
Kevin Newton
e47078fb30 [ruby/prism] Update ractor_test.rb per review
fd96a6821f
2025-03-20 17:23:36 -04:00
Earlopain
ab8b199be8 [ruby/prism] Add Prism::Translation::ParserCurrent
It's not my favorite api but for users that currently use the same thing
from `parser`, moving over is more difficult
than it needs to be.

If you plan to support both old and new ruby versions, you definitly need to
branch somewhere on the ruby version
to either choose prism or parser.
But with prism you then need to enumerate all the versions again and choose the correct one.

Also, don't recommend to use `Prism::Translation::Parser` in docs. It's version-less
but actually always just uses Ruby 3.4 which is probably
not what the user intended.

Note: parser also warns when the patch version doesn't match what it expects. But I don't think prism has such a concept,
and anyways it would require releases anytime ruby releases, which I don't think is very desirable

77177f9e92
2025-03-20 21:20:23 +00:00
Sam Bostock
f07af59a2f [ruby/prism] Dynamically register events to dispatch
Instead of requiring the consumer to provide a list of all events which
they wish to handle, we can give them to option of dynamically detecting
them, by scanning the listener's public methods.

This approach is similar to that used by Minitest (scanning for `test_`
methods) and Rails generators (running all public methods in the order
they are defined).

While this is slower than specifying a hard coded list, the penalty is
only during registration. There is no change the the behaviour of
dispatching the events.

781ebed743
2025-03-20 17:28:59 +00:00
Nobuyoshi Nakada
a51364f54b
Close reader pipes 2025-03-20 20:59:42 +09:00
Nobuyoshi Nakada
820c541671 [Bug #21026] no singleton method on pseudo variable literal 2025-03-20 17:32:26 +09:00
Kevin Newton
641f15b1c6 [ruby/prism] Mark Prism as ractor-safe
c02429765b
2025-03-19 21:11:57 +00:00
Earlopain
e5e160475b [ruby/prism] Warn when the parser translator receives an incompatible builder class
In https://github.com/ruby/prism/pull/3494 I added a bit of code
so that using the new builder doesn't break stuff.
This code can be dropped when it is enforced that builder
is _always_ the correct subclass (and makes future issues like that unlikely).

193d4b806d
2025-03-19 21:03:17 +00:00
Kevin Newton
33aaa069a4 [ruby/prism] Update truffleruby version
2afe89f8ce
2025-03-18 13:36:53 -04:00
Kevin Newton
dc48c1aca3 [ruby/prism] Add a multiple statements flag to parentheses
This can get triggered even if the list of statements only contains
a single statement. This is necessary to properly support compiling

```ruby
defined? (;a)
defined? (a;)
```

as "expression". Previously these were parsed as statements lists
with single statements in them.

b63b5d67a9
2025-03-18 13:36:53 -04:00
Earlopain
e3c8464630 [ruby/prism] Only unnest parser mlhs nodes when no rest argument is provided
```
(a,), = []

PARSER====================
s(:masgn,
  s(:mlhs,
    s(:mlhs,
      s(:lvasgn, :a))),
  s(:array))
PRISM====================
s(:masgn,
  s(:mlhs,
    s(:lvasgn, :a)),
  s(:array))
```

8aa1f4690e
2025-03-18 13:36:53 -04:00
Earlopain
94e12ffa39 [ruby/prism] Fix parser translator multiline interpolated symbols
In 2637007929 I added tests but didn't modify them correctly

de021e74de
2025-03-18 13:36:53 -04:00
Earlopain
a8adf5e006 [ruby/prism] Further refine string handling in the parser translator
Mostly around newlines and line continuation.
* percent arrays need special backslash handling in the ast
* Fix offset issue for heredocs with many line continuations (used wrong variable as index access)
* More refined rules on when to simplify string tokens
* Handle line continuations in squiggly heredocs
* Correctly dedent squiggly heredocs with interpolation
* Consider `':foo:` and `%s[foo]` to not be interpolation

4edfe9d981
2025-03-18 13:36:53 -04:00
Earlopain
fc14d3ac7d [ruby/prism] Allow to test a custom fixtures path during testing
Of course, these won't really be fixtures, but it allows to test against whole codebases
without copying them, doing symlinks or something like that.

For example, I can tell that over the whole RuboCop codebase, there are only 8 files that produce mismatched ast.
Telling what the problem is is a different problem. The ast for real files can and will be huge so I haven't checked yet
(maybe parser bug) but it's nice for discoverability regardless

2184d82ba6
2025-03-18 13:36:53 -04:00
Kevin Newton
0b4604d5a0 [ruby/prism] Use Set.new over to_set
422d5c4c64
2025-03-18 13:36:53 -04:00
Earlopain
d5503444fd [ruby/prism] Fix parser translator crash for certain octal escapes
`Integer#chr` performs some validation that we don't want/need. Octal escapes can go above 255, where it will then raise trying to convert.

`append_as_bytes` actually allows to pass a number, so we can just skip that call.
Although, on older rubies of course we still need to handle this in the polyfill.
I don't really like using `pack` but don't know of another way to do so.

For the utf-8 escapes, this is not an issue. Invalid utf-8 in these is simply a syntax error.

161c606b1f
2025-03-18 13:36:53 -04:00
Earlopain
fd7a10cf4a [ruby/prism] Further refine string handling in the parser translator
Mostly around newlines and line continuation.
* percent arrays need special backslash handling in the ast
* Fix offset issue for heredocs with many line continuations (used wrong variable as index access)
* More refined rules on when to simplify string tokens
* Handle line continuations in squiggly heredocs
* Correctly dedent squiggly heredocs with interpolation
* Consider `':foo:` and `%s[foo]` to not be interpolation

4edfe9d981
2025-03-18 13:36:53 -04:00
Earlopain
5d138f2b43 [ruby/prism] Better handle regexp in the parser translator
Turns out, it was already almost correct. If you disregard \c and \M style escapes, only a single character is allowed to be escaped in a regex so most tests passed already.

There was also a mistake where the wrong value was constructed for the ast, this is now fixed.
One test fails because of this, but I'm fairly sure it is because of a parser bug. For `/\“/`, the backslash is supposed to be removed because it is a multibyte character. But tbh,
I don't entirely understand all the rules.

Fixes more than half of the remaining ast differences for rubocop tests

e1c75f304b
2025-03-18 13:36:53 -04:00
Earlopain
177adf6fa5 [ruby/prism] Fix parser translator tokens for %-arrays with whitespace escapes
Also fixes a token incompatibility for the word separator. parser only considers whitespace until the first newline

bd3dd2b62a
2025-03-18 13:36:53 -04:00