File: base.rb

package info (click to toggle)
ruby-js-regex 3.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 164 kB
  • sloc: ruby: 1,002; makefile: 3
file content (83 lines) | stat: -rw-r--r-- 2,370 bytes parent folder | download
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