Class: ASTUtils::Scope

Inherits:
Object
  • Object
show all
Includes:
NodeHelper
Defined in:
lib/ast_utils/scope.rb

Defined Under Namespace

Classes: Assignment

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from NodeHelper

#each_child_node, #map_child_node

Constructor Details

#initialize(root:) ⇒ Scope

Returns a new instance of Scope.



35
36
37
38
39
40
41
42
43
44
# File 'lib/ast_utils/scope.rb', line 35

def initialize(root:)
  @root = root
  @all_scopes = NodeSet.new
  @child_scopes = {}
  @parent_scopes = {}
  @sub_scopes = {}
  @super_scopes = {}
  @assignment_nodes = {}
  @reference_nodes = {}
end

Instance Attribute Details

#all_scopesObject (readonly)

Returns the value of attribute all_scopes.



27
28
29
# File 'lib/ast_utils/scope.rb', line 27

def all_scopes
  @all_scopes
end

#assignment_nodesObject (readonly)

Returns the value of attribute assignment_nodes.



32
33
34
# File 'lib/ast_utils/scope.rb', line 32

def assignment_nodes
  @assignment_nodes
end

#child_scopesObject (readonly)

Returns the value of attribute child_scopes.



28
29
30
# File 'lib/ast_utils/scope.rb', line 28

def child_scopes
  @child_scopes
end

#parent_scopesObject (readonly)

Returns the value of attribute parent_scopes.



29
30
31
# File 'lib/ast_utils/scope.rb', line 29

def parent_scopes
  @parent_scopes
end

#reference_nodesObject (readonly)

Returns the value of attribute reference_nodes.



33
34
35
# File 'lib/ast_utils/scope.rb', line 33

def reference_nodes
  @reference_nodes
end

#rootObject (readonly)

Returns the value of attribute root.



26
27
28
# File 'lib/ast_utils/scope.rb', line 26

def root
  @root
end

#sub_scopesObject (readonly)

Returns the value of attribute sub_scopes.



30
31
32
# File 'lib/ast_utils/scope.rb', line 30

def sub_scopes
  @sub_scopes
end

#super_scopesObject (readonly)

Returns the value of attribute super_scopes.



31
32
33
# File 'lib/ast_utils/scope.rb', line 31

def super_scopes
  @super_scopes
end

Class Method Details

.from(node:) ⇒ Object



174
175
176
# File 'lib/ast_utils/scope.rb', line 174

def self.from(node:)
  new(root: node).tap(&:construct)
end

.scope_node?(node) ⇒ Boolean

Returns:

  • (Boolean)


178
179
180
181
182
183
184
185
# File 'lib/ast_utils/scope.rb', line 178

def self.scope_node?(node)
  case node.type
  when :class, :module, :def, :block
    true
  else
    false
  end
end

Instance Method Details

#add_scope(scope) ⇒ Object



96
97
98
99
100
101
102
# File 'lib/ast_utils/scope.rb', line 96

def add_scope(scope)
  all_scopes << scope
  child_scopes[scope.__id__] = NodeSet.new
  sub_scopes[scope.__id__] = NodeSet.new
  assignment_nodes[scope.__id__] = Set.new
  reference_nodes[scope.__id__] = Set.new
end

#assignments(scope, include_subs: false) ⇒ Object



62
63
64
65
66
67
68
69
70
# File 'lib/ast_utils/scope.rb', line 62

def assignments(scope, include_subs: false)
  if include_subs
    subs(scope).inject(assignment_nodes[scope.__id__]) {|assignments, scope_|
      assignments + assignments(scope_, include_subst: true)
    }
  else
    assignment_nodes[scope.__id__]
  end
end

#child_scope!(scope, parent_scope) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/ast_utils/scope.rb', line 104

def child_scope!(scope, parent_scope)
  add_scope(scope)

  if parent_scope
    parent_scopes[scope.__id__] = parent_scope
    child_scopes[parent_scope.__id__] << scope
  end

  each_child_node(scope) do |child|
    construct_node(child, scope)
  end
end

#children(scope) ⇒ Object



46
47
48
# File 'lib/ast_utils/scope.rb', line 46

def children(scope)
  child_scopes[scope.__id__]
end

#constructObject



87
88
89
90
91
92
93
94
# File 'lib/ast_utils/scope.rb', line 87

def construct
  if Scope.scope_node?(root)
    child_scope!(root, nil)
  else
    add_scope(root)
    construct_node(root, root)
  end
end

#construct_children(node, current_scope) ⇒ Object



162
163
164
165
166
# File 'lib/ast_utils/scope.rb', line 162

def construct_children(node, current_scope)
  each_child_node(node) do |child|
    construct_node(child, current_scope)
  end
end

#construct_node(node, current_scope) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/ast_utils/scope.rb', line 132

def construct_node(node, current_scope)
  case node.type
  when :class, :module, :def
    child_scope!(node, current_scope)
  when :block
    nested_scope!(node, current_scope)
  when :lvar
    reference_nodes[current_scope.__id__] << node
  when :lvasgn, :arg, :optarg, :restarg, :kwarg, :kwoptarg, :kwrestarg, :blockarg
    assignment_nodes[current_scope.__id__] << Assignment.new(node: node, variable: node.children[0])
    construct_children(node, current_scope)
  when :procarg0
    case node.children[0]
    when AST::Node
      construct_children(node, current_scope)
    else
      assignment_nodes[current_scope.__id__] << Assignment.new(node: node, variable: node.children[0])
      construct_children(node, current_scope)
    end
  when :match_with_lvasgn
    node.children[2].each do |var|
      assignment_nodes[current_scope.__id__] << Assignment.new(node: node, variable: var)
    end

    construct_children(node, current_scope)
  else
    construct_children(node, current_scope)
  end
end

#each(&block) ⇒ Object



83
84
85
# File 'lib/ast_utils/scope.rb', line 83

def each(&block)
  all_scopes.each(&block)
end

#nested_scope!(scope, super_scope) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/ast_utils/scope.rb', line 117

def nested_scope!(scope, super_scope)
  add_scope(scope)

  if super_scope
    parent_scopes[scope.__id__] = super_scope
    child_scopes[super_scope.__id__] << scope
    super_scopes[scope.__id__] = super_scope
    sub_scopes[super_scope.__id__] << scope
  end

  each_child_node(scope) do |child|
    construct_node(child, scope)
  end
end

#parent(scope) ⇒ Object



50
51
52
# File 'lib/ast_utils/scope.rb', line 50

def parent(scope)
  parent_scopes[scope.__id__]
end

#references(scope, include_subs: false) ⇒ Object



72
73
74
75
76
77
78
79
80
81
# File 'lib/ast_utils/scope.rb', line 72

def references(scope, include_subs: false)
  if include_subs
    subs(scope).inject(reference_nodes[scope.__id__]) {|references, scope_|
      references + references(scope_, include_subs: true)
    }
  else
    reference_nodes[scope.__id__]
  end

end

#subs(scope) ⇒ Object



54
55
56
# File 'lib/ast_utils/scope.rb', line 54

def subs(scope)
  sub_scopes[scope.__id__]
end

#sup(scope) ⇒ Object



58
59
60
# File 'lib/ast_utils/scope.rb', line 58

def sup(scope)
  super_scopes[scope.__id__]
end

#valid_scope!(node) ⇒ Object



168
169
170
171
172
# File 'lib/ast_utils/scope.rb', line 168

def valid_scope!(node)
  unless root.equal?(node) || Scope.scope_node?(node)
    raise "Invalid scope node given: #{node}"
  end
end