#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/SourceMgr.h"
namespace llvm {
///
/// Parsing is started via parseRoot(). Access to the object returned from
/// parseRoot() will parse the input lazily.
- JSONParser(StringRef Input);
+ JSONParser(StringRef Input, SourceMgr *SM);
/// \brief Returns the outermost JSON value (either an array or an object).
///
/// iterating over the result of 'parseRoot', 'failed' will return true.
bool failed() const;
- /// \brief Returns an error message when 'failed' returns true.
- std::string getErrorMessage() const;
-
private:
/// \brief These methods manage the implementation details of parsing new JSON
/// atoms.
BumpPtrAllocator ValueAllocator;
/// \brief The original input to the parser.
- const StringRef Input;
+ MemoryBuffer *InputBuffer;
+
+ /// \brief The source manager used for diagnostics and buffer management.
+ SourceMgr *SM;
/// \brief The current position in the parse stream.
StringRef::iterator Position;
- /// \brief If non-empty, an error has occurred.
- std::string ErrorMessage;
+ /// \brief The end position for fast EOF checks without introducing
+ /// unnecessary dereferences.
+ StringRef::iterator End;
+
+ /// \brief If true, an error has occurred.
+ bool Failed;
template <typename AtomT, char StartChar, char EndChar,
JSONAtom::Kind ContainerKind>
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/MemoryBuffer.h"
using namespace llvm;
-JSONParser::JSONParser(StringRef Input)
- : Input(Input), Position(Input.begin()) {}
+JSONParser::JSONParser(StringRef Input, SourceMgr *SM)
+ : SM(SM), Failed(false) {
+ InputBuffer = MemoryBuffer::getMemBuffer(Input, "JSON");
+ SM->AddNewSourceBuffer(InputBuffer, SMLoc());
+ End = InputBuffer->getBuffer().end();
+ Position = InputBuffer->getBuffer().begin();
+}
JSONValue *JSONParser::parseRoot() {
- if (Position != Input.begin())
+ if (Position != InputBuffer->getBuffer().begin())
report_fatal_error("Cannot resuse JSONParser.");
if (isWhitespace())
nextNonWhitespace();
}
bool JSONParser::validate() {
- return skip(*parseRoot());
+ JSONValue *Root = parseRoot();
+ if (Root == NULL) {
+ return false;
+ }
+ return skip(*Root);
}
bool JSONParser::skip(const JSONAtom &Atom) {
}
// Sets the current error to:
-// "Error while parsing JSON: expected <Expected>, but found <Found>".
+// "expected <Expected>, but found <Found>".
void JSONParser::setExpectedError(StringRef Expected, StringRef Found) {
- ErrorMessage = ("Error while parsing JSON: expected " +
- Expected + ", but found " + Found + ".").str();
+ SM->PrintMessage(SMLoc::getFromPointer(Position), SourceMgr::DK_Error,
+ "expected " + Expected + ", but found " + Found + ".", ArrayRef<SMRange>());
+ Failed = true;
}
// Sets the current error to:
-// "Error while parsing JSON: expected <Expected>, but found <Found>".
+// "expected <Expected>, but found <Found>".
void JSONParser::setExpectedError(StringRef Expected, char Found) {
- setExpectedError(Expected, StringRef(&Found, 1));
+ setExpectedError(Expected, ("'" + StringRef(&Found, 1) + "'").str());
}
// If there is no character available, returns true and sets the current error
-// to: "Error while parsing JSON: expected <Expected>, but found EOF.".
+// to: "expected <Expected>, but found EOF.".
bool JSONParser::errorIfAtEndOfFile(StringRef Expected) {
- if (Position == Input.end()) {
+ if (Position == End) {
setExpectedError(Expected, "EOF");
return true;
}
}
// Sets the current error if the current character is not C to:
-// "Error while parsing JSON: expected 'C', but got <current character>".
+// "expected 'C', but got <current character>".
bool JSONParser::errorIfNotAt(char C, StringRef Message) {
- if (Position == Input.end() || *Position != C) {
+ if (*Position != C) {
std::string Expected =
("'" + StringRef(&C, 1) + "' " + Message).str();
- if (Position == Input.end())
+ if (Position == End)
setExpectedError(Expected, "EOF");
else
setExpectedError(Expected, *Position);
// Parses a JSONString, assuming that the current position is on a quote.
JSONString *JSONParser::parseString() {
- assert(Position != Input.end());
+ assert(Position != End);
assert(!isWhitespace());
if (errorIfNotAt('"', "at start of string"))
return 0;
// Step over the current quote.
++Position;
// Find the next quote.
- while (Position != Input.end() && *Position != '"')
+ while (Position != End && *Position != '"')
++Position;
- if (errorIfAtEndOfFile("\" at end of string"))
+ if (errorIfAtEndOfFile("'\"' at end of string"))
return 0;
// Repeat until the previous character was not a '\' or was an escaped
// backslash.
// Checks if there is a whitespace character at the current position.
bool JSONParser::isWhitespace() {
- return Position != Input.end() && (*Position == ' ' || *Position == '\t' ||
- *Position == '\n' || *Position == '\r');
+ return *Position == ' ' || *Position == '\t' ||
+ *Position == '\n' || *Position == '\r';
}
bool JSONParser::failed() const {
- return !ErrorMessage.empty();
-}
-
-std::string JSONParser::getErrorMessage() const {
- return ErrorMessage;
+ return Failed;
}
// Parses a JSONValue, assuming that the current position is at the first
// character of the value.
JSONValue *JSONParser::parseValue() {
- assert(Position != Input.end());
+ assert(Position != End);
assert(!isWhitespace());
switch (*Position) {
case '[':
// Parses a JSONKeyValuePair, assuming that the current position is at the first
// character of the key, value pair.
JSONKeyValuePair *JSONParser::parseKeyValuePair() {
- assert(Position != Input.end());
+ assert(Position != End);
assert(!isWhitespace());
JSONString *Key = parseString();
namespace llvm {
-// Returns a buffer that contains the content of the given string without
-// the trailing zero, in order to get valgrind to catch out-of-bound reads.
-static std::vector<char> CutTrailingZero(StringRef String) {
- std::vector<char> InputWithoutZero(String.size());
- memcpy(&InputWithoutZero[0], String.data(), String.size());
- return InputWithoutZero;
-}
-
// Checks that the given input gives a parse error. Makes sure that an error
// text is available and the parse fails.
-static void ExpectParseError(StringRef Message,
- const std::vector<char> &InputWithoutZero) {
- StringRef Input = StringRef(&InputWithoutZero[0], InputWithoutZero.size());
- JSONParser Parser(Input);
+static void ExpectParseError(StringRef Message, StringRef Input) {
+ SourceMgr SM;
+ JSONParser Parser(Input, &SM);
EXPECT_FALSE(Parser.validate()) << Message << ": " << Input;
EXPECT_TRUE(Parser.failed()) << Message << ": " << Input;
- EXPECT_FALSE(Parser.getErrorMessage().empty()) << Message << ": " << Input;
-}
-
-// Overloads the above to allow using const char * as Input.
-static void ExpectParseError(StringRef Message, StringRef Input) {
- return ExpectParseError(Message, CutTrailingZero(Input));
}
// Checks that the given input can be parsed without error.
-static void ExpectParseSuccess(StringRef Message,
- const std::vector<char> &InputWithoutZero) {
- StringRef Input = StringRef(&InputWithoutZero[0], InputWithoutZero.size());
- JSONParser Parser(Input);
- EXPECT_TRUE(Parser.validate())
- << Message << ": " << Input << " - " << Parser.getErrorMessage();
-}
-
-// Overloads the above to allow using const char * as Input.
static void ExpectParseSuccess(StringRef Message, StringRef Input) {
- return ExpectParseSuccess(Message, CutTrailingZero(Input));
+ SourceMgr SM;
+ JSONParser Parser(Input, &SM);
+ EXPECT_TRUE(Parser.validate()) << Message << ": " << Input;
}
TEST(JSONParser, FailsOnEmptyString) {
- JSONParser Parser("");
- EXPECT_EQ(NULL, Parser.parseRoot());
+ ExpectParseError("Empty JSON text", "");
}
-
-TEST(JSONParser, DoesNotReadAfterInput) {
- JSONParser Parser(llvm::StringRef(NULL, 0));
- EXPECT_EQ(NULL, Parser.parseRoot());
-}
-
+
TEST(JSONParser, FailsIfStartsWithString) {
- JSONParser Character("\"x\"");
- EXPECT_EQ(NULL, Character.parseRoot());
+ ExpectParseError("Top-level string", "\"x\"");
}
TEST(JSONParser, ParsesEmptyArray) {
// of an array.
static void ExpectCanParseString(StringRef String) {
std::string StringInArray = (llvm::Twine("[\"") + String + "\"]").str();
- JSONParser Parser(StringInArray);
+ SourceMgr SM;
+ JSONParser Parser(StringInArray, &SM);
const JSONArray *ParsedArray = dyn_cast<JSONArray>(Parser.parseRoot());
StringRef ParsedString =
dyn_cast<JSONString>(*ParsedArray->begin())->getRawText();
- EXPECT_EQ(String, ParsedString.str()) << Parser.getErrorMessage();
+ EXPECT_EQ(String, ParsedString.str());
}
// Checks that parsing the given string inside an array fails.
}
TEST(JSONParser, WorksWithIteratorAlgorithms) {
- JSONParser Parser("[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"]");
+ SourceMgr SM;
+ JSONParser Parser("[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"]", &SM);
const JSONArray *Array = dyn_cast<JSONArray>(Parser.parseRoot());
EXPECT_EQ(6, std::distance(Array->begin(), Array->end()));
}
llvm::Timer Parsing((Name + ": Parsing").str(), Group);
Parsing.startTimer();
- llvm::JSONParser Parser(JSONText);
+ llvm::SourceMgr SM;
+ llvm::JSONParser Parser(JSONText, &SM);
if (!Parser.validate()) {
llvm::errs() << "Parsing error in JSON parser benchmark.\n";
exit(1);