Last active
February 24, 2022 16:00
-
-
Save lionel-/1142569ba7844ac2f24cf0fa27cdabf9 to your computer and use it in GitHub Desktop.
Unwinding scope in `source()`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Prototype of `source()` as currently implemented | |
source2 <- function(file, env = parent.frame()) { | |
exprs <- parse(file) | |
for (expr in exprs) { | |
eval(expr, env) | |
} | |
} | |
# Prototype of `source()` using an evaluation strategy where the | |
# unwinding scope is the whole file rather than each line | |
source3 <- function(file, env = parent.frame()) { | |
exprs <- parse(file) | |
cb <- function() { | |
for (expr in exprs) { | |
# Using `delayedAssign()` as an interface to the C-level function | |
# `Rf_eval()`. Unlike the R-level `eval()`, this doesn't create | |
# an unwinding scope. | |
eval(bquote(delayedAssign("do", .(expr), eval.env = env))) | |
do | |
} | |
} | |
# Here we use `eval()` to create an unwinding scope for `env`. | |
# We call ourselves back immediately once the scope is created. | |
eval(as.call(list(cb)), env) | |
invisible() | |
} | |
# Let's try these functions on the following script | |
file <- tempfile() | |
cat(file = file, " | |
on.exit(cat('on exit!\\n')) | |
cat('now!\\n') | |
return() | |
cat('never run!\\n') | |
") | |
# Whereas `source()` and `source2()` have linewise unwinding scope, | |
# `source3()` has filewise unwinding scope | |
source(file) | |
#> on exit! | |
#> now! | |
#> never run! | |
source2(file) | |
#> on exit! | |
#> now! | |
#> never run! | |
source3(file) | |
#> now! | |
#> on exit! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment