use of com.google.javascript.rhino.Token in project closure-compiler by google.
the class PeepholeFoldConstants method tryFoldAssign.
private Node tryFoldAssign(Node n, Node left, Node right) {
checkArgument(n.isAssign());
if (!late) {
return n;
}
// Tries to convert x = x + y -> x += y;
if (!right.hasChildren() || right.getSecondChild() != right.getLastChild()) {
// RHS must have two children.
return n;
}
if (mayHaveSideEffects(left)) {
return n;
}
Node newRight;
if (areNodesEqualForInlining(left, right.getFirstChild())) {
newRight = right.getLastChild();
} else if (NodeUtil.isCommutative(right.getToken()) && areNodesEqualForInlining(left, right.getLastChild())) {
newRight = right.getFirstChild();
} else {
return n;
}
Token newType = null;
switch(right.getToken()) {
case ADD:
newType = Token.ASSIGN_ADD;
break;
case BITAND:
newType = Token.ASSIGN_BITAND;
break;
case BITOR:
newType = Token.ASSIGN_BITOR;
break;
case BITXOR:
newType = Token.ASSIGN_BITXOR;
break;
case DIV:
newType = Token.ASSIGN_DIV;
break;
case LSH:
newType = Token.ASSIGN_LSH;
break;
case MOD:
newType = Token.ASSIGN_MOD;
break;
case MUL:
newType = Token.ASSIGN_MUL;
break;
case RSH:
newType = Token.ASSIGN_RSH;
break;
case SUB:
newType = Token.ASSIGN_SUB;
break;
case URSH:
newType = Token.ASSIGN_URSH;
break;
case EXPONENT:
newType = Token.ASSIGN_EXPONENT;
break;
default:
return n;
}
Node newNode = new Node(newType, left.detach(), newRight.detach());
n.replaceWith(newNode);
reportChangeToEnclosingScope(newNode);
return newNode;
}
use of com.google.javascript.rhino.Token in project closure-compiler by google.
the class PeepholeFoldConstants method tryUnfoldAssignOp.
private Node tryUnfoldAssignOp(Node n, Node left, Node right) {
if (late) {
return n;
}
if (!n.hasChildren() || n.getSecondChild() != n.getLastChild()) {
return n;
}
if (mayHaveSideEffects(left)) {
return n;
}
// Tries to convert x += y -> x = x + y;
Token op = NodeUtil.getOpFromAssignmentOp(n);
Node replacement = IR.assign(left.detach(), new Node(op, left.cloneTree(), right.detach()).srcref(n));
n.replaceWith(replacement);
reportChangeToEnclosingScope(replacement);
return replacement;
}
use of com.google.javascript.rhino.Token in project closure-compiler by google.
the class PeepholeFoldConstants method tryFoldAndOr.
/**
* Try to fold a AND/OR node.
*/
private Node tryFoldAndOr(Node n, Node left, Node right) {
Node parent = n.getParent();
Node result = null;
Node dropped = null;
Token type = n.getToken();
Tri leftVal = NodeUtil.getBooleanValue(left);
if (leftVal != Tri.UNKNOWN) {
boolean lval = leftVal.toBoolean(true);
// (FALSE && x) => FALSE
if (lval ? type == Token.OR : type == Token.AND) {
result = left;
dropped = right;
} else if (!mayHaveSideEffects(left)) {
// (FALSE || x) => x
// (TRUE && x) => x
result = right;
dropped = left;
} else {
// Left side may have side effects, but we know its boolean value.
// e.g. true_with_sideeffects || foo() => true_with_sideeffects, foo()
// or: false_with_sideeffects && foo() => false_with_sideeffects, foo()
// This, combined with PeepholeRemoveDeadCode, helps reduce expressions
// like "x() || false || z()".
n.detachChildren();
result = IR.comma(left, right);
dropped = null;
}
} else if (parent.getToken() == type && n == parent.getFirstChild()) {
Tri rightValue = NodeUtil.getBooleanValue(right);
if (!mayHaveSideEffects(right)) {
if ((rightValue == Tri.FALSE && type == Token.OR) || (rightValue == Tri.TRUE && type == Token.AND)) {
result = left;
dropped = right;
}
}
}
if (result != null) {
// Fold it!
n.detachChildren();
n.replaceWith(result);
reportChangeToEnclosingScope(result);
if (dropped != null) {
markFunctionsDeleted(dropped);
}
return result;
} else {
return n;
}
}
use of com.google.javascript.rhino.Token in project closure-compiler by google.
the class PeepholeMinimizeConditions method tryMinimizeNot.
/**
* Try to minimize NOT nodes such as !(x==y).
*
* Returns the replacement for n or the original if no change was made
*/
private Node tryMinimizeNot(Node n) {
checkArgument(n.isNot());
Node parent = n.getParent();
Node notChild = n.getFirstChild();
// negative operator of the current one : == -> != for instance.
Token complementOperator;
switch(notChild.getToken()) {
case EQ:
complementOperator = Token.NE;
break;
case NE:
complementOperator = Token.EQ;
break;
case SHEQ:
complementOperator = Token.SHNE;
break;
case SHNE:
complementOperator = Token.SHEQ;
break;
// GT, GE, LT, LE are not handled in this because !(x<NaN) != x>=NaN.
default:
return n;
}
Node newOperator = n.removeFirstChild();
newOperator.setToken(complementOperator);
n.replaceWith(newOperator);
reportChangeToEnclosingScope(parent);
return newOperator;
}
use of com.google.javascript.rhino.Token in project closure-compiler by google.
the class PeepholeMinimizeConditions method performConditionSubstitutions.
/**
* Try to minimize the given condition by applying local substitutions.
*
* The following types of transformations are performed:
* x || true --> true
* x && true --> x
* x ? false : true --> !x
* x ? true : y --> x || y
* x ? x : y --> x || y
*
* Returns the replacement for n, or the original if no change was made
*/
private Node performConditionSubstitutions(Node n) {
Node parent = n.getParent();
switch(n.getToken()) {
case OR:
case AND:
{
Node left = n.getFirstChild();
Node right = n.getLastChild();
// Because the expression is in a boolean context minimize
// the children, this can't be done in the general case.
left = performConditionSubstitutions(left);
right = performConditionSubstitutions(right);
// Remove useless conditionals
// Handle the following cases:
// x || false --> x
// x && true --> x
// This works regardless of whether x has side effects.
//
// If x does not have side effects:
// x || true --> true
// x && false --> false
//
// If x may have side effects:
// x || true --> x,true
// x && false --> x,false
//
// In the last two cases, code size may increase slightly (adding
// some parens because the comma operator has a low precedence) but
// the new AST is easier for other passes to handle.
Tri rightVal = getSideEffectFreeBooleanValue(right);
if (getSideEffectFreeBooleanValue(right) != Tri.UNKNOWN) {
Token type = n.getToken();
Node replacement = null;
boolean rval = rightVal.toBoolean(true);
// (x && TRUE) => x
if ((type == Token.OR && !rval) || (type == Token.AND && rval)) {
replacement = left;
} else if (!mayHaveSideEffects(left)) {
replacement = right;
} else {
// expr_with_sideeffects || true => expr_with_sideeffects, true
// expr_with_sideeffects && false => expr_with_sideeffects, false
n.detachChildren();
replacement = IR.comma(left, right);
}
if (replacement != null) {
n.detachChildren();
n.replaceWith(replacement);
reportChangeToEnclosingScope(parent);
return replacement;
}
}
return n;
}
case HOOK:
{
Node condition = n.getFirstChild();
Node trueNode = n.getSecondChild();
Node falseNode = n.getLastChild();
// Because the expression is in a boolean context minimize
// the result children, this can't be done in the general case.
// The condition is handled in the general case in #optimizeSubtree
trueNode = performConditionSubstitutions(trueNode);
falseNode = performConditionSubstitutions(falseNode);
// Handle five cases:
// x ? true : false --> x
// x ? false : true --> !x
// x ? true : y --> x || y
// x ? y : false --> x && y
// Only when x is NAME, hence x does not have side effects
// x ? x : y --> x || y
Node replacement = null;
Tri trueNodeVal = getSideEffectFreeBooleanValue(trueNode);
Tri falseNodeVal = getSideEffectFreeBooleanValue(falseNode);
if (trueNodeVal == Tri.TRUE && falseNodeVal == Tri.FALSE) {
// Remove useless conditionals, keep the condition
condition.detach();
replacement = condition;
} else if (trueNodeVal == Tri.FALSE && falseNodeVal == Tri.TRUE) {
// Remove useless conditionals, keep the condition
condition.detach();
replacement = IR.not(condition);
} else if (trueNodeVal == Tri.TRUE) {
// Remove useless true case.
n.detachChildren();
replacement = IR.or(condition, falseNode);
} else if (falseNodeVal == Tri.FALSE) {
// Remove useless false case
n.detachChildren();
replacement = IR.and(condition, trueNode);
} else if (!mayHaveSideEffects(condition) && !mayHaveSideEffects(trueNode) && condition.isEquivalentTo(trueNode)) {
// Remove redundant condition
n.detachChildren();
replacement = IR.or(trueNode, falseNode);
}
if (replacement != null) {
n.replaceWith(replacement);
reportChangeToEnclosingScope(replacement);
n = replacement;
}
return n;
}
default:
// while(true) --> while(1)
Tri nVal = getSideEffectFreeBooleanValue(n);
if (nVal != Tri.UNKNOWN) {
boolean result = nVal.toBoolean(true);
int equivalentResult = result ? 1 : 0;
return maybeReplaceChildWithNumber(n, equivalentResult);
}
// We can't do anything else currently.
return n;
}
}
Aggregations