void ClassVariable::analyzeProgramImpl(AnalysisResultPtr ar) { m_declaration->analyzeProgram(ar); AnalysisResult::Phase phase = ar->getPhase(); if (phase != AnalysisResult::AnalyzeAll) { return; } ClassScopePtr scope = getClassScope(); for (int i = 0; i < m_declaration->getCount(); i++) { ExpressionPtr exp = (*m_declaration)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable()); ExpressionPtr value = assignment->getValue(); scope->getVariables()->setClassInitVal(var->getName(), value); scope->getVariables()->markOverride(ar, var->getName()); } else { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(exp); scope->getVariables()->markOverride(ar, var->getName()); scope->getVariables()->setClassInitVal(var->getName(), makeConstant(ar, "null")); } } }
void ClassVariable::inferTypes(AnalysisResultPtr ar) { ASSERT(getScope().get() == getClassScope().get()); IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope()); m_declaration->inferAndCheck(ar, Type::Variant, false); if (m_modifiers->isStatic()) { ClassScopePtr scope = getClassScope(); for (int i = 0; i < m_declaration->getCount(); i++) { ExpressionPtr exp = (*m_declaration)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); // If the class variable's type is Object, we have to // force it to be a Variant, because we don't include // the class header files in global_variables.h SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable()); if (var) { TypePtr type = scope->getVariables()->getFinalType(var->getName()); if (type->is(Type::KindOfObject)) { scope->getVariables()->forceVariant(ar, var->getName(), VariableTable::AnyVars); } } ExpressionPtr value = assignment->getValue(); if (value->containsDynamicConstant(ar)) { scope->getVariables()-> setAttribute(VariableTable::ContainsDynamicStatic); } } } } }
void ClassVariable::analyzeProgram(AnalysisResultPtr ar) { m_declaration->analyzeProgram(ar); AnalysisResult::Phase phase = ar->getPhase(); if (phase != AnalysisResult::AnalyzeAll) { return; } if (m_modifiers->isAbstract()) { Compiler::Error(Compiler::AbstractProperty, shared_from_this()); } ClassScopePtr scope = getClassScope(); for (int i = 0; i < m_declaration->getCount(); i++) { ExpressionPtr exp = (*m_declaration)[i]; bool error; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable()); ExpressionPtr value = assignment->getValue(); scope->getVariables()->setClassInitVal(var->getName(), value); error = scope->getVariables()->markOverride(ar, var->getName()); } else { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(exp); error = scope->getVariables()->markOverride(ar, var->getName()); scope->getVariables()->setClassInitVal(var->getName(), makeConstant(ar, "null")); } if (error) { Compiler::Error(Compiler::InvalidOverride, exp); } } }
bool ObjectPropertyExpression::isNonPrivate(AnalysisResultPtr ar) { // To tell whether a property is declared as private in the context ClassScopePtr cls = getOriginalClass(); if (!cls || !cls->getVariables()->hasNonStaticPrivate()) return true; if (m_property->getKindOf() != Expression::KindOfScalarExpression) { return false; } ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(m_property); string propName = name->getString(); Symbol *sym = cls->getVariables()->getSymbol(propName); if (!sym || sym->isStatic() || !sym->isPrivate()) return true; return false; }
void ClassVariable::inferTypes(AnalysisResultPtr ar) { assert(getScope().get() == getClassScope().get()); IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope()); // assignments will ignore the passed in type, // but we need to ensure that Null is applied to // the simple variables. m_declaration->inferAndCheck(ar, Type::Null, false); if (m_modifiers->isStatic()) { ClassScopePtr scope = getClassScope(); for (int i = 0; i < m_declaration->getCount(); i++) { ExpressionPtr exp = (*m_declaration)[i]; SimpleVariablePtr var; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); ExpressionPtr value = assignment->getValue(); if (value->containsDynamicConstant(ar)) { scope->getVariables()-> setAttribute(VariableTable::ContainsDynamicStatic); } } } } }
void AnalysisResult::forceClassVariants( const std::string &name, ClassScopePtr curScope, bool doStatic, bool acquireLocks /* = false */) { if (curScope) { COND_TRY_LOCK(curScope, acquireLocks); curScope->getVariables()->forceVariant( shared_from_this(), name, VariableTable::GetVarClassMask(true, doStatic)); } ConditionalLock lock(getMutex(), acquireLocks); if (m_classForcedVariants[doStatic]) { return; } AnalysisResultPtr ar = shared_from_this(); for (StringToClassScopePtrVecMap::const_iterator iter = m_classDecs.begin(); iter != m_classDecs.end(); ++iter) { for (ClassScopePtr cls: iter->second) { COND_TRY_LOCK(cls, acquireLocks); cls->getVariables()->forceVariant( ar, name, VariableTable::GetVarClassMask(false, doStatic)); } } }
void ClassVariable::onParseRecur(AnalysisResultConstPtr ar, ClassScopePtr scope) { ModifierExpressionPtr modifiers = scope->setModifiers(m_modifiers); for (int i = 0; i < m_declaration->getCount(); i++) { VariableTablePtr variables = scope->getVariables(); ExpressionPtr exp = (*m_declaration)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); ExpressionPtr var = assignment->getVariable(); const std::string &name = dynamic_pointer_cast<SimpleVariable>(var)->getName(); if (variables->isPresent(name)) { Compiler::Error(Compiler::DeclaredVariableTwice, exp); m_declaration->removeElement(i--); } else { assignment->onParseRecur(ar, scope); } } else { const std::string &name = dynamic_pointer_cast<SimpleVariable>(exp)->getName(); if (variables->isPresent(name)) { Compiler::Error(Compiler::DeclaredVariableTwice, exp); m_declaration->removeElement(i--); } else { variables->add(name, Type::Variant, false, ar, exp, m_modifiers); } } } scope->setModifiers(modifiers); }
void VariableTable::forceVariants(AnalysisResultConstPtr ar, int varClass, bool recur /* = true */) { int mask = varClass & ~m_forcedVariants; if (mask) { if (!m_hasPrivate) mask &= ~AnyPrivateVars; if (!m_hasStatic) mask &= ~AnyStaticVars; if (mask) { for (unsigned int i = 0; i < m_symbolVec.size(); i++) { Symbol *sym = m_symbolVec[i]; if (!sym->isHidden() && sym->declarationSet() && mask & GetVarClassMaskForSym(sym)) { setType(ar, sym, Type::Variant, true); sym->setIndirectAltered(); } } } m_forcedVariants |= varClass; if (recur) { ClassScopePtr parent = m_blockScope.getParentScope(ar); if (parent && !parent->isRedeclaring()) { parent->getVariables()->forceVariants(ar, varClass & ~AnyPrivateVars); } } } }
void AssignmentExpression::onParseRecur(AnalysisResultConstPtr ar, ClassScopePtr scope) { // This is that much we can do during parse phase. TypePtr type; if (m_value->is(Expression::KindOfScalarExpression)) { type = static_pointer_cast<ScalarExpression>(m_value)->inferenceImpl( ar, Type::Some, false); } else if (m_value->is(Expression::KindOfUnaryOpExpression)) { UnaryOpExpressionPtr uexp = dynamic_pointer_cast<UnaryOpExpression>(m_value); if (uexp->getOp() == T_ARRAY) { type = Type::Array; } } if (!type) type = Type::Some; if (m_variable->is(Expression::KindOfConstantExpression)) { // ...as in ClassConstant statement // We are handling this one here, not in ClassConstant, purely because // we need "value" to store in constant table. ConstantExpressionPtr exp = dynamic_pointer_cast<ConstantExpression>(m_variable); scope->getConstants()->add(exp->getName(), type, m_value, ar, m_variable); } else if (m_variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_variable); scope->getVariables()->add(var->getName(), type, true, ar, shared_from_this(), scope->getModifiers()); var->clearContext(Declaration); // to avoid wrong CodeError } else { ASSERT(false); // parse phase shouldn't handle anything else } }
void AssignmentExpression::onParseRecur(AnalysisResultConstPtr ar, FileScopeRawPtr fs, ClassScopePtr scope) { auto isArray = false; if (m_value->is(Expression::KindOfUnaryOpExpression)) { auto uexp = dynamic_pointer_cast<UnaryOpExpression>(m_value); if (uexp->getOp() == T_ARRAY) { isArray = true; } } if (m_variable->is(Expression::KindOfConstantExpression)) { // ...as in ClassConstant statement // We are handling this one here, not in ClassConstant, purely because // we need "value" to store in constant table. if (isArray) { parseTimeFatal(fs, Compiler::NoError, "Arrays are not allowed in class constants"); } auto exp = dynamic_pointer_cast<ConstantExpression>(m_variable); scope->getConstants()->add(exp->getName(), m_value, ar, m_variable); } else if (m_variable->is(Expression::KindOfSimpleVariable)) { auto var = dynamic_pointer_cast<SimpleVariable>(m_variable); scope->getVariables()->add(var->getName(), true, ar, shared_from_this(), scope->getModifiers()); var->clearContext(Declaration); // to avoid wrong CodeError } else { assert(false); // parse phase shouldn't handle anything else } }
void ClassVariable::getCtorAndInitInfo( ExpressionPtr exp, bool &needsCppCtor, bool &needsInit, SimpleVariablePtr &var, TypePtr &type, Symbol *&sym, ExpressionPtr &value) { ClassScopePtr scope = getClassScope(); bool derivFromRedec = scope->derivesFromRedeclaring() && !m_modifiers->isPrivate(); AssignmentExpressionPtr assignment; bool isAssign = exp->is(Expression::KindOfAssignmentExpression); if (isAssign) { assignment = static_pointer_cast<AssignmentExpression>(exp); var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable()); ASSERT(var); value = assignment->getValue(); ASSERT(value); } else { var = dynamic_pointer_cast<SimpleVariable>(exp); ASSERT(var); } sym = scope->getVariables()->getSymbol(var->getName()); ASSERT(sym); type = scope->getVariables()->getFinalType(var->getName()); ASSERT(type); bool isValueNull = isAssign ? value->isLiteralNull() : false; bool typeIsInitable = type->is(Type::KindOfVariant) || type->getCPPInitializer(); if (!derivFromRedec && !sym->isOverride() && (isAssign ? (isValueNull || (value->is(Expression::KindOfScalarExpression) && type->isPrimitive())) : typeIsInitable)) { needsCppCtor = true; } else if (isAssign || typeIsInitable) { // if we aren't an assignment and the type is not a variant // w/ no CPP initializer, then we currently don't bother // to initialize it in init(). needsInit = true; } }
void ClassVariable::addTraitPropsToScope(AnalysisResultPtr ar, ClassScopePtr scope) { ModifierExpressionPtr modifiers = scope->setModifiers(m_modifiers); VariableTablePtr variables = scope->getVariables(); for (int i = 0; i < m_declaration->getCount(); i++) { ExpressionPtr exp = (*m_declaration)[i]; SimpleVariablePtr var; ExpressionPtr value; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable()); value = assignment->getValue(); } else { var = dynamic_pointer_cast<SimpleVariable>(exp); value = makeConstant(ar, "null"); } const string &name = var->getName(); Symbol *sym; ClassScopePtr prevScope = variables->isPresent(name) ? scope : scope->getVariables()->findParent(ar, name, sym); if (prevScope && !isEquivRedecl(name, exp, m_modifiers, prevScope->getVariables()->getSymbol(name))) { Compiler::Error(Compiler::DeclaredVariableTwice, exp); m_declaration->removeElement(i--); } else { if (prevScope != scope) { // Property is new or override, so add it variables->add(name, Type::Variant, false, ar, exp, m_modifiers); variables->getSymbol(name)->setValue(exp); variables->setClassInitVal(name, value); variables->markOverride(ar, name); } else { m_declaration->removeElement(i--); } } } scope->setModifiers(modifiers); }
void ClassVariable::inferTypes(AnalysisResultPtr ar) { m_declaration->inferAndCheck(ar, NEW_TYPE(Some), false); if (m_modifiers->isStatic()) { ClassScopePtr scope = ar->getClassScope(); for (int i = 0; i < m_declaration->getCount(); i++) { ExpressionPtr exp = (*m_declaration)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { scope->setNeedStaticInitializer(); AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); // If the class variable's type is Object, we have to // force it to be a Variant, because we don't include // the class header files in global_variables.h SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable()); if (var) { TypePtr type = scope->getVariables()->getFinalType(var->getName()); if (type->is(Type::KindOfObject)) { scope->getVariables()->forceVariant(ar, var->getName()); } } ExpressionPtr value = assignment->getValue(); if (value->containsDynamicConstant(ar)) { scope->getVariables()-> setAttribute(VariableTable::ContainsDynamicStatic); } } else { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(exp); TypePtr type = scope->getVariables()->getFinalType(var->getName()); // If the class variable's type is Object, we have to // force it to be a Variant, because we don't include // the class header files in global_variables.h if (type->is(Type::KindOfObject)) { scope->getVariables()->forceVariant(ar, var->getName()); } const char *initializer = type->getCPPInitializer(); if (initializer) scope->setNeedStaticInitializer(); } } } }
TypePtr VariableTable::checkProperty(BlockScopeRawPtr context, Symbol *sym, TypePtr type, bool coerce, AnalysisResultConstPtr ar) { always_assert(sym->isPresent()); if (sym->isOverride()) { Symbol *base; ClassScopePtr parent = findParent(ar, sym->getName(), base); assert(parent); assert(parent.get() != &m_blockScope); assert(base && !base->isPrivate()); if (context->is(BlockScope::FunctionScope)) { GET_LOCK(parent); type = parent->getVariables()->setType(ar, base, type, coerce); } else { TRY_LOCK(parent); type = parent->getVariables()->setType(ar, base, type, coerce); } } return setType(ar, sym, type, coerce); }
ClassScopePtr VariableTable::findParent(AnalysisResultConstPtr ar, const string &name, const Symbol *&sym) const { sym = nullptr; for (ClassScopePtr parent = m_blockScope.getParentScope(ar); parent && !parent->isRedeclaring(); parent = parent->getParentScope(ar)) { sym = parent->getVariables()->getSymbol(name); assert(!sym || sym->isPresent()); if (sym) return parent; } return ClassScopePtr(); }
StatementPtr ClassVariable::preOptimize(AnalysisResultConstPtr ar) { ClassScopePtr scope = getClassScope(); for (int i = 0; i < m_declaration->getCount(); i++) { ExpressionPtr exp = (*m_declaration)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable()); ExpressionPtr value = assignment->getValue(); scope->getVariables()->setClassInitVal(var->getName(), value); } } return StatementPtr(); }
void ClassVariable::analyzeProgramImpl(AnalysisResultPtr ar) { m_declaration->analyzeProgram(ar); if (ar->getPhase() != AnalysisResult::AnalyzeInclude) return; ClassScopePtr scope = ar->getClassScope(); for (int i = 0; i < m_declaration->getCount(); i++) { ExpressionPtr exp = (*m_declaration)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable()); ExpressionPtr value = assignment->getValue(); scope->getVariables()->setClassInitVal(var->getName(), value); } } }
void ClassVariable::onParseRecur(AnalysisResultConstPtr ar, ClassScopePtr scope) { ModifierExpressionPtr modifiers = scope->setModifiers(m_modifiers); if (m_modifiers->isAbstract()) { parseTimeFatal(Compiler::InvalidAttribute, "Properties cannot be declared abstract"); } if (m_modifiers->isFinal()) { parseTimeFatal(Compiler::InvalidAttribute, "Properties cannot be declared final"); } for (int i = 0; i < m_declaration->getCount(); i++) { VariableTablePtr variables = scope->getVariables(); ExpressionPtr exp = (*m_declaration)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); ExpressionPtr var = assignment->getVariable(); const std::string &name = dynamic_pointer_cast<SimpleVariable>(var)->getName(); if (variables->isPresent(name)) { exp->parseTimeFatal(Compiler::DeclaredVariableTwice, "Cannot redeclare %s::$%s", scope->getOriginalName().c_str(), name.c_str()); } else { assignment->onParseRecur(ar, scope); } } else { const std::string &name = dynamic_pointer_cast<SimpleVariable>(exp)->getName(); if (variables->isPresent(name)) { exp->parseTimeFatal(Compiler::DeclaredVariableTwice, "Cannot redeclare %s::$%s", scope->getOriginalName().c_str(), name.c_str()); } else { variables->add(name, Type::Null, false, ar, exp, m_modifiers); } } } scope->setModifiers(modifiers); }
bool AnalysisResult::declareClass(ClassScopePtr classScope) const { assert(m_phase < AnalyzeAll); string cname = classScope->getName(); // System classes override if (m_systemClasses.find(cname) != m_systemClasses.end()) { // we need someone to hold on to a reference to it // even though we're not going to do anything with it this->lock()->m_ignoredScopes.push_back(classScope); return false; } int mask = (m_classForcedVariants[0] ? VariableTable::NonPrivateNonStaticVars : 0) | (m_classForcedVariants[1] ? VariableTable::NonPrivateStaticVars : 0); if (mask) { AnalysisResultConstPtr ar = shared_from_this(); classScope->getVariables()->forceVariants(ar, mask); } return true; }
bool Option::Load(const char *filename) { ASSERT(filename && *filename); try { Scanner scanner(new ylmm::basic_buffer(filename), true, false); Logger::Info("loading options from %s...", filename); AnalysisResultPtr ar(new AnalysisResult()); struct stat sb; if (stat(filename, &sb)) { Logger::Error("Unable to stat file %s", filename); return false; } ParserPtr parser(new Parser(scanner, filename, sb.st_size, ar)); if (parser->parse()) { Logger::Error("Unable to parse file: %s\n%s", filename, parser->getMessage().c_str()); return false; } FileScopePtr file = ar->findFileScope(filename, false); ClassScopePtr cls = file->getClass("hphpoption"); if (!cls) { Logger::Error("Unable to find HPHPOption class in %s", filename); return false; } if (!Load(cls->getVariables())) { return false; } } catch (std::runtime_error) { Logger::Error("Unable to open file %s", filename); return false; } return true; }
void ClassStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr classScope = m_classScope.lock(); if (cg.getContext() == CodeGenerator::NoContext) { if (classScope->isRedeclaring()) { cg_printf("g->%s%s = ClassStaticsPtr(NEW(%s%s)());\n", Option::ClassStaticsObjectPrefix, cg.formatLabel(m_name).c_str(), Option::ClassStaticsPrefix, classScope->getId(cg).c_str()); cg_printf("g->%s%s = &%s%s;\n", Option::ClassStaticsCallbackPrefix, cg.formatLabel(m_name).c_str(), Option::ClassWrapperFunctionPrefix, classScope->getId(cg).c_str()); } if (classScope->isVolatile()) { cg_printf("g->CDEC(%s) = true;\n", m_name.c_str()); } const vector<string> &bases = classScope->getBases(); for (vector<string>::const_iterator it = bases.begin(); it != bases.end(); ++it) { ClassScopePtr base = ar->findClass(*it); if (base && base->isVolatile()) { cg_printf("checkClassExists(\"%s\", g);\n", base->getOriginalName().c_str()); } } return; } if (cg.getContext() != CodeGenerator::CppForwardDeclaration) { printSource(cg); } ar->pushScope(classScope); string clsNameStr = classScope->getId(cg); const char *clsName = clsNameStr.c_str(); bool redeclared = classScope->isRedeclaring(); switch (cg.getContext()) { case CodeGenerator::CppForwardDeclaration: if (Option::GenerateCPPMacros) { cg_printf("FORWARD_DECLARE_CLASS(%s)\n", clsName); if (redeclared) { cg_printf("FORWARD_DECLARE_REDECLARED_CLASS(%s)\n", clsName); } } if (m_stmt) { cg.setContext(CodeGenerator::CppClassConstantsDecl); m_stmt->outputCPP(cg, ar); cg.setContext(CodeGenerator::CppForwardDeclaration); } break; case CodeGenerator::CppDeclaration: { bool system = cg.getOutput() == CodeGenerator::SystemCPP; ClassScopePtr parCls; if (!m_parent.empty()) { parCls = ar->findClass(m_parent); if (parCls && parCls->isRedeclaring()) parCls.reset(); } cg_printf("class %s%s", Option::ClassPrefix, clsName); if (!m_parent.empty() && classScope->derivesDirectlyFrom(ar, m_parent)) { if (!parCls) { cg_printf(" : public DynamicObjectData"); } else { cg_printf(" : public %s%s", Option::ClassPrefix, parCls->getId(cg).c_str()); } } else { if (classScope->derivesFromRedeclaring()) { cg_printf(" : public DynamicObjectData"); } else if (system) { cg_printf(" : public ExtObjectData"); } else { cg_printf(" : public ObjectData"); } } if (m_base && Option::UseVirtualDispatch) { for (int i = 0; i < m_base->getCount(); i++) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>((*m_base)[i]); const char *intf = exp->getString().c_str(); ClassScopePtr intfClassScope = ar->findClass(intf); if (intfClassScope && !intfClassScope->isRedeclaring() && classScope->derivesDirectlyFrom(ar, intf) && (!parCls || !parCls->derivesFrom(ar, intf, true, false))) { string id = intfClassScope->getId(cg); cg_printf(", public %s%s", Option::ClassPrefix, id.c_str()); } } } cg_indentBegin(" {\n"); if (Option::GenerateCPPMacros) { // Get all of this class's ancestors vector<string> bases; getAllParents(ar, bases); // Eliminate duplicates sort(bases.begin(), bases.end()); bases.erase(unique(bases.begin(), bases.end()), bases.end()); cg_indentBegin("BEGIN_CLASS_MAP(%s)\n", Util::toLower(classScope->getName()).c_str()); for (unsigned int i = 0; i < bases.size(); i++) { cg_printf("PARENT_CLASS(%s)\n", bases[i].c_str()); } if (classScope->derivesFromRedeclaring()) { cg_printf("CLASS_MAP_REDECLARED()\n"); } cg_indentEnd("END_CLASS_MAP(%s)\n", clsName); } if (Option::GenerateCPPMacros) { bool dyn = (!parCls && !m_parent.empty()) || classScope->derivesFromRedeclaring() == ClassScope::DirectFromRedeclared; bool idyn = parCls && classScope->derivesFromRedeclaring() == ClassScope::IndirectFromRedeclared; bool redec = classScope->isRedeclaring(); if (!classScope->derivesFromRedeclaring()) { outputCPPClassDecl(cg, ar, clsName, m_originalName.c_str(), parCls ? parCls->getId(cg).c_str() : "ObjectData"); } else { cg_printf("DECLARE_DYNAMIC_CLASS(%s, %s, %s)\n", clsName, m_originalName.c_str(), dyn || !parCls ? "DynamicObjectData" : parCls->getId(cg).c_str()); } if (system || Option::EnableEval >= Option::LimitedEval) { cg_printf("DECLARE_INVOKES_FROM_EVAL\n"); } if (dyn || idyn || redec) { if (redec) { cg_printf("DECLARE_ROOT;\n"); if (!dyn && !idyn) { cg_printf("private: ObjectData* root;\n"); cg_printf("public:\n"); cg_printf("virtual ObjectData *getRoot() { return root; }\n"); } } string conInit = ":"; if (dyn) { conInit += "DynamicObjectData(\"" + m_parent + "\", r)"; } else if (idyn) { conInit += string(Option::ClassPrefix) + parCls->getId(cg) + "(r?r:this)"; } else { conInit += "root(r?r:this)"; } cg_printf("%s%s(ObjectData* r = NULL)%s {}\n", Option::ClassPrefix, clsName, conInit.c_str()); } } cg_printf("void init();\n", Option::ClassPrefix, clsName); if (classScope->needLazyStaticInitializer()) { cg_printf("static GlobalVariables *lazy_initializer" "(GlobalVariables *g);\n"); } classScope->getVariables()->outputCPPPropertyDecl(cg, ar, classScope->derivesFromRedeclaring()); if (!classScope->getAttribute(ClassScope::HasConstructor)) { FunctionScopePtr func = classScope->findFunction(ar, "__construct", false); if (func && !func->isAbstract() && !classScope->isInterface()) { ar->pushScope(func); func->outputCPPCreateDecl(cg, ar); ar->popScope(); } } if (classScope->getAttribute(ClassScope::HasDestructor)) { cg_printf("public: virtual void destruct();\n"); } // doCall if (classScope->getAttribute(ClassScope::HasUnknownMethodHandler)) { cg_printf("Variant doCall(Variant v_name, Variant v_arguments, " "bool fatal);\n"); } // doGet if (classScope->getAttribute(ClassScope::HasUnknownPropHandler)) { cg_printf("Variant doGet(Variant v_name, bool error);\n"); } if (classScope->isRedeclaring() && !classScope->derivesFromRedeclaring()) { cg_printf("Variant doRootCall(Variant v_name, Variant v_arguments, " "bool fatal);\n"); } if (m_stmt) m_stmt->outputCPP(cg, ar); { set<string> done; classScope->outputCPPStaticMethodWrappers(cg, ar, done, clsName); } if (cg.getOutput() == CodeGenerator::SystemCPP && ar->isBaseSysRsrcClass(clsName) && !classScope->hasProperty("rsrc")) { cg_printf("public: Variant %srsrc;\n", Option::PropertyPrefix); } cg_indentEnd("};\n"); if (redeclared) { cg_indentBegin("class %s%s : public ClassStatics {\n", Option::ClassStaticsPrefix, clsName); cg_printf("public:\n"); cg_printf("DECLARE_OBJECT_ALLOCATION(%s%s);\n", Option::ClassStaticsPrefix, clsName); cg_printf("%s%s() : ClassStatics(%d) {}\n", Option::ClassStaticsPrefix, clsName, classScope->getRedeclaringId()); cg_indentBegin("Variant %sgetInit(const char *s, int64 hash = -1) {\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%sgetInit(s, hash);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentBegin("Variant %sget(const char *s, int64 hash = -1) {\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%sget(s, hash);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentBegin("Variant &%slval(const char* s, int64 hash = -1) {\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%slval(s, hash);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentBegin("Variant %sinvoke(const char *c, const char *s, " "CArrRef params, int64 hash = -1, bool fatal = true) " "{\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%sinvoke(c, s, params, hash, fatal);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentBegin("Object create(CArrRef params, bool init = true, " "ObjectData* root = NULL) {\n"); cg_printf("return Object((NEW(%s%s)(root))->" "dynCreate(params, init));\n", Option::ClassPrefix, clsName); cg_indentEnd("}\n"); cg_indentBegin("Variant %sconstant(const char* s) {\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%sconstant(s);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentBegin("Variant %sinvoke_from_eval(const char *c, " "const char *s, Eval::VariableEnvironment &env, " "const Eval::FunctionCallExpression *call, " "int64 hash = -1, bool fatal = true) " "{\n", Option::ObjectStaticPrefix); cg_printf("return %s%s::%sinvoke_from_eval(c, s, env, call, hash, " "fatal);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg_indentEnd("}\n"); cg_indentEnd("};\n"); } classScope->outputCPPGlobalTableWrappersDecl(cg, ar); } break; case CodeGenerator::CppImplementation: if (m_stmt) { cg.setContext(CodeGenerator::CppClassConstantsImpl); m_stmt->outputCPP(cg, ar); cg.setContext(CodeGenerator::CppImplementation); } classScope->outputCPPSupportMethodsImpl(cg, ar); if (redeclared) { cg_printf("IMPLEMENT_OBJECT_ALLOCATION(%s%s);\n", Option::ClassStaticsPrefix, clsName); } cg_indentBegin("void %s%s::init() {\n", Option::ClassPrefix, clsName); if (!m_parent.empty()) { if (classScope->derivesFromRedeclaring() == ClassScope::DirectFromRedeclared) { cg_printf("parent->init();\n"); } else { cg_printf("%s%s::init();\n", Option::ClassPrefix, m_parent.c_str()); } } if (classScope->getVariables()-> getAttribute(VariableTable::NeedGlobalPointer)) { cg.printDeclareGlobals(); } cg.setContext(CodeGenerator::CppConstructor); if (m_stmt) m_stmt->outputCPP(cg, ar); // This is lame. Exception base class needs to prepare stacktrace outside // of its PHP constructor. Every subclass of exception also needs this // stacktrace, so we're adding an artificial __init__ in exception.php // and calling it here. if (m_name == "exception") { cg_printf("{CountableHelper h(this); t___init__();}\n"); } cg_indentEnd("}\n"); if (classScope->needStaticInitializer()) { cg_indentBegin("void %s%s::os_static_initializer() {\n", Option::ClassPrefix, clsName); cg.printDeclareGlobals(); cg.setContext(CodeGenerator::CppStaticInitializer); if (m_stmt) m_stmt->outputCPP(cg, ar); cg_indentEnd("}\n"); cg_indentBegin("void %s%s() {\n", Option::ClassStaticInitializerPrefix, clsName); cg_printf("%s%s::os_static_initializer();\n", Option::ClassPrefix, clsName); cg_indentEnd("}\n"); } if (classScope->needLazyStaticInitializer()) { cg_indentBegin("GlobalVariables *%s%s::lazy_initializer(" "GlobalVariables *g) {\n", Option::ClassPrefix, clsName); cg_indentBegin("if (!g->%s%s) {\n", Option::ClassStaticInitializerFlagPrefix, clsName); cg_printf("g->%s%s = true;\n", Option::ClassStaticInitializerFlagPrefix, clsName); cg.setContext(CodeGenerator::CppLazyStaticInitializer); if (m_stmt) m_stmt->outputCPP(cg, ar); cg_indentEnd("}\n"); cg_printf("return g;\n"); cg_indentEnd("}\n"); } cg.setContext(CodeGenerator::CppImplementation); if (m_stmt) m_stmt->outputCPP(cg, ar); break; case CodeGenerator::CppFFIDecl: case CodeGenerator::CppFFIImpl: if (m_stmt) m_stmt->outputCPP(cg, ar); break; case CodeGenerator::JavaFFI: { if (classScope->isRedeclaring()) break; // TODO support PHP namespaces, once HPHP supports it string packageName = Option::JavaFFIRootPackage; string packageDir = packageName; Util::replaceAll(packageDir, ".", "/"); string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix + packageDir + "/"; Util::mkdir(outputDir); // uses a different cg to generate a separate file for each PHP class // also, uses the original capitalized class name string clsFile = outputDir + getOriginalName() + ".java"; ofstream fcls(clsFile.c_str()); CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP); cgCls.setContext(CodeGenerator::JavaFFI); cgCls.printf("package %s;\n\n", packageName.c_str()); cgCls.printf("import hphp.*;\n\n"); printSource(cgCls); string clsModifier; switch (m_type) { case T_CLASS: break; case T_ABSTRACT: clsModifier = "abstract "; break; case T_FINAL: clsModifier = "final "; break; } cgCls.printf("public %sclass %s ", clsModifier.c_str(), getOriginalName().c_str()); ClassScopePtr parCls; if (!m_parent.empty()) parCls = ar->findClass(m_parent); if (!m_parent.empty() && classScope->derivesDirectlyFrom(ar, m_parent) && parCls && parCls->isUserClass() && !parCls->isRedeclaring()) { // system classes are not supported in static FFI translation // they shouldn't appear as superclasses as well cgCls.printf("extends %s", parCls->getOriginalName().c_str()); } else { cgCls.printf("extends HphpObject"); } if (m_base) { bool first = true; for (int i = 0; i < m_base->getCount(); i++) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>((*m_base)[i]); const char *intf = exp->getString().c_str(); ClassScopePtr intfClassScope = ar->findClass(intf); if (intfClassScope && classScope->derivesFrom(ar, intf, false, false) && intfClassScope->isUserClass()) { if (first) { cgCls.printf(" implements "); first = false; } else { cgCls.printf(", "); } cgCls.printf(intfClassScope->getOriginalName().c_str()); } } } cgCls.indentBegin(" {\n"); // constructor for initializing the variant pointer cgCls.printf("protected %s(long ptr) { super(ptr); }\n\n", getOriginalName().c_str()); FunctionScopePtr cons = classScope->findConstructor(ar, true); if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) { // if not an abstract class and not having an explicit constructor, // adds a default constructor outputJavaFFIConstructor(cgCls, ar, cons); } if (m_stmt) m_stmt->outputCPP(cgCls, ar); cgCls.indentEnd("}\n"); fcls.close(); } break; case CodeGenerator::JavaFFICppDecl: case CodeGenerator::JavaFFICppImpl: { if (classScope->isRedeclaring()) break; if (m_stmt) m_stmt->outputCPP(cg, ar); FunctionScopePtr cons = classScope->findConstructor(ar, true); if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) { outputJavaFFICPPCreator(cg, ar, cons); } } break; default: ASSERT(false); break; } ar->popScope(); }
void ClassStatement::outputCPPClassDecl(CodeGenerator &cg, AnalysisResultPtr ar, const char *clsName, const char *originalName, const char *parent) { ClassScopePtr classScope = m_classScope.lock(); VariableTablePtr variables = classScope->getVariables(); ConstantTablePtr constants = classScope->getConstants(); if (variables->hasAllJumpTables() && constants->hasJumpTable() && classScope->hasAllJumpTables()) { cg_printf("DECLARE_CLASS(%s, %s, %s)\n", clsName, originalName, parent); return; } // Now we start to break down DECLARE_CLASS into lines of code that could // be generated differently... cg_printf("DECLARE_CLASS_COMMON(%s, %s)\n", clsName, originalName); cg_printf("DECLARE_INVOKE_EX(%s, %s, %s)\n", clsName, originalName, parent); cg.printSection("DECLARE_STATIC_PROP_OPS"); cg_printf("public:\n"); if (classScope->needStaticInitializer()) { cg_printf("static void os_static_initializer();\n"); } if (variables->hasJumpTable(VariableTable::JumpTableClassStaticGetInit)) { cg_printf("static Variant os_getInit(const char *s, int64 hash);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_GETINIT_%s 1\n", clsName); } if (variables->hasJumpTable(VariableTable::JumpTableClassStaticGet)) { cg_printf("static Variant os_get(const char *s, int64 hash);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_GET_%s 1\n", clsName); } if (variables->hasJumpTable(VariableTable::JumpTableClassStaticLval)) { cg_printf("static Variant &os_lval(const char *s, int64 hash);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_LVAL_%s 1\n", clsName); } if (constants->hasJumpTable()) { cg_printf("static Variant os_constant(const char *s);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_CONSTANT_%s 1\n", clsName); } cg.printSection("DECLARE_INSTANCE_PROP_OPS"); cg_printf("public:\n"); cg_printf("virtual bool o_exists(CStrRef s, int64 hash,\n"); cg_printf(" const char *context = NULL) const;\n"); cg_printf("bool o_existsPrivate(CStrRef s, int64 hash) const;\n"); cg_printf("virtual void o_get(Array &props) const;\n"); cg_printf("virtual Variant o_get(CStrRef s, int64 hash, " "bool error = true,\n"); cg_printf(" const char *context = NULL);\n"); cg_printf("Variant o_getPrivate(CStrRef s, int64 hash, " "bool error = true);\n"); cg_printf("virtual Variant o_set(CStrRef s, int64 hash, CVarRef v,\n"); cg_printf(" bool forInit = false,\n"); cg_printf(" const char *context = NULL);\n"); cg_printf("Variant o_setPrivate(CStrRef s, int64 hash, CVarRef v, " "bool forInit);\n"); cg_printf("virtual Variant &o_lval(CStrRef s, int64 hash,\n"); cg_printf(" const char *context = NULL);\n"); cg_printf("Variant &o_lvalPrivate(CStrRef s, int64 hash);\n"); cg.printSection("DECLARE_INSTANCE_PUBLIC_PROP_OPS"); cg_printf("public:\n"); if (variables->hasJumpTable(VariableTable::JumpTableClassExistsPublic)) { cg_printf("virtual bool o_existsPublic(CStrRef s, int64 hash) const;\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_exists_PUBLIC_%s 1\n", clsName); } if (variables->hasJumpTable(VariableTable::JumpTableClassGetPublic)) { cg_printf("virtual Variant o_getPublic(CStrRef s, int64 hash,\n"); cg_printf(" bool error = true);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_get_PUBLIC_%s 1\n", clsName); } if (variables->hasJumpTable(VariableTable::JumpTableClassSetPublic)) { cg_printf("virtual Variant o_setPublic(CStrRef s, int64 hash,\n"); cg_printf(" CVarRef v, bool forInit);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_set_PUBLIC_%s 1\n", clsName); } if (variables->hasJumpTable(VariableTable::JumpTableClassLvalPublic)) { cg_printf("virtual Variant &o_lvalPublic(CStrRef s, int64 hash);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_lval_PUBLIC_%s 1\n", clsName); } cg.printSection("DECLARE_COMMON_INVOKE"); if (classScope->hasJumpTable(ClassScope::JumpTableStaticInvoke)) { cg_printf("static Variant os_invoke(const char *c, const char *s,\n"); cg_printf(" CArrRef ps, int64 h, " "bool f = true);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_INVOKE_%s 1\n", clsName); } if (classScope->hasJumpTable(ClassScope::JumpTableInvoke)) { cg_printf("virtual Variant o_invoke(const char *s, CArrRef ps, " "int64 h,\n"); cg_printf(" bool f = true);\n"); cg_printf("virtual Variant o_invoke_few_args(const char *s, int64 h,\n"); cg_printf(" int count,\n"); cg_printf(" " "INVOKE_FEW_ARGS_DECL_ARGS);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_INVOKE_%s 1\n", clsName); } cg_printf("\n"); cg_printf("public:\n"); }
bool ClassStatement::hasImpl() const { ClassScopePtr cls = m_classScope.lock(); return cls->isVolatile() || cls->getVariables()->getAttribute(VariableTable::ContainsDynamicStatic); }
void ClassVariable::onParseRecur(AnalysisResultConstRawPtr ar, FileScopeRawPtr fs, ClassScopePtr scope) { ModifierExpressionPtr modifiers = scope->setModifiers(m_modifiers); if (m_modifiers->isAbstract()) { m_modifiers->parseTimeFatal(fs, Compiler::InvalidAttribute, "Properties cannot be declared abstract"); } if (m_modifiers->isFinal()) { m_modifiers->parseTimeFatal(fs, Compiler::InvalidAttribute, "Properties cannot be declared final"); } if (!m_modifiers->isStatic() && scope->isStaticUtil()) { m_modifiers->parseTimeFatal( fs, Compiler::InvalidAttribute, "Class %s contains non-static property declaration and " "therefore cannot be declared 'abstract final'", scope->getOriginalName().c_str() ); } if ((m_modifiers->isExplicitlyPublic() + m_modifiers->isProtected() + m_modifiers->isPrivate()) > 1) { m_modifiers->parseTimeFatal( fs, Compiler::InvalidAttribute, "%s: properties of %s", Strings::PICK_ACCESS_MODIFIER, scope->getOriginalName().c_str() ); } for (int i = 0; i < m_declaration->getCount(); i++) { VariableTablePtr variables = scope->getVariables(); ExpressionPtr exp = (*m_declaration)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { auto assignment = dynamic_pointer_cast<AssignmentExpression>(exp); ExpressionPtr var = assignment->getVariable(); const auto& name = dynamic_pointer_cast<SimpleVariable>(var)->getName(); if (variables->isPresent(name)) { exp->parseTimeFatal(fs, Compiler::DeclaredVariableTwice, "Cannot redeclare %s::$%s", scope->getOriginalName().c_str(), name.c_str()); } else { assignment->onParseRecur(ar, fs, scope); } } else { const std::string &name = dynamic_pointer_cast<SimpleVariable>(exp)->getName(); if (variables->isPresent(name)) { exp->parseTimeFatal(fs, Compiler::DeclaredVariableTwice, "Cannot redeclare %s::$%s", scope->getOriginalName().c_str(), name.c_str()); } else { variables->add(name, false, ar, exp, m_modifiers); } } } scope->setModifiers(modifiers); }
void ClassStatement::outputCPPClassDecl(CodeGenerator &cg, AnalysisResultPtr ar, const char *clsName, const char *originalName, const char *parent) { ClassScopePtr classScope = m_classScope.lock(); VariableTablePtr variables = classScope->getVariables(); ConstantTablePtr constants = classScope->getConstants(); if (variables->hasAllJumpTables() && constants->hasJumpTable() && classScope->hasAllJumpTables()) { cg_printf("DECLARE_CLASS(%s, %s, %s)\n", clsName, originalName, parent); return; } // Now we start to break down DECLARE_CLASS into lines of code that could // be generated differently... cg_printf("DECLARE_CLASS_COMMON(%s, %s)\n", clsName, originalName); cg_printf("DECLARE_INVOKE_EX(%s, %s, %s)\n", clsName, originalName, parent); cg.printSection("DECLARE_STATIC_PROP_OPS"); cg_printf("public:\n"); if (classScope->needStaticInitializer()) { cg_printf("static void os_static_initializer();\n"); } if (variables->hasJumpTable(VariableTable::JumpTableClassStaticGetInit)) { cg_printf("static Variant os_getInit(CStrRef s);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_GETINIT_%s 1\n", clsName); } if (variables->hasJumpTable(VariableTable::JumpTableClassStaticGet)) { cg_printf("static Variant os_get(CStrRef s);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_GET_%s 1\n", clsName); } if (variables->hasJumpTable(VariableTable::JumpTableClassStaticLval)) { cg_printf("static Variant &os_lval(CStrRef s);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_LVAL_%s 1\n", clsName); } if (constants->hasJumpTable()) { cg_printf("static Variant os_constant(const char *s);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_CONSTANT_%s 1\n", clsName); } cg.printSection("DECLARE_INSTANCE_PROP_OPS"); cg_printf("public:\n"); if (variables->hasJumpTable(VariableTable::JumpTableClassGetArray)) { cg_printf("virtual void o_getArray(Array &props) const;\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_GETARRAY_%s 1\n", clsName); } if (variables->hasJumpTable(VariableTable::JumpTableClassSetArray)) { cg_printf("virtual void o_setArray(CArrRef props);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_SETARRAY_%s 1\n", clsName); } if (variables->hasJumpTable(VariableTable::JumpTableClassRealProp)) { cg_printf("virtual Variant *o_realProp(CStrRef s, int flags,\n"); cg_printf(" CStrRef context = null_string) " "const;\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_realProp_%s 1\n", clsName); } if (variables->hasNonStaticPrivate()) { cg_printf("Variant *o_realPropPrivate(CStrRef s, int flags) const;\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_realProp_PRIVATE_%s 1\n", clsName); } cg.printSection("DECLARE_INSTANCE_PUBLIC_PROP_OPS"); cg_printf("public:\n"); if (variables->hasJumpTable(VariableTable::JumpTableClassRealPropPublic)) { cg_printf("virtual Variant *o_realPropPublic(CStrRef s, " "int flags) const;\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_realProp_PUBLIC_%s 1\n", clsName); } cg.printSection("DECLARE_COMMON_INVOKE"); if (classScope->hasJumpTable(ClassScope::JumpTableStaticInvoke)) { cg_printf("static Variant os_invoke(const char *c, " "MethodIndex methodIndex,\n"); cg_printf(" const char *s, CArrRef ps, int64 h, " "bool f = true);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_INVOKE_%s 1\n", clsName); } if (classScope->hasJumpTable(ClassScope::JumpTableInvoke)) { cg_printf("virtual Variant o_invoke(MethodIndex methodIndex, " "const char *s, CArrRef ps,\n"); cg_printf(" int64 h, bool f = true);\n"); cg_printf("virtual Variant o_invoke_few_args(MethodIndex methodIndex, " "const char *s,\n"); cg_printf(" int64 h, int count,\n"); cg_printf(" " "INVOKE_FEW_ARGS_DECL_ARGS);\n"); } else { cg_printf("#define OMIT_JUMP_TABLE_CLASS_INVOKE_%s 1\n", clsName); } cg_printf("\n"); cg_printf("public:\n"); }
void ClassVariable::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr scope = ar->getClassScope(); bool derivFromRedec = scope->derivesFromRedeclaring() && !m_modifiers->isPrivate(); for (int i = 0; i < m_declaration->getCount(); i++) { ExpressionPtr exp = (*m_declaration)[i]; SimpleVariablePtr var; TypePtr type; switch (cg.getContext()) { case CodeGenerator::CppConstructor: if (m_modifiers->isStatic()) continue; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable()); ExpressionPtr value = assignment->getValue(); value->outputCPPBegin(cg, ar); if (derivFromRedec) { cg_printf("%sset(\"%s\",-1, ", Option::ObjectPrefix, var->getName().c_str()); value->outputCPP(cg, ar); cg_printf(")"); } else { cg_printf("%s%s = ", Option::PropertyPrefix, var->getName().c_str()); value->outputCPP(cg, ar); } cg_printf(";\n"); value->outputCPPEnd(cg, ar); } else { var = dynamic_pointer_cast<SimpleVariable>(exp); if (derivFromRedec) { cg_printf("%sset(\"%s\",-1, null);\n", Option::ObjectPrefix, var->getName().c_str()); } else { type = scope->getVariables()->getFinalType(var->getName()); const char *initializer = type->getCPPInitializer(); if (initializer) { cg_printf("%s%s = %s;\n", Option::PropertyPrefix, var->getName().c_str(), initializer); } } } break; case CodeGenerator::CppStaticInitializer: { if (!m_modifiers->isStatic()) continue; VariableTablePtr variables = scope->getVariables(); if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); var = dynamic_pointer_cast<SimpleVariable> (assignment->getVariable()); ExpressionPtr value = assignment->getValue(); if (value->containsDynamicConstant(ar)) continue; cg_printf("g->%s%s%s%s = ", Option::StaticPropertyPrefix, scope->getId(cg).c_str(), Option::IdPrefix.c_str(), var->getName().c_str()); value->outputCPP(cg, ar); } else { var = dynamic_pointer_cast<SimpleVariable>(exp); type = scope->getVariables()->getFinalType(var->getName()); const char *initializer = type->getCPPInitializer(); if (initializer) { cg_printf("g->%s%s%s%s = %s", Option::StaticPropertyPrefix, scope->getId(cg).c_str(), Option::IdPrefix.c_str(), var->getName().c_str(), initializer); } } cg_printf(";\n"); } break; case CodeGenerator::CppLazyStaticInitializer: { if (!m_modifiers->isStatic()) continue; if (!exp->is(Expression::KindOfAssignmentExpression)) continue; VariableTablePtr variables = scope->getVariables(); AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable()); ExpressionPtr value = assignment->getValue(); if (!value->containsDynamicConstant(ar)) continue; value->outputCPPBegin(cg, ar); cg_printf("g->%s%s%s%s = ", Option::StaticPropertyPrefix, scope->getId(cg).c_str(), Option::IdPrefix.c_str(), var->getName().c_str()); value->outputCPP(cg, ar); cg_printf(";\n"); value->outputCPPEnd(cg, ar); } break; default: break; } } }
void ClassStatement::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr classScope = m_classScope.lock(); if (cg.getContext() == CodeGenerator::NoContext) { if (classScope->isRedeclaring()) { cg.printf("g->%s%s = ClassStaticsPtr(NEW(%s%s)());\n", Option::ClassStaticsObjectPrefix, m_name.c_str(), Option::ClassStaticsPrefix, classScope->getId().c_str()); } if (classScope->isVolatile()) { cg.printf("g->declareClass(\"%s\");\n", m_name.c_str()); } return; } if (cg.getContext() != CodeGenerator::CppForwardDeclaration) { printSource(cg); } ar->pushScope(classScope); string clsNameStr = classScope->getId(); const char *clsName = clsNameStr.c_str(); bool redeclared = classScope->isRedeclaring(); switch (cg.getContext()) { case CodeGenerator::CppForwardDeclaration: if (Option::GenerateCPPMacros) { cg.printf("FORWARD_DECLARE_CLASS(%s)\n", clsName); if (redeclared) { cg.printf("FORWARD_DECLARE_REDECLARED_CLASS(%s)\n", clsName); } } if (m_stmt) { cg.setContext(CodeGenerator::CppClassConstantsDecl); m_stmt->outputCPP(cg, ar); cg.setContext(CodeGenerator::CppForwardDeclaration); } break; case CodeGenerator::CppDeclaration: { ClassScopePtr parCls; if (!m_parent.empty()) parCls = ar->findClass(m_parent); cg.printf("class %s%s", Option::ClassPrefix, clsName); bool derived = false; if (!m_parent.empty() && classScope->derivesFrom(ar, m_parent)) { if (parCls->isRedeclaring()) { cg.printf(" : public DynamicObjectData"); } else { cg.printf(" : virtual public %s%s", Option::ClassPrefix, parCls->getId().c_str()); } derived = true; } if (m_base) { for (int i = 0; i < m_base->getCount(); i++) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>((*m_base)[i]); const char *intf = exp->getString().c_str(); ClassScopePtr intfClassScope = ar->findClass(intf); if (intfClassScope && classScope->derivesFrom(ar, intf)) { // temporary fix for inheriting from a re-declaring class string id = intfClassScope->getId(); if (!derived) { derived = true; cg.printf(" :"); } else { cg.printf(","); } cg.printf(" virtual public %s%s", Option::ClassPrefix, id.c_str()); } } } if (!derived) { const char *op = derived ? "," : " :"; if (classScope->derivesFromRedeclaring()) { cg.printf("%s public DynamicObjectData", op); } else { cg.printf("%s virtual public ObjectData", op); } } cg.indentBegin(" {\n"); if (Option::GenerateCPPMacros) { vector<string> bases; getAllParents(ar, bases); cg.indentBegin("BEGIN_CLASS_MAP(%s)\n", clsName); for (unsigned int i = 0; i < bases.size(); i++) { cg.printf("PARENT_CLASS(%s)\n", bases[i].c_str()); } cg.indentEnd("END_CLASS_MAP(%s)\n", clsName); } if (Option::GenerateCPPMacros) { bool dyn = classScope->derivesFromRedeclaring() == ClassScope::DirectFromRedeclared; bool idyn = classScope->derivesFromRedeclaring() == ClassScope::IndirectFromRedeclared; bool redec = classScope->isRedeclaring(); if (!classScope->derivesFromRedeclaring()) { cg.printf("DECLARE_CLASS(%s, %s, %s)\n", clsName, m_originalName.c_str(), m_parent.empty() ? "ObjectData" : m_parent.c_str()); } else { cg.printf("DECLARE_DYNAMIC_CLASS(%s, %s)\n", clsName, m_originalName.c_str()); } if (cg.getOutput() == CodeGenerator::SystemCPP || Option::EnableEval >= Option::LimitedEval) { cg.printf("DECLARE_INVOKES_FROM_EVAL\n"); } if (dyn || idyn || redec) { if (redec) { cg.indentBegin("Variant %sroot_invoke(const char* s, CArrRef ps, " "int64 h, bool f = true) {\n", Option::ObjectPrefix); cg.printf("return root->%sinvoke(s, ps, h, f);\n", Option::ObjectPrefix); cg.indentEnd("}\n"); cg.indentBegin("Variant %sroot_invoke_few_args(const char* s, " "int64 h, int count", Option::ObjectPrefix); for (int i = 0; i < Option::InvokeFewArgsCount; i++) { cg.printf(", CVarRef a%d = null_variant", i); } cg.printf(") {\n"); cg.printf("return root->%sinvoke_few_args(s, h, count", Option::ObjectPrefix); for (int i = 0; i < Option::InvokeFewArgsCount; i++) { cg.printf(", a%d", i); } cg.printf(");\n"); cg.indentEnd("}\n"); if (!dyn && !idyn) cg.printf("private: ObjectData* root;\n"); cg.printf("public:\n"); } string conInit = ":"; if (dyn) { conInit += "DynamicObjectData(\"" + m_parent + "\", r)"; } else if (idyn) { conInit += string(Option::ClassPrefix) + parCls->getId() + "(r?r:this)"; } else { conInit += "root(r?r:this)"; } cg.printf("%s%s(ObjectData* r = NULL)%s {}\n", Option::ClassPrefix, clsName, conInit.c_str()); } } cg.printf("void init();\n", Option::ClassPrefix, clsName); if (classScope->needLazyStaticInitializer()) { cg.printf("static GlobalVariables *lazy_initializer" "(GlobalVariables *g);\n"); } if (!classScope->derivesFromRedeclaring()){ classScope->getVariables()->outputCPPPropertyDecl(cg, ar); } if (!classScope->getAttribute(ClassScope::HasConstructor)) { FunctionScopePtr func = classScope->findFunction(ar, "__construct", false); if (func && !func->isAbstract() && !classScope->isInterface()) { ar->pushScope(func); func->outputCPPCreateDecl(cg, ar); ar->popScope(); } } if (classScope->getAttribute(ClassScope::HasDestructor)) { cg.printf("public: virtual void destruct();\n"); } // doCall if (classScope->getAttribute(ClassScope::HasUnknownMethodHandler)) { cg.printf("Variant doCall(Variant v_name, Variant v_arguments, " "bool fatal);\n"); } if (m_stmt) m_stmt->outputCPP(cg, ar); { set<string> done; classScope->outputCPPStaticMethodWrappers(cg, ar, done, clsName); } if (cg.getOutput() == CodeGenerator::SystemCPP && ar->isBaseSysRsrcClass(clsName) && !classScope->hasProperty("rsrc")) { cg.printf("public: Variant %srsrc;\n", Option::PropertyPrefix); } cg.indentEnd("};\n"); if (redeclared) { cg.indentBegin("class %s%s : public ClassStatics {\n", Option::ClassStaticsPrefix, clsName); cg.printf("public:\n"); cg.printf("DECLARE_OBJECT_ALLOCATION(%s%s);\n", Option::ClassStaticsPrefix, clsName); cg.printf("%s%s() : ClassStatics(%d) {}\n", Option::ClassStaticsPrefix, clsName, classScope->getRedeclaringId()); cg.indentBegin("Variant %sget(const char *s, int64 hash = -1) {\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%sget(s, hash);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentBegin("Variant &%slval(const char* s, int64 hash = -1) {\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%slval(s, hash);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentBegin("Variant %sinvoke(const char *c, const char *s, " "CArrRef params, int64 hash = -1, bool fatal = true) " "{\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%sinvoke(c, s, params, hash, fatal);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentBegin("Object create(CArrRef params, bool init = true, " "ObjectData* root = NULL) {\n"); cg.printf("return Object(%s%s(NEW(%s%s)(root))->" "dynCreate(params, init));\n", Option::SmartPtrPrefix, clsName, Option::ClassPrefix, clsName); cg.indentEnd("}\n"); cg.indentBegin("Variant %sconstant(const char* s) {\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%sconstant(s);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentBegin("Variant %sinvoke_from_eval(const char *c, " "const char *s, Eval::VariableEnvironment &env, " "const Eval::FunctionCallExpression *call, " "int64 hash = -1, bool fatal = true) " "{\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%sinvoke_from_eval(c, s, env, call, hash, " "fatal);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentEnd("};\n"); } } break; case CodeGenerator::CppImplementation: if (m_stmt) { cg.setContext(CodeGenerator::CppClassConstantsImpl); m_stmt->outputCPP(cg, ar); cg.setContext(CodeGenerator::CppImplementation); } classScope->outputCPPSupportMethodsImpl(cg, ar); if (redeclared) { cg.printf("IMPLEMENT_OBJECT_ALLOCATION(%s%s);\n", Option::ClassStaticsPrefix, clsName); } cg.indentBegin("void %s%s::init() {\n", Option::ClassPrefix, clsName); if (!m_parent.empty()) { if (classScope->derivesFromRedeclaring() == ClassScope::DirectFromRedeclared) { cg.printf("parent->init();\n"); } else { cg.printf("%s%s::init();\n", Option::ClassPrefix, m_parent.c_str()); } } cg.setContext(CodeGenerator::CppConstructor); if (m_stmt) m_stmt->outputCPP(cg, ar); cg.indentEnd("}\n"); if (classScope->needStaticInitializer()) { cg.indentBegin("void %s%s::os_static_initializer() {\n", Option::ClassPrefix, clsName); cg.printDeclareGlobals(); cg.setContext(CodeGenerator::CppStaticInitializer); if (m_stmt) m_stmt->outputCPP(cg, ar); cg.indentEnd("}\n"); cg.indentBegin("void %s%s() {\n", Option::ClassStaticInitializerPrefix, clsName); cg.printf("%s%s::os_static_initializer();\n", Option::ClassPrefix, clsName); cg.indentEnd("}\n"); } if (classScope->needLazyStaticInitializer()) { cg.indentBegin("GlobalVariables *%s%s::lazy_initializer(" "GlobalVariables *g) {\n", Option::ClassPrefix, clsName); cg.indentBegin("if (!g->%s%s) {\n", Option::ClassStaticInitializerFlagPrefix, clsName); cg.printf("g->%s%s = true;\n", Option::ClassStaticInitializerFlagPrefix, clsName); cg.setContext(CodeGenerator::CppLazyStaticInitializer); if (m_stmt) m_stmt->outputCPP(cg, ar); cg.indentEnd("}\n"); cg.printf("return g;\n"); cg.indentEnd("}\n"); } cg.setContext(CodeGenerator::CppImplementation); if (m_stmt) m_stmt->outputCPP(cg, ar); break; case CodeGenerator::CppFFIDecl: case CodeGenerator::CppFFIImpl: if (m_stmt) m_stmt->outputCPP(cg, ar); break; case CodeGenerator::JavaFFI: { if (classScope->isRedeclaring()) break; // TODO support PHP namespaces, once HPHP supports it string packageName = Option::JavaFFIRootPackage; string packageDir = packageName; Util::replaceAll(packageDir, ".", "/"); string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix + packageDir + "/"; Util::mkdir(outputDir); // uses a different cg to generate a separate file for each PHP class // also, uses the original capitalized class name string clsFile = outputDir + getOriginalName() + ".java"; ofstream fcls(clsFile.c_str()); CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP); cgCls.setContext(CodeGenerator::JavaFFI); cgCls.printf("package %s;\n\n", packageName.c_str()); cgCls.printf("import hphp.*;\n\n"); printSource(cgCls); string clsModifier; switch (m_type) { case T_CLASS: break; case T_ABSTRACT: clsModifier = "abstract "; break; case T_FINAL: clsModifier = "final "; break; } cgCls.printf("public %sclass %s ", clsModifier.c_str(), getOriginalName().c_str()); ClassScopePtr parCls; if (!m_parent.empty()) parCls = ar->findClass(m_parent); if (!m_parent.empty() && classScope->derivesFrom(ar, m_parent) && parCls->isUserClass() && !parCls->isRedeclaring()) { // system classes are not supported in static FFI translation // they shouldn't appear as superclasses as well cgCls.printf("extends %s", parCls->getOriginalName()); } else { cgCls.printf("extends HphpObject"); } if (m_base) { bool first = true; for (int i = 0; i < m_base->getCount(); i++) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>((*m_base)[i]); const char *intf = exp->getString().c_str(); ClassScopePtr intfClassScope = ar->findClass(intf); if (intfClassScope && classScope->derivesFrom(ar, intf) && intfClassScope->isUserClass()) { if (first) { cgCls.printf(" implements "); first = false; } else { cgCls.printf(", "); } cgCls.printf(intfClassScope->getOriginalName()); } } } cgCls.indentBegin(" {\n"); // constructor for initializing the variant pointer cgCls.printf("protected %s(long ptr) { super(ptr); }\n\n", getOriginalName().c_str()); FunctionScopePtr cons = classScope->findConstructor(ar, true); if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) { // if not an abstract class and not having an explicit constructor, // adds a default constructor outputJavaFFIConstructor(cgCls, ar, cons); } if (m_stmt) m_stmt->outputCPP(cgCls, ar); cgCls.indentEnd("}\n"); fcls.close(); } break; case CodeGenerator::JavaFFICppDecl: case CodeGenerator::JavaFFICppImpl: { if (classScope->isRedeclaring()) break; if (m_stmt) m_stmt->outputCPP(cg, ar); FunctionScopePtr cons = classScope->findConstructor(ar, true); if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) { outputJavaFFICPPCreator(cg, ar, cons); } } break; default: ASSERT(false); break; } ar->popScope(); }