mirror of
https://github.com/fenom-template/fenom.git
synced 2023-08-10 21:13:07 +03:00
Merge pull request #12 from sectus/refactoring
Refactoring Fenom\Template::compile: Removed goto, Fix bug with ignoring
This commit is contained in:
commit
3583a2cdfd
@ -165,60 +165,63 @@ class Template extends Render {
|
|||||||
public function compile() {
|
public function compile() {
|
||||||
$end = $pos = 0;
|
$end = $pos = 0;
|
||||||
$this->escape = $this->_options & Fenom::AUTO_ESCAPE;
|
$this->escape = $this->_options & Fenom::AUTO_ESCAPE;
|
||||||
|
|
||||||
while(($start = strpos($this->_src, '{', $pos)) !== false) { // search open-symbol of tags
|
while(($start = strpos($this->_src, '{', $pos)) !== false) { // search open-symbol of tags
|
||||||
switch($this->_src[$start + 1]) { // check next character
|
switch($this->_src[$start + 1]) { // check next character
|
||||||
case "\n": case "\r": case "\t": case " ": case "}": // ignore the tag
|
case "\n": case "\r": case "\t": case " ": case "}": // ignore the tag
|
||||||
$pos = $start + 1;
|
$this->_appendText(substr($this->_src, $pos, $start - $pos + 2));
|
||||||
continue 2;
|
$end = $start + 1;
|
||||||
|
break;
|
||||||
case "*": // if comments
|
case "*": // if comments
|
||||||
$end = strpos($this->_src, '*}', $start) + 1; // find end of the comment block
|
$end = strpos($this->_src, '*}', $start); // find end of the comment block
|
||||||
if($end === false) {
|
if($end === false) {
|
||||||
throw new CompileException("Unclosed comment block in line {$this->_line}", 0, 1, $this->_name, $this->_line);
|
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));
|
$this->_appendText(substr($this->_src, $pos, $start - $pos));
|
||||||
$comment = substr($this->_src, $start, $end - $start); // read the comment block for processing
|
$comment = substr($this->_src, $start, $end - $start); // read the comment block for processing
|
||||||
$this->_line += substr_count($comment, "\n"); // count lines in comments
|
$this->_line += substr_count($comment, "\n"); // count lines in comments
|
||||||
unset($comment); // cleanup
|
unset($comment); // cleanup
|
||||||
$pos = $end + 1;
|
// $pos = $end + 1;
|
||||||
continue 2;
|
break;
|
||||||
|
default:
|
||||||
|
$this->_appendText(substr($this->_src, $pos, $start - $pos));
|
||||||
|
$end = $start + 1;
|
||||||
|
do {
|
||||||
|
$need_next_close_symbol = 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, $end - $start + 1); // variable $tag contains fenom tag '{...}'
|
||||||
|
|
||||||
|
$_tag = substr($tag, 1, -1); // strip delimiters '{' and '}'
|
||||||
|
|
||||||
|
if($this->_ignore) { // check ignore
|
||||||
|
if($_tag === '/ignore') { // turn off ignore
|
||||||
|
$this->_ignore = false;
|
||||||
|
} else { // still ignore
|
||||||
|
$this->_appendText($tag);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$tokens = new Tokenizer($_tag); // tokenize the tag
|
||||||
|
if($tokens->isIncomplete()) { // all strings finished?
|
||||||
|
$need_next_close_symbol = true;
|
||||||
|
} else {
|
||||||
|
$this->_appendCode( $this->_tag($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_next_close_symbol);
|
||||||
|
// $pos = $end + 1; // move search-pointer to end of the tag
|
||||||
|
unset($_tag, $tag); // cleanup
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
$frag = substr($this->_src, $pos, $start - $pos); // variable $frag contains chars after previous '}' and current '{'
|
$pos = $end + 1; // move search-pointer to end of the tag
|
||||||
$this->_appendText($frag);
|
|
||||||
|
|
||||||
$from = $start;
|
|
||||||
reparse: { // yep, i use goto operator. For this algorithm it is good choice
|
|
||||||
$end = strpos($this->_src, '}', $from); // 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, $end - $start + 1); // variable $tag contains fenom tag '{...}'
|
|
||||||
|
|
||||||
$_tag = substr($tag, 1, -1); // strip delimiters '{' and '}'
|
|
||||||
|
|
||||||
if($this->_ignore) { // check ignore
|
|
||||||
if($_tag === '/ignore') { // turn off ignore
|
|
||||||
$this->_ignore = false;
|
|
||||||
} else { // still ignore
|
|
||||||
$this->_appendText($tag);
|
|
||||||
}
|
|
||||||
$pos = $start + strlen($tag);
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
$tokens = new Tokenizer($_tag); // tokenize the tag
|
|
||||||
if($tokens->isIncomplete()) { // all strings finished?
|
|
||||||
$from = $end + 1;
|
|
||||||
goto reparse; // need next close-symbol
|
|
||||||
}
|
|
||||||
$this->_appendCode( $this->_tag($tokens) , $tag); // start the tag lexer
|
|
||||||
$pos = $end + 1; // move search-pointer to end of the tag
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unset($frag, $_tag, $tag); // cleanup
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gc_collect_cycles();
|
gc_collect_cycles();
|
||||||
$this->_appendText(substr($this->_src, $end ? $end + 1 : 0));
|
$this->_appendText(substr($this->_src, $end ? $end + 1 : 0));
|
||||||
if($this->_stack) {
|
if($this->_stack) {
|
||||||
|
@ -14,6 +14,10 @@ class CommentTest extends TestCase {
|
|||||||
$this->assertRender("before {*{{$tpl_val}}*} after", "before after");
|
$this->assertRender("before {*{{$tpl_val}}*} after", "before after");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testError() {
|
||||||
|
$this->execError('{* ', 'Fenom\CompileException', "Unclosed comment block in line");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider providerScalars
|
* @dataProvider providerScalars
|
||||||
*/
|
*/
|
||||||
|
@ -448,6 +448,7 @@ class TemplateTest extends TestCase {
|
|||||||
array('{if 0}none{/if} literal: {$a} end', $a, 'literal: lit. A end'),
|
array('{if 0}none{/if} literal: {$a} end', $a, 'literal: lit. A end'),
|
||||||
array('{if 0}none{/if} literal:{ignore} {$a} {/ignore} end', $a, 'literal: {$a} end'),
|
array('{if 0}none{/if} literal:{ignore} {$a} {/ignore} end', $a, 'literal: {$a} end'),
|
||||||
array('{if 0}none{/if} literal: { $a} end', $a, 'literal: { $a} end'),
|
array('{if 0}none{/if} literal: { $a} end', $a, 'literal: { $a} end'),
|
||||||
|
array('{if 0}none{/if} literal: { $a}{$a}{ $a} end', $a, 'literal: { $a}lit. A{ $a} end'),
|
||||||
array('{if 0}none{/if} literal: {
|
array('{if 0}none{/if} literal: {
|
||||||
$a} end', $a, 'literal: { $a} end'),
|
$a} end', $a, 'literal: { $a} end'),
|
||||||
array('{if 0}none{/if}literal: function () { return 1; } end', $a, 'literal: function () { return 1; } end')
|
array('{if 0}none{/if}literal: function () { return 1; } end', $a, 'literal: function () { return 1; } end')
|
||||||
|
Loading…
Reference in New Issue
Block a user