/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * File:   typehints.cpp
 * Author: pgess <v.melnychenko@xreate.org>
 *
 * Created on 24/03/2020
 */

#include "analysis/typehints.h"
#include "analysis/predefinedanns.h"
#include "analysis/utils.h"
#include "aux/expressions.h"

namespace xreate{namespace typehints{

namespace impl {
template<class Hint>
inline Hint getHint(const Expression& e, const Hint& def, unsigned annId, const ExpandedType& hintT){
  const std::list<Expression>& hintsL = getAnnotations(e);
  auto predefined = analysis::PredefinedAnns::instance();
  const Expression& hintActual = analysis::findAnnById(annId, hintT, hintsL);
  if (!hintActual.isValid()){
    return def;
  }

  return parse<Hint>(hintActual);
}
}

template<> IntBits
parse(const Expression& e){
  return {(unsigned) e.operands.at(0).getValueDouble()};
}

template<> ArrayHint
parse(const Expression& e){
  return {(unsigned) e.operands.at(0).getValueDouble()};
}

template<> FlyHint
parse(const Expression& e){
  return {e.operands.at(0)};
}

template<> IntBits
find(const Expression& e, const IntBits& def){
  auto predefined = analysis::PredefinedAnns::instance();
  return impl::getHint<IntBits>(e, def,
    (unsigned) analysis::PredefinedAnns::IntHints::SIZE,
    ExpandedType(predefined.hintsIntT)
  );
}

template<> ArrayHint
find(const Expression& e, const ArrayHint& def){
  auto predefined = analysis::PredefinedAnns::instance();
  return impl::getHint<ArrayHint>(e, def,
    (unsigned) analysis::PredefinedAnns::ContHints::ARRAY,
    ExpandedType(predefined.hintsContT)
  );
}

template<> FlyHint
find(const Expression& e, const FlyHint& def){
  auto predefined = analysis::PredefinedAnns::instance();

  return impl::getHint<FlyHint>(e, def,
    (unsigned) analysis::PredefinedAnns::ContHints::FLY,
    ExpandedType(predefined.hintsContT));
}

}}