Class: RuboCop::Cop::VariableForce::VariableTable
- Inherits:
-
Object
- Object
- RuboCop::Cop::VariableForce::VariableTable
- Defined in:
- lib/rubocop/cop/variable_force/variable_table.rb
Overview
A VariableTable manages the lifetime of all scopes and local variables in a program. This holds scopes as stack structure, and provides a way to add local variables to current scope and find local variables by considering variable visibility of the current scope.
Instance Method Summary collapse
- #accessible_variables ⇒ Object
- #assign_to_variable(name, node) ⇒ Object
- #current_scope ⇒ Object
- #current_scope_level ⇒ Object
- #declare_variable(name, node) ⇒ Object
- #find_variable(name) ⇒ Object
-
#initialize(hook_receiver = nil) ⇒ VariableTable
constructor
A new instance of VariableTable.
- #invoke_hook(hook_name, *args) ⇒ Object
- #pop_scope ⇒ Object
- #push_scope(scope_node) ⇒ Object
- #reference_variable(name, node) ⇒ Object
- #scope_stack ⇒ Object
- #variable_exist?(name) ⇒ Boolean
Constructor Details
#initialize(hook_receiver = nil) ⇒ VariableTable
Returns a new instance of VariableTable.
13 14 15 |
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 13 def initialize(hook_receiver = nil) @hook_receiver = hook_receiver end |
Instance Method Details
#accessible_variables ⇒ Object
112 113 114 115 116 117 |
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 112 def accessible_variables scope_stack.reverse_each.each_with_object([]) do |scope, variables| variables.concat(scope.variables.values) break variables unless scope.node.block_type? end end |
#assign_to_variable(name, node) ⇒ Object
57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 57 def assign_to_variable(name, node) variable = find_variable(name) unless variable raise "Assigning to undeclared local variable \"#{name}\" " \ "at #{node.source_range}, #{node.inspect}" end variable.assign(node) mark_variable_as_captured_by_block_if_so(variable) end |
#current_scope ⇒ Object
41 42 43 |
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 41 def current_scope scope_stack.last end |
#current_scope_level ⇒ Object
45 46 47 |
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 45 def current_scope_level scope_stack.count end |
#declare_variable(name, node) ⇒ Object
49 50 51 52 53 54 55 |
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 49 def declare_variable(name, node) variable = Variable.new(name, node, current_scope) invoke_hook(:before_declaring_variable, variable) current_scope.variables[variable.name] = variable invoke_hook(:after_declaring_variable, variable) variable end |
#find_variable(name) ⇒ Object
95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 95 def find_variable(name) name = name.to_sym scope_stack.reverse_each do |scope| variable = scope.variables[name] return variable if variable # Only block scope allows referencing outer scope variables. return nil unless scope.node.block_type? end nil end |
#invoke_hook(hook_name, *args) ⇒ Object
17 18 19 |
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 17 def invoke_hook(hook_name, *args) @hook_receiver.send(hook_name, *args) if @hook_receiver end |
#pop_scope ⇒ Object
33 34 35 36 37 38 39 |
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 33 def pop_scope scope = current_scope invoke_hook(:before_leaving_scope, scope) scope_stack.pop invoke_hook(:after_leaving_scope, scope) scope end |
#push_scope(scope_node) ⇒ Object
25 26 27 28 29 30 31 |
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 25 def push_scope(scope_node) scope = Scope.new(scope_node) invoke_hook(:before_entering_scope, scope) scope_stack.push(scope) invoke_hook(:after_entering_scope, scope) scope end |
#reference_variable(name, node) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 69 def reference_variable(name, node) variable = find_variable(name) # In this code: # # foo = 1 unless foo # # (if # (lvar :foo) nil # (lvasgn :foo # (int 1))) # # Parser knows whether the foo is a variable or method invocation. # This means that if a :lvar node is shown in AST, the variable is # assumed to be already declared, even if we haven't seen any :lvasgn # or :arg node before the :lvar node. # # We don't invoke #declare_variable here otherwise # Variable#declaration_node will be :lvar node, that is actually not. # So just skip. return unless variable variable.reference!(node) mark_variable_as_captured_by_block_if_so(variable) end |
#scope_stack ⇒ Object
21 22 23 |
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 21 def scope_stack @scope_stack ||= [] end |
#variable_exist?(name) ⇒ Boolean
108 109 110 |
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 108 def variable_exist?(name) find_variable(name) end |