diff options
author | dim <dim@FreeBSD.org> | 2011-05-02 19:39:53 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2011-05-02 19:39:53 +0000 |
commit | 110eaaceddcec790f7e6a5e3bf1261c9aa1e73ab (patch) | |
tree | 64a10f4c4154739d4a8191d7e1b52ce497f4ebd6 /lib/Tooling/JsonCompileCommandLineDatabase.cpp | |
parent | a0fb00f9837bd0d2e5948f16f6a6b82a7a628f51 (diff) | |
download | FreeBSD-src-110eaaceddcec790f7e6a5e3bf1261c9aa1e73ab.zip FreeBSD-src-110eaaceddcec790f7e6a5e3bf1261c9aa1e73ab.tar.gz |
Vendor import of clang trunk r130700:
http://llvm.org/svn/llvm-project/cfe/trunk@130700
Diffstat (limited to 'lib/Tooling/JsonCompileCommandLineDatabase.cpp')
-rw-r--r-- | lib/Tooling/JsonCompileCommandLineDatabase.cpp | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/lib/Tooling/JsonCompileCommandLineDatabase.cpp b/lib/Tooling/JsonCompileCommandLineDatabase.cpp new file mode 100644 index 0000000..7f027cf --- /dev/null +++ b/lib/Tooling/JsonCompileCommandLineDatabase.cpp @@ -0,0 +1,214 @@ +//===--- JsonCompileCommandLineDatabase.cpp - Simple JSON database --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements reading a compile command line database, as written +// out for example by CMake. +// +//===----------------------------------------------------------------------===// + +#include "JsonCompileCommandLineDatabase.h" +#include "llvm/ADT/Twine.h" + +namespace clang { +namespace tooling { + +namespace { + +// A parser for JSON escaped strings of command line arguments with \-escaping +// for quoted arguments (see the documentation of UnescapeJsonCommandLine(...)). +class CommandLineArgumentParser { + public: + CommandLineArgumentParser(llvm::StringRef CommandLine) + : Input(CommandLine), Position(Input.begin()-1) {} + + std::vector<std::string> Parse() { + bool HasMoreInput = true; + while (HasMoreInput && NextNonWhitespace()) { + std::string Argument; + HasMoreInput = ParseStringInto(Argument); + CommandLine.push_back(Argument); + } + return CommandLine; + } + + private: + // All private methods return true if there is more input available. + + bool ParseStringInto(std::string &String) { + do { + if (*Position == '"') { + if (!ParseQuotedStringInto(String)) return false; + } else { + if (!ParseFreeStringInto(String)) return false; + } + } while (*Position != ' '); + return true; + } + + bool ParseQuotedStringInto(std::string &String) { + if (!Next()) return false; + while (*Position != '"') { + if (!SkipEscapeCharacter()) return false; + String.push_back(*Position); + if (!Next()) return false; + } + return Next(); + } + + bool ParseFreeStringInto(std::string &String) { + do { + if (!SkipEscapeCharacter()) return false; + String.push_back(*Position); + if (!Next()) return false; + } while (*Position != ' ' && *Position != '"'); + return true; + } + + bool SkipEscapeCharacter() { + if (*Position == '\\') { + return Next(); + } + return true; + } + + bool NextNonWhitespace() { + do { + if (!Next()) return false; + } while (*Position == ' '); + return true; + } + + bool Next() { + ++Position; + if (Position == Input.end()) return false; + // Remove the JSON escaping first. This is done unconditionally. + if (*Position == '\\') ++Position; + return Position != Input.end(); + } + + const llvm::StringRef Input; + llvm::StringRef::iterator Position; + std::vector<std::string> CommandLine; +}; + +} // end namespace + +std::vector<std::string> UnescapeJsonCommandLine( + llvm::StringRef JsonEscapedCommandLine) { + CommandLineArgumentParser parser(JsonEscapedCommandLine); + return parser.Parse(); +} + +JsonCompileCommandLineParser::JsonCompileCommandLineParser( + const llvm::StringRef Input, CompileCommandHandler *CommandHandler) + : Input(Input), Position(Input.begin()-1), CommandHandler(CommandHandler) {} + +bool JsonCompileCommandLineParser::Parse() { + NextNonWhitespace(); + return ParseTranslationUnits(); +} + +std::string JsonCompileCommandLineParser::GetErrorMessage() const { + return ErrorMessage; +} + +bool JsonCompileCommandLineParser::ParseTranslationUnits() { + if (!ConsumeOrError('[', "at start of compile command file")) return false; + if (!ParseTranslationUnit(/*First=*/true)) return false; + while (Consume(',')) { + if (!ParseTranslationUnit(/*First=*/false)) return false; + } + if (!ConsumeOrError(']', "at end of array")) return false; + if (CommandHandler != NULL) { + CommandHandler->EndTranslationUnits(); + } + return true; +} + +bool JsonCompileCommandLineParser::ParseTranslationUnit(bool First) { + if (First) { + if (!Consume('{')) return true; + } else { + if (!ConsumeOrError('{', "at start of object")) return false; + } + if (!Consume('}')) { + if (!ParseObjectKeyValuePairs()) return false; + if (!ConsumeOrError('}', "at end of object")) return false; + } + if (CommandHandler != NULL) { + CommandHandler->EndTranslationUnit(); + } + return true; +} + +bool JsonCompileCommandLineParser::ParseObjectKeyValuePairs() { + do { + llvm::StringRef Key; + if (!ParseString(Key)) return false; + if (!ConsumeOrError(':', "between name and value")) return false; + llvm::StringRef Value; + if (!ParseString(Value)) return false; + if (CommandHandler != NULL) { + CommandHandler->HandleKeyValue(Key, Value); + } + } while (Consume(',')); + return true; +} + +bool JsonCompileCommandLineParser::ParseString(llvm::StringRef &String) { + if (!ConsumeOrError('"', "at start of string")) return false; + llvm::StringRef::iterator First = Position; + llvm::StringRef::iterator Last = Position; + while (!Consume('"')) { + Consume('\\'); + ++Position; + // We need to store Position, as Consume will change Last before leaving + // the loop. + Last = Position; + } + String = llvm::StringRef(First, Last - First); + return true; +} + +bool JsonCompileCommandLineParser::Consume(char C) { + if (Position == Input.end()) return false; + if (*Position != C) return false; + NextNonWhitespace(); + return true; +} + +bool JsonCompileCommandLineParser::ConsumeOrError( + char C, llvm::StringRef Message) { + if (!Consume(C)) { + SetExpectError(C, Message); + return false; + } + return true; +} + +void JsonCompileCommandLineParser::SetExpectError( + char C, llvm::StringRef Message) { + ErrorMessage = (llvm::Twine("'") + llvm::StringRef(&C, 1) + + "' expected " + Message + ".").str(); +} + +void JsonCompileCommandLineParser::NextNonWhitespace() { + do { + ++Position; + } while (IsWhitespace()); +} + +bool JsonCompileCommandLineParser::IsWhitespace() { + if (Position == Input.end()) return false; + return (*Position == ' ' || *Position == '\t' || + *Position == '\n' || *Position == '\r'); +} + +} // end namespace tooling +} // end namespace clang |