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); }
int BinaryOpExpression::getConcatList(ExpressionPtrVec &ev, ExpressionPtr exp, bool &hasVoid) { if (!exp->hasCPPTemp()) { if (exp->is(Expression::KindOfUnaryOpExpression)) { UnaryOpExpressionPtr u = static_pointer_cast<UnaryOpExpression>(exp); if (u->getOp() == '(') { return getConcatList(ev, u->getExpression(), hasVoid); } } else if (exp->is(Expression::KindOfBinaryOpExpression)) { BinaryOpExpressionPtr b = static_pointer_cast<BinaryOpExpression>(exp); if (b->getOp() == '.') { if (b->getExp1()->is(Expression::KindOfSimpleVariable) && b->getExp1()->isLocalExprAltered() && !b->getExp1()->hasCPPTemp() && b->getExp2()->hasEffect() && !b->getExp2()->hasCPPTemp()) { /* In this case, the simple variable must be evaluated after b->getExp2(). But when we output a concat list we explicitly order the expressions from left to right. */ } else { return getConcatList(ev, b->getExp1(), hasVoid) + getConcatList(ev, b->getExp2(), hasVoid); } } } else if (exp->is(Expression::KindOfEncapsListExpression)) { EncapsListExpressionPtr e = static_pointer_cast<EncapsListExpression>(exp); if (e->getType() != '`') { ExpressionListPtr el = e->getExpressions(); int num = 0; for (int i = 0, s = el->getCount(); i < s; i++) { ExpressionPtr exp = (*el)[i]; num += getConcatList(ev, exp, hasVoid); } return num; } } } else if (!exp->getActualType()) { return 0; } ev.push_back(exp); bool isVoid = !exp->getActualType(); hasVoid |= isVoid; return isVoid ? 0 : 1; }
int BinaryOpExpression::getConcatList(ExpressionPtrVec &ev, ExpressionPtr exp, bool &hasVoid) { if (!exp->hasCPPTemp()) { if (exp->is(Expression::KindOfUnaryOpExpression)) { UnaryOpExpressionPtr u = static_pointer_cast<UnaryOpExpression>(exp); if (u->getOp() == '(') { return getConcatList(ev, u->getExpression(), hasVoid); } } else if (exp->is(Expression::KindOfBinaryOpExpression)) { BinaryOpExpressionPtr b = static_pointer_cast<BinaryOpExpression>(exp); if (b->getOp() == '.') { return getConcatList(ev, b->getExp1(), hasVoid) + getConcatList(ev, b->getExp2(), hasVoid); } } else if (exp->is(Expression::KindOfEncapsListExpression)) { EncapsListExpressionPtr e = static_pointer_cast<EncapsListExpression>(exp); if (e->getType() != '`') { ExpressionListPtr el = e->getExpressions(); int num = 0; for (int i = 0, s = el->getCount(); i < s; i++) { ExpressionPtr exp = (*el)[i]; num += getConcatList(ev, exp, hasVoid); } return num; } } } ev.push_back(exp); bool isVoid = !exp->getActualType(); hasVoid |= isVoid; return isVoid ? 0 : 1; }
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(")"); }
void QOpExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (!m_cppValue.empty()) { cg_printf("%s", m_cppValue.c_str()); } else { ExpressionPtr expYes = m_expYes ? m_expYes : m_condition; bool wrapped = !isUnused(); if (wrapped) { cg_printf("("); } wrapBoolean(cg, ar, m_condition); if (isUnused()) { cg_printf(" ? "); outputUnneededExpr(cg, ar, expYes); cg_printf(" : "); outputUnneededExpr(cg, ar, m_expNo); } else { TypePtr typeYes = expYes->getActualType(); TypePtr typeNo = m_expNo->getActualType(); const char *castType = typeYes && typeNo && Type::SameType(typeYes, typeNo) && !typeYes->is(Type::KindOfVariant) && expYes->isLiteralString() == m_expNo->isLiteralString() ? "" : "(Variant)"; cg_printf(" ? (%s(", castType); expYes->outputCPP(cg, ar); cg_printf(")) : (%s(", castType); m_expNo->outputCPP(cg, ar); cg_printf("))"); } if (wrapped) { cg_printf(")"); } } }
TypePtr AssignmentExpression:: inferTypesImpl(AnalysisResultPtr ar, TypePtr type, bool coerce, ExpressionPtr variable, ExpressionPtr value /* = ExpressionPtr() */) { TypePtr ret = type; if (value) { if (coerce) { ret = value->inferAndCheck(ar, type, coerce); } else { ret = value->inferAndCheck(ar, NEW_TYPE(Some), coerce); } } BlockScopePtr scope = ar->getScope(); if (variable->is(Expression::KindOfConstantExpression)) { // ...as in ClassConstant statement ConstantExpressionPtr exp = dynamic_pointer_cast<ConstantExpression>(variable); bool p; scope->getConstants()->check(exp->getName(), ret, true, ar, variable, p); } else if (variable->is(Expression::KindOfDynamicVariable)) { // simptodo: not too sure about this ar->getFileScope()->setAttribute(FileScope::ContainsLDynamicVariable); } else if (variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable); if (var->getName() == "this" && ar->getClassScope()) { if (ar->isFirstPass()) { ar->getCodeError()->record(variable, CodeError::ReassignThis, variable); } } if (ar->getPhase() == AnalysisResult::LastInference && value) { if (!value->getExpectedType()) { value->setExpectedType(variable->getActualType()); } } } // if the value may involve object, consider the variable as "referenced" // so that objects are not destructed prematurely. bool referenced = true; if (value && value->isScalar()) referenced = false; if (ret && ret->isNoObjectInvolved()) referenced = false; if (referenced && variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable); const std::string &name = var->getName(); VariableTablePtr variables = ar->getScope()->getVariables(); variables->addReferenced(name); } TypePtr vt = variable->inferAndCheck(ar, ret, true); if (!coerce && type->is(Type::KindOfAny)) { ret = vt; } return ret; }
bool Expression::CheckNeededRHS(ExpressionPtr value) { bool needed = true; always_assert(value); while (value->is(KindOfAssignmentExpression)) { value = dynamic_pointer_cast<AssignmentExpression>(value)->getValue(); } if (value->isScalar()) { needed = false; } else { TypePtr type = value->getType(); if (type && (type->is(Type::KindOfSome) || type->is(Type::KindOfAny))) { type = value->getActualType(); } if (type && type->isNoObjectInvolved()) needed = false; } return needed; }
void UnaryOpExpression::SetExpTypeForExistsContext(AnalysisResultPtr ar, ExpressionPtr e, bool allowPrimitives) { if (!e) return; TypePtr at(e->getActualType()); if (!allowPrimitives && at && at->isExactType() && at->isPrimitive()) { at = e->inferAndCheck(ar, Type::Variant, true); } TypePtr it(e->getImplementedType()); TypePtr et(e->getExpectedType()); if (et && et->is(Type::KindOfVoid)) e->setExpectedType(TypePtr()); if (at && (!it || Type::IsMappedToVariant(it)) && ((allowPrimitives && Type::HasFastCastMethod(at)) || (!allowPrimitives && (at->is(Type::KindOfObject) || at->is(Type::KindOfArray) || at->is(Type::KindOfString))))) { e->setExpectedType(it ? at : TypePtr()); } }
static bool checkCopyElision(FunctionScopePtr func, ExpressionPtr exp) { if (!exp->getType()->is(Type::KindOfVariant) || func->isRefReturn()) { return false; } TypePtr imp = exp->getImplementedType(); if (!imp) imp = exp->getActualType(); if (!imp || !imp->is(Type::KindOfVariant)) return false; if (func->getNRVOFix() && exp->is(Expression::KindOfSimpleVariable)) { return true; } if (FunctionCallPtr fc = dynamic_pointer_cast<FunctionCall>(exp)) { FunctionScopePtr fs = fc->getFuncScope(); if (!fs || fs->isRefReturn()) { return true; } } return false; }
static void outputStringExpr(CodeGenerator &cg, AnalysisResultPtr ar, ExpressionPtr exp, bool asLitStr) { if (asLitStr && exp->isLiteralString()) { const std::string &s = exp->getLiteralString(); char *enc = string_cplus_escape(s.c_str(), s.size()); cg_printf("\"%s\", %d", enc, s.size()); free(enc); return; } bool close = false; if ((exp->hasContext(Expression::LValue) && (!exp->getActualType()->is(Type::KindOfString) || (exp->getImplementedType() && !exp->getImplementedType()->is(Type::KindOfString)))) || !exp->getType()->is(Type::KindOfString)) { cg_printf("toString("); close = true; } exp->outputCPP(cg, ar); if (close) cg_printf(")"); }
void BinaryOpExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (isOpEqual() && outputCPPImplOpEqual(cg, ar)) return; bool wrapped = true; switch (m_op) { case T_CONCAT_EQUAL: if (const char *prefix = stringBufferPrefix(cg, ar, m_exp1)) { SimpleVariablePtr sv = static_pointer_cast<SimpleVariable>(m_exp1); ExpressionPtrVec ev; bool hasVoid = false; getConcatList(ev, m_exp2, hasVoid); cg_printf("%s", stringBufferName(Option::TempPrefix, prefix, sv->getName().c_str()).c_str()); outputStringBufExprs(ev, cg, ar); return; } cg_printf("concat_assign"); break; case '.': { ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this()); ExpressionPtrVec ev; bool hasVoid = false; int num = getConcatList(ev, self, hasVoid); assert(!hasVoid); if (num <= MAX_CONCAT_ARGS) { assert(num >= 2); if (num == 2) { cg_printf("concat("); } else { if (num > MAX_CONCAT_ARGS) ar->m_concatLengths.insert(num); cg_printf("concat%d(", num); } for (size_t i = 0; i < ev.size(); i++) { ExpressionPtr exp = ev[i]; if (i) cg_printf(", "); outputStringExpr(cg, ar, exp, false); } cg_printf(")"); } else { cg_printf("StringBuffer()"); outputStringBufExprs(ev, cg, ar); cg_printf(".detach()"); } } return; case T_LOGICAL_XOR: cg_printf("logical_xor"); break; case '|': cg_printf("bitwise_or"); break; case '&': cg_printf("bitwise_and"); break; case '^': cg_printf("bitwise_xor"); break; case T_IS_IDENTICAL: cg_printf("same"); break; case T_IS_NOT_IDENTICAL: cg_printf("!same"); break; case T_IS_EQUAL: cg_printf("equal"); break; case T_IS_NOT_EQUAL: cg_printf("!equal"); break; case '<': cg_printf("less"); break; case T_IS_SMALLER_OR_EQUAL: cg_printf("not_more"); break; case '>': cg_printf("more"); break; case T_IS_GREATER_OR_EQUAL: cg_printf("not_less"); break; case '/': cg_printf("divide"); break; case '%': cg_printf("modulo"); break; case T_INSTANCEOF: cg_printf("instanceOf"); break; default: wrapped = !isUnused(); break; } if (wrapped) cg_printf("("); ExpressionPtr first = m_exp1; ExpressionPtr second = m_exp2; // we could implement these functions natively on String and Array classes switch (m_op) { case '+': case '-': case '*': case '/': if (!first->outputCPPArithArg(cg, ar, m_op == '+')) { TypePtr argType = first->hasCPPTemp() ? first->getType() : first->getActualType(); bool flag = castIfNeeded(getActualType(), argType, cg, ar, getScope()); first->outputCPP(cg, ar); if (flag) { cg_printf(")"); } } break; case T_SL: case T_SR: ASSERT(first->getType()->is(Type::KindOfInt64)); first->outputCPP(cg, ar); break; default: first->outputCPP(cg, ar); break; } switch (m_op) { case T_PLUS_EQUAL: cg_printf(" += "); break; case T_MINUS_EQUAL: cg_printf(" -= "); break; case T_MUL_EQUAL: cg_printf(" *= "); break; case T_DIV_EQUAL: cg_printf(" /= "); break; case T_MOD_EQUAL: cg_printf(" %%= "); break; case T_AND_EQUAL: cg_printf(" &= "); break; case T_OR_EQUAL: cg_printf(" |= "); break; case T_XOR_EQUAL: cg_printf(" ^= "); break; case T_SL_EQUAL: cg_printf(" <<= "); break; case T_SR_EQUAL: cg_printf(" >>= "); break; case T_BOOLEAN_OR: cg_printf(" || "); break; case T_BOOLEAN_AND: cg_printf(" && "); break; case T_LOGICAL_OR: cg_printf(" || "); break; case T_LOGICAL_AND: cg_printf(" && "); break; default: switch (m_op) { case '+': cg_printf(" + "); break; case '-': cg_printf(" - "); break; case '*': cg_printf(" * "); break; case T_SL: cg_printf(" << "); break; case T_SR: cg_printf(" >> "); break; default: cg_printf(", "); break; } break; } switch (m_op) { case '+': case '-': case '*': case '/': if (!second->outputCPPArithArg(cg, ar, m_op == '+')) { TypePtr argType = second->hasCPPTemp() ? second->getType() : second->getActualType(); bool flag = castIfNeeded(getActualType(), argType, cg, ar, getScope()); second->outputCPP(cg, ar); if (flag) { cg_printf(")"); } } break; case T_INSTANCEOF: { if (second->isScalar()) { ScalarExpressionPtr scalar = dynamic_pointer_cast<ScalarExpression>(second); bool notQuoted = scalar && !scalar->isQuoted(); std::string s = second->getLiteralString(); if (s == "static" && notQuoted) { cg_printf("FrameInjection::GetStaticClassName(fi.getThreadInfo())"); } else if (s != "") { if (s == "self" && notQuoted) { ClassScopeRawPtr cls = getOriginalClass(); if (cls) { s = cls->getOriginalName(); } } else if (s == "parent" && notQuoted) { ClassScopeRawPtr cls = getOriginalClass(); if (cls && !cls->getParent().empty()) { s = cls->getParent(); } } cg_printString(s, ar, shared_from_this()); } else { second->outputCPP(cg, ar); } } else { second->outputCPP(cg, ar); } break; } case T_PLUS_EQUAL: case T_MINUS_EQUAL: case T_MUL_EQUAL: { TypePtr t1 = first->getCPPType(); TypePtr t2 = second->getType(); if (t1 && !t1->is(Type::KindOfArray) && t2 && Type::IsCastNeeded(ar, t2, t1)) { t1->outputCPPCast(cg, ar, getScope()); cg_printf("("); second->outputCPP(cg, ar); cg_printf(")"); } else { second->outputCPP(cg, ar); } break; } case T_BOOLEAN_OR: case T_BOOLEAN_AND: case T_LOGICAL_AND: case T_LOGICAL_OR: if (isUnused()) { cg_printf("("); if (second->outputCPPUnneeded(cg, ar)) { cg_printf(","); } cg_printf("false)"); } else { second->outputCPP(cg, ar); } break; default: second->outputCPP(cg, ar); } if (wrapped) cg_printf(")"); }
void BinaryOpExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (isOpEqual() && outputCPPImplOpEqual(cg, ar)) return; bool wrapped = true; switch (m_op) { case T_CONCAT_EQUAL: if (const char *prefix = stringBufferPrefix(cg, ar, m_exp1)) { SimpleVariablePtr sv = static_pointer_cast<SimpleVariable>(m_exp1); ExpressionPtrVec ev; bool hasVoid = false; getConcatList(ev, m_exp2, hasVoid); cg_printf("%s", stringBufferName(Option::TempPrefix, prefix, sv->getName().c_str()).c_str()); outputStringBufExprs(ev, cg, ar); return; } cg_printf("concat_assign"); break; case '.': { ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this()); ExpressionPtrVec ev; bool hasVoid = false; int num = getConcatList(ev, self, hasVoid); assert(!hasVoid); if ((num <= MAX_CONCAT_ARGS || (Option::GenConcat && cg.getOutput() != CodeGenerator::SystemCPP))) { assert(num >= 2); if (num == 2) { cg_printf("concat("); } else { if (num > MAX_CONCAT_ARGS) ar->m_concatLengths.insert(num); cg_printf("concat%d(", num); } for (size_t i = 0; i < ev.size(); i++) { ExpressionPtr exp = ev[i]; if (i) cg_printf(", "); outputStringExpr(cg, ar, exp, false); } cg_printf(")"); } else { cg_printf("StringBuffer()"); outputStringBufExprs(ev, cg, ar); cg_printf(".detach()"); } } return; case T_LOGICAL_XOR: cg_printf("logical_xor"); break; case '|': cg_printf("bitwise_or"); break; case '&': cg_printf("bitwise_and"); break; case '^': cg_printf("bitwise_xor"); break; case T_IS_IDENTICAL: cg_printf("same"); break; case T_IS_NOT_IDENTICAL: cg_printf("!same"); break; case T_IS_EQUAL: cg_printf("equal"); break; case T_IS_NOT_EQUAL: cg_printf("!equal"); break; case '<': cg_printf("less"); break; case T_IS_SMALLER_OR_EQUAL: cg_printf("not_more"); break; case '>': cg_printf("more"); break; case T_IS_GREATER_OR_EQUAL: cg_printf("not_less"); break; case '/': cg_printf("divide"); break; case '%': cg_printf("modulo"); break; case T_INSTANCEOF: cg_printf("instanceOf"); break; default: wrapped = !isUnused(); break; } if (wrapped) cg_printf("("); ExpressionPtr first = m_exp1; ExpressionPtr second = m_exp2; // we could implement these functions natively on String and Array classes switch (m_op) { case '+': case '-': case '*': case '/': { TypePtr actualType = first->getActualType(); if (actualType && (actualType->is(Type::KindOfString) || (m_op != '+' && actualType->is(Type::KindOfArray)))) { cg_printf("(Variant)("); first->outputCPP(cg, ar); cg_printf(")"); } else { bool flag = castIfNeeded(getActualType(), actualType, cg, ar, getScope()); first->outputCPP(cg, ar); if (flag) { cg_printf(")"); } } break; } case T_SL: case T_SR: cg_printf("toInt64("); first->outputCPP(cg, ar); cg_printf(")"); break; default: first->outputCPP(cg, ar); break; } switch (m_op) { case T_PLUS_EQUAL: cg_printf(" += "); break; case T_MINUS_EQUAL: cg_printf(" -= "); break; case T_MUL_EQUAL: cg_printf(" *= "); break; case T_DIV_EQUAL: cg_printf(" /= "); break; case T_MOD_EQUAL: cg_printf(" %%= "); break; case T_AND_EQUAL: cg_printf(" &= "); break; case T_OR_EQUAL: cg_printf(" |= "); break; case T_XOR_EQUAL: cg_printf(" ^= "); break; case T_SL_EQUAL: cg_printf(" <<= "); break; case T_SR_EQUAL: cg_printf(" >>= "); break; case T_BOOLEAN_OR: cg_printf(" || "); break; case T_BOOLEAN_AND: cg_printf(" && "); break; case T_LOGICAL_OR: cg_printf(" || "); break; case T_LOGICAL_AND: cg_printf(" && "); break; default: switch (m_op) { case '+': cg_printf(" + "); break; case '-': cg_printf(" - "); break; case '*': cg_printf(" * "); break; case T_SL: cg_printf(" << "); break; case T_SR: cg_printf(" >> "); break; default: cg_printf(", "); break; } break; } switch (m_op) { case '+': case '-': case '*': case '/': { TypePtr actualType = second->getActualType(); if (actualType && (actualType->is(Type::KindOfString) || (m_op != '+' && actualType->is(Type::KindOfArray)))) { cg_printf("(Variant)("); second->outputCPP(cg, ar); cg_printf(")"); } else { bool flag = castIfNeeded(getActualType(), actualType, cg, ar, getScope()); second->outputCPP(cg, ar); if (flag) { cg_printf(")"); } } break; } case T_INSTANCEOF: { if (second->isScalar()) { std::string s = second->getLiteralString(); std::string sLower = Util::toLower(s); if (sLower != "") { cg_printString(sLower, ar, shared_from_this()); } else { second->outputCPP(cg, ar); } } else { second->outputCPP(cg, ar); } break; } case T_PLUS_EQUAL: case T_MINUS_EQUAL: case T_MUL_EQUAL: { TypePtr t1 = first->getCPPType(); TypePtr t2 = second->getType(); if (t1 && !t1->is(Type::KindOfArray) && t2 && Type::IsCastNeeded(ar, t2, t1)) { t1->outputCPPCast(cg, ar, getScope()); cg_printf("("); second->outputCPP(cg, ar); cg_printf(")"); } else { second->outputCPP(cg, ar); } break; } case T_BOOLEAN_OR: case T_BOOLEAN_AND: case T_LOGICAL_AND: case T_LOGICAL_OR: if (isUnused()) { cg_printf("("); if (second->outputCPPUnneeded(cg, ar)) { cg_printf(","); } cg_printf("false)"); } else { second->outputCPP(cg, ar); } break; default: second->outputCPP(cg, ar); } if (wrapped) cg_printf(")"); }
void Type::Dump(ExpressionPtr exp) { Dump(exp->getExpectedType(), "Expected: %s\t"); Dump(exp->getActualType(), "Actual: %s\n"); }
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; }
bool BinaryOpExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state) { if (isOpEqual()) return Expression::preOutputCPP(cg, ar, state); bool effect2 = m_exp2->hasEffect(); const char *prefix = 0; if (effect2 || m_exp1->hasEffect()) { ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this()); ExpressionPtrVec ev; bool hasVoid = false; int numConcat = 0; bool ok = false; if (m_op == '.') { numConcat = getConcatList(ev, self, hasVoid); ok = hasVoid || (numConcat > MAX_CONCAT_ARGS && (!Option::GenConcat || cg.getOutput() == CodeGenerator::SystemCPP)); } else if (effect2 && m_op == T_CONCAT_EQUAL) { prefix = stringBufferPrefix(cg, ar, m_exp1); ok = prefix; if (!ok) { if (m_exp1->is(KindOfSimpleVariable)) { ok = true; ev.push_back(m_exp1); numConcat++; } } numConcat += getConcatList(ev, m_exp2, hasVoid); } if (ok) { if (!cg.inExpression()) return true; cg.wrapExpressionBegin(); std::string buf; if (prefix) { SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(m_exp1)); buf = stringBufferName(Option::TempPrefix, prefix, sv->getName().c_str()); m_cppTemp = "/**/"; } else if (numConcat) { buf = m_cppTemp = genCPPTemp(cg, ar); buf += "_buf"; cg_printf("StringBuffer %s;\n", buf.c_str()); } else { m_cppTemp = "\"\""; } for (size_t i = 0; i < ev.size(); i++) { ExpressionPtr exp = ev[i]; bool is_void = !exp->getActualType(); exp->preOutputCPP(cg, ar, 0); if (!is_void) { cg_printf("%s.append(", buf.c_str()); outputStringExpr(cg, ar, exp, true); cg_printf(")"); } else { exp->outputCPPUnneeded(cg, ar); } cg_printf(";\n"); } if (numConcat && !prefix) { cg_printf("CStrRef %s(%s.detach());\n", m_cppTemp.c_str(), buf.c_str()); if (m_op == T_CONCAT_EQUAL) { m_exp1->outputCPP(cg, ar); cg_printf(" = %s;\n", m_cppTemp.c_str()); } } return true; } } if (!isShortCircuitOperator()) { return Expression::preOutputCPP(cg, ar, state); } if (!effect2) { return m_exp1->preOutputCPP(cg, ar, state); } bool fix_e1 = m_exp1->preOutputCPP(cg, ar, 0); if (!cg.inExpression()) { return fix_e1 || m_exp2->preOutputCPP(cg, ar, 0); } cg.setInExpression(false); bool fix_e2 = m_exp2->preOutputCPP(cg, ar, 0); cg.setInExpression(true); if (fix_e2) { cg.wrapExpressionBegin(); std::string tmp = genCPPTemp(cg, ar); cg_printf("bool %s = (", tmp.c_str()); m_exp1->outputCPP(cg, ar); cg_printf(");\n"); cg_indentBegin("if (%s%s) {\n", m_op == T_LOGICAL_OR || m_op == T_BOOLEAN_OR ? "!" : "", tmp.c_str()); m_exp2->preOutputCPP(cg, ar, 0); cg_printf("%s = (", tmp.c_str()); m_exp2->outputCPP(cg, ar); cg_printf(");\n"); cg_indentEnd("}\n"); m_cppTemp = tmp; } else if (state & FixOrder) { preOutputStash(cg, ar, state); fix_e1 = true; } return fix_e1 || fix_e2; }