2012-12-06 21:30:28 +01:00
|
|
|
module Mutant
|
2013-07-29 17:34:02 -07:00
|
|
|
|
2012-12-06 21:30:28 +01:00
|
|
|
# Generator for mutations
|
|
|
|
class Mutator
|
2013-07-29 17:34:02 -07:00
|
|
|
|
2012-12-06 21:30:28 +01:00
|
|
|
# Abstract base class for node mutators
|
|
|
|
class Node < self
|
2014-06-29 21:25:17 +00:00
|
|
|
include AbstractType, Unparser::Constants
|
|
|
|
include AST::NamedChildren, AST::NodePredicates, AST::Sexp, AST::Nodes
|
2012-12-06 21:30:28 +01:00
|
|
|
|
2014-08-16 20:23:51 +00:00
|
|
|
TAUTOLOGY = ->(_input) { true }
|
|
|
|
|
2014-06-29 21:25:17 +00:00
|
|
|
# Helper to define a named child
|
|
|
|
#
|
|
|
|
# @param [Parser::AST::Node] node
|
2013-06-21 15:02:47 +02:00
|
|
|
#
|
|
|
|
# @param [Fixnum] index
|
|
|
|
#
|
|
|
|
# @return [undefined]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def self.define_named_child(name, index)
|
2014-06-29 21:25:17 +00:00
|
|
|
super
|
2013-06-21 15:02:47 +02:00
|
|
|
|
2014-06-05 16:37:31 +00:00
|
|
|
define_method("emit_#{name}_mutations") do |&block|
|
|
|
|
mutate_child(index, &block)
|
2013-06-21 15:02:47 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
define_method("emit_#{name}") do |node|
|
|
|
|
emit_child_update(index, node)
|
|
|
|
end
|
|
|
|
end
|
2014-07-14 13:46:55 +00:00
|
|
|
private_class_method :define_named_child
|
2013-06-21 15:02:47 +02:00
|
|
|
|
2012-12-29 16:34:39 +01:00
|
|
|
private
|
2012-12-11 00:17:19 +01:00
|
|
|
|
2012-12-12 22:31:14 +01:00
|
|
|
# Return mutated node
|
|
|
|
#
|
2013-06-04 10:25:13 +02:00
|
|
|
# @return [Parser::AST::Node]
|
2012-12-12 22:31:14 +01:00
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
2012-12-11 00:17:19 +01:00
|
|
|
alias_method :node, :input
|
2012-12-12 22:31:14 +01:00
|
|
|
|
|
|
|
# Return duplicated node
|
|
|
|
#
|
2013-06-04 10:25:13 +02:00
|
|
|
# @return [Parser::AST::Node]
|
2012-12-12 22:31:14 +01:00
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
2012-12-11 00:17:19 +01:00
|
|
|
alias_method :dup_node, :dup_input
|
2012-12-06 21:30:28 +01:00
|
|
|
|
2014-06-29 21:25:17 +00:00
|
|
|
# Return ast meta description
|
|
|
|
#
|
|
|
|
# @return [AST::Meta]
|
|
|
|
#
|
2014-07-03 21:16:12 +00:00
|
|
|
# @api private
|
|
|
|
#
|
2014-06-29 21:25:17 +00:00
|
|
|
def meta
|
|
|
|
AST::Meta.for(node)
|
|
|
|
end
|
|
|
|
memoize :meta
|
|
|
|
|
2013-06-04 20:23:06 +02:00
|
|
|
# Return children
|
2012-12-06 21:30:28 +01:00
|
|
|
#
|
2013-06-04 20:23:06 +02:00
|
|
|
# @return [Array<Parser::AST::Node>]
|
2012-12-06 21:30:28 +01:00
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
2013-06-04 20:23:06 +02:00
|
|
|
def children
|
|
|
|
node.children
|
2012-12-06 21:30:28 +01:00
|
|
|
end
|
|
|
|
|
2013-06-04 20:23:06 +02:00
|
|
|
# Dispatch on child index
|
2012-12-06 21:30:28 +01:00
|
|
|
#
|
2013-06-04 20:23:06 +02:00
|
|
|
# @param [Fixnum] index
|
2012-12-06 21:30:28 +01:00
|
|
|
#
|
2013-06-04 20:23:06 +02:00
|
|
|
# @return [undefined]
|
2012-12-06 21:30:28 +01:00
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
2014-06-05 16:37:31 +00:00
|
|
|
def mutate_child(index, mutator = Mutator, &block)
|
2014-08-16 20:23:51 +00:00
|
|
|
block ||= TAUTOLOGY
|
2013-07-05 03:01:59 +02:00
|
|
|
child = children.at(index)
|
2013-06-24 22:10:40 +02:00
|
|
|
mutator.each(child, self) do |mutation|
|
2014-06-08 13:01:26 +00:00
|
|
|
next unless block.call(mutation)
|
|
|
|
emit_child_update(index, mutation)
|
2013-06-04 20:23:06 +02:00
|
|
|
end
|
2012-12-06 21:30:28 +01:00
|
|
|
end
|
|
|
|
|
2013-06-14 18:22:34 +02: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)
|
2014-06-03 03:51:22 +00:00
|
|
|
emit_type(*dup_children)
|
2013-06-14 18:22:34 +02:00
|
|
|
end
|
|
|
|
|
2013-06-04 20:23:06 +02:00
|
|
|
# Emit updated child
|
2012-12-06 21:30:28 +01:00
|
|
|
#
|
2013-06-04 20:23:06 +02:00
|
|
|
# @param [Fixnum] index
|
2013-07-05 03:01:59 +02:00
|
|
|
# @param [Parser::AST::Node] node
|
2012-12-06 21:30:28 +01:00
|
|
|
#
|
|
|
|
# @return [undefined]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
2013-07-05 03:01:59 +02:00
|
|
|
def emit_child_update(index, node)
|
2013-06-04 20:23:06 +02:00
|
|
|
new_children = children.dup
|
2013-07-27 20:21:27 +02:00
|
|
|
new_children[index] = node
|
2014-06-03 03:51:22 +00:00
|
|
|
emit_type(*new_children)
|
2012-12-06 21:30:28 +01:00
|
|
|
end
|
|
|
|
|
2013-06-04 20:23:06 +02:00
|
|
|
# Emit a new AST node with same class as wrapped node
|
2012-12-06 21:30:28 +01:00
|
|
|
#
|
2013-06-04 20:23:06 +02:00
|
|
|
# @param [Array<Parser::AST::Node>] children
|
2012-12-06 21:30:28 +01:00
|
|
|
#
|
2013-06-15 16:37:43 +02:00
|
|
|
# @return [undefined]
|
|
|
|
#
|
2012-12-06 21:30:28 +01:00
|
|
|
# @api private
|
|
|
|
#
|
2014-06-03 03:51:22 +00:00
|
|
|
def emit_type(*children)
|
2014-06-06 23:05:27 +00:00
|
|
|
emit(Parser::AST::Node.new(node.type, children))
|
2012-12-06 21:30:28 +01:00
|
|
|
end
|
|
|
|
|
2014-06-05 16:37:31 +00:00
|
|
|
# Emit singleton literals
|
|
|
|
#
|
|
|
|
# @return [undefined]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def emit_singletons
|
|
|
|
emit_nil
|
|
|
|
emit_self
|
|
|
|
end
|
|
|
|
|
|
|
|
# Emit a literal self
|
|
|
|
#
|
|
|
|
# @return [undefined]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def emit_self
|
|
|
|
emit(N_SELF)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Emit a literal nil
|
2012-12-06 21:30:28 +01:00
|
|
|
#
|
2013-06-25 00:33:28 -07:00
|
|
|
# @return [undefined]
|
2012-12-06 21:30:28 +01:00
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def emit_nil
|
2014-04-04 14:35:42 -04:00
|
|
|
emit(N_NIL) unless asgn_left?
|
2012-12-06 21:30:28 +01:00
|
|
|
end
|
|
|
|
|
2013-06-12 19:09:43 +02:00
|
|
|
# Emit values
|
|
|
|
#
|
|
|
|
# @param [Array<Object>] values
|
|
|
|
#
|
|
|
|
# @return [undefined]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def emit_values(values)
|
|
|
|
values.each do |value|
|
2014-06-03 03:51:22 +00:00
|
|
|
emit_type(value)
|
2013-06-12 19:09:43 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-06-10 13:42:47 +00:00
|
|
|
# Return parent node
|
|
|
|
#
|
|
|
|
# @return [Parser::AST::Node] node
|
2014-08-07 09:35:30 -07:00
|
|
|
# if parent with node is present
|
2014-06-10 13:42:47 +00:00
|
|
|
#
|
|
|
|
# @return [nil]
|
|
|
|
# otherwise
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def parent_node
|
2014-06-10 15:43:38 +00:00
|
|
|
parent.node if parent
|
2014-06-10 13:42:47 +00:00
|
|
|
end
|
|
|
|
|
2013-07-14 21:37:22 +02:00
|
|
|
# Return parent type
|
|
|
|
#
|
|
|
|
# @return [Symbol] type
|
2014-08-07 09:00:31 -07:00
|
|
|
# if parent with type is present
|
2013-07-14 21:37:22 +02:00
|
|
|
#
|
|
|
|
# @return [nil]
|
|
|
|
# otherwise
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def parent_type
|
2014-06-10 15:43:38 +00:00
|
|
|
parent_node.type if parent_node
|
2013-07-14 21:37:22 +02:00
|
|
|
end
|
|
|
|
|
2013-09-07 23:10:25 -07:00
|
|
|
# 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?
|
2014-06-29 21:25:17 +00:00
|
|
|
AST::Types::OP_ASSIGN.include?(parent_type) && parent.node.children.first.equal?(node)
|
2013-09-07 23:10:25 -07:00
|
|
|
end
|
|
|
|
|
2014-08-16 20:23:51 +00:00
|
|
|
# Return children indices
|
|
|
|
#
|
|
|
|
# @param [Range] range
|
|
|
|
#
|
|
|
|
# @return [Enumerable<Fixnum>]
|
|
|
|
#
|
|
|
|
# @api pirvate
|
|
|
|
#
|
|
|
|
def children_indices(range)
|
|
|
|
range_end = range.end
|
|
|
|
last_index = range_end >= 0 ? range_end : children.length + range_end
|
|
|
|
range.begin.upto(last_index)
|
|
|
|
end
|
|
|
|
|
2013-06-04 10:25:13 +02:00
|
|
|
end # Node
|
|
|
|
end # Mutator
|
|
|
|
end # Mutant
|