//===- Option.h - Abstract Driver Options -----------------------*- C++ -*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#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;
 
 
 
/// ArgStringList - Type used for constructing argv lists for subprocesses.
 
using ArgStringList = SmallVector<const char *, 16>;
 
 
 
/// Base flags for all options. Custom flags may be added after.
 
enum DriverFlag {
 
  HelpHidden       = (1 << 0),
 
  RenderAsInput    = (1 << 1),
 
  RenderJoined     = (1 << 2),
 
  RenderSeparate   = (1 << 3)
 
};
 
 
 
/// Option - Abstract representation for a single form of driver
 
/// argument.
 
///
 
/// An Option class represents a form of option that the driver
 
/// takes, for example how many arguments the option has and how
 
/// they can be provided. Individual option instances store
 
/// additional information about what group the option is a member
 
/// of (if any), if the option is an alias, and a number of
 
/// flags. At runtime the driver parses the command line into
 
/// concrete Arg instances, each of which corresponds to a
 
/// particular Option instance.
 
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);
 
  }
 
 
 
  /// Get the name of this option without any prefix.
 
  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);
 
  }
 
 
 
  /// Get the alias arguments as a \0 separated list.
 
  /// E.g. ["foo", "bar"] would be returned as "foo\0bar\0".
 
  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;
 
  }
 
 
 
  /// Get the default prefix for this option.
 
  StringRef getPrefix() const {
 
    return Info->Prefixes.empty()
 
               ? StringRef()
 
               : static_cast<const StringRef &>(Info->Prefixes[0]);
 
  }
 
 
 
  /// Get the name of this option with the default prefix.
 
  std::string getPrefixedName() const {
 
    std::string Ret(getPrefix());
 
    Ret += getName();
 
    return Ret;
 
  }
 
 
 
  /// Get the help text for this option.
 
  StringRef getHelpText() const {
 
    assert(Info && "Must have a valid info!");
 
    return Info->HelpText;
 
  }
 
 
 
  /// Get the meta-variable list for this option.
 
  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!");
 
  }
 
 
 
  /// Test if this option has the flag \a Val.
 
  bool hasFlag(unsigned Val) const {
 
    return Info->Flags & Val;
 
  }
 
 
 
  /// getUnaliasedOption - Return the final option this option
 
  /// aliases (itself, if the option has no alias).
 
  const Option getUnaliasedOption() const {
 
    const Option Alias = getAlias();
 
    if (Alias.isValid()) return Alias.getUnaliasedOption();
 
    return *this;
 
  }
 
 
 
  /// getRenderName - Return the name to use when rendering this
 
  /// option.
 
  StringRef getRenderName() const {
 
    return getUnaliasedOption().getName();
 
  }
 
 
 
  /// matches - Predicate for whether this option is part of the
 
  /// given option (which may be a group).
 
  ///
 
  /// Note that matches against options which are an alias should never be
 
  /// done -- aliases do not participate in matching and so such a query will
 
  /// always be false.
 
  bool matches(OptSpecifier ID) const;
 
 
 
  /// Potentially accept the current argument, returning a new Arg instance,
 
  /// or 0 if the option does not accept this argument (or the argument is
 
  /// missing values).
 
  ///
 
  /// If the option accepts the current argument, accept() sets
 
  /// Index to the position where argument parsing should resume
 
  /// (even if the argument is missing values).
 
  ///
 
  /// \p CurArg The argument to be matched. It may be shorter than the
 
  /// underlying storage to represent a Joined argument.
 
  /// \p GroupedShortOption If true, we are handling the fallback case of
 
  /// parsing a prefix of the current argument as a short option.
 
  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;
 
};
 
 
 
} // end namespace opt
 
 
 
} // end namespace llvm
 
 
 
#endif // LLVM_OPTION_OPTION_H