mutant 0.11.17 → 0.11.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/mutant/bootstrap.rb +1 -1
- data/lib/mutant/cli/command/environment/run.rb +1 -1
- data/lib/mutant/mutator/node/literal/regex.rb +8 -8
- data/lib/mutant/mutator/node/send.rb +27 -17
- data/lib/mutant/mutator/regexp.rb +211 -0
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant.rb +1 -18
- metadata +10 -33
- data/lib/mutant/ast/regexp/transformer/direct.rb +0 -145
- data/lib/mutant/ast/regexp/transformer/named_group.rb +0 -50
- data/lib/mutant/ast/regexp/transformer/options_group.rb +0 -68
- data/lib/mutant/ast/regexp/transformer/quantifier.rb +0 -92
- data/lib/mutant/ast/regexp/transformer/recursive.rb +0 -56
- data/lib/mutant/ast/regexp/transformer/root.rb +0 -28
- data/lib/mutant/ast/regexp/transformer/text.rb +0 -58
- data/lib/mutant/ast/regexp/transformer.rb +0 -152
- data/lib/mutant/ast/regexp.rb +0 -54
- data/lib/mutant/mutator/node/regexp/alternation_meta.rb +0 -20
- data/lib/mutant/mutator/node/regexp/beginning_of_line_anchor.rb +0 -20
- data/lib/mutant/mutator/node/regexp/capture_group.rb +0 -23
- data/lib/mutant/mutator/node/regexp/character_type.rb +0 -31
- data/lib/mutant/mutator/node/regexp/end_of_line_anchor.rb +0 -20
- data/lib/mutant/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor.rb +0 -20
- data/lib/mutant/mutator/node/regexp/named_group.rb +0 -39
- data/lib/mutant/mutator/node/regexp/zero_or_more.rb +0 -34
- data/lib/mutant/mutator/node/regexp.rb +0 -20
@@ -1,50 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class AST
|
5
|
-
module Regexp
|
6
|
-
class Transformer
|
7
|
-
# Transformer for named groups
|
8
|
-
class NamedGroup < self
|
9
|
-
register :regexp_named_group
|
10
|
-
|
11
|
-
# Mapper from `Regexp::Expression` to `Parser::AST::Node`
|
12
|
-
class ExpressionToAST < Transformer::ExpressionToAST
|
13
|
-
|
14
|
-
# Transform named group into node
|
15
|
-
#
|
16
|
-
# @return [Parser::AST::Node]
|
17
|
-
def call
|
18
|
-
quantify(ast(expression.name, *children))
|
19
|
-
end
|
20
|
-
end # ExpressionToAST
|
21
|
-
|
22
|
-
# Mapper from `Parser::AST::Node` to `Regexp::Expression`
|
23
|
-
class ASTToExpression < Transformer::ASTToExpression
|
24
|
-
include NamedChildren
|
25
|
-
|
26
|
-
children :name
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def transform
|
31
|
-
named_group.tap do |expression|
|
32
|
-
expression.expressions = subexpressions
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def subexpressions
|
37
|
-
remaining_children.map(&Regexp.public_method(:to_expression))
|
38
|
-
end
|
39
|
-
|
40
|
-
def named_group
|
41
|
-
::Regexp::Expression::Group::Named.new(
|
42
|
-
::Regexp::Token.new(:group, :named, "(?<#{name}>")
|
43
|
-
)
|
44
|
-
end
|
45
|
-
end # ASTToExpression
|
46
|
-
end # NamedGroup
|
47
|
-
end # Transformer
|
48
|
-
end # Regexp
|
49
|
-
end # AST
|
50
|
-
end # Mutant
|
@@ -1,68 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class AST
|
5
|
-
module Regexp
|
6
|
-
class Transformer
|
7
|
-
# Transformer for option groups
|
8
|
-
class OptionsGroup < self
|
9
|
-
register :regexp_options_group
|
10
|
-
register :regexp_options_switch_group
|
11
|
-
|
12
|
-
# Mapper from `Regexp::Expression` to `Parser::AST::Node`
|
13
|
-
class ExpressionToAST < Transformer::ExpressionToAST
|
14
|
-
|
15
|
-
# Transform options group into node
|
16
|
-
#
|
17
|
-
# @return [Parser::AST::Node]
|
18
|
-
def call
|
19
|
-
quantify(ast(expression.option_changes, *children))
|
20
|
-
end
|
21
|
-
end # ExpressionToAST
|
22
|
-
|
23
|
-
# Mapper from `Parser::AST::Node` to `Regexp::Expression`
|
24
|
-
class ASTToExpression < Transformer::ASTToExpression
|
25
|
-
include NamedChildren
|
26
|
-
|
27
|
-
children :option_changes
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def transform
|
32
|
-
options_group.tap do |expression|
|
33
|
-
expression.expressions = subexpressions
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def subexpressions
|
38
|
-
remaining_children.map(&Regexp.public_method(:to_expression))
|
39
|
-
end
|
40
|
-
|
41
|
-
def options_group
|
42
|
-
::Regexp::Expression::Group::Options.new(
|
43
|
-
::Regexp::Token.new(:group, type, text)
|
44
|
-
)
|
45
|
-
end
|
46
|
-
|
47
|
-
def type
|
48
|
-
{
|
49
|
-
regexp_options_group: :options,
|
50
|
-
regexp_options_switch_group: :options_switch
|
51
|
-
}.fetch(node.type)
|
52
|
-
end
|
53
|
-
|
54
|
-
def text
|
55
|
-
pos, neg = option_changes.partition { |_opt, val| val }.map do |arr|
|
56
|
-
arr.map(&:first).join
|
57
|
-
end
|
58
|
-
neg_opt_sep = '-' unless neg.empty?
|
59
|
-
content_sep = ':' unless type.equal?(:options_switch)
|
60
|
-
|
61
|
-
"(?#{pos}#{neg_opt_sep}#{neg}#{content_sep}"
|
62
|
-
end
|
63
|
-
end # ASTToExpression
|
64
|
-
end # OptionsGroup
|
65
|
-
end # Transformer
|
66
|
-
end # Regexp
|
67
|
-
end # AST
|
68
|
-
end # Mutant
|
@@ -1,92 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class AST
|
5
|
-
module Regexp
|
6
|
-
class Transformer
|
7
|
-
# Transformer for regexp quantifiers
|
8
|
-
class Quantifier < self
|
9
|
-
# Mapper from `Regexp::Expression` to `Parser::AST::Node`
|
10
|
-
class ExpressionToAST < Transformer::ExpressionToAST
|
11
|
-
# Transform quantifier into node
|
12
|
-
#
|
13
|
-
# @return [Parser::AST::Node]
|
14
|
-
def call
|
15
|
-
ast(expression.min, expression.max)
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def type
|
21
|
-
:"regexp_#{expression.mode}_#{expression.token}"
|
22
|
-
end
|
23
|
-
end # ExpressionToAST
|
24
|
-
|
25
|
-
# Mapper from `Parser::AST::Node` to `Regexp::Expression`
|
26
|
-
class ASTToExpression < Transformer::ASTToExpression
|
27
|
-
include NamedChildren
|
28
|
-
|
29
|
-
children :min, :max, :subject
|
30
|
-
|
31
|
-
Quantifier = Class.new.include(Concord::Public.new(:type, :suffix, :mode))
|
32
|
-
|
33
|
-
QUANTIFIER_MAP = {
|
34
|
-
regexp_greedy_zero_or_more: [:zero_or_more, '*', :greedy],
|
35
|
-
regexp_greedy_one_or_more: [:one_or_more, '+', :greedy],
|
36
|
-
regexp_greedy_zero_or_one: [:zero_or_one, '?', :greedy],
|
37
|
-
regexp_possessive_zero_or_one: [:zero_or_one, '?+', :possessive],
|
38
|
-
regexp_reluctant_zero_or_more: [:zero_or_more, '*?', :reluctant],
|
39
|
-
regexp_reluctant_one_or_more: [:one_or_more, '+?', :reluctant],
|
40
|
-
regexp_possessive_zero_or_more: [:zero_or_more, '*+', :possessive],
|
41
|
-
regexp_possessive_one_or_more: [:one_or_more, '++', :possessive],
|
42
|
-
regexp_greedy_interval: [:interval, '', :greedy],
|
43
|
-
regexp_reluctant_interval: [:interval, '?', :reluctant],
|
44
|
-
regexp_possessive_interval: [:interval, '+', :possessive]
|
45
|
-
}.transform_values { |arguments| Quantifier.new(*arguments) }
|
46
|
-
.to_h
|
47
|
-
.freeze
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def transform
|
52
|
-
Regexp.to_expression(subject).dup.tap do |expression|
|
53
|
-
expression.quantify(type, text, min, max, mode)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def text
|
58
|
-
if type.equal?(:interval)
|
59
|
-
interval_text + suffix
|
60
|
-
else
|
61
|
-
suffix
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def type
|
66
|
-
quantifier.type
|
67
|
-
end
|
68
|
-
|
69
|
-
def suffix
|
70
|
-
quantifier.suffix
|
71
|
-
end
|
72
|
-
|
73
|
-
def mode
|
74
|
-
quantifier.mode
|
75
|
-
end
|
76
|
-
|
77
|
-
def quantifier
|
78
|
-
QUANTIFIER_MAP.fetch(node.type)
|
79
|
-
end
|
80
|
-
|
81
|
-
def interval_text
|
82
|
-
interval = [min, max].map { |num| num if num.positive? }.uniq
|
83
|
-
"{#{interval.join(',')}}"
|
84
|
-
end
|
85
|
-
end # ASTToExpression
|
86
|
-
|
87
|
-
ASTToExpression::QUANTIFIER_MAP.keys.each(&method(:register))
|
88
|
-
end # Quantifier
|
89
|
-
end # Transformer
|
90
|
-
end # Regexp
|
91
|
-
end # AST
|
92
|
-
end # Mutant
|
@@ -1,56 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class AST
|
5
|
-
module Regexp
|
6
|
-
class Transformer
|
7
|
-
# Transformer for nodes with children
|
8
|
-
class Recursive < self
|
9
|
-
# Mapper from `Regexp::Expression` to `Parser::AST::Node`
|
10
|
-
class ExpressionToAST < Transformer::ExpressionToAST
|
11
|
-
# Transform expression and children into nodes
|
12
|
-
#
|
13
|
-
# @return [Parser::AST::Node]
|
14
|
-
def call
|
15
|
-
quantify(ast(*children))
|
16
|
-
end
|
17
|
-
end # ExpressionToAST
|
18
|
-
|
19
|
-
# Mapper from `Parser::AST::Node` to `Regexp::Expression`
|
20
|
-
class ASTToExpression < Transformer::ASTToExpression
|
21
|
-
include LookupTable
|
22
|
-
|
23
|
-
# Expression::Sequence represents conditional branches, alternation branches, and intersection branches
|
24
|
-
# rubocop:disable Layout/LineLength
|
25
|
-
TABLE = Table.create(
|
26
|
-
[:regexp_alternation_meta, [:meta, :alternation, '|'], ::Regexp::Expression::Alternation],
|
27
|
-
[:regexp_atomic_group, [:group, :atomic, '(?>'], ::Regexp::Expression::Group::Atomic],
|
28
|
-
[:regexp_capture_group, [:group, :capture, '('], ::Regexp::Expression::Group::Capture],
|
29
|
-
[:regexp_character_set, [:set, :character, '['], ::Regexp::Expression::CharacterSet],
|
30
|
-
[:regexp_intersection_set, [:set, :intersection, '&&'], ::Regexp::Expression::CharacterSet::Intersection],
|
31
|
-
[:regexp_lookahead_assertion, [:assertion, :lookahead, '(?='], ::Regexp::Expression::Assertion::Lookahead],
|
32
|
-
[:regexp_lookbehind_assertion, [:assertion, :lookbehind, '(?<='], ::Regexp::Expression::Assertion::Lookbehind],
|
33
|
-
[:regexp_nlookahead_assertion, [:assertion, :nlookahead, '(?!'], ::Regexp::Expression::Assertion::NegativeLookahead],
|
34
|
-
[:regexp_nlookbehind_assertion, [:assertion, :nlookbehind, '(?<!'], ::Regexp::Expression::Assertion::NegativeLookbehind],
|
35
|
-
[:regexp_open_conditional, [:conditional, :open, '(?'], ::Regexp::Expression::Conditional::Expression],
|
36
|
-
[:regexp_passive_group, [:group, :passive, '(?:'], ::Regexp::Expression::Group::Passive],
|
37
|
-
[:regexp_range_set, [:set, :range, '-'], ::Regexp::Expression::CharacterSet::Range],
|
38
|
-
[:regexp_sequence_expression, [:expression, :sequence, ''], ::Regexp::Expression::Sequence]
|
39
|
-
)
|
40
|
-
# rubocop:enable Layout/LineLength
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def transform
|
45
|
-
expression_class.new(expression_token).tap do |expression|
|
46
|
-
expression.expressions = subexpressions
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end # ASTToExpression
|
50
|
-
|
51
|
-
ASTToExpression::TABLE.types.each(&method(:register))
|
52
|
-
end # Recursive
|
53
|
-
end # Transformer
|
54
|
-
end # Regexp
|
55
|
-
end # AST
|
56
|
-
end # Mutant
|
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class AST
|
5
|
-
module Regexp
|
6
|
-
class Transformer
|
7
|
-
# Transformer for root nodes
|
8
|
-
class Root < self
|
9
|
-
register :regexp_root_expression
|
10
|
-
|
11
|
-
ExpressionToAST = Class.new(Recursive::ExpressionToAST)
|
12
|
-
|
13
|
-
# Mapper from `Parser::AST::Node` to `Regexp::Expression`
|
14
|
-
class ASTToExpression < Transformer::ASTToExpression
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def transform
|
19
|
-
::Regexp::Expression::Root.build.tap do |root|
|
20
|
-
root.expressions = subexpressions
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end # ASTToExpression
|
24
|
-
end # Root
|
25
|
-
end # Transformer
|
26
|
-
end # Regexp
|
27
|
-
end # AST
|
28
|
-
end # Mutant
|
@@ -1,58 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class AST
|
5
|
-
module Regexp
|
6
|
-
class Transformer
|
7
|
-
# Regexp AST transformer for nodes that encode a text value
|
8
|
-
class Text < self
|
9
|
-
# Mapper from `Regexp::Expression` to `Parser::AST::Node`
|
10
|
-
class ExpressionToAST < Transformer::ExpressionToAST
|
11
|
-
# Transform expression into node preserving text value
|
12
|
-
#
|
13
|
-
# @return [Parser::AST::Node]
|
14
|
-
def call
|
15
|
-
quantify(ast(expression.text))
|
16
|
-
end
|
17
|
-
end # ExpressionToAST
|
18
|
-
|
19
|
-
# Mapper from `Parser::AST::Node` to `Regexp::Expression`
|
20
|
-
class ASTToExpression < Transformer::ASTToExpression
|
21
|
-
include LookupTable
|
22
|
-
|
23
|
-
# rubocop:disable Layout/LineLength
|
24
|
-
TABLE = Table.create(
|
25
|
-
[:regexp_literal_literal, %i[literal literal], ::Regexp::Expression::Literal],
|
26
|
-
[:regexp_comment_group, %i[group comment], ::Regexp::Expression::Group::Comment],
|
27
|
-
[:regexp_number_backref, %i[backref number], ::Regexp::Expression::Backreference::Number],
|
28
|
-
[:regexp_name_call_backref, %i[backref name_call], ::Regexp::Expression::Backreference::NameCall],
|
29
|
-
[:regexp_whitespace_free_space, %i[free_space whitespace], ::Regexp::Expression::WhiteSpace],
|
30
|
-
[:regexp_comment_free_space, %i[free_space comment], ::Regexp::Expression::WhiteSpace],
|
31
|
-
[:regexp_hex_escape, %i[escape hex], ::Regexp::Expression::EscapeSequence::Hex],
|
32
|
-
[:regexp_octal_escape, %i[escape octal], ::Regexp::Expression::EscapeSequence::Octal],
|
33
|
-
[:regexp_literal_escape, %i[escape literal], ::Regexp::Expression::EscapeSequence::Literal],
|
34
|
-
[:regexp_backslash_escape, %i[escape backslash], ::Regexp::Expression::EscapeSequence::Literal],
|
35
|
-
[:regexp_tab_escape, %i[escape tab], ::Regexp::Expression::EscapeSequence::Literal],
|
36
|
-
[:regexp_codepoint_list_escape, %i[escape codepoint_list], ::Regexp::Expression::EscapeSequence::CodepointList],
|
37
|
-
[:regexp_codepoint_escape, %i[escape codepoint], ::Regexp::Expression::EscapeSequence::Codepoint],
|
38
|
-
[:regexp_control_escape, %i[escape control], ::Regexp::Expression::EscapeSequence::Control],
|
39
|
-
[:regexp_meta_sequence_escape, %i[escape meta_sequence], ::Regexp::Expression::EscapeSequence::Control],
|
40
|
-
[:regexp_condition_conditional, %i[conditional condition], ::Regexp::Expression::Conditional::Condition]
|
41
|
-
)
|
42
|
-
# rubocop:enable Layout/LineLength
|
43
|
-
|
44
|
-
private
|
45
|
-
|
46
|
-
def transform
|
47
|
-
token = expression_token.dup
|
48
|
-
token.text = Util.one(node.children)
|
49
|
-
expression_class.new(token)
|
50
|
-
end
|
51
|
-
end # ASTToExpression
|
52
|
-
|
53
|
-
ASTToExpression::TABLE.types.each(&method(:register))
|
54
|
-
end # Text
|
55
|
-
end # Transformer
|
56
|
-
end # Regexp
|
57
|
-
end # AST
|
58
|
-
end # Mutant
|
@@ -1,152 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class AST
|
5
|
-
module Regexp
|
6
|
-
# Regexp bijective mapper
|
7
|
-
#
|
8
|
-
# Transforms parsed regular expression representation from
|
9
|
-
# `Regexp::Expression` instances (provided by `regexp_parser`) into
|
10
|
-
# equivalent representations using `Parser::AST::Node`
|
11
|
-
class Transformer
|
12
|
-
include AbstractType
|
13
|
-
|
14
|
-
REGISTRY = Registry.new(
|
15
|
-
->(type) { fail "No regexp transformer registered for: #{type}" }
|
16
|
-
)
|
17
|
-
|
18
|
-
# Lookup transformer class for regular expression node type
|
19
|
-
#
|
20
|
-
# @param type [Symbol]
|
21
|
-
#
|
22
|
-
# @return [Class<Transformer>]
|
23
|
-
def self.lookup(type)
|
24
|
-
REGISTRY.lookup(type)
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.register(type)
|
28
|
-
REGISTRY.register(type, self)
|
29
|
-
end
|
30
|
-
private_class_method :register
|
31
|
-
|
32
|
-
# Transform expression
|
33
|
-
#
|
34
|
-
# @param expression [Regexp::Expression]
|
35
|
-
#
|
36
|
-
# @return [Parser::AST::Node]
|
37
|
-
def self.to_ast(expression)
|
38
|
-
self::ExpressionToAST.call(expression)
|
39
|
-
end
|
40
|
-
|
41
|
-
# Transform node
|
42
|
-
#
|
43
|
-
# @param node [Parser::AST::Node]
|
44
|
-
#
|
45
|
-
# @return [Regexp::Expression]
|
46
|
-
def self.to_expression(node)
|
47
|
-
self::ASTToExpression.call(node)
|
48
|
-
end
|
49
|
-
|
50
|
-
# Abstract expression transformer
|
51
|
-
class ExpressionToAST
|
52
|
-
PREFIX = :regexp
|
53
|
-
|
54
|
-
include Concord.new(:expression), Procto, AST::Sexp, AbstractType, Adamantium
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
def ast(*children)
|
59
|
-
s(type, *children)
|
60
|
-
end
|
61
|
-
|
62
|
-
def quantify(node)
|
63
|
-
return node unless expression.quantified?
|
64
|
-
|
65
|
-
Quantifier.to_ast(expression.quantifier).append(node)
|
66
|
-
end
|
67
|
-
|
68
|
-
def children
|
69
|
-
expression.map(&Regexp.public_method(:to_ast))
|
70
|
-
end
|
71
|
-
|
72
|
-
def type
|
73
|
-
:"#{PREFIX}_#{expression.token}_#{expression.type}"
|
74
|
-
end
|
75
|
-
end # ExpressionToAST
|
76
|
-
|
77
|
-
# Abstract node transformer
|
78
|
-
class ASTToExpression
|
79
|
-
include Concord.new(:node), Procto, AbstractType, Adamantium
|
80
|
-
|
81
|
-
# Call generic transform method and freeze result
|
82
|
-
#
|
83
|
-
# @return [Regexp::Expression]
|
84
|
-
def call
|
85
|
-
transform.freeze
|
86
|
-
end
|
87
|
-
|
88
|
-
private
|
89
|
-
|
90
|
-
abstract_method :transform
|
91
|
-
|
92
|
-
def subexpressions
|
93
|
-
node.children.map(&Regexp.public_method(:to_expression))
|
94
|
-
end
|
95
|
-
end # ASTToExpression
|
96
|
-
|
97
|
-
# Mixin for node transformers
|
98
|
-
#
|
99
|
-
# Helps construct a mapping from Parser::AST::Node domain to
|
100
|
-
# Regexp::Expression domain
|
101
|
-
module LookupTable
|
102
|
-
Mapping = Class.new.include(Concord::Public.new(:token, :regexp_class))
|
103
|
-
|
104
|
-
# Table mapping ast types to object information for regexp domain
|
105
|
-
class Table
|
106
|
-
|
107
|
-
# Coerce array of mapping information into structured table
|
108
|
-
#
|
109
|
-
# @param [Array(Symbol, Array, Class<Regexp::Expression>)]
|
110
|
-
#
|
111
|
-
# @return [Table]
|
112
|
-
def self.create(*rows)
|
113
|
-
table = rows.to_h do |ast_type, token, klass|
|
114
|
-
[ast_type, Mapping.new(::Regexp::Token.new(*token), klass)]
|
115
|
-
end
|
116
|
-
|
117
|
-
new(table)
|
118
|
-
end
|
119
|
-
|
120
|
-
include Concord.new(:table), Adamantium
|
121
|
-
|
122
|
-
# Types defined by the table
|
123
|
-
#
|
124
|
-
# @return [Array<Symbol>]
|
125
|
-
def types
|
126
|
-
table.keys
|
127
|
-
end
|
128
|
-
|
129
|
-
# Lookup mapping information given an ast node type
|
130
|
-
#
|
131
|
-
# @param type [Symbol]
|
132
|
-
#
|
133
|
-
# @return [Mapping]
|
134
|
-
def lookup(type)
|
135
|
-
table.fetch(type)
|
136
|
-
end
|
137
|
-
end # Table
|
138
|
-
|
139
|
-
private
|
140
|
-
|
141
|
-
def expression_token
|
142
|
-
self.class::TABLE.lookup(node.type).token
|
143
|
-
end
|
144
|
-
|
145
|
-
def expression_class
|
146
|
-
self.class::TABLE.lookup(node.type).regexp_class
|
147
|
-
end
|
148
|
-
end # LookupTable
|
149
|
-
end # Transformer
|
150
|
-
end # Regexp
|
151
|
-
end # AST
|
152
|
-
end # Mutant
|
data/lib/mutant/ast/regexp.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class AST
|
5
|
-
# Regexp source mapper
|
6
|
-
module Regexp
|
7
|
-
# Parse regex string into expression
|
8
|
-
#
|
9
|
-
# @param regexp [String]
|
10
|
-
#
|
11
|
-
# @return [Regexp::Expression, nil]
|
12
|
-
def self.parse(regexp)
|
13
|
-
::Regexp::Parser.parse(regexp)
|
14
|
-
end
|
15
|
-
|
16
|
-
# Convert expression into ast node
|
17
|
-
#
|
18
|
-
# @param expression [Regexp::Expression]
|
19
|
-
#
|
20
|
-
# @return [Parser::AST::Node]
|
21
|
-
def self.to_ast(expression)
|
22
|
-
ast_type = :"regexp_#{expression.token}_#{expression.type}"
|
23
|
-
|
24
|
-
Transformer.lookup(ast_type).to_ast(expression)
|
25
|
-
end
|
26
|
-
|
27
|
-
# Convert node into expression
|
28
|
-
#
|
29
|
-
# @param node [Parser::AST::Node]
|
30
|
-
#
|
31
|
-
# @return [Regexp::Expression]
|
32
|
-
def self.to_expression(node)
|
33
|
-
Transformer.lookup(node.type).to_expression(node)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Convert's a `parser` `regexp` node into more fine-grained AST nodes.
|
37
|
-
#
|
38
|
-
# @param node [Parser::AST::Node]
|
39
|
-
#
|
40
|
-
# @return [Parser::AST::Node]
|
41
|
-
def self.expand_regexp_ast(node)
|
42
|
-
*body, _opts = node.children
|
43
|
-
|
44
|
-
# NOTE: We only mutate parts of regexp body if the body is composed of
|
45
|
-
# only strings. Regular expressions with interpolation are skipped
|
46
|
-
return unless body.all? { |child| child.type.equal?(:str) }
|
47
|
-
|
48
|
-
body_expression = parse(body.map(&:children).join)
|
49
|
-
|
50
|
-
to_ast(body_expression)
|
51
|
-
end
|
52
|
-
end # Regexp
|
53
|
-
end # AST
|
54
|
-
end # Mutant
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Mutator
|
5
|
-
class Node
|
6
|
-
module Regexp
|
7
|
-
# Mutator for pipe in `/foo|bar/` regexp
|
8
|
-
class AlternationMeta < Node
|
9
|
-
handle(:regexp_alternation_meta)
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
def dispatch
|
14
|
-
children.each_index(&method(:delete_child))
|
15
|
-
end
|
16
|
-
end # AlternationMeta
|
17
|
-
end # Regexp
|
18
|
-
end # Node
|
19
|
-
end # Mutator
|
20
|
-
end # Mutant
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Mutator
|
5
|
-
class Node
|
6
|
-
module Regexp
|
7
|
-
# Mutator for beginning of line anchor `^`
|
8
|
-
class BeginningOfLineAnchor < Node
|
9
|
-
handle(:regexp_bol_anchor)
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
def dispatch
|
14
|
-
emit(s(:regexp_bos_anchor))
|
15
|
-
end
|
16
|
-
end # BeginningOfLineAnchor
|
17
|
-
end # Regexp
|
18
|
-
end # Node
|
19
|
-
end # Mutator
|
20
|
-
end # Mutant
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Mutator
|
5
|
-
class Node
|
6
|
-
module Regexp
|
7
|
-
# Mutator for regexp capture groups, such as `/(foo)/`
|
8
|
-
class CaptureGroup < Node
|
9
|
-
handle(:regexp_capture_group)
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
def dispatch
|
14
|
-
return if children.empty?
|
15
|
-
|
16
|
-
emit(s(:regexp_passive_group, *children))
|
17
|
-
children.each_index(&method(:mutate_child))
|
18
|
-
end
|
19
|
-
end # EndOfLineAnchor
|
20
|
-
end # Regexp
|
21
|
-
end # Node
|
22
|
-
end # Mutator
|
23
|
-
end # Mutant
|
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Mutator
|
5
|
-
class Node
|
6
|
-
module Regexp
|
7
|
-
# Character type mutator
|
8
|
-
class CharacterType < Node
|
9
|
-
map = {
|
10
|
-
regexp_digit_type: :regexp_nondigit_type,
|
11
|
-
regexp_hex_type: :regexp_nonhex_type,
|
12
|
-
regexp_space_type: :regexp_nonspace_type,
|
13
|
-
regexp_word_boundary_anchor: :regexp_nonword_boundary_anchor,
|
14
|
-
regexp_word_type: :regexp_nonword_type,
|
15
|
-
regexp_xgrapheme_type: :regexp_linebreak_type
|
16
|
-
}
|
17
|
-
|
18
|
-
MAP = map.merge(map.invert)
|
19
|
-
|
20
|
-
handle(*MAP.keys)
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def dispatch
|
25
|
-
emit(s(MAP.fetch(node.type)))
|
26
|
-
end
|
27
|
-
end # CharacterType
|
28
|
-
end # Regexp
|
29
|
-
end # Node
|
30
|
-
end # Mutator
|
31
|
-
end # Mutant
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Mutator
|
5
|
-
class Node
|
6
|
-
module Regexp
|
7
|
-
# Mutator for end of line anchor `$`
|
8
|
-
class EndOfLineAnchor < Node
|
9
|
-
handle(:regexp_eol_anchor)
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
def dispatch
|
14
|
-
emit(s(:regexp_eos_anchor))
|
15
|
-
end
|
16
|
-
end # EndOfLineAnchor
|
17
|
-
end # Regexp
|
18
|
-
end # Node
|
19
|
-
end # Mutator
|
20
|
-
end # Mutant
|