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