#ifndef LLVM_OPTION_OPTION_H
#define LLVM_OPTION_OPTION_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Option/OptSpecifier.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <string>
namespace llvm {
class raw_ostream;
namespace opt {
class Arg;
class ArgList;
using ArgStringList = SmallVector<const char *, 16>;
enum DriverFlag {
  HelpHidden       = (1 << 0),
  RenderAsInput    = (1 << 1),
  RenderJoined     = (1 << 2),
  RenderSeparate   = (1 << 3)
};
class Option {
public:
  enum OptionClass {
    GroupClass = 0,
    InputClass,
    UnknownClass,
    FlagClass,
    JoinedClass,
    ValuesClass,
    SeparateClass,
    RemainingArgsClass,
    RemainingArgsJoinedClass,
    CommaJoinedClass,
    MultiArgClass,
    JoinedOrSeparateClass,
    JoinedAndSeparateClass
  };
  enum RenderStyleKind {
    RenderCommaJoinedStyle,
    RenderJoinedStyle,
    RenderSeparateStyle,
    RenderValuesStyle
  };
protected:
  const OptTable::Info *Info;
  const OptTable *Owner;
public:
  Option(const OptTable::Info *Info, const OptTable *Owner);
  bool isValid() const {
    return Info != nullptr;
  }
  unsigned getID() const {
    assert(Info && "Must have a valid info!");
    return Info->ID;
  }
  OptionClass getKind() const {
    assert(Info && "Must have a valid info!");
    return OptionClass(Info->Kind);
  }
    StringRef getName() const {
    assert(Info && "Must have a valid info!");
    return Info->Name;
  }
  const Option getGroup() const {
    assert(Info && "Must have a valid info!");
    assert(Owner && "Must have a valid owner!");
    return Owner->getOption(Info->GroupID);
  }
  const Option getAlias() const {
    assert(Info && "Must have a valid info!");
    assert(Owner && "Must have a valid owner!");
    return Owner->getOption(Info->AliasID);
  }
      const char *getAliasArgs() const {
    assert(Info && "Must have a valid info!");
    assert((!Info->AliasArgs || Info->AliasArgs[0] != 0) &&
           "AliasArgs should be either 0 or non-empty.");
    return Info->AliasArgs;
  }
    StringRef getPrefix() const {
    const char *Prefix = *Info->Prefixes;
    return Prefix ? Prefix : StringRef();
  }
    std::string getPrefixedName() const {
    std::string Ret(getPrefix());
    Ret += getName();
    return Ret;
  }
    StringRef getHelpText() const {
    assert(Info && "Must have a valid info!");
    return Info->HelpText;
  }
    StringRef getMetaVar() const {
    assert(Info && "Must have a valid info!");
    return Info->MetaVar;
  }
  unsigned getNumArgs() const { return Info->Param; }
  bool hasNoOptAsInput() const { return Info->Flags & RenderAsInput;}
  RenderStyleKind getRenderStyle() const {
    if (Info->Flags & RenderJoined)
      return RenderJoinedStyle;
    if (Info->Flags & RenderSeparate)
      return RenderSeparateStyle;
    switch (getKind()) {
    case GroupClass:
    case InputClass:
    case UnknownClass:
      return RenderValuesStyle;
    case JoinedClass:
    case JoinedAndSeparateClass:
      return RenderJoinedStyle;
    case CommaJoinedClass:
      return RenderCommaJoinedStyle;
    case FlagClass:
    case ValuesClass:
    case SeparateClass:
    case MultiArgClass:
    case JoinedOrSeparateClass:
    case RemainingArgsClass:
    case RemainingArgsJoinedClass:
      return RenderSeparateStyle;
    }
    llvm_unreachable("Unexpected kind!");
  }
    bool hasFlag(unsigned Val) const {
    return Info->Flags & Val;
  }
      const Option getUnaliasedOption() const {
    const Option Alias = getAlias();
    if (Alias.isValid()) return Alias.getUnaliasedOption();
    return *this;
  }
      StringRef getRenderName() const {
    return getUnaliasedOption().getName();
  }
              bool matches(OptSpecifier ID) const;
                          std::unique_ptr<Arg> accept(const ArgList &Args, StringRef CurArg,
                              bool GroupedShortOption, unsigned &Index) const;
private:
  std::unique_ptr<Arg> acceptInternal(const ArgList &Args, StringRef CurArg,
                                      unsigned &Index) const;
public:
  void print(raw_ostream &O) const;
  void dump() const;
};
} 
} 
#endif