static RawObject parse()

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