Debug VMXTemplate

databind
vitalif 2012-09-30 22:44:37 +00:00 committed by Vitaliy Filippov
parent ee664c2dfc
commit b877d4ebbe
1 changed files with 55 additions and 14 deletions

View File

@ -4,6 +4,7 @@
# "Oh that perlists... anything they write is just another Template Toolkit"
# Rewritten 3 times: regex -> index() -> grammar. Still backwards compatible...
# Needs another rewrite to some parser generator. Maybe LIME...
# Homepage: http://yourcmc.ru/wiki/VMX::Template
# Author: Vitaliy Filippov, 2006-2012
@ -862,18 +863,25 @@ class VMXTemplateParser
{
// TODO Maybe report parse traces?
$l = strlen($this->code);
$linestart = strrpos($this->code, "\n", $this->pos-$l) ?: 0;
$linestart = strrpos($this->code, "\n", $this->pos-$l-1) ?: -1;
$lineend = strpos($this->code, "\n", $this->pos) ?: $l;
$line = substr($this->code, $linestart+1, $this->pos-$linestart-1);
$line .= '^^^';
$line .= substr($this->code, $this->pos, $lineend-$this->pos);
return "in {$this->st->input_filename}, line {$this->lineno}, byte {$this->pos}, marked by ^^^ in $line";
return "in {$this->st->input_filename}, line ".($this->lineno+1).", byte {$this->pos}, marked by ^^^ in $line";
}
function warn($text)
{
// FIXME
print $text."\n";
if (PHP_SAPI == 'cli')
{
print "$text\n";
}
else
{
print htmlspecialchars($text).'<br />';
}
}
function raise($msg)
@ -978,6 +986,18 @@ class VMXTemplateParser
return $t;
}
/**
* Assume next token is "EOD" (end-of-directive)
* Used in "stateful" directives to prevent changing state on incorrect parse
*/
function assume_eod()
{
if ($this->tok() != $this->eod)
{
$this->unexpected($this->eod, 1);
}
}
/**
* Raise "unexpected token" error
*/
@ -1033,6 +1053,7 @@ class VMXTemplateParser
$blocks = array(
array(
'begin' => $this->options->begin_code,
'end' => $this->options->end_code,
'handler' => 'parse_code',
'eat' => $this->options->eat_code_line
),
@ -1041,6 +1062,7 @@ class VMXTemplateParser
{
$blocks[] = array(
'begin' => $this->options->begin_subst,
'end' => $this->options->end_subst,
'handler' => 'parse_subst',
'eat' => false,
);
@ -1079,7 +1101,10 @@ class VMXTemplateParser
// Set source position and line number
$lineno = $this->lineno;
$pos = $blocks[$min]['pos'];
$this->lineno += substr_count($this->code, "\n", $this->pos, $pos-$this->pos);
if ($pos > $this->pos)
{
$this->lineno += substr_count($this->code, "\n", $this->pos, $pos-$this->pos);
}
$this->pos = $pos + strlen($blocks[$min]['begin']);
if ($blocks[$min]['eat'])
{
@ -1097,11 +1122,13 @@ class VMXTemplateParser
}
// Reset token buffer
$this->clear_tokens();
$this->eod = $blocks[$min]['end'];
$handler = $blocks[$min]['handler'];
try
{
// Try to parse from here, skip invalid parts
$r = $this->$handler();
$this->consume($this->eod);
// Add newline count from code fragment
$this->lineno += substr_count($this->code, "\n", $pos, $this->pos-$pos);
}
@ -1121,6 +1148,10 @@ class VMXTemplateParser
{
$p++;
}
if ($c == "\n")
{
$this->lineno++;
}
if ($p == $this->codelen || $c == "\n")
{
if ($p < $this->codelen)
@ -1201,7 +1232,10 @@ $code
if ($t == '$if')
{
$this->ptr++;
return "if (".$this->parse_exp().") {";
$e = $this->parse_exp();
$this->assume_eod();
$this->st->in[] = array('if');
return "if ($e) {";
}
elseif ($t == '$else')
{
@ -1233,6 +1267,7 @@ $code
$this->ptr++;
$exp = $this->parse_exp();
}
$this->assume_eod();
$this->st->in[] = array('for', $parts, $exp);
return $this->gen_foreach($parts, $exp);
}
@ -1257,15 +1292,16 @@ $code
}
// SET directive
$this->ptr++;
$varref = $this->gen_varref($this->parse_varref());
$def = $this->parse_varref();
if ($this->tok() == '=')
{
// SET varref = exp
$this->ptr++;
$e = $this->parse_exp();
return $varref . ' = ' . $e . ';';
return $this->gen_varref($def) . ' = ' . $e . ';';
}
$this->st->in[] = array('set', $varref);
$this->assume_eod();
$this->st->in[] = array('set', $def);
return "\$stack[] = \$t;\n\$t = '';";
}
elseif ($t == '$function' || $t == '$block' || $t == '$macro')
@ -1306,6 +1342,7 @@ $code
break;
}
}
$this->assume_eod();
$this->st->blocks[] = $bname;
$parts = $this->st->blocks;
$this->st->in[] = array('begin', array($bname), $t);
@ -1328,6 +1365,12 @@ $code
// Optionally with varref specifying what block should end here.
function parse_end()
{
$end_subj = false;
if (substr($this->tok(), 0, 1) == '$')
{
$end_subj = $this->parse_varref();
}
$this->assume_eod();
if (!count($this->st->in))
{
$this->raise("END without begin directive");
@ -1335,13 +1378,10 @@ $code
$in = array_pop($this->st->in);
$w = $in[0];
$begin_subj = isset($in[1]) ? $in[1] : false;
$end_subj = false;
if (substr($this->tok(), 0, 1) == '$')
$end_subj = $this->parse_varref();
if ($begin_subj)
{
$b = implode($begin_subj, '.');
if ($end_subj ? $b != ($e = implode($end_subj, '.')) : $this->options->strict_end)
$b = implode('.', $begin_subj);
if ($end_subj ? $b != ($e = implode('.', $end_subj)) : $this->options->strict_end)
{
$w = strtoupper($w);
$this->raise(
@ -1352,7 +1392,7 @@ $code
}
if ($w == 'set')
{
return "$in[1] = \$t;\n\$t = array_pop(\$stack);";
return $this->gen_varref($in[1])." = \$t;\n\$t = array_pop(\$stack);";
}
elseif ($w == 'function')
{
@ -1396,6 +1436,7 @@ $varref = array_pop(\$stack);";
{
$code = $this->parse_exp();
}
$this->assume_eod();
if (isset($this->st->functions[$name]))
{
$this->raise(