8000 [ExpressionLanguage] Added a way to dump AST · symfony/symfony@87af6e5 · GitHub
[go: up one dir, main page]

Skip to content

Commit 87af6e5

Browse files
committed
[ExpressionLanguage] Added a way to dump AST
1 parent e707760 commit 87af6e5

21 files changed

+306
-0
lines changed

src/Symfony/Component/ExpressionLanguage/Node/ArgumentsNode.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,15 @@ public function compile(Compiler $compiler)
2424
{
2525
$this->compileArguments($compiler, false);
2626
}
27+
28+
public function dump()
29+
{
30+
$str = '';
31+
32+
foreach ($this->getKeyValuePairs() as $pair) {
33+
$str .= sprintf('%s, ', $pair['value']->dump());
34+
}
35+
36+
return rtrim($str, ', ');
37+
}
2738
}

src/Symfony/Component/ExpressionLanguage/Node/ArrayNode.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,36 @@ public function evaluate($functions, $values)
5858
return $result;
5959
}
6060

61+
public function dump()
62+
{
63+
$array = array();
64+
foreach ($this->getKeyValuePairs() as $pair) {
65+
$array[$pair['key']->attributes['value']] = $pair['value']->dump();
66+
}
67+
68+
if ($this->isHash($array)) {
69+
$str = '{';
70+
71+
foreach ($array as $key => $value) {
72+
if (is_int($key)) {
73+
$str .= sprintf('%s: %s, ', $key, $value);
74+
} else {
75+
$str .= sprintf('"%s": %s, ', $this->dumpEscaped($key), $value);
76+
}
77+
}
78+
79+
return rtrim($str, ', ').'}';
80+
}
81+
82+
$str = '[';
83+
84+
foreach ($array as $key => $value) {
85+
$str .= sprintf('%s, ', $value);
86+
}
87+
88+
return rtrim($str, ', ').']';
89+
}
90+
6191
protected function getKeyValuePairs()
6292
{
6393
$pairs = array();

src/Symfony/Component/ExpressionLanguage/Node/BinaryNode.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,9 @@ public function evaluate($functions, $values)
154154
return preg_match($right, $left);
155155
}
156156
}
157+
158+
public function dump()
159+
{
160+
return sprintf('(%s %s %s)', $this->nodes['left']->dump(), $this->attributes['operator'], $this->nodes['right']->dump());
161+
}
157162
}

src/Symfony/Component/ExpressionLanguage/Node/ConditionalNode.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,9 @@ public function evaluate($functions, $values)
4848

4949
return $this->nodes['expr3']->evaluate($functions, $values);
5050
}
51+
52+
public function dump()
53+
{
54+
return sprintf('(%s ? %s : %s)', $this->nodes['expr1']->dump(), $this->nodes['expr2']->dump(), $this->nodes['expr3']->dump());
55+
}
5156
}

src/Symfony/Component/ExpressionLanguage/Node/ConstantNode.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,52 @@ public function evaluate($functions, $values)
3737
{
3838
return $this->attributes['value'];
3939
}
40+
41+
public function dump()
42+
{
43+
return $this->dumpValue($this->attributes['value']);
44+
}
45+
46+
private function dumpValue($value)
47+
{
48+
switch (true) {
49+
case true === $value:
50+
return 'true';
51+
52+
case false === $value:
53+
return 'false';
54+
55+
case null === $value:
56+
return 'null';
57+
58+
case is_numeric($value):
59+
return $value;
60+
61+
case is_array($value):
62+
if ($this->isHash($value)) {
63+
$str = '{';
64+
65+
foreach ($value as $key => $v) {
66+
if (is_int($key)) {
67+
$str .= sprintf('%s: %s, ', $key, $this->dumpValue($v));
68+
} else {
69+
$str .= sprintf('"%s": %s, ', $this->dumpEscaped($key), $this->dumpValue($v));
70+
}
71+
}
72+
73+
return rtrim($str, ', ').'}';
74+
}
75+
76+
$str = '[';
77+
78+
foreach ($value as $key => $v) {
79+
$str .= sprintf('%s, ', $this->dumpValue($v));
80+
}
81+
82+
return rtrim($str, ', ').']';
83+
84+
default:
85+
return sprintf('"%s"', $this->dumpEscaped($value));
86+
}
87+
}
4088
}

src/Symfony/Component/ExpressionLanguage/Node/FunctionNode.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,17 @@ public function evaluate($functions, $values)
4949

5050
return call_user_func_array($functions[$this->attributes['name']]['evaluator'], $arguments);
5151
}
52+
53+
public function dump()
54+
{
55+
$str = $this->attributes['name'];
56+
57+
$str .= '(';
58+
59+
foreach ($this->nodes['arguments']->nodes as $node) {
60+
$str .= $node->dump().', ';
61+
}
62+
63+
return rtrim($str, ', ').')';
64+
}
5265
}

src/Symfony/Component/ExpressionLanguage/Node/GetAttrNode.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,18 @@ public function evaluate($functions, $values)
9494
return $array[$this->nodes['attribute']->evaluate($functions, $values)];
9595
}
9696
}
97+
98+
public function dump()
99+
{
100+
switch ($this->attributes['type']) {
101+
case self::PROPERTY_CALL:
102+
return sprintf('%s.%s', $this->nodes['node']->dump(), trim($this->nodes['attribute']->dump(), '"'));
103+
104+
case self::METHOD_CALL:
105+
return sprintf('%s.%s(%s)', $this->nodes['node']->dump(), trim($this->nodes['attribute']->dump(), '"'), $this->nodes['arguments']->dump());
106+
107+
case self::ARRAY_CALL:
108+
return sprintf('%s[%s]', $this->nodes['node']->dump(), $this->nodes['attribute']->dump());
109+
}
110+
}
97111
}

src/Symfony/Component/ExpressionLanguage/Node/NameNode.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,9 @@ public function evaluate($functions, $values)
3737
{
3838
return $values[$this->attributes['name']];
3939
}
40+
41+
public function dump()
42+
{
43+
return $this->attributes['name'];
44+
}
4045
}

src/Symfony/Component/ExpressionLanguage/Node/Node.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,27 @@ public function evaluate($functions, $values)
7575

7676
return $results;
7777
}
78+
79+
public function dump()
80+
{
81+
throw new \BadMethodCallException(sprintf('Dumping a "%s" instance is not supported yet.', get_class($this)));
82+
}
83+
84+
protected function dumpEscaped($value)
85+
{
86+
return str_replace(array('\\', '"'), array('\\\\', '\"'), $value);
87+
}
88+
89+
protected function isHash(array $value)
90+
{
91+
$expectedKey = 0;
92+
93+
foreach ($value as $key => $val) {
94+
if ($key !== $expectedKey++) {
95+
return true;
96+
}
97+
}
98+
99+
return false;
100+
}
78101
}

src/Symfony/Component/ExpressionLanguage/Node/UnaryNode.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,9 @@ public function evaluate($functions, $values)
5858

5959
return $value;
6060
}
61+
62+
public function dump()
63+
{
64+
return sprintf('(%s %s)', $this->attributes['operator'], $this->nodes['node']->dump());
65+
}
6166
}

src/Symfony/Component/ExpressionLanguage/ParsedExpression.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,9 @@ public function getNodes()
3939
{
4040
return $this->nodes;
4141
}
42+
43+
public function dump()
44+
{
45+
return $this->nodes->dump();
46+
}
4247
}

src/Symfony/Component/ExpressionLanguage/Tests/Node/AbstractNodeTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,14 @@ public function testCompile($expected, $node, $functions = array())
3636
}
3737

3838
abstract public function getCompileData();
39+
40+
/**
41+
* @dataProvider getDumpData
42+
*/
43+
public function testDump($expected, $node)
44+
{
45+
$this->assertSame($expected, $node->dump());
46+
}
47+
48+
abstract public function getDumpData();
3949
}

src/Symfony/Component/ExpressionLanguage/Tests/Node/ArgumentsNodeTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ public function getCompileData()
2222
);
2323
}
2424

25+
public function getDumpData()
26+
{
27+
return array(
28+
array('"a", "b"', $this->getArrayNode()),
29+
);
30+
}
31+
2532
protected function createArrayNode()
2633
{
2734
return new ArgumentsNode();

src/Symfony/Component/ExpressionLanguage/Tests/Node/ArrayNodeTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,21 @@ public function getCompileData()
4242
);
4343
}
4444

45+
public function getDumpData()
46+
{
47+
yield array('{"b": "a", 0: "b"}', $this->getArrayNode());
48+
49+
$array = $this->createArrayNode();
50+
$array->addElement(new ConstantNode('c'), new ConstantNode('a"b'));
51+
$array->addElement(new ConstantNode('d'), new ConstantNode('a\b'));
52+
yield array('{"a\\"b": "c", "a\\\\b": "d"}', $array);
53+
54+
$array = $this->createArrayNode();
55+
$array->addElement(new ConstantNode('c'));
56+
$array->addElement(new ConstantNode('d'));
57+
yield array('["c", "d"]', $array);
58+
}
59+
4560
protected function getArrayNode()
4661
{
4762
$array = $this->createArrayNode();

src/Symfony/Component/ExpressionLanguage/Tests/Node/BinaryNodeTest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,53 @@ public function getCompileData()
114114
array('preg_match("/^[a-z]+/i\$/", "abc")', new BinaryNode('matches', new ConstantNode('abc'), new ConstantNode('/^[a-z]+/i$/'))),
115115
);
116116
}
117+
118+
public function getDumpData()
119+
{
120+
$array = new ArrayNode();
121+
$array->addElement(new ConstantNode('a'));
122+
$array->addElement(new ConstantNode('b'));
123+
124+
return array(
125+
array('(true or false)', new BinaryNode('or', new ConstantNode(true), new ConstantNode(false))),
126+
array('(true || false)', new BinaryNode('||', new ConstantNode(true), new ConstantNode(false))),
127+
array('(true and false)', new BinaryNode('and', new ConstantNode(true), new ConstantNode(fals C2EE e))),
128+
array('(true && false)', new BinaryNode('&&', new ConstantNode(true), new ConstantNode(false))),
129+
130+
array('(2 & 4)', new BinaryNode('&', new ConstantNode(2), new ConstantNode(4))),
131+
array('(2 | 4)', new BinaryNode('|', new ConstantNode(2), new ConstantNode(4))),
132+
array('(2 ^ 4)', new BinaryNode('^', new ConstantNode(2), new ConstantNode(4))),
133+
134+
array('(1 < 2)', new BinaryNode('<', new ConstantNode(1), new ConstantNode(2))),
135+
array('(1 <= 2)', new BinaryNode('<=', new ConstantNode(1), new ConstantNode(2))),
136+
array('(1 <= 1)', new BinaryNode('<=', new ConstantNode(1), new ConstantNode(1))),
137+
138+
array('(1 > 2)', new BinaryNode('>', new ConstantNode(1), new ConstantNode(2))),
139+
array('(1 >= 2)', new BinaryNode('>=', new ConstantNode(1), new ConstantNode(2))),
140+
array('(1 >= 1)', new BinaryNode('>=', new ConstantNode(1), new ConstantNode(1))),
141+
142+
array('(true === true)', new BinaryNode('===', new ConstantNode(true), new ConstantNode(true))),
143+
array('(true !== true)', new BinaryNode('!==', new ConstantNode(true), new ConstantNode(true))),
144+
145+
array('(2 == 1)', new BinaryNode('==', new ConstantNode(2), new ConstantNode(1))),
146+
array('(2 != 1)', new BinaryNode('!=', new ConstantNode(2), new ConstantNode(1))),
147+
148+
array('(1 - 2)', new BinaryNode('-', new ConstantNode(1), new ConstantNode(2))),
149+
array('(1 + 2)', new BinaryNode('+', new ConstantNode(1), new ConstantNode(2))),
150+
array('(2 * 2)', new BinaryNode('*', new ConstantNode(2), new ConstantNode(2))),
151+
array('(2 / 2)', new BinaryNode('/', new ConstantNode(2), new ConstantNode(2))),
152+
array('(5 % 2)', new BinaryNode('%', new ConstantNode(5), new ConstantNode(2))),
153+
array('(5 ** 2)', new BinaryNode('**', new ConstantNode(5), new ConstantNode(2))),
154+
array('("a" ~ "b")', new BinaryNode('~', new ConstantNode('a'), new ConstantNode('b'))),
155+
156+
array('("a" in ["a", "b"])', new BinaryNode('in', new ConstantNode('a'), $array)),
157+
array('("c" in ["a", "b"])', new BinaryNode('in', new ConstantNode('c'), $array)),
158+
array('("c" not in ["a", "b"])', new BinaryNode('not in', new ConstantNode('c'), $array)),
159+
array('("a" not in ["a", "b"])', new BinaryNode('not in', new ConstantNode('a'), $array)),
160+
161+
array('(1 .. 3)', new BinaryNode('..', new ConstantNode(1), new ConstantNode(3))),
162+
163+
array('("abc" matches "/^[a-z]+/i$/")', new BinaryNode('matches', new ConstantNode('abc'), new ConstantNode('/^[a-z]+/i$/'))),
164+
);
165+
}
117166
}

src/Symfony/Component/ExpressionLanguage/Tests/Node/ConditionalNodeTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,12 @@ public function getCompileData()
3131
array('((false) ? (1) : (2))', new ConditionalNode(new ConstantNode(false), new ConstantNode(1), new ConstantNode(2))),
3232
);
3333
}
34+
35+
public function getDumpData()
36+
{
37+
return array(
38+
array('(true ? 1 : 2)', new ConditionalNode(new ConstantNode(true), new ConstantNode(1), new ConstantNode(2))),
39+
array('(false ? 1 : 2)', new ConditionalNode(new ConstantNode(false), new ConstantNode(1), new ConstantNode(2))),
40+
);
41+
}
3442
}

src/Symfony/Component/ExpressionLanguage/Tests/Node/ConstantNodeTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,20 @@ public function getCompileData()
4040
array('array(0 => 1, "b" => "a")', new ConstantNode(array(1, 'b' => 'a'))),
4141
);
4242
}
43+
44+
public function getDumpData()
45+
{
46+
return array(
47+
array('false', new ConstantNode(false)),
48+
array('true', new ConstantNode(true)),
49+
array('null', new ConstantNode(null)),
50+
array(3, new ConstantNode(3)),
51+
array(3.3, new ConstantNode(3.3)),
52+
array('"foo"', new ConstantNode('foo')),
53+
array('{0: 1, "b": "a", 1: true}', new ConstantNode(array(1, 'b' => 'a', true))),
54+
array('{"a\\"b": "c", "a\\\\b": "d"}', new ConstantNode(array('a"b' => 'c', 'a\\b' => 'd'))),
55+
array('["c", "d"]', new ConstantNode(array('c', 'd'))),
56+
array('{"a": ["b"]}', new ConstantNode(array('a' => array('b')))),
57+
);
58+
}
4359
}

src/Symfony/Component/ExpressionLanguage/Tests/Node/FunctionNodeTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ public function getCompileData()
3131
);
3232
}
3333

34+
public function getDumpData()
35+
{
36+
return array(
37+
array('foo("bar")', new FunctionNode('foo', new Node(array(new ConstantNode('bar')))), array('foo' => $this->getCallables())),
38+
);
39+
}
40+
3441
protected function getCallables()
3542
{
3643
return array(

src/Symfony/Component/ExpressionLanguage/Tests/Node/GetAttrNodeTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ public function getCompileData()
4444
);
4545
}
4646

47+
public function getDumpData()
48+
{
49+
return array(
50+
array('foo[0]', new GetAttrNode(new NameNode('foo'), new ConstantNode(0), $this->getArrayNode(), GetAttrNode::ARRAY_CALL)),
51+
array('foo["b"]', new GetAttrNode(new NameNode('foo'), new ConstantNode('b'), $this->getArrayNode(), GetAttrNode::ARRAY_CALL)),
52+
53+
array('foo.foo', new GetAttrNode(new NameNode('foo'), new ConstantNode('foo'), $this->getArrayNode(), GetAttrNode::PROPERTY_CALL), array('foo' => new Obj())),
54+
55+
array('foo.foo({"b": "a", 0: "b"})', new GetAttrNode(new NameNode('foo'), new ConstantNode('foo'), $this->getArrayNode(), GetAttrNode::METHOD_CALL), array('foo' => new Obj())),
56+
array('foo[index]', new GetAttrNode(new NameNode('foo'), new NameNode('index'), $this->getArrayNode(), GetAttrNode::ARRAY_CALL)),
57+
);
58+
}
59+
4760
protected function getArrayNode()
4861
{
4962
$array = new ArrayNode();

0 commit comments

Comments
 (0)
0