Module: SyntaxTree::WithScope

Defined in:
lib/syntax_tree/with_scope.rb

Overview

WithScope is a module intended to be included in classes inheriting from Visitor. The module overrides a few visit methods to automatically keep track of local variables and arguments defined in the current scope. Example usage:

class MyVisitor < Visitor
  include WithScope

  def visit_ident(node)
    # Check if we're visiting an identifier for an argument, a local
    # variable or something else
    local = current_scope.find_local(node)

    if local.type == :argument
      # handle identifiers for arguments
    elsif local.type == :variable
      # handle identifiers for variables
    else
      # handle other identifiers, such as method names
    end
  end
end

Defined Under Namespace

Classes: Scope

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#current_scopeObject (readonly)

Returns the value of attribute current_scope.



120
121
122
# File 'lib/syntax_tree/with_scope.rb', line 120

def current_scope
  @current_scope
end

Instance Method Details

#initialize(*args, **kwargs, &block) ⇒ Object



122
123
124
125
126
127
# File 'lib/syntax_tree/with_scope.rb', line 122

def initialize(*args, **kwargs, &block)
  super

  @current_scope = Scope.new(0)
  @next_scope_id = 0
end

#visit_blockarg(node) ⇒ Object



185
186
187
188
189
190
# File 'lib/syntax_tree/with_scope.rb', line 185

def visit_blockarg(node)
  name = node.name
  current_scope.add_local_definition(name, :argument) if name

  super
end

#visit_class(node) ⇒ Object

Visits for nodes that create new scopes, such as classes, modules and method definitions.



131
132
133
# File 'lib/syntax_tree/with_scope.rb', line 131

def visit_class(node)
  with_scope { super }
end

#visit_def(node) ⇒ Object



147
148
149
# File 'lib/syntax_tree/with_scope.rb', line 147

def visit_def(node)
  with_scope { super }
end

#visit_kwrest_param(node) ⇒ Object



178
179
180
181
182
183
# File 'lib/syntax_tree/with_scope.rb', line 178

def visit_kwrest_param(node)
  name = node.name
  current_scope.add_local_definition(name, :argument) if name

  super
end

#visit_method_add_block(node) ⇒ Object

When we find a method invocation with a block, only the code that happens inside of the block needs a fresh scope. The method invocation itself happens in the same scope.



142
143
144
145
# File 'lib/syntax_tree/with_scope.rb', line 142

def visit_method_add_block(node)
  visit(node.call)
  with_scope(current_scope) { visit(node.block) }
end

#visit_module(node) ⇒ Object



135
136
137
# File 'lib/syntax_tree/with_scope.rb', line 135

def visit_module(node)
  with_scope { super }
end

#visit_params(node) ⇒ Object

Visit for keeping track of local arguments, such as method and block arguments.



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/syntax_tree/with_scope.rb', line 153

def visit_params(node)
  add_argument_definitions(node.requireds)

  node.posts.each do |param|
    current_scope.add_local_definition(param, :argument)
  end

  node.keywords.each do |param|
    current_scope.add_local_definition(param.first, :argument)
  end

  node.optionals.each do |param|
    current_scope.add_local_definition(param.first, :argument)
  end

  super
end

#visit_pinned_var_ref(node) ⇒ Object

Visit for keeping track of local variable definitions



201
202
203
204
205
206
# File 'lib/syntax_tree/with_scope.rb', line 201

def visit_pinned_var_ref(node)
  value = node.value
  current_scope.add_local_usage(value, :variable) if value.is_a?(Ident)

  super
end

#visit_rest_param(node) ⇒ Object



171
172
173
174
175
176
# File 'lib/syntax_tree/with_scope.rb', line 171

def visit_rest_param(node)
  name = node.name
  current_scope.add_local_definition(name, :argument) if name

  super
end

#visit_var_field(node) ⇒ Object

Visit for keeping track of local variable definitions



193
194
195
196
197
198
# File 'lib/syntax_tree/with_scope.rb', line 193

def visit_var_field(node)
  value = node.value
  current_scope.add_local_definition(value, :variable) if value.is_a?(Ident)

  super
end

#visit_var_ref(node) ⇒ Object

Visits for keeping track of variable and argument usages



209
210
211
212
213
214
215
216
217
218
# File 'lib/syntax_tree/with_scope.rb', line 209

def visit_var_ref(node)
  value = node.value

  if value.is_a?(Ident)
    definition = current_scope.find_local(value.value)
    current_scope.add_local_usage(value, definition.type) if definition
  end

  super
end