@ -182,12 +182,12 @@ function _create_antibot($board, $thread) {
$antibot = new AntiBot(array($board, $thread));
$antibot = new AntiBot(array($board, $thread));
query('DELETE FROM `antispam` WHERE `expires` <UNIX_TIMESTAMP()')orerror(db_error());
query('DELETE FROM ``antispam`` WHERE `expires` <UNIX_TIMESTAMP()')orerror(db_error());
if ($thread)
if ($thread)
$query = prepare('UPDATE `antispam` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE `board` = :board AND `thread` = :thread AND `expires` IS NULL');
$query = prepare('UPDATE ``antispam`` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE `board` = :board AND `thread` = :thread AND `expires` IS NULL');
else
else
$query = prepare('UPDATE `antispam` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE `board` = :board AND `thread` IS NULL AND `expires` IS NULL');
$query = prepare('UPDATE ``antispam`` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE `board` = :board AND `thread` IS NULL AND `expires` IS NULL');
$query->bindValue(':board', $board);
$query->bindValue(':board', $board);
if ($thread)
if ($thread)
@ -195,7 +195,7 @@ function _create_antibot($board, $thread) {
if (hasPermission($config['mod']['delete'], $board['uri'], $this->mod))
if (hasPermission($config['mod']['delete'], $board['uri'], $this->mod))
$built .= ' ' . secure_link_confirm($config['mod']['link_delete'], 'Delete', 'Are you sure you want to delete this?', $board['uri'] . '/delete/' . $this->id);
$built .= ' ' . secure_link_confirm($config['mod']['link_delete'], 'Delete', 'Are you sure you want to delete this?', $board['dir'] . 'delete/' . $this->id);
// Delete all posts by IP
// Delete all posts by IP
if (hasPermission($config['mod']['deletebyip'], $board['uri'], $this->mod))
if (hasPermission($config['mod']['deletebyip'], $board['uri'], $this->mod))
$built .= ' ' . secure_link_confirm($config['mod']['link_deletebyip'], 'Delete all posts by IP', 'Are you sure you want to delete all posts by this IP address?', $board['uri'] . '/deletebyip/' . $this->id);
$built .= ' ' . secure_link_confirm($config['mod']['link_deletebyip'], 'Delete all posts by IP', 'Are you sure you want to delete all posts by this IP address?', $board['dir'] . 'deletebyip/' . $this->id);
// Delete all posts by IP (global)
// Delete all posts by IP (global)
if (hasPermission($config['mod']['deletebyip_global'], $board['uri'], $this->mod))
if (hasPermission($config['mod']['deletebyip_global'], $board['uri'], $this->mod))
$built .= ' ' . secure_link_confirm($config['mod']['link_deletebyip_global'], 'Delete all posts by IP across all boards', 'Are you sure you want to delete all posts by this IP address, across all boards?', $board['uri'] . '/deletebyip/' . $this->id . '/global');
$built .= ' ' . secure_link_confirm($config['mod']['link_deletebyip_global'], 'Delete all posts by IP across all boards', 'Are you sure you want to delete all posts by this IP address, across all boards?', $board['dir'] . 'deletebyip/' . $this->id . '/global');
// Ban
// Ban
if (hasPermission($config['mod']['ban'], $board['uri'], $this->mod))
if (hasPermission($config['mod']['ban'], $board['uri'], $this->mod))
if (hasPermission($config['mod']['delete'], $board['uri'], $this->mod))
if (hasPermission($config['mod']['delete'], $board['uri'], $this->mod))
$built .= ' ' . secure_link_confirm($config['mod']['link_delete'], 'Delete', 'Are you sure you want to delete this?', $board['uri'] . '/delete/' . $this->id);
$built .= ' ' . secure_link_confirm($config['mod']['link_delete'], _('Delete'), _('Are you sure you want to delete this?'), $board['dir'] . 'delete/' . $this->id);
// Delete all posts by IP
// Delete all posts by IP
if (hasPermission($config['mod']['deletebyip'], $board['uri'], $this->mod))
if (hasPermission($config['mod']['deletebyip'], $board['uri'], $this->mod))
$built .= ' ' . secure_link_confirm($config['mod']['link_deletebyip'], 'Delete all posts by IP', 'Are you sure you want to delete all posts by this IP address?', $board['uri'] . '/deletebyip/' . $this->id);
$built .= ' ' . secure_link_confirm($config['mod']['link_deletebyip'], _('Delete all posts by IP'), _('Are you sure you want to delete all posts by this IP address?'), $board['dir'] . 'deletebyip/' . $this->id);
// Delete all posts by IP (global)
// Delete all posts by IP (global)
if (hasPermission($config['mod']['deletebyip_global'], $board['uri'], $this->mod))
if (hasPermission($config['mod']['deletebyip_global'], $board['uri'], $this->mod))
$built .= ' ' . secure_link_confirm($config['mod']['link_deletebyip_global'], 'Delete all posts by IP across all boards', 'Are you sure you want to delete all posts by this IP address, across all boards?', $board['uri'] . '/deletebyip/' . $this->id . '/global');
$built .= ' ' . secure_link_confirm($config['mod']['link_deletebyip_global'], _('Delete all posts by IP across all boards'), _('Are you sure you want to delete all posts by this IP address, across all boards?'), $board['dir'] . 'deletebyip/' . $this->id . '/global');
// Ban
// Ban
if (hasPermission($config['mod']['ban'], $board['uri'], $this->mod))
if (hasPermission($config['mod']['ban'], $board['uri'], $this->mod))
if ($config['cache']['enabled'] && ($boards = cache::get('all_boards')))
if ($config['cache']['enabled'] && ($boards = cache::get('all_boards')))
return $boards;
return $boards;
$query = query("SELECT * FROM `boards` ORDER BY `uri`") or error(db_error());
$query = query("SELECT * FROM ``boards`` ORDER BY `uri`") or error(db_error());
$boards = $query->fetchAll();
$boards = $query->fetchAll();
if ($config['cache']['enabled'])
if ($config['cache']['enabled'])
@ -527,7 +556,7 @@ function listBoards() {
function checkFlood($post) {
function checkFlood($post) {
global $board, $config;
global $board, $config;
$query = prepare(sprintf("SELECT * FROM `posts_%s` WHERE (`ip` = :ip AND `time` >= :floodtime) OR (`ip` = :ip AND `body` != '' AND `body` = :body AND `time` >= :floodsameiptime) OR (`body` != '' AND `body` = :body AND `time` >= :floodsametime) LIMIT 1", $board['uri']));
$query = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE (`ip` = :ip AND `time` >= :floodtime) OR (`ip` = :ip AND `body` != '' AND `body` = :body AND `time` >= :floodsameiptime) OR (`body` != '' AND `body` = :body AND `time` >= :floodsametime) LIMIT 1", $board['uri']));
@ -612,12 +641,12 @@ function checkBan($board = 0) {
if (event('check-ban', $board))
if (event('check-ban', $board))
return true;
return true;
$query = prepare("SELECT `set`, `expires`, `reason`, `board`, `seen`, `bans`.`id` FROM `bans` WHERE (`board` IS NULL OR `board` = :board) AND `ip` = :ip ORDER BY `expires` IS NULL DESC, `expires` DESC, `expires` DESC LIMIT 1");
$query = prepare("SELECT `set`, `expires`, `reason`, `board`, `seen`, ``bans``.`id` FROM ``bans`` WHERE (`board` IS NULL OR `board` = :board) AND `ip` = :ip ORDER BY `expires` IS NULL DESC, `expires` DESC, `expires` DESC LIMIT 1");
$query = prepare("SELECT `set`, `expires`, `reason`, `board`, `seen`, `bans`.`id` FROM `bans` WHERE (`board` IS NULL OR `board` = :board) AND :ip LIKE REPLACE(REPLACE(`ip`, '%', '!%'), '*', '%') ESCAPE '!' ORDER BY `expires` IS NULL DESC, `expires` DESC LIMIT 1");
$query = prepare("SELECT `set`, `expires`, `reason`, `board`, `seen`, ``bans``.`id` FROM ``bans`` WHERE (`board` IS NULL OR `board` = :board) AND :ip LIKE REPLACE(REPLACE(`ip`, '%', '!%'), '*', '%') ESCAPE '!' ORDER BY `expires` IS NULL DESC, `expires` DESC LIMIT 1");
// I too wish there was an easier way of doing this...
// I too wish there was an easier way of doing this...
$query = prepare(sprintf("SELECT `id` FROM `posts_%s` WHERE `thread` IS NULL ORDER BY `sticky` DESC, `bump` DESC LIMIT :offset, 9001", $board['uri']));
$query = prepare(sprintf("SELECT `id` FROM ``posts_%s`` WHERE `thread` IS NULL ORDER BY `sticky` DESC, `bump` DESC LIMIT :offset, 9001", $board['uri']));
$query = query(sprintf("SELECT `id` FROM ``posts_%s`` WHERE `thread` IS NULL ORDER BY `sticky` DESC, `bump` DESC", $board['uri'])) or error(db_error($query));
$threads = $query->fetchAll(PDO::FETCH_COLUMN);
if (($index = array_search($thread, $threads)) === false)
$query = prepare(sprintf("SELECT * FROM `posts_%s` WHERE `thread` IS NULL ORDER BY `sticky` DESC, `bump` DESC LIMIT :offset,:threads_per_page", $board['uri']));
$query = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE `thread` IS NULL ORDER BY `sticky` DESC, `bump` DESC LIMIT :offset,:threads_per_page", $board['uri']));
@ -1141,32 +1198,31 @@ function checkRobot($body) {
return true;
return true;
$body = makerobot($body);
$body = makerobot($body);
$query = prepare("SELECT 1 FROM `robot` WHERE `hash` = :hash LIMIT 1");
$query = prepare("SELECT 1 FROM ``robot`` WHERE `hash` = :hash LIMIT 1");
$query->bindValue(':hash', $body);
$query->bindValue(':hash', $body);
$query->execute() or error(db_error($query));
$query->execute() or error(db_error($query));
if ($query->fetch()) {
if ($query->fetchColumn()) {
return true;
return true;
}
}
// Insert new hash
// Insert new hash
$query = prepare("INSERT INTO `robot` VALUES (:hash)");
$query = prepare("INSERT INTO ``robot`` VALUES (:hash)");
$query->bindValue(':hash', $body);
$query->bindValue(':hash', $body);
$query->execute() or error(db_error($query));
$query->execute() or error(db_error($query));
return false;
return false;
}
}
// Returns an associative array with 'replies' and 'images' keys
// Returns an associative array with 'replies' and 'images' keys
function numPosts($id) {
function numPosts($id) {
global $board;
global $board;
$query = prepare(sprintf("SELECT COUNT(*) as `num` FROM `posts_%s` WHERE `thread` = :thread UNION ALL SELECT COUNT(*) FROM `posts_%s` WHERE `file` IS NOT NULL AND `thread` = :thread", $board['uri'], $board['uri']));
$query = prepare(sprintf("SELECT COUNT(*) FROM ``posts_%s`` WHERE `thread` = :thread UNION ALL SELECT COUNT(*) FROM ``posts_%s`` WHERE `file` IS NOT NULL AND `thread` = :thread", $board['uri'], $board['uri']));
function buildThread($id, $return = false, $mod = false) {
function buildThread($id, $return = false, $mod = false) {
global $board, $config;
global $board, $config, $build_pages;
$id = round($id);
$id = round($id);
if (event('build-thread', $id))
if (event('build-thread', $id))
@ -1562,11 +1746,11 @@ function buildThread($id, $return=false, $mod=false) {
cache::delete("thread_{$board['uri']}_{$id}");
cache::delete("thread_{$board['uri']}_{$id}");
}
}
$query = prepare(sprintf("SELECT * FROM `posts_%s` WHERE (`thread` IS NULL AND `id` = :id) OR `thread` = :id ORDER BY `thread`,`id`", $board['uri']));
$query = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE (`thread` IS NULL AND `id` = :id) OR `thread` = :id ORDER BY `thread`,`id`", $board['uri']));
throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType(), $token->getLine()), $token->getValue()), $token->getLine());
throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType(), $token->getLine()), $token->getValue()), $token->getLine(), $this->parser->getFilename());
}
}
}
}
return $this->parsePostfixExpression($node);
return $this->parsePostfixExpression($node);
}
}
public function parseStringExpression()
{
$stream = $this->parser->getStream();
$nodes = array();
// a string cannot be followed by another string in a single expression
$nextCanBeString = true;
while (true) {
if ($stream->test(Twig_Token::STRING_TYPE) && $nextCanBeString) {
$token = $stream->next();
$nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string or a number (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType(), $current->getLine()), $current->getValue()), $current->getLine());
throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType(), $current->getLine()), $current->getValue()), $current->getLine(), $this->parser->getFilename());
}
}
$key = $stream->next()->getValue();
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
$elements[$key] = $this->parseExpression();
$value = $this->parseExpression();
$node->addElement($value, $key);
}
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
return new Twig_Node_Expression_Array($elements, $stream->getCurrent()->getLine());
return $node;
}
}
public function parsePostfixExpression($node)
public function parsePostfixExpression($node)
@ -234,43 +296,56 @@ class Twig_ExpressionParser
public function getFunctionNode($name, $line)
public function getFunctionNode($name, $line)
{
{
$args = $this->parseArguments();
switch ($name) {
switch ($name) {
case 'parent':
case 'parent':
$args = $this->parseArguments();
if (!count($this->parser->getBlockStack())) {
if (!count($this->parser->getBlockStack())) {
throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line);
throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename());
}
}
if (!$this->parser->getParent()) {
if (!$this->parser->getParent()&& !$this->parser->hasTraits()) {
throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend another one is forbidden', $line);
throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename());
}
}
return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
case 'block':
case 'block':
return new Twig_Node_Expression_BlockReference($args->getNode(0), false, $line);
return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line);
case 'attribute':
case 'attribute':
$args = $this->parseArguments();
if (count($args) <2){
if (count($args) <2){
throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attribute)', $line);
throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename());
}
}
return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_TemplateInterface::ANY_CALL, $line);
return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_TemplateInterface::ANY_CALL, $line);
default:
default:
if (null !== $alias = $this->parser->getImportedFunction($name)) {
if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
return new Twig_Node_Expression_GetAttr($alias['node'], new Twig_Node_Expression_Constant($alias['name'], $line), $args, Twig_TemplateInterface::METHOD_CALL, $line);
$arguments = new Twig_Node_Expression_Array(array(), $line);
foreach ($this->parseArguments() as $n) {
$arguments->addElement($n);
}
$node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
$node->setAttribute('safe', true);
return $node;
}
}
return new Twig_Node_Expression_Function($name, $args, $line);
$arguments = new Twig_Node_Expression_Array(array(), $lineno);
$type = Twig_TemplateInterface::ANY_CALL;
$type = Twig_TemplateInterface::ANY_CALL;
if ($token->getValue() == '.') {
if ($token->getValue() == '.') {
$token = $this->parser->getStream()->next();
$token = $stream->next();
if (
if (
$token->getType() == Twig_Token::NAME_TYPE
$token->getType() == Twig_Token::NAME_TYPE
||
||
@ -280,20 +355,60 @@ class Twig_ExpressionParser
) {
) {
$arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
$arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
if ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$type = Twig_TemplateInterface::METHOD_CALL;
$type = Twig_TemplateInterface::METHOD_CALL;
$arguments = $this->parseArguments();
foreach ($this->parseArguments() as $n) {
} else {
$arguments->addElement($n);
$arguments = new Twig_Node();
}
}
}
} else {
} else {
throw new Twig_Error_Syntax('Expected name or number', $lineno);
throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename());
}
if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
if (!$arg instanceof Twig_Node_Expression_Constant) {
throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename());
}
$node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno);
$node->setAttribute('safe', true);
return $node;
}
}
} else {
} else {
$type = Twig_TemplateInterface::ARRAY_CALL;
$type = Twig_TemplateInterface::ARRAY_CALL;
// slice?
$slice = false;
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
$slice = true;
$arg = new Twig_Node_Expression_Constant(0, $token->getLine());
$node = new $class($node, $name, $arguments, $token->getLine(), $tag);
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
break;
break;
@ -330,17 +447,62 @@ class Twig_ExpressionParser
return $node;
return $node;
}
}
public function parseArguments()
/**
* Parses arguments.
*
* @param Boolean $namedArguments Whether to allow named arguments or not
* @param Boolean $definition Whether we are parsing arguments for a function definition
*/
public function parseArguments($namedArguments = false, $definition = false)
{
{
$args = array();
$args = array();
$stream = $this->parser->getStream();
$stream = $this->parser->getStream();
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must be opened by a parenthesis');
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
if (!empty($args)) {
if (!empty($args)) {
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
}
}
$args[] = $this->parseExpression();
if ($definition) {
$token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
$value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
} else {
$value = $this->parseExpression();
}
$name = null;
if ($namedArguments && $stream->test(Twig_Token::OPERATOR_TYPE, '=')) {
$token = $stream->next();
if (!$value instanceof Twig_Node_Expression_Name) {
throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename());
}
$name = $value->getAttribute('name');
if ($definition) {
$value = $this->parsePrimaryExpression();
if (!$this->checkConstantExpression($value)) {
throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $this->parser->getFilename());
}
} else {
$value = $this->parseExpression();
}
}
if ($definition) {
if (null === $name) {
$name = $value->getAttribute('name');
$value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
}
$args[$name] = $value;
} else {
if (null === $name) {
$args[] = $value;
} else {
$args[$name] = $value;
}
}
}
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
@ -353,7 +515,7 @@ class Twig_ExpressionParser
while (true) {
while (true) {
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
if (in_array($token->getValue(), array('true', 'false', 'none'))) {
if (in_array($token->getValue(), array('true', 'false', 'none'))) {
throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine());
throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename());
}
}
$targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine());
$targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine());
@ -379,4 +541,60 @@ class Twig_ExpressionParser
return new Twig_Node($targets);
return new Twig_Node($targets);
}
}
protected function getFunctionNodeClass($name, $line)
{
$env = $this->parser->getEnvironment();
if (false === $function = $env->getFunction($name)) {
$message = sprintf('The function "%s" does not exist', $name);
if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) {
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
}
throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
protected function getArguments($callable, $arguments)
{
$parameters = array();
$named = false;
foreach ($arguments as $name => $node) {
if (!is_int($name)) {
$named = true;
$name = $this->normalizeName($name);
} elseif ($named) {
throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
}
$parameters[$name] = $node;
}
if (!$named) {
return $parameters;
}
if (!$callable) {
throw new LogicException(sprintf('Named arguments are not supported for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
}
// manage named arguments
if (is_array($callable)) {
$r = new ReflectionMethod($callable[0], $callable[1]);
if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
array_shift($definition);
}
if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
array_shift($definition);
}
if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) {
foreach ($this->getAttribute('arguments') as $argument) {
array_shift($definition);
}
}
$arguments = array();
$pos = 0;
foreach ($definition as $param) {
$name = $this->normalizeName($param->name);
if (array_key_exists($name, $parameters)) {
if (array_key_exists($pos, $parameters)) {
throw new Twig_Error_Syntax(sprintf('Arguments "%s" is defined twice for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
}
$arguments[] = $parameters[$name];
unset($parameters[$name]);
} elseif (array_key_exists($pos, $parameters)) {
$arguments[] = $parameters[$pos];
unset($parameters[$pos]);
++$pos;
} elseif ($param->isDefaultValueAvailable()) {
$arguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1);
} elseif ($param->isOptional()) {
break;
} else {
throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
}
}
foreach (array_keys($parameters) as $name) {
throw new Twig_Error_Syntax(sprintf('Unknown argument "%s" for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));