void FunctionStatement::onParse(AnalysisResultConstPtr ar, FileScopePtr scope) { // Correctness checks are normally done before adding function to scope. if (m_params) { for (int i = 0; i < m_params->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); if (param->hasTypeHint() && param->defaultValue()) { param->compatibleDefault(); } } } // note it's important to add to scope, not a pushed FunctionContainer, // as a function may be declared inside a class's method, yet this function // is a global function, not a class method. FunctionScopePtr fs = onInitialParse(ar, scope); FunctionScope::RecordFunctionInfo(m_name, fs); if (!scope->addFunction(ar, fs)) { m_ignored = true; return; } if (Option::PersistenceHook) { fs->setPersistent(Option::PersistenceHook(fs, scope)); } }
void FunctionStatement::onParse(AnalysisResultConstPtr ar, FileScopePtr scope) { // Correctness checks are normally done before adding function to scope. if (m_params) { for (int i = 0; i < m_params->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); if (param->hasTypeHint() && param->defaultValue()) { param->compatibleDefault(); } } } // note it's important to add to scope, not a pushed FunctionContainer, // as a function may be declared inside a class's method, yet this function // is a global function, not a class method. FunctionScopePtr fs = onInitialParse(ar, scope); FunctionScope::RecordFunctionInfo(m_name, fs); if (!scope->addFunction(ar, fs)) { m_ignored = true; return; } if (Option::PersistenceHook) { fs->setPersistent(Option::PersistenceHook(fs, scope)); } if (fs->isNative()) { if (getStmts()) { parseTimeFatal(Compiler::InvalidAttribute, "Native functions must not have an implementation body"); } if (m_params) { int nParams = m_params->getCount(); for (int i = 0; i < nParams; ++i) { auto param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); if (!param->hasUserType()) { parseTimeFatal(Compiler::InvalidAttribute, "Native function calls must have type hints " "on all args"); } } } if (getReturnTypeConstraint().empty()) { parseTimeFatal(Compiler::InvalidAttribute, "Native function %s() must have a return type hint", getOriginalName().c_str()); } } else if (!getStmts()) { parseTimeFatal(Compiler::InvalidAttribute, "Global function %s() must contain a body", getOriginalName().c_str()); } }
void FunctionStatement::onParse(AnalysisResultConstPtr ar, FileScopePtr scope) { checkParameters(scope); // Correctness checks are normally done before adding function to scope. if (m_params) { for (int i = 0; i < m_params->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); if (param->hasTypeHint() && param->defaultValue()) { param->compatibleDefault(scope); } } } // note it's important to add to scope, not a pushed FunctionContainer, // as a function may be declared inside a class's method, yet this function // is a global function, not a class method. FunctionScopePtr fs = onInitialParse(ar, scope); FunctionScope::RecordFunctionInfo(m_originalName, fs); if (!scope->addFunction(ar, fs)) { m_ignored = true; return; } fs->setPersistent(false); if (isNamed("__autoload")) { if (m_params && m_params->getCount() != 1) { parseTimeFatal(scope, Compiler::InvalidMagicMethod, "__autoload() must take exactly 1 argument"); } } if (fs->isNative()) { if (getStmts()) { parseTimeFatal(scope, Compiler::InvalidAttribute, "Native functions must not have an implementation body"); } if (m_params) { int nParams = m_params->getCount(); for (int i = 0; i < nParams; ++i) { // Variadic capture params don't need types // since they'll be Arrays as far as HNI is concerned. auto param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); if (!param->hasUserType() && !param->isVariadic()) { parseTimeFatal(scope, Compiler::InvalidAttribute, "Native function calls must have type hints " "on all args"); } } } if (getReturnTypeConstraint().empty()) { parseTimeFatal(scope, Compiler::InvalidAttribute, "Native function %s() must have a return type hint", getOriginalName().c_str()); } } else if (!getStmts()) { parseTimeFatal(scope, Compiler::InvalidAttribute, "Global function %s() must contain a body", getOriginalName().c_str()); } }
FunctionScopePtr MethodStatement::onInitialParse(AnalysisResultConstPtr ar, FileScopePtr fs) { ConstructPtr self = shared_from_this(); int minParam = 0, numDeclParam = 0; bool hasRef = false; bool hasVariadicParam = false; if (m_params) { std::set<string> names, allDeclNames; int i = 0; numDeclParam = m_params->getCount(); ParameterExpressionPtr lastParam = dynamic_pointer_cast<ParameterExpression>( (*m_params)[numDeclParam - 1]); hasVariadicParam = lastParam->isVariadic(); if (hasVariadicParam) { allDeclNames.insert(lastParam->getName()); // prevent the next loop from visiting the variadic param and testing // its optionality. parsing ensures that the variadic capture param // can *only* be the last param. i = numDeclParam - 2; } else { i = numDeclParam - 1; } for (; i >= 0; --i) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); assert(!param->isVariadic()); if (param->isRef()) { hasRef = true; } if (!param->isOptional()) { if (!minParam) minParam = i + 1; } else if (minParam && !param->hasTypeHint()) { Compiler::Error(Compiler::RequiredAfterOptionalParam, param); } allDeclNames.insert(param->getName()); } // For the purpose of naming (having entered the the function body), a // variadic capture param acts as any other variable. for (i = (numDeclParam - 1); i >= 0; --i) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); if (names.find(param->getName()) != names.end()) { Compiler::Error(Compiler::RedundantParameter, param); for (int j = 0; j < 1000; j++) { string name = param->getName() + folly::to<string>(j); if (names.find(name) == names.end() && allDeclNames.find(name) == allDeclNames.end()) { param->rename(name); break; } } } names.insert(param->getName()); } } if (hasRef || m_ref) { m_attribute |= FileScope::ContainsReference; } if (hasVariadicParam) { m_attribute |= FileScope::VariadicArgumentParam; } vector<UserAttributePtr> attrs; if (m_attrList) { for (int i = 0; i < m_attrList->getCount(); ++i) { UserAttributePtr a = dynamic_pointer_cast<UserAttribute>((*m_attrList)[i]); attrs.push_back(a); } } StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this()); auto funcScope = std::make_shared<FunctionScope>(ar, m_method, m_originalName, stmt, m_ref, minParam, numDeclParam, m_modifiers, m_attribute, m_docComment, fs, attrs); if (!m_stmt) { funcScope->setVirtual(); } setBlockScope(funcScope); funcScope->setParamCounts(ar, -1, -1); return funcScope; }
FunctionScopePtr MethodStatement::onInitialParse(AnalysisResultConstPtr ar, FileScopePtr fs) { int minParam, maxParam; ConstructPtr self = shared_from_this(); minParam = maxParam = 0; bool hasRef = false; if (m_params) { std::set<string> names, allDeclNames; int i = 0; maxParam = m_params->getCount(); for (i = maxParam; i--; ) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); if (param->isRef()) hasRef = true; if (!param->isOptional()) { if (!minParam) minParam = i + 1; } else if (minParam && !param->hasTypeHint()) { Compiler::Error(Compiler::RequiredAfterOptionalParam, param); } allDeclNames.insert(param->getName()); } for (i = maxParam-1; i >= 0; i--) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); if (names.find(param->getName()) != names.end()) { Compiler::Error(Compiler::RedundantParameter, param); for (int j = 0; j < 1000; j++) { string name = param->getName() + lexical_cast<string>(j); if (names.find(name) == names.end() && allDeclNames.find(name) == allDeclNames.end()) { param->rename(name); break; } } } names.insert(param->getName()); } } if (hasRef || m_ref) { m_attribute |= FileScope::ContainsReference; } vector<UserAttributePtr> attrs; if (m_attrList) { for (int i = 0; i < m_attrList->getCount(); ++i) { UserAttributePtr a = dynamic_pointer_cast<UserAttribute>((*m_attrList)[i]); attrs.push_back(a); } } StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this()); FunctionScopePtr funcScope (new FunctionScope(ar, m_method, m_name, stmt, m_ref, minParam, maxParam, m_modifiers, m_attribute, m_docComment, fs, attrs)); if (!m_stmt) { funcScope->setVirtual(); } setBlockScope(funcScope); funcScope->setParamCounts(ar, -1, -1); return funcScope; }