public function parse($code) { static $regex; if (count($this->tpl->codeFilters['pre']) > 0) { foreach ($this->tpl->codeFilters['pre'] as $name) { // @ used because of stupid notice // "Object of class opt_template to string conversion". // Whatever it means, I couldn't recognize, why PHP does such things. $this->code = @$name($code, $this->tpl); } } if ($regex == NULL) { if ($this->tpl->xmlsyntaxMode == 1) { $regex = '\\<\\!\\-\\-.+\\-\\-\\>|<\\!\\[CDATA\\[|\\]\\]>|' . $regex; $this->tpl->delimiters[] = '\\<(\\/?)opt\\:(.*?)()\\>'; $this->tpl->delimiters[] = '\\<()opt\\:(.*?)(\\/)\\>'; $this->tpl->delimiters[] = 'opt\\:put\\=\\"(.*?[^\\\\])\\"'; } $regex = implode('|', $this->tpl->delimiters); } // tokenizer preg_match_all('#({\\*.+?\\*\\}|' . $regex . '|(.?))#si', $code, $result, PREG_PATTERN_ORDER); foreach ($result as $i => &$void) { if ($i != 0) { unset($result[$i]); } } $output = $this->tpl->captureTo . ' \''; if (!$this->parseRun) { // register output foreach ($this->processors as $name => $processor) { $processor->setOutput($output); } $this->parseRun = 1; } else { $this->parseRun = 2; } // initialize the tree $root = $current = new optNode(NULL, OPT_ROOT, NULL); $rootBlock = $currentBlock = new optBlock(NULL); $root->addItem($rootBlock); $textAssign = 0; $commented = 0; $literal = 0; foreach ($result[0] as $i => $item) { // comment usage if (strlen($item) > 1) { if (preg_match('/{\\*.+?\\*\\}/s', trim($item)) || preg_match('/\\<\\!\\-\\-.+\\-\\-\\>/s', $item)) { continue; } // a command // literal processing if ($literal == 1) { if ($item != '{/literal}') { $item = str_replace(array('\\', '\''), array('\\\\', '\\\''), $item); $text->addItem($item); $textAssign = 1; } else { $literal = 0; } continue; } if ($item == '{literal}' && $literal == 0) { $literal = 1; continue; } $textAssign = 0; // grep the data $sortMatches = array(0 => '', 1 => '', 2 => ''); preg_match('/' . $regex . '/', $item, $matches); $foundCommand = 0; foreach ($matches as $id => $val) { $val = trim($val); if ($val != '') { if ($val == '/') { if (!$foundCommand) { $sortMatches[0] = '/'; } else { $sortMatches[2] = '/'; } } elseif ($id != 0) { $sortMatches[1] = $val; $foundCommand = 1; } } } if (preg_match('/^(([a-zA-Z0-9\\_]+)([= ]{1}(.*))?)$/', $sortMatches[1], $found)) { // we have an instruction $realname = $found[2]; if ($sortMatches[0] == '/') { $found[2] = '/' . $found[2]; } $found[6] = $item; // general instructions if (isset($this->translator[$found[2]])) { switch ($this->translator[$found[2]]) { case OPT_COMMAND: $node = new optNode($found[2], OPT_INSTRUCTION, $current); $node->addItem(new optBlock($found[2], $found, OPT_COMMAND)); $currentBlock->addNode($node); break; case OPT_MASTER: $current->storeBlock($currentBlock); $current = new optNode($found[2], OPT_INSTRUCTION, $current); $currentBlock->addNode($current); $currentBlock = new optBlock($found[2], $found, OPT_MASTER); $current->addItem($currentBlock); break; case OPT_ALT: $currentBlock = new optBlock($found[2], $found, OPT_ALT); $current->addItem($currentBlock); break; case OPT_ENDER: $currentBlock = new optBlock($found[2], $found, OPT_ENDER); $current->addItem($currentBlock); $current = $current->getParent(); if (!is_object($current)) { $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: `' . $found[2] . '`!', 113); } $currentBlock = $current->restoreBlock(); break; } } elseif ($realname == 'component' || isset($this->tpl->components[$realname])) { if ($sortMatches[0] == '/') { $currentBlock = new optBlock($found[2], $found); $current->addItem($currentBlock); $current = $current->getParent(); if (!is_object($current)) { $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: `' . $found[2] . '`!', 113); } $currentBlock = $current->restoreBlock(); } else { $current->storeBlock($currentBlock); $current = new optNode($realname, OPT_COMPONENT, $current); $currentBlock->addNode($current); $currentBlock = new optBlock($realname, $found); $current->addItem($currentBlock); } } else { // here come the undefined command. The instruction programmer may do with them whatever he wants // the compiler is going to recognize, what sort of command is it. $ending = substr($found[2], strlen($found[2]) - 4, 4); if ($sortMatches[0] == '/') { // ending command, like in XML: /command $currentBlock = new optBlock($found[2], $found, OPT_ENDER); $current->addItem($currentBlock); $current = $current->getParent(); if (!is_object($current)) { $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: `' . $found[2] . '`!', 113); } $currentBlock = $current->restoreBlock(); } elseif ($sortMatches[2] == '/') { // standalone command, like XML: command/ $node = new optNode($found[2], OPT_UNKNOWN, $current); $node->addItem(new optBlock($found[2], $found, OPT_COMMAND)); $currentBlock->addNode($node); } elseif ($ending == 'else') { // alternative command, doesn't exist in XML: commandelse $currentBlock = new optBlock($found[2], $found, OPT_ALT); $current->addItem($currentBlock); } else { // beginning command: command $current->storeBlock($currentBlock); $current = new optNode($realname, OPT_UNKNOWN, $current); $currentBlock->addNode($current); $currentBlock = new optBlock($realname, $found, OPT_MASTER); $current->addItem($currentBlock); } } } else { // we have an expression $node = new optNode(NULL, OPT_EXPRESSION, $current); $node->addItem(new optBlock(NULL, $sortMatches[1])); $currentBlock->addNode($node); } } else { // text item if ($textAssign == 0) { $text = new optTextNode(NULL, OPT_TEXT, $current); $currentBlock->addNode($text); } // character escaping if ($item == '\'') { $item = '\\\''; } if ($item == '\\') { $item = '\\\\'; } $text->addItem($item); $textAssign = 1; } } // execute the tree $this->processors['generic']->nodeProcess($root); if ($this->parseRun < 2) { $code = $output . '\';'; } // apply postfilters if (count($this->tpl->codeFilters['post']) > 0) { foreach ($this->tpl->codeFilters['post'] as $name) { $code = $name($code, $this->tpl); } } $this->parseRun--; return $code; }
public function parse($filename, $code, $master = false) { static $regex; static $blockRegex; $this->master = false; $this->dynamic = false; $this->dynamicEnabled = false; $this->dynamicSeg = array(0 => ''); $this->di = 0; $pre = 'pre'; if ($master) { $this->master = true; $pre = 'preMaster'; } foreach ($this->tpl->filters[$pre] as $name) { // @ used because of stupid notice // "Object of class optClass to string conversion". // Whatever it means, I couldn't recognize, why PHP does such things. $code = @$name($this->tpl, $code); } $code = str_replace(array('<' . '?'), array('<?php echo \'<?\'; ?' . '>'), $code); if ($regex == NULL || $this->tpl->nschange) { $nslist = implode('|', $this->tpl->namespaces); $blockRegex = '\\{literal\\}|\\{\\/literal\\}|\\{php\\}|\\{\\/php\\}'; if ($this->tpl->xmlsyntaxMode == 1) { $regex = ''; $this->tpl->delimiters[] = '\\<(\\/?)(' . $nslist . ')\\:(.*?)(\\/?)\\>'; $this->tpl->delimiters[] = '\\<()(' . $nslist . ')\\:(.*?)(\\/)\\>'; $this->tpl->delimiters[] = '(' . $nslist . ')\\:put\\=\\"(.*?[^\\\\])\\"'; $blockRegex = '\\<opt\\:literal\\>|\\<\\/opt\\:literal\\>|\\<opt\\:php\\>|\\<\\/opt\\:php\\>|' . $blockRegex; } $regex = str_replace('$$NS$$', $nslist, implode('|', $this->tpl->delimiters)); } $this->output = ''; // initialize the tree $root = $current = new optNode(NULL, OPT_ROOT, NULL); $rootBlock = $currentBlock = new optBlock(NULL); $root->addItem($rootBlock); $textAssign = 0; $commented = 0; $literal = false; $php = false; $textBlocks = preg_split('/(' . $blockRegex . ')/si', $code, 0, PREG_SPLIT_DELIM_CAPTURE); foreach ($textBlocks as $bid => $bval) { if (preg_match('/' . $blockRegex . '/si', $bval)) { // Escape the OPT namespace, if in XML Syntax mode if ($this->tpl->xmlsyntaxMode == 1) { $bval = str_replace('opt:', '', $bval); } // Check, what we have here if (strpos($bval, '/literal') !== false || $bval == ']]>') { $literal = false; } elseif (strpos($bval, 'literal') !== false || strpos($bval, 'CDATA') !== false) { if ($textAssign == 0) { $text = new optTextNode(NULL, OPT_TEXT, $current); $currentBlock->addNode($text); } $textAssign = 1; $literal = true; } elseif (strpos($bval, '/php') !== false) { $php = false; $text->addItem('?' . '>'); } elseif (strpos($bval, 'php') !== false) { $php = true; if ($textAssign == 0) { $text = new optTextNode(NULL, OPT_TEXT, $current); $currentBlock->addNode($text); } $textAssign = 1; $text->addItem('<' . '?php'); } } elseif ($literal == true || $php == true) { // Static literal/php text $text->addItem($bval); } elseif ($literal == false && $php == false) { // tokenizer preg_match_all('#({\\*.+?\\*\\}|' . $regex . ')#si', $bval, $result, PREG_PATTERN_ORDER); $resolution = sizeof($result); $offset = 0; foreach ($result[0] as $i => &$item) { // Copy static text $id = strpos($bval, $item, $offset); $staticText = substr($bval, $offset, $id - $offset); if ($textAssign == 0) { $text = new optTextNode(NULL, OPT_TEXT, $current); $currentBlock->addNode($text); } $text->addItem($staticText); $textAssign = 1; // Move to the end of the current token $offset = $id + strlen($item); // Process the token if (preg_match('/{\\*.+?\\*\\}/s', trim($item))) { continue; } // an attribute if ($result[8][$i] == ':') { // namespace checking $fakeAttribute = false; if ($result[7][$i] == 'opt') { $attribute = $result[9][$i]; } elseif (in_array($result[7][$i], $this->tpl->namespaces)) { $attribute = $result[7][$i] . ':' . $result[9][$i]; } else { $fakeAttribute = true; } if (!$fakeAttribute) { if (isset($this->translator[$attribute])) { if ($this->translator[$attribute] == OPT_ATTRIBUTE) { $node = new optNode($attribute, OPT_ATTRIBUTE, $current); $node->addItem(new optBlock($attribute, $result[10][$i])); $currentBlock->addNode($node); $textAssign = 0; } else { $fakeAttribute = true; } } else { $fakeAttribute = true; } } if ($fakeAttribute) { // text item if ($textAssign == 0) { $text = new optTextNode(NULL, OPT_TEXT, $current); $currentBlock->addNode($text); } $text->addItem($item); $textAssign = 1; } continue; } // a command $textAssign = 0; $sortMatches = array(0 => NULL, 1 => NULL, 2 => NULL, 3 => NULL); $foundCommand = false; for ($id = 1; $id < $resolution; $id++) { $val = trim($result[$id][$i]); if ($val != '') { if ($val[strlen($val) - 1] == ':') { continue; } if ($val == '/') { if (!$foundCommand) { $sortMatches[0] = '/'; } else { $sortMatches[2] = '/'; } } elseif ($id != 1) { // Namespace support if (!is_null($sortMatches[1])) { if ($sortMatches[1] == 'opt') { $sortMatches[1] = $val; } else { $sortMatches[3] = $sortMatches[1]; $sortMatches[1] .= ':' . $val; } } else { $sortMatches[3] = 'opt'; $sortMatches[1] = $val; } $foundCommand = true; } } } $sortMatches[1] = $this->parseEntities($sortMatches[1]); if (preg_match('/^(([a-zA-Z0-9\\_\\:]+)([= \\t]{1}(.*))?)$/s', $sortMatches[1], $found)) { // we have an instruction $realname = $found[2]; if ($sortMatches[0] == '/') { $found[2] = '/' . $found[2]; } $found[6] = $item; // general instructions if (isset($this->translator[$found[2]])) { switch ($this->translator[$found[2]]) { case OPT_COMMAND: $node = new optNode($found[2], OPT_INSTRUCTION, $current); $node->addItem(new optBlock($found[2], $found, OPT_COMMAND)); $currentBlock->addNode($node); break; case OPT_MASTER: $current->storeBlock($currentBlock); $current = new optNode($found[2], OPT_INSTRUCTION, $current); $currentBlock->addNode($current); $currentBlock = new optBlock($found[2], $found, OPT_MASTER); $current->addItem($currentBlock, $this->tpl); break; case OPT_ALT: $currentBlock = new optBlock($found[2], $found, OPT_ALT); $current->addItem($currentBlock); break; case OPT_ENDER: $currentBlock = new optBlock($found[2], $found, OPT_ENDER); $current->addItem($currentBlock, $this->tpl); $current = $current->getParent(); if (!is_object($current)) { $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: "' . $found[2] . '".', OPT_E_ENCLOSING_STATEMENT); } $currentBlock = $current->restoreBlock(); break; } } elseif ($realname == 'component' || isset($this->tpl->components[$realname])) { if ($sortMatches[0] == '/') { $currentBlock = new optBlock($found[2], $found); $current->addItem($currentBlock, $this->tpl); $current = $current->getParent(); if (!is_object($current)) { $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: "' . $found[2] . '".', OPT_E_ENCLOSING_STATEMENT); } $currentBlock = $current->restoreBlock(); } else { $current->storeBlock($currentBlock); $current = new optNode($realname, OPT_COMPONENT, $current); $currentBlock->addNode($current); $currentBlock = new optBlock($realname, $found); $current->addItem($currentBlock, $this->tpl); } } else { // here comes the undefined command. The instruction programmer may do with them whatever he wants // the compiler is going to recognize, what sort of command is it. But first - a small check. The // command must belong to the "opt" namespace. Otherwise it will be simply displayed. if ($sortMatches[3] == 'opt' || in_array($sortMatches[3], $this->tpl->namespaces)) { $ending = substr($found[2], strlen($found[2]) - 4, 4); if ($sortMatches[0] == '/') { // ending command, like in XML: /command $currentBlock = new optBlock($found[2], $found, OPT_ENDER); $current->addItem($currentBlock, $this->tpl); $current = $current->getParent(); if (!$current instanceof ioptNode) { $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: "' . $found[2] . '"!', OPT_E_ENCLOSING_STATEMENT); } $currentBlock = $current->restoreBlock(); } elseif ($sortMatches[2] == '/') { // standalone command, like XML: command/ $node = new optNode($found[2], OPT_UNKNOWN, $current); $node->addItem(new optBlock($found[2], $found, OPT_COMMAND), $this->tpl); $currentBlock->addNode($node); } elseif ($ending == 'else') { // alternative command, doesn't exist in XML: commandelse $currentBlock = new optBlock($found[2], $found, OPT_ALT); $current->addItem($currentBlock, $this->tpl); } else { // beginning command: command $current->storeBlock($currentBlock); $current = new optNode($realname, OPT_UNKNOWN, $current); $currentBlock->addNode($current); $currentBlock = new optBlock($realname, $found, OPT_MASTER); $current->addItem($currentBlock, $this->tpl); } } else { // Display the undefined command that doesn't belong to the "opt" namespace if ($textAssign == 0) { $text = new optTextNode(NULL, OPT_TEXT, $current); $currentBlock->addNode($text); } $text->addItem($item); $textAssign = 1; } } } else { // we have an expression $node = new optNode(NULL, OPT_EXPRESSION, $current); $node->addItem(new optBlock(NULL, $sortMatches[1])); $currentBlock->addNode($node); } } // No tokens left, copy just the rest of the $bval if ($textAssign == 0) { $text = new optTextNode(NULL, OPT_TEXT, $current); $currentBlock->addNode($text); } $text->addItem(substr($bval, $offset, strlen($bval) - $offset)); $textAssign = 1; } } if ($current->getType() != OPT_ROOT) { $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: "NULL"!', OPT_E_ENCLOSING_STATEMENT); } // execute the tree $this->processors['generic']->nodeProcess($root); $this->output = str_replace('?><' . '?php', '', $this->output); if (!$master) { // apply postfilters foreach ($this->tpl->filters['post'] as $name) { $this->output = $name($this->tpl, $this->output); } if (!is_null($filename)) { if (!is_writeable($this->tpl->compile)) { $this->tpl->error(E_USER_ERROR, $this->tpl->compile . ' is not a writeable directory.', OPT_E_WRITEABLE); } file_put_contents($filename, $this->output); if ($this->dynamicEnabled) { file_put_contents($filename . '.dyn', serialize($this->dynamicSeg)); } } return $this->output; } return true; }
public function parse($filename, $code) { static $regex; static $blockRegex; $this->dynamic = false; $this->dynamicEnabled = false; $this->dynamicSeg = array(0 => ''); $this->di = 0; foreach ($this->tpl->filters['pre'] as $name) { // @ used because of stupid notice // "Object of class opt_template to string conversion". // Whatever it means, I couldn't recognize, why PHP does such things. $code = @$name($this->tpl, $code); } $code = str_replace(array('<' . '?'), array('<?php echo \'<?\'; ?' . '>'), $code); if ($regex == NULL) { $blockRegex = '\\{literal\\}|\\{\\/literal\\}|\\{php\\}|\\{\\/php\\}'; if ($this->tpl->xmlsyntaxMode == 1) { $regex = ''; $this->tpl->delimiters[] = '\\<(\\/?)opt\\:(.*?)(\\/?)\\>'; $this->tpl->delimiters[] = '\\<()opt\\:(.*?)(\\/)\\>'; $this->tpl->delimiters[] = 'opt\\:put\\=\\"(.*?[^\\\\])\\"'; $blockRegex = '\\<opt\\:literal\\>|\\<\\/opt\\:literal\\>|\\<opt\\:php\\>|\\<\\/opt\\:php\\>|' . $blockRegex; } $regex = implode('|', $this->tpl->delimiters); } $this->output = ''; // initialize the tree $root = $current = new optNode(NULL, OPT_ROOT, NULL); $rootBlock = $currentBlock = new optBlock(NULL); $root->addItem($rootBlock); $textAssign = 0; $commented = 0; $literal = false; $php = false; $textBlocks = preg_split('/(' . $blockRegex . ')/ms', $code, 0, PREG_SPLIT_DELIM_CAPTURE); foreach ($textBlocks as $bid => $bval) { if (preg_match('/' . $blockRegex . '/ms', $bval)) { // Escape the OPT namespace, if in XML Syntax mode if ($this->tpl->xmlsyntaxMode == 1) { $bval = str_replace('opt:', '', $bval); } // Check, what we have here if (strpos($bval, '/literal') !== false || $bval == ']]>') { $literal = false; } elseif (strpos($bval, 'literal') !== false || strpos($bval, 'CDATA') !== false) { if ($textAssign == 0) { $text = new optTextNode(NULL, OPT_TEXT, $current); $currentBlock->addNode($text); } $textAssign = 1; $literal = true; } elseif (strpos($bval, '/php') !== false) { $php = false; $text->addItem('?' . '>'); } elseif (strpos($bval, 'php') !== false) { $php = true; if ($textAssign == 0) { $text = new optTextNode(NULL, OPT_TEXT, $current); $currentBlock->addNode($text); } $textAssign = 1; $text->addItem('<' . '?php'); } } elseif ($literal == true || $php == true) { // Static literal/php text $text->addItem($bval); } elseif ($literal == false && $php == false) { // tokenizer preg_match_all('#({\\*.+?\\*\\}|' . $regex . '|(.?))#msi', $bval, $result, PREG_PATTERN_ORDER); foreach ($result as $i => &$void) { if ($i != 0) { unset($result[$i]); } } foreach ($result[0] as $i => $item) { // comment usage if (strlen($item) > 1) { if (preg_match('/{\\*.+?\\*\\}/ms', trim($item))) { continue; } // a command $textAssign = 0; // grep the data $sortMatches = array(0 => '', 1 => '', 2 => ''); preg_match('/' . $regex . '/ms', $item, $matches); $foundCommand = false; foreach ($matches as $id => $val) { $val = trim($val); if ($val != '') { if ($val == '/') { if (!$foundCommand) { $sortMatches[0] = '/'; } else { $sortMatches[2] = '/'; } } elseif ($id != 0) { $sortMatches[1] = $val; $foundCommand = true; } } } $sortMatches[1] = $this->parseEntities($sortMatches[1]); if (preg_match('/^(([a-zA-Z0-9\\_]+)([= ]{1}(.*))?)$/ms', $sortMatches[1], $found)) { // we have an instruction $realname = $found[2]; if ($sortMatches[0] == '/') { $found[2] = '/' . $found[2]; } $found[6] = $item; // general instructions if (isset($this->translator[$found[2]])) { switch ($this->translator[$found[2]]) { case OPT_COMMAND: $node = new optNode($found[2], OPT_INSTRUCTION, $current); $node->addItem(new optBlock($found[2], $found, OPT_COMMAND)); $currentBlock->addNode($node); break; case OPT_MASTER: $current->storeBlock($currentBlock); $current = new optNode($found[2], OPT_INSTRUCTION, $current); $currentBlock->addNode($current); $currentBlock = new optBlock($found[2], $found, OPT_MASTER); $current->addItem($currentBlock, $this->tpl); break; case OPT_ALT: $currentBlock = new optBlock($found[2], $found, OPT_ALT); $current->addItem($currentBlock); break; case OPT_ENDER: $currentBlock = new optBlock($found[2], $found, OPT_ENDER); $current->addItem($currentBlock, $this->tpl); $current = $current->getParent(); if (!is_object($current)) { $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: "' . $found[2] . '".', OPT_E_ENCLOSING_STATEMENT); } $currentBlock = $current->restoreBlock(); break; } } elseif ($realname == 'component' || isset($this->tpl->components[$realname])) { if ($sortMatches[0] == '/') { $currentBlock = new optBlock($found[2], $found); $current->addItem($currentBlock, $this->tpl); $current = $current->getParent(); if (!is_object($current)) { $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: "' . $found[2] . '".', OPT_E_ENCLOSING_STATEMENT); } $currentBlock = $current->restoreBlock(); } else { $current->storeBlock($currentBlock); $current = new optNode($realname, OPT_COMPONENT, $current); $currentBlock->addNode($current); $currentBlock = new optBlock($realname, $found); $current->addItem($currentBlock, $this->tpl); } } else { // here comes the undefined command. The instruction programmer may do with them whatever he wants // the compiler is going to recognize, what sort of command is it. $ending = substr($found[2], strlen($found[2]) - 4, 4); if ($sortMatches[0] == '/') { // ending command, like in XML: /command $currentBlock = new optBlock($found[2], $found, OPT_ENDER); $current->addItem($currentBlock, $this->tpl); $current = $current->getParent(); if (!$current instanceof ioptNode) { $this->tpl->error(E_USER_ERROR, 'Unexpected enclosing statement: "' . $found[2] . '"!', OPT_E_ENCLOSING_STATEMENT); } $currentBlock = $current->restoreBlock(); } elseif ($sortMatches[2] == '/') { // standalone command, like XML: command/ $node = new optNode($found[2], OPT_UNKNOWN, $current); $node->addItem(new optBlock($found[2], $found, OPT_COMMAND), $this->tpl); $currentBlock->addNode($node); } elseif ($ending == 'else') { // alternative command, doesn't exist in XML: commandelse $currentBlock = new optBlock($found[2], $found, OPT_ALT); $current->addItem($currentBlock, $this->tpl); } else { // beginning command: command $current->storeBlock($currentBlock); $current = new optNode($realname, OPT_UNKNOWN, $current); $currentBlock->addNode($current); $currentBlock = new optBlock($realname, $found, OPT_MASTER); $current->addItem($currentBlock, $this->tpl); } } } else { // we have an expression $node = new optNode(NULL, OPT_EXPRESSION, $current); $node->addItem(new optBlock(NULL, $sortMatches[1])); $currentBlock->addNode($node); } } else { // text item if ($textAssign == 0) { $text = new optTextNode(NULL, OPT_TEXT, $current); $currentBlock->addNode($text); } $text->addItem($item); $textAssign = 1; } } } } // execute the tree $this->processors['generic']->nodeProcess($root); // apply postfilters foreach ($this->tpl->filters['post'] as $name) { $this->output = $name($this->tpl, $this->output); } if (!is_null($filename)) { if (!is_writeable($this->tpl->compile)) { $this->tpl->error(E_USER_ERROR, $this->tpl->compile . ' is not a writeable directory.', OPT_E_WRITEABLE); } file_put_contents($filename, $this->output); if ($this->dynamicEnabled) { file_put_contents($filename . '.dyn', serialize($this->dynamicSeg)); } } return $this->output; }