diff options
-rw-r--r-- | lib/prism/ffi.rb | 12 | ||||
-rw-r--r-- | prism/extension.c | 5 | ||||
-rw-r--r-- | prism/templates/lib/prism/serialize.rb.erb | 2 | ||||
-rw-r--r-- | test/prism/ractor_test.rb | 61 |
4 files changed, 76 insertions, 4 deletions
diff --git a/lib/prism/ffi.rb b/lib/prism/ffi.rb index 35b91e41b2..a0da0b6195 100644 --- a/lib/prism/ffi.rb +++ b/lib/prism/ffi.rb @@ -7,6 +7,10 @@ require "rbconfig" require "ffi" +# We want to eagerly load this file if there are Ractors so that it does not get +# autoloaded from within a non-main Ractor. +require "prism/serialize" if defined?(Ractor) + module Prism module LibRubyParser # :nodoc: extend FFI::Library @@ -159,6 +163,9 @@ module Prism class PrismString # :nodoc: SIZEOF = LibRubyParser.pm_string_sizeof + PLATFORM_EXPECTS_UTF8 = + RbConfig::CONFIG["host_os"].match?(/bccwin|cygwin|djgpp|mingw|mswin|wince|darwin/i) + attr_reader :pointer, :length def initialize(pointer, length, from_string) @@ -193,8 +200,7 @@ module Prism # On Windows and Mac, it's expected that filepaths will be encoded in # UTF-8. If they are not, we need to convert them to UTF-8 before # passing them into pm_string_mapped_init. - if RbConfig::CONFIG["host_os"].match?(/bccwin|cygwin|djgpp|mingw|mswin|wince|darwin/i) && - (encoding = filepath.encoding) != Encoding::ASCII_8BIT && encoding != Encoding::UTF_8 + if PLATFORM_EXPECTS_UTF8 && (encoding = filepath.encoding) != Encoding::ASCII_8BIT && encoding != Encoding::UTF_8 filepath = filepath.encode(Encoding::UTF_8) end @@ -223,7 +229,7 @@ module Prism private_constant :LibRubyParser # The version constant is set by reading the result of calling pm_version. - VERSION = LibRubyParser.pm_version.read_string + VERSION = LibRubyParser.pm_version.read_string.freeze class << self # Mirror the Prism.dump API by using the serialization API. diff --git a/prism/extension.c b/prism/extension.c index dca2ee67a1..1533ca7bb3 100644 --- a/prism/extension.c +++ b/prism/extension.c @@ -1331,6 +1331,11 @@ Init_prism(void) { ); } +#ifdef HAVE_RB_EXT_RACTOR_SAFE + // Mark this extension as Ractor-safe. + rb_ext_ractor_safe(true); +#endif + // Grab up references to all of the constants that we're going to need to // reference throughout this extension. rb_cPrism = rb_define_module("Prism"); diff --git a/prism/templates/lib/prism/serialize.rb.erb b/prism/templates/lib/prism/serialize.rb.erb index 52821e0f7d..bc32e2fd4e 100644 --- a/prism/templates/lib/prism/serialize.rb.erb +++ b/prism/templates/lib/prism/serialize.rb.erb @@ -592,7 +592,7 @@ module Prism <%- tokens.each do |token| -%> <%= token.name.to_sym.inspect %>, <%- end -%> - ] + ].freeze private_constant :MAJOR_VERSION, :MINOR_VERSION, :PATCH_VERSION private_constant :ConstantPool, :FastStringIO, :Loader, :TOKEN_TYPES diff --git a/test/prism/ractor_test.rb b/test/prism/ractor_test.rb new file mode 100644 index 0000000000..e55a9e8c47 --- /dev/null +++ b/test/prism/ractor_test.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +return unless defined?(Ractor) + +require_relative "test_helper" + +module Prism + class RactorTest < TestCase + def test_version + refute_nil(with_ractor { Prism::VERSION }) + end + + def test_parse_file + assert_kind_of(Prism::Result, with_ractor(__FILE__) { |filepath| Prism.parse_file(filepath) }) + end + + def test_lex_file + assert_kind_of(Prism::Result, with_ractor(__FILE__) { |filepath| Prism.lex_file(filepath) }) + end + + def test_parse_file_comments + assert_kind_of(Array, with_ractor(__FILE__) { |filepath| Prism.parse_file_comments(filepath) }) + end + + def test_parse_lex_file + assert_kind_of(Prism::Result, with_ractor(__FILE__) { |filepath| Prism.parse_lex_file(filepath) }) + end + + def test_parse_success + assert(with_ractor("1 + 1") { |source| Prism.parse_success?(source) }) + end + + def test_parse_failure + assert(with_ractor("1 +") { |source| Prism.parse_failure?(source) }) + end + + def test_string_query_local + assert(with_ractor("foo") { |source| StringQuery.local?(source) }) + end + + def test_string_query_constant + assert(with_ractor("FOO") { |source| StringQuery.constant?(source) }) + end + + def test_string_query_method_name + assert(with_ractor("foo?") { |source| StringQuery.method_name?(source) }) + end + + if !ENV["PRISM_BUILD_MINIMAL"] + def test_dump_file + assert_kind_of(String, with_ractor(__FILE__) { |filepath| Prism.dump_file(filepath) }) + end + end + + private + + def with_ractor(*arguments, &block) + ignore_warnings { Ractor.new(*arguments, &block) }.take + end + end +end |