X-Git-Url: https://scripts.mit.edu/gitweb/autoinstallsdev/mediawiki.git/blobdiff_plain/19e297c21b10b1b8a3acad5e73fc71dcb35db44a..6932310fd58ebef145fa01eb76edf7150284d8ea:/vendor/wikimedia/css-sanitizer/src/Grammar/UnorderedGroup.php diff --git a/vendor/wikimedia/css-sanitizer/src/Grammar/UnorderedGroup.php b/vendor/wikimedia/css-sanitizer/src/Grammar/UnorderedGroup.php new file mode 100644 index 00000000..9152e906 --- /dev/null +++ b/vendor/wikimedia/css-sanitizer/src/Grammar/UnorderedGroup.php @@ -0,0 +1,124 @@ +matchers = $matchers; + $this->all = (bool)$all; + } + + /** + * Implements "&&": All of the options, in any order + * @param Matcher[] $matchers + * @return static + */ + public static function allOf( array $matchers ) { + return new static( $matchers, true ); + } + + /** + * Implements "||": One or more of the options, in any order + * @param Matcher[] $matchers + * @return static + */ + public static function someOf( array $matchers ) { + return new static( $matchers, false ); + } + + protected function generateMatches( ComponentValueList $values, $start, array $options ) { + $used = []; + + // As each Matcher is used, push it onto the stack along with the set + // of remaining matchers. + $stack = [ + [ + new Match( $values, $start, 0 ), + $this->matchers, + new \ArrayIterator( $this->matchers ), + null, + new \EmptyIterator + ] + ]; + do { + /** @var $lastMatch Match */ + /** @var $matchers Matcher[] */ + /** @var $matcherIter \Iterator */ + /** @var $curMatcher Matcher|null */ + /** @var $iter \Iterator */ + list( $lastMatch, $matchers, $matcherIter, $curMatcher, $iter ) = $stack[count( $stack ) - 1]; + + // If the top of the stack has more matches, process the next one. + if ( $iter->valid() ) { + $match = $iter->current(); + $iter->next(); + + // If we have unused matchers to try after this one, do so. + // Otherwise yield and continue with the current one. + if ( $matchers ) { + $stack[] = [ $match, $matchers, new \ArrayIterator( $matchers ), null, new \EmptyIterator ]; + } else { + $newMatch = $this->makeMatch( $values, $start, $match->getNext(), $match, $stack ); + $mid = $newMatch->getUniqueID(); + if ( !isset( $used[$mid] ) ) { + $used[$mid] = 1; + yield $newMatch; + } + } + continue; + } + + // We ran out of matches for the current top of the stack. Pop it, + // and put $curMatcher back into $matchers so it can be tried again + // at a later position. + array_pop( $stack ); + if ( $curMatcher ) { + $matchers[$matcherIter->key()] = $curMatcher; + $matcherIter->next(); + } + + $fromPos = $lastMatch->getNext(); + + // If there are more matchers to try, pull the next one out of + // $matchers and try it at the current position. Otherwise, maybe + // yield the current position and backtrack. + if ( $matcherIter->valid() ) { + $curMatcher = $matcherIter->current(); + unset( $matchers[$matcherIter->key()] ); + $iter = $curMatcher->generateMatches( $values, $fromPos, $options ); + $stack[] = [ $lastMatch, $matchers, $matcherIter, $curMatcher, $iter ]; + } else { + if ( $stack && !$this->all ) { + $newMatch = $this->makeMatch( $values, $start, $fromPos, $lastMatch, $stack ); + $mid = $newMatch->getUniqueID(); + if ( !isset( $used[$mid] ) ) { + $used[$mid] = 1; + yield $newMatch; + } + } + } + } while ( $stack ); + } +}