class SyntaxTree::Translation::Parser

This visitor is responsible for converting the syntax tree produced by Syntax Tree into the syntax tree produced by the whitequark/parser gem.

Attributes

buffer[R]
stack[R]

Public Class Methods

new(buffer) click to toggle source
# File lib/syntax_tree/translation/parser.rb, line 77
def initialize(buffer)
  @buffer = buffer
  @stack = []
end

Public Instance Methods

visit(node) click to toggle source

For each node that we visit, we keep track of it in a stack as we descend into its children. We do this so that child nodes can reflect on their parents if they need additional information about their context.

Calls superclass method SyntaxTree::BasicVisitor#visit
# File lib/syntax_tree/translation/parser.rb, line 85
def visit(node)
  stack << node
  result = super
  stack.pop
  result
end
visit_BEGIN(node) click to toggle source

Visit a BEGINBlock node.

# File lib/syntax_tree/translation/parser.rb, line 432
def visit_BEGIN(node)
  s(
    :preexe,
    [visit(node.statements)],
    smap_keyword(
      srange_length(node.start_char, 5),
      srange_find(node.start_char + 5, node.statements.start_char, "{"),
      srange_length(node.end_char, -1),
      srange_node(node)
    )
  )
end
visit_CHAR(node) click to toggle source

Visit a CHAR node.

# File lib/syntax_tree/translation/parser.rb, line 698
def visit_CHAR(node)
  s(
    :str,
    [node.value[1..]],
    smap_collection(
      srange_length(node.start_char, 1),
      nil,
      srange_node(node)
    )
  )
end
visit_END(node) click to toggle source

Visit an ENDBlock node.

# File lib/syntax_tree/translation/parser.rb, line 1085
def visit_END(node)
  s(
    :postexe,
    [visit(node.statements)],
    smap_keyword(
      srange_length(node.start_char, 3),
      srange_find(node.start_char + 3, node.statements.start_char, "{"),
      srange_length(node.end_char, -1),
      srange_node(node)
    )
  )
end
visit_alias(node) click to toggle source

Visit an AliasNode node.

# File lib/syntax_tree/translation/parser.rb, line 94
def visit_alias(node)
  s(
    :alias,
    [visit(node.left), visit(node.right)],
    smap_keyword_bare(
      srange_length(node.start_char, 5),
      srange_node(node)
    )
  )
end
visit_aref(node) click to toggle source

Visit an ARefNode.

# File lib/syntax_tree/translation/parser.rb, line 106
def visit_aref(node)
  if ::Parser::Builders::Default.emit_index
    if node.index.nil?
      s(
        :index,
        [visit(node.collection)],
        smap_index(
          srange_find(node.collection.end_char, node.end_char, "["),
          srange_length(node.end_char, -1),
          srange_node(node)
        )
      )
    else
      s(
        :index,
        [visit(node.collection)].concat(visit_all(node.index.parts)),
        smap_index(
          srange_find_between(node.collection, node.index, "["),
          srange_length(node.end_char, -1),
          srange_node(node)
        )
      )
    end
  else
    if node.index.nil?
      s(
        :send,
        [visit(node.collection), :[]],
        smap_send_bare(
          srange_find(node.collection.end_char, node.end_char, "[]"),
          srange_node(node)
        )
      )
    else
      s(
        :send,
        [visit(node.collection), :[], *visit_all(node.index.parts)],
        smap_send_bare(
          srange(
            srange_find_between(
              node.collection,
              node.index,
              "["
            ).begin_pos,
            node.end_char
          ),
          srange_node(node)
        )
      )
    end
  end
end
visit_aref_field(node) click to toggle source

Visit an ARefField node.

# File lib/syntax_tree/translation/parser.rb, line 160
def visit_aref_field(node)
  if ::Parser::Builders::Default.emit_index
    if node.index.nil?
      s(
        :indexasgn,
        [visit(node.collection)],
        smap_index(
          srange_find(node.collection.end_char, node.end_char, "["),
          srange_length(node.end_char, -1),
          srange_node(node)
        )
      )
    else
      s(
        :indexasgn,
        [visit(node.collection)].concat(visit_all(node.index.parts)),
        smap_index(
          srange_find_between(node.collection, node.index, "["),
          srange_length(node.end_char, -1),
          srange_node(node)
        )
      )
    end
  else
    if node.index.nil?
      s(
        :send,
        [visit(node.collection), :[]=],
        smap_send_bare(
          srange_find(node.collection.end_char, node.end_char, "[]"),
          srange_node(node)
        )
      )
    else
      s(
        :send,
        [visit(node.collection), :[]=].concat(
          visit_all(node.index.parts)
        ),
        smap_send_bare(
          srange(
            srange_find_between(
              node.collection,
              node.index,
              "["
            ).begin_pos,
            node.end_char
          ),
          srange_node(node)
        )
      )
    end
  end
end
visit_arg_block(node) click to toggle source

Visit an ArgBlock node.

# File lib/syntax_tree/translation/parser.rb, line 216
def visit_arg_block(node)
  s(
    :block_pass,
    [visit(node.value)],
    smap_operator(srange_length(node.start_char, 1), srange_node(node))
  )
end
visit_arg_star(node) click to toggle source

Visit an ArgStar node.

# File lib/syntax_tree/translation/parser.rb, line 225
def visit_arg_star(node)
  if stack[-3].is_a?(MLHSParen) && stack[-3].contents.is_a?(MLHS)
    if node.value.nil?
      s(:restarg, [], smap_variable(nil, srange_node(node)))
    else
      s(
        :restarg,
        [node.value.value.to_sym],
        smap_variable(srange_node(node.value), srange_node(node))
      )
    end
  else
    s(
      :splat,
      node.value.nil? ? [] : [visit(node.value)],
      smap_operator(
        srange_length(node.start_char, 1),
        srange_node(node)
      )
    )
  end
end
visit_args_forward(node) click to toggle source

Visit an ArgsForward node.

# File lib/syntax_tree/translation/parser.rb, line 249
def visit_args_forward(node)
  s(:forwarded_args, [], smap(srange_node(node)))
end
visit_array(node) click to toggle source

Visit an ArrayLiteral node.

# File lib/syntax_tree/translation/parser.rb, line 254
def visit_array(node)
  s(
    :array,
    node.contents ? visit_all(node.contents.parts) : [],
    if node.lbracket.nil?
      smap_collection_bare(srange_node(node))
    else
      smap_collection(
        srange_node(node.lbracket),
        srange_length(node.end_char, -1),
        srange_node(node)
      )
    end
  )
end
visit_aryptn(node) click to toggle source

Visit an AryPtn node.

# File lib/syntax_tree/translation/parser.rb, line 271
def visit_aryptn(node)
  type = :array_pattern
  children = visit_all(node.requireds)

  if node.rest.is_a?(VarField)
    if !node.rest.value.nil?
      children << s(:match_rest, [visit(node.rest)], nil)
    elsif node.posts.empty? &&
          node.rest.start_char == node.rest.end_char
      # Here we have an implicit rest, as in [foo,]. parser has a
      # specific type for these patterns.
      type = :array_pattern_with_tail
    else
      children << s(:match_rest, [], nil)
    end
  end

  if node.constant
    s(
      :const_pattern,
      [
        visit(node.constant),
        s(
          type,
          children + visit_all(node.posts),
          smap_collection_bare(
            srange(node.constant.end_char + 1, node.end_char - 1)
          )
        )
      ],
      smap_collection(
        srange_length(node.constant.end_char, 1),
        srange_length(node.end_char, -1),
        srange_node(node)
      )
    )
  else
    s(
      type,
      children + visit_all(node.posts),
      if buffer.source[node.start_char] == "["
        smap_collection(
          srange_length(node.start_char, 1),
          srange_length(node.end_char, -1),
          srange_node(node)
        )
      else
        smap_collection_bare(srange_node(node))
      end
    )
  end
end
visit_assign(node) click to toggle source

Visit an Assign node.

# File lib/syntax_tree/translation/parser.rb, line 325
def visit_assign(node)
  target = visit(node.target)
  location =
    target
      .location
      .with_operator(srange_find_between(node.target, node.value, "="))
      .with_expression(srange_node(node))

  s(target.type, target.children + [visit(node.value)], location)
end
visit_assoc(node) click to toggle source

Visit an Assoc node.

# File lib/syntax_tree/translation/parser.rb, line 337
def visit_assoc(node)
  if node.value.nil?
    # { foo: }
    expression = srange(node.start_char, node.end_char - 1)
    type, location =
      if node.key.value.start_with?(/[A-Z]/)
        [:const, smap_constant(nil, expression, expression)]
      else
        [:send, smap_send_bare(expression, expression)]
      end

    s(
      :pair,
      [
        visit(node.key),
        s(type, [nil, node.key.value.chomp(":").to_sym], location)
      ],
      smap_operator(
        srange_length(node.key.end_char, -1),
        srange_node(node)
      )
    )
  elsif node.key.is_a?(Label)
    # { foo: 1 }
    s(
      :pair,
      [visit(node.key), visit(node.value)],
      smap_operator(
        srange_length(node.key.end_char, -1),
        srange_node(node)
      )
    )
  elsif (operator = srange_search_between(node.key, node.value, "=>"))
    # { :foo => 1 }
    s(
      :pair,
      [visit(node.key), visit(node.value)],
      smap_operator(operator, srange_node(node))
    )
  else
    # { "foo": 1 }
    key = visit(node.key)
    key_location =
      smap_collection(
        key.location.begin,
        srange_length(node.key.end_char - 2, 1),
        srange(node.key.start_char, node.key.end_char - 1)
      )

    s(
      :pair,
      [s(key.type, key.children, key_location), visit(node.value)],
      smap_operator(
        srange_length(node.key.end_char, -1),
        srange_node(node)
      )
    )
  end
end
visit_assoc_splat(node) click to toggle source

Visit an AssocSplat node.

# File lib/syntax_tree/translation/parser.rb, line 398
def visit_assoc_splat(node)
  s(
    :kwsplat,
    [visit(node.value)],
    smap_operator(srange_length(node.start_char, 2), srange_node(node))
  )
end
visit_backref(node) click to toggle source

Visit a Backref node.

# File lib/syntax_tree/translation/parser.rb, line 407
def visit_backref(node)
  location = smap(srange_node(node))

  if node.value.match?(/^\$\d+$/)
    s(:nth_ref, [node.value[1..].to_i], location)
  else
    s(:back_ref, [node.value.to_sym], location)
  end
end
visit_bare_assoc_hash(node) click to toggle source

Visit a BareAssocHash node.

# File lib/syntax_tree/translation/parser.rb, line 418
def visit_bare_assoc_hash(node)
  s(
    if ::Parser::Builders::Default.emit_kwargs &&
         !stack[-2].is_a?(ArrayLiteral)
      :kwargs
    else
      :hash
    end,
    visit_all(node.assocs),
    smap_collection_bare(srange_node(node))
  )
end
visit_begin(node) click to toggle source

Visit a Begin node.

# File lib/syntax_tree/translation/parser.rb, line 446
def visit_begin(node)
  location =
    smap_collection(
      srange_length(node.start_char, 5),
      srange_length(node.end_char, -3),
      srange_node(node)
    )

  if node.bodystmt.empty?
    s(:kwbegin, [], location)
  elsif node.bodystmt.rescue_clause.nil? &&
        node.bodystmt.ensure_clause.nil? &&
        node.bodystmt.else_clause.nil?
    child = visit(node.bodystmt.statements)

    s(
      :kwbegin,
      child.type == :begin ? child.children : [child],
      location
    )
  else
    s(:kwbegin, [visit(node.bodystmt)], location)
  end
end
visit_binary(node) click to toggle source

Visit a Binary node.

# File lib/syntax_tree/translation/parser.rb, line 472
def visit_binary(node)
  case node.operator
  when :|
    current = -2
    while stack[current].is_a?(Binary) && stack[current].operator == :|
      current -= 1
    end

    if stack[current].is_a?(In)
      s(:match_alt, [visit(node.left), visit(node.right)], nil)
    else
      visit(canonical_binary(node))
    end
  when :"=>", :"&&", :and, :"||", :or
    s(
      { "=>": :match_as, "&&": :and, "||": :or }.fetch(
        node.operator,
        node.operator
      ),
      [visit(node.left), visit(node.right)],
      smap_operator(
        srange_find_between(node.left, node.right, node.operator.to_s),
        srange_node(node)
      )
    )
  when :=~
    # When you use a regular expression on the left hand side of a =~
    # operator and it doesn't have interpolatoin, then its named capture
    # groups introduce local variables into the scope. In this case the
    # parser gem has a different node (match_with_lvasgn) instead of the
    # regular send.
    if node.left.is_a?(RegexpLiteral) && node.left.parts.length == 1 &&
         node.left.parts.first.is_a?(TStringContent)
      s(
        :match_with_lvasgn,
        [visit(node.left), visit(node.right)],
        smap_operator(
          srange_find_between(
            node.left,
            node.right,
            node.operator.to_s
          ),
          srange_node(node)
        )
      )
    else
      visit(canonical_binary(node))
    end
  else
    visit(canonical_binary(node))
  end
end
visit_block_var(node) click to toggle source

Visit a BlockVar node.

# File lib/syntax_tree/translation/parser.rb, line 539
def visit_block_var(node)
  shadowargs =
    node.locals.map do |local|
      s(
        :shadowarg,
        [local.value.to_sym],
        smap_variable(srange_node(local), srange_node(local))
      )
    end

  params = node.params
  children =
    if ::Parser::Builders::Default.emit_procarg0 && node.arg0?
      # There is a special node type in the parser gem for when a single
      # required parameter to a block would potentially be expanded
      # automatically. We handle that case here.
      required = params.requireds.first
      procarg0 =
        if ::Parser::Builders::Default.emit_arg_inside_procarg0 &&
             required.is_a?(Ident)
          s(
            :procarg0,
            [
              s(
                :arg,
                [required.value.to_sym],
                smap_variable(
                  srange_node(required),
                  srange_node(required)
                )
              )
            ],
            smap_collection_bare(srange_node(required))
          )
        else
          child = visit(required)
          s(:procarg0, child, child.location)
        end

      [procarg0]
    else
      visit(params).children
    end

  s(
    :args,
    children + shadowargs,
    smap_collection(
      srange_length(node.start_char, 1),
      srange_length(node.end_char, -1),
      srange_node(node)
    )
  )
end
visit_blockarg(node) click to toggle source

Visit a BlockArg node.

# File lib/syntax_tree/translation/parser.rb, line 526
def visit_blockarg(node)
  if node.name.nil?
    s(:blockarg, [nil], smap_variable(nil, srange_node(node)))
  else
    s(
      :blockarg,
      [node.name.value.to_sym],
      smap_variable(srange_node(node.name), srange_node(node))
    )
  end
end
visit_bodystmt(node) click to toggle source

Visit a BodyStmt node.

# File lib/syntax_tree/translation/parser.rb, line 595
def visit_bodystmt(node)
  result = visit(node.statements)

  if node.rescue_clause
    rescue_node = visit(node.rescue_clause)

    children = [result] + rescue_node.children
    location = rescue_node.location

    if node.else_clause
      children.pop
      children << visit(node.else_clause)

      location =
        smap_condition(
          nil,
          nil,
          srange_length(node.else_clause.start_char - 3, -4),
          nil,
          srange(
            location.expression.begin_pos,
            node.else_clause.end_char
          )
        )
    end

    result = s(rescue_node.type, children, location)
  end

  if node.ensure_clause
    ensure_node = visit(node.ensure_clause)

    expression =
      (
        if result
          result.location.expression.join(
            ensure_node.location.expression
          )
        else
          ensure_node.location.expression
        end
      )
    location = ensure_node.location.with_expression(expression)

    result =
      s(ensure_node.type, [result] + ensure_node.children, location)
  end

  result
end
visit_break(node) click to toggle source

Visit a Break node.

# File lib/syntax_tree/translation/parser.rb, line 647
def visit_break(node)
  s(
    :break,
    visit_all(node.arguments.parts),
    smap_keyword_bare(
      srange_length(node.start_char, 5),
      srange_node(node)
    )
  )
end
visit_call(node) click to toggle source

Visit a CallNode node.

# File lib/syntax_tree/translation/parser.rb, line 659
def visit_call(node)
  visit_command_call(
    CommandCall.new(
      receiver: node.receiver,
      operator: node.operator,
      message: node.message,
      arguments: node.arguments,
      block: nil,
      location: node.location
    )
  )
end
visit_case(node) click to toggle source

Visit a Case node.

# File lib/syntax_tree/translation/parser.rb, line 673
def visit_case(node)
  clauses = [node.consequent]
  while clauses.last && !clauses.last.is_a?(Else)
    clauses << clauses.last.consequent
  end

  else_token =
    if clauses.last.is_a?(Else)
      srange_length(clauses.last.start_char, 4)
    end

  s(
    node.consequent.is_a?(In) ? :case_match : :case,
    [visit(node.value)] + clauses.map { |clause| visit(clause) },
    smap_condition(
      srange_length(node.start_char, 4),
      nil,
      else_token,
      srange_length(node.end_char, -3),
      srange_node(node)
    )
  )
end
visit_class(node) click to toggle source

Visit a ClassDeclaration node.

# File lib/syntax_tree/translation/parser.rb, line 711
def visit_class(node)
  operator =
    if node.superclass
      srange_find_between(node.constant, node.superclass, "<")
    end

  s(
    :class,
    [
      visit(node.constant),
      visit(node.superclass),
      visit(node.bodystmt)
    ],
    smap_definition(
      srange_length(node.start_char, 5),
      operator,
      srange_node(node.constant),
      srange_length(node.end_char, -3)
    ).with_expression(srange_node(node))
  )
end
visit_command(node) click to toggle source

Visit a Command node.

# File lib/syntax_tree/translation/parser.rb, line 734
def visit_command(node)
  visit_command_call(
    CommandCall.new(
      receiver: nil,
      operator: nil,
      message: node.message,
      arguments: node.arguments,
      block: node.block,
      location: node.location
    )
  )
end
visit_command_call(node) click to toggle source

Visit a CommandCall node.

# File lib/syntax_tree/translation/parser.rb, line 748
def visit_command_call(node)
  children = [
    visit(node.receiver),
    node.message == :call ? :call : node.message.value.to_sym
  ]

  begin_token = nil
  end_token = nil

  case node.arguments
  when Args
    children += visit_all(node.arguments.parts)
  when ArgParen
    case node.arguments.arguments
    when nil
      # skip
    when ArgsForward
      children << visit(node.arguments.arguments)
    else
      children += visit_all(node.arguments.arguments.parts)
    end

    begin_token = srange_length(node.arguments.start_char, 1)
    end_token = srange_length(node.arguments.end_char, -1)
  end

  dot_bound =
    if node.arguments
      node.arguments.start_char
    elsif node.block
      node.block.start_char
    else
      node.end_char
    end

  expression =
    if node.arguments.is_a?(ArgParen)
      srange(node.start_char, node.arguments.end_char)
    elsif node.arguments.is_a?(Args) && node.arguments.parts.any?
      last_part = node.arguments.parts.last
      end_char =
        if last_part.is_a?(Heredoc)
          last_part.beginning.end_char
        else
          last_part.end_char
        end

      srange(node.start_char, end_char)
    elsif node.block
      if node.receiver
        srange(node.receiver.start_char, node.message.end_char)
      else
        srange_node(node.message)
      end
    else
      srange_node(node)
    end

  call =
    s(
      if node.operator.is_a?(Op) && node.operator.value == "&."
        :csend
      else
        :send
      end,
      children,
      smap_send(
        if node.operator == :"::"
          srange_find(
            node.receiver.end_char,
            if node.message == :call
              dot_bound
            else
              node.message.start_char
            end,
            "::"
          )
        elsif node.operator
          srange_node(node.operator)
        end,
        node.message == :call ? nil : srange_node(node.message),
        begin_token,
        end_token,
        expression
      )
    )

  if node.block
    type, arguments = block_children(node.block)

    s(
      type,
      [call, arguments, visit(node.block.bodystmt)],
      smap_collection(
        srange_node(node.block.opening),
        srange_length(
          node.end_char,
          node.block.opening.is_a?(Kw) ? -3 : -1
        ),
        srange_node(node)
      )
    )
  else
    call
  end
end
visit_const(node) click to toggle source

Visit a Const node.

# File lib/syntax_tree/translation/parser.rb, line 856
def visit_const(node)
  s(
    :const,
    [nil, node.value.to_sym],
    smap_constant(nil, srange_node(node), srange_node(node))
  )
end
visit_const_path_field(node) click to toggle source

Visit a ConstPathField node.

# File lib/syntax_tree/translation/parser.rb, line 865
def visit_const_path_field(node)
  if node.parent.is_a?(VarRef) && node.parent.value.is_a?(Kw) &&
       node.parent.value.value == "self" && node.constant.is_a?(Ident)
    s(:send, [visit(node.parent), :"#{node.constant.value}="], nil)
  else
    s(
      :casgn,
      [visit(node.parent), node.constant.value.to_sym],
      smap_constant(
        srange_find_between(node.parent, node.constant, "::"),
        srange_node(node.constant),
        srange_node(node)
      )
    )
  end
end
visit_const_path_ref(node) click to toggle source

Visit a ConstPathRef node.

# File lib/syntax_tree/translation/parser.rb, line 883
def visit_const_path_ref(node)
  s(
    :const,
    [visit(node.parent), node.constant.value.to_sym],
    smap_constant(
      srange_find_between(node.parent, node.constant, "::"),
      srange_node(node.constant),
      srange_node(node)
    )
  )
end
visit_const_ref(node) click to toggle source

Visit a ConstRef node.

# File lib/syntax_tree/translation/parser.rb, line 896
def visit_const_ref(node)
  s(
    :const,
    [nil, node.constant.value.to_sym],
    smap_constant(nil, srange_node(node.constant), srange_node(node))
  )
end
visit_cvar(node) click to toggle source

Visit a CVar node.

# File lib/syntax_tree/translation/parser.rb, line 905
def visit_cvar(node)
  s(
    :cvar,
    [node.value.to_sym],
    smap_variable(srange_node(node), srange_node(node))
  )
end
visit_def(node) click to toggle source

Visit a DefNode node.

# File lib/syntax_tree/translation/parser.rb, line 914
def visit_def(node)
  name = node.name.value.to_sym
  args =
    case node.params
    when Params
      child = visit(node.params)

      s(
        child.type,
        child.children,
        smap_collection_bare(child.location&.expression)
      )
    when Paren
      child = visit(node.params.contents)

      s(
        child.type,
        child.children,
        smap_collection(
          srange_length(node.params.start_char, 1),
          srange_length(node.params.end_char, -1),
          srange_node(node.params)
        )
      )
    else
      s(:args, [], smap_collection_bare(nil))
    end

  location =
    if node.endless?
      smap_method_definition(
        srange_length(node.start_char, 3),
        nil,
        srange_node(node.name),
        nil,
        srange_find_between(
          (node.params || node.name),
          node.bodystmt,
          "="
        ),
        srange_node(node)
      )
    else
      smap_method_definition(
        srange_length(node.start_char, 3),
        nil,
        srange_node(node.name),
        srange_length(node.end_char, -3),
        nil,
        srange_node(node)
      )
    end

  if node.target
    target =
      node.target.is_a?(Paren) ? node.target.contents : node.target

    s(
      :defs,
      [visit(target), name, args, visit(node.bodystmt)],
      smap_method_definition(
        location.keyword,
        srange_node(node.operator),
        location.name,
        location.end,
        location.assignment,
        location.expression
      )
    )
  else
    s(:def, [name, args, visit(node.bodystmt)], location)
  end
end
visit_defined(node) click to toggle source

Visit a Defined node.

# File lib/syntax_tree/translation/parser.rb, line 989
def visit_defined(node)
  paren_range = (node.start_char + 8)...node.end_char
  begin_token, end_token =
    if buffer.source[paren_range].include?("(")
      [
        srange_find(paren_range.begin, paren_range.end, "("),
        srange_length(node.end_char, -1)
      ]
    end

  s(
    :defined?,
    [visit(node.value)],
    smap_keyword(
      srange_length(node.start_char, 8),
      begin_token,
      end_token,
      srange_node(node)
    )
  )
end
visit_dyna_symbol(node) click to toggle source

Visit a DynaSymbol node.

# File lib/syntax_tree/translation/parser.rb, line 1012
def visit_dyna_symbol(node)
  location =
    if node.quote
      smap_collection(
        srange_length(node.start_char, node.quote.length),
        srange_length(node.end_char, -1),
        srange_node(node)
      )
    else
      smap_collection_bare(srange_node(node))
    end

  if node.parts.length == 1 && node.parts.first.is_a?(TStringContent)
    s(:sym, ["\"#{node.parts.first.value}\"".undump.to_sym], location)
  else
    s(:dsym, visit_all(node.parts), location)
  end
end
visit_else(node) click to toggle source

Visit an Else node.

# File lib/syntax_tree/translation/parser.rb, line 1032
def visit_else(node)
  if node.statements.empty? && stack[-2].is_a?(Case)
    s(:empty_else, [], nil)
  else
    visit(node.statements)
  end
end
visit_elsif(node) click to toggle source

Visit an Elsif node.

# File lib/syntax_tree/translation/parser.rb, line 1041
def visit_elsif(node)
  begin_start = node.predicate.end_char
  begin_end =
    if node.statements.empty?
      node.statements.end_char
    else
      node.statements.body.first.start_char
    end

  begin_token =
    if buffer.source[begin_start...begin_end].include?("then")
      srange_find(begin_start, begin_end, "then")
    elsif buffer.source[begin_start...begin_end].include?(";")
      srange_find(begin_start, begin_end, ";")
    end

  else_token =
    case node.consequent
    when Elsif
      srange_length(node.consequent.start_char, 5)
    when Else
      srange_length(node.consequent.start_char, 4)
    end

  expression = srange(node.start_char, node.statements.end_char - 1)

  s(
    :if,
    [
      visit(node.predicate),
      visit(node.statements),
      visit(node.consequent)
    ],
    smap_condition(
      srange_length(node.start_char, 5),
      begin_token,
      else_token,
      nil,
      expression
    )
  )
end
visit_ensure(node) click to toggle source

Visit an Ensure node.

# File lib/syntax_tree/translation/parser.rb, line 1099
def visit_ensure(node)
  start_char = node.start_char
  end_char =
    if node.statements.empty?
      start_char + 6
    else
      node.statements.body.last.end_char
    end

  s(
    :ensure,
    [visit(node.statements)],
    smap_condition(
      srange_length(start_char, 6),
      nil,
      nil,
      nil,
      srange(start_char, end_char)
    )
  )
end
visit_field(node) click to toggle source

Visit a Field node.

# File lib/syntax_tree/translation/parser.rb, line 1122
def visit_field(node)
  message =
    case stack[-2]
    when Assign, MLHS
      Ident.new(
        value: "#{node.name.value}=",
        location: node.name.location
      )
    else
      node.name
    end

  visit_command_call(
    CommandCall.new(
      receiver: node.parent,
      operator: node.operator,
      message: message,
      arguments: nil,
      block: nil,
      location: node.location
    )
  )
end
visit_float(node) click to toggle source

Visit a FloatLiteral node.

# File lib/syntax_tree/translation/parser.rb, line 1147
def visit_float(node)
  operator =
    if %w[+ -].include?(buffer.source[node.start_char])
      srange_length(node.start_char, 1)
    end

  s(
    :float,
    [node.value.to_f],
    smap_operator(operator, srange_node(node))
  )
end
visit_fndptn(node) click to toggle source

Visit a FndPtn node.

# File lib/syntax_tree/translation/parser.rb, line 1161
def visit_fndptn(node)
  left, right =
    [node.left, node.right].map do |child|
      location =
        smap_operator(
          srange_length(child.start_char, 1),
          srange_node(child)
        )

      if child.is_a?(VarField) && child.value.nil?
        s(:match_rest, [], location)
      else
        s(:match_rest, [visit(child)], location)
      end
    end

  inner =
    s(
      :find_pattern,
      [left, *visit_all(node.values), right],
      smap_collection(
        srange_length(node.start_char, 1),
        srange_length(node.end_char, -1),
        srange_node(node)
      )
    )

  if node.constant
    s(:const_pattern, [visit(node.constant), inner], nil)
  else
    inner
  end
end
visit_for(node) click to toggle source

Visit a For node.

# File lib/syntax_tree/translation/parser.rb, line 1196
def visit_for(node)
  s(
    :for,
    [visit(node.index), visit(node.collection), visit(node.statements)],
    smap_for(
      srange_length(node.start_char, 3),
      srange_find_between(node.index, node.collection, "in"),
      srange_search_between(node.collection, node.statements, "do") ||
        srange_search_between(node.collection, node.statements, ";"),
      srange_length(node.end_char, -3),
      srange_node(node)
    )
  )
end
visit_gvar(node) click to toggle source

Visit a GVar node.

# File lib/syntax_tree/translation/parser.rb, line 1212
def visit_gvar(node)
  s(
    :gvar,
    [node.value.to_sym],
    smap_variable(srange_node(node), srange_node(node))
  )
end
visit_hash(node) click to toggle source

Visit a HashLiteral node.

# File lib/syntax_tree/translation/parser.rb, line 1221
def visit_hash(node)
  s(
    :hash,
    visit_all(node.assocs),
    smap_collection(
      srange_length(node.start_char, 1),
      srange_length(node.end_char, -1),
      srange_node(node)
    )
  )
end
visit_heredoc(node) click to toggle source

Visit a Heredoc node.

# File lib/syntax_tree/translation/parser.rb, line 1234
def visit_heredoc(node)
  heredoc = HeredocBuilder.new(node)

  # For each part of the heredoc, if it's a string content node, split
  # it into multiple string content nodes, one for each line. Otherwise,
  # visit the node as normal.
  node.parts.each do |part|
    if part.is_a?(TStringContent) && part.value.count("\n") > 1
      index = part.start_char
      lines = part.value.split("\n")

      lines.each do |line|
        length = line.length + 1
        location = smap_collection_bare(srange_length(index, length))

        heredoc << s(:str, ["#{line}\n"], location)
        index += length
      end
    else
      heredoc << visit(part)
    end
  end

  # Now that we have all of the pieces on the heredoc, we can trim it if
  # it is a heredoc that supports trimming (i.e., it has a ~ on the
  # declaration).
  heredoc.trim!

  # Generate the location for the heredoc, which goes from the
  # declaration to the ending delimiter.
  location =
    smap_heredoc(
      srange_node(node.beginning),
      srange(
        if node.parts.empty?
          node.beginning.end_char + 1
        else
          node.parts.first.start_char
        end,
        node.ending.start_char
      ),
      srange(node.ending.start_char, node.ending.end_char - 1)
    )

  # Finally, decide which kind of heredoc node to generate based on its
  # declaration and contents.
  if node.beginning.value.match?(/`\w+`\z/)
    s(:xstr, heredoc.segments, location)
  elsif heredoc.segments.length == 1
    segment = heredoc.segments.first
    s(segment.type, segment.children, location)
  else
    s(:dstr, heredoc.segments, location)
  end
end
visit_hshptn(node) click to toggle source

Visit a HshPtn node.

# File lib/syntax_tree/translation/parser.rb, line 1291
def visit_hshptn(node)
  children =
    node.keywords.map do |(keyword, value)|
      next s(:pair, [visit(keyword), visit(value)], nil) if value

      case keyword
      when DynaSymbol
        raise if keyword.parts.length > 1
        s(:match_var, [keyword.parts.first.value.to_sym], nil)
      when Label
        s(:match_var, [keyword.value.chomp(":").to_sym], nil)
      end
    end

  if node.keyword_rest.is_a?(VarField)
    children << if node.keyword_rest.value.nil?
      s(:match_rest, [], nil)
    elsif node.keyword_rest.value == :nil
      s(:match_nil_pattern, [], nil)
    else
      s(:match_rest, [visit(node.keyword_rest)], nil)
    end
  end

  inner = s(:hash_pattern, children, nil)
  if node.constant
    s(:const_pattern, [visit(node.constant), inner], nil)
  else
    inner
  end
end
visit_ident(node) click to toggle source

Visit an Ident node.

# File lib/syntax_tree/translation/parser.rb, line 1324
def visit_ident(node)
  s(
    :lvar,
    [node.value.to_sym],
    smap_variable(srange_node(node), srange_node(node))
  )
end
visit_if(node) click to toggle source

Visit an IfNode node.

# File lib/syntax_tree/translation/parser.rb, line 1333
def visit_if(node)
  s(
    :if,
    [
      visit_predicate(node.predicate),
      visit(node.statements),
      visit(node.consequent)
    ],
    if node.modifier?
      smap_keyword_bare(
        srange_find_between(node.statements, node.predicate, "if"),
        srange_node(node)
      )
    else
      begin_start = node.predicate.end_char
      begin_end =
        if node.statements.empty?
          node.statements.end_char
        else
          node.statements.body.first.start_char
        end

      begin_token =
        if buffer.source[begin_start...begin_end].include?("then")
          srange_find(begin_start, begin_end, "then")
        elsif buffer.source[begin_start...begin_end].include?(";")
          srange_find(begin_start, begin_end, ";")
        end

      else_token =
        case node.consequent
        when Elsif
          srange_length(node.consequent.start_char, 5)
        when Else
          srange_length(node.consequent.start_char, 4)
        end

      smap_condition(
        srange_length(node.start_char, 2),
        begin_token,
        else_token,
        srange_length(node.end_char, -3),
        srange_node(node)
      )
    end
  )
end
visit_if_op(node) click to toggle source

Visit an IfOp node.

# File lib/syntax_tree/translation/parser.rb, line 1382
def visit_if_op(node)
  s(
    :if,
    [visit(node.predicate), visit(node.truthy), visit(node.falsy)],
    smap_ternary(
      srange_find_between(node.predicate, node.truthy, "?"),
      srange_find_between(node.truthy, node.falsy, ":"),
      srange_node(node)
    )
  )
end
visit_imaginary(node) click to toggle source

Visit an Imaginary node.

# File lib/syntax_tree/translation/parser.rb, line 1395
def visit_imaginary(node)
  s(
    :complex,
    [
      # We have to do an eval here in order to get the value in case
      # it's something like 42ri. to_c will not give the right value in
      # that case. Maybe there's an API for this but I can't find it.
      eval(node.value)
    ],
    smap_operator(nil, srange_node(node))
  )
end
visit_in(node) click to toggle source

Visit an In node.

# File lib/syntax_tree/translation/parser.rb, line 1409
def visit_in(node)
  case node.pattern
  when IfNode
    s(
      :in_pattern,
      [
        visit(node.pattern.statements),
        s(:if_guard, [visit(node.pattern.predicate)], nil),
        visit(node.statements)
      ],
      nil
    )
  when UnlessNode
    s(
      :in_pattern,
      [
        visit(node.pattern.statements),
        s(:unless_guard, [visit(node.pattern.predicate)], nil),
        visit(node.statements)
      ],
      nil
    )
  else
    begin_token =
      srange_search_between(node.pattern, node.statements, "then")

    end_char =
      if begin_token || node.statements.empty?
        node.statements.end_char - 1
      else
        node.statements.body.last.start_char
      end

    s(
      :in_pattern,
      [visit(node.pattern), nil, visit(node.statements)],
      smap_keyword(
        srange_length(node.start_char, 2),
        begin_token,
        nil,
        srange(node.start_char, end_char)
      )
    )
  end
end
visit_int(node) click to toggle source

Visit an Int node.

# File lib/syntax_tree/translation/parser.rb, line 1456
def visit_int(node)
  operator =
    if %w[+ -].include?(buffer.source[node.start_char])
      srange_length(node.start_char, 1)
    end

  s(:int, [node.value.to_i], smap_operator(operator, srange_node(node)))
end
visit_ivar(node) click to toggle source

Visit an IVar node.

# File lib/syntax_tree/translation/parser.rb, line 1466
def visit_ivar(node)
  s(
    :ivar,
    [node.value.to_sym],
    smap_variable(srange_node(node), srange_node(node))
  )
end
visit_kw(node) click to toggle source

Visit a Kw node.

# File lib/syntax_tree/translation/parser.rb, line 1475
def visit_kw(node)
  location = smap(srange_node(node))

  case node.value
  when "__FILE__"
    s(:str, [buffer.name], location)
  when "__LINE__"
    s(
      :int,
      [node.location.start_line + buffer.first_line - 1],
      location
    )
  when "__ENCODING__"
    if ::Parser::Builders::Default.emit_encoding
      s(:__ENCODING__, [], location)
    else
      s(:const, [s(:const, [nil, :Encoding], nil), :UTF_8], location)
    end
  else
    s(node.value.to_sym, [], location)
  end
end
visit_kwrest_param(node) click to toggle source

Visit a KwRestParam node.

# File lib/syntax_tree/translation/parser.rb, line 1499
def visit_kwrest_param(node)
  if node.name.nil?
    s(:kwrestarg, [], smap_variable(nil, srange_node(node)))
  else
    s(
      :kwrestarg,
      [node.name.value.to_sym],
      smap_variable(srange_node(node.name), srange_node(node))
    )
  end
end
visit_label(node) click to toggle source

Visit a Label node.

# File lib/syntax_tree/translation/parser.rb, line 1512
def visit_label(node)
  s(
    :sym,
    [node.value.chomp(":").to_sym],
    smap_collection_bare(srange(node.start_char, node.end_char - 1))
  )
end
visit_lambda(node) click to toggle source

Visit a Lambda node.

# File lib/syntax_tree/translation/parser.rb, line 1521
def visit_lambda(node)
  args =
    node.params.is_a?(LambdaVar) ? node.params : node.params.contents
  args_node = visit(args)

  type = :block
  if args.empty? && (maximum = num_block_type(node.statements))
    type = :numblock
    args_node = maximum
  end

  begin_token, end_token =
    if (
         srange =
           srange_search_between(node.params, node.statements, "{")
       )
      [srange, srange_length(node.end_char, -1)]
    else
      [
        srange_find_between(node.params, node.statements, "do"),
        srange_length(node.end_char, -3)
      ]
    end

  selector = srange_length(node.start_char, 2)

  s(
    type,
    [
      if ::Parser::Builders::Default.emit_lambda
        s(:lambda, [], smap(selector))
      else
        s(:send, [nil, :lambda], smap_send_bare(selector, selector))
      end,
      args_node,
      visit(node.statements)
    ],
    smap_collection(begin_token, end_token, srange_node(node))
  )
end
visit_lambda_var(node) click to toggle source

Visit a LambdaVar node.

# File lib/syntax_tree/translation/parser.rb, line 1563
def visit_lambda_var(node)
  shadowargs =
    node.locals.map do |local|
      s(
        :shadowarg,
        [local.value.to_sym],
        smap_variable(srange_node(local), srange_node(local))
      )
    end

  location =
    if node.start_char == node.end_char
      smap_collection_bare(nil)
    elsif buffer.source[node.start_char - 1] == "("
      smap_collection(
        srange_length(node.start_char, 1),
        srange_length(node.end_char, -1),
        srange_node(node)
      )
    else
      smap_collection_bare(srange_node(node))
    end

  s(:args, visit(node.params).children + shadowargs, location)
end
visit_massign(node) click to toggle source

Visit an MAssign node.

# File lib/syntax_tree/translation/parser.rb, line 1590
def visit_massign(node)
  s(
    :masgn,
    [visit(node.target), visit(node.value)],
    smap_operator(
      srange_find_between(node.target, node.value, "="),
      srange_node(node)
    )
  )
end
visit_method_add_block(node) click to toggle source

Visit a MethodAddBlock node.

# File lib/syntax_tree/translation/parser.rb, line 1602
def visit_method_add_block(node)
  case node.call
  when ARef, Super, ZSuper
    type, arguments = block_children(node.block)

    s(
      type,
      [visit(node.call), arguments, visit(node.block.bodystmt)],
      smap_collection(
        srange_node(node.block.opening),
        srange_length(
          node.block.end_char,
          node.block.keywords? ? -3 : -1
        ),
        srange_node(node)
      )
    )
  else
    visit_command_call(
      CommandCall.new(
        receiver: node.call.receiver,
        operator: node.call.operator,
        message: node.call.message,
        arguments: node.call.arguments,
        block: node.block,
        location: node.location
      )
    )
  end
end
visit_mlhs(node) click to toggle source

Visit an MLHS node.

# File lib/syntax_tree/translation/parser.rb, line 1634
def visit_mlhs(node)
  s(
    :mlhs,
    node.parts.map do |part|
      if part.is_a?(Ident)
        s(
          :arg,
          [part.value.to_sym],
          smap_variable(srange_node(part), srange_node(part))
        )
      else
        visit(part)
      end
    end,
    smap_collection_bare(srange_node(node))
  )
end
visit_mlhs_paren(node) click to toggle source

Visit an MLHSParen node.

# File lib/syntax_tree/translation/parser.rb, line 1653
def visit_mlhs_paren(node)
  child = visit(node.contents)

  s(
    child.type,
    child.children,
    smap_collection(
      srange_length(node.start_char, 1),
      srange_length(node.end_char, -1),
      srange_node(node)
    )
  )
end
visit_module(node) click to toggle source

Visit a ModuleDeclaration node.

# File lib/syntax_tree/translation/parser.rb, line 1668
def visit_module(node)
  s(
    :module,
    [visit(node.constant), visit(node.bodystmt)],
    smap_definition(
      srange_length(node.start_char, 6),
      nil,
      srange_node(node.constant),
      srange_length(node.end_char, -3)
    ).with_expression(srange_node(node))
  )
end
visit_mrhs(node) click to toggle source

Visit an MRHS node.

# File lib/syntax_tree/translation/parser.rb, line 1682
def visit_mrhs(node)
  visit_array(
    ArrayLiteral.new(
      lbracket: nil,
      contents: Args.new(parts: node.parts, location: node.location),
      location: node.location
    )
  )
end
visit_next(node) click to toggle source

Visit a Next node.

# File lib/syntax_tree/translation/parser.rb, line 1693
def visit_next(node)
  s(
    :next,
    visit_all(node.arguments.parts),
    smap_keyword_bare(
      srange_length(node.start_char, 4),
      srange_node(node)
    )
  )
end
visit_not(node) click to toggle source

Visit a Not node.

# File lib/syntax_tree/translation/parser.rb, line 1705
def visit_not(node)
  if node.statement.nil?
    begin_token = srange_find(node.start_char, nil, "(")
    end_token = srange_find(node.start_char, nil, ")")

    s(
      :send,
      [
        s(
          :begin,
          [],
          smap_collection(
            begin_token,
            end_token,
            begin_token.join(end_token)
          )
        ),
        :!
      ],
      smap_send_bare(
        srange_length(node.start_char, 3),
        srange_node(node)
      )
    )
  else
    begin_token, end_token =
      if node.parentheses?
        [
          srange_find(
            node.start_char + 3,
            node.statement.start_char,
            "("
          ),
          srange_length(node.end_char, -1)
        ]
      end

    s(
      :send,
      [visit(node.statement), :!],
      smap_send(
        nil,
        srange_length(node.start_char, 3),
        begin_token,
        end_token,
        srange_node(node)
      )
    )
  end
end
visit_opassign(node) click to toggle source

Visit an OpAssign node.

# File lib/syntax_tree/translation/parser.rb, line 1757
def visit_opassign(node)
  target = visit(node.target)
  location =
    target
      .location
      .with_expression(srange_node(node))
      .with_operator(srange_node(node.operator))

  case node.operator.value
  when "||="
    s(:or_asgn, [target, visit(node.value)], location)
  when "&&="
    s(:and_asgn, [target, visit(node.value)], location)
  else
    s(
      :op_asgn,
      [
        target,
        node.operator.value.chomp("=").to_sym,
        visit(node.value)
      ],
      location
    )
  end
end
visit_params(node) click to toggle source

Visit a Params node.

# File lib/syntax_tree/translation/parser.rb, line 1784
def visit_params(node)
  children = []

  children +=
    node.requireds.map do |required|
      case required
      when MLHSParen
        visit(required)
      else
        s(
          :arg,
          [required.value.to_sym],
          smap_variable(srange_node(required), srange_node(required))
        )
      end
    end

  children +=
    node.optionals.map do |(name, value)|
      s(
        :optarg,
        [name.value.to_sym, visit(value)],
        smap_variable(
          srange_node(name),
          srange_node(name).join(srange_node(value))
        ).with_operator(srange_find_between(name, value, "="))
      )
    end

  if node.rest && !node.rest.is_a?(ExcessedComma)
    children << visit(node.rest)
  end

  children +=
    node.posts.map do |post|
      s(
        :arg,
        [post.value.to_sym],
        smap_variable(srange_node(post), srange_node(post))
      )
    end

  children +=
    node.keywords.map do |(name, value)|
      key = name.value.chomp(":").to_sym

      if value
        s(
          :kwoptarg,
          [key, visit(value)],
          smap_variable(
            srange(name.start_char, name.end_char - 1),
            srange_node(name).join(srange_node(value))
          )
        )
      else
        s(
          :kwarg,
          [key],
          smap_variable(
            srange(name.start_char, name.end_char - 1),
            srange_node(name)
          )
        )
      end
    end

  case node.keyword_rest
  when nil, ArgsForward
    # do nothing
  when :nil
    children << s(
      :kwnilarg,
      [],
      smap_variable(srange_length(node.end_char, -3), srange_node(node))
    )
  else
    children << visit(node.keyword_rest)
  end

  children << visit(node.block) if node.block

  if node.keyword_rest.is_a?(ArgsForward)
    location = smap(srange_node(node.keyword_rest))

    # If there are no other arguments and we have the emit_forward_arg
    # option enabled, then the entire argument list is represented by a
    # single forward_args node.
    if children.empty? && !::Parser::Builders::Default.emit_forward_arg
      return s(:forward_args, [], location)
    end

    # Otherwise, we need to insert a forward_arg node into the list of
    # parameters before any keyword rest or block parameters.
    index =
      node.requireds.length + node.optionals.length +
        node.keywords.length
    children.insert(index, s(:forward_arg, [], location))
  end

  location =
    unless children.empty?
      first = children.first.location.expression
      last = children.last.location.expression
      smap_collection_bare(first.join(last))
    end

  s(:args, children, location)
end
visit_paren(node) click to toggle source

Visit a Paren node.

# File lib/syntax_tree/translation/parser.rb, line 1895
def visit_paren(node)
  location =
    smap_collection(
      srange_length(node.start_char, 1),
      srange_length(node.end_char, -1),
      srange_node(node)
    )

  if node.contents.nil? ||
       (node.contents.is_a?(Statements) && node.contents.empty?)
    s(:begin, [], location)
  else
    child = visit(node.contents)
    child.type == :begin ? child : s(:begin, [child], location)
  end
end
visit_pinned_begin(node) click to toggle source

Visit a PinnedBegin node.

# File lib/syntax_tree/translation/parser.rb, line 1913
def visit_pinned_begin(node)
  s(
    :pin,
    [
      s(
        :begin,
        [visit(node.statement)],
        smap_collection(
          srange_length(node.start_char + 1, 1),
          srange_length(node.end_char, -1),
          srange(node.start_char + 1, node.end_char)
        )
      )
    ],
    smap_send_bare(srange_length(node.start_char, 1), srange_node(node))
  )
end
visit_pinned_var_ref(node) click to toggle source

Visit a PinnedVarRef node.

# File lib/syntax_tree/translation/parser.rb, line 1932
def visit_pinned_var_ref(node)
  s(
    :pin,
    [visit(node.value)],
    smap_send_bare(srange_length(node.start_char, 1), srange_node(node))
  )
end
visit_program(node) click to toggle source

Visit a Program node.

# File lib/syntax_tree/translation/parser.rb, line 1941
def visit_program(node)
  visit(node.statements)
end
visit_qsymbols(node) click to toggle source

Visit a QSymbols node.

# File lib/syntax_tree/translation/parser.rb, line 1946
def visit_qsymbols(node)
  parts =
    node.elements.map do |element|
      SymbolLiteral.new(value: element, location: element.location)
    end

  visit_array(
    ArrayLiteral.new(
      lbracket: node.beginning,
      contents: Args.new(parts: parts, location: node.location),
      location: node.location
    )
  )
end
visit_qwords(node) click to toggle source

Visit a QWords node.

# File lib/syntax_tree/translation/parser.rb, line 1962
def visit_qwords(node)
  visit_array(
    ArrayLiteral.new(
      lbracket: node.beginning,
      contents: Args.new(parts: node.elements, location: node.location),
      location: node.location
    )
  )
end
visit_range(node) click to toggle source

Visit a RangeNode node.

# File lib/syntax_tree/translation/parser.rb, line 1973
def visit_range(node)
  s(
    node.operator.value == ".." ? :irange : :erange,
    [visit(node.left), visit(node.right)],
    smap_operator(srange_node(node.operator), srange_node(node))
  )
end
visit_rassign(node) click to toggle source

Visit an RAssign node.

# File lib/syntax_tree/translation/parser.rb, line 1982
def visit_rassign(node)
  s(
    node.operator.value == "=>" ? :match_pattern : :match_pattern_p,
    [visit(node.value), visit(node.pattern)],
    smap_operator(srange_node(node.operator), srange_node(node))
  )
end
visit_rational(node) click to toggle source

Visit a Rational node.

# File lib/syntax_tree/translation/parser.rb, line 1991
def visit_rational(node)
  s(:rational, [node.value.to_r], smap_operator(nil, srange_node(node)))
end
visit_redo(node) click to toggle source

Visit a Redo node.

# File lib/syntax_tree/translation/parser.rb, line 1996
def visit_redo(node)
  s(:redo, [], smap_keyword_bare(srange_node(node), srange_node(node)))
end
visit_regexp_literal(node) click to toggle source

Visit a RegexpLiteral node.

# File lib/syntax_tree/translation/parser.rb, line 2001
def visit_regexp_literal(node)
  s(
    :regexp,
    visit_all(node.parts).push(
      s(
        :regopt,
        node.ending.scan(/[a-z]/).sort.map(&:to_sym),
        smap(srange_length(node.end_char, -(node.ending.length - 1)))
      )
    ),
    smap_collection(
      srange_length(node.start_char, node.beginning.length),
      srange_length(node.end_char - node.ending.length, 1),
      srange_node(node)
    )
  )
end
visit_rescue(node) click to toggle source

Visit a Rescue node.

# File lib/syntax_tree/translation/parser.rb, line 2020
def visit_rescue(node)
  # In the parser gem, there is a separation between the rescue node and
  # the rescue body. They have different bounds, so we have to calculate
  # those here.
  start_char = node.start_char

  body_end_char =
    if node.statements.empty?
      start_char + 6
    else
      node.statements.body.last.end_char
    end

  end_char =
    if node.consequent
      end_node = node.consequent
      end_node = end_node.consequent while end_node.consequent

      if end_node.statements.empty?
        start_char + 6
      else
        end_node.statements.body.last.end_char
      end
    else
      body_end_char
    end

  # These locations are reused for multiple children.
  keyword = srange_length(start_char, 6)
  body_expression = srange(start_char, body_end_char)
  expression = srange(start_char, end_char)

  exceptions =
    case node.exception&.exceptions
    when nil
      nil
    when MRHS
      visit_array(
        ArrayLiteral.new(
          lbracket: nil,
          contents:
            Args.new(
              parts: node.exception.exceptions.parts,
              location: node.exception.exceptions.location
            ),
          location: node.exception.exceptions.location
        )
      )
    else
      visit_array(
        ArrayLiteral.new(
          lbracket: nil,
          contents:
            Args.new(
              parts: [node.exception.exceptions],
              location: node.exception.exceptions.location
            ),
          location: node.exception.exceptions.location
        )
      )
    end

  resbody =
    if node.exception.nil?
      s(
        :resbody,
        [nil, nil, visit(node.statements)],
        smap_rescue_body(keyword, nil, nil, body_expression)
      )
    elsif node.exception.variable.nil?
      s(
        :resbody,
        [exceptions, nil, visit(node.statements)],
        smap_rescue_body(keyword, nil, nil, body_expression)
      )
    else
      s(
        :resbody,
        [
          exceptions,
          visit(node.exception.variable),
          visit(node.statements)
        ],
        smap_rescue_body(
          keyword,
          srange_find(
            node.start_char + 6,
            node.exception.variable.start_char,
            "=>"
          ),
          nil,
          body_expression
        )
      )
    end

  children = [resbody]
  if node.consequent
    children += visit(node.consequent).children
  else
    children << nil
  end

  s(:rescue, children, smap_condition_bare(expression))
end
visit_rescue_mod(node) click to toggle source

Visit a RescueMod node.

# File lib/syntax_tree/translation/parser.rb, line 2127
def visit_rescue_mod(node)
  keyword = srange_find_between(node.statement, node.value, "rescue")

  s(
    :rescue,
    [
      visit(node.statement),
      s(
        :resbody,
        [nil, nil, visit(node.value)],
        smap_rescue_body(
          keyword,
          nil,
          nil,
          keyword.join(srange_node(node.value))
        )
      ),
      nil
    ],
    smap_condition_bare(srange_node(node))
  )
end
visit_rest_param(node) click to toggle source

Visit a RestParam node.

# File lib/syntax_tree/translation/parser.rb, line 2151
def visit_rest_param(node)
  if node.name
    s(
      :restarg,
      [node.name.value.to_sym],
      smap_variable(srange_node(node.name), srange_node(node))
    )
  else
    s(:restarg, [], smap_variable(nil, srange_node(node)))
  end
end
visit_retry(node) click to toggle source

Visit a Retry node.

# File lib/syntax_tree/translation/parser.rb, line 2164
def visit_retry(node)
  s(:retry, [], smap_keyword_bare(srange_node(node), srange_node(node)))
end
visit_return(node) click to toggle source

Visit a ReturnNode node.

# File lib/syntax_tree/translation/parser.rb, line 2169
def visit_return(node)
  s(
    :return,
    node.arguments ? visit_all(node.arguments.parts) : [],
    smap_keyword_bare(
      srange_length(node.start_char, 6),
      srange_node(node)
    )
  )
end
visit_sclass(node) click to toggle source

Visit an SClass node.

# File lib/syntax_tree/translation/parser.rb, line 2181
def visit_sclass(node)
  s(
    :sclass,
    [visit(node.target), visit(node.bodystmt)],
    smap_definition(
      srange_length(node.start_char, 5),
      srange_find(node.start_char + 5, node.target.start_char, "<<"),
      nil,
      srange_length(node.end_char, -3)
    ).with_expression(srange_node(node))
  )
end
visit_statements(node) click to toggle source

Visit a Statements node.

# File lib/syntax_tree/translation/parser.rb, line 2195
def visit_statements(node)
  children =
    node.body.reject do |child|
      child.is_a?(Comment) || child.is_a?(EmbDoc) ||
        child.is_a?(EndContent) || child.is_a?(VoidStmt)
    end

  case children.length
  when 0
    nil
  when 1
    visit(children.first)
  else
    s(
      :begin,
      visit_all(children),
      smap_collection_bare(
        srange(children.first.start_char, children.last.end_char)
      )
    )
  end
end
visit_string_concat(node) click to toggle source

Visit a StringConcat node.

# File lib/syntax_tree/translation/parser.rb, line 2219
def visit_string_concat(node)
  s(
    :dstr,
    [visit(node.left), visit(node.right)],
    smap_collection_bare(srange_node(node))
  )
end
visit_string_dvar(node) click to toggle source

Visit a StringDVar node.

# File lib/syntax_tree/translation/parser.rb, line 2228
def visit_string_dvar(node)
  visit(node.variable)
end
visit_string_embexpr(node) click to toggle source

Visit a StringEmbExpr node.

# File lib/syntax_tree/translation/parser.rb, line 2233
def visit_string_embexpr(node)
  s(
    :begin,
    visit(node.statements).then { |child| child ? [child] : [] },
    smap_collection(
      srange_length(node.start_char, 2),
      srange_length(node.end_char, -1),
      srange_node(node)
    )
  )
end
visit_string_literal(node) click to toggle source

Visit a StringLiteral node.

# File lib/syntax_tree/translation/parser.rb, line 2246
def visit_string_literal(node)
  location =
    if node.quote
      smap_collection(
        srange_length(node.start_char, node.quote.length),
        srange_length(node.end_char, -1),
        srange_node(node)
      )
    else
      smap_collection_bare(srange_node(node))
    end

  if node.parts.empty?
    s(:str, [""], location)
  elsif node.parts.length == 1 && node.parts.first.is_a?(TStringContent)
    child = visit(node.parts.first)
    s(child.type, child.children, location)
  else
    s(:dstr, visit_all(node.parts), location)
  end
end
visit_super(node) click to toggle source

Visit a Super node.

# File lib/syntax_tree/translation/parser.rb, line 2269
def visit_super(node)
  if node.arguments.is_a?(Args)
    s(
      :super,
      visit_all(node.arguments.parts),
      smap_keyword_bare(
        srange_length(node.start_char, 5),
        srange_node(node)
      )
    )
  else
    case node.arguments.arguments
    when nil
      s(
        :super,
        [],
        smap_keyword(
          srange_length(node.start_char, 5),
          srange_find(node.start_char + 5, node.end_char, "("),
          srange_length(node.end_char, -1),
          srange_node(node)
        )
      )
    when ArgsForward
      s(
        :super,
        [visit(node.arguments.arguments)],
        smap_keyword(
          srange_length(node.start_char, 5),
          srange_find(node.start_char + 5, node.end_char, "("),
          srange_length(node.end_char, -1),
          srange_node(node)
        )
      )
    else
      s(
        :super,
        visit_all(node.arguments.arguments.parts),
        smap_keyword(
          srange_length(node.start_char, 5),
          srange_find(node.start_char + 5, node.end_char, "("),
          srange_length(node.end_char, -1),
          srange_node(node)
        )
      )
    end
  end
end
visit_symbol_literal(node) click to toggle source

Visit a SymbolLiteral node.

# File lib/syntax_tree/translation/parser.rb, line 2319
def visit_symbol_literal(node)
  begin_token =
    if buffer.source[node.start_char] == ":"
      srange_length(node.start_char, 1)
    end

  s(
    :sym,
    [node.value.value.to_sym],
    smap_collection(begin_token, nil, srange_node(node))
  )
end
visit_symbols(node) click to toggle source

Visit a Symbols node.

# File lib/syntax_tree/translation/parser.rb, line 2333
def visit_symbols(node)
  parts =
    node.elements.map do |element|
      part = element.parts.first

      if element.parts.length == 1 && part.is_a?(TStringContent)
        SymbolLiteral.new(value: part, location: part.location)
      else
        DynaSymbol.new(
          parts: element.parts,
          quote: nil,
          location: element.location
        )
      end
    end

  visit_array(
    ArrayLiteral.new(
      lbracket: node.beginning,
      contents: Args.new(parts: parts, location: node.location),
      location: node.location
    )
  )
end
visit_top_const_field(node) click to toggle source

Visit a TopConstField node.

# File lib/syntax_tree/translation/parser.rb, line 2359
def visit_top_const_field(node)
  s(
    :casgn,
    [
      s(:cbase, [], smap(srange_length(node.start_char, 2))),
      node.constant.value.to_sym
    ],
    smap_constant(
      srange_length(node.start_char, 2),
      srange_node(node.constant),
      srange_node(node)
    )
  )
end
visit_top_const_ref(node) click to toggle source

Visit a TopConstRef node.

# File lib/syntax_tree/translation/parser.rb, line 2375
def visit_top_const_ref(node)
  s(
    :const,
    [
      s(:cbase, [], smap(srange_length(node.start_char, 2))),
      node.constant.value.to_sym
    ],
    smap_constant(
      srange_length(node.start_char, 2),
      srange_node(node.constant),
      srange_node(node)
    )
  )
end
visit_tstring_content(node) click to toggle source

Visit a TStringContent node.

# File lib/syntax_tree/translation/parser.rb, line 2391
def visit_tstring_content(node)
  dumped = node.value.gsub(/([^[:ascii:]])/) { $1.dump[1...-1] }

  s(
    :str,
    ["\"#{dumped}\"".undump],
    smap_collection_bare(srange_node(node))
  )
end
visit_unary(node) click to toggle source

Visit a Unary node.

# File lib/syntax_tree/translation/parser.rb, line 2402
def visit_unary(node)
  # Special handling here for flipflops
  if (paren = node.statement).is_a?(Paren) &&
       paren.contents.is_a?(Statements) &&
       paren.contents.body.length == 1 &&
       (range = paren.contents.body.first).is_a?(RangeNode) &&
       node.operator == "!"
    s(
      :send,
      [
        s(
          :begin,
          [
            s(
              range.operator.value == ".." ? :iflipflop : :eflipflop,
              visit(range).children,
              smap_operator(
                srange_node(range.operator),
                srange_node(range)
              )
            )
          ],
          smap_collection(
            srange_length(paren.start_char, 1),
            srange_length(paren.end_char, -1),
            srange_node(paren)
          )
        ),
        :!
      ],
      smap_send_bare(
        srange_length(node.start_char, 1),
        srange_node(node)
      )
    )
  elsif node.operator == "!" && node.statement.is_a?(RegexpLiteral)
    s(
      :send,
      [
        s(
          :match_current_line,
          [visit(node.statement)],
          smap(srange_node(node.statement))
        ),
        :!
      ],
      smap_send_bare(
        srange_length(node.start_char, 1),
        srange_node(node)
      )
    )
  else
    visit(canonical_unary(node))
  end
end
visit_undef(node) click to toggle source

Visit an Undef node.

# File lib/syntax_tree/translation/parser.rb, line 2459
def visit_undef(node)
  s(
    :undef,
    visit_all(node.symbols),
    smap_keyword_bare(
      srange_length(node.start_char, 5),
      srange_node(node)
    )
  )
end
visit_unless(node) click to toggle source

Visit an UnlessNode node.

# File lib/syntax_tree/translation/parser.rb, line 2471
def visit_unless(node)
  s(
    :if,
    [
      visit_predicate(node.predicate),
      visit(node.consequent),
      visit(node.statements)
    ],
    if node.modifier?
      smap_keyword_bare(
        srange_find_between(node.statements, node.predicate, "unless"),
        srange_node(node)
      )
    else
      begin_start = node.predicate.end_char
      begin_end =
        if node.statements.empty?
          node.statements.end_char
        else
          node.statements.body.first.start_char
        end

      begin_token =
        if buffer.source[begin_start...begin_end].include?("then")
          srange_find(begin_start, begin_end, "then")
        elsif buffer.source[begin_start...begin_end].include?(";")
          srange_find(begin_start, begin_end, ";")
        end

      else_token =
        if node.consequent
          srange_length(node.consequent.start_char, 4)
        end

      smap_condition(
        srange_length(node.start_char, 6),
        begin_token,
        else_token,
        srange_length(node.end_char, -3),
        srange_node(node)
      )
    end
  )
end
visit_until(node) click to toggle source

Visit an UntilNode node.

# File lib/syntax_tree/translation/parser.rb, line 2517
def visit_until(node)
  s(
    loop_post?(node) ? :until_post : :until,
    [visit(node.predicate), visit(node.statements)],
    if node.modifier?
      smap_keyword_bare(
        srange_find_between(node.statements, node.predicate, "until"),
        srange_node(node)
      )
    else
      smap_keyword(
        srange_length(node.start_char, 5),
        srange_search_between(node.predicate, node.statements, "do") ||
          srange_search_between(node.predicate, node.statements, ";"),
        srange_length(node.end_char, -3),
        srange_node(node)
      )
    end
  )
end
visit_var_field(node) click to toggle source

Visit a VarField node.

# File lib/syntax_tree/translation/parser.rb, line 2539
def visit_var_field(node)
  name = node.value.value.to_sym
  match_var =
    [stack[-3], stack[-2]].any? do |parent|
      case parent
      when AryPtn, FndPtn, HshPtn, In, RAssign
        true
      when Binary
        parent.operator == :"=>"
      else
        false
      end
    end

  if match_var
    s(
      :match_var,
      [name],
      smap_variable(srange_node(node.value), srange_node(node.value))
    )
  elsif node.value.is_a?(Const)
    s(
      :casgn,
      [nil, name],
      smap_constant(nil, srange_node(node.value), srange_node(node))
    )
  else
    location = smap_variable(srange_node(node), srange_node(node))

    case node.value
    when CVar
      s(:cvasgn, [name], location)
    when GVar
      s(:gvasgn, [name], location)
    when Ident
      s(:lvasgn, [name], location)
    when IVar
      s(:ivasgn, [name], location)
    when VarRef
      s(:lvasgn, [name], location)
    else
      s(:match_rest, [], nil)
    end
  end
end
visit_var_ref(node) click to toggle source

Visit a VarRef node.

# File lib/syntax_tree/translation/parser.rb, line 2586
def visit_var_ref(node)
  visit(node.value)
end
visit_vcall(node) click to toggle source

Visit a VCall node.

# File lib/syntax_tree/translation/parser.rb, line 2591
def visit_vcall(node)
  visit_command_call(
    CommandCall.new(
      receiver: nil,
      operator: nil,
      message: node.value,
      arguments: nil,
      block: nil,
      location: node.location
    )
  )
end
visit_when(node) click to toggle source

Visit a When node.

# File lib/syntax_tree/translation/parser.rb, line 2605
def visit_when(node)
  keyword = srange_length(node.start_char, 4)
  begin_token =
    if buffer.source[node.statements.start_char] == ";"
      srange_length(node.statements.start_char, 1)
    end

  end_char =
    if node.statements.body.empty?
      node.statements.end_char
    else
      node.statements.body.last.end_char
    end

  s(
    :when,
    visit_all(node.arguments.parts) + [visit(node.statements)],
    smap_keyword(
      keyword,
      begin_token,
      nil,
      srange(keyword.begin_pos, end_char)
    )
  )
end
visit_while(node) click to toggle source

Visit a WhileNode node.

# File lib/syntax_tree/translation/parser.rb, line 2632
def visit_while(node)
  s(
    loop_post?(node) ? :while_post : :while,
    [visit(node.predicate), visit(node.statements)],
    if node.modifier?
      smap_keyword_bare(
        srange_find_between(node.statements, node.predicate, "while"),
        srange_node(node)
      )
    else
      smap_keyword(
        srange_length(node.start_char, 5),
        srange_search_between(node.predicate, node.statements, "do") ||
          srange_search_between(node.predicate, node.statements, ";"),
        srange_length(node.end_char, -3),
        srange_node(node)
      )
    end
  )
end
visit_word(node) click to toggle source

Visit a Word node.

# File lib/syntax_tree/translation/parser.rb, line 2654
def visit_word(node)
  visit_string_literal(
    StringLiteral.new(
      parts: node.parts,
      quote: nil,
      location: node.location
    )
  )
end
visit_words(node) click to toggle source

Visit a Words node.

# File lib/syntax_tree/translation/parser.rb, line 2665
def visit_words(node)
  visit_array(
    ArrayLiteral.new(
      lbracket: node.beginning,
      contents: Args.new(parts: node.elements, location: node.location),
      location: node.location
    )
  )
end
visit_xstring_literal(node) click to toggle source

Visit an XStringLiteral node.

# File lib/syntax_tree/translation/parser.rb, line 2676
def visit_xstring_literal(node)
  s(
    :xstr,
    visit_all(node.parts),
    smap_collection(
      srange_length(
        node.start_char,
        buffer.source[node.start_char] == "%" ? 3 : 1
      ),
      srange_length(node.end_char, -1),
      srange_node(node)
    )
  )
end
visit_yield(node) click to toggle source
# File lib/syntax_tree/translation/parser.rb, line 2691
def visit_yield(node)
  case node.arguments
  when nil
    s(
      :yield,
      [],
      smap_keyword_bare(
        srange_length(node.start_char, 5),
        srange_node(node)
      )
    )
  when Args
    s(
      :yield,
      visit_all(node.arguments.parts),
      smap_keyword_bare(
        srange_length(node.start_char, 5),
        srange_node(node)
      )
    )
  else
    s(
      :yield,
      visit_all(node.arguments.contents.parts),
      smap_keyword(
        srange_length(node.start_char, 5),
        srange_length(node.arguments.start_char, 1),
        srange_length(node.end_char, -1),
        srange_node(node)
      )
    )
  end
end
visit_zsuper(node) click to toggle source

Visit a ZSuper node.

# File lib/syntax_tree/translation/parser.rb, line 2726
def visit_zsuper(node)
  s(
    :zsuper,
    [],
    smap_keyword_bare(
      srange_length(node.start_char, 5),
      srange_node(node)
    )
  )
end