Changeset View
Changeset View
Standalone View
Standalone View
utils/FileCheck/FileCheck.cpp
Context not available. | |||||
#include "llvm/Support/Signals.h" | #include "llvm/Support/Signals.h" | ||||
#include "llvm/Support/SourceMgr.h" | #include "llvm/Support/SourceMgr.h" | ||||
#include "llvm/Support/raw_ostream.h" | #include "llvm/Support/raw_ostream.h" | ||||
#include "llvm/Support/Path.h" // <SYNOPSYS> | |||||
#include <algorithm> | #include <algorithm> | ||||
#include <cctype> | #include <cctype> | ||||
#include <map> | #include <map> | ||||
Context not available. | |||||
#include <string> | #include <string> | ||||
#include <system_error> | #include <system_error> | ||||
#include <vector> | #include <vector> | ||||
// <SYNOPSYS> | |||||
#include <set> | |||||
#define MAX_INCLUDING_DEPTH 20 // maximum depth for including files. | |||||
// </SYNOPSYS> | |||||
using namespace llvm; | using namespace llvm; | ||||
static cl::opt<std::string> | static cl::opt<std::string> | ||||
Context not available. | |||||
"this pattern occur which are not matched by a positive pattern"), | "this pattern occur which are not matched by a positive pattern"), | ||||
cl::value_desc("pattern")); | cl::value_desc("pattern")); | ||||
// <SYNOPSYS> | |||||
static cl::list<std::string> IncludedDirectories( | |||||
"I", | |||||
cl::desc("Add directories for searching included files in CHECK-INCLUDE")); | |||||
static cl::opt<bool> | |||||
RegexPrefixesOn ("regex-prefixes", | |||||
cl::desc("Use checks with prefixes which can be described as regular expressions.")); | |||||
// </SYNOPSYS> | |||||
static cl::opt<bool> AllowEmptyInput( | static cl::opt<bool> AllowEmptyInput( | ||||
"allow-empty", cl::init(false), | "allow-empty", cl::init(false), | ||||
cl::desc("Allow the input file to be empty. This is useful when making\n" | cl::desc("Allow the input file to be empty. This is useful when making\n" | ||||
Context not available. | |||||
CheckNot, | CheckNot, | ||||
CheckDAG, | CheckDAG, | ||||
CheckLabel, | CheckLabel, | ||||
// <SYNOPSYS> | |||||
CheckLabelDag, | |||||
CheckRepeated, | |||||
CheckNextRepeated, | |||||
CheckInclude, | |||||
CheckWord, | |||||
CheckWordNext, | |||||
CheckWordSame, | |||||
CheckWordNot, | |||||
CheckWordDAG, | |||||
CheckPattern, | |||||
// </SYNOPSYS> | |||||
/// MatchEOF - When set, this pattern only matches the end of file. This is | /// MatchEOF - When set, this pattern only matches the end of file. This is | ||||
/// used for trailing CHECK-NOTs. | /// used for trailing CHECK-NOTs. | ||||
Context not available. | |||||
/// E.g. for the pattern "foo[[bar:.*]]baz", VariableDefs will map "bar" to 1. | /// E.g. for the pattern "foo[[bar:.*]]baz", VariableDefs will map "bar" to 1. | ||||
std::map<StringRef, unsigned> VariableDefs; | std::map<StringRef, unsigned> VariableDefs; | ||||
// <SYNOPSYS> | |||||
/// MinRepeatNumber - minimum number of repeats for repeated patten type. | |||||
int MinRepeatNumber; | |||||
/// MaxRepeatNumber - maximum number of repeats for repeated patten type. Infinity = -1. | |||||
int MaxRepeatNumber; | |||||
// </SYNOPSYS> | |||||
public: | public: | ||||
Pattern(Check::CheckType Ty) | Pattern(Check::CheckType Ty, int MinNumber = 0, int MaxNumber = -1) | ||||
: CheckTy(Ty) { } | : CheckTy(Ty), MinRepeatNumber(MinNumber), MaxRepeatNumber(MaxNumber) { } // <SYNOPSYS> | ||||
/// getLoc - Return the location in source code. | /// getLoc - Return the location in source code. | ||||
SMLoc getLoc() const { return PatternLoc; } | SMLoc getLoc() const { return PatternLoc; } | ||||
// <SYNOPSYS> | |||||
int getMinRepeatNumber() const { return MinRepeatNumber; } | |||||
int getMaxRepeatNumber() const { return MaxRepeatNumber; } | |||||
StringRef getFixedString() const { return FixedStr; } | |||||
std::string getRegExStr() const { return RegExStr; } | |||||
// </SYNOPSYS> | |||||
/// ParsePattern - Parse the given string into the Pattern. Prefix provides | /// ParsePattern - Parse the given string into the Pattern. Prefix provides | ||||
/// which prefix is being matched, SM provides the SourceMgr used for error | /// 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 | /// reports, and LineNumber is the line number in the input file from which | ||||
Context not available. | |||||
/// \return offset of the closing sequence within Str, or npos if it was not | /// \return offset of the closing sequence within Str, or npos if it was not | ||||
/// found. | /// found. | ||||
size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM); | size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM); | ||||
// <SYNOPSYS> | |||||
/// 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); | |||||
// </SYNOPSYS> | |||||
}; | }; | ||||
// <SYNOPSYS> | |||||
class PatternTemplate { | |||||
/// Name of template. | |||||
std::string TemplateName; | |||||
/// Pattern which describes this template. | |||||
Pattern TemplatePattern; | |||||
/// Template parametrs. | |||||
std::map<size_t, StringRef> 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<StringRef, StringRef> &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<StringRef, 2> 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<size_t, StringRef>(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<StringRef> 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<StringRef, StringRef> &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<std::string, PatternTemplate*> 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<std::string, PatternTemplate*> TemplatesCollection::Templates; | |||||
bool TemplatesCollection::AddTemplate(PatternTemplate *AddedTemplate) { | |||||
if (Templates.find(AddedTemplate->GetTemplateName()) != Templates.end()) { | |||||
return false; | |||||
} | |||||
LastAddedTemplate = AddedTemplate->GetTemplateName(); | |||||
return Templates.insert(std::pair<std::string, PatternTemplate*>(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(); | |||||
} | |||||
// </SYNOPSYS> | |||||
bool Pattern::ParsePattern(StringRef PatternStr, | bool Pattern::ParsePattern(StringRef PatternStr, | ||||
StringRef Prefix, | StringRef Prefix, | ||||
SourceMgr &SM, | SourceMgr &SM, | ||||
Context not available. | |||||
} | } | ||||
// Check to see if this is a fixed string, or if it has regex pieces. | // Check to see if this is a fixed string, or if it has regex pieces. | ||||
if (!MatchFullLinesHere && | if (!MatchFullLinesHere && (PatternStr.size() < 2 || | ||||
(PatternStr.size() < 2 || (PatternStr.find("{{") == StringRef::npos && | (PatternStr.find("{{") == StringRef::npos && | ||||
PatternStr.find("[[") == StringRef::npos))) { | PatternStr.find("[[") == StringRef::npos))) { | ||||
FixedStr = PatternStr; | FixedStr = PatternStr; | ||||
return false; | return false; | ||||
} | } | ||||
Context not available. | |||||
return true; | return true; | ||||
} | } | ||||
// <SYNOPSYS> | |||||
size_t NextChar = End + 2; | |||||
while (NextChar < PatternStr.size() && PatternStr[NextChar] == '}') { | |||||
NextChar++; | |||||
} | |||||
End = NextChar - 2; | |||||
// </SYNOPSYS> | |||||
// Enclose {{}} patterns in parens just like [[]] even though we're not | // Enclose {{}} patterns in parens just like [[]] even though we're not | ||||
// capturing the result for any purpose. This is required in case the | // capturing the result for any purpose. This is required in case the | ||||
// expression contains an alternation like: CHECK: abc{{x|z}}def. We | // expression contains an alternation like: CHECK: abc{{x|z}}def. We | ||||
Context not available. | |||||
RegExStr += '('; | RegExStr += '('; | ||||
++CurParen; | ++CurParen; | ||||
if (AddRegExToRegEx(PatternStr.substr(2, End-2), CurParen, SM)) | // <SYNOPSYS> | ||||
StringRef RegexPart = PatternStr.substr(2, End-2); | |||||
// Find quantifier for replacing. | |||||
size_t NullQuantifier = RegexPart.find("{,"); | |||||
if (NullQuantifier != StringRef::npos && (NullQuantifier == 0 || RegexPart[NullQuantifier - 1] != '\\')) { | |||||
// Need replacing. | |||||
StringRef FirstPart = RegexPart.drop_back(RegexPart.size() - NullQuantifier - 1); | |||||
StringRef SecondPart = RegexPart.drop_front(NullQuantifier + 1); | |||||
RegexPart = StringRef(FirstPart.str() + "0" + SecondPart.str()); | |||||
} | |||||
// </SYNOPSYS> | |||||
if (AddRegExToRegEx(RegexPart, CurParen, SM)) | |||||
return true; | return true; | ||||
RegExStr += ')'; | RegExStr += ')'; | ||||
Context not available. | |||||
return false; | return false; | ||||
} | } | ||||
// <SYNOPSYS> | |||||
bool Pattern::ReplaceTemplates(StringRef RS, SourceMgr &SM, std::string &ResultRegex) { | |||||
// Replace templates with regular expressions. | |||||
SmallVector<StringRef, 2> 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<StringRef, StringRef> 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<StringRef, StringRef>(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; | |||||
} | |||||
// </SYNOPSYS> | |||||
bool Pattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, | bool Pattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, | ||||
SourceMgr &SM) { | SourceMgr &SM) { | ||||
// <SYNOPSYS> | |||||
std::string ResultRegex; | |||||
if (ReplaceTemplates(RS, SM, ResultRegex)) | |||||
return true; | |||||
RS = StringRef(ResultRegex); | |||||
// </SYNOPSYS> | |||||
Regex R(RS); | Regex R(RS); | ||||
std::string Error; | std::string Error; | ||||
if (!R.isValid(Error)) { | if (!R.isValid(Error)) { | ||||
Context not available. | |||||
// If there are variable uses, we need to create a temporary string with the | // If there are variable uses, we need to create a temporary string with the | ||||
// actual value. | // actual value. | ||||
StringRef RegExToMatch = RegExStr; | StringRef RegExToMatch = RegExStr; | ||||
std::string TmpStr; | std::string TmpStr; | ||||
if (!VariableUses.empty()) { | if (!VariableUses.empty()) { | ||||
TmpStr = RegExStr; | TmpStr = RegExStr; | ||||
Context not available. | |||||
/// file). | /// file). | ||||
std::vector<Pattern> DagNotStrings; | std::vector<Pattern> DagNotStrings; | ||||
CheckString(const Pattern &P, StringRef S, SMLoc L) | |||||
: Pat(P), Prefix(S), Loc(L) {} | |||||
CheckString(const Pattern &P, | |||||
StringRef S, | |||||
SMLoc L) | |||||
: Pat(P), Prefix(S), Loc(L) {} | |||||
/// Check - Match check string and its "not strings" and/or "dag strings". | /// Check - Match check string and its "not strings" and/or "dag strings". | ||||
size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode, | size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode, | ||||
size_t &MatchLen, StringMap<StringRef> &VariableTable) const; | size_t &MatchLen, StringMap<StringRef> &VariableTable) const; | ||||
Context not available. | |||||
/// CheckNext - Verify there is a single line in the given buffer. | /// CheckNext - Verify there is a single line in the given buffer. | ||||
bool CheckNext(const SourceMgr &SM, StringRef Buffer) const; | bool CheckNext(const SourceMgr &SM, StringRef Buffer) const; | ||||
// <SYNOPSYS> | |||||
/// CheckWord - Verify there is a single word. | |||||
bool CheckWord(const size_t &MatchPos, const size_t &MatchLen, StringRef Buffer) const; | |||||
// </SYNOPSYS> | |||||
/// CheckSame - Verify there is no newline in the given buffer. | /// CheckSame - Verify there is no newline in the given buffer. | ||||
bool CheckSame(const SourceMgr &SM, StringRef Buffer) const; | bool CheckSame(const SourceMgr &SM, StringRef Buffer) const; | ||||
Context not available. | |||||
return (isalnum(c) || c == '-' || c == '_'); | return (isalnum(c) || c == '-' || c == '_'); | ||||
} | } | ||||
// Get the size of the prefix extension. | // <SYNOPSYS> | ||||
static size_t CheckTypeSize(Check::CheckType Ty) { | static Check::CheckType FindCheckType(SourceMgr &SM, StringRef Buffer, StringRef Prefix, size_t &CheckTypeSize, | ||||
switch (Ty) { | int &MinRepeatNumber, int &MaxRepeatNumber) { | ||||
case Check::CheckNone: | MinRepeatNumber = 0; | ||||
case Check::CheckBadNot: | MaxRepeatNumber = -1; | ||||
return 0; | CheckTypeSize = 0; | ||||
bool NextStatement = false; | |||||
case Check::CheckPlain: | size_t StartRegexInPrefix = Buffer.find("{{"); | ||||
return sizeof(":") - 1; | size_t EndRegexInPrefix = Buffer.find("}}"); | ||||
size_t StringEnd = Buffer.find(':'); | |||||
case Check::CheckNext: | if (StringEnd == StringRef::npos) { | ||||
return sizeof("-NEXT:") - 1; | return Check::CheckNone; | ||||
} | |||||
std::string StringForMatch; | |||||
StringRef Rest; | |||||
if (RegexPrefixesOn && EndRegexInPrefix < StringEnd && | |||||
(StartRegexInPrefix == StringRef::npos || StartRegexInPrefix > EndRegexInPrefix)) { | |||||
StringForMatch = Buffer.substr(EndRegexInPrefix + 2, StringEnd - EndRegexInPrefix - 1).str(); | |||||
Rest = Buffer.drop_front(EndRegexInPrefix + 2); | |||||
} else { | |||||
StringForMatch = Buffer.substr(Prefix.size(), StringEnd - Prefix.size() + 1).str(); | |||||
Rest = Buffer.drop_front(Prefix.size()); | |||||
} | |||||
case Check::CheckSame: | if (Rest.startswith("-NEXT")) { | ||||
return sizeof("-SAME:") - 1; | CheckTypeSize += sizeof("-NEXT") - 1; | ||||
StringForMatch = StringForMatch.substr(5); | |||||
case Check::CheckNot: | NextStatement = true; | ||||
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"); | SmallVector<StringRef, 20> Matches; | ||||
} | StringRef MatchedString = StringRef(StringForMatch); | ||||
static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) { | |||||
char NextChar = Buffer[Prefix.size()]; | |||||
// Verify that the : is present after the prefix. | // Verify that the : is present after the prefix. | ||||
if (NextChar == ':') | if (MatchedString.startswith(":")) { | ||||
CheckTypeSize += 1; | |||||
if (NextStatement) { | |||||
return Check::CheckNext; | |||||
} | |||||
return Check::CheckPlain; | return Check::CheckPlain; | ||||
} | |||||
if (Regex(StringRef("^((\\{([0-9]+)\\})|(\\{([0-9]*),([0-9]*)\\})):"), Regex::Newline).match(MatchedString, &Matches)) { | |||||
CheckTypeSize += Matches[0].size(); | |||||
// Was match with exact number. | |||||
if (Matches[3].size() != 0) { | |||||
MinRepeatNumber = std::stoi(Matches[3].str().c_str()); | |||||
MaxRepeatNumber = MinRepeatNumber; | |||||
} else { | |||||
if (Matches[5].size() == 0 && Matches[6].size() == 0) { | |||||
return Check::CheckNone; | |||||
} | |||||
if (Matches[5].size() != 0) { | |||||
MinRepeatNumber = std::stoi(Matches[5].str().c_str()); | |||||
} | |||||
if (Matches[6].size() != 0) { | |||||
MaxRepeatNumber = std::stoi(Matches[6].str().c_str()); | |||||
} | |||||
} | |||||
if (NextChar != '-') | if (NextStatement) { | ||||
return Check::CheckNone; | return Check::CheckNextRepeated; | ||||
} | |||||
return Check::CheckRepeated; | |||||
} | |||||
StringRef Rest = Buffer.drop_front(Prefix.size() + 1); | if (MatchedString.startswith("*:")) { | ||||
if (Rest.startswith("NEXT:")) | CheckTypeSize += 2; | ||||
return Check::CheckNext; | if (NextStatement) { | ||||
return Check::CheckNextRepeated; | |||||
} | |||||
return Check::CheckRepeated; | |||||
} | |||||
if (Rest.startswith("SAME:")) | if (MatchedString.startswith("+:")) { | ||||
CheckTypeSize += 2; | |||||
MinRepeatNumber = 1; | |||||
if (NextStatement) { | |||||
return Check::CheckNextRepeated; | |||||
} | |||||
return Check::CheckRepeated; | |||||
} | |||||
if (MatchedString.startswith("-SAME:")) { | |||||
CheckTypeSize = sizeof("-SAME:") - 1; | |||||
return Check::CheckSame; | return Check::CheckSame; | ||||
} | |||||
if (Rest.startswith("NOT:")) | if (MatchedString.startswith("-NOT:")) { | ||||
CheckTypeSize = sizeof("-NOT:") - 1; | |||||
return Check::CheckNot; | return Check::CheckNot; | ||||
} | |||||
if (Rest.startswith("DAG:")) | if (MatchedString.startswith("-DAG:")) { | ||||
CheckTypeSize = sizeof("-DAG:") - 1; | |||||
return Check::CheckDAG; | return Check::CheckDAG; | ||||
} | |||||
if (Rest.startswith("LABEL:")) | if (MatchedString.startswith("-LABEL:")) { | ||||
CheckTypeSize = sizeof("-LABEL:") - 1; | |||||
return Check::CheckLabel; | return Check::CheckLabel; | ||||
} | |||||
if (MatchedString.startswith("-LABEL-DAG:")) { | |||||
CheckTypeSize = sizeof("-LABEL-DAG:") - 1; | |||||
return Check::CheckLabelDag; | |||||
} | |||||
if (MatchedString.startswith("-INCLUDE:")) { | |||||
CheckTypeSize = sizeof("-INCLUDE:") - 1; | |||||
return Check::CheckInclude; | |||||
} | |||||
if (MatchedString.startswith("-WORD:")) { | |||||
CheckTypeSize = sizeof("-WORD:") - 1; | |||||
return Check::CheckWord; | |||||
} | |||||
if (MatchedString.startswith("-WORD-NEXT:")) { | |||||
CheckTypeSize = sizeof("-WORD-NEXT:") - 1; | |||||
return Check::CheckWordNext; | |||||
} | |||||
if (MatchedString.startswith("-WORD-SAME:")) { | |||||
CheckTypeSize = sizeof("-WORD-SAME:") - 1; | |||||
return Check::CheckWordSame; | |||||
} | |||||
if (MatchedString.startswith("-WORD-NOT:")) { | |||||
CheckTypeSize = sizeof("-WORD-NOT:") - 1; | |||||
return Check::CheckWordNot; | |||||
} | |||||
if (MatchedString.startswith("-WORD-DAG:")) { | |||||
CheckTypeSize = sizeof("-WORD-DAG:") - 1; | |||||
return Check::CheckWordDAG; | |||||
} | |||||
if (Regex(StringRef("-PATTERN ([a-zA-Z0-9_]+):"), Regex::Newline).match(MatchedString, &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(); | |||||
return Check::CheckPattern; | |||||
} | |||||
// You can't combine -NOT with another suffix. | // You can't combine -NOT with another suffix. | ||||
if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") || | if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") || | ||||
Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") || | Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") || | ||||
Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:")) | Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:")) { | ||||
CheckTypeSize = 0; | |||||
return Check::CheckBadNot; | return Check::CheckBadNot; | ||||
} | |||||
return Check::CheckNone; | return Check::CheckNone; | ||||
} | } | ||||
// </SYNOPSYS> | |||||
// From the given position, find the next character after the word. | // From the given position, find the next character after the word. | ||||
static size_t SkipWord(StringRef Str, size_t Loc) { | static size_t SkipWord(StringRef Str, size_t Loc) { | ||||
Context not available. | |||||
// string and the location will be StringRef::npos. If one prefix is a substring | // 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 | // of another, the maximal match should be found. e.g. if "A" and "AA" are | ||||
// prefixes then AA-CHECK: should match the second one. | // prefixes then AA-CHECK: should match the second one. | ||||
static StringRef FindFirstCandidateMatch(StringRef &Buffer, | static StringRef FindFirstCandidateMatch(SourceMgr &SM, | ||||
StringRef &Buffer, | |||||
Check::CheckType &CheckTy, | Check::CheckType &CheckTy, | ||||
size_t &CheckLoc) { | size_t &CheckLoc, | ||||
size_t &CheckTypeSize, | |||||
int &MinRepeatNumber, | |||||
int &MaxRepeatNumber) { | |||||
StringRef FirstPrefix; | StringRef FirstPrefix; | ||||
size_t FirstLoc = StringRef::npos; | size_t FirstLoc = StringRef::npos; | ||||
size_t FirstTypeSize = StringRef::npos; | |||||
size_t SearchLoc = StringRef::npos; | size_t SearchLoc = StringRef::npos; | ||||
Check::CheckType FirstTy = Check::CheckNone; | Check::CheckType FirstTy = Check::CheckNone; | ||||
Context not available. | |||||
for (StringRef Prefix : CheckPrefixes) { | for (StringRef Prefix : CheckPrefixes) { | ||||
size_t PrefixLoc = Buffer.find(Prefix); | size_t PrefixLoc = Buffer.find(Prefix); | ||||
// <SYNOPSYS> | |||||
if (RegexPrefixesOn) { | |||||
SmallVector<StringRef, 4> Matches; | |||||
// Try ti find prefixes defined as regexes. | |||||
Regex PrefixesWithRegexes(StringRef("\\{\\{(.+)\\}\\}(-.+)?:.+$")); | |||||
StringRef BufferCopy = Buffer; | |||||
size_t DiffInLoc = 0; | |||||
while (PrefixesWithRegexes.match(BufferCopy, &Matches) && (DiffInLoc < PrefixLoc || PrefixLoc == StringRef::npos)) { | |||||
// Get regex part | |||||
StringRef RegexPart = Matches[1]; | |||||
if (RegexPart.find("}}") != StringRef::npos) { | |||||
RegexPart = RegexPart.substr(0, RegexPart.find("}}")); | |||||
} | |||||
size_t RegexPrefixLoc = Matches[1].data()-BufferCopy.data(); | |||||
DiffInLoc += RegexPrefixLoc; | |||||
// Check if current prefix matches with found. | |||||
if (Regex(RegexPart).match(Prefix)) { | |||||
if (DiffInLoc < PrefixLoc) { | |||||
PrefixLoc = DiffInLoc; | |||||
Prefix = StringRef(RegexPart.str() + "}}"); | |||||
} | |||||
} | |||||
if (BufferCopy.find("\n", RegexPrefixLoc) != StringRef::npos) { | |||||
DiffInLoc += BufferCopy.find("\n", RegexPrefixLoc) - RegexPrefixLoc; | |||||
BufferCopy = BufferCopy.drop_front(BufferCopy.find("\n", RegexPrefixLoc)); | |||||
} else { | |||||
BufferCopy = BufferCopy.drop_front(RegexPrefixLoc); | |||||
} | |||||
} | |||||
} | |||||
// </SYNOPSYS> | |||||
if (PrefixLoc == StringRef::npos) | if (PrefixLoc == StringRef::npos) | ||||
continue; | continue; | ||||
Context not available. | |||||
// since a partial match could be a substring of a later, valid prefix. | // since a partial match could be a substring of a later, valid prefix. | ||||
// Need to skip to the end of the word, otherwise we could end up | // Need to skip to the end of the word, otherwise we could end up | ||||
// matching a prefix in a substring later. | // matching a prefix in a substring later. | ||||
if (PrefixLoc < SearchLoc) | if (PrefixLoc < SearchLoc) | ||||
SearchLoc = SkipWord(Buffer, PrefixLoc); | SearchLoc = SkipWord(Buffer, PrefixLoc); | ||||
Context not available. | |||||
// We only want to find the first match to avoid skipping some. | // We only want to find the first match to avoid skipping some. | ||||
if (PrefixLoc > FirstLoc) | if (PrefixLoc > FirstLoc) | ||||
continue; | continue; | ||||
// If one matching check-prefix is a prefix of another, choose the | // If one matching check-prefix is a prefix of another, choose the | ||||
// longer one. | // longer one. | ||||
if (PrefixLoc == FirstLoc && Prefix.size() < FirstPrefix.size()) | if (PrefixLoc == FirstLoc && Prefix.size() < FirstPrefix.size()) | ||||
Context not available. | |||||
continue; | continue; | ||||
StringRef Rest = Buffer.drop_front(PrefixLoc); | StringRef Rest = Buffer.drop_front(PrefixLoc); | ||||
// Make sure we have actually found the prefix, and not a word containing | // Make sure we have actually found the prefix, and not a word containing | ||||
// it. This should also prevent matching the wrong prefix when one is a | // it. This should also prevent matching the wrong prefix when one is a | ||||
// substring of another. | // substring of another. | ||||
Context not available. | |||||
if (PrefixLoc != 0 && IsPartOfWord(Buffer[PrefixLoc - 1])) | if (PrefixLoc != 0 && IsPartOfWord(Buffer[PrefixLoc - 1])) | ||||
FirstTy = Check::CheckNone; | FirstTy = Check::CheckNone; | ||||
else | else | ||||
FirstTy = FindCheckType(Rest, Prefix); | FirstTy = FindCheckType(SM, Rest, Prefix, FirstTypeSize, MinRepeatNumber, MaxRepeatNumber); // <SYNOPSYS> | ||||
FirstLoc = PrefixLoc; | FirstLoc = PrefixLoc; | ||||
FirstPrefix = Prefix; | FirstPrefix = Prefix; | ||||
} | } | ||||
Context not available. | |||||
CheckTy = FirstTy; | CheckTy = FirstTy; | ||||
CheckLoc = FirstLoc; | CheckLoc = FirstLoc; | ||||
CheckTypeSize = FirstTypeSize; | |||||
return FirstPrefix; | return FirstPrefix; | ||||
} | } | ||||
static StringRef FindFirstMatchingPrefix(StringRef &Buffer, | static StringRef FindFirstMatchingPrefix(SourceMgr &SM, | ||||
StringRef &Buffer, | |||||
unsigned &LineNumber, | unsigned &LineNumber, | ||||
Check::CheckType &CheckTy, | Check::CheckType &CheckTy, | ||||
size_t &CheckLoc) { | size_t &CheckLoc, | ||||
size_t &CheckTypeSize, | |||||
int &MinRepeatNumber, | |||||
int &MaxRepeatNumber) { | |||||
while (!Buffer.empty()) { | while (!Buffer.empty()) { | ||||
StringRef Prefix = FindFirstCandidateMatch(Buffer, CheckTy, CheckLoc); | StringRef Prefix = FindFirstCandidateMatch(SM, Buffer, CheckTy, CheckLoc, CheckTypeSize, MinRepeatNumber, MaxRepeatNumber); | ||||
// If we found a real match, we are done. | // If we found a real match, we are done. | ||||
if (!Prefix.empty()) { | if (!Prefix.empty()) { | ||||
LineNumber += Buffer.substr(0, CheckLoc).count('\n'); | LineNumber += Buffer.substr(0, CheckLoc).count('\n'); | ||||
Context not available. | |||||
/// expected strings. The strings are added to the CheckStrings vector. | /// expected strings. The strings are added to the CheckStrings vector. | ||||
/// Returns true in case of an error, false otherwise. | /// Returns true in case of an error, false otherwise. | ||||
static bool ReadCheckFile(SourceMgr &SM, | static bool ReadCheckFile(SourceMgr &SM, | ||||
std::vector<CheckString> &CheckStrings) { | std::vector<CheckString> &CheckStrings, | ||||
std::string Filename = CheckFilename, | |||||
int IncludingLevel = 0) { | |||||
ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = | ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = | ||||
MemoryBuffer::getFileOrSTDIN(CheckFilename); | MemoryBuffer::getFileOrSTDIN(Filename); | ||||
if (std::error_code EC = FileOrErr.getError()) { | if (std::error_code EC = FileOrErr.getError()) { | ||||
errs() << "Could not open check file '" << CheckFilename | errs() << "Could not open check file '" << Filename | ||||
<< "': " << EC.message() << '\n'; | << "': " << EC.message() << '\n'; | ||||
return true; | return true; | ||||
} | } | ||||
Context not available. | |||||
while (1) { | while (1) { | ||||
Check::CheckType CheckTy; | Check::CheckType CheckTy; | ||||
// <SYNOPSYS> | |||||
int MinRepeatNumber; | |||||
int MaxRepeatNumber; | |||||
// </SYNOPSYS> | |||||
size_t PrefixLoc; | size_t PrefixLoc; | ||||
size_t CheckTypeSize; | |||||
// See if a prefix occurs in the memory buffer. | // See if a prefix occurs in the memory buffer. | ||||
StringRef UsedPrefix = FindFirstMatchingPrefix(Buffer, | StringRef UsedPrefix = FindFirstMatchingPrefix(SM, | ||||
Buffer, | |||||
LineNumber, | LineNumber, | ||||
CheckTy, | CheckTy, | ||||
PrefixLoc); | PrefixLoc, | ||||
CheckTypeSize, | |||||
MinRepeatNumber, | |||||
MaxRepeatNumber); | |||||
if (UsedPrefix.empty()) | if (UsedPrefix.empty()) | ||||
break; | break; | ||||
Context not available. | |||||
const char *UsedPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1); | const char *UsedPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1); | ||||
// PrefixLoc is to the start of the prefix. Skip to the end. | // 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. | // Complain about useful-looking but unsupported suffixes. | ||||
if (CheckTy == Check::CheckBadNot) { | if (CheckTy == Check::CheckBadNot) { | ||||
Context not available. | |||||
// Remember the location of the start of the pattern, for diagnostics. | // Remember the location of the start of the pattern, for diagnostics. | ||||
SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); | SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); | ||||
// <SYNOPSYS> | |||||
if (CheckTy == Check::CheckType::CheckPattern) { | |||||
if (TemplatesCollection::GetLastAddedTemplate()->ParseTemplate(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber)) { | |||||
return true; | |||||
} | |||||
Buffer = Buffer.substr(EOL); | |||||
continue; | |||||
} | |||||
// </SYNOPSYS> | |||||
// Parse the pattern. | // Parse the pattern. | ||||
Pattern P(CheckTy); | Pattern P(CheckTy, MinRepeatNumber, MaxRepeatNumber); | ||||
if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber)) | if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber)) | ||||
return true; | return true; | ||||
// Verify that CHECK-LABEL lines do not define or use variables | // <SYNOPSYS> | ||||
if ((CheckTy == Check::CheckLabel) && P.hasVariable()) { | // if included another file | ||||
SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), | if (CheckTy == Check::CheckInclude) { | ||||
SourceMgr::DK_Error, | // Check for escaping infinite including | ||||
"found '" + UsedPrefix + "-LABEL:'" | if (IncludingLevel > MAX_INCLUDING_DEPTH) { | ||||
" with variable definition or use"); | SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), | ||||
return true; | SourceMgr::DK_Error, | ||||
} | "Maximum including level!"); | ||||
return true; | |||||
} | |||||
// Get included file name. | |||||
StringRef IncludedFileName = P.getFixedString(); | |||||
Buffer = Buffer.substr(EOL); | std::vector<CheckString> IncludedCheckStrings; | ||||
// Try find file in included directories. | |||||
ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = | |||||
MemoryBuffer::getFileOrSTDIN(StringRef(IncludedFileName)); | |||||
if (FileOrErr.getError()) { | |||||
for (std::string Directory : IncludedDirectories) { | |||||
StringRef FullIncludedFileName = StringRef(Directory + '/' + IncludedFileName.str()); | |||||
FileOrErr = MemoryBuffer::getFileOrSTDIN(FullIncludedFileName); | |||||
if (!FileOrErr.getError()) { | |||||
IncludedFileName = FullIncludedFileName; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
// Read it and get check strings from it. | |||||
ReadCheckFile(SM, IncludedCheckStrings, IncludedFileName, IncludingLevel+1); | |||||
CheckStrings.insert(CheckStrings.end(), IncludedCheckStrings.begin(), IncludedCheckStrings.end()); | |||||
} else { | |||||
// </SYNOPSYS> | |||||
// Verify that CHECK-LABEL lines do not define or use variables | |||||
if ((CheckTy == Check::CheckLabel || CheckTy == Check::CheckLabelDag) && P.hasVariable()) { | |||||
SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), | |||||
SourceMgr::DK_Error, | |||||
"found '" + UsedPrefix + "-LABEL:'" | |||||
" with variable definition or use"); | |||||
return true; | |||||
} | |||||
// Verify that CHECK-NEXT lines have at least one CHECK line before them. | Buffer = Buffer.substr(EOL); | ||||
if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame) && | |||||
CheckStrings.empty()) { | |||||
StringRef Type = CheckTy == Check::CheckNext ? "NEXT" : "SAME"; | |||||
SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), | |||||
SourceMgr::DK_Error, | |||||
"found '" + UsedPrefix + "-" + Type + "' without previous '" | |||||
+ UsedPrefix + ": line"); | |||||
return true; | |||||
} | |||||
// Handle CHECK-DAG/-NOT. | // Verify that CHECK-NEXT lines have at least one CHECK line before them. | ||||
if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) { | if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckNextRepeated || CheckTy == Check::CheckSame || | ||||
DagNotMatches.push_back(P); | CheckTy == Check::CheckWordNext || CheckTy == Check::CheckWordSame) && | ||||
continue; | CheckStrings.empty()) { | ||||
StringRef Type = CheckTy == Check::CheckNext || Check::CheckWordNext || Check::CheckNextRepeated ? "NEXT" : "SAME"; | |||||
SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), | |||||
SourceMgr::DK_Error, | |||||
"found '" + UsedPrefix + "-" + Type + "' without previous '" | |||||
+ UsedPrefix + ": line"); | |||||
return true; | |||||
} | |||||
// Handle CHECK-DAG/-NOT. | |||||
if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot || | |||||
CheckTy == Check::CheckWordDAG || CheckTy == Check::CheckWordNot) { | |||||
DagNotMatches.push_back(P); | |||||
continue; | |||||
} | |||||
// Okay, add the string we captured to the output vector and move on. | |||||
CheckStrings.emplace_back(P, UsedPrefix, PatternLoc); | |||||
std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); | |||||
DagNotMatches = ImplicitNegativeChecks; | |||||
} | } | ||||
// Okay, add the string we captured to the output vector and move on. | |||||
CheckStrings.emplace_back(P, UsedPrefix, PatternLoc); | |||||
std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); | |||||
DagNotMatches = ImplicitNegativeChecks; | |||||
} | } | ||||
// Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first | // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first | ||||
Context not available. | |||||
errs() << "\'" << *I << ":'"; | errs() << "\'" << *I << ":'"; | ||||
++I; | ++I; | ||||
} | } | ||||
for (; I != E; ++I) | for (; I != E; ++I) | ||||
errs() << ", \'" << *I << ":'"; | errs() << ", \'" << *I << ":'"; | ||||
errs() << '\n'; | errs() << '\n'; | ||||
Context not available. | |||||
bool IsLabelScanMode, size_t &MatchLen, | bool IsLabelScanMode, size_t &MatchLen, | ||||
StringMap<StringRef> &VariableTable) const { | StringMap<StringRef> &VariableTable) const { | ||||
size_t LastPos = 0; | size_t LastPos = 0; | ||||
MatchLen = 0; | |||||
std::vector<const Pattern *> NotStrings; | std::vector<const Pattern *> NotStrings; | ||||
// IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL | // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL | ||||
Context not available. | |||||
return StringRef::npos; | return StringRef::npos; | ||||
} | } | ||||
// <SYNOPSYS> | |||||
StringRef MatchBuffer = Buffer.substr(LastPos); | |||||
// If pattern should be checked several times. | |||||
if (Pat.getCheckTy() == Check::CheckType::CheckRepeated || Pat.getCheckTy() == Check::CheckType::CheckNextRepeated) { | |||||
size_t MatchPos = 0; | |||||
int count = 0; | |||||
size_t PrevMatchLen = 0; | |||||
bool NextFall = false; | |||||
size_t BackupMatchLen = MatchLen; | |||||
size_t BackupMatchPos = MatchPos; | |||||
size_t BackupPrevMatchLen = MatchLen; | |||||
// Match much as possible. | |||||
while (MatchPos != StringRef::npos && !NextFall && (Pat.getMaxRepeatNumber() == -1 || count < Pat.getMaxRepeatNumber())) { | |||||
StringRef MatchBuffer = Buffer.substr(LastPos); | |||||
BackupMatchLen = MatchLen; | |||||
BackupMatchPos = MatchPos; | |||||
MatchPos = Pat.Match(MatchBuffer, MatchLen, VariableTable); | |||||
if (MatchPos != StringRef::npos) { | |||||
BackupPrevMatchLen = PrevMatchLen; | |||||
PrevMatchLen = MatchLen; | |||||
LastPos += MatchPos + MatchLen; | |||||
count++; | |||||
} | |||||
if (!IsLabelScanMode) { | |||||
StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos); | |||||
if (CheckNext(SM, SkippedRegion)) { | |||||
NextFall = true; | |||||
MatchLen = BackupMatchLen; | |||||
MatchPos = BackupMatchPos; | |||||
PrevMatchLen = BackupPrevMatchLen; | |||||
} | |||||
} | |||||
} | |||||
if (count < Pat.getMinRepeatNumber()) { | |||||
PrintCheckFailed(SM, *this, MatchBuffer, VariableTable); | |||||
return StringRef::npos; | |||||
} | |||||
return LastPos - PrevMatchLen; | |||||
} | |||||
// </SYNOPSYS> | |||||
// Match itself from the last position after matching CHECK-DAG. | // Match itself from the last position after matching CHECK-DAG. | ||||
StringRef MatchBuffer = Buffer.substr(LastPos); | |||||
size_t MatchPos = Pat.Match(MatchBuffer, MatchLen, VariableTable); | size_t MatchPos = Pat.Match(MatchBuffer, MatchLen, VariableTable); | ||||
if (MatchPos == StringRef::npos) { | if (MatchPos == StringRef::npos) { | ||||
PrintCheckFailed(SM, *this, MatchBuffer, VariableTable); | PrintCheckFailed(SM, *this, MatchBuffer, VariableTable); | ||||
Context not available. | |||||
// If this match had "not strings", verify that they don't exist in the | // If this match had "not strings", verify that they don't exist in the | ||||
// skipped region. | // skipped region. | ||||
if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable)) | if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable)) { | ||||
return StringRef::npos; | return StringRef::npos; | ||||
} | |||||
// <SYNOPSYS> | |||||
//if this check is a "CHECK-WORD", verify the bounds of string. | |||||
if (CheckWord(LastPos + MatchPos, MatchLen, Buffer)) | |||||
return StringRef::npos; | |||||
// </SYNOPSYS> | |||||
} | } | ||||
return LastPos + MatchPos; | return LastPos + MatchPos; | ||||
} | } | ||||
// <SYNOPSYS> | |||||
bool CheckString::CheckWord(const size_t &MatchPos, const size_t &MatchLen, StringRef Buffer) const { | |||||
bool isWord = true; | |||||
if (Pat.getCheckTy() != Check::CheckWord && Pat.getCheckTy() != Check::CheckWordNext && | |||||
Pat.getCheckTy() != Check::CheckWordSame && Pat.getCheckTy() != Check::CheckWordDAG && | |||||
Pat.getCheckTy() != Check::CheckWordNot) | |||||
return false; | |||||
// Check previous and next characters to understand word or not. | |||||
if (MatchPos != 0) { | |||||
if (!isspace(Buffer[MatchPos - 1]) && !ispunct(Buffer[MatchPos - 1])) { | |||||
isWord = false; | |||||
} | |||||
} | |||||
if (MatchPos + MatchLen < Buffer.size() && | |||||
!isspace(Buffer[MatchPos + MatchLen ]) && !ispunct(Buffer[MatchPos + MatchLen])) { | |||||
isWord = false; | |||||
} | |||||
return (Pat.getCheckTy() == Check::CheckWordNot && isWord) || (Pat.getCheckTy() != Check::CheckWordNot && !isWord); | |||||
} | |||||
// </SYNOPSYS> | |||||
bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { | bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { | ||||
if (Pat.getCheckTy() != Check::CheckNext) | // <SYNOPSYS> | ||||
if (Pat.getCheckTy() != Check::CheckNext && Pat.getCheckTy() != Check::CheckNextRepeated && | |||||
Pat.getCheckTy() != Check::CheckWordNext) | |||||
return false; | return false; | ||||
// </SYNOPSYS> | |||||
// Count the number of newlines between the previous match and this one. | // Count the number of newlines between the previous match and this one. | ||||
assert(Buffer.data() != | assert(Buffer.data() != | ||||
Context not available. | |||||
SourceMgr::DK_Note, "'next' match was here"); | SourceMgr::DK_Note, "'next' match was here"); | ||||
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, | SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, | ||||
"previous match ended here"); | "previous match ended here"); | ||||
return true; | return true; | ||||
} | } | ||||
Context not available. | |||||
"previous match ended here"); | "previous match ended here"); | ||||
SM.PrintMessage(SMLoc::getFromPointer(FirstNewLine), SourceMgr::DK_Note, | SM.PrintMessage(SMLoc::getFromPointer(FirstNewLine), SourceMgr::DK_Note, | ||||
"non-matching line after previous match is here"); | "non-matching line after previous match is here"); | ||||
return true; | return true; | ||||
} | } | ||||
Context not available. | |||||
} | } | ||||
bool CheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const { | bool CheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const { | ||||
if (Pat.getCheckTy() != Check::CheckSame) | if (Pat.getCheckTy() != Check::CheckSame && Pat.getCheckTy() != Check::CheckWordSame) // <SYNOPSYS> | ||||
return false; | return false; | ||||
// Count the number of newlines between the previous match and this one. | // Count the number of newlines between the previous match and this one. | ||||
Context not available. | |||||
const std::vector<const Pattern *> &NotStrings, | const std::vector<const Pattern *> &NotStrings, | ||||
StringMap<StringRef> &VariableTable) const { | StringMap<StringRef> &VariableTable) const { | ||||
for (const Pattern *Pat : NotStrings) { | for (const Pattern *Pat : NotStrings) { | ||||
assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!"); | assert((Pat->getCheckTy() == Check::CheckNot || Pat->getCheckTy() == Check::CheckWordNot) && "Expect CHECK-NOT!"); // <SYNOPSYS> | ||||
size_t MatchLen = 0; | size_t MatchLen = 0; | ||||
size_t Pos = Pat->Match(Buffer, MatchLen, VariableTable); | size_t Pos = Pat->Match(Buffer, MatchLen, VariableTable); | ||||
Context not available. | |||||
for (const Pattern &Pat : DagNotStrings) { | for (const Pattern &Pat : DagNotStrings) { | ||||
assert((Pat.getCheckTy() == Check::CheckDAG || | assert((Pat.getCheckTy() == Check::CheckDAG || | ||||
Pat.getCheckTy() == Check::CheckNot) && | Pat.getCheckTy() == Check::CheckNot || | ||||
Pat.getCheckTy() == Check::CheckWordDAG || | |||||
Pat.getCheckTy() == Check::CheckWordNot) && | |||||
"Invalid CHECK-DAG or CHECK-NOT!"); | "Invalid CHECK-DAG or CHECK-NOT!"); | ||||
if (Pat.getCheckTy() == Check::CheckNot) { | if (Pat.getCheckTy() == Check::CheckNot || Pat.getCheckTy() == Check::CheckWordNot) { | ||||
NotStrings.push_back(&Pat); | NotStrings.push_back(&Pat); | ||||
continue; | continue; | ||||
} | } | ||||
assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!"); | assert((Pat.getCheckTy() == Check::CheckDAG || Pat.getCheckTy() == Check::CheckWordDAG) && "Expect CHECK-DAG!"); | ||||
size_t MatchLen = 0, MatchPos; | size_t MatchLen = 0, MatchPos; | ||||
Context not available. | |||||
static void AddCheckPrefixIfNeeded() { | static void AddCheckPrefixIfNeeded() { | ||||
if (CheckPrefixes.empty()) | if (CheckPrefixes.empty()) | ||||
CheckPrefixes.push_back("CHECK"); | CheckPrefixes.push_back("CHECK"); | ||||
// <SYNOPSYS> | |||||
// Prefix wild-card which will be always matched. | |||||
if (RegexPrefixesOn) { | |||||
if (std::find(CheckPrefixes.begin(), CheckPrefixes.end(), "{{*}}") == CheckPrefixes.end()) | |||||
CheckPrefixes.push_back("{{*}}"); | |||||
} | |||||
// </SYNOPSYS> | |||||
} | } | ||||
int main(int argc, char **argv) { | int main(int argc, char **argv) { | ||||
sys::PrintStackTraceOnErrorSignal(); | sys::PrintStackTraceOnErrorSignal(); | ||||
PrettyStackTraceProgram X(argc, argv); | PrettyStackTraceProgram X(argc, argv); | ||||
cl::ParseCommandLineOptions(argc, argv); | cl::ParseCommandLineOptions(argc, argv); | ||||
if (!ValidateCheckPrefixes()) { | if (!ValidateCheckPrefixes()) { | ||||
Context not available. | |||||
bool hasError = false; | bool hasError = false; | ||||
unsigned i = 0, j = 0, e = CheckStrings.size(); | unsigned i = 0, j = 0, k = 0, e = CheckStrings.size(); | ||||
while (true) { | while (true) { | ||||
StringRef CheckRegion; | StringRef CheckRegion; | ||||
// <SYNOPSYS> | |||||
StringRef InnerCheckRegion; | |||||
std::map<size_t, unsigned> CheckLabelDagPositions; | |||||
std::vector<unsigned> CheckLabelDagsIndexes; | |||||
// </SYNOPSYS> | |||||
if (j == e) { | if (j == e) { | ||||
CheckRegion = Buffer; | CheckRegion = Buffer; | ||||
} else { | } else { | ||||
Context not available. | |||||
Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen); | Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen); | ||||
++j; | ++j; | ||||
} | } | ||||
// <SYNOPSYS> | |||||
k = 0; | |||||
// Choose all CHECK-LABEL-DAG in current check region. | |||||
while (k != j) { | |||||
const CheckString &CheckLabelDagStr = CheckStrings[k]; | |||||
if (CheckLabelDagStr.Pat.getCheckTy() != Check::CheckLabelDag) { | |||||
++k; | |||||
continue; | |||||
} | |||||
for ( ; i != j; ++i) { | // Find and remember matches of all CHECK-LABEL-DAG | ||||
size_t MatchLabelLen = 0; | |||||
size_t MatchLabelPos = CheckLabelDagStr.Check(SM, CheckRegion, true, | |||||
MatchLabelLen, VariableTable); | |||||
if (MatchLabelPos == StringRef::npos) { | |||||
hasError = true; | |||||
break; | |||||
} | |||||
CheckLabelDagPositions.insert(std::pair<size_t, unsigned>(MatchLabelPos + MatchLabelLen, k)); | |||||
CheckLabelDagsIndexes.push_back(k); | |||||
k++; | |||||
} | |||||
size_t Before = 0; | |||||
bool wasLabelDag = false; | |||||
for (const auto &MatchLabelDag : CheckLabelDagPositions) { | |||||
unsigned PrevLabelDagInDescription; | |||||
std::vector<unsigned>::iterator It; | |||||
// Get next label dag in description | |||||
It = find (CheckLabelDagsIndexes.begin(), CheckLabelDagsIndexes.end(), MatchLabelDag.second); | |||||
if (It != CheckLabelDagsIndexes.begin()) { | |||||
PrevLabelDagInDescription = *(--It); | |||||
} else { | |||||
PrevLabelDagInDescription = -1; | |||||
} | |||||
// Create check region for usual checks | |||||
InnerCheckRegion = CheckRegion.substr(Before, MatchLabelDag.first - Before); | |||||
Before = MatchLabelDag.first; | |||||
// For this check region run all checks between two label dags in description | |||||
for (i = wasLabelDag ? PrevLabelDagInDescription + 1 : 0; i != wasLabelDag ? MatchLabelDag.second : CheckLabelDagsIndexes[0]; ++i) { | |||||
// Cycle | |||||
const CheckString &CheckStr = CheckStrings[i]; | |||||
// Check each string within the scanned region, including a second check | |||||
// of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG) | |||||
size_t MatchLen = 0; | |||||
size_t MatchPos = CheckStr.Check(SM, InnerCheckRegion, false, MatchLen, | |||||
VariableTable); | |||||
if (MatchPos == StringRef::npos) { | |||||
hasError = true; | |||||
i = j; | |||||
break; | |||||
} | |||||
InnerCheckRegion = InnerCheckRegion.substr(MatchPos + MatchLen); | |||||
} | |||||
wasLabelDag = true; | |||||
} | |||||
for ( ; i != j && !wasLabelDag; ++i) { | |||||
// </SYNOPSYS> | |||||
const CheckString &CheckStr = CheckStrings[i]; | const CheckString &CheckStr = CheckStrings[i]; | ||||
// Check each string within the scanned region, including a second check | // Check each string within the scanned region, including a second check | ||||
// of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG) | // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG) | ||||
size_t MatchLen = 0; | size_t MatchLen = 0; | ||||
Context not available. |