Exemplo n.º 1
0
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));
  }
}
Exemplo n.º 2
0
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());
  }
}
Exemplo n.º 3
0
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());
  }
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
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;
}