module Prism
def self.lex_compat(source, **options)
resembles the return value of Ripper::lex.
Returns a parse result whose value is an array of tokens that closely
Prism::lex_compat(source, **options) -> LexCompat::Result
:call-seq:
def self.lex_compat(source, **options) LexCompat.new(source, **options).result # steep:ignore end
def self.load(source, serialized, freeze = false)
Prism::load(source, serialized, freeze) -> ParseResult
:call-seq:
def self.load(source, serialized, freeze = false) Serialize.load_parse(source, serialized, freeze) end
def self.scope(locals: [], forwarding: [])
suitable for passing into one of the Prism.* methods that accepts the
Create a new scope with the given locals and forwarding options that is
def self.scope(locals: [], forwarding: []) Scope.new(locals, forwarding) end
def dump(source, **options)
def dump(source, **options) LibRubyParser::PrismString.with_string(source) { |string| dump_common(string, options) } end
def dump_common(string, options) # :nodoc:
def dump_common(string, options) # :nodoc: LibRubyParser::PrismBuffer.with do |buffer| LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options)) dumped = buffer.read dumped.freeze if options.fetch(:freeze, false) dumped end end
def dump_file(filepath, **options)
def dump_file(filepath, **options) options[:filepath] = filepath LibRubyParser::PrismString.with_file(filepath) { |string| dump_common(string, options) } end
def dump_options(options)
def dump_options(options) template = +"" values = [] template << "L" if (filepath = options[:filepath]) values.push(filepath.bytesize, filepath.b) template << "A*" else values << 0 end template << "l" values << options.fetch(:line, 1) template << "L" if (encoding = options[:encoding]) name = encoding.is_a?(Encoding) ? encoding.name : encoding values.push(name.bytesize, name.b) template << "A*" else values << 0 end template << "C" values << (options.fetch(:frozen_string_literal, false) ? 1 : 0) template << "C" values << dump_options_command_line(options) template << "C" values << dump_options_version(options[:version]) template << "C" values << (options[:encoding] == false ? 1 : 0) template << "C" values << (options.fetch(:main_script, false) ? 1 : 0) template << "C" values << (options.fetch(:partial_script, false) ? 1 : 0) template << "C" values << (options.fetch(:freeze, false) ? 1 : 0) template << "L" if (scopes = options[:scopes]) values << scopes.length scopes.each do |scope| locals = nil forwarding = 0 case scope when Array locals = scope when Scope locals = scope.locals scope.forwarding.each do |forward| case forward when :* then forwarding |= 0x1 when :** then forwarding |= 0x2 when :& then forwarding |= 0x4 when :"..." then forwarding |= 0x8 else raise ArgumentError, "invalid forwarding value: #{forward}" end end else raise TypeError, "wrong argument type #{scope.class.inspect} (expected Array or Prism::Scope)" end template << "L" values << locals.length template << "C" values << forwarding locals.each do |local| name = local.name template << "L" values << name.bytesize template << "A*" values << name.b end end else values << 0 end values.pack(template) end
def dump_options_command_line(options)
def dump_options_command_line(options) command_line = options.fetch(:command_line, "") raise ArgumentError, "command_line must be a string" unless command_line.is_a?(String) command_line.each_char.inject(0) do |value, char| case char when "a" then value | 0b000001 when "e" then value | 0b000010 when "l" then value | 0b000100 when "n" then value | 0b001000 when "p" then value | 0b010000 when "x" then value | 0b100000 else raise ArgumentError, "invalid command_line option: #{char}" end end end
def dump_options_version(version)
def dump_options_version(version) current = version == "current" case current ? RUBY_VERSION : version when nil, "latest" 0 # Handled in pm_parser_init when /\A3\.3(\.\d+)?\z/ 1 when /\A3\.4(\.\d+)?\z/ 2 when /\A3\.5(\.\d+)?\z/, /\A4\.0(\.\d+)?\z/ 3 when /\A4\.1(\.\d+)?\z/ 4 else if current raise CurrentVersionError, RUBY_VERSION else raise ArgumentError, "invalid version: #{version}" end end end
def lex(code, **options)
def lex(code, **options) LibRubyParser::PrismString.with_string(code) { |string| lex_common(string, code, options) } end
def lex_common(string, code, options) # :nodoc:
def lex_common(string, code, options) # :nodoc: LibRubyParser::PrismBuffer.with do |buffer| LibRubyParser.pm_serialize_lex(buffer.pointer, string.pointer, string.length, dump_options(options)) Serialize.load_lex(code, buffer.read, options.fetch(:freeze, false)) end end
def lex_file(filepath, **options)
def lex_file(filepath, **options) options[:filepath] = filepath LibRubyParser::PrismString.with_file(filepath) { |string| lex_common(string, string.read, options) } end
def parse(code, **options)
def parse(code, **options) LibRubyParser::PrismString.with_string(code) { |string| parse_common(string, code, options) } end
def parse_comments(code, **options)
def parse_comments(code, **options) LibRubyParser::PrismString.with_string(code) { |string| parse_comments_common(string, code, options) } end
def parse_comments_common(string, code, options) # :nodoc:
def parse_comments_common(string, code, options) # :nodoc: LibRubyParser::PrismBuffer.with do |buffer| LibRubyParser.pm_serialize_parse_comments(buffer.pointer, string.pointer, string.length, dump_options(options)) Serialize.load_parse_comments(code, buffer.read, options.fetch(:freeze, false)) end end
def parse_common(string, code, options) # :nodoc:
def parse_common(string, code, options) # :nodoc: serialized = dump_common(string, options) Serialize.load_parse(code, serialized, options.fetch(:freeze, false)) end
def parse_failure?(code, **options)
def parse_failure?(code, **options) !parse_success?(code, **options) end
def parse_file(filepath, **options)
native strings instead of Ruby strings because it allows us to use mmap
Mirror the Prism.parse_file API by using the serialization API. This uses
def parse_file(filepath, **options) options[:filepath] = filepath LibRubyParser::PrismString.with_file(filepath) { |string| parse_common(string, string.read, options) } end
def parse_file_comments(filepath, **options)
API. This uses native strings instead of Ruby strings because it allows us
Mirror the Prism.parse_file_comments API by using the serialization
def parse_file_comments(filepath, **options) options[:filepath] = filepath LibRubyParser::PrismString.with_file(filepath) { |string| parse_comments_common(string, string.read, options) } end
def parse_file_failure?(filepath, **options)
def parse_file_failure?(filepath, **options) !parse_file_success?(filepath, **options) end
def parse_file_success?(filepath, **options)
def parse_file_success?(filepath, **options) options[:filepath] = filepath LibRubyParser::PrismString.with_file(filepath) { |string| parse_file_success_common(string, options) } end
def parse_file_success_common(string, options) # :nodoc:
def parse_file_success_common(string, options) # :nodoc: LibRubyParser.pm_parse_success_p(string.pointer, string.length, dump_options(options)) end
def parse_lex(code, **options)
def parse_lex(code, **options) LibRubyParser::PrismString.with_string(code) { |string| parse_lex_common(string, code, options) } end
def parse_lex_common(string, code, options) # :nodoc:
def parse_lex_common(string, code, options) # :nodoc: LibRubyParser::PrismBuffer.with do |buffer| LibRubyParser.pm_serialize_parse_lex(buffer.pointer, string.pointer, string.length, dump_options(options)) Serialize.load_parse_lex(code, buffer.read, options.fetch(:freeze, false)) end end
def parse_lex_file(filepath, **options)
def parse_lex_file(filepath, **options) options[:filepath] = filepath LibRubyParser::PrismString.with_file(filepath) { |string| parse_lex_common(string, string.read, options) } end
def parse_stream(stream, **options)
def parse_stream(stream, **options) LibRubyParser::PrismBuffer.with do |buffer| source = +"" callback = -> (string, size, _) { raise "Expected size to be >= 0, got: #{size}" if size <= 0 if !(line = stream.gets(size - 1)).nil? source << line string.write_string("#{line}\x00", line.bytesize + 1) end } eof_callback = -> (_) { stream.eof? } # In the pm_serialize_parse_stream function it accepts a pointer to the # IO object as a void* and then passes it through to the callback as the # third argument, but it never touches it itself. As such, since we have # access to the IO object already through the closure of the lambda, we # can pass a null pointer here and not worry. LibRubyParser.pm_serialize_parse_stream(buffer.pointer, nil, callback, eof_callback, dump_options(options)) Prism.load(source, buffer.read, options.fetch(:freeze, false)) end end
def parse_success?(code, **options)
def parse_success?(code, **options) LibRubyParser::PrismString.with_string(code) { |string| parse_file_success_common(string, options) } end
def profile(source, **options)
def profile(source, **options) LibRubyParser::PrismString.with_string(source) do |string| LibRubyParser::PrismBuffer.with do |buffer| LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options)) nil end end end
def profile_file(filepath, **options)
def profile_file(filepath, **options) LibRubyParser::PrismString.with_file(filepath) do |string| LibRubyParser::PrismBuffer.with do |buffer| options[:filepath] = filepath LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options)) nil end end end