void MethodStatement::inferTypes(AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); if (ar->getPhase() == AnalysisResult::FirstInference && m_stmt) { if (m_stmt->hasRetExp() || funcScope->inPseudoMain() || funcScope->getReturnType()) { bool lastIsReturn = false; if (m_stmt->getCount()) { StatementPtr lastStmt = (*m_stmt)[m_stmt->getCount()-1]; if (lastStmt->is(Statement::KindOfReturnStatement)) { lastIsReturn = true; } } if (!lastIsReturn && !(funcScope->inPseudoMain() && !Option::GenerateCPPMain)) { ExpressionPtr constant = funcScope->inPseudoMain() ? CONSTANT("true") : CONSTANT("null"); ReturnStatementPtr returnStmt = ReturnStatementPtr(new ReturnStatement(getLocation(), Statement::KindOfReturnStatement, constant)); m_stmt->addElement(returnStmt); } } } ar->pushScope(funcScope); if (m_params) { m_params->inferAndCheck(ar, NEW_TYPE(Any), false); } if (m_stmt) { m_stmt->inferTypes(ar); } ar->popScope(); }
void AnalysisResult::collectFunctionsAndClasses(FileScopePtr fs) { for (const auto& iter : fs->getFunctions()) { FunctionScopePtr func = iter.second; if (!func->inPseudoMain()) { FunctionScopePtr &funcDec = m_functionDecs[iter.first]; if (funcDec) { if (funcDec->isSystem()) { assert(funcDec->allowOverride()); funcDec = func; } else if (func->isSystem()) { assert(func->allowOverride()); } else { auto& funcVec = m_functionReDecs[iter.first]; int sz = funcVec.size(); if (!sz) { funcDec->setRedeclaring(sz++); funcVec.push_back(funcDec); } func->setRedeclaring(sz++); funcVec.push_back(func); } } else { funcDec = func; } } } if (const auto redec = fs->getRedecFunctions()) { for (const auto &iter : *redec) { auto i = iter.second.begin(); auto e = iter.second.end(); auto& funcDec = m_functionDecs[iter.first]; assert(funcDec); // because the first one was in funcs above auto& funcVec = m_functionReDecs[iter.first]; int sz = funcVec.size(); if (!sz) { funcDec->setRedeclaring(sz++); funcVec.push_back(funcDec); } while (++i != e) { // we already added the first one (*i)->setRedeclaring(sz++); funcVec.push_back(*i); } } } for (const auto& iter : fs->getClasses()) { auto& clsVec = m_classDecs[iter.first]; clsVec.insert(clsVec.end(), iter.second.begin(), iter.second.end()); } m_classAliases.insert(fs->getClassAliases().begin(), fs->getClassAliases().end()); m_typeAliasNames.insert(fs->getTypeAliasNames().begin(), fs->getTypeAliasNames().end()); }
void StatementList::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr func = getFunctionScope(); bool inPseudoMain = func && func->inPseudoMain(); std::vector<bool> isDeclaration; if (inPseudoMain) { // We need these declarations to go first, because PHP allows top level // function and class declarations to appear after usage. for (unsigned int i = 0; i < m_stmts.size(); i++) { StatementPtr stmt = m_stmts[i]; bool isDecl = false; if (stmt->is(Statement::KindOfFunctionStatement)) { isDecl = true; } else if (stmt->is(Statement::KindOfClassStatement) || stmt->is(Statement::KindOfInterfaceStatement)) { ClassScopePtr cls = (dynamic_pointer_cast<InterfaceStatement>(stmt))->getClassScope(); isDecl = cls->isBaseClass() || !cls->isVolatile(); } if (isDecl) stmt->outputCPP(cg,ar); isDeclaration.push_back(isDecl); } } for (unsigned int i = 0; i < m_stmts.size(); i++) { StatementPtr stmt = m_stmts[i]; if (stmt->is(Statement::KindOfClassStatement)) { if (!inPseudoMain || !isDeclaration[i]) stmt->outputCPP(cg, ar); } else if (!(stmt->is(Statement::KindOfFunctionStatement) || stmt->is(Statement::KindOfInterfaceStatement)) || (!inPseudoMain || !isDeclaration[i])) { stmt->outputCPP(cg, ar); if (stmt->is(Statement::KindOfMethodStatement)) { MethodStatementPtr methodStmt = dynamic_pointer_cast<MethodStatement>(stmt); std::string methodName = methodStmt->getName(); if (methodName == "offsetget") { ClassScopePtr cls = getClassScope(); std::string arrayAccess("arrayaccess"); if (cls->derivesFrom(ar, arrayAccess, false, false)) { FunctionScopePtr funcScope = methodStmt->getFunctionScope(); std::string name = funcScope->getName(); funcScope->setName("__offsetget_lval"); methodStmt->setName("__offsetget_lval"); methodStmt->outputCPP(cg, ar); funcScope->setName(name); methodStmt->setName("offsetget"); } } } } } }
void FunctionContainer::getFunctionsFlattened( const StringToFunctionScopePtrVecMap *redec, FunctionScopePtrVec &funcs, bool excludePseudoMains /* = false */) const { for (StringToFunctionScopePtrMap::const_iterator it = m_functions.begin(); it != m_functions.end(); ++it) { FunctionScopePtr func = it->second; if (!excludePseudoMains || !func->inPseudoMain()) { if (func->isLocalRedeclaring()) { const FunctionScopePtrVec &r = redec->find(it->first)->second; funcs.insert(funcs.end(), r.begin(), r.end()); } else { funcs.push_back(func); } } } }
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"); }
bool MethodStatement::outputFFI(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); ClassScopePtr clsScope = ar->getClassScope(); bool pseudoMain = funcScope->inPseudoMain(); bool inClass = !m_className.empty(); // only expose public methods, and ignore those in redeclared classes bool inaccessible = inClass && (!m_modifiers->isPublic() || clsScope->isRedeclaring()); // skip constructors bool isConstructor = inClass && funcScope->isConstructor(clsScope); bool valid = !pseudoMain && !inaccessible && !isConstructor; if (cg.getContext() == CodeGenerator::CppFFIDecl || cg.getContext() == CodeGenerator::CppFFIImpl) { if (valid) outputCPPFFIStub(cg, ar); return true; } if (cg.getContext() == CodeGenerator::HsFFI) { if (valid) outputHSFFIStub(cg, ar); return true; } if (cg.getContext() == CodeGenerator::JavaFFI || cg.getContext() == CodeGenerator::JavaFFIInterface) { if (valid) outputJavaFFIStub(cg, ar); return true; } if (cg.getContext() == CodeGenerator::JavaFFICppDecl || cg.getContext() == CodeGenerator::JavaFFICppImpl) { if (valid) outputJavaFFICPPStub(cg, ar); return true; } if (cg.getContext() == CodeGenerator::SwigFFIDecl || cg.getContext() == CodeGenerator::SwigFFIImpl) { if (valid) outputSwigFFIStub(cg, ar); return true; } return false; }
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 FunctionStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { CodeGenerator::Context context = cg.getContext(); FunctionScopePtr funcScope = m_funcScope.lock(); string fname = funcScope->getId(cg).c_str(); bool pseudoMain = funcScope->inPseudoMain(); string origFuncName = !pseudoMain ? funcScope->getOriginalName() : ("run_init::" + funcScope->getFileScope()->getName()); string funcSection; if (outputFFI(cg, ar)) return; if (context == CodeGenerator::NoContext) { string rname = cg.formatLabel(m_name); if (funcScope->isRedeclaring()) { cg.printf("g->%s%s = &%s%s;\n", Option::CallInfoPrefix, m_name.c_str(), Option::CallInfoPrefix, fname.c_str()); } if (funcScope->isVolatile()) { cg_printf("g->declareFunctionLit("); cg_printString(m_name, ar); cg_printf(");\n"); cg_printf("g->FVF(%s) = true;\n", rname.c_str()); } return; } if (context == CodeGenerator::CppDeclaration && !funcScope->isInlined()) return; if (context == CodeGenerator::CppPseudoMain && !pseudoMain) return; if (context == CodeGenerator::CppImplementation && (funcScope->isInlined() || pseudoMain)) return; ar->pushScope(funcScope); cg.setPHPLineNo(-1); if (pseudoMain && !Option::GenerateCPPMain) { if (context == CodeGenerator::CppPseudoMain) { if (cg.getOutput() != CodeGenerator::SystemCPP) { cg.setContext(CodeGenerator::NoContext); // no inner functions/classes funcScope->getVariables()->setAttribute(VariableTable::ForceGlobal); outputCPPStmt(cg, ar); funcScope->getVariables()->clearAttribute(VariableTable::ForceGlobal); cg.setContext(CodeGenerator::CppPseudoMain); ar->popScope(); return; } } else if (context == CodeGenerator::CppForwardDeclaration && cg.getOutput() != CodeGenerator::SystemCPP) { return; } } if (context == CodeGenerator::CppImplementation) { printSource(cg); } else if (context == CodeGenerator::CppForwardDeclaration && Option::GenerateCppLibCode) { cg_printf("\n"); printSource(cg); cg.printDocComment(funcScope->getDocComment()); } if (funcScope->isInlined()) cg_printf("inline "); TypePtr type = funcScope->getReturnType(); if (type) { type->outputCPPDecl(cg, ar); } else { cg_printf("void"); } funcSection = Option::FunctionSections[origFuncName]; if (!funcSection.empty()) { cg_printf(" __attribute__ ((section (\".text.%s\")))", funcSection.c_str()); } if (pseudoMain) { cg_printf(" %s%s(", Option::PseudoMainPrefix, funcScope->getFileScope()->pseudoMainName().c_str()); } else { cg_printf(" %s%s(", Option::FunctionPrefix, fname.c_str()); } switch (context) { case CodeGenerator::CppForwardDeclaration: funcScope->outputCPPParamsDecl(cg, ar, m_params, true); cg_printf(");\n"); if (funcScope->hasDirectInvoke()) { cg_printf("Variant %s%s(void *extra, CArrRef params);\n", Option::InvokePrefix, fname.c_str()); } break; case CodeGenerator::CppDeclaration: case CodeGenerator::CppImplementation: case CodeGenerator::CppPseudoMain: { funcScope->outputCPPParamsDecl(cg, ar, m_params, false); cg_indentBegin(") {\n"); const char *sys = (cg.getOutput() == CodeGenerator::SystemCPP ? "_BUILTIN" : ""); if (pseudoMain) { cg_printf("PSEUDOMAIN_INJECTION%s(%s, %s%s);\n", sys, origFuncName.c_str(), Option::PseudoMainPrefix, funcScope->getFileScope()->pseudoMainName().c_str()); } else { if (m_stmt->hasBody()) { cg_printf("FUNCTION_INJECTION%s(%s);\n", sys, origFuncName.c_str()); } outputCPPArgInjections(cg, ar, origFuncName.c_str(), ClassScopePtr(), funcScope); } funcScope->outputCPP(cg, ar); cg.setContext(CodeGenerator::NoContext); // no inner functions/classes outputCPPStmt(cg, ar); cg.setContext(context); cg_indentEnd("} /* function */\n"); } break; default: ASSERT(false); } ar->popScope(); }