11# frozen_string_literal: true
2+ # :markup: markdown
23# typed: ignore
34
45# This file is responsible for mirroring the API provided by the C extension by
78require "rbconfig"
89require "ffi"
910
11+ # We want to eagerly load this file if there are Ractors so that it does not get
12+ # autoloaded from within a non-main Ractor.
13+ require "prism/serialize" if defined? ( Ractor )
14+
1015module Prism
1116 module LibRubyParser # :nodoc:
1217 extend FFI ::Library
@@ -15,7 +20,8 @@ module LibRubyParser # :nodoc:
1520 # must align with the build shared library from make/rake.
1621 libprism_in_build = File . expand_path ( "../../build/libprism.#{ RbConfig ::CONFIG [ "SOEXT" ] } " , __dir__ )
1722 libprism_in_libdir = "#{ RbConfig ::CONFIG [ "libdir" ] } /prism/libprism.#{ RbConfig ::CONFIG [ "SOEXT" ] } "
18- if File . exist? libprism_in_build
23+
24+ if File . exist? ( libprism_in_build )
1925 INCLUDE_DIR = File . expand_path ( "../../include" , __dir__ )
2026 ffi_lib libprism_in_build
2127 else
@@ -159,6 +165,9 @@ def self.with
159165 class PrismString # :nodoc:
160166 SIZEOF = LibRubyParser . pm_string_sizeof
161167
168+ PLATFORM_EXPECTS_UTF8 =
169+ RbConfig ::CONFIG [ "host_os" ] . match? ( /bccwin|cygwin|djgpp|mingw|mswin|wince|darwin/i )
170+
162171 attr_reader :pointer , :length
163172
164173 def initialize ( pointer , length , from_string )
@@ -193,8 +202,7 @@ def self.with_file(filepath)
193202 # On Windows and Mac, it's expected that filepaths will be encoded in
194203 # UTF-8. If they are not, we need to convert them to UTF-8 before
195204 # passing them into pm_string_mapped_init.
196- if RbConfig ::CONFIG [ "host_os" ] . match? ( /bccwin|cygwin|djgpp|mingw|mswin|wince|darwin/i ) &&
197- ( encoding = filepath . encoding ) != Encoding ::ASCII_8BIT && encoding != Encoding ::UTF_8
205+ if PLATFORM_EXPECTS_UTF8 && ( encoding = filepath . encoding ) != Encoding ::ASCII_8BIT && encoding != Encoding ::UTF_8
198206 filepath = filepath . encode ( Encoding ::UTF_8 )
199207 end
200208
@@ -223,7 +231,7 @@ def self.with_file(filepath)
223231 private_constant :LibRubyParser
224232
225233 # The version constant is set by reading the result of calling pm_version.
226- VERSION = LibRubyParser . pm_version . read_string
234+ VERSION = LibRubyParser . pm_version . read_string . freeze
227235
228236 class << self
229237 # Mirror the Prism.dump API by using the serialization API.
@@ -357,50 +365,37 @@ def profile_file(filepath, **options)
357365 def dump_common ( string , options ) # :nodoc:
358366 LibRubyParser ::PrismBuffer . with do |buffer |
359367 LibRubyParser . pm_serialize_parse ( buffer . pointer , string . pointer , string . length , dump_options ( options ) )
360- buffer . read
368+
369+ dumped = buffer . read
370+ dumped . freeze if options . fetch ( :freeze , false )
371+
372+ dumped
361373 end
362374 end
363375
364376 def lex_common ( string , code , options ) # :nodoc:
365- serialized = LibRubyParser ::PrismBuffer . with do |buffer |
377+ LibRubyParser ::PrismBuffer . with do |buffer |
366378 LibRubyParser . pm_serialize_lex ( buffer . pointer , string . pointer , string . length , dump_options ( options ) )
367- buffer . read
379+ Serialize . load_lex ( code , buffer . read , options . fetch ( :freeze , false ) )
368380 end
369-
370- Serialize . load_tokens ( Source . for ( code ) , serialized )
371381 end
372382
373383 def parse_common ( string , code , options ) # :nodoc:
374384 serialized = dump_common ( string , options )
375- Prism . load ( code , serialized )
385+ Serialize . load_parse ( code , serialized , options . fetch ( :freeze , false ) )
376386 end
377387
378388 def parse_comments_common ( string , code , options ) # :nodoc:
379389 LibRubyParser ::PrismBuffer . with do |buffer |
380390 LibRubyParser . pm_serialize_parse_comments ( buffer . pointer , string . pointer , string . length , dump_options ( options ) )
381-
382- source = Source . for ( code )
383- loader = Serialize ::Loader . new ( source , buffer . read )
384-
385- loader . load_header
386- loader . load_encoding
387- loader . load_start_line
388- loader . load_comments
391+ Serialize . load_parse_comments ( code , buffer . read , options . fetch ( :freeze , false ) )
389392 end
390393 end
391394
392395 def parse_lex_common ( string , code , options ) # :nodoc:
393396 LibRubyParser ::PrismBuffer . with do |buffer |
394397 LibRubyParser . pm_serialize_parse_lex ( buffer . pointer , string . pointer , string . length , dump_options ( options ) )
395-
396- source = Source . for ( code )
397- loader = Serialize ::Loader . new ( source , buffer . read )
398-
399- tokens = loader . load_tokens
400- node , comments , magic_comments , data_loc , errors , warnings = loader . load_nodes
401- tokens . each { |token , | token . value . force_encoding ( loader . encoding ) }
402-
403- ParseLexResult . new ( [ node , tokens ] , comments , magic_comments , data_loc , errors , warnings , source )
398+ Serialize . load_parse_lex ( code , buffer . read , options . fetch ( :freeze , false ) )
404399 end
405400 end
406401
@@ -430,11 +425,13 @@ def dump_options_command_line(options)
430425 def dump_options_version ( version )
431426 case version
432427 when nil , "latest"
433- 0
428+ 0 # Handled in pm_parser_init
434429 when /\A 3\. 3(\. \d +)?\z /
435430 1
436431 when /\A 3\. 4(\. \d +)?\z /
437- 0
432+ 2
433+ when /\A 3\. 5(\. \d +)?\z /
434+ 3
438435 else
439436 raise ArgumentError , "invalid version: #{ version } "
440437 end
@@ -483,15 +480,43 @@ def dump_options(options)
483480 template << "C"
484481 values << ( options . fetch ( :partial_script , false ) ? 1 : 0 )
485482
483+ template << "C"
484+ values << ( options . fetch ( :freeze , false ) ? 1 : 0 )
485+
486486 template << "L"
487487 if ( scopes = options [ :scopes ] )
488488 values << scopes . length
489489
490490 scopes . each do |scope |
491+ locals = nil
492+ forwarding = 0
493+
494+ case scope
495+ when Array
496+ locals = scope
497+ when Scope
498+ locals = scope . locals
499+
500+ scope . forwarding . each do |forward |
501+ case forward
502+ when :* then forwarding |= 0x1
503+ when :** then forwarding |= 0x2
504+ when :& then forwarding |= 0x4
505+ when :"..." then forwarding |= 0x8
506+ else raise ArgumentError , "invalid forwarding value: #{ forward } "
507+ end
508+ end
509+ else
510+ raise TypeError , "wrong argument type #{ scope . class . inspect } (expected Array or Prism::Scope)"
511+ end
512+
491513 template << "L"
492- values << scope . length
514+ values << locals . length
515+
516+ template << "C"
517+ values << forwarding
493518
494- scope . each do |local |
519+ locals . each do |local |
495520 name = local . name
496521 template << "L"
497522 values << name . bytesize
0 commit comments