mutant 0.8.10 → 0.8.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (247) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -4
  3. data/Changelog.md +8 -0
  4. data/README.md +112 -43
  5. data/Rakefile +2 -16
  6. data/circle.yml +1 -1
  7. data/config/flay.yml +2 -2
  8. data/config/flog.yml +1 -1
  9. data/config/reek.yml +3 -4
  10. data/config/rubocop.yml +53 -16
  11. data/lib/mutant.rb +27 -6
  12. data/lib/mutant/ast/meta/const.rb +2 -0
  13. data/lib/mutant/ast/meta/optarg.rb +2 -0
  14. data/lib/mutant/ast/meta/resbody.rb +2 -0
  15. data/lib/mutant/ast/meta/restarg.rb +2 -0
  16. data/lib/mutant/ast/meta/send.rb +4 -0
  17. data/lib/mutant/ast/meta/symbol.rb +2 -0
  18. data/lib/mutant/ast/named_children.rb +14 -4
  19. data/lib/mutant/ast/nodes.rb +3 -1
  20. data/lib/mutant/ast/regexp.rb +53 -0
  21. data/lib/mutant/ast/regexp/transformer.rb +185 -0
  22. data/lib/mutant/ast/regexp/transformer/alternative.rb +39 -0
  23. data/lib/mutant/ast/regexp/transformer/character_set.rb +46 -0
  24. data/lib/mutant/ast/regexp/transformer/direct.rb +99 -0
  25. data/lib/mutant/ast/regexp/transformer/options_group.rb +66 -0
  26. data/lib/mutant/ast/regexp/transformer/quantifier.rb +112 -0
  27. data/lib/mutant/ast/regexp/transformer/recursive.rb +50 -0
  28. data/lib/mutant/ast/regexp/transformer/root.rb +29 -0
  29. data/lib/mutant/ast/regexp/transformer/text.rb +55 -0
  30. data/lib/mutant/ast/types.rb +92 -5
  31. data/lib/mutant/cli.rb +2 -14
  32. data/lib/mutant/color.rb +1 -1
  33. data/lib/mutant/config.rb +1 -3
  34. data/lib/mutant/expression/methods.rb +1 -1
  35. data/lib/mutant/expression/namespace.rb +2 -2
  36. data/lib/mutant/expression/parser.rb +1 -1
  37. data/lib/mutant/integration.rb +10 -28
  38. data/lib/mutant/isolation.rb +9 -60
  39. data/lib/mutant/isolation/fork.rb +72 -0
  40. data/lib/mutant/isolation/none.rb +25 -0
  41. data/lib/mutant/matcher/config.rb +2 -0
  42. data/lib/mutant/matcher/method/singleton.rb +5 -4
  43. data/lib/mutant/meta.rb +11 -4
  44. data/lib/mutant/meta/example.rb +2 -116
  45. data/lib/mutant/meta/example/dsl.rb +22 -19
  46. data/lib/mutant/meta/example/verification.rb +86 -0
  47. data/lib/mutant/mutator.rb +22 -49
  48. data/lib/mutant/mutator/node.rb +15 -19
  49. data/lib/mutant/mutator/node/and_asgn.rb +1 -1
  50. data/lib/mutant/mutator/node/argument.rb +10 -5
  51. data/lib/mutant/mutator/node/arguments.rb +5 -9
  52. data/lib/mutant/mutator/node/begin.rb +4 -17
  53. data/lib/mutant/mutator/node/block.rb +1 -1
  54. data/lib/mutant/mutator/node/break.rb +1 -1
  55. data/lib/mutant/mutator/node/class.rb +21 -0
  56. data/lib/mutant/mutator/node/conditional_loop.rb +1 -1
  57. data/lib/mutant/mutator/node/define.rb +1 -1
  58. data/lib/mutant/mutator/node/defined.rb +1 -1
  59. data/lib/mutant/mutator/node/dstr.rb +1 -1
  60. data/lib/mutant/mutator/node/dsym.rb +1 -1
  61. data/lib/mutant/mutator/node/generic.rb +3 -3
  62. data/lib/mutant/mutator/node/kwbegin.rb +1 -1
  63. data/lib/mutant/mutator/node/literal.rb +9 -0
  64. data/lib/mutant/mutator/node/literal/boolean.rb +1 -1
  65. data/lib/mutant/mutator/node/literal/fixnum.rb +2 -2
  66. data/lib/mutant/mutator/node/literal/float.rb +4 -6
  67. data/lib/mutant/mutator/node/literal/hash.rb +1 -1
  68. data/lib/mutant/mutator/node/literal/nil.rb +1 -1
  69. data/lib/mutant/mutator/node/literal/range.rb +2 -19
  70. data/lib/mutant/mutator/node/literal/regex.rb +43 -3
  71. data/lib/mutant/mutator/node/literal/string.rb +1 -1
  72. data/lib/mutant/mutator/node/literal/symbol.rb +2 -4
  73. data/lib/mutant/mutator/node/masgn.rb +1 -1
  74. data/lib/mutant/mutator/node/match_current_line.rb +1 -1
  75. data/lib/mutant/mutator/node/mlhs.rb +2 -3
  76. data/lib/mutant/mutator/node/named_value/access.rb +2 -2
  77. data/lib/mutant/mutator/node/named_value/constant_assignment.rb +4 -3
  78. data/lib/mutant/mutator/node/named_value/variable_assignment.rb +4 -4
  79. data/lib/mutant/mutator/node/next.rb +1 -1
  80. data/lib/mutant/mutator/node/nthref.rb +1 -1
  81. data/lib/mutant/mutator/node/or_asgn.rb +1 -1
  82. data/lib/mutant/mutator/node/regexp.rb +44 -0
  83. data/lib/mutant/mutator/node/regopt.rb +31 -0
  84. data/lib/mutant/mutator/node/resbody.rb +1 -1
  85. data/lib/mutant/mutator/node/rescue.rb +1 -3
  86. data/lib/mutant/mutator/node/return.rb +1 -1
  87. data/lib/mutant/mutator/node/send.rb +43 -3
  88. data/lib/mutant/mutator/node/send/attribute_assignment.rb +4 -1
  89. data/lib/mutant/mutator/node/send/conditional.rb +23 -0
  90. data/lib/mutant/mutator/node/send/index.rb +1 -1
  91. data/lib/mutant/mutator/node/splat.rb +1 -1
  92. data/lib/mutant/mutator/node/when.rb +1 -1
  93. data/lib/mutant/mutator/node/yield.rb +1 -1
  94. data/lib/mutant/mutator/util.rb +0 -30
  95. data/lib/mutant/mutator/util/array.rb +4 -16
  96. data/lib/mutant/parallel.rb +1 -1
  97. data/lib/mutant/parallel/worker.rb +1 -1
  98. data/lib/mutant/registry.rb +44 -0
  99. data/lib/mutant/reporter/cli/format.rb +2 -0
  100. data/lib/mutant/reporter/cli/printer.rb +2 -2
  101. data/lib/mutant/reporter/cli/printer/config.rb +0 -1
  102. data/lib/mutant/reporter/cli/printer/env_progress.rb +1 -11
  103. data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +1 -1
  104. data/lib/mutant/reporter/cli/printer/mutation_result.rb +2 -0
  105. data/lib/mutant/reporter/cli/tput.rb +1 -1
  106. data/lib/mutant/reporter/sequence.rb +3 -0
  107. data/lib/mutant/require_highjack.rb +6 -2
  108. data/lib/mutant/result.rb +1 -1
  109. data/lib/mutant/subject.rb +5 -5
  110. data/lib/mutant/subject/method/instance.rb +1 -2
  111. data/lib/mutant/util.rb +18 -0
  112. data/lib/mutant/version.rb +1 -1
  113. data/lib/mutant/zombifier.rb +5 -3
  114. data/meta/and.rb +1 -1
  115. data/meta/and_asgn.rb +1 -1
  116. data/meta/array.rb +2 -2
  117. data/meta/begin.rb +2 -2
  118. data/meta/block.rb +7 -7
  119. data/meta/block_pass.rb +1 -1
  120. data/meta/blockarg.rb +1 -1
  121. data/meta/break.rb +1 -1
  122. data/meta/case.rb +2 -2
  123. data/meta/casgn.rb +11 -2
  124. data/meta/cbase.rb +1 -1
  125. data/meta/class.rb +10 -0
  126. data/meta/const.rb +9 -1
  127. data/meta/csend.rb +8 -0
  128. data/meta/cvar.rb +1 -1
  129. data/meta/cvasgn.rb +1 -1
  130. data/meta/date.rb +4 -4
  131. data/meta/def.rb +14 -14
  132. data/meta/defined.rb +1 -1
  133. data/meta/dstr.rb +1 -1
  134. data/meta/dsym.rb +1 -1
  135. data/meta/ensure.rb +1 -1
  136. data/meta/false.rb +1 -1
  137. data/meta/float.rb +3 -3
  138. data/meta/gvar.rb +1 -1
  139. data/meta/gvasgn.rb +1 -1
  140. data/meta/hash.rb +1 -1
  141. data/meta/if.rb +17 -3
  142. data/meta/int.rb +1 -1
  143. data/meta/ivar.rb +1 -1
  144. data/meta/ivasgn.rb +14 -1
  145. data/meta/kwarg.rb +8 -0
  146. data/meta/kwbegin.rb +1 -1
  147. data/meta/kwoptarg.rb +11 -0
  148. data/meta/lvar.rb +1 -1
  149. data/meta/lvasgn.rb +1 -1
  150. data/meta/masgn.rb +1 -1
  151. data/meta/match_current_line.rb +2 -2
  152. data/meta/next.rb +1 -1
  153. data/meta/nil.rb +1 -1
  154. data/meta/nthref.rb +5 -5
  155. data/meta/op_assgn.rb +1 -1
  156. data/meta/or.rb +1 -1
  157. data/meta/or_asgn.rb +5 -5
  158. data/meta/range.rb +2 -8
  159. data/meta/redo.rb +1 -1
  160. data/meta/regexp.rb +106 -0
  161. data/meta/regexp/regexp_bol_anchor.rb +13 -0
  162. data/meta/regexp/regexp_bos_anchor.rb +26 -0
  163. data/meta/regexp/regexp_root_expression.rb +13 -0
  164. data/meta/regopt.rb +8 -0
  165. data/meta/rescue.rb +49 -4
  166. data/meta/restarg.rb +6 -9
  167. data/meta/return.rb +2 -2
  168. data/meta/self.rb +1 -1
  169. data/meta/send.rb +228 -55
  170. data/meta/str.rb +1 -1
  171. data/meta/super.rb +3 -3
  172. data/meta/{symbol.rb → sym.rb} +1 -1
  173. data/meta/true.rb +1 -1
  174. data/meta/until.rb +1 -1
  175. data/meta/while.rb +2 -2
  176. data/meta/yield.rb +1 -1
  177. data/mutant-rspec.gemspec +2 -2
  178. data/mutant.gemspec +6 -5
  179. data/spec/integration/mutant/isolation/fork_spec.rb +8 -0
  180. data/spec/integration/mutant/rspec_spec.rb +1 -1
  181. data/spec/integration/mutant/test_mutator_handles_types_spec.rb +1 -2
  182. data/spec/integrations.yml +93 -24
  183. data/spec/spec_helper.rb +12 -7
  184. data/spec/support/compress_helper.rb +1 -1
  185. data/spec/support/corpus.rb +115 -50
  186. data/spec/support/fake_actor.rb +5 -5
  187. data/spec/support/file_system.rb +1 -1
  188. data/spec/support/ice_nine_config.rb +3 -3
  189. data/spec/support/ruby_vm.rb +11 -12
  190. data/spec/support/shared_context.rb +22 -13
  191. data/spec/support/test_app.rb +1 -1
  192. data/spec/support/warning.rb +64 -0
  193. data/spec/support/warnings.yml +4 -0
  194. data/spec/support/xspec.rb +177 -0
  195. data/spec/unit/mutant/actor/env_spec.rb +2 -2
  196. data/spec/unit/mutant/actor/sender_spec.rb +1 -1
  197. data/spec/unit/mutant/ast/meta/send_spec.rb +1 -1
  198. data/spec/unit/mutant/ast/named_children_spec.rb +26 -0
  199. data/spec/unit/mutant/ast/regexp/parse_spec.rb +7 -0
  200. data/spec/unit/mutant/ast/regexp/supported_predicate_spec.rb +14 -0
  201. data/spec/unit/mutant/ast/regexp/transformer/lookup_table/table_spec.rb +19 -0
  202. data/spec/unit/mutant/ast/regexp/transformer/lookup_table_spec.rb +33 -0
  203. data/spec/unit/mutant/ast/regexp/transformer_spec.rb +19 -0
  204. data/spec/unit/mutant/ast/regexp_spec.rb +617 -0
  205. data/spec/unit/mutant/cli_spec.rb +7 -45
  206. data/spec/unit/mutant/context_spec.rb +4 -7
  207. data/spec/unit/mutant/env/{boostrap_spec.rb → bootstrap_spec.rb} +2 -2
  208. data/spec/unit/mutant/env_spec.rb +13 -16
  209. data/spec/unit/mutant/expression/namespace/{flat_spec.rb → exact_spec.rb} +0 -0
  210. data/spec/unit/mutant/integration/rspec_spec.rb +2 -2
  211. data/spec/unit/mutant/integration_spec.rb +14 -0
  212. data/spec/unit/mutant/isolation/fork_spec.rb +155 -0
  213. data/spec/unit/mutant/isolation/none_spec.rb +16 -0
  214. data/spec/unit/mutant/loader_spec.rb +1 -1
  215. data/spec/unit/mutant/matcher/methods/instance_spec.rb +2 -4
  216. data/spec/unit/mutant/meta/example/dsl_spec.rb +106 -0
  217. data/spec/unit/mutant/meta/example/verification_spec.rb +120 -0
  218. data/spec/unit/mutant/meta/example_spec.rb +32 -0
  219. data/spec/unit/mutant/mutator/node_spec.rb +37 -4
  220. data/spec/unit/mutant/mutator_spec.rb +21 -0
  221. data/spec/unit/mutant/{runner → parallel}/driver_spec.rb +0 -0
  222. data/spec/unit/mutant/parallel/master_spec.rb +13 -13
  223. data/spec/unit/mutant/registry_spec.rb +47 -0
  224. data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +0 -4
  225. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +0 -8
  226. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +0 -2
  227. data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +0 -8
  228. data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +0 -34
  229. data/spec/unit/mutant/reporter/cli_spec.rb +0 -22
  230. data/spec/unit/mutant/repository/diff_spec.rb +6 -6
  231. data/spec/unit/mutant/require_highjack_spec.rb +38 -14
  232. data/spec/unit/mutant/result/env_spec.rb +1 -4
  233. data/spec/unit/mutant/runner_spec.rb +1 -1
  234. data/spec/unit/mutant/subject/method/instance_spec.rb +1 -1
  235. data/spec/unit/mutant/subject_spec.rb +3 -3
  236. data/spec/unit/mutant/util/one_spec.rb +20 -0
  237. data/spec/unit/mutant/zombifier_spec.rb +18 -18
  238. data/test_app/{Gemfile.rspec3.3 → Gemfile.rspec3.5} +2 -2
  239. metadata +94 -24
  240. data/TODO +0 -21
  241. data/lib/mutant/mutator/node/blockarg.rb +0 -13
  242. data/lib/mutant/mutator/node/restarg.rb +0 -13
  243. data/lib/mutant/mutator/registry.rb +0 -49
  244. data/meta/boolean.rb +0 -13
  245. data/meta/regex.rb +0 -19
  246. data/spec/unit/mutant/isolation_spec.rb +0 -104
  247. data/spec/unit/mutant/mutator/registry_spec.rb +0 -57
@@ -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,
@@ -9,6 +9,8 @@ module Mutant
9
9
 
10
10
  children :base, :name
11
11
 
12
+ public :base, :name
13
+
12
14
  # Test if AST node is possibly a top level constant
13
15
  #
14
16
  # @return [Boolean]
@@ -11,6 +11,8 @@ module Mutant
11
11
 
12
12
  children :name, :default_value
13
13
 
14
+ public :name, :default_value
15
+
14
16
  # Test if optarg definition intends to be used
15
17
  #
16
18
  # @return [Boolean]
@@ -8,6 +8,8 @@ module Mutant
8
8
  include NamedChildren, Concord.new(:node)
9
9
 
10
10
  children :captures, :assignment, :body
11
+
12
+ public :captures, :assignment, :body
11
13
  end # Resbody
12
14
 
13
15
  end # Meta
@@ -8,6 +8,8 @@ module Mutant
8
8
  include NamedChildren, Concord.new(:node)
9
9
 
10
10
  children :name
11
+
12
+ public :name
11
13
  end # Restarg
12
14
 
13
15
  end # Meta
@@ -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]
@@ -9,6 +9,8 @@ module Mutant
9
9
 
10
10
  children :name
11
11
 
12
+ public :name
13
+
12
14
  end # Symbol
13
15
  end # Meta
14
16
  end # AST
@@ -42,7 +42,7 @@ module Mutant
42
42
  #
43
43
  # @return [undefined]
44
44
  def define_named_child(name, index)
45
- define_method(name) do
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
- define_method(:remaining_children_with_index) do
56
+ define_private_method(:remaining_children_with_index) do
57
57
  children.each_with_index.drop(names.length)
58
58
  end
59
59
 
60
- define_method(:remaining_children_indices) do
60
+ define_private_method(:remaining_children_indices) do
61
61
  children.each_index.drop(names.length)
62
62
  end
63
63
 
64
- define_method(:remaining_children) do
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
@@ -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 # Node
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