Class: Ibex::Impact::ActionImpact
- Inherits:
-
Object
- Object
- Ibex::Impact::ActionImpact
- Defined in:
- lib/ibex/impact/action_impact.rb,
sig/ibex/impact/action_impact.rbs
Overview
Checks only structured action metadata; action source remains opaque.
Instance Attribute Summary collapse
Instance Method Summary collapse
- #action_location_identity(production) ⇒ [ Integer, Integer ]?
- #compare ⇒ Array[Hash[Symbol, Object?]]
- #compare_rule(name) ⇒ Array[Hash[Symbol, Object?]]
- #finding_for(before, after) ⇒ Hash[Symbol, Object?]
- #finding_reason(action, before_length, after_length) ⇒ [ String, String ]
-
#initialize(before, after, affected_names: nil) ⇒ ActionImpact
constructor
A new instance of ActionImpact.
- #out_of_range?(action, length) ⇒ Boolean
- #pair_by_location(unmatched, after, pairs) ⇒ Array[[ IR::Production, IR::Production ]]
- #pair_exact_productions(unmatched, after) ⇒ Array[[ IR::Production, IR::Production ]]
- #pair_productions(before, after) ⇒ Array[[ IR::Production, IR::Production ]]
- #production_name(grammar, production) ⇒ String
- #production_signature(grammar, production) ⇒ [ Array[String], String? ]
- #productions_for(grammar, name) ⇒ Array[IR::Production]
- #to_a ⇒ Array[Hash[Symbol, Object?]]
Constructor Details
#initialize(before, after, affected_names: nil) ⇒ ActionImpact
Returns a new instance of ActionImpact.
14 15 16 17 18 19 20 |
# File 'lib/ibex/impact/action_impact.rb', line 14 def initialize(before, after, affected_names: nil) @before = before @after = after @affected_names = affected_names @findings = compare freeze end |
Instance Attribute Details
#findings ⇒ Array[Hash[Symbol, Object?]] (readonly)
11 12 13 |
# File 'lib/ibex/impact/action_impact.rb', line 11 def findings @findings end |
Instance Method Details
#action_location_identity(production) ⇒ [ Integer, Integer ]?
104 105 106 107 108 109 110 111 112 113 |
# File 'lib/ibex/impact/action_impact.rb', line 104 def action_location_identity(production) location = production.origin[:loc] || production.action&.location #: IR::location? return unless location line = location[:line] column = location[:column] return unless line && column [line, column] end |
#compare ⇒ Array[Hash[Symbol, Object?]]
30 31 32 33 34 |
# File 'lib/ibex/impact/action_impact.rb', line 30 def compare names = @after.nonterminals.map(&:name) names &= @affected_names if @affected_names names.sort.flat_map { |name| compare_rule(name) }.sort_by { |finding| finding.fetch(:production) } end |
#compare_rule(name) ⇒ Array[Hash[Symbol, Object?]]
37 38 39 40 41 42 43 44 45 |
# File 'lib/ibex/impact/action_impact.rb', line 37 def compare_rule(name) before = productions_for(@before, name) after = productions_for(@after, name) pair_productions(before, after).filter_map do |previous, production| next if previous.rhs.length == production.rhs.length finding_for(previous, production) end end |
#finding_for(before, after) ⇒ Hash[Symbol, Object?]
116 117 118 119 120 121 122 123 124 125 |
# File 'lib/ibex/impact/action_impact.rb', line 116 def finding_for(before, after) action = after.action reason, severity = finding_reason(action, before.rhs.length, after.rhs.length) { production: production_name(@after, after), severity: severity, reason: reason, context_length: { before: before.rhs.length, after: after.rhs.length }, loc: after.action&.location || after.origin[:loc] } end |
#finding_reason(action, before_length, after_length) ⇒ [ String, String ]
128 129 130 131 132 133 |
# File 'lib/ibex/impact/action_impact.rb', line 128 def finding_reason(action, before_length, after_length) return %w[named_ref_index_out_of_range high] if out_of_range?(action, after_length) return %w[context_length_stale high] if action&.context_length == before_length %w[rhs_length_changed medium] end |
#out_of_range?(action, length) ⇒ Boolean
136 137 138 |
# File 'lib/ibex/impact/action_impact.rb', line 136 def out_of_range?(action, length) action&.named_refs&.any? { |reference| reference.fetch(:index) >= length } || false end |
#pair_by_location(unmatched, after, pairs) ⇒ Array[[ IR::Production, IR::Production ]]
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/ibex/impact/action_impact.rb', line 72 def pair_by_location(unmatched, after, pairs) after.each do |production| next if pairs.any? { |_, candidate| candidate.equal?(production) } index = unmatched.index do |candidate| location = action_location_identity(production) location && location == action_location_identity(candidate) end next unless index pairs << [unmatched.delete_at(index), production] end pairs end |
#pair_exact_productions(unmatched, after) ⇒ Array[[ IR::Production, IR::Production ]]
55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/ibex/impact/action_impact.rb', line 55 def pair_exact_productions(unmatched, after) pairs = [] #: Array[[IR::Production, IR::Production]] after.each do |production| index = unmatched.index do |candidate| production_signature(@before, candidate) == production_signature(@after, production) end next unless index pairs << [unmatched.delete_at(index), production] end pairs end |
#pair_productions(before, after) ⇒ Array[[ IR::Production, IR::Production ]]
48 49 50 51 52 |
# File 'lib/ibex/impact/action_impact.rb', line 48 def pair_productions(before, after) unmatched = before.dup pairs = pair_exact_productions(unmatched, after) pair_by_location(unmatched, after, pairs) end |
#production_name(grammar, production) ⇒ String
141 142 143 144 145 |
# File 'lib/ibex/impact/action_impact.rb', line 141 def production_name(grammar, production) lhs = grammar.symbol_by_id(production.lhs)&.name || production.lhs.to_s rhs = production.rhs.map { |id| grammar.symbol_by_id(id)&.name || id.to_s } "#{lhs} -> #{rhs.join(' ')}" end |
#production_signature(grammar, production) ⇒ [ Array[String], String? ]
97 98 99 100 101 |
# File 'lib/ibex/impact/action_impact.rb', line 97 def production_signature(grammar, production) rhs = production.rhs.map { |id| grammar.symbol_by_id(id)&.name || id.to_s } precedence = grammar.symbol_by_id(production.precedence_override)&.name [rhs, precedence] end |
#productions_for(grammar, name) ⇒ Array[IR::Production]
89 90 91 92 93 94 |
# File 'lib/ibex/impact/action_impact.rb', line 89 def productions_for(grammar, name) lhs = grammar.symbol(name)&.id return [] unless lhs grammar.productions.select { |production| production.lhs == lhs } end |
#to_a ⇒ Array[Hash[Symbol, Object?]]
23 24 25 |
# File 'lib/ibex/impact/action_impact.rb', line 23 def to_a @findings end |