Class: OrigenTesters::ATP::Processors::Condition

Inherits:
OrigenTesters::ATP::Processor show all
Defined in:
lib/origen_testers/atp/processors/condition.rb

Overview

This optimizes the condition nodes such that any adjacent flow nodes that have the same condition, will be grouped together under a single condition wrapper.

For example this AST:

(flow
  (group
    (name "g1")
    (test
      (name "test1"))
    (flow-flag "bitmap" true
      (test
        (name "test2"))))
  (flow-flag "bitmap" true
    (group
      (name "g1")
      (flow-flag "x" true
        (test
          (name "test3")))
      (flow-flag "y" true
        (flow-flag "x" true
          (test
            (name "test4")))))))

Will be optimized to this:

(flow
  (group
    (name "g1")
    (test
      (name "test1"))
    (flow-flag "bitmap" true
      (test
        (name "test2"))
      (flow-flag "x" true
        (test
          (name "test3"))
        (flow-flag "y" true
          (test
            (name "test4")))))))

Instance Method Summary collapse

Methods inherited from OrigenTesters::ATP::Processor

#clean_flag, #extract_volatiles, #handler_missing, #process, #process_all, #run, #volatile?, #volatile_flags

Instance Method Details

#can_be_combined?(node1, node2) ⇒ Boolean

Returns:

  • (Boolean)

128
129
130
131
132
133
134
# File 'lib/origen_testers/atp/processors/condition.rb', line 128

def can_be_combined?(node1, node2)
  if condition_node?(node1) && condition_node?(node2)
    !(conditions(node1) & conditions(node2)).empty?
  else
    false
  end
end

#combine(node1, node2) ⇒ Object


141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/origen_testers/atp/processors/condition.rb', line 141

def combine(node1, node2)
  common = conditions(node1) & conditions(node2)
  common.each { |condition| conditions_to_remove << condition }
  node1 = process(node1)
  node1 = [node1] unless node1.is_a?(Array)
  node2 = process(node2)
  node2 = [node2] unless node2.is_a?(Array)
  common.size.times { conditions_to_remove.pop }

  node = nil
  common.reverse_each do |condition|
    if node
      node = condition.updated(nil, condition.children + [node])
    else
      node = condition.updated(nil, condition.children + node1 + node2)
    end
  end
  node
end

#condition_node?(node) ⇒ Boolean

Returns:

  • (Boolean)

136
137
138
139
# File 'lib/origen_testers/atp/processors/condition.rb', line 136

def condition_node?(node)
  # [:flow_flag, :run_flag, :test_result, :group, :job, :test_executed].include?(node.type)
  node.respond_to?(:type) && OrigenTesters::ATP::Flow::CONDITION_KEYS[node.type]
end

#conditions(node) ⇒ Object


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/origen_testers/atp/processors/condition.rb', line 161

def conditions(node)
  result = []
  # if [:flow_flag, :run_flag].include?(node.type)
  if [:if_enabled, :unless_enabled, :if_flag, :unless_flag].include?(node.type)
    flag, *children = *node
    unless volatile?(flag)
      result << node.updated(nil, [flag])
    end
    result += conditions(children.first) if children.first && children.size == 1
  # elsif [:test_result, :job, :test_executed].include?(node.type)
  elsif node.type == :group
    name, *children = *node
    # Sometimes a group can have an ID
    if children.first.try(:type) == :id
      result << node.updated(nil, [name, children.shift])
    else
      result << node.updated(nil, [name])
    end
    result += conditions(children.first) if children.first && children.size == 1
  elsif OrigenTesters::ATP::Flow::CONDITION_NODE_TYPES.include?(node.type)
    flag, *children = *node
    result << node.updated(nil, [flag])
    result += conditions(children.first) if children.first && children.size == 1
  end
  result
end

#conditions_to_removeObject


188
189
190
# File 'lib/origen_testers/atp/processors/condition.rb', line 188

def conditions_to_remove
  @conditions_to_remove ||= []
end

#on_condition_node(node) ⇒ Object


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/origen_testers/atp/processors/condition.rb', line 83

def on_condition_node(node)
  flag, *nodes = *node
  if conditions_to_remove.any? { |c| node.type == c.type && c.to_a == [flag] }
    if volatile?(flag)
      result = node.updated(:inline, optimize(process_all(nodes)))
    else
      # This ensures any duplicate conditions matching the current one get removed
      conditions_to_remove << node.updated(nil, [flag])
      result = node.updated(:inline, optimize(process_all(nodes)))
      conditions_to_remove.pop
    end
  else
    if volatile?(flag)
      result = node.updated(nil, [flag] + optimize(process_all(nodes)))
    else
      conditions_to_remove << node.updated(nil, [flag])
      result = node.updated(nil, [flag] + optimize(process_all(nodes)))
      conditions_to_remove.pop
    end
  end
  result
end

#on_flow(node) ⇒ Object


46
47
48
49
# File 'lib/origen_testers/atp/processors/condition.rb', line 46

def on_flow(node)
  extract_volatiles(node)
  node.updated(nil, optimize(process_all(node.children)))
end

#on_group(node) ⇒ Object


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
# File 'lib/origen_testers/atp/processors/condition.rb', line 55

def on_group(node)
  array_for_update = []
  if node.find(:bypass) && node.find(:comment)
    name, bypass, comment, *nodes = *node
    array_for_update = [name, bypass, comment]
  elsif node.find(:bypass)
    name, bypass, *nodes = *node
    array_for_update = [name, bypass]
  elsif node.find(:comment)
    name, comment, *nodes = *node
    array_for_update = [name, comment]
  else
    name, *nodes = *node
    array_for_update = [name]
  end

  if conditions_to_remove.any? { |c| node.type == c.type && c.to_a == [name] }
    conditions_to_remove << node.updated(nil, array_for_update)
    result = node.updated(:inline, optimize(process_all(nodes)))
    conditions_to_remove.pop
  else
    conditions_to_remove << node.updated(nil, [name, bypass, comment])
    result = node.updated(nil, array_for_update + optimize(process_all(nodes)))
    conditions_to_remove.pop
  end
  result
end

#on_sub_flow(node) ⇒ Object


51
52
53
# File 'lib/origen_testers/atp/processors/condition.rb', line 51

def on_sub_flow(node)
  node.updated(nil, optimize(process_all(node.children)))
end

#optimize(nodes) ⇒ Object


109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/origen_testers/atp/processors/condition.rb', line 109

def optimize(nodes)
  results = []
  node1 = nil
  nodes.each do |node2|
    if node1
      if can_be_combined?(node1, node2)
        node1 = process(combine(node1, node2))
      else
        results << node1
        node1 = node2
      end
    else
      node1 = node2
    end
  end
  results << node1 if node1
  results
end