Class: RuboCop::AST::NodePattern::Compiler::Binding

Inherits:
Object
  • Object
show all
Defined in:
lib/rubocop/ast/node_pattern/compiler/binding.rb

Overview

Holds the list of bound variable names

Instance Method Summary collapse

Constructor Details

#initializeBinding

Returns a new instance of Binding.



9
10
11
# File 'lib/rubocop/ast/node_pattern/compiler/binding.rb', line 9

def initialize
  @bound = {}
end

Instance Method Details

#bind(name) ⇒ String

Yields the first time a given name is bound

Returns:

  • (String)

    bound variable name



16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/rubocop/ast/node_pattern/compiler/binding.rb', line 16

def bind(name)
  var = @bound.fetch(name) do
    yield n = @bound[name] = "unify_#{name.gsub('-', '__')}"
    n
  end

  if var == :forbidden_unification
    raise Invalid, "Wildcard #{name} was first seen in a subset of a " \
                   "union and can't be used outside that union"
  end
  var
end

#union_bind(enum) ⇒ Object

Yields for each branch of the given union, forbidding unification of bindings which only appear in a subset of the union.



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
# File 'lib/rubocop/ast/node_pattern/compiler/binding.rb', line 31

def union_bind(enum) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
  # We need to reset @bound before each branch is processed.
  # Moreover we need to keep track of newly encountered wildcards.
  # Var `newly_bound_intersection` will hold those that are encountered
  # in all branches; these are not a problem.
  # Var `partially_bound` will hold those encountered in only a subset
  # of the branches; these can't be used outside of the union.

  return to_enum __method__, enum unless block_given?

  newly_bound_intersection = nil
  partially_bound = []
  bound_before = @bound.dup

  result = enum.each do |e|
    @bound = bound_before.dup if newly_bound_intersection
    yield e
    newly_bound = @bound.keys - bound_before.keys
    if newly_bound_intersection.nil?
      # First iteration
      newly_bound_intersection = newly_bound
    else
      union = newly_bound_intersection | newly_bound
      newly_bound_intersection &= newly_bound
      partially_bound |= union - newly_bound_intersection
    end
  end

  # At this point, all members of `newly_bound_intersection` can be used
  # for unification outside of the union, but partially_bound may not

  forbid(partially_bound)

  result
end