mutant 0.11.17 → 0.11.18
Sign up to get free protection for your applications and to get access to all the features.
- 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
|