diff --git a/lib/imbecile/regex/nfa.rb b/lib/imbecile/regex/nfa.rb new file mode 100644 index 0000000..317ed37 --- /dev/null +++ b/lib/imbecile/regex/nfa.rb @@ -0,0 +1,40 @@ +module Imbecile + class Regex + + class NFA + + class State + + def initialize + @transitions = [] + end + + def add_transition(code_point, destination_state) + @transitions << [code_point, destination_state] + end + + end + + attr_accessor :start_state + + attr_accessor :end_state + + def initialize + @start_state = State.new + @end_state = State.new + end + + class << self + + def empty + nfa = NFA.new + nfa.end_state = nfa.start_state + nfa + end + + end + + end + + end +end diff --git a/lib/imbecile/regex/parser.rb b/lib/imbecile/regex/parser.rb index bb7dfd4..e0d369f 100644 --- a/lib/imbecile/regex/parser.rb +++ b/lib/imbecile/regex/parser.rb @@ -14,6 +14,18 @@ module Imbecile def method_missing(*args) @units.__send__(*args) end + def to_nfa + if @units.empty? + NFA.empty + else + @units.map do |unit| + unit.to_nfa + end.reduce do |result, nfa| + result.end_state.add_transition(nil, nfa.start_state) + result + end + end + end end class AlternatesUnit < Unit @@ -47,6 +59,23 @@ module Imbecile @alternates[-1] = new_unit end end + def to_nfa + if @alternates.size == 0 + NFA.empty + elsif @alternates.size == 1 + @alternates[0].to_nfa + else + nfa = NFA.new + alternate_nfas = @alternates.map do |alternate| + alternate.to_nfa + end + alternate_nfas.each do |alternate_nfa| + nfa.start_state.add_transition(nil, alternate_nfa.start_state) + alternate_nfa.end_state.add_transition(nil, nfa.end_state) + end + nfa + end + end end class CharacterUnit < Unit