Rev 79585 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
### Checking parse(* deparse()) "inversion property" ----------------------------## EPD := eval-parse-deparse : eval(text = parse(deparse(*)))## Hopefully typically the identity():pd0 <- function(expr, backtick = TRUE, ...)parse(text = deparse(expr, backtick=backtick, ...))id_epd <- function(expr, control = "all", ...)eval(pd0(expr, control=control, ...))## "digits17" ("all") causes different results on x86_64 and## Windows/aarch64dPut <- function(x, control = c("quoteExpression", "showAttributes","niceNames", "keepInteger"))dput(x, control=control)##' Does 'x' contain "real" numbers##' with > 3 digits after "." where deparse may be platform dependent?hasReal <- function(x) {if(is.double(x) || is.complex(x))!all((x == round(x, 3)) | is.na(x))else if(is.logical(x) || is.integer(x) ||is.symbol(x) || is.call(x) || is.environment(x) || is.character(x))FALSEelse if(is.recursive(x)) # recurse :any(vapply(x, hasReal, NA))else if(isS4(x)) {if(length(sn <- slotNames(x)))any(vapply(sn, function(s) hasReal(slot(x, s)), NA))else # no slotsFALSE # ?}else FALSE}isMissObj <- function(obj) identical(obj, alist(a=)[[1]])##' Does 'obj' contain "the missing object" ?##' @note defined recursively!hasMissObj <- function(obj) {if(is.recursive(obj)) {if(is.function(obj) || is.language(obj))FALSEelse # incl pairlist()sany(vapply(obj, hasMissObj, NA))} else isMissObj(obj)}check_EPD <- function(obj, show = !hasReal(obj), oNam = deparse(substitute(obj)),## FIXME: add "niceNames" here: ?!?control = c("keepInteger","showAttributes","keepNA"),not.identical.ldouble = if(!interactive()) c("t1", "t2", "ydata"),eq.tol = if(noLdbl) 2*.Machine$double.eps else 0) {stopifnot(is.character(oNam))if(show) dPut(obj)if(is.environment(obj) || hasMissObj(obj)) {cat("__ not parse()able __:",if(is.environment(obj)) "environment" else "hasMissObj(.) is true", "\n")return(invisible(obj)) # cannot parse it}ob2 <- id_epd(obj)po <- tryCatch(pd0(obj, control=control),# the default deparse() *should* typically parseerror = function(e) {cat("default parse(*, deparse(obj)) failed:\n ",conditionMessage(e),"\n but deparse(*, control='all') should work.\n")pd0(obj, control = "all") })noLdbl <- (.Machine$sizeof.longdouble <= 8) ## TRUE typically from --disable-long-doubleif(!identical(obj, ob2, ignore.environment=TRUE,ignore.bytecode=TRUE, ignore.srcref=TRUE)) {ae <- all.equal(obj, ob2, tolerance = eq.tol, # in case of functions:check.environment=FALSE)if(is.na(match(oNam, not.identical.ldouble))) {ae.txt <- "all.equal(*,*, tol = ..)"## differs for "no-ldouble": sprintf("all.equal(*,*, tol = %.3g)", eq.tol)cat("not identical(*, ignore.env=T),", if(isTRUE(ae)) paste("but", ae.txt), "\n")}if(!isTRUE(ae)) stop("Not equal: ", ae.txt,paste(c(" giving", head(ae, 2),if(length(ae) > 2) "...."), collapse = "\n "))}if(!is.language(obj)) {ob2. <- eval(obj) ## almost always *NOT* identical to obj, but eval()ed}if(show || !is.list(obj)) { ## check it works when wrapped (but do not recurse inf.!)cat(" --> checking list(*): ")check_EPD(list(.chk = obj), show = FALSE, oNam=oNam, eq.tol=eq.tol)cat("Ok\n")}invisible(obj)}##' Check deparse <--> parse consistency for *all* objects:runEPD_checks <- function(env = .GlobalEnv) {stopifnot(is.environment(env))for(nm in ls(envir=env)) {cat(nm,": ", sep="")x <- env[[nm]]## if(!any(nm == "mf")) ## 'mf' [bug in deparse(mf, control="all") now fixed]check_EPD(x, oNam=nm)if(is.function(x) && !inherits(x, "classGeneratorFunction")) {## FIXME? classGeneratorFunction, e.g., mForm don't "work" yetcat("checking body(.):\n")check_EPD(if(is.language(bx <- body(x))) removeSource(bx) else bx)cat("checking formals(.):\n"); check_EPD(formals(x))}cat("--=--=--=--=--\n")}}