//===-- gen/cl_helpers.h - Command line processing helpers ------*- C++ -*-===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// // // Helpers to augment the LLVM command line parsing library with some extra // functionality. // //===----------------------------------------------------------------------===// #pragma once #include "dmd/globals.h" // for CHECKENABLE enum #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" template struct Array; typedef Array Strings; namespace opts { namespace cl = llvm::cl; /// Duplicate the string (incl. null-termination) and replace '/' with '\' on /// Windows. DString dupPathString(llvm::StringRef src); /// Helper function to handle -of, -od, etc. DString fromPathString(const cl::opt &src); /// Helper class to determine values template struct FlagParserDataType {}; template <> struct FlagParserDataType { static bool true_val() { return true; } static bool false_val() { return false; } }; template <> struct FlagParserDataType { static cl::boolOrDefault true_val() { return cl::BOU_TRUE; } static cl::boolOrDefault false_val() { return cl::BOU_FALSE; } }; inline bool getFlagOrDefault(cl::boolOrDefault value, bool defaultValue) { return value == cl::BOU_UNSET ? defaultValue : value == cl::BOU_TRUE; } template <> struct FlagParserDataType { static CHECKENABLE true_val() { return CHECKENABLEon; } static CHECKENABLE false_val() { return CHECKENABLEoff; } }; template class FlagParser : public cl::generic_parser_base { protected: llvm::SmallVector, 2> switches; cl::Option &owner() const { return Owner; } public: FlagParser(cl::Option &O) : generic_parser_base(O) {} typedef DataType parser_data_type; void initialize() { std::string Name(owner().ArgStr); switches.push_back( make_pair("enable-" + Name, FlagParserDataType::true_val())); switches.push_back(make_pair("disable-" + Name, FlagParserDataType::false_val())); // Replace with -enable- and register -disable-. // A literal option can only registered if the argstr is empty - // just do this first. owner().setArgStr(""); AddLiteralOption(Owner, strdup(switches[1].first.data())); owner().setArgStr(switches[0].first.data()); } enum cl::ValueExpected getValueExpectedFlagDefault() const { return cl::ValueOptional; } // Implement virtual functions needed by generic_parser_base unsigned getNumOptions() const override { return 0; } llvm::StringRef getOption(unsigned N) const override { llvm_unreachable("Unexpected call"); return ""; } llvm::StringRef getDescription(unsigned N) const override { llvm_unreachable("Unexpected call"); return ""; } private: struct OptionValue : cl::OptionValueBase { OptionValue(){}; }; const OptionValue EmptyOptionValue; public: // getOptionValue - Return the value of option name N. const cl::GenericOptionValue &getOptionValue(unsigned N) const override { return EmptyOptionValue; } // parse - Return true on error. bool parse(cl::Option &O, llvm::StringRef ArgName, llvm::StringRef Arg, DataType &Val) { for (const auto &pair : switches) { const auto &name = pair.first; if (name == ArgName || (name.size() < ArgName.size() && ArgName.substr(0, name.size()) == name && ArgName[name.size()] == '=')) { if (!parse(owner(), Arg, Val)) { Val = (Val == pair.second) ? FlagParserDataType::true_val() : FlagParserDataType::false_val(); return false; } // Invalid option value break; } } return true; } void getExtraOptionNames(llvm::SmallVectorImpl &Names) { for (auto I = switches.begin() + 1, E = switches.end(); I != E; ++I) { Names.push_back(I->first.data()); } } private: static bool parse(cl::Option &O, llvm::StringRef Arg, DataType &Val) { if (Arg == "" || Arg == "true" || Arg == "TRUE" || Arg == "True" || Arg == "1") { Val = FlagParserDataType::true_val(); return false; } if (Arg == "false" || Arg == "FALSE" || Arg == "False" || Arg == "0") { Val = FlagParserDataType::false_val(); return false; } return O.error("'" + Arg + "' is invalid value for boolean argument! Try 0 or 1"); } }; /// Helper class for options that set multiple flags class MultiSetter { std::vector locations; bool invert; explicit MultiSetter(bool); // not implemented, disable auto-conversion public: // end with a nullptr MultiSetter(bool invert, CHECKENABLE *p, ...); MultiSetter() = default; void operator=(bool val); }; /// Helper class to fill Strings with char* when given strings /// (Errors on empty strings) class StringsAdapter { const char *name; Strings *arrp; public: StringsAdapter(const char *name_, Strings &arr) { name = name_; arrp = &arr; assert(name); } void push_back(const char *cstr); void push_back(const std::string &str) { push_back(str.c_str()); } }; }