Skip to content

Instantly share code, notes, and snippets.

@zbjornson
Last active May 28, 2017 06:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zbjornson/c4b622e97e3d922292a482632909a50e to your computer and use it in GitHub Desktop.
Save zbjornson/c4b622e97e3d922292a482632909a50e to your computer and use it in GitHub Desktop.
hoistDotArgs = function(fn) {
dotCalls = list()
findDotArgs = function(exp) {
if (typeof(exp) == "closure") { # entry point
expL = as.list(exp)
args = names(expL)
if (!("..." %in% args)) return(invisible()) # no dots to hoist
body = expL[[length(expL)]]
findDotArgs(body)
} else if (typeof(exp) == "language") {
langL = as.list(exp)
if ("..." %in% langL) {
# print(exp)
fnameSym = langL[[1]]
fnameChar = as.character(fnameSym)
callee = get(fnameChar) # closure
args = names(as.list(callee))
thisCall = list()
thisCall[[fnameChar]] = args
dotCalls <<- c(dotCalls, thisCall)
} else {
lapply(langL, function (x) {
findDotArgs(x)
})
}
}
invisible()
}
findDotArgs(fn)
if (length(unique(names(dotCalls))) > 1) {
print("... passed to more than one different functions; could hoist common args")
} else {
dc = dotCalls[[1]]
fname = names(dotCalls)[[1]]
args = paste(head(dc, n = length(dc) - 1), collapse = ", ")
print(sprintf("... passed to %s. Hoist its arguments (%s)", fname, args))
}
}
@zbjornson
Copy link
Author

zbjornson commented May 28, 2017

given:

priv = function(a2, a3) {
  print(c(a2, a3))
}

priv2 = function(a2, a4) {
  print(c(a2, a4))
}

myfn = function(a1, ...) {
  print(a1)
  priv(...)
}

myfn2 = function(a1, ...) {
  if (a1) {
    priv(...)
  } else {
    priv2(...)
  }
}

then:

> hoistDotArgs(myfn2)
[1] "... passed to more than one different functions; could hoist common args"
> hoistDotArgs(myfn)
[1] "... passed to priv. Hoist its arguments (a2, a3)"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment