Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Operators are now only parenthesized if necessary #4)

  • Loading branch information...
commit 66aed8a7a8cade66cdf6437a7150d6264f2da060 1 parent 1aea667
@jmalloc jmalloc authored
View
3  composer.json
@@ -13,7 +13,8 @@
],
"require": {
"php": ">=5.3.0",
- "icecave/pasta-ast": "0.1.*"
+ "icecave/pasta-ast": "0.1.*",
+ "icecave/collections": "*"
},
"require-dev": {
"icecave/testing": "1.*"
View
108 composer.lock
@@ -1,5 +1,5 @@
{
- "hash": "f5d71db3ef962a3f2bb61f3c923ab358",
+ "hash": "e5927ca5d2ada50e74b6a0923817e751",
"packages": [
{
"name": "eloquent/enumeration",
@@ -49,6 +49,67 @@
]
},
{
+ "name": "icecave/collections",
+ "version": "0.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/IcecaveStudios/collections.git",
+ "reference": "0.5.0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://github.com/IcecaveStudios/collections/archive/0.5.0.zip",
+ "reference": "0.5.0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "icecave/repr": "1.*"
+ },
+ "require-dev": {
+ "icecave/testing": "1.*",
+ "eloquent/liberator": "1.*",
+ "eloquent/typhoon": "0.6.*"
+ },
+ "time": "2013-01-14 04:29:20",
+ "type": "library",
+ "extra": {
+ "typhoon": {
+ "output-path": "lib-typhoon",
+ "validator-namespace": "Icecave\\Collections\\TypeCheck",
+ "use-native-callable": false
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Icecave\\Collections": "lib",
+ "Icecave\\Collections\\TypeCheck": "lib-typhoon"
+ }
+ },
+ "notification-url": "http://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "James Harris",
+ "email": "james.harris@icecave.com.au"
+ }
+ ],
+ "description": "PHP collections without leaky abstractions.",
+ "homepage": "https://github.com/IcecaveStudios/collections",
+ "keywords": [
+ "container",
+ "queue",
+ "array",
+ "map",
+ "hash",
+ "sequence",
+ "collection",
+ "stack"
+ ]
+ },
+ {
"name": "icecave/pasta-ast",
"version": "0.1.0",
"source": {
@@ -95,6 +156,51 @@
"abstract",
"ast"
]
+ },
+ {
+ "name": "icecave/repr",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/IcecaveStudios/repr.git",
+ "reference": "1.0.0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://github.com/IcecaveStudios/repr/archive/1.0.0.zip",
+ "reference": "1.0.0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phake/phake": "1.*"
+ },
+ "time": "2013-01-11 00:04:43",
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Icecave\\Repr": "lib"
+ }
+ },
+ "notification-url": "http://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "James Harris",
+ "email": "james.harris@icecave.com.au"
+ }
+ ],
+ "description": "Human readable string representations of everything.",
+ "homepage": "https://github.com/IcecaveStudios/repr",
+ "keywords": [
+ "string",
+ "representation",
+ "repr"
+ ]
}
],
"packages-dev": [
View
85 lib/Icecave/Rasta/Renderer.php
@@ -1,6 +1,7 @@
<?php
namespace Icecave\Rasta;
+use Icecave\Collections\Stack;
use Icecave\Pasta\AST\ContentBlock;
use Icecave\Pasta\AST\Expr\ArrayLiteral;
use Icecave\Pasta\AST\Expr\Assign;
@@ -29,6 +30,7 @@
use Icecave\Pasta\AST\Expr\Equals;
use Icecave\Pasta\AST\Expr\Greater;
use Icecave\Pasta\AST\Expr\GreaterEqual;
+use Icecave\Pasta\AST\Expr\IOperator;
use Icecave\Pasta\AST\Expr\InstanceOfType;
use Icecave\Pasta\AST\Expr\Less;
use Icecave\Pasta\AST\Expr\LessEqual;
@@ -46,6 +48,7 @@
use Icecave\Pasta\AST\Expr\MultiplyAssign;
use Icecave\Pasta\AST\Expr\NewOperator;
use Icecave\Pasta\AST\Expr\NotEquals;
+use Icecave\Pasta\AST\Expr\OperatorTraits;
use Icecave\Pasta\AST\Expr\PolyadicOperator;
use Icecave\Pasta\AST\Expr\PostfixDecrement;
use Icecave\Pasta\AST\Expr\PostfixIncrement;
@@ -80,8 +83,8 @@
use Icecave\Pasta\AST\Stmt\ContinueStatement;
use Icecave\Pasta\AST\Stmt\DoWhileStatement;
use Icecave\Pasta\AST\Stmt\ExpressionStatement;
-use Icecave\Pasta\AST\Stmt\ForeachStatement;
use Icecave\Pasta\AST\Stmt\ForStatement;
+use Icecave\Pasta\AST\Stmt\ForeachStatement;
use Icecave\Pasta\AST\Stmt\IStatement;
use Icecave\Pasta\AST\Stmt\IfStatement;
use Icecave\Pasta\AST\Stmt\NamespaceStatement;
@@ -100,12 +103,21 @@
class Renderer implements IVisitor
{
- public function __construct($indentString = ' ', $newlineString = "\n")
- {
+ public function __construct(
+ $indentString = ' ',
+ $newlineString = "\n",
+ OperatorTraits $operatorTraits = null
+ ) {
+ if (null === $operatorTraits) {
+ $operatorTraits = new OperatorTraits;
+ }
+
$this->indentString = $indentString;
$this->indentLevel = 0;
$this->newlineString = $newlineString;
$this->isInterfaceScope = false;
+ $this->precedenceStack = new Stack;
+ $this->operatorTraits = $operatorTraits;
}
public function visitContentBlock(ContentBlock $node)
@@ -874,31 +886,50 @@ protected function visitChildren(Node $node)
protected function generateCastOperatorCode($type, UnaryOperator $node)
{
- return '(' . $type . ') ' . $node->expression()->accept($this);
+ $code = $this->startOperator($node);
+ $code .= '(' . $type . ') ' . $node->expression()->accept($this);
+ $code .= $this->endOperator();
+
+ return $code;
}
protected function generateUnaryOperatorCode($operator, UnaryOperator $node, $prefix = true)
{
+ $code = $this->startOperator($node);
+
if ($prefix) {
- return '(' . $operator . $node->expression()->accept($this) . ')';
+ $code .= $operator . $node->expression()->accept($this);
+ } else {
+ $code .= $node->expression()->accept($this) . $operator;
}
- return '(' . $node->expression()->accept($this) . $operator . ')';
+ $code .= $this->endOperator();
+
+ return $code;
}
protected function generateBinaryOperatorCode($operator, BinaryOperator $node)
{
- return '(' . $node->leftExpression()->accept($this) . ' ' . $operator . ' ' . $node->rightExpression()->accept($this) . ')';
+ $code = $this->startOperator($node);
+ $code .= $node->leftExpression()->accept($this) . ' ' . $operator . ' ' . $node->rightExpression()->accept($this);
+ $code .= $this->endOperator();
+
+ return $code;
}
protected function generatePolyadicOperatorCode($operator, PolyadicOperator $node)
{
+ $code = $this->startOperator($node);
+
$expressions = array();
foreach ($node->children() as $expression) {
$expressions[] = $expression->accept($this);
}
- return '(' . implode(' ' . $operator . ' ', $expressions) . ')';
+ $code .= implode(' ' . $operator . ' ', $expressions);
+ $code .= $this->endOperator();
+
+ return $code;
}
protected function generateStatementCode(IStatement $node, $addBraces = true)
@@ -912,10 +943,48 @@ protected function generateStatementCode(IStatement $node, $addBraces = true)
return $this->visitStatementBlock($node, false);
}
+ protected function startOperator(IOperator $operator)
+ {
+ list($precedence) = $operator->accept($this->operatorTraits);
+
+ if ($this->precedenceStack->isEmpty()) {
+ $parenthesize = false;
+ } else {
+ list($currentPrecedence) = $this->precedenceStack->next();
+ $parenthesize = $precedence > $currentPrecedence;
+ }
+
+ $this->precedenceStack->push(
+ array(
+ $precedence,
+ $parenthesize
+ )
+ );
+
+ if ($parenthesize) {
+ return '(';
+ }
+
+ return '';
+ }
+
+ protected function endOperator()
+ {
+ list(, $parenthesize) = $this->precedenceStack->pop();
+
+ if ($parenthesize) {
+ return ')';
+ }
+
+ return '';
+ }
+
const MAXIMUM_INLINE_ARITY = 3;
private $indentString;
private $indentLevel;
private $newlineString;
private $isInterfaceScope;
+ private $precedenceStack;
+ private $operatorTraits;
}
View
90 test/suite/Icecave/Rasta/RendererTest.php
@@ -7,11 +7,17 @@
use Icecave\Pasta\AST\Expr\Association;
use Icecave\Pasta\AST\Expr\Call;
use Icecave\Pasta\AST\Expr\Constant;
+use Icecave\Pasta\AST\Expr\Divide;
+use Icecave\Pasta\AST\Expr\Equals;
use Icecave\Pasta\AST\Expr\Literal;
+use Icecave\Pasta\AST\Expr\LogicalAnd;
+use Icecave\Pasta\AST\Expr\LogicalOr;
use Icecave\Pasta\AST\Expr\Member;
+use Icecave\Pasta\AST\Expr\PrefixIncrement;
use Icecave\Pasta\AST\Expr\QualifiedIdentifier;
use Icecave\Pasta\AST\Expr\StaticMember;
use Icecave\Pasta\AST\Expr\Subscript;
+use Icecave\Pasta\AST\Expr\Subtract;
use Icecave\Pasta\AST\Expr\Variable;
use Icecave\Pasta\AST\Func\ArrayTypeHint;
use Icecave\Pasta\AST\Func\CallableTypeHint;
@@ -816,9 +822,9 @@ public function testVisitClosureIndenting()
$code = $node->accept($this->_renderer);
$expected = '{' . $this->_newlineString;
- $expected .= ' ($target = function () {' . $this->_newlineString;
+ $expected .= ' $target = function () {' . $this->_newlineString;
$expected .= ' foo();' . $this->_newlineString;
- $expected .= ' });' . $this->_newlineString;
+ $expected .= ' };' . $this->_newlineString;
$expected .= '}' . $this->_newlineString;
$this->assertSame($expected, $code);
}
@@ -845,7 +851,7 @@ public function testAssignmentOperators($operator, $symbol)
$code = $node->accept($this->_renderer);
- $expected = '($target ' . $symbol . ' $source)';
+ $expected = '$target ' . $symbol . ' $source';
$this->assertSame($expected, $code);
}
@@ -865,7 +871,31 @@ public function testPolyadicOperators($operator, $symbol)
$code = $node->accept($this->_renderer);
- $expected = '($a ' . $symbol . ' $b ' . $symbol . ' $c)';
+ $expected = '$a ' . $symbol . ' $b ' . $symbol . ' $c';
+ $this->assertSame($expected, $code);
+ }
+
+ public function testPolyadicOperatorPrecedence1()
+ {
+ $var = new Variable(new Identifier('x'));
+ $left = new LogicalOr($var, $var);
+ $right = new LogicalOr($var, $var);
+ $node = new LogicalAnd($left, $right);
+ $code = $node->accept($this->_renderer);
+
+ $expected = '($x || $x) && ($x || $x)';
+ $this->assertSame($expected, $code);
+ }
+
+ public function testPolyadocOperatorPrecedence2()
+ {
+ $var = new Variable(new Identifier('x'));
+ $left = new LogicalAnd($var, $var);
+ $right = new LogicalAnd($var, $var);
+ $node = new LogicalOr($left, $right);
+ $code = $node->accept($this->_renderer);
+
+ $expected = '$x && $x || $x && $x';
$this->assertSame($expected, $code);
}
@@ -884,7 +914,31 @@ public function testBinaryOperators($operator, $symbol)
$code = $node->accept($this->_renderer);
- $expected = '($left ' . $symbol . ' $right)';
+ $expected = '$left ' . $symbol . ' $right';
+ $this->assertSame($expected, $code);
+ }
+
+ public function testBinaryOperatorPrecedence1()
+ {
+ $var = new Variable(new Identifier('x'));
+ $left = new Subtract($var, $var);
+ $right = new Subtract($var, $var);
+ $node = new Divide($left, $right);
+ $code = $node->accept($this->_renderer);
+
+ $expected = '($x - $x) / ($x - $x)';
+ $this->assertSame($expected, $code);
+ }
+
+ public function testBinaryOperatorPrecedence2()
+ {
+ $var = new Variable(new Identifier('x'));
+ $left = new Divide($var, $var);
+ $right = new Divide($var, $var);
+ $node = new Subtract($left, $right);
+ $code = $node->accept($this->_renderer);
+
+ $expected = '$x / $x - $x / $x';
$this->assertSame($expected, $code);
}
@@ -920,7 +974,7 @@ public function testPrefixUnaryOperators($operator, $symbol)
$code = $node->accept($this->_renderer);
- $expected = '(' . $symbol . '$value)';
+ $expected = $symbol . '$value';
$this->assertSame($expected, $code);
}
@@ -938,7 +992,29 @@ public function testPostfixUnaryOperators($operator, $symbol)
$code = $node->accept($this->_renderer);
- $expected = '($value' . $symbol . ')';
+ $expected = '$value' . $symbol;
+ $this->assertSame($expected, $code);
+ }
+
+ public function testUnaryOperatorPrecedence1()
+ {
+ $var = new Variable(new Identifier('x'));
+ $expr = new Subtract($var, $var);
+ $node = new PrefixIncrement($expr);
+ $code = $node->accept($this->_renderer);
+
+ $expected = '++($x - $x)';
+ $this->assertSame($expected, $code);
+ }
+
+ public function testUnaryOperatorPrecedence2()
+ {
+ $var = new Variable(new Identifier('x'));
+ $expr = new PrefixIncrement($var);
+ $node = new Subtract($expr, $var);
+ $code = $node->accept($this->_renderer);
+
+ $expected = '++$x - $x';
$this->assertSame($expected, $code);
}
Please sign in to comment.
Something went wrong with that request. Please try again.