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