Search in sources :

Example 11 with Token

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;
}
Also used : Node(com.google.javascript.rhino.Node) Token(com.google.javascript.rhino.Token)

Example 12 with Token

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;
}
Also used : Node(com.google.javascript.rhino.Node) Token(com.google.javascript.rhino.Token)

Example 13 with Token

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;
    }
}
Also used : Node(com.google.javascript.rhino.Node) Token(com.google.javascript.rhino.Token) Tri(com.google.javascript.jscomp.base.Tri)

Example 14 with Token

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;
}
Also used : MeasuredNode(com.google.javascript.jscomp.MinimizedCondition.MeasuredNode) Node(com.google.javascript.rhino.Node) Token(com.google.javascript.rhino.Token)

Example 15 with Token

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;
    }
}
Also used : MeasuredNode(com.google.javascript.jscomp.MinimizedCondition.MeasuredNode) Node(com.google.javascript.rhino.Node) Tri(com.google.javascript.jscomp.base.Tri) Token(com.google.javascript.rhino.Token)

Aggregations

Token (com.google.javascript.rhino.Token)35 Node (com.google.javascript.rhino.Node)29 JSType (com.google.javascript.rhino.jstype.JSType)4 Tri (com.google.javascript.jscomp.base.Tri)3 DiGraphNode (com.google.javascript.jscomp.graph.DiGraph.DiGraphNode)3 FlowScope (com.google.javascript.jscomp.type.FlowScope)3 JSDocInfo (com.google.javascript.rhino.JSDocInfo)3 Test (org.junit.Test)3 MeasuredNode (com.google.javascript.jscomp.MinimizedCondition.MeasuredNode)2 JSType (com.google.javascript.jscomp.newtypes.JSType)2 Preconditions.checkState (com.google.common.base.Preconditions.checkState)1 Predicate (com.google.common.base.Predicate)1 HashMultiset (com.google.common.collect.HashMultiset)1 Multiset (com.google.common.collect.Multiset)1 CheckReturnValue (com.google.errorprone.annotations.CheckReturnValue)1 AssertionFunctionLookup (com.google.javascript.jscomp.CodingConvention.AssertionFunctionLookup)1 LinearFlowState (com.google.javascript.jscomp.DataFlowAnalysis.LinearFlowState)1 FunctionlessLocalScope (com.google.javascript.jscomp.NodeIterators.FunctionlessLocalScope)1 AbstractScopedCallback (com.google.javascript.jscomp.NodeTraversal.AbstractScopedCallback)1 LogFile (com.google.javascript.jscomp.diagnostic.LogFile)1