Clean up whitespace and add comments
[oota-llvm.git] / utils / FileCheck / FileCheck.cpp
index 5d4cb0c0c5f074511b16b096a87e833f89f5aec1..fb66ac2fceb2b7e199e319701c64e948e017c398 100644 (file)
@@ -26,6 +26,7 @@
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/system_error.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringMap.h"
 #include <algorithm>
 using namespace llvm;
@@ -63,6 +64,9 @@ class Pattern {
   /// RegEx - If non-empty, this is a regex pattern.
   std::string RegExStr;
 
+  /// \brief Contains the number of line this pattern is in.
+  unsigned LineNumber;
+
   /// VariableUses - Entries in this vector map to uses of a variable in the
   /// pattern, e.g. "foo[[bar]]baz".  In this case, the RegExStr will contain
   /// "foobaz" and we'll get an entry in this vector that tells us to insert the
@@ -79,7 +83,11 @@ public:
 
   Pattern(bool matchEOF = false) : MatchEOF(matchEOF) { }
 
-  bool ParsePattern(StringRef PatternStr, SourceMgr &SM);
+  /// ParsePattern - Parse the given string into the Pattern.  SM provides the
+  /// SourceMgr used for error reports, and LineNumber is the line number in
+  /// the input file from which the pattern string was read.
+  /// Returns true in case of an error, false otherwise.
+  bool ParsePattern(StringRef PatternStr, SourceMgr &SM, unsigned LineNumber);
 
   /// Match - Match the pattern string against the input buffer Buffer.  This
   /// returns the position that is matched or npos if there is no match.  If
@@ -104,10 +112,16 @@ private:
   /// should correspond to a perfect match.
   unsigned ComputeMatchDistance(StringRef Buffer,
                                const StringMap<StringRef> &VariableTable) const;
+
+  /// \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;
 };
 
 
-bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
+bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM,
+                           unsigned LineNumber) {
+  this->LineNumber = LineNumber;
   PatternLoc = SMLoc::getFromPointer(PatternStr.data());
 
   // Ignore trailing whitespace.
@@ -117,8 +131,9 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
 
   // Check that there is something on the line.
   if (PatternStr.empty()) {
-    SM.PrintMessage(PatternLoc, "found empty check string with prefix '" +
-                    CheckPrefix+":'", "error");
+    SM.PrintMessage(PatternLoc, SourceMgr::DK_Error,
+                    "found empty check string with prefix '" +
+                    CheckPrefix+":'");
     return true;
   }
 
@@ -131,26 +146,34 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
   }
 
   // Paren value #0 is for the fully matched string.  Any new parenthesized
-  // values add from their.
+  // values add from there.
   unsigned CurParen = 1;
 
   // Otherwise, there is at least one regex piece.  Build up the regex pattern
   // by escaping scary characters in fixed strings, building up one big regex.
   while (!PatternStr.empty()) {
     // RegEx matches.
-    if (PatternStr.size() >= 2 &&
-        PatternStr[0] == '{' && PatternStr[1] == '{') {
-
-      // Otherwise, this is the start of a regex match.  Scan for the }}.
+    if (PatternStr.startswith("{{")) {
+      // This is the start of a regex match.  Scan for the }}.
       size_t End = PatternStr.find("}}");
       if (End == StringRef::npos) {
         SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
-                        "found start of regex string with no end '}}'", "error");
+                        SourceMgr::DK_Error,
+                        "found start of regex string with no end '}}'");
         return true;
       }
 
+      // Enclose {{}} patterns in parens just like [[]] even though we're not
+      // capturing the result for any purpose.  This is required in case the
+      // expression contains an alternation like: CHECK:  abc{{x|z}}def.  We
+      // want this to turn into: "abc(x|z)def" not "abcx|zdef".
+      RegExStr += '(';
+      ++CurParen;
+
       if (AddRegExToRegEx(PatternStr.substr(2, End-2), CurParen, SM))
         return true;
+      RegExStr += ')';
+
       PatternStr = PatternStr.substr(End+2);
       continue;
     }
@@ -160,13 +183,13 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
     // second form is [[foo]] which is a reference to foo.  The variable name
     // 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.size() >= 2 &&
-        PatternStr[0] == '[' && PatternStr[1] == '[') {
+    if (PatternStr.startswith("[[")) {
       // Verify that it is terminated properly.
       size_t End = PatternStr.find("]]");
       if (End == StringRef::npos) {
         SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
-                        "invalid named regex reference, no ]] found", "error");
+                        SourceMgr::DK_Error,
+                        "invalid named regex reference, no ]] found");
         return true;
       }
 
@@ -178,26 +201,38 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
       StringRef Name = MatchStr.substr(0, NameEnd);
 
       if (Name.empty()) {
-        SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
-                        "invalid name in named regex: empty name", "error");
+        SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
+                        "invalid name in named regex: empty name");
         return true;
       }
 
-      // Verify that the name is well formed.
-      for (unsigned i = 0, e = Name.size(); i != e; ++i)
-        if (Name[i] != '_' &&
-            (Name[i] < 'a' || Name[i] > 'z') &&
-            (Name[i] < 'A' || Name[i] > 'Z') &&
-            (Name[i] < '0' || Name[i] > '9')) {
+      // Verify that the name/expression is well formed. FileCheck currently
+      // supports @LINE, @LINE+number, @LINE-number expressions. The check here
+      // is relaxed, more strict check is performed in \c EvaluateExpression.
+      bool IsExpression = false;
+      for (unsigned i = 0, e = Name.size(); i != e; ++i) {
+        if (i == 0 && Name[i] == '@') {
+          if (NameEnd != StringRef::npos) {
+            SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
+                            SourceMgr::DK_Error,
+                            "invalid name in named regex definition");
+            return true;
+          }
+          IsExpression = true;
+          continue;
+        }
+        if (Name[i] != '_' && !isalnum(Name[i]) &&
+            (!IsExpression || (Name[i] != '+' && Name[i] != '-'))) {
           SM.PrintMessage(SMLoc::getFromPointer(Name.data()+i),
-                          "invalid name in named regex", "error");
+                          SourceMgr::DK_Error, "invalid name in named regex");
           return true;
         }
+      }
 
       // Name can't start with a digit.
       if (isdigit(Name[0])) {
-        SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
-                        "invalid name in named regex", "error");
+        SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
+                        "invalid name in named regex");
         return true;
       }
 
@@ -224,7 +259,6 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
     FixedMatchEnd = std::min(FixedMatchEnd, PatternStr.find("[["));
     AddFixedStringToRegEx(PatternStr.substr(0, FixedMatchEnd), RegExStr);
     PatternStr = PatternStr.substr(FixedMatchEnd);
-    continue;
   }
 
   return false;
@@ -262,8 +296,8 @@ bool Pattern::AddRegExToRegEx(StringRef RegexStr, unsigned &CurParen,
   Regex R(RegexStr);
   std::string Error;
   if (!R.isValid(Error)) {
-    SM.PrintMessage(SMLoc::getFromPointer(RegexStr.data()),
-                    "invalid regex: " + Error, "error");
+    SM.PrintMessage(SMLoc::getFromPointer(RegexStr.data()), SourceMgr::DK_Error,
+                    "invalid regex: " + Error);
     return true;
   }
 
@@ -272,6 +306,24 @@ bool Pattern::AddRegExToRegEx(StringRef RegexStr, unsigned &CurParen,
   return false;
 }
 
+bool Pattern::EvaluateExpression(StringRef Expr, std::string &Value) const {
+  // The only supported expression is @LINE([\+-]\d+)?
+  if (!Expr.startswith("@LINE"))
+    return false;
+  Expr = Expr.substr(StringRef("@LINE").size());
+  int Offset = 0;
+  if (!Expr.empty()) {
+    if (Expr[0] == '+')
+      Expr = Expr.substr(1);
+    else if (Expr[0] != '-')
+      return false;
+    if (Expr.getAsInteger(10, Offset))
+      return false;
+  }
+  Value = llvm::itostr(LineNumber + Offset);
+  return true;
+}
+
 /// Match - Match the pattern string against the input buffer Buffer.  This
 /// returns the position that is matched or npos if there is no match.  If
 /// there is a match, the size of the matched string is returned in MatchLen.
@@ -300,15 +352,21 @@ size_t Pattern::Match(StringRef Buffer, size_t &MatchLen,
 
     unsigned InsertOffset = 0;
     for (unsigned i = 0, e = VariableUses.size(); i != e; ++i) {
-      StringMap<StringRef>::iterator it =
-        VariableTable.find(VariableUses[i].first);
-      // If the variable is undefined, return an error.
-      if (it == VariableTable.end())
-        return StringRef::npos;
-
-      // Look up the value and escape it so that we can plop it into the regex.
       std::string Value;
-      AddFixedStringToRegEx(it->second, Value);
+
+      if (VariableUses[i].first[0] == '@') {
+        if (!EvaluateExpression(VariableUses[i].first, Value))
+          return StringRef::npos;
+      } else {
+        StringMap<StringRef>::iterator it =
+          VariableTable.find(VariableUses[i].first);
+        // If the variable is undefined, return an error.
+        if (it == VariableTable.end())
+          return StringRef::npos;
+
+        // Look up the value and escape it so that we can plop it into the regex.
+        AddFixedStringToRegEx(it->second, Value);
+      }
 
       // Plop it into the regex at the adjusted offset.
       TmpStr.insert(TmpStr.begin()+VariableUses[i].second+InsertOffset,
@@ -364,23 +422,35 @@ void Pattern::PrintFailureInfo(const SourceMgr &SM, StringRef Buffer,
   // variable values.
   if (!VariableUses.empty()) {
     for (unsigned i = 0, e = VariableUses.size(); i != e; ++i) {
-      StringRef Var = VariableUses[i].first;
-      StringMap<StringRef>::const_iterator it = VariableTable.find(Var);
       SmallString<256> Msg;
       raw_svector_ostream OS(Msg);
-
-      // Check for undefined variable references.
-      if (it == VariableTable.end()) {
-        OS << "uses undefined variable \"";
-        OS.write_escaped(Var) << "\"";;
+      StringRef Var = VariableUses[i].first;
+      if (Var[0] == '@') {
+        std::string Value;
+        if (EvaluateExpression(Var, Value)) {
+          OS << "with expression \"";
+          OS.write_escaped(Var) << "\" equal to \"";
+          OS.write_escaped(Value) << "\"";
+        } else {
+          OS << "uses incorrect expression \"";
+          OS.write_escaped(Var) << "\"";
+        }
       } else {
-        OS << "with variable \"";
-        OS.write_escaped(Var) << "\" equal to \"";
-        OS.write_escaped(it->second) << "\"";
+        StringMap<StringRef>::const_iterator it = VariableTable.find(Var);
+
+        // Check for undefined variable references.
+        if (it == VariableTable.end()) {
+          OS << "uses undefined variable \"";
+          OS.write_escaped(Var) << "\"";
+        } else {
+          OS << "with variable \"";
+          OS.write_escaped(Var) << "\" equal to \"";
+          OS.write_escaped(it->second) << "\"";
+        }
       }
 
-      SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), OS.str(), "note",
-                      /*ShowLine=*/false);
+      SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
+                      OS.str());
     }
   }
 
@@ -418,7 +488,7 @@ void Pattern::PrintFailureInfo(const SourceMgr &SM, StringRef Buffer,
   // line.
   if (Best && Best != StringRef::npos && BestQuality < 50) {
       SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + Best),
-                      "possible intended match here", "note");
+                      SourceMgr::DK_Note, "possible intended match here");
 
     // FIXME: If we wanted to be really friendly we would show why the match
     // failed, as it can be hard to spot simple one character differences.
@@ -463,7 +533,7 @@ static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) {
       continue;
     }
 
-    // If C is not a horizontal whitespace, skip it.
+    // If current char is not a horizontal whitespace, dump it to output as is.
     if (*Ptr != ' ' && *Ptr != '\t') {
       NewFile.push_back(*Ptr);
       continue;
@@ -487,9 +557,9 @@ static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) {
 
 /// ReadCheckFile - Read the check file, which specifies the sequence of
 /// expected strings.  The strings are added to the CheckStrings vector.
+/// Returns true in case of an error, false otherwise.
 static bool ReadCheckFile(SourceMgr &SM,
                           std::vector<CheckString> &CheckStrings) {
-  // Open the check file, and tell SourceMgr about it.
   OwningPtr<MemoryBuffer> File;
   if (error_code ec =
         MemoryBuffer::getFileOrSTDIN(CheckFilename.c_str(), File)) {
@@ -508,17 +578,23 @@ static bool ReadCheckFile(SourceMgr &SM,
 
   // Find all instances of CheckPrefix followed by : in the file.
   StringRef Buffer = F->getBuffer();
-
   std::vector<std::pair<SMLoc, Pattern> > NotMatches;
 
+  // LineNumber keeps track of the line on which CheckPrefix instances are
+  // found.
+  unsigned LineNumber = 1;
+
   while (1) {
     // See if Prefix occurs in the memory buffer.
-    Buffer = Buffer.substr(Buffer.find(CheckPrefix));
-
+    size_t PrefixLoc = Buffer.find(CheckPrefix);
     // If we didn't find a match, we're done.
-    if (Buffer.empty())
+    if (PrefixLoc == StringRef::npos)
       break;
 
+    LineNumber += Buffer.substr(0, PrefixLoc).count('\n');
+
+    Buffer = Buffer.substr(PrefixLoc);
+
     const char *CheckPrefixStart = Buffer.data();
 
     // When we find a check prefix, keep track of whether we find CHECK: or
@@ -530,11 +606,11 @@ static bool ReadCheckFile(SourceMgr &SM,
       Buffer = Buffer.substr(CheckPrefix.size()+1);
     } else if (Buffer.size() > CheckPrefix.size()+6 &&
                memcmp(Buffer.data()+CheckPrefix.size(), "-NEXT:", 6) == 0) {
-      Buffer = Buffer.substr(CheckPrefix.size()+7);
+      Buffer = Buffer.substr(CheckPrefix.size()+6);
       IsCheckNext = true;
     } else if (Buffer.size() > CheckPrefix.size()+5 &&
                memcmp(Buffer.data()+CheckPrefix.size(), "-NOT:", 5) == 0) {
-      Buffer = Buffer.substr(CheckPrefix.size()+6);
+      Buffer = Buffer.substr(CheckPrefix.size()+5);
       IsCheckNot = true;
     } else {
       Buffer = Buffer.substr(1);
@@ -553,17 +629,17 @@ static bool ReadCheckFile(SourceMgr &SM,
 
     // Parse the pattern.
     Pattern P;
-    if (P.ParsePattern(Buffer.substr(0, EOL), SM))
+    if (P.ParsePattern(Buffer.substr(0, EOL), SM, LineNumber))
       return true;
 
     Buffer = Buffer.substr(EOL);
 
-
     // Verify that CHECK-NEXT lines have at least one CHECK line before them.
     if (IsCheckNext && CheckStrings.empty()) {
       SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart),
+                      SourceMgr::DK_Error,
                       "found '"+CheckPrefix+"-NEXT:' without previous '"+
-                      CheckPrefix+ ": line", "error");
+                      CheckPrefix+ ": line");
       return true;
     }
 
@@ -574,7 +650,6 @@ static bool ReadCheckFile(SourceMgr &SM,
       continue;
     }
 
-
     // Okay, add the string we captured to the output vector and move on.
     CheckStrings.push_back(CheckString(P,
                                        PatternLoc,
@@ -603,15 +678,15 @@ static void PrintCheckFailed(const SourceMgr &SM, const CheckString &CheckStr,
                              StringRef Buffer,
                              StringMap<StringRef> &VariableTable) {
   // Otherwise, we have an error, emit an error message.
-  SM.PrintMessage(CheckStr.Loc, "expected string not found in input",
-                  "error");
+  SM.PrintMessage(CheckStr.Loc, SourceMgr::DK_Error,
+                  "expected string not found in input");
 
   // Print the "scanning from here" line.  If the current position is at the
   // end of a line, advance to the start of the next line.
   Buffer = Buffer.substr(Buffer.find_first_not_of(" \t\n\r"));
 
-  SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), "scanning from here",
-                  "note");
+  SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
+                  "scanning from here");
 
   // Allow the pattern to print additional information if desired.
   CheckStr.Pat.PrintFailureInfo(SM, Buffer, VariableTable);
@@ -655,13 +730,13 @@ int main(int argc, char **argv) {
         MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), File)) {
     errs() << "Could not open input file '" << InputFilename << "': "
            << ec.message() << '\n';
-    return true;
+    return 2;
   }
   MemoryBuffer *F = File.take();
 
   if (F->getBufferSize() == 0) {
     errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
-    return 1;
+    return 2;
   }
   
   // Remove duplicate spaces in the input file if requested.
@@ -706,25 +781,22 @@ int main(int argc, char **argv) {
 
       unsigned NumNewLines = CountNumNewlinesBetween(SkippedRegion);
       if (NumNewLines == 0) {
-        SM.PrintMessage(CheckStr.Loc,
-                    CheckPrefix+"-NEXT: is on the same line as previous match",
-                        "error");
+        SM.PrintMessage(CheckStr.Loc, SourceMgr::DK_Error,
+                    CheckPrefix+"-NEXT: is on the same line as previous match");
         SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),
-                        "'next' match was here", "note");
-        SM.PrintMessage(SMLoc::getFromPointer(LastMatch),
-                        "previous match was here", "note");
+                        SourceMgr::DK_Note, "'next' match was here");
+        SM.PrintMessage(SMLoc::getFromPointer(LastMatch), SourceMgr::DK_Note,
+                        "previous match was here");
         return 1;
       }
 
       if (NumNewLines != 1) {
-        SM.PrintMessage(CheckStr.Loc,
-                        CheckPrefix+
-                        "-NEXT: is not on the line after the previous match",
-                        "error");
+        SM.PrintMessage(CheckStr.Loc, SourceMgr::DK_Error, CheckPrefix+
+                        "-NEXT: is not on the line after the previous match");
         SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),
-                        "'next' match was here", "note");
-        SM.PrintMessage(SMLoc::getFromPointer(LastMatch),
-                        "previous match was here", "note");
+                        SourceMgr::DK_Note, "'next' match was here");
+        SM.PrintMessage(SMLoc::getFromPointer(LastMatch), SourceMgr::DK_Note,
+                        "previous match was here");
         return 1;
       }
     }
@@ -739,10 +811,10 @@ int main(int argc, char **argv) {
                                                              VariableTable);
       if (Pos == StringRef::npos) continue;
 
-      SM.PrintMessage(SMLoc::getFromPointer(LastMatch+Pos),
-                      CheckPrefix+"-NOT: string occurred!", "error");
-      SM.PrintMessage(CheckStr.NotStrings[ChunkNo].first,
-                      CheckPrefix+"-NOT: pattern specified here", "note");
+      SM.PrintMessage(SMLoc::getFromPointer(LastMatch+Pos), SourceMgr::DK_Error,
+                      CheckPrefix+"-NOT: string occurred!");
+      SM.PrintMessage(CheckStr.NotStrings[ChunkNo].first, SourceMgr::DK_Note,
+                      CheckPrefix+"-NOT: pattern specified here");
       return 1;
     }