You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
cosmopet.ae/wp-content/plugins copy/wp-all-import/libraries/XmlImportTemplateParser.php

444 lines
14 KiB

<?php
/**
* @author Olexandr Zanichkovsky <olexandr.zanichkovsky@zophiatech.com>
* @package General
*/
require_once dirname(__FILE__) . '/ast/XmlImportAstSequence.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstPrint.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstText.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstWith.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstForeach.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstIf.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstMath.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstSpintax.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstXPath.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstString.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstInteger.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstFloat.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstFunction.php';
/**
* Parses a list of nodes into AST (Abstract Syntax Tree)
*/
class XmlImportTemplateParser
{
/**
* List of tokens
*
* @var array
*/
private $tokens;
/**
* Current index
*
* @var int
*/
private $index = -1;
/**
* Stack that stores possible block endings
*
* @var array
*/
private $clauseStack = array();
/**
* Stack of sequences
*
* @var array
*/
private $sequenceStack = array();
/**
* Whether else subclause is allowed
*
* @var bool
*/
private $elseAllowed = false;
/**
* Creates new instance
*
* @param array $tokens
*/
public function __construct(array $tokens)
{
$this->tokens = $tokens;
}
/**
* Parses the list of tokens into AST tree
*
* @return XmlImportAstSequence
*/
public function parse()
{
$result = $this->parseSequence();
if (count($this->clauseStack) > 0)
throw new XmlImportException("Unexpected end of template.");
return $result;
}
/**
* Parses sequence
*
* @return XmlImportAstSequence
*/
private function parseSequence()
{
if (($this->index + 1) == count($this->tokens))
throw new XmlImportException("Reached end of template but statement sequence expected");
$sequence = new XmlImportAstSequence();
array_push($this->sequenceStack, $sequence);
if (count($this->clauseStack) == 0)
{
while (($this->index + 1) < count($this->tokens))
{
$sequence->addStatement($this->parseStatement());
}
}
else
{
while (($this->index + 1) < count($this->tokens))
{
if ($this->tokens[$this->index + 1]->getKind() == $this->clauseStack[count($this->clauseStack) - 1])
{
$this->index++;
array_pop($this->clauseStack);
break;
}
$statement = $this->parseStatement();
if (is_null($statement)){
array_pop($this->sequenceStack);
return $sequence;
}
$sequence->addStatement($statement);
}
}
array_pop($this->sequenceStack);
return $sequence;
}
/**
* Parses statement
*
* @return XmlImportAstText|XmlImportAstWith|XmlImportAstForeach|XmlImportAstPrint|XmlImportAstIf
*/
private function parseStatement()
{
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_TEXT)
{
return new XmlImportAstText($this->tokens[++$this->index]->getValue());
}
elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_PRINT)
{
$this->index++;
return new XmlImportAstPrint($this->parseExpression());
}
elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_WITH)
{
return $this->parseWith();
}
elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_FOREACH)
{
return $this->parseForeach();
}
elseif($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_MATH)
{
return new XmlImportAstPrint($this->parseExpression());
}
elseif($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_SPINTAX)
{
return new XmlImportAstPrint($this->parseExpression());
}
elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_IF)
{
return $this->parseIf();
}
elseif($this->clauseStack[count($this->clauseStack) - 1] == XmlImportToken::KIND_ENDIF &&
in_array($this->tokens[$this->index + 1]->getKind(), array(XmlImportToken::KIND_ELSE, XmlImportToken::KIND_ELSEIF)))
{
if ($this->elseAllowed)
{
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_ELSE)
$this->elseAllowed = false;
}
else
{
throw new XmlImportException("ELSEIF or ELSE is not allowed again after ELSE");
}
return null;
}
else
throw new XmlImportException ("Unexpected token {$this->tokens[$this->index + 1]->getKind()}, statement was expected.");
}
/**
* Parses expression
*
* @return XmlImportAstXPath|XmlImportAstFunction|XmlImportAstMath|XmlImportAstSpintax|XmlImportAstString|XmlImportAstInteger|XmlImportAstFloat
*/
private function parseExpression()
{
if ($this->index + 1 == count($this->tokens))
throw new XmlImportException("Reached end of template but expression was expected");
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_FUNCTION)
{
return $this->parseFunction();
}
elseif($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_MATH)
{
return $this->parseMath();
}
elseif($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_SPINTAX)
{
return $this->parseSpintax();
}
elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_XPATH)
{
$xpath = new XmlImportAstXPath($this->tokens[++$this->index]->getValue());
$this->sequenceStack[count($this->sequenceStack) - 1]->addVariable($xpath);
return $xpath;
}
elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_STRING || $this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_OPERATION)
{
return new XmlImportAstString($this->tokens[++$this->index]->getValue());
}
elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_INT)
{
return new XmlImportAstInteger($this->tokens[++$this->index]->getValue());
}
elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_FLOAT)
{
return new XmlImportAstFloat($this->tokens[++$this->index]->getValue());
}
else
throw new XmlImportException("Unexpected token " . $this->tokens[$this->index + 1]->getKind());
}
/**
* Parses function
*
* @return XmlImportAstFunction
*/
private function parseFunction()
{
$function = new XmlImportAstFunction($this->tokens[++$this->index]->getValue());
if ($this->tokens[$this->index + 1]->getKind() != XmlImportToken::KIND_OPEN)
throw new XmlImportException ("Open brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
$this->index++;
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
{
$this->index++;
return $function;
}
else
{
while ($this->index < count($this->tokens) - 2)
{
$function->addArgument($this->parseExpression());
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
{
$this->index++;
return $function;
break;
}
elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_COMMA)
$this->index++;
else
throw new XmlImportException("Comma or closing brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
}
throw new XmlImportException("Unexpected end of {$function->getName()} function argument list");
}
}
/**
* Parses function
*
* @return XmlImportAstFunction|XmlImportAstMath
*/
private function parseMath()
{
$math = new XmlImportAstMath($this->tokens[++$this->index]->getValue());
if ($this->tokens[$this->index + 1]->getKind() != XmlImportToken::KIND_OPEN)
throw new XmlImportException ("Open brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
$this->index++;
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
{
$this->index++;
return $math;
}
else
{
while ($this->index < count($this->tokens) - 2)
{
$math->addArgument($this->parseExpression());
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
{
$this->index++;
return $math;
break;
}
elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_COMMA)
$this->index++;
else
throw new XmlImportException("Comma or closing brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
}
throw new XmlImportException("Unexpected end of MATH argument list");
}
}
/**
* Parses function
*
* @return XmlImportSpintaxFunction|XmlImportAstSpintax
*/
private function parseSpintax()
{
$spintax = new XmlImportAstSpintax($this->tokens[++$this->index]->getValue());
if ($this->tokens[$this->index + 1]->getKind() != XmlImportToken::KIND_OPEN)
throw new XmlImportException ("Open brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
$this->index++;
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
{
$this->index++;
return $spintax;
}
else
{
while ($this->index < count($this->tokens) - 2)
{
$spintax->addArgument($this->parseExpression());
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
{
$this->index++;
return $spintax;
break;
}
elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_COMMA)
$this->index++;
else
throw new XmlImportException("Comma or closing brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
}
throw new XmlImportException("Unexpected end of {$function->getName()} function argument list");
}
}
/**
* Parses clause that uses XPath and returns XPath
*
* @return XmlImportAstXPath
*/
private function parseXPathDependant()
{
$this->index++;
if ($this->index + 1 == count($this->tokens))
throw new XmlImportException("Reached end of template but expression was expected");
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_OPEN)
$this->index++;
else
throw new XmlImportException("Open brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_XPATH)
{
$xpath = new XmlImportAstXPath($this->tokens[++$this->index]->getValue());
$this->sequenceStack[count($this->sequenceStack) - 1]->addVariable($xpath);
}
else
throw new XmlImportException("XPath expression expected instead of " . $this->tokens[$this->index + 1]->getKind());
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
$this->index++;
else
throw new XmlImportException("Close brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
return $xpath;
}
/**
* Parses WITH clause
*
* @return XmlImportAstWith
*/
private function parseWith()
{
$xpath = $this->parseXPathDependant();
//store sequence exit
array_push($this->clauseStack, XmlImportToken::KIND_ENDWITH);
return new XmlImportAstWith($xpath, $this->parseSequence());
}
/**
* Parses FOREACH clause
*
* @return XmlImportAstForeach
*/
private function parseForeach()
{
$xpath = $this->parseXPathDependant();
array_push($this->clauseStack, XmlImportToken::KIND_ENDFOREACH);
return new XmlImportAstForeach($xpath, $this->parseSequence());
}
/**
* Parses IF clause
*
* @return XmlImportAstIf
*/
private function parseIf()
{
$this->index++;
$this->elseAllowed = true;
array_push($this->clauseStack, XmlImportToken::KIND_ENDIF);
if ($this->index + 1 == count($this->tokens))
throw new XmlImportException("Reached end of template but expression was expected");
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_OPEN)
$this->index++;
else
throw new XmlImportException("Open brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
$if = new XmlImportAstIf($this->parseExpression());
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
$this->index++;
else
throw new XmlImportException("Close brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
$if->addIfBody($this->parseSequence());
if ($this->index + 1 != count($this->tokens))
{
while ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_ELSEIF)
{
$this->index++;
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_OPEN)
$this->index++;
else
throw new XmlImportException("Open brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
$condition = $this->parseExpression();
if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
$this->index++;
else
throw new XmlImportException("Close brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
$elseif = new XmlImportAstElseif($condition, $this->parseSequence());
$if->addElseif($elseif);
if ($this->index + 1 == count($this->tokens))
break;
}
if ($this->index + 1 < count($this->tokens) && $this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_ELSE)
{
$this->index++;
$if->addElseBody($this->parseSequence());
}
}
return $if;
}
}