\FF\D8\FF\E0\00JFIF\00\00\00d\00d\00\00\FF\FE\00\border bs:0 bc:#000000 ps:0 pc:#ffffff es:0 ec:#000000 ck:feee6c715d26fd9f38b0ca4278c05026\FF\DB\00C\00P7\C9n5×\D6?\BDê\9Ds\EBp\9F[`8m\B7)o\B5\E8\E6I\99\FE3]]A2\BA\8Cw\D6E\93\\DEv\C8\009\F2\F1NI?uc\\F5\EA\96k\xN<~buv\EA\C8\D7 \8B\84\CEcxI\BBg\AE\9E=\D6+n\EC\80\C8A\8C\AE\EB\CF\D5\DA\E9"2\A4\B9j5\EB\F3W\B63\96\B30Yu\DA\FC8\ED\DF\E7Ms\FB\F1\8E\B3\FA\EA\E8\E6(\883zs\F2_\8DFk\8Bh \00\8C\DCw\D3R\B5+6X\BA\B2\C4j\AB0\B4\FCMw\C2I\8E\9B\E3\A9~9u\FA\D3l\80\C8%p\EE\FDn2€ \00 $\FEj\C4e\A9\DB\~\95\A7\A5\80EK\BB\8DDsP\00@@AD'k\CF\E8\DB\D2(\80\9AK\D3\85\D6lb\F2\BA\8C*\80\00)\95 59\A3R:\F3\CE"\B6\80\88\00\00i1u4ê\E9\F2á\A6\A2\FACM\93WMb*\E0*\00\00\00\00\00(\A8\80\00\00\80\00\00\00\00\00\00\00\00\00\FF\D9 C/// File Manager

File Manager

Path: /opt/chef/embedded/lib/ruby/gems/2.7.0/gems/regexp_parser-1.7.1/lib/regexp_parser/

Viewing File: lexer.rb

# A very thin wrapper around the scanner that breaks quantified literal runs,
# collects emitted tokens into an array, calculates their nesting depth, and
# normalizes tokens for the parser, and checks if they are implemented by the
# given syntax flavor.
class Regexp::Lexer

  OPENING_TOKENS = [
    :capture, :passive, :lookahead, :nlookahead, :lookbehind, :nlookbehind,
    :atomic, :options, :options_switch, :named, :absence
  ].freeze

  CLOSING_TOKENS = [:close].freeze

  def self.lex(input, syntax = "ruby/#{RUBY_VERSION}", &block)
    new.lex(input, syntax, &block)
  end

  def lex(input, syntax = "ruby/#{RUBY_VERSION}", &block)
    syntax = Regexp::Syntax.new(syntax)

    self.tokens = []
    self.nesting = 0
    self.set_nesting = 0
    self.conditional_nesting = 0
    self.shift = 0

    last = nil
    Regexp::Scanner.scan(input) do |type, token, text, ts, te|
      type, token = *syntax.normalize(type, token)
      syntax.check! type, token

      ascend(type, token)

      if type == :quantifier and last
        break_literal(last)        if last.type == :literal
        break_codepoint_list(last) if last.token == :codepoint_list
      end

      current = Regexp::Token.new(type, token, text, ts + shift, te + shift,
                                  nesting, set_nesting, conditional_nesting)

      current = merge_condition(current) if type == :conditional and
        [:condition, :condition_close].include?(token)

      last.next = current if last
      current.previous = last if last

      tokens << current
      last = current

      descend(type, token)
    end

    if block_given?
      tokens.map { |t| block.call(t) }
    else
      tokens
    end
  end

  class << self
    alias :scan :lex
  end

  private

  attr_accessor :tokens, :nesting, :set_nesting, :conditional_nesting, :shift

  def ascend(type, token)
    case type
    when :group, :assertion
      self.nesting = nesting - 1 if CLOSING_TOKENS.include?(token)
    when :set
      self.set_nesting = set_nesting - 1 if token == :close
    when :conditional
      self.conditional_nesting = conditional_nesting - 1 if token == :close
    end
  end

  def descend(type, token)
    case type
    when :group, :assertion
      self.nesting = nesting + 1 if OPENING_TOKENS.include?(token)
    when :set
      self.set_nesting = set_nesting + 1 if token == :open
    when :conditional
      self.conditional_nesting = conditional_nesting + 1 if token == :open
    end
  end

  # called by scan to break a literal run that is longer than one character
  # into two separate tokens when it is followed by a quantifier
  def break_literal(token)
    lead, last, _ = token.text.partition(/.\z/mu)
    return if lead.empty?

    tokens.pop
    tokens << Regexp::Token.new(:literal, :literal, lead,
              token.ts, (token.te - last.bytesize),
              nesting, set_nesting, conditional_nesting)
    tokens << Regexp::Token.new(:literal, :literal, last,
              (token.ts + lead.bytesize), token.te,
              nesting, set_nesting, conditional_nesting)
  end

  def break_codepoint_list(token)
    lead, _, tail = token.text.rpartition(' ')
    return if lead.empty?

    tokens.pop
    tokens << Regexp::Token.new(:escape, :codepoint_list, lead + '}',
              token.ts, (token.te - tail.length),
              nesting, set_nesting, conditional_nesting)
    tokens << Regexp::Token.new(:escape, :codepoint_list, '\u{' + tail,
              (token.ts + lead.length + 1), (token.te + 3),
              nesting, set_nesting, conditional_nesting)

    self.shift = shift + 3 # one space less, but extra \, u, {, and }
  end

  def merge_condition(current)
    last = tokens.pop
    Regexp::Token.new(:conditional, :condition, last.text + current.text,
      last.ts, current.te, nesting, set_nesting, conditional_nesting)
  end

end # module Regexp::Lexer