void TextBuilder::build()

in src/debugger/TextBuilder.cpp [59:367]


void TextBuilder::build(SEXP expr) {
  SHIELD(expr);
  switch (TYPEOF(expr)) {
    case NILSXP: {
      text << "NULL";
      break;
    }
    case SYMSXP: {
      text << quoteIfNeeded(asStringUTF8(PRINTNAME(expr)));
      break;
    }
    case LISTSXP: {
      text << "pairlist(";
      ShieldSEXP names = Rf_getAttrib(expr, R_NamesSymbol);
      int i = 0;
      while (expr != R_NilValue) {
        if (i > 0) text << ", ";
        const char* name = TYPEOF(names) == STRSXP && Rf_xlength(names) > i ? asStringUTF8(STRING_ELT(names, i)) : "";
        if (strlen(name) != 0) text << quoteIfNeeded(name) << " = ";
        build(CAR(expr));
        expr = CDR(expr);
        ++i;
      }
      text << ")";
      break;
    }
    case CLOSXP:
    case SPECIALSXP:
    case BUILTINSXP: {
      buildFunction(expr);
      break;
    }
    case ENVSXP: {
      text << "`environment`";
      break;
    }
    case PROMSXP: {
      text << "`promise`";
      break;
    }
    case LANGSXP: {
      SEXP function = CAR(expr);
      SEXP args = CDR(expr);
      std::string functionName = TYPEOF(function) == SYMSXP ? asStringUTF8(PRINTNAME(function)) : "";
      if (functionName == "{") {
        std::vector<Srcref> srcrefs;
        srcrefs.push_back({currentLine, currentPosition(), currentLine, currentPosition() + 1});
        text << "{";
        ++indent;
        while (args != R_NilValue) {
          newline();
          srcrefs.push_back({currentLine, currentPosition(), -1, -1});
          build(CAR(args));
          srcrefs.back().endLine = currentLine;
          srcrefs.back().endPosition = currentPosition();
          args = CDR(args);
        }
        --indent;
        newline();
        text << "}";
        newSrcrefs.emplace_back(expr, std::move(srcrefs));
      } else if (functionName == "if" && Rf_xlength(args) >= 2 && Rf_xlength(args) <= 3) {
        text << "if (";
        build(CAR(args));
        args = CDR(args);
        text << ") ";
        build(CAR(args));
        args = CDR(args);
        if (args != R_NilValue) {
          text << " else ";
          build(CAR(args));
        }
      } else if (functionName == "(" && Rf_xlength(args) == 1) {
        text << "(";
        build(CAR(args));
        text << ")";
      } else if (functionName == "function" && Rf_xlength(args) >= 2) {
        buildFunctionHeader(CAR(args));
        text << " ";
        build(CADR(args));
      } else if (isUnaryOperator(functionName) && Rf_xlength(args) == 1) {
        text << functionName;
        build(CAR(args));
      } else if (isBinaryOperator(functionName) && Rf_xlength(args) == 2) {
        build(CAR(args));
        if (functionName == "::" || functionName == ":::" || functionName == "$") {
          text << functionName;
        } else {
          text << " " << functionName << " ";
        }
        build(CADR(args));
      } else if ((functionName == "[" || functionName == "[[") && Rf_xlength(args) >= 1) {
        build(CAR(args));
        text << functionName;
        args = CDR(args);
        ShieldSEXP names = Rf_getAttrib(expr, R_NamesSymbol);
        int i = 1;
        while (args != R_NilValue) {
          if (i > 1) text << ", ";
          ++i;
          const char* name = TYPEOF(names) == STRSXP && Rf_xlength(names) > i ? asStringUTF8(STRING_ELT(names, i)) : "";
          if (strlen(name) != 0) text << quoteIfNeeded(name) << " = ";
          build(CAR(args));
          args = CDR(args);
        }
        text << (functionName == "[" ? "]" : "]]");
      } else if ((functionName == "break" || functionName == "next") && args == R_NilValue) {
        text << functionName;
      } else if (functionName == "for" && Rf_xlength(args) == 3) {
        text << "for (";
        build(CAR(args));
        text << " in ";
        build(CADR(args));
        text << ") ";
        build(CADDR(args));
      } else if (functionName == "while" && Rf_xlength(args) == 2) {
        text << "while (";
        build(CAR(args));
        text << ") ";
        build(CADR(args));
      } else if (functionName == "repeat" && Rf_xlength(args) == 1) {
        text << "repeat ";
        build(CAR(args));
      } else {
        ShieldSEXP names = Rf_getAttrib(expr, R_NamesSymbol);
        build(function);
        text << "(";
        int i = 0;
        while (args != R_NilValue) {
          if (i > 0) text << ", ";
          ++i;
          const char* name = TYPEOF(names) == STRSXP && Rf_xlength(names) > i ? asStringUTF8(STRING_ELT(names, i)) : "";
          if (strlen(name) != 0) text << quoteIfNeeded(name) << " = ";
          build(CAR(args));
          args = CDR(args);
        }
        text << ")";
      }
      break;
    }
    case CHARSXP: {
      if (expr == R_NaString) {
        text << "NA_character_";
      } else {
        text << '"' << escapeStringCharacters(asStringUTF8(expr)) << '"';
      }
      break;
    }
    case LGLSXP: {
      int length = Rf_xlength(expr);
      if (length == 0) {
        text << "integer(0)";
      } else {
        if (length > 1) text << "c(";
        for (int i = 0; i < length; ++i) {
          if (i > 0) text << ", ";
          int value = LOGICAL(expr)[i];
          if (value == NA_LOGICAL) {
            text << "NA";
          } else if (value) {
            text << "TRUE";
          } else {
            text << "FALSE";
          }
        }
        if (length > 1) text << ")";
      }
      break;
    }
    case INTSXP: {
      int length = Rf_xlength(expr);
      if (length == 0) {
        text << "integer(0)";
      } else {
        if (length > 1) text << "c(";
        for (int i = 0; i < length; ++i) {
          if (i > 0) text << ", ";
          int value = INTEGER(expr)[i];
          if (value == R_NaInt) {
            text << "NA_integer_";
          } else {
            text << value;
          }
        }
        if (length > 1) text << ")";
      }
      break;
    }
    case REALSXP: {
      int length = Rf_xlength(expr);
      if (length == 0) {
        text << "numeric(0)";
      } else {
        if (length > 1) text << "c(";
        for (int i = 0; i < length; ++i) {
          if (i > 0) text << ", ";
          double value = REAL(expr)[i];
          if (R_IsNA(value)) {
            text << "NA_real_";
          } else {
            text << value;
          }
        }
        if (length > 1) text << ")";
      }
      break;
    }
    case CPLXSXP: {
      int length = Rf_xlength(expr);
      if (length == 0) {
        text << "complex(0)";
      } else {
        if (length > 1) text << "c(";
        for (int i = 0; i < length; ++i) {
          if (i > 0) text << ", ";
          Rcomplex value = COMPLEX(expr)[i];
          if (R_IsNA(value.r)) {
            text << "NA_complex_";
          } else {
            if (value.r == 0) {
              text << value.i << 'i';
            } else {
              text << value.r;
              if (value.i >= 0) {
                text << '+' << value.i << 'i';
              } else {
                text << '-' << -value.i << 'i';
              }
            }
          }
        }
        if (length > 1) text << ")";
      }
      break;
    }
    case STRSXP: {
      int length = Rf_xlength(expr);
      if (length == 0) {
        text << "character(0)";
      } else {
        if (length > 1) text << "c(";
        for (int i = 0; i < length; ++i) {
          if (i > 0) text << ", ";
          build(STRING_ELT(expr, i));
        }
        if (length > 1) text << ")";
      }
      break;
    }
    case DOTSXP: {
      text << "...";
      break;
    }
    case ANYSXP: {
      text << "`any`";
      break;
    }
    case VECSXP:
    case EXPRSXP: {
      if (TYPEOF(expr) == VECSXP) {
        text << "list(";
      } else {
        text << "expression(";
      }
      ShieldSEXP names = Rf_getAttrib(expr, R_NamesSymbol);
      int length = Rf_xlength(expr);
      for (int i = 0; i < length; ++i) {
        if (i > 0) text << ", ";
        const char* name = TYPEOF(names) == STRSXP && Rf_xlength(names) > i ? asStringUTF8(STRING_ELT(names, i)) : "";
        if (strlen(name) != 0) text << quoteIfNeeded(name) << " = ";
        build(VECTOR_ELT(expr, i));
      }
      text << ")";
      break;
    }
    case BCODESXP: {
      text << "`bytecode`";
      break;
    }
    case EXTPTRSXP: {
      text << "`extptr`";
      break;
    }
    case WEAKREFSXP: {
      text << "`weakref`";
      break;
    }
    case RAWSXP: {
      int length = Rf_xlength(expr);
      if (length == 0) {
        text << "raw(0)";
      } else {
        text << "as.raw(";
        if (length > 1) text << "c(";
        for (int i = 0; i < length; ++i) {
          if (i > 0) text << ", ";
          text << (unsigned)RAW(expr)[i];
        }
        if (length > 1) text << ")";
        text << ")";
      }
      break;
    }
    case S4SXP: {
      text << "`s4_object`";
      break;
    }
  }
}