Package com.google.caja.parser.js

Examples of com.google.caja.parser.js.Operation


        || e instanceof ArrayConstructor || e instanceof ObjectConstructor
        || e instanceof FunctionConstructor) {
      return true;
    }
    if (!(e instanceof Operation)) { return false; }
    Operation op = (Operation) e;
    switch (op.getOperator()) {
      case ASSIGN:
      case DELETE:
      case POST_DECREMENT: case POST_INCREMENT:
      case PRE_DECREMENT: case PRE_INCREMENT:
      case VOID: // indicates value purposely ignored
        return false;
      case FUNCTION_CALL:
        return false;
      case CONSTRUCTOR:
        return true;
      case LOGICAL_AND: case LOGICAL_OR:
        return shouldBeEvaluatedForValue(op.children().get(1));
      case TERNARY:
        return shouldBeEvaluatedForValue(op.children().get(1))
            && shouldBeEvaluatedForValue(op.children().get(2));
      case COMMA:
        // We do not allow comma, since bad things happen when commas are used.
        // Consider
        //    if (foo)
        //      return bar,
        //    baz();
        // $FALL-THROUGH
      default:
        return op.getOperator().getCategory() != OperatorCategory.ASSIGNMENT;
    }
  }
View Full Code Here


    return es.parent.cast(ForEachLoop.class).node.getKeyReceiver() == es.node;
  }

  private static boolean isCommaOperationNotEvaluatedForValue(Expression e) {
    if (!(e instanceof Operation)) { return false; }
    Operation op = (Operation) e;
    if (op.getOperator() != Operator.COMMA) { return false; }
    Expression left = op.children().get(0), right = op.children().get(1);
    return !shouldBeEvaluatedForValue(right)
        && (!shouldBeEvaluatedForValue(left)
            || isCommaOperationNotEvaluatedForValue(left));
  }
View Full Code Here

    if (oldFact != null && !oldFact.b.isLessSpecificThan(fact)) { return; }
    putFact(e, digest, fact);

    // Infer extra facts
    if (e instanceof Operation) {
      Operation op = ((Operation) e);
      List<? extends Expression> operands = op.children();
      switch (op.getOperator()) {
        case NOT:
          // If (!x) then x is falsey.
          addFuzzyFact(operands.get(0), !fact.isTruthy());
          break;
        case LESS_THAN:
        case GREATER_THAN:
          if (fact.isTruthy()) {
            // If (a < b) the a != b, and !(a > b).
            Expression left = operands.get(0);
            Expression right = operands.get(1);
            Operator included = op.getOperator() == Operator.LESS_THAN
                ? Operator.LESS_EQUALS : Operator.GREATER_EQUALS;
            addFactInt(Operation.create(UNK, included, left, right), Fact.TRUE);
            addFactInt(
                Operation.create(UNK, Operator.STRICTLY_NOT_EQUAL, left, right),
                Fact.TRUE);
            // Incomparable values like NaN means we can conclude nothing if
            // !(a < b).
          }
          break;
        case LESS_EQUALS:
        case GREATER_EQUALS:
          if (fact.isFalsey()) {
            // if !(a <= b) then a !== b.
            Expression left = operands.get(0);
            Expression right = operands.get(1);
            addFactInt(
                Operation.create(UNK, Operator.STRICTLY_NOT_EQUAL, left, right),
                Fact.TRUE);
          }
          break;
        case INSTANCE_OF:
          // if (x instanceof y) does not throw, then y must be a function.
          // if it's true, then x must be an object.
          // Note: primitives are not instances of their wrapper class.
          addFactInt(
              Operation.create(UNK, Operator.TYPEOF, operands.get(1)),
              Fact.is(StringLiteral.valueOf(UNK, "function")));
          if (fact.isTruthy()) {
            addFactInt(operands.get(0), Fact.TRUTHY);
          }
          break;
        case EQUAL:
          addFactInt(
              Operation.create(
                  UNK, Operator.NOT_EQUAL, operands.get(0), operands.get(1)),
              fact.isTruthy() ? Fact.FALSE : Fact.TRUE);
          break;
        case NOT_EQUAL:
          addFactInt(
              Operation.create(
                  UNK, Operator.EQUAL, operands.get(0), operands.get(1)),
              fact.isTruthy() ? Fact.FALSE : Fact.TRUE);
          break;
        case STRICTLY_EQUAL:
          if (fact.isTruthy()) {
            Expression lhs = operands.get(0);
            Expression rhs = operands.get(1);
            addFactInt(Operation.create(UNK, Operator.EQUAL, lhs, rhs),
                       Fact.TRUE);
            if (rhs instanceof Literal) {
              // TODO(mikesamuel): what do we do about the fact that (0 === -0)?
              // Instead of inferring that the value IS 0, we could infer that
              // it's falsey, and the typeof is number.
              addFactInt(lhs, Fact.is((Literal) rhs));

            // (this.global === this) -> global aliases the global object.
            } else if (isThis(rhs) && lhs instanceof Reference) {
              addFactInt(lhs, Fact.GLOBAL);
            } else {
              String typeOf = rhs.typeOf();
              if (typeOf != null && lhs.typeOf() == null) {
                addFactInt(
                    Operation.create(UNK, Operator.TYPEOF, lhs),
                    Fact.is(StringLiteral.valueOf(UNK, typeOf)));
              }
              // TODO(mikesamuel): Is this useful?  When, in a comparison,
              // do we know that something is truthy or falsey, but not what
              // literal value it is.  The expressions:
              //    x === function () {}
              //    y === [1,2,3]
              //    z === {}
              // are never true, so control wouldn't reach here.
              Boolean truthiness = rhs.conditionResult();
              if (truthiness != null) {
                addFuzzyFact(lhs, truthiness);
              }
            }
          } else {
            Expression lhs = operands.get(0);
            Expression rhs = operands.get(1);
            if (ParseTreeNodes.deepEquals(lhs, rhs)) {
              addFactInt(lhs, Fact.is(new RealLiteral(UNK, Double.NaN)));
            }
          }
          addFactInt(
              Operation.create(
                  UNK, Operator.STRICTLY_NOT_EQUAL,
                  operands.get(0), operands.get(1)),
              fact.isTruthy() ? Fact.FALSE : Fact.TRUE);
          break;
        case STRICTLY_NOT_EQUAL:
          addFactInt(Operation.create(
              UNK, Operator.STRICTLY_EQUAL, operands.get(0), operands.get(1)),
              fact.isTruthy() ? Fact.FALSE : Fact.TRUE);
          break;
        case LOGICAL_AND:
        case LOGICAL_OR:
          boolean isAnd = op.getOperator() == Operator.LOGICAL_AND;
          if (fact.isTruthy() == isAnd) {
            addFuzzyFact(operands.get(0), isAnd);
            addFactInt(operands.get(1), fact)// Second value is result
          }
          break;
        case MEMBER_ACCESS:
        case SQUARE_BRACKET:
          // If foo.bar is truthy, then so is foo.
          if (fact.isTruthy()) {
            addFuzzyFact(operands.get(0), true);
          }
          break;
        case TYPEOF:
          if (fact.type == Fact.Type.IS
              && fact.value instanceof StringLiteral) {
            String s = ((StringLiteral) fact.value).getUnquotedValue();
            Expression op0 = operands.get(0);
            if ("undefined".equals(s)) {
              addFactInt(op0, Fact.UNDEFINED);
            } else {
              if ("function".equals(s)) { addFactInt(op0, Fact.TRUTHY); }
              // undefined is a commonly tested value, so infer its absence
              // for other types.
              addFactInt(
                  Operation.create(
                      UNK, Operator.STRICTLY_EQUAL, op0, Fact.UNDEFINED.value),
                  Fact.FALSE);
            }
          }
          break;
        default:
          break;
      }
      // (a < b) -> (b > a) since we know (a) and (b) are pure
      if (operands.size() == 2) {
        Operator swapped = WITH_REVERSE_ORDER.get(op.getOperator());
        if (swapped != null) {
          addFactInt(
              Operation.create(
                  op.getFilePosition(), swapped,
                  operands.get(1), operands.get(0)),
              fact);
        }
      }
    }
View Full Code Here

    return sb.toString();
  }

  private Fact foldComparisonToFalsey(ParseTreeNode n) {
    if (!(n instanceof Operation)) { return null; }
    Operation op = (Operation) n;
    Operator o = op.getOperator();
    boolean eq;
    boolean strict;
    switch (o) {
      case EQUAL: case STRICTLY_EQUAL: eq = true; break;
      case NOT_EQUAL: case STRICTLY_NOT_EQUAL: eq = false; break;
      default: return null;
    }
    strict = o == Operator.STRICTLY_EQUAL || o == Operator.STRICTLY_NOT_EQUAL;
    List<? extends Expression> operands = op.children();
    Expression a = operands.get(0);
    Expression b = operands.get(1);
    if (strict ? isUndefOrLiteral(a) : isNullOrUndef(a)) {
      // continue to check
    } else if (strict ? isUndefOrLiteral(b) : isNullOrUndef(b)) {
View Full Code Here

  private static String topRef(Expression e) {
    while (true) {
      if (e instanceof Reference) { return ((Reference) e).getIdentifierName(); }
      if (!(e instanceof Operation)) { return null; }
      Operation op = (Operation) e;
      switch (op.getOperator()) {
        case MEMBER_ACCESS: case SQUARE_BRACKET:
          e = op.children().get(0);
          break;
        default: return null;
      }
    }
  }
View Full Code Here

  private static Expression withTopRef(Expression e, String lhs) {
    if (e instanceof Reference) {
      return Operation.createInfix(
          Operator.MEMBER_ACCESS, new Reference(new Identifier(UNK, lhs)), e);
    } else {
      Operation op = (Operation) e;
      List<? extends Expression> operands = op.children();
      return Operation.create(
          e.getFilePosition(), op.getOperator(),
          withTopRef(operands.get(0), lhs), operands.get(1));
    }
  }
View Full Code Here

          withTopRef(operands.get(0), lhs), operands.get(1));
    }
  }

  private static Expression withoutTopRef(Expression e) {
    Operation op = (Operation) e;
    List<? extends Expression> operands = op.children();
    Expression obj = operands.get(0), prop = operands.get(1);
    if (obj instanceof Reference) { return prop; }
    return Operation.create(
        e.getFilePosition(), op.getOperator(), withoutTopRef(obj), prop);
  }
View Full Code Here

        e.getFilePosition(), op.getOperator(), withoutTopRef(obj), prop);
  }

  private static Expression rfold(Expression e, boolean isFn) {
    if (e instanceof Operation) {
      Operation o = (Operation) e;
      List<? extends Expression> children = o.children();
      Expression[] newChildren = null;
      boolean oIsFn = o.getOperator() == Operator.FUNCTION_CALL;
      for (int i = 0, n = children.size(); i < n; ++i) {
        Expression operand = children.get(i);
        Expression newOperand = rfold(operand, oIsFn && i == 0);
        if (operand == newOperand) { continue; }
        if (newChildren == null) {
          newChildren = children.toArray(new Expression[n]);
        }
        newChildren[i] = newOperand;
      }
      if (newChildren != null) {
        e = Operation.create(e.getFilePosition(), o.getOperator(), newChildren);
      }
    }
    return normNum(e.fold(isFn));
  }
View Full Code Here

    if (!(ac.parent.node instanceof Reference)) { return null; }
    AncestorChain<?> grandparent = ac.parent.parent;
    if (grandparent == null) { return null; }
    if (grandparent.node instanceof Operation) {
      // Handles ++ac, ac += ..., ac = ...
      Operation op = grandparent.cast(Operation.class).node;
      Operator operator = op.getOperator();
      return (operator.getCategory() == OperatorCategory.ASSIGNMENT
              && ac.parent.node == op.children().get(0)) ? operator : null;
    } else if (grandparent.node instanceof ExpressionStmt
               && grandparent.parent != null
               && grandparent.parent.node instanceof ForEachLoop) {
      // Handle
      //    for (k in obj) { ... }
View Full Code Here

    return (Expression) children.get(0);
  }

  static Expression optimizeExpressionFlow(Expression e) {
    if (!(e instanceof Operation)) { return e; }
    Operation op = (Operation) e;
    List<? extends Expression> operands = op.children();
    Expression[] newOperands = null;
    int n = operands.size();
    for (int i = 0; i < n; ++i) {
      Expression operand = operands.get(i);
      Expression newOperand = optimizeExpressionFlow(operand);
      if (operand != newOperand) {
        if (newOperands == null) {
          newOperands = operands.toArray(new Expression[n]);
        }
        newOperands[i] = newOperand;
      }
    }
    Operator oper = op.getOperator();
    FilePosition pos = e.getFilePosition();
    if (oper != Operator.TERNARY) {
      return newOperands == null ? e : Operation.create(pos, oper, newOperands);
    }
    // (c ? x,z : y,z) -> (c ? x:y),z
    Expression[] ternaryOperands = newOperands != null
        ? newOperands : operands.toArray(new Expression[3]);
    Expression c = ternaryOperands[0];
    Expression x = ternaryOperands[1];
    Expression y = ternaryOperands[2];
    while (Operation.is(c, Operator.NOT)) {
      c = ((Operation) c).children().get(0);
      Expression t = x;
      x = y;
      y = t;
    }
    if (ParseTreeNodes.deepEquals(x, y)) {
      if (c.simplifyForSideEffect() == null) { return x; }
      return commaOp(pos, c, x);
    }
    if (isSimple(c)) {
      // If a reference fails with an exception because it is undefined, then
      // control would never reach the second identical expression.
      if (ParseTreeNodes.deepEquals(c, x)) {
        // (c ? c : y) -> c || y     if c not side effecting
        return Operation.create(pos, Operator.LOGICAL_OR, c, y);
      } else if (ParseTreeNodes.deepEquals(c, y)) {
        // (c ? x : c) -> c && x     if c not side effecting
        return Operation.create(pos, Operator.LOGICAL_AND, c, x);
      }
    }
    // TODO(mikesamuel): if c is simple and not a global reference, optimize
    // out he common head as well.
    CommaCommonalities opt = commaCommonalities(x, y);
    if (opt != null) {
      // Both reduced sides can't be null since we checked above whether
      // x and y are structurally identical.
      if (opt.aReduced == null) {
        // (c ? z: y,z)  ->  (c || y),z
        return commaOp(
            pos,
            Operation.createInfix(Operator.LOGICAL_OR, c, opt.bReduced),
            opt.commonTail);
      } else if (opt.bReduced == null) {
        // (c ? x,z : z)  ->  (c && x),z
        return commaOp(
            pos,
            Operation.createInfix(Operator.LOGICAL_AND, c, opt.aReduced),
            opt.commonTail);
      } else {
        // (c ? x,z : y,z) -> (c ? x : y),z
        return commaOp(
            pos,
            optimizeExpressionFlow(
                Operation.createTernary(c, opt.aReduced, opt.bReduced)),
            opt.commonTail);
      }
    }
    ternaryOperands[0] = c;
    ternaryOperands[1] = x;
    ternaryOperands[2] = y;
    if (x instanceof Operation && y instanceof Operation) {
      Operation xop = (Operation) x;
      Operation yop = (Operation) y;
      Operator xoper = xop.getOperator();
      if (xoper == yop.getOperator()) {
        List<? extends Expression> xoperands = xop.children();
        List<? extends Expression> yoperands = yop.children();
        int nOperands = xoperands.size();
        if (nOperands == yoperands.size()) {
          Expression xoperand0 = xoperands.get(0);
          // We can often pull the rightmost operand out since it would be
          // evaluated last regardless.
View Full Code Here

TOP

Related Classes of com.google.caja.parser.js.Operation

Copyright © 2018 www.massapicom. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.