Issue #1738 - Part 2: Implement well-formed JSON stringify

This implements the ES2019 spec for JSON stringification, including
lower-casing, properly escaping lone surrogates, etc.
This commit is contained in:
Moonchild 2021-02-11 13:55:24 +00:00 committed by roytam1
commit 23c9fab20d
2 changed files with 68 additions and 14 deletions

View file

@ -66,26 +66,67 @@ InfallibleQuote(RangedPtr<const SrcCharT> srcBegin, RangedPtr<const SrcCharT> sr
/* Step 1. */
*dstPtr++ = '"';
// XXX: This is a rather ugly in-line definition. Move it somewhere better?
auto ToLowerHex = [](uint8_t u) {
MOZ_ASSERT(u <= 0xF);
return "0123456789abcdef"[u];
};
/* Step 2. */
while (srcBegin != srcEnd) {
SrcCharT c = *srcBegin++;
size_t escapeIndex = c % sizeof(escapeLookup);
Latin1Char escaped = escapeLookup[escapeIndex];
if (MOZ_LIKELY((escapeIndex != size_t(c)) || !escaped)) {
const SrcCharT c = *srcBegin++;
// Handle the Latin-1 cases.
if (MOZ_LIKELY(c < sizeof(escapeLookup))) {
Latin1Char escaped = escapeLookup[c];
// Directly copy non-escaped code points.
if (escaped == 0) {
*dstPtr++ = c;
continue;
}
// Escape the rest, elaborating Unicode escapes when needed.
*dstPtr++ = '\\';
*dstPtr++ = escaped;
if (escaped == 'u') {
*dstPtr++ = '0';
*dstPtr++ = '0';
uint8_t x = c >> 4;
MOZ_ASSERT(x < 10);
*dstPtr++ = '0' + x;
*dstPtr++ = ToLowerHex(c & 0xF);
}
continue;
}
// Non-ASCII non-surrogates are directly copied.
if (!unicode::IsSurrogate(c)) {
*dstPtr++ = c;
continue;
}
*dstPtr++ = '\\';
*dstPtr++ = escaped;
if (escaped == 'u') {
MOZ_ASSERT(c < ' ');
MOZ_ASSERT((c >> 4) < 10);
uint8_t x = c >> 4, y = c % 16;
*dstPtr++ = '0';
*dstPtr++ = '0';
*dstPtr++ = '0' + x;
*dstPtr++ = y < 10 ? '0' + y : 'a' + (y - 10);
// So too for complete surrogate pairs.
if (MOZ_LIKELY(unicode::IsLeadSurrogate(c) &&
srcBegin < srcEnd &&
unicode::IsTrailSurrogate(*srcBegin)))
{
*dstPtr++ = c;
*dstPtr++ = *srcBegin++;
continue;
}
// But lone surrogates are Unicode-escaped.
char32_t as32 = char32_t(c);
*dstPtr++ = '\\';
*dstPtr++ = 'u';
*dstPtr++ = ToLowerHex(as32 >> 12);
*dstPtr++ = ToLowerHex((as32 >> 8) & 0xF);
*dstPtr++ = ToLowerHex((as32 >> 4) & 0xF);
*dstPtr++ = ToLowerHex(as32 & 0xF);
}
/* Steps 3-4. */