bool ExpressionList::getScalarValue(Variant &value) { if (m_arrayElements) { if (isScalarArrayPairs()) { ArrayInit init(m_exps.size()); for (unsigned int i = 0; i < m_exps.size(); i++) { ArrayPairExpressionPtr exp = dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]); ExpressionPtr name = exp->getName(); ExpressionPtr val = exp->getValue(); if (!name) { Variant v; bool ret = val->getScalarValue(v); if (!ret) ASSERT(false); init.set(v); } else { Variant n; Variant v; bool ret1 = name->getScalarValue(n); bool ret2 = val->getScalarValue(v); if (!(ret1 && ret2)) return ExpressionPtr(); init.set(n, v); } } value = Array(init.create()); return true; } return false; } if (m_kind != ListKindParam && !hasEffect()) { ExpressionPtr v(listValue()); return v ? v->getScalarValue(value) : false; } return false; }
bool ExpressionList::getScalarValue(Variant &value) { if (m_elems_kind != ElemsKind::None) { if (isScalarArrayPairs()) { ArrayInit init(m_exps.size(), ArrayInit::Mixed{}); for (unsigned int i = 0; i < m_exps.size(); i++) { ArrayPairExpressionPtr exp = dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]); ExpressionPtr name = exp->getName(); ExpressionPtr val = exp->getValue(); if (!name) { Variant v; bool ret = val->getScalarValue(v); if (!ret) assert(false); init.append(v); } else { Variant n; Variant v; bool ret1 = name->getScalarValue(n); bool ret2 = val->getScalarValue(v); if (!(ret1 && ret2)) return false; init.setKeyUnconverted(n, v); } } value = Array(init.create()); return true; } return false; } if (m_kind != ListKindParam && !hasEffect()) { ExpressionPtr v(listValue()); return v ? v->getScalarValue(value) : false; } return false; }
bool ExpressionList::getScalarValue(Variant &value) { if (!isScalarArrayPairs()) return false; ArrayInit init(m_exps.size()); for (unsigned int i = 0; i < m_exps.size(); i++) { ArrayPairExpressionPtr exp = dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]); ExpressionPtr name = exp->getName(); ExpressionPtr val = exp->getValue(); if (!name) { Variant v; bool ret = val->getScalarValue(v); if (!ret) ASSERT(false); init.set(i, v); } else { Variant n; Variant v; bool ret1 = name->getScalarValue(n); bool ret2 = val->getScalarValue(v); if (!(ret1 && ret2)) ASSERT(false); init.set(i, n, v); } } value = Array(init.create()); return true; }
unsigned int ExpressionList::checkIntegerKeys(int64 &max) const { ASSERT(m_arrayElements); max = 0; set<int64> keys; for (unsigned int i = 0; i < m_exps.size(); i++) { ArrayPairExpressionPtr ap = dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]); ExpressionPtr name = ap->getName(); if (!name) return 0; Variant value; bool ret = name->getScalarValue(value); if (!ret) return 0; if (!value.isInteger()) return 0; int64 v = value.toInt64(); if (i == 0) { max = v; } else if (max < v) { max = v; } keys.insert(v); } if (max >= 0) { max++; } else { max = 0; } return keys.size(); }
ExpressionPtr ConstantExpression::preOptimize(AnalysisResultConstPtr ar) { if (ar->getPhase() < AnalysisResult::FirstPreOptimize) { return ExpressionPtr(); } ConstructPtr decl; while (!isScalar() && !m_dynamic && !(m_context & LValue)) { const Symbol *sym = resolveNS(ar); if (sym && (!const_cast<Symbol*>(sym)->checkDefined() || sym->isDynamic())) { sym = 0; m_dynamic = true; } if (!sym) break; if (!sym->isSystem()) BlockScope::s_constMutex.lock(); ExpressionPtr value = dynamic_pointer_cast<Expression>(sym->getValue()); if (!sym->isSystem()) BlockScope::s_constMutex.unlock(); if (!value || !value->isScalar()) { if (!m_depsSet && sym->getDeclaration()) { sym->getDeclaration()->getScope()->addUse( getScope(), BlockScope::UseKindConstRef); m_depsSet = true; } break; } Variant scalarValue; if (value->getScalarValue(scalarValue) && !scalarValue.isAllowedAsConstantValue()) { // block further optimization const_cast<Symbol*>(sym)->setDynamic(); m_dynamic = true; break; } if (sym->isSystem() && !value->is(KindOfScalarExpression)) { if (ExpressionPtr opt = value->preOptimize(ar)) { value = opt; } } ExpressionPtr rep = Clone(value, getScope()); rep->setComment(getText()); copyLocationTo(rep); return replaceValue(rep); } return ExpressionPtr(); }
unsigned int ExpressionList::checkLitstrKeys() const { ASSERT(m_arrayElements); std::set<string> keys; for (unsigned int i = 0; i < m_exps.size(); i++) { ArrayPairExpressionPtr ap = dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]); ExpressionPtr name = ap->getName(); if (!name) return 0; Variant value; bool ret = name->getScalarValue(value); if (!ret) return 0; if (!value.isString()) return 0; String str = value.toString(); if (str->isInteger()) return 0; string s(str.data(), str.size()); keys.insert(s); } return keys.size(); }
static bool isEquivRedecl(const std::string &name, ExpressionPtr exp, ModifierExpressionPtr modif, Symbol * symbol) { assert(exp); assert(modif); assert(symbol); if (symbol->getName() != name || symbol->isProtected() != modif->isProtected() || symbol->isPrivate() != modif->isPrivate() || symbol->isPublic() != modif->isPublic() || symbol->isStatic() != modif->isStatic()) return false; auto symDeclExp = dynamic_pointer_cast<Expression>(symbol->getDeclaration()); if (!exp) return !symDeclExp; Variant v1, v2; auto s1 = exp->getScalarValue(v1); auto s2 = symDeclExp->getScalarValue(v2); if (s1 != s2) return false; if (s1) return same(v1, v2); return exp->getText() == symDeclExp->getText(); }
ExpressionPtr AssignmentExpression::preOptimize(AnalysisResultConstPtr ar) { if (Option::EliminateDeadCode && ar->getPhase() >= AnalysisResult::FirstPreOptimize) { // otherwise used & needed flags may not be up to date yet ExpressionPtr rep = optimize(ar); if (rep) return rep; } if (m_variable->getContainedEffects() & ~(CreateEffect|AccessorEffect)) { return ExpressionPtr(); } ExpressionPtr val = m_value; while (val) { if (val->is(KindOfExpressionList)) { ExpressionListPtr el(static_pointer_cast<ExpressionList>(val)); val = el->listValue(); continue; } if (val->is(KindOfAssignmentExpression)) { val = static_pointer_cast<AssignmentExpression>(val)->m_value; continue; } break; } if (val && val->isScalar()) { if (val != m_value) { ExpressionListPtr rep(new ExpressionList( getScope(), getLocation(), KindOfExpressionList, ExpressionList::ListKindWrapped)); rep->addElement(m_value); m_value = val->clone(); rep->addElement(static_pointer_cast<Expression>(shared_from_this())); return replaceValue(rep); } if (!m_ref && m_variable->is(KindOfArrayElementExpression)) { ArrayElementExpressionPtr ae( static_pointer_cast<ArrayElementExpression>(m_variable)); ExpressionPtr avar(ae->getVariable()); ExpressionPtr aoff(ae->getOffset()); if (!aoff || aoff->isScalar()) { avar = avar->getCanonLVal(); while (avar) { if (avar->isScalar()) { Variant v,o,r; if (!avar->getScalarValue(v)) break; if (!val->getScalarValue(r)) break; try { g_context->setThrowAllErrors(true); if (aoff) { if (!aoff->getScalarValue(o)) break; v.set(o, r); } else { v.append(r); } g_context->setThrowAllErrors(false); } catch (...) { break; } ExpressionPtr rep( new AssignmentExpression( getScope(), getLocation(), KindOfAssignmentExpression, m_variable->replaceValue(Clone(ae->getVariable())), makeScalarExpression(ar, v), false)); if (!isUnused()) { ExpressionListPtr el( new ExpressionList( getScope(), getLocation(), KindOfExpressionList, ExpressionList::ListKindWrapped)); el->addElement(rep); el->addElement(val); rep = el; } return replaceValue(rep); } avar = avar->getCanonPtr(); } g_context->setThrowAllErrors(false); } } } return ExpressionPtr(); }
void FunctionScope::outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar) { int attribute = ClassInfo::IsNothing; if (!isUserFunction()) attribute |= ClassInfo::IsSystem; if (isRedeclaring()) attribute |= ClassInfo::IsRedeclared; if (isVolatile()) attribute |= ClassInfo::IsVolatile; if (isRefReturn()) attribute |= ClassInfo::IsReference; if (isProtected()) { attribute |= ClassInfo::IsProtected; } else if (isPrivate()) { attribute |= ClassInfo::IsPrivate; } else { attribute |= ClassInfo::IsPublic; } if (isAbstract()) attribute |= ClassInfo::IsAbstract; if (isStatic() && !isStaticMethodAutoFixed()) { attribute |= ClassInfo::IsStatic; } if (isFinal()) attribute |= ClassInfo::IsFinal; if (!m_docComment.empty()) attribute |= ClassInfo::HasDocComment; // Use the original cased name, for reflection to work correctly. cg.printf("(const char *)0x%04X, \"%s\", NULL, NULL,\n", attribute, getOriginalName().c_str()); if (!m_docComment.empty()) { char *dc = string_cplus_escape(m_docComment.c_str()); cg.printf("\"%s\",\n", dc); free(dc); } Variant defArg; for (int i = 0; i < m_maxParam; i++) { int attr = ClassInfo::IsNothing; if (i >= m_minParam) attr |= ClassInfo::IsOptional; if (isRefParam(i)) attr |= ClassInfo::IsReference; cg.printf("(const char *)0x%04X, \"%s\", \"%s\", ", attr, m_paramNames[i].c_str(), Util::toLower(m_paramTypes[i]->getPHPName()).c_str()); if (i >= m_minParam) { MethodStatementPtr m = dynamic_pointer_cast<MethodStatement>(getStmt()); if (m) { ExpressionListPtr params = m->getParams(); assert(i < params->getCount()); ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*params)[i]); assert(param); ExpressionPtr def = param->defaultValue(); if (!def->isScalar() || !def->getScalarValue(defArg)) { defArg = "1"; } } else { defArg = "1"; } char *s = string_cplus_escape(f_serialize(defArg).data()); cg.printf("\"%s\",\n", s); free(s); } else { cg.printf("\"\",\n"); } } cg.printf("NULL,\n"); m_variables->outputCPPStaticVariables(cg, ar); }
StatementPtr IfStatement::preOptimize(AnalysisResultPtr ar) { if (ar->getPhase() < AnalysisResult::FirstPreOptimize) { return StatementPtr(); } // we cannot optimize away the code inside if statement, because // there may be a goto that goes into if statement. if (hasReachableLabel()) { return StatementPtr(); } bool changed = false; int i; int j; Variant value; bool hoist = false; for (i = 0; i < m_stmts->getCount(); i++) { IfBranchStatementPtr branch = dynamic_pointer_cast<IfBranchStatement>((*m_stmts)[i]); ExpressionPtr condition = branch->getCondition(); if (!condition) { StatementPtr stmt = branch->getStmt(); if (stmt) { if (!i && ((getFunctionScope() && !getFunctionScope()->inPseudoMain()) || !stmt->hasDecl())) { hoist = true; break; } if (stmt->is(KindOfIfStatement)) { StatementListPtr sub_stmts = dynamic_pointer_cast<IfStatement>(stmt)->m_stmts; m_stmts->removeElement(i); changed = true; for (j = 0; j < sub_stmts->getCount(); j++) { m_stmts->insertElement((*sub_stmts)[j], i++); } } } break; } else if (condition->isScalar() && condition->getScalarValue(value)) { if (value.toBoolean()) { hoist = !i && ((getFunctionScope() && !getFunctionScope()->inPseudoMain()) || !branch->hasDecl()); break; } else { m_stmts->removeElement(i--); changed = true; } } } if (!changed && i && i == m_stmts->getCount()) return StatementPtr(); // either else branch or if (true) branch without further declarations i++; while (i < m_stmts->getCount()) { m_stmts->removeElement(i); changed = true; } // if there is only one branch left, return stmt. if (hoist) { IfBranchStatementPtr branch = dynamic_pointer_cast<IfBranchStatement>((*m_stmts)[0]); return branch->getStmt() ? branch->getStmt() : NULL_STATEMENT(); } else if (m_stmts->getCount() == 0) { return NULL_STATEMENT(); } else { return changed ? static_pointer_cast<Statement>(shared_from_this()) : StatementPtr(); } }
void FunctionScope::outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar) { int attribute = ClassInfo::IsNothing; if (!isUserFunction()) attribute |= ClassInfo::IsSystem; if (isRedeclaring()) attribute |= ClassInfo::IsRedeclared; if (isVolatile()) attribute |= ClassInfo::IsVolatile; if (isRefReturn()) attribute |= ClassInfo::IsReference; if (isProtected()) { attribute |= ClassInfo::IsProtected; } else if (isPrivate()) { attribute |= ClassInfo::IsPrivate; } else { attribute |= ClassInfo::IsPublic; } if (isAbstract()) attribute |= ClassInfo::IsAbstract; if (isStatic()) { attribute |= ClassInfo::IsStatic; } if (isFinal()) attribute |= ClassInfo::IsFinal; if (isVariableArgument()) { attribute |= ClassInfo::VariableArguments; } if (isReferenceVariableArgument()) { attribute |= ClassInfo::RefVariableArguments; } if (isMixedVariableArgument()) { attribute |= ClassInfo::MixedVariableArguments; } attribute |= m_attributeClassInfo; if (!m_docComment.empty() && Option::GenerateDocComments) { attribute |= ClassInfo::HasDocComment; } else { attribute &= ~ClassInfo::HasDocComment; } // Use the original cased name, for reflection to work correctly. cg_printf("(const char *)0x%04X, \"%s\", \"%s\", (const char *)%d, " "(const char *)%d, NULL, NULL,\n", attribute, getOriginalName().c_str(), m_stmt ? m_stmt->getLocation()->file : "", m_stmt ? m_stmt->getLocation()->line0 : 0, m_stmt ? m_stmt->getLocation()->line1 : 0); if (!m_docComment.empty() && Option::GenerateDocComments) { char *dc = string_cplus_escape(m_docComment.c_str(), m_docComment.size()); cg_printf("\"%s\",\n", dc); free(dc); } Variant defArg; for (int i = 0; i < m_maxParam; i++) { int attr = ClassInfo::IsNothing; if (i >= m_minParam) attr |= ClassInfo::IsOptional; if (isRefParam(i)) attr |= ClassInfo::IsReference; const std::string &tname = m_paramTypeSpecs[i] ? m_paramTypeSpecs[i]->getPHPName() : ""; cg_printf("(const char *)0x%04X, \"%s\", \"%s\", ", attr, m_paramNames[i].c_str(), Util::toLower(tname).c_str()); if (i >= m_minParam) { MethodStatementPtr m = dynamic_pointer_cast<MethodStatement>(getStmt()); if (m) { ExpressionListPtr params = m->getParams(); assert(i < params->getCount()); ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*params)[i]); assert(param); ExpressionPtr def = param->defaultValue(); string sdef = def->getText(); char *esdef = string_cplus_escape(sdef.data(), sdef.size()); if (!def->isScalar() || !def->getScalarValue(defArg)) { /** * Special value runtime/ext/ext_reflection.cpp can check and throw. * If we want to avoid seeing this so to make getDefaultValue() * work better for reflections, we will have to implement * getScalarValue() to greater extent under compiler/expressions. */ cg_printf("\"\x01\", \"%s\",\n", esdef); } else { String str = f_serialize(defArg); char *s = string_cplus_escape(str.data(), str.size()); cg_printf("\"%s\", \"%s\",\n", s, esdef); free(s); } free(esdef); } else { char *def = string_cplus_escape(m_paramDefaults[i].data(), m_paramDefaults[i].size()); char *defText = string_cplus_escape(m_paramDefaultTexts[i].data(), m_paramDefaultTexts[i].size()); cg_printf("\"%s\", \"%s\",\n", def, defText); free(def); free(defText); } } else { cg_printf("\"\", \"\",\n"); } } cg_printf("NULL,\n"); m_variables->outputCPPStaticVariables(cg, ar); }