void getValueInfo()

in src/RLoader.cpp [35:176]


void getValueInfo(SEXP _var, ValueInfo* result) {
  ShieldSEXP var = _var;
  try {
    auto type = var.type();
    if (type == PROMSXP) {
      if (PRVALUE(var) == R_UnboundValue) {
        TextBuilder builder;
        builder.build(PRCODE(var));
        std::string code = builder.getText();
        trim(code);
        result->mutable_unevaluated()->set_code(code);
        return;
      }
      getValueInfo(PRVALUE(var), result);
      return;
    }
    ShieldSEXP classes = RI->classes(Rf_lang2(RI->quote, var));
    if (classes.type() == STRSXP) {
      int length = 0;
      for (int i = 0; i < classes.length(); ++i) {
        std::string s = stringEltUTF8(classes, i);
        if (s.empty()) continue;
        length += s.size();
        if (s.size() > MAX_PREVIEW_CLS_LENGTH) break;
        result->add_cls(s);
      }
    }
    if (type == LANGSXP || type == SYMSXP) {
      result->mutable_value()->set_isvector(false);
      TextBuilder builder;
      builder.build(var);
      std::string s = builder.getText();
      result->mutable_value()->set_iscomplete(trim(s));
      result->mutable_value()->set_textvalue(s);
    } else if (type == DOTSXP) {
      result->mutable_list()->set_length(var.length());
    } else if (type == CLOSXP || type == SPECIALSXP || type == BUILTINSXP) {
      std::string header = getFunctionHeader(var);
      if (header.size() <= MAX_PREVIEW_STRING_LENGTH) {
        result->mutable_function()->set_header(header);
      } else {
        header = getFunctionHeaderShort(var);
        if (header.size() <= MAX_PREVIEW_STRING_LENGTH) {
          result->mutable_function()->set_header(header);
        } else {
          result->mutable_function()->set_header("function(...)");
        }
      }
    } else if (type == ENVSXP) {
      std::string name = asStringUTF8(RI->environmentName(var));
      trim(name);
      result->mutable_environment()->set_name(name);
    } else if (type == BCODESXP || type == WEAKREFSXP || type == EXTPTRSXP) {
      result->mutable_value()->set_isvector(false);
      bool trimmed;
      std::string value = getPrintedValueWithLimit(RI->unclass(Rf_lang2(RI->quote, var)), MAX_PREVIEW_STRING_LENGTH, trimmed);
      result->mutable_value()->set_textvalue(value);
      result->mutable_value()->set_iscomplete(!trimmed);
    } else if (type == CHARSXP) {
      getValueInfo(Rf_ScalarString(var), result);
    } else if (Rf_inherits(var, "ggplot")) {
      result->mutable_graph();
    } else if (Rf_inherits(var, "data.frame")) {
      ValueInfo::DataFrame* dataFrame = result->mutable_dataframe();
      dataFrame->set_rows(asInt(RI->nrow(var)));
      dataFrame->set_cols(asInt(RI->ncol(var)));
    } else if (type == S4SXP) {
      result->mutable_value()->set_iss4(true);
    } else {
      if (Rf_isVector(var)) {
        ShieldSEXP dim = Rf_getAttrib(var, R_DimSymbol);
        if (dim.type() == INTSXP && dim.length() >= 2) {
          int length = std::min<int>(dim.length(), MAX_PREVIEW_PRINTED_COUNT);
          for (int i = 0; i < length; ++i) {
            result->mutable_matrix()->add_dim(asInt(dim[i]));
          }
          return;
        }
      }
      if (type == VECSXP || type == LISTSXP || type == EXPRSXP) {
        result->mutable_list()->set_length(var.length());
      } else {
        ValueInfo::Value *value = result->mutable_value();
        if (type == LGLSXP || type == INTSXP || type == REALSXP ||
            type == CPLXSXP || type == NILSXP) {
          R_xlen_t length = var.length();
          value->set_isvector(length > 1);
          PrSEXP x = Rf_inherits(var, "factor") ? (SEXP)var : RI->unclass(var);
          bool isComplete = true;
          if (length > MAX_PREVIEW_PRINTED_COUNT) {
            isComplete = false;
            x = RI->subscript(x, RI->colon(1, MAX_PREVIEW_PRINTED_COUNT));
          }
          bool trimmed;
          std::string s;
          if (Rf_inherits(x, "factor")) {
            s = evalAndGetPrintedValueWithLimit(
                RI->printFactorSimple.lang(x),
                MAX_PREVIEW_STRING_LENGTH, trimmed);
          } else {
            s = getPrintedValueWithLimit(x, MAX_PREVIEW_STRING_LENGTH, trimmed);
          }
          value->set_textvalue(s);
          value->set_iscomplete(isComplete && !trimmed);
        } else if (type == STRSXP) {
          int length = var.length();
          value->set_isvector(length > 1);
          bool isComplete = length <= MAX_PREVIEW_PRINTED_COUNT;
          ShieldSEXP unclassed = RI->unclass(var);
          ShieldSEXP vector =
              isComplete
                  ? (SEXP)unclassed
                  : RI->subscript(unclassed, RI->colon(1, MAX_PREVIEW_PRINTED_COUNT));
          ShieldSEXP vectorPrefix =
              RI->substring(vector, 1, MAX_PREVIEW_STRING_LENGTH);
          ShieldSEXP nchar = RI->nchar(vectorPrefix);
          for (int i = 0; isComplete && i < vectorPrefix.length(); ++i) {
            if (!vectorPrefix.isNA(i) &&
                asInt(nchar[i]) == MAX_PREVIEW_STRING_LENGTH) {
              isComplete = false;
            }
          }
          bool trimmed;
          value->set_textvalue(getPrintedValueWithLimit(vectorPrefix, MAX_PREVIEW_STRING_LENGTH, trimmed));
          value->set_iscomplete(isComplete && !trimmed);
        } else {
          value->set_isvector(false);
          value->set_textvalue("");
          value->set_iscomplete(true);
        }
      }
    }
  } catch (RInterruptedException const& e) {
    result->mutable_error()->set_text(e.what());
    throw;
  } catch (RExceptionBase const& e) {
    result->mutable_error()->set_text(e.what());
  } catch (...) {
    result->mutable_error()->set_text("Error");
    throw;
  }
}