public DfaMatchingState <TSetType> TakeTransition( SymbolicRegexMatcher <TSetType> matcher, DfaMatchingState <TSetType> currentStates, int mintermId, TSetType minterm) { if (currentStates.Node.Kind != SymbolicRegexKind.Or) { // Fall back to Brzozowski when the state is not a disjunction. return(default(BrzozowskiTransition).TakeTransition(matcher, currentStates, mintermId, minterm)); } SymbolicRegexBuilder <TSetType> builder = matcher._builder; Debug.Assert(builder._delta is not null); SymbolicRegexNode <TSetType> union = builder._nothing; uint kind = 0; // Produce the new list of states from the current list, considering transitions from members one at a time. Debug.Assert(currentStates.Node._alts is not null); foreach (SymbolicRegexNode <TSetType> oneState in currentStates.Node._alts) { DfaMatchingState <TSetType> nextStates = builder.MkState(oneState, currentStates.PrevCharKind); int offset = (nextStates.Id << builder._mintermsCount) | mintermId; DfaMatchingState <TSetType> p = Volatile.Read(ref builder._delta[offset]) ?? matcher.CreateNewTransition(nextStates, minterm, offset); // Observe that if p.Node is an Or it will be flattened. union = builder.MkOr2(union, p.Node); // kind is just the kind of the partition. kind = p.PrevCharKind; } return(builder.MkState(union, kind, true)); }
/// <summary>Initializes the factory.</summary> public SymbolicRegexRunnerFactory(RegexTree regexTree, RegexOptions options, TimeSpan matchTimeout) { Debug.Assert((options & (RegexOptions.RightToLeft | RegexOptions.ECMAScript)) == 0); var charSetSolver = new CharSetSolver(); var bddBuilder = new SymbolicRegexBuilder <BDD>(charSetSolver, charSetSolver); var converter = new RegexNodeConverter(bddBuilder, regexTree.CaptureNumberSparseMapping); SymbolicRegexNode <BDD> rootNode = converter.ConvertToSymbolicRegexNode(regexTree.Root); // Determine if the root node is supported for safe handling int threshold = SymbolicRegexThresholds.GetSymbolicRegexSafeSizeThreshold(); Debug.Assert(threshold > 0); // Skip the threshold check if the threshold equals int.MaxValue if (threshold != int.MaxValue) { int size = rootNode.EstimateNfaSize(); if (size > threshold) { throw new NotSupportedException(SR.Format(SR.NotSupported_NonBacktrackingUnsafeSize, size, threshold)); } } rootNode = rootNode.AddFixedLengthMarkers(); BDD[] minterms = rootNode.ComputeMinterms(); _matcher = minterms.Length > 64 ? SymbolicRegexMatcher <BitVector> .Create(regexTree.CaptureCount, regexTree.FindOptimizations, bddBuilder, rootNode, new BitVectorSolver(minterms, charSetSolver), matchTimeout) : SymbolicRegexMatcher <ulong> .Create(regexTree.CaptureCount, regexTree.FindOptimizations, bddBuilder, rootNode, new UInt64Solver(minterms, charSetSolver), matchTimeout); }
static string FormatInfo(SymbolicRegexMatcher <TSet> matcher, int transitionCount) { StringBuilder sb = new(); sb.Append($"States = {matcher._stateCache.Count} "); sb.Append($"Transitions = {transitionCount} "); sb.Append($"Min Terms ({matcher.Solver.GetMinterms()!.Length}) = ").AppendJoin(',', DescribeLabels(matcher.Solver.GetMinterms() !, matcher._builder)); return(sb.ToString()); }
public DfaMatchingState <TSetType> TakeTransition( SymbolicRegexMatcher <TSetType> matcher, DfaMatchingState <TSetType> currentState, int mintermId, TSetType minterm) { SymbolicRegexBuilder <TSetType> builder = matcher._builder; Debug.Assert(builder._delta is not null); int offset = (currentState.Id << builder._mintermsCount) | mintermId; return(Volatile.Read(ref builder._delta[offset]) ?? matcher.CreateNewTransition(currentState, minterm, offset)); }
/// <summary>Initializes the factory.</summary> public SymbolicRegexRunnerFactory(RegexCode code, RegexOptions options, TimeSpan matchTimeout, CultureInfo culture) { // RightToLeft and ECMAScript are currently not supported in conjunction with NonBacktracking. if ((options & (RegexOptions.RightToLeft | RegexOptions.ECMAScript)) != 0) { throw new NotSupportedException( SR.Format(SR.NotSupported_NonBacktrackingConflictingOption, (options & RegexOptions.RightToLeft) != 0 ? nameof(RegexOptions.RightToLeft) : nameof(RegexOptions.ECMAScript))); } var converter = new RegexNodeToSymbolicConverter(s_unicode, culture); var solver = (CharSetSolver)s_unicode._solver; SymbolicRegexNode <BDD> root = converter.Convert(code.Tree.Root, topLevel: true); _minRequiredLength = code.Tree.MinRequiredLength; BDD[] minterms = root.ComputeMinterms(); if (minterms.Length > 64) { // Use BV to represent a predicate var algBV = new BVAlgebra(solver, minterms); var builderBV = new SymbolicRegexBuilder <BV>(algBV); // The default constructor sets the following predicates to False; this update happens after the fact. // It depends on whether anchors where used in the regex whether the predicates are actually different from False. builderBV._wordLetterPredicateForAnchors = algBV.ConvertFromCharSet(solver, converter._builder._wordLetterPredicateForAnchors); builderBV._newLinePredicate = algBV.ConvertFromCharSet(solver, converter._builder._newLinePredicate); //Convert the BDD based AST to BV based AST SymbolicRegexNode <BV> rootBV = converter._builder.Transform(root, builderBV, bdd => builderBV._solver.ConvertFromCharSet(solver, bdd)); _matcher = new SymbolicRegexMatcher <BV>(rootBV, solver, minterms, matchTimeout, culture); } else { // Use ulong to represent a predicate var alg64 = new BV64Algebra(solver, minterms); var builder64 = new SymbolicRegexBuilder <ulong>(alg64) { // The default constructor sets the following predicates to False, this update happens after the fact // It depends on whether anchors where used in the regex whether the predicates are actually different from False _wordLetterPredicateForAnchors = alg64.ConvertFromCharSet(solver, converter._builder._wordLetterPredicateForAnchors), _newLinePredicate = alg64.ConvertFromCharSet(solver, converter._builder._newLinePredicate) }; // Convert the BDD-based AST to ulong-based AST SymbolicRegexNode <ulong> root64 = converter._builder.Transform(root, builder64, bdd => builder64._solver.ConvertFromCharSet(solver, bdd)); _matcher = new SymbolicRegexMatcher <ulong>(root64, solver, minterms, matchTimeout, culture); } }
static IEnumerable <MatchingState <TSet> > GetInitialStates(SymbolicRegexMatcher <TSet> matcher) { foreach (MatchingState <TSet> state in matcher._dotstarredInitialStates) { yield return(state); } foreach (MatchingState <TSet> state in matcher._initialStates) { yield return(state); } foreach (MatchingState <TSet> state in matcher._reverseInitialStates) { yield return(state); } }
/// <summary>Initializes the factory.</summary> public SymbolicRegexRunnerFactory(RegexTree regexTree, RegexOptions options, TimeSpan matchTimeout, CultureInfo culture) { Debug.Assert((options & (RegexOptions.RightToLeft | RegexOptions.ECMAScript)) == 0); var bddBuilder = new SymbolicRegexBuilder <BDD>(CharSetSolver.Instance); var converter = new RegexNodeConverter(bddBuilder, culture, regexTree.CaptureNumberSparseMapping); SymbolicRegexNode <BDD> rootNode = converter.ConvertToSymbolicRegexNode(regexTree.Root, tryCreateFixedLengthMarker: true); BDD[] minterms = rootNode.ComputeMinterms(); _matcher = minterms.Length > 64 ? SymbolicRegexMatcher <BitVector> .Create(regexTree.CaptureCount, regexTree.FindOptimizations, bddBuilder, rootNode, new BitVectorAlgebra(minterms), matchTimeout) : SymbolicRegexMatcher <ulong> .Create(regexTree.CaptureCount, regexTree.FindOptimizations, bddBuilder, rootNode, new UInt64Algebra(minterms), matchTimeout); }
/// <summary>Initializes the factory.</summary> public SymbolicRegexRunnerFactory(RegexTree regexTree, RegexOptions options, TimeSpan matchTimeout, CultureInfo culture) { // RightToLeft and ECMAScript are currently not supported in conjunction with NonBacktracking. if ((options & (RegexOptions.RightToLeft | RegexOptions.ECMAScript)) != 0) { throw new NotSupportedException( SR.Format(SR.NotSupported_NonBacktrackingConflictingOption, (options & RegexOptions.RightToLeft) != 0 ? nameof(RegexOptions.RightToLeft) : nameof(RegexOptions.ECMAScript))); } var converter = new RegexNodeConverter(culture, regexTree.CaptureNumberSparseMapping); CharSetSolver solver = CharSetSolver.Instance; SymbolicRegexNode <BDD> root = converter.ConvertToSymbolicRegexNode(regexTree.Root, tryCreateFixedLengthMarker: true); BDD[] minterms = root.ComputeMinterms(); if (minterms.Length > 64) { // Use BitVector to represent a predicate var algebra = new BitVectorAlgebra(solver, minterms); var builder = new SymbolicRegexBuilder <BitVector>(algebra) { // The default constructor sets the following predicates to False; this update happens after the fact. // It depends on whether anchors where used in the regex whether the predicates are actually different from False. _wordLetterPredicateForAnchors = algebra.ConvertFromCharSet(solver, converter._builder._wordLetterPredicateForAnchors), _newLinePredicate = algebra.ConvertFromCharSet(solver, converter._builder._newLinePredicate) }; // Convert the BDD-based AST to BitVector-based AST SymbolicRegexNode <BitVector> rootNode = converter._builder.Transform(root, builder, bdd => builder._solver.ConvertFromCharSet(solver, bdd)); _matcher = new SymbolicRegexMatcher <BitVector>(rootNode, regexTree, minterms, matchTimeout); } else { // Use ulong to represent a predicate var algebra = new BitVector64Algebra(solver, minterms); var builder = new SymbolicRegexBuilder <ulong>(algebra) { // The default constructor sets the following predicates to False, this update happens after the fact // It depends on whether anchors where used in the regex whether the predicates are actually different from False _wordLetterPredicateForAnchors = algebra.ConvertFromCharSet(solver, converter._builder._wordLetterPredicateForAnchors), _newLinePredicate = algebra.ConvertFromCharSet(solver, converter._builder._newLinePredicate) }; // Convert the BDD-based AST to ulong-based AST SymbolicRegexNode <ulong> rootNode = converter._builder.Transform(root, builder, bdd => builder._solver.ConvertFromCharSet(solver, bdd)); _matcher = new SymbolicRegexMatcher <ulong>(rootNode, regexTree, minterms, matchTimeout); } }
/// <summary>Initializes the factory.</summary> public SymbolicRegexRunnerFactory(RegexTree regexTree, RegexOptions options, TimeSpan matchTimeout) { Debug.Assert((options & (RegexOptions.RightToLeft | RegexOptions.ECMAScript)) == 0); var charSetSolver = new CharSetSolver(); var bddBuilder = new SymbolicRegexBuilder <BDD>(charSetSolver, charSetSolver); var converter = new RegexNodeConverter(bddBuilder, regexTree.CaptureNumberSparseMapping); SymbolicRegexNode <BDD> rootNode = converter.ConvertToSymbolicRegexNode(regexTree.Root); BDD[] minterms = rootNode.ComputeMinterms(); _matcher = minterms.Length > 64 ? SymbolicRegexMatcher <BitVector> .Create(regexTree.CaptureCount, regexTree.FindOptimizations, bddBuilder, rootNode, new BitVectorSolver(minterms, charSetSolver), matchTimeout) : SymbolicRegexMatcher <ulong> .Create(regexTree.CaptureCount, regexTree.FindOptimizations, bddBuilder, rootNode, new UInt64Solver(minterms, charSetSolver), matchTimeout); }
private SymbolicRegexRunner(RegexCode code, TimeSpan matchTimeout, CultureInfo culture) { var converter = new RegexNodeToSymbolicConverter(s_unicode, culture); var solver = (CharSetSolver)s_unicode._solver; SymbolicRegexNode <BDD> root = converter.Convert(code.Tree.Root, topLevel: true); _minRequiredLength = code.Tree.MinRequiredLength; BDD[] minterms = root.ComputeMinterms(); if (minterms.Length > 64) { // Use BV to represent a predicate var algBV = new BVAlgebra(solver, minterms); var builderBV = new SymbolicRegexBuilder <BV>(algBV); // The default constructor sets the following predicates to False; this update happens after the fact. // It depends on whether anchors where used in the regex whether the predicates are actually different from False. builderBV._wordLetterPredicateForAnchors = algBV.ConvertFromCharSet(solver, converter._builder._wordLetterPredicateForAnchors); builderBV._newLinePredicate = algBV.ConvertFromCharSet(solver, converter._builder._newLinePredicate); //Convert the BDD based AST to BV based AST SymbolicRegexNode <BV> rootBV = converter._builder.Transform(root, builderBV, bdd => builderBV._solver.ConvertFromCharSet(solver, bdd)); _matcher = new SymbolicRegexMatcher <BV>(rootBV, solver, minterms, matchTimeout, culture); } else { // Use ulong to represent a predicate var alg64 = new BV64Algebra(solver, minterms); var builder64 = new SymbolicRegexBuilder <ulong>(alg64) { // The default constructor sets the following predicates to False, this update happens after the fact // It depends on whether anchors where used in the regex whether the predicates are actually different from False _wordLetterPredicateForAnchors = alg64.ConvertFromCharSet(solver, converter._builder._wordLetterPredicateForAnchors), _newLinePredicate = alg64.ConvertFromCharSet(solver, converter._builder._newLinePredicate) }; // Convert the BDD-based AST to ulong-based AST SymbolicRegexNode <ulong> root64 = converter._builder.Transform(root, builder64, bdd => builder64._solver.ConvertFromCharSet(solver, bdd)); _matcher = new SymbolicRegexMatcher <ulong>(root64, solver, minterms, matchTimeout, culture); } }
/// <summary>Write the DFA or NFA in DGML format into the TextWriter.</summary> /// <param name="matcher">The <see cref="SymbolicRegexMatcher"/> for the regular expression.</param> /// <param name="writer">Writer to which the DGML is written.</param> /// <param name="nfa">True to create an NFA instead of a DFA.</param> /// <param name="addDotStar">True to prepend .*? onto the pattern (outside of the implicit root capture).</param> /// <param name="reverse">If true, then unwind the regex backwards (and <paramref name="addDotStar"/> is ignored).</param> /// <param name="maxStates">The approximate maximum number of states to include; less than or equal to 0 for no maximum.</param> /// <param name="maxLabelLength">maximum length of labels in nodes anything over that length is indicated with .. </param> public static void Write( TextWriter writer, SymbolicRegexMatcher <TSet> matcher, bool nfa = false, bool addDotStar = true, bool reverse = false, int maxStates = -1, int maxLabelLength = -1) { var charSetSolver = new CharSetSolver(); var explorer = new DfaExplorer(matcher, nfa, addDotStar, reverse, maxStates); var nonEpsilonTransitions = new Dictionary <(int SourceState, int TargetState), List <(SymbolicRegexNode <TSet>?, TSet)> >(); var epsilonTransitions = new List <Transition>(); foreach (Transition transition in explorer.GetTransitions()) { if (transition.IsEpsilon) { epsilonTransitions.Add(transition); } else { (int SourceState, int TargetState)p = (transition.SourceState, transition.TargetState); if (!nonEpsilonTransitions.TryGetValue(p, out List <(SymbolicRegexNode <TSet>?, TSet)>?rules)) { nonEpsilonTransitions[p] = rules = new List <(SymbolicRegexNode <TSet>?, TSet)>(); } rules.Add(transition.Label); } } writer.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); writer.WriteLine("<DirectedGraph xmlns=\"http://schemas.microsoft.com/vs/2009/dgml\" ZoomLevel=\"1.5\" GraphDirection=\"TopToBottom\" >"); writer.WriteLine(" <Nodes>"); writer.WriteLine(" <Node Id=\"dfa\" Label=\" \" Group=\"Collapsed\" Category=\"DFA\" DFAInfo=\"{0}\" />", GetDFAInfo(explorer, charSetSolver)); writer.WriteLine(" <Node Id=\"dfainfo\" Category=\"DFAInfo\" Label=\"{0}\"/>", GetDFAInfo(explorer, charSetSolver)); foreach (int state in explorer.GetStates()) { writer.WriteLine(" <Node Id=\"{0}\" Label=\"{0}\" Category=\"State\" Group=\"Collapsed\" StateInfo=\"{1}\">", state, explorer.DescribeState(state)); if (state == explorer.InitialState) { writer.WriteLine(" <Category Ref=\"InitialState\" />"); } if (explorer.IsFinalState(state)) { writer.WriteLine(" <Category Ref=\"FinalState\" />"); } writer.WriteLine(" </Node>"); writer.WriteLine(" <Node Id=\"{0}info\" Label=\"{1}\" Category=\"StateInfo\"/>", state, explorer.DescribeState(state)); } writer.WriteLine(" </Nodes>"); writer.WriteLine(" <Links>"); writer.WriteLine(" <Link Source=\"dfa\" Target=\"{0}\" Label=\"\" Category=\"StartTransition\" />", explorer.InitialState); writer.WriteLine(" <Link Source=\"dfa\" Target=\"dfainfo\" Label=\"\" Category=\"Contains\" />"); foreach (Transition transition in epsilonTransitions) { writer.WriteLine(" <Link Source=\"{0}\" Target=\"{1}\" Category=\"EpsilonTransition\" />", transition.SourceState, transition.TargetState); } foreach (KeyValuePair <(int, int), List <(SymbolicRegexNode <TSet>?, TSet)> > transition in nonEpsilonTransitions) { string label = string.Join($",{Environment.NewLine} ", DescribeLabels(explorer, transition.Value, charSetSolver)); string info = ""; if (label.Length > (uint)maxLabelLength) { info = $"FullLabel = \"{label}\" "; label = string.Concat(label.AsSpan(0, maxLabelLength), ".."); } writer.WriteLine($" <Link Source=\"{transition.Key.Item1}\" Target=\"{transition.Key.Item2}\" Label=\"{label}\" Category=\"NonEpsilonTransition\" {info}/>"); } foreach (int state in explorer.GetStates()) { writer.WriteLine(" <Link Source=\"{0}\" Target=\"{0}info\" Category=\"Contains\" />", state); } writer.WriteLine(" </Links>"); writer.WriteLine(" <Categories>"); writer.WriteLine(" <Category Id=\"DFA\" Label=\"DFA\" IsTag=\"True\" />"); writer.WriteLine(" <Category Id=\"EpsilonTransition\" Label=\"Epsilon transition\" IsTag=\"True\" />"); writer.WriteLine(" <Category Id=\"StartTransition\" Label=\"Initial transition\" IsTag=\"True\" />"); writer.WriteLine(" <Category Id=\"FinalLabel\" Label=\"Final transition\" IsTag=\"True\" />"); writer.WriteLine(" <Category Id=\"FinalState\" Label=\"Final\" IsTag=\"True\" />"); writer.WriteLine(" <Category Id=\"SinkState\" Label=\"Sink state\" IsTag=\"True\" />"); writer.WriteLine(" <Category Id=\"EpsilonState\" Label=\"Epsilon state\" IsTag=\"True\" />"); writer.WriteLine(" <Category Id=\"InitialState\" Label=\"Initial\" IsTag=\"True\" />"); writer.WriteLine(" <Category Id=\"NonEpsilonTransition\" Label=\"Nonepsilon transition\" IsTag=\"True\" />"); writer.WriteLine(" <Category Id=\"State\" Label=\"State\" IsTag=\"True\" />"); writer.WriteLine(" </Categories>"); writer.WriteLine(" <Styles>"); writer.WriteLine(" <Style TargetType=\"Node\" GroupLabel=\"InitialState\" ValueLabel=\"True\">"); writer.WriteLine(" <Condition Expression=\"HasCategory('InitialState')\" />"); writer.WriteLine(" <Setter Property=\"Background\" Value=\"lightgray\" />"); writer.WriteLine(" <Setter Property=\"MinWidth\" Value=\"0\" />"); writer.WriteLine(" </Style>"); writer.WriteLine(" <Style TargetType=\"Node\" GroupLabel=\"FinalState\" ValueLabel=\"True\">"); writer.WriteLine(" <Condition Expression=\"HasCategory('FinalState')\" />"); writer.WriteLine(" <Setter Property=\"Background\" Value=\"lightgreen\" />"); writer.WriteLine(" <Setter Property=\"StrokeThickness\" Value=\"4\" />"); writer.WriteLine(" </Style>"); writer.WriteLine(" <Style TargetType=\"Node\" GroupLabel=\"State\" ValueLabel=\"True\">"); writer.WriteLine(" <Condition Expression=\"HasCategory('State')\" />"); writer.WriteLine(" <Setter Property=\"Stroke\" Value=\"black\" />"); writer.WriteLine(" <Setter Property=\"Background\" Value=\"white\" />"); writer.WriteLine(" <Setter Property=\"MinWidth\" Value=\"0\" />"); writer.WriteLine(" <Setter Property=\"FontSize\" Value=\"12\" />"); writer.WriteLine(" <Setter Property=\"FontFamily\" Value=\"Arial\" />"); writer.WriteLine(" </Style>"); writer.WriteLine(" <Style TargetType=\"Link\" GroupLabel=\"NonEpsilonTransition\" ValueLabel=\"True\">"); writer.WriteLine(" <Condition Expression=\"HasCategory('NonEpsilonTransition')\" />"); writer.WriteLine(" <Setter Property=\"Stroke\" Value=\"black\" />"); writer.WriteLine(" <Setter Property=\"FontSize\" Value=\"18\" />"); writer.WriteLine(" <Setter Property=\"FontFamily\" Value=\"Arial\" />"); writer.WriteLine(" </Style>"); writer.WriteLine(" <Style TargetType=\"Link\" GroupLabel=\"StartTransition\" ValueLabel=\"True\">"); writer.WriteLine(" <Condition Expression=\"HasCategory('StartTransition')\" />"); writer.WriteLine(" <Setter Property=\"Stroke\" Value=\"black\" />"); writer.WriteLine(" </Style>"); writer.WriteLine(" <Style TargetType=\"Link\" GroupLabel=\"EpsilonTransition\" ValueLabel=\"True\">"); writer.WriteLine(" <Condition Expression=\"HasCategory('EpsilonTransition')\" />"); writer.WriteLine(" <Setter Property=\"Stroke\" Value=\"black\" />"); writer.WriteLine(" <Setter Property=\"StrokeDashArray\" Value=\"8 8\" />"); writer.WriteLine(" </Style>"); writer.WriteLine(" <Style TargetType=\"Link\" GroupLabel=\"FinalLabel\" ValueLabel=\"False\">"); writer.WriteLine(" <Condition Expression=\"HasCategory('FinalLabel')\" />"); writer.WriteLine(" <Setter Property=\"Stroke\" Value=\"black\" />"); writer.WriteLine(" <Setter Property=\"StrokeDashArray\" Value=\"8 8\" />"); writer.WriteLine(" </Style>"); writer.WriteLine(" <Style TargetType=\"Node\" GroupLabel=\"StateInfo\" ValueLabel=\"True\">"); writer.WriteLine(" <Setter Property=\"Stroke\" Value=\"white\" />"); writer.WriteLine(" <Setter Property=\"FontSize\" Value=\"18\" />"); writer.WriteLine(" <Setter Property=\"FontFamily\" Value=\"Arial\" />"); writer.WriteLine(" </Style>"); writer.WriteLine(" <Style TargetType=\"Node\" GroupLabel=\"DFAInfo\" ValueLabel=\"True\">"); writer.WriteLine(" <Setter Property=\"Stroke\" Value=\"white\" />"); writer.WriteLine(" <Setter Property=\"FontSize\" Value=\"18\" />"); writer.WriteLine(" <Setter Property=\"FontFamily\" Value=\"Arial\" />"); writer.WriteLine(" </Style>"); writer.WriteLine(" </Styles>"); writer.WriteLine("</DirectedGraph>"); }
internal Runner(SymbolicRegexMatcher <TSet> matcher) { _matcher = matcher; _perThreadData = matcher.CreatePerThreadData(); }
// This function gathers all transitions in the given builder and groups them by (source,destination) state ID static Dictionary <(int Source, int Target), (TSet Rule, List <int> NfaTargets)> GatherTransitions(SymbolicRegexMatcher <TSet> matcher) { Dictionary <(int Source, int Target), (TSet Rule, List <int> NfaTargets)> result = new(); foreach (MatchingState <TSet> source in matcher._stateCache.Values) { // Get the span of entries in delta that gives the transitions for the different minterms Span <int> deltas = matcher.GetDeltasFor(source); Span <int[]?> nfaDeltas = matcher.GetNfaDeltasFor(source); Debug.Assert(deltas.Length == matcher._minterms.Length); for (int i = 0; i < deltas.Length; ++i) { // negative entries are transitions not explored yet, so skip them int targetId = deltas[i]; if (targetId >= 0) { // Get or create the data for this (source,destination) state ID pair (int Source, int Target)key = (source.Id, targetId); if (!result.TryGetValue(key, out (TSet Rule, List <int> NfaTargets)entry)) { entry = (matcher.Solver.Empty, new List <int>()); } // If this state has an NFA transition for the same minterm, then associate // those with the transition. if (nfaDeltas.Length > 0 && nfaDeltas[i] is int[] nfaTargets) { foreach (int nfaTarget in nfaTargets) { entry.NfaTargets.Add(matcher._nfaCoreIdArray[nfaTarget]); } } // Expand the rule for this minterm result[key] = (matcher.Solver.Or(entry.Rule, matcher._minterms[i]), entry.NfaTargets); } } } return(result); }
#pragma warning disable CA2252 // This API requires opting into preview features /// <summary>Find the next state given the current state and next character.</summary> static abstract DfaMatchingState <TSetType> TakeTransition(SymbolicRegexMatcher <TSetType> matcher, DfaMatchingState <TSetType> currentState, int mintermId, TSetType minterm);
internal Runner(SymbolicRegexMatcher <TSetType> matcher) => _matcher = matcher;
internal Runner(SymbolicRegexMatcher matcher, int minRequiredLength) { _matcher = matcher; _minRequiredLength = minRequiredLength; }