blob: d1cbb685d86880b1d906e1007548fa572b677671 [file] [log] [blame]
# File src/library/utils/R/sourceutils.R
# Part of the R package, https://www.R-project.org
#
# Copyright (C) 1995-2018 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/
removeSource <- function(fn) {
recurse <- function(part) {
if (is.name(part)) return(part) # handles missing arg, PR#15957
attr(part, "srcref") <- NULL
attr(part, "wholeSrcref") <- NULL
attr(part, "srcfile") <- NULL
if (is.language(part) && is.recursive(part)) {
for (i in seq_along(part))
part[i] <- list(recurse(part[[i]])) # recurse(*) may be NULL
}
part
}
if(is.function(fn)) {
if(!is.primitive(fn)) {
attr(fn, "srcref") <- NULL
attr(body(fn), "wholeSrcref") <- NULL
attr(body(fn), "srcfile") <- NULL
body(fn) <- recurse(body(fn))
}
fn
}
else if(is.language(fn)) { # expression, call, or symbol=name
recurse(fn)
}
else
stop("argument is not a function or language object:", typeof(fn))
}
getSrcFilename <- function(x, full.names=FALSE, unique=TRUE) {
srcref <- getSrcref(x)
if (is.list(srcref))
result <- sapply(srcref, getSrcFilename, full.names, unique)
else {
srcfile <- attr(srcref, "srcfile")
if (is.null(srcfile)) result <- character()
else result <- srcfile$filename
}
result <- if (full.names) result
else basename(result)
if (unique) unique(result)
else result
}
getSrcDirectory <- function(x, unique=TRUE) {
result <- dirname(getSrcFilename(x, full.names=TRUE, unique=unique))
if (unique) unique(result)
else result
}
getSrcref <- function(x) {
if (inherits(x, "srcref"))
x
else if (!is.null(srcref <- attr(x, "srcref")) ||
is.function(x) && !is.null(srcref <- getSrcref(body(x))))
srcref
else if (methods::is(x, "MethodDefinition"))
getSrcref(unclass(methods::unRematchDefinition(x)))
## else NULL
}
getSrcLocation <- function(x, which=c("line", "column", "byte", "parse"), first=TRUE) {
srcref <- getSrcref(x)
if (is.null(srcref)) return(NULL)
if (is.list(srcref)) sapply(srcref, getSrcLocation, which, first)
else {
if (length(srcref) == 6L) srcref <- c(srcref, srcref[c(1L,3L)])
which <- match.arg(which)
if (first) index <- c(line=1L, column=5L, byte=2L, parse=7L)[which]
else index <- c(line=3L, column=6L, byte=4L, parse=8L)[which]
srcref[index]
}
}
##' Simplified version of getSrcLocation(x, "byte", first=TRUE),
##' always returning integer(1)
getSrcByte <- function(x) {
srcref <- attr(x, "srcref")
if(is.null(srcref)) -1L else srcref[2L]
}
getSrcfile <- function(x) {
if (!is.null(r <- attr(x, "srcfile"))) return(r)
srcref <- attr(x, "wholeSrcref")
if (is.null(srcref)) {
srcref <- getSrcref(x)
if (is.list(srcref) && length(srcref))
srcref <- srcref[[length(srcref)]]
}
attr(srcref, "srcfile")
}
substr_with_tabs <- function(x, start, stop, tabsize = 8) {
widths <- rep_len(1, nchar(x))
tabs <- which(strsplit(x,"")[[1]] == "\t")
for (i in tabs) {
cols <- cumsum(widths)
widths[i] <- tabsize - (cols[i] - 1) %% tabsize
}
cols <- cumsum(widths)
start <- which(cols >= start)
if (!length(start))
return("")
start <- start[1]
stop <- which(cols <= stop)
if (length(stop)) {
stop <- stop[length(stop)]
substr(x, start, stop)
} else
""
}
getParseData <- function(x, includeText = NA) {
if (inherits(x, "srcfile"))
srcfile <- x
else
srcfile <- getSrcfile(x)
if (is.null(srcfile))
return(NULL)
else
data <- srcfile$parseData
if (!is.null(data)) {
tokens <- attr(data, "tokens")
data <- t(unclass(data))
colnames(data) <- c( "line1", "col1",
"line2", "col2",
"terminal", "token.num", "id", "parent" )
data <- data.frame(data[, -c(5,6), drop = FALSE], token = tokens,
terminal = as.logical(data[,"terminal"]),
text = attr(data, "text"),
stringsAsFactors = FALSE)
o <- order(data[,1], data[,2], -data[,3], -data[,4])
data <- data[o,]
rownames(data) <- data$id
attr(data, "srcfile") <- srcfile
if (isTRUE(includeText)) gettext <- which(!nzchar(data$text))
else if (is.na(includeText)) gettext <- which(!nzchar(data$text) & data$terminal)
else {
gettext <- integer(0)
data$text <- NULL
}
if (length(gettext))
data$text[gettext] <- getParseText(data, data$id[gettext])
}
data
}
getParseText <- function(parseData, id) {
srcfile <- attr(parseData, "srcfile")
d <- parseData[as.character(id),]
text <- d$text
if (is.null(text)) {
text <- character(nrow(d))
blank <- seq_along(text)
} else
blank <- which(!nzchar(text) | (d$token == "STR_CONST" & startsWith(text, "[")))
for (i in blank) {
lines <- getSrcLines(srcfile, d$line1[i], d$line2[i])
n <- length(lines)
lines[n] <- substr_with_tabs(lines[n], 1, d$col2[i])
lines[1] <- substr_with_tabs(lines[1], d$col1[i], Inf)
text[i] <- paste(lines, collapse="\n")
}
text
}