Skip to content

Commit

Permalink
simplify recurse as well
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinushey committed Sep 30, 2024
1 parent 112a03b commit a37b891
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 55 deletions.
41 changes: 11 additions & 30 deletions R/dependencies.R
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ renv_dependencies_discover_rmd_yaml_header <- function(path, mode) {
pattern <- renv_regexps_package_name()

# check recursively for package usages of the form 'package::method'
recurse(yaml, function(node, stack) {
recurse(yaml, function(node) {
# look for keys of the form 'package::method'
values <- c(names(node), if (pstring(node)) node)
for (value in values) {
Expand Down Expand Up @@ -1118,7 +1118,7 @@ renv_dependencies_discover_r_xfun <- function(node, envir) {

# extract character vectors from `...`
strings <- stack()
recurse(matched[["..."]], function(node, stack) {
recurse(matched[["..."]], function(node) {
if (is.character(node))
strings$push(node)
})
Expand Down Expand Up @@ -1887,43 +1887,24 @@ renv_dependencies_eval <- function(expr) {

}

# like 'recurse', but only recurses into calls
renv_dependencies_recurse <- function(object, callback, ...) {
renv_dependencies_recurse_impl(object, callback, ...)
}


renv_dependencies_recurse_impl <- function(object, callback, ...) {

# initialize work queue

queue <- vector("list", 8192L)
queue[[1L]] <- object
index <- 0L
slot <- 1L

# index of current work item in queue
index <- 1L

# index of next slot in queue
slot <- 2L

# start working
while (index < slot) {

# retrieve next work item
object <- queue[[index]]

# invoke callback
result <- callback(object, ...)
if (is.call(result))
object <- result
while (index != slot) {

# update the index
index <- index + 1L
result <- callback(queue[[index]], ...)

# push children of object onto queue
if (is.recursive(object)) {
if (is.recursive(object <- if (is.call(result)) result else queue[[index]])) {
for (i in seq_along(object)) {
if (is.call(object[[i]])) {
queue[[slot]] <- object[[i]]
if (is.call(oi <- object[[i]])) {
slot <- slot + 1L
queue[[slot]] <- oi
}
}
}
Expand Down
43 changes: 20 additions & 23 deletions R/recurse.R
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@

recurse <- function(object, callback, ...) {
renv_recurse_impl(list(), object, callback, ...)

queue <- vector("list", 8192L)
queue[[1L]] <- object
index <- 0L
slot <- 1L

while (index != slot) {

index <- index + 1L
result <- callback(queue[[index]], ...)

if (is.recursive(object <- if (is.call(result)) result else queue[[index]])) {
for (i in seq_along(object)) {
slot <- slot + 1L
queue[[slot]] <- object[[i]]
}
}

}

}

renv_recurse_impl <- function(stack, object, callback, ...) {

# ignore missing values
if (missing(object) || identical(object, quote(expr = )))
return(FALSE)

# push node on to stack
stack[[length(stack) + 1]] <- object

# invoke callback
result <- callback(object, stack, ...)
if (is.call(result))
object <- result
else if (identical(result, FALSE))
return(FALSE)

# recurse
if (is.recursive(object))
for (i in seq_along(object))
renv_recurse_impl(stack, object[[i]], callback, ...)

}
2 changes: 1 addition & 1 deletion tests/testthat/test-bootstrap.R
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ test_that("bootstrap functions don't depend on non-bootstrap APIs", {

# iterate over those functions and look for the called functions
calls <- stack(mode = "character")
recurse(bodies, function(node, stack) {
recurse(bodies, function(node) {
if (is.call(node) && is.symbol(node[[1L]]))
calls$push(as.character(node[[1L]]))
})
Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/test-json.R
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ test_that("json-read.R can function standalone", {
# for each function, check that it only uses functions from base
ok <- list()
for (val in vals) {
recurse(body(val), function(node, stack) {
recurse(body(val), function(node) {
if (is.call(node) && is.symbol(node[[1L]])) {
lhs <- as.character(node[[1L]])
ok[[lhs]] <<- exists(lhs, envir = envir)
Expand Down
5 changes: 5 additions & 0 deletions tests/testthat/test-recurse.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

test_that("recurse() can handle missing objects", {
data <- substitute(list(a = A), list(A = quote(expr = )))
expect_no_error(recurse(data, function(node) print(node)))
})

0 comments on commit a37b891

Please sign in to comment.