bool ExpressionList::flattenLiteralStrings(vector<ExpressionPtr> &literals) const { for (unsigned i = 0; i < m_exps.size(); i++) { ExpressionPtr e = m_exps[i]; if (e->is(Expression::KindOfArrayPairExpression)) { ArrayPairExpressionPtr ap = dynamic_pointer_cast<ArrayPairExpression>(e); if (ap->getName()) return false; e = ap->getValue(); } if (e->is(Expression::KindOfUnaryOpExpression)) { UnaryOpExpressionPtr unary = dynamic_pointer_cast<UnaryOpExpression>(e); if (unary->getOp() == T_ARRAY) { ExpressionListPtr el = dynamic_pointer_cast<ExpressionList>(unary->getExpression()); if (!el->flattenLiteralStrings(literals)) { return false; } } } else if (e->isLiteralString()) { literals.push_back(e); } else { return false; } } return true; }
void AssignmentExpression::onParseRecur(AnalysisResultConstPtr ar, ClassScopePtr scope) { // This is that much we can do during parse phase. TypePtr type; if (m_value->is(Expression::KindOfScalarExpression)) { type = static_pointer_cast<ScalarExpression>(m_value)->inferenceImpl( ar, Type::Some, false); } else if (m_value->is(Expression::KindOfUnaryOpExpression)) { UnaryOpExpressionPtr uexp = dynamic_pointer_cast<UnaryOpExpression>(m_value); if (uexp->getOp() == T_ARRAY) { type = Type::Array; } } if (!type) type = Type::Some; if (m_variable->is(Expression::KindOfConstantExpression)) { // ...as in ClassConstant statement // We are handling this one here, not in ClassConstant, purely because // we need "value" to store in constant table. ConstantExpressionPtr exp = dynamic_pointer_cast<ConstantExpression>(m_variable); scope->getConstants()->add(exp->getName(), type, m_value, ar, m_variable); } else if (m_variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_variable); scope->getVariables()->add(var->getName(), type, true, ar, shared_from_this(), scope->getModifiers()); var->clearContext(Declaration); // to avoid wrong CodeError } else { ASSERT(false); // parse phase shouldn't handle anything else } }
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; }
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; }
bool Option::GetArrayElements(ExpressionPtr value, ExpressionListPtr &out) { UnaryOpExpressionPtr v = dynamic_pointer_cast<UnaryOpExpression>(value); if (!v || v->getOp() != T_ARRAY) { Logger::Error("Line %d: invalid array: %s", value->getLocation()->line1, value->getText().c_str()); return false; } ExpressionPtr exp = v->getExpression(); out = dynamic_pointer_cast<ExpressionList>(exp); if (!out) { Logger::Error("Line %d: invalid array: %s", value->getLocation()->line1, value->getText().c_str()); return false; } return true; }
void Parser::onUnaryOpExp(Token *out, Token *operand, int op, bool front) { switch (op) { case T_INCLUDE: case T_INCLUDE_ONCE: case T_REQUIRE: case T_REQUIRE_ONCE: { IncludeExpressionPtr exp = NEW_EXP(IncludeExpression, operand->exp, op); out->exp = exp; exp->onParse(m_ar); } break; default: { UnaryOpExpressionPtr exp = NEW_EXP(UnaryOpExpression, operand->exp, op, front); out->exp = exp; exp->onParse(m_ar); } break; } }
bool Option::Load(map<string, int> &option, ExpressionPtr value) { ExpressionListPtr elements; if (!GetArrayElements(value, elements)) return false; for (int i = 0; i < elements->getCount(); i++) { ExpressionPtr e = (*elements)[i]; ArrayPairExpressionPtr pair = dynamic_pointer_cast<ArrayPairExpression>(e); bool negative = false; ScalarExpressionPtr n, v; if (pair) n = dynamic_pointer_cast<ScalarExpression>(pair->getName()); if (pair) { if (pair->getValue()->is(Expression::KindOfUnaryOpExpression)) { UnaryOpExpressionPtr una = dynamic_pointer_cast<UnaryOpExpression>(pair->getValue()); if (una->getOp() != '+' && una->getOp() != '-') { Logger::Error("Line %d: invalid integer: %s", una->getLocation()->line1, una->getText().c_str()); return false; } v = dynamic_pointer_cast<ScalarExpression>(una->getExpression()); if (una->getOp() == '-') { negative = true; } } else { v = dynamic_pointer_cast<ScalarExpression>(pair->getValue()); } } if (!pair || !n || !v || !n->isLiteralString() || !v->isLiteralInteger()) { Logger::Error("Line %d: invalid element: %s", e->getLocation()->line1, e->getText().c_str()); return false; } if (negative) { option[n->getLiteralString()] = - v->getLiteralInteger(); } else { option[n->getLiteralString()] = v->getLiteralInteger(); } } return true; }
/** * If the unary operation is not PHP specific, but something a query * processor can handle (+ - ! ~), then rewrite the operand to something * the query processor can evaluate (such as a query parameter reference) * and rewrite the entire expression to use the rewritten operand. * If the rewritten operand is the same as the original operand, just * return the expression as is. */ ExpressionPtr CaptureExtractor::rewriteUnary(UnaryOpExpressionPtr ue) { assert (ue != nullptr); if (!ue->getFront()) return nullptr; switch (ue->getOp()) { case '+': case '-': case '!': case '~': break; // Could be something the query processor can handle default: return newQueryParamRef(ue); } auto expr = ue->getExpression(); auto newExpr = rewrite(expr); if (expr == newExpr) return ue; return std::make_shared<UnaryOpExpression>( ue->getScope(), ue->getRange(), newExpr, ue->getOp(), true); }
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(); }