Module: Ruby::Rego::Builtins::Regex::GlobIntersection

Defined in:
lib/ruby/rego/builtins/regex/glob_intersection.rb,
lib/ruby/rego/builtins/regex/glob_intersection/trim.rb,
lib/ruby/rego/builtins/regex/glob_intersection/tokenizer.rb,
lib/ruby/rego/builtins/regex/glob_intersection/intersector.rb

Overview

Reopens GlobIntersection to host the recursive intersection engine. Lives apart from the tokenizer/trim core so the main file stays under RubyCritic’s complexity budget. GlobError, MAX_WORK, and match? live in the main file (loaded first, before this require_relative).

Defined Under Namespace

Classes: GlobError, Intersector, RuneBudget, Token

Constant Summary collapse

MAX_GLOB_SOURCE =

Maximum byte length of a single glob pattern.

100_000
MAX_GLOB_FLAGS =

Maximum number of flags (*/+) in the smaller-flagged glob; the algorithm is exponential in this count.

20
MAX_SET_RUNES =

Maximum codepoints all character-class ranges in one glob may expand to, cumulatively. Bounds tokenization work, which runs before MAX_WORK applies.

1_000_000
MAX_WORK =

Maximum number of intersection steps before bailing out.

5_000_000

Class Method Summary collapse

Class Method Details

.match?(token_lhs, token_rhs) ⇒ Boolean

Whether two atoms (ignoring flags) can match a common character.

Returns:

  • (Boolean)


140
141
142
143
144
145
146
147
148
149
150
# File 'lib/ruby/rego/builtins/regex/glob_intersection.rb', line 140

def self.match?(token_lhs, token_rhs)
  type_lhs = token_lhs.type
  type_rhs = token_rhs.type
  return true if type_lhs == :dot || type_rhs == :dot
  return token_lhs.rune == token_rhs.rune if type_lhs == :char && type_rhs == :char
  # Only :char and :set remain; a char's codepoint vs the other's rune set.
  return runes_of(token_rhs).include?(token_lhs.rune.to_s.ord) if type_lhs == :char
  return runes_of(token_lhs).include?(token_rhs.rune.to_s.ord) if type_rhs == :char

  runes_of(token_lhs).intersect?(runes_of(token_rhs))
end

.new_glob(input) ⇒ Array<Token>

Returns:

Raises:



109
110
111
112
113
# File 'lib/ruby/rego/builtins/regex/glob_intersection.rb', line 109

def self.new_glob(input)
  raise GlobError, "glob too long" if input.bytesize > MAX_GLOB_SOURCE

  simplify(tokenize(input))
end

.non_empty?(lhs, rhs) ⇒ bool

Returns:

  • (bool)


95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/ruby/rego/builtins/regex/glob_intersection.rb', line 95

def self.non_empty?(lhs, rhs)
  lhs = new_glob(lhs)
  rhs = new_glob(rhs)
  # Checked before trimming (as gintersect does); trimming only removes
  # unflagged tokens, so the post-trim flag count is never higher.
  ensure_within_flag_limit(lhs, rhs)

  lhs, rhs, prefix_ok = trim_globs(lhs, rhs)
  return false unless prefix_ok

  Intersector.new.intersect_normal(lhs, rhs)
end

.tokenize(input) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
# File 'lib/ruby/rego/builtins/regex/glob_intersection/tokenizer.rb', line 27

def self.tokenize(input)
  chars = input.chars
  tokens = [] # @type var tokens: Array[Token]
  budget = RuneBudget.new(MAX_SET_RUNES)
  index = 0
  while index < chars.length
    token, index = next_token(chars, index, budget)
    tokens << token
  end
  tokens
end