text: //
  // Copyright 2018 The ANGLE Project Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  //
  // FunctionLookup.cpp: Used for storing function calls that have not yet been resolved during
  // parsing.
  //
  
  #include "compiler/translator/FunctionLookup.h"
  #include "compiler/translator/ImmutableStringBuilder.h"
  
  namespace sh
  {
  
  namespace
  {
  
  const char kFunctionMangledNameSeparator = '(';
  
  constexpr const ImmutableString kEmptyName("");
  
  // Helper function for GetMangledNames
  // Gets all ordered combinations of elements in list[currentIndex, end]
  std::vector<std::vector<int>> GetImplicitConversionCombinations(const std::vector<int> &list)
  {
      std::vector<std::vector<int>> target;
      target.push_back(std::vector<int>());
  
      for (size_t currentIndex = 0; currentIndex < list.size(); currentIndex++)
      {
          size_t prevIterSize = target.size();
          for (size_t copyIndex = 0; copyIndex < prevIterSize; copyIndex++)
          {
              std::vector<int> combination = target[copyIndex];
              combination.push_back(list[currentIndex]);
              target.push_back(combination);
          }
      }
  
      return target;
  }
  
  }  // anonymous namespace
  
  TFunctionLookup::TFunctionLookup(const ImmutableString &name,
                                   const TType *constructorType,
                                   const TSymbol *symbol)
      : mName(name), mConstructorType(constructorType), mThisNode(nullptr), mSymbol(symbol)
  {}
  
  // static
  TFunctionLookup *TFunctionLookup::CreateConstructor(const TType *type)
  {
      ASSERT(type != nullptr);
      return new TFunctionLookup(kEmptyName, type, nullptr);
  }
  
  // static
  TFunctionLookup *TFunctionLookup::CreateFunctionCall(const ImmutableString &name,
                                                       const TSymbol *symbol)
  {
      ASSERT(name != "");
      return new TFunctionLookup(name, nullptr, symbol);
  }
  
  const ImmutableString &TFunctionLookup::name() const
  {
      return mName;
  }
  
  ImmutableString TFunctionLookup::getMangledName() const
  {
      return GetMangledName(mName.data(), mArguments);
  }
  
  ImmutableString TFunctionLookup::GetMangledName(const char *functionName,
                                                  const TIntermSequence &arguments)
  {
      std::string newName(functionName);
      newName += kFunctionMangledNameSeparator;
  
      for (TIntermNode *argument : arguments)
      {
          newName += argument->getAsTyped()->getType().getMangledName();
      }
      return ImmutableString(newName);
  }
  
  std::vector<ImmutableString> GetMangledNames(const char *functionName,
                                               const TIntermSequence &arguments)
  {
      std::vector<ImmutableString> target;
  
      std::vector<int> indexes;
      for (int i = 0; i < static_cast<int>(arguments.size()); i++)
      {
          TIntermNode *argument = arguments[i];
          TBasicType argType    = argument->getAsTyped()->getType().getBasicType();
          if (argType == EbtInt || argType == EbtUInt)
          {
              indexes.push_back(i);
          }
      }
  
      std::vector<std::vector<int>> combinations = GetImplicitConversionCombinations(indexes);
      for (const std::vector<int> &combination : combinations)
      {
          // combination: ordered list of indexes for arguments that should be converted to float
          std::string newName(functionName);
          newName += kFunctionMangledNameSeparator;
          // combination[currentIndex] represents index of next argument to be converted
          int currentIndex = 0;
          for (int i = 0; i < (int)arguments.size(); i++)
          {
              TIntermNode *argument = arguments[i];
  
              if (currentIndex != static_cast<int>(combination.size()) &&
                  combination[currentIndex] == i)
              {
                  // Convert
                  TType type = argument->getAsTyped()->getType();
                  type.setBasicType(EbtFloat);
                  newName += type.getMangledName();
                  currentIndex++;
              }
              else
              {
                  // Don't convert
                  newName += argument->getAsTyped()->getType().getMangledName();
              }
          }
          target.push_back(ImmutableString(newName));
      }
  
      return target;
  }
  
  std::vector<ImmutableString> TFunctionLookup::getMangledNamesForImplicitConversions() const
  {
      return GetMangledNames(mName.data(), mArguments);
  }
  
  bool TFunctionLookup::isConstructor() const
  {
      return mConstructorType != nullptr;
  }
  
  const TType &TFunctionLookup::constructorType() const
  {
      return *mConstructorType;
  }
  
  void TFunctionLookup::setThisNode(TIntermTyped *thisNode)
  {
      mThisNode = thisNode;
  }
  
  TIntermTyped *TFunctionLookup::thisNode() const
  {
      return mThisNode;
  }
  
  void TFunctionLookup::addArgument(TIntermTyped *argument)
  {
      mArguments.push_back(argument);
  }
  
  TIntermSequence &TFunctionLookup::arguments()
  {
      return mArguments;
  }
  
  const TSymbol *TFunctionLookup::symbol() const
  {
      return mSymbol;
  }
  
  }  // namespace sh
  