Use regexp_parser 1.2.0

This commit is contained in:
Jannosch Müller 2018-09-28 10:23:09 +02:00
parent 6d26d1fabc
commit 82c546fe92
23 changed files with 322 additions and 236 deletions

View File

@ -15,7 +15,7 @@ PATH
parallel (~> 1.3)
parser (~> 2.5.1)
procto (~> 0.0.2)
regexp_parser (~> 0.4.9)
regexp_parser (~> 1.2)
unparser (~> 0.2.5)
mutant-rspec (0.8.16)
mutant (~> 0.8.16)
@ -107,7 +107,7 @@ GEM
kwalify (~> 0.7.0)
parser (>= 2.5.0.0, < 2.6, != 2.5.1.1)
rainbow (>= 2.0, < 4.0)
regexp_parser (0.4.13)
regexp_parser (1.2.0)
rspec (3.8.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)

View File

@ -1,3 +1,3 @@
---
threshold: 16
total_score: 1318
total_score: 1364

View File

@ -56,13 +56,12 @@ require 'mutant/ast/node_predicates'
require 'mutant/ast/regexp'
require 'mutant/ast/regexp/transformer'
require 'mutant/ast/regexp/transformer/direct'
require 'mutant/ast/regexp/transformer/text'
require 'mutant/ast/regexp/transformer/recursive'
require 'mutant/ast/regexp/transformer/quantifier'
require 'mutant/ast/regexp/transformer/named_group'
require 'mutant/ast/regexp/transformer/options_group'
require 'mutant/ast/regexp/transformer/character_set'
require 'mutant/ast/regexp/transformer/quantifier'
require 'mutant/ast/regexp/transformer/recursive'
require 'mutant/ast/regexp/transformer/root'
require 'mutant/ast/regexp/transformer/alternative'
require 'mutant/ast/regexp/transformer/text'
require 'mutant/ast/meta'
require 'mutant/ast/meta/send'
require 'mutant/ast/meta/const'

View File

@ -4,10 +4,6 @@ module Mutant
module AST
# Regexp source mapper
module Regexp
UNSUPPORTED_EXPRESSION_TYPE = :conditional
private_constant(*constants(false))
# Parse regex string into expression
#
# @param regexp [String]
@ -17,17 +13,6 @@ module Mutant
::Regexp::Parser.parse(regexp)
end
# Check if expression is supported by mapper
#
# @param expression [Regexp::Expression]
#
# @return [Boolean]
def self.supported?(expression)
expression.terminal? || expression.all? do |subexp|
!subexp.type.equal?(UNSUPPORTED_EXPRESSION_TYPE) && supported?(subexp)
end
end
# Convert expression into ast node
#
# @param expression [Regexp::Expression]

View File

@ -1,41 +0,0 @@
# frozen_string_literal: true
module Mutant
module AST
module Regexp
class Transformer
# Transformer for Regexp `alternative` nodes
#
# This transformer is very similar to the generic recursive mapper
# except for the fact that the `Regexp::Expression` class for
# `alternative` nodes has a unique constructor
class Alternative < self
register :regexp_sequence_expression
# Mapper from `Regexp::Expression` to `Parser::AST::Node`
ExpressionToAST = Class.new(Recursive::ExpressionToAST)
# Mapper from `Parser::AST::Node` to `Regexp::Expression`
class ASTToExpression < Transformer::ASTToExpression
# Alternative instance with dummy values for `level`, `set_level`,
# and `conditional_level`. These values do not affect unparsing
ALTERNATIVE = IceNine.deep_freeze(
::Regexp::Expression::Alternative.new(0, 0, 0)
)
private
# Transform ast into expression
#
# @return [Regexp::Expression::Alternative]
def transform
ALTERNATIVE.dup.tap do |alt|
alt.expressions = subexpressions
end
end
end # ASTToExpression
end # Alternative
end # Transformer
end # Regexp
end # AST
end # Mutant

View File

@ -1,48 +0,0 @@
# frozen_string_literal: true
module Mutant
module AST
module Regexp
class Transformer
# Transformer for character sets
#
# The `Regexp::Expression` representation of a character set
# is unique due to its usage of the `#members` attribute which
# is why it gets its own transformer
class CharacterSet < self
register :regexp_character_set
# Mapper from `Regexp::Expression` to `Parser::AST::Node`
class ExpressionToAST < Transformer::ExpressionToAST
# Transform character set expression into node
#
# @return [Parser::AST::Node]
def call
quantify(ast(*expression.members))
end
end # ExpressionToAST
# Mapper from `Parser::AST::Node` to `Regexp::Expression`
class ASTToExpression < Transformer::ASTToExpression
CHARACTER_SET = IceNine.deep_freeze(
::Regexp::Expression::CharacterSet.new(
::Regexp::Token.new(:set, :character, '[')
)
)
private
# Transform node into expression
#
# @return [Regexp::Expression]
def transform
CHARACTER_SET.dup.tap do |expression|
expression.members = node.children
end
end
end # ASTToExpression
end # CharacterSet
end # Transformer
end # Regexp
end # AST
end # Mutant

View File

@ -38,53 +38,71 @@ module Mutant
# rubocop:disable LineLength
TABLE = Table.create(
[:regexp_alpha_property, [:property, :alpha, '\p{Alpha}'], ::Regexp::Expression::UnicodeProperty::Alpha],
[:regexp_alternation_escape, [:escape, :alternation, '\|'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_bell_escape, [:escape, :bell, '\a'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_bol_anchor, [:anchor, :bol, '^'], ::Regexp::Expression::Anchor::BeginningOfLine],
[:regexp_bol_escape, [:escape, :bol, '\^'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_bos_anchor, [:anchor, :bos, '\\A'], ::Regexp::Expression::Anchor::BeginningOfString],
[:regexp_carriage_escape, [:escape, :carriage, '\r'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_digit_type, [:type, :digit, '\d'], ::Regexp::Expression::CharacterType::Digit],
[:regexp_dot_escape, [:escape, :dot, '\.'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_dot_meta, [:meta, :dot, '.'], ::Regexp::Expression::CharacterType::Any],
[:regexp_eol_anchor, [:anchor, :eol, '$'], ::Regexp::Expression::Anchor::EndOfLine],
[:regexp_eol_escape, [:escape, :eol, '\$'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_eos_anchor, [:anchor, :eos, '\\z'], ::Regexp::Expression::Anchor::EndOfString],
[:regexp_eos_ob_eol_anchor, [:anchor, :eos_ob_eol, '\\Z'], ::Regexp::Expression::Anchor::EndOfStringOrBeforeEndOfLine],
[:regexp_escape_escape, [:escape, :escape, '\e'], ::Regexp::Expression::EscapeSequence::AsciiEscape],
[:regexp_form_feed_escape, [:escape, :form_feed, '\f'], ::Regexp::Expression::EscapeSequence::FormFeed],
[:regexp_group_close_escape, [:escape, :group_close, '\)'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_group_open_escape, [:escape, :group_open, '\('], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_hex_type, [:type, :hex, '\h'], ::Regexp::Expression::CharacterType::Hex],
[:regexp_interval_close_escape, [:escape, :interval_close, '\}'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_interval_open_escape, [:escape, :interval_open, '\{'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_letter_any_property, [:property, :letter_any, '\p{L}'], ::Regexp::Expression::UnicodeProperty::Letter::Any],
[:regexp_mark_keep, [:keep, :mark, '\K'], ::Regexp::Expression::Keep::Mark],
[:regexp_match_start_anchor, [:anchor, :match_start, '\\G'], ::Regexp::Expression::Anchor::MatchStart],
[:regexp_newline_escape, [:escape, :newline, '\n'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_nondigit_type, [:type, :nondigit, '\D'], ::Regexp::Expression::CharacterType::NonDigit],
[:regexp_nonhex_type, [:type, :nonhex, '\H'], ::Regexp::Expression::CharacterType::NonHex],
[:regexp_nonspace_type, [:type, :nonspace, '\S'], ::Regexp::Expression::CharacterType::NonSpace],
[:regexp_nonword_boundary_anchor, [:anchor, :nonword_boundary, '\\B'], ::Regexp::Expression::Anchor::NonWordBoundary],
[:regexp_nonword_type, [:type, :nonword, '\W'], ::Regexp::Expression::CharacterType::NonWord],
[:regexp_one_or_more_escape, [:escape, :one_or_more, '\+'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_print_nonproperty, [:property, :nonprint, '\P{Print}'], ::Regexp::Expression::UnicodeProperty::Print],
[:regexp_print_property, [:property, :print, '\p{Print}'], ::Regexp::Expression::UnicodeProperty::Print],
[:regexp_script_arabic_property, [:property, :script_arabic, '\p{Arabic}'], ::Regexp::Expression::UnicodeProperty::Script],
[:regexp_script_han_property, [:property, :script_han, '\p{Han}'], ::Regexp::Expression::UnicodeProperty::Script],
[:regexp_script_hangul_property, [:property, :script_hangul, '\p{Hangul}'], ::Regexp::Expression::UnicodeProperty::Script],
[:regexp_script_hiragana_property, [:property, :script_hiragana, '\p{Hiragana}'], ::Regexp::Expression::UnicodeProperty::Script],
[:regexp_script_katakana_property, [:property, :script_katakana, '\p{Katakana}'], ::Regexp::Expression::UnicodeProperty::Script],
[:regexp_set_close_escape, [:escape, :set_close, '\]'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_set_open_escape, [:escape, :set_open, '\['], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_space_type, [:type, :space, '\s'], ::Regexp::Expression::CharacterType::Space],
[:regexp_vertical_tab_escape, [:escape, :vertical_tab, '\v'], ::Regexp::Expression::EscapeSequence::VerticalTab],
[:regexp_word_boundary_anchor, [:anchor, :word_boundary, '\b'], ::Regexp::Expression::Anchor::WordBoundary],
[:regexp_word_type, [:type, :word, '\w'], ::Regexp::Expression::CharacterType::Word],
[:regexp_xgrapheme_type, [:type, :xgrapheme, '\X'], ::Regexp::Expression::CharacterType::ExtendedGrapheme],
[:regexp_zero_or_more_escape, [:escape, :zero_or_more, '\*'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_zero_or_one_escape, [:escape, :zero_or_one, '\?'], ::Regexp::Expression::EscapeSequence::Literal]
[:regexp_alnum_posixclass, [:posixclass, :alnum, '[:alnum:]'], ::Regexp::Expression::PosixClass],
[:regexp_alpha_posixclass, [:posixclass, :alpha, '[:alpha:]'], ::Regexp::Expression::PosixClass],
[:regexp_alpha_property, [:property, :alpha, '\p{Alpha}'], ::Regexp::Expression::UnicodeProperty::Alpha],
[:regexp_alternation_escape, [:escape, :alternation, '\|'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_arabic_property, [:property, :arabic, '\p{Arabic}'], ::Regexp::Expression::UnicodeProperty::Script],
[:regexp_ascii_posixclass, [:posixclass, :ascii, '[:ascii:]'], ::Regexp::Expression::PosixClass],
[:regexp_backspace_escape, [:escape, :backspace, '\b'], ::Regexp::Expression::EscapeSequence::Backspace],
[:regexp_bell_escape, [:escape, :bell, '\a'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_blank_posixclass, [:posixclass, :blank, '[:blank:]'], ::Regexp::Expression::PosixClass],
[:regexp_bol_anchor, [:anchor, :bol, '^'], ::Regexp::Expression::Anchor::BeginningOfLine],
[:regexp_bol_escape, [:escape, :bol, '\^'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_bos_anchor, [:anchor, :bos, '\\A'], ::Regexp::Expression::Anchor::BeginningOfString],
[:regexp_carriage_escape, [:escape, :carriage, '\r'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_cntrl_posixclass, [:posixclass, :cntrl, '[:cntrl:]'], ::Regexp::Expression::PosixClass],
[:regexp_digit_posixclass, [:posixclass, :digit, '[:digit:]'], ::Regexp::Expression::PosixClass],
[:regexp_digit_type, [:type, :digit, '\d'], ::Regexp::Expression::CharacterType::Digit],
[:regexp_dot_escape, [:escape, :dot, '\.'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_dot_meta, [:meta, :dot, '.'], ::Regexp::Expression::CharacterType::Any],
[:regexp_eol_anchor, [:anchor, :eol, '$'], ::Regexp::Expression::Anchor::EndOfLine],
[:regexp_eol_escape, [:escape, :eol, '\$'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_eos_anchor, [:anchor, :eos, '\\z'], ::Regexp::Expression::Anchor::EndOfString],
[:regexp_eos_ob_eol_anchor, [:anchor, :eos_ob_eol, '\\Z'], ::Regexp::Expression::Anchor::EndOfStringOrBeforeEndOfLine],
[:regexp_escape_escape, [:escape, :escape, '\e'], ::Regexp::Expression::EscapeSequence::AsciiEscape],
[:regexp_form_feed_escape, [:escape, :form_feed, '\f'], ::Regexp::Expression::EscapeSequence::FormFeed],
[:regexp_graph_posixclass, [:posixclass, :graph, '[:graph:]'], ::Regexp::Expression::PosixClass],
[:regexp_group_close_escape, [:escape, :group_close, '\)'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_group_open_escape, [:escape, :group_open, '\('], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_han_property, [:property, :han, '\p{Han}'], ::Regexp::Expression::UnicodeProperty::Script],
[:regexp_hangul_property, [:property, :hangul, '\p{Hangul}'], ::Regexp::Expression::UnicodeProperty::Script],
[:regexp_hex_type, [:type, :hex, '\h'], ::Regexp::Expression::CharacterType::Hex],
[:regexp_hiragana_property, [:property, :hiragana, '\p{Hiragana}'], ::Regexp::Expression::UnicodeProperty::Script],
[:regexp_interval_close_escape, [:escape, :interval_close, '\}'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_interval_open_escape, [:escape, :interval_open, '\{'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_katakana_property, [:property, :katakana, '\p{Katakana}'], ::Regexp::Expression::UnicodeProperty::Script],
[:regexp_letter_property, [:property, :letter, '\p{L}'], ::Regexp::Expression::UnicodeProperty::Letter::Any],
[:regexp_linebreak_type, [:type, :linebreak, '\R'], ::Regexp::Expression::CharacterType::Linebreak],
[:regexp_lower_posixclass, [:posixclass, :lower, '[:lower:]'], ::Regexp::Expression::PosixClass],
[:regexp_mark_keep, [:keep, :mark, '\K'], ::Regexp::Expression::Keep::Mark],
[:regexp_match_start_anchor, [:anchor, :match_start, '\\G'], ::Regexp::Expression::Anchor::MatchStart],
[:regexp_newline_escape, [:escape, :newline, '\n'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_nondigit_type, [:type, :nondigit, '\D'], ::Regexp::Expression::CharacterType::NonDigit],
[:regexp_nonhex_type, [:type, :nonhex, '\H'], ::Regexp::Expression::CharacterType::NonHex],
[:regexp_nonspace_type, [:type, :nonspace, '\S'], ::Regexp::Expression::CharacterType::NonSpace],
[:regexp_nonword_boundary_anchor, [:anchor, :nonword_boundary, '\\B'], ::Regexp::Expression::Anchor::NonWordBoundary],
[:regexp_nonword_type, [:type, :nonword, '\W'], ::Regexp::Expression::CharacterType::NonWord],
[:regexp_one_or_more_escape, [:escape, :one_or_more, '\+'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_print_nonposixclass, [:nonposixclass, :print, '[:^print:]'], ::Regexp::Expression::PosixClass],
[:regexp_print_nonproperty, [:nonproperty, :print, '\P{Print}'], ::Regexp::Expression::UnicodeProperty::Print],
[:regexp_print_posixclass, [:posixclass, :print, '[:print:]'], ::Regexp::Expression::PosixClass],
[:regexp_print_posixclass, [:posixclass, :print, '[:print:]'], ::Regexp::Expression::PosixClass],
[:regexp_print_property, [:property, :print, '\p{Print}'], ::Regexp::Expression::UnicodeProperty::Print],
[:regexp_punct_posixclass, [:posixclass, :punct, '[:punct:]'], ::Regexp::Expression::PosixClass],
[:regexp_set_close_escape, [:escape, :set_close, '\]'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_set_open_escape, [:escape, :set_open, '\['], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_space_posixclass, [:posixclass, :space, '[:space:]'], ::Regexp::Expression::PosixClass],
[:regexp_space_type, [:type, :space, '\s'], ::Regexp::Expression::CharacterType::Space],
[:regexp_upper_posixclass, [:posixclass, :upper, '[:upper:]'], ::Regexp::Expression::PosixClass],
[:regexp_vertical_tab_escape, [:escape, :vertical_tab, '\v'], ::Regexp::Expression::EscapeSequence::VerticalTab],
[:regexp_word_boundary_anchor, [:anchor, :word_boundary, '\b'], ::Regexp::Expression::Anchor::WordBoundary],
[:regexp_word_posixclass, [:posixclass, :word, '[:word:]'], ::Regexp::Expression::PosixClass],
[:regexp_word_type, [:type, :word, '\w'], ::Regexp::Expression::CharacterType::Word],
[:regexp_xdigit_posixclass, [:posixclass, :xdigit, '[:xdigit:]'], ::Regexp::Expression::PosixClass],
[:regexp_xgrapheme_type, [:type, :xgrapheme, '\X'], ::Regexp::Expression::CharacterType::ExtendedGrapheme],
[:regexp_zero_or_more_escape, [:escape, :zero_or_more, '\*'], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_zero_or_one_escape, [:escape, :zero_or_one, '\?'], ::Regexp::Expression::EscapeSequence::Literal]
)
private

View File

@ -0,0 +1,59 @@
# frozen_string_literal: true
module Mutant
module AST
module Regexp
class Transformer
# Transformer for named groups
class NamedGroup < self
register :regexp_named_group
# Mapper from `Regexp::Expression` to `Parser::AST::Node`
class ExpressionToAST < Transformer::ExpressionToAST
# Transform named group into node
#
# @return [Parser::AST::Node]
def call
quantify(ast(expression.name, *children))
end
end # ExpressionToAST
# Mapper from `Parser::AST::Node` to `Regexp::Expression`
class ASTToExpression < Transformer::ASTToExpression
include NamedChildren
children :name
private
# Convert node into expression
#
# @return [Regexp::Expression::Group::Named]
def transform
named_group.tap do |expression|
expression.expressions = subexpressions
end
end
# Recursive mapping of children
#
# @return [Array<Regexp::Expression>]
def subexpressions
remaining_children.map(&Regexp.public_method(:to_expression))
end
# Named group instance constructed using name
#
# @return [Regexp::Expression::Group::Named]
def named_group
::Regexp::Expression::Group::Named.new(
::Regexp::Token.new(:group, :named, "(?<#{name}>")
)
end
end # ASTToExpression
end # NamedGroup
end # Transformer
end # Regexp
end # AST
end # Mutant

View File

@ -7,6 +7,7 @@ module Mutant
# Transformer for option groups
class OptionsGroup < self
register :regexp_options_group
register :regexp_options_switch_group
# Mapper from `Regexp::Expression` to `Parser::AST::Node`
class ExpressionToAST < Transformer::ExpressionToAST
@ -15,7 +16,7 @@ module Mutant
#
# @return [Parser::AST::Node]
def call
quantify(ast(expression.options, *children))
quantify(ast(expression.option_changes, *children))
end
end # ExpressionToAST
@ -23,11 +24,11 @@ module Mutant
class ASTToExpression < Transformer::ASTToExpression
include NamedChildren
children :options
children :option_changes
private
# Covnert node into expression
# Convert node into expression
#
# @return [Regexp::Expression::Group::Options]
def transform
@ -48,17 +49,31 @@ module Mutant
# @return [Regexp::Expression::Group::Options]
def options_group
::Regexp::Expression::Group::Options.new(
::Regexp::Token.new(:group, :options, text)
::Regexp::Token.new(:group, type, text)
)
end
# Flag text constructed from enabled options
# Options group type derived from node type
#
# @return [Symbol]
def type
{
regexp_options_group: :options,
regexp_options_switch_group: :options_switch
}.fetch(node.type)
end
# Flag text constructed from enabled and disabled options
#
# @return [String]
def text
flags = options.map { |key, value| key if value }.join
pos, neg = option_changes.partition { |_opt, val| val }.map do |arr|
arr.map(&:first).join
end
neg_opt_sep = '-' unless neg.empty?
content_sep = ':' unless type.equal?(:options_switch)
"(?#{flags}-:"
"(?#{pos}#{neg_opt_sep}#{neg}#{content_sep}"
end
end # ASTToExpression
end # OptionsGroup

View File

@ -21,15 +21,21 @@ module Mutant
include LookupTable
# rubocop:disable LineLength
# Expression::Sequence represents conditional branches, alternation branches, and intersection branches
TABLE = Table.create(
[:regexp_alternation_meta, [:meta, :alternation, '|'], ::Regexp::Expression::Alternation],
[:regexp_nlookahead_assertion, [:assertion, :nlookahead, '(?!'], ::Regexp::Expression::Assertion::NegativeLookahead],
[:regexp_passive_group, [:group, :passive, '(?:'], ::Regexp::Expression::Group::Passive],
[:regexp_nlookbehind_assertion, [:assertion, :nlookbehind, '(?<!'], ::Regexp::Expression::Assertion::NegativeLookbehind],
[:regexp_lookbehind_assertion, [:assertion, :lookbehind, '(?<='], ::Regexp::Expression::Assertion::Lookbehind],
[:regexp_lookahead_assertion, [:assertion, :lookahead, '(?='], ::Regexp::Expression::Assertion::Lookahead],
[:regexp_atomic_group, [:group, :atomic, '(?>'], ::Regexp::Expression::Group::Atomic],
[:regexp_capture_group, [:group, :capture, '('], ::Regexp::Expression::Group::Capture]
[:regexp_alternation_meta, [:meta, :alternation, '|'], ::Regexp::Expression::Alternation],
[:regexp_atomic_group, [:group, :atomic, '(?>'], ::Regexp::Expression::Group::Atomic],
[:regexp_capture_group, [:group, :capture, '('], ::Regexp::Expression::Group::Capture],
[:regexp_character_set, [:set, :character, '['], ::Regexp::Expression::CharacterSet],
[:regexp_intersection_set, [:set, :intersection, '&&'], ::Regexp::Expression::CharacterSet::Intersection],
[:regexp_lookahead_assertion, [:assertion, :lookahead, '(?='], ::Regexp::Expression::Assertion::Lookahead],
[:regexp_lookbehind_assertion, [:assertion, :lookbehind, '(?<='], ::Regexp::Expression::Assertion::Lookbehind],
[:regexp_nlookahead_assertion, [:assertion, :nlookahead, '(?!'], ::Regexp::Expression::Assertion::NegativeLookahead],
[:regexp_nlookbehind_assertion, [:assertion, :nlookbehind, '(?<!'], ::Regexp::Expression::Assertion::NegativeLookbehind],
[:regexp_open_conditional, [:conditional, :open, '(?'], ::Regexp::Expression::Conditional::Expression],
[:regexp_passive_group, [:group, :passive, '(?:'], ::Regexp::Expression::Group::Passive],
[:regexp_range_set, [:set, :range, '-'], ::Regexp::Expression::CharacterSet::Range],
[:regexp_sequence_expression, [:expression, :sequence, ''], ::Regexp::Expression::Sequence]
)
private

View File

@ -19,7 +19,7 @@ module Mutant
#
# @return [Regexp::Expression::Root]
def transform
::Regexp::Expression::Root.new.tap do |root|
::Regexp::Expression::Root.build.tap do |root|
root.expressions = subexpressions
end
end

View File

@ -20,22 +20,24 @@ module Mutant
class ASTToExpression < Transformer::ASTToExpression
include LookupTable
# rubocop:disable LineLength
TABLE = Table.create(
[:regexp_literal_literal, %i[literal literal], ::Regexp::Expression::Literal],
[:regexp_comment_group, %i[group comment], ::Regexp::Expression::Group::Comment],
[:regexp_named_group, %i[group named], ::Regexp::Expression::Group::Named],
[:regexp_number_backref, %i[backref number], ::Regexp::Expression::Backreference::Number],
[:regexp_name_call_backref, %i[backref name_call], ::Regexp::Expression::Backreference::NameCall],
[:regexp_whitespace_free_space, %i[free_space whitespace], ::Regexp::Expression::WhiteSpace],
[:regexp_comment_free_space, %i[free_space comment], ::Regexp::Expression::WhiteSpace],
[:regexp_hex_escape, %i[escape hex], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_hex_escape, %i[escape hex], ::Regexp::Expression::EscapeSequence::Hex],
[:regexp_octal_escape, %i[escape octal], ::Regexp::Expression::EscapeSequence::Octal],
[:regexp_literal_escape, %i[escape literal], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_backslash_escape, %i[escape backslash], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_tab_escape, %i[escape tab], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_codepoint_list_escape, %i[escape codepoint_list], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_codepoint_escape, %i[escape codepoint], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_codepoint_list_escape, %i[escape codepoint_list], ::Regexp::Expression::EscapeSequence::CodepointList],
[:regexp_codepoint_escape, %i[escape codepoint], ::Regexp::Expression::EscapeSequence::Codepoint],
[:regexp_control_escape, %i[escape control], ::Regexp::Expression::EscapeSequence::Control],
[:regexp_meta_sequence_escape, %i[escape meta_sequence], ::Regexp::Expression::EscapeSequence::Control]
[:regexp_meta_sequence_escape, %i[escape meta_sequence], ::Regexp::Expression::EscapeSequence::Control],
[:regexp_condition_conditional, %i[conditional condition], ::Regexp::Expression::Conditional::Condition]
)
private

View File

@ -45,23 +45,32 @@ module Mutant
# Nodes generated by regular expression body parsing
REGEXP = symbolset.(%w[
regexp_alnum_posixclass
regexp_alpha_posixclass
regexp_alpha_property
regexp_alternation_escape
regexp_alternation_meta
regexp_arabic_property
regexp_ascii_posixclass
regexp_atomic_group
regexp_backslash_escape
regexp_backspace_escape
regexp_bell_escape
regexp_blank_posixclass
regexp_bol_anchor
regexp_bol_escape
regexp_bos_anchor
regexp_capture_group
regexp_carriage_escape
regexp_character_set
regexp_cntrl_posixclass
regexp_codepoint_escape
regexp_codepoint_list_escape
regexp_comment_free_space
regexp_comment_group
regexp_condition_conditional
regexp_control_escape
regexp_digit_posixclass
regexp_digit_type
regexp_dot_escape
regexp_dot_meta
@ -71,21 +80,29 @@ module Mutant
regexp_eos_ob_eol_anchor
regexp_escape_escape
regexp_form_feed_escape
regexp_graph_posixclass
regexp_greedy_interval
regexp_greedy_one_or_more
regexp_greedy_zero_or_more
regexp_greedy_zero_or_one
regexp_group_close_escape
regexp_group_open_escape
regexp_han_property
regexp_hangul_property
regexp_hex_escape
regexp_hex_type
regexp_hiragana_property
regexp_intersection_set
regexp_interval_close_escape
regexp_interval_open_escape
regexp_letter_any_property
regexp_katakana_property
regexp_letter_property
regexp_linebreak_type
regexp_literal_escape
regexp_literal_literal
regexp_lookahead_assertion
regexp_lookbehind_assertion
regexp_lower_posixclass
regexp_mark_keep
regexp_match_start_anchor
regexp_meta_sequence_escape
@ -100,34 +117,40 @@ module Mutant
regexp_nonword_boundary_anchor
regexp_nonword_type
regexp_number_backref
regexp_octal_escape
regexp_one_or_more_escape
regexp_open_conditional
regexp_options_group
regexp_options_switch_group
regexp_passive_group
regexp_possessive_interval
regexp_possessive_one_or_more
regexp_possessive_zero_or_more
regexp_possessive_zero_or_one
regexp_print_nonposixclass
regexp_print_nonproperty
regexp_print_posixclass
regexp_print_posixclass
regexp_print_property
regexp_punct_posixclass
regexp_range_set
regexp_reluctant_interval
regexp_reluctant_one_or_more
regexp_reluctant_zero_or_more
regexp_root_expression
regexp_script_arabic_property
regexp_script_han_property
regexp_script_hangul_property
regexp_script_hiragana_property
regexp_script_katakana_property
regexp_sequence_expression
regexp_set_close_escape
regexp_set_open_escape
regexp_space_posixclass
regexp_space_type
regexp_tab_escape
regexp_upper_posixclass
regexp_vertical_tab_escape
regexp_whitespace_free_space
regexp_word_boundary_anchor
regexp_word_posixclass
regexp_word_type
regexp_xdigit_posixclass
regexp_xgrapheme_type
regexp_zero_or_more_escape
regexp_zero_or_one_escape

View File

@ -47,6 +47,7 @@ module Mutant
regexp_eos_ob_eol_anchor
regexp_greedy_zero_or_more
regexp_hex_type
regexp_linebreak_type
regexp_nondigit_type
regexp_nonhex_type
regexp_nonspace_type

View File

@ -43,7 +43,6 @@ module Mutant
# @return [undefined]
def mutate_body
return unless body.all?(&method(:n_str?))
return unless AST::Regexp.supported?(body_expression)
Mutator.mutate(body_ast).each do |mutation|
source = AST::Regexp.to_expression(mutation).to_s

View File

@ -12,7 +12,7 @@ module Mutant
regexp_space_type: :regexp_nonspace_type,
regexp_word_boundary_anchor: :regexp_nonword_boundary_anchor,
regexp_word_type: :regexp_nonword_type,
regexp_xgrapheme_type: :regexp_space_type
regexp_xgrapheme_type: :regexp_linebreak_type
}
MAP = IceNine.deep_freeze(map.merge(map.invert))

View File

@ -71,6 +71,9 @@ Mutant::Meta::Example.add :regexp do
singleton_mutations
regexp_mutations
mutation '/(?(1)(?:foo)(bar))/'
mutation '/(?(1)(foo)(?:bar))/'
end
Pathname

View File

@ -6,7 +6,7 @@ mutations = {
[:regexp_space_type, '/\s/'] => [:regexp_nonspace_type, '/\S/'],
[:regexp_word_boundary_anchor, '/\b/'] => [:regexp_nonword_boundary_anchor, '/\B/'],
[:regexp_word_type, '/\w/'] => [:regexp_nonword_type, '/\W/'],
[:regexp_xgrapheme_type, '/\X/'] => [:regexp_space_type, '/\s/']
[:regexp_xgrapheme_type, '/\X/'] => [:regexp_linebreak_type, '/\R/']
}
mutations = mutations.merge(mutations.invert)

View File

@ -36,7 +36,7 @@ Gem::Specification.new do |gem|
gem.add_runtime_dependency('parallel', '~> 1.3')
gem.add_runtime_dependency('parser', '~> 2.5.1')
gem.add_runtime_dependency('procto', '~> 0.0.2')
gem.add_runtime_dependency('regexp_parser', '~> 0.4.9')
gem.add_runtime_dependency('regexp_parser', '~> 1.2')
gem.add_runtime_dependency('unparser', '~> 0.2.5')
gem.add_development_dependency('bundler', '~> 1.10')

View File

@ -23,13 +23,11 @@
- name: regexp_parser
namespace: Regexp
repo_uri: 'https://github.com/ammar/regexp_parser.git'
repo_ref: 'v0.4.4'
repo_ref: 'v1.2.0'
ruby_glob_pattern: '**/*.rb'
mutation_coverage: false
mutation_generation: true
expected_errors:
"Regexp::Syntax::Ruby::V233 does not implement: [escape:codepoint]":
- regexp_parser/test/parser/test_escapes.rb
expected_errors: {}
exclude: []
- name: auom
namespace: AUOM

View File

@ -3,6 +3,4 @@
- 'lib/parallel.rb:222: warning: shadowing outer local variable - args'
- 'lib/parallel.rb:227: warning: shadowing outer local variable - args'
- 'lib/parser/lexer.rb:10836: warning: assigned but unused variable - testEof'
- 'lib/regexp_parser/scanner.rb:1675: warning: assigned but unused variable - testEof'
- 'lib/regexp_parser/scanner.rb:1689: warning: assigned but unused variable - testEof'
- 'lib/regexp_parser/scanner.rb:1692: warning: assigned but unused variable - testEof'
- 'lib/regexp_parser/scanner.rb:1146: warning: assigned but unused variable - testEof'

View File

@ -1,16 +0,0 @@
# frozen_string_literal: true
RSpec.describe Mutant::AST::Regexp, '.supported?' do
subject { described_class.supported?(expression) }
let(:expression) { described_class.parse(regexp) }
let(:regexp) { /foo/ }
it { should be(true) }
context 'conditional regular expressions' do
let(:regexp) { /((?(1)(foo)(bar)))/ }
it { should be(false) }
end
end

View File

@ -202,17 +202,53 @@ end
RegexpSpec.expect_mapping(/[ab]+/, :regexp_character_set) do
s(:regexp_root_expression,
s(:regexp_greedy_one_or_more, 1, -1,
s(:regexp_character_set, 'a', 'b')))
s(:regexp_character_set,
s(:regexp_literal_literal, 'a'),
s(:regexp_literal_literal, 'b'))))
end
RegexpSpec.expect_mapping(/[ab]/, :regexp_character_set) do
s(:regexp_root_expression,
s(:regexp_character_set, 'a', 'b'))
s(:regexp_character_set,
s(:regexp_literal_literal, 'a'),
s(:regexp_literal_literal, 'b')))
end
RegexpSpec.expect_mapping(/[a-j]/, :regexp_character_set) do
s(:regexp_root_expression,
s(:regexp_character_set, 'a-j'))
s(:regexp_character_set,
s(:regexp_range_set,
s(:regexp_literal_literal, 'a'),
s(:regexp_literal_literal, 'j'))))
end
RegexpSpec.expect_mapping(/[\b]/, :regexp_backspace_escape) do
s(:regexp_root_expression,
s(:regexp_character_set,
s(:regexp_backspace_escape)))
end
RegexpSpec.expect_mapping(/()(?(1)a|b)/, :regexp_open_conditional) do
s(:regexp_root_expression,
s(:regexp_capture_group),
s(:regexp_open_conditional,
s(:regexp_condition_conditional, '(1)'),
s(:regexp_sequence_expression,
s(:regexp_literal_literal, 'a')),
s(:regexp_sequence_expression,
s(:regexp_literal_literal, 'b'))))
end
RegexpSpec.expect_mapping(/[ab&&bc]/, :regexp_intersection_set) do
s(:regexp_root_expression,
s(:regexp_character_set,
s(:regexp_intersection_set,
s(:regexp_sequence_expression,
s(:regexp_literal_literal, 'a'),
s(:regexp_literal_literal, 'b')),
s(:regexp_sequence_expression,
s(:regexp_literal_literal, 'b'),
s(:regexp_literal_literal, 'c')))))
end
RegexpSpec.expect_mapping(/\u{9879}/, :regexp_codepoint_list_escape) do
@ -225,7 +261,7 @@ RegexpSpec.expect_mapping(/(?#foo)/, :regexp_comment_group) do
s(:regexp_comment_group, '(?#foo)'))
end
RegexpSpec.expect_mapping(/(?x-: # comment
RegexpSpec.expect_mapping(/(?x: # comment
)/, :regexp_comment_free_space) do
s(:regexp_root_expression,
s(:regexp_options_group, {
@ -304,7 +340,9 @@ end
RegexpSpec.expect_mapping(/[ab]+/, :regexp_greedy_one_or_more) do
s(:regexp_root_expression,
s(:regexp_greedy_one_or_more, 1, -1,
s(:regexp_character_set, 'a', 'b')))
s(:regexp_character_set,
s(:regexp_literal_literal, 'a'),
s(:regexp_literal_literal, 'b'))))
end
RegexpSpec.expect_mapping(/(a)*/, :regexp_greedy_zero_or_more) do
@ -336,6 +374,11 @@ RegexpSpec.expect_mapping(/\(/, :regexp_group_open_escape) do
s(:regexp_group_open_escape))
end
RegexpSpec.expect_mapping(/\101/, :regexp_octal_escape) do
s(:regexp_root_expression,
s(:regexp_octal_escape, '\\101'))
end
RegexpSpec.expect_mapping(/\xFF/n, :regexp_hex_escape) do
s(:regexp_root_expression,
s(:regexp_hex_escape, '\\xFF'))
@ -346,11 +389,16 @@ RegexpSpec.expect_mapping(/\h/, :regexp_hex_type) do
s(:regexp_hex_type))
end
RegexpSpec.expect_mapping(/\H/, :regexp_hex_type) do
RegexpSpec.expect_mapping(/\H/, :regexp_nonhex_type) do
s(:regexp_root_expression,
s(:regexp_nonhex_type))
end
RegexpSpec.expect_mapping(/\R/, :regexp_linebreak_type) do
s(:regexp_root_expression,
s(:regexp_linebreak_type))
end
RegexpSpec.expect_mapping(/\X/, :regexp_xgrapheme_type) do
s(:regexp_root_expression,
s(:regexp_xgrapheme_type))
@ -366,9 +414,9 @@ RegexpSpec.expect_mapping(/\{/, :regexp_interval_open_escape) do
s(:regexp_interval_open_escape))
end
RegexpSpec.expect_mapping(/\p{L}/, :regexp_letter_any_property) do
RegexpSpec.expect_mapping(/\p{L}/, :regexp_letter_property) do
s(:regexp_root_expression,
s(:regexp_letter_any_property))
s(:regexp_letter_property))
end
RegexpSpec.expect_mapping(/\-/, :regexp_literal_escape) do
@ -424,14 +472,16 @@ RegexpSpec.expect_mapping(/\G/, :regexp_match_start_anchor) do
s(:regexp_match_start_anchor))
end
RegexpSpec.expect_mapping(/(?<foo>)/, :regexp_named_group) do
RegexpSpec.expect_mapping(/(?<foo>a)+/, :regexp_named_group) do
s(:regexp_root_expression,
s(:regexp_named_group, '(?<foo>'))
s(:regexp_greedy_one_or_more, 1, -1,
s(:regexp_named_group, 'foo',
s(:regexp_literal_literal, 'a'))))
end
RegexpSpec.expect_mapping(/(?<a>)\g<a>/, :regexp_name_call_backref) do
s(:regexp_root_expression,
s(:regexp_named_group, '(?<a>'),
s(:regexp_named_group, 'a'),
s(:regexp_name_call_backref, '\\g<a>'))
end
@ -477,7 +527,7 @@ RegexpSpec.expect_mapping(/\+/, :regexp_one_or_more_escape) do
s(:regexp_one_or_more_escape))
end
RegexpSpec.expect_mapping(/(?i-:a)+/, :regexp_options_group) do
RegexpSpec.expect_mapping(/(?i:a)+/, :regexp_options_group) do
s(:regexp_root_expression,
s(:regexp_greedy_one_or_more, 1, -1,
s(:regexp_options_group,
@ -487,7 +537,25 @@ RegexpSpec.expect_mapping(/(?i-:a)+/, :regexp_options_group) do
s(:regexp_literal_literal, 'a'))))
end
RegexpSpec.expect_mapping(/(?x-: #{"\n"} )/, :regexp_whitespace_free_space) do
RegexpSpec.expect_mapping(/(?i-x:a)+/, :regexp_options_group) do
s(:regexp_root_expression,
s(:regexp_greedy_one_or_more, 1, -1,
s(:regexp_options_group,
{
i: true,
x: false
},
s(:regexp_literal_literal, 'a'))))
end
RegexpSpec.expect_mapping(/a(?i)b/, :regexp_options_switch_group) do
s(:regexp_root_expression,
s(:regexp_literal_literal, 'a'),
s(:regexp_options_switch_group, i: true),
s(:regexp_literal_literal, 'b'))
end
RegexpSpec.expect_mapping(/(?x: #{"\n"} )/, :regexp_whitespace_free_space) do
s(:regexp_root_expression,
s(:regexp_options_group,
{
@ -526,6 +594,23 @@ RegexpSpec.expect_mapping(/.?+/, :regexp_possessive_zero_or_one) do
s(:regexp_dot_meta)))
end
RegexpSpec.expect_mapping(/\P{Print}/, :regexp_print_nonproperty) do
s(:regexp_root_expression,
s(:regexp_print_nonproperty))
end
RegexpSpec.expect_mapping(/[[:print:]]/, :regexp_print_posixclass) do
s(:regexp_root_expression,
s(:regexp_character_set,
s(:regexp_print_posixclass)))
end
RegexpSpec.expect_mapping(/[[:^print:]]/, :regexp_print_nonposixclass) do
s(:regexp_root_expression,
s(:regexp_character_set,
s(:regexp_print_nonposixclass)))
end
RegexpSpec.expect_mapping(/.{1,3}?/, :regexp_reluctant_interval) do
s(:regexp_root_expression,
s(:regexp_reluctant_interval, 1, 3,
@ -544,29 +629,29 @@ RegexpSpec.expect_mapping(/.*?/, :regexp_reluctant_zero_or_more) do
s(:regexp_dot_meta)))
end
RegexpSpec.expect_mapping(/\p{Arabic}/, :regexp_script_arabic_property) do
RegexpSpec.expect_mapping(/\p{Arabic}/, :regexp_arabic_property) do
s(:regexp_root_expression,
s(:regexp_script_arabic_property))
s(:regexp_arabic_property))
end
RegexpSpec.expect_mapping(/\p{Han}/, :regexp_script_han_property) do
RegexpSpec.expect_mapping(/\p{Han}/, :regexp_han_property) do
s(:regexp_root_expression,
s(:regexp_script_han_property))
s(:regexp_han_property))
end
RegexpSpec.expect_mapping(/\p{Hangul}/, :regexp_script_hangul_property) do
RegexpSpec.expect_mapping(/\p{Hangul}/, :regexp_hangul_property) do
s(:regexp_root_expression,
s(:regexp_script_hangul_property))
s(:regexp_hangul_property))
end
RegexpSpec.expect_mapping(/\p{Hiragana}/, :regexp_script_hiragana_property) do
RegexpSpec.expect_mapping(/\p{Hiragana}/, :regexp_hiragana_property) do
s(:regexp_root_expression,
s(:regexp_script_hiragana_property))
s(:regexp_hiragana_property))
end
RegexpSpec.expect_mapping(/\p{Katakana}/, :regexp_script_katakana_property) do
RegexpSpec.expect_mapping(/\p{Katakana}/, :regexp_katakana_property) do
s(:regexp_root_expression,
s(:regexp_script_katakana_property))
s(:regexp_katakana_property))
end
RegexpSpec.expect_mapping(/foo|bar/, :regexp_sequence_expression) do