Module: Ibex::LALR::OnErrorReductions

Defined in:
lib/ibex/lalr/on_error_reductions.rb,
sig/ibex/lalr/on_error_reductions.rbs

Overview

Delays syntax-error detection by filling only otherwise erroneous table cells with one uniquely highest-priority declared reduction.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.apply(grammar, states) ⇒ Object

RBS:

  • (IR::Grammar grammar, Array[IR::AutomatonState] states) -> Array[IR::AutomatonState]



9
10
11
12
13
14
15
# File 'lib/ibex/lalr/on_error_reductions.rb', line 9

def apply(grammar, states)
  priorities = reduction_priorities(grammar)
  return states if priorities.empty?

  terminal_ids = grammar.terminals.reject { |terminal| terminal.name == "error" }.map(&:id)
  states.map { |state| apply_state(grammar, state, priorities, terminal_ids) }
end

.apply_state(grammar, state, priorities, terminal_ids) ⇒ Object

RBS:

  • (IR::Grammar grammar, IR::AutomatonState state, Hash[Integer, Integer] priorities, Array[Integer] terminal_ids) -> IR::AutomatonState



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/ibex/lalr/on_error_reductions.rb', line 32

def apply_state(grammar, state, priorities, terminal_ids)
  production_id = selected_production(grammar, state, priorities)
  return state unless production_id

  reduction = { type: :reduce, production: production_id } #: IR::reduce_action
  actions = state.actions.dup
  terminal_ids.each do |token_id|
    action = actions[token_id]
    actions[token_id] = reduction if action.nil? || action[:type] == :error
  end
  IR::AutomatonState.new(
    id: state.id, items: state.items, transitions: state.transitions,
    actions: actions, gotos: state.gotos, default_action: state.default_action,
    conflicts: state.conflicts
  )
end

.reduction_priorities(grammar) ⇒ Object

RBS:

  • (IR::Grammar grammar) -> Hash[Integer, Integer]



19
20
21
22
23
24
25
26
27
28
# File 'lib/ibex/lalr/on_error_reductions.rb', line 19

def reduction_priorities(grammar)
  priorities = {} #: Hash[Integer, Integer]
  grammar.recovery[:on_error_reduce].each_with_index do |names, priority|
    names.each do |name|
      symbol = grammar.symbol(name) || raise(Ibex::Error, "missing on-error reduction symbol #{name}")
      priorities[symbol.id] = priority
    end
  end
  priorities
end

.selected_production(grammar, state, priorities) ⇒ Object

RBS:

  • (IR::Grammar grammar, IR::AutomatonState state, Hash[Integer, Integer] priorities) -> Integer?



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/ibex/lalr/on_error_reductions.rb', line 50

def selected_production(grammar, state, priorities)
  candidates = state.items.filter_map do |item|
    next if item.production.negative?

    production = grammar.productions.fetch(item.production)
    next unless item.dot == production.rhs.length

    priority = priorities[production.lhs]
    [priority, production.id] if priority
  end.uniq
  highest = candidates.filter_map(&:first).max
  return unless highest

  productions = candidates.filter_map { |priority, production| production if priority == highest }.uniq
  productions.one? ? productions.fetch(0) : nil
end

Instance Method Details

#apply_state(grammar, state, priorities, terminal_ids) ⇒ IR::AutomatonState

RBS:

  • (IR::Grammar grammar, IR::AutomatonState state, Hash[Integer, Integer] priorities, Array[Integer] terminal_ids) -> IR::AutomatonState

Parameters:

Returns:



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/ibex/lalr/on_error_reductions.rb', line 32

def apply_state(grammar, state, priorities, terminal_ids)
  production_id = selected_production(grammar, state, priorities)
  return state unless production_id

  reduction = { type: :reduce, production: production_id } #: IR::reduce_action
  actions = state.actions.dup
  terminal_ids.each do |token_id|
    action = actions[token_id]
    actions[token_id] = reduction if action.nil? || action[:type] == :error
  end
  IR::AutomatonState.new(
    id: state.id, items: state.items, transitions: state.transitions,
    actions: actions, gotos: state.gotos, default_action: state.default_action,
    conflicts: state.conflicts
  )
end

#selected_production(grammar, state, priorities) ⇒ Integer?

RBS:

  • (IR::Grammar grammar, IR::AutomatonState state, Hash[Integer, Integer] priorities) -> Integer?

Parameters:

Returns:

  • (Integer, nil)


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/ibex/lalr/on_error_reductions.rb', line 50

def selected_production(grammar, state, priorities)
  candidates = state.items.filter_map do |item|
    next if item.production.negative?

    production = grammar.productions.fetch(item.production)
    next unless item.dot == production.rhs.length

    priority = priorities[production.lhs]
    [priority, production.id] if priority
  end.uniq
  highest = candidates.filter_map(&:first).max
  return unless highest

  productions = candidates.filter_map { |priority, production| production if priority == highest }.uniq
  productions.one? ? productions.fetch(0) : nil
end

#self?.applyArray[IR::AutomatonState]

RBS:

  • (IR::Grammar grammar, Array[IR::AutomatonState] states) -> Array[IR::AutomatonState]

Parameters:

Returns:



9
# File 'sig/ibex/lalr/on_error_reductions.rbs', line 9

def self?.apply: (IR::Grammar grammar, Array[IR::AutomatonState] states) -> Array[IR::AutomatonState]

#self?.reduction_prioritiesHash[Integer, Integer]

RBS:

  • (IR::Grammar grammar) -> Hash[Integer, Integer]

Parameters:

Returns:

  • (Hash[Integer, Integer])


12
# File 'sig/ibex/lalr/on_error_reductions.rbs', line 12

def self?.reduction_priorities: (IR::Grammar grammar) -> Hash[Integer, Integer]