bool AssignmentExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
                                        int state) {
  if (m_variable->is(Expression::KindOfArrayElementExpression)) {
    ExpressionPtr exp = m_value;
    ExpressionPtr vv(
      static_pointer_cast<ArrayElementExpression>(m_variable)->getVariable());
    if ((vv->is(KindOfArrayElementExpression) ||
         vv->is(KindOfObjectPropertyExpression)) &&
        (vv->getContainedEffects() && (CreateEffect|AccessorEffect))) {
      /*
        We are in a case such as
          $a->b['c'] = ...;
          $a['b']['c'] = ...;
        Where evaluating m_variable may modify $a. Unless we can prove that
        the rhs is not referring to the same thing as $a, we must generate
        a temporary for it (note that we could do better with the following
        checks).
      */
      if (!(m_ref && exp->isRefable()) &&
          !exp->isTemporary() && !exp->isScalar() &&
          exp->getActualType() && !exp->getActualType()->isPrimitive() &&
          exp->getActualType()->getKindOf() != Type::KindOfString) {
        state |= Expression::StashAll;
      }
    }
  }

  return Expression::preOutputCPP(cg, ar, state);
}
static void wrapValue(CodeGenerator &cg, AnalysisResultPtr ar,
                      ExpressionPtr exp, bool ref, bool array, bool varnr) {
  bool close = false;
  if (ref) {
    cg_printf("ref(");
    close = true;
  } else if (array && !exp->hasCPPTemp() &&
             !exp->isTemporary() && !exp->isScalar() &&
             exp->getActualType() && !exp->getActualType()->isPrimitive() &&
             exp->getActualType()->getKindOf() != Type::KindOfString) {
    cg_printf("wrap_variant(");
    close = true;
  } else if (varnr && exp->getCPPType()->isExactType()) {
    bool isScalar = exp->isScalar();
    if (!isScalar || !Option::UseScalarVariant) {
      cg_printf("VarNR(");
      close = true;
    } else if (isScalar) {
      ASSERT(!cg.hasScalarVariant());
      cg.setScalarVariant();
    }
  }
  exp->outputCPP(cg, ar);
  cg.clearScalarVariant();
  if (close) cg_printf(")");
}
bool AssignmentExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
                                        int state) {
  if (m_variable->is(Expression::KindOfArrayElementExpression)) {
    ExpressionPtr exp = m_value;
    if (!(m_ref && exp->isRefable()) &&
        !exp->isTemporary() && !exp->isScalar() &&
        exp->getActualType() && !exp->getActualType()->isPrimitive() &&
        exp->getActualType()->getKindOf() != Type::KindOfString) {
      state |= Expression::StashAll;
    }
  }
  return Expression::preOutputCPP(cg, ar, state);
}
static void wrapValue(CodeGenerator &cg, AnalysisResultPtr ar,
                      ExpressionPtr exp, bool ref, bool array) {
  bool close = false;
  if (ref) {
    cg_printf("ref(");
    close = true;
  } else if (array && !exp->hasCPPTemp() &&
             !exp->isTemporary() && !exp->isScalar() &&
             exp->getActualType() && !exp->getActualType()->isPrimitive() &&
             exp->getActualType()->getKindOf() != Type::KindOfString) {
    cg_printf("wrap_variant(");
    close = true;
  }
  exp->outputCPP(cg, ar);
  if (close) cg_printf(")");
}
Exemplo n.º 5
0
bool ExpressionList::hasNonArrayCreateValue(
  bool arrayElements /* = true */, unsigned int start /* = 0 */) const {
  for (unsigned int i = start; i < m_exps.size(); i++) {
    ExpressionPtr value = m_exps[i];
    if (arrayElements) {
      ArrayPairExpressionPtr ap =
        dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]);
      value = ap->getValue();
    }
    ASSERT(value);
    if (value->hasContext(RefValue) ||
        (value->hasEffect() && !value->isTemporary())) {
      return true;
    }
  }
  return false;
}
Exemplo n.º 6
0
bool ExpressionList::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
                                  int state) {
  if (m_kind == ListKindParam && !m_arrayElements) {
    return Expression::preOutputCPP(cg, ar, state|StashKidVars);
  }

  unsigned n = m_exps.size();
  bool inExpression = cg.inExpression();
  if (!inExpression && (state & FixOrder)) {
    return true;
  }

  cg.setInExpression(false);
  bool ret = false;
  if (m_arrayElements) {
    /*
     * would like to do:
     *  ret = Expression::preOutputCPP(cg, ar, state);
     * but icc has problems with the generated code.
     */
    ret = hasEffect();
  } else if (n > 1 && m_kind == ListKindLeft) {
    ret = true;
  } else {
    for (unsigned int i = 0; i < n; i++) {
      if (m_exps[i]->preOutputCPP(cg, ar, 0)) {
        ret = true;
        break;
      }
    }
    if (!ret) {
      ExpressionPtr e = m_exps[n - 1];
      if (hasContext(LValue) && !hasAnyContext(RefValue|InvokeArgument) &&
          !(e->hasContext(LValue) &&
            !e->hasAnyContext(RefValue|InvokeArgument))) {
        ret = true;
      } else if (hasContext(RefValue) &&
                 !e->hasAllContext(LValue|ReturnContext) &&
                 !e->hasContext(RefValue)) {
        ret = true;
      }
    }
  }

  if (!inExpression) return ret;

  cg.setInExpression(true);
  if (!ret) {
    if (state & FixOrder) {
      preOutputStash(cg, ar, state);
      return true;
    }
    return false;
  }

  cg.wrapExpressionBegin();
  if (m_arrayElements) {
    setCPPTemp(genCPPTemp(cg, ar));
    outputCPPInternal(cg, ar, true, true);
  } else {
    unsigned ix = isUnused() ? (unsigned)-1 :
      m_kind == ListKindLeft ? 0 : n - 1;
    for (unsigned int i = 0; i < n; i++) {
      ExpressionPtr e = m_exps[i];
      e->preOutputCPP(cg, ar, i == ix ? state : 0);
      if (i != ix) {
        if (e->outputCPPUnneeded(cg, ar)) {
          cg_printf(";\n");
        }
        e->setCPPTemp("/**/");
        continue;
      }
      /*
        We inlined a by-value function into the rhs of a by-ref assignment.
      */
      bool noRef = hasContext(RefValue) &&
        !e->hasAllContext(LValue|ReturnContext) &&
        !e->hasContext(RefValue) &&
        !e->isTemporary() &&
        Type::IsMappedToVariant(e->getActualType());
      /*
        If we need a non-const reference, but the expression is
        going to generate a const reference, fix it
      */
      bool lvSwitch =
        hasContext(LValue) && !hasAnyContext(RefValue|InvokeArgument) &&
        !(e->hasContext(LValue) &&
          !e->hasAnyContext(RefValue|InvokeArgument));

      if (e->hasAllContext(LValue|ReturnContext) && i + 1 == n) {
        e->clearContext(ReturnContext);
      }

      if (noRef || lvSwitch || (!i && n > 1)) {
        e->Expression::preOutputStash(cg, ar, state | FixOrder | StashAll);
        if (!(state & FixOrder)) {
          cg_printf("id(%s);\n", e->cppTemp().c_str());
        }
      }
      if (e->hasCPPTemp() &&
          Type::SameType(e->getGenType(), getGenType())) {
        string t = e->cppTemp();
        if (noRef) {
          cg_printf("CVarRef %s_nr = wrap_variant(%s);\n",
                    t.c_str(), t.c_str());
          t += "_nr";
        }

        if (lvSwitch) {
          cg_printf("Variant &%s_lv = const_cast<Variant&>(%s);\n",
                    t.c_str(), t.c_str());
          t += "_lv";
        }
        setCPPTemp(t);
      }
    }
  }
  return true;
}