Module: Ibex::Codegen::Report
- Defined in:
- lib/ibex/codegen/report.rb,
sig/ibex/codegen/report.rbs
Overview
Renders a human-readable state and conflict report from Automaton IR.
Class Method Summary collapse
- .append_counterexample(lines, example, grammar, labels) ⇒ Object
- .append_state(lines, state, grammar, examples, labels) ⇒ Object
- .append_tree(lines, tree, indentation, grammar, labels) ⇒ Object
- .display_conflict(conflict, grammar, labels) ⇒ Object
- .format_action(action) ⇒ Object
- .format_item(item, grammar, labels) ⇒ Object
-
.format_value(value) ⇒ Object
Keep reports byte-identical across Ruby versions whose Hash#inspect formatting differs for symbol keys.
- .render(automaton, max_tokens: LALR::Counterexample::DEFAULT_MAX_TOKENS, max_configurations: LALR::Counterexample::DEFAULT_MAX_CONFIGURATIONS) ⇒ Object
- .symbol_name(labels, id) ⇒ Object
- .tree_label(grammar, labels, value) ⇒ Object
Instance Method Summary collapse
Class Method Details
.append_counterexample(lines, example, grammar, labels) ⇒ Object
90 91 92 93 94 95 96 97 98 99 |
# File 'lib/ibex/codegen/report.rb', line 90 def append_counterexample(lines, example, grammar, labels) label = example[:unifying] ? "unifying counterexample" : "nonunifying witness" sentence = example[:sentence].map { |name| tree_label(grammar, labels, name) } sentence = sentence.dup.insert(example[:lookahead_index], "•").join(" ") lines << " #{label}: #{sentence}" example[:interpretations].each do |interpretation| lines << " #{interpretation[:kind]} derivation:" append_tree(lines, interpretation[:tree], " ", grammar, labels) end end |
.append_state(lines, state, grammar, examples, labels) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/ibex/codegen/report.rb', line 74 def append_state(lines, state, grammar, examples, labels) lines << "State #{state.id}" state.items.each { |item| lines << " #{format_item(item, grammar, labels)}" } state.actions.each do |token_id, action| lines << " on #{symbol_name(labels, token_id)}: #{format_action(action)}" end lines << " default: #{format_action(state.default_action)}" if state.default_action state.gotos.each { |symbol_id, target| lines << " goto #{symbol_name(labels, symbol_id)}: #{target}" } state.conflicts.each do |conflict| lines << " conflict: #{format_value(display_conflict(conflict, grammar, labels))}" end examples.each { |example| append_counterexample(lines, example, grammar, labels) } lines << "" end |
.append_tree(lines, tree, indentation, grammar, labels) ⇒ Object
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/ibex/codegen/report.rb', line 102 def append_tree(lines, tree, indentation, grammar, labels) unless tree.is_a?(Hash) lines << "#{indentation}#{tree_label(grammar, labels, tree)}" return end symbol = tree_label(grammar, labels, tree[:symbol] || tree[:token]) unless tree[:children] lines << "#{indentation}#{symbol}" return end production = tree[:production] ? " (production #{tree[:production]})" : "" lines << "#{indentation}#{symbol}#{production}" tree[:children].each { |child| append_tree(lines, child, "#{indentation} ", grammar, labels) } end |
.display_conflict(conflict, grammar, labels) ⇒ Object
156 157 158 159 160 161 |
# File 'lib/ibex/codegen/report.rb', line 156 def display_conflict(conflict, grammar, labels) symbol = grammar.symbol(conflict[:symbol]) return conflict unless symbol conflict.merge(symbol: symbol_name(labels, symbol.id)) end |
.format_action(action) ⇒ Object
136 137 138 139 140 141 142 |
# File 'lib/ibex/codegen/report.rb', line 136 def format_action(action) case action[:type] when :shift then "shift #{action[:state]}" when :reduce then "reduce #{action[:production]}" else action[:type].to_s end end |
.format_item(item, grammar, labels) ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/ibex/codegen/report.rb', line 120 def format_item(item, grammar, labels) if item.production == LALR::Builder::AUGMENTED_PRODUCTION start = grammar.symbol(grammar.start) rhs = [grammar.starts.one? && start ? symbol_name(labels, start.id) : "<entry>"] lhs = "$accept" else production = grammar.productions.fetch(item.production) rhs = production.rhs.map { |id| symbol_name(labels, id) } lhs = symbol_name(labels, production.lhs) end rhs = rhs.dup.insert(item.dot, "•") lookaheads = item.lookaheads.map { |id| symbol_name(labels, id) }.join(", ") "#{lhs} -> #{rhs.join(' ')} [#{lookaheads}]" end |
.format_value(value) ⇒ Object
Keep reports byte-identical across Ruby versions whose Hash#inspect formatting differs for symbol keys.
166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/ibex/codegen/report.rb', line 166 def format_value(value) case value when Hash entries = value.map do |key, item| label = key.is_a?(Symbol) ? "#{key}:" : "#{format_value(key)} =>" "#{label} #{format_value(item)}" end "{#{entries.join(', ')}}" when Array "[#{value.map { |item| format_value(item) }.join(', ')}]" else value.inspect end end |
.render(automaton, max_tokens: LALR::Counterexample::DEFAULT_MAX_TOKENS, max_configurations: LALR::Counterexample::DEFAULT_MAX_CONFIGURATIONS) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/ibex/codegen/report.rb', line 50 def render(automaton, max_tokens: LALR::Counterexample::DEFAULT_MAX_TOKENS, max_configurations: LALR::Counterexample::DEFAULT_MAX_CONFIGURATIONS) grammar = automaton.grammar labels = SymbolLabels.build(grammar) entries = automaton.entry_states.map { |name, state| "#{name}=#{state}" }.join(", ") lines = ["Algorithm: #{automaton.algorithm}", "States: #{automaton.states.length}"] lines << "Entries: #{entries}" if automaton.entry_states.length > 1 lines << "" examples = LALR::Counterexample.new( automaton, max_tokens: max_tokens, max_configurations: max_configurations ).all.group_by { |example| example[:state] } automaton.states.each do |state| append_state(lines, state, grammar, examples.fetch(state.id, Array.new(0)), labels) end summary = automaton.conflict_summary lines << "Conflicts: #{summary[:sr]} shift/reduce, #{summary[:rr]} reduce/reduce" "#{lines.join("\n")}\n" end |
.symbol_name(labels, id) ⇒ Object
145 146 147 |
# File 'lib/ibex/codegen/report.rb', line 145 def symbol_name(labels, id) labels.fetch(id) { raise Ibex::Error, "missing grammar symbol id #{id}" } end |
.tree_label(grammar, labels, value) ⇒ Object
150 151 152 153 |
# File 'lib/ibex/codegen/report.rb', line 150 def tree_label(grammar, labels, value) symbol = grammar.symbol(value.to_s) symbol ? symbol_name(labels, symbol.id) : value end |
Instance Method Details
#self?.render ⇒ String
44 |
# File 'sig/ibex/codegen/report.rbs', line 44
def self?.render: (IR::Automaton automaton, ?max_tokens: Integer, ?max_configurations: Integer) -> String
|