RawObject tracebackWrite()

in runtime/traceback-builtins.cpp [211:309]


RawObject tracebackWrite(Thread* thread, const Traceback& traceback,
                         const Object& file) {
  HandleScope scope(thread);
  Runtime* runtime = thread->runtime();
  Object limit_obj(
      &scope, runtime->lookupNameInModule(thread, ID(sys), ID(tracebacklimit)));

  word limit = kTracebackLimit;
  if (!limit_obj.isErrorNotFound() && runtime->isInstanceOfInt(*limit_obj)) {
    limit = intUnderlying(*limit_obj).asWordSaturated();
    if (limit <= 0) {
      return NoneType::object();
    }
  }

  Str line(&scope,
           runtime->newStrFromCStr("Traceback (most recent call last):\n"));
  Object result(&scope, thread->invokeMethod2(file, ID(write), line));
  if (result.isErrorException()) return *result;

  word depth = 0;
  Object tb(&scope, *traceback);
  while (tb.isTraceback()) {
    depth++;
    tb = Traceback::cast(*tb).next();
  }

  Traceback current(&scope, *traceback);
  while (depth > limit) {
    depth--;
    current = current.next();
  }

  MutableBytes buffer(&scope, runtime->emptyMutableBytes());
  Object filename(&scope, NoneType::object());
  Object function_name(&scope, NoneType::object());
  Object lineno(&scope, NoneType::object());
  Object last_filename(&scope, NoneType::object());
  Object last_function_name(&scope, NoneType::object());
  Object last_lineno(&scope, NoneType::object());
  Object next(&scope, NoneType::object());
  for (word count = 0;;) {
    filename = tracebackFilename(thread, current);
    lineno = tracebackLineno(thread, current);
    function_name = tracebackFunctionName(thread, current);
    bool filename_changed =
        last_filename.isNoneType() || filename.isNoneType() ||
        !Str::cast(*last_filename).equals(Str::cast(*filename));
    bool lineno_changed = last_lineno.isNoneType() || lineno != last_lineno;
    bool function_name_changed =
        last_function_name.isNoneType() || function_name.isNoneType() ||
        !Str::cast(*last_function_name).equals(Str::cast(*function_name));
    if (filename_changed || lineno_changed || function_name_changed) {
      if (count > kTracebackRecursiveCutoff) {
        line = lineRepeated(thread, count);
        result = thread->invokeMethod2(file, ID(write), line);
        if (result.isErrorException()) return *result;
      }
      last_filename = *filename;
      last_lineno = *lineno;
      last_function_name = *function_name;
      count = 0;
    }

    count++;
    if (count <= kTracebackRecursiveCutoff) {
      word size =
          tracebackWriteLine(filename, lineno, function_name, buffer, true);
      buffer = runtime->newMutableBytesUninitialized(size);
      tracebackWriteLine(filename, lineno, function_name, buffer, false);
      line = buffer.becomeStr();
      result = thread->invokeMethod2(file, ID(write), line);
      if (result.isErrorException()) return *result;

      result = sourceLine(thread, filename, lineno);
      if (result.isErrorException()) return *result;
      if (result.isStr()) {
        result = thread->invokeMethod2(file, ID(write), result);
        if (result.isErrorException()) return *result;
      }

      result = runtime->handlePendingSignals(thread);
      if (result.isErrorException()) return *result;
    }

    next = current.next();
    if (next.isNoneType()) {
      if (count > kTracebackRecursiveCutoff) {
        line = lineRepeated(thread, count);
        result = thread->invokeMethod2(file, ID(write), line);
        if (result.isErrorException()) return *result;
      }
      return NoneType::object();
    }

    current = *next;
    buffer = runtime->emptyMutableBytes();
  }
}