Compare commits
13 Commits
Author | SHA1 | Date |
---|---|---|
Vitaliy Filippov | feb2b5dd47 | |
Vitaliy Filippov | 7643be39f0 | |
Vitaliy Filippov | 56ef120056 | |
Vitaliy Filippov | e8c9cad6f6 | |
Vitaliy Filippov | 5f582e684b | |
Vitaliy Filippov | f32d481341 | |
Vitaliy Filippov | 912141f7c8 | |
Vitaliy Filippov | 86d7f58e00 | |
Vitaliy Filippov | 7a6be906c0 | |
Vitaliy Filippov | 0264610697 | |
Vitaliy Filippov | 0d0cfa98fd | |
Vitaliy Filippov | fc01aaeeb4 | |
Vitaliy Filippov | edb5c2d45c |
|
@ -7,12 +7,12 @@
|
||||||
*
|
*
|
||||||
* Homepage: http://yourcmc.ru/wiki/VMX::Template
|
* Homepage: http://yourcmc.ru/wiki/VMX::Template
|
||||||
* License: GNU GPLv3 or later
|
* License: GNU GPLv3 or later
|
||||||
* Author: Vitaliy Filippov, 2006-2015
|
* Author: Vitaliy Filippov, 2006-2020
|
||||||
* Version: V3 (LALR), 2015-04-12
|
* Version: V3 (LALR), 2020-01-01
|
||||||
*
|
*
|
||||||
* The template engine is split into two parts:
|
* The template engine is split into two parts:
|
||||||
* (1) This file - always used when running templates
|
* (1) This file - always used when running templates
|
||||||
* (2) template.parser.php - used only when compiling new templates
|
* (2) VMXTemplateCompiler.php - used only when compiling new templates
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,6 +49,9 @@ if (!defined('TS_UNIX'))
|
||||||
|
|
||||||
class VMXTemplate
|
class VMXTemplate
|
||||||
{
|
{
|
||||||
|
// Loaded template class names
|
||||||
|
public static $loadedClasses = [];
|
||||||
|
|
||||||
static $Mon, $mon, $Wday;
|
static $Mon, $mon, $Wday;
|
||||||
static $cache_type = NULL;
|
static $cache_type = NULL;
|
||||||
static $cache = array();
|
static $cache = array();
|
||||||
|
@ -230,16 +233,17 @@ class VMXTemplate
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* parse_real variant that does not require $vars to be an lvalue
|
* parse_real variant that does not require $vars to be an lvalue
|
||||||
|
* and does not run filters on output
|
||||||
*/
|
*/
|
||||||
protected function parse_discard($fn, $inline, $func, $vars = NULL)
|
protected function parse_discard($fn, $inline, $func, $vars = NULL)
|
||||||
{
|
{
|
||||||
return $this->parse_real($fn, $inline, $func, $vars);
|
return $this->parse_real($fn, $inline, $func, $vars, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Real" parse function, handles all parse_*()
|
* "Real" parse function, handles all parse_*()
|
||||||
*/
|
*/
|
||||||
protected function parse_real($fn, $inline, $func, &$vars = NULL)
|
protected function parse_real($fn, $inline, $func, &$vars = NULL, $run_filters = true)
|
||||||
{
|
{
|
||||||
if (!$fn)
|
if (!$fn)
|
||||||
{
|
{
|
||||||
|
@ -325,7 +329,7 @@ class VMXTemplate
|
||||||
{
|
{
|
||||||
error_reporting($old);
|
error_reporting($old);
|
||||||
}
|
}
|
||||||
if ($this->options->filters)
|
if ($run_filters && $this->options->filters)
|
||||||
{
|
{
|
||||||
$filters = $this->options->filters;
|
$filters = $this->options->filters;
|
||||||
if (is_callable($filters) || is_string($filters) && is_callable(array(__CLASS__, "filter_$filters")))
|
if (is_callable($filters) || is_string($filters) && is_callable(array(__CLASS__, "filter_$filters")))
|
||||||
|
@ -348,6 +352,40 @@ class VMXTemplate
|
||||||
return $t;
|
return $t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translate template file line number from stack frame $frame (taken from debug_backtrace())
|
||||||
|
*/
|
||||||
|
public function translateLine(&$frame)
|
||||||
|
{
|
||||||
|
if (isset(VMXTemplate::$loadedClasses[$frame['file']]))
|
||||||
|
{
|
||||||
|
$class = VMXTemplate::$loadedClasses[$frame['file']];
|
||||||
|
if (isset($class::$smap))
|
||||||
|
{
|
||||||
|
$l = $frame['line'];
|
||||||
|
$s = 0;
|
||||||
|
$e = count($class::$smap);
|
||||||
|
while ($e > $s+1)
|
||||||
|
{
|
||||||
|
if ($l < $class::$smap[($e+$s)>>1][0])
|
||||||
|
$e = ($e+$s)>>1;
|
||||||
|
else
|
||||||
|
$s = ($e+$s)>>1;
|
||||||
|
}
|
||||||
|
$frame['file'] = $class::$template_filename;
|
||||||
|
$frame['line'] = $class::$smap[$s][1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($frame['class']) && substr($frame['class'], 0, 9) == 'Template_')
|
||||||
|
{
|
||||||
|
$class = $frame['class'];
|
||||||
|
$frame['class'] = $class::$template_filename;
|
||||||
|
$frame['type'] = '->';
|
||||||
|
if (substr($frame['function'], 0, 3) == 'fn_')
|
||||||
|
$frame['function'] = substr($frame['function'], 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load file (with caching)
|
* Load file (with caching)
|
||||||
*
|
*
|
||||||
|
@ -424,12 +462,15 @@ class VMXTemplate
|
||||||
$func_ns = md5($fn);
|
$func_ns = md5($fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->options->strip_space)
|
||||||
|
self::filter_strip_space($code);
|
||||||
if (!$this->compiler)
|
if (!$this->compiler)
|
||||||
{
|
{
|
||||||
require_once(dirname(__FILE__).'/template.parser.php');
|
require_once(dirname(__FILE__).'/VMXTemplateCompiler.php');
|
||||||
$this->compiler = new VMXTemplateCompiler($this->options);
|
$this->compiler = new VMXTemplateCompiler($this->options);
|
||||||
}
|
}
|
||||||
$compiled = $this->compiler->parse_all($code, $fn, $func_ns);
|
$compiled = $this->compiler->parse_all($code, $fn, $func_ns);
|
||||||
|
$compiled .= "VMXTemplate::\$loadedClasses['".addcslashes(realpath(dirname($file)).'/'.basename($file), '\\\'')."'] = 'Template_$func_ns';\n";
|
||||||
if (!file_put_contents($file, $compiled))
|
if (!file_put_contents($file, $compiled))
|
||||||
{
|
{
|
||||||
throw new VMXTemplateException("Failed writing $file");
|
throw new VMXTemplateException("Failed writing $file");
|
||||||
|
@ -460,7 +501,7 @@ class VMXTemplate
|
||||||
{
|
{
|
||||||
// FIXME maybe do it better!
|
// FIXME maybe do it better!
|
||||||
$fn = $this->function_search_path[$block][0][0];
|
$fn = $this->function_search_path[$block][0][0];
|
||||||
return $this->parse_real($fn, NULL, $block, $args);
|
return $this->parse_real($fn, NULL, $block, $args, false);
|
||||||
}
|
}
|
||||||
throw new VMXTemplateException("Unknown block '$block'$errorinfo");
|
throw new VMXTemplateException("Unknown block '$block'$errorinfo");
|
||||||
}
|
}
|
||||||
|
@ -471,7 +512,7 @@ class VMXTemplate
|
||||||
{
|
{
|
||||||
$fun = $this->function_search_path[$block][0];
|
$fun = $this->function_search_path[$block][0];
|
||||||
$args = array_combine($fun[1], array_pad(array_slice($args, 0, count($fun[1])), count($fun[1]), NULL));
|
$args = array_combine($fun[1], array_pad(array_slice($args, 0, count($fun[1])), count($fun[1]), NULL));
|
||||||
return $this->parse_real($fun[0], NULL, $block, $args);
|
return $this->parse_real($fun[0], NULL, $block, $args, false);
|
||||||
}
|
}
|
||||||
throw new VMXTemplateException("Unknown block or function '$block'$errorinfo");
|
throw new VMXTemplateException("Unknown block or function '$block'$errorinfo");
|
||||||
}
|
}
|
||||||
|
@ -556,7 +597,14 @@ class VMXTemplate
|
||||||
static function exec_subst($str)
|
static function exec_subst($str)
|
||||||
{
|
{
|
||||||
$args = func_get_args();
|
$args = func_get_args();
|
||||||
$str = preg_replace_callback('/(?<!\\\\)((?:\\\\\\\\)*)\$(?:([1-9]\d*)|\{([1-9]\d*)\})/is', create_function('$m', 'return $args[$m[2]?$m[2]:$m[3]];'), $str);
|
$str = preg_replace_callback(
|
||||||
|
'/(?<!\\\\)((?:\\\\\\\\)*)\$(?:([1-9]\d*)|\{([1-9]\d*)\})/is',
|
||||||
|
function($m) use($args)
|
||||||
|
{
|
||||||
|
return $args[$m[2] ? $m[2] : $m[3]];
|
||||||
|
},
|
||||||
|
$str
|
||||||
|
);
|
||||||
return $str;
|
return $str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,11 +632,11 @@ class VMXTemplate
|
||||||
}
|
}
|
||||||
|
|
||||||
// For a hash, returns an array with pairs { key => 'key', value => 'value' }
|
// For a hash, returns an array with pairs { key => 'key', value => 'value' }
|
||||||
static function exec_pairs($array)
|
static function exec_pairs($array, $kf = 'key', $vf = 'value')
|
||||||
{
|
{
|
||||||
$r = array();
|
$r = array();
|
||||||
foreach ($array as $k => $v)
|
foreach ($array as $k => $v)
|
||||||
$r[] = array('key' => $k, 'value' => $v);
|
$r[] = array($kf => $k, $vf => $v);
|
||||||
return $r;
|
return $r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -784,22 +832,18 @@ class VMXTemplateOptions
|
||||||
$this->$k = $v;
|
$this->$k = $v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->strip_space && array_search('strip_space', $this->filters) === false)
|
|
||||||
{
|
|
||||||
$this->filters[] = 'strip_space';
|
|
||||||
}
|
|
||||||
if (!$this->begin_subst || !$this->end_subst)
|
if (!$this->begin_subst || !$this->end_subst)
|
||||||
{
|
{
|
||||||
$this->begin_subst = false;
|
$this->begin_subst = false;
|
||||||
$this->end_subst = false;
|
$this->end_subst = false;
|
||||||
$this->no_code_subst = false;
|
$this->no_code_subst = false;
|
||||||
}
|
}
|
||||||
$this->cache_dir = preg_replace('!/*$!s', '/', $this->cache_dir);
|
$this->cache_dir = preg_replace('!([^/])/*$!s', '\1/', $this->cache_dir);
|
||||||
if (!is_writable($this->cache_dir))
|
if (!is_writable($this->cache_dir))
|
||||||
{
|
{
|
||||||
throw new VMXTemplateException('VMXTemplate: cache_dir='.$this->cache_dir.' is not writable');
|
throw new VMXTemplateException('VMXTemplate: cache_dir='.$this->cache_dir.' is not writable');
|
||||||
}
|
}
|
||||||
$this->root = preg_replace('!/*$!s', '/', $this->root);
|
$this->root = preg_replace('!([^/])/*$!s', '\1/', $this->root);
|
||||||
}
|
}
|
||||||
|
|
||||||
function __destruct()
|
function __destruct()
|
File diff suppressed because it is too large
Load Diff
10
compile.sh
10
compile.sh
|
@ -1,14 +1,14 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
if [ "$LIME_DIR" = "" ]; then
|
if [ "$LIME_DIR" = "" ]; then
|
||||||
LIME_DIR=~/gits/lime/
|
LIME_DIR=./lime/
|
||||||
fi
|
fi
|
||||||
|
|
||||||
php -d xdebug.max_nesting_level=200 $LIME_DIR/lime.php template.lime | tail -n +2 > template.class
|
php -d xdebug.max_nesting_level=200 $LIME_DIR/lime.php template.lime | tail -n +2 > template.class
|
||||||
LINES=`grep -n -h " \*\*\* DON'T EDIT THIS FILE! \*\*\*" template.parser.php | perl -pe 's/(\d+):.*/$1-2/e'`
|
LINES=`grep -n -h " \*\*\* DON'T EDIT THIS FILE! \*\*\*" VMXTemplateCompiler.php | perl -pe 's/(\d+):.*/$1-2/e'`
|
||||||
if [ "$LINES" != "" ]; then
|
if [ "$LINES" != "" ]; then
|
||||||
head -n $LINES template.parser.php | cat - template.class > template.parser.php.new
|
head -n $LINES VMXTemplateCompiler.php | cat - template.class > VMXTemplateCompiler.php.new
|
||||||
else
|
else
|
||||||
cat template.parser.php template.class > template.parser.php.new
|
cat VMXTemplateCompiler.php template.class > VMXTemplateCompiler.php.new
|
||||||
fi
|
fi
|
||||||
mv template.parser.php.new template.parser.php
|
mv VMXTemplateCompiler.php.new VMXTemplateCompiler.php
|
||||||
|
|
|
@ -50,6 +50,8 @@
|
||||||
%token ">" "greater than operator '>'"
|
%token ">" "greater than operator '>'"
|
||||||
%token "<=" "less or equal operator '<='"
|
%token "<=" "less or equal operator '<='"
|
||||||
%token ">=" "greater or equal operator '>='"
|
%token ">=" "greater or equal operator '>='"
|
||||||
|
%token "?" "ternary operator '? :'"
|
||||||
|
%token ":" "ternary operator '? :'"
|
||||||
%token "+" "plus operator '+'"
|
%token "+" "plus operator '+'"
|
||||||
%token "-" "minus operator '-'"
|
%token "-" "minus operator '-'"
|
||||||
%token "*" "multiply operator '*'"
|
%token "*" "multiply operator '*'"
|
||||||
|
@ -71,6 +73,7 @@
|
||||||
%token "}}" "substitution end"
|
%token "}}" "substitution end"
|
||||||
|
|
||||||
%left ".."
|
%left ".."
|
||||||
|
%nonassoc "?" ":"
|
||||||
%left "||" "OR" "XOR"
|
%left "||" "OR" "XOR"
|
||||||
%left "&&" "AND"
|
%left "&&" "AND"
|
||||||
%nonassoc "==" "!=" "<" ">" "<=" ">="
|
%nonassoc "==" "!=" "<" ">" "<=" ">="
|
||||||
|
@ -89,7 +92,7 @@ chunks = {
|
||||||
$$ = '';
|
$$ = '';
|
||||||
}
|
}
|
||||||
| chunks chunk {
|
| chunks chunk {
|
||||||
$$ = $1 . $2;
|
$$ = $1 . "# line ".$this->template->lexer->lineno."\n" . $2;
|
||||||
}
|
}
|
||||||
.
|
.
|
||||||
chunk = literal {
|
chunk = literal {
|
||||||
|
@ -140,7 +143,7 @@ c_fn = fn name/name "(" arglist/args ")" "=" exp/exp {
|
||||||
$this->template->st->functions[$name] = array(
|
$this->template->st->functions[$name] = array(
|
||||||
'name' => $name,
|
'name' => $name,
|
||||||
'args' => $args,
|
'args' => $args,
|
||||||
'body' => 'function fn_'.$name." () {\nreturn ".$exp.";\n}\n",
|
'body' => 'function fn_'.$name." () {\nreturn ".$exp[0].";\n}\n",
|
||||||
//'line' => $line, Ой, я чо - аргументы не юзаю?
|
//'line' => $line, Ой, я чо - аргументы не юзаю?
|
||||||
//'pos' => $pos,
|
//'pos' => $pos,
|
||||||
);
|
);
|
||||||
|
@ -196,6 +199,9 @@ exp: exp/a ".." exp/b {
|
||||||
| exp/a "AND" exp/b {
|
| exp/a "AND" exp/b {
|
||||||
$$ = [ '(' . $a[0] . ' && ' . $b[0] . ')', true ];
|
$$ = [ '(' . $a[0] . ' && ' . $b[0] . ')', true ];
|
||||||
}
|
}
|
||||||
|
| exp/a "?" exp/b ":" exp/c {
|
||||||
|
$$ = [ '(' . $a[0] . ' ? ' . $b[0] . ' : ' . $c[0] . ')', $b[1] && $c[1] ];
|
||||||
|
}
|
||||||
| exp/a "==" exp/b {
|
| exp/a "==" exp/b {
|
||||||
$$ = [ '(' . $a[0] . ' == ' . $b[0] . ')', true ];
|
$$ = [ '(' . $a[0] . ' == ' . $b[0] . ')', true ];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue