/** * Convert template to PHP code * * @throws CompileException */ public function compile() { $end = $pos = 0; foreach ($this->_fenom->getPreFilters() as $filter) { $this->_src = call_user_func($filter, $this, $this->_src); } while (($start = strpos($this->_src, '{', $pos)) !== false) { // search open-symbol of tags switch (substr($this->_src, $start + 1, 1)) { // check next character case "\n": case "\r": case "\t": case " ": case "}": // ignore the tag $this->_appendText(substr($this->_src, $pos, $start - $pos + 2)); $end = $start + 1; break; case "*": // comment block $end = strpos($this->_src, '*}', $start); // find end of the comment block if ($end === false) { throw new CompileException("Unclosed comment block in line {$this->_line}", 0, 1, $this->_name, $this->_line); } $end++; $this->_appendText(substr($this->_src, $pos, $start - $pos)); $comment = substr($this->_src, $start, $end - $start); // read the comment block for processing $this->_line += substr_count($comment, "\n"); // count lines in comments unset($comment); // cleanup break; default: $this->_appendText(substr($this->_src, $pos, $start - $pos)); $end = $start + 1; do { $need_more = false; $end = strpos($this->_src, '}', $end + 1); // search close-symbol of the tag if ($end === false) { // if unexpected end of template throw new CompileException("Unclosed tag in line {$this->_line}", 0, 1, $this->_name, $this->_line); } $tag = substr($this->_src, $start + 1, $end - $start - 1); if ($this->_ignore) { // check ignore if ($tag === '/' . $this->_ignore) { // turn off ignore $this->_ignore = false; } else { // still ignore $this->_appendText('{' . $tag . '}'); continue; } } if ($this->_tag_filters) { foreach ($this->_tag_filters as $filter) { $tag = call_user_func($filter, $tag, $this); } } $tokens = new Tokenizer($tag); // tokenize the tag if ($tokens->isIncomplete()) { // all strings finished? $need_more = true; } else { $this->_appendCode($this->parseTag($tokens), '{' . $tag . '}'); // start the tag lexer if ($tokens->key()) { // if tokenizer have tokens - throws exceptions throw new CompileException("Unexpected token '" . $tokens->current() . "' in {$this} line {$this->_line}, near '{" . $tokens->getSnippetAsString(0, 0) . "' <- there", 0, E_ERROR, $this->_name, $this->_line); } } } while ($need_more); unset($tag); // cleanup break; } $pos = $end + 1; // move search-pointer to end of the tag } gc_collect_cycles(); $this->_appendText(substr($this->_src, $end ? $end + 1 : 0)); // append tail of the template if ($this->_stack) { $_names = array(); foreach ($this->_stack as $scope) { $_names[] = '{' . $scope->name . '} opened on line ' . $scope->line; } /* @var Tag $scope */ $message = "Unclosed tag" . (count($_names) > 1 ? "s" : "") . ": " . implode(", ", $_names); throw new CompileException($message, 0, 1, $this->_name, $scope->line); } $this->_src = ""; // cleanup if ($this->_post) { foreach ($this->_post as $cb) { call_user_func_array($cb, array($this, &$this->_body)); } } $this->addDepend($this); // for 'verify' performance foreach ($this->_fenom->getPostFilters() as $filter) { $this->_body = call_user_func($filter, $this, $this->_body); } }