Пример #1
0
            /// <summary>Enumerates all the paths in this transition excluding paths to dead-ends (and unexplored states if any)</summary>
            internal IEnumerable <(S, SymbolicRegexNode <S>?, int)> EnumeratePaths(IBooleanAlgebra <S> solver, S pathCondition)
            {
                switch (_kind)
                {
                case TransitionRegexKind.Leaf:
                    // Omit any path that leads to a deadend or is unexplored
                    if (_leaf >= 0)
                    {
                        yield return(pathCondition, null, _leaf);
                    }
                    break;

                case TransitionRegexKind.Union:
                    Debug.Assert(_first is not null && _second is not null);
                    foreach ((S, SymbolicRegexNode <S>?, int)path in _first.EnumeratePaths(solver, pathCondition))
                    {
                        yield return(path);
                    }
                    foreach ((S, SymbolicRegexNode <S>?, int)path in _second.EnumeratePaths(solver, pathCondition))
                    {
                        yield return(path);
                    }
                    break;

                case TransitionRegexKind.Conditional:
                    Debug.Assert(_test is not null && _first is not null && _second is not null);
                    foreach ((S, SymbolicRegexNode <S>?, int)path in _first.EnumeratePaths(solver, solver.And(pathCondition, _test)))
                    {
                        yield return(path);
                    }
                    foreach ((S, SymbolicRegexNode <S>?, int)path in _second.EnumeratePaths(solver, solver.And(pathCondition, solver.Not(_test))))
                    {
                        yield return(path);
                    }
                    break;

                default:
                    Debug.Assert(_kind is TransitionRegexKind.Lookaround && _look is not null && _first is not null && _second is not null);
                    foreach ((S, SymbolicRegexNode <S>?, int)path in _first.EnumeratePaths(solver, pathCondition))
                    {
                        SymbolicRegexNode <S> nullabilityTest = path.Item2 is null ? _look : _look._builder.MkAnd(path.Item2, _look);
                        yield return(path.Item1, nullabilityTest, path.Item3);
                    }
                    foreach ((S, SymbolicRegexNode <S>?, int)path in _second.EnumeratePaths(solver, pathCondition))
                    {
                        // Complement the nullability test
                        SymbolicRegexNode <S> nullabilityTest = path.Item2 is null?_look._builder.MkNot(_look) : _look._builder.MkAnd(path.Item2, _look._builder.MkNot(_look));

                        yield return(path.Item1, nullabilityTest, path.Item3);
                    }
                    break;
                }
            }
Пример #2
0
        /// <summary>Enumerates all target states from the given source state</summary>
        /// <param name="sourceState">must be a an integer between 0 and StateCount-1</param>
        /// <param name="input">must be a value that acts as a minterm for the transitions emanating from the source state</param>
        /// <param name="context">reflects the immediate surrounding of the input and is used to determine nullability of anchors</param>
        public IEnumerable <int> EnumerateTargetStates(int sourceState, S input, uint context)
        {
            Debug.Assert(sourceState >= 0 && sourceState < _transitionFunction.Length);

            // First operate in a mode assuming no Union happens by finding the target leaf state if one exists
            Transition transition = _transitionFunction[sourceState];

            while (transition._kind != TransitionRegexKind.Union)
            {
                switch (transition._kind)
                {
                case TransitionRegexKind.Leaf:
                    // deadend and unexplored are negative
                    if (transition._leaf >= 0)
                    {
                        Debug.Assert(transition._leaf < _transitionFunction.Length);
                        yield return(transition._leaf);
                    }
                    // The single target (or no target) state was found, so exit the whole enumeration
                    yield break;

                case TransitionRegexKind.Conditional:
                    Debug.Assert(transition._test is not null && transition._first is not null && transition._second is not null);
                    // Branch according to the input condition in relation to the test condition
                    if (_solver.IsSatisfiable(_solver.And(input, transition._test)))
                    {
                        // in a conditional transition input must be exclusive
                        Debug.Assert(!_solver.IsSatisfiable(_solver.And(input, _solver.Not(transition._test))));
                        transition = transition._first;
                    }
                    else
                    {
                        transition = transition._second;
                    }
                    break;

                default:
                    Debug.Assert(transition._kind == TransitionRegexKind.Lookaround && transition._look is not null && transition._first is not null && transition._second is not null);
                    // Branch according to nullability of the lookaround condition in the given context
                    transition = transition._look.IsNullableFor(context) ?
                                 transition._first :
                                 transition._second;
                    break;
                }
            }

            // Continue operating in a mode where several target states can be yielded
            Debug.Assert(transition._first is not null && transition._second is not null);
            Stack <Transition> todo = new();

            todo.Push(transition._second);
            todo.Push(transition._first);
            while (todo.TryPop(out _))
            {
                switch (transition._kind)
                {
                case TransitionRegexKind.Leaf:
                    // dead-end
                    if (transition._leaf >= 0)
                    {
                        Debug.Assert(transition._leaf < _transitionFunction.Length);
                        yield return(transition._leaf);
                    }
                    break;

                case TransitionRegexKind.Conditional:
                    Debug.Assert(transition._test is not null && transition._first is not null && transition._second is not null);
                    // Branch according to the input condition in relation to the test condition
                    if (_solver.IsSatisfiable(_solver.And(input, transition._test)))
                    {
                        // in a conditional transition input must be exclusive
                        Debug.Assert(!_solver.IsSatisfiable(_solver.And(input, _solver.Not(transition._test))));
                        todo.Push(transition._first);
                    }
                    else
                    {
                        todo.Push(transition._second);
                    }
                    break;

                case TransitionRegexKind.Lookaround:
                    Debug.Assert(transition._look is not null && transition._first is not null && transition._second is not null);
                    // Branch according to nullability of the lookaround condition in the given context
                    todo.Push(transition._look.IsNullableFor(context) ? transition._first : transition._second);
                    break;


                default:
                    Debug.Assert(transition._kind == TransitionRegexKind.Union && transition._first is not null && transition._second is not null);
                    todo.Push(transition._second);
                    todo.Push(transition._first);
                    break;
                }
            }
        }