|
|
<?php
|
|
|
|
|
|
/*
|
|
|
|
|
|
Copyrights for code authored by Yahoo! Inc. is licensed under the following terms:
|
|
|
MIT License
|
|
|
Copyright (c) 2013-2015 Yahoo! Inc. All Rights Reserved.
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
Copyrights for code authored by Yahoo! Inc. is licensed under the following terms:
|
|
|
MIT License
|
|
|
Copyright (c) 2013-2015 Yahoo! Inc. All Rights Reserved.
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
Origin: https://github.com/zordius/lightncandy
|
|
|
*/
|
|
|
Origin: https://github.com/zordius/lightncandy
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* This is abstract engine which defines must-have methods.
|
...
|
...
|
@@ -17,27 +18,26 @@ Origin: https://github.com/zordius/lightncandy |
|
|
* @package LightnCandy
|
|
|
* @author Zordius <zordius@yahoo-inc.com>
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* LightnCandy static core class.
|
|
|
*/
|
|
|
|
|
|
namespace Plugin;
|
|
|
|
|
|
class LightnCandy {
|
|
|
class LightnCandy
|
|
|
{
|
|
|
|
|
|
// Compile time error handling flags
|
|
|
const FLAG_ERROR_LOG = 1;
|
|
|
const FLAG_ERROR_EXCEPTION = 2;
|
|
|
const FLAG_ERROR_SKIPPARTIAL = 4194304;
|
|
|
|
|
|
// Compile the template as standalone PHP code which can execute without including LightnCandy
|
|
|
const FLAG_STANDALONE = 4;
|
|
|
const FLAG_BARE = 33554432;
|
|
|
const FLAG_NOESCAPE = 67108864;
|
|
|
|
|
|
// JavaScript compatibility
|
|
|
const FLAG_JSTRUE = 8;
|
|
|
const FLAG_JSOBJECT = 16;
|
|
|
|
|
|
// Handlebars.js compatibility
|
|
|
const FLAG_THIS = 32;
|
|
|
const FLAG_WITH = 64;
|
...
|
...
|
@@ -49,22 +49,18 @@ class LightnCandy { |
|
|
const FLAG_SPVARS = 4096;
|
|
|
const FLAG_SLASH = 8388608;
|
|
|
const FLAG_ELSE = 16777216;
|
|
|
|
|
|
// PHP behavior flags
|
|
|
const FLAG_EXTHELPER = 8192;
|
|
|
const FLAG_ECHO = 16384;
|
|
|
const FLAG_PROPERTY = 32768;
|
|
|
const FLAG_METHOD = 65536;
|
|
|
const FLAG_RUNTIMEPARTIAL = 1048576;
|
|
|
|
|
|
// Mustache compatibility
|
|
|
const FLAG_MUSTACHESP = 131072;
|
|
|
const FLAG_MUSTACHELOOKUP = 262144;
|
|
|
const FLAG_MUSTACHEPAIN = 2097152;
|
|
|
|
|
|
// Template rendering time debug flags
|
|
|
const FLAG_RENDER_DEBUG = 524288;
|
|
|
|
|
|
// alias flags
|
|
|
const FLAG_BESTPERFORMANCE = 16384; // FLAG_ECHO
|
|
|
const FLAG_JS = 24; // FLAG_JSTRUE + FLAG_JSOBJECT
|
...
|
...
|
@@ -72,12 +68,10 @@ class LightnCandy { |
|
|
const FLAG_HANDLEBARS = 27402208; // FLAG_THIS + FLAG_WITH + FLAG_PARENT + FLAG_JSQUOTE + FLAG_ADVARNAME + FLAG_SPACECTL + FLAG_NAMEDARG + FLAG_SPVARS + FLAG_SLASH + FLAG_ELSE + FLAG_MUSTACHESP + FLAG_MUSTACHEPAIN
|
|
|
const FLAG_HANDLEBARSJS = 27402232; // FLAG_JS + FLAG_HANDLEBARS
|
|
|
const FLAG_INSTANCE = 98304; // FLAG_PROPERTY + FLAG_METHOD
|
|
|
|
|
|
// RegExps
|
|
|
const VARNAME_SEARCH = '/(\\[[^\\]]+\\]|[^\\[\\]\\.]+)/';
|
|
|
const EXTENDED_COMMENT_SEARCH = '/{{!--.*?--}}/s';
|
|
|
const IS_SUBEXP_SEARCH = '/^\(.+\)$/s';
|
|
|
|
|
|
// Positions of matched token
|
|
|
const POS_LOTHER = 1;
|
|
|
const POS_LSPACE = 2;
|
...
|
...
|
@@ -101,7 +95,8 @@ class LightnCandy { |
|
|
*
|
|
|
* @return string|false Compiled PHP code when successed. If error happened and compile failed, return false.
|
|
|
*/
|
|
|
public static function compile($template, $options = array('flags' => self::FLAG_BESTPERFORMANCE)) {
|
|
|
public static function compile($template, $options = array('flags' => self::FLAG_BESTPERFORMANCE))
|
|
|
{
|
|
|
$context = static::buildContext($options);
|
|
|
|
|
|
if (static::handleError($context)) {
|
...
|
...
|
@@ -141,7 +136,8 @@ class LightnCandy { |
|
|
/**
|
|
|
* Include all partials when using dynamic partials
|
|
|
*/
|
|
|
protected static function handleDynamicPartial(&$context) {
|
|
|
protected static function handleDynamicPartial(&$context)
|
|
|
{
|
|
|
if ($context['usedFeature']['dynpartial'] == 0) {
|
|
|
return;
|
|
|
}
|
...
|
...
|
@@ -162,7 +158,8 @@ class LightnCandy { |
|
|
* @expect 'a\\\\bc' when input 'a\bc'
|
|
|
* @expect 'a\\\'bc' when input 'a\'bc'
|
|
|
*/
|
|
|
protected static function escapeTemplate($template) {
|
|
|
protected static function escapeTemplate($template)
|
|
|
{
|
|
|
return addcslashes(addcslashes($template, '\\'), "'");
|
|
|
}
|
|
|
|
...
|
...
|
@@ -173,7 +170,8 @@ class LightnCandy { |
|
|
* @param string $left left string of a token
|
|
|
* @param string $right right string of a token
|
|
|
*/
|
|
|
protected static function setupToken(&$context, $left = '{{', $right = '}}') {
|
|
|
protected static function setupToken(&$context, $left = '{{', $right = '}}')
|
|
|
{
|
|
|
if (preg_match('/=/', "$left$right")) {
|
|
|
$context['error'][] = "Can not set delimiter contains '=' , you try to set delimiter as '$left' and '$right'.";
|
|
|
return;
|
...
|
...
|
@@ -200,9 +198,10 @@ class LightnCandy { |
|
|
* @param array<string,array|string|integer> $context Current context
|
|
|
* @param string $template handlebars template
|
|
|
*/
|
|
|
protected static function verifyTemplate(&$context, $template) {
|
|
|
protected static function verifyTemplate(&$context, $template)
|
|
|
{
|
|
|
while (preg_match($context['tokens']['search'], $template, $matches)) {
|
|
|
$context['tokens']['count']++;
|
|
|
$context['tokens']['count'] ++;
|
|
|
static::scanFeatures($matches, $context);
|
|
|
$template = $matches[self::POS_ROTHER];
|
|
|
}
|
...
|
...
|
@@ -217,7 +216,8 @@ class LightnCandy { |
|
|
*
|
|
|
* @return string generated PHP code
|
|
|
*/
|
|
|
protected static function compileTemplate(&$context, $template, $partial = '') {
|
|
|
protected static function compileTemplate(&$context, $template, $partial = '')
|
|
|
{
|
|
|
// Check for recursive partial
|
|
|
if ($partial && !$context['flags']['runpart']) {
|
|
|
$context['partialStack'][] = $partial;
|
...
|
...
|
@@ -245,7 +245,7 @@ class LightnCandy { |
|
|
}
|
|
|
}
|
|
|
|
|
|
$context['tokens']['current']++;
|
|
|
$context['tokens']['current'] ++;
|
|
|
$tmpl = static::compileToken($matches, $context);
|
|
|
if ($tmpl == $context['ops']['seperator']) {
|
|
|
$tmpl = '';
|
...
|
...
|
@@ -271,7 +271,8 @@ class LightnCandy { |
|
|
*
|
|
|
* @return string Composed PHP code
|
|
|
*/
|
|
|
protected static function composePHPRender($context, $code) {
|
|
|
protected static function composePHPRender($context, $code)
|
|
|
{
|
|
|
$flagJStrue = static::getBoolStr($context['flags']['jstrue']);
|
|
|
$flagJSObj = static::getBoolStr($context['flags']['jsobj']);
|
|
|
$flagSPVar = static::getBoolStr($context['flags']['spvar']);
|
...
|
...
|
@@ -324,7 +325,8 @@ $libstr |
|
|
*
|
|
|
* @return array<string,array|string|integer> Context from options
|
|
|
*/
|
|
|
protected static function buildContext($options) {
|
|
|
protected static function buildContext($options)
|
|
|
{
|
|
|
if (!is_array($options)) {
|
|
|
$options = array();
|
|
|
}
|
...
|
...
|
@@ -423,7 +425,7 @@ $libstr |
|
|
'cnd_then' => '{echo ',
|
|
|
'cnd_else' => ';}else{echo ',
|
|
|
'cnd_end' => ';}echo ',
|
|
|
) : array(
|
|
|
) : array(
|
|
|
'seperator' => '.',
|
|
|
'f_start' => 'return ',
|
|
|
'f_end' => ';',
|
...
|
...
|
@@ -458,7 +460,8 @@ $libstr |
|
|
* @expect array('flags' => array('exhlp' => 1), 'helpers' => array('LCRun3::raw' => 'LCRun3::raw')) when input array('flags' => array('exhlp' => 1), 'helpers' => array()), array('helpers' => array('LCRun3::raw'))
|
|
|
* @expect array('flags' => array('exhlp' => 1), 'helpers' => array('test' => 'LCRun3::raw')) when input array('flags' => array('exhlp' => 1), 'helpers' => array()), array('helpers' => array('test' => 'LCRun3::raw'))
|
|
|
*/
|
|
|
protected static function buildHelperTable($context, $options, $tname = 'helpers') {
|
|
|
protected static function buildHelperTable($context, $options, $tname = 'helpers')
|
|
|
{
|
|
|
if (isset($options[$tname]) && is_array($options[$tname])) {
|
|
|
foreach ($options[$tname] as $name => $func) {
|
|
|
if (is_callable($func)) {
|
...
|
...
|
@@ -483,8 +486,9 @@ $libstr |
|
|
* @param string $name partial name
|
|
|
* @param array<string,array|string|integer> $context Current context of compiler progress.
|
|
|
*/
|
|
|
protected static function readPartial($name, &$context) {
|
|
|
$context['usedFeature']['partial']++;
|
|
|
protected static function readPartial($name, &$context)
|
|
|
{
|
|
|
$context['usedFeature']['partial'] ++;
|
|
|
|
|
|
if (isset($context['usedPartial'][$name])) {
|
|
|
return;
|
...
|
...
|
@@ -498,7 +502,7 @@ $libstr |
|
|
|
|
|
if (preg_match(static::IS_SUBEXP_SEARCH, $name)) {
|
|
|
if ($context['flags']['runpart']) {
|
|
|
$context['usedFeature']['dynpartial']++;
|
|
|
$context['usedFeature']['dynpartial'] ++;
|
|
|
return;
|
|
|
} else {
|
|
|
$context['error'][] = "You use dynamic partial name as '$name', this only works with option FLAG_RUNTIMEPARTIAL enabled";
|
...
|
...
|
@@ -519,7 +523,8 @@ $libstr |
|
|
*
|
|
|
* @return string|null $content partial content
|
|
|
*/
|
|
|
protected static function resolvePartial(&$name, &$context) {
|
|
|
protected static function resolvePartial(&$name, &$context)
|
|
|
{
|
|
|
if (isset($context['partials'][$name])) {
|
|
|
return $context['partials'][$name];
|
|
|
}
|
...
|
...
|
@@ -542,7 +547,8 @@ $libstr |
|
|
* @param array<string,array|string|integer> $context Current context of compiler progress.
|
|
|
* @param string $content partial content
|
|
|
*/
|
|
|
protected static function compilePartial(&$name, &$context, $content) {
|
|
|
protected static function compilePartial(&$name, &$context, $content)
|
|
|
{
|
|
|
$context['usedPartial'][$name] = static::escapeTemplate($content);
|
|
|
|
|
|
$originalAhead = $context['tokens']['ahead'];
|
...
|
...
|
@@ -582,7 +588,8 @@ $libstr |
|
|
* @expect array('test1') when input array('fileext' => array('test1'))
|
|
|
* @expect array('test2', 'test3') when input array('fileext' => array('test2', 'test3'))
|
|
|
*/
|
|
|
protected static function buildCXFileext($options) {
|
|
|
protected static function buildCXFileext($options)
|
|
|
{
|
|
|
$exts = isset($options['fileext']) ? $options['fileext'] : '.tmpl';
|
|
|
return is_array($exts) ? $exts : array($exts);
|
|
|
}
|
...
|
...
|
@@ -600,7 +607,8 @@ $libstr |
|
|
* @expect array('src') when input array('basedir' => array('src', 'dir_not_found'))
|
|
|
* @expect array('src', 'tests') when input array('basedir' => array('src', 'tests'))
|
|
|
*/
|
|
|
protected static function buildCXBasedir($options) {
|
|
|
protected static function buildCXBasedir($options)
|
|
|
{
|
|
|
$dirs = isset($options['basedir']) ? $options['basedir'] : 0;
|
|
|
$dirs = is_array($dirs) ? $dirs : array($dirs);
|
|
|
$ret = array();
|
...
|
...
|
@@ -624,7 +632,8 @@ $libstr |
|
|
* @expect 'function($a) {return;}' when input function ($a) {return;}
|
|
|
* @expect 'function($a) {return;}' when input function ($a) {return;}
|
|
|
*/
|
|
|
protected static function getPHPCode($closure) {
|
|
|
protected static function getPHPCode($closure)
|
|
|
{
|
|
|
if (is_string($closure) && preg_match('/(.+)::(.+)/', $closure, $matched)) {
|
|
|
$ref = new ReflectionMethod($matched[1], $matched[2]);
|
|
|
} else {
|
...
|
...
|
@@ -650,7 +659,8 @@ $libstr |
|
|
*
|
|
|
* @return string
|
|
|
*/
|
|
|
protected static function exportHelper($context, $tname = 'helpers') {
|
|
|
protected static function exportHelper($context, $tname = 'helpers')
|
|
|
{
|
|
|
$ret = '';
|
|
|
foreach ($context[$tname] as $name => $func) {
|
|
|
if (!isset($context['usedCount'][$tname][$name])) {
|
...
|
...
|
@@ -673,7 +683,8 @@ $libstr |
|
|
*
|
|
|
* @return string
|
|
|
*/
|
|
|
protected static function exportLCRun($context) {
|
|
|
protected static function exportLCRun($context)
|
|
|
{
|
|
|
if ($context['flags']['standalone'] == 0) {
|
|
|
return '';
|
|
|
}
|
...
|
...
|
@@ -699,15 +710,15 @@ $libstr |
|
|
|
|
|
while (true) {
|
|
|
if (array_sum(array_map(function ($name) use (&$exports, $methods) {
|
|
|
$n = 0;
|
|
|
foreach ($methods[$name][1] as $child => $count) {
|
|
|
if (!in_array($child, $exports)) {
|
|
|
$exports[] = $child;
|
|
|
$n++;
|
|
|
}
|
|
|
}
|
|
|
return $n;
|
|
|
}, $exports)) == 0) {
|
|
|
$n = 0;
|
|
|
foreach ($methods[$name][1] as $child => $count) {
|
|
|
if (!in_array($child, $exports)) {
|
|
|
$exports[] = $child;
|
|
|
$n++;
|
|
|
}
|
|
|
}
|
|
|
return $n;
|
|
|
}, $exports)) == 0) {
|
|
|
break;
|
|
|
}
|
|
|
}
|
...
|
...
|
@@ -726,7 +737,8 @@ $libstr |
|
|
*
|
|
|
* @return string
|
|
|
*/
|
|
|
protected static function exportLCRunConstant($context) {
|
|
|
protected static function exportLCRunConstant($context)
|
|
|
{
|
|
|
if ($context['flags']['standalone'] == 0) {
|
|
|
return 'array()';
|
|
|
}
|
...
|
...
|
@@ -734,8 +746,8 @@ $libstr |
|
|
$class = new ReflectionClass($context['lcrun']);
|
|
|
$constants = $class->getConstants();
|
|
|
$ret = " array(\n";
|
|
|
foreach($constants as $name => $value) {
|
|
|
$ret .= " '$name' => ". (is_string($value) ? "'$value'" : $value ) . ",\n";
|
|
|
foreach ($constants as $name => $value) {
|
|
|
$ret .= " '$name' => " . (is_string($value) ? "'$value'" : $value ) . ",\n";
|
|
|
}
|
|
|
$ret .= " )";
|
|
|
return $ret;
|
...
|
...
|
@@ -749,14 +761,15 @@ $libstr |
|
|
*
|
|
|
* @return array<string|array> list of converted code and children array
|
|
|
*/
|
|
|
protected static function scanLCRunDependency($context, $code) {
|
|
|
protected static function scanLCRunDependency($context, $code)
|
|
|
{
|
|
|
$child = array();
|
|
|
|
|
|
$code = preg_replace_callback('/self::(\w+?)\s*\(/', function ($matches) use ($context, &$child) {
|
|
|
if (!isset($child[$matches[1]])) {
|
|
|
$child[$matches[1]] = 0;
|
|
|
}
|
|
|
$child[$matches[1]]++;
|
|
|
$child[$matches[1]] ++;
|
|
|
|
|
|
return "\$cx['funcs']['{$matches[1]}'](";
|
|
|
}, $code);
|
...
|
...
|
@@ -778,7 +791,8 @@ $libstr |
|
|
* @expect false when input array('level' => 0, 'error' => array())
|
|
|
* @expect true when input array('level' => 0, 'error' => array('some error'), 'flags' => array('errorlog' => 0, 'exception' => 0))
|
|
|
*/
|
|
|
protected static function handleError(&$context) {
|
|
|
protected static function handleError(&$context)
|
|
|
{
|
|
|
if ($context['level'] > 0) {
|
|
|
$token = array_pop($context['stack']);
|
|
|
$context['error'][] = "Unclosed token {{{#$token}}} !!";
|
...
|
...
|
@@ -810,7 +824,8 @@ $libstr |
|
|
* @expect 'false' when input 0
|
|
|
* @expect 'false' when input -1
|
|
|
*/
|
|
|
protected static function getBoolStr($v) {
|
|
|
protected static function getBoolStr($v)
|
|
|
{
|
|
|
return ($v > 0) ? 'true' : 'false';
|
|
|
}
|
|
|
|
...
|
...
|
@@ -819,7 +834,8 @@ $libstr |
|
|
*
|
|
|
* @return array<string,array|string|integer> Context data
|
|
|
*/
|
|
|
public static function getContext() {
|
|
|
public static function getContext()
|
|
|
{
|
|
|
return static::$lastContext;
|
|
|
}
|
|
|
|
...
|
...
|
@@ -834,7 +850,8 @@ $libstr |
|
|
*
|
|
|
* @deprecated
|
|
|
*/
|
|
|
public static function prepare($php, $tmpDir = null, $delete = true) {
|
|
|
public static function prepare($php, $tmpDir = null, $delete = true)
|
|
|
{
|
|
|
if (!ini_get('allow_url_include') || !ini_get('allow_url_fopen')) {
|
|
|
if (!is_string($tmpDir) || !is_dir($tmpDir)) {
|
|
|
$tmpDir = sys_get_temp_dir();
|
...
|
...
|
@@ -878,7 +895,8 @@ $libstr |
|
|
* @expect "\$cx['funcs']['test3'](" when input array('flags' => array('standalone' => 1, 'debug' => 0), 'lcrun' => 'LCRun3'), 'test3', ''
|
|
|
* @expect 'LCRun3::debug(\'abc\', \'test\', ' when input array('flags' => array('standalone' => 0, 'debug' => 1), 'lcrun' => 'LCRun3'), 'test', 'abc'
|
|
|
*/
|
|
|
protected static function getFuncName(&$context, $name, $tag) {
|
|
|
protected static function getFuncName(&$context, $name, $tag)
|
|
|
{
|
|
|
static::addUsageCount($context, 'lcrun', $name);
|
|
|
|
|
|
if ($context['flags']['debug'] && ($name != 'miss')) {
|
...
|
...
|
@@ -903,7 +921,8 @@ $libstr |
|
|
* @expect '[a]' when input array('a')
|
|
|
* @expect '[a][b][c]' when input array('a', 'b', 'c')
|
|
|
*/
|
|
|
protected static function getArrayStr($scopes) {
|
|
|
protected static function getArrayStr($scopes)
|
|
|
{
|
|
|
return count($scopes) ? '[' . implode('][', $scopes) . ']' : '';
|
|
|
}
|
|
|
|
...
|
...
|
@@ -918,10 +937,11 @@ $libstr |
|
|
* @expect "['a']" when input array('a')
|
|
|
* @expect "['a']['b']['c']" when input array('a', 'b', 'c')
|
|
|
*/
|
|
|
protected static function getArrayCode($list) {
|
|
|
protected static function getArrayCode($list)
|
|
|
{
|
|
|
return static::getArrayStr(array_map(function ($v) {
|
|
|
return "'$v'";
|
|
|
}, $list));
|
|
|
return "'$v'";
|
|
|
}, $list));
|
|
|
}
|
|
|
|
|
|
/**
|
...
|
...
|
@@ -936,7 +956,8 @@ $libstr |
|
|
* @expect array('array(array($in,$in),array())', array('this', 'this')) when input array(null, null), array('flags'=>array('spvar'=>true))
|
|
|
* @expect array('array(array(),array(\'a\'=>$in))', array('this')) when input array('a' => null), array('flags'=>array('spvar'=>true))
|
|
|
*/
|
|
|
protected static function getVariableNames($vn, &$context) {
|
|
|
protected static function getVariableNames($vn, &$context)
|
|
|
{
|
|
|
$vars = array(array(), array());
|
|
|
$exps = array();
|
|
|
foreach ($vn as $i => $v) {
|
...
|
...
|
@@ -960,7 +981,8 @@ $libstr |
|
|
*
|
|
|
* @return array<string> code representing passed expression
|
|
|
*/
|
|
|
protected static function compileSubExpression($subExpression, &$context, $keepCount = false) {
|
|
|
protected static function compileSubExpression($subExpression, &$context, $keepCount = false)
|
|
|
{
|
|
|
// mock up a token for this expression
|
|
|
$token = array_fill(self::POS_LOTHER, self::POS_ROTHER, '');
|
|
|
|
...
|
...
|
@@ -979,14 +1001,14 @@ $libstr |
|
|
if ($keepCount) {
|
|
|
$context['usedFeature'] = $oldCount;
|
|
|
} else {
|
|
|
$context['usedFeature']['subexp']++;
|
|
|
$context['usedFeature']['subexp'] ++;
|
|
|
// detect handlebars custom helpers.
|
|
|
if (isset($context['hbhelpers'][$vars[0][0]])) {
|
|
|
$context['usedFeature']['hbhelper']++;
|
|
|
$context['usedFeature']['hbhelper'] ++;
|
|
|
} else {
|
|
|
// detect custom helpers.
|
|
|
if (isset($context['helpers'][$vars[0][0]])) {
|
|
|
$context['usedFeature']['helper']++;
|
|
|
$context['usedFeature']['helper'] ++;
|
|
|
}
|
|
|
}
|
|
|
}
|
...
|
...
|
@@ -1002,7 +1024,8 @@ $libstr |
|
|
*
|
|
|
* @return array<string> variable names
|
|
|
*/
|
|
|
protected static function getVariableNameOrSubExpression($var, &$context) {
|
|
|
protected static function getVariableNameOrSubExpression($var, &$context)
|
|
|
{
|
|
|
if (isset($var[0]) && preg_match(static::IS_SUBEXP_SEARCH, $var[0])) {
|
|
|
return static::compileSubExpression($var[0], $context, true);
|
|
|
}
|
...
|
...
|
@@ -1037,7 +1060,8 @@ $libstr |
|
|
* @expect array('((isset($in[\'id\']) && is_array($in)) ? $in[\'id\'] : null)', 'this.[id]') when input array(null, 'id'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
|
|
|
* @expect array('LCRun3::v($cx, $in, array(\'id\'))', 'this.[id]') when input array(null, 'id'), array('flags'=>array('prop'=>true,'spvar'=>true,'debug'=>0,'method'=>0,'mustlok'=>0,'standalone'=>0), 'lcrun' => 'LCRun3')
|
|
|
*/
|
|
|
protected static function getVariableName($var, &$context) {
|
|
|
protected static function getVariableName($var, &$context)
|
|
|
{
|
|
|
if (isset($var[0]) && ($var[0] === 0)) {
|
|
|
return array($var[1], preg_replace('/\'(.*)\'/', '$1', $var[1]));
|
|
|
}
|
...
|
...
|
@@ -1089,8 +1113,8 @@ $libstr |
|
|
// the only way is using slower rendering time variable resolver.
|
|
|
if ($context['flags']['prop'] || $context['flags']['method'] || $context['flags']['mustlok']) {
|
|
|
return array(static::getFuncName($context, 'v', $exp) . "\$cx, $base, array(" . implode(',', array_map(function ($V) {
|
|
|
return "'$V'";
|
|
|
}, $var)) . '))', $exp);
|
|
|
return "'$V'";
|
|
|
}, $var)) . '))', $exp);
|
|
|
}
|
|
|
|
|
|
$n = static::getArrayCode($var);
|
...
|
...
|
@@ -1117,10 +1141,11 @@ $libstr |
|
|
* @expect '../../[a].[b]' when input 2, false, array('a', 'b')
|
|
|
* @expect '../[a\'b]' when input 1, false, array('a\'b')
|
|
|
*/
|
|
|
protected static function getExpression($levels, $spvar, $var) {
|
|
|
protected static function getExpression($levels, $spvar, $var)
|
|
|
{
|
|
|
return ($spvar ? '@' : '') . str_repeat('../', $levels) . ((is_array($var) && count($var)) ? implode('.', array_map(function($v) {
|
|
|
return is_null($v) ? 'this' : "[$v]";
|
|
|
}, $var)) : 'this');
|
|
|
return is_null($v) ? 'this' : "[$v]";
|
|
|
}, $var)) : 'this');
|
|
|
}
|
|
|
|
|
|
/**
|
...
|
...
|
@@ -1145,7 +1170,8 @@ $libstr |
|
|
* @expect array(0, '123') when input '123', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
|
|
|
* @expect array(0, 'null') when input 'null', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
|
|
|
*/
|
|
|
protected static function fixVariable($v, &$context) {
|
|
|
protected static function fixVariable($v, &$context)
|
|
|
{
|
|
|
// handle number
|
|
|
if (is_numeric($v)) {
|
|
|
// convert 0x00 or 0b00 numbers to decimal
|
...
|
...
|
@@ -1240,7 +1266,8 @@ $libstr |
|
|
* @expect array(false, array(array('a'), 'q' => array(0, "' d e'"))) when input array(0,0,0,0,0,0,"a q=\' d e\'"), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
|
|
|
* @expect array(false, array('q' => array('( foo bar)'))) when input array(0,0,0,0,0,0,'q=( foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0, 'exhlp' => 0), 'scan' => false, 'usedFeature' => array(), 'ops' => array('seperator' => 0))
|
|
|
*/
|
|
|
protected static function parseTokenArgs(&$token, &$context) {
|
|
|
protected static function parseTokenArgs(&$token, &$context)
|
|
|
{
|
|
|
trim($token[self::POS_INNERTAG]);
|
|
|
|
|
|
// Handle delimiter change
|
...
|
...
|
@@ -1360,7 +1387,7 @@ $libstr |
|
|
|
|
|
$esc = $context['scan'] ? '' : '\\\\';
|
|
|
if ($context['flags']['advar'] && !preg_match("/^(\"|$esc')(.*)(\"|$esc')$/", $var)) {
|
|
|
// foo] Rule 1: no starting [ or [ not start from head
|
|
|
// foo] Rule 1: no starting [ or [ not start from head
|
|
|
if (preg_match('/^[^\\[\\.]+[\\]\\[]/', $var)
|
|
|
// [bar Rule 2: no ending ] or ] not in the end
|
|
|
|| preg_match('/[\\[\\]][^\\]\\.]+$/', $var)
|
...
|
...
|
@@ -1412,7 +1439,8 @@ $libstr |
|
|
* @expect 'b' when input array(0, 'a', 'b', 'c'), 1
|
|
|
* @expect 'c' when input array(0, 'a', 'b', 'c', 'd', 'e')
|
|
|
*/
|
|
|
protected static function tokenString($token, $remove = 2) {
|
|
|
protected static function tokenString($token, $remove = 2)
|
|
|
{
|
|
|
return implode('', array_slice($token, 1 + $remove, -$remove));
|
|
|
}
|
|
|
|
...
|
...
|
@@ -1428,7 +1456,8 @@ $libstr |
|
|
* @expect null when input array_fill(0, 9, '}}'), array()
|
|
|
* @expect true when input array_fill(0, 9, '{{{'), array()
|
|
|
*/
|
|
|
protected static function validateStartEnd($token, &$context) {
|
|
|
protected static function validateStartEnd($token, &$context)
|
|
|
{
|
|
|
// {{ }}} or {{{ }} are invalid
|
|
|
if (strlen($token[self::POS_BEGINTAG]) !== strlen($token[self::POS_ENDTAG])) {
|
|
|
$context['error'][] = 'Bad token ' . static::tokenString($token) . ' ! Do you mean {{' . static::tokenString($token, 4) . '}} or {{{' . static::tokenString($token, 4) . '}}}?';
|
...
|
...
|
@@ -1464,7 +1493,8 @@ $libstr |
|
|
* @expect 11 when input array(0, 0, 0, 0, 0, '#', '...'), array('hbhelpers' => array('abc' => ''), 'usedFeature' => array('hbhelper' => 10), 'level' => 0), array(array('abc'))
|
|
|
* @expect true when input array(0, 0, 0, 0, 0, '>', '...'), array('basedir' => array('.'), 'fileext' => array('.tmpl'), 'usedFeature' => array('unless' => 7, 'partial' => 7), 'level' => 0, 'flags' => array('skippartial' => 0)), array('test')
|
|
|
*/
|
|
|
protected static function validateOperations($token, &$context, $vars) {
|
|
|
protected static function validateOperations($token, &$context, $vars)
|
|
|
{
|
|
|
switch ($token[self::POS_OP]) {
|
|
|
case '>':
|
|
|
static::readPartial($vars[0][0], $context);
|
...
|
...
|
@@ -1476,7 +1506,7 @@ $libstr |
|
|
case '^':
|
|
|
if (isset($vars[0][0])) {
|
|
|
$context['stack'][] = $token[self::POS_INNERTAG];
|
|
|
$context['level']++;
|
|
|
$context['level'] ++;
|
|
|
return ++$context['usedFeature']['isec'];
|
|
|
}
|
|
|
|
...
|
...
|
@@ -1487,7 +1517,7 @@ $libstr |
|
|
|
|
|
case '/':
|
|
|
array_pop($context['stack']);
|
|
|
$context['level']--;
|
|
|
$context['level'] --;
|
|
|
return true;
|
|
|
|
|
|
case '!':
|
...
|
...
|
@@ -1495,7 +1525,7 @@ $libstr |
|
|
|
|
|
case '#':
|
|
|
$context['stack'][] = $token[self::POS_INNERTAG];
|
|
|
$context['level']++;
|
|
|
$context['level'] ++;
|
|
|
|
|
|
if (!isset($vars[0][0])) {
|
|
|
return;
|
...
|
...
|
@@ -1524,7 +1554,7 @@ $libstr |
|
|
$context['error'][] = 'Do not support {{#with var}}, you should do compile with LightnCandy::FLAG_WITH flag';
|
|
|
}
|
|
|
}
|
|
|
// Continue to add usage...
|
|
|
// Continue to add usage...
|
|
|
case 'each':
|
|
|
case 'unless':
|
|
|
case 'if':
|
...
|
...
|
@@ -1542,7 +1572,8 @@ $libstr |
|
|
* @param string[] $token detected handlebars {{ }} token
|
|
|
* @param array<string,array|string|integer> $context current compile context
|
|
|
*/
|
|
|
protected static function scanFeatures($token, &$context) {
|
|
|
protected static function scanFeatures($token, &$context)
|
|
|
{
|
|
|
list($raw, $vars) = static::parseTokenArgs($token, $context);
|
|
|
|
|
|
if (static::validateStartEnd($token, $context)) {
|
...
|
...
|
@@ -1554,7 +1585,7 @@ $libstr |
|
|
}
|
|
|
|
|
|
if (($token[self::POS_OP] === '^') && ($context['flags']['else'])) {
|
|
|
return $context['usedFeature']['else']++;
|
|
|
return $context['usedFeature']['else'] ++;
|
|
|
}
|
|
|
|
|
|
if (count($vars) == 0) {
|
...
|
...
|
@@ -1566,15 +1597,15 @@ $libstr |
|
|
}
|
|
|
|
|
|
if ($vars[0] !== 'else') {
|
|
|
$context['usedFeature'][$raw ? 'raw' : 'enc']++;
|
|
|
$context['usedFeature'][$raw ? 'raw' : 'enc'] ++;
|
|
|
}
|
|
|
|
|
|
foreach ($vars as $var) {
|
|
|
if (!isset($var[0])) {
|
|
|
if ($context['level'] == 0) {
|
|
|
$context['usedFeature']['rootthis']++;
|
|
|
$context['usedFeature']['rootthis'] ++;
|
|
|
}
|
|
|
$context['usedFeature']['this']++;
|
|
|
$context['usedFeature']['this'] ++;
|
|
|
}
|
|
|
}
|
|
|
|
...
|
...
|
@@ -1584,18 +1615,18 @@ $libstr |
|
|
|
|
|
if ($vars[0][0] === 'else') {
|
|
|
if ($context['flags']['else']) {
|
|
|
return $context['usedFeature']['else']++;
|
|
|
return $context['usedFeature']['else'] ++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// detect handlebars custom helpers.
|
|
|
if (isset($context['hbhelpers'][$vars[0][0]])) {
|
|
|
return $context['usedFeature']['hbhelper']++;
|
|
|
return $context['usedFeature']['hbhelper'] ++;
|
|
|
}
|
|
|
|
|
|
// detect custom helpers.
|
|
|
if (isset($context['helpers'][$vars[0][0]])) {
|
|
|
return $context['usedFeature']['helper']++;
|
|
|
return $context['usedFeature']['helper'] ++;
|
|
|
}
|
|
|
}
|
|
|
|
...
|
...
|
@@ -1607,7 +1638,8 @@ $libstr |
|
|
* @param boolean $named is named arguments
|
|
|
* @param string $suggest extended hint for this no named argument error
|
|
|
*/
|
|
|
public static function noNamedArguments($token, &$context, $named, $suggest = '!') {
|
|
|
public static function noNamedArguments($token, &$context, $named, $suggest = '!')
|
|
|
{
|
|
|
if ($named) {
|
|
|
$context['error'][] = 'Do not support name=value in ' . static::tokenString($token) . $suggest;
|
|
|
}
|
...
|
...
|
@@ -1622,7 +1654,8 @@ $libstr |
|
|
*
|
|
|
* @return string|null Return compiled code segment for the token
|
|
|
*/
|
|
|
public static function handleMustacheSpacing(&$token, $vars, &$context) {
|
|
|
public static function handleMustacheSpacing(&$token, $vars, &$context)
|
|
|
{
|
|
|
if (!$context['flags']['mustsp'] && !$context['flags']['mustpi']) {
|
|
|
return;
|
|
|
}
|
...
|
...
|
@@ -1667,7 +1700,7 @@ $libstr |
|
|
if ($st && (($lsp && $rsp) // both side cr
|
|
|
|| ($rsp && !$token[self::POS_LOTHER]) // first line without left
|
|
|
|| ($lsp && ($context['tokens']['current'] == $context['tokens']['count']) && !$token[self::POS_ROTHER]) // final line
|
|
|
)) {
|
|
|
)) {
|
|
|
// handle partial
|
|
|
if ($context['flags']['mustpi'] && ($token[self::POS_OP] === '>')) {
|
|
|
$context['tokens']['partialind'] = $ind;
|
...
|
...
|
@@ -1687,7 +1720,8 @@ $libstr |
|
|
*
|
|
|
* @return string Return compiled code segment for the token
|
|
|
*/
|
|
|
public static function compileToken(&$token, &$context) {
|
|
|
public static function compileToken(&$token, &$context)
|
|
|
{
|
|
|
list($raw, $vars) = static::parseTokenArgs($token, $context);
|
|
|
$named = count(array_diff_key($vars, array_keys(array_keys($vars)))) > 0;
|
|
|
|
...
|
...
|
@@ -1731,7 +1765,8 @@ $libstr |
|
|
*
|
|
|
* @return string|null Return compiled code segment for the token when the token is section
|
|
|
*/
|
|
|
protected static function compileSection(&$token, &$context, &$vars, $named) {
|
|
|
protected static function compileSection(&$token, &$context, &$vars, $named)
|
|
|
{
|
|
|
switch ($token[self::POS_OP]) {
|
|
|
case '>':
|
|
|
// mustache spec: ignore missing partial
|
...
|
...
|
@@ -1743,7 +1778,7 @@ $libstr |
|
|
$vars[0] = array();
|
|
|
}
|
|
|
$v = static::getVariableNames($vars, $context);
|
|
|
$tag = ">$p[0] " .implode(' ', $v[1]);
|
|
|
$tag = ">$p[0] " . implode(' ', $v[1]);
|
|
|
if ($context['flags']['runpart']) {
|
|
|
if (preg_match(static::IS_SUBEXP_SEARCH, $p[0])) {
|
|
|
list($p) = static::compileSubExpression($p[0], $context);
|
...
|
...
|
@@ -1803,7 +1838,8 @@ $libstr |
|
|
*
|
|
|
* @return string|null Return compiled code segment for the token
|
|
|
*/
|
|
|
protected static function compileBlockCustomHelper(&$context, $vars, $inverted = false) {
|
|
|
protected static function compileBlockCustomHelper(&$context, $vars, $inverted = false)
|
|
|
{
|
|
|
if (!isset($vars[0][0])) {
|
|
|
return;
|
|
|
}
|
...
|
...
|
@@ -1833,7 +1869,8 @@ $libstr |
|
|
*
|
|
|
* @return string Return compiled code segment for the token
|
|
|
*/
|
|
|
protected static function compileBlockEnd(&$token, &$context, $vars) {
|
|
|
protected static function compileBlockEnd(&$token, &$context, $vars)
|
|
|
{
|
|
|
$each = false;
|
|
|
$pop = array_pop($context['stack']);
|
|
|
switch ($token[self::POS_INNERTAG]) {
|
...
|
...
|
@@ -1857,7 +1894,7 @@ $libstr |
|
|
$each = true;
|
|
|
}
|
|
|
|
|
|
switch($pop) {
|
|
|
switch ($pop) {
|
|
|
case '#':
|
|
|
case '^':
|
|
|
$pop2 = array_pop($context['stack']);
|
...
|
...
|
@@ -1884,20 +1921,17 @@ $libstr |
|
|
*
|
|
|
* @return string Return compiled code segment for the token
|
|
|
*/
|
|
|
protected static function compileBlockBegin(&$context, $vars) {
|
|
|
protected static function compileBlockBegin(&$context, $vars)
|
|
|
{
|
|
|
$each = 'false';
|
|
|
$v = isset($vars[1]) ? static::getVariableNameOrSubExpression($vars[1], $context) : array(null, array());
|
|
|
switch (isset($vars[0][0]) ? $vars[0][0] : null) {
|
|
|
case 'if':
|
|
|
$context['stack'][] = 'if';
|
|
|
return $context['usedFeature']['parent']
|
|
|
? $context['ops']['seperator'] . static::getFuncName($context, 'ifv', 'if ' . $v[1]) . "\$cx, {$v[0]}, \$in, function(\$cx, \$in) {{$context['ops']['f_start']}"
|
|
|
: "{$context['ops']['cnd_start']}(" . static::getFuncName($context, 'ifvar', $v[1]) . "\$cx, {$v[0]})){$context['ops']['cnd_then']}";
|
|
|
return $context['usedFeature']['parent'] ? $context['ops']['seperator'] . static::getFuncName($context, 'ifv', 'if ' . $v[1]) . "\$cx, {$v[0]}, \$in, function(\$cx, \$in) {{$context['ops']['f_start']}" : "{$context['ops']['cnd_start']}(" . static::getFuncName($context, 'ifvar', $v[1]) . "\$cx, {$v[0]})){$context['ops']['cnd_then']}";
|
|
|
case 'unless':
|
|
|
$context['stack'][] = 'unless';
|
|
|
return $context['usedFeature']['parent']
|
|
|
? $context['ops']['seperator'] . static::getFuncName($context, 'unl', 'unless ' . $v[1]) . "\$cx, {$v[0]}, \$in, function(\$cx, \$in) {{$context['ops']['f_start']}"
|
|
|
: "{$context['ops']['cnd_start']}(!" . static::getFuncName($context, 'ifvar', $v[1]) . "\$cx, {$v[0]})){$context['ops']['cnd_then']}";
|
|
|
return $context['usedFeature']['parent'] ? $context['ops']['seperator'] . static::getFuncName($context, 'unl', 'unless ' . $v[1]) . "\$cx, {$v[0]}, \$in, function(\$cx, \$in) {{$context['ops']['f_start']}" : "{$context['ops']['cnd_start']}(!" . static::getFuncName($context, 'ifvar', $v[1]) . "\$cx, {$v[0]})){$context['ops']['cnd_then']}";
|
|
|
case 'each':
|
|
|
$each = 'true';
|
|
|
array_shift($vars);
|
...
|
...
|
@@ -1928,7 +1962,8 @@ $libstr |
|
|
*
|
|
|
* @return string|null Return compiled code segment for the token when the token is custom helper
|
|
|
*/
|
|
|
protected static function compileCustomHelper(&$context, $vars, $raw, $err = false) {
|
|
|
protected static function compileCustomHelper(&$context, $vars, $raw, $err = false)
|
|
|
{
|
|
|
$notHH = !isset($context['hbhelpers'][$vars[0][0]]);
|
|
|
if (!isset($context['helpers'][$vars[0][0]]) && $notHH) {
|
|
|
if ($err) {
|
...
|
...
|
@@ -1954,7 +1989,8 @@ $libstr |
|
|
*
|
|
|
* @return string|null Return compiled code segment for the token when the token is else
|
|
|
*/
|
|
|
protected static function compileElse(&$context, &$vars) {
|
|
|
protected static function compileElse(&$context, &$vars)
|
|
|
{
|
|
|
if ($vars[0][0] === 'else') {
|
|
|
$c = count($context['stack']) - 1;
|
|
|
if ($c >= 0) {
|
...
|
...
|
@@ -1983,7 +2019,8 @@ $libstr |
|
|
*
|
|
|
* @return string Return compiled code segment for the token
|
|
|
*/
|
|
|
protected static function compileVariable(&$context, &$vars, $raw) {
|
|
|
protected static function compileVariable(&$context, &$vars, $raw)
|
|
|
{
|
|
|
$v = static::getVariableName($vars[0], $context);
|
|
|
if ($context['flags']['jsobj'] || $context['flags']['jstrue'] || $context['flags']['debug']) {
|
|
|
return $context['ops']['seperator'] . static::getFuncName($context, $raw ? 'raw' : $context['ops']['enc'], $v[1]) . "\$cx, {$v[0]}){$context['ops']['seperator']}";
|
...
|
...
|
@@ -2004,18 +2041,22 @@ $libstr |
|
|
* @expect 3 when input array('usedCount' => array('test' => array('testname' => 2))), 'test', 'testname'
|
|
|
* @expect 5 when input array('usedCount' => array('test' => array('testname' => 2))), 'test', 'testname', 3
|
|
|
*/
|
|
|
protected static function addUsageCount(&$context, $category, $name, $count = 1) {
|
|
|
protected static function addUsageCount(&$context, $category, $name, $count = 1)
|
|
|
{
|
|
|
if (!isset($context['usedCount'][$category][$name])) {
|
|
|
$context['usedCount'][$category][$name] = 0;
|
|
|
}
|
|
|
return ($context['usedCount'][$category][$name] += $count);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* LightnCandy static class for compiled template runtime methods.
|
|
|
*/
|
|
|
class LCRun3 {
|
|
|
class LCRun3
|
|
|
{
|
|
|
|
|
|
const DEBUG_ERROR_LOG = 1;
|
|
|
const DEBUG_ERROR_EXCEPTION = 2;
|
|
|
const DEBUG_TAGS = 4;
|
...
|
...
|
@@ -2032,7 +2073,8 @@ class LCRun3 { |
|
|
* @expect '{{123}}' when input '123', 'miss', array('flags' => array('debug' => LCRun3::DEBUG_TAGS), 'lcrun' => 'LCRun3'), ''
|
|
|
* @expect '<!--MISSED((-->{{#123}}<!--))--><!--SKIPPED--><!--MISSED((-->{{/123}}<!--))-->' when input '123', 'wi', array('flags' => array('debug' => LCRun3::DEBUG_TAGS_HTML), 'lcrun' => 'LCRun3'), false, false, function () {return 'A';}
|
|
|
*/
|
|
|
public static function debug($v, $f, $cx) {
|
|
|
public static function debug($v, $f, $cx)
|
|
|
{
|
|
|
$params = array_slice(func_get_args(), 2);
|
|
|
$r = call_user_func_array((isset($cx['funcs'][$f]) ? $cx['funcs'][$f] : "{$cx['lcrun']}::$f"), $params);
|
|
|
|
...
|
...
|
@@ -2040,9 +2082,9 @@ class LCRun3 { |
|
|
$ansi = $cx['flags']['debug'] & (self::DEBUG_TAGS_ANSI - self::DEBUG_TAGS);
|
|
|
$html = $cx['flags']['debug'] & (self::DEBUG_TAGS_HTML - self::DEBUG_TAGS);
|
|
|
$cs = ($html ? (($r !== '') ? '<!!--OK((-->' : '<!--MISSED((-->') : '')
|
|
|
. ($ansi ? (($r !== '') ? "\033[0;32m" : "\033[0;31m") : '');
|
|
|
. ($ansi ? (($r !== '') ? "\033[0;32m" : "\033[0;31m") : '');
|
|
|
$ce = ($html ? '<!--))-->' : '')
|
|
|
. ($ansi ? "\033[0m" : '');
|
|
|
. ($ansi ? "\033[0m" : '');
|
|
|
switch ($f) {
|
|
|
case 'sec':
|
|
|
case 'ifv':
|
...
|
...
|
@@ -2071,7 +2113,8 @@ class LCRun3 { |
|
|
* @param array<string,array|string|integer> $cx render time context
|
|
|
* @param string $v expression
|
|
|
*/
|
|
|
public static function miss($cx, $v) {
|
|
|
public static function miss($cx, $v)
|
|
|
{
|
|
|
$e = "LCRun3: $v is not exist";
|
|
|
if ($cx['flags']['debug'] & self::DEBUG_ERROR_LOG) {
|
|
|
error_log($e);
|
...
|
...
|
@@ -2096,7 +2139,8 @@ class LCRun3 { |
|
|
* @expect null when input array('scopes' => array(), 'flags' => array('prop' => 0, 'method' => 0, 'mustlok' => 0)), (Object) array('a' => array('b' => 3)), array('a', 'b')
|
|
|
* @expect 3 when input array('scopes' => array(), 'flags' => array('prop' => 1, 'method' => 0, 'mustlok' => 0)), (Object) array('a' => array('b' => 3)), array('a', 'b')
|
|
|
*/
|
|
|
public static function v($cx, $base, $path) {
|
|
|
public static function v($cx, $base, $path)
|
|
|
{
|
|
|
$count = count($cx['scopes']);
|
|
|
while ($base) {
|
|
|
$v = $base;
|
...
|
...
|
@@ -2155,7 +2199,8 @@ class LCRun3 { |
|
|
* @expect true when input array(), array('')
|
|
|
* @expect true when input array(), array(0)
|
|
|
*/
|
|
|
public static function ifvar($cx, $v) {
|
|
|
public static function ifvar($cx, $v)
|
|
|
{
|
|
|
return !is_null($v) && ($v !== false) && ($v !== 0) && ($v !== 0.0) && ($v !== '') && (is_array($v) ? (count($v) > 0) : true);
|
|
|
}
|
|
|
|
...
|
...
|
@@ -2175,7 +2220,8 @@ class LCRun3 { |
|
|
* @expect 'Y' when input array('scopes' => array()), 1, array(), function () {return 'Y';}
|
|
|
* @expect 'N' when input array('scopes' => array()), null, array(), function () {return 'Y';}, function () {return 'N';}
|
|
|
*/
|
|
|
public static function ifv($cx, $v, $in, $truecb, $falsecb = null) {
|
|
|
public static function ifv($cx, $v, $in, $truecb, $falsecb = null)
|
|
|
{
|
|
|
$ret = '';
|
|
|
if (self::ifvar($cx, $v)) {
|
|
|
if ($truecb) {
|
...
|
...
|
@@ -2210,7 +2256,8 @@ class LCRun3 { |
|
|
* @expect 'Y' when input array('scopes' => array()), null, array(), function () {return 'Y';}, function () {return 'N';}
|
|
|
* @expect 'N' when input array('scopes' => array()), true, array(), function () {return 'Y';}, function () {return 'N';}
|
|
|
*/
|
|
|
public static function unl($cx, $var, $in, $truecb, $falsecb = null) {
|
|
|
public static function unl($cx, $var, $in, $truecb, $falsecb = null)
|
|
|
{
|
|
|
return self::ifv($cx, $var, $in, $falsecb, $truecb);
|
|
|
}
|
|
|
|
...
|
...
|
@@ -2229,7 +2276,8 @@ class LCRun3 { |
|
|
* @expect true when input array(), array()
|
|
|
* @expect false when input array(), array('1')
|
|
|
*/
|
|
|
public static function isec($cx, $v) {
|
|
|
public static function isec($cx, $v)
|
|
|
{
|
|
|
return is_null($v) || ($v === false) || (is_array($v) && (count($v) === 0));
|
|
|
}
|
|
|
|
...
|
...
|
@@ -2255,7 +2303,8 @@ class LCRun3 { |
|
|
* @expect 'a,' when input array('flags' => array('jstrue' => 0, 'jsobj' => 1)), array('a',false)
|
|
|
* @expect 'a,false' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1)), array('a',false)
|
|
|
*/
|
|
|
public static function raw($cx, $v) {
|
|
|
public static function raw($cx, $v)
|
|
|
{
|
|
|
if ($v === true) {
|
|
|
if ($cx['flags']['jstrue']) {
|
|
|
return 'true';
|
...
|
...
|
@@ -2299,7 +2348,8 @@ class LCRun3 { |
|
|
* @expect 'a&b' when input array(), 'a&b'
|
|
|
* @expect 'a'b' when input array(), 'a\'b'
|
|
|
*/
|
|
|
public static function enc($cx, $var) {
|
|
|
public static function enc($cx, $var)
|
|
|
{
|
|
|
return htmlentities(self::raw($cx, $var), ENT_QUOTES, 'UTF-8');
|
|
|
}
|
|
|
|
...
|
...
|
@@ -2316,7 +2366,8 @@ class LCRun3 { |
|
|
* @expect 'a'b' when input array(), 'a\'b'
|
|
|
* @expect '`a'b' when input array(), '`a\'b'
|
|
|
*/
|
|
|
public static function encq($cx, $var) {
|
|
|
public static function encq($cx, $var)
|
|
|
{
|
|
|
return preg_replace('/`/', '`', preg_replace('/'/', ''', htmlentities(self::raw($cx, $var), ENT_QUOTES, 'UTF-8')));
|
|
|
}
|
|
|
|
...
|
...
|
@@ -2357,7 +2408,8 @@ class LCRun3 { |
|
|
* @expect '268' when input array('flags' => array('spvar' => 1), 'sp_vars'=>array('root' => 0)), array(1,3,4), 0, false, function ($c, $i) {return $i * 2;}
|
|
|
* @expect '038' when input array('flags' => array('spvar' => 1), 'sp_vars'=>array('root' => 0)), array(1,3,'a'=>4), 0, true, function ($c, $i) {return $i * $c['sp_vars']['index'];}
|
|
|
*/
|
|
|
public static function sec($cx, $v, $in, $each, $cb, $else = null) {
|
|
|
public static function sec($cx, $v, $in, $each, $cb, $else = null)
|
|
|
{
|
|
|
$isAry = is_array($v) || ($v instanceof ArrayObject);
|
|
|
$isTrav = $v instanceof Traversable;
|
|
|
$loop = $each;
|
...
|
...
|
@@ -2473,7 +2525,8 @@ class LCRun3 { |
|
|
* @expect '{"a":"b"}' when input array(), array('a'=>'b'), array('a'=>'c'), function ($c, $i) {return json_encode($i);}
|
|
|
* @expect '-b=' when input array(), 'b', array('a'=>'b'), function ($c, $i) {return "-$i=";}
|
|
|
*/
|
|
|
public static function wi($cx, $v, $in, $cb, $else = null) {
|
|
|
public static function wi($cx, $v, $in, $cb, $else = null)
|
|
|
{
|
|
|
if (($v === false) || ($v === null)) {
|
|
|
return $else ? $else($cx, $in) : '';
|
|
|
}
|
...
|
...
|
@@ -2493,7 +2546,8 @@ class LCRun3 { |
|
|
* @return string The rendered string of the partial
|
|
|
*
|
|
|
*/
|
|
|
public static function p($cx, $p, $v, $sp = '') {
|
|
|
public static function p($cx, $p, $v, $sp = '')
|
|
|
{
|
|
|
$param = $v[0][0];
|
|
|
|
|
|
if (is_array($v[1])) {
|
...
|
...
|
@@ -2524,7 +2578,8 @@ class LCRun3 { |
|
|
* @expect '='=' when input array('helpers' => array('a' => function ($i) {return "=$i[0]=";})), 'a', array(array('\''),array()), 'encq'
|
|
|
* @expect '=b=' when input array('helpers' => array('a' => function ($i,$j) {return "={$j['a']}=";})), 'a', array(array(),array('a' => 'b')), 'raw'
|
|
|
*/
|
|
|
public static function ch($cx, $ch, $vars, $op) {
|
|
|
public static function ch($cx, $ch, $vars, $op)
|
|
|
{
|
|
|
return self::chret(call_user_func_array($cx['helpers'][$ch], $vars), $op);
|
|
|
}
|
|
|
|
...
|
...
|
@@ -2546,7 +2601,8 @@ class LCRun3 { |
|
|
* @expect '=&=' when input array('=&=', 'raw'), 'enc'
|
|
|
* @expect '=&'=' when input array('=&\'=', 'encq'), 'raw'
|
|
|
*/
|
|
|
public static function chret($ret, $op) {
|
|
|
public static function chret($ret, $op)
|
|
|
{
|
|
|
if (is_array($ret)) {
|
|
|
if (isset($ret[1]) && $ret[1]) {
|
|
|
$op = $ret[1];
|
...
|
...
|
@@ -2576,7 +2632,8 @@ class LCRun3 { |
|
|
*
|
|
|
* @return string The rendered string of the token
|
|
|
*/
|
|
|
public static function hbch($cx, $ch, $vars, $op, $inverted, $cb = null, $else = null) {
|
|
|
public static function hbch($cx, $ch, $vars, $op, $inverted, $cb = null, $else = null)
|
|
|
{
|
|
|
$isBlock = (is_object($cb) && ($cb instanceof Closure));
|
|
|
$args = $vars[0];
|
|
|
$options = array(
|
...
|
...
|
@@ -2640,7 +2697,7 @@ class LCRun3 { |
|
|
$e = "LCRun3: call custom helper '$ch' error: " . $E->getMessage();
|
|
|
}
|
|
|
|
|
|
if($e !== null) {
|
|
|
if ($e !== null) {
|
|
|
if ($cx['flags']['debug'] & self::DEBUG_ERROR_LOG) {
|
|
|
error_log($e);
|
|
|
}
|
...
|
...
|
@@ -2669,7 +2726,8 @@ class LCRun3 { |
|
|
* @expect '2.6.5' when input array('blockhelpers' => array('a' => function ($cx,$in) {return array($cx,$in[0],5);})), 'a', array('6', 0), 2, false, function($cx, $i) {return implode('.', $i);}
|
|
|
* @expect '' when input array('blockhelpers' => array('a' => function ($cx,$in) {})), 'a', array('6', 0), 2, false, function($cx, $i) {return implode('.', $i);}
|
|
|
*/
|
|
|
public static function bch($cx, $ch, $vars, $in, $inverted, $cb, $else = null) {
|
|
|
public static function bch($cx, $ch, $vars, $in, $inverted, $cb, $else = null)
|
|
|
{
|
|
|
$r = call_user_func($cx['blockhelpers'][$ch], $in, $vars[0], $vars[1]);
|
|
|
|
|
|
// $invert the logic
|
...
|
...
|
@@ -2696,4 +2754,5 @@ class LCRun3 { |
|
|
|
|
|
return $ret;
|
|
|
}
|
|
|
|
|
|
} |
...
|
...
|
|