Файловый менеджер - Редактировать - /var/www/html/mediawiki-1.43.1/extensions/Math/src/WikiTexVC/Nodes/TexArray.php
Ðазад
<?php declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\WikiTexVC\Nodes; use Generator; use InvalidArgumentException; use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLParsingUtil; use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLutil; use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmo; use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmrow; use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmstyle; use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmsup; use MediaWiki\Extension\Math\WikiTexVC\TexUtil; /** * */ class TexArray extends TexNode implements \ArrayAccess, \IteratorAggregate { protected bool $curly = false; private ?LengthSpec $rowSpecs = null; /** * @param TexNode|string ...$args * @return self */ public static function newCurly( ...$args ) { $node = new self( ...$args ); $node->curly = true; return $node; } /** @inheritDoc */ public function __construct( ...$args ) { $nargs = []; foreach ( $args as &$arg ) { if ( $arg !== null ) { array_push( $nargs, $arg ); } } self::checkInput( $nargs ); parent::__construct( ...$nargs ); } public function checkForStyleArgs( TexNode $node ): ?array { if ( $node instanceof Literal ) { $name = trim( $node->getArg() ); switch ( $name ) { case "\\displaystyle": return [ "displaystyle" => "true", "scriptlevel" => "0" ]; case "\\scriptstyle": return [ "displaystyle" => "false", "scriptlevel" => "1" ]; case "\\scriptscriptstyle": return [ "displaystyle" => "false", "scriptlevel" => "2" ]; case "\\textstyle": return [ "displaystyle" => "false", "scriptlevel" => "0" ]; } } return null; } /** * Checks if an TexNode of Literal contains color information (color, pagecolor) * and returns info how to continue with the parsing. * @param TexNode $node node to check if it contains color info * @return array index 0: (bool) was color element found, index 1: (string) specified color */ public function checkForColor( TexNode $node ) { if ( $node instanceof Literal ) { $name = trim( $node->getArg() ); if ( str_contains( $name, "\\color" ) ) { $foundOperatorContent = MMLutil::initalParseLiteralExpression( $node->getArg() ); if ( !$foundOperatorContent ) { // discarding color elements which not specify color return [ true, null ]; } else { return [ true, $foundOperatorContent[2][0] ]; } } elseif ( str_contains( $name, "\\pagecolor" ) ) { return [ true, null ]; } } return [ false, null ]; } public function checkForColorDefinition( TexNode $node ): ?array { if ( $node instanceof Literal ) { $name = trim( $node->getArg() ); if ( str_contains( $name, "\\definecolor" ) ) { return MMLParsingUtil::parseDefineColorExpression( $node->getArg() ); } } return null; } /** * Checks two sequential nodes in TexArray if they contain information on sideset expressions. * @param TexNode $currentNode first node in array to check (for sideset expression) * @param TexNode|null $nextNode second node in array to check (for succeeding operator) * @return TexNode|null the succeeding operator for further Parsing or null if sideset not found or invalid */ public function checkForSideset( TexNode $currentNode, ?TexNode $nextNode ): ?TexNode { if ( !( $currentNode instanceof Fun2nb && $currentNode->getFname() == "\\sideset" ) ) { return null; } if ( $nextNode instanceof Literal || $nextNode instanceof DQ || $nextNode instanceof UQ || $nextNode instanceof FQ ) { return $nextNode; } return null; } public function checkForLimits( TexNode $currentNode, ?TexNode $nextNode ): array { // Preceding 'lim' in example: "\\lim_{x \\to 2}" if ( ( $currentNode instanceof DQ || $currentNode instanceof FQ ) && $currentNode->containsFunc( "\\lim" ) ) { if ( $currentNode->getBase() instanceof TexArray ) { return [ $currentNode->getBase()->getArgs()[0], false ]; } else { return [ $currentNode->getBase(), false ]; } } /** Find cases which have preceding Literals with nullary_macro-type operators i.e.: * "\iint\limits_D \, dx\,dy" */ $tu = TexUtil::getInstance(); // Check whether the current node is a possible preceding literal if ( !( // logically superfluous brackets were inserted to improve readability ( $currentNode instanceof Literal && // Check if the current node is a nullary macro such as \iint, \sum, \prod, etc. ( $tu->nullary_macro( trim( $currentNode->getArg() ) ) // or a limit operator || ( trim( $currentNode->getArg() ) == "\\lim" ) ) ) || // or the special case of \operatorname ( $currentNode instanceof Fun1nb && $currentNode->getFname() == "\\operatorname" ) ) ) { return [ null, false ]; } // Check whether the next node is a possible limits construct if ( !( ( $nextNode instanceof DQ || $nextNode instanceof FQ ) && $nextNode->getBase() instanceof Literal && ( $nextNode->containsFunc( "\\limits" ) || $nextNode->containsFunc( "\\nolimits" ) ) ) ) { return [ null, false ]; } return [ $currentNode, true ]; } public function checkForNot( TexNode $currentNode ): bool { if ( $currentNode instanceof Literal && trim( $currentNode->getArg() ) == "\\not" ) { return true; } return false; } public function checkForDerivatives( int $iStart, array $args ): int { $ctr = 0; for ( $i = $iStart, $count = count( $this->args ); $i < $count; $i++ ) { $followUp = $args[$i]; if ( $followUp instanceof Literal && $followUp->getArg() === "'" ) { $ctr++; } else { break; } } return $ctr; } public function checkForNamedFctArgs( TexNode $currentNode, ?TexNode $nextNode ): array { // Check if current node is named function $hasNamedFct = false; if ( $currentNode instanceof TexArray && count( $currentNode->args ) == 2 ) { $tu = TexUtil::getInstance(); $currentNodeContent = $currentNode[0]; if ( $currentNodeContent instanceof Literal && $tu->latex_function_names( $currentNodeContent->getArg() ) ) { $hasNamedFct = true; } } elseif ( $currentNode instanceof Fun1nb && $currentNode->getFname() === '\\operatorname' ) { $hasNamedFct = true; } // Check if there is a valid argument as next parameter $hasValidParameters = false; if ( !$hasNamedFct ) { return [ $hasNamedFct, $hasValidParameters ]; } if ( $nextNode && !( $nextNode instanceof Literal && $nextNode->getArg() === "'" ) ) { $hasValidParameters = true; } return [ $hasNamedFct, $hasValidParameters ]; } private function squashLiterals() { $tmp = ''; foreach ( $this->args as $arg ) { if ( !( $arg instanceof Literal ) ) { return; } // Don't squash if there is a macro in the literal if ( preg_match( "/[\\\\]/", $arg->getArg() ) ) { return; } $tmp .= $arg->getArg(); } $this->args = [ new Literal( $tmp ) ]; $this->curly = false; } /** @inheritDoc */ public function renderMML( $arguments = [], &$state = [] ) { // Everything here is for parsing displaystyle, probably refactored to WikiTexVC grammar later $fullRenderedArray = ""; $mmlStyles = []; $currentColor = null; if ( array_key_exists( 'squashLiterals', $state ) ) { $this->squashLiterals(); } for ( $i = 0, $count = count( $this->args ); $i < $count; $i++ ) { $current = $this->args[$i]; if ( isset( $this->args[$i + 1] ) ) { $next = $this->args[$i + 1]; } else { $next = null; } // Check for sideset $foundSideset = $this->checkForSideset( $current, $next ); if ( $foundSideset ) { $state["sideset"] = $foundSideset; // Skipping the succeeding Literal $i++; } // Check for limits $foundLimits = $this->checkForLimits( $current, $next ); if ( $foundLimits[0] ) { $state["limits"] = $foundLimits[0]; if ( $foundLimits[1] ) { continue; } } // Check for Not $foundNot = $this->checkForNot( $current ); if ( $foundNot ) { $state["not"] = true; continue; } // Check for derivatives $foundDeriv = $this->checkForDerivatives( $i + 1, $this->args ); if ( $foundDeriv > 0 ) { // skip the next indices which are derivative characters $i += $foundDeriv; $state["deriv"] = $foundDeriv; } // Check if there is a new color definition and add it to state $foundColorDef = $this->checkForColorDefinition( $current ); if ( $foundColorDef ) { $state["colorDefinitions"][$foundColorDef["name"]] = $foundColorDef; continue; } // Pass preceding color info to state $foundColor = $this->checkForColor( $current ); if ( $foundColor[0] ) { $currentColor = $foundColor[1]; // Skipping the color element itself for rendering continue; } $styleArguments = $this->checkForStyleArgs( $current ); $foundNamedFct = $this->checkForNamedFctArgs( $current, $next ); if ( $foundNamedFct[0] ) { $state["foundNamedFct"] = $foundNamedFct; } if ( $styleArguments ) { $state["styleargs"] = $styleArguments; $mmlStyle = new MMLmstyle( "", $styleArguments ); $fullRenderedArray .= $mmlStyle->getStart(); if ( $next instanceof TexNode && $next->isCurly() ) { // Wrap with style-tags when the next element is a Curly which determines start and end tag. $fullRenderedArray .= $this->createMMLwithContext( $currentColor, $next, $state, $arguments ); $fullRenderedArray .= $mmlStyle->getEnd(); $mmlStyle = null; unset( $state["styleargs"] ); $i++; } else { // Start the style indicator in cases like \textstyle abc $mmlStyles[] = $mmlStyle->getEnd(); } } else { $fullRenderedArray .= $this->createMMLwithContext( $currentColor, $current, $state, $arguments ); } if ( array_key_exists( "not", $state ) ) { unset( $state["not"] ); } if ( array_key_exists( "limits", $state ) ) { unset( $state["limits"] ); } if ( array_key_exists( "deriv", $state ) ) { unset( $state["deriv"] ); } } foreach ( array_reverse( $mmlStyles ) as $mmlStyleEnd ) { $fullRenderedArray .= $mmlStyleEnd; } if ( $this->curly && $this->getLength() > 1 ) { $mmlRow = new MMLmrow(); return $mmlRow->encapsulateRaw( $fullRenderedArray ); } return $fullRenderedArray; } private function createMMLwithContext( ?string $currentColor, TexNode $currentNode, array &$state, array $arguments ): string { if ( $currentColor ) { if ( array_key_exists( "colorDefinitions", $state ) && is_array( $state["colorDefinitions"] ) && array_key_exists( $currentColor, $state["colorDefinitions"] ?? [] ) && is_array( $state["colorDefinitions"][$currentColor] ) && array_key_exists( "hex", $state["colorDefinitions"][$currentColor] ) ) { $displayedColor = $state["colorDefinitions"][$currentColor]["hex"]; } else { $resColor = TexUtil::getInstance()->color( ucfirst( $currentColor ) ); $displayedColor = $resColor ?: $currentColor; } $mmlStyleColor = new MMLmstyle( "", [ "mathcolor" => $displayedColor ] ); $ret = $mmlStyleColor->encapsulateRaw( $currentNode->renderMML( $arguments, $state ) ); } else { $ret = $currentNode->renderMML( $arguments, $state ); } return $this->addDerivativesContext( $state, $ret ); } /** * If derivative was recognized, add the corresponding derivative math operator * to the mml and wrap with msup element. * @param array &$state state indicator which indicates derivative * @param string $mml mathml input * @return string mml with additional mml-elements for derivatives */ public function addDerivativesContext( array &$state, string $mml ): string { if ( array_key_exists( "deriv", $state ) && $state["deriv"] > 0 ) { $msup = new MMLmsup(); $moDeriv = new MMLmo(); if ( $state["deriv"] == 1 ) { $derInfo = "′"; } elseif ( $state["deriv"] == 2 ) { $derInfo = "″"; } elseif ( $state["deriv"] == 3 ) { $derInfo = "‴"; } elseif ( $state["deriv"] == 4 ) { $derInfo = "⁗"; } else { $derInfo = str_repeat( "′", $state["deriv"] ); } $mml = $msup->encapsulateRaw( $mml . $moDeriv->encapsulateRaw( $derInfo ) ); if ( ( $state['foundNamedFct'][0] ?? false ) && !( $state['foundNamedFct'][1] ?? true ) ) { $mml .= MMLParsingUtil::renderApplyFunction(); } } return $mml; } /** @inheritDoc */ public function inCurlies() { if ( isset( $this->args[0] ) && count( $this->args ) == 1 ) { return $this->args[0]->inCurlies(); } else { return '{' . parent::render() . '}'; } } /** @inheritDoc */ public function extractSubscripts() { $y = []; foreach ( $this->args as $x ) { $y = array_merge( $y, $x->extractSubscripts() ); } if ( isset( $this->args[0] ) && ( count( $this->args ) == count( $y ) ) ) { return implode( '', $y ); } return []; } /** @inheritDoc */ public function extractIdentifiers( $args = null ) { if ( $args == null ) { $args = $this->args; } $list = parent::extractIdentifiers( $args ); $outpos = 0; $offset = 0; $int = 0; for ( $inpos = 0; $inpos < count( $list ); $inpos++ ) { $outpos = $inpos - $offset; switch ( $list[$inpos] ) { case '\'': $list[$outpos - 1] .= '\''; $offset++; break; case '\\int': $int++; $offset++; break; case '\\mathrm{d}': case 'd': if ( $int ) { $int--; $offset++; break; } // no break default: if ( isset( $list[0] ) ) { $list[$outpos] = $list[$inpos]; } } } return array_slice( $list, 0, count( $list ) - $offset ); } /** @inheritDoc */ public function getModIdent() { $y = []; foreach ( $this->args as $x ) { $y = array_merge( $y, $x->getModIdent() ); } if ( isset( $this->args[0] ) && ( count( $this->args ) == count( $y ) ) ) { return implode( "", $y ); } return []; } /** * @param TexNode|string ...$elements */ public function push( ...$elements ): TexArray { self::checkInput( $elements ); array_push( $this->args, ...$elements ); return $this; } public function pop() { array_splice( $this->args, 0, 1 ); } /** * @return TexNode|null first value */ public function first() { return $this->args[0] ?? null; } /** * @return TexNode|null second value */ public function second() { return $this->args[1] ?? null; } /** * @param TexNode|string ...$elements */ public function unshift( ...$elements ): TexArray { array_unshift( $this->args, ...$elements ); return $this; } /** * @throws InvalidArgumentException if args not of correct type * @param TexNode[] $args input args * @return void */ private static function checkInput( $args ): void { foreach ( $args as $arg ) { if ( !( $arg instanceof TexNode ) ) { throw new InvalidArgumentException( 'Wrong input type specified in input elements.' ); } } } public function render() { if ( $this->curly ) { return $this->inCurlies(); } return parent::render(); } public function isCurly(): bool { return $this->curly; } public function setCurly( bool $curly = true ): TexArray { $this->curly = $curly; return $this; } /** * @return Generator<TexNode> */ public function getIterator(): Generator { yield from $this->args; } /** * @return TexNode[] */ public function getArgs(): array { return parent::getArgs(); } /** @inheritDoc */ public function offsetExists( $offset ): bool { return isset( $this->args[$offset] ); } /** @inheritDoc */ public function offsetGet( $offset ): ?TexNode { return $this->args[$offset] ?? null; } /** @inheritDoc */ public function offsetSet( $offset, $value ): void { if ( !( $value instanceof TexNode ) ) { throw new InvalidArgumentException( 'TexArray elements must be of type TexNode.' ); } $this->args[$offset] = $value; } /** @inheritDoc */ public function offsetUnset( $offset ): void { unset( $this->args[$offset] ); } public function setRowSpecs( ?LengthSpec $r ) { $this->rowSpecs = $r; } public function getRowSpecs(): ?LengthSpec { return $this->rowSpecs; } }
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка