/** * Parses bits for template tag helpers (simple_tag, include_tag and * assignment_tag), in particular by detecting syntax errors and by * extracting positional and keyword arguments. * * @static * * @param Parser $parser * @param array $bits * @param array $params * @param $varargs * @param $varkw * @param $defaults * @param bool $takes_context * @param string $name * * @return array * @throws TemplateSyntaxError */ public static function parseBits($parser, $bits, $params, $varargs, $varkw, $defaults, $takes_context, $name) { if ($takes_context) { if ($params[0] == 'context') { $params = py_slice($params, 1); } else { throw new TemplateSyntaxError('\'' . $name . '\' is decorated with takes_context=True so it must have a first argument of \'context\''); } } $args = $kwargs = array(); $unhandled_params = $params; foreach ($bits as $bit) { // First we try to extract a potential kwarg from the bit $bit_ = array($bit); $kwarg = DjaBase::tokenKwargs($bit_, $parser); unset($bit_); if ($kwarg) { // Not until PHP supports keyword arguments %) } else { if ($kwargs) { throw new TemplateSyntaxError('\'' . $name . '\' received some positional argument(s) after some keyword argument(s)'); } else { // Record the positional argument $args[] = $parser->compileFilter($bit); try { // Consume from the list of expected positional arguments py_arr_pop($unhandled_params, 0); } catch (IndexError $e) { if ($varargs === null) { throw new TemplateSyntaxError('\'' . $name . '\' received too many positional arguments'); } } } } } if ($defaults !== null) { // Consider the last n params handled, where n is the number of defaults. $unhandled_params = py_slice($unhandled_params, null, -count($defaults)); } if ($unhandled_params) { // Some positional arguments were not supplied $args_ = array(); foreach ($unhandled_params as $p) { $args_ = "'{$p}'"; } throw new TemplateSyntaxError('\'' . $name . '\' did not receive value(s) for the argument(s): ' . join(', ', $args_)); } return array($args, $kwargs); }
* @var Parser $parser * @var Token $token */ $bits = $token->splitContents(); if (count($bits) < 2) { throw new TemplateSyntaxError('\'include\' tag takes at least one argument: the name of the template to be included.'); } $options = array(); $remaining_bits = py_slice($bits, 2); while ($remaining_bits) { $option = py_arr_pop($remaining_bits, 0); if (isset($options[$option])) { throw new TemplateSyntaxError('The ' . $option . ' option was specified more than once.'); } if ($option == 'with') { $value = DjaBase::tokenKwargs($remaining_bits, $parser, False); if (!$value) { throw new TemplateSyntaxError('"with" in \'include\' tag needs at least one keyword argument.'); } } elseif ($option == 'only') { $value = True; } else { throw new TemplateSyntaxError('Unknown argument for \'include\' tag: ' . $option . '.'); } $options[$option] = $value; } $isolated_context = py_arr_get($options, 'only', False); $namemap = py_arr_get($options, 'with', array()); $path = $bits[1]; if (in_array($path[0], array('"', "'")) && py_arr_get($path, -1) == $path[0]) { return new ConstantIncludeNode(py_slice($path, 1, -1), $namemap, $isolated_context);
$lib->tag('widthratio', function ($parser, $token) { /** * @var Parser $parser * @var Token $token */ $bits = py_str_split($token->contents); if (count($bits) != 4) { throw new TemplateSyntaxError('widthratio takes three arguments'); } list($tag, $this_value_expr, $max_value_expr, $max_width) = $bits; return new WidthRatioNode($parser->compileFilter($this_value_expr), $parser->compileFilter($max_value_expr), $parser->compileFilter($max_width)); }); $lib->tag('with', function ($parser, $token) { /** * @var Parser $parser * @var Token $token */ $bits = py_str_split($token->contents); $remaining_bits = py_slice($bits, 1); $extra_context = DjaBase::tokenKwargs($remaining_bits, $parser, True); if (!$extra_context) { throw new TemplateSyntaxError('\'with\' expected at least one variable assignment'); } if ($remaining_bits) { throw new TemplateSyntaxError('\'with\' received an invalid token: ' . $remaining_bits[0]); } $nodelist = $parser->parse(array('endwith')); $parser->deleteFirstToken(); return new WithNode(null, null, $nodelist, $extra_context); }); return $lib;