547 Commits

Author SHA1 Message Date
Kevin Newton
2947aa41d4 [ruby/prism] Use each_line to avoid allocating array
Though very unlikely, it could potentially allocate a large array
of whitespace.

https://github.com/ruby/prism/commit/3389947819
2026-01-26 14:43:01 +00:00
Earlopain
5f25420918 [ruby/prism] Fix on_words_sep for ripper translator with newlines
Ripper emits a token each per line.

https://github.com/ruby/prism/commit/4b5c9f5437
2026-01-26 11:34:49 +00:00
Earlopain
9269069e90 [ruby/prism] Optimize ripper translator token sorting
With the benchmark from 2ea81398cc
Prism is:
* 1.33x slower before
* 1.07x slower after

https://github.com/ruby/prism/commit/a18b0acd80
2026-01-25 21:14:13 +00:00
Earlopain
985b58a4ed [ruby/prism] Remove unneeded lex_compat token types
These are either fixed in prism or ruby/ripper itself.

https://github.com/ruby/prism/commit/41c7c126b2
2026-01-24 23:11:19 +00:00
Earlopain
f7bc28d824 [ruby/prism] Further optimize ripper translator by not using delegate
Using it seems pretty bad for performance:

```rb
require "benchmark/ips"
require "prism"
require "ripper"

codes = Dir["**/*.rb"].map { File.read(it) }

Benchmark.ips do |x|
  x.report("prism") { codes.each { Prism::Translation::Ripper.lex(it) } }
  x.report("ripper") { codes.each { Ripper.lex(it) } }
  x.compare!
end
```

```
# Before
ruby 4.0.0 (2025-12-25 revision https://github.com/ruby/prism/commit/553f1675f3) +PRISM [x86_64-linux]
Warming up --------------------------------------
               prism     1.000 i/100ms
              ripper     1.000 i/100ms
Calculating -------------------------------------
               prism      0.319 (± 0.0%) i/s     (3.14 s/i) -      2.000 in   6.276154s
              ripper      0.647 (± 0.0%) i/s     (1.54 s/i) -      4.000 in   6.182662s

Comparison:
              ripper:        0.6 i/s
               prism:        0.3 i/s - 2.03x  slower
# After
ruby 4.0.0 (2025-12-25 revision https://github.com/ruby/prism/commit/553f1675f3) +PRISM [x86_64-linux]
Warming up --------------------------------------
               prism     1.000 i/100ms
              ripper     1.000 i/100ms
Calculating -------------------------------------
               prism      0.482 (± 0.0%) i/s     (2.08 s/i) -      3.000 in   6.225603s
              ripper      0.645 (± 0.0%) i/s     (1.55 s/i) -      4.000 in   6.205636s

Comparison:
              ripper:        0.6 i/s
               prism:        0.5 i/s - 1.34x  slower
```

`vernier` tells me it does `method_missing` even for explicitly defined methods like `location`.

https://github.com/ruby/prism/commit/2ea81398cc
2026-01-24 23:10:34 +00:00
Earlopain
8aedb89681 [ruby/prism] Also handle BasicObject as a return value
We should touch these as little as possible and just pass them along

https://github.com/ruby/prism/commit/52c4fa785e
2026-01-21 13:21:37 +00:00
Benoit Daloze
913ffcd1dd [ruby/prism] Check using Prism nodes if a command call has any arguments in Ripper translator
* We don't know what `on_*` events might return so we cannot assume it's an Array.
* See https://github.com/ruby/prism/issues/3838#issuecomment-3774702396

https://github.com/ruby/prism/commit/bed4271ce2
2026-01-21 13:21:37 +00:00
Earlopain
9ad8dd00b1 [ruby/prism] Fix on_* return value of ripper translator
You're supposed to return the first argument.
```rb
# Before
[[:stmts_new], [:rescue_mod, nil, nil], [:stmts_add, nil, nil], [:program, nil]]
# After
[[:stmts_new], [:rescue_mod, "1", "2"], [:stmts_add, nil, "1"], [:program, nil]]
```

The correct result would be:
`[[:rescue_mod, "1", "2"], [:stmts_new], [:stmts_add, nil, "1"], [:program, nil]]`

But the order depends on the prism AST so it seems very difficult to match.

https://github.com/ruby/prism/commit/94e0107729
2026-01-20 20:23:18 +00:00
Earlopain
2842e61c92 Reapply "[ruby/prism] Add Ripper :on_sp events for Prism.lex_compat and Prism::Translation::Ripper"
This reverts commit 58f1127b51cf4fbb1f334f8701a041f40701dca2.
2026-01-20 14:18:30 +01:00
Hiroshi SHIBATA
58f1127b51
Revert "[ruby/prism] Add Ripper :on_sp events for Prism.lex_compat and Prism::Translation::Ripper"
This reverts commit 35a7b5159f39de2cac848c072674e5350cc41aa4.

This broke syntax_suggest.

https://github.com/ruby/ruby/actions/runs/21167011751/job/60874111912
2026-01-20 19:10:16 +09:00
Benoit Daloze
35a7b5159f [ruby/prism] Add Ripper :on_sp events for Prism.lex_compat and Prism::Translation::Ripper
* Handle line continuations.
* Handle space at the end of file in LexCompat.

https://github.com/ruby/prism/commit/32bd13eb7d

Co-authored-by: Earlopain <14981592+Earlopain@users.noreply.github.com>
2026-01-20 09:53:08 +00:00
Earlopain
16adb9303f [ruby/prism] Optimize ripper translator
Creating state classes is pretty expensive.
Since they are not modifiable, we can reuse them instead.

Benchmark script:
```rb
require "ripper"
require "prism"
require "benchmark/ips"

codes = Dir["**/*.rb"].map { File.read(it) }

Benchmark.ips do |x|
  x.config(time: 10)
  x.report("prism") { codes.each { Prism::Translation::Ripper.lex(it) } }
  x.report("ripper") { codes.each { Ripper.lex(it) } }

  x.compare!
end
```

Before:

```
ruby 4.0.0 (2025-12-25 revision https://github.com/ruby/prism/commit/553f1675f3) +PRISM [x86_64-linux]
Warming up --------------------------------------
               prism     1.000 i/100ms
              ripper     1.000 i/100ms
Calculating -------------------------------------
               prism      0.293 (± 0.0%) i/s     (3.42 s/i) -      3.000 in  10.248348s
              ripper      0.633 (± 0.0%) i/s     (1.58 s/i) -      7.000 in  11.055687s

Comparison:
              ripper:        0.6 i/s
               prism:        0.3 i/s - 2.16x  slower
```

After

```
ruby 4.0.0 (2025-12-25 revision https://github.com/ruby/prism/commit/553f1675f3) +PRISM [x86_64-linux]
Warming up --------------------------------------
               prism     1.000 i/100ms
              ripper     1.000 i/100ms
Calculating -------------------------------------
               prism      0.486 (± 0.0%) i/s     (2.06 s/i) -      5.000 in  10.280413s
              ripper      0.635 (± 0.0%) i/s     (1.58 s/i) -      7.000 in  11.027169s

Comparison:
              ripper:        0.6 i/s
               prism:        0.5 i/s - 1.31x  slower
```

https://github.com/ruby/prism/commit/bdde16554c
2026-01-19 23:54:39 +00:00
Benoit Daloze
859920dfd2 [ruby/prism] Add Prism::Source#line_to_byte_offset and replace direct accesses to offsets
https://github.com/ruby/prism/commit/ff81a29ba5
2026-01-19 12:03:33 +00:00
Earlopain
d1dc4bdb2f [ruby/prism] Fix ripper translator for __END__
https://github.com/ruby/prism/commit/2792ac78ca
2026-01-18 14:07:06 +00:00
Earlopain
87147ba5e9 [ruby/prism] Make the ripper shim work with rdoc
The filter class is a 1:1 copy of ruby.

rdoc has 32 test failures. It seems to expect `on_sp` in some cases to render code as written.

https://github.com/ruby/prism/commit/74bb12c825
2026-01-16 20:19:26 +00:00
Earlopain
074a23ab77 [ruby/prism] Add Ripper.tokenize to translation layer
It's public API and trivial to implement.

https://github.com/ruby/prism/commit/e77545f8b5
2026-01-16 12:07:41 +00:00
Earlopain
15939e3c30 [ruby/prism] Make irb work with the ripper shim
This is everything that `irb` uses. It works in their test-suite, but there are 20 failures when using the shim that I haven't looked into at all.

`parse` is not used by `irb`. `scan` is, and it's basically `parse` but also including errors. `irb` doesn't seem to care about the errors, so I didn't implement that.

https://github.com/ruby/prism/commit/2c5826b39f
2026-01-15 21:03:55 +00:00
Takashi Kokubun
ead107f0d7 [ruby/prism] Bump to v1.8.0
https://github.com/ruby/prism/commit/9c12be6e6a
2026-01-13 01:52:48 +00:00
Earlopain
ee1aa78bee [ruby/prism] Correctly expose ripper state
It is for example used by `irb`, `rdoc`, `syntax_suggest`

https://github.com/ruby/prism/commit/255aeb2485
2026-01-12 22:08:25 +00:00
Earlopain
a1ba9f5733 [ruby/prism] Use one file for versioned parser classes
One per version seems excessive.

Do note that `rubocop-ast` used to require individual parser files. I wouldn't consider that to be part of the API since everything is autoloaded.
From a GitHub code search, I didn't find anyone else doing it like that.

https://github.com/ruby/prism/commit/458f622c34
2026-01-12 16:13:08 +00:00
Earlopain
16863f2ec1 [ruby/prism] Decouple ripper translator from ripper library
Ripper exposes Ripper::Lexer:State in its output, which is a bit of a problem. To make this work, I basically copy-pasted the implementation.

I'm unsure if that is acceptable and added a test to make sure that these values never go out of sync.
I don't imagine them changing often, prism maps them 1:1 for its own usage.

This also fixed the shim by accident. `Ripper.lex` went to `Translation::Ripper.lex` when it should have been the original. Removing the need for the original resolves that issue.

https://github.com/ruby/prism/commit/2c0bea076d
2026-01-08 18:35:26 +00:00
Earlopain
fc66de3e6b [ruby/prism] Remove unneeded ripper requires
Ripper is either not used or loaded where it is actually needed

https://github.com/ruby/prism/commit/a73a4fb00c
2026-01-08 18:35:25 +00:00
Earlopain
3bfc86558b [ruby/prism] Move LexRipper into its own file
It has a hard dependency on ripper that can't be removed.
This makes it so that ripper can be loaded only when the class is actually used.

https://github.com/ruby/prism/commit/3b5b4a8a6d
2026-01-08 18:35:25 +00:00
Earlopain
65634d8df5 [ruby/prism] Optimize ruby visitor
`compact_child_nodes` allocates an array. We can skip that step by simply yielding the nodes.

Benchmark for visiting the rails codebase:

```rb
require "prism"
require "benchmark/ips"

files = Dir.glob("../rails/**/*.rb")
results = files.map { Prism.parse_file(it) }
visitor = Prism::Visitor.new

Benchmark.ips do |x|
  x.config(warmup: 3, time: 10)

  x.report do
    results.each do
      visitor.visit(it.value)
    end
  end
end

RubyVM::YJIT.enable

Benchmark.ips do |x|
  x.config(warmup: 3, time: 10)

  x.report do
    results.each do
      visitor.visit(it.value)
    end
  end
end
```

Before:
```
ruby 3.4.8 (2025-12-17 revision https://github.com/ruby/prism/commit/995b59f666) +PRISM [x86_64-linux]
Warming up --------------------------------------
                         1.000 i/100ms
Calculating -------------------------------------
                          2.691 (± 0.0%) i/s  (371.55 ms/i) -     27.000 in  10.089422s
ruby 3.4.8 (2025-12-17 revision https://github.com/ruby/prism/commit/995b59f666) +YJIT +PRISM [x86_64-linux]
Warming up --------------------------------------
                         1.000 i/100ms
Calculating -------------------------------------
                          7.278 (±13.7%) i/s  (137.39 ms/i) -     70.000 in  10.071568s
```
After:
```
ruby 3.4.8 (2025-12-17 revision https://github.com/ruby/prism/commit/995b59f666) +PRISM [x86_64-linux]
Warming up --------------------------------------
                         1.000 i/100ms
Calculating -------------------------------------
                          3.429 (± 0.0%) i/s  (291.65 ms/i) -     35.000 in  10.208580s
ruby 3.4.8 (2025-12-17 revision https://github.com/ruby/prism/commit/995b59f666) +YJIT +PRISM [x86_64-linux]
Warming up --------------------------------------
                         1.000 i/100ms
Calculating -------------------------------------
                         16.815 (± 0.0%) i/s   (59.47 ms/i) -    169.000 in  10.054668s
```

~21% faster on the interpreter, ~56% with YJIT

https://github.com/ruby/prism/commit/bf631750cf
2025-12-29 14:14:00 +00:00
Koichi ITO
f3149af35a [ruby/prism] Sync Prism::Translation::ParserCurrent with Ruby 4.0
This PR updates the fallback version for `Prism::Translation::ParserCurrent` from 3.4 to 4.0.

Currently, the fallback resolves to `Parser34`, as shown below:

```console
$ ruby -v -rprism -rprism/translation/parser_current -e 'p Prism::Translation::ParserCurrent'
ruby 3.0.7p220 (2024-04-23 revision https://github.com/ruby/prism/commit/724a071175) [x86_64-darwin23]
warning: `Prism::Translation::Current` is loading Prism::Translation::Parser34, but you are running 3.0.
Prism::Translation::Parser34
```

Following the comment "Keep this in sync with released Ruby.",
it seems like the right time to set this to Ruby 4.0, which is scheduled for release this week.

https://github.com/ruby/prism/commit/115f0a118c
2025-12-26 11:00:51 +09:00
Kevin Newton
5c0c0dd873 [ruby/prism] Bump to v1.7.0
https://github.com/ruby/prism/commit/21c499d6e4
2025-12-18 19:58:53 -05:00
Earlopain
76248400b7 [ruby/prism] Add Ruby 4.1 as a version specifier
https://github.com/ruby/prism/commit/138db9ccc4
2025-12-18 19:58:53 -05:00
Earlopain
490a03bad9 [ruby/prism] Fix sexp_processor gem reference
It's https://rubygems.org/gems/sexp_processor, not https://rubygems.org/gems/sexp

https://github.com/ruby/prism/commit/b8a00a5f15
2025-12-14 21:11:21 +00:00
Ryan Davis
4a84fa1b39 [ruby/prism] Define RubyParser::SyntaxError directly and drop require for ruby_parser.
Had to add a require of sexp since that came in indirectly via ruby_parser.

https://github.com/ruby/prism/commit/df677c324f
2025-12-14 16:42:51 +00:00
Ryan Davis
bb4a6f3951 [ruby/prism] Fixed Prism::Translation::RubyParser's comment processing
Tests were failing in Flay under Prism.

https://github.com/ruby/prism/commit/af9b3640a8
2025-12-12 17:52:16 +00:00
Earlopain
c06c2203ed [ruby/prism] Fix the ripper translator to parse as the current ruby
Otherwise, it uses the latest prism version

https://github.com/ruby/prism/commit/86406f63aa
2025-12-02 16:20:43 +00:00
Earlopain
48a73303e4 [ruby/prism] Optimize Prism::Source#find_line
This is more concise and ruby does a better job performance-wise.

This used to be `bsearch_index` already but 6d8358c083 changed it.
https://github.com/ruby/prism/pull/1733#discussion_r1373702087 said:
> Yeah the edge case was that the value matched an element exactly

But surely there would be a test to show this behaviour?

Gets called as part of pretty-printing nodes.
Further reduces the time for `SnapshotsTest` by ~16% for me.

https://github.com/ruby/prism/commit/f448e2b995
2025-11-29 19:01:11 +00:00
Nobuyoshi Nakada
0e604623d8 [ruby/prism] Use method_defined? instead of instance_methods.include?
While the latter creates an intermediate array of all method names
including all ancestors, the former just traverse the inheritance
chain and can stop if found once.

https://github.com/ruby/prism/commit/6da384dd0e
2025-11-14 13:47:49 +00:00
Earlopain
7037d8f89e [ruby/prism] Rename Ruby 3.5 to Ruby 4.0
See 6d81969b47

It leaves the old variant around. RuboCop for examples accesses `Prism::Translation::Parser35`
to test against ruby-head. For now I left these simply as an alias

https://github.com/ruby/prism/commit/d0a823f045
2025-11-08 00:22:17 +00:00
Nobuyoshi Nakada
f4e01783d3 Prism update for 4.0 2025-11-07 20:42:29 +09:00
Kevin Newton
8e7d427a72 [ruby/prism] Add equal_loc to call nodes
In the case of attribute writes, there are use cases where you want
to know the location of the = sign. (Internally we actually need
this for translation to the writequark AST.)

https://github.com/ruby/prism/commit/bfc798a7ec
2025-10-30 13:06:09 +00:00
Kevin Newton
aa2d3cd513 [ruby/prism] Bump to v1.6.0
https://github.com/ruby/prism/commit/b72fcc6183
2025-10-16 12:43:49 +00:00
Earlopain
f5d3b6e626 [ruby/prism] Add support for Prism.parse(foo, version: "current")
The docs currently say to use `Prism.parse(foo, version: RUBY_VERSION)` for this.
By specifying "current" instead, we can have prism raise a more specifc error.

Note: Does not use `ruby_version` from `ruby/version.h` because writing a test for that is not really possible.
`RUBY_VERSION` is nicely stubbable for both the c-ext and FFI backend.

https://github.com/ruby/prism/commit/9c5cd205cf
2025-10-16 12:34:14 +00:00
Kevin Newton
f486b3905f [ruby/prism] Bump to v
https://github.com/ruby/prism/commit/7574837b7b
2025-10-09 13:31:51 +00:00
Earlopain
b08573c815 [ruby/prism] Fix back reference for ruby_parser on Ruby 2.7
Symbol#name is only a thing since Ruby 3.0

https://github.com/ruby/prism/commit/2de82b15fc
2025-09-15 11:10:34 -04:00
Earlopain
9299cf31b1 [ruby/prism] Fix warn polyfill when no uplevel is provided
An unspecified uplevel is not the same as an uplevel of 1:

```
$ irb
irb(main):001> warn("foo")
foo
=> nil
irb(main):002> warn("foo", uplevel: 1)
/home/user/.rbenv/versions/2.7.8/lib/ruby/gems/2.7.0/gems/irb-1.14.0/lib/irb/workspace.rb:121: warning: foo
=> nil
```

https://github.com/ruby/prism/commit/dcedd14357
2025-09-15 11:03:12 +00:00
Kevin Newton
b897a47ae9 [ruby/prism] Documentation for Prism::Translation::Parser
Make it clear that it parses with the most recent version of Ruby
syntax.

https://github.com/ruby/prism/commit/7285d1fbab
2025-09-13 14:16:59 +00:00
Kevin Newton
f4ce5e90b2 [ruby/prism] Bump to v1.5.1
https://github.com/ruby/prism/commit/cac5118884
2025-09-13 14:00:04 +00:00
Kevin Newton
f0578492ad [ruby/prism] Bump to v1.5.0
https://github.com/ruby/prism/commit/194edab827
2025-09-12 19:29:42 +00:00
Earlopain
f17405b69c [ruby/prism] Reject some cases with return and command calls
The same also applies to `break`/`next`.

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

https://github.com/ruby/prism/commit/3a38b192e3
2025-09-11 15:55:55 +00:00
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.

https://github.com/ruby/prism/commit/4a3866af19
2025-08-14 15:42:33 +00:00
Aaron Patterson
89d89fa49d When reading from stdin, put a wrapper around the IO object
The purpose of this commit is to fix Bug #21188.  We need to detect when
stdin has run in to an EOF case.  Unfortunately we can't _call_ the eof
function on IO because it will block.

Here is a short script to demonstrate the issue:

```ruby
x = STDIN.gets
puts x
puts x.eof?
```

If you run the script, then type some characters (but _NOT_ a newline),
then hit Ctrl-D twice, it will print the input string.  Unfortunately,
calling `eof?` will try to read from STDIN again causing us to need a
3rd Ctrl-D to exit the program.

Before introducing the EOF callback to Prism, the input loop looked
kind of like this:

```ruby
loop do
  str = STDIN.gets
  process(str)

  if str.nil?
    p :DONE
  end
end
```

Which required 3 Ctrl-D to exit.  If we naively changed it to something
like this:

```ruby
loop do
  str = STDIN.gets
  process(str)

  if STDIN.eof?
    p :DONE
  end
end
```

It would still require 3 Ctrl-D because `eof?` would block.  In this
patch, we're wrapping the IO object, checking the buffer for a newline
and length, and then using that to simulate a non-blocking eof? method.

This commit wraps STDIN and emulates a non-blocking `eof` function.

[Bug #21188]
2025-08-04 12:34:33 -07:00
Justin Collins
885862a853 [ruby/prism] Match RubyParser behavior for -> lambda args
https://github.com/ruby/prism/commit/9f55551b09
2025-08-01 16:57:17 +00:00
Justin Collins
d289eb2723 [ruby/prism] RubyParser translation for stabby lambdas with it
https://github.com/ruby/prism/commit/c2e372a8d8
2025-08-01 16:57:17 +00:00
Earlopain
026079925c [ruby/prism] Do not use 0 to indicate the latest ruby version to parse
This makes it hard to do version checks against this value. The current version checks work because there are so few possible values at the moment.

As an example, PR 3337 introduces new syntax for ruby 3.5 and uses `PM_OPTIONS_VERSION_LATEST` as its version guard. Because what is considered the latest changes every year, it must later be changed to `parser->version == parser->version == PM_OPTIONS_VERSION_CRUBY_3_5 || parser->version == PM_OPTIONS_VERSION_LATEST`, with one extra version each year.

With this change, the PR can instead write `parser->version >= PM_OPTIONS_VERSION_CRUBY_3_5` which is self-explanatory
and works for future versions.

https://github.com/ruby/prism/commit/8318a113ca
2025-07-29 17:17:28 +00:00