ExpressionPtr
BinaryOpExpression::foldConstRightAssoc(AnalysisResultPtr ar) {
  ExpressionPtr optExp1;
  switch (m_op) {
  case '.':
  case '+':
  case '*':
    if (m_exp1->is(Expression::KindOfBinaryOpExpression)) {
      BinaryOpExpressionPtr binOpExp =
        dynamic_pointer_cast<BinaryOpExpression>(m_exp1);
      if (binOpExp->m_op == m_op) {
        // turn a Op b Op c, namely (a Op b) Op c into a Op (b Op c)
        ExpressionPtr aExp = binOpExp->m_exp1;
        ExpressionPtr bExp = binOpExp->m_exp2;
        ExpressionPtr cExp = m_exp2;
        BinaryOpExpressionPtr bcExp =
          BinaryOpExpressionPtr(new BinaryOpExpression(
                                  getScope(), getLocation(),
                                  Expression::KindOfBinaryOpExpression,
                                  bExp, cExp, m_op));
        ExpressionPtr optExp = bcExp->foldConst(ar);
        if (optExp) {
          BinaryOpExpressionPtr a_bcExp
            (new BinaryOpExpression(getScope(), getLocation(),
                                    Expression::KindOfBinaryOpExpression,
                                    aExp, optExp, m_op));
          optExp = a_bcExp->foldConstRightAssoc(ar);
          if (optExp) return optExp;
          else return a_bcExp;
        }
      }
    }
    break;
  default:
    break;
  }
  return ExpressionPtr();
}
Example #2
0
/**
 * If the binary operation is not PHP specific, but something a query
 * processor can handle (+ - * and so on), then rewrite the operands to
 * something the query processor can evaluate (such as a query parameter
 * references) and rewrite the entire expression to use the rewritten operands.
 * If the rewritten operands are the same as the original operands, just
 * return the expression as is.
 */
ExpressionPtr CaptureExtractor::rewriteBinary(BinaryOpExpressionPtr be) {
  assert(be != nullptr);
  switch (be->getOp()) {
    case '+':
    case '-':
    case '*':
    case '/':
    case '%':
    case '&':
    case '|':
    case '^':
    case T_IS_IDENTICAL:
    case T_IS_EQUAL:
    case '>':
    case '<':
    case T_IS_GREATER_OR_EQUAL:
    case T_IS_SMALLER_OR_EQUAL:
    case T_IS_NOT_IDENTICAL:
    case T_IS_NOT_EQUAL:
    case T_BOOLEAN_OR:
    case T_BOOLEAN_AND:
    case T_LOGICAL_OR:
    case T_LOGICAL_AND:
    case '.':
      break; // Could be something the query processor can handle

    default:
      return newQueryParamRef(be);
  }
  auto expr1 = be->getExp1();
  auto expr2 = be->getExp2();
  auto newExpr1 = rewrite(expr1);
  auto newExpr2 = rewrite(expr2);
  if (expr1 == newExpr1 && expr2 == newExpr2) return be;
  return
    std::make_shared<BinaryOpExpression>(
      be->getScope(), be->getRange(), newExpr1, newExpr2, be->getOp());
}
Example #3
0
void ExpressionList::stripConcat() {
    ExpressionList &el = *this;
    for (int i = 0; i < el.getCount(); ) {
        ExpressionPtr &e = el[i];
        if (e->is(Expression::KindOfUnaryOpExpression)) {
            UnaryOpExpressionPtr u(static_pointer_cast<UnaryOpExpression>(e));
            if (u->getOp() == '(') {
                e = u->getExpression();
            }
        }
        if (e->is(Expression::KindOfBinaryOpExpression)) {
            BinaryOpExpressionPtr b
            (static_pointer_cast<BinaryOpExpression>(e));
            if (b->getOp() == '.') {
                if (!b->getExp1()->isArray() && !b->getExp2()->isArray()) {
                    e = b->getExp1();
                    el.insertElement(b->getExp2(), i + 1);
                    continue;
                }
            }
        }
        i++;
    }
}
Example #4
0
// foldConst() is callable from the parse phase as well as the analysis phase.
// We take advantage of this during the parse phase to reduce very simple
// expressions down to a single scalar and keep the parse tree smaller,
// especially in cases of long chains of binary operators. However, we limit
// the effectivness of this during parse to ensure that we eliminate only
// very simple scalars that don't require analysis in later phases. For now,
// that's just simply scalar values.
ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) {
  ExpressionPtr optExp;
  Variant v1;
  Variant v2;

  if (!m_exp2->getScalarValue(v2)) {
    if ((ar->getPhase() != AnalysisResult::ParseAllFiles) &&
        m_exp1->isScalar() && m_exp1->getScalarValue(v1)) {
      switch (m_op) {
        case T_IS_IDENTICAL:
        case T_IS_NOT_IDENTICAL:
          if (v1.isNull()) {
            return makeIsNull(ar, getLocation(), m_exp2,
                              m_op == T_IS_NOT_IDENTICAL);
          }
          break;
        case T_LOGICAL_AND:
        case T_BOOLEAN_AND:
        case T_LOGICAL_OR:
        case T_BOOLEAN_OR: {
          ExpressionPtr rep =
            v1.toBoolean() == (m_op == T_LOGICAL_AND ||
                               m_op == T_BOOLEAN_AND) ? m_exp2 : m_exp1;
          rep = ExpressionPtr(
              new UnaryOpExpression(
                getScope(), getLocation(),
                rep, T_BOOL_CAST, true));
          rep->setActualType(Type::Boolean);
          return replaceValue(rep);
        }
        case '+':
        case '.':
        case '*':
        case '&':
        case '|':
        case '^':
          if (m_exp2->is(KindOfBinaryOpExpression)) {
            BinaryOpExpressionPtr binOpExp =
              dynamic_pointer_cast<BinaryOpExpression>(m_exp2);
            if (binOpExp->m_op == m_op && binOpExp->m_exp1->isScalar()) {
              ExpressionPtr aExp = m_exp1;
              ExpressionPtr bExp = binOpExp->m_exp1;
              ExpressionPtr cExp = binOpExp->m_exp2;
              if (aExp->isArray() || bExp->isArray() || cExp->isArray()) {
                break;
              }
              m_exp1 = binOpExp = Clone(binOpExp);
              m_exp2 = cExp;
              binOpExp->m_exp1 = aExp;
              binOpExp->m_exp2 = bExp;
              if (ExpressionPtr optExp = binOpExp->foldConst(ar)) {
                m_exp1 = optExp;
              }
              return static_pointer_cast<Expression>(shared_from_this());
            }
          }
        break;
        default:
          break;
      }
    }

    return ExpressionPtr();
  }

  if (m_exp1->isScalar()) {
    if (!m_exp1->getScalarValue(v1)) return ExpressionPtr();
    try {
      ScalarExpressionPtr scalar1 =
        dynamic_pointer_cast<ScalarExpression>(m_exp1);
      ScalarExpressionPtr scalar2 =
        dynamic_pointer_cast<ScalarExpression>(m_exp2);
      // Some data, like the values of __CLASS__ and friends, are not available
      // while we're still in the initial parse phase.
      if (ar->getPhase() == AnalysisResult::ParseAllFiles) {
        if ((scalar1 && scalar1->needsTranslation()) ||
            (scalar2 && scalar2->needsTranslation())) {
          return ExpressionPtr();
        }
      }
      if (!Option::WholeProgram || !Option::ParseTimeOpts) {
        // In the VM, don't optimize __CLASS__ if within a trait, since
        // __CLASS__ is not resolved yet.
        ClassScopeRawPtr clsScope = getOriginalClass();
        if (clsScope && clsScope->isTrait()) {
          if ((scalar1 && scalar1->getType() == T_CLASS_C) ||
              (scalar2 && scalar2->getType() == T_CLASS_C)) {
            return ExpressionPtr();
          }
        }
      }
      Variant result;
      switch (m_op) {
        case T_LOGICAL_XOR:
          result = static_cast<bool>(v1.toBoolean() ^ v2.toBoolean());
          break;
        case '|':
          *result.asCell() = cellBitOr(*v1.asCell(), *v2.asCell());
          break;
        case '&':
          *result.asCell() = cellBitAnd(*v1.asCell(), *v2.asCell());
          break;
        case '^':
          *result.asCell() = cellBitXor(*v1.asCell(), *v2.asCell());
          break;
        case '.':
          if (v1.isArray() || v2.isArray()) {
            return ExpressionPtr();
          }
          result = concat(v1.toString(), v2.toString());
          break;
        case T_IS_IDENTICAL:
          result = same(v1, v2);
          break;
        case T_IS_NOT_IDENTICAL:
          result = !same(v1, v2);
          break;
        case T_IS_EQUAL:
          result = equal(v1, v2);
          break;
        case T_IS_NOT_EQUAL:
          result = !equal(v1, v2);
          break;
        case '<':
          result = less(v1, v2);
          break;
        case T_IS_SMALLER_OR_EQUAL:
          result = cellLessOrEqual(*v1.asCell(), *v2.asCell());
          break;
        case '>':
          result = more(v1, v2);
          break;
        case T_IS_GREATER_OR_EQUAL:
          result = cellGreaterOrEqual(*v1.asCell(), *v2.asCell());
          break;
        case '+':
          *result.asCell() = cellAdd(*v1.asCell(), *v2.asCell());
          break;
        case '-':
          *result.asCell() = cellSub(*v1.asCell(), *v2.asCell());
          break;
        case '*':
          *result.asCell() = cellMul(*v1.asCell(), *v2.asCell());
          break;
        case '/':
          if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
            return ExpressionPtr();
          }
          *result.asCell() = cellDiv(*v1.asCell(), *v2.asCell());
          break;
        case '%':
          if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
            return ExpressionPtr();
          }
          *result.asCell() = cellMod(*v1.asCell(), *v2.asCell());
          break;
        case T_SL:
          result = v1.toInt64() << v2.toInt64();
          break;
        case T_SR:
          result = v1.toInt64() >> v2.toInt64();
          break;
        case T_BOOLEAN_OR:
          result = v1.toBoolean() || v2.toBoolean(); break;
        case T_BOOLEAN_AND:
          result = v1.toBoolean() && v2.toBoolean(); break;
        case T_LOGICAL_OR:
          result = v1.toBoolean() || v2.toBoolean(); break;
        case T_LOGICAL_AND:
          result = v1.toBoolean() && v2.toBoolean(); break;
        case T_INSTANCEOF: {
          if (v2.isString()) {
            if (v1.isArray() &&
                interface_supports_array(v2.getStringData())) {
              result = true;
              break;
            }
            if (v1.isString() &&
                interface_supports_string(v2.getStringData())) {
              result = true;
              break;
            }
            if (v1.isInteger() &&
                interface_supports_int(v2.getStringData())) {
              result = true;
              break;
            }
            if (v1.isDouble() &&
                interface_supports_double(v2.getStringData())) {
              result = true;
              break;
            }
          }
          result = false;
          break;
        }
        default:
          return ExpressionPtr();
      }
      return makeScalarExpression(ar, result);
    } catch (...) {
    }
  } else if (ar->getPhase() != AnalysisResult::ParseAllFiles) {
bool StatementList::mergeConcatAssign() {
  if (Option::LocalCopyProp) {
    return false;
  } else {
    // check for vector string concat assignment such as
    //   $space = " ";
    //   $a .= "hello";
    //   $a .= $space;
    //   $a .= "world!";
    // turn into (for constant folding and concat sequence)
    //   $a .= " " . "hello " . $space . "world!";
    unsigned int i = 0;
    bool merged = false;
    do {
      std::string lhsName;
      int length = 0;
      for (; i < m_stmts.size(); i++) {
        StatementPtr stmt = m_stmts[i];
        if (!stmt->is(Statement::KindOfExpStatement)) break;
        ExpStatementPtr expStmt = dynamic_pointer_cast<ExpStatement>(stmt);
        ExpressionPtr exp = expStmt->getExpression();

        // check the first assignment
        if (exp->is(Expression::KindOfAssignmentExpression)) {
          AssignmentExpressionPtr assignment_exp =
            dynamic_pointer_cast<AssignmentExpression>(exp);
          ExpressionPtr variable = assignment_exp->getVariable();
          ExpressionPtr value = assignment_exp->getValue();
          std::string variableName = variable->getText();
          if (variableName.find("->") != std::string::npos) break;
          if (value->hasEffect()) break;
          // cannot turn $a .= $b; a .= $a into $a .= $b . $a;
          if (value->getText().find(variableName) != std::string::npos) break;
          if (lhsName.empty()) {
            lhsName = variable->getText();
            length++;
            continue;
          } else {
            break;
          }
        } else if (!exp->is(Expression::KindOfBinaryOpExpression)) {
          break;
        }
        BinaryOpExpressionPtr binaryOpExp =
          dynamic_pointer_cast<BinaryOpExpression>(exp);
        if (binaryOpExp->getOp() != T_CONCAT_EQUAL) break;
        ExpressionPtr exp1 = binaryOpExp->getExp1();
        std::string exp1Text = exp1->getText();
        if (exp1Text.find("->") != std::string::npos) break;
        ExpressionPtr exp2 = binaryOpExp->getExp2();
        if (exp2->hasEffect()) break;
        if (exp2->getText().find(exp1Text) != std::string::npos) break;
        if (lhsName.empty()) {
          lhsName = exp1Text;
          length++;
        } else if (lhsName == exp1Text) {
          length++;
        } else {
          break;
        }
      }
      if (length > 1) {
        // replace m_stmts[j] to m_stmts[i - 1] with a new statement
        unsigned j = i - length;
        ExpStatementPtr expStmt;
        ExpressionPtr exp;
        BinaryOpExpressionPtr binaryOpExp;
        ExpressionPtr var;
        ExpressionPtr exp1;
        ExpressionPtr exp2;
        bool isAssignment = false;
        expStmt = dynamic_pointer_cast<ExpStatement>(m_stmts[j++]);
        exp = expStmt->getExpression();
        if (exp->is(Expression::KindOfAssignmentExpression)) {
          isAssignment = true;
          AssignmentExpressionPtr assignment_exp =
            dynamic_pointer_cast<AssignmentExpression>(exp);
          var = assignment_exp->getVariable();
          exp1 = assignment_exp->getValue();
        } else {
          binaryOpExp = dynamic_pointer_cast<BinaryOpExpression>(exp);
          var = binaryOpExp->getExp1();
          exp1 = binaryOpExp->getExp2();
        }

        for (; j < i; j++) {
          expStmt = dynamic_pointer_cast<ExpStatement>(m_stmts[j]);
          exp = expStmt->getExpression();
          binaryOpExp = dynamic_pointer_cast<BinaryOpExpression>(exp);
          exp2 = binaryOpExp->getExp2();
          exp1 = BinaryOpExpressionPtr
            (new BinaryOpExpression(getScope(), getLocation(),
                                    Expression::KindOfBinaryOpExpression,
                                    exp1, exp2, '.'));
        }
        if (isAssignment) {
          exp = AssignmentExpressionPtr
            (new AssignmentExpression(exp->getScope(), exp->getLocation(),
                                      Expression::KindOfAssignmentExpression,
                                      var, exp1,
                                      false));
        } else {
          exp = BinaryOpExpressionPtr
            (new BinaryOpExpression(getScope(), getLocation(),
                                    Expression::KindOfBinaryOpExpression,
                                    var, exp1, T_CONCAT_EQUAL));
        }
        expStmt = ExpStatementPtr
          (new ExpStatement(getScope(), getLocation(),
                            Statement::KindOfExpStatement, exp));

        m_stmts[i - length] = expStmt;
        for (j = i - (length - 1); i > j; i--) removeElement(j);
        merged = true;
      } else if (length == 0) {
        i++;
      }
    } while (i < m_stmts.size());
    return merged;
  }
}
// foldConst() is callable from the parse phase as well as the analysis phase.
// We take advantage of this during the parse phase to reduce very simple
// expressions down to a single scalar and keep the parse tree smaller,
// especially in cases of long chains of binary operators. However, we limit
// the effectivness of this during parse to ensure that we eliminate only
// very simple scalars that don't require analysis in later phases. For now,
// that's just simply scalar values.
ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) {
  ExpressionPtr optExp;
  Variant v1;
  Variant v2;

  if (!m_exp2->getScalarValue(v2)) {
    if ((ar->getPhase() != AnalysisResult::ParseAllFiles) &&
        m_exp1->isScalar() && m_exp1->getScalarValue(v1)) {
      switch (m_op) {
        case T_IS_IDENTICAL:
        case T_IS_NOT_IDENTICAL:
          if (v1.isNull()) {
            return makeIsNull(ar, getLocation(), m_exp2,
                              m_op == T_IS_NOT_IDENTICAL);
          }
          break;
        case T_LOGICAL_AND:
        case T_BOOLEAN_AND:
        case T_LOGICAL_OR:
        case T_BOOLEAN_OR: {
          ExpressionPtr rep =
            v1.toBoolean() == (m_op == T_LOGICAL_AND ||
                               m_op == T_BOOLEAN_AND) ? m_exp2 : m_exp1;
          rep = ExpressionPtr(
              new UnaryOpExpression(
                getScope(), getLocation(),
                rep, T_BOOL_CAST, true));
          rep->setActualType(Type::Boolean);
          return replaceValue(rep);
        }
        case '+':
        case '.':
        case '*':
        case '&':
        case '|':
        case '^':
          if (m_exp2->is(KindOfBinaryOpExpression)) {
            BinaryOpExpressionPtr binOpExp =
              dynamic_pointer_cast<BinaryOpExpression>(m_exp2);
            if (binOpExp->m_op == m_op && binOpExp->m_exp1->isScalar()) {
              ExpressionPtr aExp = m_exp1;
              ExpressionPtr bExp = binOpExp->m_exp1;
              ExpressionPtr cExp = binOpExp->m_exp2;
              m_exp1 = binOpExp = Clone(binOpExp);
              m_exp2 = cExp;
              binOpExp->m_exp1 = aExp;
              binOpExp->m_exp2 = bExp;
              if (ExpressionPtr optExp = binOpExp->foldConst(ar)) {
                m_exp1 = optExp;
              }
              return static_pointer_cast<Expression>(shared_from_this());
            }
          }
        break;
        default:
          break;
      }
    }

    return ExpressionPtr();
  }

  if (m_exp1->isScalar()) {
    if (!m_exp1->getScalarValue(v1)) return ExpressionPtr();
    try {
      ScalarExpressionPtr scalar1 =
        dynamic_pointer_cast<ScalarExpression>(m_exp1);
      ScalarExpressionPtr scalar2 =
        dynamic_pointer_cast<ScalarExpression>(m_exp2);
      // Some data, like the values of __CLASS__ and friends, are not available
      // while we're still in the initial parse phase.
      if (ar->getPhase() == AnalysisResult::ParseAllFiles) {
        if ((scalar1 && scalar1->needsTranslation()) ||
            (scalar2 && scalar2->needsTranslation())) {
          return ExpressionPtr();
        }
      }
      if (!Option::WholeProgram || !Option::ParseTimeOpts) {
        // In the VM, don't optimize __CLASS__ if within a trait, since
        // __CLASS__ is not resolved yet.
        ClassScopeRawPtr clsScope = getOriginalClass();
        if (clsScope && clsScope->isTrait()) {
          if ((scalar1 && scalar1->getType() == T_CLASS_C) ||
              (scalar2 && scalar2->getType() == T_CLASS_C)) {
            return ExpressionPtr();
          }
        }
      }
      Variant result;
      switch (m_op) {
        case T_LOGICAL_XOR:
          result = logical_xor(v1, v2); break;
        case '|':
          result = bitwise_or(v1, v2); break;
        case '&':
          result = bitwise_and(v1, v2); break;
        case '^':
          result = bitwise_xor(v1, v2); break;
        case '.':
          result = concat(v1, v2); break;
        case T_IS_IDENTICAL:
          result = same(v1, v2); break;
        case T_IS_NOT_IDENTICAL:
          result = !same(v1, v2); break;
        case T_IS_EQUAL:
          result = equal(v1, v2); break;
        case T_IS_NOT_EQUAL:
          result = !equal(v1, v2); break;
        case '<':
          result = less(v1, v2); break;
        case T_IS_SMALLER_OR_EQUAL:
          result = less_or_equal(v1, v2); break;
        case '>':
          result = more(v1, v2); break;
        case T_IS_GREATER_OR_EQUAL:
          result = more_or_equal(v1, v2); break;
        case '+':
          result = plus(v1, v2); break;
        case '-':
          result = minus(v1, v2); break;
        case '*':
          result = multiply(v1, v2); break;
        case '/':
          if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
            return ExpressionPtr();
          }
          result = divide(v1, v2); break;
        case '%':
          if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
            return ExpressionPtr();
          }
          result = modulo(v1, v2); break;
        case T_SL:
          result = shift_left(v1, v2); break;
        case T_SR:
          result = shift_right(v1, v2); break;
        case T_BOOLEAN_OR:
          result = v1 || v2; break;
        case T_BOOLEAN_AND:
          result = v1 && v2; break;
        case T_LOGICAL_OR:
          result = v1 || v2; break;
        case T_LOGICAL_AND:
          result = v1 && v2; break;
        case T_INSTANCEOF:
          result = false; break;
        default:
          return ExpressionPtr();
      }
      return makeScalarExpression(ar, result);
    } catch (...) {
    }
  } else if (ar->getPhase() != AnalysisResult::ParseAllFiles) {
    switch (m_op) {
      case T_LOGICAL_AND:
      case T_BOOLEAN_AND:
      case T_LOGICAL_OR:
      case T_BOOLEAN_OR: {
        bool useFirst = v2.toBoolean() == (m_op == T_LOGICAL_AND ||
                                           m_op == T_BOOLEAN_AND);
        ExpressionPtr rep = useFirst ? m_exp1 : m_exp2;
        rep = ExpressionPtr(
          new UnaryOpExpression(
            getScope(), getLocation(),
            rep, T_BOOL_CAST, true));
        rep->setActualType(Type::Boolean);
        if (!useFirst) {
          ExpressionListPtr l(
            new ExpressionList(
              getScope(), getLocation(),
              ExpressionList::ListKindComma));
          l->addElement(m_exp1);
          l->addElement(rep);
          l->setActualType(Type::Boolean);
          rep = l;
        }
        rep->setExpectedType(getExpectedType());
        return replaceValue(rep);
      }
      case T_LOGICAL_XOR:
      case '|':
      case '&':
      case '^':
      case '.':
      case '+':
      case '*':
        optExp = foldRightAssoc(ar);
        if (optExp) return optExp;
        break;
      case T_IS_IDENTICAL:
      case T_IS_NOT_IDENTICAL:
        if (v2.isNull()) {
          return makeIsNull(ar, getLocation(), m_exp1,
                            m_op == T_IS_NOT_IDENTICAL);
        }
        break;
      default:
        break;
    }
  }
  return ExpressionPtr();
}
ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) {
    ExpressionPtr optExp;
    Variant v1;
    Variant v2;

    if (!m_exp2->getScalarValue(v2)) {
        if (m_exp1->isScalar() && m_exp1->getScalarValue(v1)) {
            switch (m_op) {
            case T_IS_IDENTICAL:
            case T_IS_NOT_IDENTICAL:
                if (v1.isNull()) {
                    return makeIsNull(ar, getLocation(), m_exp2,
                                      m_op == T_IS_NOT_IDENTICAL);
                }
                break;
            case T_LOGICAL_AND:
            case T_BOOLEAN_AND:
            case T_LOGICAL_OR:
            case T_BOOLEAN_OR: {
                ExpressionPtr rep =
                    v1.toBoolean() == (m_op == T_LOGICAL_AND ||
                                       m_op == T_BOOLEAN_AND) ? m_exp2 : m_exp1;
                rep = ExpressionPtr(
                          new UnaryOpExpression(
                              getScope(), getLocation(),
                              rep, T_BOOL_CAST, true));
                rep->setActualType(Type::Boolean);
                return replaceValue(rep);
            }
            case '+':
            case '.':
            case '*':
            case '&':
            case '|':
            case '^':
                if (m_exp2->is(KindOfBinaryOpExpression)) {
                    BinaryOpExpressionPtr binOpExp =
                        dynamic_pointer_cast<BinaryOpExpression>(m_exp2);
                    if (binOpExp->m_op == m_op && binOpExp->m_exp1->isScalar()) {
                        ExpressionPtr aExp = m_exp1;
                        ExpressionPtr bExp = binOpExp->m_exp1;
                        ExpressionPtr cExp = binOpExp->m_exp2;
                        m_exp1 = binOpExp = Clone(binOpExp);
                        m_exp2 = cExp;
                        binOpExp->m_exp1 = aExp;
                        binOpExp->m_exp2 = bExp;
                        if (ExpressionPtr optExp = binOpExp->foldConst(ar)) {
                            m_exp1 = optExp;
                        }
                        return static_pointer_cast<Expression>(shared_from_this());
                    }
                }
                break;
            default:
                break;
            }
        }

        return ExpressionPtr();
    }

    if (m_exp1->isScalar()) {
        if (!m_exp1->getScalarValue(v1)) return ExpressionPtr();
        try {
            Variant result;
            switch (m_op) {
            case T_LOGICAL_XOR:
                result = logical_xor(v1, v2);
                break;
            case '|':
                result = bitwise_or(v1, v2);
                break;
            case '&':
                result = bitwise_and(v1, v2);
                break;
            case '^':
                result = bitwise_xor(v1, v2);
                break;
            case '.':
                result = concat(v1, v2);
                break;
            case T_IS_IDENTICAL:
                result = same(v1, v2);
                break;
            case T_IS_NOT_IDENTICAL:
                result = !same(v1, v2);
                break;
            case T_IS_EQUAL:
                result = equal(v1, v2);
                break;
            case T_IS_NOT_EQUAL:
                result = !equal(v1, v2);
                break;
            case '<':
                result = less(v1, v2);
                break;
            case T_IS_SMALLER_OR_EQUAL:
                result = not_more(v1, v2);
                break;
            case '>':
                result = more(v1, v2);
                break;
            case T_IS_GREATER_OR_EQUAL:
                result = not_less(v1, v2);
                break;
            case '+':
                result = plus(v1, v2);
                break;
            case '-':
                result = minus(v1, v2);
                break;
            case '*':
                result = multiply(v1, v2);
                break;
            case '/':
                if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
                    return ExpressionPtr();
                }
                result = divide(v1, v2);
                break;
            case '%':
                if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
                    return ExpressionPtr();
                }
                result = modulo(v1, v2);
                break;
            case T_SL:
                result = shift_left(v1, v2);
                break;
            case T_SR:
                result = shift_right(v1, v2);
                break;
            case T_BOOLEAN_OR:
                result = v1 || v2;
                break;
            case T_BOOLEAN_AND:
                result = v1 && v2;
                break;
            case T_LOGICAL_OR:
                result = v1 || v2;
                break;
            case T_LOGICAL_AND:
                result = v1 && v2;
                break;
            case T_INSTANCEOF:
                result = false;
                break;
            default:
                return ExpressionPtr();
            }
            return makeScalarExpression(ar, result);
        } catch (...) {
        }
    } else {
        switch (m_op) {
        case T_LOGICAL_AND:
        case T_BOOLEAN_AND:
        case T_LOGICAL_OR:
        case T_BOOLEAN_OR: {
            bool useFirst = v2.toBoolean() == (m_op == T_LOGICAL_AND ||
                                               m_op == T_BOOLEAN_AND);
            ExpressionPtr rep = useFirst ? m_exp1 : m_exp2;
            rep = ExpressionPtr(
                      new UnaryOpExpression(
                          getScope(), getLocation(),
                          rep, T_BOOL_CAST, true));
            rep->setActualType(Type::Boolean);
            if (!useFirst) {
                ExpressionListPtr l(
                    new ExpressionList(
                        getScope(), getLocation(),
                        ExpressionList::ListKindComma));
                l->addElement(m_exp1);
                l->addElement(rep);
                l->setActualType(Type::Boolean);
                rep = l;
            }
            rep->setExpectedType(getExpectedType());
            return replaceValue(rep);
        }
        case T_LOGICAL_XOR:
        case '|':
        case '&':
        case '^':
        case '.':
        case '+':
        case '*':
            optExp = foldRightAssoc(ar);
            if (optExp) return optExp;
            break;
        case T_IS_IDENTICAL:
        case T_IS_NOT_IDENTICAL:
            if (v2.isNull()) {
                return makeIsNull(ar, getLocation(), m_exp1,
                                  m_op == T_IS_NOT_IDENTICAL);
            }
            break;
        default:
            break;
        }
    }
    return ExpressionPtr();
}
Example #8
0
ExpressionPtr AliasManager::canonicalizeNode(ExpressionPtr e) {
  e->setCanonPtr(ExpressionPtr());
  e->setCanonID(0);

  switch (e->getKindOf()) {
  case Expression::KindOfObjectMethodExpression:
  case Expression::KindOfDynamicFunctionCall:
  case Expression::KindOfSimpleFunctionCall:
  case Expression::KindOfNewObjectExpression:
    add(m_bucketMap[0], e);
    break;

  case Expression::KindOfListAssignment:
    add(m_bucketMap[0], e);
    break;

  case Expression::KindOfAssignmentExpression: {
    AssignmentExpressionPtr ae = spc(AssignmentExpression,e);
    if (e->getContext() & Expression::DeadStore) {
      Construct::recomputeEffects();
      return ae->getValue();
    }
    ExpressionPtr rep;
    int interf = findInterf(ae->getVariable(), false, rep);
    if (interf == SameAccess) {
      switch (rep->getKindOf()) {
      default:
        break;
      case Expression::KindOfAssignmentExpression:
        {
          AssignmentExpressionPtr a = spc(AssignmentExpression, rep);
          ExpressionPtr value = a->getValue();
          if (a->getValue()->getContext() & Expression::RefValue) {
            break;
          }
        }
      case Expression::KindOfUnaryOpExpression:
      case Expression::KindOfBinaryOpExpression:
        rep->setContext(Expression::DeadStore);
        break;
      }
    }
    add(m_bucketMap[0], e);
    break;
  }

  case Expression::KindOfConstantExpression:
  case Expression::KindOfSimpleVariable:
  case Expression::KindOfDynamicVariable:
  case Expression::KindOfArrayElementExpression:
  case Expression::KindOfObjectPropertyExpression:
  case Expression::KindOfStaticMemberExpression:
    if (!(e->getContext() & (Expression::AssignmentLHS|
                             Expression::DeepAssignmentLHS|
                             Expression::OprLValue))) {
      if (!(e->getContext() & (Expression::LValue|
                               Expression::RefValue|
                               Expression::RefParameter|
                               Expression::UnsetContext))) {
        ExpressionPtr rep;
        int interf = findInterf(e, true, rep);
        if (interf == SameAccess) {
          if (rep->getKindOf() == e->getKindOf()) {
            e->setCanonID(rep->getCanonID());
            e->setCanonPtr(rep);
            return ExpressionPtr();
          }
          if (rep->getKindOf() == Expression::KindOfAssignmentExpression) {
            ExpressionPtr rhs = spc(AssignmentExpression,rep)->getValue();
            if (rhs->is(Expression::KindOfScalarExpression)) {
              rhs = rhs->clone();
              getCanonical(rhs);
              return rhs;
            }
            e->setCanonPtr(rhs);
          }
        }
      }
      add(m_bucketMap[0], e);
    } else {
      getCanonical(e);
    }
    break;

  case Expression::KindOfBinaryOpExpression: {
    BinaryOpExpressionPtr bop = spc(BinaryOpExpression, e);

    int rop = getOpForAssignmentOp(bop->getOp());
    if (rop) {
      ExpressionPtr lhs = bop->getExp1();
      ExpressionPtr rep;
      if (bop->getContext() & Expression::DeadStore) {
        Construct::recomputeEffects();
        ExpressionPtr rhs = bop->getExp2()->clone();
        lhs = lhs->clone();
        lhs->clearContext(Expression::LValue);
        lhs->clearContext(Expression::NoLValueWrapper);
        lhs->clearContext(Expression::OprLValue);
        rep = ExpressionPtr
          (new BinaryOpExpression(e->getLocation(),
                                  Expression::KindOfBinaryOpExpression,
                                  lhs, rhs, rop));

      } else {
        ExpressionPtr alt;
        int interf = findInterf(lhs, true, alt);
        if (interf == SameAccess &&
            alt->is(Expression::KindOfAssignmentExpression)) {
          ExpressionPtr op0 = spc(AssignmentExpression,alt)->getValue();
          if (op0->is(Expression::KindOfScalarExpression)) {
            ExpressionPtr op1 = bop->getExp2();
            ExpressionPtr rhs
              (new BinaryOpExpression(e->getLocation(),
                                      Expression::KindOfBinaryOpExpression,
                                      op0->clone(), op1->clone(), rop));

            lhs = lhs->clone();
            lhs->clearContext(Expression::OprLValue);
            rep = ExpressionPtr
              (new AssignmentExpression(e->getLocation(),
                                        Expression::KindOfAssignmentExpression,
                                        lhs, rhs, false));
          }
        }
      }
      if (rep) {
        ExpressionPtr c = canonicalizeRecur(rep);
        return c ? c : rep;
      }
      add(m_bucketMap[0], e);
    } else {
      getCanonical(e);
    }
    break;
  }

  case Expression::KindOfUnaryOpExpression:
    {
      UnaryOpExpressionPtr uop = spc(UnaryOpExpression, e);
      switch (uop->getOp()) {
      case T_INC:
      case T_DEC:
        if (uop->getContext() & Expression::DeadStore) {
          Construct::recomputeEffects();
          ExpressionPtr val = uop->getExpression()->clone();
          val->clearContext(Expression::LValue);
          val->clearContext(Expression::NoLValueWrapper);
          val->clearContext(Expression::OprLValue);
          if (uop->getFront()) {
            ExpressionPtr inc
              (new ScalarExpression(uop->getLocation(),
                                    Expression::KindOfScalarExpression,
                                    T_LNUMBER, string("1")));

            val = ExpressionPtr
              (new BinaryOpExpression(uop->getLocation(),
                                      Expression::KindOfBinaryOpExpression,
                                      val, inc,
                                      uop->getOp() == T_INC ? '+' : '-'));

          }

          ExpressionPtr r = canonicalizeRecur(val);
          return r ? r : val;
        }
        add(m_bucketMap[0], e);
        break;
      default:
        getCanonical(e);
        break;
      }
      break;
    }

  default:
    getCanonical(e);
    break;
  }

  return ExpressionPtr();
}