free_mutant/lib/mutant/mutator/node.rb

230 lines
4.7 KiB
Ruby
Raw Normal View History

# encoding: utf-8
module Mutant
2013-07-29 20:34:02 -04:00
# Generator for mutations
class Mutator
2013-07-29 20:34:02 -04:00
# Abstract base class for node mutators
class Node < self
2013-06-14 13:35:09 -04:00
include AbstractType, NodeHelpers, Unparser::Constants
2013-06-21 09:02:47 -04:00
# Define named child
#
# @param [Symbol] name
# @param [Fixnum] index
#
# @return [undefined]
#
# @api private
#
def self.define_named_child(name, index)
2013-12-07 14:53:56 -05:00
define_method(name) do
children.at(index)
2013-06-21 09:02:47 -04:00
end
define_method("emit_#{name}_mutations") do
mutate_child(index)
end
define_method("emit_#{name}") do |node|
emit_child_update(index, node)
end
end
private_class_method :define_named_child
# Define remaining children
#
# @param [Array<Symbol>] names
2013-06-21 09:02:47 -04:00
#
# @return [undefined]
#
# @api private
#
def self.define_remaining_children(names)
define_method(:remaining_children_with_index) do
children.each_with_index.drop(names.length)
end
define_method(:remaining_children_indices) do
children.each_index.drop(names.length)
end
2013-06-21 09:02:47 -04:00
define_method(:remaining_children) do
children.drop(names.length)
2013-06-21 09:02:47 -04:00
end
end
private_class_method :define_remaining_children
# Create name helpers
#
# @return [undefined]
#
# @api private
#
def self.children(*names)
names.each_with_index do |name, index|
define_named_child(name, index)
end
define_remaining_children(names)
2013-06-21 09:02:47 -04:00
end
private_class_method :children
private
# Return mutated node
#
# @return [Parser::AST::Node]
#
# @api private
#
alias_method :node, :input
# Return duplicated node
#
# @return [Parser::AST::Node]
#
# @api private
#
alias_method :dup_node, :dup_input
2013-06-04 17:44:17 -04:00
# Emit children mutations
#
# @return [undefined]
#
# @api private
#
def emit_children_mutations
Mutator::Util::Array.each(children, self) do |children|
2013-06-10 04:15:59 -04:00
emit_self(*children)
2013-06-04 17:44:17 -04:00
end
end
# Return children
#
# @return [Array<Parser::AST::Node>]
#
# @api private
#
def children
node.children
end
# Dispatch on child index
#
# @param [Fixnum] index
#
# @return [undefined]
#
# @api private
#
def mutate_child(index, mutator = Mutator)
2013-07-04 21:01:59 -04:00
child = children.at(index)
mutator.each(child, self) do |mutation|
emit_child_update(index, mutation)
end
end
2013-06-14 12:22:34 -04:00
# Emit delete child mutation
#
# @param [Fixnum] index
#
# @return [undefined]
#
# @api private
#
def delete_child(index)
dup_children = children.dup
dup_children.delete_at(index)
emit_self(*dup_children)
end
# Emit updated child
#
# @param [Fixnum] index
2013-07-04 21:01:59 -04:00
# @param [Parser::AST::Node] node
#
# @return [undefined]
#
# @api private
#
2013-07-04 21:01:59 -04:00
def emit_child_update(index, node)
new_children = children.dup
new_children[index] = node
2013-06-10 04:15:59 -04:00
emit_self(*new_children)
end
# Emit a new AST node with same class as wrapped node
#
# @param [Array<Parser::AST::Node>] children
#
2013-06-15 10:37:43 -04:00
# @return [undefined]
#
# @api private
#
2013-06-10 04:15:59 -04:00
def emit_self(*children)
emit(new_self(*children))
end
# Emit a new AST node with NilLiteral class
#
2013-06-25 03:33:28 -04:00
# @return [undefined]
#
# @api private
#
def emit_nil
2014-04-04 14:35:42 -04:00
emit(N_NIL) unless asgn_left?
end
2013-06-10 04:15:59 -04:00
# Return new self typed child
#
# @return [Parser::AST::Node]
#
# @api private
#
def new_self(*children)
Parser::AST::Node.new(node.type, children)
end
2013-06-12 13:09:43 -04:00
# Emit values
#
# @param [Array<Object>] values
#
# @return [undefined]
#
# @api private
#
def emit_values(values)
values.each do |value|
emit_self(value)
end
end
# Return parent type
#
# @return [Symbol] type
# if parent with type is presnet
#
# @return [nil]
# otherwise
#
# @api private
#
def parent_type
parent && parent.node.type
end
# Test if the node is the left of an or_asgn or op_asgn
#
# @return [Boolean]
#
# @api private
#
2014-04-04 14:35:42 -04:00
def asgn_left?
2013-09-08 05:37:53 -04:00
OP_ASSIGN.include?(parent_type) && parent.left.equal?(node)
end
end # Node
end # Mutator
end # Mutant