pokemon-showdown-client/lib/css-sanitizer/Wikimedia/CSS/Grammar/GrammarMatch.php
2023-06-16 11:33:53 -07:00

152 lines
3.8 KiB
PHP

<?php
/**
* @file
* @license https://opensource.org/licenses/Apache-2.0 Apache-2.0
*/
namespace Wikimedia\CSS\Grammar;
use Wikimedia\CSS\Objects\ComponentValue;
use Wikimedia\CSS\Objects\ComponentValueList;
use Wikimedia\CSS\Objects\Token;
use Wikimedia\CSS\Util;
/**
* Represent a match from a Matcher.
*/
class GrammarMatch {
/** @var int */
protected $start;
/** @var int */
protected $length;
/** @var ComponentValue[] Matched ComponentValues */
protected $values;
/** @var string|null */
protected $name = null;
/** @var GrammarMatch[] Captured submatches */
protected $capturedMatches = [];
/**
* @param ComponentValueList $list List containing the match
* @param int $start Starting index of the match.
* @param int $length Number of tokens in the match.
* @param string|null $name Give a name to this match.
* @param GrammarMatch[] $capturedMatches Captured submatches of this match.
*/
public function __construct(
ComponentValueList $list, $start, $length, $name = null, array $capturedMatches = []
) {
Util::assertAllInstanceOf( $capturedMatches, self::class, '$capturedMatches' );
$this->values = $list->slice( $start, $length );
$this->start = $start;
$this->length = $length;
$this->name = $name;
$this->capturedMatches = $capturedMatches;
}
/**
* The matched values
* @return ComponentValue[]
*/
public function getValues() {
return $this->values;
}
/**
* The starting position of this match within the original list of values.
* @return int
*/
public function getStart() {
return $this->start;
}
/**
* The length of this match
* @return int
*/
public function getLength() {
return $this->length;
}
/**
* The position after this match, as in index into the original list of values.
* @return int
*/
public function getNext() {
return $this->start + $this->length;
}
/**
* The name of this match
* @return string|null
*/
public function getName() {
return $this->name;
}
/**
* The captured submatches of this match
*
* This returns the matches from capturing submatchers (see
* Matcher::capture()) that matched during the matching of the top-level
* matcher that returned this match. If capturing submatchers were nested,
* the GrammarMatch objects returned here will themselves have captured sub-
* matches to return.
*
* To borrow PCRE regular expression syntax, if the "pattern" described by
* the Matchers resembled `www(?<A>xxx(?<B>yyy)xxx)(?<C>zzz)*` then the
* top-level GrammarMatch's getCapturedMatches() would return a GrammarMatch
* named "A" (containing the "xxxyyyxxx" bit) and zero or more matches named
* "C" (for each "zzz"), and that "A" GrammarMatch's getCapturedMatches()
* would return a GrammarMatch named "B" (containing just the "yyy").
*
* Note that the start and end positions reported by captured matches may be
* relative to a containing SimpleBlock or CSSFunction's value rather than
* to the ComponentValueList passed to the top-level Matcher.
*
* @return GrammarMatch[]
*/
public function getCapturedMatches() {
return $this->capturedMatches;
}
/**
* Return a key for this matcher's state
* @return string
*/
public function getUniqueID() {
$data = [ $this->start, $this->length, $this->name ];
foreach ( $this->capturedMatches as $m ) {
$data[] = $m->getUniqueId();
}
return md5( implode( "\n", $data ) );
}
/**
* Replace whitespace in the matched values
* @private For use by Matcher only
* @param Token $old
* @param Token $new
*/
public function fixWhitespace( Token $old, Token $new ) {
foreach ( $this->values as $k => $v ) {
if ( $v === $old ) {
$this->values[$k] = $new;
}
}
foreach ( $this->capturedMatches as $m ) {
$m->fixWhitespace( $old, $new );
}
}
public function __toString() {
return Util::stringify( $this->getValues() );
}
}