/** * Return compiled PHP code for a handlebars block end token * * @param array<string,array|string|integer> $context current compile context * @param array<boolean|integer|string|array> $vars parsed arguments list * @param string|null $match should also match to this operator * * @return boolean Return true */ protected static function blockEnd(&$context, &$vars, $match = null) { $context['level']--; $c = count($context['stack']) - 2; $pop = $c >= 0 ? $context['stack'][$c + 1] : ''; if ($match !== null && $match !== $pop) { return; } $pop2 = $c >= 0 ? $context['stack'][$c] : ''; switch ($context['currentToken'][Token::POS_INNERTAG]) { case 'with': if (!$context['flags']['nohbh']) { if ($pop2 !== '[with]') { $context['error'][] = 'Unexpect token: {{/with}} !'; return; } } return true; } switch ($pop) { case '#': case '^': $elsechain = array_shift($context['elselvl']); if (isset($elsechain[0])) { $context['currentToken'][Token::POS_RSPACE] = $context['currentToken'][Token::POS_BACKFILL] = '{{/' . implode('}}{{/', $elsechain) . '}}' . Token::toString($context['currentToken']) . $context['currentToken'][Token::POS_RSPACE]; return Token::POS_BACKFILL; } case '#>': case '#*': list($levels, $spvar, $var) = Expression::analyze($context, $vars[0]); $v = Expression::toString($levels, $spvar, $var); if ($pop2 !== $v) { $context['error'][] = 'Unexpect token ' . Token::toString($context['currentToken']) . " ! Previous token {{{$pop}{$pop2}}} is not closed"; return; } return true; default: $context['error'][] = 'Unexpect token: ' . Token::toString($context['currentToken']) . ' !'; return; } }
/** * Get string presentation of a variable * * @param array<array|string|integer> $var variable parsed path * @param array<array|string|integer> $context current compile context * @param array<string> $lookup extra lookup string as valid PHP variable name * * @return array<string> variable names * * @expect array('$in', 'this') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(null) * @expect array('((isset($in[\'true\']) && is_array($in)) ? $in[\'true\'] : null)', '[true]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('true') * @expect array('((isset($in[\'false\']) && is_array($in)) ? $in[\'false\'] : null)', '[false]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('false') * @expect array('true', 'true') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(-1, 'true') * @expect array('false', 'false') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(-1, 'false') * @expect array('((isset($in[\'2\']) && is_array($in)) ? $in[\'2\'] : null)', '[2]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('2') * @expect array('2', '2') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0)), array(-1, '2') * @expect array('((isset($in[\'@index\']) && is_array($in)) ? $in[\'@index\'] : null)', '[@index]') when input array('flags'=>array('spvar'=>false,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('@index') * @expect array("((isset(\$cx['sp_vars']['index']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['index'] : null)", '@[index]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('@index') * @expect array("((isset(\$cx['sp_vars']['key']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['key'] : null)", '@[key]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('@key') * @expect array("((isset(\$cx['sp_vars']['first']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['first'] : null)", '@[first]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('@first') * @expect array("((isset(\$cx['sp_vars']['last']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['last'] : null)", '@[last]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('@last') * @expect array('((isset($in[\'"a"\']) && is_array($in)) ? $in[\'"a"\'] : null)', '["a"]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('"a"') * @expect array('"a"', '"a"') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(-1, '"a"') * @expect array('((isset($in[\'a\']) && is_array($in)) ? $in[\'a\'] : null)', '[a]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('a') * @expect array('((isset($cx[\'scopes\'][count($cx[\'scopes\'])-1][\'a\']) && is_array($cx[\'scopes\'][count($cx[\'scopes\'])-1])) ? $cx[\'scopes\'][count($cx[\'scopes\'])-1][\'a\'] : null)', '../[a]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array(1,'a') * @expect array('((isset($cx[\'scopes\'][count($cx[\'scopes\'])-3][\'a\']) && is_array($cx[\'scopes\'][count($cx[\'scopes\'])-3])) ? $cx[\'scopes\'][count($cx[\'scopes\'])-3][\'a\'] : null)', '../../../[a]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array(3,'a') * @expect array('((isset($in[\'id\']) && is_array($in)) ? $in[\'id\'] : null)', 'this.[id]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array(null, 'id') * @expect array('LR::v($cx, $in, isset($in) ? $in : null, array(\'id\'))', 'this.[id]') when input array('flags'=>array('prop'=>true,'spvar'=>true,'debug'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0,'standalone'=>0), 'runtime' => 'Runtime'), array(null, 'id') */ protected static function getVariableName(&$context, $var, $lookup = null, $args = null) { if (isset($var[0]) && $var[0] === Parser::LITERAL) { if ($var[1] === "undefined") { $var[1] = "null"; } return array($var[1], preg_replace('/\'(.*)\'/', '$1', $var[1])); } list($levels, $spvar, $var) = Expression::analyze($context, $var); $exp = Expression::toString($levels, $spvar, $var); $base = $spvar ? "\$cx['sp_vars']" : '$in'; // change base when trace to parent if ($levels > 0) { if ($spvar) { $base .= str_repeat("['_parent']", $levels); } else { $base = "\$cx['scopes'][count(\$cx['scopes'])-{$levels}]"; } } if (count($var) == 0 || $var[0] === null && count($var) == 1) { return array($base, $exp); } if ($var[0] === null) { array_shift($var); } // To support recursive context lookup, instance properties + methods and lambdas // the only way is using slower rendering time variable resolver. if ($context['flags']['prop'] || $context['flags']['method'] || $context['flags']['mustlok'] || $context['flags']['mustlam'] || $context['flags']['lambda']) { $L = $lookup ? ", {$lookup['0']}" : ''; $A = $args ? ",{$args['0']}" : ''; $E = $args ? ' ' . implode(' ', $args[1]) : ''; return array(static::getFuncName($context, 'v', $exp) . "\$cx, \$in, isset({$base}) ? {$base} : null, array(" . Expression::listString($var) . "{$L}){$A})", $lookup ? "lookup {$exp} {$lookup['1']}" : "{$exp}{$E}"); } $n = Expression::arrayString($var); array_pop($var); $L = $lookup ? "[{$lookup[0]}]" : ''; $p = $lookup ? $n : (count($var) ? Expression::arrayString($var) : ''); return array("((isset({$base}{$n}{$L}) && is_array({$base}{$p})) ? {$base}{$n}{$L} : " . ($context['flags']['debug'] ? static::getFuncName($context, 'miss', '') . "\$cx, '{$exp}')" : 'null') . ')', $lookup ? "lookup {$exp} {$lookup['1']}" : $exp); }
/** * Return compiled PHP code for a handlebars block end token * * @param array<string,array|string|integer> $context current compile context * @param array<boolean|integer|string|array> $vars parsed arguments list * @param string|null $matchop should also match to this operator * * @return boolean Return true */ protected static function blockEnd(&$context, $vars, $match = null) { $context['level']--; $c = count($context['stack']) - 2; $pop = $c >= 0 ? $context['stack'][$c + 1] : ''; if ($match !== null && $match !== $pop) { return; } $pop2 = $c >= 0 ? $context['stack'][$c] : ''; switch ($context['currentToken'][Token::POS_INNERTAG]) { case 'with': if (!$context['flags']['nohbh']) { if ($pop2 !== '[with]') { $context['error'][] = 'Unexpect token: {{/with}} !'; return; } } return true; } switch ($pop) { case '#>': case '#*': case '#': case '^': list($levels, $spvar, $var) = Expression::analyze($context, $vars[0]); $v = Expression::toString($levels, $spvar, $var); if ($pop2 !== $v) { $context['error'][] = 'Unexpect token ' . Token::toString($context['currentToken']) . " ! Previous token {{{$pop}{$pop2}}} is not closed"; return; } if ($pop == '^') { return "{$context['ops']['cnd_else']}''{$context['ops']['cnd_end']}"; } return "{$context['ops']['f_end']}}){$context['ops']['seperator']}"; default: $context['error'][] = 'Unexpect token: ' . Token::toString($context['currentToken']) . ' !'; return; } }