Module: SyntaxTree::WithEnvironment

Defined in:
lib/syntax_tree/visitor/with_environment.rb

Overview

WithEnvironment 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 environment. Example usage:

class MyVisitor < Visitor
  include WithEnvironment

  def visit_ident(node)
    # Check if we're visiting an identifier for an argument, a local
    variable or something else
    local = current_environment.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

Instance Method Summary collapse

Instance Method Details

#current_environmentObject



25
26
27
# File 'lib/syntax_tree/visitor/with_environment.rb', line 25

def current_environment
  @current_environment ||= Environment.new
end

#visit_blockarg(node) ⇒ Object



93
94
95
96
97
98
# File 'lib/syntax_tree/visitor/with_environment.rb', line 93

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

  super
end

#visit_class(node) ⇒ Object

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



39
40
41
# File 'lib/syntax_tree/visitor/with_environment.rb', line 39

def visit_class(node)
  with_new_environment { super }
end

#visit_def(node) ⇒ Object



55
56
57
# File 'lib/syntax_tree/visitor/with_environment.rb', line 55

def visit_def(node)
  with_new_environment { super }
end

#visit_kwrest_param(node) ⇒ Object



86
87
88
89
90
91
# File 'lib/syntax_tree/visitor/with_environment.rb', line 86

def visit_kwrest_param(node)
  name = node.name
  current_environment.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 environment. The method invocation itself happens in the same environment



50
51
52
53
# File 'lib/syntax_tree/visitor/with_environment.rb', line 50

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

#visit_module(node) ⇒ Object



43
44
45
# File 'lib/syntax_tree/visitor/with_environment.rb', line 43

def visit_module(node)
  with_new_environment { super }
end

#visit_params(node) ⇒ Object

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



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/syntax_tree/visitor/with_environment.rb', line 61

def visit_params(node)
  add_argument_definitions(node.requireds)

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

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

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

  super
end

#visit_rest_param(node) ⇒ Object



79
80
81
82
83
84
# File 'lib/syntax_tree/visitor/with_environment.rb', line 79

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

  super
end

#visit_var_field(node) ⇒ Object Also known as: visit_pinned_var_ref

Visit for keeping track of local variable definitions



101
102
103
104
105
106
107
108
109
# File 'lib/syntax_tree/visitor/with_environment.rb', line 101

def visit_var_field(node)
  value = node.value

  if value.is_a?(SyntaxTree::Ident)
    current_environment.add_local_definition(value, :variable)
  end

  super
end

#visit_var_ref(node) ⇒ Object

Visits for keeping track of variable and argument usages



114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/syntax_tree/visitor/with_environment.rb', line 114

def visit_var_ref(node)
  value = node.value

  if value.is_a?(SyntaxTree::Ident)
    definition = current_environment.find_local(value.value)

    if definition
      current_environment.add_local_usage(value, definition.type)
    end
  end

  super
end

#with_new_environmentObject



29
30
31
32
33
34
35
# File 'lib/syntax_tree/visitor/with_environment.rb', line 29

def with_new_environment
  previous_environment = @current_environment
  @current_environment = Environment.new(previous_environment)
  yield
ensure
  @current_environment = previous_environment
end