class SyntaxTree::YARV::Compiler

This class is an experiment in transforming Syntax Tree nodes into their corresponding YARV instruction sequences. It attempts to mirror the behavior of RubyVM::InstructionSequence.compile.

You use this as with any other visitor. First you parse code into a tree, then you visit it with this compiler. Visiting the root node of the tree will return a SyntaxTree::YARV::Compiler::InstructionSequence object. With that object you can call to_a on it, which will return a serialized form of the instruction sequence as an array. This array should mirror the array given by RubyVM::InstructionSequence#to_a.

As an example, here is how you would compile a single expression:

program = SyntaxTree.parse("1 + 2")
program.accept(SyntaxTree::YARV::Compiler.new).to_a

[
  "YARVInstructionSequence/SimpleDataFormat",
  3,
  1,
  1,
  {:arg_size=>0, :local_size=>0, :stack_max=>2},
  "<compiled>",
  "<compiled>",
  "<compiled>",
  1,
  :top,
  [],
  {},
  [],
  [
    [:putobject_INT2FIX_1_],
    [:putobject, 2],
    [:opt_plus, {:mid=>:+, :flag=>16, :orig_argc=>1}],
    [:leave]
  ]
]

Note that this is the same output as calling:

RubyVM::InstructionSequence.compile("1 + 2").to_a

Attributes

iseq[R]

The current instruction sequence that is being compiled.

last_statement[R]

A boolean to track if we’re currently compiling the last statement within a set of statements. This information is necessary to determine if we need to return the value of the last statement.

options[R]

These options mirror the compilation options that we currently support that can be also passed to RubyVM::InstructionSequence.compile.

Public Class Methods

new(options = Options.new) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 293
def initialize(options = Options.new)
  @options = options
  @iseq = nil
  @last_statement = false
end

Public Instance Methods

visit_BEGIN(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 299
def visit_BEGIN(node)
  visit(node.statements)
end
visit_CHAR(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 303
def visit_CHAR(node)
  if options.frozen_string_literal?
    iseq.putobject(node.value[1..])
  else
    iseq.putstring(node.value[1..])
  end
end
visit_END(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 311
def visit_END(node)
  start_line = node.location.start_line
  once_iseq =
    with_child_iseq(iseq.block_child_iseq(start_line)) do
      postexe_iseq =
        with_child_iseq(iseq.block_child_iseq(start_line)) do
          iseq.event(:RUBY_EVENT_B_CALL)

          *statements, last_statement = node.statements.body
          visit_all(statements)
          with_last_statement { visit(last_statement) }

          iseq.event(:RUBY_EVENT_B_RETURN)
          iseq.leave
        end

      iseq.putspecialobject(PutSpecialObject::OBJECT_VMCORE)
      iseq.send(
        YARV.calldata(:"core#set_postexe", 0, CallData::CALL_FCALL),
        postexe_iseq
      )
      iseq.leave
    end

  iseq.once(once_iseq, iseq.inline_storage)
  iseq.pop
end
visit_alias(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 339
def visit_alias(node)
  iseq.putspecialobject(PutSpecialObject::OBJECT_VMCORE)
  iseq.putspecialobject(PutSpecialObject::OBJECT_CBASE)
  visit(node.left)
  visit(node.right)
  iseq.send(YARV.calldata(:"core#set_method_alias", 3))
end
visit_aref(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 347
def visit_aref(node)
  calldata = YARV.calldata(:[], 1)
  visit(node.collection)

  if !options.frozen_string_literal? &&
       options.specialized_instruction? && (node.index.parts.length == 1)
    arg = node.index.parts.first

    if arg.is_a?(StringLiteral) && (arg.parts.length == 1)
      string_part = arg.parts.first

      if string_part.is_a?(TStringContent)
        iseq.opt_aref_with(string_part.value, calldata)
        return
      end
    end
  end

  visit(node.index)
  iseq.send(calldata)
end
visit_arg_block(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 369
def visit_arg_block(node)
  visit(node.value)
end
visit_arg_paren(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 373
def visit_arg_paren(node)
  visit(node.arguments)
end
visit_arg_star(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 377
def visit_arg_star(node)
  visit(node.value)
  iseq.splatarray(false)
end
visit_args(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 382
def visit_args(node)
  visit_all(node.parts)
end
visit_array(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 386
def visit_array(node)
  if (compiled = RubyVisitor.compile(node))
    iseq.duparray(compiled)
  elsif node.contents && node.contents.parts.length == 1 &&
        node.contents.parts.first.is_a?(BareAssocHash) &&
        node.contents.parts.first.assocs.length == 1 &&
        node.contents.parts.first.assocs.first.is_a?(AssocSplat)
    iseq.putspecialobject(PutSpecialObject::OBJECT_VMCORE)
    iseq.newhash(0)
    visit(node.contents.parts.first)
    iseq.send(YARV.calldata(:"core#hash_merge_kwd", 2))
    iseq.newarraykwsplat(1)
  else
    length = 0

    node.contents.parts.each do |part|
      if part.is_a?(ArgStar)
        if length > 0
          iseq.newarray(length)
          length = 0
        end

        visit(part.value)
        iseq.concatarray
      else
        visit(part)
        length += 1
      end
    end

    iseq.newarray(length) if length > 0
    iseq.concatarray if length > 0 && length != node.contents.parts.length
  end
end
visit_aryptn(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 421
def visit_aryptn(node)
end
visit_assign(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 424
def visit_assign(node)
  case node.target
  when ARefField
    calldata = YARV.calldata(:[]=, 2)

    if !options.frozen_string_literal? &&
         options.specialized_instruction? &&
         (node.target.index.parts.length == 1)
      arg = node.target.index.parts.first

      if arg.is_a?(StringLiteral) && (arg.parts.length == 1)
        string_part = arg.parts.first

        if string_part.is_a?(TStringContent)
          visit(node.target.collection)
          visit(node.value)
          iseq.swap
          iseq.topn(1)
          iseq.opt_aset_with(string_part.value, calldata)
          iseq.pop
          return
        end
      end
    end

    iseq.putnil
    visit(node.target.collection)
    visit(node.target.index)
    visit(node.value)
    iseq.setn(3)
    iseq.send(calldata)
    iseq.pop
  when ConstPathField
    names = constant_names(node.target)
    name = names.pop

    if RUBY_VERSION >= "3.2"
      iseq.opt_getconstant_path(names)
      visit(node.value)
      iseq.swap
      iseq.topn(1)
      iseq.swap
      iseq.setconstant(name)
    else
      visit(node.value)
      iseq.dup if last_statement?
      iseq.opt_getconstant_path(names)
      iseq.setconstant(name)
    end
  when Field
    iseq.putnil
    visit(node.target)
    visit(node.value)
    iseq.setn(2)
    iseq.send(YARV.calldata(:"#{node.target.name.value}=", 1))
    iseq.pop
  when TopConstField
    name = node.target.constant.value.to_sym

    if RUBY_VERSION >= "3.2"
      iseq.putobject(Object)
      visit(node.value)
      iseq.swap
      iseq.topn(1)
      iseq.swap
      iseq.setconstant(name)
    else
      visit(node.value)
      iseq.dup if last_statement?
      iseq.putobject(Object)
      iseq.setconstant(name)
    end
  when VarField
    visit(node.value)
    iseq.dup if last_statement?

    case node.target.value
    when Const
      iseq.putspecialobject(PutSpecialObject::OBJECT_CONST_BASE)
      iseq.setconstant(node.target.value.value.to_sym)
    when CVar
      iseq.setclassvariable(node.target.value.value.to_sym)
    when GVar
      iseq.setglobal(node.target.value.value.to_sym)
    when Ident
      lookup = visit(node.target)

      if lookup.local.is_a?(LocalTable::BlockLocal)
        iseq.setblockparam(lookup.index, lookup.level)
      else
        iseq.setlocal(lookup.index, lookup.level)
      end
    when IVar
      iseq.setinstancevariable(node.target.value.value.to_sym)
    end
  end
end
visit_assoc(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 522
def visit_assoc(node)
  visit(node.key)
  visit(node.value)
end
visit_assoc_splat(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 527
def visit_assoc_splat(node)
  visit(node.value)
end
visit_backref(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 531
def visit_backref(node)
  iseq.getspecial(GetSpecial::SVAR_BACKREF, node.value[1..].to_i << 1)
end
visit_bare_assoc_hash(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 535
def visit_bare_assoc_hash(node)
  if (compiled = RubyVisitor.compile(node))
    iseq.duphash(compiled)
  else
    visit_all(node.assocs)
  end
end
visit_begin(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 543
def visit_begin(node)
end
visit_binary(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 546
def visit_binary(node)
  case node.operator
  when :"&&"
    done_label = iseq.label

    visit(node.left)
    iseq.dup
    iseq.branchunless(done_label)

    iseq.pop
    visit(node.right)
    iseq.push(done_label)
  when :"||"
    visit(node.left)
    iseq.dup

    skip_right_label = iseq.label
    iseq.branchif(skip_right_label)
    iseq.pop

    visit(node.right)
    iseq.push(skip_right_label)
  else
    visit(node.left)
    visit(node.right)
    iseq.send(YARV.calldata(node.operator, 1))
  end
end
visit_block(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 575
def visit_block(node)
  with_child_iseq(iseq.block_child_iseq(node.location.start_line)) do
    iseq.event(:RUBY_EVENT_B_CALL)
    visit(node.block_var)
    visit(node.bodystmt)
    iseq.event(:RUBY_EVENT_B_RETURN)
    iseq.leave
  end
end
visit_block_var(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 585
def visit_block_var(node)
  params = node.params

  if params.requireds.length == 1 && params.optionals.empty? &&
       !params.rest && params.posts.empty? && params.keywords.empty? &&
       !params.keyword_rest && !params.block
    iseq.argument_options[:ambiguous_param0] = true
  end

  visit(node.params)

  node.locals.each { |local| iseq.local_table.plain(local.value.to_sym) }
end
visit_blockarg(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 599
def visit_blockarg(node)
  iseq.argument_options[:block_start] = iseq.argument_size
  iseq.local_table.block(node.name.value.to_sym)
  iseq.argument_size += 1
end
visit_bodystmt(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 605
def visit_bodystmt(node)
  visit(node.statements)
end
visit_break(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 609
def visit_break(node)
end
visit_call(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 612
def visit_call(node)
  if node.is_a?(CallNode)
    return(
      visit_call(
        CommandCall.new(
          receiver: node.receiver,
          operator: node.operator,
          message: node.message,
          arguments: node.arguments,
          block: nil,
          location: node.location
        )
      )
    )
  end

  # Track whether or not this is a method call on a block proxy receiver.
  # If it is, we can potentially do tailcall optimizations on it.
  block_receiver = false

  if node.receiver
    if node.receiver.is_a?(VarRef)
      lookup = iseq.local_variable(node.receiver.value.value.to_sym)

      if lookup.local.is_a?(LocalTable::BlockLocal)
        iseq.getblockparamproxy(lookup.index, lookup.level)
        block_receiver = true
      else
        visit(node.receiver)
      end
    else
      visit(node.receiver)
    end
  else
    iseq.putself
  end

  after_call_label = nil
  if node.operator&.value == "&."
    iseq.dup
    after_call_label = iseq.label
    iseq.branchnil(after_call_label)
  end

  arg_parts = argument_parts(node.arguments)
  argc = arg_parts.length
  flag = 0

  arg_parts.each do |arg_part|
    case arg_part
    when ArgBlock
      argc -= 1
      flag |= CallData::CALL_ARGS_BLOCKARG
      visit(arg_part)
    when ArgStar
      flag |= CallData::CALL_ARGS_SPLAT
      visit(arg_part)
    when ArgsForward
      flag |= CallData::CALL_TAILCALL if options.tailcall_optimization?

      flag |= CallData::CALL_ARGS_SPLAT
      lookup = iseq.local_table.find(:*)
      iseq.getlocal(lookup.index, lookup.level)
      iseq.splatarray(arg_parts.length != 1)

      flag |= CallData::CALL_ARGS_BLOCKARG
      lookup = iseq.local_table.find(:&)
      iseq.getblockparamproxy(lookup.index, lookup.level)
    when BareAssocHash
      flag |= CallData::CALL_KW_SPLAT
      visit(arg_part)
    else
      visit(arg_part)
    end
  end

  block_iseq = visit(node.block) if node.block

  # If there's no block and we don't already have any special flags set,
  # then we can safely call this simple arguments. Note that has to be the
  # first flag we set after looking at the arguments to get the flags
  # correct.
  flag |= CallData::CALL_ARGS_SIMPLE if block_iseq.nil? && flag == 0

  # If there's no receiver, then this is an "fcall".
  flag |= CallData::CALL_FCALL if node.receiver.nil?

  # If we're calling a method on the passed block object and we have
  # tailcall optimizations turned on, then we can set the tailcall flag.
  if block_receiver && options.tailcall_optimization?
    flag |= CallData::CALL_TAILCALL
  end

  iseq.send(
    YARV.calldata(node.message.value.to_sym, argc, flag),
    block_iseq
  )
  iseq.event(after_call_label) if after_call_label
end
visit_case(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 712
def visit_case(node)
  visit(node.value) if node.value

  clauses = []
  else_clause = nil
  current = node.consequent

  while current
    clauses << current

    if (current = current.consequent).is_a?(Else)
      else_clause = current
      break
    end
  end

  branches =
    clauses.map do |clause|
      visit(clause.arguments)
      iseq.topn(1)
      iseq.send(
        YARV.calldata(
          :===,
          1,
          CallData::CALL_FCALL | CallData::CALL_ARGS_SIMPLE
        )
      )

      label = iseq.label
      iseq.branchif(label)
      [clause, label]
    end

  iseq.pop
  else_clause ? visit(else_clause) : iseq.putnil
  iseq.leave

  branches.each_with_index do |(clause, label), index|
    iseq.leave if index != 0
    iseq.push(label)
    iseq.pop
    visit(clause)
  end
end
visit_class(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 757
def visit_class(node)
  name = node.constant.constant.value.to_sym
  class_iseq =
    with_child_iseq(
      iseq.class_child_iseq(name, node.location.start_line)
    ) do
      iseq.event(:RUBY_EVENT_CLASS)
      visit(node.bodystmt)
      iseq.event(:RUBY_EVENT_END)
      iseq.leave
    end

  flags = DefineClass::TYPE_CLASS

  case node.constant
  when ConstPathRef
    flags |= DefineClass::FLAG_SCOPED
    visit(node.constant.parent)
  when ConstRef
    iseq.putspecialobject(PutSpecialObject::OBJECT_CONST_BASE)
  when TopConstRef
    flags |= DefineClass::FLAG_SCOPED
    iseq.putobject(Object)
  end

  if node.superclass
    flags |= DefineClass::FLAG_HAS_SUPERCLASS
    visit(node.superclass)
  else
    iseq.putnil
  end

  iseq.defineclass(name, class_iseq, flags)
end
visit_command(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 792
def visit_command(node)
  visit_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
# File lib/syntax_tree/yarv/compiler.rb, line 805
def visit_command_call(node)
  visit_call(
    CommandCall.new(
      receiver: node.receiver,
      operator: node.operator,
      message: node.message,
      arguments: node.arguments,
      block: node.block,
      location: node.location
    )
  )
end
visit_const_path_field(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 818
def visit_const_path_field(node)
  visit(node.parent)
end
visit_const_path_ref(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 822
def visit_const_path_ref(node)
  names = constant_names(node)
  iseq.opt_getconstant_path(names)
end
visit_def(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 827
def visit_def(node)
  name = node.name.value.to_sym
  method_iseq =
    iseq.method_child_iseq(name.to_s, node.location.start_line)

  with_child_iseq(method_iseq) do
    visit(node.params) if node.params
    iseq.event(:RUBY_EVENT_CALL)
    visit(node.bodystmt)
    iseq.event(:RUBY_EVENT_RETURN)
    iseq.leave
  end

  if node.target
    visit(node.target)
    iseq.definesmethod(name, method_iseq)
  else
    iseq.definemethod(name, method_iseq)
  end

  iseq.putobject(name)
end
visit_defined(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 850
def visit_defined(node)
  case node.value
  when Assign
    # If we're assigning to a local variable, then we need to make sure
    # that we put it into the local table.
    if node.value.target.is_a?(VarField) &&
         node.value.target.value.is_a?(Ident)
      iseq.local_table.plain(node.value.target.value.value.to_sym)
    end

    iseq.putobject("assignment")
  when VarRef
    value = node.value.value
    name = value.value.to_sym

    case value
    when Const
      iseq.putnil
      iseq.defined(Defined::TYPE_CONST, name, "constant")
    when CVar
      iseq.putnil
      iseq.defined(Defined::TYPE_CVAR, name, "class variable")
    when GVar
      iseq.putnil
      iseq.defined(Defined::TYPE_GVAR, name, "global-variable")
    when Ident
      iseq.putobject("local-variable")
    when IVar
      iseq.definedivar(name, iseq.inline_storage, "instance-variable")
    when Kw
      case name
      when :false
        iseq.putobject("false")
      when :nil
        iseq.putobject("nil")
      when :self
        iseq.putobject("self")
      when :true
        iseq.putobject("true")
      end
    end
  when VCall
    iseq.putself

    name = node.value.value.value.to_sym
    iseq.defined(Defined::TYPE_FUNC, name, "method")
  when YieldNode
    iseq.putnil
    iseq.defined(Defined::TYPE_YIELD, false, "yield")
  when ZSuper
    iseq.putnil
    iseq.defined(Defined::TYPE_ZSUPER, false, "super")
  else
    iseq.putobject("expression")
  end
end
visit_dyna_symbol(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 907
def visit_dyna_symbol(node)
  if node.parts.length == 1 && node.parts.first.is_a?(TStringContent)
    iseq.putobject(node.parts.first.value.to_sym)
  end
end
visit_else(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 913
def visit_else(node)
  visit(node.statements)
  iseq.pop unless last_statement?
end
visit_elsif(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 918
def visit_elsif(node)
  visit_if(
    IfNode.new(
      predicate: node.predicate,
      statements: node.statements,
      consequent: node.consequent,
      location: node.location
    )
  )
end
visit_ensure(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 929
def visit_ensure(node)
end
visit_field(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 932
def visit_field(node)
  visit(node.parent)
end
visit_float(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 936
def visit_float(node)
  iseq.putobject(node.accept(RubyVisitor.new))
end
visit_fndptn(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 940
def visit_fndptn(node)
end
visit_for(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 943
def visit_for(node)
  visit(node.collection)

  name = node.index.value.value.to_sym
  iseq.local_table.plain(name)

  block_iseq =
    with_child_iseq(
      iseq.block_child_iseq(node.statements.location.start_line)
    ) do
      iseq.argument_options[:lead_num] ||= 0
      iseq.argument_options[:lead_num] += 1
      iseq.argument_options[:ambiguous_param0] = true

      iseq.argument_size += 1
      iseq.local_table.plain(2)

      iseq.getlocal(0, 0)

      local_variable = iseq.local_variable(name)
      iseq.setlocal(local_variable.index, local_variable.level)

      iseq.event(:RUBY_EVENT_B_CALL)
      iseq.nop

      visit(node.statements)
      iseq.event(:RUBY_EVENT_B_RETURN)
      iseq.leave
    end

  iseq.send(YARV.calldata(:each, 0, 0), block_iseq)
end
visit_hash(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 976
def visit_hash(node)
  if (compiled = RubyVisitor.compile(node))
    iseq.duphash(compiled)
  else
    visit_all(node.assocs)
    iseq.newhash(node.assocs.length * 2)
  end
end
visit_heredoc(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 988
def visit_heredoc(node)
  if node.beginning.value.end_with?("`")
    visit_xstring_literal(node)
  elsif node.parts.length == 1 && node.parts.first.is_a?(TStringContent)
    visit(node.parts.first)
  else
    length = visit_string_parts(node)
    iseq.concatstrings(length)
  end
end
visit_hshptn(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 985
def visit_hshptn(node)
end
visit_if(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 999
def visit_if(node)
  if node.predicate.is_a?(RangeNode)
    true_label = iseq.label
    false_label = iseq.label
    end_label = iseq.label

    iseq.getspecial(GetSpecial::SVAR_FLIPFLOP_START, 0)
    iseq.branchif(true_label)

    visit(node.predicate.left)
    iseq.branchunless(end_label)

    iseq.putobject(true)
    iseq.setspecial(GetSpecial::SVAR_FLIPFLOP_START)

    iseq.push(true_label)
    visit(node.predicate.right)
    iseq.branchunless(false_label)

    iseq.putobject(false)
    iseq.setspecial(GetSpecial::SVAR_FLIPFLOP_START)

    iseq.push(false_label)
    visit(node.statements)
    iseq.leave
    iseq.push(end_label)
    iseq.putnil
  else
    consequent_label = iseq.label

    visit(node.predicate)
    iseq.branchunless(consequent_label)
    visit(node.statements)

    if last_statement?
      iseq.leave
      iseq.push(consequent_label)
      node.consequent ? visit(node.consequent) : iseq.putnil
    else
      iseq.pop

      if node.consequent
        done_label = iseq.label
        iseq.jump(done_label)
        iseq.push(consequent_label)
        visit(node.consequent)
        iseq.push(done_label)
      else
        iseq.push(consequent_label)
      end
    end
  end
end
visit_if_op(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1053
def visit_if_op(node)
  visit_if(
    IfNode.new(
      predicate: node.predicate,
      statements:
        Statements.new(body: [node.truthy], location: Location.default),
      consequent:
        Else.new(
          keyword: Kw.new(value: "else", location: Location.default),
          statements:
            Statements.new(
              body: [node.falsy],
              location: Location.default
            ),
          location: Location.default
        ),
      location: Location.default
    )
  )
end
visit_imaginary(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1074
def visit_imaginary(node)
  iseq.putobject(node.accept(RubyVisitor.new))
end
visit_int(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1078
def visit_int(node)
  iseq.putobject(node.accept(RubyVisitor.new))
end
visit_kwrest_param(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1082
def visit_kwrest_param(node)
  iseq.argument_options[:kwrest] = iseq.argument_size
  iseq.argument_size += 1
  iseq.local_table.plain(node.name.value.to_sym)
end
visit_label(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1088
def visit_label(node)
  iseq.putobject(node.accept(RubyVisitor.new))
end
visit_lambda(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1092
def visit_lambda(node)
  lambda_iseq =
    with_child_iseq(iseq.block_child_iseq(node.location.start_line)) do
      iseq.event(:RUBY_EVENT_B_CALL)
      visit(node.params)
      visit(node.statements)
      iseq.event(:RUBY_EVENT_B_RETURN)
      iseq.leave
    end

  iseq.putspecialobject(PutSpecialObject::OBJECT_VMCORE)
  iseq.send(YARV.calldata(:lambda, 0, CallData::CALL_FCALL), lambda_iseq)
end
visit_lambda_var(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1106
def visit_lambda_var(node)
  visit_block_var(node)
end
visit_massign(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1110
def visit_massign(node)
  visit(node.value)
  iseq.dup
  visit(node.target)
end
visit_method_add_block(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1116
def visit_method_add_block(node)
  visit_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
visit_mlhs(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1129
def visit_mlhs(node)
  lookups = []
  node.parts.each do |part|
    case part
    when VarField
      lookups << visit(part)
    end
  end

  iseq.expandarray(lookups.length, 0)
  lookups.each { |lookup| iseq.setlocal(lookup.index, lookup.level) }
end
visit_module(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1142
def visit_module(node)
  name = node.constant.constant.value.to_sym
  module_iseq =
    with_child_iseq(
      iseq.module_child_iseq(name, node.location.start_line)
    ) do
      iseq.event(:RUBY_EVENT_CLASS)
      visit(node.bodystmt)
      iseq.event(:RUBY_EVENT_END)
      iseq.leave
    end

  flags = DefineClass::TYPE_MODULE

  case node.constant
  when ConstPathRef
    flags |= DefineClass::FLAG_SCOPED
    visit(node.constant.parent)
  when ConstRef
    iseq.putspecialobject(PutSpecialObject::OBJECT_CONST_BASE)
  when TopConstRef
    flags |= DefineClass::FLAG_SCOPED
    iseq.putobject(Object)
  end

  iseq.putnil
  iseq.defineclass(name, module_iseq, flags)
end
visit_mrhs(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1171
def visit_mrhs(node)
  if (compiled = RubyVisitor.compile(node))
    iseq.duparray(compiled)
  else
    visit_all(node.parts)
    iseq.newarray(node.parts.length)
  end
end
visit_next(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1180
def visit_next(node)
end
visit_not(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1183
def visit_not(node)
  visit(node.statement)
  iseq.send(YARV.calldata(:!))
end
visit_opassign(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1188
def visit_opassign(node)
  flag = CallData::CALL_ARGS_SIMPLE
  if node.target.is_a?(ConstPathField) || node.target.is_a?(TopConstField)
    flag |= CallData::CALL_FCALL
  end

  case (operator = node.operator.value.chomp("=").to_sym)
  when :"&&"
    done_label = iseq.label

    with_opassign(node) do
      iseq.dup
      iseq.branchunless(done_label)
      iseq.pop
      visit(node.value)
    end

    case node.target
    when ARefField
      iseq.leave
      iseq.push(done_label)
      iseq.setn(3)
      iseq.adjuststack(3)
    when ConstPathField, TopConstField
      iseq.push(done_label)
      iseq.swap
      iseq.pop
    else
      iseq.push(done_label)
    end
  when :"||"
    if node.target.is_a?(ConstPathField) ||
         node.target.is_a?(TopConstField)
      opassign_defined(node)
      iseq.swap
      iseq.pop
    elsif node.target.is_a?(VarField) &&
          [Const, CVar, GVar].include?(node.target.value.class)
      opassign_defined(node)
    else
      skip_value_label = iseq.label

      with_opassign(node) do
        iseq.dup
        iseq.branchif(skip_value_label)
        iseq.pop
        visit(node.value)
      end

      if node.target.is_a?(ARefField)
        iseq.leave
        iseq.push(skip_value_label)
        iseq.setn(3)
        iseq.adjuststack(3)
      else
        iseq.push(skip_value_label)
      end
    end
  else
    with_opassign(node) do
      visit(node.value)
      iseq.send(YARV.calldata(operator, 1, flag))
    end
  end
end
visit_params(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1254
def visit_params(node)
  if node.requireds.any?
    iseq.argument_options[:lead_num] = 0

    node.requireds.each do |required|
      iseq.local_table.plain(required.value.to_sym)
      iseq.argument_size += 1
      iseq.argument_options[:lead_num] += 1
    end
  end

  node.optionals.each do |(optional, value)|
    index = iseq.local_table.size
    name = optional.value.to_sym

    iseq.local_table.plain(name)
    iseq.argument_size += 1

    unless iseq.argument_options.key?(:opt)
      start_label = iseq.label
      iseq.push(start_label)
      iseq.argument_options[:opt] = [start_label]
    end

    visit(value)
    iseq.setlocal(index, 0)

    arg_given_label = iseq.label
    iseq.push(arg_given_label)
    iseq.argument_options[:opt] << arg_given_label
  end

  visit(node.rest) if node.rest

  if node.posts.any?
    iseq.argument_options[:post_start] = iseq.argument_size
    iseq.argument_options[:post_num] = 0

    node.posts.each do |post|
      iseq.local_table.plain(post.value.to_sym)
      iseq.argument_size += 1
      iseq.argument_options[:post_num] += 1
    end
  end

  if node.keywords.any?
    iseq.argument_options[:kwbits] = 0
    iseq.argument_options[:keyword] = []

    keyword_bits_name = node.keyword_rest ? 3 : 2
    iseq.argument_size += 1
    keyword_bits_index = iseq.local_table.locals.size + node.keywords.size

    node.keywords.each_with_index do |(keyword, value), keyword_index|
      name = keyword.value.chomp(":").to_sym
      index = iseq.local_table.size

      iseq.local_table.plain(name)
      iseq.argument_size += 1
      iseq.argument_options[:kwbits] += 1

      if value.nil?
        iseq.argument_options[:keyword] << name
      elsif (compiled = RubyVisitor.compile(value))
        iseq.argument_options[:keyword] << [name, compiled]
      else
        skip_value_label = iseq.label

        iseq.argument_options[:keyword] << [name]
        iseq.checkkeyword(keyword_bits_index, keyword_index)
        iseq.branchif(skip_value_label)
        visit(value)
        iseq.setlocal(index, 0)
        iseq.push(skip_value_label)
      end
    end

    iseq.local_table.plain(keyword_bits_name)
  end

  if node.keyword_rest.is_a?(ArgsForward)
    if RUBY_VERSION >= "3.2"
      iseq.local_table.plain(:*)
      iseq.local_table.plain(:&)
      iseq.local_table.plain(:"...")

      iseq.argument_options[:rest_start] = iseq.argument_size
      iseq.argument_options[:block_start] = iseq.argument_size + 1

      iseq.argument_size += 2
    else
      iseq.local_table.plain(:*)
      iseq.local_table.plain(:&)

      iseq.argument_options[:rest_start] = iseq.argument_size
      iseq.argument_options[:block_start] = iseq.argument_size + 1

      iseq.argument_size += 2
    end
  elsif node.keyword_rest
    visit(node.keyword_rest)
  end

  visit(node.block) if node.block
end
visit_paren(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1360
def visit_paren(node)
  visit(node.contents)
end
visit_pinned_begin(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1364
def visit_pinned_begin(node)
end
visit_pinned_var_ref(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1367
def visit_pinned_var_ref(node)
end
visit_program(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1370
def visit_program(node)
  node.statements.body.each do |statement|
    break unless statement.is_a?(Comment)

    if statement.value == "# frozen_string_literal: true"
      options.frozen_string_literal!
    end
  end

  preexes = []
  statements = []

  node.statements.body.each do |statement|
    case statement
    when Comment, EmbDoc, EndContent, VoidStmt
      # ignore
    when BEGINBlock
      preexes << statement
    else
      statements << statement
    end
  end

  top_iseq =
    InstructionSequence.new(
      "<compiled>",
      "<compiled>",
      1,
      :top,
      nil,
      options
    )

  with_child_iseq(top_iseq) do
    visit_all(preexes)

    if statements.empty?
      iseq.putnil
    else
      *statements, last_statement = statements
      visit_all(statements)
      with_last_statement { visit(last_statement) }
    end

    iseq.leave
  end

  top_iseq.compile!
  top_iseq
end
visit_qsymbols(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1421
def visit_qsymbols(node)
  iseq.duparray(node.accept(RubyVisitor.new))
end
visit_qwords(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1425
def visit_qwords(node)
  if options.frozen_string_literal?
    iseq.duparray(node.accept(RubyVisitor.new))
  else
    visit_all(node.elements)
    iseq.newarray(node.elements.length)
  end
end
visit_range(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1434
def visit_range(node)
  if (compiled = RubyVisitor.compile(node))
    iseq.putobject(compiled)
  else
    visit(node.left)
    visit(node.right)
    iseq.newrange(node.operator.value == ".." ? 0 : 1)
  end
end
visit_rassign(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1444
def visit_rassign(node)
  iseq.putnil

  if node.operator.is_a?(Kw)
    match_label = iseq.label

    visit(node.value)
    iseq.dup

    visit_pattern(node.pattern, match_label)

    iseq.pop
    iseq.pop
    iseq.putobject(false)
    iseq.leave

    iseq.push(match_label)
    iseq.adjuststack(2)
    iseq.putobject(true)
  else
    no_key_label = iseq.label
    end_leave_label = iseq.label
    end_label = iseq.label

    iseq.putnil
    iseq.putobject(false)
    iseq.putnil
    iseq.putnil
    visit(node.value)
    iseq.dup

    visit_pattern(node.pattern, end_label)

    # First we're going to push the core onto the stack, then we'll check
    # if the value to match is truthy. If it is, we'll jump down to raise
    # NoMatchingPatternKeyError. Otherwise we'll raise
    # NoMatchingPatternError.
    iseq.putspecialobject(PutSpecialObject::OBJECT_VMCORE)
    iseq.topn(4)
    iseq.branchif(no_key_label)

    # Here we're going to raise NoMatchingPatternError.
    iseq.putobject(NoMatchingPatternError)
    iseq.putspecialobject(PutSpecialObject::OBJECT_VMCORE)
    iseq.putobject("%p: %s")
    iseq.topn(4)
    iseq.topn(7)
    iseq.send(YARV.calldata(:"core#sprintf", 3))
    iseq.send(YARV.calldata(:"core#raise", 2))
    iseq.jump(end_leave_label)

    # Here we're going to raise NoMatchingPatternKeyError.
    iseq.push(no_key_label)
    iseq.putobject(NoMatchingPatternKeyError)
    iseq.putspecialobject(PutSpecialObject::OBJECT_VMCORE)
    iseq.putobject("%p: %s")
    iseq.topn(4)
    iseq.topn(7)
    iseq.send(YARV.calldata(:"core#sprintf", 3))
    iseq.topn(7)
    iseq.topn(9)
    iseq.send(
      YARV.calldata(:new, 1, CallData::CALL_KWARG, %i[matchee key])
    )
    iseq.send(YARV.calldata(:"core#raise", 1))

    iseq.push(end_leave_label)
    iseq.adjuststack(7)
    iseq.putnil
    iseq.leave

    iseq.push(end_label)
    iseq.adjuststack(6)
    iseq.putnil
  end
end
visit_rational(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1521
def visit_rational(node)
  iseq.putobject(node.accept(RubyVisitor.new))
end
visit_redo(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1525
def visit_redo(node)
end
visit_regexp_literal(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1528
def visit_regexp_literal(node)
  if (compiled = RubyVisitor.compile(node))
    iseq.putobject(compiled)
  else
    flags = RubyVisitor.new.visit_regexp_literal_flags(node)
    length = visit_string_parts(node)
    iseq.toregexp(flags, length)
  end
end
visit_rescue(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1538
def visit_rescue(node)
end
visit_rescue_ex(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1541
def visit_rescue_ex(node)
end
visit_rescue_mod(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1544
def visit_rescue_mod(node)
end
visit_rest_param(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1547
def visit_rest_param(node)
  iseq.local_table.plain(node.name.value.to_sym)
  iseq.argument_options[:rest_start] = iseq.argument_size
  iseq.argument_size += 1
end
visit_retry(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1553
def visit_retry(node)
end
visit_return(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1556
def visit_return(node)
end
visit_sclass(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1559
def visit_sclass(node)
  visit(node.target)
  iseq.putnil

  singleton_iseq =
    with_child_iseq(
      iseq.singleton_class_child_iseq(node.location.start_line)
    ) do
      iseq.event(:RUBY_EVENT_CLASS)
      visit(node.bodystmt)
      iseq.event(:RUBY_EVENT_END)
      iseq.leave
    end

  iseq.defineclass(
    :singletonclass,
    singleton_iseq,
    DefineClass::TYPE_SINGLETON_CLASS
  )
end
visit_statements(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1580
def visit_statements(node)
  statements =
    node.body.select do |statement|
      case statement
      when Comment, EmbDoc, EndContent, VoidStmt
        false
      else
        true
      end
    end

  statements.empty? ? iseq.putnil : visit_all(statements)
end
visit_string_concat(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1594
def visit_string_concat(node)
  value = node.left.parts.first.value + node.right.parts.first.value

  visit_string_literal(
    StringLiteral.new(
      parts: [TStringContent.new(value: value, location: node.location)],
      quote: node.left.quote,
      location: node.location
    )
  )
end
visit_string_embexpr(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1606
def visit_string_embexpr(node)
  visit(node.statements)
end
visit_string_literal(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1610
def visit_string_literal(node)
  if node.parts.length == 1 && node.parts.first.is_a?(TStringContent)
    visit(node.parts.first)
  else
    length = visit_string_parts(node)
    iseq.concatstrings(length)
  end
end
visit_super(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1619
def visit_super(node)
  iseq.putself
  visit(node.arguments)
  iseq.invokesuper(
    YARV.calldata(
      nil,
      argument_parts(node.arguments).length,
      CallData::CALL_FCALL | CallData::CALL_ARGS_SIMPLE |
        CallData::CALL_SUPER
    ),
    nil
  )
end
visit_symbol_literal(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1633
def visit_symbol_literal(node)
  iseq.putobject(node.accept(RubyVisitor.new))
end
visit_symbols(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1637
def visit_symbols(node)
  if (compiled = RubyVisitor.compile(node))
    iseq.duparray(compiled)
  else
    node.elements.each do |element|
      if element.parts.length == 1 &&
           element.parts.first.is_a?(TStringContent)
        iseq.putobject(element.parts.first.value.to_sym)
      else
        length = visit_string_parts(element)
        iseq.concatstrings(length)
        iseq.intern
      end
    end

    iseq.newarray(node.elements.length)
  end
end
visit_top_const_ref(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1656
def visit_top_const_ref(node)
  iseq.opt_getconstant_path(constant_names(node))
end
visit_tstring_content(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1660
def visit_tstring_content(node)
  if options.frozen_string_literal?
    iseq.putobject(node.accept(RubyVisitor.new))
  else
    iseq.putstring(node.accept(RubyVisitor.new))
  end
end
visit_unary(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1668
def visit_unary(node)
  method_id =
    case node.operator
    when "+", "-"
      "#{node.operator}@"
    else
      node.operator
    end

  visit_call(
    CommandCall.new(
      receiver: node.statement,
      operator: nil,
      message: Ident.new(value: method_id, location: Location.default),
      arguments: nil,
      block: nil,
      location: Location.default
    )
  )
end
visit_undef(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1689
def visit_undef(node)
  node.symbols.each_with_index do |symbol, index|
    iseq.pop if index != 0
    iseq.putspecialobject(PutSpecialObject::OBJECT_VMCORE)
    iseq.putspecialobject(PutSpecialObject::OBJECT_CBASE)
    visit(symbol)
    iseq.send(YARV.calldata(:"core#undef_method", 2))
  end
end
visit_unless(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1699
def visit_unless(node)
  statements_label = iseq.label

  visit(node.predicate)
  iseq.branchunless(statements_label)
  node.consequent ? visit(node.consequent) : iseq.putnil

  if last_statement?
    iseq.leave
    iseq.push(statements_label)
    visit(node.statements)
  else
    iseq.pop

    if node.consequent
      done_label = iseq.label
      iseq.jump(done_label)
      iseq.push(statements_label)
      visit(node.consequent)
      iseq.push(done_label)
    else
      iseq.push(statements_label)
    end
  end
end
visit_until(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1725
def visit_until(node)
  predicate_label = iseq.label
  statements_label = iseq.label

  iseq.jump(predicate_label)
  iseq.putnil
  iseq.pop
  iseq.jump(predicate_label)

  iseq.push(statements_label)
  visit(node.statements)
  iseq.pop

  iseq.push(predicate_label)
  visit(node.predicate)
  iseq.branchunless(statements_label)
  iseq.putnil if last_statement?
end
visit_var_field(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1744
def visit_var_field(node)
  case node.value
  when CVar, IVar
    name = node.value.value.to_sym
    iseq.inline_storage_for(name)
  when Ident
    name = node.value.value.to_sym

    if (local_variable = iseq.local_variable(name))
      local_variable
    else
      iseq.local_table.plain(name)
      iseq.local_variable(name)
    end
  end
end
visit_var_ref(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1761
def visit_var_ref(node)
  case node.value
  when Const
    iseq.opt_getconstant_path(constant_names(node))
  when CVar
    name = node.value.value.to_sym
    iseq.getclassvariable(name)
  when GVar
    iseq.getglobal(node.value.value.to_sym)
  when Ident
    lookup = iseq.local_variable(node.value.value.to_sym)

    case lookup.local
    when LocalTable::BlockLocal
      iseq.getblockparam(lookup.index, lookup.level)
    when LocalTable::PlainLocal
      iseq.getlocal(lookup.index, lookup.level)
    end
  when IVar
    name = node.value.value.to_sym
    iseq.getinstancevariable(name)
  when Kw
    case node.value.value
    when "false"
      iseq.putobject(false)
    when "nil"
      iseq.putnil
    when "self"
      iseq.putself
    when "true"
      iseq.putobject(true)
    end
  end
end
visit_vcall(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1796
def visit_vcall(node)
  iseq.putself
  iseq.send(
    YARV.calldata(
      node.value.value.to_sym,
      0,
      CallData::CALL_FCALL | CallData::CALL_VCALL |
        CallData::CALL_ARGS_SIMPLE
    )
  )
end
visit_when(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1808
def visit_when(node)
  visit(node.statements)
end
visit_while(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1812
def visit_while(node)
  predicate_label = iseq.label
  statements_label = iseq.label

  iseq.jump(predicate_label)
  iseq.putnil
  iseq.pop
  iseq.jump(predicate_label)

  iseq.push(statements_label)
  visit(node.statements)
  iseq.pop

  iseq.push(predicate_label)
  visit(node.predicate)
  iseq.branchif(statements_label)
  iseq.putnil if last_statement?
end
visit_word(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1831
def visit_word(node)
  if node.parts.length == 1 && node.parts.first.is_a?(TStringContent)
    visit(node.parts.first)
  else
    length = visit_string_parts(node)
    iseq.concatstrings(length)
  end
end
visit_words(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1840
def visit_words(node)
  if options.frozen_string_literal? &&
       (compiled = RubyVisitor.compile(node))
    iseq.duparray(compiled)
  else
    visit_all(node.elements)
    iseq.newarray(node.elements.length)
  end
end
visit_xstring_literal(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1850
def visit_xstring_literal(node)
  iseq.putself
  length = visit_string_parts(node)
  iseq.concatstrings(node.parts.length) if length > 1
  iseq.send(
    YARV.calldata(
      :`,
      1,
      CallData::CALL_FCALL | CallData::CALL_ARGS_SIMPLE
    )
  )
end
visit_yield(node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1863
def visit_yield(node)
  parts = argument_parts(node.arguments)
  visit_all(parts)
  iseq.invokeblock(YARV.calldata(nil, parts.length))
end
visit_zsuper(_node) click to toggle source
# File lib/syntax_tree/yarv/compiler.rb, line 1869
def visit_zsuper(_node)
  iseq.putself
  iseq.invokesuper(
    YARV.calldata(
      nil,
      0,
      CallData::CALL_FCALL | CallData::CALL_ARGS_SIMPLE |
        CallData::CALL_SUPER | CallData::CALL_ZSUPER
    ),
    nil
  )
end