void SimpleFunctionCall::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) { outputLineMap(cg, ar); if (!m_className.empty()) { cg.printf("%s::%s(", m_className.c_str(), m_name.c_str()); } else { if (cg.getOutput() == CodeGenerator::InlinedPHP || cg.getOutput() == CodeGenerator::TrimmedPHP) { if (cg.getOutput() == CodeGenerator::TrimmedPHP && cg.usingStream(CodeGenerator::PrimaryStream) && Option::DynamicFunctionCalls.find(m_name) != Option::DynamicFunctionCalls.end()) { int funcNamePos = Option::DynamicFunctionCalls[m_name]; if (m_params && m_params->getCount() && m_params->getCount() >= funcNamePos + 1) { if (funcNamePos == -1) funcNamePos = m_params->getCount() - 1; ExpressionPtr funcName = (*m_params)[funcNamePos]; if (!funcName->is(Expression::KindOfScalarExpression)) { cg.printf("%s(", m_name.c_str()); for (int i = 0; i < m_params->getCount(); i++) { if (i > 0) cg.printf(", "); if (i == funcNamePos) { cg.printf("%sdynamic_load(", Option::IdPrefix.c_str()); funcName->outputPHP(cg, ar); cg.printf(")"); } else { ExpressionPtr param = (*m_params)[i]; if (param) param->outputPHP(cg, ar); } } cg.printf(")"); return; } } } /* simptodo: I dunno if (m_type == RenderTemplateFunction && !m_template.empty()) { cg.printf("%s_%s(", m_name.c_str(), Util::getIdentifier(m_template).c_str()); } else if (m_type == RenderTemplateIncludeFunction) { string templateName = ar->getProgram()->getCurrentTemplate(); cg.printf("%s_%s(", m_name.c_str(), Util::getIdentifier(templateName).c_str()); } else { */ cg.printf("%s(", m_name.c_str()); //} } else { cg.printf("%s(", m_name.c_str()); } } if (m_params) m_params->outputPHP(cg, ar); cg.printf(")"); }
bool ExpressionList::outputCPPArrayCreate(CodeGenerator &cg, AnalysisResultPtr ar, bool isVector, bool pre) { ASSERT(pre == !m_cppTemp.empty()); if (!Option::GenArrayCreate || cg.getOutput() == CodeGenerator::SystemCPP) { return false; } if (hasNonArrayCreateValue()) return false; unsigned int n = isVector ? m_exps.size() : 0; bool uniqLitstrKeys = false; if (isVector) { n = m_exps.size(); } else { n = checkLitstrKeys(); if (n > 0 && n == m_exps.size()) uniqLitstrKeys = true; } if (isVector) { if (ar->m_arrayIntegerKeyMaxSize < (int)n) ar->m_arrayIntegerKeyMaxSize = n; } else if (uniqLitstrKeys) { if (ar->m_arrayLitstrKeyMaxSize < (int)n) ar->m_arrayLitstrKeyMaxSize = n; } else { return false; } if (pre) { Expression::preOutputCPP(cg, ar, StashKidVars); cg_printf("ArrayInit %s(", m_cppTemp.c_str()); outputCPPUniqLitKeyArrayInit(cg, ar, uniqLitstrKeys, n); cg_printf(");\n"); } else { outputCPPUniqLitKeyArrayInit(cg, ar, uniqLitstrKeys, n); } return true; }
/////////////////////////////////////////////////////////////////////////////// // code generation functions void DynamicFunctionCall::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) { outputLineMap(cg, ar); if (m_class || !m_className.empty()) { StaticClassName::outputPHP(cg, ar); cg_printf("::"); m_nameExp->outputPHP(cg, ar); } else { const char *prefix = Option::IdPrefix.c_str(); if (cg.getOutput() == CodeGenerator::TrimmedPHP && cg.usingStream(CodeGenerator::PrimaryStream) && !m_nameExp->is(Expression::KindOfScalarExpression)) { cg_printf("${%sdynamic_load($%stmp = (", prefix, prefix); m_nameExp->outputPHP(cg, ar); cg_printf("), '%stmp'", prefix); cg_printf(")}"); } else { m_nameExp->outputPHP(cg, ar); } } cg_printf("("); if (m_params) m_params->outputPHP(cg, ar); cg_printf(")"); }
void FunctionScope::outputCPPArguments(ExpressionListPtr params, CodeGenerator &cg, AnalysisResultPtr ar, int extraArg, bool variableArgument, int extraArgArrayId /* = -1 */) { int paramCount = params ? params->getOutputCount() : 0; ASSERT(extraArg <= paramCount); int iMax = paramCount - extraArg; bool extra = false; if (variableArgument) { if (paramCount == 0) { cg.printf("0"); } else { cg.printf("%d, ", paramCount); } } int firstExtra = 0; for (int i = 0; i < paramCount; i++) { ExpressionPtr param = (*params)[i]; cg.setItemIndex(i); if (i > 0) cg.printf(extra ? "." : ", "); if (!extra && (i == iMax || extraArg < 0)) { if (extraArgArrayId != -1) { if (cg.getOutput() == CodeGenerator::SystemCPP) { cg.printf("SystemScalarArrays::%s[%d]", Option::SystemScalarArrayName, extraArgArrayId); } else { cg.printf("ScalarArrays::%s[%d]", Option::ScalarArrayName, extraArgArrayId); } break; } extra = true; // Parameter arrays are always vectors. cg.printf("Array(ArrayInit(%d, true).", paramCount - i); firstExtra = i; } if (extra) { bool needRef = param->hasContext(Expression::RefValue) && !param->hasContext(Expression::NoRefWrapper) && param->isRefable(); cg.printf("set%s(%d, ", needRef ? "Ref" : "", i - firstExtra); if (needRef) { // The parameter itself shouldn't be wrapped with ref() any more. param->setContext(Expression::NoRefWrapper); } param->outputCPP(cg, ar); cg.printf(")"); } else { param->outputCPP(cg, ar); } } if (extra) { cg.printf(".create())"); } }
void ConstantTable::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) { bool decl = true; if (cg.getContext() == CodeGenerator::CppConstantsDecl) { decl = false; } bool printed = false; for (StringToSymbolMap::iterator iter = m_symbolMap.begin(), end = m_symbolMap.end(); iter != end; ++iter) { Symbol *sym = &iter->second; if (!sym->declarationSet() || sym->isDynamic()) continue; if (sym->isSystem() && cg.getOutput() != CodeGenerator::SystemCPP) continue; const string &name = sym->getName(); ConstructPtr value = sym->getValue(); printed = true; cg_printf(decl ? "extern const " : "const "); TypePtr type = sym->getFinalType(); bool isString = type->is(Type::KindOfString); if (isString) { cg_printf("StaticString"); } else { type->outputCPPDecl(cg, ar); } if (decl) { cg_printf(" %s%s", Option::ConstantPrefix, cg.formatLabel(name).c_str()); } else { cg_printf(" %s%s", Option::ConstantPrefix, cg.formatLabel(name).c_str()); cg_printf(isString ? "(" : " = "); if (value) { ExpressionPtr exp = dynamic_pointer_cast<Expression>(value); ASSERT(!exp->getExpectedType()); ScalarExpressionPtr scalarExp = dynamic_pointer_cast<ScalarExpression>(exp); if (isString && scalarExp) { cg_printf("LITSTR_INIT(%s)", scalarExp->getCPPLiteralString(cg).c_str()); } else { exp->outputCPP(cg, ar); } } else { cg_printf("\"%s\"", cg.escapeLabel(name).c_str()); } if (isString) { cg_printf(")"); } } cg_printf(";\n"); } if (printed) { cg_printf("\n"); } }
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"); }
void FunctionScope::outputCPPCreateImpl(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr scope = ar->getClassScope(); string clsNameStr = scope->getId(cg); const char *clsName = clsNameStr.c_str(); const char *consName = scope->classNameCtor() ? scope->getName().c_str() : "__construct"; cg_printf("%s%s *%s%s::create(", Option::ClassPrefix, clsName, Option::ClassPrefix, clsName); outputCPPParamsImpl(cg, ar); cg_indentBegin(") {\n"); cg_printf("CountableHelper h(this);\n"); cg_printf("init();\n"); cg_printf("%s%s(", Option::MethodPrefix, consName); outputCPPParamsCall(cg, ar, false); cg_printf(");\n"); cg_printf("return this;\n"); cg_indentEnd("}\n"); cg_indentBegin("ObjectData *%s%s::dynCreate(CArrRef params, " "bool construct /* = true */) {\n", Option::ClassPrefix, clsName); cg_printf("init();\n"); cg_indentBegin("if (construct) {\n"); cg_printf("CountableHelper h(this);\n"); OutputCPPDynamicInvokeCount(cg); outputCPPDynamicInvoke(cg, ar, Option::MethodPrefix, cg.formatLabel(consName).c_str(), true, false, false, NULL, true); cg_indentEnd("}\n"); cg_printf("return this;\n"); cg_indentEnd("}\n"); if (isDynamic() || isSepExtension()) { cg_indentBegin("void %s%s::dynConstruct(CArrRef params) {\n", Option::ClassPrefix, clsName); OutputCPPDynamicInvokeCount(cg); outputCPPDynamicInvoke(cg, ar, Option::MethodPrefix, cg.formatLabel(consName).c_str(), true, false, false, NULL, true); cg_indentEnd("}\n"); if (cg.getOutput() == CodeGenerator::SystemCPP || Option::EnableEval >= Option::LimitedEval) { cg_indentBegin("void %s%s::dynConstructFromEval(" "Eval::VariableEnvironment &env, " "const Eval::FunctionCallExpression *caller) {\n", Option::ClassPrefix, clsName); outputCPPEvalInvoke(cg, ar, Option::MethodPrefix, cg.formatLabel(consName).c_str(), NULL, false); cg_indentEnd("}\n"); } } }
void ConstantTable::outputCPPJumpTable(CodeGenerator &cg, AnalysisResultPtr ar, bool needsGlobals, bool ret) { bool system = cg.getOutput() == CodeGenerator::SystemCPP; vector<const char *> strings; if (!m_symbolVec.empty()) { strings.reserve(m_symbolVec.size()); BOOST_FOREACH(Symbol *sym, m_symbolVec) { // Extension defined constants have no value but we are sure they exist if (!system && !sym->getValue()) continue; strings.push_back(sym->getName().c_str()); } }
void ConstantTable::outputCPPJumpTable(CodeGenerator &cg, AnalysisResultPtr ar, bool ret /* = true */) { bool system = cg.getOutput() == CodeGenerator::SystemCPP; bool hasDynamic = m_dynamic.size() > 0; vector<const char *> strings; if (!m_symbols.empty()) { strings.reserve(m_symbols.size()); BOOST_FOREACH(string s, m_symbols) { // Extension defined constants have no value but we are sure they exist if (!system && !getValue(s)) continue; strings.push_back(s.c_str()); } }
void IncludeExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { bool linemap = outputLineMap(cg, ar, true); // Includes aren't really supported in system mode if (cg.getOutput() == CodeGenerator::SystemCPP) { cg_printf("true"); if (linemap) cg_printf(")"); return; } const char *vars = m_privateScope ? "lvar_ptr(LVariableTable())" : "variables"; bool require = (m_op == T_REQUIRE || m_op == T_REQUIRE_ONCE); bool once = (m_op == T_INCLUDE_ONCE || m_op == T_REQUIRE_ONCE); if (!getCurrentInclude(ar).empty()) { FileScopePtr fs = ar->findFileScope(getCurrentInclude(ar), false); if (fs) { cg_printf("%s%s(%s, %s)", Option::PseudoMainPrefix, fs->pseudoMainName().c_str(), once ? "true" : "false", vars); if (linemap) cg_printf(")"); return; } } // include() and require() need containing file's directory string currentDir = "NULL"; if (m_loc && m_loc->file && *m_loc->file) { string file = m_loc->file; size_t pos = file.rfind('/'); if (pos != string::npos) { currentDir = '"'; currentDir += file.substr(0, pos + 1); currentDir += '"'; } } // fallback to dynamic include cg_printf("%s(", require ? "require" : "include"); m_exp->outputCPP(cg, ar); cg_printf(", %s, %s, %s)", once ? "true" : "false", vars, currentDir.c_str()); if (linemap) cg_printf(")"); }
void MethodStatement::outputCPPArgInjections(CodeGenerator &cg, AnalysisResultPtr ar, const char *name, ClassScopePtr cls, FunctionScopePtr funcScope) { if (cg.getOutput() != CodeGenerator::SystemCPP) { if (m_params) { int n = m_params->getCount(); cg_printf("INTERCEPT_INJECTION(\"%s\", ", name); if (Option::GenArrayCreate && !hasRefParam()) { ar->m_arrayIntegerKeySizes.insert(n); outputParamArrayCreate(cg, true); cg_printf(", %s);\n", funcScope->isRefReturn() ? "ref(r)" : "r"); } else { cg_printf("(Array(ArrayInit(%d, true)", n); for (int i = 0; i < n; i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); const string ¶mName = param->getName(); cg_printf(".set%s(%d, %s%s)", param->isRef() ? "Ref" : "", i, Option::VariablePrefix, paramName.c_str()); } cg_printf(".create())), %s);\n", funcScope->isRefReturn() ? "ref(r)" : "r"); } } else { cg_printf("INTERCEPT_INJECTION(\"%s\", null_array, %s);\n", name, funcScope->isRefReturn() ? "ref(r)" : "r"); } } 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(cls, funcScope, paramName); if (id != -1) { cg_printf("RTTI_INJECTION(%s%s, %d);\n", Option::VariablePrefix, paramName.c_str(), id); } } } } }
bool ExpressionList::outputCPPArrayCreate(CodeGenerator &cg, AnalysisResultPtr ar, bool isVector, bool pre) { ASSERT(pre == !m_cppTemp.empty()); if (!Option::GenArrayCreate || cg.getOutput() == CodeGenerator::SystemCPP) { return false; } if (hasNonArrayCreateValue()) return false; int64 max = m_exps.size(); unsigned int n = isVector ? m_exps.size() : checkIntegerKeys(max); bool uniqIntegerKeys = false; bool uniqLitstrKeys = false; if (n > 0 && n == m_exps.size()) { uniqIntegerKeys = true; } else if (!isVector) { n = checkLitstrKeys(); if (n > 0 && n == m_exps.size()) uniqLitstrKeys = true; } if (uniqIntegerKeys) { ar->m_arrayIntegerKeySizes.insert(n); } else if (uniqLitstrKeys) { ar->m_arrayLitstrKeySizes.insert(n); } else { return false; } if (pre) { for (unsigned i = 0; i < m_exps.size(); i++) { if (ExpressionPtr exp = m_exps[i]) { exp->preOutputCPP(cg, ar, 0); } } cg_printf("ArrayInit %s(", m_cppTemp.c_str()); outputCPPUniqLitKeyArrayInit(cg, ar, uniqIntegerKeys ? max : 0); cg_printf(");\n"); } else if (uniqIntegerKeys) { outputCPPUniqLitKeyArrayInit(cg, ar, max); } else { outputCPPUniqLitKeyArrayInit(cg, ar, 0); } return true; }
void ReturnStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { bool braced = false; FunctionScopePtr func = getFunctionScope(); ClassScopePtr cls = getClassScope(); if (func->isConstructor(cls)) { cg_indentBegin("{\n"); braced = true; cg_printf("gasInCtor(oldInCtor);\n"); } if (m_exp) { if (m_exp->hasContext(Expression::RefValue)) { m_exp->setContext(Expression::NoRefWrapper); } m_exp->outputCPPBegin(cg, ar); } cg_printf("return"); if (m_exp) { bool close = false; cg_printf(" "); if (m_exp->hasContext(Expression::RefValue) && m_exp->isRefable()) { cg_printf("strongBind("); close = true; } else if (checkCopyElision(func, m_exp)) { cg_printf("wrap_variant("); close = true; } m_exp->outputCPP(cg, ar); if (close) cg_printf(")"); cg_printf(";\n"); cg.setReferenceTempUsed(false); m_exp->outputCPPEnd(cg, ar); } else if (func && !(func->inPseudoMain() && !Option::GenerateCPPMain && cg.getOutput() != CodeGenerator::SystemCPP)) { TypePtr type = func->getReturnType(); if (type) { const char *initializer = type->getCPPInitializer(); cg_printf(" %s", initializer ? initializer : "null"); } cg_printf(";\n"); } if (braced) cg_indentEnd("}\n"); }
void ConstantTable::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) { bool decl = true; if (cg.getContext() == CodeGenerator::CppConstantsDecl) { decl = false; } bool printed = false; for (StringToConstructPtrMap::const_iterator iter = m_declarations.begin(); iter != m_declarations.end(); ++iter) { const string &name = iter->first; if (isSystem(name) && cg.getOutput() != CodeGenerator::SystemCPP) continue; ConstructPtr value = getValue(name); if (isDynamic(name)) continue; printed = true; cg.printf(decl ? "extern const " : "const "); TypePtr type = getFinalType(name); if (type->is(Type::KindOfString)) { cg.printf("StaticString"); } else { type->outputCPPDecl(cg, ar); } const char *nameStr = name.c_str(); if (decl) { cg.printf(" %s%s", Option::ConstantPrefix, nameStr); } else { cg.printf(" %s%s = ", Option::ConstantPrefix, nameStr); if (value) { ExpressionPtr exp = dynamic_pointer_cast<Expression>(value); ASSERT(!exp->getExpectedType()); exp->outputCPP(cg, ar); } else { cg.printf("\"%s\"", nameStr); } } cg.printf(";\n"); } if (printed) { cg.printf("\n"); } }
bool FunctionScope::outputCPPInvokeArgCountCheck(CodeGenerator &cg, AnalysisResultPtr ar, bool ret, bool constructor) { bool variable = isVariableArgument(); // system function has different handling of argument counts bool system = (m_system || m_sep || cg.getOutput() == CodeGenerator::SystemCPP); if (!system) { ClassScopePtr scope = ar->getClassScope(); if (scope) system = (!scope->isUserClass() || scope->isExtensionClass() || scope->isSepExtension()); } bool checkMissing = (m_minParam > 0); bool checkTooMany = (!variable && (system || RuntimeOption::ThrowTooManyArguments)); const char *sysret = (system && ret) ? "return " : ""; const char *level = (system ? (constructor ? ", 2" : ", 1") : ""); bool guarded = system && (ret || constructor); string fullname = getOriginalFullName(); if (checkMissing && checkTooMany) { if (!variable && m_minParam == m_maxParam) { cg_printf("if (count != %d)" " %sthrow_wrong_arguments(\"%s\", count, %d, %d%s);\n", m_minParam, sysret, fullname.c_str(), m_minParam, m_maxParam, level); } else { cg_printf("if (count < %d || count > %d)" " %sthrow_wrong_arguments(\"%s\", count, %d, %d%s);\n", m_minParam, m_maxParam, sysret, fullname.c_str(), m_minParam, variable ? -1 : m_maxParam, level); } } else if (checkMissing) { cg_printf("if (count < %d)" " %sthrow_missing_arguments(\"%s\", count+1%s);\n", m_minParam, sysret, fullname.c_str(), level); } else if (checkTooMany) { cg_printf("if (count > %d)" " %sthrow_toomany_arguments(\"%s\", %d%s);\n", m_maxParam, sysret, fullname.c_str(), m_maxParam, level); } return guarded; }
void FunctionScope::outputCPPCreateDecl(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr scope = ar->getClassScope(); cg.printf("public: %s%s *create(", Option::ClassPrefix, scope->getId().c_str()); outputCPPParamsDecl(cg, ar, dynamic_pointer_cast<MethodStatement>(getStmt()) ->getParams(), true); cg.printf(");\n"); cg.printf("public: ObjectData *dynCreate(CArrRef params, bool init = true);" "\n"); if (isDynamic()) { cg.printf("public: void dynConstruct(CArrRef params);\n"); if (cg.getOutput() == CodeGenerator::SystemCPP || Option::EnableEval >= Option::LimitedEval) { cg.printf("public: void dynConstructFromEval(Eval::VariableEnvironment " "&env, const Eval::FunctionCallExpression *call);\n"); } } }
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 ConstantTable::outputCPPDynamicDecl(CodeGenerator &cg, AnalysisResultPtr ar, Type2SymbolListMap &type2names) { const char *prefix = Option::ConstantPrefix; string classId; const char *fmt = ""; ClassScopePtr scope = getClassScope(); if (scope) { prefix = Option::ClassConstantPrefix; classId = scope->getId(cg); fmt = "_"; } bool system = cg.getOutput() == CodeGenerator::SystemCPP; SymbolList &symbols = type2names["Variant"]; BOOST_FOREACH(Symbol *sym, m_symbolVec) { if (sym->declarationSet() && sym->isDynamic() && system == sym->isSystem()) { symbols.push_back(string(prefix) + classId + fmt + cg.formatLabel(sym->getName())); } } }
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 ObjectPropertyExpression::outputCPPObjProperty(CodeGenerator &cg, AnalysisResultPtr ar, bool directVariant, int doExist) { bool bThis = m_object->isThis(); bool useGetThis = false; FunctionScopePtr funcScope = ar->getFunctionScope(); if (bThis) { if (funcScope && funcScope->isStatic()) { cg_printf("GET_THIS_ARROW()"); } else { // in order for __set() and __get() to be called useGetThis = true; } } const char *op = "."; string func = Option::ObjectPrefix; const char *error = ", true"; ClassScopePtr cls = ar->getClassScope(); const char *context = ""; if (cg.getOutput() != CodeGenerator::SystemCPP) { if (cls) { context = ", s_class_name"; } else if (funcScope && !funcScope->inPseudoMain()) { context = ", empty_string"; } } if (doExist) { func = doExist > 0 ? "doIsSet" : "doEmpty"; error = ""; } else { if (bThis && funcScope && funcScope->isStatic()) { func = Option::ObjectStaticPrefix; error = ""; context = ""; } else if (m_context & ExistContext) { error = ", false"; } if (m_context & (LValue | RefValue | UnsetContext)) { func += "lval"; error = ""; } else { func += "get"; } } if (m_property->getKindOf() == Expression::KindOfScalarExpression) { ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(m_property); const char *propName = name->getString().c_str(); if (m_valid && m_object->getType()->isSpecificObject()) { if (m_static) { if (!bThis) { ASSERT(m_class); if (doExist) cg_printf(doExist > 0 ? "isset(" : "empty("); cg_printf("g->%s%s%s%s", Option::StaticPropertyPrefix, m_class->getName().c_str(), Option::IdPrefix.c_str(), propName); if (doExist) cg_printf(")"); } else { // if $val is a class static variable (static $val), then $val // cannot be declared as a class variable (var $val), $this->val // refers to a non-static class variable and has to use get/lval. if (useGetThis) cg_printf("GET_THIS_DOT()"); cg_printf("%s(", func.c_str()); cg_printString(propName, ar); cg_printf("%s%s)", error, context); } } else { if (doExist) cg_printf(doExist > 0 ? "isset(" : "empty("); if (!bThis) { ASSERT(!directVariant); m_object->outputCPP(cg, ar); cg_printf("->"); } cg_printf("%s%s", Option::PropertyPrefix, propName); if (doExist) cg_printf(")"); } } else { if (!bThis) { if (directVariant) { TypePtr expectedType = m_object->getExpectedType(); ASSERT(expectedType->is(Type::KindOfObject)); // Clear m_expectedType to avoid type cast (toObject). m_object->setExpectedType(TypePtr()); m_object->outputCPP(cg, ar); m_object->setExpectedType(expectedType); } else { m_object->outputCPP(cg, ar); } cg_printf(op); } else { if (useGetThis) cg_printf("GET_THIS_DOT()"); } cg_printf("%s(", func.c_str()); cg_printString(propName, ar); cg_printf("%s%s)", error, context); } } else { if (!bThis) { if (directVariant) { TypePtr expectedType = m_object->getExpectedType(); ASSERT(expectedType->is(Type::KindOfObject)); // Clear m_expectedType to avoid type cast (toObject). m_object->setExpectedType(TypePtr()); m_object->outputCPP(cg, ar); m_object->setExpectedType(expectedType); } else { m_object->outputCPP(cg, ar); } cg_printf(op); } else { if (useGetThis) cg_printf("GET_THIS_DOT()"); } cg_printf("%s(", func.c_str()); m_property->outputCPP(cg, ar); cg_printf("%s%s)", error, context); } }
void UnaryOpExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (m_arrayId != -1) { if (cg.getOutput() == CodeGenerator::SystemCPP) { cg.printf("SystemScalarArrays::%s[%d]", Option::SystemScalarArrayName, m_arrayId); } else { cg.printf("ScalarArrays::%s[%d]", Option::ScalarArrayName, m_arrayId); } return; } if ((m_op == T_ISSET || m_op == T_EMPTY) && m_exp) { if (m_exp->is(Expression::KindOfExpressionList)) { ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp); if (exps->getCount() > 1) { cg.printf("("); } for (int i = 0; i < exps->getCount(); i++) { if (i > 0) cg.printf(" && "); (*exps)[i]->outputCPPExistTest(cg, ar, m_op); } if (exps->getCount() > 1) { cg.printf(")"); } } else { m_exp->outputCPPExistTest(cg, ar, m_op); } return; } if (m_front) { switch (m_op) { case T_CLONE: cg.printf("f_clone("); break; case T_INC: cg.printf("++"); break; case T_DEC: cg.printf("--"); break; case '+': cg.printf("+"); break; case '-': cg.printf("negate("); break; case '!': cg.printf("!("); break; case '~': cg.printf("~"); break; case '(': cg.printf("("); break; case T_INT_CAST: cg.printf("("); break; case T_DOUBLE_CAST: cg.printf("("); break; case T_STRING_CAST: cg.printf("("); break; case T_ARRAY_CAST: cg.printf("("); break; case T_OBJECT_CAST: cg.printf("("); break; case T_BOOL_CAST: cg.printf("("); break; case T_UNSET_CAST: cg.printf("unset("); break; case T_EXIT: cg.printf("f_exit("); break; case T_ARRAY: if (ar->getInsideScalarArray()) { cg.printf("StaticArray("); } else { cg.printf("Array("); } break; case T_PRINT: cg.printf("print("); break; case T_EVAL: if (Option::EnableEval > Option::NoEval) { cg.printf("eval(%s, Object(%s), ", ar->getScope()->inPseudoMain() ? "get_variable_table()" : "variables", ar->getClassScope() ? "this" : ""); } else { cg.printf("f_eval("); } break; case '@': cg.printf("(%s%d.enable(),%s%d.disable(", Option::SilencerPrefix, m_silencer, Option::SilencerPrefix, m_silencer); break; case T_FILE: cg.printf("get_source_filename(\"%s\")", getLocation()->file); break; break; default: ASSERT(false); } } if (m_exp) { switch (m_op) { case '+': case '-': if (m_exp->getActualType() && (m_exp->getActualType()->is(Type::KindOfString) || m_exp->getActualType()->is(Type::KindOfArray))) { cg.printf("(Variant)("); m_exp->outputCPP(cg, ar); cg.printf(")"); } else { m_exp->outputCPP(cg, ar); } break; case '@': // Void needs to return something to silenceDec if (!m_exp->getActualType()) { cg.printf("("); m_exp->outputCPP(cg, ar); cg.printf(",null)"); } else { m_exp->outputCPP(cg, ar); } break; default: m_exp->outputCPP(cg, ar); break; } } if (m_front) { switch (m_op) { case T_ARRAY: { ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp); if (!exps) { cg.printf("ArrayData::Create()"); } cg.printf(")"); } break; case T_CLONE: case '!': case '(': case '-': case T_INT_CAST: case T_DOUBLE_CAST: case T_STRING_CAST: case T_ARRAY_CAST: case T_OBJECT_CAST: case T_BOOL_CAST: case T_UNSET_CAST: case T_EXIT: case T_PRINT: case T_EVAL: case T_INCLUDE: case T_INCLUDE_ONCE: case T_REQUIRE: case T_REQUIRE_ONCE: cg.printf(")"); break; case '@': cg.printf("))"); break; default: break; } } else { switch (m_op) { case T_INC: cg.printf("++"); break; case T_DEC: cg.printf("--"); break; default: ASSERT(false); } } }
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 ClassStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopeRawPtr classScope = getClassScope(); if (cg.getContext() == CodeGenerator::NoContext) { if (classScope->isVolatile()) { string name = cg.formatLabel(m_name); if (classScope->isRedeclaring()) { cg_printf("g->%s%s = ClassStaticsPtr(NEWOBJ(%s%s)());\n", Option::ClassStaticsObjectPrefix, name.c_str(), Option::ClassStaticsPrefix, classScope->getId(cg).c_str()); cg_printf("g->%s%s = &%s%s;\n", Option::ClassStaticsCallbackPrefix, name.c_str(), Option::ClassWrapperFunctionPrefix, classScope->getId(cg).c_str()); } cg_printf("g->CDEC(%s) = true;\n", name.c_str()); const vector<string> &bases = classScope->getBases(); for (vector<string>::const_iterator it = bases.begin(); it != bases.end(); ++it) { if (cg.checkHoistedClass(*it)) continue; ClassScopePtr base = ar->findClass(*it); if (base && base->isVolatile()) { cg_printf("checkClassExists("); cg_printString(base->getOriginalName(), ar, shared_from_this()); string lname = Util::toLower(base->getOriginalName()); cg_printf(", &%s->CDEC(%s), %s->FVF(__autoload));\n", cg.getGlobals(ar), cg.formatLabel(lname).c_str(), cg.getGlobals(ar)); } } } return; } if (cg.getContext() != CodeGenerator::CppForwardDeclaration) { printSource(cg); } string clsNameStr = classScope->getId(cg); const char *clsName = clsNameStr.c_str(); bool redeclared = classScope->isRedeclaring(); switch (cg.getContext()) { case CodeGenerator::CppDeclaration: { if (Option::GenerateCPPMacros) { classScope->outputForwardDeclaration(cg); } bool system = cg.getOutput() == CodeGenerator::SystemCPP; ClassScopePtr parCls; if (!m_parent.empty()) { parCls = ar->findClass(m_parent); if (parCls && parCls->isRedeclaring()) parCls.reset(); } if (Option::GenerateCppLibCode) { cg.printDocComment(classScope->getDocComment()); } cg_printf("class %s%s", Option::ClassPrefix, clsName); if (!m_parent.empty() && classScope->derivesDirectlyFrom(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(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"); cg_printf("public:\n"); cg.printSection("Properties"); classScope->getVariables()->outputCPPPropertyDecl(cg, ar, classScope->derivesFromRedeclaring()); if (Option::GenerateCppLibCode) { cg.printSection("Methods"); classScope->outputMethodWrappers(cg, ar); cg.printSection(">>>>>>>>>> Internal Implementation <<<<<<<<<<"); cg_printf("// NOTE: Anything below is subject to change. " "Use everything above instead.\n"); } cg.printSection("Class Map"); if (Option::GenerateCPPMacros) { cg_printf("virtual bool o_instanceof(CStrRef s) const;\n"); } 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()); } bool hasGet = classScope->getAttribute( ClassScope::HasUnknownPropGetter); bool hasSet = classScope->getAttribute( ClassScope::HasUnknownPropSetter); bool hasCall = classScope->getAttribute( ClassScope::HasUnknownMethodHandler); bool hasCallStatic = classScope->getAttribute( ClassScope::HasUnknownStaticMethodHandler); if (dyn || idyn || redec || hasGet || hasSet || hasCall || hasCallStatic) { if (redec && classScope->derivedByDynamic()) { if (!dyn && !idyn) { cg_printf("private: ObjectData* root;\n"); cg_printf("public:\n"); cg_printf("virtual ObjectData *getRoot() { return root; }\n"); } } string conInit = ""; bool hasParam = false; if (dyn) { conInit = " : DynamicObjectData(\"" + m_parent + "\", r)"; hasParam = true; } else if (idyn) { conInit = " : " + string(Option::ClassPrefix) + parCls->getId(cg) + "(r ? r : this)"; hasParam = true; } else { if (redec && classScope->derivedByDynamic()) { conInit = " : root(r ? r : this)"; } hasParam = true; } cg_indentBegin("%s%s(%s)%s {%s", Option::ClassPrefix, clsName, hasParam ? "ObjectData* r = NULL" : "", conInit.c_str(), hasGet || hasSet || hasCall || hasCallStatic ? "\n" : ""); if (hasGet) cg_printf("setAttribute(UseGet);\n"); if (hasSet) cg_printf("setAttribute(UseSet);\n"); if (hasCall) cg_printf("setAttribute(HasCall);\n"); if (hasCallStatic) cg_printf("setAttribute(HasCallStatic);\n"); cg_indentEnd("}\n"); } } cg_printf("void init();\n"); if (classScope->needLazyStaticInitializer()) { cg_printf("static GlobalVariables *lazy_initializer" "(GlobalVariables *g);\n"); } if (!classScope->getAttribute(ClassScope::HasConstructor)) { FunctionScopePtr func = classScope->findFunction(ar, "__construct", false); if (func && !func->isAbstract() && !classScope->isInterface()) { func->outputCPPCreateDecl(cg, ar); } } 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 (classScope->isRedeclaring() && !classScope->derivesFromRedeclaring() && classScope->derivedByDynamic()) { 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); } if (Option::GenerateCPPMacros) { classScope->outputCPPJumpTableDecl(cg, ar); } 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(CStrRef s) {\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%sgetInit(s);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentBegin("Variant %sget(CStrRef s) {\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%sget(s);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentBegin("Variant &%slval(CStrRef s) {\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%slval(s);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentBegin("Object createOnly(ObjectData* root = NULL) {\n"); cg_printf("Object r((NEWOBJ(%s%s)(root)));\n", Option::ClassPrefix, clsName); cg_printf("r->init();\n"); cg_printf("return r;\n"); 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("bool %sget_call_info(MethodCallPackage &mcp, " "int64 hash = -1) {\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%sget_call_info(mcp, hash);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentEnd("};\n"); } if (m_stmt) { cg.setContext(CodeGenerator::CppClassConstantsDecl); m_stmt->outputCPP(cg, ar); cg.setContext(CodeGenerator::CppDeclaration); } 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 { ClassScopePtr parCls = ar->findClass(m_parent); cg_printf("%s%s::init();\n", Option::ClassPrefix, parCls->getId(cg).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(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; } }
void BinaryOpExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (isOpEqual() && outputCPPImplOpEqual(cg, ar)) return; bool wrapped = true; switch (m_op) { case T_CONCAT_EQUAL: if (const char *prefix = stringBufferPrefix(cg, ar, m_exp1)) { SimpleVariablePtr sv = static_pointer_cast<SimpleVariable>(m_exp1); ExpressionPtrVec ev; bool hasVoid = false; getConcatList(ev, m_exp2, hasVoid); cg_printf("%s", stringBufferName(Option::TempPrefix, prefix, sv->getName().c_str()).c_str()); outputStringBufExprs(ev, cg, ar); return; } cg_printf("concat_assign"); break; case '.': { ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this()); ExpressionPtrVec ev; bool hasVoid = false; int num = getConcatList(ev, self, hasVoid); assert(!hasVoid); if ((num <= MAX_CONCAT_ARGS || (Option::GenConcat && cg.getOutput() != CodeGenerator::SystemCPP))) { assert(num >= 2); if (num == 2) { cg_printf("concat("); } else { if (num > MAX_CONCAT_ARGS) ar->m_concatLengths.insert(num); cg_printf("concat%d(", num); } for (size_t i = 0; i < ev.size(); i++) { ExpressionPtr exp = ev[i]; if (i) cg_printf(", "); outputStringExpr(cg, ar, exp, false); } cg_printf(")"); } else { cg_printf("StringBuffer()"); outputStringBufExprs(ev, cg, ar); cg_printf(".detach()"); } } return; case T_LOGICAL_XOR: cg_printf("logical_xor"); break; case '|': cg_printf("bitwise_or"); break; case '&': cg_printf("bitwise_and"); break; case '^': cg_printf("bitwise_xor"); break; case T_IS_IDENTICAL: cg_printf("same"); break; case T_IS_NOT_IDENTICAL: cg_printf("!same"); break; case T_IS_EQUAL: cg_printf("equal"); break; case T_IS_NOT_EQUAL: cg_printf("!equal"); break; case '<': cg_printf("less"); break; case T_IS_SMALLER_OR_EQUAL: cg_printf("not_more"); break; case '>': cg_printf("more"); break; case T_IS_GREATER_OR_EQUAL: cg_printf("not_less"); break; case '/': cg_printf("divide"); break; case '%': cg_printf("modulo"); break; case T_INSTANCEOF: cg_printf("instanceOf"); break; default: wrapped = !isUnused(); break; } if (wrapped) cg_printf("("); ExpressionPtr first = m_exp1; ExpressionPtr second = m_exp2; // we could implement these functions natively on String and Array classes switch (m_op) { case '+': case '-': case '*': case '/': { TypePtr actualType = first->getActualType(); if (actualType && (actualType->is(Type::KindOfString) || (m_op != '+' && actualType->is(Type::KindOfArray)))) { cg_printf("(Variant)("); first->outputCPP(cg, ar); cg_printf(")"); } else { bool flag = castIfNeeded(getActualType(), actualType, cg, ar, getScope()); first->outputCPP(cg, ar); if (flag) { cg_printf(")"); } } break; } case T_SL: case T_SR: cg_printf("toInt64("); first->outputCPP(cg, ar); cg_printf(")"); break; default: first->outputCPP(cg, ar); break; } switch (m_op) { case T_PLUS_EQUAL: cg_printf(" += "); break; case T_MINUS_EQUAL: cg_printf(" -= "); break; case T_MUL_EQUAL: cg_printf(" *= "); break; case T_DIV_EQUAL: cg_printf(" /= "); break; case T_MOD_EQUAL: cg_printf(" %%= "); break; case T_AND_EQUAL: cg_printf(" &= "); break; case T_OR_EQUAL: cg_printf(" |= "); break; case T_XOR_EQUAL: cg_printf(" ^= "); break; case T_SL_EQUAL: cg_printf(" <<= "); break; case T_SR_EQUAL: cg_printf(" >>= "); break; case T_BOOLEAN_OR: cg_printf(" || "); break; case T_BOOLEAN_AND: cg_printf(" && "); break; case T_LOGICAL_OR: cg_printf(" || "); break; case T_LOGICAL_AND: cg_printf(" && "); break; default: switch (m_op) { case '+': cg_printf(" + "); break; case '-': cg_printf(" - "); break; case '*': cg_printf(" * "); break; case T_SL: cg_printf(" << "); break; case T_SR: cg_printf(" >> "); break; default: cg_printf(", "); break; } break; } switch (m_op) { case '+': case '-': case '*': case '/': { TypePtr actualType = second->getActualType(); if (actualType && (actualType->is(Type::KindOfString) || (m_op != '+' && actualType->is(Type::KindOfArray)))) { cg_printf("(Variant)("); second->outputCPP(cg, ar); cg_printf(")"); } else { bool flag = castIfNeeded(getActualType(), actualType, cg, ar, getScope()); second->outputCPP(cg, ar); if (flag) { cg_printf(")"); } } break; } case T_INSTANCEOF: { if (second->isScalar()) { std::string s = second->getLiteralString(); std::string sLower = Util::toLower(s); if (sLower != "") { cg_printString(sLower, ar, shared_from_this()); } else { second->outputCPP(cg, ar); } } else { second->outputCPP(cg, ar); } break; } case T_PLUS_EQUAL: case T_MINUS_EQUAL: case T_MUL_EQUAL: { TypePtr t1 = first->getCPPType(); TypePtr t2 = second->getType(); if (t1 && !t1->is(Type::KindOfArray) && t2 && Type::IsCastNeeded(ar, t2, t1)) { t1->outputCPPCast(cg, ar, getScope()); cg_printf("("); second->outputCPP(cg, ar); cg_printf(")"); } else { second->outputCPP(cg, ar); } break; } case T_BOOLEAN_OR: case T_BOOLEAN_AND: case T_LOGICAL_AND: case T_LOGICAL_OR: if (isUnused()) { cg_printf("("); if (second->outputCPPUnneeded(cg, ar)) { cg_printf(","); } cg_printf("false)"); } else { second->outputCPP(cg, ar); } break; default: second->outputCPP(cg, ar); } if (wrapped) cg_printf(")"); }
void ObjectPropertyExpression::outputCPPObjProperty(CodeGenerator &cg, AnalysisResultPtr ar, int doExist) { string func = Option::ObjectPrefix; const char *error = ", true"; std::string context = ""; bool doUnset = m_context & LValue && m_context & UnsetContext; bool needTemp = false; if (cg.getOutput() != CodeGenerator::SystemCPP) { context = originalClassName(cg, true); } if (doUnset) { func = "o_unset"; error = ""; } else if (doExist) { func = doExist > 0 ? "o_isset" : "o_empty"; error = ""; } else { if (m_context & ExistContext) { error = ", false"; } if (m_context & InvokeArgument) { ASSERT(cg.callInfoTop() != -1); func += "argval"; } else if (m_context & (LValue | RefValue | DeepReference | UnsetContext)) { if (m_context & UnsetContext) { assert(!(m_context & LValue)); // handled by doUnset func += "unsetLval"; } else { func += "lval"; } error = ""; needTemp = true; } else { func += "get"; if (isNonPrivate(ar)) { func += "Public"; context = ""; } } } if (m_valid && doExist) cg_printf(doExist > 0 ? "isset(" : "empty("); bool flag = outputCPPObject(cg, ar, doUnset || (!m_valid && doExist)); if (flag) { cg_printf("id("); outputCPPProperty(cg, ar); cg_printf(")"); if (doExist) cg_printf(", %s", doExist > 0 ? "false" : "true"); cg_printf(")"); } else if (!doUnset && m_valid) { assert(m_object->getType()->isSpecificObject()); ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(m_property); cg_printf("%s%s", Option::PropertyPrefix, name->getString().c_str()); if (doExist) cg_printf(")"); } else { cg_printf("%s(", func.c_str()); if (hasContext(InvokeArgument)) { cg_printf("cit%d->isRef(%d), ", cg.callInfoTop(), m_argNum); } outputCPPProperty(cg, ar); if (needTemp) { const string &tmp = cg.getReferenceTemp(); context = ", " + (tmp.empty() ? "Variant()" : tmp) + context; } cg_printf("%s%s)", error, context.c_str()); } }
bool BinaryOpExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state) { if (isOpEqual()) return Expression::preOutputCPP(cg, ar, state); bool effect2 = m_exp2->hasEffect(); const char *prefix = 0; if (effect2 || m_exp1->hasEffect()) { ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this()); ExpressionPtrVec ev; bool hasVoid = false; int numConcat = 0; bool ok = false; if (m_op == '.') { numConcat = getConcatList(ev, self, hasVoid); ok = hasVoid || (numConcat > MAX_CONCAT_ARGS && (!Option::GenConcat || cg.getOutput() == CodeGenerator::SystemCPP)); } else if (effect2 && m_op == T_CONCAT_EQUAL) { prefix = stringBufferPrefix(cg, ar, m_exp1); ok = prefix; if (!ok) { if (m_exp1->is(KindOfSimpleVariable)) { ok = true; ev.push_back(m_exp1); numConcat++; } } numConcat += getConcatList(ev, m_exp2, hasVoid); } if (ok) { if (!cg.inExpression()) return true; cg.wrapExpressionBegin(); std::string buf; if (prefix) { SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(m_exp1)); buf = stringBufferName(Option::TempPrefix, prefix, sv->getName().c_str()); m_cppTemp = "/**/"; } else if (numConcat) { buf = m_cppTemp = genCPPTemp(cg, ar); buf += "_buf"; cg_printf("StringBuffer %s;\n", buf.c_str()); } else { m_cppTemp = "\"\""; } for (size_t i = 0; i < ev.size(); i++) { ExpressionPtr exp = ev[i]; bool is_void = !exp->getActualType(); exp->preOutputCPP(cg, ar, 0); if (!is_void) { cg_printf("%s.append(", buf.c_str()); outputStringExpr(cg, ar, exp, true); cg_printf(")"); } else { exp->outputCPPUnneeded(cg, ar); } cg_printf(";\n"); } if (numConcat && !prefix) { cg_printf("CStrRef %s(%s.detach());\n", m_cppTemp.c_str(), buf.c_str()); if (m_op == T_CONCAT_EQUAL) { m_exp1->outputCPP(cg, ar); cg_printf(" = %s;\n", m_cppTemp.c_str()); } } return true; } } if (!isShortCircuitOperator()) { return Expression::preOutputCPP(cg, ar, state); } if (!effect2) { return m_exp1->preOutputCPP(cg, ar, state); } bool fix_e1 = m_exp1->preOutputCPP(cg, ar, 0); if (!cg.inExpression()) { return fix_e1 || m_exp2->preOutputCPP(cg, ar, 0); } cg.setInExpression(false); bool fix_e2 = m_exp2->preOutputCPP(cg, ar, 0); cg.setInExpression(true); if (fix_e2) { cg.wrapExpressionBegin(); std::string tmp = genCPPTemp(cg, ar); cg_printf("bool %s = (", tmp.c_str()); m_exp1->outputCPP(cg, ar); cg_printf(");\n"); cg_indentBegin("if (%s%s) {\n", m_op == T_LOGICAL_OR || m_op == T_BOOLEAN_OR ? "!" : "", tmp.c_str()); m_exp2->preOutputCPP(cg, ar, 0); cg_printf("%s = (", tmp.c_str()); m_exp2->outputCPP(cg, ar); cg_printf(");\n"); cg_indentEnd("}\n"); m_cppTemp = tmp; } else if (state & FixOrder) { preOutputStash(cg, ar, state); fix_e1 = true; } return fix_e1 || fix_e2; }
void MethodStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); ClassScopePtr scope = getClassScope(); if (outputFFI(cg, ar)) return; cg.setPHPLineNo(-1); CodeGenerator::Context context = cg.getContext(); if (context == CodeGenerator::CppImplementation) { printSource(cg); } bool isWrapper = context == CodeGenerator::CppTypedParamsWrapperDecl || context == CodeGenerator::CppTypedParamsWrapperImpl; bool needsWrapper = isWrapper || (Option::HardTypeHints && funcScope->needsTypeCheckWrapper()); const char *prefix = needsWrapper && !isWrapper ? Option::TypedMethodPrefix : Option::MethodPrefix; switch (context) { case CodeGenerator::CppDeclaration: case CodeGenerator::CppTypedParamsWrapperDecl: { if (!m_stmt && !funcScope->isPerfectVirtual()) { cg_printf("// "); } m_modifiers->outputCPP(cg, ar); if (!m_stmt || m_name == "__offsetget_lval" || funcScope->isPerfectVirtual()) { cg_printf("virtual "); } TypePtr type = funcScope->getReturnType(); if (type) { type->outputCPPDecl(cg, ar); } else { cg_printf("void"); } 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(CStrRef cls%s", needsWrapper && !isWrapper ? Option::TypedMethodImplPrefix : Option::MethodImplPrefix, cg.formatLabel(m_name).c_str(), funcScope->isVariableArgument() || (m_params && m_params->getCount()) ? ", " : ""); } else { cg_printf(" %s%s(", prefix, cg.formatLabel(m_name).c_str()); } funcScope->outputCPPParamsDecl(cg, ar, m_params, true); if (m_stmt) { cg_printf(");\n"); } else if (funcScope->isPerfectVirtual()) { cg_printf(") { return throw_fatal(\"pure virtual\");}\n"); } else { cg_printf(") = 0;\n"); } if (context != CodeGenerator::CppTypedParamsWrapperDecl) { if (funcScope->isConstructor(scope) && !funcScope->isAbstract() && !scope->isInterface()) { funcScope->outputCPPCreateDecl(cg, ar); } if (Option::HardTypeHints && funcScope->needsTypeCheckWrapper()) { cg.setContext(CodeGenerator::CppTypedParamsWrapperDecl); outputCPPImpl(cg, ar); cg.setContext(context); } } } break; case CodeGenerator::CppImplementation: case CodeGenerator::CppTypedParamsWrapperImpl: if (m_stmt) { TypePtr type = funcScope->getReturnType(); if (type) { type->outputCPPDecl(cg, ar); } else { cg_printf("void"); } string origFuncName = getOriginalFullName(); string funcSection = Option::FunctionSections[origFuncName]; if (!funcSection.empty()) { cg_printf(" __attribute__ ((section (\".text.%s\")))", funcSection.c_str()); } if (m_name == "__offsetget_lval") { cg_printf(" &%s%s::___offsetget_lval(", Option::ClassPrefix, scope->getId(cg).c_str()); } else if (m_modifiers->isStatic()) { cg_printf(" %s%s::%s%s(CStrRef cls%s", Option::ClassPrefix, scope->getId(cg).c_str(), needsWrapper && !isWrapper ? Option::TypedMethodImplPrefix : Option::MethodImplPrefix, cg.formatLabel(m_name).c_str(), funcScope->isVariableArgument() || (m_params && m_params->getCount()) ? ", " : ""); } else { cg_printf(" %s%s::%s%s(", Option::ClassPrefix, scope->getId(cg).c_str(), prefix, cg.formatLabel(m_name).c_str()); } funcScope->outputCPPParamsDecl(cg, ar, m_params, false); cg_indentBegin(") {\n"); if (context != CodeGenerator::CppTypedParamsWrapperImpl) { if (m_stmt->hasBody()) { const char *sys = (cg.getOutput() == CodeGenerator::SystemCPP ? "_BUILTIN" : ""); if (m_modifiers->isStatic()) { cg_printf("STATIC_METHOD_INJECTION%s(%s, %s);\n", sys, scope->getOriginalName().c_str(), origFuncName.c_str()); } else if (cg.getOutput() != CodeGenerator::SystemCPP && !scope->isRedeclaring() && !scope->derivedByDynamic()) { cg_printf("INSTANCE_METHOD_INJECTION_ROOTLESS(%s, %s);\n", scope->getOriginalName().c_str(), origFuncName.c_str()); } else { cg_printf("INSTANCE_METHOD_INJECTION%s(%s, %s);\n", sys, scope->getOriginalName().c_str(), origFuncName.c_str()); } } outputCPPArgInjections(cg, ar, origFuncName.c_str(), scope, funcScope); if (m_name == "__offsetget_lval") { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[0]); cg_printf("Variant &v = %s->__lvalProxy;\n", cg.getGlobals(ar)); string lowered = Util::toLower(m_originalName); cg_printf("v = %s%s(%s%s);\n", prefix, 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"); } 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_indentEnd("}\n"); if (Option::HardTypeHints && funcScope->needsTypeCheckWrapper()) { cg.setContext(CodeGenerator::CppTypedParamsWrapperImpl); outputCPPImpl(cg, ar); } } else { outputCPPTypeCheckWrapper(cg, ar); cg_indentEnd("}\n"); } cg.setContext(context); cg.printImplSplitter(); } break; default: break; } }
void FunctionStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { CodeGenerator::Context context = cg.getContext(); FunctionScopeRawPtr funcScope = getFunctionScope(); string fname = funcScope->getId(cg); bool pseudoMain = funcScope->inPseudoMain(); string origFuncName = !pseudoMain ? funcScope->getOriginalName() : ("run_init::" + funcScope->getContainingFile()->getName()); string funcSection; if (outputFFI(cg, ar)) return; if (context == CodeGenerator::NoContext) { string rname = cg.formatLabel(m_name); if (funcScope->isRedeclaring()) { cg.printf("g->GCI(%s) = &%s%s;\n", m_name.c_str(), Option::CallInfoPrefix, fname.c_str()); } if (funcScope->isVolatile()) { cg_printf("g->declareFunctionLit("); cg_printString(m_name, ar, shared_from_this()); 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; 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); 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()); } bool isWrapper = context == CodeGenerator::CppTypedParamsWrapperDecl || context == CodeGenerator::CppTypedParamsWrapperImpl; bool needsWrapper = isWrapper || (Option::HardTypeHints && funcScope->needsTypeCheckWrapper()); if (funcScope->isInlined()) cg_printf("inline "); TypePtr type = funcScope->getReturnType(); if (type) { type->outputCPPDecl(cg, ar, getScope()); } 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->getContainingFile()->pseudoMainName().c_str()); } else { cg_printf(" %s%s(", needsWrapper && !isWrapper ? Option::TypedFunctionPrefix : Option::FunctionPrefix, fname.c_str()); } switch (context) { case CodeGenerator::CppForwardDeclaration: case CodeGenerator::CppTypedParamsWrapperDecl: funcScope->outputCPPParamsDecl(cg, ar, m_params, true); cg_printf(");\n"); if (!isWrapper) { if (funcScope->hasDirectInvoke()) { cg_printf("Variant %s%s(void *extra, CArrRef params);\n", Option::InvokePrefix, fname.c_str()); } if (needsWrapper) { cg.setContext(CodeGenerator::CppTypedParamsWrapperDecl); outputCPPImpl(cg, ar); cg.setContext(context); } } break; case CodeGenerator::CppDeclaration: case CodeGenerator::CppImplementation: case CodeGenerator::CppPseudoMain: case CodeGenerator::CppTypedParamsWrapperImpl: { funcScope->outputCPPParamsDecl(cg, ar, m_params, false); cg_indentBegin(") {\n"); if (!isWrapper) { 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->getContainingFile()->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_indentEnd("}\n"); if (needsWrapper) { cg.setContext(CodeGenerator::CppTypedParamsWrapperImpl); outputCPPImpl(cg, ar); } cg.setContext(context); } else { outputCPPTypeCheckWrapper(cg, ar); cg_indentEnd("}\n"); } cg.printImplSplitter(); } break; default: ASSERT(false); } }
void FunctionStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { CodeGenerator::Context context = cg.getContext(); FunctionScopeRawPtr funcScope = getFunctionScope(); string fname = funcScope->getId(); bool pseudoMain = funcScope->inPseudoMain(); string origFuncName = !pseudoMain ? funcScope->getOriginalName() : ("run_init::" + funcScope->getContainingFile()->getName()); if (outputFFI(cg, ar)) return; if (context == CodeGenerator::NoContext) { funcScope->outputCPPDef(cg); return; } if (context == CodeGenerator::CppDeclaration && !funcScope->isInlined()) return; if (context == CodeGenerator::CppPseudoMain && (!pseudoMain || getFileScope()->canUseDummyPseudoMain(ar))) { return; } if (context == CodeGenerator::CppImplementation && (funcScope->isInlined() || pseudoMain)) return; 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); 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()); } bool isWrapper = context == CodeGenerator::CppTypedParamsWrapperDecl || context == CodeGenerator::CppTypedParamsWrapperImpl; bool needsWrapper = isWrapper || (Option::HardTypeHints && funcScope->needsTypeCheckWrapper()); int startLineImplementation = -1; if (context == CodeGenerator::CppDeclaration || context == CodeGenerator::CppImplementation || context == CodeGenerator::CppPseudoMain) { startLineImplementation = cg.getLineNo(CodeGenerator::PrimaryStream); } if (funcScope->isInlined()) cg_printf("inline "); TypePtr type = funcScope->getReturnType(); if (type) { bool isHeader = cg.isFileOrClassHeader(); cg.setFileOrClassHeader(true); type->outputCPPDecl(cg, ar, getScope()); cg.setFileOrClassHeader(isHeader); } else { cg_printf("void"); } if (Option::FunctionSections.find(origFuncName) != Option::FunctionSections.end()) { string 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->getContainingFile()->pseudoMainName().c_str()); } else { cg_printf(" %s%s(", needsWrapper && !isWrapper ? Option::TypedFunctionPrefix : Option::FunctionPrefix, fname.c_str()); } switch (context) { case CodeGenerator::CppForwardDeclaration: case CodeGenerator::CppTypedParamsWrapperDecl: funcScope->outputCPPParamsDecl(cg, ar, m_params, true); if (!isWrapper) { int opt = Option::GetOptimizationLevel(m_cppLength); if (opt < 3) cg_printf(") __attribute__((optimize(%d))", opt); } cg_printf(");\n"); if (!isWrapper) { if (funcScope->hasDirectInvoke()) { cg_printf("Variant %s%s(void *extra, CArrRef params);\n", Option::InvokePrefix, fname.c_str()); } if (needsWrapper) { cg.setContext(CodeGenerator::CppTypedParamsWrapperDecl); outputCPPImpl(cg, ar); cg.setContext(context); } } break; case CodeGenerator::CppDeclaration: case CodeGenerator::CppImplementation: case CodeGenerator::CppPseudoMain: case CodeGenerator::CppTypedParamsWrapperImpl: { funcScope->outputCPPParamsDecl(cg, ar, m_params, false); cg_indentBegin(") {\n"); if (!isWrapper) { const char *suffix = (cg.getOutput() == CodeGenerator::SystemCPP ? "_BUILTIN" : ""); if (pseudoMain) { cg_printf("PSEUDOMAIN_INJECTION%s(%s, %s%s);\n", suffix, origFuncName.c_str(), Option::PseudoMainPrefix, funcScope->getContainingFile()->pseudoMainName().c_str()); } else { if (m_stmt->hasBody()) { if (suffix[0] == '\0' && !funcScope->needsCheckMem()) { suffix = "_NOMEM"; } const string &name = funcScope->getInjectionId(); cg_printf("FUNCTION_INJECTION%s(%s);\n", suffix, name.c_str()); } outputCPPArgInjections(cg, ar, origFuncName.c_str(), ClassScopePtr(), funcScope); } funcScope->outputCPP(cg, ar); if (funcScope->needsRefTemp()) cg.genReferenceTemp(shared_from_this()); if (funcScope->needsObjTemp()) { cg_printf("ObjectData *obj_tmp UNUSED;\n"); } cg.setContext(CodeGenerator::NoContext); // no inner functions/classes outputCPPStmt(cg, ar); if (funcScope->needsRefTemp()) cg.clearRefereceTemp(); cg_indentEnd("}\n"); ASSERT(startLineImplementation >= 0); m_cppLength = cg.getLineNo(CodeGenerator::PrimaryStream) - startLineImplementation; if (needsWrapper) { cg.setContext(CodeGenerator::CppTypedParamsWrapperImpl); outputCPPImpl(cg, ar); } cg.setContext(context); } else { outputCPPTypeCheckWrapper(cg, ar); cg_indentEnd("}\n"); } cg.printImplSplitter(); } break; default: ASSERT(false); } }
void ClassStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (cg.getContext() == CodeGenerator::NoContext) { InterfaceStatement::outputCPPImpl(cg, ar); return; } ClassScopeRawPtr classScope = getClassScope(); if (cg.getContext() != CodeGenerator::CppForwardDeclaration) { printSource(cg); } string clsNameStr = classScope->getId(); const char *clsName = clsNameStr.c_str(); switch (cg.getContext()) { case CodeGenerator::CppDeclaration: { if (Option::GenerateCPPMacros) { classScope->outputForwardDeclaration(cg); } classScope->outputCPPGlobalTableWrappersDecl(cg, ar); bool system = cg.getOutput() == CodeGenerator::SystemCPP; ClassScopePtr parCls; if (!m_parent.empty()) { parCls = ar->findClass(m_parent); if (parCls && parCls->isRedeclaring()) parCls.reset(); } if (Option::GenerateCppLibCode) { cg.printDocComment(classScope->getDocComment()); } cg_printf("class %s%s", Option::ClassPrefix, clsName); if (!m_parent.empty() && classScope->derivesDirectlyFrom(m_parent)) { if (!parCls) { cg_printf(" : public DynamicObjectData"); } else { cg_printf(" : public %s%s", Option::ClassPrefix, parCls->getId().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(intf) && (!parCls || !parCls->derivesFrom(ar, intf, true, false))) { string id = intfClassScope->getId(); cg_printf(", public %s%s", Option::ClassPrefix, id.c_str()); } } } cg_indentBegin(" {\n"); cg_printf("public:\n"); cg.printSection("Properties"); if (classScope->getVariables()->outputCPPPropertyDecl( cg, ar, classScope->derivesFromRedeclaring())) { cg.printSection("Destructor"); cg_printf("~%s%s() NEVER_INLINE {}", Option::ClassPrefix, clsName); } if (Option::GenerateCppLibCode) { cg.printSection("Methods"); classScope->outputMethodWrappers(cg, ar); cg.printSection(">>>>>>>>>> Internal Implementation <<<<<<<<<<"); cg_printf("// NOTE: Anything below is subject to change. " "Use everything above instead.\n"); } cg.printSection("Class Map"); bool hasEmitCppCtor = false; bool needsCppCtor = classScope->needsCppCtor(); bool needsInit = classScope->needsInitMethod(); bool disableDestructor = !classScope->canSkipCreateMethod(ar) || (!classScope->derivesFromRedeclaring() && !classScope->hasAttribute(ClassScope::HasDestructor, ar)); if (Option::GenerateCPPMacros) { bool dyn = classScope->derivesFromRedeclaring() == ClassScope::DirectFromRedeclared; bool idyn = parCls && classScope->derivesFromRedeclaring() == ClassScope::IndirectFromRedeclared; bool redec = classScope->isRedeclaring(); if (!parCls && !m_parent.empty()) { assert(dyn); } if (!classScope->derivesFromRedeclaring()) { outputCPPClassDecl(cg, ar, clsName, m_originalName.c_str(), parCls ? parCls->getId().c_str() : "ObjectData"); } else { cg_printf("DECLARE_DYNAMIC_CLASS(%s, %s, %s)\n", clsName, m_originalName.c_str(), dyn || !parCls ? "DynamicObjectData" : parCls->getId().c_str()); } if (classScope->checkHasPropTable()) { cg_printf("static const ClassPropTable %sprop_table;\n", Option::ObjectStaticPrefix); } bool hasGet = classScope->getAttribute( ClassScope::HasUnknownPropGetter); bool hasSet = classScope->getAttribute( ClassScope::HasUnknownPropSetter); bool hasIsset = classScope->getAttribute( ClassScope::HasUnknownPropTester); bool hasUnset = classScope->getAttribute( ClassScope::HasPropUnsetter); bool hasCall = classScope->getAttribute( ClassScope::HasUnknownMethodHandler); bool hasCallStatic = classScope->getAttribute( ClassScope::HasUnknownStaticMethodHandler); bool hasRootParam = classScope->derivedByDynamic() && (redec || dyn || idyn); string lateInit = ""; if (redec && classScope->derivedByDynamic()) { if (!dyn && !idyn && (!parCls || parCls->isUserClass())) { cg_printf("private: ObjectData* root;\n"); cg_printf("public:\n"); cg_printf("virtual ObjectData *getRoot() { return root; }\n"); lateInit = "root(r ? r : this)"; } } string callbacks = Option::ClassStaticsCallbackPrefix + clsNameStr; string conInit = ""; if (dyn) { conInit = "DynamicObjectData(cb, \"" + CodeGenerator::EscapeLabel(m_parent) + "\", "; if (hasRootParam) { conInit += "r)"; } else { conInit += "this)"; } } else if (parCls) { conInit = string(Option::ClassPrefix) + parCls->getId() + "("; if (parCls->derivedByDynamic() && (parCls->isRedeclaring() || parCls->derivesFromRedeclaring() != ClassScope::FromNormal)) { if (hasRootParam) { conInit += "r ? r : "; } conInit += "this, "; } conInit += "cb)"; } else { if (system) { conInit = "ExtObjectData(cb)"; } else { if (hasRootParam) { conInit = "ObjectData(cb, r)"; } else { conInit = "ObjectData(cb, false)"; } } } cg_printf("%s%s(%sconst ObjectStaticCallbacks *cb = &%s%s) : %s", Option::ClassPrefix, clsName, hasRootParam ? "ObjectData* r = NULL," : "", callbacks.c_str(), redec ? ".oscb" : "", conInit.c_str()); if (needsCppCtor) { cg_printf(", "); cg.setContext(CodeGenerator::CppConstructor); ASSERT(!cg.hasInitListFirstElem()); m_stmt->outputCPP(cg, ar); cg.clearInitListFirstElem(); cg.setContext(CodeGenerator::CppDeclaration); } if (!lateInit.empty()) { cg_printf(", %s", lateInit.c_str()); } cg_indentBegin(" {%s", hasGet || hasSet || hasIsset || hasUnset || hasCall || hasCallStatic || disableDestructor || hasRootParam ? "\n" : ""); if (hasRootParam) { cg_printf("setId(r);\n"); } if (hasGet) cg_printf("setAttribute(UseGet);\n"); if (hasSet) cg_printf("setAttribute(UseSet);\n"); if (hasIsset) cg_printf("setAttribute(UseIsset);\n"); if (hasUnset) cg_printf("setAttribute(UseUnset);\n"); if (hasCall) cg_printf("setAttribute(HasCall);\n"); if (hasCallStatic) cg_printf("setAttribute(HasCallStatic);\n"); if (disableDestructor) { cg_printf("if (!hhvm) setAttribute(NoDestructor);\n"); } cg_indentEnd("}\n"); hasEmitCppCtor = true; } if (needsCppCtor && !hasEmitCppCtor) { cg_printf("%s%s() : ", Option::ClassPrefix, clsName); cg.setContext(CodeGenerator::CppConstructor); ASSERT(!cg.hasInitListFirstElem()); m_stmt->outputCPP(cg, ar); cg.clearInitListFirstElem(); cg.setContext(CodeGenerator::CppDeclaration); cg_printf(" {%s}\n", disableDestructor ? " if (!hhvm) setAttribute(NoDestructor); " : ""); } if (needsInit) { cg_printf("void init();\n"); } // doCall if (classScope->getAttribute(ClassScope::HasUnknownMethodHandler)) { cg_printf("Variant doCall(Variant v_name, Variant v_arguments, " "bool fatal);\n"); } if (classScope->getAttribute(ClassScope::HasInvokeMethod)) { FunctionScopePtr func = classScope->findFunction(ar, "__invoke", false); ASSERT(func); if (!func->isAbstract()) { cg_printf("const CallInfo *" "t___invokeCallInfoHelper(void *&extra);\n"); } } if (classScope->isRedeclaring() && !classScope->derivesFromRedeclaring() && classScope->derivedByDynamic()) { cg_printf("Variant doRootCall(Variant v_name, Variant v_arguments, " "bool fatal);\n"); } if (m_stmt) m_stmt->outputCPP(cg, ar); { std::set<string> done; classScope->outputCPPStaticMethodWrappers(cg, ar, done, clsName); } if (Option::GenerateCPPMacros) { classScope->outputCPPJumpTableDecl(cg, ar); } cg_indentEnd("};\n"); classScope->outputCPPDynamicClassDecl(cg); if (m_stmt) { cg.setContext(CodeGenerator::CppClassConstantsDecl); m_stmt->outputCPP(cg, ar); cg.setContext(CodeGenerator::CppDeclaration); } } break; case CodeGenerator::CppImplementation: { if (m_stmt) { cg.setContext(CodeGenerator::CppClassConstantsImpl); m_stmt->outputCPP(cg, ar); cg.setContext(CodeGenerator::CppImplementation); } classScope->outputCPPSupportMethodsImpl(cg, ar); bool needsInit = classScope->needsInitMethod(); if (needsInit) { 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 { ClassScopePtr parCls = ar->findClass(m_parent); cg_printf("%s%s::init();\n", Option::ClassPrefix, parCls->getId().c_str()); } } if (classScope->getVariables()-> getAttribute(VariableTable::NeedGlobalPointer)) { cg.printDeclareGlobals(); } cg.setContext(CodeGenerator::CppInitializer); 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"); } 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"; std::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(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; } }