From 061d2baa572d4caf4aaa4c9f67c834c7154c7c2a Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Sun, 2 Dec 2012 16:02:41 +0000 Subject: [PATCH] Fix a bug in FileCheck that wouldn't let define variables as follows: ; CHECK: [[VAR:[a-z]]] The problem was that to find the end of the regex var definition, it was simplistically looking for the next ]] and finding the incorrect one. A better approach is to count nesting of brackets (taking escaping into account). This way the brackets that are part of the regex can be discovered and skipped properly, and the ]] ending is detected in the right place. llvm-svn: 169109 --- llvm/test/FileCheck/regex-brackets.txt | 7 ++++ llvm/test/FileCheck/simple-var-capture.txt | 3 +- llvm/utils/FileCheck/FileCheck.cpp | 51 +++++++++++++++++++++++++++--- 3 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 llvm/test/FileCheck/regex-brackets.txt diff --git a/llvm/test/FileCheck/regex-brackets.txt b/llvm/test/FileCheck/regex-brackets.txt new file mode 100644 index 0000000..fd8568d --- /dev/null +++ b/llvm/test/FileCheck/regex-brackets.txt @@ -0,0 +1,7 @@ +// RUN: FileCheck -input-file %s %s + +op r1 +op r2, [x r1] +; CHECK: op [[REG:r[0-9]]] +; CHECK: op [[REG2:r[0-9]]], [x [[REG]]] + diff --git a/llvm/test/FileCheck/simple-var-capture.txt b/llvm/test/FileCheck/simple-var-capture.txt index c0214d9..a487baa 100644 --- a/llvm/test/FileCheck/simple-var-capture.txt +++ b/llvm/test/FileCheck/simple-var-capture.txt @@ -2,7 +2,7 @@ op1 r1 op2 r1, r2 -; CHECK: op1 [[REG:r[0-9]+]] +; CHECK: op1 [[REG:r[0-9]]] ; CHECK-NEXT: op2 [[REG]] op3 r16, r18, r21 @@ -10,3 +10,4 @@ op4 r30, r18, r21 ; CHECK: op3 {{r[0-9]+}}, [[REGa:r[0-9]+]], [[REGb:r[0-9]+]] ; CHECK-NEXT: op4 {{r[0-9]+}}, [[REGa]], [[REGb]] + diff --git a/llvm/utils/FileCheck/FileCheck.cpp b/llvm/utils/FileCheck/FileCheck.cpp index 7b330d5..c1d017f 100644 --- a/llvm/utils/FileCheck/FileCheck.cpp +++ b/llvm/utils/FileCheck/FileCheck.cpp @@ -119,6 +119,13 @@ private: /// \brief Evaluates expression and stores the result to \p Value. /// \return true on success. false when the expression has invalid syntax. bool EvaluateExpression(StringRef Expr, std::string &Value) const; + + /// \brief Finds the closing sequence of a regex variable usage or + /// definition. Str has to point in the beginning of the definition + /// (right after the opening sequence). + /// \return offset of the closing sequence within Str, or npos if it was not + /// found. + size_t FindRegexVarEnd(StringRef Str); }; @@ -187,8 +194,10 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM, // itself must be of the form "[a-zA-Z_][0-9a-zA-Z_]*", otherwise we reject // it. This is to catch some common errors. if (PatternStr.startswith("[[")) { - // Verify that it is terminated properly. - size_t End = PatternStr.find("]]"); + // Find the closing bracket pair ending the match. End is going to be an + // offset relative to the beginning of the match string. + size_t End = FindRegexVarEnd(PatternStr.substr(2)); + if (End == StringRef::npos) { SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()), SourceMgr::DK_Error, @@ -196,8 +205,8 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM, return true; } - StringRef MatchStr = PatternStr.substr(2, End-2); - PatternStr = PatternStr.substr(End+2); + StringRef MatchStr = PatternStr.substr(2, End); + PatternStr = PatternStr.substr(End+4); // Get the regex name (e.g. "foo"). size_t NameEnd = MatchStr.find(':'); @@ -519,6 +528,40 @@ void Pattern::PrintFailureInfo(const SourceMgr &SM, StringRef Buffer, } } +size_t Pattern::FindRegexVarEnd(StringRef Str) { + // Offset keeps track of the current offset within the input Str + size_t Offset = 0; + // [...] Nesting depth + size_t BracketDepth = 0; + + while (!Str.empty()) { + if (Str.startswith("]]") && BracketDepth == 0) + return Offset; + if (Str[0] == '\\') { + // Backslash escapes the next char within regexes, so skip them both. + Str = Str.substr(2); + Offset += 2; + } else { + switch (Str[0]) { + default: + break; + case '[': + BracketDepth++; + break; + case ']': + assert(BracketDepth > 0 && "Invalid regex"); + BracketDepth--; + break; + } + Str = Str.substr(1); + Offset++; + } + } + + return StringRef::npos; +} + + //===----------------------------------------------------------------------===// // Check Strings. //===----------------------------------------------------------------------===// -- 2.7.4