class ActionDispatch::Journey::NFA::TransitionTable
:nodoc:
:nodoc:
:nodoc:
def []=(i, f, s)
def []=(i, f, s) @table[f][i] = s end
def accepting?(state)
def accepting?(state) accepting == state end
def accepting_states
def accepting_states [accepting] end
def add_memo(idx, memo)
def add_memo(idx, memo) @memos[idx] = memo end
def alphabet
def alphabet inverted.values.map(&:keys).flatten.compact.uniq.sort_by { |x| x.to_s } end
def eclosure(t)
Returns a set of NFA states reachable from some NFA state +s+ in set
def eclosure(t) stack = Array(t) seen = {} children = [] until stack.empty? s = stack.pop next if seen[s] seen[s] = true children << s stack.concat(inverted[s][nil]) end children.uniq end
def following_states(t, a)
Returns set of NFA states to which there is a transition on ast symbol
def following_states(t, a) Array(t).map { |s| inverted[s][a] }.flatten.uniq end
def generalized_table
are reduced like a DFA, but the table must be simulated like an NFA.
Returns a generalized transition graph with reduced states. The states
def generalized_table gt = GTG::TransitionTable.new marked = {} state_id = Hash.new { |h,k| h[k] = h.length } alphabet = self.alphabet stack = [eclosure(0)] until stack.empty? state = stack.pop next if marked[state] || state.empty? marked[state] = true alphabet.each do |alpha| next_state = eclosure(following_states(state, alpha)) next if next_state.empty? gt[state_id[state], state_id[next_state]] = alpha stack << next_state end end final_groups = state_id.keys.find_all { |s| s.sort.last == accepting } final_groups.each do |states| id = state_id[states] gt.add_accepting(id) save = states.find { |s| @memos.key?(s) && eclosure(s).sort.last == accepting } gt.add_memo(id, memo(save)) end gt end
def initialize
def initialize @table = Hash.new { |h,f| h[f] = {} } @memos = {} @accepting = nil @inverted = nil end
def inverted
def inverted return @inverted if @inverted @inverted = Hash.new { |h, from| h[from] = Hash.new { |j, s| j[s] = [] } } @table.each { |to, hash| hash.each { |from, sym| if sym sym = Nodes::Symbol === sym ? sym.regexp : sym.left end @inverted[from][sym] << to } } @inverted end
def memo(idx)
def memo(idx) @memos[idx] end
def merge(left, right)
def merge(left, right) @memos[right] = @memos.delete(left) @table[right] = @table.delete(left) end
def move(t, a)
Returns set of NFA states to which there is a transition on ast symbol
def move(t, a) Array(t).map { |s| inverted[s].keys.compact.find_all { |sym| sym === a }.map { |sym| inverted[s][sym] } }.flatten.uniq end
def states
def states (@table.keys + @table.values.map(&:keys).flatten).uniq end
def transitions
def transitions @table.map { |to, hash| hash.map { |from, sym| [from, sym, to] } }.flatten(1) end