ctxt_stack() can be tricky to use in real code because all intervening frames are returned with the stack, including those at ctxt_stack() own call site. stack_trim() makes it easy to remove layers of intervening calls.

stack_trim(stack, n = 1)

Arguments

stack

An evaluation stack.

n

The number of call frames (not eval frames) to trim off the top of the stack. In other words, the number of layers of intervening frames to trim.

Life cycle

These functions are in the questioning stage. We are no longer convinced they belong in rlang as they are mostly for REPL interaction and runtime inspection rather than function development.

Examples

# Intervening frames appear on the evaluation stack: identity(identity(ctxt_stack()))
#> [[1]] #> <frame 24> (22) #> expr: identity(ctxt_stack()) #> env: [local 0x7f82920f67f8] #> #> [[2]] #> <frame 23> (22) #> expr: identity(identity(ctxt_stack())) #> env: [local 0x7f82920f66e0] #> #> [[3]] #> <frame 22> (21) #> expr: eval(expr, envir, enclos) #> env: [local 0x7f82923a6b48] #> #> [[4]] #> <frame 21> (11) #> expr: eval(expr, envir, enclos) #> env: [local 0x7f82920f64e8] #> #> [[5]] #> <frame 20> (11) #> expr: withVisible(eval(expr, envir, enclos)) #> env: [local 0x7f82920f71b8] #> #> [[6]] #> <frame 19> (11) #> expr: withCallingHandlers(withVisible(eval(expr, envir, enclos)), warning = wHandler, <...> #> env: [local 0x7f82920f7b08] #> #> [[7]] #> <frame 18> (17) #> expr: doTryCatch(return(expr), name, parentenv, handler) #> env: [local 0x7f82920f74e8] #> #> [[8]] #> <frame 17> (16) #> expr: tryCatchOne(expr, names, parentenv, handlers[[1L]]) #> env: [local 0x7f82920f8148] #> #> [[9]] #> <frame 16> (15) #> expr: tryCatchList(expr, classes, parentenv, handlers) #> env: [local 0x7f82920f7d90] #> #> [[10]] #> <frame 15> (14) #> expr: tryCatch(expr, error = function(e) { <...> #> env: [local 0x7f82920f8670] #> #> [[11]] #> <frame 14> (13) #> expr: try(f, silent = TRUE) #> env: [local 0x7f82920fa378] #> #> [[12]] #> <frame 13> (11) #> expr: handle(ev <- withCallingHandlers(withVisible(eval(expr, envir, <...> #> env: [local 0x7f82920fa1f0] #> #> [[13]] #> <frame 12> (11) #> expr: timing_fn(handle(ev <- withCallingHandlers(withVisible(eval(expr, <...> #> env: [local 0x7f82920fa110] #> #> [[14]] #> <frame 11> (10) #> expr: evaluate_call(expr, parsed$src[[i]], envir = envir, enclos = enclos, <...> #> env: [frame 0x7f82923d4588] #> #> [[15]] #> <frame 10> (9) #> expr: evaluate::evaluate(code, env, new_device = TRUE) #> env: [frame 0x7f8295c5cd90] #> #> [[16]] #> <frame 9> (8) #> expr: .f(code = .l[[c(1L, 1L)]], run = .l[[c(2L, 1L)]], show = .l[[c(3L, <...> #> env: [frame 0x7f8295c66ce8] #> #> [[17]] #> <frame 8> (7) #> expr: purrr::pmap_chr(list(code = code, run = run, show = show), format_example_chunk, <...> #> env: [frame 0x7f8295c7a470] #> #> [[18]] #> <frame 7> (5) #> expr: as_data.tag_examples(tags$tag_examples[[1]], env = new.env(parent = globalenv()), <...> #> env: [frame 0x7f8292a5c7b8] #> #> [[19]] #> <frame 6> (5) #> expr: as_data(tags$tag_examples[[1]], env = new.env(parent = globalenv()), <...> #> env: [frame 0x7f8292a5ca78] #> #> [[20]] #> <frame 5> (4) #> expr: data_reference_topic(topic, pkg, path = path, examples = examples, <...> #> env: [frame 0x7f8293acbc08] #> #> [[21]] #> <frame 4> (3) #> expr: .f(.x[[i]], ...) #> env: [frame 0x7f8293b3cf50] #> #> [[22]] #> <frame 3> (2) #> expr: purrr::map(topics, build_reference_topic, path, pkg = pkg, lazy = lazy, <...> #> env: [frame 0x7f829512a5c0] #> #> [[23]] #> <frame 2> (1) #> expr: build_reference(pkg, lazy = FALSE, examples = examples, run_dont_run = run_dont_run, <...> #> env: [frame 0x7f8293d05f50] #> #> [[24]] #> <frame 1> (0) #> expr: pkgdown::build_site() #> env: [frame 0x7f8293da3268] #> #> [[25]] #> <frame 0> [global] #> expr: NULL #> env: [global] #> #> attr(,"class") #> [1] "ctxt_stack" "stack"
# stack_trim() will trim the first n layers of calls: stack_trim(identity(identity(ctxt_stack())))
#> [[1]] #> <frame 22> (21) #> expr: eval(expr, envir, enclos) #> env: [local 0x7f82923a6b48] #> #> [[2]] #> <frame 21> (11) #> expr: eval(expr, envir, enclos) #> env: [local 0x7f82948053c0] #> #> [[3]] #> <frame 20> (11) #> expr: withVisible(eval(expr, envir, enclos)) #> env: [local 0x7f8294805158] #> #> [[4]] #> <frame 19> (11) #> expr: withCallingHandlers(withVisible(eval(expr, envir, enclos)), warning = wHandler, <...> #> env: [local 0x7f829488d270] #> #> [[5]] #> <frame 18> (17) #> expr: doTryCatch(return(expr), name, parentenv, handler) #> env: [local 0x7f829488da38] #> #> [[6]] #> <frame 17> (16) #> expr: tryCatchOne(expr, names, parentenv, handlers[[1L]]) #> env: [local 0x7f829488f580] #> #> [[7]] #> <frame 16> (15) #> expr: tryCatchList(expr, classes, parentenv, handlers) #> env: [local 0x7f829488f238] #> #> [[8]] #> <frame 15> (14) #> expr: tryCatch(expr, error = function(e) { <...> #> env: [local 0x7f82948902e0] #> #> [[9]] #> <frame 14> (13) #> expr: try(f, silent = TRUE) #> env: [local 0x7f82948900b0] #> #> [[10]] #> <frame 13> (11) #> expr: handle(ev <- withCallingHandlers(withVisible(eval(expr, envir, <...> #> env: [local 0x7f8294890d80] #> #> [[11]] #> <frame 12> (11) #> expr: timing_fn(handle(ev <- withCallingHandlers(withVisible(eval(expr, <...> #> env: [local 0x7f8294890c68] #> #> [[12]] #> <frame 11> (10) #> expr: evaluate_call(expr, parsed$src[[i]], envir = envir, enclos = enclos, <...> #> env: [frame 0x7f8290cca390] #> #> [[13]] #> <frame 10> (9) #> expr: evaluate::evaluate(code, env, new_device = TRUE) #> env: [frame 0x7f8295c5cd90] #> #> [[14]] #> <frame 9> (8) #> expr: .f(code = .l[[c(1L, 1L)]], run = .l[[c(2L, 1L)]], show = .l[[c(3L, <...> #> env: [frame 0x7f8295c66ce8] #> #> [[15]] #> <frame 8> (7) #> expr: purrr::pmap_chr(list(code = code, run = run, show = show), format_example_chunk, <...> #> env: [frame 0x7f8295c7a470] #> #> [[16]] #> <frame 7> (5) #> expr: as_data.tag_examples(tags$tag_examples[[1]], env = new.env(parent = globalenv()), <...> #> env: [frame 0x7f8292a5c7b8] #> #> [[17]] #> <frame 6> (5) #> expr: as_data(tags$tag_examples[[1]], env = new.env(parent = globalenv()), <...> #> env: [frame 0x7f8292a5ca78] #> #> [[18]] #> <frame 5> (4) #> expr: data_reference_topic(topic, pkg, path = path, examples = examples, <...> #> env: [frame 0x7f8293acbc08] #> #> [[19]] #> <frame 4> (3) #> expr: .f(.x[[i]], ...) #> env: [frame 0x7f8293b3cf50] #> #> [[20]] #> <frame 3> (2) #> expr: purrr::map(topics, build_reference_topic, path, pkg = pkg, lazy = lazy, <...> #> env: [frame 0x7f829512a5c0] #> #> [[21]] #> <frame 2> (1) #> expr: build_reference(pkg, lazy = FALSE, examples = examples, run_dont_run = run_dont_run, <...> #> env: [frame 0x7f8293d05f50] #> #> [[22]] #> <frame 1> (0) #> expr: pkgdown::build_site() #> env: [frame 0x7f8293da3268] #> #> [[23]] #> <frame 0> [global] #> expr: NULL #> env: [global] #> #> attr(,"class") #> [1] "ctxt_stack" "stack"
# Note that it also takes care of calls intervening at its own call # site: identity(identity( stack_trim(identity(identity(ctxt_stack()))) ))
#> [[1]] #> <frame 22> (21) #> expr: eval(expr, envir, enclos) #> env: [local 0x7f82923a6b48] #> #> [[2]] #> <frame 21> (11) #> expr: eval(expr, envir, enclos) #> env: [local 0x7f829332b200] #> #> [[3]] #> <frame 20> (11) #> expr: withVisible(eval(expr, envir, enclos)) #> env: [local 0x7f829332be28] #> #> [[4]] #> <frame 19> (11) #> expr: withCallingHandlers(withVisible(eval(expr, envir, enclos)), warning = wHandler, <...> #> env: [local 0x7f829332c660] #> #> [[5]] #> <frame 18> (17) #> expr: doTryCatch(return(expr), name, parentenv, handler) #> env: [local 0x7f829332cd48] #> #> [[6]] #> <frame 17> (16) #> expr: tryCatchOne(expr, names, parentenv, handlers[[1L]]) #> env: [local 0x7f829332ca00] #> #> [[7]] #> <frame 16> (15) #> expr: tryCatchList(expr, classes, parentenv, handlers) #> env: [local 0x7f829332d3f8] #> #> [[8]] #> <frame 15> (14) #> expr: tryCatch(expr, error = function(e) { <...> #> env: [local 0x7f829332da38] #> #> [[9]] #> <frame 14> (13) #> expr: try(f, silent = TRUE) #> env: [local 0x7f829332e778] #> #> [[10]] #> <frame 13> (11) #> expr: handle(ev <- withCallingHandlers(withVisible(eval(expr, envir, <...> #> env: [local 0x7f829332e468] #> #> [[11]] #> <frame 12> (11) #> expr: timing_fn(handle(ev <- withCallingHandlers(withVisible(eval(expr, <...> #> env: [local 0x7f829332e388] #> #> [[12]] #> <frame 11> (10) #> expr: evaluate_call(expr, parsed$src[[i]], envir = envir, enclos = enclos, <...> #> env: [frame 0x7f829335adf0] #> #> [[13]] #> <frame 10> (9) #> expr: evaluate::evaluate(code, env, new_device = TRUE) #> env: [frame 0x7f8295c5cd90] #> #> [[14]] #> <frame 9> (8) #> expr: .f(code = .l[[c(1L, 1L)]], run = .l[[c(2L, 1L)]], show = .l[[c(3L, <...> #> env: [frame 0x7f8295c66ce8] #> #> [[15]] #> <frame 8> (7) #> expr: purrr::pmap_chr(list(code = code, run = run, show = show), format_example_chunk, <...> #> env: [frame 0x7f8295c7a470] #> #> [[16]] #> <frame 7> (5) #> expr: as_data.tag_examples(tags$tag_examples[[1]], env = new.env(parent = globalenv()), <...> #> env: [frame 0x7f8292a5c7b8] #> #> [[17]] #> <frame 6> (5) #> expr: as_data(tags$tag_examples[[1]], env = new.env(parent = globalenv()), <...> #> env: [frame 0x7f8292a5ca78] #> #> [[18]] #> <frame 5> (4) #> expr: data_reference_topic(topic, pkg, path = path, examples = examples, <...> #> env: [frame 0x7f8293acbc08] #> #> [[19]] #> <frame 4> (3) #> expr: .f(.x[[i]], ...) #> env: [frame 0x7f8293b3cf50] #> #> [[20]] #> <frame 3> (2) #> expr: purrr::map(topics, build_reference_topic, path, pkg = pkg, lazy = lazy, <...> #> env: [frame 0x7f829512a5c0] #> #> [[21]] #> <frame 2> (1) #> expr: build_reference(pkg, lazy = FALSE, examples = examples, run_dont_run = run_dont_run, <...> #> env: [frame 0x7f8293d05f50] #> #> [[22]] #> <frame 1> (0) #> expr: pkgdown::build_site() #> env: [frame 0x7f8293da3268] #> #> [[23]] #> <frame 0> [global] #> expr: NULL #> env: [global] #> #> attr(,"class") #> [1] "ctxt_stack" "stack"
# It is especially useful when used within a function that needs to # inspect the evaluation stack but should nonetheless be callable # within nested calls without side effects: stack_util <- function() { # n = 2 means that two layers of intervening calls should be # removed: The layer at ctxt_stack()'s call site (including the # stack_trim() call), and the layer at stack_util()'s call. stack <- stack_trim(ctxt_stack(), n = 2) stack } user_fn <- function() { # A user calls your stack utility with intervening frames: identity(identity(stack_util())) } # These intervening frames won't appear in the evaluation stack identity(user_fn())
#> [[1]] #> <frame 24> (22) #> expr: user_fn() #> env: [local 0x7f829138a108] #> #> [[2]] #> <frame 23> (22) #> expr: identity(user_fn()) #> env: [local 0x7f8291389ff0] #> #> [[3]] #> <frame 22> (21) #> expr: eval(expr, envir, enclos) #> env: [local 0x7f82923a6b48] #> #> [[4]] #> <frame 21> (11) #> expr: eval(expr, envir, enclos) #> env: [local 0x7f8291389df8] #> #> [[5]] #> <frame 20> (11) #> expr: withVisible(eval(expr, envir, enclos)) #> env: [local 0x7f8291389a78] #> #> [[6]] #> <frame 19> (11) #> expr: withCallingHandlers(withVisible(eval(expr, envir, enclos)), warning = wHandler, <...> #> env: [local 0x7f829138a358] #> #> [[7]] #> <frame 18> (17) #> expr: doTryCatch(return(expr), name, parentenv, handler) #> env: [local 0x7f829138ac70] #> #> [[8]] #> <frame 17> (16) #> expr: tryCatchOne(expr, names, parentenv, handlers[[1L]]) #> env: [local 0x7f829138b828] #> #> [[9]] #> <frame 16> (15) #> expr: tryCatchList(expr, classes, parentenv, handlers) #> env: [local 0x7f829138b438] #> #> [[10]] #> <frame 15> (14) #> expr: tryCatch(expr, error = function(e) { <...> #> env: [local 0x7f829138c978] #> #> [[11]] #> <frame 14> (13) #> expr: try(f, silent = TRUE) #> env: [local 0x7f829138c748] #> #> [[12]] #> <frame 13> (11) #> expr: handle(ev <- withCallingHandlers(withVisible(eval(expr, envir, <...> #> env: [local 0x7f829138c4e0] #> #> [[13]] #> <frame 12> (11) #> expr: timing_fn(handle(ev <- withCallingHandlers(withVisible(eval(expr, <...> #> env: [local 0x7f829138c400] #> #> [[14]] #> <frame 11> (10) #> expr: evaluate_call(expr, parsed$src[[i]], envir = envir, enclos = enclos, <...> #> env: [frame 0x7f82913bd6d8] #> #> [[15]] #> <frame 10> (9) #> expr: evaluate::evaluate(code, env, new_device = TRUE) #> env: [frame 0x7f8295c5cd90] #> #> [[16]] #> <frame 9> (8) #> expr: .f(code = .l[[c(1L, 1L)]], run = .l[[c(2L, 1L)]], show = .l[[c(3L, <...> #> env: [frame 0x7f8295c66ce8] #> #> [[17]] #> <frame 8> (7) #> expr: purrr::pmap_chr(list(code = code, run = run, show = show), format_example_chunk, <...> #> env: [frame 0x7f8295c7a470] #> #> [[18]] #> <frame 7> (5) #> expr: as_data.tag_examples(tags$tag_examples[[1]], env = new.env(parent = globalenv()), <...> #> env: [frame 0x7f8292a5c7b8] #> #> [[19]] #> <frame 6> (5) #> expr: as_data(tags$tag_examples[[1]], env = new.env(parent = globalenv()), <...> #> env: [frame 0x7f8292a5ca78] #> #> [[20]] #> <frame 5> (4) #> expr: data_reference_topic(topic, pkg, path = path, examples = examples, <...> #> env: [frame 0x7f8293acbc08] #> #> [[21]] #> <frame 4> (3) #> expr: .f(.x[[i]], ...) #> env: [frame 0x7f8293b3cf50] #> #> [[22]] #> <frame 3> (2) #> expr: purrr::map(topics, build_reference_topic, path, pkg = pkg, lazy = lazy, <...> #> env: [frame 0x7f829512a5c0] #> #> [[23]] #> <frame 2> (1) #> expr: build_reference(pkg, lazy = FALSE, examples = examples, run_dont_run = run_dont_run, <...> #> env: [frame 0x7f8293d05f50] #> #> [[24]] #> <frame 1> (0) #> expr: pkgdown::build_site() #> env: [frame 0x7f8293da3268] #> #> [[25]] #> <frame 0> [global] #> expr: NULL #> env: [global] #> #> attr(,"class") #> [1] "ctxt_stack" "stack"