42 const REGEX_NAME =
'/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
44 const REGEX_STRING =
'/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
53 $this->options = array_merge(array(
54 'tag_comment' => array(
'{#',
'#}'),
55 'tag_block' => array(
'{%',
'%}'),
56 'tag_variable' => array(
'{{',
'}}'),
57 'whitespace_trim' =>
'-',
58 'interpolation' => array(
'#{',
'}'),
61 $this->regexes = array(
62 'lex_var' =>
'/\s*'.preg_quote($this->options[
'whitespace_trim'].$this->options[
'tag_variable'][1],
'/').
'\s*|\s*'.preg_quote($this->options[
'tag_variable'][1],
'/').
'/A',
63 'lex_block' =>
'/\s*(?:'.preg_quote($this->options[
'whitespace_trim'].$this->options[
'tag_block'][1],
'/').
'\s*|\s*'.preg_quote($this->options[
'tag_block'][1],
'/').
')\n?/A',
64 'lex_raw_data' =>
'/('.preg_quote($this->options[
'tag_block'][0].$this->options[
'whitespace_trim'],
'/').
'|'.preg_quote($this->options[
'tag_block'][0],
'/').
')\s*(?:end%s)\s*(?:'.preg_quote($this->options[
'whitespace_trim'].$this->options[
'tag_block'][1],
'/').
'\s*|\s*'.preg_quote($this->options[
'tag_block'][1],
'/').
')/s',
66 'lex_comment' =>
'/(?:'.preg_quote($this->options[
'whitespace_trim'],
'/').preg_quote($this->options[
'tag_comment'][1],
'/').
'\s*|'.preg_quote($this->options[
'tag_comment'][1],
'/').
')\n?/s',
67 'lex_block_raw' =>
'/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options[
'whitespace_trim'].$this->options[
'tag_block'][1],
'/').
'\s*|\s*'.preg_quote($this->options[
'tag_block'][1],
'/').
')/As',
68 'lex_block_line' =>
'/\s*line\s+(\d+)\s*'.preg_quote($this->options[
'tag_block'][1],
'/').
'/As',
69 'lex_tokens_start' =>
'/('.preg_quote($this->options[
'tag_variable'][0],
'/').
'|'.preg_quote($this->options[
'tag_block'][0],
'/').
'|'.preg_quote($this->options[
'tag_comment'][0],
'/').
')('.preg_quote($this->options[
'whitespace_trim'],
'/').
')?/s',
70 'interpolation_start' =>
'/'.preg_quote($this->options[
'interpolation'][0],
'/').
'\s*/A',
71 'interpolation_end' =>
'/\s*'.preg_quote($this->options[
'interpolation'][1],
'/').
'/A',
85 if (function_exists(
'mb_internal_encoding') && ((
int) ini_get(
'mbstring.func_overload')) & 2) {
86 $mbEncoding = mb_internal_encoding();
87 mb_internal_encoding(
'ASCII');
90 $this->code = str_replace(array(
"\r\n",
"\r"),
"\n",
$code);
94 $this->end = strlen($this->code);
95 $this->tokens = array();
96 $this->state = self::STATE_DATA;
97 $this->states = array();
98 $this->brackets = array();
102 preg_match_all($this->regexes[
'lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE);
103 $this->positions = $matches;
105 while ($this->cursor < $this->end) {
108 switch ($this->state) {
109 case self::STATE_DATA:
113 case self::STATE_BLOCK:
117 case self::STATE_VAR:
121 case self::STATE_STRING:
125 case self::STATE_INTERPOLATION:
133 if (!empty($this->brackets)) {
134 list($expect,
$lineno) = array_pop($this->brackets);
138 if (isset($mbEncoding)) {
139 mb_internal_encoding($mbEncoding);
148 if ($this->position == count($this->positions[0]) - 1) {
158 if ($this->position == count($this->positions[0]) - 1) {
165 $text = $textContent = substr($this->code, $this->cursor,
$position[1] - $this->cursor);
166 if (isset($this->positions[2][$this->position][0])) {
167 $text = rtrim($text);
172 switch ($this->positions[1][$this->position][0]) {
173 case $this->options[
'tag_comment'][0]:
177 case $this->options[
'tag_block'][0]:
179 if (preg_match($this->regexes[
'lex_block_raw'], $this->code,
$match, null, $this->cursor)) {
183 }
elseif (preg_match($this->regexes[
'lex_block_line'], $this->code,
$match, null, $this->cursor)) {
185 $this->lineno = (int)
$match[1];
193 case $this->options[
'tag_variable'][0]:
203 if (empty($this->brackets) && preg_match($this->regexes[
'lex_block'], $this->code,
$match, null, $this->cursor)) {
214 if (empty($this->brackets) && preg_match($this->regexes[
'lex_var'], $this->code,
$match, null, $this->cursor)) {
226 if (preg_match(
'/\s+/A', $this->code,
$match, null, $this->cursor)) {
229 if ($this->cursor >= $this->end) {
230 throw new Twig_Error_Syntax(sprintf(
'Unclosed "%s"', $this->state === self::STATE_BLOCK ?
'block' :
'variable'), $this->currentVarBlockLine, $this->filename);
235 if (preg_match($this->regexes[
'operator'], $this->code,
$match, null, $this->cursor)) {
240 elseif (preg_match(self::REGEX_NAME, $this->code,
$match, null, $this->cursor)) {
245 elseif (preg_match(self::REGEX_NUMBER, $this->code,
$match, null, $this->cursor)) {
246 $number = (float)
$match[0];
247 if (ctype_digit(
$match[0]) && $number <= PHP_INT_MAX) {
248 $number = (int)
$match[0];
254 elseif (
false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) {
256 if (
false !== strpos(
'([{', $this->code[$this->cursor])) {
257 $this->brackets[] = array($this->code[$this->cursor], $this->lineno);
260 elseif (
false !== strpos(
')]}', $this->code[$this->cursor])) {
261 if (empty($this->brackets)) {
262 throw new Twig_Error_Syntax(sprintf(
'Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
265 list($expect,
$lineno) = array_pop($this->brackets);
266 if ($this->code[$this->cursor] != strtr($expect,
'([{',
')]}')) {
275 elseif (preg_match(self::REGEX_STRING, $this->code,
$match, null, $this->cursor)) {
280 elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code,
$match, null, $this->cursor)) {
281 $this->brackets[] = array(
'"', $this->lineno);
287 throw new Twig_Error_Syntax(sprintf(
'Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
293 if (!preg_match(str_replace(
'%s', $tag, $this->regexes[
'lex_raw_data']), $this->code,
$match, PREG_OFFSET_CAPTURE, $this->cursor)) {
294 throw new Twig_Error_Syntax(sprintf(
'Unexpected end of file: Unclosed "%s" block', $tag), $this->lineno, $this->filename);
297 $text = substr($this->code, $this->cursor,
$match[0][1] - $this->cursor);
300 if (
false !== strpos(
$match[1][0], $this->options[
'whitespace_trim'])) {
301 $text = rtrim($text);
309 if (!preg_match($this->regexes[
'lex_comment'], $this->code,
$match, PREG_OFFSET_CAPTURE, $this->cursor)) {
318 if (preg_match($this->regexes[
'interpolation_start'], $this->code,
$match, null, $this->cursor)) {
319 $this->brackets[] = array($this->options[
'interpolation'][0], $this->lineno);
322 $this->
pushState(self::STATE_INTERPOLATION);
324 }
elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code,
$match, null, $this->cursor) && strlen(
$match[0]) > 0) {
328 }
elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code,
$match, null, $this->cursor)) {
330 list($expect,
$lineno) = array_pop($this->brackets);
331 if ($this->code[$this->cursor] !=
'"') {
342 $bracket = end($this->brackets);
343 if ($this->options[
'interpolation'][0] === $bracket[0] && preg_match($this->regexes[
'interpolation_end'], $this->code,
$match, null, $this->cursor)) {
344 array_pop($this->brackets);
360 $this->tokens[] =
new Twig_Token($type, $value, $this->lineno);
365 $this->cursor += strlen($text);
366 $this->lineno += substr_count($text,
"\n");
371 $operators = array_merge(
373 array_keys($this->env->getUnaryOperators()),
374 array_keys($this->env->getBinaryOperators())
377 $operators = array_combine($operators, array_map(
'strlen', $operators));
381 foreach ($operators as $operator => $length) {
384 if (ctype_alpha($operator[$length - 1])) {
385 $regex[] = preg_quote($operator,
'/').
'(?=[\s()])';
387 $regex[] = preg_quote($operator,
'/');
391 return '/'.implode(
'|', $regex).
'/A';
402 if (0 === count($this->states)) {
403 throw new Exception(
'Cannot pop state without a previous state');
406 $this->state = array_pop($this->states);
const REGEX_DQ_STRING_DELIM
__construct(Twig_Environment $env, array $options=array())
Exception thrown when a syntax error occurs during lexing or parsing of a template.
tokenize($code, $filename=null)
Tokenizes a source code.
Interface implemented by lexer classes.
const INTERPOLATION_END_TYPE
if(strlen($date2)== '10') if($type== 'users-by-age'&&a_priv('admin_users', true)) elseif($type== 'forums-count'&&a_priv('admin_content', true)) elseif($type== 'forums-categories'&&a_priv('admin_content', true)) elseif($type== 'users-count'&&a_priv('admin_users', true)) elseif($type== 'product-categories'&&a_priv('admin_products', true)) elseif($type== 'users-by-sex'&&a_priv('admin_users', true)) elseif($type== 'users-by-country'&&a_priv('admin_users', true)) elseif($type== 'sales'&&a_priv('admin_sales', true))
const REGEX_DQ_STRING_PART
Represents a token stream.
const STATE_INTERPOLATION
pushToken($type, $value= '')
const INTERPOLATION_START_TYPE
Stores the Twig configuration.