Add three new option properties.

Adds new option properties 'multi_val', 'one_or_more' and 'zero_or_one'.

llvm-svn: 63172
This commit is contained in:
Mikhail Glushenkov 2009-01-28 03:47:20 +00:00
parent 57cf3964f3
commit 2115d09a10
6 changed files with 201 additions and 55 deletions

View File

@ -36,11 +36,14 @@ def prefix_list_option;
// Possible option properties. // Possible option properties.
def extern;
def help; def help;
def hidden; def hidden;
def multi_val;
def one_or_more;
def really_hidden; def really_hidden;
def required; def required;
def extern; def zero_or_one;
// Empty DAG marker. // Empty DAG marker.
def empty; def empty;

View File

@ -1,6 +1,7 @@
// Check that extern options work. // Check that extern options work.
// The dummy tool and graph are required to silence warnings. // The dummy tool and graph are required to silence warnings.
// RUN: tblgen -I $srcroot/include --gen-llvmc %s | grep {extern .* AutoGeneratedSwitch_Wall} // RUN: tblgen -I $srcroot/include --gen-llvmc %s -o %t
// RUN: grep {extern .* AutoGeneratedSwitch_Wall} %t
include "llvm/CompilerDriver/Common.td" include "llvm/CompilerDriver/Common.td"

View File

@ -0,0 +1,21 @@
// Check that multivalued options work.
// The dummy tool and graph are required to silence warnings.
// RUN: tblgen -I $srcroot/include --gen-llvmc %s -o %t
// RUN: grep cl::multi_val(2) %t | count 1
include "llvm/CompilerDriver/Common.td"
def OptList : OptionList<[
(prefix_list_option "foo", (multi_val 2)),
(parameter_list_option "baz", (multi_val 2), (extern))]>;
def dummy_tool : Tool<[
(cmd_line "dummy_cmd"),
(in_language "dummy"),
(out_language "dummy"),
(actions (case
(not_empty "foo"), (forward_as "foo", "bar"),
(not_empty "baz"), (forward "baz")))
]>;
def DummyGraph : CompilationGraph<[SimpleEdge<"root", "dummy_tool">]>;

View File

@ -0,0 +1,22 @@
// Check that (one_or_more) and (zero_or_one) properties work.
// The dummy tool and graph are required to silence warnings.
// RUN: tblgen -I $srcroot/include --gen-llvmc %s -o %t
// RUN: grep cl::ZeroOrOne %t | count 1
// RUN: grep cl::OneOrMore %t | count 1
include "llvm/CompilerDriver/Common.td"
def OptList : OptionList<[
(prefix_list_option "foo", (one_or_more)),
(parameter_list_option "baz", (zero_or_one))]>;
def dummy_tool : Tool<[
(cmd_line "dummy_cmd"),
(in_language "dummy"),
(out_language "dummy"),
(actions (case
(not_empty "foo"), (forward_as "foo", "bar"),
(not_empty "baz"), (forward "baz")))
]>;
def DummyGraph : CompilationGraph<[SimpleEdge<"root", "dummy_tool">]>;

View File

@ -262,37 +262,47 @@ separate option groups syntactically.
* Possible option types: * Possible option types:
- ``switch_option`` - a simple boolean switch without arguments, - ``switch_option`` - a simple boolean switch without arguments, for example
for example ``-O2`` or ``-time``. ``-O2`` or ``-time``. At most one occurrence is allowed.
- ``parameter_option`` - option that takes one argument, for - ``parameter_option`` - option that takes one argument, for example
example ``-std=c99``. It is also allowed to use spaces instead of ``-std=c99``. It is also allowed to use spaces instead of the equality
the equality sign: ``-std c99``. sign: ``-std c99``. At most one occurrence is allowed.
- ``parameter_list_option`` - same as the above, but more than one - ``parameter_list_option`` - same as the above, but more than one option
option occurence is allowed. occurence is allowed.
- ``prefix_option`` - same as the parameter_option, but the option - ``prefix_option`` - same as the parameter_option, but the option name and
name and argument do not have to be separated. Example: argument do not have to be separated. Example: ``-ofile``. This can be also
``-ofile``. This can be also specified as ``-o file``; however, specified as ``-o file``; however, ``-o=file`` will be parsed incorrectly
``-o=file`` will be parsed incorrectly (``=file`` will be (``=file`` will be interpreted as option value). At most one occurrence is
interpreted as option value). allowed.
- ``prefix_list_option`` - same as the above, but more than one - ``prefix_list_option`` - same as the above, but more than one occurence of
occurence of the option is allowed; example: ``-lm -lpthread``. the option is allowed; example: ``-lm -lpthread``.
- ``alias_option`` - a special option type for creating - ``alias_option`` - a special option type for creating aliases. Unlike other
aliases. Unlike other option types, aliases are not allowed to option types, aliases are not allowed to have any properties besides the
have any properties besides the aliased option name. Usage aliased option name. Usage example: ``(alias_option "preprocess", "E")``
example: ``(alias_option "preprocess", "E")``
* Possible option properties: * Possible option properties:
- ``help`` - help string associated with this option. Used for - ``help`` - help string associated with this option. Used for ``--help``
``--help`` output. output.
- ``required`` - this option is obligatory. - ``required`` - this option must be specified exactly once (or, in case of
the list options without the ``multi_val`` property, at least
once). Incompatible with ``zero_or_one`` and ``one_or_more``.
- ``one_or_more`` - the option must be specified at least one time. Useful
only for list options in conjunction with ``multi_val``; for ordinary lists
it is synonymous with ``required``. Incompatible with ``required`` and
``zero_or_one``.
- ``zero_or_one`` - the option can be specified zero or one times. Useful
only for list options in conjunction with ``multi_val``. Incompatible with
``required`` and ``one_or_more``.
- ``hidden`` - the description of this option will not appear in - ``hidden`` - the description of this option will not appear in
the ``--help`` output (but will appear in the ``--help-hidden`` the ``--help`` output (but will appear in the ``--help-hidden``
@ -301,6 +311,11 @@ separate option groups syntactically.
- ``really_hidden`` - the option will not be mentioned in any help - ``really_hidden`` - the option will not be mentioned in any help
output. output.
- ``multi_val n`` - this option takes *n* arguments (can be useful in some
special cases). Usage example: ``(parameter_list_option "foo", (multi_val
3))``. Only list options can have this attribute; you can, however, use
the ``one_or_more`` and ``zero_or_one`` properties.
- ``extern`` - this option is defined in some other plugin, see below. - ``extern`` - this option is defined in some other plugin, see below.
External options External options

View File

@ -127,13 +127,19 @@ bool oneOf(const char* lst, char c) {
return false; return false;
} }
template <class I, class S>
void checkedIncrement(I& P, I E, S ErrorString) {
++P;
if (P == E)
throw ErrorString;
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// Back-end specific code /// Back-end specific code
/// OptionType - One of six different option types. See the /// OptionType - One of six different option types. See the
/// documentation for detailed description of differences. /// documentation for detailed description of differences.
/// Extern* options are those that are defined in some other plugin.
namespace OptionType { namespace OptionType {
enum OptionType { Alias, Switch, Parameter, ParameterList, enum OptionType { Alias, Switch, Parameter, ParameterList,
Prefix, PrefixList}; Prefix, PrefixList};
@ -171,7 +177,8 @@ OptionType::OptionType stringToOptionType(const std::string& T) {
namespace OptionDescriptionFlags { namespace OptionDescriptionFlags {
enum OptionDescriptionFlags { Required = 0x1, Hidden = 0x2, enum OptionDescriptionFlags { Required = 0x1, Hidden = 0x2,
ReallyHidden = 0x4, Extern = 0x8 }; ReallyHidden = 0x4, Extern = 0x8,
OneOrMore = 0x10, ZeroOrOne = 0x20 };
} }
/// OptionDescription - Represents data contained in a single /// OptionDescription - Represents data contained in a single
@ -181,11 +188,12 @@ struct OptionDescription {
std::string Name; std::string Name;
unsigned Flags; unsigned Flags;
std::string Help; std::string Help;
unsigned MultiVal;
OptionDescription(OptionType::OptionType t = OptionType::Switch, OptionDescription(OptionType::OptionType t = OptionType::Switch,
const std::string& n = "", const std::string& n = "",
const std::string& h = DefaultHelpString) const std::string& h = DefaultHelpString)
: Type(t), Name(n), Flags(0x0), Help(h) : Type(t), Name(n), Flags(0x0), Help(h), MultiVal(1)
{} {}
/// GenTypeDeclaration - Returns the C++ variable type of this /// GenTypeDeclaration - Returns the C++ variable type of this
@ -203,17 +211,26 @@ struct OptionDescription {
bool isAlias() const; bool isAlias() const;
bool isMultiVal() const;
bool isExtern() const; bool isExtern() const;
void setExtern(); void setExtern();
bool isRequired() const; bool isRequired() const;
void setRequired(); void setRequired();
bool isOneOrMore() const;
void setOneOrMore();
bool isZeroOrOne() const;
void setZeroOrOne();
bool isHidden() const; bool isHidden() const;
void setHidden(); void setHidden();
bool isReallyHidden() const; bool isReallyHidden() const;
void setReallyHidden(); void setReallyHidden();
}; };
void OptionDescription::Merge (const OptionDescription& other) void OptionDescription::Merge (const OptionDescription& other)
@ -235,6 +252,10 @@ bool OptionDescription::isAlias() const {
return Type == OptionType::Alias; return Type == OptionType::Alias;
} }
bool OptionDescription::isMultiVal() const {
return MultiVal == 1;
}
bool OptionDescription::isExtern() const { bool OptionDescription::isExtern() const {
return Flags & OptionDescriptionFlags::Extern; return Flags & OptionDescriptionFlags::Extern;
} }
@ -249,6 +270,20 @@ void OptionDescription::setRequired() {
Flags |= OptionDescriptionFlags::Required; Flags |= OptionDescriptionFlags::Required;
} }
bool OptionDescription::isOneOrMore() const {
return Flags & OptionDescriptionFlags::OneOrMore;
}
void OptionDescription::setOneOrMore() {
Flags |= OptionDescriptionFlags::OneOrMore;
}
bool OptionDescription::isZeroOrOne() const {
return Flags & OptionDescriptionFlags::ZeroOrOne;
}
void OptionDescription::setZeroOrOne() {
Flags |= OptionDescriptionFlags::ZeroOrOne;
}
bool OptionDescription::isHidden() const { bool OptionDescription::isHidden() const {
return Flags & OptionDescriptionFlags::Hidden; return Flags & OptionDescriptionFlags::Hidden;
} }
@ -405,8 +440,11 @@ public:
AddHandler("extern", &CollectOptionProperties::onExtern); AddHandler("extern", &CollectOptionProperties::onExtern);
AddHandler("help", &CollectOptionProperties::onHelp); AddHandler("help", &CollectOptionProperties::onHelp);
AddHandler("hidden", &CollectOptionProperties::onHidden); AddHandler("hidden", &CollectOptionProperties::onHidden);
AddHandler("multi_val", &CollectOptionProperties::onMultiVal);
AddHandler("one_or_more", &CollectOptionProperties::onOneOrMore);
AddHandler("really_hidden", &CollectOptionProperties::onReallyHidden); AddHandler("really_hidden", &CollectOptionProperties::onReallyHidden);
AddHandler("required", &CollectOptionProperties::onRequired); AddHandler("required", &CollectOptionProperties::onRequired);
AddHandler("zero_or_one", &CollectOptionProperties::onZeroOrOne);
staticMembersInitialized_ = true; staticMembersInitialized_ = true;
} }
@ -439,9 +477,46 @@ private:
void onRequired (const DagInit* d) { void onRequired (const DagInit* d) {
checkNumberOfArguments(d, 0); checkNumberOfArguments(d, 0);
if (optDesc_.isOneOrMore())
throw std::string("An option can't have both (required) "
"and (one_or_more) properties!");
optDesc_.setRequired(); optDesc_.setRequired();
} }
void onOneOrMore (const DagInit* d) {
checkNumberOfArguments(d, 0);
if (optDesc_.isRequired() || optDesc_.isZeroOrOne())
throw std::string("Only one of (required), (zero_or_one) or "
"(one_or_more) properties is allowed!");
if (!OptionType::IsList(optDesc_.Type))
llvm::cerr << "Warning: specifying the 'one_or_more' property "
"on a non-list option will have no effect.\n";
optDesc_.setOneOrMore();
}
void onZeroOrOne (const DagInit* d) {
checkNumberOfArguments(d, 0);
if (optDesc_.isRequired() || optDesc_.isOneOrMore())
throw std::string("Only one of (required), (zero_or_one) or "
"(one_or_more) properties is allowed!");
if (!OptionType::IsList(optDesc_.Type))
llvm::cerr << "Warning: specifying the 'zero_or_one' property"
"on a non-list option will have no effect.\n";
optDesc_.setZeroOrOne();
}
void onMultiVal (const DagInit* d) {
checkNumberOfArguments(d, 1);
int val = InitPtrToInt(d->getArg(0));
if (val < 2)
throw std::string("Error in the 'multi_val' property: "
"the value must be greater than 1!");
if (!OptionType::IsList(optDesc_.Type))
throw std::string("The multi_val property is valid only "
"on list options!");
optDesc_.MultiVal = val;
}
}; };
/// AddOption - A function object that is applied to every option /// AddOption - A function object that is applied to every option
@ -639,7 +714,6 @@ private:
}; };
/// CollectToolDescriptions - Gather information about tool properties /// CollectToolDescriptions - Gather information about tool properties
/// from the parsed TableGen data (basically a wrapper for the /// from the parsed TableGen data (basically a wrapper for the
/// CollectToolProperties function object). /// CollectToolProperties function object).
@ -1131,13 +1205,6 @@ void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) {
} }
} }
template <class I, class S>
void checkedIncrement(I& P, I E, S ErrorString) {
++P;
if (P == E)
throw ErrorString;
}
/// SubstituteSpecialCommands - Perform string substitution for $CALL /// SubstituteSpecialCommands - Perform string substitution for $CALL
/// and $ENV. Helper function used by EmitCmdLineVecFill(). /// and $ENV. Helper function used by EmitCmdLineVecFill().
StrVector::const_iterator SubstituteSpecialCommands StrVector::const_iterator SubstituteSpecialCommands
@ -1308,18 +1375,31 @@ void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D,
case OptionType::PrefixList: case OptionType::PrefixList:
O << Indent << "for (" << D.GenTypeDeclaration() O << Indent << "for (" << D.GenTypeDeclaration()
<< "::iterator B = " << D.GenVariableName() << ".begin(),\n" << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
<< Indent << "E = " << D.GenVariableName() << ".end(); B != E; ++B)\n" << Indent << "E = " << D.GenVariableName() << ".end(); B != E;) {\n"
<< Indent << Indent1 << "vec.push_back(\"" << Name << "\" + " << Indent << Indent1 << "vec.push_back(\"" << Name << "\" + "
<< "*B);\n"; << "*B);\n"
<< Indent << Indent1 << "++B;\n";
for (int i = 1, j = D.MultiVal; i < j; ++i) {
O << Indent << Indent1 << "vec.push_back(*B);\n"
<< Indent << Indent1 << "++B;\n";
}
O << Indent << "}\n";
break; break;
case OptionType::ParameterList: case OptionType::ParameterList:
O << Indent << "for (" << D.GenTypeDeclaration() O << Indent << "for (" << D.GenTypeDeclaration()
<< "::iterator B = " << D.GenVariableName() << ".begin(),\n" << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
<< Indent << "E = " << D.GenVariableName() << Indent << "E = " << D.GenVariableName()
<< ".end() ; B != E; ++B) {\n" << ".end() ; B != E;) {\n"
<< Indent << Indent1 << "vec.push_back(\"" << Name << "\");\n" << Indent << Indent1 << "vec.push_back(\"" << Name << "\");\n";
<< Indent << Indent1 << "vec.push_back(*B);\n"
<< Indent << "}\n"; for (int i = 0, j = D.MultiVal; i < j; ++i) {
O << Indent << Indent1 << "vec.push_back(*B);\n"
<< Indent << Indent1 << "++B;\n";
}
O << Indent << "}\n";
break; break;
case OptionType::Alias: case OptionType::Alias:
default: default:
@ -1376,6 +1456,9 @@ class EmitActionHandler {
const std::string& Name = InitPtrToString(Dag.getArg(0)); const std::string& Name = InitPtrToString(Dag.getArg(0));
const OptionDescription& D = OptDescs.FindOption(Name); const OptionDescription& D = OptDescs.FindOption(Name);
if (D.isMultiVal())
throw std::string("Can't use unpack_values with multi-valued options!");
if (OptionType::IsList(D.Type)) { if (OptionType::IsList(D.Type)) {
O << IndentLevel << "for (" << D.GenTypeDeclaration() O << IndentLevel << "for (" << D.GenTypeDeclaration()
<< "::iterator B = " << D.GenVariableName() << ".begin(),\n" << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
@ -1599,26 +1682,27 @@ void EmitOptionDefintions (const OptionDescriptions& descs,
O << ", cl::Prefix"; O << ", cl::Prefix";
if (val.isRequired()) { if (val.isRequired()) {
switch (val.Type) { if (OptionType::IsList(val.Type) && !val.isMultiVal())
case OptionType::PrefixList:
case OptionType::ParameterList:
O << ", cl::OneOrMore"; O << ", cl::OneOrMore";
break; else
default:
O << ", cl::Required"; O << ", cl::Required";
} }
else if (val.isOneOrMore() && OptionType::IsList(val.Type)) {
O << ", cl::OneOrMore";
}
else if (val.isZeroOrOne() && OptionType::IsList(val.Type)) {
O << ", cl::ZeroOrOne";
} }
if (val.isReallyHidden() || val.isHidden()) { if (val.isReallyHidden()) {
if (val.isRequired()) O << ", cl::ReallyHidden";
O << " |";
else
O << ",";
if (val.isReallyHidden())
O << " cl::ReallyHidden";
else
O << " cl::Hidden";
} }
else if (val.isHidden()) {
O << ", cl::Hidden";
}
if (val.MultiVal > 1)
O << ", cl::multi_val(" << val.MultiVal << ")";
if (!val.Help.empty()) if (!val.Help.empty())
O << ", cl::desc(\"" << val.Help << "\")"; O << ", cl::desc(\"" << val.Help << "\")";