//===-- support/type_token.cpp ----------------------------------*- C++ -*-===//
//
//                                 The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file support/type_token.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Implementation for rosa/support/type_token.hpp.
///
/// \todo Automatically generate proper cases for the switches with a big number
/// of handcrafted similar cases in them.
///
//===----------------------------------------------------------------------===//

#include "rosa/support/type_token.hpp"

namespace rosa {

using namespace token;

bool validToken(const Token T) {
  Token TT = T;
  bool Valid = true;
  while (Valid && !emptyToken(TT)) {
    Valid &= validTypeNumber(headOfToken(TT));
    dropHeadOfToken(TT);
  }
  return Valid;
}

bool emptyToken(const Token T) { return static_cast<token_t>(T) == 0; }

token_size_t lengthOfToken(const Token T) {
  Token TT = T;
  token_size_t N = 0;
  while (!emptyToken(TT)) {
    ++N;
    dropHeadOfToken(TT);
  }
  return N;
}

size_t sizeOfValuesOfToken(const Token T) {
  ASSERT(validToken(T));
  Token TT = T;
  size_t S = 0;
  while (!emptyToken(TT)) {
    S += sizeOfHeadOfToken(TT);
    dropHeadOfToken(TT);
  }
  return S;
}

#define SIZECASE(N)                                                            \
  {                                                                            \
  case N:                                                                      \
    return TypeForNumber<static_cast<TypeNumber>(N)>::Size;                    \
  }

size_t sizeOfHeadOfToken(const Token T) {
  ASSERT(!emptyToken(T) && validToken(T));
  switch (static_cast<type_nr_t>(headOfToken(T))) {
  default: {
    // Should never come here when \p T is valid and the case-list below covers
    // \c rosa::BuiltinTypes.
    ROSA_CRITICAL("unknown type number");
  }
    SIZECASE(1);
    SIZECASE(2);
    SIZECASE(3);
    SIZECASE(4);
    SIZECASE(5);
    SIZECASE(6);
    SIZECASE(7);
    SIZECASE(8);
    SIZECASE(9);
    SIZECASE(10);
    SIZECASE(11);
    SIZECASE(12);
    SIZECASE(13);
    SIZECASE(14);
    SIZECASE(15);
  }
}

#define NAMECASE(N)                                                            \
  {                                                                            \
  case N:                                                                      \
    return TypeForNumber<static_cast<TypeNumber>(N)>::Name;                    \
  }

const char *nameOfHeadOfToken(const Token T) {
  ASSERT(!emptyToken(T) && validToken(T));
  switch (static_cast<type_nr_t>(headOfToken(T))) {
  default: {
    // Should never come here when \p T is valid and the case-list below covers
    // \c rosa::BuiltinTypes.
    ROSA_CRITICAL("unknown type number");
  }
    NAMECASE(1);
    NAMECASE(2);
    NAMECASE(3);
    NAMECASE(4);
    NAMECASE(5);
    NAMECASE(6);
    NAMECASE(7);
    NAMECASE(8);
    NAMECASE(9);
    NAMECASE(10);
    NAMECASE(11);
    NAMECASE(12);
    NAMECASE(13);
    NAMECASE(14);
    NAMECASE(15);
  }
}

void dropHeadOfToken(Token &T) {
  T = static_cast<Token>(static_cast<token_t>(T) >> RepresentationBits);
}

void dropNOfToken(Token &T, const size_t N) {
  T = static_cast<Token>(static_cast<token_t>(T) >> (N * RepresentationBits));
}

} // End namespace rosa
