X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=utils%2FTableGen%2FLLVMCConfigurationEmitter.cpp;h=c40a39dff729824674db75a5eb1d102c59aee2c6;hb=75f6e89ea9f8fe9cf8c8f9fe6a3322bd6566fdf1;hp=42d9d9ce0a35ec5d8a00859e778d8ed3d771f273;hpb=b797000820b576f4d5964be6b659dac15ad6fec8;p=oota-llvm.git diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp index 42d9d9ce0a3..c40a39dff72 100644 --- a/utils/TableGen/LLVMCConfigurationEmitter.cpp +++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp @@ -15,10 +15,9 @@ #include "Record.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" + #include #include #include @@ -26,6 +25,7 @@ #include #include + using namespace llvm; namespace { @@ -34,29 +34,38 @@ namespace { /// Typedefs typedef std::vector RecordVector; +typedef std::vector DagVector; typedef std::vector StrVector; //===----------------------------------------------------------------------===// /// Constants -// Indentation strings. -const char * Indent1 = " "; -const char * Indent2 = " "; -const char * Indent3 = " "; +// Indentation. +const unsigned TabWidth = 4; +const unsigned Indent1 = TabWidth*1; +const unsigned Indent2 = TabWidth*2; +const unsigned Indent3 = TabWidth*3; +const unsigned Indent4 = TabWidth*4; // Default help string. -const char * DefaultHelpString = "NO HELP MESSAGE PROVIDED"; +const char * const DefaultHelpString = "NO HELP MESSAGE PROVIDED"; // Name for the "sink" option. -const char * SinkOptionName = "AutoGeneratedSinkOption"; +const char * const SinkOptionName = "SinkOption"; //===----------------------------------------------------------------------===// /// Helper functions /// Id - An 'identity' function object. struct Id { - template - void operator()(const T&) const { + template + void operator()(const T0&) const { + } + template + void operator()(const T0&, const T1&) const { + } + template + void operator()(const T0&, const T1&, const T2&) const { } }; @@ -80,22 +89,32 @@ const DagInit& InitPtrToDag(const Init* ptr) { return val; } -// checkNumberOfArguments - Ensure that the number of args in d is -// greater than or equal to min_arguments, otherwise throw an exception. -void checkNumberOfArguments (const DagInit* d, unsigned min_arguments) { - if (!d || d->getNumArgs() < min_arguments) - throw d->getOperator()->getAsString() + ": too few arguments!"; +const std::string GetOperatorName(const DagInit& D) { + return D.getOperator()->getAsString(); +} + +/// CheckBooleanConstant - Check that the provided value is a boolean constant. +void CheckBooleanConstant(const Init* I) { + const DefInit& val = dynamic_cast(*I); + const std::string& str = val.getAsString(); + + if (str != "true" && str != "false") { + throw "Incorrect boolean value: '" + str + + "': must be either 'true' or 'false'"; + } } -// isDagEmpty - is this DAG marked with an empty marker? -bool isDagEmpty (const DagInit* d) { - return d->getOperator()->getAsString() == "empty"; +// CheckNumberOfArguments - Ensure that the number of args in d is +// greater than or equal to min_arguments, otherwise throw an exception. +void CheckNumberOfArguments (const DagInit& d, unsigned minArgs) { + if (d.getNumArgs() < minArgs) + throw GetOperatorName(d) + ": too few arguments!"; } // EscapeVariableName - Escape commas and other symbols not allowed // in the C++ variable names. Makes it possible to use options named // like "Wa," (useful for prefix options). -std::string EscapeVariableName(const std::string& Var) { +std::string EscapeVariableName (const std::string& Var) { std::string ret; for (unsigned i = 0; i != Var.size(); ++i) { char cur_char = Var[i]; @@ -115,8 +134,23 @@ std::string EscapeVariableName(const std::string& Var) { return ret; } -/// oneOf - Does the input string contain this character? -bool oneOf(const char* lst, char c) { +/// EscapeQuotes - Replace '"' with '\"'. +std::string EscapeQuotes (const std::string& Var) { + std::string ret; + for (unsigned i = 0; i != Var.size(); ++i) { + char cur_char = Var[i]; + if (cur_char == '"') { + ret += "\\\""; + } + else { + ret.push_back(cur_char); + } + } + return ret; +} + +/// OneOf - Does the input string contain this character? +bool OneOf(const char* lst, char c) { while (*lst) { if (*lst++ == c) return true; @@ -125,7 +159,7 @@ bool oneOf(const char* lst, char c) { } template -void checkedIncrement(I& P, I E, S ErrorString) { +void CheckedIncrement(I& P, I E, S ErrorString) { ++P; if (P == E) throw ErrorString; @@ -138,20 +172,29 @@ void checkedIncrement(I& P, I E, S ErrorString) { /// OptionType - One of six different option types. See the /// documentation for detailed description of differences. namespace OptionType { - enum OptionType { Alias, Switch, Parameter, ParameterList, - Prefix, PrefixList}; -bool IsList (OptionType t) { - return (t == ParameterList || t == PrefixList); -} + enum OptionType { Alias, Switch, SwitchList, + Parameter, ParameterList, Prefix, PrefixList }; -bool IsSwitch (OptionType t) { - return (t == Switch); -} + bool IsAlias(OptionType t) { + return (t == Alias); + } -bool IsParameter (OptionType t) { - return (t == Parameter || t == Prefix); -} + bool IsList (OptionType t) { + return (t == SwitchList || t == ParameterList || t == PrefixList); + } + + bool IsSwitch (OptionType t) { + return (t == Switch); + } + + bool IsSwitchList (OptionType t) { + return (t == SwitchList); + } + + bool IsParameter (OptionType t) { + return (t == Parameter || t == Prefix); + } } @@ -160,6 +203,8 @@ OptionType::OptionType stringToOptionType(const std::string& T) { return OptionType::Alias; else if (T == "switch_option") return OptionType::Switch; + else if (T == "switch_list_option") + return OptionType::SwitchList; else if (T == "parameter_option") return OptionType::Parameter; else if (T == "parameter_list_option") @@ -174,8 +219,9 @@ OptionType::OptionType stringToOptionType(const std::string& T) { namespace OptionDescriptionFlags { enum OptionDescriptionFlags { Required = 0x1, Hidden = 0x2, - ReallyHidden = 0x4, Extern = 0x8, - OneOrMore = 0x10, ZeroOrOne = 0x20 }; + ReallyHidden = 0x4, OneOrMore = 0x8, + Optional = 0x10, CommaSeparated = 0x20, + ForwardNotSplit = 0x40, ZeroOrMore = 0x80 }; } /// OptionDescription - Represents data contained in a single @@ -186,11 +232,12 @@ struct OptionDescription { unsigned Flags; std::string Help; unsigned MultiVal; + Init* InitVal; OptionDescription(OptionType::OptionType t = OptionType::Switch, const std::string& n = "", const std::string& h = DefaultHelpString) - : Type(t), Name(n), Flags(0x0), Help(h), MultiVal(1) + : Type(t), Name(n), Flags(0x0), Help(h), MultiVal(1), InitVal(0) {} /// GenTypeDeclaration - Returns the C++ variable type of this @@ -199,19 +246,31 @@ struct OptionDescription { /// GenVariableName - Returns the variable name used in the /// generated C++ code. - std::string GenVariableName() const; + std::string GenVariableName() const + { return "autogenerated::" + GenOptionType() + EscapeVariableName(Name); } + + /// GenPlainVariableName - Returns the variable name without the namespace + /// prefix. + std::string GenPlainVariableName() const + { return GenOptionType() + EscapeVariableName(Name); } /// Merge - Merge two option descriptions. void Merge (const OptionDescription& other); + /// CheckConsistency - Check that the flags are consistent. + void CheckConsistency() const; + // Misc convenient getters/setters. bool isAlias() const; bool isMultiVal() const; - bool isExtern() const; - void setExtern(); + bool isCommaSeparated() const; + void setCommaSeparated(); + + bool isForwardNotSplit() const; + void setForwardNotSplit(); bool isRequired() const; void setRequired(); @@ -219,8 +278,11 @@ struct OptionDescription { bool isOneOrMore() const; void setOneOrMore(); - bool isZeroOrOne() const; - void setZeroOrOne(); + bool isZeroOrMore() const; + void setZeroOrMore(); + + bool isOptional() const; + void setOptional(); bool isHidden() const; void setHidden(); @@ -228,8 +290,42 @@ struct OptionDescription { bool isReallyHidden() const; void setReallyHidden(); + bool isSwitch() const + { return OptionType::IsSwitch(this->Type); } + + bool isSwitchList() const + { return OptionType::IsSwitchList(this->Type); } + + bool isParameter() const + { return OptionType::IsParameter(this->Type); } + + bool isList() const + { return OptionType::IsList(this->Type); } + + bool isParameterList() const + { return (OptionType::IsList(this->Type) + && !OptionType::IsSwitchList(this->Type)); } + +private: + + // GenOptionType - Helper function used by GenVariableName(). + std::string GenOptionType() const; }; +void OptionDescription::CheckConsistency() const { + unsigned i = 0; + + i += this->isRequired(); + i += this->isOptional(); + i += this->isOneOrMore(); + i += this->isZeroOrMore(); + + if (i > 1) { + throw "Only one of (required), (optional), (one_or_more) or " + "(zero_or_more) properties is allowed!"; + } +} + void OptionDescription::Merge (const OptionDescription& other) { if (other.Type != Type) @@ -246,18 +342,25 @@ void OptionDescription::Merge (const OptionDescription& other) } bool OptionDescription::isAlias() const { - return Type == OptionType::Alias; + return OptionType::IsAlias(this->Type); } bool OptionDescription::isMultiVal() const { return MultiVal > 1; } -bool OptionDescription::isExtern() const { - return Flags & OptionDescriptionFlags::Extern; +bool OptionDescription::isCommaSeparated() const { + return Flags & OptionDescriptionFlags::CommaSeparated; } -void OptionDescription::setExtern() { - Flags |= OptionDescriptionFlags::Extern; +void OptionDescription::setCommaSeparated() { + Flags |= OptionDescriptionFlags::CommaSeparated; +} + +bool OptionDescription::isForwardNotSplit() const { + return Flags & OptionDescriptionFlags::ForwardNotSplit; +} +void OptionDescription::setForwardNotSplit() { + Flags |= OptionDescriptionFlags::ForwardNotSplit; } bool OptionDescription::isRequired() const { @@ -274,11 +377,18 @@ void OptionDescription::setOneOrMore() { Flags |= OptionDescriptionFlags::OneOrMore; } -bool OptionDescription::isZeroOrOne() const { - return Flags & OptionDescriptionFlags::ZeroOrOne; +bool OptionDescription::isZeroOrMore() const { + return Flags & OptionDescriptionFlags::ZeroOrMore; +} +void OptionDescription::setZeroOrMore() { + Flags |= OptionDescriptionFlags::ZeroOrMore; +} + +bool OptionDescription::isOptional() const { + return Flags & OptionDescriptionFlags::Optional; } -void OptionDescription::setZeroOrOne() { - Flags |= OptionDescriptionFlags::ZeroOrOne; +void OptionDescription::setOptional() { + Flags |= OptionDescriptionFlags::Optional; } bool OptionDescription::isHidden() const { @@ -304,6 +414,8 @@ const char* OptionDescription::GenTypeDeclaration() const { return "cl::list"; case OptionType::Switch: return "cl::opt"; + case OptionType::SwitchList: + return "cl::list"; case OptionType::Parameter: case OptionType::Prefix: default: @@ -311,20 +423,21 @@ const char* OptionDescription::GenTypeDeclaration() const { } } -std::string OptionDescription::GenVariableName() const { - const std::string& EscapedName = EscapeVariableName(Name); +std::string OptionDescription::GenOptionType() const { switch (Type) { case OptionType::Alias: - return "AutoGeneratedAlias_" + EscapedName; + return "Alias_"; case OptionType::PrefixList: case OptionType::ParameterList: - return "AutoGeneratedList_" + EscapedName; + return "List_"; case OptionType::Switch: - return "AutoGeneratedSwitch_" + EscapedName; + return "Switch_"; + case OptionType::SwitchList: + return "SwitchList_"; case OptionType::Prefix: case OptionType::Parameter: default: - return "AutoGeneratedParameter_" + EscapedName; + return "Parameter_"; } } @@ -340,6 +453,16 @@ public: /// FindOption - exception-throwing wrapper for find(). const OptionDescription& FindOption(const std::string& OptName) const; + // Wrappers for FindOption that throw an exception in case the option has a + // wrong type. + const OptionDescription& FindSwitch(const std::string& OptName) const; + const OptionDescription& FindParameter(const std::string& OptName) const; + const OptionDescription& FindParameterList(const std::string& OptName) const; + const OptionDescription& + FindListOrParameter(const std::string& OptName) const; + const OptionDescription& + FindParameterListOrParameter(const std::string& OptName) const; + /// insertDescription - Insert new OptionDescription into /// OptionDescriptions list void InsertDescription (const OptionDescription& o); @@ -351,8 +474,7 @@ public: }; const OptionDescription& -OptionDescriptions::FindOption(const std::string& OptName) const -{ +OptionDescriptions::FindOption(const std::string& OptName) const { const_iterator I = Descriptions.find(OptName); if (I != Descriptions.end()) return I->second; @@ -360,8 +482,50 @@ OptionDescriptions::FindOption(const std::string& OptName) const throw OptName + ": no such option!"; } -void OptionDescriptions::InsertDescription (const OptionDescription& o) -{ +const OptionDescription& +OptionDescriptions::FindSwitch(const std::string& OptName) const { + const OptionDescription& OptDesc = this->FindOption(OptName); + if (!OptDesc.isSwitch()) + throw OptName + ": incorrect option type - should be a switch!"; + return OptDesc; +} + +const OptionDescription& +OptionDescriptions::FindParameterList(const std::string& OptName) const { + const OptionDescription& OptDesc = this->FindOption(OptName); + if (!OptDesc.isList() || OptDesc.isSwitchList()) + throw OptName + ": incorrect option type - should be a parameter list!"; + return OptDesc; +} + +const OptionDescription& +OptionDescriptions::FindParameter(const std::string& OptName) const { + const OptionDescription& OptDesc = this->FindOption(OptName); + if (!OptDesc.isParameter()) + throw OptName + ": incorrect option type - should be a parameter!"; + return OptDesc; +} + +const OptionDescription& +OptionDescriptions::FindListOrParameter(const std::string& OptName) const { + const OptionDescription& OptDesc = this->FindOption(OptName); + if (!OptDesc.isList() && !OptDesc.isParameter()) + throw OptName + + ": incorrect option type - should be a list or parameter!"; + return OptDesc; +} + +const OptionDescription& +OptionDescriptions::FindParameterListOrParameter +(const std::string& OptName) const { + const OptionDescription& OptDesc = this->FindOption(OptName); + if ((!OptDesc.isList() && !OptDesc.isParameter()) || OptDesc.isSwitchList()) + throw OptName + + ": incorrect option type - should be a parameter list or parameter!"; + return OptDesc; +} + +void OptionDescriptions::InsertDescription (const OptionDescription& o) { container_type::iterator I = Descriptions.find(o.Name); if (I != Descriptions.end()) { OptionDescription& D = I->second; @@ -374,54 +538,82 @@ void OptionDescriptions::InsertDescription (const OptionDescription& o) /// HandlerTable - A base class for function objects implemented as /// 'tables of handlers'. -template +template class HandlerTable { protected: // Implementation details. - /// Handler - - typedef void (T::* Handler) (const DagInit*); /// HandlerMap - A map from property names to property handlers typedef StringMap HandlerMap; static HandlerMap Handlers_; static bool staticMembersInitialized_; - T* childPtr; public: - HandlerTable(T* cp) : childPtr(cp) - {} - - /// operator() - Just forwards to the corresponding property - /// handler. - void operator() (Init* i) { - const DagInit& property = InitPtrToDag(i); - const std::string& property_name = property.getOperator()->getAsString(); - typename HandlerMap::iterator method = Handlers_.find(property_name); + Handler GetHandler (const std::string& HandlerName) const { + typename HandlerMap::iterator method = Handlers_.find(HandlerName); if (method != Handlers_.end()) { Handler h = method->second; - (childPtr->*h)(&property); + return h; } else { - throw "No handler found for property " + property_name + "!"; + throw "No handler found for property " + HandlerName + "!"; } } - void AddHandler(const char* Property, Handler Handl) { - Handlers_[Property] = Handl; + void AddHandler(const char* Property, Handler H) { + Handlers_[Property] = H; } + }; -template typename HandlerTable::HandlerMap -HandlerTable::Handlers_; -template bool HandlerTable::staticMembersInitialized_ = false; +template +Handler GetHandler(FunctionObject* Obj, const DagInit& Dag) { + const std::string& HandlerName = GetOperatorName(Dag); + return Obj->GetHandler(HandlerName); +} + +template +void InvokeDagInitHandler(FunctionObject* Obj, Init* I) { + typedef void (FunctionObject::*Handler) (const DagInit&); + + const DagInit& Dag = InitPtrToDag(I); + Handler h = GetHandler(Obj, Dag); + + ((Obj)->*(h))(Dag); +} + +template +void InvokeDagInitHandler(const FunctionObject* const Obj, + const Init* I, unsigned IndentLevel, raw_ostream& O) +{ + typedef void (FunctionObject::*Handler) + (const DagInit&, unsigned IndentLevel, raw_ostream& O) const; + + const DagInit& Dag = InitPtrToDag(I); + Handler h = GetHandler(Obj, Dag); + + ((Obj)->*(h))(Dag, IndentLevel, O); +} + +template +typename HandlerTable::HandlerMap HandlerTable::Handlers_; + +template +bool HandlerTable::staticMembersInitialized_ = false; /// CollectOptionProperties - Function object for iterating over an /// option property list. -class CollectOptionProperties : public HandlerTable { +class CollectOptionProperties; +typedef void (CollectOptionProperties::* CollectOptionPropertiesHandler) +(const DagInit&); + +class CollectOptionProperties +: public HandlerTable +{ private: /// optDescs_ - OptionDescriptions table. This is where the @@ -431,86 +623,124 @@ private: public: explicit CollectOptionProperties(OptionDescription& OD) - : HandlerTable(this), optDesc_(OD) + : optDesc_(OD) { if (!staticMembersInitialized_) { - AddHandler("extern", &CollectOptionProperties::onExtern); AddHandler("help", &CollectOptionProperties::onHelp); AddHandler("hidden", &CollectOptionProperties::onHidden); + AddHandler("init", &CollectOptionProperties::onInit); AddHandler("multi_val", &CollectOptionProperties::onMultiVal); AddHandler("one_or_more", &CollectOptionProperties::onOneOrMore); + AddHandler("zero_or_more", &CollectOptionProperties::onZeroOrMore); AddHandler("really_hidden", &CollectOptionProperties::onReallyHidden); AddHandler("required", &CollectOptionProperties::onRequired); - AddHandler("zero_or_one", &CollectOptionProperties::onZeroOrOne); + AddHandler("optional", &CollectOptionProperties::onOptional); + AddHandler("comma_separated", &CollectOptionProperties::onCommaSeparated); + AddHandler("forward_not_split", + &CollectOptionProperties::onForwardNotSplit); staticMembersInitialized_ = true; } } + /// operator() - Just forwards to the corresponding property + /// handler. + void operator() (Init* I) { + InvokeDagInitHandler(this, I); + } + private: /// Option property handlers -- /// Methods that handle option properties such as (help) or (hidden). - void onExtern (const DagInit* d) { - checkNumberOfArguments(d, 0); - optDesc_.setExtern(); - } - - void onHelp (const DagInit* d) { - checkNumberOfArguments(d, 1); - optDesc_.Help = InitPtrToString(d->getArg(0)); + void onHelp (const DagInit& d) { + CheckNumberOfArguments(d, 1); + optDesc_.Help = EscapeQuotes(InitPtrToString(d.getArg(0))); } - void onHidden (const DagInit* d) { - checkNumberOfArguments(d, 0); + void onHidden (const DagInit& d) { + CheckNumberOfArguments(d, 0); optDesc_.setHidden(); } - void onReallyHidden (const DagInit* d) { - checkNumberOfArguments(d, 0); + void onReallyHidden (const DagInit& d) { + CheckNumberOfArguments(d, 0); optDesc_.setReallyHidden(); } - void onRequired (const DagInit* d) { - checkNumberOfArguments(d, 0); - if (optDesc_.isOneOrMore()) - throw std::string("An option can't have both (required) " - "and (one_or_more) properties!"); + void onCommaSeparated (const DagInit& d) { + CheckNumberOfArguments(d, 0); + if (!optDesc_.isParameterList()) + throw "'comma_separated' is valid only on parameter list options!"; + optDesc_.setCommaSeparated(); + } + + void onForwardNotSplit (const DagInit& d) { + CheckNumberOfArguments(d, 0); + if (!optDesc_.isParameter()) + throw "'forward_not_split' is valid only for parameter options!"; + optDesc_.setForwardNotSplit(); + } + + void onRequired (const DagInit& d) { + CheckNumberOfArguments(d, 0); + optDesc_.setRequired(); + optDesc_.CheckConsistency(); + } + + void onInit (const DagInit& d) { + CheckNumberOfArguments(d, 1); + Init* i = d.getArg(0); + const std::string& str = i->getAsString(); + + bool correct = optDesc_.isParameter() && dynamic_cast(i); + correct |= (optDesc_.isSwitch() && (str == "true" || str == "false")); + + if (!correct) + throw "Incorrect usage of the 'init' option property!"; + + optDesc_.InitVal = i; } - 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::errs() << "Warning: specifying the 'one_or_more' property " - "on a non-list option will have no effect.\n"; + void onOneOrMore (const DagInit& d) { + CheckNumberOfArguments(d, 0); + optDesc_.setOneOrMore(); + optDesc_.CheckConsistency(); + } + + void onZeroOrMore (const DagInit& d) { + CheckNumberOfArguments(d, 0); + + if (optDesc_.isList()) + llvm::errs() << "Warning: specifying the 'zero_or_more' property " + "on a list option has no effect.\n"; + + optDesc_.setZeroOrMore(); + optDesc_.CheckConsistency(); } - 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::errs() << "Warning: specifying the 'zero_or_one' property" - "on a non-list option will have no effect.\n"; - optDesc_.setZeroOrOne(); + void onOptional (const DagInit& d) { + CheckNumberOfArguments(d, 0); + + if (!optDesc_.isList()) + llvm::errs() << "Warning: specifying the 'optional' property" + "on a non-list option has no effect.\n"; + + optDesc_.setOptional(); + optDesc_.CheckConsistency(); } - void onMultiVal (const DagInit* d) { - checkNumberOfArguments(d, 1); - int val = InitPtrToInt(d->getArg(0)); + 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!"); + throw "Error in the 'multi_val' property: " + "the value must be greater than 1!"; + if (!optDesc_.isParameterList()) + throw "The multi_val property is valid only on list options!"; optDesc_.MultiVal = val; } @@ -528,54 +758,59 @@ public: void operator()(const Init* i) { const DagInit& d = InitPtrToDag(i); - checkNumberOfArguments(&d, 1); + CheckNumberOfArguments(d, 1); const OptionType::OptionType Type = - stringToOptionType(d.getOperator()->getAsString()); + stringToOptionType(GetOperatorName(d)); const std::string& Name = InitPtrToString(d.getArg(0)); OptionDescription OD(Type, Name); - if (!OD.isExtern()) - checkNumberOfArguments(&d, 2); + CheckNumberOfArguments(d, 2); + // Alias option store the aliased option name in the 'Help' field and do not + // have any properties. if (OD.isAlias()) { - // Aliases store the aliased option name in the 'Help' field. OD.Help = InitPtrToString(d.getArg(1)); } - else if (!OD.isExtern()) { - processOptionProperties(&d, OD); + else { + processOptionProperties(d, OD); + } + + // Switch options are ZeroOrMore by default. + if (OD.isSwitch()) { + if (!(OD.isOptional() || OD.isOneOrMore() || OD.isRequired())) + OD.setZeroOrMore(); } + OptDescs_.InsertDescription(OD); } private: /// processOptionProperties - Go through the list of option /// properties and call a corresponding handler for each. - static void processOptionProperties (const DagInit* d, OptionDescription& o) { - checkNumberOfArguments(d, 2); - DagInit::const_arg_iterator B = d->arg_begin(); + static void processOptionProperties (const DagInit& d, OptionDescription& o) { + CheckNumberOfArguments(d, 2); + DagInit::const_arg_iterator B = d.arg_begin(); // Skip the first argument: it's always the option name. ++B; - std::for_each(B, d->arg_end(), CollectOptionProperties(o)); + std::for_each(B, d.arg_end(), CollectOptionProperties(o)); } }; /// CollectOptionDescriptions - Collects option properties from all /// OptionLists. -void CollectOptionDescriptions (RecordVector::const_iterator B, - RecordVector::const_iterator E, +void CollectOptionDescriptions (const RecordVector& V, OptionDescriptions& OptDescs) { // For every OptionList: - for (; B!=E; ++B) { - RecordVector::value_type T = *B; + for (RecordVector::const_iterator B = V.begin(), E = V.end(); B!=E; ++B) + { // Throws an exception if the value does not exist. - ListInit* PropList = T->getValueAsListInit("options"); + ListInit* PropList = (*B)->getValueAsListInit("options"); - // For every option description in this list: - // collect the information and + // For every option description in this list: invoke AddOption. std::for_each(PropList->begin(), PropList->end(), AddOption(OptDescs)); } } @@ -591,9 +826,12 @@ struct ToolDescription : public RefCountedBase { Init* CmdLine; Init* Actions; StrVector InLanguage; - std::string OutLanguage; + std::string InFileOption; + std::string OutFileOption; + StrVector OutLanguage; std::string OutputSuffix; unsigned Flags; + const Init* OnEmpty; // Various boolean properties void setSink() { Flags |= ToolFlags::Sink; } @@ -603,9 +841,9 @@ struct ToolDescription : public RefCountedBase { // Default ctor here is needed because StringMap can only store // DefaultConstructible objects - ToolDescription() : CmdLine(0), Actions(0), Flags(0) {} - ToolDescription (const std::string& n) - : Name(n), CmdLine(0), Actions(0), Flags(0) + ToolDescription (const std::string &n = "") + : Name(n), CmdLine(0), Actions(0), OutFileOption("-o"), + Flags(0), OnEmpty(0) {} }; @@ -615,7 +853,13 @@ typedef std::vector > ToolDescriptions; /// CollectToolProperties - Function object for iterating over a list of /// tool property records. -class CollectToolProperties : public HandlerTable { + +class CollectToolProperties; +typedef void (CollectToolProperties::* CollectToolPropertiesHandler) +(const DagInit&); + +class CollectToolProperties : public HandlerTable +{ private: /// toolDesc_ - Properties of the current Tool. This is where the @@ -625,101 +869,115 @@ private: public: explicit CollectToolProperties (ToolDescription& d) - : HandlerTable(this) , toolDesc_(d) + : toolDesc_(d) { if (!staticMembersInitialized_) { AddHandler("actions", &CollectToolProperties::onActions); - AddHandler("cmd_line", &CollectToolProperties::onCmdLine); + AddHandler("command", &CollectToolProperties::onCommand); AddHandler("in_language", &CollectToolProperties::onInLanguage); AddHandler("join", &CollectToolProperties::onJoin); AddHandler("out_language", &CollectToolProperties::onOutLanguage); + + AddHandler("out_file_option", &CollectToolProperties::onOutFileOption); + AddHandler("in_file_option", &CollectToolProperties::onInFileOption); + AddHandler("output_suffix", &CollectToolProperties::onOutputSuffix); AddHandler("sink", &CollectToolProperties::onSink); + AddHandler("works_on_empty", &CollectToolProperties::onWorksOnEmpty); staticMembersInitialized_ = true; } } + void operator() (Init* I) { + InvokeDagInitHandler(this, I); + } + private: /// Property handlers -- /// Functions that extract information about tool properties from /// DAG representation. - void onActions (const DagInit* d) { - checkNumberOfArguments(d, 1); - Init* Case = d->getArg(0); + void onActions (const DagInit& d) { + CheckNumberOfArguments(d, 1); + Init* Case = d.getArg(0); if (typeid(*Case) != typeid(DagInit) || - static_cast(Case)->getOperator()->getAsString() != "case") - throw - std::string("The argument to (actions) should be a 'case' construct!"); + GetOperatorName(static_cast(*Case)) != "case") + throw "The argument to (actions) should be a 'case' construct!"; toolDesc_.Actions = Case; } - void onCmdLine (const DagInit* d) { - checkNumberOfArguments(d, 1); - toolDesc_.CmdLine = d->getArg(0); + void onCommand (const DagInit& d) { + CheckNumberOfArguments(d, 1); + toolDesc_.CmdLine = d.getArg(0); } - void onInLanguage (const DagInit* d) { - checkNumberOfArguments(d, 1); - Init* arg = d->getArg(0); + /// onInOutLanguage - Common implementation of on{In,Out}Language(). + void onInOutLanguage (const DagInit& d, StrVector& OutVec) { + CheckNumberOfArguments(d, 1); - // Find out the argument's type. - if (typeid(*arg) == typeid(StringInit)) { - // It's a string. - toolDesc_.InLanguage.push_back(InitPtrToString(arg)); + // Copy strings to the output vector. + for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) { + OutVec.push_back(InitPtrToString(d.getArg(i))); } - else { - // It's a list. - const ListInit& lst = InitPtrToList(arg); - StrVector& out = toolDesc_.InLanguage; - // Copy strings to the output vector. - for (ListInit::const_iterator B = lst.begin(), E = lst.end(); - B != E; ++B) { - out.push_back(InitPtrToString(*B)); - } + // Remove duplicates. + std::sort(OutVec.begin(), OutVec.end()); + StrVector::iterator newE = std::unique(OutVec.begin(), OutVec.end()); + OutVec.erase(newE, OutVec.end()); + } - // Remove duplicates. - std::sort(out.begin(), out.end()); - StrVector::iterator newE = std::unique(out.begin(), out.end()); - out.erase(newE, out.end()); - } + + void onInLanguage (const DagInit& d) { + this->onInOutLanguage(d, toolDesc_.InLanguage); } - void onJoin (const DagInit* d) { - checkNumberOfArguments(d, 0); + void onJoin (const DagInit& d) { + CheckNumberOfArguments(d, 0); toolDesc_.setJoin(); } - void onOutLanguage (const DagInit* d) { - checkNumberOfArguments(d, 1); - toolDesc_.OutLanguage = InitPtrToString(d->getArg(0)); + void onOutLanguage (const DagInit& d) { + this->onInOutLanguage(d, toolDesc_.OutLanguage); + } + + void onOutFileOption (const DagInit& d) { + CheckNumberOfArguments(d, 1); + toolDesc_.OutFileOption = InitPtrToString(d.getArg(0)); + } + + void onInFileOption (const DagInit& d) { + CheckNumberOfArguments(d, 1); + toolDesc_.InFileOption = InitPtrToString(d.getArg(0)); } - void onOutputSuffix (const DagInit* d) { - checkNumberOfArguments(d, 1); - toolDesc_.OutputSuffix = InitPtrToString(d->getArg(0)); + void onOutputSuffix (const DagInit& d) { + CheckNumberOfArguments(d, 1); + toolDesc_.OutputSuffix = InitPtrToString(d.getArg(0)); } - void onSink (const DagInit* d) { - checkNumberOfArguments(d, 0); + void onSink (const DagInit& d) { + CheckNumberOfArguments(d, 0); toolDesc_.setSink(); } + void onWorksOnEmpty (const DagInit& d) { + toolDesc_.OnEmpty = d.getArg(0); + } + }; /// CollectToolDescriptions - Gather information about tool properties /// from the parsed TableGen data (basically a wrapper for the /// CollectToolProperties function object). -void CollectToolDescriptions (RecordVector::const_iterator B, - RecordVector::const_iterator E, +void CollectToolDescriptions (const RecordVector& Tools, ToolDescriptions& ToolDescs) { // Iterate over a properties list of every Tool definition - for (;B!=E;++B) { + for (RecordVector::const_iterator B = Tools.begin(), + E = Tools.end(); B!=E; ++B) { const Record* T = *B; // Throws an exception if the value does not exist. ListInit* PropList = T->getValueAsListInit("properties"); @@ -735,24 +993,17 @@ void CollectToolDescriptions (RecordVector::const_iterator B, /// FillInEdgeVector - Merge all compilation graph definitions into /// one single edge list. -void FillInEdgeVector(RecordVector::const_iterator B, - RecordVector::const_iterator E, RecordVector& Out) { - for (; B != E; ++B) { - const ListInit* edges = (*B)->getValueAsListInit("edges"); - - for (unsigned i = 0; i < edges->size(); ++i) - Out.push_back(edges->getElementAsRecord(i)); - } -} - -/// CalculatePriority - Calculate the priority of this plugin. -int CalculatePriority(RecordVector::const_iterator B, - RecordVector::const_iterator E) { - int total = 0; - for (; B!=E; ++B) { - total += static_cast((*B)->getValueAsInt("priority")); +void FillInEdgeVector(const RecordVector& CompilationGraphs, + DagVector& Out) { + for (RecordVector::const_iterator B = CompilationGraphs.begin(), + E = CompilationGraphs.end(); B != E; ++B) { + const ListInit* Edges = (*B)->getValueAsListInit("edges"); + + for (ListInit::const_iterator B = Edges->begin(), + E = Edges->end(); B != E; ++B) { + Out.push_back(&InitPtrToDag(*B)); + } } - return total; } /// NotInGraph - Helper function object for FilterNotInGraph. @@ -772,18 +1023,18 @@ public: /// FilterNotInGraph - Filter out from ToolDescs all Tools not /// mentioned in the compilation graph definition. -void FilterNotInGraph (const RecordVector& EdgeVector, +void FilterNotInGraph (const DagVector& EdgeVector, ToolDescriptions& ToolDescs) { // List all tools mentioned in the graph. llvm::StringSet<> ToolsInGraph; - for (RecordVector::const_iterator B = EdgeVector.begin(), + for (DagVector::const_iterator B = EdgeVector.begin(), E = EdgeVector.end(); B != E; ++B) { - const Record* Edge = *B; - const std::string& NodeA = Edge->getValueAsString("a"); - const std::string& NodeB = Edge->getValueAsString("b"); + const DagInit* Edge = *B; + const std::string& NodeA = InitPtrToString(Edge->getArg(0)); + const std::string& NodeB = InitPtrToString(Edge->getArg(1)); if (NodeA != "root") ToolsInGraph.insert(NodeA); @@ -798,71 +1049,122 @@ void FilterNotInGraph (const RecordVector& EdgeVector, } /// FillInToolToLang - Fills in two tables that map tool names to -/// (input, output) languages. Helper function used by TypecheckGraph(). +/// input & output language names. Helper function used by TypecheckGraph(). void FillInToolToLang (const ToolDescriptions& ToolDescs, StringMap >& ToolToInLang, - StringMap& ToolToOutLang) { + StringMap >& ToolToOutLang) { for (ToolDescriptions::const_iterator B = ToolDescs.begin(), E = ToolDescs.end(); B != E; ++B) { const ToolDescription& D = *(*B); for (StrVector::const_iterator B = D.InLanguage.begin(), E = D.InLanguage.end(); B != E; ++B) ToolToInLang[D.Name].insert(*B); - ToolToOutLang[D.Name] = D.OutLanguage; + for (StrVector::const_iterator B = D.OutLanguage.begin(), + E = D.OutLanguage.end(); B != E; ++B) + ToolToOutLang[D.Name].insert(*B); } } +/// Intersect - Is set intersection non-empty? +bool Intersect (const StringSet<>& S1, const StringSet<>& S2) { + for (StringSet<>::const_iterator B = S1.begin(), E = S1.end(); B != E; ++B) { + if (S2.count(B->first()) != 0) + return true; + } + return false; +} + /// TypecheckGraph - Check that names for output and input languages -/// on all edges do match. This doesn't do much when the information -/// about the whole graph is not available (i.e. when compiling most -/// plugins). -void TypecheckGraph (const RecordVector& EdgeVector, +/// on all edges do match. +void TypecheckGraph (const DagVector& EdgeVector, const ToolDescriptions& ToolDescs) { StringMap > ToolToInLang; - StringMap ToolToOutLang; + StringMap > ToolToOutLang; FillInToolToLang(ToolDescs, ToolToInLang, ToolToOutLang); - StringMap::iterator IAE = ToolToOutLang.end(); - StringMap >::iterator IBE = ToolToInLang.end(); - for (RecordVector::const_iterator B = EdgeVector.begin(), + for (DagVector::const_iterator B = EdgeVector.begin(), E = EdgeVector.end(); B != E; ++B) { - const Record* Edge = *B; - const std::string& NodeA = Edge->getValueAsString("a"); - const std::string& NodeB = Edge->getValueAsString("b"); - StringMap::iterator IA = ToolToOutLang.find(NodeA); + const DagInit* Edge = *B; + const std::string& NodeA = InitPtrToString(Edge->getArg(0)); + const std::string& NodeB = InitPtrToString(Edge->getArg(1)); + StringMap >::iterator IA = ToolToOutLang.find(NodeA); StringMap >::iterator IB = ToolToInLang.find(NodeB); + if (NodeB == "root") + throw "Edges back to the root are not allowed!"; + if (NodeA != "root") { - if (IA != IAE && IB != IBE && IB->second.count(IA->second) == 0) + if (IA == ToolToOutLang.end()) + throw NodeA + ": no output language defined!"; + if (IB == ToolToInLang.end()) + throw NodeB + ": no input language defined!"; + + if (!Intersect(IA->second, IB->second)) { throw "Edge " + NodeA + "->" + NodeB + ": output->input language mismatch"; + } } - - if (NodeB == "root") - throw std::string("Edges back to the root are not allowed!"); } } /// WalkCase - Walks the 'case' expression DAG and invokes /// TestCallback on every test, and StatementCallback on every /// statement. Handles 'case' nesting, but not the 'and' and 'or' -/// combinators. -// TODO: Re-implement EmitCaseConstructHandler on top of this function? +/// combinators (that is, they are passed directly to TestCallback). +/// TestCallback must have type 'void TestCallback(const DagInit*, unsigned +/// IndentLevel, bool FirstTest)'. +/// StatementCallback must have type 'void StatementCallback(const Init*, +/// unsigned IndentLevel)'. template -void WalkCase(Init* Case, F1 TestCallback, F2 StatementCallback) { +void WalkCase(const Init* Case, F1 TestCallback, F2 StatementCallback, + unsigned IndentLevel = 0) +{ const DagInit& d = InitPtrToDag(Case); + + // Error checks. + if (GetOperatorName(d) != "case") + throw "WalkCase should be invoked only on 'case' expressions!"; + + if (d.getNumArgs() < 2) + throw "There should be at least one clause in the 'case' expression:\n" + + d.getAsString(); + + // Main loop. bool even = false; + const unsigned numArgs = d.getNumArgs(); + unsigned i = 1; for (DagInit::const_arg_iterator B = d.arg_begin(), E = d.arg_end(); B != E; ++B) { Init* arg = *B; - if (even && dynamic_cast(arg) - && static_cast(arg)->getOperator()->getAsString() == "case") - WalkCase(arg, TestCallback, StatementCallback); - else if (!even) - TestCallback(arg); + + if (!even) + { + // Handle test. + const DagInit& Test = InitPtrToDag(arg); + + if (GetOperatorName(Test) == "default" && (i+1 != numArgs)) + throw "The 'default' clause should be the last in the " + "'case' construct!"; + if (i == numArgs) + throw "Case construct handler: no corresponding action " + "found for the test " + Test.getAsString() + '!'; + + TestCallback(Test, IndentLevel, (i == 1)); + } else - StatementCallback(arg); + { + if (dynamic_cast(arg) + && GetOperatorName(static_cast(*arg)) == "case") { + // Nested 'case'. + WalkCase(arg, TestCallback, StatementCallback, IndentLevel + Indent1); + } + + // Handle statement. + StatementCallback(arg, IndentLevel); + } + + ++i; even = !even; } } @@ -874,16 +1176,27 @@ class ExtractOptionNames { void processDag(const Init* Statement) { const DagInit& Stmt = InitPtrToDag(Statement); - const std::string& ActionName = Stmt.getOperator()->getAsString(); + const std::string& ActionName = GetOperatorName(Stmt); if (ActionName == "forward" || ActionName == "forward_as" || - ActionName == "unpack_values" || ActionName == "switch_on" || - ActionName == "parameter_equals" || ActionName == "element_in_list" || - ActionName == "not_empty" || ActionName == "empty") { - checkNumberOfArguments(&Stmt, 1); - const std::string& Name = InitPtrToString(Stmt.getArg(0)); - OptionNames_.insert(Name); - } - else if (ActionName == "and" || ActionName == "or") { + ActionName == "forward_value" || + ActionName == "forward_transformed_value" || + ActionName == "parameter_equals" || ActionName == "element_in_list") { + CheckNumberOfArguments(Stmt, 1); + + Init* Arg = Stmt.getArg(0); + if (typeid(*Arg) == typeid(StringInit)) + OptionNames_.insert(InitPtrToString(Arg)); + } + else if (ActionName == "any_switch_on" || ActionName == "switch_on" || + ActionName == "any_not_empty" || ActionName == "any_empty" || + ActionName == "not_empty" || ActionName == "empty") { + for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) { + Init* Arg = Stmt.getArg(i); + if (typeid(*Arg) == typeid(StringInit)) + OptionNames_.insert(InitPtrToString(Arg)); + } + } + else if (ActionName == "and" || ActionName == "or" || ActionName == "not") { for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) { this->processDag(Stmt.getArg(i)); } @@ -895,6 +1208,7 @@ public: {} void operator()(const Init* Statement) { + // Statement is either a dag, or a list of dags. if (typeid(*Statement) == typeid(ListInit)) { const ListInit& DagList = *static_cast(Statement); for (ListInit::const_iterator B = DagList.begin(), E = DagList.end(); @@ -905,12 +1219,24 @@ public: this->processDag(Statement); } } + + void operator()(const DagInit& Test, unsigned, bool) { + this->operator()(&Test); + } + void operator()(const Init* Statement, unsigned) { + this->operator()(Statement); + } }; +/// IsOptionalEdge - Validate that the 'optional_edge' has proper structure. +bool IsOptionalEdge (const DagInit& Edg) { + return (GetOperatorName(Edg) == "optional_edge") && (Edg.getNumArgs() > 2); +} + /// CheckForSuperfluousOptions - Check that there are no side /// effect-free options (specified only in the OptionList). Otherwise, /// output a warning. -void CheckForSuperfluousOptions (const RecordVector& Edges, +void CheckForSuperfluousOptions (const DagVector& EdgeVector, const ToolDescriptions& ToolDescs, const OptionDescriptions& OptDescs) { llvm::StringSet<> nonSuperfluousOptions; @@ -928,13 +1254,13 @@ void CheckForSuperfluousOptions (const RecordVector& Edges, // Add all options mentioned in the 'case' clauses of the // OptionalEdges of the compilation graph to the set of // non-superfluous options. - for (RecordVector::const_iterator B = Edges.begin(), E = Edges.end(); - B != E; ++B) { - const Record* Edge = *B; - DagInit* Weight = Edge->getValueAsDag("weight"); - - if (!isDagEmpty(Weight)) - WalkCase(Weight, ExtractOptionNames(nonSuperfluousOptions), Id()); + for (DagVector::const_iterator B = EdgeVector.begin(), + E = EdgeVector.end(); B != E; ++B) { + const DagInit& Edge = **B; + if (IsOptionalEdge(Edge)) { + const DagInit& Weight = InitPtrToDag(Edge.getArg(2)); + WalkCase(&Weight, ExtractOptionNames(nonSuperfluousOptions), Id()); + } } // Check that all options in OptDescs belong to the set of @@ -949,75 +1275,159 @@ void CheckForSuperfluousOptions (const RecordVector& Edges, } } -/// EmitCaseTest1Arg - Helper function used by -/// EmitCaseConstructHandler. -bool EmitCaseTest1Arg(const std::string& TestName, - const DagInit& d, - const OptionDescriptions& OptDescs, - raw_ostream& O) { - checkNumberOfArguments(&d, 1); - const std::string& OptName = InitPtrToString(d.getArg(0)); +/// EmitCaseTest0Args - Helper function used by EmitCaseConstructHandler(). +bool EmitCaseTest0Args(const std::string& TestName, raw_ostream& O) { + if (TestName == "single_input_file") { + O << "InputFilenames.size() == 1"; + return true; + } + else if (TestName == "multiple_input_files") { + O << "InputFilenames.size() > 1"; + return true; + } + + return false; +} + +/// EmitMultipleArgumentTest - Helper function used by +/// EmitCaseTestMultipleArgs() +template +void EmitMultipleArgumentTest(const DagInit& D, const char* LogicOp, + F Callback, raw_ostream& O) +{ + for (unsigned i = 0, NumArgs = D.getNumArgs(); i < NumArgs; ++i) { + if (i != 0) + O << ' ' << LogicOp << ' '; + Callback(InitPtrToString(D.getArg(i)), O); + } +} + +// Callbacks for use with EmitMultipleArgumentTest + +class EmitSwitchOn { + const OptionDescriptions& OptDescs_; +public: + EmitSwitchOn(const OptionDescriptions& OptDescs) : OptDescs_(OptDescs) + {} - if (TestName == "switch_on") { - const OptionDescription& OptDesc = OptDescs.FindOption(OptName); - if (!OptionType::IsSwitch(OptDesc.Type)) - throw OptName + ": incorrect option type - should be a switch!"; + void operator()(const std::string& OptName, raw_ostream& O) const { + const OptionDescription& OptDesc = OptDescs_.FindSwitch(OptName); O << OptDesc.GenVariableName(); + } +}; + +class EmitEmptyTest { + bool EmitNegate_; + const OptionDescriptions& OptDescs_; +public: + EmitEmptyTest(bool EmitNegate, const OptionDescriptions& OptDescs) + : EmitNegate_(EmitNegate), OptDescs_(OptDescs) + {} + + void operator()(const std::string& OptName, raw_ostream& O) const { + const char* Neg = (EmitNegate_ ? "!" : ""); + if (OptName == "o") { + O << Neg << "OutputFilename.empty()"; + } + else if (OptName == "save-temps") { + O << Neg << "(SaveTemps == SaveTempsEnum::Unset)"; + } + else { + const OptionDescription& OptDesc = OptDescs_.FindListOrParameter(OptName); + O << Neg << OptDesc.GenVariableName() << ".empty()"; + } + } +}; + + +/// EmitCaseTestMultipleArgs - Helper function used by EmitCaseTest1Arg() +bool EmitCaseTestMultipleArgs (const std::string& TestName, + const DagInit& d, + const OptionDescriptions& OptDescs, + raw_ostream& O) { + if (TestName == "any_switch_on") { + EmitMultipleArgumentTest(d, "||", EmitSwitchOn(OptDescs), O); + return true; + } + else if (TestName == "switch_on") { + EmitMultipleArgumentTest(d, "&&", EmitSwitchOn(OptDescs), O); + return true; + } + else if (TestName == "any_not_empty") { + EmitMultipleArgumentTest(d, "||", EmitEmptyTest(true, OptDescs), O); + return true; + } + else if (TestName == "any_empty") { + EmitMultipleArgumentTest(d, "||", EmitEmptyTest(false, OptDescs), O); return true; - } else if (TestName == "input_languages_contain") { - O << "InLangs.count(\"" << OptName << "\") != 0"; + } + else if (TestName == "not_empty") { + EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(true, OptDescs), O); + return true; + } + else if (TestName == "empty") { + EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(false, OptDescs), O); + return true; + } + + return false; +} + +/// EmitCaseTest1Arg - Helper function used by EmitCaseTest1OrMoreArgs() +bool EmitCaseTest1Arg (const std::string& TestName, + const DagInit& d, + const OptionDescriptions& OptDescs, + raw_ostream& O) { + const std::string& Arg = InitPtrToString(d.getArg(0)); + + if (TestName == "input_languages_contain") { + O << "InLangs.count(\"" << Arg << "\") != 0"; return true; - } else if (TestName == "in_language") { + } + else if (TestName == "in_language") { // This works only for single-argument Tool::GenerateAction. Join // tools can process several files in different languages simultaneously. // TODO: make this work with Edge::Weight (if possible). - O << "LangMap.GetLanguage(inFile) == \"" << OptName << '\"'; + O << "LangMap.GetLanguage(inFile) == \"" << Arg << '\"'; return true; - } else if (TestName == "not_empty" || TestName == "empty") { - const char* Test = (TestName == "empty") ? "" : "!"; - - if (OptName == "o") { - O << Test << "OutputFilename.empty()"; - return true; - } - else { - const OptionDescription& OptDesc = OptDescs.FindOption(OptName); - if (OptionType::IsSwitch(OptDesc.Type)) - throw OptName - + ": incorrect option type - should be a list or parameter!"; - O << Test << OptDesc.GenVariableName() << ".empty()"; - return true; - } } return false; } -/// EmitCaseTest2Args - Helper function used by -/// EmitCaseConstructHandler. +/// EmitCaseTest1OrMoreArgs - Helper function used by +/// EmitCaseConstructHandler() +bool EmitCaseTest1OrMoreArgs(const std::string& TestName, + const DagInit& d, + const OptionDescriptions& OptDescs, + raw_ostream& O) { + CheckNumberOfArguments(d, 1); + return EmitCaseTest1Arg(TestName, d, OptDescs, O) || + EmitCaseTestMultipleArgs(TestName, d, OptDescs, O); +} + +/// EmitCaseTest2Args - Helper function used by EmitCaseConstructHandler(). bool EmitCaseTest2Args(const std::string& TestName, const DagInit& d, - const char* IndentLevel, + unsigned IndentLevel, const OptionDescriptions& OptDescs, raw_ostream& O) { - checkNumberOfArguments(&d, 2); + CheckNumberOfArguments(d, 2); const std::string& OptName = InitPtrToString(d.getArg(0)); const std::string& OptArg = InitPtrToString(d.getArg(1)); - const OptionDescription& OptDesc = OptDescs.FindOption(OptName); if (TestName == "parameter_equals") { - if (!OptionType::IsParameter(OptDesc.Type)) - throw OptName + ": incorrect option type - should be a parameter!"; + const OptionDescription& OptDesc = OptDescs.FindParameter(OptName); O << OptDesc.GenVariableName() << " == \"" << OptArg << "\""; return true; } else if (TestName == "element_in_list") { - if (!OptionType::IsList(OptDesc.Type)) - throw OptName + ": incorrect option type - should be a list!"; + const OptionDescription& OptDesc = OptDescs.FindParameterList(OptName); const std::string& VarName = OptDesc.GenVariableName(); - O << "std::find(" << VarName << ".begin(),\n" - << IndentLevel << Indent1 << VarName << ".end(), \"" + O << "std::find(" << VarName << ".begin(),\n"; + O.indent(IndentLevel + Indent1) + << VarName << ".end(), \"" << OptArg << "\") != " << VarName << ".end()"; return true; } @@ -1027,104 +1437,143 @@ bool EmitCaseTest2Args(const std::string& TestName, // Forward declaration. // EmitLogicalOperationTest and EmitCaseTest are mutually recursive. -void EmitCaseTest(const DagInit& d, const char* IndentLevel, +void EmitCaseTest(const DagInit& d, unsigned IndentLevel, const OptionDescriptions& OptDescs, raw_ostream& O); /// EmitLogicalOperationTest - Helper function used by /// EmitCaseConstructHandler. void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp, - const char* IndentLevel, + unsigned IndentLevel, const OptionDescriptions& OptDescs, raw_ostream& O) { O << '('; - for (unsigned j = 0, NumArgs = d.getNumArgs(); j < NumArgs; ++j) { - const DagInit& InnerTest = InitPtrToDag(d.getArg(j)); + for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) { + const DagInit& InnerTest = InitPtrToDag(d.getArg(i)); EmitCaseTest(InnerTest, IndentLevel, OptDescs, O); - if (j != NumArgs - 1) - O << ")\n" << IndentLevel << Indent1 << ' ' << LogicOp << " ("; - else + if (i != NumArgs - 1) { + O << ")\n"; + O.indent(IndentLevel + Indent1) << ' ' << LogicOp << " ("; + } + else { O << ')'; + } } } +void EmitLogicalNot(const DagInit& d, unsigned IndentLevel, + const OptionDescriptions& OptDescs, raw_ostream& O) +{ + CheckNumberOfArguments(d, 1); + const DagInit& InnerTest = InitPtrToDag(d.getArg(0)); + O << "! ("; + EmitCaseTest(InnerTest, IndentLevel, OptDescs, O); + O << ")"; +} + /// EmitCaseTest - Helper function used by EmitCaseConstructHandler. -void EmitCaseTest(const DagInit& d, const char* IndentLevel, +void EmitCaseTest(const DagInit& d, unsigned IndentLevel, const OptionDescriptions& OptDescs, raw_ostream& O) { - const std::string& TestName = d.getOperator()->getAsString(); + const std::string& TestName = GetOperatorName(d); if (TestName == "and") EmitLogicalOperationTest(d, "&&", IndentLevel, OptDescs, O); else if (TestName == "or") EmitLogicalOperationTest(d, "||", IndentLevel, OptDescs, O); - else if (EmitCaseTest1Arg(TestName, d, OptDescs, O)) + else if (TestName == "not") + EmitLogicalNot(d, IndentLevel, OptDescs, O); + else if (EmitCaseTest0Args(TestName, O)) + return; + else if (EmitCaseTest1OrMoreArgs(TestName, d, OptDescs, O)) return; else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O)) return; else - throw TestName + ": unknown edge property!"; + throw "Unknown test '" + TestName + "' used in the 'case' construct!"; } -// Emit code that handles the 'case' construct. -// Takes a function object that should emit code for every case clause. -// Callback's type is -// void F(Init* Statement, const char* IndentLevel, raw_ostream& O). -template -void EmitCaseConstructHandler(const Init* Dag, const char* IndentLevel, - F Callback, bool EmitElseIf, - const OptionDescriptions& OptDescs, - raw_ostream& O) { - const DagInit* d = &InitPtrToDag(Dag); - if (d->getOperator()->getAsString() != "case") - throw std::string("EmitCaseConstructHandler should be invoked" - " only on 'case' expressions!"); - unsigned numArgs = d->getNumArgs(); - if (d->getNumArgs() < 2) - throw "There should be at least one clause in the 'case' expression:\n" - + d->getAsString(); +/// EmitCaseTestCallback - Callback used by EmitCaseConstructHandler. +class EmitCaseTestCallback { + bool EmitElseIf_; + const OptionDescriptions& OptDescs_; + raw_ostream& O_; +public: - for (unsigned i = 0; i != numArgs; ++i) { - const DagInit& Test = InitPtrToDag(d->getArg(i)); + EmitCaseTestCallback(bool EmitElseIf, + const OptionDescriptions& OptDescs, raw_ostream& O) + : EmitElseIf_(EmitElseIf), OptDescs_(OptDescs), O_(O) + {} - // Emit the test. - if (Test.getOperator()->getAsString() == "default") { - if (i+2 != numArgs) - throw std::string("The 'default' clause should be the last in the" - "'case' construct!"); - O << IndentLevel << "else {\n"; + void operator()(const DagInit& Test, unsigned IndentLevel, bool FirstTest) + { + if (GetOperatorName(Test) == "default") { + O_.indent(IndentLevel) << "else {\n"; } else { - O << IndentLevel << ((i != 0 && EmitElseIf) ? "else if (" : "if ("); - EmitCaseTest(Test, IndentLevel, OptDescs, O); - O << ") {\n"; + O_.indent(IndentLevel) + << ((!FirstTest && EmitElseIf_) ? "else if (" : "if ("); + EmitCaseTest(Test, IndentLevel, OptDescs_, O_); + O_ << ") {\n"; } + } +}; - // Emit the corresponding statement. - ++i; - if (i == numArgs) - throw "Case construct handler: no corresponding action " - "found for the test " + Test.getAsString() + '!'; +/// EmitCaseStatementCallback - Callback used by EmitCaseConstructHandler. +template +class EmitCaseStatementCallback { + F Callback_; + raw_ostream& O_; +public: - Init* arg = d->getArg(i); - const DagInit* nd = dynamic_cast(arg); - if (nd && (nd->getOperator()->getAsString() == "case")) { - // Handle the nested 'case'. - EmitCaseConstructHandler(nd, (std::string(IndentLevel) + Indent1).c_str(), - Callback, EmitElseIf, OptDescs, O); - } - else { - Callback(arg, (std::string(IndentLevel) + Indent1).c_str(), O); + EmitCaseStatementCallback(F Callback, raw_ostream& O) + : Callback_(Callback), O_(O) + {} + + void operator() (const Init* Statement, unsigned IndentLevel) { + // Is this a nested 'case'? + bool IsCase = dynamic_cast(Statement) && + GetOperatorName(static_cast(*Statement)) == "case"; + + // If so, ignore it, it is handled by our caller, WalkCase. + if (!IsCase) { + if (typeid(*Statement) == typeid(ListInit)) { + const ListInit& DagList = *static_cast(Statement); + for (ListInit::const_iterator B = DagList.begin(), E = DagList.end(); + B != E; ++B) + Callback_(*B, (IndentLevel + Indent1), O_); + } + else { + Callback_(Statement, (IndentLevel + Indent1), O_); + } } - O << IndentLevel << "}\n"; + O_.indent(IndentLevel) << "}\n"; } + +}; + +/// EmitCaseConstructHandler - Emit code that handles the 'case' +/// construct. Takes a function object that should emit code for every case +/// clause. Implemented on top of WalkCase. +/// Callback's type is void F(const Init* Statement, unsigned IndentLevel, +/// raw_ostream& O). +/// EmitElseIf parameter controls the type of condition that is emitted ('if +/// (..) {..} else if (..) {} .. else {..}' vs. 'if (..) {..} if(..) {..} +/// .. else {..}'). +template +void EmitCaseConstructHandler(const Init* Case, unsigned IndentLevel, + F Callback, bool EmitElseIf, + const OptionDescriptions& OptDescs, + raw_ostream& O) { + WalkCase(Case, EmitCaseTestCallback(EmitElseIf, OptDescs, O), + EmitCaseStatementCallback(Callback, O), IndentLevel); } -/// TokenizeCmdline - converts from "$CALL(HookName, 'Arg1', 'Arg2')/path" to -/// ["$CALL(", "HookName", "Arg1", "Arg2", ")/path"] . -/// Helper function used by EmitCmdLineVecFill and. -void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) { +/// TokenizeCmdLine - converts from +/// "$CALL(HookName, 'Arg1', 'Arg2')/path -arg1 -arg2" to +/// ["$CALL(", "HookName", "Arg1", "Arg2", ")/path", "-arg1", "-arg2"]. +void TokenizeCmdLine(const std::string& CmdLine, StrVector& Out) { const char* Delimiters = " \t\n\v\f\r"; enum TokenizerState { Normal, SpecialCommand, InsideSpecialCommand, InsideQuotationMarks } @@ -1146,7 +1595,7 @@ void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) { cur_st = SpecialCommand; break; } - if (oneOf(Delimiters, cur_ch)) { + if (OneOf(Delimiters, cur_ch)) { // Skip whitespace B = CmdLine.find_first_not_of(Delimiters, B); if (B == std::string::npos) { @@ -1161,7 +1610,7 @@ void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) { case SpecialCommand: - if (oneOf(Delimiters, cur_ch)) { + if (OneOf(Delimiters, cur_ch)) { cur_st = Normal; Out.push_back(""); continue; @@ -1174,7 +1623,7 @@ void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) { break; case InsideSpecialCommand: - if (oneOf(Delimiters, cur_ch)) { + if (OneOf(Delimiters, cur_ch)) { continue; } if (cur_ch == '\'') { @@ -1204,62 +1653,99 @@ void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) { } } -/// SubstituteSpecialCommands - Perform string substitution for $CALL -/// and $ENV. Helper function used by EmitCmdLineVecFill(). -StrVector::const_iterator SubstituteSpecialCommands -(StrVector::const_iterator Pos, StrVector::const_iterator End, raw_ostream& O) +/// SubstituteCall - Given "$CALL(HookName, [Arg1 [, Arg2 [...]]])", output +/// "hooks::HookName([Arg1 [, Arg2 [, ...]]])". Helper function used by +/// SubstituteSpecialCommands(). +StrVector::const_iterator +SubstituteCall (StrVector::const_iterator Pos, + StrVector::const_iterator End, + bool IsJoin, raw_ostream& O) { + const char* errorMessage = "Syntax error in $CALL invocation!"; + CheckedIncrement(Pos, End, errorMessage); + const std::string& CmdName = *Pos; - const std::string& cmd = *Pos; - - if (cmd == "$CALL") { - checkedIncrement(Pos, End, "Syntax error in $CALL invocation!"); - const std::string& CmdName = *Pos; + if (CmdName == ")") + throw "$CALL invocation: empty argument list!"; - if (CmdName == ")") - throw std::string("$CALL invocation: empty argument list!"); + O << "hooks::"; + O << CmdName << "("; - O << "hooks::"; - O << CmdName << "("; + bool firstIteration = true; + while (true) { + CheckedIncrement(Pos, End, errorMessage); + const std::string& Arg = *Pos; + assert(Arg.size() != 0); - bool firstIteration = true; - while (true) { - checkedIncrement(Pos, End, "Syntax error in $CALL invocation!"); - const std::string& Arg = *Pos; - assert(Arg.size() != 0); + if (Arg[0] == ')') + break; - if (Arg[0] == ')') - break; + if (firstIteration) + firstIteration = false; + else + O << ", "; - if (firstIteration) - firstIteration = false; + if (Arg == "$INFILE") { + if (IsJoin) + throw "$CALL(Hook, $INFILE) can't be used with a Join tool!"; else - O << ", "; - + O << "inFile.c_str()"; + } + else { O << '"' << Arg << '"'; } + } - O << ')'; + O << ')'; - } - else if (cmd == "$ENV") { - checkedIncrement(Pos, End, "Syntax error in $ENV invocation!"); - const std::string& EnvName = *Pos; + return Pos; +} + +/// SubstituteEnv - Given '$ENV(VAR_NAME)', output 'getenv("VAR_NAME")'. Helper +/// function used by SubstituteSpecialCommands(). +StrVector::const_iterator +SubstituteEnv (StrVector::const_iterator Pos, + StrVector::const_iterator End, raw_ostream& O) +{ + const char* errorMessage = "Syntax error in $ENV invocation!"; + CheckedIncrement(Pos, End, errorMessage); + const std::string& EnvName = *Pos; + + if (EnvName == ")") + throw "$ENV invocation: empty argument list!"; + + O << "checkCString(std::getenv(\""; + O << EnvName; + O << "\"))"; + + CheckedIncrement(Pos, End, errorMessage); + + return Pos; +} - if (EnvName == ")") - throw "$ENV invocation: empty argument list!"; +/// SubstituteSpecialCommands - Given an invocation of $CALL or $ENV, output +/// handler code. Helper function used by EmitCmdLineVecFill(). +StrVector::const_iterator +SubstituteSpecialCommands (StrVector::const_iterator Pos, + StrVector::const_iterator End, + bool IsJoin, raw_ostream& O) +{ - O << "checkCString(std::getenv(\""; - O << EnvName; - O << "\"))"; + const std::string& cmd = *Pos; - checkedIncrement(Pos, End, "Syntax error in $ENV invocation!"); + // Perform substitution. + if (cmd == "$CALL") { + Pos = SubstituteCall(Pos, End, IsJoin, O); + } + else if (cmd == "$ENV") { + Pos = SubstituteEnv(Pos, End, O); } else { throw "Unknown special command: " + cmd; } + // Handle '$CMD(ARG)/additional/text'. const std::string& Leftover = *Pos; assert(Leftover.at(0) == ')'); if (Leftover.size() != 1) @@ -1271,287 +1757,454 @@ StrVector::const_iterator SubstituteSpecialCommands /// EmitCmdLineVecFill - Emit code that fills in the command line /// vector. Helper function used by EmitGenerateActionMethod(). void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName, - bool IsJoin, const char* IndentLevel, + bool IsJoin, unsigned IndentLevel, raw_ostream& O) { StrVector StrVec; - TokenizeCmdline(InitPtrToString(CmdLine), StrVec); + TokenizeCmdLine(InitPtrToString(CmdLine), StrVec); if (StrVec.empty()) throw "Tool '" + ToolName + "' has empty command line!"; - StrVector::const_iterator I = StrVec.begin(), E = StrVec.end(); + StrVector::const_iterator B = StrVec.begin(), E = StrVec.end(); - // If there is a hook invocation on the place of the first command, skip it. + // Emit the command itself. assert(!StrVec[0].empty()); + O.indent(IndentLevel) << "cmd = "; if (StrVec[0][0] == '$') { - while (I != E && (*I)[0] != ')' ) - ++I; - - // Skip the ')' symbol. - ++I; + B = SubstituteSpecialCommands(B, E, IsJoin, O); + ++B; } else { - ++I; + O << '"' << StrVec[0] << '"'; + ++B; } + O << ";\n"; + + // Go through the command arguments. + assert(B <= E); + for (; B != E; ++B) { + const std::string& cmd = *B; - for (; I != E; ++I) { - const std::string& cmd = *I; assert(!cmd.empty()); - O << IndentLevel; + O.indent(IndentLevel); + if (cmd.at(0) == '$') { - if (cmd == "$INFILE") { - if (IsJoin) - O << "for (PathVector::const_iterator B = inFiles.begin()" - << ", E = inFiles.end();\n" - << IndentLevel << "B != E; ++B)\n" - << IndentLevel << Indent1 << "vec.push_back(B->toString());\n"; - else - O << "vec.push_back(inFile.toString());\n"; - } - else if (cmd == "$OUTFILE") { - O << "vec.push_back(out_file);\n"; - } - else { - O << "vec.push_back("; - I = SubstituteSpecialCommands(I, E, O); - O << ");\n"; - } + O << "vec.push_back(std::make_pair(0, "; + B = SubstituteSpecialCommands(B, E, IsJoin, O); + O << "));\n"; } else { - O << "vec.push_back(\"" << cmd << "\");\n"; + O << "vec.push_back(std::make_pair(0, \"" << cmd << "\"));\n"; } } - O << IndentLevel << "cmd = "; - if (StrVec[0][0] == '$') - SubstituteSpecialCommands(StrVec.begin(), StrVec.end(), O); - else - O << '"' << StrVec[0] << '"'; - O << ";\n"; } -/// EmitCmdLineVecFillCallback - A function object wrapper around -/// EmitCmdLineVecFill(). Used by EmitGenerateActionMethod() as an -/// argument to EmitCaseConstructHandler(). -class EmitCmdLineVecFillCallback { - bool IsJoin; - const std::string& ToolName; - public: - EmitCmdLineVecFillCallback(bool J, const std::string& TN) - : IsJoin(J), ToolName(TN) {} +/// EmitForEachListElementCycleHeader - Emit common code for iterating through +/// all elements of a list. Helper function used by +/// EmitForwardOptionPropertyHandlingCode. +void EmitForEachListElementCycleHeader (const OptionDescription& D, + unsigned IndentLevel, + raw_ostream& O) { + unsigned IndentLevel1 = IndentLevel + Indent1; - void operator()(const Init* Statement, const char* IndentLevel, - raw_ostream& O) const - { - EmitCmdLineVecFill(Statement, ToolName, IsJoin, - IndentLevel, O); - } -}; + O.indent(IndentLevel) + << "for (" << D.GenTypeDeclaration() + << "::iterator B = " << D.GenVariableName() << ".begin(),\n"; + O.indent(IndentLevel) + << "E = " << D.GenVariableName() << ".end(); B != E;) {\n"; + O.indent(IndentLevel1) << "unsigned pos = " << D.GenVariableName() + << ".getPosition(B - " << D.GenVariableName() + << ".begin());\n"; +} /// EmitForwardOptionPropertyHandlingCode - Helper function used to /// implement EmitActionHandler. Emits code for /// handling the (forward) and (forward_as) option properties. void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D, - const char* Indent, + unsigned IndentLevel, const std::string& NewName, raw_ostream& O) { const std::string& Name = NewName.empty() ? ("-" + D.Name) : NewName; + unsigned IndentLevel1 = IndentLevel + Indent1; switch (D.Type) { case OptionType::Switch: - O << Indent << "vec.push_back(\"" << Name << "\");\n"; + O.indent(IndentLevel) + << "vec.push_back(std::make_pair(" << D.GenVariableName() + << ".getPosition(), \"" << Name << "\"));\n"; break; case OptionType::Parameter: - O << Indent << "vec.push_back(\"" << Name << "\");\n"; - O << Indent << "vec.push_back(" << D.GenVariableName() << ");\n"; + O.indent(IndentLevel) << "vec.push_back(std::make_pair(" + << D.GenVariableName() + <<".getPosition(), \"" << Name; + + if (!D.isForwardNotSplit()) { + O << "\"));\n"; + O.indent(IndentLevel) << "vec.push_back(std::make_pair(" + << D.GenVariableName() << ".getPosition(), " + << D.GenVariableName() << "));\n"; + } + else { + O << "=\" + " << D.GenVariableName() << "));\n"; + } break; case OptionType::Prefix: - O << Indent << "vec.push_back(\"" << Name << "\" + " - << D.GenVariableName() << ");\n"; + O.indent(IndentLevel) << "vec.push_back(std::make_pair(" + << D.GenVariableName() << ".getPosition(), \"" + << Name << "\" + " + << D.GenVariableName() << "));\n"; break; case OptionType::PrefixList: - O << Indent << "for (" << D.GenTypeDeclaration() - << "::iterator B = " << D.GenVariableName() << ".begin(),\n" - << Indent << "E = " << D.GenVariableName() << ".end(); B != E;) {\n" - << Indent << Indent1 << "vec.push_back(\"" << Name << "\" + " - << "*B);\n" - << Indent << Indent1 << "++B;\n"; + EmitForEachListElementCycleHeader(D, IndentLevel, O); + O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, \"" + << Name << "\" + " << "*B));\n"; + O.indent(IndentLevel1) << "++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(IndentLevel1) << "vec.push_back(std::make_pair(pos, *B));\n"; + O.indent(IndentLevel1) << "++B;\n"; } - O << Indent << "}\n"; + O.indent(IndentLevel) << "}\n"; break; case OptionType::ParameterList: - O << Indent << "for (" << D.GenTypeDeclaration() - << "::iterator B = " << D.GenVariableName() << ".begin(),\n" - << Indent << "E = " << D.GenVariableName() - << ".end() ; B != E;) {\n" - << Indent << Indent1 << "vec.push_back(\"" << Name << "\");\n"; + EmitForEachListElementCycleHeader(D, IndentLevel, O); + O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, \"" + << Name << "\"));\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(IndentLevel1) << "vec.push_back(std::make_pair(pos, *B));\n"; + O.indent(IndentLevel1) << "++B;\n"; } - O << Indent << "}\n"; + O.indent(IndentLevel) << "}\n"; + break; + case OptionType::SwitchList: + EmitForEachListElementCycleHeader(D, IndentLevel, O); + O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, \"" + << Name << "\"));\n"; + O.indent(IndentLevel1) << "++B;\n"; + O.indent(IndentLevel) << "}\n"; break; case OptionType::Alias: default: - throw std::string("Aliases are not allowed in tool option descriptions!"); + throw "Aliases are not allowed in tool option descriptions!"; } } -/// EmitActionHandler - Emit code that handles actions. Used by -/// EmitGenerateActionMethod() as an argument to -/// EmitCaseConstructHandler(). -class EmitActionHandler { +/// ActionHandlingCallbackBase - Base class of EmitActionHandlersCallback and +/// EmitPreprocessOptionsCallback. +struct ActionHandlingCallbackBase +{ + + void onErrorDag(const DagInit& d, + unsigned IndentLevel, raw_ostream& O) const + { + O.indent(IndentLevel) + << "PrintError(\"" + << (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0)) : "Unknown error!") + << "\");\n"; + O.indent(IndentLevel) << "return 1;\n"; + } + + void onWarningDag(const DagInit& d, + unsigned IndentLevel, raw_ostream& O) const + { + CheckNumberOfArguments(d, 1); + O.indent(IndentLevel) << "llvm::errs() << \"" + << InitPtrToString(d.getArg(0)) << "\";\n"; + } + +}; + +/// EmitActionHandlersCallback - Emit code that handles actions. Used by +/// EmitGenerateActionMethod() as an argument to EmitCaseConstructHandler(). +class EmitActionHandlersCallback; + +typedef void (EmitActionHandlersCallback::* EmitActionHandlersCallbackHandler) +(const DagInit&, unsigned, raw_ostream&) const; + +class EmitActionHandlersCallback : + public ActionHandlingCallbackBase, + public HandlerTable +{ + typedef EmitActionHandlersCallbackHandler Handler; + const OptionDescriptions& OptDescs; - void processActionDag(const Init* Statement, const char* IndentLevel, - raw_ostream& O) const + /// EmitHookInvocation - Common code for hook invocation from actions. Used by + /// onAppendCmd and onOutputSuffix. + void EmitHookInvocation(const std::string& Str, + const char* BlockOpen, const char* BlockClose, + unsigned IndentLevel, raw_ostream& O) const { - const DagInit& Dag = InitPtrToDag(Statement); - const std::string& ActionName = Dag.getOperator()->getAsString(); + StrVector Out; + TokenizeCmdLine(Str, Out); - if (ActionName == "append_cmd") { - checkNumberOfArguments(&Dag, 1); - const std::string& Cmd = InitPtrToString(Dag.getArg(0)); - StrVector Out; - llvm::SplitString(Cmd, Out); + for (StrVector::const_iterator B = Out.begin(), E = Out.end(); + B != E; ++B) { + const std::string& cmd = *B; - for (StrVector::const_iterator B = Out.begin(), E = Out.end(); - B != E; ++B) - O << IndentLevel << "vec.push_back(\"" << *B << "\");\n"; - } - else if (ActionName == "error") { - O << IndentLevel << "throw std::runtime_error(\"" << - (Dag.getNumArgs() >= 1 ? InitPtrToString(Dag.getArg(0)) - : "Unknown error!") - << "\");\n"; - } - else if (ActionName == "forward") { - checkNumberOfArguments(&Dag, 1); - const std::string& Name = InitPtrToString(Dag.getArg(0)); - EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name), - IndentLevel, "", O); - } - else if (ActionName == "forward_as") { - checkNumberOfArguments(&Dag, 2); - const std::string& Name = InitPtrToString(Dag.getArg(0)); - const std::string& NewName = InitPtrToString(Dag.getArg(1)); - EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name), - IndentLevel, NewName, O); - } - else if (ActionName == "output_suffix") { - checkNumberOfArguments(&Dag, 1); - const std::string& OutSuf = InitPtrToString(Dag.getArg(0)); - O << IndentLevel << "output_suffix = \"" << OutSuf << "\";\n"; - } - else if (ActionName == "stop_compilation") { - O << IndentLevel << "stop_compilation = true;\n"; - } - else if (ActionName == "unpack_values") { - checkNumberOfArguments(&Dag, 1); - const std::string& Name = InitPtrToString(Dag.getArg(0)); - 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)) { - O << IndentLevel << "for (" << D.GenTypeDeclaration() - << "::iterator B = " << D.GenVariableName() << ".begin(),\n" - << IndentLevel << "E = " << D.GenVariableName() - << ".end(); B != E; ++B)\n" - << IndentLevel << Indent1 << "llvm::SplitString(*B, vec, \",\");\n"; - } - else if (OptionType::IsParameter(D.Type)){ - O << Indent3 << "llvm::SplitString(" - << D.GenVariableName() << ", vec, \",\");\n"; - } - else { - throw "Option '" + D.Name + - "': switches can't have the 'unpack_values' property!"; - } + O.indent(IndentLevel) << BlockOpen; + + if (cmd.at(0) == '$') + B = SubstituteSpecialCommands(B, E, /* IsJoin = */ true, O); + else + O << '"' << cmd << '"'; + + O << BlockClose; + } + } + + void onAppendCmd (const DagInit& Dag, + unsigned IndentLevel, raw_ostream& O) const + { + CheckNumberOfArguments(Dag, 1); + this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)), + "vec.push_back(std::make_pair(65536, ", "));\n", + IndentLevel, O); + } + + void onForward (const DagInit& Dag, + unsigned IndentLevel, raw_ostream& O) const + { + CheckNumberOfArguments(Dag, 1); + const std::string& Name = InitPtrToString(Dag.getArg(0)); + EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name), + IndentLevel, "", O); + } + + void onForwardAs (const DagInit& Dag, + unsigned IndentLevel, raw_ostream& O) const + { + CheckNumberOfArguments(Dag, 2); + const std::string& Name = InitPtrToString(Dag.getArg(0)); + const std::string& NewName = InitPtrToString(Dag.getArg(1)); + EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name), + IndentLevel, NewName, O); + } + + void onForwardValue (const DagInit& Dag, + unsigned IndentLevel, raw_ostream& O) const + { + CheckNumberOfArguments(Dag, 1); + const std::string& Name = InitPtrToString(Dag.getArg(0)); + const OptionDescription& D = OptDescs.FindParameterListOrParameter(Name); + + if (D.isSwitchList()) { + throw std::runtime_error + ("forward_value is not allowed with switch_list"); + } + + if (D.isParameter()) { + O.indent(IndentLevel) << "vec.push_back(std::make_pair(" + << D.GenVariableName() << ".getPosition(), " + << D.GenVariableName() << "));\n"; } else { - throw "Unknown action name: " + ActionName + "!"; + O.indent(IndentLevel) << "for (" << D.GenTypeDeclaration() + << "::iterator B = " << D.GenVariableName() + << ".begin(), \n"; + O.indent(IndentLevel + Indent1) << " E = " << D.GenVariableName() + << ".end(); B != E; ++B)\n"; + O.indent(IndentLevel) << "{\n"; + O.indent(IndentLevel + Indent1) + << "unsigned pos = " << D.GenVariableName() + << ".getPosition(B - " << D.GenVariableName() + << ".begin());\n"; + O.indent(IndentLevel + Indent1) + << "vec.push_back(std::make_pair(pos, *B));\n"; + O.indent(IndentLevel) << "}\n"; } } + + void onForwardTransformedValue (const DagInit& Dag, + unsigned IndentLevel, raw_ostream& O) const + { + CheckNumberOfArguments(Dag, 2); + const std::string& Name = InitPtrToString(Dag.getArg(0)); + const std::string& Hook = InitPtrToString(Dag.getArg(1)); + const OptionDescription& D = OptDescs.FindParameterListOrParameter(Name); + + O.indent(IndentLevel) << "vec.push_back(std::make_pair(" + << D.GenVariableName() << ".getPosition(" + << (D.isList() ? "0" : "") << "), " + << "hooks::" << Hook << "(" << D.GenVariableName() + << (D.isParameter() ? ".c_str()" : "") << ")));\n"; + } + + void onNoOutFile (const DagInit& Dag, + unsigned IndentLevel, raw_ostream& O) const + { + CheckNumberOfArguments(Dag, 0); + O.indent(IndentLevel) << "no_out_file = true;\n"; + } + + void onOutputSuffix (const DagInit& Dag, + unsigned IndentLevel, raw_ostream& O) const + { + CheckNumberOfArguments(Dag, 1); + this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)), + "output_suffix = ", ";\n", IndentLevel, O); + } + + void onStopCompilation (const DagInit& Dag, + unsigned IndentLevel, raw_ostream& O) const + { + O.indent(IndentLevel) << "stop_compilation = true;\n"; + } + + + void onUnpackValues (const DagInit& Dag, + unsigned IndentLevel, raw_ostream& O) const + { + throw "'unpack_values' is deprecated. " + "Use 'comma_separated' + 'forward_value' instead!"; + } + public: - EmitActionHandler(const OptionDescriptions& OD) - : OptDescs(OD) {} - void operator()(const Init* Statement, const char* IndentLevel, - raw_ostream& O) const + explicit EmitActionHandlersCallback(const OptionDescriptions& OD) + : OptDescs(OD) { - if (typeid(*Statement) == typeid(ListInit)) { - const ListInit& DagList = *static_cast(Statement); - for (ListInit::const_iterator B = DagList.begin(), E = DagList.end(); - B != E; ++B) - this->processActionDag(*B, IndentLevel, O); - } - else { - this->processActionDag(Statement, IndentLevel, O); + if (!staticMembersInitialized_) { + AddHandler("error", &EmitActionHandlersCallback::onErrorDag); + AddHandler("warning", &EmitActionHandlersCallback::onWarningDag); + AddHandler("append_cmd", &EmitActionHandlersCallback::onAppendCmd); + AddHandler("forward", &EmitActionHandlersCallback::onForward); + AddHandler("forward_as", &EmitActionHandlersCallback::onForwardAs); + AddHandler("forward_value", &EmitActionHandlersCallback::onForwardValue); + AddHandler("forward_transformed_value", + &EmitActionHandlersCallback::onForwardTransformedValue); + AddHandler("no_out_file", + &EmitActionHandlersCallback::onNoOutFile); + AddHandler("output_suffix", &EmitActionHandlersCallback::onOutputSuffix); + AddHandler("stop_compilation", + &EmitActionHandlersCallback::onStopCompilation); + AddHandler("unpack_values", + &EmitActionHandlersCallback::onUnpackValues); + + + staticMembersInitialized_ = true; } } + + void operator()(const Init* I, + unsigned IndentLevel, raw_ostream& O) const + { + InvokeDagInitHandler(this, I, IndentLevel, O); + } }; -// EmitGenerateActionMethod - Emit one of two versions of the +void EmitGenerateActionMethodHeader(const ToolDescription& D, + bool IsJoin, bool Naked, + raw_ostream& O) +{ + O.indent(Indent1) << "int GenerateAction(Action& Out,\n"; + + if (IsJoin) + O.indent(Indent2) << "const PathVector& inFiles,\n"; + else + O.indent(Indent2) << "const sys::Path& inFile,\n"; + + O.indent(Indent2) << "const bool HasChildren,\n"; + O.indent(Indent2) << "const llvm::sys::Path& TempDir,\n"; + O.indent(Indent2) << "const InputLanguagesSet& InLangs,\n"; + O.indent(Indent2) << "const LanguageMap& LangMap) const\n"; + O.indent(Indent1) << "{\n"; + + if (!Naked) { + O.indent(Indent2) << "std::string cmd;\n"; + O.indent(Indent2) << "std::string out_file;\n"; + O.indent(Indent2) + << "std::vector > vec;\n"; + O.indent(Indent2) << "bool stop_compilation = !HasChildren;\n"; + O.indent(Indent2) << "bool no_out_file = false;\n"; + O.indent(Indent2) << "std::string output_suffix(\"" + << D.OutputSuffix << "\");\n"; + } +} + +// EmitGenerateActionMethod - Emit either a normal or a "join" version of the // Tool::GenerateAction() method. void EmitGenerateActionMethod (const ToolDescription& D, const OptionDescriptions& OptDescs, bool IsJoin, raw_ostream& O) { - if (IsJoin) - O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n"; - else - O << Indent1 << "Action GenerateAction(const sys::Path& inFile,\n"; - - O << Indent2 << "bool HasChildren,\n" - << Indent2 << "const llvm::sys::Path& TempDir,\n" - << Indent2 << "const InputLanguagesSet& InLangs,\n" - << Indent2 << "const LanguageMap& LangMap) const\n" - << Indent1 << "{\n" - << Indent2 << "std::string cmd;\n" - << Indent2 << "std::vector vec;\n" - << Indent2 << "bool stop_compilation = !HasChildren;\n" - << Indent2 << "const char* output_suffix = \"" << D.OutputSuffix << "\";\n" - << Indent2 << "std::string out_file;\n\n"; - - // For every understood option, emit handling code. - if (D.Actions) - EmitCaseConstructHandler(D.Actions, Indent2, EmitActionHandler(OptDescs), - false, OptDescs, O); - O << '\n' << Indent2 - << "out_file = OutFilename(" << (IsJoin ? "sys::Path(),\n" : "inFile,\n") - << Indent3 << "TempDir, stop_compilation, output_suffix).toString();\n\n"; + EmitGenerateActionMethodHeader(D, IsJoin, /* Naked = */ false, O); - // cmd_line is either a string or a 'case' construct. if (!D.CmdLine) throw "Tool " + D.Name + " has no cmd_line property!"; - else if (typeid(*D.CmdLine) == typeid(StringInit)) - EmitCmdLineVecFill(D.CmdLine, D.Name, IsJoin, Indent2, O); - else - EmitCaseConstructHandler(D.CmdLine, Indent2, - EmitCmdLineVecFillCallback(IsJoin, D.Name), - true, OptDescs, O); + + // Process the 'command' property. + O << '\n'; + EmitCmdLineVecFill(D.CmdLine, D.Name, IsJoin, Indent2, O); + O << '\n'; + + // Process the 'actions' list of this tool. + if (D.Actions) + EmitCaseConstructHandler(D.Actions, Indent2, + EmitActionHandlersCallback(OptDescs), + false, OptDescs, O); + O << '\n'; + + // Input file (s) + if (!D.InFileOption.empty()) { + O.indent(Indent2) + << "vec.push_back(std::make_pair(InputFilenames.getPosition(0), \"" + << D.InFileOption << "\");\n"; + } + + if (IsJoin) { + O.indent(Indent2) + << "for (PathVector::const_iterator B = inFiles.begin(),\n"; + O.indent(Indent3) << "E = inFiles.end(); B != E; ++B)\n"; + O.indent(Indent2) << "{\n"; + O.indent(Indent3) << "vec.push_back(std::make_pair(" + << "InputFilenames.getPosition(B - inFiles.begin()), " + << "B->str()));\n"; + O.indent(Indent2) << "}\n"; + } + else { + O.indent(Indent2) << "vec.push_back(std::make_pair(" + << "InputFilenames.getPosition(0), inFile.str()));\n"; + } + + // Output file + O.indent(Indent2) << "if (!no_out_file) {\n"; + if (!D.OutFileOption.empty()) + O.indent(Indent3) << "vec.push_back(std::make_pair(65536, \"" + << D.OutFileOption << "\"));\n"; + + O.indent(Indent3) << "out_file = this->OutFilename(" + << (IsJoin ? "sys::Path(),\n" : "inFile,\n"); + O.indent(Indent4) << + "TempDir, stop_compilation, output_suffix.c_str()).str();\n\n"; + O.indent(Indent3) << "vec.push_back(std::make_pair(65536, out_file));\n"; + + O.indent(Indent2) << "}\n\n"; // Handle the Sink property. + std::string SinkOption("autogenerated::"); + SinkOption += SinkOptionName; if (D.isSink()) { - O << Indent2 << "if (!" << SinkOptionName << ".empty()) {\n" - << Indent3 << "vec.insert(vec.end(), " - << SinkOptionName << ".begin(), " << SinkOptionName << ".end());\n" - << Indent2 << "}\n"; + O.indent(Indent2) << "if (!" << SinkOption << ".empty()) {\n"; + O.indent(Indent3) << "for (cl::list::iterator B = " + << SinkOption << ".begin(), E = " << SinkOption + << ".end(); B != E; ++B)\n"; + O.indent(Indent4) << "vec.push_back(std::make_pair(" << SinkOption + << ".getPosition(B - " << SinkOption + << ".begin()), *B));\n"; + O.indent(Indent2) << "}\n"; } - O << Indent2 << "return Action(cmd, vec, stop_compilation, out_file);\n" - << Indent1 << "}\n\n"; + O.indent(Indent2) << "Out.Construct(cmd, this->SortArgs(vec), " + << "stop_compilation, out_file);\n"; + O.indent(Indent2) << "return 0;\n"; + O.indent(Indent1) << "}\n\n"; } /// EmitGenerateActionMethods - Emit two GenerateAction() methods for @@ -1559,18 +2212,17 @@ void EmitGenerateActionMethod (const ToolDescription& D, void EmitGenerateActionMethods (const ToolDescription& ToolDesc, const OptionDescriptions& OptDescs, raw_ostream& O) { - if (!ToolDesc.isJoin()) - O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n" - << Indent2 << "bool HasChildren,\n" - << Indent2 << "const llvm::sys::Path& TempDir,\n" - << Indent2 << "const InputLanguagesSet& InLangs,\n" - << Indent2 << "const LanguageMap& LangMap) const\n" - << Indent1 << "{\n" - << Indent2 << "throw std::runtime_error(\"" << ToolDesc.Name - << " is not a Join tool!\");\n" - << Indent1 << "}\n\n"; - else + if (!ToolDesc.isJoin()) { + EmitGenerateActionMethodHeader(ToolDesc, /* IsJoin = */ true, + /* Naked = */ true, O); + O.indent(Indent2) << "PrintError(\"" << ToolDesc.Name + << " is not a Join tool!\");\n"; + O.indent(Indent2) << "return -1;\n"; + O.indent(Indent1) << "}\n\n"; + } + else { EmitGenerateActionMethod(ToolDesc, OptDescs, true, O); + } EmitGenerateActionMethod(ToolDesc, OptDescs, false, O); } @@ -1578,34 +2230,65 @@ void EmitGenerateActionMethods (const ToolDescription& ToolDesc, /// EmitInOutLanguageMethods - Emit the [Input,Output]Language() /// methods for a given Tool class. void EmitInOutLanguageMethods (const ToolDescription& D, raw_ostream& O) { - O << Indent1 << "const char** InputLanguages() const {\n" - << Indent2 << "return InputLanguages_;\n" - << Indent1 << "}\n\n"; - - if (D.OutLanguage.empty()) - throw "Tool " + D.Name + " has no 'out_language' property!"; + O.indent(Indent1) << "const char** InputLanguages() const {\n"; + O.indent(Indent2) << "return InputLanguages_;\n"; + O.indent(Indent1) << "}\n\n"; - O << Indent1 << "const char* OutputLanguage() const {\n" - << Indent2 << "return \"" << D.OutLanguage << "\";\n" - << Indent1 << "}\n\n"; + O.indent(Indent1) << "const char** OutputLanguages() const {\n"; + O.indent(Indent2) << "return OutputLanguages_;\n"; + O.indent(Indent1) << "}\n\n"; } /// EmitNameMethod - Emit the Name() method for a given Tool class. void EmitNameMethod (const ToolDescription& D, raw_ostream& O) { - O << Indent1 << "const char* Name() const {\n" - << Indent2 << "return \"" << D.Name << "\";\n" - << Indent1 << "}\n\n"; + O.indent(Indent1) << "const char* Name() const {\n"; + O.indent(Indent2) << "return \"" << D.Name << "\";\n"; + O.indent(Indent1) << "}\n\n"; } /// EmitIsJoinMethod - Emit the IsJoin() method for a given Tool /// class. void EmitIsJoinMethod (const ToolDescription& D, raw_ostream& O) { - O << Indent1 << "bool IsJoin() const {\n"; + O.indent(Indent1) << "bool IsJoin() const {\n"; if (D.isJoin()) - O << Indent2 << "return true;\n"; + O.indent(Indent2) << "return true;\n"; + else + O.indent(Indent2) << "return false;\n"; + O.indent(Indent1) << "}\n\n"; +} + +/// EmitWorksOnEmptyCallback - Callback used by EmitWorksOnEmptyMethod in +/// conjunction with EmitCaseConstructHandler. +void EmitWorksOnEmptyCallback (const Init* Value, + unsigned IndentLevel, raw_ostream& O) { + CheckBooleanConstant(Value); + O.indent(IndentLevel) << "return " << Value->getAsString() << ";\n"; +} + +/// EmitWorksOnEmptyMethod - Emit the WorksOnEmpty() method for a given Tool +/// class. +void EmitWorksOnEmptyMethod (const ToolDescription& D, + const OptionDescriptions& OptDescs, + raw_ostream& O) +{ + O.indent(Indent1) << "bool WorksOnEmpty() const {\n"; + if (D.OnEmpty == 0) + O.indent(Indent2) << "return false;\n"; else - O << Indent2 << "return false;\n"; - O << Indent1 << "}\n\n"; + EmitCaseConstructHandler(D.OnEmpty, Indent2, EmitWorksOnEmptyCallback, + /*EmitElseIf = */ true, OptDescs, O); + O.indent(Indent1) << "}\n\n"; +} + +/// EmitStrArray - Emit definition of a 'const char**' static member +/// variable. Helper used by EmitStaticMemberDefinitions(); +void EmitStrArray(const std::string& Name, const std::string& VarName, + const StrVector& StrVec, raw_ostream& O) { + O << "const char* " << Name << "::" << VarName << "[] = {"; + for (StrVector::const_iterator B = StrVec.begin(), E = StrVec.end(); + B != E; ++B) + O << '\"' << *B << "\", "; + O << "0};\n"; } /// EmitStaticMemberDefinitions - Emit static member definitions for a @@ -1613,12 +2296,12 @@ void EmitIsJoinMethod (const ToolDescription& D, raw_ostream& O) { void EmitStaticMemberDefinitions(const ToolDescription& D, raw_ostream& O) { if (D.InLanguage.empty()) throw "Tool " + D.Name + " has no 'in_language' property!"; + if (D.OutLanguage.empty()) + throw "Tool " + D.Name + " has no 'out_language' property!"; - O << "const char* " << D.Name << "::InputLanguages_[] = {"; - for (StrVector::const_iterator B = D.InLanguage.begin(), - E = D.InLanguage.end(); B != E; ++B) - O << '\"' << *B << "\", "; - O << "0};\n\n"; + EmitStrArray(D.Name, "InputLanguages_", D.InLanguage, O); + EmitStrArray(D.Name, "OutputLanguages_", D.OutLanguage, O); + O << '\n'; } /// EmitToolClassDefinition - Emit a Tool class definition. @@ -1635,13 +2318,15 @@ void EmitToolClassDefinition (const ToolDescription& D, else O << "Tool"; - O << "{\nprivate:\n" - << Indent1 << "static const char* InputLanguages_[];\n\n"; + O << " {\nprivate:\n"; + O.indent(Indent1) << "static const char* InputLanguages_[];\n"; + O.indent(Indent1) << "static const char* OutputLanguages_[];\n\n"; O << "public:\n"; EmitNameMethod(D, O); EmitInOutLanguageMethods(D, O); EmitIsJoinMethod(D, O); + EmitWorksOnEmptyMethod(D, OptDescs, O); EmitGenerateActionMethods(D, OptDescs, O); // Close class definition @@ -1654,8 +2339,7 @@ void EmitToolClassDefinition (const ToolDescription& D, /// EmitOptionDefinitions - Iterate over a list of option descriptions /// and emit registration code. void EmitOptionDefinitions (const OptionDescriptions& descs, - bool HasSink, bool HasExterns, - raw_ostream& O) + bool HasSink, raw_ostream& O) { std::vector Aliases; @@ -1669,16 +2353,8 @@ void EmitOptionDefinitions (const OptionDescriptions& descs, continue; } - if (val.isExtern()) - O << "extern "; - O << val.GenTypeDeclaration() << ' ' - << val.GenVariableName(); - - if (val.isExtern()) { - O << ";\n"; - continue; - } + << val.GenPlainVariableName(); O << "(\"" << val.Name << "\"\n"; @@ -1686,27 +2362,36 @@ void EmitOptionDefinitions (const OptionDescriptions& descs, O << ", cl::Prefix"; if (val.isRequired()) { - if (OptionType::IsList(val.Type) && !val.isMultiVal()) + if (val.isList() && !val.isMultiVal()) O << ", cl::OneOrMore"; else O << ", cl::Required"; } - else if (val.isOneOrMore() && OptionType::IsList(val.Type)) { + + if (val.isOptional()) + O << ", cl::Optional"; + + if (val.isOneOrMore()) O << ", cl::OneOrMore"; - } - else if (val.isZeroOrOne() && OptionType::IsList(val.Type)) { - O << ", cl::ZeroOrOne"; - } - if (val.isReallyHidden()) { + if (val.isZeroOrMore()) + O << ", cl::ZeroOrMore"; + + if (val.isReallyHidden()) O << ", cl::ReallyHidden"; - } - else if (val.isHidden()) { + else if (val.isHidden()) O << ", cl::Hidden"; - } + + if (val.isCommaSeparated()) + O << ", cl::CommaSeparated"; if (val.MultiVal > 1) - O << ", cl::multi_val(" << val.MultiVal << ")"; + O << ", cl::multi_val(" << val.MultiVal << ')'; + + if (val.InitVal) { + const std::string& str = val.InitVal->getAsString(); + O << ", cl::init(" << str << ')'; + } if (!val.Help.empty()) O << ", cl::desc(\"" << val.Help << "\")"; @@ -1720,7 +2405,7 @@ void EmitOptionDefinitions (const OptionDescriptions& descs, const OptionDescription& val = *B; O << val.GenTypeDeclaration() << ' ' - << val.GenVariableName() + << val.GenPlainVariableName() << "(\"" << val.Name << '\"'; const OptionDescription& D = descs.FindOption(val.Help); @@ -1731,69 +2416,284 @@ void EmitOptionDefinitions (const OptionDescriptions& descs, // Emit the sink option. if (HasSink) - O << (HasExterns ? "extern cl" : "cl") - << "::list " << SinkOptionName - << (HasExterns ? ";\n" : "(cl::Sink);\n"); + O << "cl::list " << SinkOptionName << "(cl::Sink);\n"; O << '\n'; } -/// EmitPopulateLanguageMap - Emit the PopulateLanguageMap() function. -void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O) +/// EmitPreprocessOptionsCallback - Helper function passed to +/// EmitCaseConstructHandler() by EmitPreprocessOptions(). + +class EmitPreprocessOptionsCallback; + +typedef void +(EmitPreprocessOptionsCallback::* EmitPreprocessOptionsCallbackHandler) +(const DagInit&, unsigned, raw_ostream&) const; + +class EmitPreprocessOptionsCallback : + public ActionHandlingCallbackBase, + public HandlerTable { - // Generate code - O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n"; + typedef EmitPreprocessOptionsCallbackHandler Handler; + typedef void + (EmitPreprocessOptionsCallback::* HandlerImpl) + (const Init*, unsigned, raw_ostream&) const; + + const OptionDescriptions& OptDescs_; + + void onEachArgument(const DagInit& d, HandlerImpl h, + unsigned IndentLevel, raw_ostream& O) const + { + CheckNumberOfArguments(d, 1); + + for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) { + ((this)->*(h))(d.getArg(i), IndentLevel, O); + } + } + + void onUnsetOptionImpl(const Init* I, + unsigned IndentLevel, raw_ostream& O) const + { + const std::string& OptName = InitPtrToString(I); + const OptionDescription& OptDesc = OptDescs_.FindOption(OptName); + + if (OptDesc.isSwitch()) { + O.indent(IndentLevel) << OptDesc.GenVariableName() << " = false;\n"; + } + else if (OptDesc.isParameter()) { + O.indent(IndentLevel) << OptDesc.GenVariableName() << " = \"\";\n"; + } + else if (OptDesc.isList()) { + O.indent(IndentLevel) << OptDesc.GenVariableName() << ".clear();\n"; + } + else { + throw "Can't apply 'unset_option' to alias option '" + OptName + "'!"; + } + } + + void onUnsetOption(const DagInit& d, + unsigned IndentLevel, raw_ostream& O) const + { + this->onEachArgument(d, &EmitPreprocessOptionsCallback::onUnsetOptionImpl, + IndentLevel, O); + } + + void onSetOptionImpl(const DagInit& D, + unsigned IndentLevel, raw_ostream& O) const { + CheckNumberOfArguments(D, 2); + + const std::string& OptName = InitPtrToString(D.getArg(0)); + const OptionDescription& OptDesc = OptDescs_.FindOption(OptName); + const Init* Value = D.getArg(1); + + if (OptDesc.isList()) { + const ListInit& List = InitPtrToList(Value); + + O.indent(IndentLevel) << OptDesc.GenVariableName() << ".clear();\n"; + for (ListInit::const_iterator B = List.begin(), E = List.end(); + B != E; ++B) { + const Init* CurElem = *B; + if (OptDesc.isSwitchList()) + CheckBooleanConstant(CurElem); + + O.indent(IndentLevel) + << OptDesc.GenVariableName() << ".push_back(\"" + << (OptDesc.isSwitchList() ? CurElem->getAsString() + : InitPtrToString(CurElem)) + << "\");\n"; + } + } + else if (OptDesc.isSwitch()) { + CheckBooleanConstant(Value); + O.indent(IndentLevel) << OptDesc.GenVariableName() + << " = " << Value->getAsString() << ";\n"; + } + else if (OptDesc.isParameter()) { + const std::string& Str = InitPtrToString(Value); + O.indent(IndentLevel) << OptDesc.GenVariableName() + << " = \"" << Str << "\";\n"; + } + else { + throw "Can't apply 'set_option' to alias option '" + OptName + "'!"; + } + } - // Get the relevant field out of RecordKeeper - const Record* LangMapRecord = Records.getDef("LanguageMap"); + void onSetSwitch(const Init* I, + unsigned IndentLevel, raw_ostream& O) const { + const std::string& OptName = InitPtrToString(I); + const OptionDescription& OptDesc = OptDescs_.FindOption(OptName); - // It is allowed for a plugin to have no language map. - if (LangMapRecord) { + if (OptDesc.isSwitch()) + O.indent(IndentLevel) << OptDesc.GenVariableName() << " = true;\n"; + else + throw "set_option: -" + OptName + " is not a switch option!"; + } - ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map"); - if (!LangsToSuffixesList) - throw std::string("Error in the language map definition!"); + void onSetOption(const DagInit& d, + unsigned IndentLevel, raw_ostream& O) const + { + CheckNumberOfArguments(d, 1); + + // 2-argument form: (set_option "A", true), (set_option "B", "C"), + // (set_option "D", ["E", "F"]) + if (d.getNumArgs() == 2) { + const OptionDescription& OptDesc = + OptDescs_.FindOption(InitPtrToString(d.getArg(0))); + const Init* Opt2 = d.getArg(1); + + if (!OptDesc.isSwitch() || typeid(*Opt2) != typeid(StringInit)) { + this->onSetOptionImpl(d, IndentLevel, O); + return; + } + } - for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) { - const Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i); + // Multiple argument form: (set_option "A"), (set_option "B", "C", "D") + this->onEachArgument(d, &EmitPreprocessOptionsCallback::onSetSwitch, + IndentLevel, O); + } - const std::string& Lang = LangToSuffixes->getValueAsString("lang"); - const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes"); +public: - for (unsigned i = 0; i < Suffixes->size(); ++i) - O << Indent1 << "langMap[\"" - << InitPtrToString(Suffixes->getElement(i)) - << "\"] = \"" << Lang << "\";\n"; + EmitPreprocessOptionsCallback(const OptionDescriptions& OptDescs) + : OptDescs_(OptDescs) + { + if (!staticMembersInitialized_) { + AddHandler("error", &EmitPreprocessOptionsCallback::onErrorDag); + AddHandler("warning", &EmitPreprocessOptionsCallback::onWarningDag); + AddHandler("unset_option", &EmitPreprocessOptionsCallback::onUnsetOption); + AddHandler("set_option", &EmitPreprocessOptionsCallback::onSetOption); + + staticMembersInitialized_ = true; } } + void operator()(const Init* I, + unsigned IndentLevel, raw_ostream& O) const + { + InvokeDagInitHandler(this, I, IndentLevel, O); + } + +}; + +/// EmitPreprocessOptions - Emit the PreprocessOptions() function. +void EmitPreprocessOptions (const RecordKeeper& Records, + const OptionDescriptions& OptDecs, raw_ostream& O) +{ + O << "int PreprocessOptions () {\n"; + + const RecordVector& OptionPreprocessors = + Records.getAllDerivedDefinitions("OptionPreprocessor"); + + for (RecordVector::const_iterator B = OptionPreprocessors.begin(), + E = OptionPreprocessors.end(); B!=E; ++B) { + DagInit* Case = (*B)->getValueAsDag("preprocessor"); + EmitCaseConstructHandler(Case, Indent1, + EmitPreprocessOptionsCallback(OptDecs), + false, OptDecs, O); + } + + O << '\n'; + O.indent(Indent1) << "return 0;\n"; O << "}\n\n"; } -/// IncDecWeight - Helper function passed to EmitCaseConstructHandler() -/// by EmitEdgeClass(). -void IncDecWeight (const Init* i, const char* IndentLevel, - raw_ostream& O) { +class DoEmitPopulateLanguageMap; +typedef void (DoEmitPopulateLanguageMap::* DoEmitPopulateLanguageMapHandler) +(const DagInit& D); + +class DoEmitPopulateLanguageMap +: public HandlerTable +{ +private: + raw_ostream& O_; + +public: + + explicit DoEmitPopulateLanguageMap (raw_ostream& O) : O_(O) { + if (!staticMembersInitialized_) { + AddHandler("lang_to_suffixes", + &DoEmitPopulateLanguageMap::onLangToSuffixes); + + staticMembersInitialized_ = true; + } + } + + void operator() (Init* I) { + InvokeDagInitHandler(this, I); + } + +private: + + void onLangToSuffixes (const DagInit& d) { + CheckNumberOfArguments(d, 2); + + const std::string& Lang = InitPtrToString(d.getArg(0)); + Init* Suffixes = d.getArg(1); + + // Second argument to lang_to_suffixes is either a single string... + if (typeid(*Suffixes) == typeid(StringInit)) { + O_.indent(Indent1) << "langMap[\"" << InitPtrToString(Suffixes) + << "\"] = \"" << Lang << "\";\n"; + } + // ...or a list of strings. + else { + const ListInit& Lst = InitPtrToList(Suffixes); + assert(Lst.size() != 0); + for (ListInit::const_iterator B = Lst.begin(), E = Lst.end(); + B != E; ++B) { + O_.indent(Indent1) << "langMap[\"" << InitPtrToString(*B) + << "\"] = \"" << Lang << "\";\n"; + } + } + } + +}; + +/// EmitPopulateLanguageMap - Emit the PopulateLanguageMap() function. +void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O) +{ + O << "int PopulateLanguageMap (LanguageMap& langMap) {\n"; + + // For each LanguageMap: + const RecordVector& LangMaps = + Records.getAllDerivedDefinitions("LanguageMap"); + + // Call DoEmitPopulateLanguageMap. + for (RecordVector::const_iterator B = LangMaps.begin(), + E = LangMaps.end(); B!=E; ++B) { + ListInit* LangMap = (*B)->getValueAsListInit("map"); + std::for_each(LangMap->begin(), LangMap->end(), + DoEmitPopulateLanguageMap(O)); + } + + O << '\n'; + O.indent(Indent1) << "return 0;\n"; + O << "}\n\n"; +} + +/// EmitEdgePropertyHandlerCallback - Emits code that handles edge +/// properties. Helper function passed to EmitCaseConstructHandler() by +/// EmitEdgeClass(). +void EmitEdgePropertyHandlerCallback (const Init* i, unsigned IndentLevel, + raw_ostream& O) { const DagInit& d = InitPtrToDag(i); - const std::string& OpName = d.getOperator()->getAsString(); + const std::string& OpName = GetOperatorName(d); if (OpName == "inc_weight") { - O << IndentLevel << "ret += "; - } - else if (OpName == "dec_weight") { - O << IndentLevel << "ret -= "; + O.indent(IndentLevel) << "ret += "; } else if (OpName == "error") { - O << IndentLevel << "throw std::runtime_error(\"" << - (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0)) - : "Unknown error!") - << "\");\n"; + CheckNumberOfArguments(d, 1); + O.indent(IndentLevel) << "PrintError(\"" + << InitPtrToString(d.getArg(0)) + << "\");\n"; + O.indent(IndentLevel) << "return -1;\n"; return; } - - else - throw "Unknown operator in edge properties list: " + OpName + '!' + + else { + throw "Unknown operator in edge properties list: '" + OpName + "'!" "\nOnly 'inc_weight', 'dec_weight' and 'error' are allowed."; + } if (d.getNumArgs() > 0) O << InitPtrToInt(d.getArg(0)) << ";\n"; @@ -1804,103 +2704,158 @@ void IncDecWeight (const Init* i, const char* IndentLevel, /// EmitEdgeClass - Emit a single Edge# class. void EmitEdgeClass (unsigned N, const std::string& Target, - DagInit* Case, const OptionDescriptions& OptDescs, + const DagInit& Case, const OptionDescriptions& OptDescs, raw_ostream& O) { // Class constructor. O << "class Edge" << N << ": public Edge {\n" - << "public:\n" - << Indent1 << "Edge" << N << "() : Edge(\"" << Target - << "\") {}\n\n" + << "public:\n"; + O.indent(Indent1) << "Edge" << N << "() : Edge(\"" << Target + << "\") {}\n\n"; // Function Weight(). - << Indent1 << "unsigned Weight(const InputLanguagesSet& InLangs) const {\n" - << Indent2 << "unsigned ret = 0;\n"; + O.indent(Indent1) + << "int Weight(const InputLanguagesSet& InLangs) const {\n"; + O.indent(Indent2) << "unsigned ret = 0;\n"; // Handle the 'case' construct. - EmitCaseConstructHandler(Case, Indent2, IncDecWeight, false, OptDescs, O); + EmitCaseConstructHandler(&Case, Indent2, EmitEdgePropertyHandlerCallback, + false, OptDescs, O); - O << Indent2 << "return ret;\n" - << Indent1 << "};\n\n};\n\n"; + O.indent(Indent2) << "return ret;\n"; + O.indent(Indent1) << "}\n\n};\n\n"; } /// EmitEdgeClasses - Emit Edge* classes that represent graph edges. -void EmitEdgeClasses (const RecordVector& EdgeVector, +void EmitEdgeClasses (const DagVector& EdgeVector, const OptionDescriptions& OptDescs, raw_ostream& O) { int i = 0; - for (RecordVector::const_iterator B = EdgeVector.begin(), + for (DagVector::const_iterator B = EdgeVector.begin(), E = EdgeVector.end(); B != E; ++B) { - const Record* Edge = *B; - const std::string& NodeB = Edge->getValueAsString("b"); - DagInit* Weight = Edge->getValueAsDag("weight"); + const DagInit& Edge = **B; + const std::string& Name = GetOperatorName(Edge); - if (!isDagEmpty(Weight)) + if (Name == "optional_edge") { + assert(IsOptionalEdge(Edge)); + const std::string& NodeB = InitPtrToString(Edge.getArg(1)); + + const DagInit& Weight = InitPtrToDag(Edge.getArg(2)); EmitEdgeClass(i, NodeB, Weight, OptDescs, O); + } + else if (Name != "edge") { + throw "Unknown edge class: '" + Name + "'!"; + } + ++i; } } -/// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraph() -/// function. -void EmitPopulateCompilationGraph (const RecordVector& EdgeVector, +/// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraph() function. +void EmitPopulateCompilationGraph (const DagVector& EdgeVector, const ToolDescriptions& ToolDescs, raw_ostream& O) { - O << "void PopulateCompilationGraphLocal(CompilationGraph& G) {\n"; + O << "int PopulateCompilationGraph (CompilationGraph& G) {\n"; for (ToolDescriptions::const_iterator B = ToolDescs.begin(), E = ToolDescs.end(); B != E; ++B) - O << Indent1 << "G.insertNode(new " << (*B)->Name << "());\n"; + O.indent(Indent1) << "G.insertNode(new " << (*B)->Name << "());\n"; O << '\n'; // Insert edges. int i = 0; - for (RecordVector::const_iterator B = EdgeVector.begin(), + for (DagVector::const_iterator B = EdgeVector.begin(), E = EdgeVector.end(); B != E; ++B) { - const Record* Edge = *B; - const std::string& NodeA = Edge->getValueAsString("a"); - const std::string& NodeB = Edge->getValueAsString("b"); - DagInit* Weight = Edge->getValueAsDag("weight"); + const DagInit& Edge = **B; + const std::string& NodeA = InitPtrToString(Edge.getArg(0)); + const std::string& NodeB = InitPtrToString(Edge.getArg(1)); - O << Indent1 << "G.insertEdge(\"" << NodeA << "\", "; + O.indent(Indent1) << "if (int ret = G.insertEdge(\"" << NodeA << "\", "; - if (isDagEmpty(Weight)) - O << "new SimpleEdge(\"" << NodeB << "\")"; - else + if (IsOptionalEdge(Edge)) O << "new Edge" << i << "()"; + else + O << "new SimpleEdge(\"" << NodeB << "\")"; + + O << "))\n"; + O.indent(Indent2) << "return ret;\n"; - O << ");\n"; ++i; } + O << '\n'; + O.indent(Indent1) << "return 0;\n"; O << "}\n\n"; } +/// HookInfo - Information about the hook type and number of arguments. +struct HookInfo { + + // A hook can either have a single parameter of type std::vector, + // or NumArgs parameters of type const char*. + enum HookType { ListHook, ArgHook }; + + HookType Type; + unsigned NumArgs; + + HookInfo() : Type(ArgHook), NumArgs(1) + {} + + HookInfo(HookType T) : Type(T), NumArgs(1) + {} + + HookInfo(unsigned N) : Type(ArgHook), NumArgs(N) + {} +}; + +typedef llvm::StringMap HookInfoMap; + /// ExtractHookNames - Extract the hook names from all instances of -/// $CALL(HookName) in the provided command line string. Helper +/// $CALL(HookName) in the provided command line string/action. Helper /// function used by FillInHookNames(). class ExtractHookNames { - llvm::StringMap& HookNames_; + HookInfoMap& HookNames_; + const OptionDescriptions& OptDescs_; public: - ExtractHookNames(llvm::StringMap& HookNames) - : HookNames_(HookNames) {} + ExtractHookNames(HookInfoMap& HookNames, const OptionDescriptions& OptDescs) + : HookNames_(HookNames), OptDescs_(OptDescs) + {} + + void onAction (const DagInit& Dag) { + const std::string& Name = GetOperatorName(Dag); + + if (Name == "forward_transformed_value") { + CheckNumberOfArguments(Dag, 2); + const std::string& OptName = InitPtrToString(Dag.getArg(0)); + const std::string& HookName = InitPtrToString(Dag.getArg(1)); + const OptionDescription& D = + OptDescs_.FindParameterListOrParameter(OptName); - void operator()(const Init* CmdLine) { + HookNames_[HookName] = HookInfo(D.isList() ? HookInfo::ListHook + : HookInfo::ArgHook); + } + else if (Name == "append_cmd" || Name == "output_suffix") { + CheckNumberOfArguments(Dag, 1); + this->onCmdLine(InitPtrToString(Dag.getArg(0))); + } + } + + void onCmdLine(const std::string& Cmd) { StrVector cmds; - TokenizeCmdline(InitPtrToString(CmdLine), cmds); + TokenizeCmdLine(Cmd, cmds); + for (StrVector::const_iterator B = cmds.begin(), E = cmds.end(); B != E; ++B) { const std::string& cmd = *B; if (cmd == "$CALL") { unsigned NumArgs = 0; - checkedIncrement(B, E, "Syntax error in $CALL invocation!"); + CheckedIncrement(B, E, "Syntax error in $CALL invocation!"); const std::string& HookName = *B; - if (HookName.at(0) == ')') throw "$CALL invoked with no arguments!"; @@ -1908,109 +2863,133 @@ public: ++NumArgs; } - StringMap::const_iterator H = HookNames_.find(HookName); + HookInfoMap::const_iterator H = HookNames_.find(HookName); - if (H != HookNames_.end() && H->second != NumArgs) + if (H != HookNames_.end() && H->second.NumArgs != NumArgs && + H->second.Type != HookInfo::ArgHook) throw "Overloading of hooks is not allowed. Overloaded hook: " + HookName; else - HookNames_[HookName] = NumArgs; + HookNames_[HookName] = HookInfo(NumArgs); + } + } + } + void operator()(const Init* Arg) { + + // We're invoked on an action (either a dag or a dag list). + if (typeid(*Arg) == typeid(DagInit)) { + const DagInit& Dag = InitPtrToDag(Arg); + this->onAction(Dag); + return; + } + else if (typeid(*Arg) == typeid(ListInit)) { + const ListInit& List = InitPtrToList(Arg); + for (ListInit::const_iterator B = List.begin(), E = List.end(); B != E; + ++B) { + const DagInit& Dag = InitPtrToDag(*B); + this->onAction(Dag); } + return; } + + // We're invoked on a command line string. + this->onCmdLine(InitPtrToString(Arg)); + } + + void operator()(const Init* Statement, unsigned) { + this->operator()(Statement); } }; /// FillInHookNames - Actually extract the hook names from all command /// line strings. Helper function used by EmitHookDeclarations(). void FillInHookNames(const ToolDescriptions& ToolDescs, - llvm::StringMap& HookNames) + const OptionDescriptions& OptDescs, + HookInfoMap& HookNames) { - // For all command lines: + // For all tool descriptions: for (ToolDescriptions::const_iterator B = ToolDescs.begin(), E = ToolDescs.end(); B != E; ++B) { const ToolDescription& D = *(*B); + + // Look for 'forward_transformed_value' in 'actions'. + if (D.Actions) + WalkCase(D.Actions, Id(), ExtractHookNames(HookNames, OptDescs)); + + // Look for hook invocations in 'cmd_line'. if (!D.CmdLine) continue; if (dynamic_cast(D.CmdLine)) // This is a string. - ExtractHookNames(HookNames).operator()(D.CmdLine); + ExtractHookNames(HookNames, OptDescs).operator()(D.CmdLine); else // This is a 'case' construct. - WalkCase(D.CmdLine, Id(), ExtractHookNames(HookNames)); + WalkCase(D.CmdLine, Id(), ExtractHookNames(HookNames, OptDescs)); } } /// EmitHookDeclarations - Parse CmdLine fields of all the tool /// property records and emit hook function declaration for each /// instance of $CALL(HookName). -void EmitHookDeclarations(const ToolDescriptions& ToolDescs, raw_ostream& O) { - llvm::StringMap HookNames; +void EmitHookDeclarations(const ToolDescriptions& ToolDescs, + const OptionDescriptions& OptDescs, raw_ostream& O) { + HookInfoMap HookNames; - FillInHookNames(ToolDescs, HookNames); + FillInHookNames(ToolDescs, OptDescs, HookNames); if (HookNames.empty()) return; - O << "namespace hooks {\n"; - for (StringMap::const_iterator B = HookNames.begin(), + for (HookInfoMap::const_iterator B = HookNames.begin(), E = HookNames.end(); B != E; ++B) { - O << Indent1 << "std::string " << B->first() << "("; + const char* HookName = B->first(); + const HookInfo& Info = B->second; + + O.indent(Indent1) << "std::string " << HookName << "("; - for (unsigned i = 0, j = B->second; i < j; ++i) { - O << "const char* Arg" << i << (i+1 == j ? "" : ", "); + if (Info.Type == HookInfo::ArgHook) { + for (unsigned i = 0, j = Info.NumArgs; i < j; ++i) { + O << "const char* Arg" << i << (i+1 == j ? "" : ", "); + } + } + else { + O << "const std::vector& Arg"; } O <<");\n"; } - O << "}\n\n"; -} - -/// EmitRegisterPlugin - Emit code to register this plugin. -void EmitRegisterPlugin(int Priority, raw_ostream& O) { - O << "struct Plugin : public llvmc::BasePlugin {\n\n" - << Indent1 << "int Priority() const { return " << Priority << "; }\n\n" - << Indent1 << "void PopulateLanguageMap(LanguageMap& langMap) const\n" - << Indent1 << "{ PopulateLanguageMapLocal(langMap); }\n\n" - << Indent1 - << "void PopulateCompilationGraph(CompilationGraph& graph) const\n" - << Indent1 << "{ PopulateCompilationGraphLocal(graph); }\n" - << "};\n\n" - - << "static llvmc::RegisterPlugin RP;\n\n"; } /// EmitIncludes - Emit necessary #include directives and some /// additional declarations. void EmitIncludes(raw_ostream& O) { - O << "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n" - << "#include \"llvm/CompilerDriver/ForceLinkageMacros.h\"\n" - << "#include \"llvm/CompilerDriver/Plugin.h\"\n" + O << "#include \"llvm/CompilerDriver/BuiltinOptions.h\"\n" + << "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n" + << "#include \"llvm/CompilerDriver/Error.h\"\n" << "#include \"llvm/CompilerDriver/Tool.h\"\n\n" - << "#include \"llvm/ADT/StringExtras.h\"\n" - << "#include \"llvm/Support/CommandLine.h\"\n\n" + << "#include \"llvm/Support/CommandLine.h\"\n" + << "#include \"llvm/Support/raw_ostream.h\"\n\n" + << "#include \n" << "#include \n" + << "#include \n" << "#include \n\n" << "using namespace llvm;\n" << "using namespace llvmc;\n\n" - << "extern cl::opt OutputFilename;\n\n" - << "inline const char* checkCString(const char* s)\n" << "{ return s == NULL ? \"\" : s; }\n\n"; } -/// PluginData - Holds all information about a plugin. -struct PluginData { +/// DriverData - Holds all information about the driver. +struct DriverData { OptionDescriptions OptDescs; - bool HasSink; - bool HasExterns; ToolDescriptions ToolDescs; - RecordVector Edges; - int Priority; + DagVector Edges; + bool HasSink; }; /// HasSink - Go through the list of tool descriptions and check if @@ -2024,46 +3003,27 @@ bool HasSink(const ToolDescriptions& ToolDescs) { return false; } -/// HasExterns - Go through the list of option descriptions and check -/// if there are any external options. -bool HasExterns(const OptionDescriptions& OptDescs) { - for (OptionDescriptions::const_iterator B = OptDescs.begin(), - E = OptDescs.end(); B != E; ++B) - if (B->second.isExtern()) - return true; - - return false; -} - -/// CollectPluginData - Collect tool and option properties, -/// compilation graph edges and plugin priority from the parse tree. -void CollectPluginData (const RecordKeeper& Records, PluginData& Data) { +/// CollectDriverData - Collect compilation graph edges, tool properties and +/// option properties from the parse tree. +void CollectDriverData (const RecordKeeper& Records, DriverData& Data) { // Collect option properties. const RecordVector& OptionLists = Records.getAllDerivedDefinitions("OptionList"); - CollectOptionDescriptions(OptionLists.begin(), OptionLists.end(), - Data.OptDescs); + CollectOptionDescriptions(OptionLists, Data.OptDescs); // Collect tool properties. const RecordVector& Tools = Records.getAllDerivedDefinitions("Tool"); - CollectToolDescriptions(Tools.begin(), Tools.end(), Data.ToolDescs); + CollectToolDescriptions(Tools, Data.ToolDescs); Data.HasSink = HasSink(Data.ToolDescs); - Data.HasExterns = HasExterns(Data.OptDescs); // Collect compilation graph edges. const RecordVector& CompilationGraphs = Records.getAllDerivedDefinitions("CompilationGraph"); - FillInEdgeVector(CompilationGraphs.begin(), CompilationGraphs.end(), - Data.Edges); - - // Calculate the priority of this plugin. - const RecordVector& Priorities = - Records.getAllDerivedDefinitions("PluginPriority"); - Data.Priority = CalculatePriority(Priorities.begin(), Priorities.end()); + FillInEdgeVector(CompilationGraphs, Data.Edges); } -/// CheckPluginData - Perform some sanity checks on the collected data. -void CheckPluginData(PluginData& Data) { +/// CheckDriverData - Perform some sanity checks on the collected data. +void CheckDriverData(DriverData& Data) { // Filter out all tools not mentioned in the compilation graph. FilterNotInGraph(Data.Edges, Data.ToolDescs); @@ -2073,24 +3033,27 @@ void CheckPluginData(PluginData& Data) { // Check that there are no options without side effects (specified // only in the OptionList). CheckForSuperfluousOptions(Data.Edges, Data.ToolDescs, Data.OptDescs); - } -void EmitPluginCode(const PluginData& Data, raw_ostream& O) { +void EmitDriverCode(const DriverData& Data, + raw_ostream& O, RecordKeeper &Records) { // Emit file header. EmitIncludes(O); // Emit global option registration code. - EmitOptionDefinitions(Data.OptDescs, Data.HasSink, Data.HasExterns, O); + O << "namespace llvmc {\n" + << "namespace autogenerated {\n\n"; + EmitOptionDefinitions(Data.OptDescs, Data.HasSink, O); + O << "} // End namespace autogenerated.\n" + << "} // End namespace llvmc.\n\n"; // Emit hook declarations. - EmitHookDeclarations(Data.ToolDescs, O); + O << "namespace hooks {\n"; + EmitHookDeclarations(Data.ToolDescs, Data.OptDescs, O); + O << "} // End namespace hooks.\n\n"; O << "namespace {\n\n"; - - // Emit PopulateLanguageMap() function - // (a language map maps from file extensions to language names). - EmitPopulateLanguageMap(Records, O); + O << "using namespace llvmc::autogenerated;\n\n"; // Emit Tool classes. for (ToolDescriptions::const_iterator B = Data.ToolDescs.begin(), @@ -2100,18 +3063,23 @@ void EmitPluginCode(const PluginData& Data, raw_ostream& O) { // Emit Edge# classes. EmitEdgeClasses(Data.Edges, Data.OptDescs, O); - // Emit PopulateCompilationGraph() function. - EmitPopulateCompilationGraph(Data.Edges, Data.ToolDescs, O); - - // Emit code for plugin registration. - EmitRegisterPlugin(Data.Priority, O); - O << "} // End anonymous namespace.\n\n"; - // Force linkage magic. O << "namespace llvmc {\n"; - O << "LLVMC_FORCE_LINKAGE_DECL(LLVMC_PLUGIN_NAME) {}\n"; - O << "}\n"; + O << "namespace autogenerated {\n\n"; + + // Emit PreprocessOptions() function. + EmitPreprocessOptions(Records, Data.OptDescs, O); + + // Emit PopulateLanguageMap() function + // (language map maps from file extensions to language names). + EmitPopulateLanguageMap(Records, O); + + // Emit PopulateCompilationGraph() function. + EmitPopulateCompilationGraph(Data.Edges, Data.ToolDescs, O); + + O << "} // End namespace autogenerated.\n"; + O << "} // End namespace llvmc.\n\n"; // EOF } @@ -2123,13 +3091,13 @@ void EmitPluginCode(const PluginData& Data, raw_ostream& O) { /// run - The back-end entry point. void LLVMCConfigurationEmitter::run (raw_ostream &O) { try { - PluginData Data; + DriverData Data; - CollectPluginData(Records, Data); - CheckPluginData(Data); + CollectDriverData(Records, Data); + CheckDriverData(Data); - EmitSourceFileHeader("LLVMC Configuration Library", O); - EmitPluginCode(Data, O); + this->EmitSourceFileHeader("llvmc-based driver: auto-generated code", O); + EmitDriverCode(Data, O, Records); } catch (std::exception& Error) { throw Error.what() + std::string(" - usually this means a syntax error.");