Page MenuHomeWickedGov Phorge

Frame.php
No OneTemporary

Size
5 KB
Referenced Files
None
Subscribers
None

Frame.php

<?php
declare( strict_types = 1 );
namespace Wikimedia\Parsoid\Wt2Html;
use Wikimedia\Parsoid\Config\Env;
use Wikimedia\Parsoid\Tokens\EOFTk;
use Wikimedia\Parsoid\Tokens\KV;
use Wikimedia\Parsoid\Tokens\SourceRange;
use Wikimedia\Parsoid\Tokens\Token;
use Wikimedia\Parsoid\Utils\PHPUtils;
use Wikimedia\Parsoid\Utils\PipelineUtils;
use Wikimedia\Parsoid\Utils\Title;
use Wikimedia\Parsoid\Utils\TokenUtils;
/**
* A frame represents a template expansion scope including parameters passed
* to the template (args). It provides a generic 'expand' method which
* expands / converts individual parameter values in its scope. It also
* provides methods to check if another expansion would lead to loops or
* exceed the maximum expansion depth.
*/
class Frame {
/** @var ?Frame */
private $parentFrame;
/** @var Env */
private $env;
/** @var Title */
private $title;
/** @var Params */
private $args;
/** @var string */
private $srcText;
/** @var int */
private $depth;
/**
* @param Title $title
* @param Env $env
* @param KV[] $args
* @param string $srcText
* @param ?Frame $parentFrame
*/
public function __construct(
Title $title, Env $env, array $args, string $srcText,
?Frame $parentFrame = null
) {
$this->title = $title;
$this->env = $env;
$this->args = new Params( $args );
$this->srcText = $srcText;
if ( $parentFrame ) {
$this->parentFrame = $parentFrame;
$this->depth = $parentFrame->depth + 1;
} else {
$this->parentFrame = null;
$this->depth = 0;
}
}
public function getEnv(): Env {
return $this->env;
}
public function getTitle(): Title {
return $this->title;
}
public function getArgs(): Params {
return $this->args;
}
public function getSrcText(): string {
return $this->srcText;
}
/**
* Create a new child frame.
* @param Title $title
* @param KV[] $args
* @param string $srcText
* @return Frame
*/
public function newChild( Title $title, array $args, string $srcText ): Frame {
return new Frame( $title, $this->env, $args, $srcText, $this );
}
/**
* Expand / convert a thunk (a chunk of tokens not yet fully expanded).
* @param array<Token|string> $chunk
* @param array $options
* @return array<Token|string>
*/
public function expand( array $chunk, array $options ): array {
$this->env->log( 'debug', 'Frame.expand', $chunk );
if ( !$chunk ) {
return $chunk;
}
// Add an EOFTk if it isn't present
$content = $chunk;
if ( !( PHPUtils::lastItem( $chunk ) instanceof EOFTk ) ) {
$content[] = new EOFTk();
}
// Downstream template uses should be tracked and wrapped only if:
// - not in a nested template Ex: {{Templ:Foo}} and we are processing Foo
// - not in a template use context Ex: {{ .. | {{ here }} | .. }}
// - the attribute use is wrappable Ex: [[ ... | {{ .. link text }} ]]
$opts = [
'pipelineType' => 'peg-tokens-to-expanded-tokens',
'pipelineOpts' => [
'isInclude' => $this->depth > 0,
'expandTemplates' => $options['expandTemplates'],
'inTemplate' => $options['inTemplate'],
'attrExpansion' => $options['attrExpansion'] ?? false
],
'sol' => true,
'srcOffsets' => $options['srcOffsets'] ?? null,
'tplArgs' => [ 'name' => null, 'title' => null, 'attribs' => [] ]
];
$tokens = PipelineUtils::processContentInPipeline( $this->env, $this, $content, $opts );
TokenUtils::stripEOFTkfromTokens( $tokens );
return $tokens;
}
/**
* Check if expanding a template would lead to a loop, or would exceed the
* maximum expansion depth.
*
* @param Title $title
* @param int $maxDepth
* @param bool $ignoreLoop
* @return ?string null => no error; non-null => error message
*/
public function loopAndDepthCheck( Title $title, int $maxDepth, bool $ignoreLoop ): ?string {
if ( $this->depth > $maxDepth ) {
// Too deep
return "Template recursion depth limit exceeded ($maxDepth): ";
}
if ( $ignoreLoop ) {
return null;
}
$frame = $this;
do {
if ( $title->equals( $frame->title ) ) {
// Loop detected
return 'Template loop detected: ';
}
$frame = $frame->parentFrame;
} while ( $frame );
// No loop detected.
return null;
}
/**
* @param mixed $arg
* @param SourceRange $srcOffsets
* @return array
*/
private function expandArg( $arg, SourceRange $srcOffsets ): array {
if ( is_string( $arg ) ) {
return [ $arg ];
} else {
return $this->expand( $arg, [
'expandTemplates' => true,
'inTemplate' => true,
'srcOffsets' => $srcOffsets,
] );
}
}
/**
* @param Token $tplArgToken
* @return array tokens representing the arg value
*/
public function expandTemplateArg( Token $tplArgToken ): array {
$args = $this->args->named();
$attribs = $tplArgToken->attribs;
$expandedKeyToks = $this->expandArg(
$attribs[0]->k,
$attribs[0]->srcOffsets->key
);
$argName = trim( TokenUtils::tokensToString( $expandedKeyToks ) );
$res = $args['dict'][$argName] ?? null;
if ( $res !== null ) {
$res = isset( $args['namedArgs'][$argName] ) ?
TokenUtils::tokenTrim( $res ) : $res;
return is_string( $res ) ? [ $res ] : $res;
} elseif ( count( $attribs ) > 1 ) {
return $this->expandArg(
$attribs[1]->v,
$attribs[1]->srcOffsets->value
);
} else {
return array_merge( [ '{{{' ], $expandedKeyToks, [ '}}}' ] );
}
}
}

File Metadata

Mime Type
text/x-php
Expires
Tue, Aug 18, 21:29 (4 d, 23 h ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
89/80/31e0ab03a4dfb2d4e88596fdf19a
Default Alt Text
Frame.php (5 KB)

Event Timeline