RawObject FUNC()

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);
}