in runtime/under-json-module.cpp [711:829]
static RawObject parse(Thread* thread, JSONParser* env, const DataArray& data) {
HandleScope scope(thread);
Runtime* runtime = thread->runtime();
Object container(&scope, NoneType::object());
Object dict_key(&scope, NoneType::object());
Object value(&scope, NoneType::object());
MutableTuple dict_key_set(&scope,
runtime->newMutableTuple(kDictKeySetInitLength));
word dict_key_set_remaining =
internSetComputeRemaining(kDictKeySetInitLength);
byte b = nextNonWhitespace(thread, env, data);
for (;;) {
int scan_result = scan(thread, env, data, b, &value);
switch (scan_result) {
case 0:
// Already have a finished object.
b = nextNonWhitespace(thread, env, data);
break;
case '[':
value = runtime->newList();
b = nextNonWhitespace(thread, env, data);
if (b != ']') {
if (thread->wouldStackOverflow(kPointerSize) &&
thread->handleInterrupt(kPointerSize)) {
return Error::exception();
}
thread->stackPush(*container);
container = *value;
continue;
}
b = nextNonWhitespace(thread, env, data);
break;
case '{':
value = runtime->newDict();
b = nextNonWhitespace(thread, env, data);
if (b != '}') {
if (thread->wouldStackOverflow(2 * kPointerSize) &&
thread->handleInterrupt(2 * kPointerSize)) {
return Error::exception();
}
thread->stackPush(*container);
container = *value;
dict_key = scanDictKey(thread, env, data, b, &dict_key_set,
&dict_key_set_remaining);
if (dict_key.isErrorException()) return *dict_key;
b = nextNonWhitespace(thread, env, data);
thread->stackPush(*dict_key);
continue;
}
if (env->has_object_hook) {
value = callObjectHook(thread, env, value);
if (value.isErrorException()) return *value;
}
b = nextNonWhitespace(thread, env, data);
break;
default:
DCHECK(value.isErrorException(), "expected error raised");
return *value;
}
for (;;) {
// We finished reading the object `value`. Add it to the outer container
// or return if there is no container left.
if (container.isList()) {
List list(&scope, *container);
runtime->listAdd(thread, list, value);
if (b == ',') {
b = nextNonWhitespace(thread, env, data);
break;
}
if (b == ']') {
value = *container;
container = thread->stackPop();
b = nextNonWhitespace(thread, env, data);
continue;
}
return raiseJSONDecodeError(thread, env, data, env->next - 1,
"Expecting ',' delimiter");
}
if (container.isDict()) {
Dict dict(&scope, *container);
dict_key = thread->stackPop();
dictAtPutByStr(thread, dict, dict_key, value);
if (b == ',') {
b = nextNonWhitespace(thread, env, data);
dict_key = scanDictKey(thread, env, data, b, &dict_key_set,
&dict_key_set_remaining);
if (dict_key.isErrorException()) return *dict_key;
b = nextNonWhitespace(thread, env, data);
thread->stackPush(*dict_key);
break;
}
if (b == '}') {
value = *container;
container = thread->stackPop();
b = nextNonWhitespace(thread, env, data);
if (env->has_object_hook) {
value = callObjectHook(thread, env, value);
if (value.isErrorException()) return *value;
}
continue;
}
return raiseJSONDecodeError(thread, env, data, env->next - 1,
"Expecting ',' delimiter");
}
DCHECK(container.isNoneType(), "expected no container");
if (env->next <= env->length) {
return raiseJSONDecodeError(thread, env, data, env->next - 1,
"Extra data");
}
return *value;
}
}
}