1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
require_relative 'base'
class JsRegex
module Converter
#
# Template class implementation.
#
class GroupConverter < JsRegex::Converter::Base
private
def convert_data
case subtype
when :capture then build_group
when :named then build_named_group
when :atomic then emulate_atomic_group
when :comment then drop_without_warning
when :options, :options_switch then build_options_group
when :passive then build_passive_group
when :absence then build_absence_group_if_simple
else warn_of_unsupported_feature
end
end
def build_named_group
if context.es_2018_or_higher?
# ES 2018+ supports named groups, but only the angled-bracket syntax
build_group(head: "(?<#{expression.name}>")
else
build_group
end
end
def emulate_atomic_group
if context.in_atomic_group
warn_of_unsupported_feature('nested atomic group')
build_passive_group
else
context.start_atomic_group
result = wrap_in_backrefed_lookahead(convert_subexpressions)
context.end_atomic_group
result
end
end
def build_options_group
if subtype.equal?(:options_switch)
# can be ignored since #options on subsequent Expressions are correct
drop_without_warning
else
build_passive_group
end
end
def build_passive_group
build_group(head: '(?:', capturing: false)
end
def build_absence_group_if_simple
if unmatchable_absence_group?
unmatchable_substitution
elsif expression.inner_match_length.fixed?
build_absence_group
else
warn_of_unsupported_feature('variable-length absence group content')
end
end
def unmatchable_absence_group?
expression.empty?
end
def unmatchable_substitution
'(?!)'
end
def build_absence_group
head = "(?:(?:.|\\n){,#{expression.inner_match_length.min - 1}}|(?:(?!"
tail = ')(?:.|\n))*)'
build_group(head: head, tail: tail, capturing: false)
end
def build_group(opts = {})
head = opts[:head] || '('
tail = opts[:tail] || ')'
return Node.new(*wrap(head, tail)) if opts[:capturing].equal?(false)
context.capture_group
ref = expression.number
Node.new(*wrap(head, tail), reference: ref, type: :captured_group)
end
def wrap(head, tail)
[head, convert_subexpressions, tail]
end
end
end
end
|