void FunctionScope::outputCPPParamsCall(CodeGenerator &cg, AnalysisResultPtr ar, bool aggregateParams) { if (isVariableArgument()) { cg.printf("num_args, "); } bool userFunc = isUserFunction(); ExpressionListPtr params; if (userFunc) { MethodStatementPtr stmt = dynamic_pointer_cast<MethodStatement>(m_stmt); params = stmt->getParams(); } if (aggregateParams) { cg.printf("Array("); if (m_maxParam) { // param arrays are always vectors cg.printf("ArrayInit(%d, true).", m_maxParam); } } for (int i = 0; i < m_maxParam; i++) { if (i > 0) cg.printf(aggregateParams ? "." : ", "); bool isRef; if (userFunc) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*params)[i]); isRef = param->isRef(); if (aggregateParams) { cg.printf("set%s(%d, v_%s", isRef ? "Ref" : "", i, param->getName().c_str()); } else { cg.printf("%sv_%s%s", isRef ? "ref(" : "", param->getName().c_str(), isRef ? ")" : ""); } } else { isRef = isRefParam(i); if (aggregateParams) { cg.printf("set%s(%d, a%d", isRef ? "Ref" : "", i, i); } else { cg.printf("%sa%d%s", isRef ? "ref(" : "", i, isRef ? ")" : ""); } } if (aggregateParams) cg.printf(")"); } if (aggregateParams) { if (m_maxParam) cg.printf(".create()"); cg.printf(")"); } if (isVariableArgument()) { if (aggregateParams || m_maxParam > 0) cg.printf(","); cg.printf("args"); } }
void ClassStatement::onParse(AnalysisResultPtr ar) { ClassScope::KindOf kindOf = ClassScope::KindOfObjectClass; switch (m_type) { case T_CLASS: kindOf = ClassScope::KindOfObjectClass; break; case T_ABSTRACT: kindOf = ClassScope::KindOfAbstractClass; break; case T_FINAL: kindOf = ClassScope::KindOfFinalClass; break; default: ASSERT(false); } vector<string> bases; if (!m_parent.empty()) { bases.push_back(m_parent); ar->addNonFinal(m_parent); } if (m_base) m_base->getStrings(bases); StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this()); ClassScopePtr classScope(new ClassScope(kindOf, m_originalName, m_parent, bases, m_docComment, stmt, ar->getFileScope())); m_classScope = classScope; if (!ar->getFileScope()->addClass(ar, classScope)) { m_ignored = true; return; } ar->recordClassSource(m_name, ar->getFileScope()->getName()); if (m_stmt) { ar->pushScope(classScope); bool seenConstruct = false; for (int i = 0; i < m_stmt->getCount(); i++) { MethodStatementPtr meth = dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]); if (meth && meth->getName() == "__construct") { seenConstruct = true; break; } } for (int i = 0; i < m_stmt->getCount(); i++) { if (!seenConstruct) { MethodStatementPtr meth = dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]); if (meth && classScope && meth->getName() == classScope->getName() && !meth->getModifiers()->isStatic()) { // class-name constructor classScope->setAttribute(ClassScope::classNameConstructor); } } IParseHandlerPtr ph = dynamic_pointer_cast<IParseHandler>((*m_stmt)[i]); ph->onParse(ar); } ar->popScope(); } }
StatementPtr ClassStatement::addClone(StatementPtr origStmt) { assert(m_stmt); StatementPtr newStmt = Clone(origStmt); MethodStatementPtr newMethStmt = dynamic_pointer_cast<MethodStatement>(newStmt); if (newMethStmt) { newMethStmt->setClassName(m_name); newMethStmt->setOriginalClassName(m_originalName); } m_stmt->addElement(newStmt); return newStmt; }
void Parser::onMethod(Token &out, Token &modifiers, Token &ref, Token &name, Token ¶ms, Token &stmt) { ClassStatementPtr cs = peekClass(); MethodStatementPtr ms = peekFunc()->unsafe_cast<MethodStatement>(); ASSERT(ms); popFunc(); StatementListStatementPtr stmts = stmt->getStmtList(); ms->resetLoc(this); if (stmts) stmts->resetLoc(this); ms->init(this, ref.num(), params->params(), stmts, m_hasCallToGetArgs); cs->addMethod(ms); }
void ClassScope::findTraitMethodsToImport(AnalysisResultPtr ar, ClassScopePtr trait) { assert(Option::WholeProgram); ClassStatementPtr tStmt = dynamic_pointer_cast<ClassStatement>(trait->getStmt()); StatementListPtr tStmts = tStmt->getStmts(); if (!tStmts) return; for (int s = 0; s < tStmts->getCount(); s++) { MethodStatementPtr meth = dynamic_pointer_cast<MethodStatement>((*tStmts)[s]); if (meth) { TraitMethod traitMethod(trait, meth, ModifierExpressionPtr(), MethodStatementPtr()); addImportTraitMethod(traitMethod, meth->getName()); } } }
MethodStatementPtr ClassScope::findTraitMethod(AnalysisResultPtr ar, ClassScopePtr trait, const string &methodName, std::set<ClassScopePtr> &visitedTraits) { if (visitedTraits.find(trait) != visitedTraits.end()) { return MethodStatementPtr(); } visitedTraits.insert(trait); ClassStatementPtr tStmt = dynamic_pointer_cast<ClassStatement>(trait->getStmt()); StatementListPtr tStmts = tStmt->getStmts(); // Look in the current trait for (int s = 0; s < tStmts->getCount(); s++) { MethodStatementPtr meth = dynamic_pointer_cast<MethodStatement>((*tStmts)[s]); if (meth) { // Handle methods if (meth->getName() == methodName) { return meth; } } } // Look into children traits for (int s = 0; s < tStmts->getCount(); s++) { UseTraitStatementPtr useTraitStmt = dynamic_pointer_cast<UseTraitStatement>((*tStmts)[s]); if (useTraitStmt) { vector<string> usedTraits; useTraitStmt->getUsedTraitNames(usedTraits); for (unsigned i = 0; i < usedTraits.size(); i++) { MethodStatementPtr foundMethod = findTraitMethod(ar, ar->findClass(usedTraits[i]), methodName, visitedTraits); if (foundMethod) return foundMethod; } } } return MethodStatementPtr(); // not found }
void FunctionScope::setParamSpecs(AnalysisResultPtr ar) { if (m_maxParam > 0 && m_stmt) { MethodStatementPtr stmt = dynamic_pointer_cast<MethodStatement>(m_stmt); ExpressionListPtr params = stmt->getParams(); for (int i = 0; i < m_maxParam; i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*params)[i]); TypePtr specType = param->getTypeSpec(ar, false); if (specType && !specType->is(Type::KindOfSome) && !specType->is(Type::KindOfVariant)) { m_paramTypeSpecs[i] = specType; } ExpressionPtr exp = param->defaultValue(); if (exp) { m_paramDefaults[i] = exp->getText(false, false, ar); } } } }
MethodStatementPtr ClassScope::importTraitMethod(const TraitMethod& traitMethod, AnalysisResultPtr ar, std::string methName) { MethodStatementPtr meth = traitMethod.method; std::string origMethName = traitMethod.originalName; ModifierExpressionPtr modifiers = traitMethod.modifiers; auto cloneMeth = dynamic_pointer_cast<MethodStatement>( dynamic_pointer_cast<ClassStatement>(m_stmt)->addClone(meth)); cloneMeth->setOriginalName(origMethName); // Note: keep previous modifiers if none specified when importing the trait if (modifiers && modifiers->getCount()) { cloneMeth->setModifiers(modifiers); } FunctionScopePtr funcScope = meth->getFunctionScope(); // Trait method typehints, self and parent, need to be converted auto cScope = dynamic_pointer_cast<ClassScope>(shared_from_this()); cloneMeth->fixupSelfAndParentTypehints( cScope ); auto cloneFuncScope = std::make_shared<HPHP::FunctionScope>( funcScope, ar, origMethName, cloneMeth, cloneMeth->getModifiers(), cScope->isUserClass()); cloneMeth->resetScope(cloneFuncScope); cloneFuncScope->setOuterScope(shared_from_this()); cloneFuncScope->setFromTrait(true); informClosuresAboutScopeClone(cloneMeth, cloneFuncScope, ar); cloneMeth->addTraitMethodToScope(ar, dynamic_pointer_cast<ClassScope>(shared_from_this())); // Preserve original filename (as this varies per-function and not per-unit // in the case of methods imported from flattened traits) auto const& name = meth->getOriginalFilename().empty() ? meth->getFileScope()->getName() : meth->getOriginalFilename(); cloneMeth->setOriginalFilename(name); return cloneMeth; }
void StatementList::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr func = getFunctionScope(); for (unsigned int i = 0; i < m_stmts.size(); i++) { StatementPtr stmt = m_stmts[i]; stmt->outputCPP(cg, ar); if (stmt->is(Statement::KindOfMethodStatement)) { MethodStatementPtr methodStmt = dynamic_pointer_cast<MethodStatement>(stmt); std::string methodName = methodStmt->getName(); if (methodName == "offsetget") { ClassScopePtr cls = getClassScope(); std::string arrayAccess("arrayaccess"); if (cls->derivesFrom(ar, arrayAccess, false, false)) { FunctionScopePtr funcScope = methodStmt->getFunctionScope(); std::string name = funcScope->getName(); funcScope->setName("__offsetget_lval"); methodStmt->setName("__offsetget_lval"); methodStmt->outputCPP(cg, ar); funcScope->setName(name); methodStmt->setName("offsetget"); } } } } }
void StatementList::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr func = getFunctionScope(); bool inPseudoMain = func && func->inPseudoMain(); std::vector<bool> isDeclaration; if (inPseudoMain) { // We need these declarations to go first, because PHP allows top level // function and class declarations to appear after usage. for (unsigned int i = 0; i < m_stmts.size(); i++) { StatementPtr stmt = m_stmts[i]; bool isDecl = false; if (stmt->is(Statement::KindOfFunctionStatement)) { isDecl = true; } else if (stmt->is(Statement::KindOfClassStatement) || stmt->is(Statement::KindOfInterfaceStatement)) { ClassScopePtr cls = (dynamic_pointer_cast<InterfaceStatement>(stmt))->getClassScope(); isDecl = cls->isBaseClass() || !cls->isVolatile(); } if (isDecl) stmt->outputCPP(cg,ar); isDeclaration.push_back(isDecl); } } for (unsigned int i = 0; i < m_stmts.size(); i++) { StatementPtr stmt = m_stmts[i]; if (stmt->is(Statement::KindOfClassStatement)) { if (!inPseudoMain || !isDeclaration[i]) stmt->outputCPP(cg, ar); } else if (!(stmt->is(Statement::KindOfFunctionStatement) || stmt->is(Statement::KindOfInterfaceStatement)) || (!inPseudoMain || !isDeclaration[i])) { stmt->outputCPP(cg, ar); if (stmt->is(Statement::KindOfMethodStatement)) { MethodStatementPtr methodStmt = dynamic_pointer_cast<MethodStatement>(stmt); std::string methodName = methodStmt->getName(); if (methodName == "offsetget") { ClassScopePtr cls = getClassScope(); std::string arrayAccess("arrayaccess"); if (cls->derivesFrom(ar, arrayAccess, false, false)) { FunctionScopePtr funcScope = methodStmt->getFunctionScope(); std::string name = funcScope->getName(); funcScope->setName("__offsetget_lval"); methodStmt->setName("__offsetget_lval"); methodStmt->outputCPP(cg, ar); funcScope->setName(name); methodStmt->setName("offsetget"); } } } } } }
void Parser::onMethod(Token &out, Token &modifiers, Token &ret, Token &ref, Token &name, Token ¶ms, Token &stmt, bool reloc /* = true */) { ClassStatementPtr cs = peekClass(); MethodStatementPtr ms = peekFunc()->unsafe_cast<MethodStatement>(); ASSERT(ms); popFunc(); if (reloc) { ms->setLoc(popFuncLocation().get()); } ms->resetLoc(this); bool hasCallToGetArgs = m_hasCallToGetArgs.back(); m_hasCallToGetArgs.pop_back(); m_foreaches.pop_back(); m_pendingStatements.pop_back(); if (ms->hasYield()) { string closureName = getClosureName(); ms->setName(closureName); ms->setPublic(); Token new_params; prepare_generator(this, stmt, new_params, ms->getYieldCount()); StatementListStatementPtr stmts = stmt->getStmtList(); if (stmts) stmts->resetLoc(this); ms->init(this, ref.num(), new_params->params(), stmts, hasCallToGetArgs); String clsname = cs->name(); create_generator(this, out, params, name, closureName, clsname.data(), &modifiers, hasCallToGetArgs); } else { StatementListStatementPtr stmts = stmt->getStmtList(); if (stmts) stmts->resetLoc(this); ms->init(this, ref.num(), params->params(), stmts, hasCallToGetArgs); } cs->addMethod(ms); }
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); }
ExpressionPtr FunctionCall::inliner(AnalysisResultConstPtr ar, ExpressionPtr obj, std::string localThis) { FunctionScopePtr fs = getFunctionScope(); if (m_noInline || !fs || fs == m_funcScope || !m_funcScope->getStmt()) { return ExpressionPtr(); } BlockScope::s_jobStateMutex.lock(); if (m_funcScope->getMark() == BlockScope::MarkProcessing) { fs->setForceRerun(true); BlockScope::s_jobStateMutex.unlock(); return ExpressionPtr(); } ReadLock lock(m_funcScope->getInlineMutex()); BlockScope::s_jobStateMutex.unlock(); if (!m_funcScope->getInlineAsExpr()) { return ExpressionPtr(); } if (m_funcScope->getInlineSameContext() && m_funcScope->getContainingClass() && m_funcScope->getContainingClass() != getClassScope()) { /* The function contains a context sensitive construct such as call_user_func (context sensitive because it could call array('parent', 'foo')) so its not safe to inline it into a different context. */ return ExpressionPtr(); } MethodStatementPtr m (dynamic_pointer_cast<MethodStatement>(m_funcScope->getStmt())); VariableTablePtr vt = fs->getVariables(); int nAct = m_params ? m_params->getCount() : 0; int nMax = m_funcScope->getMaxParamCount(); if (nAct < m_funcScope->getMinParamCount() || !m->getStmts()) { return ExpressionPtr(); } InlineCloneInfo info(m_funcScope); info.elist = ExpressionListPtr(new ExpressionList( getScope(), getLocation(), ExpressionList::ListKindWrapped)); std::ostringstream oss; oss << fs->nextInlineIndex() << "_" << m_name << "_"; std::string prefix = oss.str(); if (obj) { info.callWithThis = true; if (!obj->isThis()) { SimpleVariablePtr var (new SimpleVariable(getScope(), obj->getLocation(), prefix + "this")); var->updateSymbol(SimpleVariablePtr()); var->getSymbol()->setHidden(); var->getSymbol()->setUsed(); var->getSymbol()->setReferenced(); AssignmentExpressionPtr ae (new AssignmentExpression(getScope(), obj->getLocation(), var, obj, false)); info.elist->addElement(ae); info.sepm[var->getName()] = var; info.localThis = var->getName(); } } else { if (m_classScope) { if (!m_funcScope->isStatic()) { ClassScopeRawPtr oCls = getOriginalClass(); FunctionScopeRawPtr oFunc = getOriginalFunction(); if (oCls && !oFunc->isStatic() && (oCls == m_classScope || oCls->derivesFrom(ar, m_className, true, false))) { info.callWithThis = true; info.localThis = localThis; } } if (!isSelf() && !isParent() && !isStatic()) { info.staticClass = m_className; } } } ExpressionListPtr plist = m->getParams(); int i; for (i = 0; i < nMax || i < nAct; i++) { ParameterExpressionPtr param (i < nMax ? dynamic_pointer_cast<ParameterExpression>((*plist)[i]) : ParameterExpressionPtr()); ExpressionPtr arg = i < nAct ? (*m_params)[i] : Clone(param->defaultValue(), getScope()); SimpleVariablePtr var (new SimpleVariable(getScope(), (i < nAct ? arg.get() : this)->getLocation(), prefix + (param ? param->getName() : lexical_cast<string>(i)))); var->updateSymbol(SimpleVariablePtr()); var->getSymbol()->setHidden(); var->getSymbol()->setUsed(); var->getSymbol()->setReferenced(); bool ref = (i < nMax && m_funcScope->isRefParam(i)) || arg->hasContext(RefParameter); arg->clearContext(RefParameter); AssignmentExpressionPtr ae (new AssignmentExpression(getScope(), arg->getLocation(), var, arg, ref)); info.elist->addElement(ae); if (i < nAct && (ref || !arg->isScalar())) { info.sepm[var->getName()] = var; } } if (cloneStmtsForInline(info, m->getStmts(), prefix, ar, getFunctionScope()) <= 0) { info.elist->addElement(makeConstant(ar, "null")); } if (info.sepm.size()) { ExpressionListPtr unset_list (new ExpressionList(getScope(), getLocation())); for (StringToExpressionPtrMap::iterator it = info.sepm.begin(), end = info.sepm.end(); it != end; ++it) { ExpressionPtr var = it->second->clone(); var->clearContext((Context)(unsigned)-1); unset_list->addElement(var); } ExpressionPtr unset( new UnaryOpExpression(getScope(), getLocation(), unset_list, T_UNSET, true)); i = info.elist->getCount(); ExpressionPtr ret = (*info.elist)[--i]; if (ret->isScalar()) { info.elist->insertElement(unset, i); } else { ExpressionListPtr result_list (new ExpressionList(getScope(), getLocation(), ExpressionList::ListKindLeft)); if (ret->hasContext(LValue)) { result_list->setContext(LValue); result_list->setContext(ReturnContext); } result_list->addElement(ret); result_list->addElement(unset); (*info.elist)[i] = result_list; } } recomputeEffects(); return replaceValue(info.elist); }
void FunctionScope::outputCPPParamsCall(CodeGenerator &cg, AnalysisResultPtr ar, bool aggregateParams) { if (isVariableArgument()) { cg_printf("num_args, "); } bool userFunc = isUserFunction(); MethodStatementPtr stmt; ExpressionListPtr params; if (userFunc) { stmt = dynamic_pointer_cast<MethodStatement>(m_stmt); params = stmt->getParams(); } bool arrayCreated = false; if (Option::GenArrayCreate && cg.getOutput() != CodeGenerator::SystemCPP && aggregateParams && m_maxParam > 0) { if (stmt && !stmt->hasRefParam()) { cg_printf("Array("); stmt->outputParamArrayInit(cg); cg_printf(")"); arrayCreated = true; } else if (!userFunc && !hasRefParam(m_maxParam)) { cg_printf("Array("); for (int i = 0; i < m_maxParam; i++) { if (isRefParam(i)) { cg_printf("%d, ref(a%d)", i, i); } else { cg_printf("%d, a%d", i, i); } if (i < m_maxParam - 1) { cg_printf(", "); } else { cg_printf(")"); } } cg_printf(")"); arrayCreated = true; } } if (arrayCreated && isVariableArgument()) { cg_printf(","); cg_printf("args"); return; } if (aggregateParams) { cg_printf("Array("); if (m_maxParam) { // param arrays are always vectors cg_printf("ArrayInit(%d, true).", m_maxParam); } } for (int i = 0; i < m_maxParam; i++) { if (i > 0) cg_printf(aggregateParams ? "." : ", "); bool isRef; if (userFunc) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*params)[i]); isRef = param->isRef(); if (aggregateParams) { cg_printf("set%s(v_%s", isRef ? "Ref" : "", param->getName().c_str()); } else { cg_printf("%sv_%s%s", isRef ? "ref(" : "", param->getName().c_str(), isRef ? ")" : ""); } } else { isRef = isRefParam(i); if (aggregateParams) { cg_printf("set%s(a%d", isRef ? "Ref" : "", i); } else { cg_printf("%sa%d%s", isRef ? "ref(" : "", i, isRef ? ")" : ""); } } if (aggregateParams) cg_printf(")"); } if (aggregateParams) { if (m_maxParam) cg_printf(".create()"); cg_printf(")"); } if (isVariableArgument()) { if (aggregateParams || m_maxParam > 0) cg_printf(","); cg_printf("args"); } }
void ClassStatement::onParse(AnalysisResultConstPtr ar, FileScopePtr fs) { ClassScope::KindOf kindOf = ClassScope::KindOfObjectClass; switch (m_type) { case T_CLASS: kindOf = ClassScope::KindOfObjectClass; break; case T_ABSTRACT: kindOf = ClassScope::KindOfAbstractClass; break; case T_FINAL: kindOf = ClassScope::KindOfFinalClass; break; default: ASSERT(false); } vector<string> bases; if (!m_parent.empty()) { bases.push_back(m_parent); } if (m_base) m_base->getStrings(bases); StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this()); ClassScopePtr classScope(new ClassScope(kindOf, m_originalName, m_parent, bases, m_docComment, stmt)); setBlockScope(classScope); if (!fs->addClass(ar, classScope)) { m_ignored = true; return; } if (m_stmt) { bool seenConstruct = false; // flatten continuation StatementList into MethodStatements for (int i = 0; i < m_stmt->getCount(); i++) { StatementListPtr stmts = dynamic_pointer_cast<StatementList>((*m_stmt)[i]); if (stmts) { m_stmt->removeElement(i); for (int j = 0; j < stmts->getCount(); j++) { m_stmt->insertElement((*stmts)[j], i + j); } } } for (int i = 0; i < m_stmt->getCount(); i++) { MethodStatementPtr meth = dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]); if (meth && meth->getName() == "__construct") { seenConstruct = true; break; } } for (int i = 0; i < m_stmt->getCount(); i++) { if (!seenConstruct) { MethodStatementPtr meth = dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]); if (meth && classScope && meth->getName() == classScope->getName() && !meth->getModifiers()->isStatic()) { // class-name constructor classScope->setAttribute(ClassScope::ClassNameConstructor); } } IParseHandlerPtr ph = dynamic_pointer_cast<IParseHandler>((*m_stmt)[i]); ph->onParseRecur(ar, classScope); } } }
void Dictionary::build(MethodStatementPtr m) { if (StatementPtr s = m->getStmts()) { build(s); } }
void ClassStatement::onParse(AnalysisResultConstPtr ar, FileScopePtr fs) { ClassScope::KindOf kindOf = ClassScope::KindOfObjectClass; switch (m_type) { case T_CLASS: kindOf = ClassScope::KindOfObjectClass; break; case T_ABSTRACT: kindOf = ClassScope::KindOfAbstractClass; break; case T_FINAL: kindOf = ClassScope::KindOfFinalClass; break; case T_TRAIT: kindOf = ClassScope::KindOfTrait; break; default: assert(false); } vector<string> bases; if (!m_originalParent.empty()) { bases.push_back(m_originalParent); } if (m_base) m_base->getOriginalStrings(bases); for (auto &b : bases) { ar->parseOnDemandByClass(Util::toLower(b)); } vector<UserAttributePtr> attrs; if (m_attrList) { for (int i = 0; i < m_attrList->getCount(); ++i) { UserAttributePtr a = dynamic_pointer_cast<UserAttribute>((*m_attrList)[i]); attrs.push_back(a); } } StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this()); ClassScopePtr classScope(new ClassScope(kindOf, m_originalName, m_originalParent, bases, m_docComment, stmt, attrs)); setBlockScope(classScope); if (!fs->addClass(ar, classScope)) { m_ignored = true; return; } if (Option::PersistenceHook) { classScope->setPersistent(Option::PersistenceHook(classScope, fs)); } if (m_stmt) { MethodStatementPtr constructor; // flatten continuation StatementList into MethodStatements for (int i = 0; i < m_stmt->getCount(); i++) { StatementListPtr stmts = dynamic_pointer_cast<StatementList>((*m_stmt)[i]); if (stmts) { m_stmt->removeElement(i); for (int j = 0; j < stmts->getCount(); j++) { m_stmt->insertElement((*stmts)[j], i + j); } } } for (int i = 0; i < m_stmt->getCount(); i++) { MethodStatementPtr meth = dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]); if (meth && meth->getName() == "__construct") { constructor = meth; break; } } for (int i = 0; i < m_stmt->getCount(); i++) { if (!constructor) { MethodStatementPtr meth = dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]); if (meth && meth->getName() == classScope->getName() && !classScope->isTrait()) { // class-name constructor constructor = meth; classScope->setAttribute(ClassScope::ClassNameConstructor); } } IParseHandlerPtr ph = dynamic_pointer_cast<IParseHandler>((*m_stmt)[i]); ph->onParseRecur(ar, classScope); } if (constructor && constructor->getModifiers()->isStatic()) { constructor->parseTimeFatal(Compiler::InvalidAttribute, "Constructor %s::%s() cannot be static", classScope->getOriginalName().c_str(), constructor->getOriginalName().c_str()); } } }
void ClassStatement::onParse(AnalysisResultConstPtr ar, FileScopePtr fs) { ClassScope::KindOf kindOf = ClassScope::KindOf::ObjectClass; switch (m_type) { case T_CLASS: kindOf = ClassScope::KindOf::ObjectClass; break; case T_ABSTRACT: kindOf = ClassScope::KindOf::AbstractClass; break; case T_STATIC: // Slight hack: see comments in hphp.y kindOf = ClassScope::KindOf::UtilClass; break; case T_FINAL: kindOf = ClassScope::KindOf::FinalClass; break; case T_TRAIT: kindOf = ClassScope::KindOf::Trait; break; case T_ENUM: kindOf = ClassScope::KindOf::Enum; break; default: assert(false); } std::vector<std::string> bases; if (!m_originalParent.empty()) { bases.push_back(m_originalParent); } if (m_base) m_base->getStrings(bases); for (auto &b : bases) { ar->parseOnDemandByClass(b); } std::vector<UserAttributePtr> attrs; if (m_attrList) { for (int i = 0; i < m_attrList->getCount(); ++i) { UserAttributePtr a = dynamic_pointer_cast<UserAttribute>((*m_attrList)[i]); attrs.push_back(a); } } StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this()); auto classScope = std::make_shared<ClassScope>( fs, kindOf, m_originalName, m_originalParent, bases, m_docComment, stmt, attrs); setBlockScope(classScope); if (!fs->addClass(ar, classScope)) { m_ignored = true; return; } classScope->setPersistent(false); if (m_stmt) { MethodStatementPtr constructor = nullptr; MethodStatementPtr destructor = nullptr; MethodStatementPtr clone = nullptr; // flatten continuation StatementList into MethodStatements for (int i = 0; i < m_stmt->getCount(); i++) { StatementListPtr stmts = dynamic_pointer_cast<StatementList>((*m_stmt)[i]); if (stmts) { m_stmt->removeElement(i); for (int j = 0; j < stmts->getCount(); j++) { m_stmt->insertElement((*stmts)[j], i + j); } } } for (int i = 0; i < m_stmt->getCount(); i++) { MethodStatementPtr meth = dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]); if (meth) { if (meth->isNamed("__construct")) { constructor = meth; continue; } if (meth->isNamed("__destruct")) { destructor = meth; continue; } if (meth->isNamed("__clone")) { clone = meth; continue; } } if (constructor && destructor && clone) { break; } } for (int i = 0; i < m_stmt->getCount(); i++) { if (!constructor) { MethodStatementPtr meth = dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]); if (meth && meth->isNamed(classScope->getOriginalName()) && !classScope->isTrait()) { // class-name constructor constructor = meth; classScope->setAttribute(ClassScope::ClassNameConstructor); } } IParseHandlerPtr ph = dynamic_pointer_cast<IParseHandler>((*m_stmt)[i]); ph->onParseRecur(ar, fs, classScope); } if (constructor && constructor->getModifiers()->isStatic()) { constructor->parseTimeFatal(fs, Compiler::InvalidAttribute, "Constructor %s::%s() cannot be static", classScope->getOriginalName().c_str(), constructor->getOriginalName().c_str()); } if (destructor && destructor->getModifiers()->isStatic()) { destructor->parseTimeFatal(fs, Compiler::InvalidAttribute, "Destructor %s::%s() cannot be static", classScope->getOriginalName().c_str(), destructor->getOriginalName().c_str()); } if (clone && clone->getModifiers()->isStatic()) { clone->parseTimeFatal(fs, Compiler::InvalidAttribute, "Clone method %s::%s() cannot be static", classScope->getOriginalName().c_str(), clone->getOriginalName().c_str()); } } }
void FunctionScope::init(AnalysisResultConstPtr ar) { m_dynamicInvoke = false; bool canInline = true; if (m_pseudoMain) { canInline = false; m_variables->forceVariants(ar, VariableTable::AnyVars); setReturnType(ar, Type::Variant); } if (m_refReturn) { m_returnType = Type::Variant; } if (!strcasecmp(m_name.c_str(), "__autoload")) { setVolatile(); } // FileScope's flags are from parser, but VariableTable has more flags // coming from type inference phase. So we are tranferring these flags // just for better modularization between FileScope and VariableTable. if (m_attribute & FileScope::ContainsDynamicVariable) { m_variables->setAttribute(VariableTable::ContainsDynamicVariable); } if (m_attribute & FileScope::ContainsLDynamicVariable) { m_variables->setAttribute(VariableTable::ContainsLDynamicVariable); } if (m_attribute & FileScope::ContainsExtract) { m_variables->setAttribute(VariableTable::ContainsExtract); } if (m_attribute & FileScope::ContainsAssert) { m_variables->setAttribute(VariableTable::ContainsAssert); } if (m_attribute & FileScope::ContainsCompact) { m_variables->setAttribute(VariableTable::ContainsCompact); } if (m_attribute & FileScope::ContainsUnset) { m_variables->setAttribute(VariableTable::ContainsUnset); } if (m_attribute & FileScope::ContainsGetDefinedVars) { m_variables->setAttribute(VariableTable::ContainsGetDefinedVars); } if (m_stmt && Option::AllVolatile && !m_pseudoMain && !m_method) { m_volatile = true; } m_dynamic = Option::IsDynamicFunction(m_method, m_name) || Option::EnableEval == Option::FullEval || Option::AllDynamic; if (!m_method && Option::DynamicInvokeFunctions.find(m_name) != Option::DynamicInvokeFunctions.end()) { setDynamicInvoke(); } if (m_modifiers) { m_virtual = m_modifiers->isAbstract(); } if (m_stmt) { MethodStatementPtr stmt = dynamic_pointer_cast<MethodStatement>(m_stmt); StatementListPtr stmts = stmt->getStmts(); if (stmts) { if (stmts->getRecursiveCount() > Option::InlineFunctionThreshold) canInline = false; for (int i = 0; i < stmts->getCount(); i++) { StatementPtr stmt = (*stmts)[i]; stmt->setFileLevel(); if (stmt->is(Statement::KindOfExpStatement)) { ExpStatementPtr expStmt = dynamic_pointer_cast<ExpStatement>(stmt); ExpressionPtr exp = expStmt->getExpression(); exp->setTopLevel(); } } } } else { canInline = false; } m_inlineable = canInline; }
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); }
FunctionScope::FunctionScope(AnalysisResultPtr ar, bool method, const std::string &name, StatementPtr stmt, bool reference, int minParam, int maxParam, ModifierExpressionPtr modifiers, int attribute, const std::string &docComment, FileScopePtr file, bool inPseudoMain /* = false */) : BlockScope(name, docComment, stmt, BlockScope::FunctionScope), m_method(method), m_file(file), m_minParam(0), m_maxParam(0), m_attribute(attribute), m_refReturn(reference), m_modifiers(modifiers), m_virtual(false), m_overriding(false), m_redeclaring(-1), m_volatile(false), m_ignored(false), m_pseudoMain(inPseudoMain), m_magicMethod(false), m_system(false), m_inlineable(false), m_sep(false), m_containsThis(false), m_staticMethodAutoFixed(false), m_callTempCountMax(0), m_callTempCountCurrent(0) { bool canInline = true; if (inPseudoMain) { canInline = false; m_variables->forceVariants(ar); setReturnType(ar, Type::Variant); } setParamCounts(ar, minParam, maxParam); if (m_refReturn) { m_returnType = Type::Variant; } // FileScope's flags are from parser, but VariableTable has more flags // coming from type inference phase. So we are tranferring these two // flags just for better modularization between FileScope and VariableTable. if (m_attribute & FileScope::ContainsDynamicVariable) { m_variables->setAttribute(VariableTable::ContainsDynamicVariable); } if (m_attribute & FileScope::ContainsLDynamicVariable) { m_variables->setAttribute(VariableTable::ContainsLDynamicVariable); } if (m_attribute & FileScope::ContainsExtract) { m_variables->setAttribute(VariableTable::ContainsExtract); } if (m_attribute & FileScope::ContainsCompact) { m_variables->setAttribute(VariableTable::ContainsCompact); } if (m_attribute & FileScope::ContainsUnset) { m_variables->setAttribute(VariableTable::ContainsUnset); } if (m_attribute & FileScope::ContainsGetDefinedVars) { m_variables->setAttribute(VariableTable::ContainsGetDefinedVars); } if (m_stmt && Option::AllVolatile) { m_volatile = true; } m_dynamic = Option::IsDynamicFunction(method, m_name) || Option::EnableEval == Option::FullEval; if (modifiers) { m_virtual = modifiers->isAbstract(); } if (m_stmt) { MethodStatementPtr stmt = dynamic_pointer_cast<MethodStatement>(m_stmt); StatementListPtr stmts = stmt->getStmts(); if (stmts) { if (stmts->getRecursiveCount() > Option::InlineFunctionThreshold) canInline = false; for (int i = 0; i < stmts->getCount(); i++) { StatementPtr stmt = (*stmts)[i]; stmt->setFileLevel(); if (stmt->is(Statement::KindOfExpStatement)) { ExpStatementPtr expStmt = dynamic_pointer_cast<ExpStatement>(stmt); ExpressionPtr exp = expStmt->getExpression(); exp->setTopLevel(); } } } } else { canInline = false; } m_inlineable = canInline; }