123456789_123456789_123456789_123456789_123456789_

Class: Prism::Translation::Ripper

Relationships & Source Files
Namespace Children
Classes:
Extension / Inclusion / Inheritance Descendants
Subclasses:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, Compiler
Instance Chain:
self, Compiler
Inherits: Compiler
  • ::Object
Defined in: lib/prism/translation/ripper.rb,
lib/prism/translation/ripper/filter.rb,
lib/prism/translation/ripper/lexer.rb,
lib/prism/translation/ripper/sexp.rb

Overview

This class provides a compatibility layer between prism and Ripper. It functions by parsing the entire tree first and then walking it and executing each of the Ripper callbacks as it goes. To use this class, you treat Ripper effectively as you would treat the Ripper class.

Note that this class will serve the most common use cases, but Ripper's API is extensive and undocumented. It relies on reporting the state of the parser at any given time. We do our best to replicate that here, but because it is a different architecture it is not possible to perfectly replicate the behavior of Ripper.

The main known difference is that we may omit dispatching some events in some cases. This impacts the following events:

  • on_assign_error
  • on_comma
  • on_ignored_nl
  • on_ignored_sp
  • on_nl
  • on_operator_ambiguous
  • on_semicolon
  • on_sp

Constant Summary

  • BINARY_OPERATORS = private

    A list of all of the Ruby binary operators.

    # File 'lib/prism/translation/ripper.rb', line 353
    [
      :!=,
      :!~,
      :=~,
      :==,
      :===,
      :<=>,
      :>,
      :>=,
      :<,
      :<=,
      :&,
      :|,
      :^,
      :>>,
      :<<,
      :-,
      :+,
      :%,
      :/,
      :*,
      :**
    ].to_set
  • EVENTS =

    This array contains name of all ripper events.

    # File 'lib/prism/translation/ripper.rb', line 305
    PARSER_EVENTS + SCANNER_EVENTS
  • EXPR_ARG_ANY =
    # File 'lib/prism/translation/ripper.rb', line 522
    EXPR_ARG | EXPR_CMDARG
  • EXPR_BEG_ANY =
    # File 'lib/prism/translation/ripper.rb', line 521
    EXPR_BEG | EXPR_MID | EXPR_CLASS
  • EXPR_END_ANY =
    # File 'lib/prism/translation/ripper.rb', line 523
    EXPR_END | EXPR_ENDARG | EXPR_ENDFN
  • EXPR_NONE =
    # File 'lib/prism/translation/ripper.rb', line 519
    0
  • EXPR_VALUE =
    # File 'lib/prism/translation/ripper.rb', line 520
    EXPR_BEG
  • KEYWORDS = private

    A list of all of the Ruby keywords.

    # File 'lib/prism/translation/ripper.rb', line 308
    [
      "alias",
      "and",
      "begin",
      "BEGIN",
      "break",
      "case",
      "class",
      "def",
      "defined?",
      "do",
      "else",
      "elsif",
      "end",
      "END",
      "ensure",
      "false",
      "for",
      "if",
      "in",
      "module",
      "next",
      "nil",
      "not",
      "or",
      "redo",
      "rescue",
      "retry",
      "return",
      "self",
      "super",
      "then",
      "true",
      "undef",
      "unless",
      "until",
      "when",
      "while",
      "yield",
      "__ENCODING__",
      "__FILE__",
      "__LINE__"
    ].to_set
  • LEX_STATE_NAMES = private

    Ripper-internal bitflags.

    # File 'lib/prism/translation/ripper.rb', line 511
    %i[
      BEG END ENDARG ENDFN ARG CMDARG MID FNAME DOT CLASS LABEL LABELED FITEM
    ].map.with_index.to_h { |name, i| [2 ** i, name] }.freeze
  • PARSER_EVENTS =

    This array contains name of parser events.

    # File 'lib/prism/translation/ripper.rb', line 299
    PARSER_EVENT_TABLE.keys
  • PARSER_EVENT_TABLE =

    This contains a table of all of the parser events and their corresponding arity.

    # File 'lib/prism/translation/ripper.rb', line 100
    {
      BEGIN: 1,
      END: 1,
      alias: 2,
      alias_error: 2,
      aref: 2,
      aref_field: 2,
      arg_ambiguous: 1,
      arg_paren: 1,
      args_add: 2,
      args_add_block: 2,
      args_add_star: 2,
      args_forward: 0,
      args_new: 0,
      array: 1,
      aryptn: 4,
      assign: 2,
      assign_error: 2,
      assoc_new: 2,
      assoc_splat: 1,
      assoclist_from_args: 1,
      bare_assoc_hash: 1,
      begin: 1,
      binary: 3,
      block_var: 2,
      blockarg: 1,
      bodystmt: 4,
      brace_block: 2,
      break: 1,
      call: 3,
      case: 2,
      class: 3,
      class_name_error: 2,
      command: 2,
      command_call: 4,
      const_path_field: 2,
      const_path_ref: 2,
      const_ref: 1,
      def: 3,
      defined: 1,
      defs: 5,
      do_block: 2,
      dot2: 2,
      dot3: 2,
      dyna_symbol: 1,
      else: 1,
      elsif: 3,
      ensure: 1,
      excessed_comma: 0,
      fcall: 1,
      field: 3,
      fndptn: 4,
      for: 3,
      hash: 1,
      heredoc_dedent: 2,
      hshptn: 3,
      if: 3,
      if_mod: 2,
      ifop: 3,
      in: 3,
      kwrest_param: 1,
      lambda: 2,
      magic_comment: 2,
      massign: 2,
      method_add_arg: 2,
      method_add_block: 2,
      mlhs_add: 2,
      mlhs_add_post: 2,
      mlhs_add_star: 2,
      mlhs_new: 0,
      mlhs_paren: 1,
      module: 2,
      mrhs_add: 2,
      mrhs_add_star: 2,
      mrhs_new: 0,
      mrhs_new_from_args: 1,
      next: 1,
      nokw_param: 1,
      opassign: 3,
      operator_ambiguous: 2,
      param_error: 2,
      params: 7,
      paren: 1,
      parse_error: 1,
      program: 1,
      qsymbols_add: 2,
      qsymbols_new: 0,
      qwords_add: 2,
      qwords_new: 0,
      redo: 0,
      regexp_add: 2,
      regexp_literal: 2,
      regexp_new: 0,
      rescue: 4,
      rescue_mod: 2,
      rest_param: 1,
      retry: 0,
      return: 1,
      return0: 0,
      sclass: 2,
      stmts_add: 2,
      stmts_new: 0,
      string_add: 2,
      string_concat: 2,
      string_content: 0,
      string_dvar: 1,
      string_embexpr: 1,
      string_literal: 1,
      super: 1,
      symbol: 1,
      symbol_literal: 1,
      symbols_add: 2,
      symbols_new: 0,
      top_const_field: 1,
      top_const_ref: 1,
      unary: 2,
      undef: 1,
      unless: 3,
      unless_mod: 2,
      until: 2,
      until_mod: 2,
      var_alias: 2,
      var_field: 1,
      var_ref: 1,
      vcall: 1,
      void_stmt: 0,
      when: 3,
      while: 2,
      while_mod: 2,
      word_add: 2,
      word_new: 0,
      words_add: 2,
      words_new: 0,
      xstring_add: 2,
      xstring_literal: 1,
      xstring_new: 0,
      yield: 1,
      yield0: 0,
      zsuper: 0
    }
  • SCANNER_EVENTS =

    This array contains name of scanner events.

    # File 'lib/prism/translation/ripper.rb', line 302
    SCANNER_EVENT_TABLE.keys
  • SCANNER_EVENT_TABLE =

    This contains a table of all of the scanner events and their corresponding arity.

    # File 'lib/prism/translation/ripper.rb', line 243
    {
      CHAR: 1,
      __end__: 1,
      backref: 1,
      backtick: 1,
      comma: 1,
      comment: 1,
      const: 1,
      cvar: 1,
      embdoc: 1,
      embdoc_beg: 1,
      embdoc_end: 1,
      embexpr_beg: 1,
      embexpr_end: 1,
      embvar: 1,
      float: 1,
      gvar: 1,
      heredoc_beg: 1,
      heredoc_end: 1,
      ident: 1,
      ignored_nl: 1,
      imaginary: 1,
      int: 1,
      ivar: 1,
      kw: 1,
      label: 1,
      label_end: 1,
      lbrace: 1,
      lbracket: 1,
      lparen: 1,
      nl: 1,
      op: 1,
      period: 1,
      qsymbols_beg: 1,
      qwords_beg: 1,
      rational: 1,
      rbrace: 1,
      rbracket: 1,
      regexp_beg: 1,
      regexp_end: 1,
      rparen: 1,
      semicolon: 1,
      sp: 1,
      symbeg: 1,
      symbols_beg: 1,
      tlambda: 1,
      tlambeg: 1,
      tstring_beg: 1,
      tstring_content: 1,
      tstring_end: 1,
      words_beg: 1,
      words_sep: 1,
      ignored_sp: 1
    }

Class Method Summary

Instance Attribute Summary

  • #column readonly

    The current column in bytes of the parser.

  • #end_seen? ⇒ Boolean readonly

    Return true if parsed source ended by __END__.

  • #error? ⇒ Boolean readonly

    True if the parser encountered an error during parsing.

  • #filename readonly

    The filename of the source being parsed.

  • #lineno readonly

    The current line number of the parser.

  • #source readonly

    The source that is being parsed.

Instance Method Summary

Constructor Details

.new(source, filename = "(ripper)", lineno = 1) ⇒ Ripper

Create a new Ripper object with the given source.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 544

def initialize(source, filename = "(ripper)", lineno = 1)
  @source = Ripper.coerce_source(source)
  @filename = filename
  @lineno = lineno
  @column = 0
  @result = nil
  @line_and_column_cache = nil
end

Class Method Details

.coerce_source(source)

This method is for internal use only.

Mirros the various lex_types that ripper supports

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 84

def self.coerce_source(source) # :nodoc:
  if source.is_a?(IO)
    source.read
  elsif source.respond_to?(:gets)
    src = +""
    while line = source.gets
      src << line
    end
    src
  else
    source.to_str
  end
end

.lex(src, filename = "-", lineno = 1, raise_errors: false)

Tokenizes the Ruby program and returns an array of an array, which is formatted like [[lineno, column], type, token, state]. The #filename argument is mostly ignored. By default, this method does not handle syntax errors in src, use the raise_errors keyword to raise a SyntaxError for an error in src.

require "ripper"
require "pp"

pp Ripper.lex("def m(a) nil end")
#=> [[[1,  0], :on_kw,     "def", FNAME    ],
     [[1,  3], :on_sp,     " ",   FNAME    ],
     [[1,  4], :on_ident,  "m",   ENDFN    ],
     [[1,  5], :on_lparen, "(",   BEG|LABEL],
     [[1,  6], :on_ident,  "a",   ARG      ],
     [[1,  7], :on_rparen, ")",   ENDFN    ],
     [[1,  8], :on_sp,     " ",   BEG      ],
     [[1,  9], :on_kw,     "nil", END      ],
     [[1, 12], :on_sp,     " ",   END      ],
     [[1, 13], :on_kw,     "end", END      ]]
[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 59

def self.lex(src, filename = "-", lineno = 1, raise_errors: false)
  coerced = coerce_source(src)
  result = Prism.lex_compat(coerced, filepath: filename, line: lineno, version: "current", encoding: coerced.encoding)

  if result.failure? && raise_errors
    raise SyntaxError, result.errors.first.message
  else
    result.value
  end
end

.lex_state_name(state)

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 525

def self.lex_state_name(state)
  LEX_STATE_NAMES.filter_map { |flag, name| name if state & flag != 0  }.join("|")
end

.parse(src, filename = "(ripper)", lineno = 1)

Parses the given Ruby program read from src. src must be a String or an IO or a object with a #gets method.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 33

def self.parse(src, filename = "(ripper)", lineno = 1)
  new(src, filename, lineno).parse
end

.sexp(src, filename = "-", lineno = 1, raise_errors: false)

Parses src and create S-exp tree. Returns more readable tree rather than .sexp_raw. This method is mainly for developer use. The #filename argument is mostly ignored. By default, this method does not handle syntax errors in src, returning nil in such cases. Use the raise_errors keyword to raise a SyntaxError for an error in src.

require "ripper"
require "pp"

pp Ripper.sexp("def m(a) nil end")
  #=> [:program,
       [[:def,
        [:@ident, "m", [1, 4]],
        [:paren, [:params, [[:@ident, "a", [1, 6]]], nil, nil, nil, nil, nil, nil]],
        [:bodystmt, [[:var_ref, [:@kw, "nil", [1, 9]]]], nil, nil, nil]]]]
[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 397

def self.sexp(src, filename = "-", lineno = 1, raise_errors: false)
  builder = SexpBuilderPP.new(src, filename, lineno)
  sexp = builder.parse
  if builder.error?
    if raise_errors
      raise SyntaxError, builder.error
    end
  else
    sexp
  end
end

.sexp_raw(src, filename = "-", lineno = 1, raise_errors: false)

Parses src and create S-exp tree. This method is mainly for developer use. The #filename argument is mostly ignored. By default, this method does not handle syntax errors in src, returning nil in such cases. Use the raise_errors keyword to raise a SyntaxError for an error in src.

require "ripper"
require "pp"

pp Ripper.sexp_raw("def m(a) nil end")
  #=> [:program,
       [:stmts_add,
        [:stmts_new],
        [:def,
         [:@ident, "m", [1, 4]],
         [:paren, [:params, [[:@ident, "a", [1, 6]]], nil, nil, nil]],
         [:bodystmt,
          [:stmts_add, [:stmts_new], [:var_ref, [:@kw, "nil", [1, 9]]]],
          nil,
          nil,
          nil]]]]
[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 432

def self.sexp_raw(src, filename = "-", lineno = 1, raise_errors: false)
  builder = SexpBuilder.new(src, filename, lineno)
  sexp = builder.parse
  if builder.error?
    if raise_errors
      raise SyntaxError, builder.error
    end
  else
    sexp
  end
end

.tokenize

Tokenizes the Ruby program and returns an array of strings. The #filename and #lineno arguments are mostly ignored, since the return value is just the tokenized input. By default, this method does not handle syntax errors in src, use the raise_errors keyword to raise a SyntaxError for an error in src.

p Ripper.tokenize("def m(a) nil end")
 # => ["def", " ", "m", "(", "a", ")", " ", "nil", " ", "end"]
[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 79

def self.tokenize(...)
  lex(...).map { |token| token[2] }
end

Instance Attribute Details

#column (readonly)

The current column in bytes of the parser.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 541

attr_reader :column

#end_seen?Boolean (readonly)

Return true if parsed source ended by __END__.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 657

def end_seen?
  !!result.data_loc
end

#error?Boolean (readonly)

True if the parser encountered an error during parsing.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 558

def error?
  result.failure?
end

#filename (readonly)

The filename of the source being parsed.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 535

attr_reader :filename

#lineno (readonly)

The current line number of the parser.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 538

attr_reader :lineno

#source (readonly)

The source that is being parsed.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 532

attr_reader :source

Instance Method Details

#_dispatch_0 (private)

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4213

def _dispatch_0; end

#_dispatch_1(arg) (private)

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4214

def _dispatch_1(arg); arg end

#_dispatch_2(arg, _) (private)

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4215

def _dispatch_2(arg, _); arg end

#_dispatch_3(arg, _, _) (private)

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4216

def _dispatch_3(arg, _, _); arg end

#_dispatch_4(arg, _, _, _) (private)

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4217

def _dispatch_4(arg, _, _, _); arg end

#_dispatch_5(arg, _, _, _, _) (private)

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4218

def _dispatch_5(arg, _, _, _, _); arg end

#_dispatch_7(arg, _, _, _, _, _, _) (private)

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4219

def _dispatch_7(arg, _, _, _, _, _, _); arg end

#bounds(location) (private)

This method is responsible for updating lineno and column information to reflect the current node.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4202

def bounds(location)
  @lineno, @column = line_and_column_cache.line_and_column(location.start_offset)
end

#command?(node) ⇒ Boolean (private)

Returns true if the given node is a command node.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1474

private def command?(node)
  node.is_a?(CallNode) &&
    node.opening_loc.nil? &&
    (!node.arguments.nil? || node.block.is_a?(BlockArgumentNode)) &&
    !BINARY_OPERATORS.include?(node.name)
end

#compile_error(msg) (private)

This method is called when the parser found syntax error.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4241

def compile_error(msg)
end

#dedent_string(string, width) (private)

This method is provided by the Ripper C extension. It is called when a string needs to be dedented because of a tilde heredoc. It is expected that it will modify the string in place and return the number of bytes that were removed.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4256

def dedent_string(string, width)
  whitespace = 0
  cursor = 0

  while cursor < string.length && string[cursor].match?(/\s/) && whitespace < width
    if string[cursor] == "\t"
      whitespace = ((whitespace / 8 + 1) * 8)
      break if whitespace > width
    else
      whitespace += 1
    end

    cursor += 1
  end

  string.replace(string[cursor..])
  cursor
end

#encoding

Return encoding of the source.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 652

def encoding
  result.source.encoding
end

#get_arguments_and_block(arguments_node, block_node) (private)

Extract the arguments and block Ripper-style, which means if the block is like &b then it's moved to arguments.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1439

private def get_arguments_and_block(arguments_node, block_node)
  arguments = arguments_node&.arguments || []
  block = block_node

  if block.is_a?(BlockArgumentNode)
    arguments += [block]
    block = nil
  end

  [arguments, block]
end

#line_and_column_cache (private)

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4094

def line_and_column_cache
  @line_and_column_cache ||= LineAndColumnCache.new(result.source)
end

#parse

Parse the source and return the result.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 563

def parse
  result.comments.each do |comment|
    location = comment.location
    bounds(location)

    if comment.is_a?(InlineComment)
      # Inline comments always contain a newline if the line itself contains it
      if result.source.source.bytesize > comment.location.end_offset
        on_comment("#{comment.slice}\n")
      else
        on_comment(comment.slice)
      end
    else
      offset = location.start_offset
      lines = comment.slice.lines

      lines.each_with_index do |line, index|
        bounds(location.copy(start_offset: offset))

        if index == 0
          on_embdoc_beg(line)
        elsif index == lines.size - 1
          on_embdoc_end(line)
        else
          on_embdoc(line)
        end

        offset += line.bytesize
      end
    end
  end

  result.magic_comments.each do |magic_comment|
    on_magic_comment(magic_comment.key, magic_comment.value)
  end

  unless result.data_loc.nil?
    on___end__(result.data_loc.slice.each_line.first)
  end

  result.warnings.each do |warning|
    bounds(warning.location)

    if warning.level == :default
      warning(warning.message)
    else
      case warning.type
      when :ambiguous_first_argument_plus
        on_arg_ambiguous("+")
      when :ambiguous_first_argument_minus
        on_arg_ambiguous("-")
      when :ambiguous_slash
        on_arg_ambiguous("/")
      else
        warn(warning.message)
      end
    end
  end

  if error?
    result.errors.each do |error|
      location = error.location
      bounds(location)

      case error.type
      when :alias_argument
        on_alias_error("can't make alias for the number variables", location.slice)
      when :argument_formal_class
        on_param_error("formal argument cannot be a class variable", location.slice)
      when :argument_format_constant
        on_param_error("formal argument cannot be a constant", location.slice)
      when :argument_formal_global
        on_param_error("formal argument cannot be a global variable", location.slice)
      when :argument_formal_ivar
        on_param_error("formal argument cannot be an instance variable", location.slice)
      when :class_name, :module_name
        on_class_name_error("class/module name must be CONSTANT", location.slice)
      else
        on_parse_error(error.message)
      end
    end

    nil
  else
    result.value.accept(self)
  end
end

#result (private)

Lazily initialize the parse result.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4090

def result
  @result ||= Prism.parse(source, partial_script: true, version: "current", freeze: true, encoding: source.encoding)
end

#trailing_comma?(left, right) ⇒ Boolean (private)

Returns true if there is a comma between the two locations.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4103

def trailing_comma?(left, right)
  source.byteslice(left.end_offset...right.start_offset).include?(",")
end

#visit_alias_global_variable_node(node)

alias $foo $bar ^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 682

def visit_alias_global_variable_node(node)
  bounds(node.keyword_loc)
  on_kw("alias")

  new_name = visit_alias_global_variable_node_value(node.new_name)
  old_name = visit_alias_global_variable_node_value(node.old_name)

  bounds(node.location)
  on_var_alias(new_name, old_name)
end

#visit_alias_global_variable_node_value(node) (private)

Visit one side of an alias global variable node.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 694

private def visit_alias_global_variable_node_value(node)
  bounds(node.location)

  case node
  when BackReferenceReadNode
    on_backref(node.slice)
  when GlobalVariableReadNode
    on_gvar(node.name.to_s)
  else
    raise
  end
end

#visit_alias_method_node(node)

alias foo bar ^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 669

def visit_alias_method_node(node)
  bounds(node.keyword_loc)
  on_kw("alias")

  new_name = visit(node.new_name)
  old_name = visit(node.old_name)

  bounds(node.location)
  on_alias(new_name, old_name)
end

#visit_alternation_pattern_node(node)

foo => bar | baz ^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 709

def visit_alternation_pattern_node(node)
  left = visit_pattern_node(node.left)

  bounds(node.operator_loc)
  on_op("|")

  right = visit_pattern_node(node.right)

  bounds(node.location)
  on_binary(left, :|, right)
end

#visit_and_node(node)

a and b ^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 739

def visit_and_node(node)
  left = visit(node.left)

  bounds(node.operator_loc)
  if node.operator == "and"
    on_kw("and")
  else
    on_op("&&")
  end

  right = visit(node.right)

  bounds(node.location)
  on_binary(left, node.operator.to_sym, right)
end

#visit_arguments(elements) (private)

Visit a list of elements, like the elements of an array or arguments.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 912

private def visit_arguments(elements)
  bounds(elements.first.location)
  elements.inject(on_args_new) do |args, element|
    arg = visit(element)
    bounds(element.location)

    case element
    when BlockArgumentNode
      on_args_add_block(args, arg)
    when SplatNode
      on_args_add_star(args, arg)
    else
      on_args_add(args, arg)
    end
  end
end

#visit_arguments_node(node)

foo(bar) ^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 965

def visit_arguments_node(node)
  arguments, _ = visit_call_node_arguments(node, nil, false)
  arguments
end

#visit_array_node(node)

[] ^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 757

def visit_array_node(node)
  case (opening = node.opening)
  when /^%w/
    opening_loc = node.opening_loc
    bounds(opening_loc)
    on_qwords_beg(opening)

    elements = on_qwords_new
    previous = nil

    node.elements.each do |element|
      visit_words_sep(opening_loc, previous, element)

      bounds(element.location)
      elements = on_qwords_add(elements, on_tstring_content(element.content))

      previous = element
    end

    visit_words_sep(opening_loc, node.elements.last, node.closing_loc)

    bounds(node.closing_loc)
    on_tstring_end(node.closing)
  when /^%i/
    opening_loc = node.opening_loc
    bounds(opening_loc)
    on_qsymbols_beg(opening)

    elements = on_qsymbols_new
    previous = nil

    node.elements.each do |element|
      visit_words_sep(opening_loc, previous, element)

      bounds(element.location)
      elements = on_qsymbols_add(elements, on_tstring_content(element.value))

      previous = element
    end

    visit_words_sep(opening_loc, node.elements.last, node.closing_loc)

    bounds(node.closing_loc)
    on_tstring_end(node.closing)
  when /^%W/
    opening_loc = node.opening_loc
    bounds(opening_loc)
    on_words_beg(opening)

    elements = on_words_new
    previous = nil

    node.elements.each do |element|
      visit_words_sep(opening_loc, previous, element)

      bounds(element.location)
      elements =
        on_words_add(
          elements,
          if element.is_a?(StringNode)
            on_word_add(on_word_new, on_tstring_content(element.content))
          else
            element.parts.inject(on_word_new) do |word, part|
              word_part =
                if part.is_a?(StringNode)
                  bounds(part.location)
                  on_tstring_content(part.content)
                else
                  visit(part)
                end

              on_word_add(word, word_part)
            end
          end
        )

      previous = element
    end

    visit_words_sep(opening_loc, node.elements.last, node.closing_loc)

    bounds(node.closing_loc)
    on_tstring_end(node.closing)
  when /^%I/
    opening_loc = node.opening_loc
    bounds(opening_loc)
    on_symbols_beg(opening)

    elements = on_symbols_new
    previous = nil

    node.elements.each do |element|
      visit_words_sep(opening_loc, previous, element)

      bounds(element.location)
      elements =
        on_symbols_add(
          elements,
          if element.is_a?(SymbolNode)
            on_word_add(on_word_new, on_tstring_content(element.value))
          else
            element.parts.inject(on_word_new) do |word, part|
              word_part =
                if part.is_a?(StringNode)
                  bounds(part.location)
                  on_tstring_content(part.content)
                else
                  visit(part)
                end

              on_word_add(word, word_part)
            end
          end
        )

      previous = element
    end

    visit_words_sep(opening_loc, node.elements.last, node.closing_loc)

    bounds(node.closing_loc)
    on_tstring_end(node.closing)
  else
    bounds(node.opening_loc)
    on_lbracket(opening)

    elements = visit_arguments(node.elements) unless node.elements.empty?

    bounds(node.closing_loc)
    on_rbracket(node.closing)
  end

  bounds(node.location)
  on_array(elements)
end

#visit_array_pattern_node(node)

foo => [bar] ^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 931

def visit_array_pattern_node(node)
  constant = visit(node.constant)

  if node.opening_loc
    bounds(node.opening_loc)
    node.opening == "[" ? on_lbracket("[") : on_lparen("(")
  end

  requireds = visit_all(node.requireds) if node.requireds.any?
  rest =
    if (rest_node = node.rest).is_a?(SplatNode)
      bounds(rest_node.operator_loc)
      on_op("*")

      if rest_node.expression.nil?
        bounds(rest_node.location)
        on_var_field(nil)
      else
        visit(rest_node.expression)
      end
    end

  posts = visit_all(node.posts) if node.posts.any?

  if node.closing_loc
    bounds(node.closing_loc)
    node.closing == "]" ? on_rbracket("]") : on_rparen(")")
  end
  bounds(node.location)
  on_aryptn(constant, requireds, rest, posts)
end

#visit_assoc_node(node)

{ a: 1 } ^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 972

def visit_assoc_node(node)
  key = visit(node.key)

  if node.operator_loc
    bounds(node.operator_loc)
    on_op("=>")
  end

  value = visit(node.value)

  bounds(node.location)
  on_assoc_new(key, value)
end

#visit_assoc_splat_node(node)

def foo(); bar(); end ^^

{ **foo } ^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 991

def visit_assoc_splat_node(node)
  bounds(node.operator_loc)
  on_op("**")

  value = visit(node.value)

  bounds(node.location)
  on_assoc_splat(value)
end

#visit_back_reference_read_node(node)

$+ ^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1003

def visit_back_reference_read_node(node)
  bounds(node.location)
  on_backref(node.slice)
end

#visit_begin_node(node)

begin end ^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1010

def visit_begin_node(node)
  if node.begin_keyword_loc
    bounds(node.begin_keyword_loc)
    on_kw("begin")
  end

  clauses = visit_begin_node_clauses(node.begin_keyword_loc, node, false)

  if node.end_keyword_loc
    bounds(node.end_keyword_loc)
    on_kw("end")
  end

  bounds(node.location)
  on_begin(clauses)
end

#visit_begin_node_clauses(location, node, allow_newline) (private)

Visit the clauses of a begin node to form an on_bodystmt call.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1028

private def visit_begin_node_clauses(location, node, allow_newline)
  statements =
    if node.statements.nil?
      on_stmts_add(on_stmts_new, on_void_stmt)
    else
      body = node.statements.body
      body = [nil, *body] if void_stmt?(location, node.statements.body[0].location, allow_newline)

      bounds(node.statements.location)
      visit_statements_node_body(body)
    end

  rescue_clause = visit(node.rescue_clause)
  else_clause =
    unless (else_clause_node = node.else_clause).nil?
      bounds(else_clause_node.else_keyword_loc)
      on_kw("else")

      else_statements =
        if else_clause_node.statements.nil?
          [nil]
        else
          body = else_clause_node.statements.body
          body = [nil, *body] if void_stmt?(else_clause_node.else_keyword_loc, else_clause_node.statements.body[0].location, allow_newline)
          body
        end

      bounds(else_clause_node.location)
      visit_statements_node_body(else_statements)
    end
  ensure_clause = visit(node.ensure_clause)

  bounds(node.location)
  on_bodystmt(statements, rescue_clause, else_clause, ensure_clause)
end

#visit_block_argument_node(node)

foo(&bar) ^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1087

def visit_block_argument_node(node)
  bounds(node.operator_loc)
  on_op("&")
  visit(node.expression)
end

#visit_block_local_variable_node(node)

foo { |; bar| } ^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1095

def visit_block_local_variable_node(node)
  bounds(node.location)
  on_ident(node.name.to_s)
end

#visit_block_node(node)

Visit a BlockNode.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1101

def visit_block_node(node)
  braces = node.opening == "{"
  bounds(node.opening_loc)
  if braces
    on_lbrace("{")
  else
    on_kw("do")
  end

  parameters = visit(node.parameters)

  body =
    case node.body
    when nil
      bounds(node.location)
      stmts = on_stmts_add(on_stmts_new, on_void_stmt)

      bounds(node.location)
      braces ? stmts : on_bodystmt(stmts, nil, nil, nil)
    when StatementsNode
      stmts = node.body.body
      stmts = [nil, *stmts] if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false)
      stmts = visit_statements_node_body(stmts)

      bounds(node.body.location)
      braces ? stmts : on_bodystmt(stmts, nil, nil, nil)
    when BeginNode
      visit_body_node(node.parameters&.location || node.opening_loc, node.body)
    else
      raise
    end

  if braces
    bounds(node.closing_loc)
    on_rbrace("}")
  else
    bounds(node.closing_loc)
    on_kw("end")
  end

  if braces
    bounds(node.location)
    on_brace_block(parameters, body)
  else
    bounds(node.location)
    on_do_block(parameters, body)
  end
end

#visit_block_parameter_node(node)

def foo(&bar); end ^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1152

def visit_block_parameter_node(node)
  bounds(node.operator_loc)
  on_op("&")

  if node.name_loc.nil?
    bounds(node.location)
    on_blockarg(nil)
  else
    bounds(node.name_loc)
    name = on_ident(node.name.to_s)

    bounds(node.location)
    on_blockarg(name)
  end
end

#visit_block_parameters_node(node)

A block's parameters.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1169

def visit_block_parameters_node(node)
  bounds(node.opening_loc)
  on_op("|")

  parameters =
    if node.parameters.nil?
      on_params(nil, nil, nil, nil, nil, nil, nil)
    else
      visit(node.parameters)
    end

  locals =
    if node.locals.any?
      visit_all(node.locals)
    else
      false
    end

  bounds(node.closing_loc)
  on_op("|")

  bounds(node.location)
  on_block_var(parameters, locals)
end

#visit_body_node(location, node, allow_newline = false) (private)

Visit the body of a structure that can have either a set of statements or statements wrapped in rescue/else/ensure.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1066

private def visit_body_node(location, node, allow_newline = false)
  case node
  when nil
    bounds(location)
    on_bodystmt(visit_statements_node_body([nil]), nil, nil, nil)
  when StatementsNode
    body = [*node.body]
    body = [nil, *body] if void_stmt?(location, body[0].location, allow_newline)
    stmts = visit_statements_node_body(body)

    bounds(node.body.first.location)
    on_bodystmt(stmts, nil, nil, nil)
  when BeginNode
    visit_begin_node_clauses(location, node, allow_newline)
  else
    raise
  end
end

#visit_break_node(node)

break ^^^^^

break foo ^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1199

def visit_break_node(node)
  bounds(node.keyword_loc)
  on_kw("break")

  if node.arguments.nil?
    bounds(node.location)
    on_break(on_args_new)
  else
    arguments = visit(node.arguments)

    bounds(node.location)
    on_break(arguments)
  end
end

#visit_call_and_write_node(node)

foo.bar &&= baz ^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1505

def visit_call_and_write_node(node)
  receiver = visit(node.receiver)

  bounds(node.call_operator_loc)
  call_operator = visit_call_operator(node.call_operator)

  bounds(node.message_loc)
  message = visit_token(node.message)

  bounds(node.location)
  target = on_field(receiver, call_operator, message)

  bounds(node.operator_loc)
  operator = on_op("&&=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_call_node(node)

foo ^^^

foo.bar ^^^^^^^

foo.bar() {} ^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1222

def visit_call_node(node)
  if node.call_operator_loc.nil?
    case node.name
    when :[]
      receiver = visit(node.receiver)

      bounds(node.opening_loc)
      on_lbracket("[")

      arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))

      bounds(node.closing_loc)
      on_rbracket("]")

      block = visit(block_node)

      bounds(node.location)
      call = on_aref(receiver, arguments)

      if block_node
        bounds(node.location)
        on_method_add_block(call, block)
      else
        call
      end
    when :[]=
      receiver = visit(node.receiver)

      bounds(node.opening_loc)
      on_lbracket("[")

      *arguments, last_argument = node.arguments.arguments
      arguments << node.block if !node.block.nil?

      arguments =
        if arguments.any?
          args = visit_arguments(arguments)

          if !node.block.nil?
            args
          else
            bounds(arguments.first.location)
            on_args_add_block(args, false)
          end
        end

      bounds(node.closing_loc)
      on_rbracket("]")
      bounds(node.equal_loc)
      on_op("=")

      bounds(node.location)
      call = on_aref_field(receiver, arguments)
      value = visit_write_value(last_argument)

      bounds(last_argument.location)
      on_assign(call, value)
    when :-@, :+@, :~
      bounds(node.message_loc)
      on_op(node.message)

      receiver = visit(node.receiver)
      bounds(node.location)
      on_unary(node.name, receiver)
    when :!
      bounds(node.message_loc)
      if node.message == "not"
        on_kw("not")

        if node.opening_loc
          bounds(node.opening_loc)
          on_lparen("(")
        end

        receiver =
          if node.receiver.is_a?(ParenthesesNode) && node.receiver.body.nil?
            # The parens in `not()` just emit parens and nothing else.
            bounds(node.receiver.opening_loc)
            on_lparen("(")
            bounds(node.receiver.closing_loc)
            on_rparen(")")
            nil
          else
            visit(node.receiver)
          end

        if node.closing_loc
          bounds(node.closing_loc)
          on_rparen(")")
        end
        bounds(node.location)
        on_unary(:not, receiver)
      else
        on_op("!")

        receiver = visit(node.receiver)

        bounds(node.location)
        on_unary(:!, receiver)
      end
    when BINARY_OPERATORS
      receiver = visit(node.receiver)

      bounds(node.message_loc)
      on_op(node.message)

      value = visit(node.arguments.arguments.first)

      bounds(node.location)
      on_binary(receiver, node.name, value)
    else
      bounds(node.message_loc)
      message = visit_token(node.message, false)

      if node.variable_call?
        on_vcall(message)
      else
        if node.opening_loc
          bounds(node.opening_loc)
          on_lparen("(")
        end

        arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc || node.location))

        if node.closing_loc
          bounds(node.closing_loc)
          on_rparen(")")
        end

        block = visit(block_node)
        call =
          if node.opening_loc.nil? && get_arguments_and_block(node.arguments, node.block).first.any?
            bounds(node.location)
            on_command(message, arguments)
          elsif !node.opening_loc.nil?
            bounds(node.location)
            on_method_add_arg(on_fcall(message), on_arg_paren(arguments))
          else
            bounds(node.location)
            on_method_add_arg(on_fcall(message), on_args_new)
          end

        if block_node
          bounds(node.block.location)
          on_method_add_block(call, block)
        else
          call
        end
      end
    end
  else
    receiver = visit(node.receiver)

    bounds(node.call_operator_loc)
    call_operator = visit_call_operator(node.call_operator)

    message =
      if node.message_loc.nil?
        :call
      else
        bounds(node.message_loc)
        visit_token(node.message, false)
      end

    if node.equal_loc
      bounds(node.equal_loc)
      on_op("=")
    end

    if node.name.end_with?("=") && !node.message.end_with?("=") && !node.arguments.nil? && node.block.nil?
      value = visit_write_value(node.arguments.arguments.first)

      bounds(node.location)
      on_assign(on_field(receiver, call_operator, message), value)
    else
      if node.opening_loc
        bounds(node.opening_loc)
        on_lparen("(")
      end

      arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc || node.location))

      if node.closing_loc
        bounds(node.closing_loc)
        on_rparen(")")
      end

      block = visit(block_node)
      call =
        if node.opening_loc.nil?
          bounds(node.location)

          if node.arguments.nil? && !node.block.is_a?(BlockArgumentNode)
            on_call(receiver, call_operator, message)
          else
            on_command_call(receiver, call_operator, message, arguments)
          end
        else
          bounds(node.opening_loc)
          arguments = on_arg_paren(arguments)

          bounds(node.location)
          on_method_add_arg(on_call(receiver, call_operator, message), arguments)
        end

      if block_node
        bounds(node.block.location)
        on_method_add_block(call, block)
      else
        call
      end
    end
  end
end

#visit_call_node_arguments(arguments_node, block_node, trailing_comma) (private)

Visit the arguments and block of a call node and return the arguments and block as they should be used.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1453

private def visit_call_node_arguments(arguments_node, block_node, trailing_comma)
  arguments, block = get_arguments_and_block(arguments_node, block_node)

  [
    if arguments.length == 1 && arguments.first.is_a?(ForwardingArgumentsNode)
      visit(arguments.first)
    elsif arguments.any?
      args = visit_arguments(arguments)

      if block_node.is_a?(BlockArgumentNode) || arguments.last.is_a?(ForwardingArgumentsNode) || command?(arguments.last) || trailing_comma
        args
      else
        bounds(arguments.first.location)
        on_args_add_block(args, false)
      end
    end,
    block,
  ]
end

#visit_call_operator(token) (private)

Visit either ., &., or ::.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4140

def visit_call_operator(token)
  token == "." ? on_period(token) : on_op(token)
end

#visit_call_operator_write_node(node)

foo.bar += baz ^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1483

def visit_call_operator_write_node(node)
  receiver = visit(node.receiver)

  bounds(node.call_operator_loc)
  call_operator = visit_call_operator(node.call_operator)

  bounds(node.message_loc)
  message = visit_token(node.message)

  bounds(node.location)
  target = on_field(receiver, call_operator, message)

  bounds(node.binary_operator_loc)
  operator = on_op("#{node.binary_operator}=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_call_or_write_node(node)

foo.bar ||= baz ^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1527

def visit_call_or_write_node(node)
  receiver = visit(node.receiver)

  bounds(node.call_operator_loc)
  call_operator = visit_call_operator(node.call_operator)

  bounds(node.message_loc)
  message = visit_token(node.message)

  bounds(node.location)
  target = on_field(receiver, call_operator, message)

  bounds(node.operator_loc)
  operator = on_op("||=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_call_target_node(node)

foo.bar, = 1 ^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1549

def visit_call_target_node(node)
  if node.call_operator == "::"
    receiver = visit(node.receiver)

    bounds(node.call_operator_loc)
    on_op("::")

    bounds(node.message_loc)
    message = visit_token(node.message)

    bounds(node.location)
    on_const_path_field(receiver, message)
  else
    receiver = visit(node.receiver)

    bounds(node.call_operator_loc)
    call_operator = visit_call_operator(node.call_operator)

    bounds(node.message_loc)
    message = visit_token(node.message)

    bounds(node.location)
    on_field(receiver, call_operator, message)
  end
end

#visit_capture_pattern_node(node)

foo => bar => baz ^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1577

def visit_capture_pattern_node(node)
  value = visit(node.value)

  bounds(node.operator_loc)
  on_op("=>")

  target = visit(node.target)

  bounds(node.location)
  on_binary(value, :"=>", target)
end

#visit_case_match_node(node)

case foo; in bar; end ^^^^^^^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1615

def visit_case_match_node(node)
  bounds(node.case_keyword_loc)
  on_kw("case")

  predicate = visit(node.predicate)
  visited_conditions = node.conditions.map do | condition|
    visit(condition)
  end
  visited_else_clause = visit(node.else_clause)

  if !node.else_clause
    bounds(node.end_keyword_loc)
    on_kw("end")
  end

  clauses =
    visited_conditions.reverse_each.inject(visited_else_clause) do |current, condition|
      on_in(*condition, current)
    end

  bounds(node.location)
  on_case(predicate, clauses)
end

#visit_case_node(node)

case foo; when bar; end ^^^^^^^^^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1591

def visit_case_node(node)
  bounds(node.case_keyword_loc)
  on_kw("case")

  predicate = visit(node.predicate)
  visited_conditions = node.conditions.map { |condition| visit(condition) }
  visited_else_clause = visit(node.else_clause)

  if !node.else_clause
    bounds(node.end_keyword_loc)
    on_kw("end")
  end

  clauses =
    visited_conditions.reverse_each.inject(visited_else_clause) do |current, condition|
      on_when(*condition, current)
    end

  bounds(node.location)
  on_case(predicate, clauses)
end

#visit_class_node(node)

class Foo; end ^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1641

def visit_class_node(node)
  bounds(node.class_keyword_loc)
  on_kw("class")

  constant_path =
    if node.constant_path.is_a?(ConstantReadNode)
      bounds(node.constant_path.location)
      on_const_ref(on_const(node.constant_path.name.to_s))
    else
      visit(node.constant_path)
    end

  if node.inheritance_operator_loc
    bounds(node.inheritance_operator_loc)
    on_op("<")
  end

  superclass = visit(node.superclass)
  bodystmt = visit_body_node(node.superclass&.location || node.constant_path.location, node.body, node.superclass.nil?)

  bounds(node.end_keyword_loc)
  on_kw("end")

  bounds(node.location)
  on_class(constant_path, superclass, bodystmt)
end

#visit_class_variable_and_write_node(node)

@@foo &&= bar ^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1706

def visit_class_variable_and_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_cvar(node.name.to_s))

  bounds(node.operator_loc)
  operator = on_op("&&=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_class_variable_operator_write_node(node)

@@foo += bar ^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1692

def visit_class_variable_operator_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_cvar(node.name.to_s))

  bounds(node.binary_operator_loc)
  operator = on_op("#{node.binary_operator}=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_class_variable_or_write_node(node)

@@foo ||= bar ^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1720

def visit_class_variable_or_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_cvar(node.name.to_s))

  bounds(node.operator_loc)
  operator = on_op("||=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_class_variable_read_node(node)

@@foo ^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1670

def visit_class_variable_read_node(node)
  bounds(node.location)
  on_var_ref(on_cvar(node.slice))
end

#visit_class_variable_target_node(node)

@@foo, = bar ^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1734

def visit_class_variable_target_node(node)
  bounds(node.location)
  on_var_field(on_cvar(node.name.to_s))
end

#visit_class_variable_write_node(node)

@@foo = 1 ^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1677

def visit_class_variable_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_cvar(node.name.to_s))

  bounds(node.operator_loc)
  on_op("=")

  value = visit_write_value(node.value)

  bounds(node.location)
  on_assign(target, value)
end

#visit_constant_and_write_node(node)

Foo &&= bar ^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1777

def visit_constant_and_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_const(node.name.to_s))

  bounds(node.operator_loc)
  operator = on_op("&&=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_constant_operator_write_node(node)

Foo += bar ^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1763

def visit_constant_operator_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_const(node.name.to_s))

  bounds(node.binary_operator_loc)
  operator = on_op("#{node.binary_operator}=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_constant_or_write_node(node)

Foo ||= bar ^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1791

def visit_constant_or_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_const(node.name.to_s))

  bounds(node.operator_loc)
  operator = on_op("||=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_constant_path_and_write_node(node)

Foo::Bar &&= baz ^^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1894

def visit_constant_path_and_write_node(node)
  target = visit_constant_path_write_node_target(node.target)

  bounds(node.operator_loc)
  operator = on_op("&&=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_constant_path_node(node)

Foo::Bar ^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1812

def visit_constant_path_node(node)
  if node.parent.nil?
    if node.delimiter_loc
      bounds(node.delimiter_loc)
      on_op("::")
    end

    bounds(node.name_loc)
    child = on_const(node.name.to_s)

    bounds(node.location)
    on_top_const_ref(child)
  else
    parent = visit(node.parent)

    bounds(node.delimiter_loc)
    on_op("::")

    bounds(node.name_loc)
    child = on_const(node.name.to_s)

    bounds(node.location)
    on_const_path_ref(parent, child)
  end
end

#visit_constant_path_operator_write_node(node)

Foo::Bar += baz ^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1881

def visit_constant_path_operator_write_node(node)
  target = visit_constant_path_write_node_target(node.target)

  bounds(node.binary_operator_loc)
  operator = on_op("#{node.binary_operator}=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_constant_path_or_write_node(node)

Foo::Bar ||= baz ^^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1907

def visit_constant_path_or_write_node(node)
  target = visit_constant_path_write_node_target(node.target)

  bounds(node.operator_loc)
  operator = on_op("||=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_constant_path_target_node(node)

Foo::Bar, = baz ^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1920

def visit_constant_path_target_node(node)
  visit_constant_path_write_node_target(node)
end

#visit_constant_path_write_node(node)

Foo::Bar = 1 ^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1840

def visit_constant_path_write_node(node)
  target = visit_constant_path_write_node_target(node.target)

  bounds(node.operator_loc)
  on_op("=")

  value = visit_write_value(node.value)

  bounds(node.location)
  on_assign(target, value)
end

#visit_constant_path_write_node_target(node) (private)

Visit a constant path that is part of a write node.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1853

private def visit_constant_path_write_node_target(node)
  if node.parent.nil?
    if node.delimiter_loc
      bounds(node.delimiter_loc)
      on_op("::")
    end

    bounds(node.name_loc)
    child = on_const(node.name.to_s)

    bounds(node.location)
    on_top_const_field(child)
  else
    parent = visit(node.parent)

    bounds(node.delimiter_loc)
    on_op("::")

    bounds(node.name_loc)
    child = on_const(node.name.to_s)

    bounds(node.location)
    on_const_path_field(parent, child)
  end
end

#visit_constant_read_node(node)

Foo ^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1741

def visit_constant_read_node(node)
  bounds(node.location)
  on_var_ref(on_const(node.name.to_s))
end

#visit_constant_target_node(node)

Foo, = bar ^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1805

def visit_constant_target_node(node)
  bounds(node.location)
  on_var_field(on_const(node.name.to_s))
end

#visit_constant_write_node(node)

Foo = 1 ^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1748

def visit_constant_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_const(node.name.to_s))

  bounds(node.operator_loc)
  on_op("=")

  value = visit_write_value(node.value)

  bounds(node.location)
  on_assign(target, value)
end

#visit_def_node(node)

def foo; end ^^^^^^^^^^^^

def self.foo; end ^^^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1929

def visit_def_node(node)
  bounds(node.def_keyword_loc)
  on_kw("def")

  receiver = visit(node.receiver)
  operator =
    if !node.operator_loc.nil?
      bounds(node.operator_loc)
      node.operator == "." ? on_period(".") : on_op("::")
    end

  bounds(node.name_loc)
  name = visit_token(node.name_loc.slice)

  if node.lparen_loc
    bounds(node.lparen_loc)
    on_lparen("(")
  end

  parameters =
    if node.parameters.nil?
      bounds(node.location)
      on_params(nil, nil, nil, nil, nil, nil, nil)
    else
      visit(node.parameters)
    end

  if !node.lparen_loc.nil?
    bounds(node.rparen_loc)
    on_rparen(")")
    bounds(node.lparen_loc)
    parameters = on_paren(parameters)
  end

  if node.equal_loc
    bounds(node.equal_loc)
    on_op("=")
  end

  bodystmt =
    if node.equal_loc.nil?
      visit_body_node(node.rparen_loc || node.end_keyword_loc, node.body)
    else
      body = visit(node.body.body.first)

      bounds(node.body.location)
      on_bodystmt(body, nil, nil, nil)
    end

  if node.end_keyword_loc
    bounds(node.end_keyword_loc)
    on_kw("end")
  end

  bounds(node.location)
  if receiver
    on_defs(receiver, operator, name, parameters, bodystmt)
  else
    on_def(name, parameters, bodystmt)
  end
end

#visit_defined_node(node)

defined? a ^^^^^^^^^^

defined?(a) ^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 1996

def visit_defined_node(node)
  bounds(node.keyword_loc)
  on_kw("defined?")

  if node.lparen_loc
    bounds(node.lparen_loc)
    on_lparen("(")
  end

  expression = visit(node.value)

  if node.rparen_loc
    bounds(node.rparen_loc)
    on_rparen(")")
  end

  # Very weird circumstances here where something like:
  #
  #     defined?
  #     (1)
  #
  # gets parsed in Ruby as having only the `1` expression but in Ripper it
  # gets parsed as having a parentheses node. In this case we need to
  # synthesize that node to match Ripper's behavior.
  if node.lparen_loc && node.keyword_loc.join(node.lparen_loc).slice.include?("\n")
    bounds(node.lparen_loc.join(node.rparen_loc))
    expression = on_paren(on_stmts_add(on_stmts_new, expression))
  end

  bounds(node.location)
  on_defined(expression)
end

#visit_destructured_parameter_node(node) (private)

Visit a destructured positional parameter node.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3257

private def visit_destructured_parameter_node(node)
  if node.lparen_loc
    bounds(node.lparen_loc)
    on_lparen("(")
  end

  bounds(node.location)
  targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, false)

  if node.rparen_loc
    bounds(node.rparen_loc)
    on_rparen(")")
  end

  bounds(node.lparen_loc)
  on_mlhs_paren(targets)
end

#visit_else_node(node)

if foo then bar else baz end ^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2031

def visit_else_node(node)
  bounds(node.else_keyword_loc)
  on_kw("else")

  statements =
    if node.statements.nil?
      [nil]
    else
      body = node.statements.body
      body = [nil, *body] if void_stmt?(node.else_keyword_loc, node.statements.body[0].location, false)
      body
    end

  else_statements = visit_statements_node_body(statements)

  bounds(node.end_keyword_loc)
  on_kw("end")
  bounds(node.location)
  on_else(else_statements)
end

#visit_embedded_statements_node(node)

"foo #bar" ^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2054

def visit_embedded_statements_node(node)
  bounds(node.opening_loc)
  on_embexpr_beg(node.opening)

  statements =
    if node.statements.nil?
      bounds(node.location)
      on_stmts_add(on_stmts_new, on_void_stmt)
    else
      visit(node.statements)
    end

  bounds(node.closing_loc)
  on_embexpr_end(node.closing)

  bounds(node.location)
  on_string_embexpr(statements)
end

#visit_embedded_variable_node(node)

"foo #@bar" ^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2075

def visit_embedded_variable_node(node)
  bounds(node.operator_loc)
  on_embvar(node.operator)

  variable = visit(node.variable)

  bounds(node.location)
  on_string_dvar(variable)
end

#visit_ensure_node(node)

Visit an EnsureNode node.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2086

def visit_ensure_node(node)
  bounds(node.ensure_keyword_loc)
  on_kw("ensure")

  statements =
    if node.statements.nil?
      [nil]
    else
      body = node.statements.body
      body = [nil, *body] if void_stmt?(node.ensure_keyword_loc, body[0].location, false)
      body
    end

  statements = visit_statements_node_body(statements)

  bounds(node.location)
  on_ensure(statements)
end

#visit_error_recovery_node(node)

A node that is missing from the syntax tree. This is only used in the case of a syntax error.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3015

def visit_error_recovery_node(node)
  raise "Cannot visit error recovery nodes directly."
end

#visit_false_node(node)

false ^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2107

def visit_false_node(node)
  bounds(node.location)
  on_var_ref(on_kw("false"))
end

#visit_find_pattern_node(node)

foo => [*, bar, *] ^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2114

def visit_find_pattern_node(node)
  constant = visit(node.constant)

  if node.opening_loc
    bounds(node.opening_loc)
    node.opening == "[" ? on_lbracket("[") : on_lparen("(")
  end
  bounds(node.left.operator_loc)
  on_op("*")

  left =
    if node.left.expression.nil?
      bounds(node.left.location)
      on_var_field(nil)
    else
      visit(node.left.expression)
    end

  requireds = visit_all(node.requireds) if node.requireds.any?

  bounds(node.right.operator_loc)
  on_op("*")

  right =
    if node.right.expression.nil?
      bounds(node.right.location)
      on_var_field(nil)
    else
      visit(node.right.expression)
    end

  if node.closing_loc
    bounds(node.closing_loc)
    node.closing == "]" ? on_rbracket("]") : on_rparen(")")
  end
  bounds(node.location)
  on_fndptn(constant, left, requireds, right)
end

#visit_flip_flop_node(node)

if foo .. bar; end ^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2155

def visit_flip_flop_node(node)
  left = visit(node.left)

  bounds(node.operator_loc)
  on_op(node.operator)

  right = visit(node.right)

  bounds(node.location)
  if node.exclude_end?
    on_dot3(left, right)
  else
    on_dot2(left, right)
  end
end

#visit_float_node(node)

1.0 ^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2173

def visit_float_node(node)
  visit_number_node(node) { |text| on_float(text) }
end

#visit_for_node(node)

for foo in bar do end ^^^^^^^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2179

def visit_for_node(node)
  bounds(node.for_keyword_loc)
  on_kw("for")

  index = visit(node.index)
  bounds(node.in_keyword_loc)
  on_kw("in")

  collection = visit(node.collection)
  if node.do_keyword_loc
    bounds(node.do_keyword_loc)
    on_kw("do")
  end
  statements =
    if node.statements.nil?
      bounds(node.location)
      on_stmts_add(on_stmts_new, on_void_stmt)
    else
      visit(node.statements)
    end

  bounds(node.end_keyword_loc)
  on_kw("end")

  bounds(node.location)
  on_for(index, collection, statements)
end

#visit_forwarding_arguments_node(node)

def foo(...); bar(...); end ^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2209

def visit_forwarding_arguments_node(node)
  bounds(node.location)
  on_op("...")
  on_args_forward
end

#visit_forwarding_parameter_node(node)

def foo(...); end ^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2217

def visit_forwarding_parameter_node(node)
  bounds(node.location)
  on_op("...")
  on_args_forward
end

#visit_forwarding_super_node(node)

super ^^^^^

super {} ^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2228

def visit_forwarding_super_node(node)
  bounds(node.keyword_loc)
  on_kw("super")

  if node.block.nil?
    bounds(node.location)
    on_zsuper
  else
    block = visit(node.block)

    bounds(node.location)
    on_method_add_block(on_zsuper, block)
  end
end

#visit_global_variable_and_write_node(node)

$foo &&= bar ^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2281

def visit_global_variable_and_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_gvar(node.name.to_s))

  bounds(node.operator_loc)
  operator = on_op("&&=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_global_variable_operator_write_node(node)

$foo += bar ^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2267

def visit_global_variable_operator_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_gvar(node.name.to_s))

  bounds(node.binary_operator_loc)
  operator = on_op("#{node.binary_operator}=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_global_variable_or_write_node(node)

$foo ||= bar ^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2295

def visit_global_variable_or_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_gvar(node.name.to_s))

  bounds(node.operator_loc)
  operator = on_op("||=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_global_variable_read_node(node)

$foo ^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2245

def visit_global_variable_read_node(node)
  bounds(node.location)
  on_var_ref(on_gvar(node.name.to_s))
end

#visit_global_variable_target_node(node)

$foo, = bar ^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2309

def visit_global_variable_target_node(node)
  bounds(node.location)
  on_var_field(on_gvar(node.name.to_s))
end

#visit_global_variable_write_node(node)

$foo = 1 ^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2252

def visit_global_variable_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_gvar(node.name.to_s))

  bounds(node.operator_loc)
  on_op("=")

  value = visit_write_value(node.value)

  bounds(node.location)
  on_assign(target, value)
end

#visit_hash_node(node)

{} ^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2316

def visit_hash_node(node)
  bounds(node.opening_loc)
  on_lbrace("{")

  elements =
    if node.elements.any?
      args = visit_all(node.elements)

      bounds(node.elements.first.location)
      on_assoclist_from_args(args)
    end

  bounds(node.closing_loc)
  on_rbrace("}")
  bounds(node.location)
  on_hash(elements)
end

#visit_hash_pattern_node(node)

foo => {} ^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2336

def visit_hash_pattern_node(node)
  constant = visit(node.constant)

  if node.constant
    bounds(node.opening_loc)
    node.opening == "[" ? on_lbracket("[") : on_lparen("(")
  elsif node.opening_loc
    bounds(node.opening_loc)
    on_lbrace("{")
  end

  elements =
    if node.elements.any? || !node.rest.nil?
      node.elements.map do |element|
        [
          if (key = element.key).opening_loc.nil?
            visit(key)
          else
            bounds(key.value_loc)
            if (value = key.value).empty?
              on_string_content
            else
              on_string_add(on_string_content, on_tstring_content(value))
            end
          end,
          visit(element.value)
        ]
      end
    end

  rest =
    case node.rest
    when AssocSplatNode
      bounds(node.rest.operator_loc)
      on_op("**")
      visit(node.rest.value)
    when NoKeywordsParameterNode
      bounds(node.rest.location)
      on_var_field(visit(node.rest))
    end

  if node.constant
    bounds(node.closing_loc)
    node.closing == "]" ? on_rbracket("]") : on_rparen(")")
  elsif node.closing_loc
    bounds(node.closing_loc)
    on_rbrace("}")
  end
  bounds(node.location)
  on_hshptn(constant, elements, rest)
end

#visit_heredoc_node(parts, base) (private)

Visit a string that is expressed using a <<~ heredoc.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3742

private def visit_heredoc_node(parts, base)
  common_whitespace = visit_heredoc_node_whitespace(parts)

  if common_whitespace == 0
    bounds(parts.first.location)

    string = []
    result = base

    parts.each do |part|
      if part.is_a?(StringNode)
        if string.empty?
          string = [part]
        else
          string << part
        end
      else
        unless string.empty?
          bounds(string[0].location)
          result = yield result, on_tstring_content(string.map(&:content).join)
          string = []
        end

        result = yield result, visit(part)
      end
    end

    unless string.empty?
      bounds(string[0].location)
      result = yield result, on_tstring_content(string.map(&:content).join)
    end

    result
  else
    bounds(parts.first.location)
    result =
      parts.inject(base) do |string_content, part|
        yield string_content, visit_string_content(part)
      end

    bounds(parts.first.location)
    on_heredoc_dedent(result, common_whitespace)
  end
end

#visit_heredoc_node_whitespace(parts) (private)

Ripper gives back the escaped string content but strips out the common leading whitespace. ::Prism gives back the unescaped string content and a location for the escaped string content. Unfortunately these don't work well together, so here we need to re-derive the common leading whitespace.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3717

private def visit_heredoc_node_whitespace(parts)
  common_whitespace = nil
  dedent_next = true

  parts.each do |part|
    if part.is_a?(StringNode)
      if dedent_next && !(content = part.content).chomp.empty?
        common_whitespace = [
          common_whitespace || Float::INFINITY,
          content[/\A\s*/].each_char.inject(0) do |part_whitespace, char|
            char == "\t" ? ((part_whitespace / 8 + 1) * 8) : (part_whitespace + 1)
          end
        ].min
      end

      dedent_next = true
    else
      dedent_next = false
    end
  end

  common_whitespace || 0
end

#visit_heredoc_string_node(node) (private)

Visit a heredoc node that is representing a string.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3788

private def visit_heredoc_string_node(node)
  bounds(node.location)
  visit_heredoc_node(node.parts, on_string_content) do |parts, part|
    on_string_add(parts, part)
  end
end

#visit_heredoc_x_string_node(node) (private)

Visit a heredoc node that is representing an xstring.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3796

private def visit_heredoc_x_string_node(node)
  bounds(node.location)
  visit_heredoc_node(node.parts, on_xstring_new) do |parts, part|
    on_xstring_add(parts, part)
  end
end

#visit_if_node(node)

if foo then bar end ^^^^^^^^^^^^^^^^^^^

bar if foo ^^^^^^^^^^

foo ? bar : baz ^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2396

def visit_if_node(node)
  if node.then_keyword == "?"
    predicate = visit(node.predicate)

    bounds(node.then_keyword_loc)
    on_op("?")

    truthy = visit(node.statements.body.first)

    bounds(node.subsequent.else_keyword_loc)
    on_op(":")

    falsy = visit(node.subsequent.statements.body.first)

    bounds(node.location)
    on_ifop(predicate, truthy, falsy)
  elsif node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
    bounds(node.if_keyword_loc)
    on_kw(node.if_keyword)
    predicate = visit(node.predicate)
    if node.then_keyword_loc && node.then_keyword != "?"
      bounds(node.then_keyword_loc)
      on_kw("then")
    end
    statements =
      if node.statements.nil?
        bounds(node.location)
        on_stmts_add(on_stmts_new, on_void_stmt)
      else
        visit(node.statements)
      end
    subsequent = visit(node.subsequent)

    if node.end_keyword_loc && !node.subsequent
      bounds(node.end_keyword_loc)
      on_kw("end")
    end

    bounds(node.location)
    if node.if_keyword == "if"
      on_if(predicate, statements, subsequent)
    else
      on_elsif(predicate, statements, subsequent)
    end
  else
    statements = visit(node.statements.body.first)
    bounds(node.if_keyword_loc)
    on_kw(node.if_keyword)
    predicate = visit(node.predicate)

    bounds(node.location)
    on_if_mod(predicate, statements)
  end
end

#visit_imaginary_node(node)

1i ^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2453

def visit_imaginary_node(node)
  visit_number_node(node) { |text| on_imaginary(text) }
end

#visit_implicit_node(node)

{ foo: } ^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2459

def visit_implicit_node(node)
end

#visit_implicit_rest_node(node)

foo { |bar,| } ^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2464

def visit_implicit_rest_node(node)
  bounds(node.location)
  on_excessed_comma
end

#visit_in_node(node)

case foo; in bar; end ^^^^^^^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2471

def visit_in_node(node)
  # This is a special case where we're not going to call on_in directly
  # because we don't have access to the subsequent. Instead, we'll return
  # the component parts and let the parent node handle it.
  bounds(node.in_loc)
  on_kw("in")

  pattern = visit_pattern_node(node.pattern)
  if node.then_loc
    bounds(node.then_loc)
    on_kw("then")
  end
  statements =
    if node.statements.nil?
      bounds(node.location)
      on_stmts_add(on_stmts_new, on_void_stmt)
    else
      visit(node.statements)
    end

  [pattern, statements]
end

#visit_index_and_write_node(node)

foo &&= baz ^^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2520

def visit_index_and_write_node(node)
  receiver = visit(node.receiver)

  bounds(node.opening_loc)
  on_lbracket("[")

  arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))

  bounds(node.closing_loc)
  on_rbracket("]")

  bounds(node.location)
  target = on_aref_field(receiver, arguments)

  bounds(node.operator_loc)
  operator = on_op("&&=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_index_operator_write_node(node)

foo += baz ^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2496

def visit_index_operator_write_node(node)
  receiver = visit(node.receiver)

  bounds(node.opening_loc)
  on_lbracket("[")

  arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))

  bounds(node.closing_loc)
  on_rbracket("]")

  bounds(node.location)
  target = on_aref_field(receiver, arguments)

  bounds(node.binary_operator_loc)
  operator = on_op("#{node.binary_operator}=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_index_or_write_node(node)

foo ||= baz ^^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2544

def visit_index_or_write_node(node)
  receiver = visit(node.receiver)

  bounds(node.opening_loc)
  on_lbracket("[")

  arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))

  bounds(node.closing_loc)
  on_rbracket("]")

  bounds(node.location)
  target = on_aref_field(receiver, arguments)

  bounds(node.operator_loc)
  operator = on_op("||=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_index_target_node(node)

foo, = 1 ^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2568

def visit_index_target_node(node)
  receiver = visit(node.receiver)

  bounds(node.opening_loc)
  on_lbracket("[")

  arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))

  bounds(node.closing_loc)
  on_rbracket("]")

  bounds(node.location)
  on_aref_field(receiver, arguments)
end

#visit_instance_variable_and_write_node(node)

^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2621

def visit_instance_variable_and_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_ivar(node.name.to_s))

  bounds(node.operator_loc)
  operator = on_op("&&=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_instance_variable_operator_write_node(node)

^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2607

def visit_instance_variable_operator_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_ivar(node.name.to_s))

  bounds(node.binary_operator_loc)
  operator = on_op("#{node.binary_operator}=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_instance_variable_or_write_node(node)

^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2635

def visit_instance_variable_or_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_ivar(node.name.to_s))

  bounds(node.operator_loc)
  operator = on_op("||=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_instance_variable_read_node(node)

^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2585

def visit_instance_variable_read_node(node)
  bounds(node.location)
  on_var_ref(on_ivar(node.name.to_s))
end

#visit_instance_variable_target_node(node)

@foo, = bar ^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2649

def visit_instance_variable_target_node(node)
  bounds(node.location)
  on_var_field(on_ivar(node.name.to_s))
end

#visit_instance_variable_write_node(node)

^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2592

def visit_instance_variable_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_ivar(node.name.to_s))

  bounds(node.operator_loc)
  on_op("=")

  value = visit_write_value(node.value)

  bounds(node.location)
  on_assign(target, value)
end

#visit_integer_node(node)

1 ^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2656

def visit_integer_node(node)
  visit_number_node(node) { |text| on_int(text) }
end

#visit_interpolated_match_last_line_node(node)

if /foo #bar/ then end ^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2662

def visit_interpolated_match_last_line_node(node)
  bounds(node.opening_loc)
  on_regexp_beg(node.opening)

  bounds(node.parts.first.location)
  parts =
    node.parts.inject(on_regexp_new) do |content, part|
      on_regexp_add(content, visit_string_content(part))
    end

  bounds(node.closing_loc)
  closing = on_regexp_end(node.closing)

  bounds(node.location)
  on_regexp_literal(parts, closing)
end

#visit_interpolated_regular_expression_node(node)

/foo #bar/ ^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2681

def visit_interpolated_regular_expression_node(node)
  bounds(node.opening_loc)
  on_regexp_beg(node.opening)

  bounds(node.parts.first.location)
  parts =
    node.parts.inject(on_regexp_new) do |content, part|
      on_regexp_add(content, visit_string_content(part))
    end

  bounds(node.closing_loc)
  closing = on_regexp_end(node.closing)

  bounds(node.location)
  on_regexp_literal(parts, closing)
end

#visit_interpolated_string_node(node)

"foo #bar" ^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2700

def visit_interpolated_string_node(node)
  with_string_bounds(node) do
    if node.opening&.start_with?("<<~")
      heredoc = visit_heredoc_string_node(node)

      bounds(node.location)
      on_string_literal(heredoc)
    elsif !node.heredoc? && node.parts.length > 1 && node.parts.any? { |part| (part.is_a?(StringNode) || part.is_a?(InterpolatedStringNode)) && !part.opening_loc.nil? }
      first, *rest = node.parts
      rest.inject(visit(first)) do |content, part|
        concat = visit(part)

        bounds(part.location)
        on_string_concat(content, concat)
      end
    else
      bounds(node.parts.first.location)
      parts =
        node.parts.inject(on_string_content) do |content, part|
          on_string_add(content, visit_string_content(part))
        end

      bounds(node.location)
      on_string_literal(parts)
    end
  end
end

#visit_interpolated_symbol_node(node)

:"foo #bar" ^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2730

def visit_interpolated_symbol_node(node)
  with_string_bounds(node) do
    bounds(node.parts.first.location)
    parts =
      node.parts.inject(on_string_content) do |content, part|
        on_string_add(content, visit_string_content(part))
      end

    bounds(node.location)
    on_dyna_symbol(parts)
  end
end

#visit_interpolated_x_string_node(node)

foo #{bar} ^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2745

def visit_interpolated_x_string_node(node)
  with_string_bounds(node) do
    if node.opening.start_with?("<<~")
      heredoc = visit_heredoc_x_string_node(node)

      bounds(node.location)
      on_xstring_literal(heredoc)
    else
      bounds(node.parts.first.location)
      parts =
        node.parts.inject(on_xstring_new) do |content, part|
          on_xstring_add(content, visit_string_content(part))
        end

      bounds(node.location)
      on_xstring_literal(parts)
    end
  end
end

#visit_it_local_variable_read_node(node)

-> { it } ^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2777

def visit_it_local_variable_read_node(node)
  bounds(node.location)
  on_vcall(on_ident(node.slice))
end

#visit_it_parameters_node(node)

-> { it } ^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2784

def visit_it_parameters_node(node)
end

#visit_keyword_hash_node(node)

foo(bar: baz) ^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2789

def visit_keyword_hash_node(node)
  elements = visit_all(node.elements)

  bounds(node.location)
  on_bare_assoc_hash(elements)
end

#visit_keyword_rest_parameter_node(node)

def foo(**bar); end ^^^^^

def foo(**); end ^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2801

def visit_keyword_rest_parameter_node(node)
  bounds(node.operator_loc)
  on_op("**")

  if node.name_loc.nil?
    bounds(node.location)
    on_kwrest_param(nil)
  else
    bounds(node.name_loc)
    name = on_ident(node.name.to_s)

    bounds(node.location)
    on_kwrest_param(name)
  end
end

#visit_lambda_node(node)

-> {}

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2818

def visit_lambda_node(node)
  bounds(node.operator_loc)
  on_tlambda(node.operator)

  parameters =
    if node.parameters.is_a?(BlockParametersNode)
      if node.parameters.opening_loc
        bounds(node.parameters.opening_loc)
        on_lparen("(")
      end

      # Ripper does not track block-locals within lambdas, so we skip
      # directly to the parameters here.
      params =
        if node.parameters.parameters.nil?
          bounds(node.location)
          on_params(nil, nil, nil, nil, nil, nil, nil)
        else
          visit(node.parameters.parameters)
        end

      visit_all(node.parameters.locals)

      if node.parameters.closing_loc
        bounds(node.parameters.closing_loc)
        on_rparen(")")
      end

      if node.parameters.opening_loc.nil?
        params
      else
        bounds(node.parameters.opening_loc)
        on_paren(params)
      end
    else
      bounds(node.location)
      on_params(nil, nil, nil, nil, nil, nil, nil)
    end

  braces = node.opening == "{"
  bounds(node.opening_loc)
  if braces
    on_tlambeg(node.opening)
  else
    on_kw("do")
  end

  body =
    case node.body
    when nil
      bounds(node.location)
      stmts = on_stmts_add(on_stmts_new, on_void_stmt)

      bounds(node.location)
      braces ? stmts : on_bodystmt(stmts, nil, nil, nil)
    when StatementsNode
      stmts = node.body.body
      stmts = [nil, *stmts] if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false)
      stmts = visit_statements_node_body(stmts)

      bounds(node.body.location)
      braces ? stmts : on_bodystmt(stmts, nil, nil, nil)
    when BeginNode
      visit_body_node(node.opening_loc, node.body)
    else
      raise
    end

    bounds(node.closing_loc)
  if braces
    on_rbrace("}")
  else
    on_kw("end")
  end

  bounds(node.location)
  on_lambda(parameters, body)
end

#visit_local_variable_and_write_node(node)

foo &&= bar ^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2935

def visit_local_variable_and_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_ident(node.name_loc.slice))

  bounds(node.operator_loc)
  operator = on_op("&&=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_local_variable_operator_write_node(node)

foo += bar ^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2921

def visit_local_variable_operator_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_ident(node.name_loc.slice))

  bounds(node.binary_operator_loc)
  operator = on_op("#{node.binary_operator}=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_local_variable_or_write_node(node)

foo ||= bar ^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2949

def visit_local_variable_or_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_ident(node.name_loc.slice))

  bounds(node.operator_loc)
  operator = on_op("||=")
  value = visit_write_value(node.value)

  bounds(node.location)
  on_opassign(target, operator, value)
end

#visit_local_variable_read_node(node)

foo ^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2899

def visit_local_variable_read_node(node)
  bounds(node.location)
  on_var_ref(on_ident(node.slice))
end

#visit_local_variable_target_node(node)

foo, = bar ^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2963

def visit_local_variable_target_node(node)
  bounds(node.location)
  on_var_field(on_ident(node.name.to_s))
end

#visit_local_variable_write_node(node)

foo = 1 ^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2906

def visit_local_variable_write_node(node)
  bounds(node.name_loc)
  target = on_var_field(on_ident(node.name_loc.slice))

  bounds(node.operator_loc)
  on_op("=")

  value = visit_write_value(node.value)

  bounds(node.location)
  on_assign(target, value)
end

#visit_match_last_line_node(node)

if /foo/ then end ^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2970

def visit_match_last_line_node(node)
  bounds(node.opening_loc)
  on_regexp_beg(node.opening)

  bounds(node.content_loc)
  tstring_content = on_tstring_content(node.content)

  bounds(node.closing_loc)
  closing = on_regexp_end(node.closing)

  on_regexp_literal(on_regexp_add(on_regexp_new, tstring_content), closing)
end

#visit_match_predicate_node(node)

foo in bar ^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2985

def visit_match_predicate_node(node)
  value = visit(node.value)
  bounds(node.operator_loc)
  on_kw("in")
  pattern = on_in(visit_pattern_node(node.pattern), nil, nil)

  on_case(value, pattern)
end

#visit_match_required_node(node)

foo => bar ^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2996

def visit_match_required_node(node)
  value = visit(node.value)

  bounds(node.operator_loc)
  on_op("=>")

  pattern = on_in(visit_pattern_node(node.pattern), nil, nil)

  on_case(value, pattern)
end

#visit_match_write_node(node)

/(?foo)/ =~ bar ^^^^^^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3009

def visit_match_write_node(node)
  visit(node.call)
end

#visit_module_node(node)

module Foo; end ^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3021

def visit_module_node(node)
  bounds(node.module_keyword_loc)
  on_kw("module")

  constant_path =
    if node.constant_path.is_a?(ConstantReadNode)
      bounds(node.constant_path.location)
      on_const_ref(on_const(node.constant_path.name.to_s))
    else
      visit(node.constant_path)
    end

  bodystmt = visit_body_node(node.constant_path.location, node.body, true)

  bounds(node.end_keyword_loc)
  on_kw("end")

  bounds(node.location)
  on_module(constant_path, bodystmt)
end

#visit_multi_target_node(node)

(foo, bar), bar = qux ^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3044

def visit_multi_target_node(node)
  if node.lparen_loc
    bounds(node.lparen_loc)
    on_lparen("(")
  end

  bounds(node.location)
  targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, true)

  if node.rparen_loc
    bounds(node.rparen_loc)
    on_rparen(")")
  end

  if node.lparen_loc.nil?
    targets
  else
    bounds(node.lparen_loc)
    on_mlhs_paren(targets)
  end
end

#visit_multi_target_node_targets(lefts, rest, rights, skippable) (private)

Visit the targets of a multi-target node.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3067

private def visit_multi_target_node_targets(lefts, rest, rights, skippable)
  if skippable && lefts.length == 1 && lefts.first.is_a?(MultiTargetNode) && rest.nil? && rights.empty?
    return visit(lefts.first)
  end

  mlhs = on_mlhs_new

  lefts.each do |left|
    bounds(left.location)
    mlhs = on_mlhs_add(mlhs, visit(left))
  end

  case rest
  when nil
    # do nothing
  when ImplicitRestNode
    # these do not get put into the generated tree
    bounds(rest.location)
    on_excessed_comma
  else
    bounds(rest.location)
    mlhs = on_mlhs_add_star(mlhs, visit(rest))
  end

  if rights.any?
    bounds(rights.first.location)
    post = on_mlhs_new

    rights.each do |right|
      bounds(right.location)
      post = on_mlhs_add(post, visit(right))
    end

    mlhs = on_mlhs_add_post(mlhs, post)
  end

  mlhs
end

#visit_multi_write_node(node)

foo, bar = baz ^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3108

def visit_multi_write_node(node)
  if node.lparen_loc
    bounds(node.lparen_loc)
    on_lparen("(")
  end

  bounds(node.location)
  targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, true)

  if node.rparen_loc
    bounds(node.rparen_loc)
    on_rparen(")")
  end

  bounds(node.operator_loc)
  on_op("=")

  unless node.lparen_loc.nil?
    bounds(node.lparen_loc)
    targets = on_mlhs_paren(targets)
  end

  value = visit_write_value(node.value)

  bounds(node.location)
  on_massign(targets, value)
end

#visit_next_node(node)

next ^^^^

next foo ^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3141

def visit_next_node(node)
  bounds(node.keyword_loc)
  on_kw("next")

  if node.arguments.nil?
    bounds(node.location)
    on_next(on_args_new)
  else
    arguments = visit(node.arguments)

    bounds(node.location)
    on_next(arguments)
  end
end

#visit_nil_node(node)

nil ^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3158

def visit_nil_node(node)
  bounds(node.location)
  on_var_ref(on_kw("nil"))
end

#visit_no_block_parameter_node(node)

def foo(&nil); end ^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3165

def visit_no_block_parameter_node(node)
  bounds(node.operator_loc)
  on_op("&")
  bounds(node.keyword_loc)
  on_kw("nil")
  bounds(node.location)
  on_blockarg(:nil)
end

#visit_no_keywords_parameter_node(node)

def foo(**nil); end ^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3176

def visit_no_keywords_parameter_node(node)
  bounds(node.operator_loc)
  on_op("**")
  bounds(node.keyword_loc)
  on_kw("nil")
  bounds(node.location)
  on_nokw_param(nil)

  :nil
end

#visit_number_node(node) (private)

Visit a node that represents a number. We need to explicitly handle the unary - operator.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4146

def visit_number_node(node)
  slice = node.slice
  location = node.location

  if slice[0] == "-"
    bounds(location.copy(length: 1))
    on_op("-")

    bounds(location.copy(start_offset: location.start_offset + 1))
    value = yield slice[1..-1]

    bounds(node.location)
    on_unary(:-@, value)
  else
    bounds(location)
    yield slice
  end
end

#visit_numbered_parameters_node(node)

-> { _1 + _2 } ^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3189

def visit_numbered_parameters_node(node)
end

#visit_numbered_reference_read_node(node)

$1 ^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3194

def visit_numbered_reference_read_node(node)
  bounds(node.location)
  on_backref(node.slice)
end

#visit_optional_keyword_parameter_node(node)

def foo(bar: baz); end ^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3201

def visit_optional_keyword_parameter_node(node)
  bounds(node.name_loc)
  name = on_label("#{node.name}:")
  value = visit(node.value)

  [name, value]
end

#visit_optional_parameter_node(node)

def foo(bar = 1); end ^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3211

def visit_optional_parameter_node(node)
  bounds(node.name_loc)
  name = on_ident(node.name.to_s)

  bounds(node.operator_loc)
  on_op("=")

  value = visit(node.value)

  [name, value]
end

#visit_or_node(node)

a or b ^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3225

def visit_or_node(node)
  left = visit(node.left)

  bounds(node.operator_loc)
  if node.operator == "or"
    on_kw("or")
  else
    on_op("||")
  end

  right = visit(node.right)

  bounds(node.location)
  on_binary(left, node.operator.to_sym, right)
end

#visit_parameters_node(node)

def foo(bar, *baz); end ^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3243

def visit_parameters_node(node)
  requireds = node.requireds.map { |required| required.is_a?(MultiTargetNode) ? visit_destructured_parameter_node(required) : visit(required) } if node.requireds.any?
  optionals = visit_all(node.optionals) if node.optionals.any?
  rest = visit(node.rest)
  posts = node.posts.map { |post| post.is_a?(MultiTargetNode) ? visit_destructured_parameter_node(post) : visit(post) } if node.posts.any?
  keywords = visit_all(node.keywords) if node.keywords.any?
  keyword_rest = visit(node.keyword_rest)
  block = visit(node.block)

  bounds(node.location)
  on_params(requireds, optionals, rest, posts, keywords, keyword_rest, block)
end

#visit_parentheses_node(node)

() ^^

(1) ^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3280

def visit_parentheses_node(node)
  bounds(node.opening_loc)
  on_lparen("(")

  body =
    if node.body.nil?
      on_stmts_add(on_stmts_new, on_void_stmt)
    else
      visit(node.body)
    end

  bounds(node.closing_loc)
  on_rparen(")")
  bounds(node.location)
  on_paren(body)
end

#visit_pattern_node(node) (private)

Visit a pattern within a pattern match. This is used to bypass the parenthesis node that can be used to wrap patterns.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 723

private def visit_pattern_node(node)
  if node.is_a?(ParenthesesNode)
    bounds(node.opening_loc)
    on_lparen("(")
    result = visit(node.body)
    bounds(node.closing_loc)
    on_rparen(")")

    result
  else
    visit(node)
  end
end

#visit_pinned_expression_node(node)

foo => ^(bar) ^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3299

def visit_pinned_expression_node(node)
  bounds(node.operator_loc)
  on_op("^")
  bounds(node.lparen_loc)
  on_lparen("(")

  expression = visit(node.expression)

  bounds(node.rparen_loc)
  on_rparen(")")
  bounds(node.location)
  on_begin(expression)
end

#visit_pinned_variable_node(node)

foo = 1 and bar => ^foo ^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3315

def visit_pinned_variable_node(node)
  bounds(node.operator_loc)
  on_op("^")

  visit(node.variable)
end

#visit_post_execution_node(node)

END {} ^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3324

def visit_post_execution_node(node)
  bounds(node.keyword_loc)
  on_kw("END")
  bounds(node.opening_loc)
  on_lbrace("{")

  statements =
    if node.statements.nil?
      bounds(node.location)
      on_stmts_add(on_stmts_new, on_void_stmt)
    else
      visit(node.statements)
    end

  bounds(node.closing_loc)
  on_rbrace("}")
  bounds(node.location)
  on_END(statements)
end

#visit_pre_execution_node(node)

BEGIN {} ^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3346

def visit_pre_execution_node(node)
  bounds(node.keyword_loc)
  on_kw("BEGIN")
  bounds(node.opening_loc)
  on_lbrace("{")

  statements =
    if node.statements.nil?
      bounds(node.location)
      on_stmts_add(on_stmts_new, on_void_stmt)
    else
      visit(node.statements)
    end

  bounds(node.closing_loc)
  on_rbrace("}")
  bounds(node.location)
  on_BEGIN(statements)
end

#visit_program_node(node)

The top-level program node.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3367

def visit_program_node(node)
  body = node.statements.body
  body = [nil] if body.empty?
  statements = visit_statements_node_body(body)

  bounds(node.location)
  on_program(statements)
end

#visit_range_node(node)

0..5 ^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3378

def visit_range_node(node)
  left = visit(node.left)

  bounds(node.operator_loc)
  on_op(node.operator)

  right = visit(node.right)

  bounds(node.location)
  if node.exclude_end?
    on_dot3(left, right)
  else
    on_dot2(left, right)
  end
end

#visit_rational_node(node)

1r ^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3396

def visit_rational_node(node)
  visit_number_node(node) { |text| on_rational(text) }
end

#visit_redo_node(node)

redo ^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3402

def visit_redo_node(node)
  bounds(node.location)
  on_kw("redo")
  on_redo
end

#visit_regular_expression_node(node)

/foo/ ^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3410

def visit_regular_expression_node(node)
  bounds(node.opening_loc)
  on_regexp_beg(node.opening)

  if node.content.empty?
    bounds(node.closing_loc)
    closing = on_regexp_end(node.closing)

    on_regexp_literal(on_regexp_new, closing)
  else
    bounds(node.content_loc)
    tstring_content = on_tstring_content(node.content)

    bounds(node.closing_loc)
    closing = on_regexp_end(node.closing)

    on_regexp_literal(on_regexp_add(on_regexp_new, tstring_content), closing)
  end
end

#visit_required_keyword_parameter_node(node)

def foo(bar:); end ^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3432

def visit_required_keyword_parameter_node(node)
  bounds(node.name_loc)
  [on_label("#{node.name}:"), false]
end

#visit_required_parameter_node(node)

def foo(bar); end ^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3439

def visit_required_parameter_node(node)
  bounds(node.location)
  on_ident(node.name.to_s)
end

#visit_rescue_modifier_node(node)

foo rescue bar ^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3446

def visit_rescue_modifier_node(node)
  bounds(node.keyword_loc)
  on_kw("rescue")

  expression = visit_write_value(node.expression)
  rescue_expression = visit(node.rescue_expression)

  bounds(node.location)
  on_rescue_mod(expression, rescue_expression)
end

#visit_rescue_node(node)

begin; rescue; end ^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3459

def visit_rescue_node(node)
  bounds(node.keyword_loc)
  on_kw("rescue")

  exceptions =
    case node.exceptions.length
    when 0
      nil
    when 1
      if (exception = node.exceptions.first).is_a?(SplatNode)
        bounds(exception.location)
        on_mrhs_add_star(on_mrhs_new, visit(exception))
      else
        [visit(node.exceptions.first)]
      end
    else
      bounds(node.location)
      length = node.exceptions.length

      node.exceptions.each_with_index.inject(on_args_new) do |mrhs, (exception, index)|
        arg = visit(exception)

        bounds(exception.location)
        mrhs = on_mrhs_new_from_args(mrhs) if index == length - 1

        if exception.is_a?(SplatNode)
          if index == length - 1
            on_mrhs_add_star(mrhs, arg)
          else
            on_args_add_star(mrhs, arg)
          end
        else
          if index == length - 1
            on_mrhs_add(mrhs, arg)
          else
            on_args_add(mrhs, arg)
          end
        end
      end
    end

  if node.operator_loc
    bounds(node.operator_loc)
    on_op("=>")
  end

  reference = visit(node.reference)
  statements =
    if node.statements.nil?
      bounds(node.location)
      on_stmts_add(on_stmts_new, on_void_stmt)
    else
      visit(node.statements)
    end

  subsequent = visit(node.subsequent)

  bounds(node.location)
  on_rescue(exceptions, reference, statements, subsequent)
end

#visit_rest_parameter_node(node)

def foo(*bar); end ^^^^

def foo(*); end ^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3525

def visit_rest_parameter_node(node)
  bounds(node.operator_loc)
  on_op("*")

  if node.name_loc.nil?
    bounds(node.location)
    on_rest_param(nil)
  else
    bounds(node.name_loc)
    on_rest_param(on_ident(node.name.to_s))
  end
end

#visit_retry_node(node)

retry ^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3540

def visit_retry_node(node)
  bounds(node.location)
  on_kw("retry")
  on_retry
end

#visit_return_node(node)

return ^^^^^^

return 1 ^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3551

def visit_return_node(node)
  bounds(node.keyword_loc)
  on_kw("return")

  if node.arguments.nil?
    bounds(node.location)
    on_return0
  else
    arguments = visit(node.arguments)

    bounds(node.location)
    on_return(arguments)
  end
end

#visit_self_node(node)

self ^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3568

def visit_self_node(node)
  bounds(node.location)
  on_var_ref(on_kw("self"))
end

#visit_shareable_constant_node(node)

A shareable constant.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3574

def visit_shareable_constant_node(node)
  visit(node.write)
end

#visit_singleton_class_node(node)

class << self; end ^^^^^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3580

def visit_singleton_class_node(node)
  bounds(node.class_keyword_loc)
  on_kw("class")
  bounds(node.operator_loc)
  on_op("<<")

  expression = visit(node.expression)
  bodystmt = visit_body_node(node.body&.location || node.end_keyword_loc, node.body)

  bounds(node.end_keyword_loc)
  on_kw("end")

  bounds(node.location)
  on_sclass(expression, bodystmt)
end

#visit_source_encoding_node(node)

ENCODING ^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3598

def visit_source_encoding_node(node)
  bounds(node.location)
  on_var_ref(on_kw("__ENCODING__"))
end

#visit_source_file_node(node)

FILE ^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3605

def visit_source_file_node(node)
  bounds(node.location)
  on_var_ref(on_kw("__FILE__"))
end

#visit_source_line_node(node)

LINE ^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3612

def visit_source_line_node(node)
  bounds(node.location)
  on_var_ref(on_kw("__LINE__"))
end

#visit_splat_node(node)

foo(*bar) ^^^^

def foo((bar, *baz)); end ^^^^

def foo(); bar(); end ^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3625

def visit_splat_node(node)
  bounds(node.operator_loc)
  on_op("*")
  visit(node.expression)
end

#visit_statements_node(node)

A list of statements.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3632

def visit_statements_node(node)
  bounds(node.location)
  visit_statements_node_body(node.body)
end

#visit_statements_node_body(body) (private)

Visit the list of statements of a statements node. We support nil statements in the list. This would normally not be allowed by the structure of the prism parse tree, but we manually add them here so that we can mirror Ripper's void stmt.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3641

private def visit_statements_node_body(body)
  body.inject(on_stmts_new) do |stmts, stmt|
    on_stmts_add(stmts, stmt.nil? ? on_void_stmt : visit(stmt))
  end
end

#visit_string_content(part) (private)

Visit an individual part of a string-like node.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 2766

private def visit_string_content(part)
  if part.is_a?(StringNode)
    bounds(part.content_loc)
    on_tstring_content(part.content)
  else
    visit(part)
  end
end

#visit_string_node(node)

"foo" ^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3649

def visit_string_node(node)
  with_string_bounds(node) do
    if (content = node.content).empty?
      bounds(node.location)
      on_string_literal(on_string_content)
    elsif (opening = node.opening) == "?"
      bounds(node.location)
      on_CHAR("?#{node.content}")
    elsif opening.start_with?("<<~")
      heredoc = visit_heredoc_string_node(node.to_interpolated)

      bounds(node.location)
      on_string_literal(heredoc)
    else
      bounds(node.content_loc)
      tstring_content = on_tstring_content(content)

      bounds(node.location)
      on_string_literal(on_string_add(on_string_content, tstring_content))
    end
  end
end

#visit_super_node(node)

super(foo) ^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3805

def visit_super_node(node)
  bounds(node.keyword_loc)
  on_kw("super")

  if node.lparen_loc
    bounds(node.lparen_loc)
    on_lparen("(")
  end

  arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.rparen_loc || node.location))

  if node.rparen_loc
    bounds(node.rparen_loc)
    on_rparen(")")
  end

  block = visit(block_node)

  if !node.lparen_loc.nil?
    bounds(node.lparen_loc)
    arguments = on_arg_paren(arguments)
  end

  bounds(node.location)
  call = on_super(arguments)

  if block_node
    bounds(node.block.location)
    on_method_add_block(call, block)
  else
    call
  end
end

#visit_symbol_node(node)

:foo ^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3841

def visit_symbol_node(node)
  with_string_bounds(node) do
    if node.value_loc.nil?
      bounds(node.location)
      on_dyna_symbol(on_string_content)
    elsif (opening = node.opening)&.match?(/^%s|['"]:?$/)
      bounds(node.value_loc)
      content = on_string_add(on_string_content, on_tstring_content(node.value))
      bounds(node.location)
      on_dyna_symbol(content)
    elsif (closing = node.closing) == ":"
      bounds(node.location)
      on_label("#{node.value}:")
    elsif opening.nil? && node.closing_loc.nil?
      bounds(node.value_loc)
      on_symbol_literal(visit_token(node.value))
    else
      bounds(node.value_loc)
      on_symbol_literal(on_symbol(visit_token(node.value)))
    end
  end
end

#visit_token(token, allow_keywords = true) (private)

Visit the string content of a particular node. This method is used to split into the various token types.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4115

def visit_token(token, allow_keywords = true)
  if token == "."
    on_period(token)
  elsif token == "`"
    on_backtick(token)
  elsif allow_keywords && KEYWORDS.include?(token)
    on_kw(token)
  elsif token.start_with?("_")
    on_ident(token)
  elsif token.match?(/^[[:upper:]]\w*$/)
    on_const(token)
  elsif token.start_with?("@@")
    on_cvar(token)
  elsif token.start_with?("@")
    on_ivar(token)
  elsif token.start_with?("$")
    on_gvar(token)
  elsif token.match?(/^[[:punct:]]/)
    on_op(token)
  else
    on_ident(token)
  end
end

#visit_true_node(node)

true ^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3866

def visit_true_node(node)
  bounds(node.location)
  on_var_ref(on_kw("true"))
end

#visit_undef_node(node)

undef foo ^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3873

def visit_undef_node(node)
  bounds(node.keyword_loc)
  on_kw("undef")

  names = visit_all(node.names)

  bounds(node.location)
  on_undef(names)
end

#visit_unless_node(node)

unless foo; bar end ^^^^^^^^^^^^^^^^^^^

bar unless foo ^^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3888

def visit_unless_node(node)
  if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
    bounds(node.keyword_loc)
    on_kw("unless")
    predicate = visit(node.predicate)
    if node.then_keyword_loc
      bounds(node.then_keyword_loc)
      on_kw("then")
    end
    statements =
      if node.statements.nil?
        bounds(node.location)
        on_stmts_add(on_stmts_new, on_void_stmt)
      else
        visit(node.statements)
      end
    else_clause = visit(node.else_clause)

    if node.end_keyword_loc && !node.else_clause
      bounds(node.end_keyword_loc)
      on_kw("end")
    end

    bounds(node.location)
    on_unless(predicate, statements, else_clause)
  else
    statements = visit(node.statements.body.first)
    bounds(node.keyword_loc)
    on_kw("unless")
    predicate = visit(node.predicate)

    bounds(node.location)
    on_unless_mod(predicate, statements)
  end
end

#visit_until_node(node)

until foo; bar end ^^^^^^^^^^^^^^^^^

bar until foo ^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3929

def visit_until_node(node)
  bounds(node.keyword_loc)
  on_kw("until")

  if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
    if node.do_keyword_loc
      bounds(node.do_keyword_loc)
      on_kw("do")
    end
    predicate = visit(node.predicate)
    statements =
      if node.statements.nil?
        bounds(node.location)
        on_stmts_add(on_stmts_new, on_void_stmt)
      else
        visit(node.statements)
      end

    if node.closing_loc
      bounds(node.closing_loc)
      on_kw("end")
    end

    bounds(node.location)
    on_until(predicate, statements)
  else
    statements = visit(node.statements.body.first)
    predicate = visit(node.predicate)

    bounds(node.location)
    on_until_mod(predicate, statements)
  end
end

#visit_when_node(node)

case foo; when bar; end ^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3965

def visit_when_node(node)
  # This is a special case where we're not going to call on_when directly
  # because we don't have access to the subsequent. Instead, we'll return
  # the component parts and let the parent node handle it.
  bounds(node.keyword_loc)
  on_kw("when")

  conditions = visit_arguments(node.conditions)
  if node.then_keyword_loc
    bounds(node.then_keyword_loc)
    on_kw("then")
  end
  statements =
    if node.statements.nil?
      bounds(node.location)
      on_stmts_add(on_stmts_new, on_void_stmt)
    else
      visit(node.statements)
    end

  [conditions, statements]
end

#visit_while_node(node)

while foo; bar end ^^^^^^^^^^^^^^^^^^

bar while foo ^^^^^^^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3993

def visit_while_node(node)
  if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
    bounds(node.keyword_loc)
    on_kw("while")
    if node.do_keyword_loc
      bounds(node.do_keyword_loc)
      on_kw("do")
    end
    predicate = visit(node.predicate)
    if node.closing_loc
      bounds(node.closing_loc)
      on_kw("end")
    end
    statements =
      if node.statements.nil?
        bounds(node.location)
        on_stmts_add(on_stmts_new, on_void_stmt)
      else
        visit(node.statements)
      end

    bounds(node.location)
    on_while(predicate, statements)
  else
    statements = visit(node.statements.body.first)
    bounds(node.keyword_loc)
    on_kw("while")
    predicate = visit(node.predicate)

    bounds(node.location)
    on_while_mod(predicate, statements)
  end
end

#visit_words_sep(opening_loc, previous, current) (private)

Dispatch words_sep events that contains the whitespace between the elements of list literals.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 895

private def visit_words_sep(opening_loc, previous, current)
  start_offset = (previous.nil? ? opening_loc : previous.location).end_offset
  end_offset = current.start_offset
  length = end_offset - start_offset

  if length > 0
    whitespace = source.byteslice(start_offset, length)
    current_offset = start_offset
    whitespace.each_line do |part|
      bounds(opening_loc.copy(start_offset: current_offset, length: part.bytesize))
      on_words_sep(part)
      current_offset += part.bytesize
    end
  end
end

#visit_write_value(node) (private)

Visit a node that represents a write value. This is used to handle the special case of an implicit array that is generated without brackets.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4167

def visit_write_value(node)
  if node.is_a?(ArrayNode) && node.opening_loc.nil?
    elements = node.elements
    length = elements.length

    bounds(elements.first.location)
    elements.each_with_index.inject((elements.first.is_a?(SplatNode) && length == 1) ? on_mrhs_new : on_args_new) do |args, (element, index)|
      arg = visit(element)
      bounds(element.location)

      if index == length - 1
        if element.is_a?(SplatNode)
          mrhs = index == 0 ? args : on_mrhs_new_from_args(args)
          on_mrhs_add_star(mrhs, arg)
        else
          on_mrhs_add(on_mrhs_new_from_args(args), arg)
        end
      else
        case element
        when BlockArgumentNode
          on_args_add_block(args, arg)
        when SplatNode
          on_args_add_star(args, arg)
        else
          on_args_add(args, arg)
        end
      end
    end
  else
    visit(node)
  end
end

#visit_x_string_node(node)

foo ^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4029

def visit_x_string_node(node)
  with_string_bounds(node) do
    if node.unescaped.empty?
      bounds(node.location)
      on_xstring_literal(on_xstring_new)
    elsif node.opening.start_with?("<<~")
      heredoc = visit_heredoc_x_string_node(node.to_interpolated)

      bounds(node.location)
      on_xstring_literal(heredoc)
    else
      bounds(node.content_loc)
      content = on_tstring_content(node.content)

      bounds(node.location)
      on_xstring_literal(on_xstring_add(on_xstring_new, content))
    end
  end
end

#visit_yield_node(node)

yield ^^^^^

yield 1 ^^^^^^^

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4054

def visit_yield_node(node)
  bounds(node.keyword_loc)
  on_kw("yield")

  if node.arguments.nil? && node.lparen_loc.nil?
    bounds(node.location)
    on_yield0
  else
    if node.lparen_loc
      bounds(node.lparen_loc)
      on_lparen("(")
    end

    arguments =
      if node.arguments.nil?
        bounds(node.location)
        on_args_new
      else
        visit(node.arguments)
      end

    unless node.lparen_loc.nil?
      bounds(node.rparen_loc)
      on_rparen(")")
      bounds(node.lparen_loc)
      arguments = on_paren(arguments)
    end

    bounds(node.location)
    on_yield(arguments)
  end
end

#void_stmt?(left, right, allow_newline) ⇒ Boolean (private)

Returns true if there is a semicolon between the two locations.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4108

def void_stmt?(left, right, allow_newline)
  pattern = allow_newline ? /[;\n]/ : /;/
  source.byteslice(left.end_offset...right.start_offset).match?(pattern)
end

#warn(fmt, *args) (private)

This method is called when weak warning is produced by the parser. fmt and args is printf style.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4232

def warn(fmt, *args)
end

#warning(fmt, *args) (private)

This method is called when strong warning is produced by the parser. fmt and args is printf style.

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 4237

def warning(fmt, *args)
end

#with_string_bounds(node) (private)

Responsible for emitting the various string-like begin/end events

[ GitHub ]

  
# File 'lib/prism/translation/ripper.rb', line 3673

private def with_string_bounds(node)
  # `foo "bar": baz` doesn't emit the closing location
  assoc = !(opening = node.opening)&.include?(":") && node.closing&.end_with?(":")

  is_heredoc = opening&.start_with?("<<")
  if is_heredoc
    bounds(node.opening_loc)
    on_heredoc_beg(node.opening)
  elsif opening&.start_with?(":", "%s")
    bounds(node.opening_loc)
    on_symbeg(node.opening)
  elsif opening&.start_with?("`", "%x")
    bounds(node.opening_loc)
    on_backtick(node.opening)
  elsif opening && !opening.start_with?("?")
    bounds(node.opening_loc)
    on_tstring_beg(opening)
  end

  result = yield
  if assoc
    if node.closing != ":"
      bounds(node.closing_loc)
      on_label_end(node.closing)
    end
    return result
  end

  if is_heredoc
    bounds(node.closing_loc)
    on_heredoc_end(node.closing)
  elsif node.closing_loc
    bounds(node.closing_loc)
    on_tstring_end(node.closing)
  end

  result
end