// The fast scanner. Each function below is one `lexscan` call that consumes a
// whole group of tokens: leading whitespace, punctuation, a property name and
// a value. A value is a whole scalar, an empty `{}` or `[]`, or the opening
// bracket of a non-empty container. The regular expressions accept exactly the
// valid groups, so the fallback case means the input is malformed somewhere
// in the group. The fallback consumes nothing and hands over to the slow
// scanner (`slow.mbt`), which scans the same group token by token and reports
// the precise error.
//
// The captures cover the whole match, so the parser can keep its position:
// whitespace pieces may contain line breaks, while strings, numbers and
// literals cannot.
//
// The value regex, shared by every group:
//
// \"(?:[^\"\\\u{0}-\u{1f}]|\\[\"\\/bfnrt]|\\u[0-9a-fA-F]{4})*\"
// | -?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+\-]?[0-9]+)?
// | true | false | null
// | \{[ \t\r\n]*\} | \[[ \t\r\n]*\] | \{ | \[
//
// The number regex is the one of core's lexscan JSON parser.
///|
/// State `Value` or `ArrayFirst`: whitespace, then a value.
async fn Parser::scan_value(self : Parser) -> Unit {
let matched = lexscan self.lexbuf with longest {
(re"^[ \t\r\n]*" as w) +
(
re"\"(?:[^\"\\\u{0}-\u{1f}]|\\[\"\\/bfnrt]|\\u[0-9a-fA-F]{4})*\"|-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+\-]?[0-9]+)?|true|false|null|[{][ \t\r\n]*[}]|\[[ \t\r\n]*\]|[{]|\[" as v
) => {
self.advance_text(w)
self.on_value(v, w.length())
true
}
_ => false
}
if !matched {
self.slow_step()
}
}
///|
/// State `ArrayNext`: `]`, or `,` and the next element.
async fn Parser::scan_array_next(self : Parser) -> Unit {
let matched = lexscan self.lexbuf with longest {
re"^[ \t\r\n]*\]" as w => {
self.advance_text(w)
self.close()
true
}
(re"^[ \t\r\n]*,[ \t\r\n]*" as w) +
(
re"\"(?:[^\"\\\u{0}-\u{1f}]|\\[\"\\/bfnrt]|\\u[0-9a-fA-F]{4})*\"|-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+\-]?[0-9]+)?|true|false|null|[{][ \t\r\n]*[}]|\[[ \t\r\n]*\]|[{]|\[" as v
) => {
self.advance_text(w)
self.on_value(v, w.length())
true
}
_ => false
}
if !matched {
self.slow_step()
}
}
///|
/// State `ObjectFirst`: the first member. An empty object never gets here
/// from the fast scanner, since `{}` is scanned as one value.
async fn Parser::scan_member(self : Parser) -> Unit {
let matched = lexscan self.lexbuf with longest {
(re"^[ \t\r\n]*\"" as h1) +
(re"(?:[^\"\\\u{0}-\u{1f}]|\\[\"\\/bfnrt]|\\u[0-9a-fA-F]{4})*" as k) +
(re"\"[ \t\r\n]*:[ \t\r\n]*" as h2) +
(
re"\"(?:[^\"\\\u{0}-\u{1f}]|\\[\"\\/bfnrt]|\\u[0-9a-fA-F]{4})*\"|-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+\-]?[0-9]+)?|true|false|null|[{][ \t\r\n]*[}]|\[[ \t\r\n]*\]|[{]|\[" as v
) => {
self.on_member(h1, k, h2, v)
true
}
_ => false
}
if !matched {
self.slow_step()
}
}
///|
/// State `ObjectNext`: `}`, or `,` and the next member.
async fn Parser::scan_object_next(self : Parser) -> Unit {
let matched = lexscan self.lexbuf with longest {
re"^[ \t\r\n]*[}]" as w => {
self.advance_text(w)
self.close()
true
}
(re"^[ \t\r\n]*,[ \t\r\n]*\"" as h1) +
(re"(?:[^\"\\\u{0}-\u{1f}]|\\[\"\\/bfnrt]|\\u[0-9a-fA-F]{4})*" as k) +
(re"\"[ \t\r\n]*:[ \t\r\n]*" as h2) +
(
re"\"(?:[^\"\\\u{0}-\u{1f}]|\\[\"\\/bfnrt]|\\u[0-9a-fA-F]{4})*\"|-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+\-]?[0-9]+)?|true|false|null|[{][ \t\r\n]*[}]|\[[ \t\r\n]*\]|[{]|\[" as v
) => {
self.on_member(h1, k, h2, v)
true
}
_ => false
}
if !matched {
self.slow_step()
}
}
///|
/// Handles a member scanned as `h1` (up to the opening quote), the raw
/// property name `k`, `h2` (closing quote to the value) and the value `v`.
fn Parser::on_member(
self : Parser,
h1 : StringView,
k : StringView,
h2 : StringView,
v : StringView,
) -> Unit raise ParseError {
self.advance_text(h1)
let key = self.decode_string(k, self.offset)
self.advance(k.length())
self.advance_text(h2)
self.pending.push(Key(key))
self.on_value(v, 1)
}
///|
/// Handles a value `v` matched by the value regex at the current position,
/// after `ws` code units of whitespace.
fn Parser::on_value(
self : Parser,
v : StringView,
ws : Int32,
) -> Unit raise ParseError {
let c = v.unsafe_get(0)
if self.multiple_values {
self.check_separator(ws, c.to_int().unsafe_to_char())
}
match c {
'"' => {
let s = self.decode_string(v[1:v.length() - 1], self.offset + 1)
self.advance(v.length())
self.scalar(Json::string(s), false)
}
't' => {
self.advance(4)
self.scalar(Json::boolean(true), true)
}
'f' => {
self.advance(5)
self.scalar(Json::boolean(false), true)
}
'n' => {
self.advance(4)
self.scalar(Json::null(), true)
}
'{' | '[' => {
self.open(c == '{', self.pos())
if v.length() == 1 {
self.advance(1)
} else {
self.advance_text(v)
self.close()
}
}
_ => {
let value = number_value(v)
self.advance(v.length())
self.scalar(value, true)
}
}
}