mutant 0.8.10 → 0.8.11
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/.rubocop.yml +1 -4
- data/Changelog.md +8 -0
- data/README.md +112 -43
- data/Rakefile +2 -16
- data/circle.yml +1 -1
- data/config/flay.yml +2 -2
- data/config/flog.yml +1 -1
- data/config/reek.yml +3 -4
- data/config/rubocop.yml +53 -16
- data/lib/mutant.rb +27 -6
- data/lib/mutant/ast/meta/const.rb +2 -0
- data/lib/mutant/ast/meta/optarg.rb +2 -0
- data/lib/mutant/ast/meta/resbody.rb +2 -0
- data/lib/mutant/ast/meta/restarg.rb +2 -0
- data/lib/mutant/ast/meta/send.rb +4 -0
- data/lib/mutant/ast/meta/symbol.rb +2 -0
- data/lib/mutant/ast/named_children.rb +14 -4
- data/lib/mutant/ast/nodes.rb +3 -1
- data/lib/mutant/ast/regexp.rb +53 -0
- data/lib/mutant/ast/regexp/transformer.rb +185 -0
- data/lib/mutant/ast/regexp/transformer/alternative.rb +39 -0
- data/lib/mutant/ast/regexp/transformer/character_set.rb +46 -0
- data/lib/mutant/ast/regexp/transformer/direct.rb +99 -0
- data/lib/mutant/ast/regexp/transformer/options_group.rb +66 -0
- data/lib/mutant/ast/regexp/transformer/quantifier.rb +112 -0
- data/lib/mutant/ast/regexp/transformer/recursive.rb +50 -0
- data/lib/mutant/ast/regexp/transformer/root.rb +29 -0
- data/lib/mutant/ast/regexp/transformer/text.rb +55 -0
- data/lib/mutant/ast/types.rb +92 -5
- data/lib/mutant/cli.rb +2 -14
- data/lib/mutant/color.rb +1 -1
- data/lib/mutant/config.rb +1 -3
- data/lib/mutant/expression/methods.rb +1 -1
- data/lib/mutant/expression/namespace.rb +2 -2
- data/lib/mutant/expression/parser.rb +1 -1
- data/lib/mutant/integration.rb +10 -28
- data/lib/mutant/isolation.rb +9 -60
- data/lib/mutant/isolation/fork.rb +72 -0
- data/lib/mutant/isolation/none.rb +25 -0
- data/lib/mutant/matcher/config.rb +2 -0
- data/lib/mutant/matcher/method/singleton.rb +5 -4
- data/lib/mutant/meta.rb +11 -4
- data/lib/mutant/meta/example.rb +2 -116
- data/lib/mutant/meta/example/dsl.rb +22 -19
- data/lib/mutant/meta/example/verification.rb +86 -0
- data/lib/mutant/mutator.rb +22 -49
- data/lib/mutant/mutator/node.rb +15 -19
- data/lib/mutant/mutator/node/and_asgn.rb +1 -1
- data/lib/mutant/mutator/node/argument.rb +10 -5
- data/lib/mutant/mutator/node/arguments.rb +5 -9
- data/lib/mutant/mutator/node/begin.rb +4 -17
- data/lib/mutant/mutator/node/block.rb +1 -1
- data/lib/mutant/mutator/node/break.rb +1 -1
- data/lib/mutant/mutator/node/class.rb +21 -0
- data/lib/mutant/mutator/node/conditional_loop.rb +1 -1
- data/lib/mutant/mutator/node/define.rb +1 -1
- data/lib/mutant/mutator/node/defined.rb +1 -1
- data/lib/mutant/mutator/node/dstr.rb +1 -1
- data/lib/mutant/mutator/node/dsym.rb +1 -1
- data/lib/mutant/mutator/node/generic.rb +3 -3
- data/lib/mutant/mutator/node/kwbegin.rb +1 -1
- data/lib/mutant/mutator/node/literal.rb +9 -0
- data/lib/mutant/mutator/node/literal/boolean.rb +1 -1
- data/lib/mutant/mutator/node/literal/fixnum.rb +2 -2
- data/lib/mutant/mutator/node/literal/float.rb +4 -6
- data/lib/mutant/mutator/node/literal/hash.rb +1 -1
- data/lib/mutant/mutator/node/literal/nil.rb +1 -1
- data/lib/mutant/mutator/node/literal/range.rb +2 -19
- data/lib/mutant/mutator/node/literal/regex.rb +43 -3
- data/lib/mutant/mutator/node/literal/string.rb +1 -1
- data/lib/mutant/mutator/node/literal/symbol.rb +2 -4
- data/lib/mutant/mutator/node/masgn.rb +1 -1
- data/lib/mutant/mutator/node/match_current_line.rb +1 -1
- data/lib/mutant/mutator/node/mlhs.rb +2 -3
- data/lib/mutant/mutator/node/named_value/access.rb +2 -2
- data/lib/mutant/mutator/node/named_value/constant_assignment.rb +4 -3
- data/lib/mutant/mutator/node/named_value/variable_assignment.rb +4 -4
- data/lib/mutant/mutator/node/next.rb +1 -1
- data/lib/mutant/mutator/node/nthref.rb +1 -1
- data/lib/mutant/mutator/node/or_asgn.rb +1 -1
- data/lib/mutant/mutator/node/regexp.rb +44 -0
- data/lib/mutant/mutator/node/regopt.rb +31 -0
- data/lib/mutant/mutator/node/resbody.rb +1 -1
- data/lib/mutant/mutator/node/rescue.rb +1 -3
- data/lib/mutant/mutator/node/return.rb +1 -1
- data/lib/mutant/mutator/node/send.rb +43 -3
- data/lib/mutant/mutator/node/send/attribute_assignment.rb +4 -1
- data/lib/mutant/mutator/node/send/conditional.rb +23 -0
- data/lib/mutant/mutator/node/send/index.rb +1 -1
- data/lib/mutant/mutator/node/splat.rb +1 -1
- data/lib/mutant/mutator/node/when.rb +1 -1
- data/lib/mutant/mutator/node/yield.rb +1 -1
- data/lib/mutant/mutator/util.rb +0 -30
- data/lib/mutant/mutator/util/array.rb +4 -16
- data/lib/mutant/parallel.rb +1 -1
- data/lib/mutant/parallel/worker.rb +1 -1
- data/lib/mutant/registry.rb +44 -0
- data/lib/mutant/reporter/cli/format.rb +2 -0
- data/lib/mutant/reporter/cli/printer.rb +2 -2
- data/lib/mutant/reporter/cli/printer/config.rb +0 -1
- data/lib/mutant/reporter/cli/printer/env_progress.rb +1 -11
- data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +1 -1
- data/lib/mutant/reporter/cli/printer/mutation_result.rb +2 -0
- data/lib/mutant/reporter/cli/tput.rb +1 -1
- data/lib/mutant/reporter/sequence.rb +3 -0
- data/lib/mutant/require_highjack.rb +6 -2
- data/lib/mutant/result.rb +1 -1
- data/lib/mutant/subject.rb +5 -5
- data/lib/mutant/subject/method/instance.rb +1 -2
- data/lib/mutant/util.rb +18 -0
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/zombifier.rb +5 -3
- data/meta/and.rb +1 -1
- data/meta/and_asgn.rb +1 -1
- data/meta/array.rb +2 -2
- data/meta/begin.rb +2 -2
- data/meta/block.rb +7 -7
- data/meta/block_pass.rb +1 -1
- data/meta/blockarg.rb +1 -1
- data/meta/break.rb +1 -1
- data/meta/case.rb +2 -2
- data/meta/casgn.rb +11 -2
- data/meta/cbase.rb +1 -1
- data/meta/class.rb +10 -0
- data/meta/const.rb +9 -1
- data/meta/csend.rb +8 -0
- data/meta/cvar.rb +1 -1
- data/meta/cvasgn.rb +1 -1
- data/meta/date.rb +4 -4
- data/meta/def.rb +14 -14
- data/meta/defined.rb +1 -1
- data/meta/dstr.rb +1 -1
- data/meta/dsym.rb +1 -1
- data/meta/ensure.rb +1 -1
- data/meta/false.rb +1 -1
- data/meta/float.rb +3 -3
- data/meta/gvar.rb +1 -1
- data/meta/gvasgn.rb +1 -1
- data/meta/hash.rb +1 -1
- data/meta/if.rb +17 -3
- data/meta/int.rb +1 -1
- data/meta/ivar.rb +1 -1
- data/meta/ivasgn.rb +14 -1
- data/meta/kwarg.rb +8 -0
- data/meta/kwbegin.rb +1 -1
- data/meta/kwoptarg.rb +11 -0
- data/meta/lvar.rb +1 -1
- data/meta/lvasgn.rb +1 -1
- data/meta/masgn.rb +1 -1
- data/meta/match_current_line.rb +2 -2
- data/meta/next.rb +1 -1
- data/meta/nil.rb +1 -1
- data/meta/nthref.rb +5 -5
- data/meta/op_assgn.rb +1 -1
- data/meta/or.rb +1 -1
- data/meta/or_asgn.rb +5 -5
- data/meta/range.rb +2 -8
- data/meta/redo.rb +1 -1
- data/meta/regexp.rb +106 -0
- data/meta/regexp/regexp_bol_anchor.rb +13 -0
- data/meta/regexp/regexp_bos_anchor.rb +26 -0
- data/meta/regexp/regexp_root_expression.rb +13 -0
- data/meta/regopt.rb +8 -0
- data/meta/rescue.rb +49 -4
- data/meta/restarg.rb +6 -9
- data/meta/return.rb +2 -2
- data/meta/self.rb +1 -1
- data/meta/send.rb +228 -55
- data/meta/str.rb +1 -1
- data/meta/super.rb +3 -3
- data/meta/{symbol.rb → sym.rb} +1 -1
- data/meta/true.rb +1 -1
- data/meta/until.rb +1 -1
- data/meta/while.rb +2 -2
- data/meta/yield.rb +1 -1
- data/mutant-rspec.gemspec +2 -2
- data/mutant.gemspec +6 -5
- data/spec/integration/mutant/isolation/fork_spec.rb +8 -0
- data/spec/integration/mutant/rspec_spec.rb +1 -1
- data/spec/integration/mutant/test_mutator_handles_types_spec.rb +1 -2
- data/spec/integrations.yml +93 -24
- data/spec/spec_helper.rb +12 -7
- data/spec/support/compress_helper.rb +1 -1
- data/spec/support/corpus.rb +115 -50
- data/spec/support/fake_actor.rb +5 -5
- data/spec/support/file_system.rb +1 -1
- data/spec/support/ice_nine_config.rb +3 -3
- data/spec/support/ruby_vm.rb +11 -12
- data/spec/support/shared_context.rb +22 -13
- data/spec/support/test_app.rb +1 -1
- data/spec/support/warning.rb +64 -0
- data/spec/support/warnings.yml +4 -0
- data/spec/support/xspec.rb +177 -0
- data/spec/unit/mutant/actor/env_spec.rb +2 -2
- data/spec/unit/mutant/actor/sender_spec.rb +1 -1
- data/spec/unit/mutant/ast/meta/send_spec.rb +1 -1
- data/spec/unit/mutant/ast/named_children_spec.rb +26 -0
- data/spec/unit/mutant/ast/regexp/parse_spec.rb +7 -0
- data/spec/unit/mutant/ast/regexp/supported_predicate_spec.rb +14 -0
- data/spec/unit/mutant/ast/regexp/transformer/lookup_table/table_spec.rb +19 -0
- data/spec/unit/mutant/ast/regexp/transformer/lookup_table_spec.rb +33 -0
- data/spec/unit/mutant/ast/regexp/transformer_spec.rb +19 -0
- data/spec/unit/mutant/ast/regexp_spec.rb +617 -0
- data/spec/unit/mutant/cli_spec.rb +7 -45
- data/spec/unit/mutant/context_spec.rb +4 -7
- data/spec/unit/mutant/env/{boostrap_spec.rb → bootstrap_spec.rb} +2 -2
- data/spec/unit/mutant/env_spec.rb +13 -16
- data/spec/unit/mutant/expression/namespace/{flat_spec.rb → exact_spec.rb} +0 -0
- data/spec/unit/mutant/integration/rspec_spec.rb +2 -2
- data/spec/unit/mutant/integration_spec.rb +14 -0
- data/spec/unit/mutant/isolation/fork_spec.rb +155 -0
- data/spec/unit/mutant/isolation/none_spec.rb +16 -0
- data/spec/unit/mutant/loader_spec.rb +1 -1
- data/spec/unit/mutant/matcher/methods/instance_spec.rb +2 -4
- data/spec/unit/mutant/meta/example/dsl_spec.rb +106 -0
- data/spec/unit/mutant/meta/example/verification_spec.rb +120 -0
- data/spec/unit/mutant/meta/example_spec.rb +32 -0
- data/spec/unit/mutant/mutator/node_spec.rb +37 -4
- data/spec/unit/mutant/mutator_spec.rb +21 -0
- data/spec/unit/mutant/{runner → parallel}/driver_spec.rb +0 -0
- data/spec/unit/mutant/parallel/master_spec.rb +13 -13
- data/spec/unit/mutant/registry_spec.rb +47 -0
- data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +0 -4
- data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +0 -8
- data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +0 -2
- data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +0 -8
- data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +0 -34
- data/spec/unit/mutant/reporter/cli_spec.rb +0 -22
- data/spec/unit/mutant/repository/diff_spec.rb +6 -6
- data/spec/unit/mutant/require_highjack_spec.rb +38 -14
- data/spec/unit/mutant/result/env_spec.rb +1 -4
- data/spec/unit/mutant/runner_spec.rb +1 -1
- data/spec/unit/mutant/subject/method/instance_spec.rb +1 -1
- data/spec/unit/mutant/subject_spec.rb +3 -3
- data/spec/unit/mutant/util/one_spec.rb +20 -0
- data/spec/unit/mutant/zombifier_spec.rb +18 -18
- data/test_app/{Gemfile.rspec3.3 → Gemfile.rspec3.5} +2 -2
- metadata +94 -24
- data/TODO +0 -21
- data/lib/mutant/mutator/node/blockarg.rb +0 -13
- data/lib/mutant/mutator/node/restarg.rb +0 -13
- data/lib/mutant/mutator/registry.rb +0 -49
- data/meta/boolean.rb +0 -13
- data/meta/regex.rb +0 -19
- data/spec/unit/mutant/isolation_spec.rb +0 -104
- data/spec/unit/mutant/mutator/registry_spec.rb +0 -57
data/lib/mutant.rb
CHANGED
@@ -14,6 +14,7 @@ require 'parallel'
|
|
14
14
|
require 'parser'
|
15
15
|
require 'parser/current'
|
16
16
|
require 'pathname'
|
17
|
+
require 'regexp_parser'
|
17
18
|
require 'set'
|
18
19
|
require 'stringio'
|
19
20
|
require 'unparser'
|
@@ -42,12 +43,24 @@ end # Mutant
|
|
42
43
|
require 'mutant/version'
|
43
44
|
require 'mutant/env'
|
44
45
|
require 'mutant/env/bootstrap'
|
46
|
+
require 'mutant/util'
|
47
|
+
require 'mutant/registry'
|
45
48
|
require 'mutant/ast'
|
46
49
|
require 'mutant/ast/sexp'
|
47
50
|
require 'mutant/ast/types'
|
48
51
|
require 'mutant/ast/nodes'
|
49
52
|
require 'mutant/ast/named_children'
|
50
53
|
require 'mutant/ast/node_predicates'
|
54
|
+
require 'mutant/ast/regexp'
|
55
|
+
require 'mutant/ast/regexp/transformer'
|
56
|
+
require 'mutant/ast/regexp/transformer/direct'
|
57
|
+
require 'mutant/ast/regexp/transformer/text'
|
58
|
+
require 'mutant/ast/regexp/transformer/recursive'
|
59
|
+
require 'mutant/ast/regexp/transformer/quantifier'
|
60
|
+
require 'mutant/ast/regexp/transformer/options_group'
|
61
|
+
require 'mutant/ast/regexp/transformer/character_set'
|
62
|
+
require 'mutant/ast/regexp/transformer/root'
|
63
|
+
require 'mutant/ast/regexp/transformer/alternative'
|
51
64
|
require 'mutant/ast/meta'
|
52
65
|
require 'mutant/ast/meta/send'
|
53
66
|
require 'mutant/ast/meta/const'
|
@@ -62,6 +75,8 @@ require 'mutant/actor/mailbox'
|
|
62
75
|
require 'mutant/actor/env'
|
63
76
|
require 'mutant/parser'
|
64
77
|
require 'mutant/isolation'
|
78
|
+
require 'mutant/isolation/none'
|
79
|
+
require 'mutant/isolation/fork'
|
65
80
|
require 'mutant/parallel'
|
66
81
|
require 'mutant/parallel/master'
|
67
82
|
require 'mutant/parallel/worker'
|
@@ -70,12 +85,12 @@ require 'mutant/warning_filter'
|
|
70
85
|
require 'mutant/require_highjack'
|
71
86
|
require 'mutant/mutation'
|
72
87
|
require 'mutant/mutator'
|
73
|
-
require 'mutant/mutator/registry'
|
74
88
|
require 'mutant/mutator/util'
|
75
89
|
require 'mutant/mutator/util/array'
|
76
90
|
require 'mutant/mutator/util/symbol'
|
77
91
|
require 'mutant/mutator/node'
|
78
92
|
require 'mutant/mutator/node/generic'
|
93
|
+
require 'mutant/mutator/node/regexp'
|
79
94
|
require 'mutant/mutator/node/literal'
|
80
95
|
require 'mutant/mutator/node/literal/boolean'
|
81
96
|
require 'mutant/mutator/node/literal/range'
|
@@ -89,7 +104,6 @@ require 'mutant/mutator/node/literal/regex'
|
|
89
104
|
require 'mutant/mutator/node/literal/nil'
|
90
105
|
require 'mutant/mutator/node/argument'
|
91
106
|
require 'mutant/mutator/node/arguments'
|
92
|
-
require 'mutant/mutator/node/blockarg'
|
93
107
|
require 'mutant/mutator/node/begin'
|
94
108
|
require 'mutant/mutator/node/binary'
|
95
109
|
require 'mutant/mutator/node/const'
|
@@ -110,12 +124,13 @@ require 'mutant/mutator/node/conditional_loop'
|
|
110
124
|
require 'mutant/mutator/node/yield'
|
111
125
|
require 'mutant/mutator/node/super'
|
112
126
|
require 'mutant/mutator/node/zsuper'
|
113
|
-
require 'mutant/mutator/node/restarg'
|
114
127
|
require 'mutant/mutator/node/send'
|
115
128
|
require 'mutant/mutator/node/send/binary'
|
129
|
+
require 'mutant/mutator/node/send/conditional'
|
116
130
|
require 'mutant/mutator/node/send/attribute_assignment'
|
117
131
|
require 'mutant/mutator/node/send/index'
|
118
132
|
require 'mutant/mutator/node/when'
|
133
|
+
require 'mutant/mutator/node/class'
|
119
134
|
require 'mutant/mutator/node/define'
|
120
135
|
require 'mutant/mutator/node/mlhs'
|
121
136
|
require 'mutant/mutator/node/nthref'
|
@@ -125,6 +140,7 @@ require 'mutant/mutator/node/block'
|
|
125
140
|
require 'mutant/mutator/node/if'
|
126
141
|
require 'mutant/mutator/node/case'
|
127
142
|
require 'mutant/mutator/node/splat'
|
143
|
+
require 'mutant/mutator/node/regopt'
|
128
144
|
require 'mutant/mutator/node/resbody'
|
129
145
|
require 'mutant/mutator/node/rescue'
|
130
146
|
require 'mutant/mutator/node/match_current_line'
|
@@ -188,8 +204,6 @@ module Mutant
|
|
188
204
|
# Reopen class to initialize constant to avoid dep circle
|
189
205
|
class Config
|
190
206
|
DEFAULT = new(
|
191
|
-
debug: false,
|
192
|
-
expected_coverage: Rational(1),
|
193
207
|
expression_parser: Expression::Parser.new([
|
194
208
|
Expression::Method,
|
195
209
|
Expression::Methods,
|
@@ -199,7 +213,14 @@ module Mutant
|
|
199
213
|
fail_fast: false,
|
200
214
|
includes: EMPTY_ARRAY,
|
201
215
|
integration: Integration::Null,
|
202
|
-
isolation: Mutant::Isolation::Fork
|
216
|
+
isolation: Mutant::Isolation::Fork.new(
|
217
|
+
devnull: ->(&block) { File.open(File::NULL, File::WRONLY, &block) },
|
218
|
+
stdout: $stdout,
|
219
|
+
stderr: $stderr,
|
220
|
+
io: IO,
|
221
|
+
marshal: Marshal,
|
222
|
+
process: Process
|
223
|
+
),
|
203
224
|
jobs: ::Parallel.processor_count,
|
204
225
|
kernel: Kernel,
|
205
226
|
load_path: $LOAD_PATH,
|
data/lib/mutant/ast/meta/send.rb
CHANGED
@@ -9,6 +9,8 @@ module Mutant
|
|
9
9
|
|
10
10
|
children :receiver, :selector
|
11
11
|
|
12
|
+
public :receiver, :selector
|
13
|
+
|
12
14
|
INDEX_ASSIGNMENT_SELECTOR = :[]=
|
13
15
|
ATTRIBUTE_ASSIGNMENT_SELECTOR_SUFFIX = '='.freeze
|
14
16
|
|
@@ -17,6 +19,8 @@ module Mutant
|
|
17
19
|
# @return [Enumerable<Parser::AST::Node>]
|
18
20
|
alias_method :arguments, :remaining_children
|
19
21
|
|
22
|
+
public :arguments
|
23
|
+
|
20
24
|
# Test if AST node is a valid assignment target
|
21
25
|
#
|
22
26
|
# @return [Boolean]
|
@@ -42,7 +42,7 @@ module Mutant
|
|
42
42
|
#
|
43
43
|
# @return [undefined]
|
44
44
|
def define_named_child(name, index)
|
45
|
-
|
45
|
+
define_private_method(name) do
|
46
46
|
children.at(index)
|
47
47
|
end
|
48
48
|
end
|
@@ -53,15 +53,15 @@ module Mutant
|
|
53
53
|
#
|
54
54
|
# @return [undefined]
|
55
55
|
def define_remaining_children(names)
|
56
|
-
|
56
|
+
define_private_method(:remaining_children_with_index) do
|
57
57
|
children.each_with_index.drop(names.length)
|
58
58
|
end
|
59
59
|
|
60
|
-
|
60
|
+
define_private_method(:remaining_children_indices) do
|
61
61
|
children.each_index.drop(names.length)
|
62
62
|
end
|
63
63
|
|
64
|
-
|
64
|
+
define_private_method(:remaining_children) do
|
65
65
|
children.drop(names.length)
|
66
66
|
end
|
67
67
|
end
|
@@ -76,6 +76,16 @@ module Mutant
|
|
76
76
|
define_remaining_children(names)
|
77
77
|
end
|
78
78
|
|
79
|
+
# Define private method
|
80
|
+
#
|
81
|
+
# @param [Symbol] name
|
82
|
+
#
|
83
|
+
# @return [undefined]
|
84
|
+
def define_private_method(name, &block)
|
85
|
+
define_method(name, &block)
|
86
|
+
private(name)
|
87
|
+
end
|
88
|
+
|
79
89
|
end # ClassMethods
|
80
90
|
end # NamedChildren
|
81
91
|
end # AST
|
data/lib/mutant/ast/nodes.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module Mutant
|
2
2
|
module AST
|
3
3
|
# Singleton nodes
|
4
|
+
#
|
5
|
+
# :reek:TooManyConstants
|
4
6
|
module Nodes
|
5
7
|
extend Sexp
|
6
8
|
|
@@ -16,6 +18,6 @@ module Mutant
|
|
16
18
|
N_ZSUPER = s(:zsuper)
|
17
19
|
N_EMPTY_SUPER = s(:super)
|
18
20
|
|
19
|
-
end #
|
21
|
+
end # Nodes
|
20
22
|
end # AST
|
21
23
|
end # Mutant
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Mutant
|
2
|
+
module AST
|
3
|
+
# Regexp source mapper
|
4
|
+
module Regexp
|
5
|
+
UNSUPPORTED_EXPRESSION_TYPE = :conditional
|
6
|
+
|
7
|
+
private_constant(*constants(false))
|
8
|
+
|
9
|
+
# Parse regex string into expression
|
10
|
+
#
|
11
|
+
# @param regexp [String]
|
12
|
+
#
|
13
|
+
# @return [Regexp::Expression]
|
14
|
+
def self.parse(regexp)
|
15
|
+
::Regexp::Parser.parse(
|
16
|
+
regexp,
|
17
|
+
"ruby/#{RUBY_VERSION.split('.').first(2).join('.')}"
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Check if expression is supported by mapper
|
22
|
+
#
|
23
|
+
# @param expression [Regexp::Expression]
|
24
|
+
#
|
25
|
+
# @return [Boolean]
|
26
|
+
def self.supported?(expression)
|
27
|
+
expression.terminal? || expression.all? do |subexp|
|
28
|
+
!subexp.type.equal?(UNSUPPORTED_EXPRESSION_TYPE) && supported?(subexp)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Convert expression into ast node
|
33
|
+
#
|
34
|
+
# @param expression [Regexp::Expression]
|
35
|
+
#
|
36
|
+
# @return [Parser::AST::Node]
|
37
|
+
def self.to_ast(expression)
|
38
|
+
ast_type = :"regexp_#{expression.token}_#{expression.type}"
|
39
|
+
|
40
|
+
Transformer.lookup(ast_type).to_ast(expression)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Convert node into expression
|
44
|
+
#
|
45
|
+
# @param node [Parser::AST::Node]
|
46
|
+
#
|
47
|
+
# @return [Regexp::Expression]
|
48
|
+
def self.to_expression(node)
|
49
|
+
Transformer.lookup(node.type).to_expression(node)
|
50
|
+
end
|
51
|
+
end # Regexp
|
52
|
+
end # AST
|
53
|
+
end # Mutant
|
@@ -0,0 +1,185 @@
|
|
1
|
+
module Mutant
|
2
|
+
module AST
|
3
|
+
module Regexp
|
4
|
+
# Regexp bijective mapper
|
5
|
+
#
|
6
|
+
# Transforms parsed regular expression representation from
|
7
|
+
# `Regexp::Expression` instances (provided by `regexp_parser`) into
|
8
|
+
# equivalent representations using `Parser::AST::Node`
|
9
|
+
class Transformer
|
10
|
+
include AbstractType
|
11
|
+
|
12
|
+
REGISTRY = Registry.new
|
13
|
+
|
14
|
+
# Lookup transformer class for regular expression node type
|
15
|
+
#
|
16
|
+
# @param type [Symbol]
|
17
|
+
#
|
18
|
+
# @return [Class<Transformer>]
|
19
|
+
def self.lookup(type)
|
20
|
+
REGISTRY.lookup(type)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Register transformer class as responsible for handling node type
|
24
|
+
#
|
25
|
+
# @param type [Symbol]
|
26
|
+
#
|
27
|
+
# @return [undefined]
|
28
|
+
def self.register(type)
|
29
|
+
REGISTRY.register(type, self)
|
30
|
+
end
|
31
|
+
private_class_method :register
|
32
|
+
|
33
|
+
# Transform expression
|
34
|
+
#
|
35
|
+
# @param expression [Regexp::Expression]
|
36
|
+
#
|
37
|
+
# @return [Parser::AST::Node]
|
38
|
+
def self.to_ast(expression)
|
39
|
+
self::ExpressionToAST.call(expression)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Transform node
|
43
|
+
#
|
44
|
+
# @param node [Parser::AST::Node]
|
45
|
+
#
|
46
|
+
# @return [Regexp::Expression]
|
47
|
+
def self.to_expression(node)
|
48
|
+
self::ASTToExpression.call(node)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Abstract expression transformer
|
52
|
+
class ExpressionToAST
|
53
|
+
PREFIX = :regexp
|
54
|
+
|
55
|
+
include Concord.new(:expression), Procto.call, AST::Sexp, AbstractType, Adamantium
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Node with provided children using node type constructed in `type`
|
60
|
+
#
|
61
|
+
# @param [Object,Parser::AST::Node] child of node
|
62
|
+
#
|
63
|
+
# @return [Parser::AST::Node]
|
64
|
+
def ast(*children)
|
65
|
+
s(type, *children)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Wrap provided node in a quantifier
|
69
|
+
#
|
70
|
+
# @param node [Parser::AST::Node]
|
71
|
+
#
|
72
|
+
# @return [Parser::AST::Node]
|
73
|
+
# quantifier node wrapping provided node if expression is quantified
|
74
|
+
#
|
75
|
+
# @return [Parser::AST::Node]
|
76
|
+
# original node otherwise
|
77
|
+
def quantify(node)
|
78
|
+
return node unless expression.quantified?
|
79
|
+
|
80
|
+
Quantifier.to_ast(expression.quantifier).append(node)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Transformed children of expression
|
84
|
+
#
|
85
|
+
# @return [Array<Parser::AST::Node>]
|
86
|
+
def children
|
87
|
+
expression.expressions.map(&Regexp.method(:to_ast))
|
88
|
+
end
|
89
|
+
|
90
|
+
# Node type constructed from token and type of `Regexp::Expression`
|
91
|
+
#
|
92
|
+
# @return [Symbol]
|
93
|
+
def type
|
94
|
+
:"#{PREFIX}_#{expression.token}_#{expression.type}"
|
95
|
+
end
|
96
|
+
end # ExpressionToAST
|
97
|
+
|
98
|
+
# Abstract node transformer
|
99
|
+
class ASTToExpression
|
100
|
+
include Concord.new(:node), Procto.call, AbstractType, Adamantium
|
101
|
+
|
102
|
+
# Call generic transform method and freeze result
|
103
|
+
#
|
104
|
+
# @return [Regexp::Expression]
|
105
|
+
def call
|
106
|
+
transform.freeze
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
# Transformation of ast into expression
|
112
|
+
#
|
113
|
+
# @return [Regexp::Expression]
|
114
|
+
abstract_method :transform
|
115
|
+
|
116
|
+
# Transformed children of node
|
117
|
+
#
|
118
|
+
# @return [Array<Regexp::Expression>]
|
119
|
+
def subexpressions
|
120
|
+
node.children.map(&Regexp.public_method(:to_expression))
|
121
|
+
end
|
122
|
+
end # ASTToExpression
|
123
|
+
|
124
|
+
# Mixin for node transformers
|
125
|
+
#
|
126
|
+
# Helps construct a mapping from Parser::AST::Node domain to
|
127
|
+
# Regexp::Expression domain
|
128
|
+
module LookupTable
|
129
|
+
Mapping = Class.new.include(Concord::Public.new(:token, :regexp_class))
|
130
|
+
|
131
|
+
# Table mapping ast types to object information for regexp domain
|
132
|
+
class Table
|
133
|
+
|
134
|
+
# Coerce array of mapping information into structured table
|
135
|
+
#
|
136
|
+
# @param [Array(Symbol, Array, Class<Regexp::Expression>)]
|
137
|
+
#
|
138
|
+
# @return [Table]
|
139
|
+
def self.create(*rows)
|
140
|
+
table = rows.map do |ast_type, token, klass|
|
141
|
+
[ast_type, Mapping.new(::Regexp::Token.new(*token), klass)]
|
142
|
+
end.to_h
|
143
|
+
|
144
|
+
new(table)
|
145
|
+
end
|
146
|
+
|
147
|
+
include Concord.new(:table), Adamantium
|
148
|
+
|
149
|
+
# Types defined by the table
|
150
|
+
#
|
151
|
+
# @return [Array<Symbol>]
|
152
|
+
def types
|
153
|
+
table.keys
|
154
|
+
end
|
155
|
+
|
156
|
+
# Lookup mapping information given an ast node type
|
157
|
+
#
|
158
|
+
# @param type [Symbol]
|
159
|
+
#
|
160
|
+
# @return [Mapping]
|
161
|
+
def lookup(type)
|
162
|
+
table.fetch(type)
|
163
|
+
end
|
164
|
+
end # Table
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
# Lookup expression token given node type
|
169
|
+
#
|
170
|
+
# @return [Regexp::Token]
|
171
|
+
def expression_token
|
172
|
+
self.class::TABLE.lookup(node.type).token
|
173
|
+
end
|
174
|
+
|
175
|
+
# Lookup regexp class given node type
|
176
|
+
#
|
177
|
+
# @return [Class<Regexp::Expression>]
|
178
|
+
def expression_class
|
179
|
+
self.class::TABLE.lookup(node.type).regexp_class
|
180
|
+
end
|
181
|
+
end # LookupTable
|
182
|
+
end # Transformer
|
183
|
+
end # Regexp
|
184
|
+
end # AST
|
185
|
+
end # Mutant
|