123456789_123456789_123456789_123456789_123456789_

Module: Prism

Relationships & Source Files
Namespace Children
Modules:
Classes:
Defined in: lib/prism.rb,
lib/prism/desugar_compiler.rb,
lib/prism/ffi.rb,
lib/prism/lex_compat.rb,
lib/prism/node_ext.rb,
lib/prism/pack.rb,
lib/prism/parse_result.rb,
lib/prism/pattern.rb,
lib/prism/relocation.rb,
lib/prism/string_query.rb,
lib/prism/translation.rb,
lib/prism/parse_result/comments.rb,
lib/prism/parse_result/errors.rb,
lib/prism/parse_result/newlines.rb,
lib/prism/translation/parser.rb,
lib/prism/translation/parser33.rb,
lib/prism/translation/parser34.rb,
lib/prism/translation/ripper.rb,
lib/prism/translation/ruby_parser.rb,
lib/prism/translation/parser/compiler.rb,
lib/prism/translation/parser/lexer.rb,
lib/prism/translation/ripper/sexp.rb,
prism/api_pack.c,
prism/extension.c

Overview

The Prism Ruby parser.

“Parsing Ruby is suddenly manageable!”

- You, hopefully

Constant Summary

Class Method Summary

Class Method Details

.dump(source, **options) ⇒ String

Dump the AST corresponding to the given string to a string. For supported options, see .parse.

[ GitHub ]

  
# File 'prism/extension.c', line 333

static VALUE
dump(int argc, VALUE *argv, VALUE self) {
    pm_string_t input;
    pm_options_t options = { 0 };
    string_options(argc, argv, &input, &options);

#ifdef PRISM_BUILD_DEBUG
    size_t length = pm_string_length(&input);
    char* dup = xmalloc(length);
    memcpy(dup, pm_string_source(&input), length);
    pm_string_constant_init(&input, dup, length);
#endif

    VALUE value = dump_input(&input, &options);

#ifdef PRISM_BUILD_DEBUG
    xfree(dup);
#endif

    pm_string_free(&input);
    pm_options_free(&options);

    return value;
}

.dump_common(string, options) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/prism/ffi.rb', line 354

def dump_common(string, options) # :nodoc:
  LibRubyParser::PrismBuffer.with do |buffer|
    LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
    buffer.read
  end
end

.dump_file(filepath, **options) ⇒ String

Dump the AST corresponding to the given file to a string. For supported options, see .parse.

[ GitHub ]

  
# File 'prism/extension.c', line 365

static VALUE
dump_file(int argc, VALUE *argv, VALUE self) {
    pm_string_t input;
    pm_options_t options = { 0 };

    VALUE encoded_filepath;
    file_options(argc, argv, &input, &options, &encoded_filepath);

    VALUE value = dump_input(&input, &options);
    pm_string_free(&input);
    pm_options_free(&options);

    return value;
}

.dump_options(options) (private)

Convert the given options into a serialized options string.

[ GitHub ]

  
# File 'lib/prism/ffi.rb', line 441

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 << "L"
  if (scopes = options[:scopes])
    values << scopes.length

    scopes.each do |scope|
      template << "L"
      values << scope.length

      scope.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

.dump_options_command_line(options) (private)

Return the value that should be dumped for the command_line option.

Raises:

  • (ArgumentError)
[ GitHub ]

  
# File 'lib/prism/ffi.rb', line 409

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

.dump_options_version(version) (private)

Return the value that should be dumped for the version option.

[ GitHub ]

  
# File 'lib/prism/ffi.rb', line 427

def dump_options_version(version)
  case version
  when nil, "latest"
    0
  when /\A3\.3(\.\d+)?\z/
    1
  when /\A3\.4(\.\d+)?\z/
    0
  else
    raise ArgumentError, "invalid version: #{version}"
  end
end

.lex(source, **options) ⇒ LexResult

Return a ::Prism::LexResult instance that contains an array of ::Prism::Token instances corresponding to the given string. For supported options, see .parse.

[ GitHub ]

  
# File 'prism/extension.c', line 679

static VALUE
lex(int argc, VALUE *argv, VALUE self) {
    pm_string_t input;
    pm_options_t options = { 0 };
    string_options(argc, argv, &input, &options);

    VALUE result = parse_lex_input(&input, &options, false);
    pm_string_free(&input);
    pm_options_free(&options);

    return result;
}

.lex_common(string, code, options) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/prism/ffi.rb', line 361

def lex_common(string, code, options) # :nodoc:
  serialized = LibRubyParser::PrismBuffer.with do |buffer|
    LibRubyParser.pm_serialize_lex(buffer.pointer, string.pointer, string.length, dump_options(options))
    buffer.read
  end

  Serialize.load_tokens(Source.for(code), serialized)
end

.lex_compat(source, **options) ⇒ LexCompat::Result

Returns a parse result whose value is an array of tokens that closely resembles the return value of Ripper.lex. The main difference is that the :on_sp token is not emitted.

For supported options, see .parse.

[ GitHub ]

  
# File 'lib/prism.rb', line 47

def self.lex_compat(source, **options)
  LexCompat.new(source, **options).result # steep:ignore
end

.lex_file(filepath, **options) ⇒ LexResult

Return a ::Prism::LexResult instance that contains an array of ::Prism::Token instances corresponding to the given file. For supported options, see .parse.

[ GitHub ]

  
# File 'prism/extension.c', line 699

static VALUE
lex_file(int argc, VALUE *argv, VALUE self) {
    pm_string_t input;
    pm_options_t options = { 0 };

    VALUE encoded_filepath;
    file_options(argc, argv, &input, &options, &encoded_filepath);

    VALUE value = parse_lex_input(&input, &options, false);
    pm_string_free(&input);
    pm_options_free(&options);

    return value;
}

.lex_ripper(source) ⇒ Array

This lexes with the Ripper lex. It drops any space events but otherwise returns the same tokens. Raises SyntaxError if the syntax in source is invalid.

[ GitHub ]

  
# File 'lib/prism.rb', line 57

def self.lex_ripper(source)
  LexRipper.new(source).result # steep:ignore
end

.load(source, serialized) ⇒ ParseResult

Load the serialized AST using the source as a reference into a tree.

[ GitHub ]

  
# File 'lib/prism.rb', line 65

def self.load(source, serialized)
  Serialize.load(source, serialized)
end

.parse(source, **options) ⇒ ParseResult

Parse the given string and return a ::Prism::ParseResult instance. The options that are supported are:

  • command_line - either nil or a string of the various options that were

    set on the command line. Valid values are combinations of "a", "l",
    "n", "p", and "x".
  • encoding - the encoding of the source being parsed. This should be an

    encoding or nil.
  • filepath - the filepath of the source being parsed. This should be a

    string or nil.
  • frozen_string_literal - whether or not the frozen string literal pragma

    has been set. This should be a boolean or nil.
  • line - the line number that the parse starts on. This should be an

    integer or nil. Note that this is 1-indexed.
  • main_script - a boolean indicating whether or not the source being parsed

    is the main script being run by the interpreter. This controls whether
    or not shebangs are parsed for additional flags and whether or not the
    parser will attempt to find a matching shebang if the first one does
    not contain the word "ruby".
  • partial_script - when the file being parsed is considered a “partial”

    script, jumps will not be marked as errors if they are not contained
    within loops/blocks. This is used in the case that you're parsing a
    script that you know will be embedded inside another script later, but
    you do not have that context yet. For example, when parsing an ERB
    template that will be evaluated inside another script.
  • scopes - the locals that are in scope surrounding the code that is being

    parsed. This should be an array of arrays of symbols or nil. Scopes are
    ordered from the outermost scope to the innermost one.
  • version - the version of Ruby syntax that prism should used to parse Ruby

    code. By default prism assumes you want to parse with the latest version
    of Ruby syntax (which you can trigger with {nil} or {"latest"}). You
    may also restrict the syntax to a specific version of Ruby, e.g., with {"3.3.0"}.
    To parse with the same syntax version that the current Ruby is running
    use `version: RUBY_VERSION`. Raises ArgumentError if the version is not
    currently supported by Prism.
[ GitHub ]

  
# File 'prism/extension.c', line 779

static VALUE
parse(int argc, VALUE *argv, VALUE self) {
    pm_string_t input;
    pm_options_t options = { 0 };
    string_options(argc, argv, &input, &options);

#ifdef PRISM_BUILD_DEBUG
    size_t length = pm_string_length(&input);
    char* dup = xmalloc(length);
    memcpy(dup, pm_string_source(&input), length);
    pm_string_constant_init(&input, dup, length);
#endif

    VALUE value = parse_input(&input, &options);

#ifdef PRISM_BUILD_DEBUG
    xfree(dup);
#endif

    pm_string_free(&input);
    pm_options_free(&options);
    return value;
}

.parse_comments(source, **options) ⇒ Array

Parse the given string and return an array of ::Prism::Comment objects. For supported options, see .parse.

[ GitHub ]

  
# File 'prism/extension.c', line 963

static VALUE
parse_comments(int argc, VALUE *argv, VALUE self) {
    pm_string_t input;
    pm_options_t options = { 0 };
    string_options(argc, argv, &input, &options);

    VALUE result = parse_input_comments(&input, &options);
    pm_string_free(&input);
    pm_options_free(&options);

    return result;
}

.parse_comments_common(string, code, options) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/prism/ffi.rb', line 375

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))

    source = Source.for(code)
    loader = Serialize::Loader.new(source, buffer.read)

    loader.load_header
    loader.load_encoding
    loader.load_start_line
    loader.load_comments
  end
end

.parse_common(string, code, options) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/prism/ffi.rb', line 370

def parse_common(string, code, options) # :nodoc:
  serialized = dump_common(string, options)
  Prism.load(code, serialized)
end

.parse_failure?(source, **options) ⇒ Boolean

Parse the given string and return true if it parses with errors. For supported options, see .parse.

[ GitHub ]

  
# File 'prism/extension.c', line 1098

static VALUE
parse_failure_p(int argc, VALUE *argv, VALUE self) {
    return RTEST(parse_success_p(argc, argv, self)) ? Qfalse : Qtrue;
}

.parse_file(filepath, **options)

Mirror the parse_file API by using the serialization API. This uses native strings instead of Ruby strings because it allows us to use mmap when it is available.

[ GitHub ]

  
# File 'prism/extension.c', line 810

static VALUE
parse_file(int argc, VALUE *argv, VALUE self) {
    pm_string_t input;
    pm_options_t options = { 0 };

    VALUE encoded_filepath;
    file_options(argc, argv, &input, &options, &encoded_filepath);

    VALUE value = parse_input(&input, &options);
    pm_string_free(&input);
    pm_options_free(&options);

    return value;
}

.parse_file_comments(filepath, **options)

Mirror the parse_file_comments API by using the serialization API. This uses native strings instead of Ruby strings because it allows us to use mmap when it is available.

[ GitHub ]

  
# File 'prism/extension.c', line 983

static VALUE
parse_file_comments(int argc, VALUE *argv, VALUE self) {
    pm_string_t input;
    pm_options_t options = { 0 };

    VALUE encoded_filepath;
    file_options(argc, argv, &input, &options, &encoded_filepath);

    VALUE value = parse_input_comments(&input, &options);
    pm_string_free(&input);
    pm_options_free(&options);

    return value;
}

.parse_file_failure?(filepath, **options) ⇒ Boolean

Parse the given file and return true if it parses with errors. For supported options, see .parse.

[ GitHub ]

  
# File 'prism/extension.c', line 1132

static VALUE
parse_file_failure_p(int argc, VALUE *argv, VALUE self) {
    return RTEST(parse_file_success_p(argc, argv, self)) ? Qfalse : Qtrue;
}

.parse_file_success?(filepath, **options) ⇒ Boolean

Parse the given file and return true if it parses without errors. For supported options, see .parse.

[ GitHub ]

  
# File 'prism/extension.c', line 1110

static VALUE
parse_file_success_p(int argc, VALUE *argv, VALUE self) {
    pm_string_t input;
    pm_options_t options = { 0 };

    VALUE encoded_filepath;
    file_options(argc, argv, &input, &options, &encoded_filepath);

    VALUE result = parse_input_success_p(&input, &options);
    pm_string_free(&input);
    pm_options_free(&options);

    return result;
}

.parse_file_success_common(string, options) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/prism/ffi.rb', line 404

def parse_file_success_common(string, options) # :nodoc:
  LibRubyParser.pm_parse_success_p(string.pointer, string.length, dump_options(options))
end

.parse_lex(source, **options) ⇒ ParseLexResult

Parse the given string and return a ::Prism::ParseLexResult instance that contains a 2-element array, where the first element is the AST and the second element is an array of ::Prism::Token instances.

This API is only meant to be used in the case where you need both the AST and the tokens. If you only need one or the other, use either .parse or .lex.

For supported options, see .parse.

[ GitHub ]

  
# File 'prism/extension.c', line 1012

static VALUE
parse_lex(int argc, VALUE *argv, VALUE self) {
    pm_string_t input;
    pm_options_t options = { 0 };
    string_options(argc, argv, &input, &options);

    VALUE value = parse_lex_input(&input, &options, true);
    pm_string_free(&input);
    pm_options_free(&options);

    return value;
}

.parse_lex_common(string, code, options) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/prism/ffi.rb', line 389

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))

    source = Source.for(code)
    loader = Serialize::Loader.new(source, buffer.read)

    tokens = loader.load_tokens
    node, comments, magic_comments, data_loc, errors, warnings = loader.load_nodes
    tokens.each { |token,| token.value.force_encoding(loader.encoding) }

    ParseLexResult.new([node, tokens], comments, magic_comments, data_loc, errors, warnings, source)
  end
end

.parse_lex_file(filepath, **options) ⇒ ParseLexResult

Parse the given file and return a ::Prism::ParseLexResult instance that contains a 2-element array, where the first element is the AST and the second element is an array of ::Prism::Token instances.

This API is only meant to be used in the case where you need both the AST and the tokens. If you only need one or the other, use either .parse_file or .lex_file.

For supported options, see .parse.

[ GitHub ]

  
# File 'prism/extension.c', line 1039

static VALUE
parse_lex_file(int argc, VALUE *argv, VALUE self) {
    pm_string_t input;
    pm_options_t options = { 0 };

    VALUE encoded_filepath;
    file_options(argc, argv, &input, &options, &encoded_filepath);

    VALUE value = parse_lex_input(&input, &options, true);
    pm_string_free(&input);
    pm_options_free(&options);

    return value;
}

.parse_stream(stream, **options) ⇒ ParseResult

Parse the given object that responds to gets and return a ::Prism::ParseResult instance. The options that are supported are the same as .parse.

[ GitHub ]

  
# File 'prism/extension.c', line 910

static VALUE
parse_stream(int argc, VALUE *argv, VALUE self) {
    VALUE stream;
    VALUE keywords;
    rb_scan_args(argc, argv, "1:", &stream, &keywords);

    pm_options_t options = { 0 };
    extract_options(&options, Qnil, keywords);

    pm_parser_t parser;
    pm_buffer_t buffer;

    pm_node_t *node = pm_parse_stream(&parser, &buffer, (void *) stream, parse_stream_fgets, &options);
    rb_encoding *encoding = rb_enc_find(parser.encoding->name);

    VALUE source = pm_source_new(&parser, encoding);
    VALUE value = pm_ast_new(&parser, node, encoding, source);
    VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source);

    pm_node_destroy(&parser, node);
    pm_buffer_free(&buffer);
    pm_parser_free(&parser);

    return result;
}

.parse_success?(source, **options) ⇒ Boolean

Parse the given string and return true if it parses without errors. For supported options, see .parse.

[ GitHub ]

  
# File 'prism/extension.c', line 1078

static VALUE
parse_success_p(int argc, VALUE *argv, VALUE self) {
    pm_string_t input;
    pm_options_t options = { 0 };
    string_options(argc, argv, &input, &options);

    VALUE result = parse_input_success_p(&input, &options);
    pm_string_free(&input);
    pm_options_free(&options);

    return result;
}

.profile(source, **options) ⇒ nil

Parse the given string and return nothing. This method is meant to allow profilers to avoid the overhead of reifying the AST to Ruby. For supported options, see .parse.

[ GitHub ]

  
# File 'prism/extension.c', line 846

static VALUE
profile(int argc, VALUE *argv, VALUE self) {
    pm_string_t input;
    pm_options_t options = { 0 };

    string_options(argc, argv, &input, &options);
    profile_input(&input, &options);
    pm_string_free(&input);
    pm_options_free(&options);

    return Qnil;
}

.profile_file(filepath, **options) ⇒ nil

Parse the given file and return nothing. This method is meant to allow profilers to avoid the overhead of reifying the AST to Ruby. For supported options, see .parse.

[ GitHub ]

  
# File 'prism/extension.c', line 867

static VALUE
profile_file(int argc, VALUE *argv, VALUE self) {
    pm_string_t input;
    pm_options_t options = { 0 };

    VALUE encoded_filepath;
    file_options(argc, argv, &input, &options, &encoded_filepath);

    profile_input(&input, &options);
    pm_string_free(&input);
    pm_options_free(&options);

    return Qnil;
}