public static function Compile($template) { // Initialization self::$current_line = 1; self::$tag_stack = array(); self::$literal_stack = array(); self::$capture_stack = array(); self::$errors = array(); self::$defines = array(); self::$has_nocache = false; // Convert to Unix newline characters $template = String::FormatNewlines($template); // Mark with line numbers $line_number = 0; $marked_template = ''; foreach (explode(String::NEWLINE_UNIX, $template) as $line) { $line_number++; $marked_template .= preg_replace('~{([/$a-z"]+)~i', "(*{$line_number}*){\\1", $line) . String::NEWLINE_UNIX; } unset($template); // Strip comment sections $marked_template = preg_replace('~{\\*.*?\\*}~msi', '', $marked_template); // Create regular expression $regex = '~\\(\\*(\\d+)\\*\\)' . self::DELIMITER_START . '([/*$a-z"]+.*?)' . self::DELIMITER_END . '~msi'; // Compile the code $compiled = preg_replace_callback($regex, array('self', 'CompileTag'), $marked_template); // Second pass to handle {nocache} sections $compiled = preg_replace_callback('~\\{nocache\\}(.*?)\\{/nocache\\}~msi', array('self', 'NocachePass'), $compiled); // Check for unclosed tag(s) foreach (self::$tag_stack as $unclosed_tag) { self::$errors[] = 'Unclosed {' . $unclosed_tag . '} tag at end of template'; } // Check for unclosed literal sections foreach (self::$literal_stack as $unclosed_tag) { self::$errors[] = 'Unclosed {' . $unclosed_tag . '} tag at end of template'; } // Code cleanup $compiled = preg_replace("~\n+~", "\n", trim($compiled)); if (self::$has_nocache) { $compiled = self::PHP_START . '$this->nocache = true;' . self::PHP_END . $compiled; } return count(self::$errors) ? false : $compiled; }