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
@@ -0,0 +1,39 @@
1
+ module Mutant
2
+ module AST
3
+ module Regexp
4
+ class Transformer
5
+ # Transformer for Regexp `alternative` nodes
6
+ #
7
+ # This transformer is very similar to the generic recursive mapper
8
+ # except for the fact that the `Regexp::Expression` class for
9
+ # `alternative` nodes has a unique constructor
10
+ class Alternative < self
11
+ register :regexp_sequence_expression
12
+
13
+ # Mapper from `Regexp::Expression` to `Parser::AST::Node`
14
+ ExpressionToAST = Class.new(Recursive::ExpressionToAST)
15
+
16
+ # Mapper from `Parser::AST::Node` to `Regexp::Expression`
17
+ class ASTToExpression < Transformer::ASTToExpression
18
+ # Alternative instance with dummy values for `level`, `set_level`,
19
+ # and `conditional_level`. These values do not affect unparsing
20
+ ALTERNATIVE = IceNine.deep_freeze(
21
+ ::Regexp::Expression::Alternative.new(0, 0, 0)
22
+ )
23
+
24
+ private
25
+
26
+ # Transform ast into expression
27
+ #
28
+ # @return [Regexp::Expression::Alternative]
29
+ def transform
30
+ ALTERNATIVE.dup.tap do |alt|
31
+ alt.expressions = subexpressions
32
+ end
33
+ end
34
+ end # ASTToExpression
35
+ end # Alternative
36
+ end # Transformer
37
+ end # Regexp
38
+ end # AST
39
+ end # Mutant
@@ -0,0 +1,46 @@
1
+ module Mutant
2
+ module AST
3
+ module Regexp
4
+ class Transformer
5
+ # Transformer for character sets
6
+ #
7
+ # The `Regexp::Expression` representation of a character set
8
+ # is unique due to its usage of the `#members` attribute which
9
+ # is why it gets its own transformer
10
+ class CharacterSet < self
11
+ register :regexp_character_set
12
+
13
+ # Mapper from `Regexp::Expression` to `Parser::AST::Node`
14
+ class ExpressionToAST < Transformer::ExpressionToAST
15
+ # Transform character set expression into node
16
+ #
17
+ # @return [Parser::AST::Node]
18
+ def call
19
+ quantify(ast(*expression.members))
20
+ end
21
+ end # ExpressionToAST
22
+
23
+ # Mapper from `Parser::AST::Node` to `Regexp::Expression`
24
+ class ASTToExpression < Transformer::ASTToExpression
25
+ CHARACTER_SET = IceNine.deep_freeze(
26
+ ::Regexp::Expression::CharacterSet.new(
27
+ ::Regexp::Token.new(:set, :character, '[')
28
+ )
29
+ )
30
+
31
+ private
32
+
33
+ # Transform node into expression
34
+ #
35
+ # @return [Regexp::Expression]
36
+ def transform
37
+ CHARACTER_SET.dup.tap do |expression|
38
+ expression.members = node.children
39
+ end
40
+ end
41
+ end # ASTToExpression
42
+ end # CharacterSet
43
+ end # Transformer
44
+ end # Regexp
45
+ end # AST
46
+ end # Mutant
@@ -0,0 +1,99 @@
1
+ module Mutant
2
+ module AST
3
+ module Regexp
4
+ class Transformer
5
+ # Transformer for nodes which map directly to other domain
6
+ #
7
+ # A node maps "directly" to another domain if the node never
8
+ # has children or text which needs to be preserved for a mapping
9
+ #
10
+ # @example direct mapping
11
+ #
12
+ # input = /\d/
13
+ # expression = Regexp::Parser.parse(input).first
14
+ # node = Transformer::Direct.to_ast(expression)
15
+ #
16
+ # # the digit type always has the same text and no children
17
+ # expression.text # => "\\d"
18
+ # expression.terminal? # => true
19
+ #
20
+ # # therefore the `Parser::AST::Node` is always the same
21
+ # node # => s(:regexp_digit_type)
22
+ class Direct < self
23
+ # Mapper from `Regexp::Expression` to `Parser::AST::Node`
24
+ class ExpressionToAST < Transformer::ExpressionToAST
25
+ # Transform expression into node
26
+ #
27
+ # @return [Parser::AST::Node]
28
+ def call
29
+ quantify(ast)
30
+ end
31
+ end # ExpressionToAST
32
+
33
+ # Mapper from `Parser::AST::Node` to `Regexp::Expression`
34
+ class ASTToExpression < Transformer::ASTToExpression
35
+ include LookupTable
36
+
37
+ # rubocop:disable LineLength
38
+ TABLE = Table.create(
39
+ [:regexp_one_or_more_escape, [:escape, :one_or_more, '\+'], ::Regexp::Expression::EscapeSequence::Literal],
40
+ [:regexp_zero_or_one_escape, [:escape, :zero_or_one, '\?'], ::Regexp::Expression::EscapeSequence::Literal],
41
+ [:regexp_alternation_escape, [:escape, :alternation, '\|'], ::Regexp::Expression::EscapeSequence::Literal],
42
+ [:regexp_group_open_escape, [:escape, :group_open, '\('], ::Regexp::Expression::EscapeSequence::Literal],
43
+ [:regexp_group_close_escape, [:escape, :group_close, '\)'], ::Regexp::Expression::EscapeSequence::Literal],
44
+ [:regexp_interval_open_escape, [:escape, :interval_open, '\{'], ::Regexp::Expression::EscapeSequence::Literal],
45
+ [:regexp_interval_close_escape, [:escape, :interval_close, '\}'], ::Regexp::Expression::EscapeSequence::Literal],
46
+ [:regexp_newline_escape, [:escape, :newline, '\n'], ::Regexp::Expression::EscapeSequence::Literal],
47
+ [:regexp_zero_or_more_escape, [:escape, :zero_or_more, '\*'], ::Regexp::Expression::EscapeSequence::Literal],
48
+ [:regexp_carriage_escape, [:escape, :carriage, '\r'], ::Regexp::Expression::EscapeSequence::Literal],
49
+ [:regexp_dot_escape, [:escape, :dot, '\.'], ::Regexp::Expression::EscapeSequence::Literal],
50
+ [:regexp_set_open_escape, [:escape, :set_open, '\['], ::Regexp::Expression::EscapeSequence::Literal],
51
+ [:regexp_set_close_escape, [:escape, :set_close, '\]'], ::Regexp::Expression::EscapeSequence::Literal],
52
+ [:regexp_eol_escape, [:escape, :eol, '\$'], ::Regexp::Expression::EscapeSequence::Literal],
53
+ [:regexp_bell_escape, [:escape, :bell, '\a'], ::Regexp::Expression::EscapeSequence::Literal],
54
+ [:regexp_escape_escape, [:escape, :escape, '\e'], ::Regexp::Expression::EscapeSequence::AsciiEscape],
55
+ [:regexp_form_feed_escape, [:escape, :form_feed, '\f'], ::Regexp::Expression::EscapeSequence::FormFeed],
56
+ [:regexp_vertical_tab_escape, [:escape, :vertical_tab, '\v'], ::Regexp::Expression::EscapeSequence::VerticalTab],
57
+ [:regexp_mark_keep, [:keep, :mark, '\K'], ::Regexp::Expression::Keep::Mark],
58
+ [:regexp_bos_anchor, [:anchor, :bos, '\\A'], ::Regexp::Expression::Anchor::BeginningOfString],
59
+ [:regexp_match_start_anchor, [:anchor, :match_start, '\\G'], ::Regexp::Expression::Anchor::MatchStart],
60
+ [:regexp_word_boundary_anchor, [:anchor, :word_boundary, '\b'], ::Regexp::Expression::Anchor::WordBoundary],
61
+ [:regexp_eos_ob_eol_anchor, [:anchor, :eos_ob_eol, '\\Z'], ::Regexp::Expression::Anchor::EndOfStringOrBeforeEndOfLine],
62
+ [:regexp_eos_anchor, [:anchor, :eos, '\\z'], ::Regexp::Expression::Anchor::EndOfString],
63
+ [:regexp_bol_anchor, [:anchor, :bol, '^'], ::Regexp::Expression::Anchor::BeginningOfLine],
64
+ [:regexp_eol_anchor, [:anchor, :eol, '$'], ::Regexp::Expression::Anchor::EndOfLine],
65
+ [:regexp_nonword_boundary_anchor, [:anchor, :nonword_boundary, '\\B'], ::Regexp::Expression::Anchor::NonWordBoundary],
66
+ [:regexp_alpha_property, [:property, :alpha, '\p{Alpha}'], ::Regexp::Expression::UnicodeProperty::Alpha],
67
+ [:regexp_script_arabic_property, [:property, :script_arabic, '\p{Arabic}'], ::Regexp::Expression::UnicodeProperty::Script],
68
+ [:regexp_script_hangul_property, [:property, :script_hangul, '\p{Hangul}'], ::Regexp::Expression::UnicodeProperty::Script],
69
+ [:regexp_script_han_property, [:property, :script_han, '\p{Han}'], ::Regexp::Expression::UnicodeProperty::Script],
70
+ [:regexp_script_hiragana_property, [:property, :script_hiragana, '\p{Hiragana}'], ::Regexp::Expression::UnicodeProperty::Script],
71
+ [:regexp_script_katakana_property, [:property, :script_katakana, '\p{Katakana}'], ::Regexp::Expression::UnicodeProperty::Script],
72
+ [:regexp_letter_any_property, [:property, :letter_any, '\p{L}'], ::Regexp::Expression::UnicodeProperty::Letter::Any],
73
+ [:regexp_digit_type, [:type, :digit, '\d'], ::Regexp::Expression::CharacterType::Digit],
74
+ [:regexp_space_type, [:type, :space, '\s'], ::Regexp::Expression::CharacterType::Space],
75
+ [:regexp_word_type, [:type, :word, '\w'], ::Regexp::Expression::CharacterType::Word],
76
+ [:regexp_hex_type, [:type, :hex, '\h'], ::Regexp::Expression::CharacterType::Hex],
77
+ [:regexp_nonhex_type, [:type, :nonhex, '\H'], ::Regexp::Expression::CharacterType::NonHex],
78
+ [:regexp_nondigit_type, [:type, :nondigit, '\D'], ::Regexp::Expression::CharacterType::NonDigit],
79
+ [:regexp_nonspace_type, [:type, :nonspace, '\S'], ::Regexp::Expression::CharacterType::NonSpace],
80
+ [:regexp_nonword_type, [:type, :nonword, '\W'], ::Regexp::Expression::CharacterType::NonWord],
81
+ [:regexp_dot_meta, [:meta, :dot, '.'], ::Regexp::Expression::CharacterType::Any]
82
+ )
83
+
84
+ private
85
+
86
+ # Transform ast into expression
87
+ #
88
+ # @return [Regexp::Expression]
89
+ def transform
90
+ expression_class.new(expression_token)
91
+ end
92
+ end # ASTToExpression
93
+
94
+ ASTToExpression::TABLE.types.each(&method(:register))
95
+ end # Direct
96
+ end # Transformer
97
+ end # Regexp
98
+ end # AST
99
+ end # Mutant
@@ -0,0 +1,66 @@
1
+ module Mutant
2
+ module AST
3
+ module Regexp
4
+ class Transformer
5
+ # Transformer for option groups
6
+ class OptionsGroup < self
7
+ register :regexp_options_group
8
+
9
+ # Mapper from `Regexp::Expression` to `Parser::AST::Node`
10
+ class ExpressionToAST < Transformer::ExpressionToAST
11
+
12
+ # Transform options group into node
13
+ #
14
+ # @return [Parser::AST::Node]
15
+ def call
16
+ quantify(ast(expression.options, *children))
17
+ end
18
+ end # ExpressionToAST
19
+
20
+ # Mapper from `Parser::AST::Node` to `Regexp::Expression`
21
+ class ASTToExpression < Transformer::ASTToExpression
22
+ include NamedChildren
23
+
24
+ children :options
25
+
26
+ private
27
+
28
+ # Covnert node into expression
29
+ #
30
+ # @return [Regexp::Expression::Group::Options]
31
+ def transform
32
+ options_group.tap do |expression|
33
+ expression.expressions = subexpressions
34
+ end
35
+ end
36
+
37
+ # Recursive mapping of children
38
+ #
39
+ # @return [Array<Regexp::Expression>]
40
+ def subexpressions
41
+ remaining_children.map(&Regexp.public_method(:to_expression))
42
+ end
43
+
44
+ # Options group instance constructed from options text
45
+ #
46
+ # @return [Regexp::Expression::Group::Options]
47
+ def options_group
48
+ ::Regexp::Expression::Group::Options.new(
49
+ ::Regexp::Token.new(:group, :options, text)
50
+ )
51
+ end
52
+
53
+ # Flag text constructed from enabled options
54
+ #
55
+ # @return [String]
56
+ def text
57
+ flags = options.map { |key, value| key if value }.join
58
+
59
+ "(?#{flags}-:"
60
+ end
61
+ end # ASTToExpression
62
+ end # OptionsGroup
63
+ end # Transformer
64
+ end # Regexp
65
+ end # AST
66
+ end # Mutant
@@ -0,0 +1,112 @@
1
+ module Mutant
2
+ module AST
3
+ module Regexp
4
+ class Transformer
5
+ # Transformer for regexp quantifiers
6
+ class Quantifier < self
7
+ # Mapper from `Regexp::Expression` to `Parser::AST::Node`
8
+ class ExpressionToAST < Transformer::ExpressionToAST
9
+ # Transform quantifier into node
10
+ #
11
+ # @return [Parser::AST::Node]
12
+ def call
13
+ ast(expression.min, expression.max)
14
+ end
15
+
16
+ private
17
+
18
+ # Custom `type` for quantifiers which use `mode` instead of `type`
19
+ #
20
+ # @return [Symbol]
21
+ def type
22
+ :"regexp_#{expression.mode}_#{expression.token}"
23
+ end
24
+ end # ExpressionToAST
25
+
26
+ # Mapper from `Parser::AST::Node` to `Regexp::Expression`
27
+ class ASTToExpression < Transformer::ASTToExpression
28
+ include NamedChildren
29
+
30
+ children :min, :max, :subject
31
+
32
+ Quantifier = Class.new.include(Concord::Public.new(:type, :suffix, :mode))
33
+
34
+ QUANTIFIER_MAP = IceNine.deep_freeze({
35
+ regexp_greedy_zero_or_more: [:zero_or_more, '*', :greedy],
36
+ regexp_greedy_one_or_more: [:one_or_more, '+', :greedy],
37
+ regexp_greedy_zero_or_one: [:zero_or_one, '?', :greedy],
38
+ regexp_possessive_zero_or_one: [:zero_or_one, '?+', :possessive],
39
+ regexp_reluctant_zero_or_more: [:zero_or_more, '*?', :reluctant],
40
+ regexp_reluctant_one_or_more: [:one_or_more, '+?', :reluctant],
41
+ regexp_possessive_zero_or_more: [:zero_or_more, '*+', :possessive],
42
+ regexp_possessive_one_or_more: [:one_or_more, '++', :possessive],
43
+ regexp_greedy_interval: [:interval, '', :greedy],
44
+ regexp_reluctant_interval: [:interval, '?', :reluctant],
45
+ regexp_possessive_interval: [:interval, '+', :possessive]
46
+ }.map { |ast_type, arguments| [ast_type, Quantifier.new(*arguments)] }.to_h)
47
+
48
+ private
49
+
50
+ # Transform ast into quantifier attached to expression
51
+ #
52
+ # @return [Regexp::Expression]
53
+ def transform
54
+ Regexp.to_expression(subject).dup.tap do |expression|
55
+ expression.quantify(type, text, min, max, mode)
56
+ end
57
+ end
58
+
59
+ # Quantifier text
60
+ #
61
+ # @return [String]
62
+ def text
63
+ if type.equal?(:interval)
64
+ interval_text + suffix
65
+ else
66
+ suffix
67
+ end
68
+ end
69
+
70
+ # Type of quantifier
71
+ #
72
+ # @return [:zero_or_more,:one_or_more,:interval]
73
+ def type
74
+ quantifier.type
75
+ end
76
+
77
+ # Regexp symbols used to specify quantifier
78
+ #
79
+ # @return [String]
80
+ def suffix
81
+ quantifier.suffix
82
+ end
83
+
84
+ # The quantifier "mode"
85
+ #
86
+ # @return [:greedy,:possessive,:reluctant]
87
+ def mode
88
+ quantifier.mode
89
+ end
90
+
91
+ # Quantifier mapping information for current node
92
+ #
93
+ # @return [Quantifier]
94
+ def quantifier
95
+ QUANTIFIER_MAP.fetch(node.type)
96
+ end
97
+
98
+ # Interval text constructed from min and max
99
+ #
100
+ # @return [String]
101
+ def interval_text
102
+ interval = [min, max].map { |num| num if num > 0 }.uniq
103
+ "{#{interval.join(',')}}"
104
+ end
105
+ end # ASTToExpression
106
+
107
+ ASTToExpression::QUANTIFIER_MAP.keys.each(&method(:register))
108
+ end # Quantifier
109
+ end # Transformer
110
+ end # Regexp
111
+ end # AST
112
+ end # Mutant
@@ -0,0 +1,50 @@
1
+ module Mutant
2
+ module AST
3
+ module Regexp
4
+ class Transformer
5
+ # Transformer for nodes with children
6
+ class Recursive < self
7
+ # Mapper from `Regexp::Expression` to `Parser::AST::Node`
8
+ class ExpressionToAST < Transformer::ExpressionToAST
9
+ # Transform expression and children into nodes
10
+ #
11
+ # @return [Parser::AST::Node]
12
+ def call
13
+ quantify(ast(*children))
14
+ end
15
+ end # ExpressionToAST
16
+
17
+ # Mapper from `Parser::AST::Node` to `Regexp::Expression`
18
+ class ASTToExpression < Transformer::ASTToExpression
19
+ include LookupTable
20
+
21
+ # rubocop:disable LineLength
22
+ TABLE = Table.create(
23
+ [:regexp_alternation_meta, [:meta, :alternation, '|'], ::Regexp::Expression::Alternation],
24
+ [:regexp_nlookahead_assertion, [:assertion, :nlookahead, '(?!'], ::Regexp::Expression::Assertion::NegativeLookahead],
25
+ [:regexp_passive_group, [:group, :passive, '(?:'], ::Regexp::Expression::Group::Passive],
26
+ [:regexp_nlookbehind_assertion, [:assertion, :nlookbehind, '(?<!'], ::Regexp::Expression::Assertion::NegativeLookbehind],
27
+ [:regexp_lookbehind_assertion, [:assertion, :lookbehind, '(?<='], ::Regexp::Expression::Assertion::Lookbehind],
28
+ [:regexp_lookahead_assertion, [:assertion, :lookahead, '(?='], ::Regexp::Expression::Assertion::Lookahead],
29
+ [:regexp_atomic_group, [:group, :atomic, '(?>'], ::Regexp::Expression::Group::Atomic],
30
+ [:regexp_capture_group, [:group, :capture, '('], ::Regexp::Expression::Group::Capture]
31
+ )
32
+
33
+ private
34
+
35
+ # Transform nodes and their children into expressions
36
+ #
37
+ # @return [Regexp::Expression]
38
+ def transform
39
+ expression_class.new(expression_token).tap do |expression|
40
+ expression.expressions = subexpressions
41
+ end
42
+ end
43
+ end # ASTToExpression
44
+
45
+ ASTToExpression::TABLE.types.each(&method(:register))
46
+ end # Recursive
47
+ end # Transformer
48
+ end # Regexp
49
+ end # AST
50
+ end # Mutant
@@ -0,0 +1,29 @@
1
+ module Mutant
2
+ module AST
3
+ module Regexp
4
+ class Transformer
5
+ # Transformer for root nodes
6
+ class Root < self
7
+ register :regexp_root_expression
8
+
9
+ ExpressionToAST = Class.new(Recursive::ExpressionToAST)
10
+
11
+ # Mapper from `Parser::AST::Node` to `Regexp::Expression`
12
+ class ASTToExpression < Transformer::ASTToExpression
13
+
14
+ private
15
+
16
+ # Transform node into root expression
17
+ #
18
+ # @return [Regexp::Expression::Root]
19
+ def transform
20
+ ::Regexp::Expression::Root.new.tap do |root|
21
+ root.expressions = subexpressions
22
+ end
23
+ end
24
+ end # ASTToExpression
25
+ end # Root
26
+ end # Transformer
27
+ end # Regexp
28
+ end # AST
29
+ end # Mutant