void ParameterExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr func = getFunctionScope(); VariableTablePtr variables = func->getVariables(); Symbol *sym = variables->getSymbol(m_name); assert(sym && sym->isParameter()); bool inHeader = cg.isFileOrClassHeader(); cg.setFileOrClassHeader(true); CodeGenerator::Context context = cg.getContext(); bool typedWrapper = (context == CodeGenerator::CppTypedParamsWrapperImpl || context == CodeGenerator::CppTypedParamsWrapperDecl); TypePtr paramType = typedWrapper && func->getParamTypeSpec(sym->getParameterIndex()) ? Type::Variant : func->getParamType(sym->getParameterIndex()); bool wrapper = typedWrapper || context == CodeGenerator::CppFunctionWrapperImpl || context == CodeGenerator::CppFunctionWrapperDecl; bool isCVarRef = false; const char *prefix = ""; if (m_ref) { cg_printf("VRefParam"); if (!wrapper) { prefix = "r"; } } else if (wrapper || (!variables->isLvalParam(m_name) && !variables->getAttribute(VariableTable::ContainsDynamicVariable) && !variables->getAttribute(VariableTable::ContainsExtract))) { if (paramType->is(Type::KindOfVariant) || paramType->is(Type::KindOfSome)) { cg_printf("CVarRef"); isCVarRef = true; } else if (paramType->is(Type::KindOfArray)) cg_printf("CArrRef"); else if (paramType->is(Type::KindOfString)) cg_printf("CStrRef"); else paramType->outputCPPDecl(cg, ar, getScope()); } else { paramType->outputCPPDecl(cg, ar, getScope()); } cg_printf(" %s%s%s", prefix, Option::VariablePrefix, CodeGenerator::FormatLabel(m_name).c_str()); if (m_defaultValue && sym->getParameterIndex() >= func->getMinParamCount()) { bool comment = context == CodeGenerator::CppTypedParamsWrapperImpl || context == CodeGenerator::CppFunctionWrapperImpl || context == CodeGenerator::CppImplementation || (context == CodeGenerator::CppDeclaration && func->isInlined()); if (comment) { cg_printf(" // "); } cg_printf(" = "); ConstantExpressionPtr con = dynamic_pointer_cast<ConstantExpression>(m_defaultValue); bool done = false; if (con && con->isNull()) { done = true; if (isCVarRef) { cg_printf("null_variant"); } else if (paramType->is(Type::KindOfVariant) || paramType->is(Type::KindOfSome)) { cg_printf("null"); } else if (paramType->is(Type::KindOfObject)) { cg_printf("Object()"); } else if (paramType->is(Type::KindOfArray)) { cg_printf("Array()"); } else if (paramType->is(Type::KindOfString)) { cg_printf("String()"); } else { done = false; } } if (!done) { if (comment) { cg.setContext(CodeGenerator::CppParameterDefaultValueImpl); } else { cg.setContext(CodeGenerator::CppParameterDefaultValueDecl); } bool isScalar = m_defaultValue->isScalar(); if (isCVarRef && isScalar) { ASSERT(!cg.hasScalarVariant()); cg.setScalarVariant(); } m_defaultValue->outputCPP(cg, ar); if (isCVarRef && isScalar) cg.clearScalarVariant(); ASSERT(!cg.hasScalarVariant()); cg.setContext(context); } if (comment) { cg_printf("\n"); } } cg.setFileOrClassHeader(inHeader); }
TypePtr SimpleVariable::inferAndCheck(AnalysisResultPtr ar, TypePtr type, bool coerce) { TypePtr ret; ConstructPtr construct = shared_from_this(); BlockScopePtr scope = getScope(); VariableTablePtr variables = scope->getVariables(); // check function parameter that can occur in lval context if (m_sym && m_sym->isParameter() && m_context & (LValue | RefValue | DeepReference | UnsetContext | InvokeArgument | OprLValue | DeepOprLValue)) { m_sym->setLvalParam(); } if (m_this) { ClassScopePtr cls = getOriginalClass(); if (!hasContext(ObjectContext) && cls->derivedByDynamic()) { ret = Type::Object; } else { ret = Type::CreateObjectType(cls->getName()); } if (!hasContext(ObjectContext) && variables->getAttribute(VariableTable::ContainsDynamicVariable)) { ret = variables->add(m_sym, ret, true, ar, construct, scope->getModifiers()); } } else if ((m_context & (LValue|Declaration)) && !(m_context & (ObjectContext|RefValue))) { if (m_globals) { ret = Type::Variant; } else if (m_superGlobal) { ret = m_superGlobalType; } else if (m_superGlobalType) { // For system ret = variables->add(m_sym, m_superGlobalType, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } else { ret = variables->add(m_sym, type, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } } else { if (m_superGlobalType) { ret = m_superGlobalType; } else if (m_globals) { ret = Type::Array; } else if (scope->is(BlockScope::ClassScope)) { // ClassVariable expression will come to this block of code ret = getClassScope()->checkProperty(m_sym, type, true, ar); } else { TypePtr tmpType = type; if (m_context & RefValue) { tmpType = Type::Variant; coerce = true; } int p; ret = variables->checkVariable(m_sym, tmpType, coerce, ar, construct, p); } } TypePtr actual = propagateTypes(ar, ret); setTypes(ar, actual, type); if (Type::SameType(actual, ret)) { m_implementedType.reset(); } else { m_implementedType = ret; } return actual; }
void ParameterExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr func = getFunctionScope(); VariableTablePtr variables = func->getVariables(); Symbol *sym = variables->getSymbol(m_name); assert(sym && sym->isParameter()); CodeGenerator::Context context = cg.getContext(); bool typedWrapper = (context == CodeGenerator::CppTypedParamsWrapperImpl || context == CodeGenerator::CppTypedParamsWrapperDecl); TypePtr paramType = typedWrapper && func->getParamTypeSpec(sym->getParameterIndex()) ? Type::Variant : func->getParamType(sym->getParameterIndex()); bool isCVarRef = false; if (cg.getContext() == CodeGenerator::CppStaticMethodWrapper || typedWrapper || (!variables->isLvalParam(m_name) && !variables->getAttribute(VariableTable::ContainsDynamicVariable) && !variables->getAttribute(VariableTable::ContainsExtract) && !m_ref)) { if (paramType->is(Type::KindOfVariant) || paramType->is(Type::KindOfSome)) { cg_printf("CVarRef"); isCVarRef = true; } else if (paramType->is(Type::KindOfArray)) cg_printf("CArrRef"); else if (paramType->is(Type::KindOfString)) cg_printf("CStrRef"); else paramType->outputCPPDecl(cg, ar, getScope()); } else { paramType->outputCPPDecl(cg, ar, getScope()); } cg_printf(" %s%s", Option::VariablePrefix, m_name.c_str()); if (m_defaultValue && sym->getParameterIndex() >= func->getMinParamCount()) { bool comment = context == CodeGenerator::CppTypedParamsWrapperImpl || context == CodeGenerator::CppImplementation || (context == CodeGenerator::CppDeclaration && func->isInlined()); if (comment) { cg_printf(" // "); } cg_printf(" = "); ConstantExpressionPtr con = dynamic_pointer_cast<ConstantExpression>(m_defaultValue); if (isCVarRef && con && con->isNull()) { cg_printf("null_variant"); } else { if (comment) { cg.setContext(CodeGenerator::CppParameterDefaultValueImpl); } else { cg.setContext(CodeGenerator::CppParameterDefaultValueDecl); } m_defaultValue->outputCPP(cg, ar); cg.setContext(context); } if (comment) { cg_printf("\n"); } } }
void SimpleVariable::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { VariableTablePtr variables = getScope()->getVariables(); if (m_this) { ASSERT((getContext() & ObjectContext) == 0); if (hasContext(OprLValue) || hasContext(AssignmentLHS)) { cg_printf("throw_assign_this()"); return; } if (variables->getAttribute(VariableTable::ContainsLDynamicVariable)) { ASSERT(m_sym); const string &namePrefix = getNamePrefix(); cg_printf("%s%sthis", namePrefix.c_str(), variables->getVariablePrefix(m_sym)); } else if (hasContext(DeepOprLValue) || hasContext(DeepAssignmentLHS) || hasContext(LValue)) { // $this[] op= ...; or $this[] = ... cg_printf("Variant(GET_THIS())"); } else { ClassScopePtr cls = getOriginalClass(); if (!cls || cls->derivedByDynamic()) { cg_printf("Object(GET_THIS())"); } else { cg_printf("GET_THIS_TYPED(%s)", cls->getId().c_str()); } } } else if (m_superGlobal) { const string &name = variables->getGlobalVariableName(ar, m_name); cg_printf("g->%s", name.c_str()); } else if (m_globals) { cg_printf("get_global_array_wrapper()"); } else { ASSERT(m_sym); bool sw = false; if (m_sym->isShrinkWrapped() && m_context == Declaration) { ASSERT(!getFunctionScope()->isGenerator()); TypePtr type = m_sym->getFinalType(); type->outputCPPDecl(cg, ar, getScope()); sw = true; cg_printf(" "); } const string &prefix0 = getNamePrefix(); const char *prefix1 = variables->getVariablePrefix(m_sym); cg_printf("%s%s%s", prefix0.c_str(), prefix1, CodeGenerator::FormatLabel(m_name).c_str()); if (m_originalSym) { cg.printf(" /* %s */", m_originalSym->getName().c_str()); } if (sw) { TypePtr type = m_sym->getFinalType(); const char *initializer = type->getCPPInitializer(); if (initializer) { cg_printf(" = %s", initializer); } } } }
bool SimpleVariable::hasAssignableCPPVariable() const { if (!m_this) return true; if (hasAnyContext(OprLValue | AssignmentLHS)) return false; VariableTablePtr variables = getScope()->getVariables(); return variables->getAttribute(VariableTable::ContainsLDynamicVariable); }
TypePtr SimpleVariable::inferAndCheck(AnalysisResultPtr ar, TypePtr type, bool coerce) { IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope()); resetTypes(); TypePtr ret; ConstructPtr construct = shared_from_this(); BlockScopePtr scope = getScope(); VariableTablePtr variables = scope->getVariables(); // check function parameter that can occur in lval context if (m_sym && m_sym->isParameter() && m_context & (LValue | RefValue | DeepReference | UnsetContext | InvokeArgument | OprLValue | DeepOprLValue)) { m_sym->setLvalParam(); } if (coerce && m_sym && type && type->is(Type::KindOfAutoSequence)) { TypePtr t = m_sym->getType(); if (!t || t->is(Type::KindOfVoid) || t->is(Type::KindOfSome) || t->is(Type::KindOfArray)) { type = Type::Array; } } if (m_this) { ret = Type::Object; ClassScopePtr cls = getOriginalClass(); if (cls && (hasContext(ObjectContext) || !cls->derivedByDynamic())) { ret = Type::CreateObjectType(cls->getName()); } if (!hasContext(ObjectContext) && variables->getAttribute(VariableTable::ContainsDynamicVariable)) { if (variables->getAttribute(VariableTable::ContainsLDynamicVariable)) { ret = Type::Variant; } ret = variables->add(m_sym, ret, true, ar, construct, scope->getModifiers()); } } else if ((m_context & (LValue|Declaration)) && !(m_context & (ObjectContext|RefValue))) { if (m_globals) { ret = Type::Array; } else if (m_superGlobal) { ret = m_superGlobalType; } else if (m_superGlobalType) { // For system ret = variables->add(m_sym, m_superGlobalType, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } else { ret = variables->add(m_sym, type, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } } else { if (m_superGlobalType) { ret = m_superGlobalType; } else if (m_globals) { ret = Type::Array; } else if (scope->is(BlockScope::ClassScope)) { ASSERT(getClassScope().get() == scope.get()); // ClassVariable expression will come to this block of code ret = getClassScope()->checkProperty(getScope(), m_sym, type, true, ar); } else { TypePtr tmpType = type; if (m_context & RefValue) { tmpType = Type::Variant; coerce = true; } ret = variables->checkVariable(m_sym, tmpType, coerce, ar, construct); if (ret && (ret->is(Type::KindOfSome) || ret->is(Type::KindOfAny))) { ret = Type::Variant; } } } // if m_assertedType is set, then this is a type assertion node TypePtr inType = m_assertedType ? GetAssertedInType(ar, m_assertedType, ret) : ret; TypePtr actual = propagateTypes(ar, inType); setTypes(ar, actual, type); if (Type::SameType(actual, ret)) { m_implementedType.reset(); } else { m_implementedType = ret; } return actual; }
void SimpleVariable::analyzeProgram(AnalysisResultPtr ar) { m_superGlobal = BuiltinSymbols::IsSuperGlobal(m_name); m_superGlobalType = BuiltinSymbols::GetSuperGlobalType(m_name); VariableTablePtr variables = getScope()->getVariables(); if (m_superGlobal) { variables->setAttribute(VariableTable::NeedGlobalPointer); } else if (m_name == "GLOBALS") { m_globals = true; } else { m_sym = variables->addDeclaredSymbol( m_name, hhvm && Option::OutputHHBC ? shared_from_this() : ConstructPtr()); } if (ar->getPhase() == AnalysisResult::AnalyzeAll) { if (FunctionScopePtr func = getFunctionScope()) { if (m_name == "this" && (func->inPseudoMain() || getClassScope())) { func->setContainsThis(); m_this = true; if (!hasContext(ObjectContext)) { bool unset = hasAllContext(UnsetContext | LValue); func->setContainsBareThis( true, hasAnyContext(RefValue | RefAssignmentLHS) || m_sym->isRefClosureVar() || unset); if (variables->getAttribute(VariableTable::ContainsDynamicVariable)) { ClassScopePtr cls = getClassScope(); TypePtr t = !cls || cls->isRedeclaring() ? Type::Variant : Type::CreateObjectType(cls->getName()); variables->add(m_sym, t, true, ar, shared_from_this(), getScope()->getModifiers()); } } } if (m_sym && !(m_context & AssignmentLHS) && !((m_context & UnsetContext) && (m_context & LValue))) { m_sym->setUsed(); } } } else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { if (m_sym) { if (!m_sym->isSystem() && !(getContext() & (LValue|RefValue|RefParameter|UnsetContext|ExistContext)) && m_sym->getDeclaration().get() == this && !variables->getAttribute(VariableTable::ContainsLDynamicVariable) && !getScope()->is(BlockScope::ClassScope)) { if (getScope()->inPseudoMain()) { Compiler::Error(Compiler::UseUndeclaredGlobalVariable, shared_from_this()); } else if (!m_sym->isClosureVar()) { Compiler::Error(Compiler::UseUndeclaredVariable, shared_from_this()); } } // check function parameter that can occur in lval context if (m_sym->isParameter() && m_context & (LValue | RefValue | DeepReference | UnsetContext | InvokeArgument | OprLValue | DeepOprLValue)) { m_sym->setLvalParam(); } } if (m_superGlobal || m_name == "GLOBALS") { FunctionScopePtr func = getFunctionScope(); if (func) func->setNeedsCheckMem(); } } }
void SimpleVariable::analyzeProgram(AnalysisResultPtr ar) { m_superGlobal = BuiltinSymbols::IsSuperGlobal(m_name); VariableTablePtr variables = getScope()->getVariables(); if (m_name == "GLOBALS") { m_globals = true; } else { m_sym = variables->addDeclaredSymbol(m_name, shared_from_this()); } if (m_name == "http_response_header" || m_name == "php_errormsg") { setInited(); } if (ar->getPhase() == AnalysisResult::AnalyzeAll) { if (FunctionScopePtr func = getFunctionScope()) { if (m_name == "this" && func->mayContainThis()) { func->setContainsThis(); m_this = true; if (!hasContext(ObjectContext)) { bool unset = hasAllContext(UnsetContext | LValue); func->setContainsBareThis( true, hasAnyContext(RefValue | RefAssignmentLHS) || m_sym->isRefClosureVar() || unset); if (variables->getAttribute(VariableTable::ContainsDynamicVariable)) { variables->add(m_sym, true, ar, shared_from_this(), getScope()->getModifiers()); } } } if (m_sym && !(m_context & AssignmentLHS) && !((m_context & UnsetContext) && (m_context & LValue))) { m_sym->setUsed(); } } } else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { if (m_sym && !m_this) { if (!m_sym->isSystem() && !(getContext() & (LValue|RefValue|RefParameter|UnsetContext|ExistContext)) && m_sym->getDeclaration().get() == this && !m_sym->isParameter()) { if (!variables->getAttribute(VariableTable::ContainsLDynamicVariable) && !getScope()->is(BlockScope::ClassScope)) { if (getScope()->inPseudoMain()) { Compiler::Error(Compiler::UseUndeclaredGlobalVariable, shared_from_this()); } else if (!m_sym->isClosureVar()) { Compiler::Error(Compiler::UseUndeclaredVariable, shared_from_this()); } } } // check function parameter that can occur in lval context if (m_sym->isParameter() && m_context & (LValue | RefValue | DeepReference | UnsetContext | InvokeArgument | OprLValue | DeepOprLValue)) { m_sym->setLvalParam(); } } } }