class Riml::AST_Rewriter::ClassDefinitionToFunctions::SuperToSuperclassFunction

rewrites calls to ‘super’ in public/private non-initialize functions

Public Instance Methods

add_superclass_func_ref_to_constructor(superclass) click to toggle source
# File lib/riml/ast_rewriter.rb, line 790
def add_superclass_func_ref_to_constructor(superclass)
  super_func_name = superclass_func_name(superclass)
  assign_node = AssignNode.new('=',
    DictGetDotNode.new(
      GetVariableNode.new(nil, ast.constructor_obj_name),
      [super_func_name]
    ),
    CallNode.new(
      nil, 'function', [
        BinaryOperatorNode.new(
          '.',
          [
            BinaryOperatorNode.new(
              '.',
              [
                StringNode.new('<SNR>', :s),
                CallNode.new('s:', 'SID', []),
              ]
            ),
            StringNode.new("_s:#{super_func_name}", :s)
          ]
        )
      ]
    )
  )
  ast.constructor.expressions << assign_node
  reestablish_parents(ast.constructor)
end
match?(node) click to toggle source
# File lib/riml/ast_rewriter.rb, line 722
def match?(node)
  return false unless SuperNode === node
  n = node
  n = n.parent until DefNode === n || n.nil?
  return false if n.nil? || ast.constructor == n
  @function_node = n
end
replace(node) click to toggle source
# File lib/riml/ast_rewriter.rb, line 730
def replace(node)
  func_scope = 's:'
  superclass = classes[ast.superclass_full_name]
  while superclass && !superclass.has_function?(func_scope, superclass_func_name(superclass)) && superclass.superclass?
    superclass = classes[superclass.superclass_full_name]
  end
  superclass_function = superclass.find_function(func_scope, superclass_func_name(superclass))
  if superclass.nil? || !superclass_function
    error_msg = "super was called in class #{ast.full_name} in " \
      "function #{@function_node.original_name}, but there are no " \
      "functions with this name in that class's superclass hierarchy."
    error = Riml::InvalidSuper.new(error_msg, node)
    raise error
  end
  node_args = if node.arguments.empty? && !node.with_parens && superclass_function.splat
    [SplatNode.new(GetVariableNode.new('a:', '000'))]
  else
    if @function_node.private_function?
      node.arguments.unshift GetVariableNode.new(nil, @function_node.parameters.first)
    end
    node.arguments
  end
  # check if SplatNode is in node_args. If it is, check if the splat
  # value is equal to splat param. If it is, and we're inside a
  # private function, we have to add the explicit object (first
  # parameter to the function we're in) to the splat arg
  if @function_node.private_function?
    if (splat_node = node_args.detect { |arg| SplatNode === arg })
      self_var = GetVariableNode.new('a:', @function_node.parameters.first)
      splat_node.expression = BinaryOperatorNode.new('+', [ListNode.wrap(self_var), splat_node.expression])
      establish_parents(splat_node.expression)
    end
    # call s:ClassA_private_func(args)
    call_node_name = superclass_func_name(superclass)
  else
    # call self.ClassA_public_func(args)
    call_node_name = DictGetDotNode.new(
      GetVariableNode.new(nil, 'self'),
      [superclass_func_name(superclass)]
    )
  end
  call_node = CallNode.new(
    nil,
    call_node_name,
    node_args
  )

  call_node.super_call = true
  node.replace_with(call_node)
  # private functions are NOT extended in constructor function
  unless @function_node.private_function?
    add_superclass_func_ref_to_constructor(superclass)
  end
  reestablish_parents(@function_node)
end
superclass_func_name(superclass) click to toggle source
# File lib/riml/ast_rewriter.rb, line 786
def superclass_func_name(superclass)
  "#{superclass.name}_#{@function_node.original_name}"
end