/** * Parse a parameter * * @param ezcTemplateCursor $cursor * @return bool */ protected function parseParameter($cursor) { // Without this, the expression parser keeps on reading. if ($cursor->match(')', false)) { return false; } $this->readingParameter = true; $startCursor = clone $cursor; $namedParameter = $cursor->pregMatch("#^[a-zA-Z_][a-zA-Z0-9_]*#"); if ($namedParameter !== false) { $this->findNextElement(); if (!$cursor->match("=")) { $namedParameter = false; } } if ($namedParameter === false) { $cursor->copy($startCursor); } // Check for expression, the parser will call self::atEnd() to check for end of expression. $expressionStartCursor = clone $cursor; $expressionParser = new ezcTemplateExpressionSourceToTstParser($this->parser, $this, null); $expressionParser->allowIdentifier = true; if (!$this->parseRequiredType($expressionParser) || $this->lastParser->currentOperator === null) { return false; } $rootOperator = $this->lastParser->currentOperator; if ($rootOperator instanceof ezcTemplateOperatorTstNode) { $rootOperator = $rootOperator->getRoot(); } if ($rootOperator instanceof ezcTemplateModifyingOperatorTstNode) { throw new ezcTemplateParserException($this->parser->source, $this->startCursor, $this->currentCursor, sprintf(ezcTemplateSourceToTstErrorMessages::MSG_PARAMETER_CANNOT_BE_MODIFYING_BLOCK, $this->parameterCount)); } if ($namedParameter !== false) { if (isset($this->functionCall->parameters[$namedParameter])) { throw new ezcTemplateParserException($this->parser->source, $this->startCursor, $this->currentCursor, sprintf(ezcTemplateSourceToTstErrorMessages::MSG_NAMED_PARAMETER_ALREADY_ASSIGNED, $namedParameter)); } $this->functionCall->parameters[$namedParameter] = $rootOperator; } else { $this->functionCall->appendParameter($rootOperator); } $this->readingParameter = false; return true; }
/** * Parse operator * * @param ezcTemplateCursor $cursor * @param bool $canDoAssignment * @return bool */ protected function parseOperator($cursor, $canDoAssignment = true) { // Try som generic operators $operator = null; // This will contain the name of the operator if it is found. $operatorName = false; $operatorSymbols = array(array(3, array('===', '!==')), array(2, array('==', '!=', '<=', '>=', '&&', '||', '+=', '-=', '*=', '/=', '.=', '%=', '..', '=>')), array(1, array('+', '-', '.', '*', '/', '%', '<', '>', '='))); foreach ($operatorSymbols as $symbolEntry) { $chars = $cursor->current($symbolEntry[0]); if (in_array($chars, $symbolEntry[1])) { $operatorName = $chars; break; } } if ($operatorName !== false && $operatorName == "=>") { return false; } // Cannot do an assignment right now. if ($operatorName == "=" && !$canDoAssignment) { return false; } if ($operatorName !== false) { $operatorStartCursor = clone $cursor; $cursor->advance(strlen($operatorName)); $operatorMap = array('+' => 'PlusOperator', '-' => 'MinusOperator', '.' => 'ConcatOperator', '*' => 'MultiplicationOperator', '/' => 'DivisionOperator', '%' => 'ModuloOperator', '==' => 'EqualOperator', '!=' => 'NotEqualOperator', '===' => 'IdenticalOperator', '!==' => 'NotIdenticalOperator', '<' => 'LessThanOperator', '>' => 'GreaterThanOperator', '<=' => 'LessEqualOperator', '>=' => 'GreaterEqualOperator', '&&' => 'LogicalAndOperator', '||' => 'LogicalOrOperator', '=' => 'AssignmentOperator', '+=' => 'PlusAssignmentOperator', '-=' => 'MinusAssignmentOperator', '*=' => 'MultiplicationAssignmentOperator', '/=' => 'DivisionAssignmentOperator', '.=' => 'ConcatAssignmentOperator', '%=' => 'ModuloAssignmentOperator', '..' => 'ArrayRangeOperator'); $requestedName = $operatorName; $operatorName = $operatorMap[$operatorName]; $function = "ezcTemplate" . $operatorName . "TstNode"; $operator = new $function($this->parser->source, clone $this->lastCursor, $cursor); // If the min precedence has been reached we immediately stop parsing // and return a successful parse result if ($this->minPrecedence !== false && $operator->precedence < $this->minPrecedence) { $cursor->copy($operatorStartCursor); return $operatorName; } $this->checkForValidOperator($this->currentOperator, $operator, $operatorStartCursor); $this->currentOperator = $this->parser->handleOperatorPrecedence($this->currentOperator, $operator); $this->lastCursor->copy($cursor); return $operatorName; } return false; }
/** * Parses the literal by using the ezcTemplateLiteralParser class. * * @param ezcTemplateCursor $cursor * @return bool */ protected function parseCurrent(ezcTemplateCursor $cursor) { // $cursor will be update as the parser continues $this->block = new ezcTemplateLiteralBlockTstNode($this->parser->source, clone $this->startCursor, $cursor); // skip whitespace and comments if (!$this->findNextElement()) { return false; } $hasClosingMarker = $cursor->current() == '/'; if ($hasClosingMarker) { $closingCursor = clone $cursor; $cursor->advance(); $this->findNextElement(); } $matches = $cursor->pregMatchComplete("#^(literal)(?:[^a-zA-Z0-9_])#"); if ($matches === false) { return false; } $cursor->advance(strlen($matches[1][0])); // skip whitespace and comments if (!$this->findNextElement()) { return false; } // Assume end of first {literal} block if (!$cursor->match("}")) { throw new ezcTemplateParserException($this->parser->source, $this->startCursor, $cursor, ezcTemplateSourceToTstErrorMessages::MSG_EXPECT_CURLY_BRACKET_CLOSE); } if ($hasClosingMarker) { throw new ezcTemplateParserException($this->parser->source, $this->startCursor, $cursor, "Found closing block {/literal} without an opening block."); } $literalTextCursor = clone $cursor; // Start searching for ending literal block. while (!$cursor->atEnd()) { // Find the next block $tagPos = $cursor->findPosition("{"); if ($tagPos === false) { return false; } $tagCursor = clone $cursor; $tagCursor->gotoPosition($tagPos - 1); if ($tagCursor->current() == "\\") { // This means the tag is escaped and should be treated as text. $cursor->copy($tagCursor); $cursor->advance(2); unset($tagCursor); continue; } // Reached a block {...} $cursor->gotoPosition($tagPos); $literalTextEndCursor = clone $cursor; $cursor->advance(); $continue = false; while (!$cursor->atEnd()) { // skip whitespace and comments if (!$this->findNextElement()) { return false; } // Check for end, if not continue search if (!$cursor->match('/literal')) { $continue = true; break; } // skip whitespace and comments if (!$this->findNextElement()) { return false; } if ($cursor->current() == '}') { $this->block->textStartCursor = $literalTextCursor; $this->block->textEndCursor = $literalTextEndCursor; $cursor->advance(); $this->block->endCursor = clone $cursor; // Make sure the text is extracted now that the cursor are correct $this->block->storeText(); $this->appendElement($this->block); return true; } } if ($continue) { continue; } } return false; }