final class · System.Text
JsonReader
public final class JsonReader
Reads a value from UTF-8 units. Arrays and objects nest at most MaxDepth deep (a FormatError beyond).
- Kind
- final class
- Namespace
- System.Text
- Assembly
- System.Core
- Access
- public, final
- Source file
Json.ant
Inheritance
- Base classes
-
AnyJsonReader
Constructors
Properties
Methods
Fail(str what)
#
SkipSpace()
#
ExpectWord(str word)
#
A number by the JSON grammar: -?, 0 or digits not starting with one, a fraction . digits, an
exponent e/E, a sign, digits (no leading zeros, no 1., no .5).
Past the digits here; how many there were.
ReadText() : str
#
ReadKey() : str
#
An object's key: the string of an earlier key with the same units when there is one.
Constants
Private and internal members (8)
Inherited members (5)
GetTypemethod from AnyUndescribedmethod from AnyToStringmethod from AnyHashmethod from Anydestroymethod from Any
Source
JsonReader as Antril, decompiled from its Larva HIR.
// System.Text.JsonReader — System.Core (decompiled from Larva HIR)
import System;
into namespace System.Text
{
/// Reads a value from UTF-8 units. Arrays and objects nest at most MaxDepth deep (a FormatError beyond).
public final class JsonReader
{
u8[] p;
i32 at;
i32 depth;
u8[] scratch;
i32 used;
str?[] keys;
Enter()
{
depth++;
if (depth > 256)
Fail("nesting deeper than " + 256);
}
Put(u32 unit)
{
if (used == scratch.Length)
{
u8[] bigger = new u8[scratch.Length * 2];
Array.Copy(scratch, 0, bigger, 0, used);
scratch = bigger;
}
scratch[used] = (u8)unit;
used++;
}
public:
const i32 MaxDepth = 256;
new(u8[] units)
{
p = units;
scratch = new u8[64];
keys = new str?[64];
}
Fail(str what)
{
throw new FormatError("JSON: " + what + " at " + at);
}
SkipSpace()
{
loop (at < p.Length && (p[at] == 32 || p[at] == 9 || p[at] == 10 || p[at] == 13))
at++;
}
ReadValue() : JsonValue
{
SkipSpace();
if (at >= p.Length)
Fail("unexpected end");
u32 c = p[at];
if (c == 123)
return ReadObject();
if (c == 91)
return ReadArray();
if (c == 34)
return JsonValue.Of(ReadText());
if (c == 116)
{
ExpectWord("true");
return JsonValue.Of(true);
}
if (c == 102)
{
ExpectWord("false");
return JsonValue.Of(false);
}
if (c == 110)
{
ExpectWord("null");
return JsonValue.Null();
}
if (c == 45 || c >= 48 && c <= 57)
return ReadNumber();
Fail("unexpected character");
return JsonValue.Null();
}
ExpectWord(str word)
{
i32 n = word.Length;
loop (i32 i = 0..n)
{
if (at + i >= p.Length || p[at + i] != word[i])
Fail("expected " + word);
}
at += n;
}
/// A number by the JSON grammar: `-`?, `0` or digits not starting with one, a fraction `.` digits, an
/// exponent `e`/`E`, a sign, digits (no leading zeros, no `1.`, no `.5`).
ReadNumber() : JsonValue
{
i32 start = at;
bool negative = p[at] == 45;
if (negative)
at++;
if (at < p.Length && p[at] == 48)
at++;
else if (Digits() == 0)
Fail("bad number");
i32 whole = at - start - (negative ? 1 : 0);
bool integer = !(at < p.Length && (p[at] == 46 || p[at] == 101 || p[at] == 69));
if (integer && whole <= 15 && !(negative && whole == 1 && p[at - 1] == 48))
{
i64 value = 0;
loop (i32 i = at - whole..at)
value = value * 10 + ((i64)p[i] - 48);
return JsonValue.Of(negative ? -value : value);
}
if (at < p.Length && p[at] == 46)
{
at++;
if (Digits() == 0)
Fail("bad number");
}
if (at < p.Length && (p[at] == 101 || p[at] == 69))
{
at++;
if (at < p.Length && (p[at] == 43 || p[at] == 45))
at++;
if (Digits() == 0)
Fail("bad number");
}
f64? parsed = Float64.TryParse(new str(p, start, at - start));
if (parsed == null)
Fail("bad number");
return JsonValue.Of(parsed ?? 0.0);
}
/// Past the digits here; how many there were.
Digits() : i32
{
i32 start = at;
loop (at < p.Length && p[at] >= 48 && p[at] <= 57)
at++;
return at - start;
}
ReadText() : str
{
at++;
i32 start = at;
loop (at < p.Length && p[at] != 34 && p[at] != 92)
at++;
if (at >= p.Length)
Fail("unterminated string");
if (p[at] == 34)
{
at++;
return new str(p, start, at - 1 - start);
}
used = 0;
loop (i32 i = start..at)
Put(p[i]);
loop (true)
{
if (at >= p.Length)
Fail("unterminated string");
u32 c = p[at];
at++;
if (c == 34)
break;
if (c != 92)
{
Put(c);
continue;
}
if (at >= p.Length)
Fail("unterminated escape");
u32 e = p[at];
at++;
if (e == 110)
Put(10);
else if (e == 116)
Put(9);
else if (e == 114)
Put(13);
else if (e == 98)
Put(8);
else if (e == 102)
Put(12);
else if (e == 34 || e == 92 || e == 47)
Put(e);
else if (e == 117)
{
u32 code = ReadHex4();
if (code >= 55296 && code < 56320)
{
i32 before = at;
u32 low = 0;
if (at + 1 < p.Length && p[at] == 92 && p[at + 1] == 117)
{
at += 2;
low = ReadHex4();
}
if (low >= 56320 && low < 57344)
code = 65536 + (code - 55296 << 10) + (low - 56320);
else
{
at = before;
code = 65533;
}
}
else if (code >= 56320 && code < 57344)
code = 65533;
if (code < 128)
Put(code);
else if (code < 2048)
{
Put(192 | code >> 6);
Put(128 | code & 63);
}
else if (code < 65536)
{
Put(224 | code >> 12);
Put(128 | code >> 6 & 63);
Put(128 | code & 63);
}
else
{
Put(240 | code >> 18);
Put(128 | code >> 12 & 63);
Put(128 | code >> 6 & 63);
Put(128 | code & 63);
}
}
else
Fail("bad escape");
}
return new str(scratch, 0, used);
}
/// An object's key: the string of an earlier key with the same units when there is one.
ReadKey() : str
{
i32 start = at + 1;
i32 end = start;
u32 h = 0;
loop (end < p.Length && p[end] != 34 && p[end] != 92)
{
h = h * 31 + (u32)p[end];
end++;
}
if (end >= p.Length || p[end] != 34 || end - start > 32)
return ReadText();
i32 count = end - start;
i32 slot = (i32)(h & 63);
at = end + 1;
if (keys[slot] is str known && known.Length == count)
{
bool same = true;
loop (i32 i = 0..count)
{
if (known[i] != p[start + i])
{
same = false;
break;
}
}
if (same)
return known;
}
str key = new str(p, start, count);
keys[slot] = key;
return key;
}
ReadHex4() : u32
{
u32 value = 0;
loop (i32 i = 0..4)
{
if (at >= p.Length)
Fail("bad \\u escape");
u32 c = p[at];
at++;
u32 digit = c >= 48 && c <= 57 ? c - 48 : c >= 97 && c <= 102 ? c - 97 + 10 : c >= 65 && c <= 70 ? c - 65 + 10 : 16;
if (digit > 15)
Fail("bad \\u escape");
value = value * 16 + digit;
}
return value;
}
ReadArray() : JsonValue
{
at++;
Enter();
JsonValue array = JsonValue.NewArray();
SkipSpace();
if (at < p.Length && p[at] == 93)
{
at++;
depth--;
return array;
}
loop (true)
{
array.Add(ReadValue());
SkipSpace();
if (at >= p.Length)
Fail("unterminated array");
u32 c = p[at];
at++;
if (c == 93)
break;
if (c != 44)
Fail("expected , or ]");
}
depth--;
return array;
}
ReadObject() : JsonValue
{
at++;
Enter();
JsonValue obj = JsonValue.NewObject();
SkipSpace();
if (at < p.Length && p[at] == 125)
{
at++;
depth--;
return obj;
}
loop (true)
{
SkipSpace();
if (at >= p.Length || p[at] != 34)
Fail("expected a key");
str key = ReadKey();
SkipSpace();
if (at >= p.Length || p[at] != 58)
Fail("expected :");
at++;
obj.Set(key, ReadValue());
SkipSpace();
if (at >= p.Length)
Fail("unterminated obj");
u32 c = p[at];
at++;
if (c == 125)
break;
if (c != 44)
Fail("expected , or }");
}
depth--;
return obj;
}
bool AtEnd
{
get => at >= p.Length;
}
}
}