Index: docs/CommandGuide/FileCheck.rst =================================================================== --- docs/CommandGuide/FileCheck.rst +++ docs/CommandGuide/FileCheck.rst @@ -480,3 +480,80 @@ letting us set the :program:`FileCheck` variable ``DLOC`` to the desired value ``0x00000233``, extracted from the line immediately preceding "``intd``". + +Templates +~~~~~~~~~ + +Some regular expressions are used very often. In this case directive for describing template +of regular expression may be used. + +Templates syntax: + +CHECK-DEFINE-PATTERN: [name of describing template]: [pattern of template] - directive to define pattern. + + +CHECK-DEFINE-PATTERN directive is used for describing templates. + + .. code-block:: c++ + + // CHECK-DEFINE-PATTERN: [name of describing template]: [pattern of template] + // CHECK-DEFINE-PATTERN: [name of describing template][list of parameters]: [pattern of template] + +For example + +.. code-block:: c++ + + // CHECK-DEFINE-PATTERN: hex_num: {{0x[0-9a-fA-F]+}} + +This directive only describes template and doesn’t match anything. + +Pattern of template should be a regular expression and should be writen as {{regex}}. + +Templates can have parameters for cases when there is same part, but also there are always +some changing parts. Parameters should be set in round brackets after name of pattern. +For example, register(RegName). regName is parameter name. It will be placed by it's value +which should be defined in check string. There can be many parameters and parameters can be +used some times in different parts of template.Parameters in pattern definition are all +words outside {{ }}. + +.. code-block:: c++ + + // CHECK-DEFINE-PATTERN: reg(RegName): RegName{{0x[0-9a-fA-F]+}} + +After describing new template it’s possible to use this regular expression by its template +name in any directive CHECK, CHECK-NEXT, CHECK-SAME and etc. + +[[@pattern_name(param1, ..., paramN)]] - usage of pattern. If pattern doesn't have parameters, +brackets aren't necessery. + +[[variable_name @pattern_name(param1, ..., paramN)]] - expression to capture pattern match value +into variable. + +For example + +.. code-block:: c++ + + // CHECK : reg[@hex_num] + +This check is equal to + +.. code-block:: c++ + + // CHECK : reg{{0x[0-9a-fA-F]+}} + + +To use templates with parameters you need to set values for each parameter. + +Example + +.. code-block:: c++ + + // CHECK : INC [@reg_hex_num(reg)] + +This is equal to + +.. code-block:: c++ + + // CHECK : INC reg{{0x[0-9a-fA-F]+}} + +Parameters are useful if there are a lot of similar checks in file. \ No newline at end of file Index: test/FileCheck/check-pattern.txt =================================================================== --- /dev/null +++ test/FileCheck/check-pattern.txt @@ -0,0 +1,33 @@ +// RUN: FileCheck -input-file %s %s + +op0xA1; +op0xc2; +op0x33; +// CHECK-DEFINE-PATTERN: hex_num: {{0x[0-9a-fA-F]+}} +// CHECK-DEFINE-PATTERN: reg(RegName): RegName{{0x[0-9a-fA-F]+}} +// CHECK-DEFINE-PATTERN: operation(OpName): OpName{{ }} +// CHECK-DEFINE-PATTERN: inc(VarName, Number): VarName{{ = }}VarName{{\+}}Number +// CHECK-DEFINE-PATTERN: alt: {{x|y}} +// CHECK-DEFINE-PATTERN: altincheck: {{check }}{{x|y}} + +// CHECK: op[[@hex_num]]; +reg0x0 +// CHECK: [[@reg("reg")]] + +ADD r0xA, reg0x10 +// CHECK: [[@operation("ADD")]][[@reg("r")]]{{, }}[[@reg("reg")]] + +TEMP = TEMP+4 +// CHECK: [[@inc("TEMP", "4")]] + +check y +// CHECK: [[@altincheck]] + +SUB r0xA, reg0x10 +// CHECK: [[sub @operation("SUB")]] + +SUB r0xA, reg0x10 +// CHECK: [[sub]] + +test.cpp:33:6: error: expected ';' after top level declarator +// CHECK: test.cpp:[[@LINE]]:6: error: expected ';' after top level declarator \ No newline at end of file Index: test/FileCheck/check-patterns-prefixes.txt =================================================================== --- /dev/null +++ test/FileCheck/check-patterns-prefixes.txt @@ -0,0 +1,30 @@ +// RUN: FileCheck -check-prefix=FOO -input-file %s %s + +// FOO-DEFINE-PATTERN: hex_num: {{0x[0-9a-fA-F]+}} +// FOO-DEFINE-PATTERN: reg(RegName): RegName{{0x[0-9a-fA-F]+}} +// FOO-DEFINE-PATTERN: inc(VarName, Number): VarName{{ = }}VarName{{\+}}Number +// FOO-DEFINE-PATTERN: block: {{block #[0-9]+}} + +block #2 +bar +op0x33 0xA1; + +something + +TEMP = TEMP+4 + +block #1 +T = T+2 +r0xFF; +register0x2B; + +// FOO-LABEL: [[@block]] +// FOO: bar +// FOO-NEXT: op[[@hex_num]] +// FOO-SAME: [[@hex_num]]; +// FOO-NOT: [[@reg("reg")]] +// FOO: [[@inc("TEMP", "4")]] +// FOO-LABEL: [[@block]] +// FOO-DAG: [[@reg("r")]] +// FOO-DAG: [[@reg("register")]] +// FOO-DAG: [[@inc("T", "2")]] \ No newline at end of file Index: test/FileCheck/pattern-errors.txt =================================================================== --- /dev/null +++ test/FileCheck/pattern-errors.txt @@ -0,0 +1,41 @@ +// RUN: not FileCheck -check-prefix=NOT_DECLARED -input-file %s %s 2>&1 | FileCheck -check-prefix=NOT_DECLARED_CHECK %s +// RUN: not FileCheck -check-prefix=NOT_STRING -input-file %s %s 2>&1 | FileCheck -check-prefix=NOT_STRING_CHECK %s +// RUN: not FileCheck -check-prefix=NO_CLOSE -input-file %s %s 2>&1 | FileCheck -check-prefix=NO_CLOSE_CHECK %s +// RUN: not FileCheck -check-prefix=EXTRA -input-file %s %s 2>&1 | FileCheck -check-prefix=EXTRA_CHECK %s +// RUN: not FileCheck -check-prefix=PARAM_NUMBER -input-file %s %s 2>&1 | FileCheck -check-prefix=PARAM_NUMBER_CHECK %s +// RUN: not FileCheck -check-prefix=REPEATED_NAME -input-file %s %s 2>&1 | FileCheck -check-prefix=REPEATED_NAME_CHECK %s +// RUN: not FileCheck -check-prefix=WITHOUT_NAME -input-file %s %s 2>&1 | FileCheck -check-prefix=WITHOUT_NAME_CHECK %s +// RUN: not FileCheck -check-prefix=UNDECLARED_PARAM -input-file %s %s 2>&1 | FileCheck -check-prefix=UNDECLARED_PARAM_CHECK %s +// RUN: not FileCheck -check-prefix=REPEATED_PARAM -input-file %s %s 2>&1 | FileCheck -check-prefix=REPEATED_PARAM_CHECK %s + +// NOT_DECLARED: [[@sometemplate]] +// NOT_DECLARED_CHECK: {{template sometemplate wasn't declared}} + +// NOT_STRING-DEFINE-PATTERN: reg(RegName): RegName{{0x[0-9a-fA-F]+}} +// NOT_STRING: [[@reg(reg)]] +// NOT_STRING_CHECK:{{Pattern parameter should be quoted string}} + +// NO_CLOSE-DEFINE-PATTERN: reg(RegName): RegName{{0x[0-9a-fA-F]+}} +// NO_CLOSE: [[@reg("reg)]] +// NO_CLOSE_CHECK:{{No close quote}} + +// EXTRA-DEFINE-PATTERN: reg(RegName): RegName{{0x[0-9a-fA-F]+}} +// EXTRA: [[@reg("reg"###)]] +// EXTRA_CHECK:{{Extra characters in parameters list}} + +// PARAM_NUMBER-DEFINE-PATTERN: reg(RegName): RegName{{0x[0-9a-fA-F]+}} +// PARAM_NUMBER: [[@reg("reg", "extra")]] +// PARAM_NUMBER_CHECK:{{Number of declared parameters differs from necessary}} + +// REPEATED_NAME-DEFINE-PATTERN: reg(RegName): RegName{{0x[0-9a-fA-F]+}} +// REPEATED_NAME-DEFINE-PATTERN: reg: {{0x[0-9a-fA-F]+}} +// REPEATED_NAME_CHECK: {{the template name reg is already used}} + +// WITHOUT_NAME-DEFINE-PATTERN: (RegName): RegName{{0x[0-9a-fA-F]+}} +// WITHOUT_NAME_CHECK: {{No name was defined for pattern}} + +// UNDECLARED_PARAM-DEFINE-PATTERN: reg: RegName{{0x[0-9a-fA-F]+}} +// UNDECLARED_PARAM_CHECK: {{Parameter RegName wasn't declared}} + +// REPEATED_PARAM-DEFINE-PATTERN: reg(RegName, RegName): RegName{{0x[0-9a-fA-F]+}} +// REPEATED_PARAM_CHECK: {{Parameter RegName is repeated}} \ No newline at end of file Index: test/FileCheck/pattern-usage-with-another-prefix.txt =================================================================== --- /dev/null +++ test/FileCheck/pattern-usage-with-another-prefix.txt @@ -0,0 +1,15 @@ +// RUN: not FileCheck -input-file %s %s -check-prefix=FOO -check-prefix=BAR 2>&1 | FileCheck %s + + +// FOO-DEFINE-PATTERN: hex_num: {{0x[0-9a-fA-F]+}} +// BAR-DEFINE-PATTERN: reg(RegName): RegName{{0x[0-9a-fA-F]+}} +// FOO-DEFINE-PATTERN: inc(VarName, Number): VarName{{ = }}VarName{{\+}}Number + +op0x33; +// FOO: op[[@hex_num]]; +reg0x0 +// BAR: [[@reg("reg")]] + +TEMP = TEMP+4 +// BAR: [[@inc("TEMP", "4")]] +// CHECK: {{template inc wasn't declared}} \ No newline at end of file Index: test/FileCheck/repeated-pattern-with-another-prefix.txt =================================================================== --- /dev/null +++ test/FileCheck/repeated-pattern-with-another-prefix.txt @@ -0,0 +1,9 @@ +// RUN: not FileCheck -input-file %s %s -check-prefix=FOO -check-prefix=BAR 2>&1 | FileCheck -check-prefix=BAR %s + +// FOO-DEFINE-PATTERN: hex_num: {{0x[0-9a-fA-F]+}} +// BAR-DEFINE-PATTERN: reg(RegName): RegName{{0x[0-9a-fA-F]+}} +// FOO-DEFINE-PATTERN: inc(VarName, Number): VarName{{ = }}VarName{{\+}}Number +// BAR-DEFINE-PATTERN: inc(VarName): VarName{{ = }}VarName + +// BAR: {{the template name inc is already used}} +// BAR: {{BAR-DEFINE-PATTERN: inc\(VarName\)}} \ No newline at end of file Index: utils/FileCheck/FileCheck.cpp =================================================================== --- utils/FileCheck/FileCheck.cpp +++ utils/FileCheck/FileCheck.cpp @@ -16,11 +16,14 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Regex.h" @@ -88,6 +91,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 +135,12 @@ /// getLoc - Return the location in source code. SMLoc getLoc() const { return PatternLoc; } + /// getRegExStr - Return regex pattern. + StringRef getRegExStr() const { return StringRef(RegExStr); } + + /// getFixedStr - Return fixed string. + StringRef getFixedStr() const { return FixedStr; } + /// 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,8 +190,257 @@ /// \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 regular expression with replaced templates + Expected ReplaceTemplates(StringRef TemplateName, + StringRef& Buffer, const StringRef Prefix, + SourceMgr &SM); + /// Add defined variable. + bool AddVariable(StringRef Name, unsigned &CurParen, SourceMgr &SM, + StringRef AddedRegex); }; +class PatternTemplate { + /// Name of template. + std::string TemplateName; + std::string TemplatePrefix; + /// Pattern which describes this template. + Pattern TemplatePattern; + + SmallVector DeclaredParameters; + /// Template parameters. + std::map Parameters; + + +public: + PatternTemplate(StringRef Name, StringRef Prefix, + Check::CheckType Ty = Check::CheckType::CheckNone) + : TemplateName(Name.str()), TemplatePrefix(Prefix.str()), + 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 + /// parameters. + bool ParseTemplate(StringRef TemplateString, StringRef Prefix, SourceMgr &SM, + unsigned LineNumber); + + /// Parse list of template parameters. + bool ParseParameters(StringRef ParametersList, SourceMgr &SM, + StringRef Buffer); + + /// Get template name. + const std::string &GetTemplateName() const; + + bool DefinedForPrefix(const StringRef Prefix) const; + + /// Get number of parameters which this template includes. + size_t getNumParameters() 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. + std::string GetRegularExpression(SmallVectorImpl &Values) const; + + const Pattern *GetTemplatePattern() const { return &TemplatePattern; } +}; + +bool PatternTemplate::ParseTemplate(StringRef TemplateString, StringRef Prefix, + SourceMgr &SM, unsigned LineNumber) { + size_t NewLine = TemplateString.find_first_of("\n"); + size_t CurPos = 0; + size_t NewPos = 0; + size_t DiffInLoc = 0; + bool IsOpen = false; + unsigned PatternsCount = 0; + while (CurPos < NewLine) { + if (!IsOpen) { + NewPos = TemplateString.find("{{", CurPos); + // Get substring with parameters. + if (CurPos < NewLine) { + IsOpen = true; + StringRef ParametersUsage = TemplateString.slice(CurPos, NewPos); + // Parse parameters. + SmallVector Params; + bool FirstParam = true; + ParametersUsage.split(Params, ' '); + for (const auto &Param : Params) { + if (!Param.empty()) { + // Check if parameters was declared. + if (!HasParameter(Param)) { + SM.PrintMessage(SMLoc::getFromPointer(TemplateString.data() + + CurPos + DiffInLoc), + SourceMgr::DK_Error, + "Parameter " + Param + " wasn't declared"); + return true; + } + + Parameters.emplace(CurPos + DiffInLoc - PatternsCount * 2, + Param.str()); + } + if (!FirstParam) { + DiffInLoc++; + } + FirstParam = false; + } + } + } else { + NewPos = TemplateString.find_first_of("}}", CurPos) + 2; + IsOpen = false; + PatternsCount++; + } + CurPos = NewPos; + } + + if (TemplatePattern.ParsePattern(TemplateString, Prefix, SM, LineNumber)) + return true; + + return false; +} + +bool PatternTemplate::ParseParameters(StringRef ParametersList, SourceMgr &SM, + StringRef Buffer) { + std::set UniqueParameters; + if (ParametersList.empty()) + return false; + ParametersList.split(DeclaredParameters, ','); + + // Remove extra spaces. + for (auto &Param : DeclaredParameters) { + Param = Param.ltrim(); + Param = Param.rtrim(); + if (UniqueParameters.find(Param) != UniqueParameters.end()) { + SM.PrintMessage( + SMLoc::getFromPointer(Buffer.data() + Buffer.find_first_of(Param)), + SourceMgr::DK_Error, "Parameter " + Param + " is repeated."); + return true; + } + UniqueParameters.insert(Param); + } + + return false; +} + +const std::string &PatternTemplate::GetTemplateName() const { + return TemplateName; +} + +size_t PatternTemplate::getNumParameters() const { + return DeclaredParameters.size(); +} + +bool PatternTemplate::DefinedForPrefix(const StringRef Prefix) const { + return Prefix.str() == TemplatePrefix; +} + +bool PatternTemplate::HasParameter(StringRef ParameterName) const { + for (const auto &Parameter : DeclaredParameters) { + if (Parameter == ParameterName) { + return true; + } + } + return false; +} + +std::string PatternTemplate::GetRegularExpression( + SmallVectorImpl &Values) const { + // Cteate map with values of each parameter. + StringMap ParametersValues; + SmallVectorImpl::iterator It = Values.begin(); + for (const auto &Parameter : DeclaredParameters) { + ParametersValues.insert(std::pair(Parameter, *It)); + ++It; + } + std::string Regex = TemplatePattern.getRegExStr().str(); + + int RegexWithoutParametersLoc = + 0; // variable for place of regex part without variables. + SmallVector RegexComponents; + // Change all parameters to their values. + for (const auto &Parameter : Parameters) { + StringRef Value = ParametersValues[Parameter.second]; + RegexComponents.push_back( + Regex.substr(RegexWithoutParametersLoc, + Parameter.first - RegexWithoutParametersLoc)); + + + RegexWithoutParametersLoc = Parameter.first + Parameter.second.size(); + RegexComponents.push_back("(" + Value.str() + ")"); + } + RegexComponents.push_back(Regex.substr(RegexWithoutParametersLoc)); + + if (!Parameters.empty()) { + Regex = join(RegexComponents.begin(), RegexComponents.end(), ""); + } + + + return Regex; +} + +class TemplatesCollection { + /// Described templates + StringMap> Templates; + + TemplatesCollection(); + +public: + static TemplatesCollection &Instance() { + static TemplatesCollection singleton; + return singleton; + } + /// Add template + PatternTemplate *AddTemplate(std::unique_ptr AddedTemplate); + /// Get template by its name. + PatternTemplate *GetTemplate(StringRef TemplateName); + /// Check if there is current template in collection. + bool HasTemplate(const StringRef &TemplateName, const StringRef Prefix); +}; + +TemplatesCollection::TemplatesCollection() {} + +PatternTemplate *TemplatesCollection::AddTemplate( + std::unique_ptr AddedTemplate) { + if (Templates.find(AddedTemplate->GetTemplateName()) != Templates.end()) + return nullptr; + std::string TemplateName = AddedTemplate->GetTemplateName(); + Templates + .insert(std::pair>( + AddedTemplate->GetTemplateName(), std::move(AddedTemplate))); + return Templates[TemplateName].get(); +} + +PatternTemplate *TemplatesCollection::GetTemplate(StringRef TemplateName) { + const auto PatternIt = Templates.find(TemplateName); + if (PatternIt == Templates.end()) + return nullptr; + return PatternIt->second.get(); +} + +bool TemplatesCollection::HasTemplate(const StringRef &TemplateName, + const StringRef Prefix) { + auto Template = Templates.find(TemplateName); + return Template != Templates.end() && + Template->second->DefinedForPrefix(Prefix); +} + +bool Pattern::AddVariable(StringRef Name, unsigned& CurParen, SourceMgr &SM, + StringRef AddedRegex) { + VariableDefs[Name] = CurParen; + RegExStr += '('; + ++CurParen; + + if (AddRegExToRegEx(AddedRegex, CurParen, SM)) + return true; + + RegExStr += ')'; + return false; +} bool Pattern::ParsePattern(StringRef PatternStr, StringRef Prefix, @@ -268,10 +527,39 @@ "invalid named regex reference, no ]] found"); return true; } + // Handle templates. + SmallVector Matches; + if (Regex(StringRef("(([a-zA-Z0-9_]+)? *@([a-zA-Z0-9_]+) " + "*)(\\(.+\\))? *]]"), + Regex::Newline) + .match(PatternStr, &Matches)) { + if (Matches[3].str() != "LINE") { + PatternStr = PatternStr.substr(2 + Matches[1].size()); + auto TemplateRegex = + ReplaceTemplates(Matches[3], PatternStr, Prefix, SM); + if (!TemplateRegex) { + handleAllErrors(TemplateRegex.takeError(), [&](const ErrorInfoBase &EI) {}); + return true; + } + // There is variable for remembering match. + if (!Matches[2].empty()) { + AddVariable(Matches[2], CurParen, SM, *TemplateRegex); + } else { + RegExStr += '('; + ++CurParen; + if (AddRegExToRegEx(*TemplateRegex, CurParen, SM)) + return true; + RegExStr += ')'; + } + continue; + } + } StringRef MatchStr = PatternStr.substr(2, End); PatternStr = PatternStr.substr(End+4); + + // Get the regex name (e.g. "foo"). size_t NameEnd = MatchStr.find(':'); StringRef Name = MatchStr.substr(0, NameEnd); @@ -332,14 +620,8 @@ } // Handle [[foo:.*]]. - VariableDefs[Name] = CurParen; - RegExStr += '('; - ++CurParen; - - if (AddRegExToRegEx(MatchStr.substr(NameEnd+1), CurParen, SM)) + if (AddVariable(Name, CurParen, SM, MatchStr.substr(NameEnd+1))) return true; - - RegExStr += ')'; } // Handle fixed string matches. @@ -355,7 +637,6 @@ RegExStr += " *"; RegExStr += '$'; } - return false; } @@ -441,8 +722,7 @@ // Look up the value and escape it so that we can put it into the regex. Value += Regex::escape(it->second); - } - + } // Plop it into the regex at the adjusted offset. TmpStr.insert(TmpStr.begin() + VariableUse.second + InsertOffset, Value.begin(), Value.end()); @@ -607,6 +887,96 @@ return StringRef::npos; } +Expected Pattern::ReplaceTemplates(StringRef TemplateName, + StringRef& Buffer, + const StringRef Prefix, + SourceMgr &SM) { + // Replace templates with regular expressions. + std::string ResultRegex; + bool ParametersEndFound = false; + // Check if template was declared + if (!TemplatesCollection::Instance().HasTemplate(TemplateName, Prefix)) { + SM.PrintMessage(SMLoc::getFromPointer(TemplateName.data()), + SourceMgr::DK_Error, + "template " + TemplateName.str() + " wasn't declared"); + return llvm::make_error( + "Template " + TemplateName.str() + " wasn't declared", + llvm::inconvertibleErrorCode()); + } + + PatternTemplate *Temp = + TemplatesCollection::Instance().GetTemplate(TemplateName); + SmallVector ParametersValues; + Buffer = Buffer.rtrim(); + if (Buffer.startswith("(")) + Buffer = Buffer.drop_front(1); + else + ParametersEndFound = true; + + while (!ParametersEndFound) { + Buffer = Buffer.ltrim(); + if (!Buffer.startswith("\"")) { + SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), + SourceMgr::DK_Error, + "Pattern parameter should be quoted string."); + return llvm::make_error( + "Pattern parameter should be quoted string", + llvm::inconvertibleErrorCode()); + } + // Find close quote. + size_t StringEnd = Buffer.find_first_of('"', 1); + if (StringEnd != StringRef::npos && Buffer[StringEnd - 1] == '\\') { + StringEnd = Buffer.find_first_of('"', StringEnd + 1); + } + if (StringEnd == StringRef::npos) { + SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), + SourceMgr::DK_Error, + "No close quote was found."); + return llvm::make_error( + "No close quote was found.", + llvm::inconvertibleErrorCode()); + } + ParametersValues.push_back(Buffer.slice(1, StringEnd)); + Buffer = Buffer.drop_front(StringEnd + 1); + Buffer = Buffer.ltrim(); + + if (Buffer.startswith(")")) + ParametersEndFound = true; + + if (!(Buffer.startswith(",") || Buffer.startswith(")"))) { + SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), + SourceMgr::DK_Error, + "Extra characters in parameters list"); + return llvm::make_error( + "Extra characters in parameters list.", + llvm::inconvertibleErrorCode()); + } + + if (!Buffer.empty()) + Buffer = Buffer.drop_front(1); + } + + Buffer = Buffer.drop_front(Buffer.find("]]") + 2); + + // Check number of parameters. + if (Temp->getNumParameters() != ParametersValues.size()) { + SM.PrintMessage( + SMLoc::getFromPointer(Buffer.data() + TemplateName.size()), + SourceMgr::DK_Error, + "Number of declared parameters differs from necessary."); + return llvm::make_error( + "Number of declared parameters differs from necessary.", + llvm::inconvertibleErrorCode()); + } + + ResultRegex = Temp->GetRegularExpression(ParametersValues); + VariableUses.insert(VariableUses.end(), + Temp->GetTemplatePattern()->VariableUses.begin(), + Temp->GetTemplatePattern()->VariableUses.end()); + VariableDefs.insert(Temp->GetTemplatePattern()->VariableDefs.begin(), + Temp->GetTemplatePattern()->VariableDefs.end()); + return ResultRegex; +} //===----------------------------------------------------------------------===// // Check Strings. @@ -696,63 +1066,50 @@ 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; + } + + if (Rest.startswith("DEFINE-PATTERN:")) { + CheckTypeSize = sizeof("-DEFINE-PATTERN:") - 1; + return Check::CheckPattern; + } // You can't combine -NOT with another suffix. if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") || @@ -778,11 +1135,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 +1177,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 +1191,18 @@ 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'); @@ -901,7 +1263,6 @@ "IMPLICIT-CHECK", SM, 0); } - std::vector DagNotMatches = ImplicitNegativeChecks; // LineNumber keeps track of the line on which CheckPrefix instances are @@ -911,12 +1272,11 @@ while (1) { Check::CheckType CheckTy; size_t PrefixLoc; + size_t CheckTypeSize; // See if a prefix occurs in the memory buffer. - StringRef UsedPrefix = FindFirstMatchingPrefix(Buffer, - LineNumber, - CheckTy, - PrefixLoc); + StringRef UsedPrefix = FindFirstMatchingPrefix( + SM, Buffer, LineNumber, CheckTy, PrefixLoc, CheckTypeSize); if (UsedPrefix.empty()) break; @@ -926,12 +1286,11 @@ 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) { - SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), - SourceMgr::DK_Error, + SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error, "unsupported -NOT combo on prefix '" + UsedPrefix + "'"); return true; } @@ -946,6 +1305,44 @@ // Remember the location of the start of the pattern, for diagnostics. SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); + if (CheckTy == Check::CheckType::CheckPattern) { + // Get name of pattern. + SmallVector Matches; + if (Regex(StringRef("^([a-zA-Z0-9_]+) *(\\((([a-zA-Z0-9_]+ *, " + "*)*[a-zA-Z0-9_]+)\\))? *:"), + Regex::Newline) + .match(Buffer, &Matches)) { + std::unique_ptr Template = + make_unique(Matches[1], UsedPrefix); + PatternTemplate *AddedTemplate = + TemplatesCollection::Instance().AddTemplate(std::move(Template)); + + // Error template with same name. + if (AddedTemplate == nullptr) { + SM.PrintMessage( + SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Warning, + "the template name " + Matches[1].str() + " is already used"); + return true; + } + + Buffer = Buffer.drop_front(Matches[0].size()); + EOL -= Matches[0].size(); + if (AddedTemplate->ParseParameters(Matches[3], SM, Buffer)) + return true; + if (AddedTemplate->ParseTemplate(Buffer.substr(0, EOL).ltrim(), + UsedPrefix, SM, LineNumber)) + return true; + } else { + SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), + SourceMgr::DK_Warning, + "No name was defined for pattern."); + return true; + } + + Buffer = Buffer.substr(EOL); + continue; + } + // Parse the pattern. Pattern P(CheckTy); if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber)) @@ -953,10 +1350,10 @@ // Verify that CHECK-LABEL lines do not define or use variables if ((CheckTy == Check::CheckLabel) && P.hasVariable()) { - SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), - SourceMgr::DK_Error, - "found '" + UsedPrefix + "-LABEL:'" - " with variable definition or use"); + SM.PrintMessage( + SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, + "found '" + UsedPrefix + "-LABEL:'" + " with variable definition or use"); return true; } @@ -968,8 +1365,8 @@ StringRef Type = CheckTy == Check::CheckNext ? "NEXT" : "SAME"; SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, - "found '" + UsedPrefix + "-" + Type + "' without previous '" - + UsedPrefix + ": line"); + "found '" + UsedPrefix + "-" + Type + + "' without previous '" + UsedPrefix + ": line"); return true; }