26 return try_emplace(std::move(K),
nullptr).first->getSecond();
42 return V->getAsNull();
47 return V->getAsBoolean();
52 return V->getAsNumber();
57 return V->getAsInteger();
62 return V->getAsString();
67 return V->getAsObject();
72 return V->getAsObject();
77 return V->getAsArray();
82 return V->getAsArray();
86 if (
LHS.size() !=
RHS.size())
88 for (
const auto &L :
LHS) {
89 auto R =
RHS.find(L.first);
90 if (R ==
RHS.end() || L.second != R->second)
97 V.reserve(Elements.size());
98 for (
const Value &V : Elements) {
100 back().moveFrom(std::move(V));
107void Value::copyFrom(
const Value &M) {
115 memcpy(&Union, &M.Union,
sizeof(Union));
121 create<std::string>(M.as<std::string>());
132void Value::moveFrom(
const Value &&M) {
140 memcpy(&Union, &M.Union,
sizeof(Union));
143 create<StringRef>(M.as<StringRef>());
146 create<std::string>(std::move(M.as<std::string>()));
150 create<json::Object>(std::move(M.as<json::Object>()));
154 create<json::Array>(std::move(M.as<json::Array>()));
160void Value::destroy() {
169 as<StringRef>().~StringRef();
172 as<std::string>().~basic_string();
175 as<json::Object>().~Object();
178 as<json::Array>().~Array();
184 if (L.kind() != R.kind())
188 return *L.getAsNull() == *R.getAsNull();
190 return *L.getAsBoolean() == *R.getAsBoolean();
196 if (L.Type == Value::T_Integer || R.Type == Value::T_Integer)
197 return L.getAsInteger() == R.getAsInteger();
198 return *L.getAsNumber() == *R.getAsNumber();
200 return *L.getAsString() == *R.getAsString();
202 return *L.getAsArray() == *R.getAsArray();
204 return *L.getAsObject() == *R.getAsObject();
213 for (
P =
this;
P->Parent !=
nullptr;
P =
P->Parent)
217 R->ErrorMessage = Msg;
218 R->ErrorPath.resize(Count);
219 auto It = R->ErrorPath.begin();
220 for (
P =
this;
P->Parent !=
nullptr;
P =
P->Parent)
227 OS << (ErrorMessage.
empty() ?
"invalid JSON contents" : ErrorMessage);
228 if (ErrorPath.empty()) {
230 OS <<
" when parsing " << Name;
232 OS <<
" at " << (Name.
empty() ?
"(root)" : Name);
235 OS <<
'.' << S.field();
237 OS <<
'[' << S.index() <<
']';
245std::vector<const Object::value_type *> sortedElements(
const Object &O) {
246 std::vector<const Object::value_type *> Elements;
247 for (
const auto &
E : O)
248 Elements.push_back(&
E);
251 return L->first < R->first;
259void abbreviate(
const Value &V, OStream &JOS) {
262 JOS.rawValue(V.getAsArray()->empty() ?
"[]" :
"[ ... ]");
265 JOS.rawValue(V.getAsObject()->empty() ?
"{}" :
"{ ... }");
273 Truncated.append(
"...");
274 JOS.value(Truncated);
285void abbreviateChildren(
const Value &V, OStream &JOS) {
289 for (
const auto &
I : *
V.getAsArray())
295 for (
const auto *KV : sortedElements(*
V.getAsObject())) {
296 JOS.attributeBegin(KV->first);
297 abbreviate(KV->second, JOS);
319 auto HighlightCurrent = [&] {
320 std::string Comment =
"error: ";
321 Comment.append(ErrorMessage.data(), ErrorMessage.size());
323 abbreviateChildren(V, JOS);
326 return HighlightCurrent();
327 const Segment &S =
Path.back();
331 const Object *O = V.getAsObject();
332 if (!O || !O->get(FieldName))
333 return HighlightCurrent();
335 for (
const auto *KV : sortedElements(*O)) {
338 Recurse(KV->second,
Path.drop_back(), Recurse);
340 abbreviate(KV->second, JOS);
346 const Array *
A = V.getAsArray();
347 if (!
A || S.index() >=
A->size())
348 return HighlightCurrent();
350 unsigned Current = 0;
351 for (
const auto &V : *
A) {
352 if (Current++ == S.index())
353 Recurse(V,
Path.drop_back(), Recurse);
360 PrintValue(R, ErrorPath, PrintValue);
368 : Start(JSON.begin()),
P(JSON.begin()), End(JSON.end()) {}
374 P = Start + ErrOffset;
375 return parseError(
"Invalid UTF-8 sequence");
378 bool parseValue(
Value &Out);
384 return parseError(
"Text after end of document");
389 return std::move(*Err);
393 void eatWhitespace() {
394 while (
P != End && (*
P ==
' ' || *
P ==
'\r' || *
P ==
'\n' || *
P ==
'\t'))
399 bool parseNumber(
char First, Value &Out);
400 bool parseString(std::string &Out);
401 bool parseUnicode(std::string &Out);
402 bool parseError(
const char *Msg);
404 char next() {
return P == End ? 0 : *
P++; }
405 char peek() {
return P == End ? 0 : *
P; }
406 static bool isNumber(
char C) {
407 return C ==
'0' ||
C ==
'1' ||
C ==
'2' ||
C ==
'3' ||
C ==
'4' ||
408 C ==
'5' ||
C ==
'6' ||
C ==
'7' ||
C ==
'8' ||
C ==
'9' ||
409 C ==
'e' ||
C ==
'E' ||
C ==
'+' ||
C ==
'-' ||
C ==
'.';
412 std::optional<Error> Err;
413 const char *Start, *
P, *End;
416bool Parser::parseValue(Value &Out) {
419 return parseError(
"Unexpected EOF");
420 switch (
char C = next()) {
424 return (next() ==
'u' && next() ==
'l' && next() ==
'l') ||
425 parseError(
"Invalid JSON value (null?)");
428 return (next() ==
'r' && next() ==
'u' && next() ==
'e') ||
429 parseError(
"Invalid JSON value (true?)");
432 return (next() ==
'a' && next() ==
'l' && next() ==
's' && next() ==
'e') ||
433 parseError(
"Invalid JSON value (false?)");
436 if (parseString(S)) {
444 Array &
A = *Out.getAsArray();
451 A.emplace_back(
nullptr);
452 if (!parseValue(
A.back()))
462 return parseError(
"Expected , or ] after array element");
468 Object &
O = *Out.getAsObject();
476 return parseError(
"Expected object key");
482 return parseError(
"Expected : after object key");
484 if (!parseValue(O[std::move(K)]))
494 return parseError(
"Expected , or } after object property");
500 return parseNumber(
C, Out);
501 return parseError(
"Invalid JSON value");
505bool Parser::parseNumber(
char First, Value &Out) {
509 while (isNumber(
peek()))
516 int64_t
I = std::strtoll(S.c_str(), &End, 10);
517 if (End == S.end() && errno != ERANGE) {
526 uint64_t UI = std::strtoull(S.c_str(), &End, 10);
527 if (End == S.end() && errno != ERANGE) {
533 Out = std::strtod(S.c_str(), &End);
534 return End == S.end() || parseError(
"Invalid JSON value (number?)");
537bool Parser::parseString(std::string &Out) {
539 for (
char C = next();
C !=
'"';
C = next()) {
541 return parseError(
"Unterminated string");
543 return parseError(
"Control character in string");
549 switch (
C = next()) {
571 if (!parseUnicode(Out))
575 return parseError(
"Invalid escape sequence");
581static void encodeUtf8(
uint32_t Rune, std::string &Out) {
583 Out.push_back(Rune & 0x7F);
584 }
else if (Rune < 0x800) {
585 uint8_t FirstByte = 0xC0 | ((Rune & 0x7C0) >> 6);
586 uint8_t SecondByte = 0x80 | (Rune & 0x3F);
587 Out.push_back(FirstByte);
588 Out.push_back(SecondByte);
589 }
else if (Rune < 0x10000) {
590 uint8_t FirstByte = 0xE0 | ((Rune & 0xF000) >> 12);
591 uint8_t SecondByte = 0x80 | ((Rune & 0xFC0) >> 6);
592 uint8_t ThirdByte = 0x80 | (Rune & 0x3F);
593 Out.push_back(FirstByte);
594 Out.push_back(SecondByte);
595 Out.push_back(ThirdByte);
596 }
else if (Rune < 0x110000) {
597 uint8_t FirstByte = 0xF0 | ((Rune & 0x1F0000) >> 18);
598 uint8_t SecondByte = 0x80 | ((Rune & 0x3F000) >> 12);
599 uint8_t ThirdByte = 0x80 | ((Rune & 0xFC0) >> 6);
600 uint8_t FourthByte = 0x80 | (Rune & 0x3F);
601 Out.push_back(FirstByte);
602 Out.push_back(SecondByte);
603 Out.push_back(ThirdByte);
604 Out.push_back(FourthByte);
614bool Parser::parseUnicode(std::string &Out) {
616 auto Invalid = [&] { Out.append( {
'\xef',
'\xbf',
'\xbd'}); };
618 auto Parse4Hex = [
this](
uint16_t &Out) ->
bool {
620 char Bytes[] = {next(), next(), next(), next()};
621 for (
unsigned char C : Bytes) {
622 if (!std::isxdigit(
C))
623 return parseError(
"Invalid \\u escape sequence");
625 Out |= (
C >
'9') ? (
C & ~0x20) -
'A' + 10 : (
C -
'0');
630 if (!Parse4Hex(First))
636 if (
LLVM_LIKELY(First < 0xD800 || First >= 0xE000)) {
637 encodeUtf8(First, Out);
655 if (!Parse4Hex(Second))
664 encodeUtf8(0x10000 | ((First - 0xD800) << 10) | (Second - 0xDC00), Out);
669bool Parser::parseError(
const char *Msg) {
671 const char *StartOfLine = Start;
672 for (
const char *
X = Start;
X <
P; ++
X) {
679 std::make_unique<ParseError>(Msg, Line,
P - StartOfLine,
P - Start));
691 return P.takeError();
705 *ErrOffset = Rest -
Data;
711 std::vector<UTF32> Codepoints(S.
size());
712 const UTF8 *In8 =
reinterpret_cast<const UTF8 *
>(S.
data());
713 UTF32 *Out32 = Codepoints.data();
716 Codepoints.resize(Out32 - Codepoints.data());
717 std::string Res(4 * Codepoints.size(), 0);
718 const UTF32 *In32 = Codepoints.data();
719 UTF8 *Out8 =
reinterpret_cast<UTF8 *
>(&Res[0]);
722 Res.resize(
reinterpret_cast<char *
>(Out8) - Res.data());
728 for (
unsigned char C : S) {
729 if (
C == 0x22 ||
C == 0x5C)
764 OS << (*V.getAsBoolean() ?
"true" :
"false");
768 if (V.Type == Value::T_Integer)
769 OS << *V.getAsInteger();
770 else if (V.Type == Value::T_UINT64)
771 OS << *V.getAsUINT64();
773 OS <<
format(
"%.*g", std::numeric_limits<double>::max_digits10,
782 for (
const Value &
E : *V.getAsArray())
788 attribute(
E->first,
E->second);
793void llvm::json::OStream::valueBegin() {
794 assert(Stack.back().Ctx !=
Object &&
"Only attributes allowed here");
795 if (Stack.back().HasValue) {
796 assert(Stack.back().Ctx != Singleton &&
"Only one value allowed here");
799 if (Stack.back().Ctx == Array)
802 Stack.back().HasValue =
true;
806 assert(PendingComment.empty() &&
"Only one comment per value!");
807 PendingComment = Comment;
810void OStream::flushComment() {
811 if (PendingComment.empty())
813 OS << (IndentSize ?
"/* " :
"/*");
815 while (!PendingComment.empty()) {
816 auto Pos = PendingComment.find(
"*/");
818 OS << PendingComment;
821 OS << PendingComment.take_front(Pos) <<
"* /";
822 PendingComment = PendingComment.drop_front(Pos + 2);
825 OS << (IndentSize ?
" */" :
"*/");
827 if (
Stack.size() > 1 &&
Stack.back().Ctx == Singleton) {
835void llvm::json::OStream::newline() {
844 Stack.emplace_back();
845 Stack.back().Ctx =
Array;
846 Indent += IndentSize;
852 Indent -= IndentSize;
853 if (Stack.back().HasValue)
856 assert(PendingComment.empty());
863 Stack.emplace_back();
864 Stack.back().Ctx =
Object;
865 Indent += IndentSize;
871 Indent -= IndentSize;
872 if (Stack.back().HasValue)
875 assert(PendingComment.empty());
882 if (Stack.back().HasValue)
886 Stack.back().HasValue =
true;
887 Stack.emplace_back();
888 Stack.back().Ctx = Singleton;
892 assert(
false &&
"Invalid UTF-8 in attribute key");
901 assert(Stack.back().Ctx == Singleton);
902 assert(Stack.back().HasValue &&
"Attribute must have a value");
903 assert(PendingComment.empty());
910 Stack.emplace_back();
911 Stack.back().Ctx = RawValue;
916 assert(Stack.back().Ctx == RawValue);
925 unsigned IndentAmount = 0;
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_UNLIKELY(EXPR)
#define LLVM_LIKELY(EXPR)
Given that RA is a live value
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
This file supports working with JSON data.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static bool peek(struct InternalInstruction *insn, uint8_t &byte)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Lightweight error class with error context and mandatory checking.
Tagged union holding either a T or a Error.
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
StringRef - Represent a constant reference to a string, i.e.
constexpr bool empty() const
empty - Check if the string is empty.
constexpr size_t size() const
size - Get the string size.
StringRef take_front(size_t N=1) const
Return a StringRef equal to 'this' but with only the first N elements remaining.
bool equals(StringRef RHS) const
equals - Check for string equality, this is more efficient than compare() when the relative ordering ...
static constexpr size_t npos
const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM Value Representation.
An Array is a JSON array, which contains heterogeneous JSON values.
void emplace_back(Args &&...A)
json::OStream allows writing well-formed JSON without materializing all structures as json::Value ahe...
void object(Block Contents)
Emit an object whose elements are emitted in the provided Block.
void attributeBegin(llvm::StringRef Key)
raw_ostream & rawValueBegin()
void comment(llvm::StringRef)
Emit a JavaScript comment associated with the next printed value.
void array(Block Contents)
Emit an array whose elements are emitted in the provided Block.
void value(const Value &V)
Emit a self-contained value (number, string, vector<string> etc).
ObjectKey is a used to capture keys in Object.
An Object is a JSON object, which maps strings to heterogenous JSON values.
std::optional< bool > getBoolean(StringRef K) const
Value & operator[](const ObjectKey &K)
std::optional< double > getNumber(StringRef K) const
const json::Object * getObject(StringRef K) const
std::optional< llvm::StringRef > getString(StringRef K) const
Storage::value_type value_type
std::optional< int64_t > getInteger(StringRef K) const
std::optional< std::nullptr_t > getNull(StringRef K) const
std::pair< iterator, bool > try_emplace(const ObjectKey &K, Ts &&... Args)
iterator find(StringRef K)
const json::Array * getArray(StringRef K) const
The root is the trivial Path to the root value.
void printErrorContext(const Value &, llvm::raw_ostream &) const
Print the root value with the error shown inline as a comment.
Error getError() const
Returns the last error reported, or else a generic error.
A "cursor" marking a position within a Value.
void report(llvm::StringLiteral Message)
Records that the value at the current path is invalid.
A Value is an JSON value of unknown type.
@ Number
Number values can store both int64s and doubles at full precision, depending on what they were constr...
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an std::string.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
bool operator==(const Object &LHS, const Object &RHS)
bool isUTF8(llvm::StringRef S, size_t *ErrOffset=nullptr)
Returns true if S is valid UTF-8, which is required for use as JSON.
static void quote(llvm::raw_ostream &OS, llvm::StringRef S)
std::string fixUTF8(llvm::StringRef S)
Replaces invalid UTF-8 sequences in S with the replacement character (U+FFFD).
This is an optimization pass for GlobalISel generic memory operations.
ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd, UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags)
Convert a partial UTF8 sequence to UTF32.
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
auto reverse(ContainerTy &&C)
void sort(IteratorTy Start, IteratorTy End)
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
void write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style, std::optional< size_t > Width=std::nullopt)
ConversionResult ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd, UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
@ Invalid
Denotes invalid value.
Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd)