///|
/// A JSON syntax or range error, mirroring serde_json's error codes and
/// positions (1-based line, column in UTF-8 bytes).
pub(all) suberror ParseError {
ParseError(message~ : String, line~ : Int, column~ : Int)
} derive(Debug, Eq)
///|
pub impl Show for ParseError with fn output(self, logger) {
let ParseError(message~, line~, column~) = self
logger.write_string("\{message} at line \{line} column \{column}")
}
///|
/// serde_json's default recursion limit.
let recursion_limit : Int = 128
///|
/// A byte-level port of serde_json's `Deserializer` restricted to
/// what `from_str::` exercises.
priv struct Parser {
src : Bytes
mut index : Int
mut remaining_depth : Int
/// Whether the last string parsed contained an escape sequence.
mut last_escaped : Bool
/// Lenient mode defers errors that serde_json only reports when a value is
/// actually visited (not skipped as an ignored field).
lenient : Bool
/// The first deferred error within the value being parsed.
mut pending : ParseError?
/// Nesting levels past the recursion limit being parsed leniently.
mut unlimited : Int
}
///|
/// Record a deferrable error: raise in strict mode, remember in lenient mode.
fn Parser::postpone(self : Parser, e : ParseError) -> Unit raise ParseError {
if !self.lenient {
raise e
}
if self.pending is None {
self.pending = Some(e)
}
}
///|
fn Parser::take_pending(self : Parser) -> ParseError? {
let p = self.pending
self.pending = None
p
}
///|
/// serde_json's `POW10` table (exactly rounded powers of ten).
let pow10 : ReadOnlyArray[Double] = [
1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10, 1.0e11,
1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20, 1.0e21,
1.0e22, 1.0e23, 1.0e24, 1.0e25, 1.0e26, 1.0e27, 1.0e28, 1.0e29, 1.0e30, 1.0e31,
1.0e32, 1.0e33, 1.0e34, 1.0e35, 1.0e36, 1.0e37, 1.0e38, 1.0e39, 1.0e40, 1.0e41,
1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49, 1.0e50, 1.0e51,
1.0e52, 1.0e53, 1.0e54, 1.0e55, 1.0e56, 1.0e57, 1.0e58, 1.0e59, 1.0e60, 1.0e61,
1.0e62, 1.0e63, 1.0e64, 1.0e65, 1.0e66, 1.0e67, 1.0e68, 1.0e69, 1.0e70, 1.0e71,
1.0e72, 1.0e73, 1.0e74, 1.0e75, 1.0e76, 1.0e77, 1.0e78, 1.0e79, 1.0e80, 1.0e81,
1.0e82, 1.0e83, 1.0e84, 1.0e85, 1.0e86, 1.0e87, 1.0e88, 1.0e89, 1.0e90, 1.0e91,
1.0e92, 1.0e93, 1.0e94, 1.0e95, 1.0e96, 1.0e97, 1.0e98, 1.0e99, 1.0e100, 1.0e101,
1.0e102, 1.0e103, 1.0e104, 1.0e105, 1.0e106, 1.0e107, 1.0e108, 1.0e109, 1.0e110,
1.0e111, 1.0e112, 1.0e113, 1.0e114, 1.0e115, 1.0e116, 1.0e117, 1.0e118, 1.0e119,
1.0e120, 1.0e121, 1.0e122, 1.0e123, 1.0e124, 1.0e125, 1.0e126, 1.0e127, 1.0e128,
1.0e129, 1.0e130, 1.0e131, 1.0e132, 1.0e133, 1.0e134, 1.0e135, 1.0e136, 1.0e137,
1.0e138, 1.0e139, 1.0e140, 1.0e141, 1.0e142, 1.0e143, 1.0e144, 1.0e145, 1.0e146,
1.0e147, 1.0e148, 1.0e149, 1.0e150, 1.0e151, 1.0e152, 1.0e153, 1.0e154, 1.0e155,
1.0e156, 1.0e157, 1.0e158, 1.0e159, 1.0e160, 1.0e161, 1.0e162, 1.0e163, 1.0e164,
1.0e165, 1.0e166, 1.0e167, 1.0e168, 1.0e169, 1.0e170, 1.0e171, 1.0e172, 1.0e173,
1.0e174, 1.0e175, 1.0e176, 1.0e177, 1.0e178, 1.0e179, 1.0e180, 1.0e181, 1.0e182,
1.0e183, 1.0e184, 1.0e185, 1.0e186, 1.0e187, 1.0e188, 1.0e189, 1.0e190, 1.0e191,
1.0e192, 1.0e193, 1.0e194, 1.0e195, 1.0e196, 1.0e197, 1.0e198, 1.0e199, 1.0e200,
1.0e201, 1.0e202, 1.0e203, 1.0e204, 1.0e205, 1.0e206, 1.0e207, 1.0e208, 1.0e209,
1.0e210, 1.0e211, 1.0e212, 1.0e213, 1.0e214, 1.0e215, 1.0e216, 1.0e217, 1.0e218,
1.0e219, 1.0e220, 1.0e221, 1.0e222, 1.0e223, 1.0e224, 1.0e225, 1.0e226, 1.0e227,
1.0e228, 1.0e229, 1.0e230, 1.0e231, 1.0e232, 1.0e233, 1.0e234, 1.0e235, 1.0e236,
1.0e237, 1.0e238, 1.0e239, 1.0e240, 1.0e241, 1.0e242, 1.0e243, 1.0e244, 1.0e245,
1.0e246, 1.0e247, 1.0e248, 1.0e249, 1.0e250, 1.0e251, 1.0e252, 1.0e253, 1.0e254,
1.0e255, 1.0e256, 1.0e257, 1.0e258, 1.0e259, 1.0e260, 1.0e261, 1.0e262, 1.0e263,
1.0e264, 1.0e265, 1.0e266, 1.0e267, 1.0e268, 1.0e269, 1.0e270, 1.0e271, 1.0e272,
1.0e273, 1.0e274, 1.0e275, 1.0e276, 1.0e277, 1.0e278, 1.0e279, 1.0e280, 1.0e281,
1.0e282, 1.0e283, 1.0e284, 1.0e285, 1.0e286, 1.0e287, 1.0e288, 1.0e289, 1.0e290,
1.0e291, 1.0e292, 1.0e293, 1.0e294, 1.0e295, 1.0e296, 1.0e297, 1.0e298, 1.0e299,
1.0e300, 1.0e301, 1.0e302, 1.0e303, 1.0e304, 1.0e305, 1.0e306, 1.0e307, 1.0e308,
]
///|
/// `SliceRead::position_of_index`.
fn Parser::error_at(self : Parser, i : Int, message : String) -> ParseError {
let mut line = 1
let mut start_of_line = 0
for j in 0.. ParseError {
self.error_at(self.index, message)
}
///|
/// serde_json `peek_error`: position just after the peeked byte.
fn Parser::peek_error(self : Parser, message : String) -> ParseError {
self.error_at((self.index + 1).min(self.src.length()), message)
}
///|
fn Parser::peek(self : Parser) -> Int {
if self.index < self.src.length() {
self.src[self.index].to_int()
} else {
-1
}
}
///|
fn Parser::next_char(self : Parser) -> Int {
let c = self.peek()
if c >= 0 {
self.index += 1
}
c
}
///|
/// `parse_whitespace`: skip whitespace and peek.
fn Parser::parse_whitespace(self : Parser) -> Int {
while self.peek() is (0x20 | 0x0A | 0x0D | 0x09) {
self.index += 1
}
self.peek()
}
///|
fn Parser::parse_ident(self : Parser, ident : String) -> Unit raise ParseError {
for c in ident {
let next = self.next_char()
if next < 0 {
raise self.error("EOF while parsing a value")
} else if next != c.to_int() {
raise self.error("expected ident")
}
}
}
///|
/// `deserialize_any` building an ordered `Content`.
fn Parser::parse_value(self : Parser) -> Content raise ParseError {
let peek = self.parse_whitespace()
match peek {
-1 => raise self.peek_error("EOF while parsing a value")
'n' => {
self.index += 1
self.parse_ident("ull")
Null
}
't' => {
self.index += 1
self.parse_ident("rue")
Bool(true)
}
'f' => {
self.index += 1
self.parse_ident("alse")
Bool(false)
}
'-' => {
self.index += 1
self.number_or_deferred(false)
}
'0'..='9' => self.number_or_deferred(true)
'"' => {
self.index += 1
let s = self.parse_str()
match self.take_pending() {
Some(e) => Invalid(e)
None => String(s)
}
}
'[' => {
let too_deep = self.check_recursion()
self.index += 1
let items = self.parse_seq()
self.leave()
// end_seq: the visitor only returns after peeking `]`.
self.index += 1
match too_deep {
Some(e) => Invalid(e)
None => Array(items)
}
}
'{' => {
let too_deep = self.check_recursion()
self.index += 1
let obj = self.parse_map()
self.leave()
self.index += 1
match too_deep {
Some(e) => Invalid(e)
None => Object(obj)
}
}
_ => raise self.peek_error("expected value")
}
}
///|
/// Enter a nested array/object. Returns a deferred error when the recursion
/// limit is exceeded in lenient mode (the subtree is then parsed without
/// limit, as serde_json skips ignored values).
fn Parser::check_recursion(self : Parser) -> ParseError? raise ParseError {
if self.unlimited > 0 {
self.unlimited += 1
return None
}
self.remaining_depth -= 1
if self.remaining_depth == 0 {
let e = self.peek_error("recursion limit exceeded")
if !self.lenient {
raise e
}
self.remaining_depth += 1
self.unlimited = 1
return Some(e)
}
None
}
///|
fn Parser::leave(self : Parser) -> Unit {
if self.unlimited > 0 {
self.unlimited -= 1
} else {
self.remaining_depth += 1
}
}
///|
/// `SeqAccess::next_element_seed` driven to completion. Leaves the closing
/// `]` unconsumed.
fn Parser::parse_seq(self : Parser) -> Array[Content] raise ParseError {
let items = []
for first = true {
let peek = self.parse_whitespace()
if peek < 0 {
raise self.peek_error("EOF while parsing a list")
}
if peek == ']' {
break
} else if first {
()
} else if peek == ',' {
self.index += 1
match self.parse_whitespace() {
']' => raise self.peek_error("trailing comma")
-1 => raise self.peek_error("EOF while parsing a value")
_ => ()
}
} else {
raise self.peek_error("expected `,` or `]`")
}
items.push(self.parse_value())
continue false
}
items
}
///|
/// `MapAccess` driven to completion. Leaves the closing `}` unconsumed.
fn Parser::parse_map(self : Parser) -> Array[Entry] raise ParseError {
let obj = []
for first = true {
let peek = self.parse_whitespace()
if peek < 0 {
raise self.peek_error("EOF while parsing an object")
}
if peek == '}' {
break
} else if first {
if peek != '"' {
raise self.peek_error("key must be a string")
}
} else if peek == ',' {
self.index += 1
match self.parse_whitespace() {
'"' => ()
'}' => raise self.peek_error("trailing comma")
-1 => raise self.peek_error("EOF while parsing a value")
_ => raise self.peek_error("key must be a string")
}
} else {
raise self.peek_error("expected `,` or `}`")
}
// MapKey: eat the quote and parse the string.
self.index += 1
let key = self.parse_str()
let key_escaped = self.last_escaped
let key_error = self.take_pending()
// parse_object_colon
match self.parse_whitespace() {
':' => self.index += 1
-1 => raise self.peek_error("EOF while parsing an object")
_ => raise self.peek_error("expected `:`")
}
// Entries keep their order and duplicates.
obj.push({ key, key_escaped, key_error, value: self.parse_value(), })
continue false
}
obj
}
///|
fn push_utf8(buf : Buffer, cp : Int) -> Unit {
if cp < 0x80 {
buf.write_byte(cp.to_byte())
} else if cp < 0x800 {
buf.write_byte((0xC0 | (cp >> 6)).to_byte())
buf.write_byte((0x80 | (cp & 0x3F)).to_byte())
} else if cp < 0x10000 {
buf.write_byte((0xE0 | (cp >> 12)).to_byte())
buf.write_byte((0x80 | ((cp >> 6) & 0x3F)).to_byte())
buf.write_byte((0x80 | (cp & 0x3F)).to_byte())
} else {
buf.write_byte((0xF0 | (cp >> 18)).to_byte())
buf.write_byte((0x80 | ((cp >> 12) & 0x3F)).to_byte())
buf.write_byte((0x80 | ((cp >> 6) & 0x3F)).to_byte())
buf.write_byte((0x80 | (cp & 0x3F)).to_byte())
}
}
///|
/// `SliceRead::decode_hex_escape`.
fn Parser::decode_hex_escape(self : Parser) -> Int raise ParseError {
if self.index + 4 > self.src.length() {
self.index = self.src.length()
raise self.error("EOF while parsing a string")
}
let mut n = 0
let mut ok = true
for k in 0..<4 {
let c = self.src[self.index + k].to_int()
let d = match c {
'0'..='9' => c - '0'
'a'..='f' => c - 'a' + 10
'A'..='F' => c - 'A' + 10
_ => {
ok = false
0
}
}
n = n * 16 + d
}
self.index += 4
if !ok {
raise self.error("invalid escape")
}
n
}
///|
/// `parse_escape` + `parse_unicode_escape` with `validate = true`.
fn Parser::parse_escape(self : Parser, buf : Buffer) -> Unit raise ParseError {
let ch = self.next_char()
match ch {
-1 => raise self.error("EOF while parsing a string")
'"' => buf.write_byte(b'"')
'\\' => buf.write_byte(b'\\')
'/' => buf.write_byte(b'/')
'b' => buf.write_byte(b'\x08')
'f' => buf.write_byte(b'\x0c')
'n' => buf.write_byte(b'\n')
'r' => buf.write_byte(b'\r')
't' => buf.write_byte(b'\t')
'u' => {
let n = self.decode_hex_escape()
if n >= 0xDC00 && n <= 0xDFFF {
self.postpone(self.error("lone leading surrogate in hex escape"))
return
}
if n < 0xD800 || n > 0xDBFF {
push_utf8(buf, n)
return
}
// A leading surrogate must be followed by `\u` + trailing surrogate.
// (When skipping, serde_json does not pair surrogates at all.)
match self.peek() {
-1 => raise self.error("EOF while parsing a string")
'\\' => self.index += 1
_ => {
self.index += 1
let e = self.error("unexpected end of hex escape")
self.index -= 1
self.postpone(e)
return
}
}
match self.peek() {
-1 => raise self.error("EOF while parsing a string")
'u' => self.index += 1
_ => {
self.index += 1
let e = self.error("unexpected end of hex escape")
// Resume at the backslash: it starts an ordinary escape.
self.index -= 2
self.postpone(e)
return
}
}
let n2 = self.decode_hex_escape()
if n2 < 0xDC00 || n2 > 0xDFFF {
self.postpone(self.error("lone leading surrogate in hex escape"))
return
}
push_utf8(buf, 0x10000 + ((n - 0xD800) << 10) + (n2 - 0xDC00))
}
_ => raise self.error("invalid escape")
}
}
///|
/// `SliceRead::parse_str_bytes`; the opening quote has been consumed.
fn Parser::parse_str(self : Parser) -> String raise ParseError {
let buf = Buffer()
self.last_escaped = false
for ;; {
let c = self.peek()
match c {
-1 => raise self.error("EOF while parsing a string")
'"' => {
self.index += 1
break
}
'\\' => {
self.index += 1
self.last_escaped = true
self.parse_escape(buf)
}
_ if c < 0x20 => {
self.index += 1
raise self.error(
"control character (\\u0000-\\u001F) found while parsing a string",
)
}
_ => {
buf.write_byte(c.to_byte())
self.index += 1
}
}
}
@utf8.decode(buf.to_bytes()) catch {
_ => abort("unreachable: input and escapes are valid UTF-8")
}
}
///|
/// Parse a number; in lenient mode an out-of-range number becomes a deferred
/// error after validating its syntax like serde_json's `ignore_number`.
fn Parser::number_or_deferred(
self : Parser,
positive : Bool,
) -> Content raise ParseError {
let start = self.index
try self.parse_integer(positive) catch {
ParseError(message="number out of range", ..) as e if self.lenient => {
self.index = start
self.ignore_number()
Invalid(e)
}
e => raise e
} noraise {
n => Number(n)
}
}
///|
/// serde_json's `ignore_integer` / `ignore_decimal` / `ignore_exponent`:
/// syntax only.
fn Parser::ignore_number(self : Parser) -> Unit raise ParseError {
match self.next_char() {
'0' =>
if self.peek() is ('0'..='9') {
raise self.peek_error("invalid number")
}
'1'..='9' =>
while self.peek() is ('0'..='9') {
self.index += 1
}
-1 => raise self.error("EOF while parsing a value")
_ => raise self.error("invalid number")
}
if self.peek() == '.' {
self.index += 1
let mut digits = 0
while self.peek() is ('0'..='9') {
self.index += 1
digits += 1
}
if digits == 0 {
if self.peek() < 0 {
raise self.peek_error("EOF while parsing a value")
}
raise self.peek_error("invalid number")
}
}
if self.peek() is ('e' | 'E') {
self.index += 1
if self.peek() is ('+' | '-') {
self.index += 1
}
match self.next_char() {
'0'..='9' => ()
-1 => raise self.error("EOF while parsing a value")
_ => raise self.error("invalid number")
}
while self.peek() is ('0'..='9') {
self.index += 1
}
}
}
///|
fn overflows_u64(significand : UInt64, digit : UInt64) -> Bool {
let max = 0xFFFF_FFFF_FFFF_FFFFUL
significand >= max / 10 && (significand > max / 10 || digit > max % 10)
}
///|
fn Parser::parse_integer(
self : Parser,
positive : Bool,
) -> Number raise ParseError {
let next = self.next_char()
match next {
-1 => raise self.error("EOF while parsing a value")
'0' => {
// There can be only one leading '0'.
if self.peek() is ('0'..='9') {
raise self.peek_error("invalid number")
}
self.parse_number(positive, 0)
}
'1'..='9' => {
let mut significand = (next - '0').to_uint64()
for ;; {
let c = self.peek()
if !(c is ('0'..='9')) {
break self.parse_number(positive, significand)
}
let digit = (c - '0').to_uint64()
if overflows_u64(significand, digit) {
break Float(self.parse_long_integer(positive, significand))
}
self.index += 1
significand = significand * 10 + digit
}
}
_ => raise self.error("invalid number")
}
}
///|
fn Parser::parse_number(
self : Parser,
positive : Bool,
significand : UInt64,
) -> Number raise ParseError {
match self.peek() {
'.' => Float(self.parse_decimal(positive, significand, 0))
'e' | 'E' => Float(self.parse_exponent(positive, significand, 0))
_ =>
if positive {
PosInt(significand)
} else {
let neg = -significand.reinterpret_as_int64()
// Convert into a float if we underflow, or on `-0`.
if neg >= 0L {
Float(-significand.to_double())
} else {
NegInt(neg)
}
}
}
}
///|
fn Parser::parse_decimal(
self : Parser,
positive : Bool,
significand : UInt64,
exponent_before_decimal_point : Int,
) -> Double raise ParseError {
self.index += 1 // '.'
let mut significand = significand
let mut exponent_after_decimal_point = 0
while self.peek() is ('0'..='9') {
let digit = (self.peek() - '0').to_uint64()
if overflows_u64(significand, digit) {
let exponent = exponent_before_decimal_point +
exponent_after_decimal_point
// parse_decimal_overflow: ignore all further digits.
while self.peek() is ('0'..='9') {
self.index += 1
}
return match self.peek() {
'e' | 'E' => self.parse_exponent(positive, significand, exponent)
_ => self.f64_from_parts(positive, significand, exponent)
}
}
self.index += 1
significand = significand * 10 + digit
exponent_after_decimal_point -= 1
}
// Error if there is not at least one digit after the decimal point.
if exponent_after_decimal_point == 0 {
if self.peek() < 0 {
raise self.peek_error("EOF while parsing a value")
}
raise self.peek_error("invalid number")
}
let exponent = exponent_before_decimal_point + exponent_after_decimal_point
match self.peek() {
'e' | 'E' => self.parse_exponent(positive, significand, exponent)
_ => self.f64_from_parts(positive, significand, exponent)
}
}
///|
fn Parser::parse_exponent(
self : Parser,
positive : Bool,
significand : UInt64,
starting_exp : Int,
) -> Double raise ParseError {
self.index += 1 // 'e' | 'E'
let positive_exp = match self.peek() {
'+' => {
self.index += 1
true
}
'-' => {
self.index += 1
false
}
_ => true
}
let next = self.next_char()
if next < 0 {
raise self.error("EOF while parsing a value")
}
// Make sure a digit follows the exponent place.
if !(next is ('0'..='9')) {
raise self.error("invalid number")
}
let mut exp = next - '0'
let int_max = 2147483647
while self.peek() is ('0'..='9') {
let digit = self.peek() - '0'
self.index += 1
if exp >= int_max / 10 && (exp > int_max / 10 || digit > int_max % 10) {
// parse_exponent_overflow: error instead of +/- infinity.
if significand != 0UL && positive_exp {
raise self.error("number out of range")
}
while self.peek() is ('0'..='9') {
self.index += 1
}
return if positive { 0.0 } else { -0.0 }
}
exp = exp * 10 + digit
}
let final_exp = if positive_exp {
saturating_add(starting_exp, exp)
} else {
saturating_add(starting_exp, -exp)
}
self.f64_from_parts(positive, significand, final_exp)
}
///|
fn saturating_add(a : Int, b : Int) -> Int {
let r = a.to_int64() + b.to_int64()
if r > 2147483647L {
2147483647
} else if r < -2147483648L {
-2147483648
} else {
r.to_int()
}
}
///|
/// serde_json's non-`float_roundtrip` float assembly (de.rs `f64_from_parts`).
/// Note: this is not always correctly rounded, exactly like serde_json.
fn Parser::f64_from_parts(
self : Parser,
positive : Bool,
significand : UInt64,
exponent : Int,
) -> Double raise ParseError {
let mut f = significand.to_double()
let mut exponent = exponent
for ;; {
// `exponent.wrapping_abs() as usize`
let idx = if exponent == -2147483648 { -1 } else { exponent.abs() }
if idx >= 0 && idx < pow10.length() {
if exponent >= 0 {
f = f * pow10[idx]
if f.is_inf() {
raise self.error("number out of range")
}
} else {
f = f / pow10[idx]
}
break
}
if f == 0.0 {
break
}
if exponent >= 0 {
raise self.error("number out of range")
}
f = f / 1.0e308
exponent += 308
}
if positive {
f
} else {
-f
}
}
///|
fn Parser::parse_long_integer(
self : Parser,
positive : Bool,
significand : UInt64,
) -> Double raise ParseError {
let mut exponent = 0
for ;; {
match self.peek() {
'0'..='9' => {
self.index += 1
exponent += 1
}
'.' => break self.parse_decimal(positive, significand, exponent)
'e' | 'E' => break self.parse_exponent(positive, significand, exponent)
_ => break self.f64_from_parts(positive, significand, exponent)
}
}
}
///|
/// Parse JSON text exactly like `serde_json::from_str::`, including
/// its error messages and positions.
pub fn parse(text : StringView) -> Value raise ParseError {
parse_content(text).to_value()
}
///|
/// Parse JSON text into an ordered document that keeps duplicate keys,
/// number classes and key-escape information (serde's `Content` view of the
/// input).
pub fn parse_content(
text : StringView,
lenient? : Bool = false,
) -> Content raise ParseError {
let p = Parser::{
src: @utf8.encode(text),
index: 0,
remaining_depth: recursion_limit,
last_escaped: false,
lenient,
pending: None,
unlimited: 0,
}
let v = p.parse_value()
// Deserializer::end
if p.parse_whitespace() >= 0 {
raise p.peek_error("trailing characters")
}
v
}