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.
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