mutant 0.8.10 → 0.8.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -4
- data/Changelog.md +8 -0
- data/README.md +112 -43
- data/Rakefile +2 -16
- data/circle.yml +1 -1
- data/config/flay.yml +2 -2
- data/config/flog.yml +1 -1
- data/config/reek.yml +3 -4
- data/config/rubocop.yml +53 -16
- data/lib/mutant.rb +27 -6
- data/lib/mutant/ast/meta/const.rb +2 -0
- data/lib/mutant/ast/meta/optarg.rb +2 -0
- data/lib/mutant/ast/meta/resbody.rb +2 -0
- data/lib/mutant/ast/meta/restarg.rb +2 -0
- data/lib/mutant/ast/meta/send.rb +4 -0
- data/lib/mutant/ast/meta/symbol.rb +2 -0
- data/lib/mutant/ast/named_children.rb +14 -4
- data/lib/mutant/ast/nodes.rb +3 -1
- data/lib/mutant/ast/regexp.rb +53 -0
- data/lib/mutant/ast/regexp/transformer.rb +185 -0
- data/lib/mutant/ast/regexp/transformer/alternative.rb +39 -0
- data/lib/mutant/ast/regexp/transformer/character_set.rb +46 -0
- data/lib/mutant/ast/regexp/transformer/direct.rb +99 -0
- data/lib/mutant/ast/regexp/transformer/options_group.rb +66 -0
- data/lib/mutant/ast/regexp/transformer/quantifier.rb +112 -0
- data/lib/mutant/ast/regexp/transformer/recursive.rb +50 -0
- data/lib/mutant/ast/regexp/transformer/root.rb +29 -0
- data/lib/mutant/ast/regexp/transformer/text.rb +55 -0
- data/lib/mutant/ast/types.rb +92 -5
- data/lib/mutant/cli.rb +2 -14
- data/lib/mutant/color.rb +1 -1
- data/lib/mutant/config.rb +1 -3
- data/lib/mutant/expression/methods.rb +1 -1
- data/lib/mutant/expression/namespace.rb +2 -2
- data/lib/mutant/expression/parser.rb +1 -1
- data/lib/mutant/integration.rb +10 -28
- data/lib/mutant/isolation.rb +9 -60
- data/lib/mutant/isolation/fork.rb +72 -0
- data/lib/mutant/isolation/none.rb +25 -0
- data/lib/mutant/matcher/config.rb +2 -0
- data/lib/mutant/matcher/method/singleton.rb +5 -4
- data/lib/mutant/meta.rb +11 -4
- data/lib/mutant/meta/example.rb +2 -116
- data/lib/mutant/meta/example/dsl.rb +22 -19
- data/lib/mutant/meta/example/verification.rb +86 -0
- data/lib/mutant/mutator.rb +22 -49
- data/lib/mutant/mutator/node.rb +15 -19
- data/lib/mutant/mutator/node/and_asgn.rb +1 -1
- data/lib/mutant/mutator/node/argument.rb +10 -5
- data/lib/mutant/mutator/node/arguments.rb +5 -9
- data/lib/mutant/mutator/node/begin.rb +4 -17
- data/lib/mutant/mutator/node/block.rb +1 -1
- data/lib/mutant/mutator/node/break.rb +1 -1
- data/lib/mutant/mutator/node/class.rb +21 -0
- data/lib/mutant/mutator/node/conditional_loop.rb +1 -1
- data/lib/mutant/mutator/node/define.rb +1 -1
- data/lib/mutant/mutator/node/defined.rb +1 -1
- data/lib/mutant/mutator/node/dstr.rb +1 -1
- data/lib/mutant/mutator/node/dsym.rb +1 -1
- data/lib/mutant/mutator/node/generic.rb +3 -3
- data/lib/mutant/mutator/node/kwbegin.rb +1 -1
- data/lib/mutant/mutator/node/literal.rb +9 -0
- data/lib/mutant/mutator/node/literal/boolean.rb +1 -1
- data/lib/mutant/mutator/node/literal/fixnum.rb +2 -2
- data/lib/mutant/mutator/node/literal/float.rb +4 -6
- data/lib/mutant/mutator/node/literal/hash.rb +1 -1
- data/lib/mutant/mutator/node/literal/nil.rb +1 -1
- data/lib/mutant/mutator/node/literal/range.rb +2 -19
- data/lib/mutant/mutator/node/literal/regex.rb +43 -3
- data/lib/mutant/mutator/node/literal/string.rb +1 -1
- data/lib/mutant/mutator/node/literal/symbol.rb +2 -4
- data/lib/mutant/mutator/node/masgn.rb +1 -1
- data/lib/mutant/mutator/node/match_current_line.rb +1 -1
- data/lib/mutant/mutator/node/mlhs.rb +2 -3
- data/lib/mutant/mutator/node/named_value/access.rb +2 -2
- data/lib/mutant/mutator/node/named_value/constant_assignment.rb +4 -3
- data/lib/mutant/mutator/node/named_value/variable_assignment.rb +4 -4
- data/lib/mutant/mutator/node/next.rb +1 -1
- data/lib/mutant/mutator/node/nthref.rb +1 -1
- data/lib/mutant/mutator/node/or_asgn.rb +1 -1
- data/lib/mutant/mutator/node/regexp.rb +44 -0
- data/lib/mutant/mutator/node/regopt.rb +31 -0
- data/lib/mutant/mutator/node/resbody.rb +1 -1
- data/lib/mutant/mutator/node/rescue.rb +1 -3
- data/lib/mutant/mutator/node/return.rb +1 -1
- data/lib/mutant/mutator/node/send.rb +43 -3
- data/lib/mutant/mutator/node/send/attribute_assignment.rb +4 -1
- data/lib/mutant/mutator/node/send/conditional.rb +23 -0
- data/lib/mutant/mutator/node/send/index.rb +1 -1
- data/lib/mutant/mutator/node/splat.rb +1 -1
- data/lib/mutant/mutator/node/when.rb +1 -1
- data/lib/mutant/mutator/node/yield.rb +1 -1
- data/lib/mutant/mutator/util.rb +0 -30
- data/lib/mutant/mutator/util/array.rb +4 -16
- data/lib/mutant/parallel.rb +1 -1
- data/lib/mutant/parallel/worker.rb +1 -1
- data/lib/mutant/registry.rb +44 -0
- data/lib/mutant/reporter/cli/format.rb +2 -0
- data/lib/mutant/reporter/cli/printer.rb +2 -2
- data/lib/mutant/reporter/cli/printer/config.rb +0 -1
- data/lib/mutant/reporter/cli/printer/env_progress.rb +1 -11
- data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +1 -1
- data/lib/mutant/reporter/cli/printer/mutation_result.rb +2 -0
- data/lib/mutant/reporter/cli/tput.rb +1 -1
- data/lib/mutant/reporter/sequence.rb +3 -0
- data/lib/mutant/require_highjack.rb +6 -2
- data/lib/mutant/result.rb +1 -1
- data/lib/mutant/subject.rb +5 -5
- data/lib/mutant/subject/method/instance.rb +1 -2
- data/lib/mutant/util.rb +18 -0
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/zombifier.rb +5 -3
- data/meta/and.rb +1 -1
- data/meta/and_asgn.rb +1 -1
- data/meta/array.rb +2 -2
- data/meta/begin.rb +2 -2
- data/meta/block.rb +7 -7
- data/meta/block_pass.rb +1 -1
- data/meta/blockarg.rb +1 -1
- data/meta/break.rb +1 -1
- data/meta/case.rb +2 -2
- data/meta/casgn.rb +11 -2
- data/meta/cbase.rb +1 -1
- data/meta/class.rb +10 -0
- data/meta/const.rb +9 -1
- data/meta/csend.rb +8 -0
- data/meta/cvar.rb +1 -1
- data/meta/cvasgn.rb +1 -1
- data/meta/date.rb +4 -4
- data/meta/def.rb +14 -14
- data/meta/defined.rb +1 -1
- data/meta/dstr.rb +1 -1
- data/meta/dsym.rb +1 -1
- data/meta/ensure.rb +1 -1
- data/meta/false.rb +1 -1
- data/meta/float.rb +3 -3
- data/meta/gvar.rb +1 -1
- data/meta/gvasgn.rb +1 -1
- data/meta/hash.rb +1 -1
- data/meta/if.rb +17 -3
- data/meta/int.rb +1 -1
- data/meta/ivar.rb +1 -1
- data/meta/ivasgn.rb +14 -1
- data/meta/kwarg.rb +8 -0
- data/meta/kwbegin.rb +1 -1
- data/meta/kwoptarg.rb +11 -0
- data/meta/lvar.rb +1 -1
- data/meta/lvasgn.rb +1 -1
- data/meta/masgn.rb +1 -1
- data/meta/match_current_line.rb +2 -2
- data/meta/next.rb +1 -1
- data/meta/nil.rb +1 -1
- data/meta/nthref.rb +5 -5
- data/meta/op_assgn.rb +1 -1
- data/meta/or.rb +1 -1
- data/meta/or_asgn.rb +5 -5
- data/meta/range.rb +2 -8
- data/meta/redo.rb +1 -1
- data/meta/regexp.rb +106 -0
- data/meta/regexp/regexp_bol_anchor.rb +13 -0
- data/meta/regexp/regexp_bos_anchor.rb +26 -0
- data/meta/regexp/regexp_root_expression.rb +13 -0
- data/meta/regopt.rb +8 -0
- data/meta/rescue.rb +49 -4
- data/meta/restarg.rb +6 -9
- data/meta/return.rb +2 -2
- data/meta/self.rb +1 -1
- data/meta/send.rb +228 -55
- data/meta/str.rb +1 -1
- data/meta/super.rb +3 -3
- data/meta/{symbol.rb → sym.rb} +1 -1
- data/meta/true.rb +1 -1
- data/meta/until.rb +1 -1
- data/meta/while.rb +2 -2
- data/meta/yield.rb +1 -1
- data/mutant-rspec.gemspec +2 -2
- data/mutant.gemspec +6 -5
- data/spec/integration/mutant/isolation/fork_spec.rb +8 -0
- data/spec/integration/mutant/rspec_spec.rb +1 -1
- data/spec/integration/mutant/test_mutator_handles_types_spec.rb +1 -2
- data/spec/integrations.yml +93 -24
- data/spec/spec_helper.rb +12 -7
- data/spec/support/compress_helper.rb +1 -1
- data/spec/support/corpus.rb +115 -50
- data/spec/support/fake_actor.rb +5 -5
- data/spec/support/file_system.rb +1 -1
- data/spec/support/ice_nine_config.rb +3 -3
- data/spec/support/ruby_vm.rb +11 -12
- data/spec/support/shared_context.rb +22 -13
- data/spec/support/test_app.rb +1 -1
- data/spec/support/warning.rb +64 -0
- data/spec/support/warnings.yml +4 -0
- data/spec/support/xspec.rb +177 -0
- data/spec/unit/mutant/actor/env_spec.rb +2 -2
- data/spec/unit/mutant/actor/sender_spec.rb +1 -1
- data/spec/unit/mutant/ast/meta/send_spec.rb +1 -1
- data/spec/unit/mutant/ast/named_children_spec.rb +26 -0
- data/spec/unit/mutant/ast/regexp/parse_spec.rb +7 -0
- data/spec/unit/mutant/ast/regexp/supported_predicate_spec.rb +14 -0
- data/spec/unit/mutant/ast/regexp/transformer/lookup_table/table_spec.rb +19 -0
- data/spec/unit/mutant/ast/regexp/transformer/lookup_table_spec.rb +33 -0
- data/spec/unit/mutant/ast/regexp/transformer_spec.rb +19 -0
- data/spec/unit/mutant/ast/regexp_spec.rb +617 -0
- data/spec/unit/mutant/cli_spec.rb +7 -45
- data/spec/unit/mutant/context_spec.rb +4 -7
- data/spec/unit/mutant/env/{boostrap_spec.rb → bootstrap_spec.rb} +2 -2
- data/spec/unit/mutant/env_spec.rb +13 -16
- data/spec/unit/mutant/expression/namespace/{flat_spec.rb → exact_spec.rb} +0 -0
- data/spec/unit/mutant/integration/rspec_spec.rb +2 -2
- data/spec/unit/mutant/integration_spec.rb +14 -0
- data/spec/unit/mutant/isolation/fork_spec.rb +155 -0
- data/spec/unit/mutant/isolation/none_spec.rb +16 -0
- data/spec/unit/mutant/loader_spec.rb +1 -1
- data/spec/unit/mutant/matcher/methods/instance_spec.rb +2 -4
- data/spec/unit/mutant/meta/example/dsl_spec.rb +106 -0
- data/spec/unit/mutant/meta/example/verification_spec.rb +120 -0
- data/spec/unit/mutant/meta/example_spec.rb +32 -0
- data/spec/unit/mutant/mutator/node_spec.rb +37 -4
- data/spec/unit/mutant/mutator_spec.rb +21 -0
- data/spec/unit/mutant/{runner → parallel}/driver_spec.rb +0 -0
- data/spec/unit/mutant/parallel/master_spec.rb +13 -13
- data/spec/unit/mutant/registry_spec.rb +47 -0
- data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +0 -4
- data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +0 -8
- data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +0 -2
- data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +0 -8
- data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +0 -34
- data/spec/unit/mutant/reporter/cli_spec.rb +0 -22
- data/spec/unit/mutant/repository/diff_spec.rb +6 -6
- data/spec/unit/mutant/require_highjack_spec.rb +38 -14
- data/spec/unit/mutant/result/env_spec.rb +1 -4
- data/spec/unit/mutant/runner_spec.rb +1 -1
- data/spec/unit/mutant/subject/method/instance_spec.rb +1 -1
- data/spec/unit/mutant/subject_spec.rb +3 -3
- data/spec/unit/mutant/util/one_spec.rb +20 -0
- data/spec/unit/mutant/zombifier_spec.rb +18 -18
- data/test_app/{Gemfile.rspec3.3 → Gemfile.rspec3.5} +2 -2
- metadata +94 -24
- data/TODO +0 -21
- data/lib/mutant/mutator/node/blockarg.rb +0 -13
- data/lib/mutant/mutator/node/restarg.rb +0 -13
- data/lib/mutant/mutator/registry.rb +0 -49
- data/meta/boolean.rb +0 -13
- data/meta/regex.rb +0 -19
- data/spec/unit/mutant/isolation_spec.rb +0 -104
- data/spec/unit/mutant/mutator/registry_spec.rb +0 -57
@@ -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
|