/* +----------------------------------------------------------------------+ | HipHop for PHP | +----------------------------------------------------------------------+ | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ */ #include #include #include #include #include #include #include #include #include #include #include #include using namespace HPHP; /////////////////////////////////////////////////////////////////////////////// // constructors/destructors InterfaceStatement::InterfaceStatement (STATEMENT_CONSTRUCTOR_BASE_PARAMETERS, const std::string &name, ExpressionListPtr base, const std::string &docComment, StatementListPtr stmt, ExpressionListPtr attrList) : Statement(STATEMENT_CONSTRUCTOR_BASE_PARAMETER_VALUES), m_originalName(name), m_base(base), m_docComment(docComment), m_stmt(stmt), m_attrList(attrList) { m_name = Util::toLower(name); if (m_base) m_base->toLower(); } InterfaceStatement::InterfaceStatement (STATEMENT_CONSTRUCTOR_PARAMETERS, const std::string &name, ExpressionListPtr base, const std::string &docComment, StatementListPtr stmt, ExpressionListPtr attrList) : Statement(STATEMENT_CONSTRUCTOR_PARAMETER_VALUES(InterfaceStatement)), m_originalName(name), m_base(base), m_docComment(docComment), m_stmt(stmt), m_attrList(attrList) { m_name = Util::toLower(name); if (m_base) m_base->toLower(); } StatementPtr InterfaceStatement::clone() { InterfaceStatementPtr stmt(new InterfaceStatement(*this)); stmt->m_stmt = Clone(m_stmt); stmt->m_base = Clone(m_base); return stmt; } bool InterfaceStatement::hasImpl() const { return true; } int InterfaceStatement::getRecursiveCount() const { return m_stmt ? m_stmt->getRecursiveCount() : 0; } /////////////////////////////////////////////////////////////////////////////// // parser functions void InterfaceStatement::onParse(AnalysisResultConstPtr ar, FileScopePtr scope) { vector bases; if (m_base) m_base->getOriginalStrings(bases); for (auto &b : bases) { ar->parseOnDemandByClass(Util::toLower(b)); } StatementPtr stmt = dynamic_pointer_cast(shared_from_this()); vector attrs; if (m_attrList) { for (int i = 0; i < m_attrList->getCount(); ++i) { UserAttributePtr a = dynamic_pointer_cast((*m_attrList)[i]); attrs.push_back(a); } } ClassScopePtr classScope (new ClassScope(ClassScope::KindOfInterface, m_name, "", bases, m_docComment, stmt, attrs)); setBlockScope(classScope); scope->addClass(ar, classScope); if (Option::PersistenceHook) { classScope->setPersistent(Option::PersistenceHook(classScope, scope)); } if (m_stmt) { for (int i = 0; i < m_stmt->getCount(); i++) { IParseHandlerPtr ph = dynamic_pointer_cast((*m_stmt)[i]); ph->onParseRecur(ar, classScope); } } } /////////////////////////////////////////////////////////////////////////////// // static analysis functions int InterfaceStatement::getLocalEffects() const { ClassScopeRawPtr classScope = getClassScope(); return classScope->isVolatile() ? OtherEffect | CanThrow : NoEffect; } std::string InterfaceStatement::getName() const { return string("Interface ") + getScope()->getName(); } bool InterfaceStatement::checkVolatileBases(AnalysisResultConstPtr ar) { ClassScopeRawPtr classScope = getClassScope(); assert(!classScope->isVolatile()); const vector &bases = classScope->getBases(); for (vector::const_iterator it = bases.begin(); it != bases.end(); ++it) { ClassScopePtr base = ar->findClass(*it); if (base && base->isVolatile()) return true; } return false; } void InterfaceStatement::checkVolatile(AnalysisResultConstPtr ar) { ClassScopeRawPtr classScope = getClassScope(); // redeclared classes/interfaces are automatically volatile if (!classScope->isVolatile()) { if (checkVolatileBases(ar)) { // if any base is volatile, the class is volatile classScope->setVolatile(); } } if (classScope->isVolatile()) { classScope->getOuterScope()->getVariables()-> setAttribute(VariableTable::NeedGlobalPointer); } } void InterfaceStatement::analyzeProgram(AnalysisResultPtr ar) { ClassScopeRawPtr classScope = getClassScope(); if (m_stmt) { m_stmt->analyzeProgram(ar); } checkVolatile(ar); if (ar->getPhase() != AnalysisResult::AnalyzeAll) return; vector bases; if (m_base) m_base->getStrings(bases); for (unsigned int i = 0; i < bases.size(); i++) { addUserClass(ar, bases[i]); ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { if (!cls->isInterface()) { Compiler::Error( Compiler::InvalidDerivation, shared_from_this(), cls->getOriginalName() + " must be an interface"); } if (cls->isUserClass()) { cls->addUse(classScope, BlockScope::UseKindParentRef); } } } } ConstructPtr InterfaceStatement::getNthKid(int n) const { switch (n) { case 0: return m_stmt; case 1: return m_base; default: assert(false); break; } return ConstructPtr(); } int InterfaceStatement::getKidCount() const { return 2; } void InterfaceStatement::setNthKid(int n, ConstructPtr cp) { switch (n) { case 0: m_stmt = boost::dynamic_pointer_cast(cp); break; case 1: m_base = boost::dynamic_pointer_cast(cp); break; default: assert(false); break; } } StatementPtr InterfaceStatement::preOptimize(AnalysisResultConstPtr ar) { if (ar->getPhase() >= AnalysisResult::AnalyzeAll) { checkVolatile(ar); } return StatementPtr(); } void InterfaceStatement::inferTypes(AnalysisResultPtr ar) { } /////////////////////////////////////////////////////////////////////////////// // code generation functions void InterfaceStatement::getAllParents(AnalysisResultConstPtr ar, std::vector &names) { vector bases; if (m_base) { m_base->getStrings(bases); for (unsigned int i = 0; i < bases.size(); i++) { ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { cls->getAllParents(ar, names); names.push_back(cls->getOriginalName()); } } } } void InterfaceStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopeRawPtr classScope = getClassScope(); if (cg.getOutput() == CodeGenerator::InlinedPHP || cg.getOutput() == CodeGenerator::TrimmedPHP) { if (!classScope->isUserClass()) { return; } } cg_printf("interface %s", m_originalName.c_str()); if (m_base) { cg_printf(" extends "); m_base->outputPHP(cg, ar); } cg_indentBegin(" {\n"); classScope->outputPHP(cg, ar); if (m_stmt) m_stmt->outputPHP(cg, ar); cg_indentEnd("}\n"); }