Index: test/FileCheck/check-pattern.txt =================================================================== --- /dev/null +++ test/FileCheck/check-pattern.txt @@ -0,0 +1,24 @@ +// RUN: FileCheck -input-file %s %s + +op0xA1; +op0xc2; +op0x33; +// CHECK-PATTERN hex_num: {{0x[0-9a-fA-F]+}} +// CHECK-PATTERN reg: {{\:(RegName)\#(hex_num)}} +// CHECK-PATTERN operation: {{\:(OpName) \#(reg)\:(RegName)\=(r), \#(reg)\:(RegName)\=(reg)}} +// CHECK-PATTERN inc: {{\:(VarName) = \:(VarName)\+\:(Number)}} +// CHECK-PATTERN alt: {{x|y}} +// CHECK-PATTERN altincheck: check {{\#(alt)}} + +// CHECK: {{op\#(hex_num)}}; +reg0x0 +// CHECK: {{\#(reg)\:(RegName)\=(reg)}} + +ADD r0xA, reg0x10 +// CHECK: {{\#(operation)\:(OpName)\=(ADD)}} + +TEMP = TEMP+4 +// CHECK: {{\#(inc)\:(Number)\=(4)\:(VarName)\=(TEMP)}} + +check y +// CHECK: {{\#altincheck}} Index: utils/FileCheck/FileCheck.cpp =================================================================== --- utils/FileCheck/FileCheck.cpp +++ utils/FileCheck/FileCheck.cpp @@ -33,6 +33,7 @@ #include #include #include +#include using namespace llvm; static cl::opt @@ -88,6 +89,7 @@ CheckNot, CheckDAG, CheckLabel, + CheckPattern, /// MatchEOF - When set, this pattern only matches the end of file. This is /// used for trailing CHECK-NOTs. @@ -131,6 +133,8 @@ /// getLoc - Return the location in source code. SMLoc getLoc() const { return PatternLoc; } + std::string getRegExStr() const { return RegExStr; } + /// ParsePattern - Parse the given string into the Pattern. Prefix provides /// which prefix is being matched, SM provides the SourceMgr used for error /// reports, and LineNumber is the line number in the input file from which @@ -180,9 +184,157 @@ /// \return offset of the closing sequence within Str, or npos if it was not /// found. size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM); + + /// Replace templates if they are to associated with them regular expressions. + /// \return true if there is error in regular expression + bool ReplaceTemplates(StringRef RS, SourceMgr &SM, std::string &ResultRegex); +}; + +class PatternTemplate { + /// Name of template. + std::string TemplateName; + /// Pattern which describes this template. + Pattern TemplatePattern; + /// Template parametrs. + std::map Parameters; + +public: + PatternTemplate(std::string Name, Check::CheckType Ty = Check::CheckType::CheckNone): + TemplateName(Name), TemplatePattern(Pattern(Ty)) {} + + PatternTemplate(Check::CheckType Ty = Check::CheckType::CheckNone):TemplatePattern(Pattern(Ty)) {} + + /// Parse the given string for getting parameters of template. + /// \return true if string has error in description regular expression or parametrs. + bool ParseTemplate(StringRef TemplateString, + StringRef Prefix, + SourceMgr &SM, + unsigned LineNumber); + + /// Get template name. + /// \return template name. + std::string GetTemplateName() const; + + /// Get number of parametrs which this template includes. + /// \return parameters number. + size_t GetParametersNumber() const; + + /// Checks if this template has such parameter + /// \return true if template has. + bool HasParameter(StringRef ParameterName) const; + + /// Generate result regular expression for matching with inserted parameters values. + StringRef GetRegularExpression(std::map &ParametersValues) const; }; +bool PatternTemplate::ParseTemplate(StringRef TemplateString, + StringRef Prefix, + SourceMgr &SM, + unsigned LineNumber) { + + if (TemplatePattern.ParsePattern(TemplateString, Prefix, SM, LineNumber)) + return true; + + // Find parametrs in pattern + SmallVector Matches; + Regex Parametr(StringRef("\\\\:\\(([a-zA-Z_0-9]+)\\)")); + size_t DiffInLoc = 0; + StringRef PatternString = StringRef(TemplatePattern.getRegExStr()); + + while (Parametr.match(PatternString, &Matches)) { + size_t ParametrPos = Matches[0].data() - PatternString.data(); + Parameters.insert(std::pair(ParametrPos + DiffInLoc, Matches[1])); + PatternString = PatternString.drop_front(ParametrPos + Matches[1].size() + 3); + DiffInLoc += ParametrPos + Matches[1].size() + 3; + } + + return false; +} + +std::string PatternTemplate::GetTemplateName() const { + return TemplateName; +} + +size_t PatternTemplate::GetParametersNumber() const { + std::set UniqueParametrs; + for (const auto &Parameter : Parameters) { + UniqueParametrs.insert(Parameter.second); + } + return UniqueParametrs.size(); +} + +bool PatternTemplate::HasParameter(StringRef ParameterName) const { + for (const auto &Parameter : Parameters) { + if (Parameter.second == ParameterName) { + return true; + } + } + return false; +} + +StringRef PatternTemplate::GetRegularExpression(std::map &ParametersValues) const { + std::string Regex = TemplatePattern.getRegExStr(); + + int DiffInLoc = 0; // variable for shifts after replacing parametrs' names by parametrs' values + + // Change all parameters to their values. + for (const auto &Parameter : Parameters) { + StringRef Value = ParametersValues[Parameter.second]; + std::string RegexStart = StringRef(Regex.substr(0, Parameter.first + DiffInLoc)).str(); + StringRef RegexEnd = Regex.substr(Parameter.first + DiffInLoc + Parameter.second.size() + 4); + Regex = RegexStart + "(" + Value.str() + ")" + RegexEnd.str(); + DiffInLoc += Value.size() - Parameter.second.size() - 2; + } + + return StringRef(Regex); +} + +class TemplatesCollection { + /// Described templates + static std::map Templates; + /// Last added template (for generating error) + static std::string LastAddedTemplate; + +public: + /// Add template + static bool AddTemplate(PatternTemplate *AddedTemplate); + /// Get template by its name. + static PatternTemplate* GetTemplate(const StringRef &TemplateName); + /// Get last added template + static PatternTemplate* GetLastAddedTemplate(); + /// Check if there is current template in collection. + static bool HasTemplate(const StringRef &TemplateName); +}; + +std::string TemplatesCollection::LastAddedTemplate; +std::map TemplatesCollection::Templates; + +bool TemplatesCollection::AddTemplate(PatternTemplate *AddedTemplate) { + if (Templates.find(AddedTemplate->GetTemplateName()) != Templates.end()) { + return false; + } + LastAddedTemplate = AddedTemplate->GetTemplateName(); + return Templates.insert(std::pair(AddedTemplate->GetTemplateName(), AddedTemplate)).second; +} + +PatternTemplate* TemplatesCollection::GetTemplate(const StringRef &TemplateName) { + if (HasTemplate(TemplateName)) { + return Templates[TemplateName.str()]; + } + + return NULL; +} + +PatternTemplate* TemplatesCollection::GetLastAddedTemplate() { + return Templates[LastAddedTemplate]; +} + +bool TemplatesCollection::HasTemplate(const StringRef &TemplateName) { + return Templates.find(TemplateName.str()) != Templates.end(); +} + + bool Pattern::ParsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM, @@ -361,6 +513,11 @@ bool Pattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) { + std::string ResultRegex; + if (ReplaceTemplates(RS, SM, ResultRegex)) + return true; + + RS = StringRef(ResultRegex); Regex R(RS); std::string Error; if (!R.isValid(Error)) { @@ -607,6 +764,86 @@ return StringRef::npos; } +bool Pattern::ReplaceTemplates(StringRef RS, SourceMgr &SM, std::string &ResultRegex) { + // Replace templates with regular expressions. + SmallVector MatchInfo; + size_t DiffInLoc = 0; + StringRef RegexStr = StringRef(RS); + + while (Regex(StringRef("\\\\#\\(([a-zA-Z0-9_]+)\\)")).match(RegexStr, &MatchInfo)) { + + // Check if template was declared + if (!TemplatesCollection::HasTemplate(MatchInfo[1])) { + SM.PrintMessage(SMLoc::getFromPointer(RS.data() + DiffInLoc + (MatchInfo[1].data() - RegexStr.data())), SourceMgr::DK_Error, + "template " + MatchInfo[1].str() + " wasn't declared"); + return true; + } + // Add pat of regex before template usage. + ResultRegex = ResultRegex + RegexStr.substr(0, MatchInfo[0].data() - RegexStr.data()).str(); + RegexStr = RegexStr.drop_front(MatchInfo[0].data() - RegexStr.data() + MatchInfo[0].size()); + + DiffInLoc += MatchInfo[0].data() - RegexStr.data() + MatchInfo[0].size(); + PatternTemplate *Temp = TemplatesCollection::GetTemplate(MatchInfo[1]); + + // Get template parametres. + std::map ParametersValues; + while (RegexStr.startswith("\\:(")) { + size_t ParameterNameEnd = RegexStr.find(')'); + if (ParameterNameEnd == StringRef::npos) { + SM.PrintMessage(SMLoc::getFromPointer(RS.data() + DiffInLoc), SourceMgr::DK_Error, + "wrong description of parameter. No closed bracket."); + return true; + } + StringRef ParameterName = RegexStr.substr(3, ParameterNameEnd - 3); + + // Check if template has such parametr in description. + if (!Temp->HasParameter(ParameterName)) { + SM.PrintMessage(SMLoc::getFromPointer(RS.data() + DiffInLoc), SourceMgr::DK_Error, + "template " + MatchInfo[1].str() + " doesn't have parameter " + ParameterName.str()); + return true; + } + + // Find value of parameter. + DiffInLoc += ParameterNameEnd + 1; + RegexStr = RegexStr.drop_front(ParameterNameEnd + 1); + if (!RegexStr.startswith("\\=(")) { + SM.PrintMessage(SMLoc::getFromPointer(RS.data() + DiffInLoc), SourceMgr::DK_Error, + "parameter " + ParameterName.str() + " has no value"); + return true; + } + + size_t ParameterValueEnd = RegexStr.find(')'); + if (ParameterValueEnd == StringRef::npos) { + SM.PrintMessage(SMLoc::getFromPointer(RS.data() + DiffInLoc), SourceMgr::DK_Error, + "wrong description of parameter value. No closed bracket."); + return true; + } + StringRef ParameterValue = RegexStr.substr(3, ParameterValueEnd - 3); + + // TODO - may value be template? + ParametersValues.insert(std::pair(ParameterName, ParameterValue)); + + DiffInLoc += ParameterValueEnd + 1; + RegexStr = RegexStr.drop_front(ParameterValueEnd + 1); + } + + if (Temp->GetParametersNumber() != ParametersValues.size()) { + SM.PrintMessage(SMLoc::getFromPointer(RS.data() + DiffInLoc), SourceMgr::DK_Error, + "not all parametrs of template " + Temp->GetTemplateName() + " are defined"); + return true; + } + + // Get regular expression by template. + StringRef FullTemplateRegex = Temp->GetRegularExpression(ParametersValues); + // Add template regex. + ResultRegex = ResultRegex + FullTemplateRegex.str(); + + } + // Add left part without templates. + ResultRegex = ResultRegex + RegexStr.str(); + return false; +} + //===----------------------------------------------------------------------===// // Check Strings. @@ -696,63 +933,57 @@ return (isalnum(c) || c == '-' || c == '_'); } -// Get the size of the prefix extension. -static size_t CheckTypeSize(Check::CheckType Ty) { - switch (Ty) { - case Check::CheckNone: - case Check::CheckBadNot: - return 0; - - case Check::CheckPlain: - return sizeof(":") - 1; - - case Check::CheckNext: - return sizeof("-NEXT:") - 1; - - case Check::CheckSame: - return sizeof("-SAME:") - 1; - - case Check::CheckNot: - return sizeof("-NOT:") - 1; - - case Check::CheckDAG: - return sizeof("-DAG:") - 1; - - case Check::CheckLabel: - return sizeof("-LABEL:") - 1; - - case Check::CheckEOF: - llvm_unreachable("Should not be using EOF size"); - } - - llvm_unreachable("Bad check type"); -} - -static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) { +static Check::CheckType FindCheckType(SourceMgr &SM, StringRef Buffer, StringRef Prefix, size_t &CheckTypeSize) { char NextChar = Buffer[Prefix.size()]; + CheckTypeSize = 0; // Verify that the : is present after the prefix. - if (NextChar == ':') + if (NextChar == ':') { + CheckTypeSize = 1; return Check::CheckPlain; + } if (NextChar != '-') return Check::CheckNone; StringRef Rest = Buffer.drop_front(Prefix.size() + 1); - if (Rest.startswith("NEXT:")) + if (Rest.startswith("NEXT:")) { + CheckTypeSize = sizeof("-NEXT:") - 1; return Check::CheckNext; + } - if (Rest.startswith("SAME:")) + if (Rest.startswith("SAME:")) { + CheckTypeSize = sizeof("-SAME:") - 1; return Check::CheckSame; + } - if (Rest.startswith("NOT:")) + if (Rest.startswith("NOT:")) { + CheckTypeSize = sizeof("-NOT:") - 1; return Check::CheckNot; + } - if (Rest.startswith("DAG:")) + if (Rest.startswith("DAG:")) { + CheckTypeSize = sizeof("-DAG:") - 1; return Check::CheckDAG; + } - if (Rest.startswith("LABEL:")) + if (Rest.startswith("LABEL:")) { + CheckTypeSize = sizeof("-LABEL:") - 1; return Check::CheckLabel; + } + + SmallVector Matches; + + if (Regex(StringRef("PATTERN ([a-zA-Z0-9_]+):"), Regex::Newline).match(Rest, &Matches)) { + if (!TemplatesCollection::AddTemplate(new PatternTemplate(Matches[1]))) { + SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), + SourceMgr::DK_Warning, + "the template name " + Matches[1].str() + "is already used"); + return Check::CheckNone; + } + CheckTypeSize = Matches[0].size() + 1; + return Check::CheckPattern; + } // You can't combine -NOT with another suffix. if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") || @@ -778,11 +1009,13 @@ // string and the location will be StringRef::npos. If one prefix is a substring // of another, the maximal match should be found. e.g. if "A" and "AA" are // prefixes then AA-CHECK: should match the second one. -static StringRef FindFirstCandidateMatch(StringRef &Buffer, +static StringRef FindFirstCandidateMatch(SourceMgr &SM, StringRef &Buffer, Check::CheckType &CheckTy, - size_t &CheckLoc) { + size_t &CheckLoc, + size_t &CheckTypeSize) { StringRef FirstPrefix; size_t FirstLoc = StringRef::npos; + size_t FirstTypeSize = StringRef::npos; size_t SearchLoc = StringRef::npos; Check::CheckType FirstTy = Check::CheckNone; @@ -818,7 +1051,7 @@ if (PrefixLoc != 0 && IsPartOfWord(Buffer[PrefixLoc - 1])) FirstTy = Check::CheckNone; else - FirstTy = FindCheckType(Rest, Prefix); + FirstTy = FindCheckType(SM, Rest, Prefix, FirstTypeSize); FirstLoc = PrefixLoc; FirstPrefix = Prefix; @@ -832,15 +1065,17 @@ CheckTy = FirstTy; CheckLoc = FirstLoc; + CheckTypeSize = FirstTypeSize; return FirstPrefix; } -static StringRef FindFirstMatchingPrefix(StringRef &Buffer, +static StringRef FindFirstMatchingPrefix(SourceMgr &SM, StringRef &Buffer, unsigned &LineNumber, Check::CheckType &CheckTy, - size_t &CheckLoc) { + size_t &CheckLoc, + size_t &CheckTypeSize) { while (!Buffer.empty()) { - StringRef Prefix = FindFirstCandidateMatch(Buffer, CheckTy, CheckLoc); + StringRef Prefix = FindFirstCandidateMatch(SM, Buffer, CheckTy, CheckLoc, CheckTypeSize); // If we found a real match, we are done. if (!Prefix.empty()) { LineNumber += Buffer.substr(0, CheckLoc).count('\n'); @@ -911,12 +1146,14 @@ while (1) { Check::CheckType CheckTy; size_t PrefixLoc; + size_t CheckTypeSize; // See if a prefix occurs in the memory buffer. - StringRef UsedPrefix = FindFirstMatchingPrefix(Buffer, + StringRef UsedPrefix = FindFirstMatchingPrefix(SM, Buffer, LineNumber, CheckTy, - PrefixLoc); + PrefixLoc, + CheckTypeSize); if (UsedPrefix.empty()) break; @@ -926,7 +1163,7 @@ const char *UsedPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1); // PrefixLoc is to the start of the prefix. Skip to the end. - Buffer = Buffer.drop_front(UsedPrefix.size() + CheckTypeSize(CheckTy)); + Buffer = Buffer.drop_front(UsedPrefix.size() + CheckTypeSize); // Complain about useful-looking but unsupported suffixes. if (CheckTy == Check::CheckBadNot) { @@ -946,6 +1183,14 @@ // Remember the location of the start of the pattern, for diagnostics. SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); + if (CheckTy == Check::CheckType::CheckPattern) { + if (TemplatesCollection::GetLastAddedTemplate()->ParseTemplate(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber)) { + return true; + } + Buffer = Buffer.substr(EOL); + continue; + } + // Parse the pattern. Pattern P(CheckTy); if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber))