void ClassStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr classScope = m_classScope.lock(); if (!classScope->isUserClass()) return; if (ar) ar->pushScope(classScope); switch (m_type) { case T_CLASS: break; case T_ABSTRACT: cg_printf("abstract "); break; case T_FINAL: cg_printf("final "); break; default: ASSERT(false); } cg_printf("class %s", m_name.c_str()); if (!m_parent.empty()) { cg_printf(" extends %s", m_parent.c_str()); } if (m_base) { cg_printf(" implements "); m_base->outputPHP(cg, ar); } cg_indentBegin(" {\n"); m_classScope.lock()->outputPHP(cg, ar); if (m_stmt) m_stmt->outputPHP(cg, ar); cg_indentEnd("}\n"); if (ar) ar->popScope(); }
void BlockScope::inferTypes(AnalysisResultPtr ar) { if (m_stmt) { ar->pushScope(shared_from_this()); m_stmt->inferTypes(ar); ar->popScope(); } }
void MethodStatement::inferTypes(AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); if (ar->getPhase() == AnalysisResult::FirstInference && m_stmt) { if (m_stmt->hasRetExp() || funcScope->inPseudoMain() || funcScope->getReturnType()) { bool lastIsReturn = false; if (m_stmt->getCount()) { StatementPtr lastStmt = (*m_stmt)[m_stmt->getCount()-1]; if (lastStmt->is(Statement::KindOfReturnStatement)) { lastIsReturn = true; } } if (!lastIsReturn && !(funcScope->inPseudoMain() && !Option::GenerateCPPMain)) { ExpressionPtr constant = funcScope->inPseudoMain() ? CONSTANT("true") : CONSTANT("null"); ReturnStatementPtr returnStmt = ReturnStatementPtr(new ReturnStatement(getLocation(), Statement::KindOfReturnStatement, constant)); m_stmt->addElement(returnStmt); } } } ar->pushScope(funcScope); if (m_params) { m_params->inferAndCheck(ar, NEW_TYPE(Any), false); } if (m_stmt) { m_stmt->inferTypes(ar); } ar->popScope(); }
void ClassStatement::inferTypes(AnalysisResultPtr ar) { if (m_stmt) { ClassScopePtr classScope = m_classScope.lock(); ar->pushScope(classScope); m_stmt->inferTypes(ar); ar->popScope(); } }
StatementPtr InterfaceStatement::postOptimize(AnalysisResultPtr ar) { ar->postOptimize(m_base); if (m_stmt) { ClassScopePtr classScope = m_classScope.lock(); ar->pushScope(classScope); ar->postOptimize(m_stmt); ar->popScope(); } return StatementPtr(); }
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 InterfaceStatement::preOptimize(AnalysisResultPtr ar) { ar->preOptimize(m_base); if (m_stmt) { ClassScopePtr classScope = m_classScope.lock(); ar->pushScope(classScope); ar->preOptimize(m_stmt); ar->popScope(); } if (ar->getPhase() >= AnalysisResult::AnalyzeAll) { checkVolatile(ar); } return StatementPtr(); }
void InterfaceStatement::inferTypes(AnalysisResultPtr ar) { vector<string> bases; if (m_base) m_base->getStrings(bases); for (unsigned int i = 0; i < bases.size(); i++) { addUserClass(ar, bases[i]); } if (m_stmt) { ClassScopePtr classScope = m_classScope.lock(); ar->pushScope(classScope); m_stmt->inferTypes(ar); ar->popScope(); } }
void ClassStatement::analyzeProgramImpl(AnalysisResultPtr ar) { vector<string> bases; if (!m_parent.empty()) bases.push_back(m_parent); if (m_base) m_base->getStrings(bases); for (unsigned int i = 0; i < bases.size(); i++) { string className = bases[i]; addUserClass(ar, bases[i]); } ClassScopePtr classScope = m_classScope.lock(); if (hasHphpNote("Volatile")) { classScope->setVolatile(); } checkVolatile(ar); if (m_stmt) { ar->pushScope(classScope); m_stmt->analyzeProgram(ar); ar->popScope(); } if (ar->getPhase() != AnalysisResult::AnalyzeAll) return; DependencyGraphPtr dependencies = ar->getDependencyGraph(); for (unsigned int i = 0; i < bases.size(); i++) { ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { if ((!cls->isInterface() && (m_parent.empty() || i > 0 )) || (cls->isInterface() && (!m_parent.empty() && i == 0 ))) { ar->getCodeError()->record(CodeError::InvalidDerivation, shared_from_this(), ConstructPtr(), cls->getOriginalName().c_str()); } if (dependencies->checkCircle(DependencyGraph::KindOfClassDerivation, m_originalName, cls->getOriginalName())) { ar->getCodeError()->record(CodeError::InvalidDerivation, shared_from_this(), ConstructPtr(), cls->getOriginalName().c_str()); m_parent = ""; m_base = ExpressionListPtr(); classScope->clearBases(); } else if (cls->isUserClass()) { dependencies->add(DependencyGraph::KindOfClassDerivation, ar->getName(), m_originalName, shared_from_this(), cls->getOriginalName(), cls->getStmt()); } } } }
void FunctionStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); if (!funcScope->isUserFunction()) return; if (ar) ar->pushScope(funcScope); cg_printf("function "); if (m_ref) cg_printf("&"); cg_printf("%s(", m_name.c_str()); if (m_params) m_params->outputPHP(cg, ar); cg_indentBegin(") {\n"); m_funcScope.lock()->outputPHP(cg, ar); if (m_stmt) m_stmt->outputPHP(cg, ar); cg_indentEnd("}\n"); if (ar) ar->popScope(); }
void MethodStatement::analyzeProgramImpl(AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); // registering myself as a parent in dependency graph, so that // (1) we can tell orphaned parents // (2) overwrite non-master copy of function declarations if (ar->isFirstPass()) { ar->getDependencyGraph()->addParent(DependencyGraph::KindOfFunctionCall, "", getFullName(), shared_from_this()); if (Option::AllDynamic || hasHphpNote("Dynamic") || funcScope->isSepExtension() || BuiltinSymbols::IsDeclaredDynamic(m_name) || Option::IsDynamicFunction(m_method, m_name)) { funcScope->setDynamic(); } if (hasHphpNote("Volatile")) funcScope->setVolatile(); } funcScope->setIncludeLevel(ar->getIncludeLevel()); ar->pushScope(funcScope); if (m_params) { m_params->analyzeProgram(ar); if (Option::GenRTTIProfileData && ar->getPhase() == AnalysisResult::AnalyzeFinal) { addParamRTTI(ar); } } if (m_stmt) m_stmt->analyzeProgram(ar); if (ar->isFirstPass()) { if (!funcScope->isStatic() && ar->getClassScope() && funcScope->getVariables()-> getAttribute(VariableTable::ContainsDynamicVariable)) { // Add this to variable table if we'll need it in a lookup table // Use object because there's no point to specializing, just makes // code gen harder when dealing with redeclared classes. TypePtr tp(NEW_TYPE(Object)); funcScope->getVariables()->add("this", tp, true, ar, shared_from_this(), ModifierExpressionPtr()); } FunctionScope::RecordRefParamInfo(m_name, funcScope); } ar->popScope(); }
void ClassStatement::analyzeProgram(AnalysisResultPtr ar) { vector<string> bases; if (!m_parent.empty()) bases.push_back(m_parent); if (m_base) m_base->getStrings(bases); for (unsigned int i = 0; i < bases.size(); i++) { string className = bases[i]; addUserClass(ar, bases[i]); } ClassScopePtr classScope = m_classScope.lock(); if (hasHphpNote("Volatile")) classScope->setVolatile(); FunctionScopePtr func = ar->getFunctionScope(); // redeclared classes are automatically volatile if (classScope->isVolatile()) { func->getVariables()->setAttribute(VariableTable::NeedGlobalPointer); } if (m_stmt) { ar->pushScope(classScope); m_stmt->analyzeProgram(ar); ar->popScope(); } DependencyGraphPtr dependencies = ar->getDependencyGraph(); for (unsigned int i = 0; i < bases.size(); i++) { ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { if (dependencies->checkCircle(DependencyGraph::KindOfClassDerivation, m_originalName, cls->getOriginalName())) { ClassScopePtr classScope = m_classScope.lock(); ar->getCodeError()->record(CodeError::InvalidDerivation, shared_from_this(), ConstructPtr(), cls->getOriginalName()); m_parent = ""; m_base = ExpressionListPtr(); classScope->clearBases(); } else if (cls->isUserClass()) { dependencies->add(DependencyGraph::KindOfClassDerivation, ar->getName(), m_originalName, shared_from_this(), cls->getOriginalName(), cls->getStmt()); } } } }
void InterfaceStatement::analyzeProgramImpl(AnalysisResultPtr ar) { ClassScopePtr classScope = m_classScope.lock(); if (hasHphpNote("Volatile")) classScope->setVolatile(); if (m_stmt) { classScope->setIncludeLevel(ar->getIncludeLevel()); ar->pushScope(classScope); m_stmt->analyzeProgram(ar); ar->popScope(); } ar->recordClassSource(m_name, ar->getFileScope()->getName()); checkVolatile(ar); if (ar->getPhase() != AnalysisResult::AnalyzeAll) return; vector<string> bases; if (m_base) m_base->getStrings(bases); DependencyGraphPtr dependencies = ar->getDependencyGraph(); for (unsigned int i = 0; i < bases.size(); i++) { ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { if (!cls->isInterface()) { ar->getCodeError()->record(CodeError::InvalidDerivation, shared_from_this(), ConstructPtr(), cls->getOriginalName()); } if (dependencies->checkCircle(DependencyGraph::KindOfClassDerivation, m_originalName, cls->getOriginalName())) { ClassScopePtr classScope = m_classScope.lock(); ar->getCodeError()->record(CodeError::InvalidDerivation, shared_from_this(), ConstructPtr(), cls->getOriginalName()); m_base = ExpressionListPtr(); classScope->clearBases(); } else if (cls->isUserClass()) { dependencies->add(DependencyGraph::KindOfClassDerivation, ar->getName(), m_originalName, shared_from_this(), cls->getOriginalName(), cls->getStmt()); } } } }
void MethodStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); if (ar) ar->pushScope(funcScope); m_modifiers->outputPHP(cg, ar); cg.printf(" function "); if (m_ref) cg.printf("&"); cg.printf("%s(", m_originalName.c_str()); if (m_params) m_params->outputPHP(cg, ar); if (m_stmt) { cg.indentBegin(") {\n"); funcScope->outputPHP(cg, ar); m_stmt->outputPHP(cg, ar); cg.indentEnd("}\n"); } else { cg.printf(");\n"); } if (ar) ar->popScope(); }
StatementPtr MethodStatement::preOptimize(AnalysisResultPtr ar) { ar->preOptimize(m_modifiers); ar->preOptimize(m_params); FunctionScopePtr funcScope = m_funcScope.lock(); ar->pushScope(funcScope); if (ar->getPhase() != AnalysisResult::AnalyzeInclude && AliasManager::doLocalCopyProp()) { bool flag; do { AliasManager am; MethodStatementPtr self = static_pointer_cast<MethodStatement>(shared_from_this()); flag = am.optimize(ar, self); ar->preOptimize(m_stmt); } while (flag); } else { ar->preOptimize(m_stmt); } ar->popScope(); return StatementPtr(); }
ExpressionPtr ClassConstantExpression::preOptimize(AnalysisResultPtr ar) { if (ar->getPhase() < AnalysisResult::FirstPreOptimize) { return ExpressionPtr(); } if (m_redeclared) return ExpressionPtr(); ClassScopePtr cls = ar->resolveClass(m_className); if (!cls || cls->isRedeclaring()) return ExpressionPtr(); ConstantTablePtr constants = cls->getConstants(); if (constants->isExplicitlyDeclared(m_varName)) { ConstructPtr decl = constants->getValue(m_varName); if (decl) { ExpressionPtr value = dynamic_pointer_cast<Expression>(decl); if (!m_visited) { m_visited = true; ar->pushScope(cls); ExpressionPtr optExp = value->preOptimize(ar); ar->popScope(); m_visited = false; if (optExp) value = optExp; } if (value->isScalar()) { // inline the value if (value->is(Expression::KindOfScalarExpression)) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>(Clone(value)); exp->setComment(getText()); return exp; } else if (value->is(Expression::KindOfConstantExpression)) { // inline the value ConstantExpressionPtr exp = dynamic_pointer_cast<ConstantExpression>(Clone(value)); exp->setComment(getText()); return exp; } } } } return ExpressionPtr(); }
void InterfaceStatement::onParse(AnalysisResultPtr ar) { vector<string> bases; if (m_base) m_base->getStrings(bases); StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this()); ClassScopePtr classScope(new ClassScope(ClassScope::KindOfInterface, m_name, "", bases, m_docComment, stmt, ar->getFileScope())); m_classScope = classScope; ar->getFileScope()->addClass(ar, classScope); ar->getDependencyGraph()->addParent(DependencyGraph::KindOfProgramUserClass, "", m_originalName, stmt); if (m_stmt) { ar->pushScope(classScope); for (int i = 0; i < m_stmt->getCount(); i++) { IParseHandlerPtr ph = dynamic_pointer_cast<IParseHandler>((*m_stmt)[i]); ph->onParse(ar); } ar->popScope(); } }
void MethodStatement::outputCPPStaticMethodWrapper(CodeGenerator &cg, AnalysisResultPtr ar, const char *cls) { if (!m_modifiers->isStatic() || !m_stmt) return; FunctionScopePtr funcScope = m_funcScope.lock(); ar->pushScope(funcScope); m_modifiers->outputCPP(cg, ar); TypePtr type = funcScope->getReturnType(); if (type) { type->outputCPPDecl(cg, ar); } else { cg.printf("void"); } cg.printf(" %s%s(", Option::MethodPrefix, m_name.c_str()); CodeGenerator::Context old = cg.getContext(); cg.setContext(CodeGenerator::CppStaticMethodWrapper); funcScope->outputCPPParamsDecl(cg, ar, m_params, true); cg.setContext(old); cg.printf(") { %s%s%s(\"%s\"", type ? "return " : "", Option::MethodImplPrefix, m_name.c_str(), cls); if (funcScope->isVariableArgument()) { cg.printf(", num_args"); } if (m_params) { for (int i = 0; i < m_params->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); ASSERT(param); cg.printf(", %s%s", Option::VariablePrefix, param->getName().c_str()); } } if (funcScope->isVariableArgument()) { cg.printf(", args"); } cg.printf("); }\n"); ar->popScope(); }
void InterfaceStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr classScope = m_classScope.lock(); if (cg.getOutput() == CodeGenerator::InlinedPHP || cg.getOutput() == CodeGenerator::TrimmedPHP) { if (!classScope->isUserClass()) { return; } } if (ar) ar->pushScope(classScope); cg.printf("interface %s", m_name.c_str()); if (m_base) { cg.printf(" extends "); m_base->outputPHP(cg, ar); } cg.indentBegin(" {\n"); m_classScope.lock()->outputPHP(cg, ar); if (m_stmt) m_stmt->outputPHP(cg, ar); cg.indentEnd("}\n"); if (ar) ar->popScope(); }
void ClassStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr classScope = m_classScope.lock(); if (cg.getContext() == CodeGenerator::NoContext) { if (classScope->isRedeclaring()) { cg_printf("g->%s%s = ClassStaticsPtr(NEW(%s%s)());\n", Option::ClassStaticsObjectPrefix, cg.formatLabel(m_name).c_str(), Option::ClassStaticsPrefix, classScope->getId(cg).c_str()); cg_printf("g->%s%s = &%s%s;\n", Option::ClassStaticsCallbackPrefix, cg.formatLabel(m_name).c_str(), Option::ClassWrapperFunctionPrefix, classScope->getId(cg).c_str()); } if (classScope->isVolatile()) { cg_printf("g->CDEC(%s) = true;\n", m_name.c_str()); } const vector<string> &bases = classScope->getBases(); for (vector<string>::const_iterator it = bases.begin(); it != bases.end(); ++it) { ClassScopePtr base = ar->findClass(*it); if (base && base->isVolatile()) { cg_printf("checkClassExists(\"%s\", g);\n", base->getOriginalName().c_str()); } } return; } if (cg.getContext() != CodeGenerator::CppForwardDeclaration) { printSource(cg); } ar->pushScope(classScope); string clsNameStr = classScope->getId(cg); const char *clsName = clsNameStr.c_str(); bool redeclared = classScope->isRedeclaring(); switch (cg.getContext()) { case CodeGenerator::CppForwardDeclaration: if (Option::GenerateCPPMacros) { cg_printf("FORWARD_DECLARE_CLASS(%s)\n", clsName); if (redeclared) { cg_printf("FORWARD_DECLARE_REDECLARED_CLASS(%s)\n", clsName); } } if (m_stmt) { cg.setContext(CodeGenerator::CppClassConstantsDecl); m_stmt->outputCPP(cg, ar); cg.setContext(CodeGenerator::CppForwardDeclaration); } break; case CodeGenerator::CppDeclaration: { bool system = cg.getOutput() == CodeGenerator::SystemCPP; ClassScopePtr parCls; if (!m_parent.empty()) { parCls = ar->findClass(m_parent); if (parCls && parCls->isRedeclaring()) parCls.reset(); } cg_printf("class %s%s", Option::ClassPrefix, clsName); if (!m_parent.empty() && classScope->derivesDirectlyFrom(ar, m_parent)) { if (!parCls) { cg_printf(" : public DynamicObjectData"); } else { cg_printf(" : public %s%s", Option::ClassPrefix, parCls->getId(cg).c_str()); } } else { if (classScope->derivesFromRedeclaring()) { cg_printf(" : public DynamicObjectData"); } else if (system) { cg_printf(" : public ExtObjectData"); } else { cg_printf(" : public ObjectData"); } } if (m_base && Option::UseVirtualDispatch) { for (int i = 0; i < m_base->getCount(); i++) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>((*m_base)[i]); const char *intf = exp->getString().c_str(); ClassScopePtr intfClassScope = ar->findClass(intf); if (intfClassScope && !intfClassScope->isRedeclaring() && classScope->derivesDirectlyFrom(ar, intf) && (!parCls || !parCls->derivesFrom(ar, intf, true, false))) { string id = intfClassScope->getId(cg); cg_printf(", public %s%s", Option::ClassPrefix, id.c_str()); } } } cg_indentBegin(" {\n"); if (Option::GenerateCPPMacros) { // Get all of this class's ancestors vector<string> bases; getAllParents(ar, bases); // Eliminate duplicates sort(bases.begin(), bases.end()); bases.erase(unique(bases.begin(), bases.end()), bases.end()); cg_indentBegin("BEGIN_CLASS_MAP(%s)\n", Util::toLower(classScope->getName()).c_str()); for (unsigned int i = 0; i < bases.size(); i++) { cg_printf("PARENT_CLASS(%s)\n", bases[i].c_str()); } if (classScope->derivesFromRedeclaring()) { cg_printf("CLASS_MAP_REDECLARED()\n"); } cg_indentEnd("END_CLASS_MAP(%s)\n", clsName); } if (Option::GenerateCPPMacros) { bool dyn = (!parCls && !m_parent.empty()) || classScope->derivesFromRedeclaring() == ClassScope::DirectFromRedeclared; bool idyn = parCls && classScope->derivesFromRedeclaring() == ClassScope::IndirectFromRedeclared; bool redec = classScope->isRedeclaring(); if (!classScope->derivesFromRedeclaring()) { outputCPPClassDecl(cg, ar, clsName, m_originalName.c_str(), parCls ? parCls->getId(cg).c_str() : "ObjectData"); } else { cg_printf("DECLARE_DYNAMIC_CLASS(%s, %s, %s)\n", clsName, m_originalName.c_str(), dyn || !parCls ? "DynamicObjectData" : parCls->getId(cg).c_str()); } if (system || Option::EnableEval >= Option::LimitedEval) { cg_printf("DECLARE_INVOKES_FROM_EVAL\n"); } if (dyn || idyn || redec) { if (redec) { cg_printf("DECLARE_ROOT;\n"); if (!dyn && !idyn) { cg_printf("private: ObjectData* root;\n"); cg_printf("public:\n"); cg_printf("virtual ObjectData *getRoot() { return root; }\n"); } } string conInit = ":"; if (dyn) { conInit += "DynamicObjectData(\"" + m_parent + "\", r)"; } else if (idyn) { conInit += string(Option::ClassPrefix) + parCls->getId(cg) + "(r?r:this)"; } else { conInit += "root(r?r:this)"; } cg_printf("%s%s(ObjectData* r = NULL)%s {}\n", Option::ClassPrefix, clsName, conInit.c_str()); } } cg_printf("void init();\n", Option::ClassPrefix, clsName); if (classScope->needLazyStaticInitializer()) { cg_printf("static GlobalVariables *lazy_initializer" "(GlobalVariables *g);\n"); } classScope->getVariables()->outputCPPPropertyDecl(cg, ar, classScope->derivesFromRedeclaring()); if (!classScope->getAttribute(ClassScope::HasConstructor)) { FunctionScopePtr func = classScope->findFunction(ar, "__construct", false); if (func && !func->isAbstract() && !classScope->isInterface()) { ar->pushScope(func); func->outputCPPCreateDecl(cg, ar); ar->popScope(); } } if (classScope->getAttribute(ClassScope::HasDestructor)) { cg_printf("public: virtual void destruct();\n"); } // doCall if (classScope->getAttribute(ClassScope::HasUnknownMethodHandler)) { cg_printf("Variant doCall(Variant v_name, Variant v_arguments, " "bool fatal);\n"); } // doGet if (classScope->getAttribute(ClassScope::HasUnknownPropHandler)) { cg_printf("Variant doGet(Variant v_name, bool error);\n"); } if (classScope->isRedeclaring() && !classScope->derivesFromRedeclaring()) { cg_printf("Variant doRootCall(Variant v_name, Variant v_arguments, " "bool fatal);\n"); } if (m_stmt) m_stmt->outputCPP(cg, ar); { set<string> done; classScope->outputCPPStaticMethodWrappers(cg, ar, done, clsName); } if (cg.getOutput() == CodeGenerator::SystemCPP && ar->isBaseSysRsrcClass(clsName) && !classScope->hasProperty("rsrc")) { cg_printf("public: Variant %srsrc;\n", Option::PropertyPrefix); } cg_indentEnd("};\n"); if (redeclared) { cg_indentBegin("class %s%s : public ClassStatics {\n", Option::ClassStaticsPrefix, clsName); cg_printf("public:\n"); cg_printf("DECLARE_OBJECT_ALLOCATION(%s%s);\n", Option::ClassStaticsPrefix, clsName); cg_printf("%s%s() : ClassStatics(%d) {}\n", Option::ClassStaticsPrefix, clsName, classScope->getRedeclaringId()); cg_indentBegin("Variant %sgetInit(const char *s, int64 hash = -1) {\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%sgetInit(s, hash);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentBegin("Variant %sget(const char *s, int64 hash = -1) {\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%sget(s, hash);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentBegin("Variant &%slval(const char* s, int64 hash = -1) {\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%slval(s, hash);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentBegin("Variant %sinvoke(const char *c, const char *s, " "CArrRef params, int64 hash = -1, bool fatal = true) " "{\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%sinvoke(c, s, params, hash, fatal);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentBegin("Object create(CArrRef params, bool init = true, " "ObjectData* root = NULL) {\n"); cg_printf("return Object((NEW(%s%s)(root))->" "dynCreate(params, init));\n", Option::ClassPrefix, clsName); cg_indentEnd("}\n"); cg_indentBegin("Variant %sconstant(const char* s) {\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%sconstant(s);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentBegin("Variant %sinvoke_from_eval(const char *c, " "const char *s, Eval::VariableEnvironment &env, " "const Eval::FunctionCallExpression *call, " "int64 hash = -1, bool fatal = true) " "{\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%sinvoke_from_eval(c, s, env, call, hash, " "fatal);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentEnd("};\n"); } classScope->outputCPPGlobalTableWrappersDecl(cg, ar); } break; case CodeGenerator::CppImplementation: if (m_stmt) { cg.setContext(CodeGenerator::CppClassConstantsImpl); m_stmt->outputCPP(cg, ar); cg.setContext(CodeGenerator::CppImplementation); } classScope->outputCPPSupportMethodsImpl(cg, ar); if (redeclared) { cg_printf("IMPLEMENT_OBJECT_ALLOCATION(%s%s);\n", Option::ClassStaticsPrefix, clsName); } cg_indentBegin("void %s%s::init() {\n", Option::ClassPrefix, clsName); if (!m_parent.empty()) { if (classScope->derivesFromRedeclaring() == ClassScope::DirectFromRedeclared) { cg_printf("parent->init();\n"); } else { cg_printf("%s%s::init();\n", Option::ClassPrefix, m_parent.c_str()); } } if (classScope->getVariables()-> getAttribute(VariableTable::NeedGlobalPointer)) { cg.printDeclareGlobals(); } cg.setContext(CodeGenerator::CppConstructor); if (m_stmt) m_stmt->outputCPP(cg, ar); // This is lame. Exception base class needs to prepare stacktrace outside // of its PHP constructor. Every subclass of exception also needs this // stacktrace, so we're adding an artificial __init__ in exception.php // and calling it here. if (m_name == "exception") { cg_printf("{CountableHelper h(this); t___init__();}\n"); } cg_indentEnd("}\n"); if (classScope->needStaticInitializer()) { cg_indentBegin("void %s%s::os_static_initializer() {\n", Option::ClassPrefix, clsName); cg.printDeclareGlobals(); cg.setContext(CodeGenerator::CppStaticInitializer); if (m_stmt) m_stmt->outputCPP(cg, ar); cg_indentEnd("}\n"); cg_indentBegin("void %s%s() {\n", Option::ClassStaticInitializerPrefix, clsName); cg_printf("%s%s::os_static_initializer();\n", Option::ClassPrefix, clsName); cg_indentEnd("}\n"); } if (classScope->needLazyStaticInitializer()) { cg_indentBegin("GlobalVariables *%s%s::lazy_initializer(" "GlobalVariables *g) {\n", Option::ClassPrefix, clsName); cg_indentBegin("if (!g->%s%s) {\n", Option::ClassStaticInitializerFlagPrefix, clsName); cg_printf("g->%s%s = true;\n", Option::ClassStaticInitializerFlagPrefix, clsName); cg.setContext(CodeGenerator::CppLazyStaticInitializer); if (m_stmt) m_stmt->outputCPP(cg, ar); cg_indentEnd("}\n"); cg_printf("return g;\n"); cg_indentEnd("}\n"); } cg.setContext(CodeGenerator::CppImplementation); if (m_stmt) m_stmt->outputCPP(cg, ar); break; case CodeGenerator::CppFFIDecl: case CodeGenerator::CppFFIImpl: if (m_stmt) m_stmt->outputCPP(cg, ar); break; case CodeGenerator::JavaFFI: { if (classScope->isRedeclaring()) break; // TODO support PHP namespaces, once HPHP supports it string packageName = Option::JavaFFIRootPackage; string packageDir = packageName; Util::replaceAll(packageDir, ".", "/"); string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix + packageDir + "/"; Util::mkdir(outputDir); // uses a different cg to generate a separate file for each PHP class // also, uses the original capitalized class name string clsFile = outputDir + getOriginalName() + ".java"; ofstream fcls(clsFile.c_str()); CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP); cgCls.setContext(CodeGenerator::JavaFFI); cgCls.printf("package %s;\n\n", packageName.c_str()); cgCls.printf("import hphp.*;\n\n"); printSource(cgCls); string clsModifier; switch (m_type) { case T_CLASS: break; case T_ABSTRACT: clsModifier = "abstract "; break; case T_FINAL: clsModifier = "final "; break; } cgCls.printf("public %sclass %s ", clsModifier.c_str(), getOriginalName().c_str()); ClassScopePtr parCls; if (!m_parent.empty()) parCls = ar->findClass(m_parent); if (!m_parent.empty() && classScope->derivesDirectlyFrom(ar, m_parent) && parCls && parCls->isUserClass() && !parCls->isRedeclaring()) { // system classes are not supported in static FFI translation // they shouldn't appear as superclasses as well cgCls.printf("extends %s", parCls->getOriginalName().c_str()); } else { cgCls.printf("extends HphpObject"); } if (m_base) { bool first = true; for (int i = 0; i < m_base->getCount(); i++) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>((*m_base)[i]); const char *intf = exp->getString().c_str(); ClassScopePtr intfClassScope = ar->findClass(intf); if (intfClassScope && classScope->derivesFrom(ar, intf, false, false) && intfClassScope->isUserClass()) { if (first) { cgCls.printf(" implements "); first = false; } else { cgCls.printf(", "); } cgCls.printf(intfClassScope->getOriginalName().c_str()); } } } cgCls.indentBegin(" {\n"); // constructor for initializing the variant pointer cgCls.printf("protected %s(long ptr) { super(ptr); }\n\n", getOriginalName().c_str()); FunctionScopePtr cons = classScope->findConstructor(ar, true); if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) { // if not an abstract class and not having an explicit constructor, // adds a default constructor outputJavaFFIConstructor(cgCls, ar, cons); } if (m_stmt) m_stmt->outputCPP(cgCls, ar); cgCls.indentEnd("}\n"); fcls.close(); } break; case CodeGenerator::JavaFFICppDecl: case CodeGenerator::JavaFFICppImpl: { if (classScope->isRedeclaring()) break; if (m_stmt) m_stmt->outputCPP(cg, ar); FunctionScopePtr cons = classScope->findConstructor(ar, true); if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) { outputJavaFFICPPCreator(cg, ar, cons); } } break; default: ASSERT(false); break; } ar->popScope(); }
void ClassStatement::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr classScope = m_classScope.lock(); if (cg.getContext() == CodeGenerator::NoContext) { if (classScope->isRedeclaring()) { cg.printf("g->%s%s = ClassStaticsPtr(NEW(%s%s)());\n", Option::ClassStaticsObjectPrefix, m_name.c_str(), Option::ClassStaticsPrefix, classScope->getId().c_str()); } if (classScope->isVolatile()) { cg.printf("g->declareClass(\"%s\");\n", m_name.c_str()); } return; } if (cg.getContext() != CodeGenerator::CppForwardDeclaration) { printSource(cg); } ar->pushScope(classScope); string clsNameStr = classScope->getId(); const char *clsName = clsNameStr.c_str(); bool redeclared = classScope->isRedeclaring(); switch (cg.getContext()) { case CodeGenerator::CppForwardDeclaration: if (Option::GenerateCPPMacros) { cg.printf("FORWARD_DECLARE_CLASS(%s)\n", clsName); if (redeclared) { cg.printf("FORWARD_DECLARE_REDECLARED_CLASS(%s)\n", clsName); } } if (m_stmt) { cg.setContext(CodeGenerator::CppClassConstantsDecl); m_stmt->outputCPP(cg, ar); cg.setContext(CodeGenerator::CppForwardDeclaration); } break; case CodeGenerator::CppDeclaration: { ClassScopePtr parCls; if (!m_parent.empty()) parCls = ar->findClass(m_parent); cg.printf("class %s%s", Option::ClassPrefix, clsName); bool derived = false; if (!m_parent.empty() && classScope->derivesFrom(ar, m_parent)) { if (parCls->isRedeclaring()) { cg.printf(" : public DynamicObjectData"); } else { cg.printf(" : virtual public %s%s", Option::ClassPrefix, parCls->getId().c_str()); } derived = true; } if (m_base) { for (int i = 0; i < m_base->getCount(); i++) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>((*m_base)[i]); const char *intf = exp->getString().c_str(); ClassScopePtr intfClassScope = ar->findClass(intf); if (intfClassScope && classScope->derivesFrom(ar, intf)) { // temporary fix for inheriting from a re-declaring class string id = intfClassScope->getId(); if (!derived) { derived = true; cg.printf(" :"); } else { cg.printf(","); } cg.printf(" virtual public %s%s", Option::ClassPrefix, id.c_str()); } } } if (!derived) { const char *op = derived ? "," : " :"; if (classScope->derivesFromRedeclaring()) { cg.printf("%s public DynamicObjectData", op); } else { cg.printf("%s virtual public ObjectData", op); } } cg.indentBegin(" {\n"); if (Option::GenerateCPPMacros) { vector<string> bases; getAllParents(ar, bases); cg.indentBegin("BEGIN_CLASS_MAP(%s)\n", clsName); for (unsigned int i = 0; i < bases.size(); i++) { cg.printf("PARENT_CLASS(%s)\n", bases[i].c_str()); } cg.indentEnd("END_CLASS_MAP(%s)\n", clsName); } if (Option::GenerateCPPMacros) { bool dyn = classScope->derivesFromRedeclaring() == ClassScope::DirectFromRedeclared; bool idyn = classScope->derivesFromRedeclaring() == ClassScope::IndirectFromRedeclared; bool redec = classScope->isRedeclaring(); if (!classScope->derivesFromRedeclaring()) { cg.printf("DECLARE_CLASS(%s, %s, %s)\n", clsName, m_originalName.c_str(), m_parent.empty() ? "ObjectData" : m_parent.c_str()); } else { cg.printf("DECLARE_DYNAMIC_CLASS(%s, %s)\n", clsName, m_originalName.c_str()); } if (cg.getOutput() == CodeGenerator::SystemCPP || Option::EnableEval >= Option::LimitedEval) { cg.printf("DECLARE_INVOKES_FROM_EVAL\n"); } if (dyn || idyn || redec) { if (redec) { cg.indentBegin("Variant %sroot_invoke(const char* s, CArrRef ps, " "int64 h, bool f = true) {\n", Option::ObjectPrefix); cg.printf("return root->%sinvoke(s, ps, h, f);\n", Option::ObjectPrefix); cg.indentEnd("}\n"); cg.indentBegin("Variant %sroot_invoke_few_args(const char* s, " "int64 h, int count", Option::ObjectPrefix); for (int i = 0; i < Option::InvokeFewArgsCount; i++) { cg.printf(", CVarRef a%d = null_variant", i); } cg.printf(") {\n"); cg.printf("return root->%sinvoke_few_args(s, h, count", Option::ObjectPrefix); for (int i = 0; i < Option::InvokeFewArgsCount; i++) { cg.printf(", a%d", i); } cg.printf(");\n"); cg.indentEnd("}\n"); if (!dyn && !idyn) cg.printf("private: ObjectData* root;\n"); cg.printf("public:\n"); } string conInit = ":"; if (dyn) { conInit += "DynamicObjectData(\"" + m_parent + "\", r)"; } else if (idyn) { conInit += string(Option::ClassPrefix) + parCls->getId() + "(r?r:this)"; } else { conInit += "root(r?r:this)"; } cg.printf("%s%s(ObjectData* r = NULL)%s {}\n", Option::ClassPrefix, clsName, conInit.c_str()); } } cg.printf("void init();\n", Option::ClassPrefix, clsName); if (classScope->needLazyStaticInitializer()) { cg.printf("static GlobalVariables *lazy_initializer" "(GlobalVariables *g);\n"); } if (!classScope->derivesFromRedeclaring()){ classScope->getVariables()->outputCPPPropertyDecl(cg, ar); } if (!classScope->getAttribute(ClassScope::HasConstructor)) { FunctionScopePtr func = classScope->findFunction(ar, "__construct", false); if (func && !func->isAbstract() && !classScope->isInterface()) { ar->pushScope(func); func->outputCPPCreateDecl(cg, ar); ar->popScope(); } } if (classScope->getAttribute(ClassScope::HasDestructor)) { cg.printf("public: virtual void destruct();\n"); } // doCall if (classScope->getAttribute(ClassScope::HasUnknownMethodHandler)) { cg.printf("Variant doCall(Variant v_name, Variant v_arguments, " "bool fatal);\n"); } if (m_stmt) m_stmt->outputCPP(cg, ar); { set<string> done; classScope->outputCPPStaticMethodWrappers(cg, ar, done, clsName); } if (cg.getOutput() == CodeGenerator::SystemCPP && ar->isBaseSysRsrcClass(clsName) && !classScope->hasProperty("rsrc")) { cg.printf("public: Variant %srsrc;\n", Option::PropertyPrefix); } cg.indentEnd("};\n"); if (redeclared) { cg.indentBegin("class %s%s : public ClassStatics {\n", Option::ClassStaticsPrefix, clsName); cg.printf("public:\n"); cg.printf("DECLARE_OBJECT_ALLOCATION(%s%s);\n", Option::ClassStaticsPrefix, clsName); cg.printf("%s%s() : ClassStatics(%d) {}\n", Option::ClassStaticsPrefix, clsName, classScope->getRedeclaringId()); cg.indentBegin("Variant %sget(const char *s, int64 hash = -1) {\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%sget(s, hash);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentBegin("Variant &%slval(const char* s, int64 hash = -1) {\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%slval(s, hash);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentBegin("Variant %sinvoke(const char *c, const char *s, " "CArrRef params, int64 hash = -1, bool fatal = true) " "{\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%sinvoke(c, s, params, hash, fatal);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentBegin("Object create(CArrRef params, bool init = true, " "ObjectData* root = NULL) {\n"); cg.printf("return Object(%s%s(NEW(%s%s)(root))->" "dynCreate(params, init));\n", Option::SmartPtrPrefix, clsName, Option::ClassPrefix, clsName); cg.indentEnd("}\n"); cg.indentBegin("Variant %sconstant(const char* s) {\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%sconstant(s);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentBegin("Variant %sinvoke_from_eval(const char *c, " "const char *s, Eval::VariableEnvironment &env, " "const Eval::FunctionCallExpression *call, " "int64 hash = -1, bool fatal = true) " "{\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%sinvoke_from_eval(c, s, env, call, hash, " "fatal);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentEnd("};\n"); } } break; case CodeGenerator::CppImplementation: if (m_stmt) { cg.setContext(CodeGenerator::CppClassConstantsImpl); m_stmt->outputCPP(cg, ar); cg.setContext(CodeGenerator::CppImplementation); } classScope->outputCPPSupportMethodsImpl(cg, ar); if (redeclared) { cg.printf("IMPLEMENT_OBJECT_ALLOCATION(%s%s);\n", Option::ClassStaticsPrefix, clsName); } cg.indentBegin("void %s%s::init() {\n", Option::ClassPrefix, clsName); if (!m_parent.empty()) { if (classScope->derivesFromRedeclaring() == ClassScope::DirectFromRedeclared) { cg.printf("parent->init();\n"); } else { cg.printf("%s%s::init();\n", Option::ClassPrefix, m_parent.c_str()); } } cg.setContext(CodeGenerator::CppConstructor); if (m_stmt) m_stmt->outputCPP(cg, ar); cg.indentEnd("}\n"); if (classScope->needStaticInitializer()) { cg.indentBegin("void %s%s::os_static_initializer() {\n", Option::ClassPrefix, clsName); cg.printDeclareGlobals(); cg.setContext(CodeGenerator::CppStaticInitializer); if (m_stmt) m_stmt->outputCPP(cg, ar); cg.indentEnd("}\n"); cg.indentBegin("void %s%s() {\n", Option::ClassStaticInitializerPrefix, clsName); cg.printf("%s%s::os_static_initializer();\n", Option::ClassPrefix, clsName); cg.indentEnd("}\n"); } if (classScope->needLazyStaticInitializer()) { cg.indentBegin("GlobalVariables *%s%s::lazy_initializer(" "GlobalVariables *g) {\n", Option::ClassPrefix, clsName); cg.indentBegin("if (!g->%s%s) {\n", Option::ClassStaticInitializerFlagPrefix, clsName); cg.printf("g->%s%s = true;\n", Option::ClassStaticInitializerFlagPrefix, clsName); cg.setContext(CodeGenerator::CppLazyStaticInitializer); if (m_stmt) m_stmt->outputCPP(cg, ar); cg.indentEnd("}\n"); cg.printf("return g;\n"); cg.indentEnd("}\n"); } cg.setContext(CodeGenerator::CppImplementation); if (m_stmt) m_stmt->outputCPP(cg, ar); break; case CodeGenerator::CppFFIDecl: case CodeGenerator::CppFFIImpl: if (m_stmt) m_stmt->outputCPP(cg, ar); break; case CodeGenerator::JavaFFI: { if (classScope->isRedeclaring()) break; // TODO support PHP namespaces, once HPHP supports it string packageName = Option::JavaFFIRootPackage; string packageDir = packageName; Util::replaceAll(packageDir, ".", "/"); string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix + packageDir + "/"; Util::mkdir(outputDir); // uses a different cg to generate a separate file for each PHP class // also, uses the original capitalized class name string clsFile = outputDir + getOriginalName() + ".java"; ofstream fcls(clsFile.c_str()); CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP); cgCls.setContext(CodeGenerator::JavaFFI); cgCls.printf("package %s;\n\n", packageName.c_str()); cgCls.printf("import hphp.*;\n\n"); printSource(cgCls); string clsModifier; switch (m_type) { case T_CLASS: break; case T_ABSTRACT: clsModifier = "abstract "; break; case T_FINAL: clsModifier = "final "; break; } cgCls.printf("public %sclass %s ", clsModifier.c_str(), getOriginalName().c_str()); ClassScopePtr parCls; if (!m_parent.empty()) parCls = ar->findClass(m_parent); if (!m_parent.empty() && classScope->derivesFrom(ar, m_parent) && parCls->isUserClass() && !parCls->isRedeclaring()) { // system classes are not supported in static FFI translation // they shouldn't appear as superclasses as well cgCls.printf("extends %s", parCls->getOriginalName()); } else { cgCls.printf("extends HphpObject"); } if (m_base) { bool first = true; for (int i = 0; i < m_base->getCount(); i++) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>((*m_base)[i]); const char *intf = exp->getString().c_str(); ClassScopePtr intfClassScope = ar->findClass(intf); if (intfClassScope && classScope->derivesFrom(ar, intf) && intfClassScope->isUserClass()) { if (first) { cgCls.printf(" implements "); first = false; } else { cgCls.printf(", "); } cgCls.printf(intfClassScope->getOriginalName()); } } } cgCls.indentBegin(" {\n"); // constructor for initializing the variant pointer cgCls.printf("protected %s(long ptr) { super(ptr); }\n\n", getOriginalName().c_str()); FunctionScopePtr cons = classScope->findConstructor(ar, true); if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) { // if not an abstract class and not having an explicit constructor, // adds a default constructor outputJavaFFIConstructor(cgCls, ar, cons); } if (m_stmt) m_stmt->outputCPP(cgCls, ar); cgCls.indentEnd("}\n"); fcls.close(); } break; case CodeGenerator::JavaFFICppDecl: case CodeGenerator::JavaFFICppImpl: { if (classScope->isRedeclaring()) break; if (m_stmt) m_stmt->outputCPP(cg, ar); FunctionScopePtr cons = classScope->findConstructor(ar, true); if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) { outputJavaFFICPPCreator(cg, ar, cons); } } break; default: ASSERT(false); break; } ar->popScope(); }
void MethodStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); ClassScopePtr scope = ar->getClassScope(); string origFuncName; ar->pushScope(funcScope); if (outputFFI(cg, ar)) return; cg.setPHPLineNo(-1); if (cg.getContext() == CodeGenerator::CppImplementation) { printSource(cg); } switch (cg.getContext()) { case CodeGenerator::CppDeclaration: { if (!m_stmt) { cg.printf("// "); } m_modifiers->outputCPP(cg, ar); if (m_name == "__offsetget_lval") { cg.printf("virtual "); } TypePtr type = funcScope->getReturnType(); if (type) { type->outputCPPDecl(cg, ar); } else { cg.printf("void"); } if (m_name == "__lval") { cg.printf(" &___lval("); } else if (m_name == "__offsetget_lval") { cg.printf(" &___offsetget_lval("); } else if (m_modifiers->isStatic() && m_stmt) { // Static method wrappers get generated as support methods cg.printf(" %s%s(const char* cls%s", Option::MethodImplPrefix, m_name.c_str(), funcScope->isVariableArgument() || (m_params && m_params->getCount()) ? ", " : ""); } else { cg.printf(" %s%s(", Option::MethodPrefix, m_name.c_str()); } funcScope->outputCPPParamsDecl(cg, ar, m_params, true); if (m_stmt) { cg.printf(");\n"); } else { cg.printf(") = 0;\n"); } if (funcScope->isConstructor(scope) && !funcScope->isAbstract() && !scope->isInterface()) { funcScope->outputCPPCreateDecl(cg, ar); } } break; case CodeGenerator::CppImplementation: if (m_stmt) { TypePtr type = funcScope->getReturnType(); if (type) { type->outputCPPDecl(cg, ar); } else { cg.printf("void"); } origFuncName = std::string(scope->getOriginalName()) + "::" + m_originalName; if (Option::HotFunctions.find(origFuncName) != Option::HotFunctions.end()) { cg.printf(" __attribute((__section__(\".text.hot\")))"); } else if (Option::ColdFunctions.find(origFuncName) != Option::ColdFunctions.end()) { cg.printf(" __attribute((__section__(\".text.cold\")))"); } if (m_name == "__lval") { cg.printf(" &%s%s::___lval(", Option::ClassPrefix, scope->getId().c_str()); } else if (m_name == "__offsetget_lval") { cg.printf(" &%s%s::___offsetget_lval(", Option::ClassPrefix, scope->getId().c_str()); } else if (m_modifiers->isStatic()) { cg.printf(" %s%s::%s%s(const char* cls%s", Option::ClassPrefix, scope->getId().c_str(), Option::MethodImplPrefix, m_name.c_str(), funcScope->isVariableArgument() || (m_params && m_params->getCount()) ? ", " : ""); } else { cg.printf(" %s%s::%s%s(", Option::ClassPrefix, scope->getId().c_str(), Option::MethodPrefix, m_name.c_str()); } funcScope->outputCPPParamsDecl(cg, ar, m_params, false); cg.indentBegin(") {\n"); if (m_modifiers->isStatic()) { cg.printf("STATIC_METHOD_INJECTION(%s, %s::%s);\n", scope->getOriginalName(), scope->getOriginalName(), m_originalName.c_str()); } else { cg.printf("INSTANCE_METHOD_INJECTION(%s, %s::%s);\n", scope->getOriginalName(), scope->getOriginalName(), m_originalName.c_str()); } if (Option::GenRTTIProfileData && m_params) { for (int i = 0; i < m_params->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); if (param->hasRTTI()) { const string ¶mName = param->getName(); int id = ar->getParamRTTIEntryId(ar->getClassScope(), funcScope, paramName); if (id != -1) { cg.printf("RTTI_INJECTION(%s%s, %d);\n", Option::VariablePrefix, paramName.c_str(), id); } } } } if (m_name == "__lval" || m_name == "__offsetget_lval") { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[0]); cg.printf("Variant &v = %s->__lvalProxy;\n", cg.getOutput() == CodeGenerator::SystemCPP ? "get_system_globals()" : "get_global_variables()"); string lowered = Util::toLower(m_originalName); cg.printf("v = %s%s(%s%s);\n", Option::MethodPrefix, lowered.c_str(), Option::VariablePrefix, param->getName().c_str()); cg.printf("return v;\n"); } else { if (funcScope->isConstructor(scope)) { cg.printf("bool oldInCtor = gasInCtor(true);\n"); } else if (m_name == "__destruct") { cg.printf("setInDtor();\n"); } else if (m_name == "__call") { ParameterExpressionPtr param; if (m_params->getCount() > 0) { param = dynamic_pointer_cast<ParameterExpression>((*m_params)[0]); cg.printf("INCALL_HELPER(%s%s);\n", Option::VariablePrefix, param->getName().c_str()); } else { cg.printf("INCALL_HELPER(\"\");\n"); } } funcScope->outputCPP(cg, ar); cg.setContext(CodeGenerator::NoContext); // no inner functions/classes if (!funcScope->isStatic() && funcScope->getVariables()-> getAttribute(VariableTable::ContainsDynamicVariable)) { cg.printf("%sthis = this;\n", Option::VariablePrefix); } outputCPPStmt(cg, ar); cg.setContext(CodeGenerator::CppImplementation); } cg.indentEnd("} /* function */\n"); } break; default: break; } ar->popScope(); }
void InterfaceStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr classScope = m_classScope.lock(); if (cg.getContext() == CodeGenerator::NoContext) { if (classScope->isVolatile()) { cg.printf("g->CDEC(%s) = true;\n", m_name.c_str()); } return; } ar->pushScope(classScope); string clsNameStr = classScope->getId(); const char *clsName = clsNameStr.c_str(); switch (cg.getContext()) { case CodeGenerator::CppForwardDeclaration: if (Option::GenerateCPPMacros) { cg.printf("FORWARD_DECLARE_CLASS(%s);\n", clsName); } break; case CodeGenerator::CppDeclaration: { printSource(cg); cg.printf("class %s%s", Option::ClassPrefix, clsName); cg.indentBegin(" {\n"); if (m_stmt) m_stmt->outputCPP(cg, ar); cg.indentEnd("};\n"); } break; case CodeGenerator::CppImplementation: // do nothing break; case CodeGenerator::CppFFIDecl: case CodeGenerator::CppFFIImpl: // do nothing break; case CodeGenerator::JavaFFI: { // TODO support PHP namespaces, once HPHP supports it string packageName = Option::JavaFFIRootPackage; string packageDir = packageName; Util::replaceAll(packageDir, ".", "/"); string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix + packageDir + "/"; Util::mkdir(outputDir); // uses a different cg to generate a separate file for each PHP class string clsFile = outputDir + getOriginalName() + ".java"; ofstream fcls(clsFile.c_str()); CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP); cgCls.setContext(CodeGenerator::JavaFFIInterface); cgCls.printf("package %s;\n\n", packageName.c_str()); cgCls.printf("import hphp.*;\n\n"); cgCls.printf("public interface %s", getOriginalName().c_str()); if (m_base) { bool first = true; for (int i = 0; i < m_base->getCount(); i++) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>((*m_base)[i]); const char *intf = exp->getString().c_str(); ClassScopePtr intfClassScope = ar->findClass(intf); if (intfClassScope && classScope->derivesFrom(ar, intf, false, false) && intfClassScope->isUserClass()) { if (first) { cgCls.printf(" extends "); first = false; } else { cgCls.printf(", "); } cgCls.printf(intfClassScope->getOriginalName()); } } } cgCls.indentBegin(" {\n"); if (m_stmt) m_stmt->outputCPP(cgCls, ar); cgCls.indentEnd("}\n"); fcls.close(); } break; case CodeGenerator::JavaFFICppDecl: case CodeGenerator::JavaFFICppImpl: // do nothing break; default: ASSERT(false); break; } ar->popScope(); }
void FunctionStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { CodeGenerator::Context context = cg.getContext(); FunctionScopePtr funcScope = m_funcScope.lock(); string fname = funcScope->getId(cg).c_str(); bool pseudoMain = funcScope->inPseudoMain(); string origFuncName = !pseudoMain ? funcScope->getOriginalName() : ("run_init::" + funcScope->getFileScope()->getName()); string funcSection; if (outputFFI(cg, ar)) return; if (context == CodeGenerator::NoContext) { string rname = cg.formatLabel(m_name); if (funcScope->isRedeclaring()) { cg.printf("g->%s%s = &%s%s;\n", Option::CallInfoPrefix, m_name.c_str(), Option::CallInfoPrefix, fname.c_str()); } if (funcScope->isVolatile()) { cg_printf("g->declareFunctionLit("); cg_printString(m_name, ar); cg_printf(");\n"); cg_printf("g->FVF(%s) = true;\n", rname.c_str()); } return; } if (context == CodeGenerator::CppDeclaration && !funcScope->isInlined()) return; if (context == CodeGenerator::CppPseudoMain && !pseudoMain) return; if (context == CodeGenerator::CppImplementation && (funcScope->isInlined() || pseudoMain)) return; ar->pushScope(funcScope); cg.setPHPLineNo(-1); if (pseudoMain && !Option::GenerateCPPMain) { if (context == CodeGenerator::CppPseudoMain) { if (cg.getOutput() != CodeGenerator::SystemCPP) { cg.setContext(CodeGenerator::NoContext); // no inner functions/classes funcScope->getVariables()->setAttribute(VariableTable::ForceGlobal); outputCPPStmt(cg, ar); funcScope->getVariables()->clearAttribute(VariableTable::ForceGlobal); cg.setContext(CodeGenerator::CppPseudoMain); ar->popScope(); return; } } else if (context == CodeGenerator::CppForwardDeclaration && cg.getOutput() != CodeGenerator::SystemCPP) { return; } } if (context == CodeGenerator::CppImplementation) { printSource(cg); } else if (context == CodeGenerator::CppForwardDeclaration && Option::GenerateCppLibCode) { cg_printf("\n"); printSource(cg); cg.printDocComment(funcScope->getDocComment()); } if (funcScope->isInlined()) cg_printf("inline "); TypePtr type = funcScope->getReturnType(); if (type) { type->outputCPPDecl(cg, ar); } else { cg_printf("void"); } funcSection = Option::FunctionSections[origFuncName]; if (!funcSection.empty()) { cg_printf(" __attribute__ ((section (\".text.%s\")))", funcSection.c_str()); } if (pseudoMain) { cg_printf(" %s%s(", Option::PseudoMainPrefix, funcScope->getFileScope()->pseudoMainName().c_str()); } else { cg_printf(" %s%s(", Option::FunctionPrefix, fname.c_str()); } switch (context) { case CodeGenerator::CppForwardDeclaration: funcScope->outputCPPParamsDecl(cg, ar, m_params, true); cg_printf(");\n"); if (funcScope->hasDirectInvoke()) { cg_printf("Variant %s%s(void *extra, CArrRef params);\n", Option::InvokePrefix, fname.c_str()); } break; case CodeGenerator::CppDeclaration: case CodeGenerator::CppImplementation: case CodeGenerator::CppPseudoMain: { funcScope->outputCPPParamsDecl(cg, ar, m_params, false); cg_indentBegin(") {\n"); const char *sys = (cg.getOutput() == CodeGenerator::SystemCPP ? "_BUILTIN" : ""); if (pseudoMain) { cg_printf("PSEUDOMAIN_INJECTION%s(%s, %s%s);\n", sys, origFuncName.c_str(), Option::PseudoMainPrefix, funcScope->getFileScope()->pseudoMainName().c_str()); } else { if (m_stmt->hasBody()) { cg_printf("FUNCTION_INJECTION%s(%s);\n", sys, origFuncName.c_str()); } outputCPPArgInjections(cg, ar, origFuncName.c_str(), ClassScopePtr(), funcScope); } funcScope->outputCPP(cg, ar); cg.setContext(CodeGenerator::NoContext); // no inner functions/classes outputCPPStmt(cg, ar); cg.setContext(context); cg_indentEnd("} /* function */\n"); } break; default: ASSERT(false); } ar->popScope(); }