Skip to content

Add support for Prism.parse(foo, version: "current")#3679

Merged
kddnewton merged 1 commit into
ruby:mainfrom
Earlopain:parse-as-current
Oct 16, 2025
Merged

Add support for Prism.parse(foo, version: "current")#3679
kddnewton merged 1 commit into
ruby:mainfrom
Earlopain:parse-as-current

Conversation

@Earlopain

Copy link
Copy Markdown
Collaborator

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. It doesn't add much code so I think being more explicit is worth it. It's similar to Prism::Translation::ParserCurrent but instead of warning it raises.

For a smooth experience, it requires a prism release right around when a new ruby version is released. But that is also already true for using RUBY_VERSION.

Note: Does not use ruby_version from ruby/version.h because writing a test for that is not really possible. I instead pull it from RUBY_VERSION constant at runtime so it can be stubbed.

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

@Earlopain
Earlopain force-pushed the parse-as-current branch 2 times, most recently from b506238 to 281a687 Compare October 14, 2025 08:59
@Earlopain

Copy link
Copy Markdown
Collaborator Author

Unsure about the ffi backend. My understanding is that alternate ruby versions will use it, basically the interface to the version of prism shipped with their runtime itself. So it should also be supported there. Is that right?

Comment thread lib/prism/ffi.rb Outdated
Comment thread test/prism/api/parse_test.rb Outdated

@eregon eregon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me 👍

@eregon

eregon commented Oct 14, 2025

Copy link
Copy Markdown
Member

Unsure about the ffi backend. My understanding is that alternate ruby versions will use it, basically the interface to the version of prism shipped with their runtime itself.

Not quite, you can think of it as Prism gem having 2 backends: a C extension, only used on CRuby, and the FFI backend used on JRuby and TruffleRuby.
Whether it's the prism default gem or later-installed prism gem doesn't really make a difference.

So it should also be supported there. Is that right?

Yes.

@eregon

eregon commented Oct 14, 2025

Copy link
Copy Markdown
Member

I wonder if Prism.parse(foo, version: :current) could be easily supported?
That seems nice to me because :current is a "symbolic value" to mean current version.
It's a detail though, so if not trivial probably not worth it.

@Earlopain

Copy link
Copy Markdown
Collaborator Author

Thanks for the the review!

Not quite, you can think of it as Prism gem having 2 backends: a C extension, only used on CRuby, and the FFI backend used on JRuby and TruffleRuby.
Whether it's the prism default gem or later-installed prism gem doesn't really make a difference.

Ah, right. I thought that at least on truffleruby it would use the c extension when part of the gemfile (i.e. explicitly installed)

I wonder if Prism.parse(foo, version: :current) could be easily supported?

Probably, just convert it to a string somewhere. There is already Prism.parse(foo, version: "latest") though, so I would not do it in this PR. I'm not so interested in it, feel free to open an issue for that if you want it.

@kddnewton kddnewton left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general I'm totally fine with this approach, but we're doing a lot of string parsing here that I think we should do away with, as this is not going to be a common path. Instead, I would prefer something like:

if 3.3, 3.4, 3.5 -> use version
else -> raise SomeError, given

and then declare SomeError in Ruby and have it shared between the native API and the serialization API.

@Earlopain

Copy link
Copy Markdown
Collaborator Author

I guess you're saying to move the C extension code for version handling into ruby as well, and then share that between ffi? Something like Prism.resolve_ruby_version_or_raise! or something. Is there a place for this already? I didn't really find something that would fit.

@kddnewton

Copy link
Copy Markdown
Collaborator

Not quite. What I mean is that instead of:

if (RSTRING_LEN(value) == 7 && strncmp(version, "current", 7) == 0) {
    if (strncmp || strncmp || strncmp || strncmp) { rb_raise }
    if (!pm_options_version_set(options, current_version, 3)) { rb_raise(ArgumentError, "...") }
}

and:

if current
  case RUBY_VERSION
  when ...
    raise ArgumentError, "..."
  end
end

and in the tests:

error = assert_raise(ArgumentError) { Prism.parse(...) }
assert_equal error.message, "..."

you somewhat simplify to:

# prism.rb
class CurrentVersionError < ArgumentError
  def initialize(version)
    super("Prism does not support #{version}. Please specify a supported version instead of 'current'.")
  end
end

and:

if (RSTRING_LEN(value) == 7 && strncmp(version, "current", 7) == 0) {
    if (!pm_options_version_set(options, current_version, 3)) { rb_raise(rb_cCurrentVersionError, "...") }
}

and:

if current && RUBY_VERSION !~ /supported-versions-pattern/
  raise CurrentVersionError, "..."
end

and in the tests:

error = assert_raise(CurrentVersionError) { Prism.parse(...) }

@Earlopain
Earlopain force-pushed the parse-as-current branch 2 times, most recently from 175205b to 39b0ccf Compare October 14, 2025 18:57
@Earlopain

Copy link
Copy Markdown
Collaborator Author

Ah, gotcha. That is nicer. Thanks for the explanation

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.
@kddnewton
kddnewton merged commit 1a22357 into ruby:main Oct 16, 2025
60 checks passed
Comment thread lib/prism.rb
message = +"invalid version: Requested to parse as `version: 'current'`; "
gem_version =
begin
Gem::Version.new(version)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ruby/ruby CI is failing here because Gem is not loaded: https://github.com/ruby/ruby/actions/runs/18561653353/job/52911907413

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh of course. I'll fix it. Shouldn't have cowboy'd.

@Earlopain Earlopain Oct 16, 2025

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I seem to have messed something up as well https://github.com/ruby/ruby/actions/runs/18562695205/job/52915425235
Can't look into that right now though

(This one doesn't crash: https://github.com/ruby/ruby/actions/runs/18562695142/job/52915424818)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's weird. I think RUBY_VERSION is just not consistent inside hte CRuby test suite. I reduced a lot of the tests and just ended up with some bare minimum stuff, and it appears to have resolved.

@Earlopain
Earlopain deleted the parse-as-current branch December 3, 2025 07:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants