Class: ASTUtils::Labeling

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

Defined Under Namespace

Classes: LabeledName

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from NodeHelper

#each_child_node, #map_child_node

Constructor Details

#initializeLabeling

Returns a new instance of Labeling.



37
38
39
# File 'lib/ast_utils/labeling.rb', line 37

def initialize
  self.counter = 0
end

Instance Attribute Details

#counterObject

Returns the value of attribute counter.



35
36
37
# File 'lib/ast_utils/labeling.rb', line 35

def counter
  @counter
end

Class Method Details

.extract_variables(string) ⇒ Object



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

def self.extract_variables(string)
  string.scan(/\(\?(\<([\w_]+)\>)|(\'([\w_]+)\')/).map do |_, b, _, d|
    (b || d).to_sym
  end
end

.translate(node:) ⇒ Object



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

def self.translate(node:)
  self.new.translate(node, {})
end

Instance Method Details

#lookup_env(name:, env:) ⇒ Object



145
146
147
148
149
150
151
152
153
154
# File 'lib/ast_utils/labeling.rb', line 145

def lookup_env(name:, env:)
  labeled_name = env[name]

  unless labeled_name
    labeled_name = LabeledName.new(name: name, label: next_label!)
    env[name] = labeled_name
  end

  labeled_name
end

#next_label!Object



41
42
43
44
45
46
47
48
49
50
51
# File 'lib/ast_utils/labeling.rb', line 41

def next_label!
  self.counter += 1

  new_label = self.counter

  if block_given?
    yield new_label
  else
    new_label
  end
end

#replace(array, index) ⇒ Object



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

def replace(array, index)
  array = array.dup
  array[index] = yield(array[index])
  array
end

#translate(node, env) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/ast_utils/labeling.rb', line 53

def translate(node, env)
  case node.type
  when :lvasgn
    children = PartialMap.apply(node.children) do |map|
      map.on!(0) {|name| lookup_env(name: name, env: env) }
      map.on?(1) {|child| translate(child, env) }
    end

    node.updated(nil, children, nil)

  when :lvar
    children = replace(node.children, 0) {|name| lookup_env(name: name, env: env) }
    node.updated(nil, children, nil)

  when :arg, :restarg, :kwarg, :kwrestarg, :blockarg
    name = node.children[0]

    labeled_name = LabeledName.new(name: name, label: next_label!)
    env[name] = labeled_name

    children = replace(node.children, 0) {|_| labeled_name }
    node.updated(nil, children, nil)

  when :procarg0
    case node.children[0]
    when AST::Node
      children = map_child_node(node) {|child| translate(child, env) }
      node.updated(nil, children, nil)
    when Symbol
      name = node.children[0]

      labeled_name = LabeledName.new(name: name, label: next_label!)
      env[name] = labeled_name

      children = replace(node.children, 0) {|_| labeled_name }
      node.updated(nil, children, nil)
    else
      raise "Unexpected node structure: #{node}"
    end
  when :optarg, :kwoptarg
    children = PartialMap.apply(node.children) do |map|
      map.on!(0) {|name| lookup_env(name: name, env: env) }
      map.on?(1) {|child| translate(child, env) }
    end

    node.updated(nil, children, nil)

  when :def
    env_ = {}
    children = map_child_node(node) {|child| translate(child, env_) }
    node.updated(nil, children, nil)

  when :block
    children = node.children.dup
    translate_child!(children, 0, env)

    block_env = env.dup
    translate_child!(children, 1, block_env)
    translate_child!(children, 2, block_env)

    node.updated(nil, children, nil)

  when :class
    children = PartialMap.apply(node.children) do |map|
      map.on!(0) {|child| translate(child, env) }
      map.on?(1) {|child| translate(child, env) }
      map.on?(2) {|child| translate(child, {}) }
    end

    node.updated(nil, children, nil)

  when :module
    children = PartialMap.apply(node.children) do |map|
      map.on!(0) {|child| translate(child, env) }
      map.on?(1) {|child| translate(child, {}) }
    end

    node.updated(nil, children, nil)

  when :match_with_lvasgn
    names = self.class.extract_variables(node.children[0].children[0].children[0])
    vars = names.map {|name| lookup_env(name: name, env: env) }

    children = map_child_node(node) {|child| translate(child, env) }
    node.updated(nil, children + [vars], nil)

  else
    children = map_child_node(node) {|child| translate(child, env) }
    node.updated(nil, children, nil)
  end
end

#translate_child!(children, index, env) ⇒ Object



156
157
158
159
160
# File 'lib/ast_utils/labeling.rb', line 156

def translate_child!(children, index, env)
  if children[index]
    children[index] = translate(children[index], env)
  end
end