/// <summary> /// Returns a <see cref="PartialNFA"/> constructed /// by concatenating the left and right partials with a epsilon transition between /// them /// </summary> /// <param name="left">Left partial NFA</param> /// <param name="right">Right partial NFA</param> /// <returns></returns> public PartialNFA Concatenation(PartialNFA left, PartialNFA right) { return(new PartialNFA( left.Initial, right.Terminal, left.Transitions .Union(right.Transitions) .Union(new[] { Transition(left.Terminal, Epsilon, right.Initial) }) )); }
/// <summary> /// Returns a clone of the supplied <see cref="PartialNFA"/> /// where each state is replaced with a new state and all transitions are mapped /// across to use the new states /// </summary> /// <param name="partial"><see cref="PartialNFA"/> /// to be cloned</param> /// <returns></returns> public PartialNFA Clone( PartialNFA partial) { var map = Enumerable.Union( partial.Transitions.Select(t => t.Source), partial.Transitions.Select(t => t.Target) ).Distinct().ToDictionary(s => s, s => State()); return(new PartialNFA( map[partial.Initial], map[partial.Terminal], partial.Transitions.Select(t => Transition(map[t.Source], t.Input, map[t.Target])) )); }
/// <summary> /// Returns a <see cref="PartialNFA"/> constructed /// to make the inner partial optional using the Kleene star expression /// </summary> /// <param name="inner">Inner partial NFA to make optional</param> /// <returns></returns> public PartialNFA OptionalRepeating(PartialNFA inner) { var initial = State(); var terminal = State(); return(new PartialNFA( initial, terminal, inner.Transitions .Union(new[] { Transition(initial, Epsilon, inner.Initial), Transition(initial, Epsilon, terminal), Transition(inner.Terminal, Epsilon, terminal), Transition(inner.Terminal, Epsilon, inner.Initial), }) )); }
/// <summary> /// Returns a <see cref="PartialNFA"/> constructed /// to give alternative routes between the left and right partials with epsilon /// transitions from the new initial to the partial initials, and from the partial /// terminals to the new terminal /// </summary> /// <param name="left">Left partial NFA</param> /// <param name="right">Right partial NFA</param>s /// <returns></returns> public PartialNFA Alternative(PartialNFA left, PartialNFA right) { var initial = State(); var terminal = State(); return(new PartialNFA( initial, terminal, left.Transitions .Union(right.Transitions) .Union(new[] { Transition(initial, Epsilon, left.Initial), Transition(initial, Epsilon, right.Initial), Transition(left.Terminal, Epsilon, terminal), Transition(right.Terminal, Epsilon, terminal), }) )); }
/// <summary> /// Returns a <see cref="PartialNFA"/> constructed /// to optionally match the inner partial /// </summary> /// <param name="inner"></param> /// <returns></returns> public PartialNFA Optional(PartialNFA inner) => Alternative(inner, Input(Epsilon));
/// <summary> /// Returns a <see cref="PartialNFA"/> constructed /// to match one or more instances of the inner partial /// </summary> /// <param name="inner"></param> /// <returns></returns> public PartialNFA RequiredRepeating(PartialNFA inner) => Concatenation(inner, OptionalRepeating(Clone(inner)));