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
|
class JsRegex
module Converter
#
# Template class. Implement #convert_data in subclasses and return
# instance of String or Node from it.
#
class Base
# returns instance of Node with #quantifier attached.
def convert(expression, context)
self.context = context
self.expression = expression
node = convert_data
node = Node.new(node) if node.instance_of?(String)
apply_quantifier(node)
end
private
attr_accessor :context, :expression
def subtype
expression.token
end
def data
expression.text
end
alias pass_through data
def apply_quantifier(node)
return node if node.dropped? || (qtf = expression.quantifier).nil?
if qtf.possessive?
node.update(quantifier: qtf.dup.tap { |q| q.text = q.text[0..-2] })
return wrap_in_backrefed_lookahead(node)
elsif qtf.token == :interval && qtf.text[0..1] == "{,"
node.update(quantifier: qtf.dup.tap { |q| q.text = "{0,#{q.max}}" })
else
node.update(quantifier: qtf)
end
node
end
def convert_subexpressions
Node.new(*expression.map { |subexp| convert_expression(subexp) })
end
def convert_expression(expression)
Converter.convert(expression, context)
end
def warn_of_unsupported_feature(description = nil, min_target: nil)
description ||= "#{subtype} #{expression.type}".tr('_', ' ')
full_text = "Dropped unsupported #{description} '#{expression}' "\
"at index #{expression.ts}"
if min_target
full_text += " (requires at least `target: '#{min_target}'`)"
end
warn_of(full_text)
drop
end
def warn_of(text)
context.warnings << text
end
def drop
Node.new(type: :dropped)
end
alias drop_without_warning drop
def wrap_in_backrefed_lookahead(content)
number = context.capturing_group_count + 1
backref_node = Node.new("\\#{number}", reference: number, type: :backref)
context.increment_local_capturing_group_count
# an empty passive group (?:) is appended as literal digits may follow
Node.new('(?=(', *content, '))', backref_node, '(?:)')
end
end
end
end
|