text: //
  // Copyright (c) 2002-2012 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.
  //
  
  //
  // Symbol table for parsing.  Most functionaliy and main ideas
  // are documented in the header file.
  //
  
  #if defined(_MSC_VER)
  #pragma warning(disable: 4718)
  #endif
  
  #include "compiler/SymbolTable.h"
  
  #include <stdio.h>
  #include <algorithm>
  #include <climits>
  
  TType::TType(const TPublicType &p) :
              type(p.type), precision(p.precision), qualifier(p.qualifier), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize), structure(0)
  {
      if (p.userDef)
          structure = p.userDef->getStruct();
  }
  
  //
  // Recursively generate mangled names.
  //
  TString TType::buildMangledName() const
  {
      TString mangledName;
      if (isMatrix())
          mangledName += 'm';
      else if (isVector())
          mangledName += 'v';
  
      switch (type) {
      case EbtFloat:       mangledName += 'f';      break;
      case EbtInt:         mangledName += 'i';      break;
      case EbtBool:        mangledName += 'b';      break;
      case EbtSampler2D:   mangledName += "s2";     break;
      case EbtSamplerCube: mangledName += "sC";     break;
      case EbtStruct:      mangledName += structure->mangledName(); break;
      default:             break;
      }
  
      mangledName += static_cast<char>('0' + getNominalSize());
      if (isArray()) {
          char buf[20];
          snprintf(buf, sizeof(buf), "%d", arraySize);
          mangledName += '[';
          mangledName += buf;
          mangledName += ']';
      }
      return mangledName;
  }
  
  size_t TType::getObjectSize() const
  {
      size_t totalSize = 0;
  
      if (getBasicType() == EbtStruct)
          totalSize = structure->objectSize();
      else if (matrix)
          totalSize = size * size;
      else
          totalSize = size;
  
      if (isArray()) {
          size_t arraySize = getArraySize();
          if (arraySize > INT_MAX / totalSize)
              totalSize = INT_MAX;
          else
              totalSize *= arraySize;
      }
  
      return totalSize;
  }
  
  bool TStructure::containsArrays() const
  {
      for (size_t i = 0; i < mFields->size(); ++i) {
          const TType* fieldType = (*mFields)[i]->type();
          if (fieldType->isArray() || fieldType->isStructureContainingArrays())
              return true;
      }
      return false;
  }
  
  TString TStructure::buildMangledName() const
  {
      TString mangledName("struct-");
      mangledName += *mName;
      for (size_t i = 0; i < mFields->size(); ++i) {
          mangledName += '-';
          mangledName += (*mFields)[i]->type()->getMangledName();
      }
      return mangledName;
  }
  
  size_t TStructure::calculateObjectSize() const
  {
      size_t size = 0;
      for (size_t i = 0; i < mFields->size(); ++i) {
          size_t fieldSize = (*mFields)[i]->type()->getObjectSize();
          if (fieldSize > INT_MAX - size)
              size = INT_MAX;
          else
              size += fieldSize;
      }
      return size;
  }
  
  int TStructure::calculateDeepestNesting() const
  {
      int maxNesting = 0;
      for (size_t i = 0; i < mFields->size(); ++i) {
          maxNesting = std::max(maxNesting, (*mFields)[i]->type()->getDeepestStructNesting());
      }
      return 1 + maxNesting;
  }
  
  //
  // Dump functions.
  //
  
  void TVariable::dump(TInfoSink& infoSink) const
  {
      infoSink.debug << getName().c_str() << ": " << type.getQualifierString() << " " << type.getPrecisionString() << " " << type.getBasicString();
      if (type.isArray()) {
          infoSink.debug << "[0]";
      }
      infoSink.debug << "\n";
  }
  
  void TFunction::dump(TInfoSink &infoSink) const
  {
      infoSink.debug << getName().c_str() << ": " <<  returnType.getBasicString() << " " << getMangledName().c_str() << "\n";
  }
  
  void TSymbolTableLevel::dump(TInfoSink &infoSink) const
  {
      tLevel::const_iterator it;
      for (it = level.begin(); it != level.end(); ++it)
          (*it).second->dump(infoSink);
  }
  
  void TSymbolTable::dump(TInfoSink &infoSink) const
  {
      for (int level = currentLevel(); level >= 0; --level) {
          infoSink.debug << "LEVEL " << level << "\n";
          table[level]->dump(infoSink);
      }
  }
  
  //
  // Functions have buried pointers to delete.
  //
  TFunction::~TFunction()
  {
      for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i)
          delete (*i).type;
  }
  
  //
  // Symbol table levels are a map of pointers to symbols that have to be deleted.
  //
  TSymbolTableLevel::~TSymbolTableLevel()
  {
      for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
          delete (*it).second;
  }
  
  //
  // Change all function entries in the table with the non-mangled name
  // to be related to the provided built-in operation.  This is a low
  // performance operation, and only intended for symbol tables that
  // live across a large number of compiles.
  //
  void TSymbolTableLevel::relateToOperator(const char* name, TOperator op)
  {
      tLevel::iterator it;
      for (it = level.begin(); it != level.end(); ++it) {
          if ((*it).second->isFunction()) {
              TFunction* function = static_cast<TFunction*>((*it).second);
              if (function->getName() == name)
                  function->relateToOperator(op);
          }
      }
  }
  
  //
  // Change all function entries in the table with the non-mangled name
  // to be related to the provided built-in extension. This is a low
  // performance operation, and only intended for symbol tables that
  // live across a large number of compiles.
  //
  void TSymbolTableLevel::relateToExtension(const char* name, const TString& ext)
  {
      for (tLevel::iterator it = level.begin(); it != level.end(); ++it) {
          TSymbol* symbol = it->second;
          if (symbol->getName() == name)
              symbol->relateToExtension(ext);
      }
  }
  