3

沿着 getAnywhere() 行是否有任何相当简单、直接的函数,它返回带有任何注释的函数的源代码,这样如果我没有看到任何注释,我可以确信没有任何注释,无论代码是否在 R 中, c、c++、Fortran 还是其他?例如,stats:::plot.acf 中似乎没有任何注释。我可以由此得出结论,对其文本没有评论吗?

我知道有一个类似流程图的搜索过程,如果你知道源代码是用 R 编写的,那么包括评论的源代码可以通过一些适当的搜索方法从特定的 github 存储库中获得 tp gethub。此外,如果您确定代码是使用某种指定的其他语言,则可以通过更复杂的搜索过程获得该过程,该过程涉及找到正确的文件,然后在其中进行文本搜索,这对于基础包和贡献包是不同的。我的印象是,至少直到最近,如果您想了解是否存在包含注释的代码版本,那么至少直到最近还没有通过隐式流程图搜索方法学习和工作的捷径。此外,我相信那些包含或不包含注释的代码版本在任何地方都没有被识别出来,

然而,R 是一个快速发展的生态系统,我认为希望现在可能存在更简单的工具来确定是否存在包含评论的源版本,并在存在时找到它,这并不是完全不合理的。他们有吗?

4

1 回答 1

6

R 函数的源代码是否在内部保留(通过其srcref属性)取决于keep.source定义函数时 option 的值。源代码是指用户输入的代码,带有注释、可能不一致的缩进、可能不一致的运算符间距等。

options(keep.source = FALSE)
f <- function(x) {
    ## A comment
        x +
  1}

getSrcref(f)
## NULL # (invisibly)

deparse(f, control = "all")
## [1] "function (x) "
## [2] "{"            
## [3] "    x + 1"    
## [4] "}" 
options(keep.source = TRUE)
g <- function(x) {
    ## A comment
        x +
  1}

getSrcref(g)
## function(x) {
##     ## A comment
##         x +
##   1}

deparse(g, control = "all")
## [1] "function(x) {"   
## [2] "    ## A comment"
## [3] "        x +"     
## [4] "  1}"

贡献包中的函数是否保留其源代码取决于R CMD INSTALL从源(由您或由 CRAN)构建包时传递给的选项。--with-keep.source默认是丢弃源代码,但您可以通过从源安装并设置标志来避免这种情况:

install.packages(pkgs, type = "source", INSTALL_opts = "--with-keep.source")

base基本包( ,等)中的函数stats不会有它们的源代码,除非你从源代码构建 R 本身并将环境变量R_KEEP_PKG_SOURCE设置为yes- 至少,这是我从?options. 要了解构建 R,请参阅相应的手册

给定一个带有源引用的函数,您可以以编程方式从源代码中提取注释。一种快速而肮脏的方法是模式匹配:

zzz <- deparse(g, control = "all")
grep("#", zzz, value = TRUE)
## [1] "    ## A comment"

但是,可能存在误报,因为该模式#还匹配包含哈希字符的字符串和非语法名称,它们根本不是注释。

grep("#", "\"## Not a comment\"", value = TRUE)
## [1] "\"## Not a comment\""

提取评论的一种更可靠的方法是检查解析数据中的类型标记COMMENT

getParseData(parse(text = zzz), includeText = NA)
##    line1 col1 line2 col2 id parent          token terminal         text
## 23     1    1     4    4 23      0           expr    FALSE             
## 1      1    1     1    8  1     23       FUNCTION     TRUE     function
## 2      1    9     1    9  2     23            '('     TRUE            (
## 3      1   10     1   10  3     23 SYMBOL_FORMALS     TRUE            x
## 4      1   11     1   11  4     23            ')'     TRUE            )
## 20     1   13     4    4 20     23           expr    FALSE             
## 6      1   13     1   13  6     20            '{'     TRUE            {
## 8      2    5     2   16  8     20        COMMENT     TRUE ## A comment
## 17     3    9     4    3 17     20           expr    FALSE             
## 10     3    9     3    9 10     12         SYMBOL     TRUE            x
## 12     3    9     3    9 12     17           expr    FALSE             
## 11     3   11     3   11 11     17            '+'     TRUE            +
## 14     4    3     4    3 14     15      NUM_CONST     TRUE            1
## 15     4    3     4    3 15     17           expr    FALSE             
## 16     4    4     4    4 16     20            '}'     TRUE            }

显然,getParseData返回的信息比您需要的多得多。这是一个您可以使用的实用程序,它将具有源引用的函数作为参数,并返回列出注释的字符向量(如果有):

getComments <- function(func) {
    func <- match.fun(func)
    if (is.null(getSrcref(func))) {
        stop("'func' has no source references")
    }
    data <- getParseData(func, includeText = NA) 
    if (is.null(data)) {
        op <- options(keep.source = TRUE, keep.parse.data = TRUE)
        on.exit(options(op))
        expr <- parse(text = deparse(func, control = "all"))
        data <- getParseData(expr, includeText = NA)
    }
    data$text[data$token == "COMMENT"]
}
getComments(g)
## [1] "## A comment"

h <- function(x) {
    ## I will comment
            ##     anywhere
    ######## and with as many hashes
    x + 1 # as I want!
}

getComments(h)
## [1] "## I will comment"                
## [2] "##     anywhere"                 
## [3] "######## and with as many hashes"
## [4] "# as I want!"

## You will need Rtools on Windows and Command Line Tools on macOS
## to install from sources packages containing C/C++/Fortran code.
## 'lme4' is one such package ... feel free to choose a different one.
install.packages("lme4", type = "source", INSTALL_opts = "--with-keep.source")
getComments(lme4::lmer)
##  [1] "## , ...)"                                                                              
##  [2] "## see functions in modular.R for the body .."                                          
##  [3] "## back-compatibility kluge"                                                            
##  [4] "## if (!is.null(list(...)[[\"family\"]])) {"                                            
##  [5] "##    warning(\"calling lmer with 'family' is deprecated; please use glmer() instead\")"
##  [6] "##    mc[[1]] <- quote(lme4::glmer)"                                                    
##  [7] "##    if(missCtrl) mc$control <- glmerControl()"                                        
##  [8] "##    return(eval(mc, parent.frame(1L)))"                                               
##  [9] "## }"                                                                                   
## [10] "## update for  back-compatibility kluge"                                                
## [11] "## https://github.com/lme4/lme4/issues/50"                                              
## [12] "## parse data and formula"                                                              
## [13] "## create deviance function for covariance parameters (theta)"                          
## [14] "## optimize deviance function over covariance parameters"                               
## [15] "## prepare output"

AFAIK,没有方便的机制来检查 R 函数调用的 C 代码在编译之前是否包含注释......

与往常一样,相关文档有点分散。我发现这些帮助页面很有用:?parse?deparse?.deparseOpts?srcref(以及其中的链接)?options、 和?getParseData

于 2022-02-12T04:12:53.870 回答