From a4565e88edbc8e3bd092a475469769c86a4c350c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C5=93uillet?= Date: Fri, 2 Aug 2013 22:40:51 +0200 Subject: add Twig & refactor poche --- inc/Twig/Node/Expression/Array.php | 86 +++++++++++ inc/Twig/Node/Expression/AssignName.php | 28 ++++ inc/Twig/Node/Expression/Binary.php | 40 +++++ inc/Twig/Node/Expression/Binary/Add.php | 18 +++ inc/Twig/Node/Expression/Binary/And.php | 18 +++ inc/Twig/Node/Expression/Binary/BitwiseAnd.php | 18 +++ inc/Twig/Node/Expression/Binary/BitwiseOr.php | 18 +++ inc/Twig/Node/Expression/Binary/BitwiseXor.php | 18 +++ inc/Twig/Node/Expression/Binary/Concat.php | 18 +++ inc/Twig/Node/Expression/Binary/Div.php | 18 +++ inc/Twig/Node/Expression/Binary/Equal.php | 17 +++ inc/Twig/Node/Expression/Binary/FloorDiv.php | 29 ++++ inc/Twig/Node/Expression/Binary/Greater.php | 17 +++ inc/Twig/Node/Expression/Binary/GreaterEqual.php | 17 +++ inc/Twig/Node/Expression/Binary/In.php | 33 +++++ inc/Twig/Node/Expression/Binary/Less.php | 17 +++ inc/Twig/Node/Expression/Binary/LessEqual.php | 17 +++ inc/Twig/Node/Expression/Binary/Mod.php | 18 +++ inc/Twig/Node/Expression/Binary/Mul.php | 18 +++ inc/Twig/Node/Expression/Binary/NotEqual.php | 17 +++ inc/Twig/Node/Expression/Binary/NotIn.php | 33 +++++ inc/Twig/Node/Expression/Binary/Or.php | 18 +++ inc/Twig/Node/Expression/Binary/Power.php | 33 +++++ inc/Twig/Node/Expression/Binary/Range.php | 33 +++++ inc/Twig/Node/Expression/Binary/Sub.php | 18 +++ inc/Twig/Node/Expression/BlockReference.php | 51 +++++++ inc/Twig/Node/Expression/Call.php | 178 +++++++++++++++++++++++ inc/Twig/Node/Expression/Conditional.php | 31 ++++ inc/Twig/Node/Expression/Constant.php | 23 +++ inc/Twig/Node/Expression/ExtensionReference.php | 33 +++++ inc/Twig/Node/Expression/Filter.php | 36 +++++ inc/Twig/Node/Expression/Filter/Default.php | 43 ++++++ inc/Twig/Node/Expression/Function.php | 35 +++++ inc/Twig/Node/Expression/GetAttr.php | 53 +++++++ inc/Twig/Node/Expression/MethodCall.php | 41 ++++++ inc/Twig/Node/Expression/Name.php | 88 +++++++++++ inc/Twig/Node/Expression/Parent.php | 47 ++++++ inc/Twig/Node/Expression/TempName.php | 26 ++++ inc/Twig/Node/Expression/Test.php | 32 ++++ inc/Twig/Node/Expression/Test/Constant.php | 46 ++++++ inc/Twig/Node/Expression/Test/Defined.php | 54 +++++++ inc/Twig/Node/Expression/Test/Divisibleby.php | 33 +++++ inc/Twig/Node/Expression/Test/Even.php | 32 ++++ inc/Twig/Node/Expression/Test/Null.php | 31 ++++ inc/Twig/Node/Expression/Test/Odd.php | 32 ++++ inc/Twig/Node/Expression/Test/Sameas.php | 29 ++++ inc/Twig/Node/Expression/Unary.php | 30 ++++ inc/Twig/Node/Expression/Unary/Neg.php | 18 +++ inc/Twig/Node/Expression/Unary/Not.php | 18 +++ inc/Twig/Node/Expression/Unary/Pos.php | 18 +++ 50 files changed, 1673 insertions(+) create mode 100644 inc/Twig/Node/Expression/Array.php create mode 100644 inc/Twig/Node/Expression/AssignName.php create mode 100644 inc/Twig/Node/Expression/Binary.php create mode 100644 inc/Twig/Node/Expression/Binary/Add.php create mode 100644 inc/Twig/Node/Expression/Binary/And.php create mode 100644 inc/Twig/Node/Expression/Binary/BitwiseAnd.php create mode 100644 inc/Twig/Node/Expression/Binary/BitwiseOr.php create mode 100644 inc/Twig/Node/Expression/Binary/BitwiseXor.php create mode 100644 inc/Twig/Node/Expression/Binary/Concat.php create mode 100644 inc/Twig/Node/Expression/Binary/Div.php create mode 100644 inc/Twig/Node/Expression/Binary/Equal.php create mode 100644 inc/Twig/Node/Expression/Binary/FloorDiv.php create mode 100644 inc/Twig/Node/Expression/Binary/Greater.php create mode 100644 inc/Twig/Node/Expression/Binary/GreaterEqual.php create mode 100644 inc/Twig/Node/Expression/Binary/In.php create mode 100644 inc/Twig/Node/Expression/Binary/Less.php create mode 100644 inc/Twig/Node/Expression/Binary/LessEqual.php create mode 100644 inc/Twig/Node/Expression/Binary/Mod.php create mode 100644 inc/Twig/Node/Expression/Binary/Mul.php create mode 100644 inc/Twig/Node/Expression/Binary/NotEqual.php create mode 100644 inc/Twig/Node/Expression/Binary/NotIn.php create mode 100644 inc/Twig/Node/Expression/Binary/Or.php create mode 100644 inc/Twig/Node/Expression/Binary/Power.php create mode 100644 inc/Twig/Node/Expression/Binary/Range.php create mode 100644 inc/Twig/Node/Expression/Binary/Sub.php create mode 100644 inc/Twig/Node/Expression/BlockReference.php create mode 100644 inc/Twig/Node/Expression/Call.php create mode 100644 inc/Twig/Node/Expression/Conditional.php create mode 100644 inc/Twig/Node/Expression/Constant.php create mode 100644 inc/Twig/Node/Expression/ExtensionReference.php create mode 100644 inc/Twig/Node/Expression/Filter.php create mode 100644 inc/Twig/Node/Expression/Filter/Default.php create mode 100644 inc/Twig/Node/Expression/Function.php create mode 100644 inc/Twig/Node/Expression/GetAttr.php create mode 100644 inc/Twig/Node/Expression/MethodCall.php create mode 100644 inc/Twig/Node/Expression/Name.php create mode 100644 inc/Twig/Node/Expression/Parent.php create mode 100644 inc/Twig/Node/Expression/TempName.php create mode 100644 inc/Twig/Node/Expression/Test.php create mode 100644 inc/Twig/Node/Expression/Test/Constant.php create mode 100644 inc/Twig/Node/Expression/Test/Defined.php create mode 100644 inc/Twig/Node/Expression/Test/Divisibleby.php create mode 100644 inc/Twig/Node/Expression/Test/Even.php create mode 100644 inc/Twig/Node/Expression/Test/Null.php create mode 100644 inc/Twig/Node/Expression/Test/Odd.php create mode 100644 inc/Twig/Node/Expression/Test/Sameas.php create mode 100644 inc/Twig/Node/Expression/Unary.php create mode 100644 inc/Twig/Node/Expression/Unary/Neg.php create mode 100644 inc/Twig/Node/Expression/Unary/Not.php create mode 100644 inc/Twig/Node/Expression/Unary/Pos.php (limited to 'inc/Twig/Node/Expression') diff --git a/inc/Twig/Node/Expression/Array.php b/inc/Twig/Node/Expression/Array.php new file mode 100644 index 00000000..1da785fe --- /dev/null +++ b/inc/Twig/Node/Expression/Array.php @@ -0,0 +1,86 @@ +index = -1; + foreach ($this->getKeyValuePairs() as $pair) { + if ($pair['key'] instanceof Twig_Node_Expression_Constant && ctype_digit((string) $pair['key']->getAttribute('value')) && $pair['key']->getAttribute('value') > $this->index) { + $this->index = $pair['key']->getAttribute('value'); + } + } + } + + public function getKeyValuePairs() + { + $pairs = array(); + + foreach (array_chunk($this->nodes, 2) as $pair) { + $pairs[] = array( + 'key' => $pair[0], + 'value' => $pair[1], + ); + } + + return $pairs; + } + + public function hasElement(Twig_Node_Expression $key) + { + foreach ($this->getKeyValuePairs() as $pair) { + // we compare the string representation of the keys + // to avoid comparing the line numbers which are not relevant here. + if ((string) $key == (string) $pair['key']) { + return true; + } + } + + return false; + } + + public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null) + { + if (null === $key) { + $key = new Twig_Node_Expression_Constant(++$this->index, $value->getLine()); + } + + array_push($this->nodes, $key, $value); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler->raw('array('); + $first = true; + foreach ($this->getKeyValuePairs() as $pair) { + if (!$first) { + $compiler->raw(', '); + } + $first = false; + + $compiler + ->subcompile($pair['key']) + ->raw(' => ') + ->subcompile($pair['value']) + ; + } + $compiler->raw(')'); + } +} diff --git a/inc/Twig/Node/Expression/AssignName.php b/inc/Twig/Node/Expression/AssignName.php new file mode 100644 index 00000000..2ddea78c --- /dev/null +++ b/inc/Twig/Node/Expression/AssignName.php @@ -0,0 +1,28 @@ +raw('$context[') + ->string($this->getAttribute('name')) + ->raw(']') + ; + } +} diff --git a/inc/Twig/Node/Expression/Binary.php b/inc/Twig/Node/Expression/Binary.php new file mode 100644 index 00000000..9dd5de2c --- /dev/null +++ b/inc/Twig/Node/Expression/Binary.php @@ -0,0 +1,40 @@ + $left, 'right' => $right), array(), $lineno); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('(') + ->subcompile($this->getNode('left')) + ->raw(' ') + ; + $this->operator($compiler); + $compiler + ->raw(' ') + ->subcompile($this->getNode('right')) + ->raw(')') + ; + } + + abstract public function operator(Twig_Compiler $compiler); +} diff --git a/inc/Twig/Node/Expression/Binary/Add.php b/inc/Twig/Node/Expression/Binary/Add.php new file mode 100644 index 00000000..0ef8e117 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/Add.php @@ -0,0 +1,18 @@ +raw('+'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/And.php b/inc/Twig/Node/Expression/Binary/And.php new file mode 100644 index 00000000..d5752ebb --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/And.php @@ -0,0 +1,18 @@ +raw('&&'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/BitwiseAnd.php b/inc/Twig/Node/Expression/Binary/BitwiseAnd.php new file mode 100644 index 00000000..9a46d845 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/BitwiseAnd.php @@ -0,0 +1,18 @@ +raw('&'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/BitwiseOr.php b/inc/Twig/Node/Expression/Binary/BitwiseOr.php new file mode 100644 index 00000000..058a20bf --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/BitwiseOr.php @@ -0,0 +1,18 @@ +raw('|'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/BitwiseXor.php b/inc/Twig/Node/Expression/Binary/BitwiseXor.php new file mode 100644 index 00000000..f4da73d4 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/BitwiseXor.php @@ -0,0 +1,18 @@ +raw('^'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/Concat.php b/inc/Twig/Node/Expression/Binary/Concat.php new file mode 100644 index 00000000..f9a64627 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/Concat.php @@ -0,0 +1,18 @@ +raw('.'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/Div.php b/inc/Twig/Node/Expression/Binary/Div.php new file mode 100644 index 00000000..e0797a61 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/Div.php @@ -0,0 +1,18 @@ +raw('/'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/Equal.php b/inc/Twig/Node/Expression/Binary/Equal.php new file mode 100644 index 00000000..7b1236d0 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/Equal.php @@ -0,0 +1,17 @@ +raw('=='); + } +} diff --git a/inc/Twig/Node/Expression/Binary/FloorDiv.php b/inc/Twig/Node/Expression/Binary/FloorDiv.php new file mode 100644 index 00000000..7fbd0556 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/FloorDiv.php @@ -0,0 +1,29 @@ +raw('intval(floor('); + parent::compile($compiler); + $compiler->raw('))'); + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw('/'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/Greater.php b/inc/Twig/Node/Expression/Binary/Greater.php new file mode 100644 index 00000000..a110bd92 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/Greater.php @@ -0,0 +1,17 @@ +raw('>'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/GreaterEqual.php b/inc/Twig/Node/Expression/Binary/GreaterEqual.php new file mode 100644 index 00000000..3754fed2 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/GreaterEqual.php @@ -0,0 +1,17 @@ +raw('>='); + } +} diff --git a/inc/Twig/Node/Expression/Binary/In.php b/inc/Twig/Node/Expression/Binary/In.php new file mode 100644 index 00000000..788f9377 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/In.php @@ -0,0 +1,33 @@ +raw('twig_in_filter(') + ->subcompile($this->getNode('left')) + ->raw(', ') + ->subcompile($this->getNode('right')) + ->raw(')') + ; + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw('in'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/Less.php b/inc/Twig/Node/Expression/Binary/Less.php new file mode 100644 index 00000000..45fd3004 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/Less.php @@ -0,0 +1,17 @@ +raw('<'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/LessEqual.php b/inc/Twig/Node/Expression/Binary/LessEqual.php new file mode 100644 index 00000000..e38e257c --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/LessEqual.php @@ -0,0 +1,17 @@ +raw('<='); + } +} diff --git a/inc/Twig/Node/Expression/Binary/Mod.php b/inc/Twig/Node/Expression/Binary/Mod.php new file mode 100644 index 00000000..9924114f --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/Mod.php @@ -0,0 +1,18 @@ +raw('%'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/Mul.php b/inc/Twig/Node/Expression/Binary/Mul.php new file mode 100644 index 00000000..c91529ca --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/Mul.php @@ -0,0 +1,18 @@ +raw('*'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/NotEqual.php b/inc/Twig/Node/Expression/Binary/NotEqual.php new file mode 100644 index 00000000..26867ba2 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/NotEqual.php @@ -0,0 +1,17 @@ +raw('!='); + } +} diff --git a/inc/Twig/Node/Expression/Binary/NotIn.php b/inc/Twig/Node/Expression/Binary/NotIn.php new file mode 100644 index 00000000..f347b7b6 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/NotIn.php @@ -0,0 +1,33 @@ +raw('!twig_in_filter(') + ->subcompile($this->getNode('left')) + ->raw(', ') + ->subcompile($this->getNode('right')) + ->raw(')') + ; + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw('not in'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/Or.php b/inc/Twig/Node/Expression/Binary/Or.php new file mode 100644 index 00000000..adba49c6 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/Or.php @@ -0,0 +1,18 @@ +raw('||'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/Power.php b/inc/Twig/Node/Expression/Binary/Power.php new file mode 100644 index 00000000..b2c59040 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/Power.php @@ -0,0 +1,33 @@ +raw('pow(') + ->subcompile($this->getNode('left')) + ->raw(', ') + ->subcompile($this->getNode('right')) + ->raw(')') + ; + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw('**'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/Range.php b/inc/Twig/Node/Expression/Binary/Range.php new file mode 100644 index 00000000..bea4f2a6 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/Range.php @@ -0,0 +1,33 @@ +raw('range(') + ->subcompile($this->getNode('left')) + ->raw(', ') + ->subcompile($this->getNode('right')) + ->raw(')') + ; + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw('..'); + } +} diff --git a/inc/Twig/Node/Expression/Binary/Sub.php b/inc/Twig/Node/Expression/Binary/Sub.php new file mode 100644 index 00000000..d4463991 --- /dev/null +++ b/inc/Twig/Node/Expression/Binary/Sub.php @@ -0,0 +1,18 @@ +raw('-'); + } +} diff --git a/inc/Twig/Node/Expression/BlockReference.php b/inc/Twig/Node/Expression/BlockReference.php new file mode 100644 index 00000000..647196eb --- /dev/null +++ b/inc/Twig/Node/Expression/BlockReference.php @@ -0,0 +1,51 @@ + + */ +class Twig_Node_Expression_BlockReference extends Twig_Node_Expression +{ + public function __construct(Twig_NodeInterface $name, $asString = false, $lineno, $tag = null) + { + parent::__construct(array('name' => $name), array('as_string' => $asString, 'output' => false), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + if ($this->getAttribute('as_string')) { + $compiler->raw('(string) '); + } + + if ($this->getAttribute('output')) { + $compiler + ->addDebugInfo($this) + ->write("\$this->displayBlock(") + ->subcompile($this->getNode('name')) + ->raw(", \$context, \$blocks);\n") + ; + } else { + $compiler + ->raw("\$this->renderBlock(") + ->subcompile($this->getNode('name')) + ->raw(", \$context, \$blocks)") + ; + } + } +} diff --git a/inc/Twig/Node/Expression/Call.php b/inc/Twig/Node/Expression/Call.php new file mode 100644 index 00000000..87b62deb --- /dev/null +++ b/inc/Twig/Node/Expression/Call.php @@ -0,0 +1,178 @@ +getAttribute('callable'); + + $closingParenthesis = false; + if ($callable) { + if (is_string($callable)) { + $compiler->raw($callable); + } elseif (is_array($callable) && $callable[0] instanceof Twig_ExtensionInterface) { + $compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', $callable[0]->getName(), $callable[1])); + } else { + $type = ucfirst($this->getAttribute('type')); + $compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name'))); + $closingParenthesis = true; + } + } else { + $compiler->raw($this->getAttribute('thing')->compile()); + } + + $this->compileArguments($compiler); + + if ($closingParenthesis) { + $compiler->raw(')'); + } + } + + protected function compileArguments(Twig_Compiler $compiler) + { + $compiler->raw('('); + + $first = true; + + if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) { + $compiler->raw('$this->env'); + $first = false; + } + + if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) { + if (!$first) { + $compiler->raw(', '); + } + $compiler->raw('$context'); + $first = false; + } + + if ($this->hasAttribute('arguments')) { + foreach ($this->getAttribute('arguments') as $argument) { + if (!$first) { + $compiler->raw(', '); + } + $compiler->string($argument); + $first = false; + } + } + + if ($this->hasNode('node')) { + if (!$first) { + $compiler->raw(', '); + } + $compiler->subcompile($this->getNode('node')); + $first = false; + } + + if ($this->hasNode('arguments') && null !== $this->getNode('arguments')) { + $callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null; + + $arguments = $this->getArguments($callable, $this->getNode('arguments')); + + foreach ($arguments as $node) { + if (!$first) { + $compiler->raw(', '); + } + $compiler->subcompile($node); + $first = false; + } + } + + $compiler->raw(')'); + } + + 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]); + } elseif (is_object($callable) && !$callable instanceof Closure) { + $r = new ReflectionObject($callable); + $r = $r->getMethod('__invoke'); + } else { + $r = new ReflectionFunction($callable); + } + + $definition = $r->getParameters(); + if ($this->hasNode('node')) { + array_shift($definition); + } + 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'))); + } + + return $arguments; + } + + protected function normalizeName($name) + { + return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name)); + } +} diff --git a/inc/Twig/Node/Expression/Conditional.php b/inc/Twig/Node/Expression/Conditional.php new file mode 100644 index 00000000..edcb1e2d --- /dev/null +++ b/inc/Twig/Node/Expression/Conditional.php @@ -0,0 +1,31 @@ + $expr1, 'expr2' => $expr2, 'expr3' => $expr3), array(), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('((') + ->subcompile($this->getNode('expr1')) + ->raw(') ? (') + ->subcompile($this->getNode('expr2')) + ->raw(') : (') + ->subcompile($this->getNode('expr3')) + ->raw('))') + ; + } +} diff --git a/inc/Twig/Node/Expression/Constant.php b/inc/Twig/Node/Expression/Constant.php new file mode 100644 index 00000000..a91dc698 --- /dev/null +++ b/inc/Twig/Node/Expression/Constant.php @@ -0,0 +1,23 @@ + $value), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + $compiler->repr($this->getAttribute('value')); + } +} diff --git a/inc/Twig/Node/Expression/ExtensionReference.php b/inc/Twig/Node/Expression/ExtensionReference.php new file mode 100644 index 00000000..00ac6701 --- /dev/null +++ b/inc/Twig/Node/Expression/ExtensionReference.php @@ -0,0 +1,33 @@ + + */ +class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression +{ + public function __construct($name, $lineno, $tag = null) + { + parent::__construct(array(), array('name' => $name), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name'))); + } +} diff --git a/inc/Twig/Node/Expression/Filter.php b/inc/Twig/Node/Expression/Filter.php new file mode 100644 index 00000000..207b062a --- /dev/null +++ b/inc/Twig/Node/Expression/Filter.php @@ -0,0 +1,36 @@ + $node, 'filter' => $filterName, 'arguments' => $arguments), array(), $lineno, $tag); + } + + public function compile(Twig_Compiler $compiler) + { + $name = $this->getNode('filter')->getAttribute('value'); + $filter = $compiler->getEnvironment()->getFilter($name); + + $this->setAttribute('name', $name); + $this->setAttribute('type', 'filter'); + $this->setAttribute('thing', $filter); + $this->setAttribute('needs_environment', $filter->needsEnvironment()); + $this->setAttribute('needs_context', $filter->needsContext()); + $this->setAttribute('arguments', $filter->getArguments()); + if ($filter instanceof Twig_FilterCallableInterface || $filter instanceof Twig_SimpleFilter) { + $this->setAttribute('callable', $filter->getCallable()); + } + + $this->compileCallable($compiler); + } +} diff --git a/inc/Twig/Node/Expression/Filter/Default.php b/inc/Twig/Node/Expression/Filter/Default.php new file mode 100644 index 00000000..1827c888 --- /dev/null +++ b/inc/Twig/Node/Expression/Filter/Default.php @@ -0,0 +1,43 @@ + + * {{ var.foo|default('foo item on var is not defined') }} + * + * + * @author Fabien Potencier + */ +class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter +{ + public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null) + { + $default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('default', $node->getLine()), $arguments, $node->getLine()); + + if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) { + $test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getLine()); + $false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine()); + + $node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getLine()); + } else { + $node = $default; + } + + parent::__construct($node, $filterName, $arguments, $lineno, $tag); + } + + public function compile(Twig_Compiler $compiler) + { + $compiler->subcompile($this->getNode('node')); + } +} diff --git a/inc/Twig/Node/Expression/Function.php b/inc/Twig/Node/Expression/Function.php new file mode 100644 index 00000000..3e1f6b55 --- /dev/null +++ b/inc/Twig/Node/Expression/Function.php @@ -0,0 +1,35 @@ + $arguments), array('name' => $name), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + $name = $this->getAttribute('name'); + $function = $compiler->getEnvironment()->getFunction($name); + + $this->setAttribute('name', $name); + $this->setAttribute('type', 'function'); + $this->setAttribute('thing', $function); + $this->setAttribute('needs_environment', $function->needsEnvironment()); + $this->setAttribute('needs_context', $function->needsContext()); + $this->setAttribute('arguments', $function->getArguments()); + if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) { + $this->setAttribute('callable', $function->getCallable()); + } + + $this->compileCallable($compiler); + } +} diff --git a/inc/Twig/Node/Expression/GetAttr.php b/inc/Twig/Node/Expression/GetAttr.php new file mode 100644 index 00000000..81a9b137 --- /dev/null +++ b/inc/Twig/Node/Expression/GetAttr.php @@ -0,0 +1,53 @@ + $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) { + $compiler->raw('twig_template_get_attributes($this, '); + } else { + $compiler->raw('$this->getAttribute('); + } + + if ($this->getAttribute('ignore_strict_check')) { + $this->getNode('node')->setAttribute('ignore_strict_check', true); + } + + $compiler->subcompile($this->getNode('node')); + + $compiler->raw(', ')->subcompile($this->getNode('attribute')); + + if (count($this->getNode('arguments')) || Twig_TemplateInterface::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { + $compiler->raw(', ')->subcompile($this->getNode('arguments')); + + if (Twig_TemplateInterface::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { + $compiler->raw(', ')->repr($this->getAttribute('type')); + } + + if ($this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { + $compiler->raw(', '.($this->getAttribute('is_defined_test') ? 'true' : 'false')); + } + + if ($this->getAttribute('ignore_strict_check')) { + $compiler->raw(', '.($this->getAttribute('ignore_strict_check') ? 'true' : 'false')); + } + } + + $compiler->raw(')'); + } +} diff --git a/inc/Twig/Node/Expression/MethodCall.php b/inc/Twig/Node/Expression/MethodCall.php new file mode 100644 index 00000000..620b02bf --- /dev/null +++ b/inc/Twig/Node/Expression/MethodCall.php @@ -0,0 +1,41 @@ + $node, 'arguments' => $arguments), array('method' => $method, 'safe' => false), $lineno); + + if ($node instanceof Twig_Node_Expression_Name) { + $node->setAttribute('always_defined', true); + } + } + + public function compile(Twig_Compiler $compiler) + { + $compiler + ->subcompile($this->getNode('node')) + ->raw('->') + ->raw($this->getAttribute('method')) + ->raw('(') + ; + $first = true; + foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) { + if (!$first) { + $compiler->raw(', '); + } + $first = false; + + $compiler->subcompile($pair['value']); + } + $compiler->raw(')'); + } +} diff --git a/inc/Twig/Node/Expression/Name.php b/inc/Twig/Node/Expression/Name.php new file mode 100644 index 00000000..3b8fae01 --- /dev/null +++ b/inc/Twig/Node/Expression/Name.php @@ -0,0 +1,88 @@ + '$this', + '_context' => '$context', + '_charset' => '$this->env->getCharset()', + ); + + public function __construct($name, $lineno) + { + parent::__construct(array(), array('name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + $name = $this->getAttribute('name'); + + if ($this->getAttribute('is_defined_test')) { + if ($this->isSpecial()) { + $compiler->repr(true); + } else { + $compiler->raw('array_key_exists(')->repr($name)->raw(', $context)'); + } + } elseif ($this->isSpecial()) { + $compiler->raw($this->specialVars[$name]); + } elseif ($this->getAttribute('always_defined')) { + $compiler + ->raw('$context[') + ->string($name) + ->raw(']') + ; + } else { + // remove the non-PHP 5.4 version when PHP 5.3 support is dropped + // as the non-optimized version is just a workaround for slow ternary operator + // when the context has a lot of variables + if (version_compare(phpversion(), '5.4.0RC1', '>=')) { + // PHP 5.4 ternary operator performance was optimized + $compiler + ->raw('(isset($context[') + ->string($name) + ->raw(']) ? $context[') + ->string($name) + ->raw('] : ') + ; + + if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) { + $compiler->raw('null)'); + } else { + $compiler->raw('$this->getContext($context, ')->string($name)->raw('))'); + } + } else { + $compiler + ->raw('$this->getContext($context, ') + ->string($name) + ; + + if ($this->getAttribute('ignore_strict_check')) { + $compiler->raw(', true'); + } + + $compiler + ->raw(')') + ; + } + } + } + + public function isSpecial() + { + return isset($this->specialVars[$this->getAttribute('name')]); + } + + public function isSimple() + { + return !$this->isSpecial() && !$this->getAttribute('is_defined_test'); + } +} diff --git a/inc/Twig/Node/Expression/Parent.php b/inc/Twig/Node/Expression/Parent.php new file mode 100644 index 00000000..dcf618c0 --- /dev/null +++ b/inc/Twig/Node/Expression/Parent.php @@ -0,0 +1,47 @@ + + */ +class Twig_Node_Expression_Parent extends Twig_Node_Expression +{ + public function __construct($name, $lineno, $tag = null) + { + parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + if ($this->getAttribute('output')) { + $compiler + ->addDebugInfo($this) + ->write("\$this->displayParentBlock(") + ->string($this->getAttribute('name')) + ->raw(", \$context, \$blocks);\n") + ; + } else { + $compiler + ->raw("\$this->renderParentBlock(") + ->string($this->getAttribute('name')) + ->raw(", \$context, \$blocks)") + ; + } + } +} diff --git a/inc/Twig/Node/Expression/TempName.php b/inc/Twig/Node/Expression/TempName.php new file mode 100644 index 00000000..e6b058e8 --- /dev/null +++ b/inc/Twig/Node/Expression/TempName.php @@ -0,0 +1,26 @@ + $name), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('$_') + ->raw($this->getAttribute('name')) + ->raw('_') + ; + } +} diff --git a/inc/Twig/Node/Expression/Test.php b/inc/Twig/Node/Expression/Test.php new file mode 100644 index 00000000..639f501a --- /dev/null +++ b/inc/Twig/Node/Expression/Test.php @@ -0,0 +1,32 @@ + $node, 'arguments' => $arguments), array('name' => $name), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + $name = $this->getAttribute('name'); + $test = $compiler->getEnvironment()->getTest($name); + + $this->setAttribute('name', $name); + $this->setAttribute('type', 'test'); + $this->setAttribute('thing', $test); + if ($test instanceof Twig_TestCallableInterface || $test instanceof Twig_SimpleTest) { + $this->setAttribute('callable', $test->getCallable()); + } + + $this->compileCallable($compiler); + } +} diff --git a/inc/Twig/Node/Expression/Test/Constant.php b/inc/Twig/Node/Expression/Test/Constant.php new file mode 100644 index 00000000..de55f5f5 --- /dev/null +++ b/inc/Twig/Node/Expression/Test/Constant.php @@ -0,0 +1,46 @@ + + * {% if post.status is constant('Post::PUBLISHED') %} + * the status attribute is exactly the same as Post::PUBLISHED + * {% endif %} + * + * + * @author Fabien Potencier + */ +class Twig_Node_Expression_Test_Constant extends Twig_Node_Expression_Test +{ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('(') + ->subcompile($this->getNode('node')) + ->raw(' === constant(') + ; + + if ($this->getNode('arguments')->hasNode(1)) { + $compiler + ->raw('get_class(') + ->subcompile($this->getNode('arguments')->getNode(1)) + ->raw(')."::".') + ; + } + + $compiler + ->subcompile($this->getNode('arguments')->getNode(0)) + ->raw('))') + ; + } +} diff --git a/inc/Twig/Node/Expression/Test/Defined.php b/inc/Twig/Node/Expression/Test/Defined.php new file mode 100644 index 00000000..247b2e23 --- /dev/null +++ b/inc/Twig/Node/Expression/Test/Defined.php @@ -0,0 +1,54 @@ + + * {# defined works with variable names and variable attributes #} + * {% if foo is defined %} + * {# ... #} + * {% endif %} + * + * + * @author Fabien Potencier + */ +class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test +{ + public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno) + { + parent::__construct($node, $name, $arguments, $lineno); + + if ($node instanceof Twig_Node_Expression_Name) { + $node->setAttribute('is_defined_test', true); + } elseif ($node instanceof Twig_Node_Expression_GetAttr) { + $node->setAttribute('is_defined_test', true); + + $this->changeIgnoreStrictCheck($node); + } else { + throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine()); + } + } + + protected function changeIgnoreStrictCheck(Twig_Node_Expression_GetAttr $node) + { + $node->setAttribute('ignore_strict_check', true); + + if ($node->getNode('node') instanceof Twig_Node_Expression_GetAttr) { + $this->changeIgnoreStrictCheck($node->getNode('node')); + } + } + + public function compile(Twig_Compiler $compiler) + { + $compiler->subcompile($this->getNode('node')); + } +} diff --git a/inc/Twig/Node/Expression/Test/Divisibleby.php b/inc/Twig/Node/Expression/Test/Divisibleby.php new file mode 100644 index 00000000..0aceb530 --- /dev/null +++ b/inc/Twig/Node/Expression/Test/Divisibleby.php @@ -0,0 +1,33 @@ + + * {% if loop.index is divisibleby(3) %} + * + * + * @author Fabien Potencier + */ +class Twig_Node_Expression_Test_Divisibleby extends Twig_Node_Expression_Test +{ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('(0 == ') + ->subcompile($this->getNode('node')) + ->raw(' % ') + ->subcompile($this->getNode('arguments')->getNode(0)) + ->raw(')') + ; + } +} diff --git a/inc/Twig/Node/Expression/Test/Even.php b/inc/Twig/Node/Expression/Test/Even.php new file mode 100644 index 00000000..d7853e89 --- /dev/null +++ b/inc/Twig/Node/Expression/Test/Even.php @@ -0,0 +1,32 @@ + + * {{ var is even }} + * + * + * @author Fabien Potencier + */ +class Twig_Node_Expression_Test_Even extends Twig_Node_Expression_Test +{ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('(') + ->subcompile($this->getNode('node')) + ->raw(' % 2 == 0') + ->raw(')') + ; + } +} diff --git a/inc/Twig/Node/Expression/Test/Null.php b/inc/Twig/Node/Expression/Test/Null.php new file mode 100644 index 00000000..1c83825a --- /dev/null +++ b/inc/Twig/Node/Expression/Test/Null.php @@ -0,0 +1,31 @@ + + * {{ var is none }} + * + * + * @author Fabien Potencier + */ +class Twig_Node_Expression_Test_Null extends Twig_Node_Expression_Test +{ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('(null === ') + ->subcompile($this->getNode('node')) + ->raw(')') + ; + } +} diff --git a/inc/Twig/Node/Expression/Test/Odd.php b/inc/Twig/Node/Expression/Test/Odd.php new file mode 100644 index 00000000..421c19e8 --- /dev/null +++ b/inc/Twig/Node/Expression/Test/Odd.php @@ -0,0 +1,32 @@ + + * {{ var is odd }} + * + * + * @author Fabien Potencier + */ +class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test +{ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('(') + ->subcompile($this->getNode('node')) + ->raw(' % 2 == 1') + ->raw(')') + ; + } +} diff --git a/inc/Twig/Node/Expression/Test/Sameas.php b/inc/Twig/Node/Expression/Test/Sameas.php new file mode 100644 index 00000000..b48905ee --- /dev/null +++ b/inc/Twig/Node/Expression/Test/Sameas.php @@ -0,0 +1,29 @@ + + */ +class Twig_Node_Expression_Test_Sameas extends Twig_Node_Expression_Test +{ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('(') + ->subcompile($this->getNode('node')) + ->raw(' === ') + ->subcompile($this->getNode('arguments')->getNode(0)) + ->raw(')') + ; + } +} diff --git a/inc/Twig/Node/Expression/Unary.php b/inc/Twig/Node/Expression/Unary.php new file mode 100644 index 00000000..c514388e --- /dev/null +++ b/inc/Twig/Node/Expression/Unary.php @@ -0,0 +1,30 @@ + $node), array(), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + $compiler->raw('('); + $this->operator($compiler); + $compiler + ->subcompile($this->getNode('node')) + ->raw(')') + ; + } + + abstract public function operator(Twig_Compiler $compiler); +} diff --git a/inc/Twig/Node/Expression/Unary/Neg.php b/inc/Twig/Node/Expression/Unary/Neg.php new file mode 100644 index 00000000..2a3937ec --- /dev/null +++ b/inc/Twig/Node/Expression/Unary/Neg.php @@ -0,0 +1,18 @@ +raw('-'); + } +} diff --git a/inc/Twig/Node/Expression/Unary/Not.php b/inc/Twig/Node/Expression/Unary/Not.php new file mode 100644 index 00000000..f94073cf --- /dev/null +++ b/inc/Twig/Node/Expression/Unary/Not.php @@ -0,0 +1,18 @@ +raw('!'); + } +} diff --git a/inc/Twig/Node/Expression/Unary/Pos.php b/inc/Twig/Node/Expression/Unary/Pos.php new file mode 100644 index 00000000..04edb52a --- /dev/null +++ b/inc/Twig/Node/Expression/Unary/Pos.php @@ -0,0 +1,18 @@ +raw('+'); + } +} -- cgit v1.2.3