in runtime/under-json-module.cpp [831:944]
RawObject FUNC(_json, loads)(Thread* thread, Arguments args) {
HandleScope scope(thread);
Runtime* runtime = thread->runtime();
DataArray data(&scope, runtime->emptyMutableBytes());
Object s(&scope, args.get(static_cast<word>(LoadsArg::kString)));
word length;
word next = 0;
if (runtime->isInstanceOfStr(*s)) {
s = strUnderlying(*s);
length = Str::cast(*s).length();
} else if (runtime->isInstanceOfBytes(*s)) {
Bytes bytes(&scope, bytesUnderlying(*s));
length = bytes.length();
s = maybeDecode(thread, s, bytes, length, &next);
if (s.isErrorException()) return *s;
if (s == bytes) {
if (bytes.isSmallBytes()) {
MutableBytes copy(&scope,
runtime->newMutableBytesUninitialized(length));
copy.replaceFromWithBytes(0, *bytes, length);
data = *copy;
} else {
data = LargeBytes::cast(*bytes);
}
} else {
CHECK(s.isStr(), "expected str return from decoder");
length = Str::cast(*s).length();
}
} else if (runtime->isInstanceOfBytearray(*s)) {
Bytearray array(&scope, *s);
Bytes items(&scope, array.items());
length = array.numItems();
s = maybeDecode(thread, s, items, length, &next);
if (s.isErrorException()) return *s;
if (s == items) {
data = MutableBytes::cast(*items);
} else {
CHECK(s.isStr(), "expected str return from decoder");
length = Str::cast(*s).length();
}
} else {
return thread->raiseWithFmt(
LayoutId::kTypeError,
"the JSON object must be str, bytes or bytearray, not %T", &s);
}
if (s.isSmallStr()) {
DCHECK(length == SmallStr::cast(*s).length(), "length mismatch");
MutableBytes copy(&scope, runtime->newMutableBytesUninitialized(length));
copy.replaceFromWithStr(0, Str::cast(*s), length);
data = *copy;
} else if (s.isLargeStr()) {
DCHECK(length == LargeStr::cast(*s).length(), "length mismatch");
data = LargeStr::cast(*s);
}
Dict kw(&scope, args.get(static_cast<word>(LoadsArg::kKw)));
Object strict_obj(&scope, dictAtById(thread, kw, ID(strict)));
bool strict;
bool had_strict = false;
if (!strict_obj.isErrorNotFound()) {
if (!runtime->isInstanceOfInt(*strict_obj)) {
return thread->raiseRequiresType(strict_obj, ID(int));
}
had_strict = true;
strict = !intUnderlying(*strict_obj).isZero();
} else {
strict = true;
}
Object cls(&scope, args.get(static_cast<word>(LoadsArg::kCls)));
if (!cls.isNoneType() || kw.numItems() > static_cast<word>(had_strict)) {
Object function(&scope, runtime->lookupNameInModule(thread, ID(_json),
ID(_decode_with_cls)));
CHECK(!function.isErrorNotFound(), "missing function in internal module");
thread->stackPush(*function);
MutableTuple call_args(&scope, runtime->newMutableTuple(7));
call_args.atPut(0, *s);
call_args.atPut(1, *cls);
call_args.atPut(2, args.get(static_cast<word>(LoadsArg::kObjectHook)));
call_args.atPut(3, args.get(static_cast<word>(LoadsArg::kParseFloat)));
call_args.atPut(4, args.get(static_cast<word>(LoadsArg::kParseInt)));
call_args.atPut(5, args.get(static_cast<word>(LoadsArg::kParseConstant)));
call_args.atPut(6, args.get(static_cast<word>(LoadsArg::kObjectPairsHook)));
thread->stackPush(call_args.becomeImmutable());
thread->stackPush(*kw);
return Interpreter::callEx(thread, CallFunctionExFlag::VAR_KEYWORDS);
}
JSONParser env;
memset(&env, 0, sizeof(env));
env.next = next;
env.length = length;
env.args = args;
env.strict = strict;
if (!args.get(static_cast<word>(LoadsArg::kObjectHook)).isNoneType()) {
env.has_object_hook = true;
}
if (!args.get(static_cast<word>(LoadsArg::kParseFloat)).isNoneType()) {
env.has_parse_float = true;
}
if (!args.get(static_cast<word>(LoadsArg::kParseInt)).isNoneType()) {
env.has_parse_int = true;
}
if (!args.get(static_cast<word>(LoadsArg::kParseConstant)).isNoneType()) {
env.has_parse_constant = true;
}
if (!args.get(static_cast<word>(LoadsArg::kObjectPairsHook)).isNoneType()) {
env.has_object_hook = true;
env.has_object_pairs_hook = true;
}
return parse(thread, &env, data);
}