//===- StaticResolver.h ---------------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef MCLD_LD_STATICRESOLVER_H_
#define MCLD_LD_STATICRESOLVER_H_
#include "mcld/LD/ResolveInfo.h"
#include "mcld/LD/Resolver.h"

#include <string>

namespace mcld {

class NamePool;

/** \class StaticResolver
 */
class StaticResolver : public Resolver {
 public:
  /** \enum LinkAction
   *  LinkAction follows BFD:linker.c (binary file descriptor).
   *  List all actions to take in the state table
   */
  enum LinkAction {
    FAIL,    // abort.
    NOACT,   // no action.
    UND,     // override by symbol undefined symbol.
    WEAK,    // override by symbol weak undefined.
    DEF,     // override by symbol defined.
    DEFW,    // override by symbol weak defined.
    DEFD,    // override by symbol dynamic defined.
    DEFWD,   // override by symbol dynamic weak defined.
    MDEFD,   // mark symbol dynamic defined.
    MDEFWD,  // mark symbol dynamic weak defined.
    DUND,    // override dynamic defined symbol by undefined one.
    DUNDW,   // oevrride dynamic defined symbol by weak undefined one.
    COM,     // override by symbol common.
    CREF,    // Possibly warn about common reference to defined symbol.
    CDEF,    // redefine existing common symbol.
    BIG,     // override by symbol common using largest size.
    MBIG,    // mark common symbol by larger size.
    IND,     // override by indirect symbol.
    CIND,    // mark indirect symbol from existing common symbol.
    MDEF,    // multiple definition error.
    MIND,    // multiple indirect symbols.
    REFC     // Mark indirect symbol referenced and then CYCLE.
  };

 private:
  // These are the values generated by the bit codes.
  /** Encoding:
   *  D -> define
   *  U -> undefine
   *  d -> dynamic
   *  w -> weak
   *  C -> common
   *  I -> indirect
   */
  enum {
    U    = ResolveInfo::global_flag | ResolveInfo::regular_flag | ResolveInfo::undefine_flag,  // NOLINT
    w_U  = ResolveInfo::weak_flag   | ResolveInfo::regular_flag | ResolveInfo::undefine_flag,  // NOLINT
    d_U  = ResolveInfo::global_flag | ResolveInfo::dynamic_flag | ResolveInfo::undefine_flag,  // NOLINT
    wd_U = ResolveInfo::weak_flag   | ResolveInfo::dynamic_flag | ResolveInfo::undefine_flag,  // NOLINT
    D    = ResolveInfo::global_flag | ResolveInfo::regular_flag | ResolveInfo::define_flag,    // NOLINT
    w_D  = ResolveInfo::weak_flag   | ResolveInfo::regular_flag | ResolveInfo::define_flag,    // NOLINT
    d_D  = ResolveInfo::global_flag | ResolveInfo::dynamic_flag | ResolveInfo::define_flag,    // NOLINT
    wd_D = ResolveInfo::weak_flag   | ResolveInfo::dynamic_flag | ResolveInfo::define_flag,    // NOLINT
    C    = ResolveInfo::global_flag | ResolveInfo::regular_flag | ResolveInfo::common_flag,    // NOLINT
    w_C  = ResolveInfo::weak_flag   | ResolveInfo::regular_flag | ResolveInfo::common_flag,    // NOLINT
    d_C  = ResolveInfo::global_flag | ResolveInfo::dynamic_flag | ResolveInfo::common_flag,    // NOLINT
    wd_C = ResolveInfo::weak_flag   | ResolveInfo::dynamic_flag | ResolveInfo::common_flag,    // NOLINT
    I    = ResolveInfo::global_flag | ResolveInfo::regular_flag | ResolveInfo::indirect_flag,  // NOLINT
    w_I  = ResolveInfo::weak_flag   | ResolveInfo::regular_flag | ResolveInfo::indirect_flag,  // NOLINT
    d_I  = ResolveInfo::global_flag | ResolveInfo::dynamic_flag | ResolveInfo::indirect_flag,  // NOLINT
    wd_I = ResolveInfo::weak_flag   | ResolveInfo::dynamic_flag | ResolveInfo::indirect_flag   // NOLINT
  };

  enum ORDINATE {
    U_ORD,
    w_U_ORD,
    d_U_ORD,
    wd_U_ORD,
    D_ORD,
    w_D_ORD,
    d_D_ORD,
    wd_D_ORD,
    C_ORD,
    w_C_ORD,
    Cs_ORD,
    Is_ORD,
    LAST_ORD
  };

 public:
  virtual ~StaticResolver();

  /// shouldOverride - Can resolver override the symbol pOld by the symbol pNew?
  /// @return successfully resolved, return true; otherwise, return false.
  /// @param pOld the symbol which may be overridden.
  /// @param pNew the symbol which is used to replace pOld
  virtual bool resolve(ResolveInfo& __restrict__ pOld,
                       const ResolveInfo& __restrict__ pNew,
                       bool& pOverride,
                       LDSymbol::ValueType pValue) const;

 private:
  inline unsigned int getOrdinate(const ResolveInfo& pInfo) const {
    if (pInfo.isAbsolute() && pInfo.isDyn())
      return d_D_ORD;
    if (pInfo.isAbsolute())
      return D_ORD;
    if (pInfo.isCommon() && pInfo.isDyn())
      return Cs_ORD;
    if (pInfo.isCommon() && pInfo.isDefine())
      return C_ORD;
    if (pInfo.isCommon() && pInfo.isWeak())
      return w_C_ORD;
    if (pInfo.isIndirect())
      return Is_ORD;
    return pInfo.info();
  }
};

}  // namespace mcld

#endif  // MCLD_LD_STATICRESOLVER_H_