Rev 86207 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
## File src/library/utils/R/debugcall.R## Part of the R package, https://www.R-project.org#### Copyright (C) 1995-2024 The R Core Team#### This program is free software; you can redistribute it and/or modify## it under the terms of the GNU General Public License as published by## the Free Software Foundation; either version 2 of the License, or## (at your option) any later version.#### This program is distributed in the hope that it will be useful,## but WITHOUT ANY WARRANTY; without even the implied warranty of## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the## GNU General Public License for more details.#### A copy of the GNU General Public License is available at## https://www.R-project.org/Licenses/.debugcall <- function(call, op) {funsym <- deparse(call[[1L]])func <- get(funsym, parent.frame(2L), mode="function")have.methods <- isNamespaceLoaded("methods")func <- if(is.primitive(func)) {if (have.methods) methods::getGeneric(func)} else funcif(is.null(func)) {stop("Cannot debug primitive functions unless they are implicit generics (requires loading the methods package)")}mcall <- match.call(func, call)env <- parent.frame(2L)isS4Generic <- have.methods && methods::isGeneric(funsym, env)if(!isS4Generic) {s3ret <- isS3stdGeneric(func)if(s3ret) {genname <- names(s3ret)arg <- eval(mcall[[2L]], envir=env)func <- getS3method(genname, class(arg))}sig <- NULL} else {sig <- .signatureFromCall(func, mcall, env)}op(func, signature = sig)}.signatureFromCall <- function(fdef, expr, envir, doEval = TRUE) {args <- formals(fdef)call <- match.call(fdef, expr, expand.dots = FALSE)args[names(call[-1L])] <- call[-1L]if ("..." %in% names(call))args$... <- args$...[[1L]]sigNames <- fdef@signaturesigClasses <- rep.int("missing", length(sigNames))names(sigClasses) <- sigNamesfor (arg in sigNames) {argExpr <- methods::elNamed(args, arg)if (!missing(argExpr) && !is.null(argExpr)) {simple <- (is.character(argExpr) || is.name(argExpr))## TODO: ideally, if doEval is TRUE, we would like to## create the same context used by applyClosure in## eval.c, but then skip the actual evaluation of the## body. If we could create this environment then## passing it to selectMethod is closer to the semantics## of the "real" function call than the code below.## But, seems to need a change to eval.c and a flag to## the evaluator.if (doEval || !simple) {argVal <- try(eval(argExpr, envir))if (methods::is(argVal, "try-error"))stop(gettextf("error in trying to evaluate the expression for argument %s (%s)",sQuote(arg), deparse(argExpr)), domain = NA)sigClasses[[arg]] <- class(argVal)[1L]}else sigClasses[[arg]] <- as.character(argExpr)}}sigClasses}debugcall <- function(call, once = FALSE) {stopifnot(length(once) == 1L, is.logical(once), !is.na(once))call <- substitute(call).debugcall(call, if (once) debugonce else debug)invisible(call)}undebugcall <- function(call) {call <- substitute(call).debugcall(call, undebug)invisible(NULL)}