1 2# Soft-deprecated in rlang 0.4.0 3 4## Types 5 6#' Base type of an object 7#' 8#' @description 9#' 10#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("soft-deprecated")} 11#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("experimental")} 12#' 13#' This is equivalent to [base::typeof()] with a few differences that 14#' make dispatching easier: 15#' * The type of one-sided formulas is "quote". 16#' * The type of character vectors of length 1 is "string". 17#' * The type of special and builtin functions is "primitive". 18#' 19#' 20#' @section Life cycle: 21#' 22#' `type_of()` is an experimental function. Expect API changes. 23#' 24#' @param x An R object. 25#' @export 26#' @keywords internal 27#' @examples 28#' type_of(10L) 29#' 30#' # Quosures are treated as a new base type but not formulas: 31#' type_of(quo(10L)) 32#' type_of(~10L) 33#' 34#' # Compare to base::typeof(): 35#' typeof(quo(10L)) 36#' 37#' # Strings are treated as a new base type: 38#' type_of(letters) 39#' type_of(letters[[1]]) 40#' 41#' # This is a bit inconsistent with the core language tenet that data 42#' # types are vectors. However, treating strings as a different 43#' # scalar type is quite helpful for switching on function inputs 44#' # since so many arguments expect strings: 45#' switch_type("foo", character = abort("vector!"), string = "result") 46#' 47#' # Special and builtin primitives are both treated as primitives. 48#' # That's because it is often irrelevant which type of primitive an 49#' # input is: 50#' typeof(list) 51#' typeof(`$`) 52#' type_of(list) 53#' type_of(`$`) 54type_of <- function(x) { 55 signal_soft_deprecated(c( 56 "`type_of()` is deprecated as of rlang 0.4.0.", 57 "Please use `typeof()` or your own version instead." 58 )) 59 type_of_(x) 60} 61 62#' Dispatch on base types 63#' 64#' @description 65#' 66#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("soft-deprecated")} 67#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("experimental")} 68#' 69#' `switch_type()` is equivalent to 70#' \code{\link[base]{switch}(\link{type_of}(x, ...))}, while 71#' `switch_class()` switchpatches based on `class(x)`. The `coerce_` 72#' versions are intended for type conversion and provide a standard 73#' error message when conversion fails. 74#' 75#' 76#' @param .x An object from which to dispatch. 77#' @param ... Named clauses. The names should be types as returned by 78#' [type_of()]. 79#' @param .to This is useful when you switchpatch within a coercing 80#' function. If supplied, this should be a string indicating the 81#' target type. A catch-all clause is then added to signal an error 82#' stating the conversion failure. This type is prettified unless 83#' `.to` inherits from the S3 class `"AsIs"` (see [base::I()]). 84#' @export 85#' @keywords internal 86#' @examples 87#' switch_type(3L, 88#' double = "foo", 89#' integer = "bar", 90#' "default" 91#' ) 92#' 93#' # Use the coerce_ version to get standardised error handling when no 94#' # type matches: 95#' to_chr <- function(x) { 96#' coerce_type(x, "a chr", 97#' integer = as.character(x), 98#' double = as.character(x) 99#' ) 100#' } 101#' to_chr(3L) 102#' 103#' # Strings have their own type: 104#' switch_type("str", 105#' character = "foo", 106#' string = "bar", 107#' "default" 108#' ) 109#' 110#' # Use a fallthrough clause if you need to dispatch on all character 111#' # vectors, including strings: 112#' switch_type("str", 113#' string = , 114#' character = "foo", 115#' "default" 116#' ) 117#' 118#' # special and builtin functions are treated as primitive, since 119#' # there is usually no reason to treat them differently: 120#' switch_type(base::list, 121#' primitive = "foo", 122#' "default" 123#' ) 124#' switch_type(base::`$`, 125#' primitive = "foo", 126#' "default" 127#' ) 128#' 129#' # closures are not primitives: 130#' switch_type(rlang::switch_type, 131#' primitive = "foo", 132#' "default" 133#' ) 134switch_type <- function(.x, ...) { 135 signal_soft_deprecated(c( 136 "`switch_type()` is soft-deprecated as of rlang 0.4.0.", 137 "Please use `switch(typeof())` or `switch(my_typeof())` instead." 138 )) 139 switch(type_of_(.x), ...) 140} 141#' @rdname switch_type 142#' @export 143coerce_type <- function(.x, .to, ...) { 144 signal_soft_deprecated("`coerce_type()` is soft-deprecated as of rlang 0.4.0.") 145 switch(type_of_(.x), ..., abort_coercion(.x, .to)) 146} 147#' @rdname switch_type 148#' @export 149switch_class <- function(.x, ...) { 150 signal_soft_deprecated("`switch_class()` is soft-deprecated as of rlang 0.4.0.") 151 switch(class(.x), ...) 152} 153#' @rdname switch_type 154#' @export 155coerce_class <- function(.x, .to, ...) { 156 signal_soft_deprecated("`coerce_class()` is soft-deprecated as of rlang 0.4.0.") 157 switch(class(.x), ..., abort_coercion(.x, .to)) 158} 159 160 161## Casting 162 163#' Coerce an object to a base type 164#' 165#' @description 166#' 167#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("soft-deprecated")} 168#' 169#' These are equivalent to the base functions (e.g. [as.logical()], 170#' [as.list()], etc), but perform coercion rather than conversion. 171#' This means they are not generic and will not call S3 conversion 172#' methods. They only attempt to coerce the base type of their 173#' input. In addition, they have stricter implicit coercion rules and 174#' will never attempt any kind of parsing. E.g. they will not try to 175#' figure out if a character vector represents integers or booleans. 176#' Finally, they treat attributes consistently, unlike the base R 177#' functions: all attributes except names are removed. 178#' 179#' 180#' @section Lifecycle: 181#' 182#' These functions are deprecated in favour of `vctrs::vec_cast()`. 183#' 184#' 185#' @section Coercion to logical and numeric atomic vectors: 186#' 187#' * To logical vectors: Integer and integerish double vectors. See 188#' [is_integerish()]. 189#' * To integer vectors: Logical and integerish double vectors. 190#' * To double vectors: Logical and integer vectors. 191#' * To complex vectors: Logical, integer and double vectors. 192#' 193#' 194#' @section Coercion to character vectors: 195#' 196#' `as_character()` and `as_string()` have an optional `encoding` 197#' argument to specify the encoding. R uses this information for 198#' internal handling of strings and character vectors. Note that this 199#' is only declarative, no encoding conversion is attempted. 200#' 201#' Note that only `as_string()` can coerce symbols to a scalar 202#' character vector. This makes the code more explicit and adds an 203#' extra type check. 204#' 205#' 206#' @section Coercion to lists: 207#' 208#' `as_list()` only coerces vector and dictionary types (environments 209#' are an example of dictionary type). Unlike [base::as.list()], 210#' `as_list()` removes all attributes except names. 211#' 212#' 213#' @section Effects of removing attributes: 214#' 215#' A technical side-effect of removing the attributes of the input is 216#' that the underlying objects has to be copied. This has no 217#' performance implications in the case of lists because this is a 218#' shallow copy: only the list structure is copied, not the contents 219#' (see [duplicate()]). However, be aware that atomic vectors 220#' containing large amounts of data will have to be copied. 221#' 222#' In general, any attribute modification creates a copy, which is why 223#' it is better to avoid using attributes with heavy atomic vectors. 224#' Uncopyable objects like environments and symbols are an exception 225#' to this rule: in this case, attributes modification happens in 226#' place and has side-effects. 227#' 228#' @inheritParams string 229#' @param x An object to coerce to a base type. 230#' 231#' @keywords internal 232#' @examples 233#' # Coercing atomic vectors removes attributes with both base R and rlang: 234#' x <- structure(TRUE, class = "foo", bar = "baz") 235#' as.logical(x) 236#' 237#' # But coercing lists preserves attributes in base R but not rlang: 238#' l <- structure(list(TRUE), class = "foo", bar = "baz") 239#' as.list(l) 240#' as_list(l) 241#' 242#' # Implicit conversions are performed in base R but not rlang: 243#' as.logical(l) 244#' \dontrun{ 245#' as_logical(l) 246#' } 247#' 248#' # Conversion methods are bypassed, making the result of the 249#' # coercion more predictable: 250#' as.list.foo <- function(x) "wrong" 251#' as.list(l) 252#' as_list(l) 253#' 254#' # The input is never parsed. E.g. character vectors of numbers are 255#' # not converted to numeric types: 256#' as.integer("33") 257#' \dontrun{ 258#' as_integer("33") 259#' } 260#' 261#' 262#' # With base R tools there is no way to convert an environment to a 263#' # list without either triggering method dispatch, or changing the 264#' # original environment. as_list() makes it easy: 265#' x <- structure(as_environment(mtcars[1:2]), class = "foobar") 266#' as.list.foobar <- function(x) abort("dont call me") 267#' as_list(x) 268#' @name vector-coercion 269NULL 270 271signal_deprecated_cast <- function(fn, env = caller_env(2)) { 272 signal_soft_deprecated(env = env, c( 273 sprintf("`%s()` is deprecated as of rlang 0.4.0", fn), 274 "Please use `vctrs::vec_cast()` instead." 275 )) 276} 277 278#' @rdname vector-coercion 279#' @export 280as_logical <- function(x) { 281 signal_deprecated_cast("as_logical") 282 coerce_type_vec(x, friendly_type("logical"), 283 logical = { attributes(x) <- NULL; x }, 284 integer = as_base_type(x, as.logical), 285 double = as_integerish_type(x, as.logical, "logical") 286 ) 287} 288#' @rdname vector-coercion 289#' @export 290as_integer <- function(x) { 291 signal_deprecated_cast("as_integer") 292 coerce_type_vec(x, friendly_type("integer"), 293 logical = as_base_type(x, as.integer), 294 integer = { attributes(x) <- NULL; x }, 295 double = as_integerish_type(x, as.integer, "integer") 296 ) 297} 298#' @rdname vector-coercion 299#' @export 300as_double <- function(x) { 301 signal_deprecated_cast("as_double") 302 coerce_type_vec(x, friendly_type("double"), 303 logical = , 304 integer = as_base_type(x, as.double), 305 double = { attributes(x) <- NULL; x } 306 ) 307} 308#' @rdname vector-coercion 309#' @export 310as_complex <- function(x) { 311 signal_deprecated_cast("as_complex") 312 coerce_type_vec(x, friendly_type("complex"), 313 logical = , 314 integer = , 315 double = as_base_type(x, as.complex), 316 complex = { attributes(x) <- NULL; x } 317 ) 318} 319#' @rdname vector-coercion 320#' @export 321as_character <- function(x, encoding = NULL) { 322 signal_deprecated_cast("as_character") 323 if (is_unspecified(x)) { 324 return(rep_along(x, na_chr)) 325 } 326 coerce_type_vec(x, friendly_type("character"), 327 string = , 328 character = { 329 attributes(x) <- NULL 330 if (!is_null(encoding)) { 331 Encoding(x) <- encoding 332 } 333 x 334 } 335 ) 336} 337#' @rdname vector-coercion 338#' @export 339as_list <- function(x) { 340 signal_deprecated_cast("as_list") 341 switch_type(x, 342 environment = env_as_list(x), 343 vec_as_list(x) 344 ) 345} 346env_as_list <- function(x) { 347 names_x <- names(x) 348 x <- as_base_type(x, as.list) 349 set_names(x, .Call(rlang_unescape_character, names_x)) 350} 351vec_as_list <- function(x) { 352 coerce_type_vec(x, friendly_type("list"), 353 logical = , 354 integer = , 355 double = , 356 string = , 357 character = , 358 complex = , 359 raw = as_base_type(x, as.list), 360 list = { attributes(x) <- NULL; x } 361 ) 362} 363 364is_unspecified <- function(x) { 365 is_logical(x) && all(map_lgl(x, identical, NA)) 366} 367 368as_base_type <- function(x, as_type) { 369 # Zap attributes temporarily instead of unclassing. We want to avoid 370 # method dispatch, but we also want to avoid an extra copy of atomic 371 # vectors: the first when unclassing, the second when coercing. This 372 # is also useful for uncopyable types like environments. 373 attrs <- .Call(rlang_attrib, x) 374 .Call(rlang_poke_attrib, x, NULL) 375 376 # This function assumes that the target type is different than the 377 # input type, otherwise no duplication is done and the output will 378 # be modified by side effect when we restore the input attributes. 379 on.exit(.Call(rlang_poke_attrib, x, attrs)) 380 381 as_type(x) 382} 383as_integerish_type <- function(x, as_type, to) { 384 if (is_integerish(x)) { 385 as_base_type(x, as_type) 386 } else { 387 abort(paste0( 388 "Can't convert a fractional double vector to ", friendly_type(to), "" 389 )) 390 } 391} 392 393coerce_type_vec <- function(.x, .to, ...) { 394 # Cannot reuse coerce_type() because switch() has a bug with 395 # fallthrough and multiple levels of dots forwarding. 396 out <- switch(type_of_(.x), ..., abort_coercion(.x, .to)) 397 398 if (!is_null(names(.x))) { 399 # Avoid a copy of `out` when we restore the names, since it could be 400 # a heavy atomic vector. We own `out`, so it is ok to change its 401 # attributes inplace. 402 .Call(rlang_poke_attrib, out, pairlist(names = names(.x))) 403 } 404 405 out 406} 407vec_coerce <- function(x, type) { 408 .Call(rlang_vec_coerce, x, type) 409} 410 411 412# Stack and frames ------------------------------------------------- 413 414#' Get caller frame 415#' 416#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 417#' 418#' @param n Number of frames to go back. 419#' @keywords internal 420#' @export 421caller_frame <- function(n = 1) { 422 warn_deprecated("`caller_frame()` is deprecated as of rlang 0.3.0.") 423 call_frame(n + 2) 424} 425 426#' Call stack information 427#' 428#' @description 429#' 430#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 431#' 432#' The `eval_` and `call_` families of functions provide a replacement 433#' for the base R functions prefixed with `sys.` (which are all about 434#' the context stack), as well as for [parent.frame()] (which is the 435#' only base R function for querying the call stack). The context 436#' stack includes all R-level evaluation contexts. It is linear in 437#' terms of execution history but due to lazy evaluation it is 438#' potentially nonlinear in terms of call history. The call stack 439#' history, on the other hand, is homogenous. 440#' 441#' @details 442#' 443#' `ctxt_frame()` and `call_frame()` return a `frame` object 444#' containing the following fields: `expr` and `env` (call expression 445#' and evaluation environment), `pos` and `caller_pos` (position of 446#' current frame in the context stack and position of the caller), and 447#' `fun` (function of the current frame). `ctxt_stack()` and 448#' `call_stack()` return a list of all context or call frames on the 449#' stack. Finally, `ctxt_depth()` and `call_depth()` report the 450#' current context position or the number of calling frames on the 451#' stack. 452#' 453#' The base R functions take two sorts of arguments to indicate which 454#' frame to query: `which` and `n`. The `n` argument is 455#' straightforward: it's the number of frames to go down the stack, 456#' with `n = 1` referring to the current context. The `which` argument 457#' is more complicated and changes meaning for values lower than 1. 458#' For the sake of consistency, the rlang functions all take the 459#' same kind of argument `n`. This argument has a single meaning (the 460#' number of frames to go down the stack) and cannot be lower than 1. 461#' 462#' Note finally that `parent.frame(1)` corresponds to 463#' `call_frame(2)$env`, as `n = 1` always refers to the current 464#' frame. This makes the `_frame()` and `_stack()` functions 465#' consistent: `ctxt_frame(2)` is the same as `ctxt_stack()[[2]]`. 466#' Also, `ctxt_depth()` returns one more frame than 467#' [base::sys.nframe()] because it counts the global frame. That is 468#' consistent with the `_stack()` functions which return the global 469#' frame as well. This way, `call_stack(call_depth())` is the same as 470#' `global_frame()`. 471#' 472#' 473#' @section Life cycle: 474#' 475#' These functions are soft-deprecated and replaced by [trace_back()]. 476#' 477#' @param n The number of frames to go back in the stack. 478#' @param clean Whether to post-process the call stack to clean 479#' non-standard frames. If `TRUE`, suboptimal call-stack entries by 480#' [base::eval()] will be cleaned up: the duplicate frame created by 481#' `eval()` is eliminated. 482#' @param trim The number of layers of intervening frames to trim off 483#' the stack. See [stack_trim()] and examples. 484#' @name stack 485#' @keywords internal 486#' @examples 487#' # Expressions within arguments count as contexts 488#' identity(identity(ctxt_depth())) # returns 2 489#' 490#' # But they are not part of the call stack because arguments are 491#' # evaluated within the calling function (or the global environment 492#' # if called at top level) 493#' identity(identity(call_depth())) # returns 0 494#' 495#' # The context stacks includes all intervening execution frames. The 496#' # call stack doesn't: 497#' f <- function(x) identity(x) 498#' f(f(ctxt_stack())) 499#' f(f(call_stack())) 500#' 501#' g <- function(cmd) cmd() 502#' f(g(ctxt_stack)) 503#' f(g(call_stack)) 504#' 505#' # The rlang _stack() functions return a list of frame 506#' # objects. Use purrr::transpose() or index a field with 507#' # purrr::map()'s to extract a particular field from a stack: 508#' 509#' # stack <- f(f(call_stack())) 510#' # purrr::map(stack, "env") 511#' # purrr::transpose(stack)$expr 512#' 513#' # current_frame() is an alias for ctxt_frame(1) 514#' fn <- function() list(current = current_frame(), first = ctxt_frame(1)) 515#' fn() 516#' 517#' # While current_frame() is the top of the stack, global_frame() is 518#' # the bottom: 519#' fn <- function() { 520#' n <- ctxt_depth() 521#' ctxt_frame(n) 522#' } 523#' identical(fn(), global_frame()) 524#' 525#' 526#' # ctxt_stack() returns a stack with all intervening frames. You can 527#' # trim layers of intervening frames with the trim argument: 528#' identity(identity(ctxt_stack())) 529#' identity(identity(ctxt_stack(trim = 1))) 530#' 531#' # ctxt_stack() is called within fn() with intervening frames: 532#' fn <- function(trim) identity(identity(ctxt_stack(trim = trim))) 533#' fn(0) 534#' 535#' # We can trim the first layer of those: 536#' fn(1) 537#' 538#' # The outside intervening frames (at the fn() call site) are still 539#' # returned, but can be trimmed as well: 540#' identity(identity(fn(1))) 541#' identity(identity(fn(2))) 542#' 543#' g <- function(trim) identity(identity(fn(trim))) 544#' g(2) 545#' g(3) 546NULL 547 548new_frame <- function(x) { 549 structure(x, class = "frame") 550} 551#' @export 552print.frame <- function(x, ...) { 553 cat("<frame ", x$pos, ">", sep = "") 554 if (!x$pos) { 555 cat(" [global]\n") 556 } else { 557 cat(" (", x$caller_pos, ")\n", sep = "") 558 } 559 560 expr <- deparse(x$expr) 561 if (length(expr) > 1) { 562 expr <- paste(expr[[1]], "<...>") 563 } 564 cat("expr: ", expr, "\n", sep = "") 565 cat("env: [", env_format(x$env), "]\n", sep = "") 566} 567#' Is object a frame? 568#' 569#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 570#' 571#' @param x Object to test 572#' @keywords internal 573#' @export 574is_frame <- function(x) { 575 inherits(x, "frame") 576} 577 578#' @rdname stack 579#' @export 580global_frame <- function() { 581 warn_deprecated("`global_frame()` is deprecated as of rlang 0.3.0.") 582 new_frame(list( 583 pos = 0L, 584 caller_pos = NA_integer_, 585 expr = NULL, 586 env = globalenv(), 587 fn = NULL, 588 fn_name = NULL 589 )) 590} 591#' @rdname stack 592#' @export 593current_frame <- function() { 594 warn_deprecated("`current_frame()` is deprecated as of rlang 0.3.0.") 595 ctxt_frame(2) 596} 597 598#' @rdname stack 599#' @export 600ctxt_frame <- function(n = 1) { 601 warn_deprecated("`ctxt_frame()` is deprecated as of rlang 0.3.0.") 602 stopifnot(n > 0) 603 pos <- sys.nframe() - n 604 605 if (pos < 0L) { 606 stop("not that many frames on the stack", call. = FALSE) 607 } else if (pos == 0L) { 608 global_frame() 609 } else { 610 new_frame(list( 611 pos = pos, 612 caller_pos = sys.parent(n + 1), 613 expr = sys.call(-n), 614 env = sys.frame(-n), 615 fn = sys.function(-n), 616 fn_name = call_name(sys.call(-n)) 617 )) 618 } 619} 620 621# Positions of frames in the call stack up to `n` 622trail_make <- function(callers, n = NULL, clean = TRUE) { 623 n_ctxt <- length(callers) 624 if (is.null(n)) { 625 n_max <- n_ctxt 626 } else { 627 if (n > n_ctxt) { 628 stop("not that many frames on the evaluation stack", call. = FALSE) 629 } 630 n_max <- n + 1 631 } 632 633 state <- trail_next(callers, 1, clean) 634 if (!length(state$i) || state$i == 0) { 635 return(0L) 636 } 637 j <- 1 638 639 # Preallocate a sufficiently large vector 640 out <- integer(n_max) 641 out[j] <- state$i 642 643 while (state$i != 0 && j < n_max) { 644 j <- j + 1 645 n_ctxt <- length(state$callers) 646 next_pos <- n_ctxt - state$i + 1 647 state <- trail_next(state$callers, next_pos, clean) 648 out[j] <- state$i 649 } 650 651 # Return relevant subset 652 if (!is.null(n) && n > j) { 653 stop("not that many frames on the call stack", call. = FALSE) 654 } 655 out[seq_len(j)] 656} 657 658trail_next <- function(callers, i, clean) { 659 if (i == 0L) { 660 return(list(callers = callers, i = 0L)) 661 } 662 663 i <- callers[i] 664 665 if (clean) { 666 # base::Recall() creates a custom context with the wrong sys.parent() 667 if (identical(sys.function(i - 1L), base::Recall)) { 668 i_pos <- trail_index(callers, i) 669 callers[i_pos] <- i - 1L 670 } 671 672 # The R-level eval() creates two contexts. We skip the second one 673 if (length(i) && is_prim_eval(sys.function(i))) { 674 n_ctxt <- length(callers) 675 special_eval_pos <- trail_index(callers, i) 676 callers <- callers[-special_eval_pos] 677 i <- i - 1L 678 } 679 680 } 681 682 list(callers = callers, i = i) 683} 684 685trail_index <- function(callers, i) { 686 n_ctxt <- length(callers) 687 n_ctxt - i + 1L 688} 689 690#' @rdname stack 691#' @export 692call_frame <- function(n = 1, clean = TRUE) { 693 stopifnot(n > 0) 694 695 eval_callers <- ctxt_stack_callers() 696 trail <- trail_make(eval_callers, n, clean = clean) 697 pos <- trail[n] 698 699 if (identical(pos, 0L)) { 700 return(global_frame()) 701 } 702 703 frame <- new_frame(list( 704 pos = pos, 705 caller_pos = trail[n + 1], 706 expr = sys.call(pos), 707 env = sys.frame(pos), 708 fn = sys.function(pos), 709 fn_name = call_name(sys.call(pos)) 710 )) 711 712 if (clean) { 713 frame <- frame_clean_eval(frame) 714 } 715 frame 716} 717 718 719# The _depth() functions count the global frame as well 720 721#' @rdname stack 722#' @export 723ctxt_depth <- function() { 724 warn_deprecated("`ctxt_depth()` is deprecated as of rlang 0.3.0.") 725 sys.nframe() 726} 727#' @rdname stack 728#' @export 729call_depth <- function() { 730 warn_deprecated("`call_depth()` is deprecated as of rlang 0.3.0.") 731 eval_callers <- ctxt_stack_callers() 732 trail <- trail_make(eval_callers) 733 length(trail) 734} 735 736 737# Summaries ---------------------------------------------------------- 738 739#' @rdname stack 740#' @export 741ctxt_stack <- function(n = NULL, trim = 0) { 742 warn_deprecated("`ctxt_stack()` is deprecated as of rlang 0.3.0.") 743 744 stack_data <- list( 745 pos = ctxt_stack_trail(), 746 caller_pos = ctxt_stack_callers(), 747 expr = ctxt_stack_exprs(), 748 env = ctxt_stack_envs(), 749 fn = ctxt_stack_fns() 750 ) 751 752 # Remove ctxt_stack() from stack 753 stack_data <- map(stack_data, drop_first) 754 755 stack_data <- stack_subset(stack_data, n) 756 stack_data$fn_name <- map(stack_data$expr, call_name) 757 758 stack <- transpose(stack_data) 759 stack <- map(stack, new_frame) 760 761 if (is.null(n) || (length(n) && n > length(stack))) { 762 stack <- c(stack, list(global_frame())) 763 } 764 if (trim > 0) { 765 stack <- stack_trim(stack, n = trim + 1) 766 } 767 768 structure(stack, class = c("ctxt_stack", "stack")) 769} 770 771ctxt_stack_trail <- function() { 772 pos <- sys.nframe() - 1 773 seq(pos, 1) 774} 775ctxt_stack_exprs <- function() { 776 exprs <- sys.calls() 777 rev(drop_last(exprs)) 778} 779ctxt_stack_envs <- function(n = 1) { 780 envs <- sys.frames() 781 rev(drop_last(envs)) 782} 783ctxt_stack_callers <- function() { 784 callers <- sys.parents() 785 rev(drop_last(callers)) 786} 787ctxt_stack_fns <- function() { 788 pos <- sys.nframe() - 1 789 map(seq(pos, 1), sys.function) 790} 791 792stack_subset <- function(stack_data, n) { 793 if (length(n)) { 794 stopifnot(n > 0) 795 n_stack <- length(stack_data[[1]]) 796 if (n == n_stack + 1) { 797 # We'll add the global frame later 798 n <- n <- n - 1 799 } else if (n > n_stack + 1) { 800 stop("not that many frames on the stack", call. = FALSE) 801 } 802 stack_data <- map(stack_data, `[`, seq_len(n)) 803 } 804 stack_data 805} 806 807#' @rdname stack 808#' @export 809call_stack <- function(n = NULL, clean = TRUE) { 810 warn_deprecated("`call_stack()` is deprecated as of rlang 0.3.0.") 811 812 eval_callers <- ctxt_stack_callers() 813 trail <- trail_make(eval_callers, n, clean = clean) 814 815 stack_data <- list( 816 pos = drop_last(trail), 817 caller_pos = drop_first(trail), 818 expr = map(trail, sys.call), 819 env = map(trail, sys.frame), 820 fn = map(trail, sys.function) 821 ) 822 stack_data$fn_name <- map(stack_data$expr, call_name) 823 824 stack <- transpose(stack_data) 825 stack <- map(stack, new_frame) 826 if (clean) { 827 stack <- map(stack, frame_clean_eval) 828 } 829 830 if (trail[length(trail)] == 0L) { 831 stack <- c(stack, list(global_frame())) 832 } 833 834 structure(stack, class = c("call_stack", "stack")) 835} 836 837frame_clean_eval <- function(frame) { 838 if (identical(frame$fn, base::eval)) { 839 # Use the environment from the context created in do_eval() 840 # (the context with the fake primitive call) 841 stopifnot(is_prim_eval(sys.function(frame$pos + 1))) 842 frame$env <- sys.frame(frame$pos + 1) 843 } 844 845 frame 846} 847 848#' Is object a stack? 849#' 850#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("soft-deprecated")} 851#' 852#' @param x An object to test 853#' @keywords internal 854#' @export 855is_stack <- function(x) { 856 warn_deprecated("`is_stack()` is deprecated as of rlang 0.3.0.") 857 inherits(x, "stack") 858} 859 860#' @rdname is_stack 861#' @export 862is_eval_stack <- function(x) { 863 warn_deprecated("`is_eval_stack()` is deprecated as of rlang 0.3.0.") 864 inherits(x, "ctxt_stack") 865} 866 867#' @rdname is_stack 868#' @export 869is_call_stack <- function(x) { 870 warn_deprecated("`is_call_stack()` is deprecated as of rlang 0.3.0.") 871 inherits(x, "call_stack") 872} 873 874#' @export 875`[.stack` <- function(x, i) { 876 structure(NextMethod(), class = class(x)) 877} 878 879# Handles global_frame() whose `caller_pos` is NA 880sys_frame <- function(n) { 881 if (is.na(n)) { 882 NULL 883 } else { 884 sys.frame(n) 885 } 886} 887 888#' Find the position or distance of a frame on the evaluation stack 889#' 890#' @description 891#' 892#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 893#' 894#' The frame position on the stack can be computed by counting frames 895#' from the global frame (the bottom of the stack, the default) or 896#' from the current frame (the top of the stack). 897#' 898#' @details 899#' 900#' While this function returns the position of the frame on the 901#' evaluation stack, it can safely be called with intervening frames 902#' as those will be discarded. 903#' 904#' 905#' @section Life cycle: 906#' 907#' These functions are deprecated and replaced by [trace_back()]. 908#' 909#' @param frame The environment of a frame. Can be any object with a 910#' [get_env()] method. Note that for frame objects, the position from 911#' the global frame is simply `frame$pos`. Alternatively, `frame` 912#' can be an integer that represents the position on the stack (and 913#' is thus returned as is if `from` is "global". 914#' @param from Whether to compute distance from the global frame (the 915#' bottom of the evaluation stack), or from the current frame (the 916#' top of the evaluation stack). 917#' 918#' @keywords internal 919#' @export 920#' @examples 921#' fn <- function() g(environment()) 922#' g <- function(env) frame_position(env) 923#' 924#' # frame_position() returns the position of the frame on the evaluation stack: 925#' fn() 926#' identity(identity(fn())) 927#' 928#' # Note that it trims off intervening calls before counting so you 929#' # can safely nest it within other calls: 930#' g <- function(env) identity(identity(frame_position(env))) 931#' fn() 932#' 933#' # You can also ask for the position from the current frame rather 934#' # than the global frame: 935#' fn <- function() g(environment()) 936#' g <- function(env) h(env) 937#' h <- function(env) frame_position(env, from = "current") 938#' fn() 939frame_position <- function(frame, from = c("global", "current")) { 940 warn_deprecated("`frame_position()` is deprecated as of rlang 0.3.0.") 941 942 stack <- stack_trim(ctxt_stack(), n = 2) 943 944 if (arg_match(from) == "global") { 945 frame_position_global(frame, stack) 946 } else { 947 caller_pos <- call_frame(2)$pos 948 frame_position_current(frame, stack, caller_pos) 949 } 950} 951 952frame_position_global <- function(frame, stack = NULL) { 953 if (is_frame(frame)) { 954 return(frame$pos) 955 } else if (is_integerish(frame)) { 956 return(frame) 957 } 958 959 frame <- get_env(frame) 960 stack <- stack %||% stack_trim(ctxt_stack(), n = 2) 961 envs <- pluck(stack, "env") 962 963 i <- 1 964 for (env in envs) { 965 if (identical(env, frame)) { 966 return(length(envs) - i) 967 } 968 i <- i + 1 969 } 970 971 abort("`frame` not found on evaluation stack") 972} 973 974frame_position_current <- function(frame, stack = NULL, 975 caller_pos = NULL) { 976 if (is_integerish(frame)) { 977 pos <- frame 978 } else { 979 stack <- stack %||% stack_trim(ctxt_stack(), n = 2) 980 pos <- frame_position_global(frame, stack) 981 } 982 caller_pos <- caller_pos %||% call_frame(2)$pos 983 caller_pos - pos + 1 984} 985 986 987#' Trim top call layers from the evaluation stack 988#' 989#' @description 990#' 991#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 992#' 993#' [ctxt_stack()] can be tricky to use in real code because all 994#' intervening frames are returned with the stack, including those at 995#' `ctxt_stack()` own call site. `stack_trim()` makes it easy to 996#' remove layers of intervening calls. 997#' 998#' 999#' @section Life cycle: 1000#' 1001#' These functions are deprecated and replaced by [trace_back()]. 1002#' 1003#' @param stack An evaluation stack. 1004#' @param n The number of call frames (not eval frames) to trim off 1005#' the top of the stack. In other words, the number of layers of 1006#' intervening frames to trim. 1007#' @export 1008#' @keywords internal 1009#' @examples 1010#' # Intervening frames appear on the evaluation stack: 1011#' identity(identity(ctxt_stack())) 1012#' 1013#' # stack_trim() will trim the first n layers of calls: 1014#' stack_trim(identity(identity(ctxt_stack()))) 1015#' 1016#' # Note that it also takes care of calls intervening at its own call 1017#' # site: 1018#' identity(identity( 1019#' stack_trim(identity(identity(ctxt_stack()))) 1020#' )) 1021#' 1022#' # It is especially useful when used within a function that needs to 1023#' # inspect the evaluation stack but should nonetheless be callable 1024#' # within nested calls without side effects: 1025#' stack_util <- function() { 1026#' # n = 2 means that two layers of intervening calls should be 1027#' # removed: The layer at ctxt_stack()'s call site (including the 1028#' # stack_trim() call), and the layer at stack_util()'s call. 1029#' stack <- stack_trim(ctxt_stack(), n = 2) 1030#' stack 1031#' } 1032#' user_fn <- function() { 1033#' # A user calls your stack utility with intervening frames: 1034#' identity(identity(stack_util())) 1035#' } 1036#' # These intervening frames won't appear in the evaluation stack 1037#' identity(user_fn()) 1038stack_trim <- function(stack, n = 1) { 1039 warn_deprecated("`stack_trim()` is deprecated as of rlang 0.3.0.") 1040 1041 if (n < 1) { 1042 return(stack) 1043 } 1044 1045 # Add 1 to discard stack_trim()'s own intervening frames 1046 caller_pos <- call_frame(n + 1, clean = FALSE)$pos 1047 1048 n_frames <- length(stack) 1049 n_skip <- n_frames - caller_pos 1050 stack[seq(n_skip, n_frames)] 1051} 1052 1053 1054# Tidy eval -------------------------------------------------------- 1055 1056#' Parse text into a quosure 1057#' 1058#' @description 1059#' 1060#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1061#' 1062#' These functions were deprecated and renamed to [parse_quo()] 1063#' and [parse_quos()] in rlang 0.2.0. This is for consistency with the 1064#' convention that suffixes indicating return types are not 1065#' abbreviated. 1066#' 1067#' @inheritParams parse_expr 1068#' @keywords internal 1069#' @export 1070parse_quosure <- function(x, env = caller_env()) { 1071 warn_deprecated(paste_line( 1072 "`parse_quosure()` is deprecated as of rlang 0.2.0.", 1073 "Please use `parse_quo()` instead." 1074 )) 1075 parse_quo(x, env = env) 1076} 1077#' @rdname parse_quosure 1078#' @export 1079parse_quosures <- function(x, env = caller_env()) { 1080 warn_deprecated(paste_line( 1081 "`parse_quosures()` is deprecated as of rlang 0.2.0.", 1082 "Please use `parse_quos()` instead." 1083 )) 1084 parse_quos(x, env = env) 1085} 1086 1087#' Squash a quosure 1088#' 1089#' @description 1090#' 1091#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1092#' 1093#' This function is deprecated, please use [quo_squash()] instead. 1094#' 1095#' @inheritParams quo_squash 1096#' @keywords internal 1097#' @export 1098quo_expr <- function(quo, warn = FALSE) { 1099 warn_deprecated(paste_line( 1100 "`quo_expr()` is deprecated as of rlang 0.2.0.", 1101 "Please use `quo_squash()` instead." 1102 )) 1103 quo_squash(quo, warn = warn) 1104} 1105 1106#' Create an overscope 1107#' 1108#' @description 1109#' 1110#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1111#' 1112#' These functions have been deprecated in rlang 0.2.0. Please use 1113#' [as_data_mask()] and [new_data_mask()] instead. We no longer 1114#' require the mask to be cleaned up so `overscope_clean()` does not 1115#' have a replacement. 1116#' 1117#' @inheritParams as_data_mask 1118#' @param quo A [quosure][nse-defuse]. 1119#' 1120#' @keywords internal 1121#' @export 1122as_overscope <- function(quo, data = NULL) { 1123 warn_deprecated(paste_line( 1124 "`as_overscope()` is deprecated as of rlang 0.2.0.", 1125 "Please use `as_data_mask()` instead." 1126 )) 1127 as_data_mask(data) 1128} 1129#' @rdname as_overscope 1130#' @param enclosure The `parent` argument of [new_data_mask()]. 1131#' @export 1132new_overscope <- function(bottom, top = NULL, enclosure = NULL) { 1133 warn_deprecated(paste_line( 1134 "`new_overscope()` is deprecated as of rlang 0.2.0.", 1135 "Please use `new_data_mask()` instead." 1136 )) 1137 new_data_mask(bottom, top) 1138} 1139#' @rdname as_overscope 1140#' @param overscope A data mask. 1141#' @export 1142overscope_clean <- function(overscope) { 1143 warn_deprecated("`overscope_clean()` is deprecated as of rlang 0.2.0.") 1144 invisible(.Call(rlang_data_mask_clean, overscope)) 1145} 1146 1147#' Evaluate next quosure in a data mask 1148#' 1149#' @description 1150#' 1151#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1152#' 1153#' `overscope_eval_next()` is deprecated as of rlang 0.2.0. Please use 1154#' `eval_tidy()` to which you can now supply an overscope. 1155#' 1156#' @param quo A quosure. 1157#' @param overscope A valid overscope containing bindings for `~`, 1158#' `.top_env` and `_F` and whose parents contain overscoped bindings 1159#' for tidy evaluation. 1160#' @param env The lexical enclosure in case `quo` is not a validly 1161#' scoped quosure. This is the [base environment][base_env] by 1162#' default. 1163#' 1164#' @keywords internal 1165#' @export 1166overscope_eval_next <- function(overscope, quo, env = base_env()) { 1167 warn_deprecated(paste_line( 1168 "`overscope_eval_next()` is deprecated as of rlang 0.2.0.", 1169 "Please use `eval_tidy()` with a data mask instead." 1170 )) 1171 .External2(rlang_ext2_eval_tidy, quo, overscope, env) 1172} 1173 1174 1175# Expressions ------------------------------------------------------ 1176 1177#' Create a call 1178#' 1179#' @description 1180#' 1181#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1182#' 1183#' These functions are deprecated, please use [call2()] and 1184#' [new_call()] instead. 1185#' 1186#' @inheritParams call2 1187#' @keywords internal 1188#' @export 1189lang <- function(.fn, ..., .ns = NULL) { 1190 warn_deprecated(paste_line( 1191 "`lang()` is deprecated as of rlang 0.2.0.", 1192 "Please use `call2()` instead." 1193 )) 1194 call2(.fn, ..., .ns = .ns) 1195} 1196#' @rdname lang 1197#' @inheritParams new_call 1198#' @export 1199new_language <- function(head, tail = NULL) { 1200 warn_deprecated(paste_line( 1201 "`new_language()` is deprecated as of rlang 0.2.0.", 1202 "Please use `new_call()` instead." 1203 )) 1204 new_call(head, tail) 1205} 1206 1207#' Is object a call? 1208#' 1209#' @description 1210#' 1211#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1212#' 1213#' These functions are deprecated, please use [is_call()] and its `n` 1214#' argument instead. 1215#' 1216#' @inheritParams is_call 1217#' @keywords internal 1218#' @export 1219is_lang <- function(x, name = NULL, n = NULL, ns = NULL) { 1220 warn_deprecated(paste_line( 1221 "`is_lang()` is deprecated as of rlang 0.2.0.", 1222 "Please use `is_call()` instead." 1223 )) 1224 is_call(x, name, n, ns) 1225} 1226#' @rdname is_lang 1227#' @export 1228is_unary_lang <- function(x, name = NULL, ns = NULL) { 1229 warn_deprecated(paste_line( 1230 "`is_unary_lang()` is deprecated as of rlang 0.2.0.", 1231 "Please use `is_call()` instead." 1232 )) 1233 is_call(x, name, n = 1L, ns = ns) 1234} 1235#' @rdname is_lang 1236#' @export 1237is_binary_lang <- function(x, name = NULL, ns = NULL) { 1238 warn_deprecated(paste_line( 1239 "`is_binary_lang()` is deprecated as of rlang 0.2.0.", 1240 "Please use `is_call()` instead." 1241 )) 1242 is_call(x, name, n = 2L, ns = ns) 1243} 1244#' @rdname is_lang 1245#' @param quo A quosure to test. 1246#' @export 1247quo_is_lang <- function(quo) { 1248 warn_deprecated(paste_line( 1249 "`quo_is_lang()` is deprecated as of rlang 0.2.0.", 1250 "Please use `quo_is_call()` instead." 1251 )) 1252 .Call(rlang_quo_is_call, quo) 1253} 1254 1255#' Manipulate or access a call 1256#' 1257#' @description 1258#' 1259#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1260#' 1261#' These functions are deprecated, please use [call_modify()], 1262#' [call_standardise()], or [call_fn()] instead. 1263#' 1264#' @inheritParams call_modify 1265#' @param lang,.lang The `call` or `.call` argument of the renamed 1266#' functions. 1267#' @keywords internal 1268#' @export 1269lang_modify <- function(.lang, ..., .standardise = FALSE) { 1270 warn_deprecated(paste_line( 1271 "`lang_modify()` is deprecated as of rlang 0.2.0.", 1272 "Please use `call_modify()` instead." 1273 )) 1274 if (.standardise) { 1275 .lang <- call_standardise(.lang, caller_env()) 1276 } 1277 call_modify(.lang, ...) 1278} 1279#' @rdname lang_modify 1280#' @export 1281lang_standardise <- function(lang) { 1282 warn_deprecated(paste_line( 1283 "`lang_standardise()` is deprecated as of rlang 0.2.0.", 1284 "Please use `call_standardise()` instead." 1285 )) 1286 call_standardise(lang, env = caller_env()) 1287} 1288#' @rdname lang_modify 1289#' @export 1290lang_fn <- function(lang) { 1291 warn_deprecated(paste_line( 1292 "`lang_fn()` is deprecated as of rlang 0.2.0.", 1293 "Please use `call_fn()` instead." 1294 )) 1295 call_fn(lang, caller_env()) 1296} 1297#' @rdname lang_modify 1298#' @export 1299lang_name <- function(lang) { 1300 warn_deprecated(paste_line( 1301 "`lang_name()` is deprecated as of rlang 0.2.0.", 1302 "Please use `call_name()` instead." 1303 )) 1304 call_name(lang) 1305} 1306#' @rdname lang_modify 1307#' @export 1308lang_args <- function(lang) { 1309 warn_deprecated(paste_line( 1310 "`lang_args()` is deprecated as of rlang 0.2.0.", 1311 "Please use `call_args()` instead." 1312 )) 1313 call_args(lang) 1314} 1315#' @rdname lang_modify 1316#' @export 1317lang_args_names <- function(lang) { 1318 warn_deprecated(paste_line( 1319 "`lang_args_names()` is deprecated as of rlang 0.2.0.", 1320 "Please use `call_args_names()` instead." 1321 )) 1322 call_args_names(lang) 1323} 1324 1325 1326#' Return the head or tail of a call 1327#' 1328#' @description 1329#' 1330#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1331#' 1332#' As of rlang 0.2.0 these functions are retired (deprecated for now) 1333#' because they are low level accessors that are rarely needed for end 1334#' users. 1335#' 1336#' @param lang A call. 1337#' @keywords internal 1338#' @export 1339lang_head <- function(lang) { 1340 warn_deprecated("`lang_head()` is deprecated as of rlang 0.2.0.") 1341 call <- get_expr(lang) 1342 stopifnot(is_call(call)) 1343 node_car(call) 1344} 1345#' @rdname lang_head 1346#' @export 1347lang_tail <- function(lang) { 1348 warn_deprecated("`lang_tail()` is deprecated as of rlang 0.2.0.") 1349 call <- get_expr(lang) 1350 stopifnot(is_call(call)) 1351 node_cdr(call) 1352} 1353 1354#' Is an object an expression? 1355#' 1356#' @description 1357#' 1358#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1359#' 1360#' This function was deprecated and renamed to [is_expression()] in 1361#' rlang 0.2.0. This is for consistency with other type predicates 1362#' which are not abbreviated. 1363#' 1364#' @inheritParams is_expression 1365#' @keywords internal 1366#' @export 1367is_expr <- function(x) { 1368 warn_deprecated(paste_line( 1369 "`is_expr()` is deprecated as of rlang 0.2.0.", 1370 "Please use `is_expression()` instead." 1371 )) 1372 is_expression(x) 1373} 1374 1375 1376# Nodes ------------------------------------------------------------ 1377 1378#' Mutate node components 1379#' 1380#' @description 1381#' 1382#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1383#' 1384#' These functions were deprecated and renamed with `node_poke_` 1385#' prefix in rlang 0.2.0. This change follows a new naming convention 1386#' where mutation is referred to as "poking". 1387#' 1388#' @inheritParams new_node 1389#' 1390#' @keywords internal 1391#' @export 1392mut_node_car <- function(x, newcar) { 1393 warn_deprecated("`mut_node_car()` is deprecated as of rlang 0.2.0.") 1394 invisible(.Call(rlang_node_poke_car, x, newcar)) 1395} 1396#' @rdname mut_node_car 1397#' @export 1398mut_node_cdr <- function(x, newcdr) { 1399 warn_deprecated("`mut_node_cdr()` is deprecated as of rlang 0.2.0.") 1400 invisible(.Call(rlang_node_poke_cdr, x, newcdr)) 1401} 1402#' @rdname mut_node_car 1403#' @export 1404mut_node_caar <- function(x, newcar) { 1405 warn_deprecated("`mut_node_caar()` is deprecated as of rlang 0.2.0.") 1406 invisible(.Call(rlang_node_poke_caar, x, newcar)) 1407} 1408#' @rdname mut_node_car 1409#' @export 1410mut_node_cadr <- function(x, newcar) { 1411 warn_deprecated("`mut_node_cadr()` is deprecated as of rlang 0.2.0.") 1412 invisible(.Call(rlang_node_poke_cadr, x, newcar)) 1413} 1414#' @rdname mut_node_car 1415#' @export 1416mut_node_cdar <- function(x, newcdr) { 1417 warn_deprecated("`mut_node_cdar()` is deprecated as of rlang 0.2.0.") 1418 invisible(.Call(rlang_node_poke_cdar, x, newcdr)) 1419} 1420#' @rdname mut_node_car 1421#' @export 1422mut_node_cddr <- function(x, newcdr) { 1423 warn_deprecated("`mut_node_cddr()` is deprecated as of rlang 0.2.0.") 1424 invisible(.Call(rlang_node_poke_cddr, x, newcdr)) 1425} 1426#' @rdname mut_node_car 1427#' @export 1428mut_node_tag <- function(x, newtag) { 1429 warn_deprecated("`mut_node_tag()` is deprecated as of rlang 0.2.0.") 1430 invisible(.Call(rlang_node_poke_tag, x, newtag)) 1431} 1432 1433#' @rdname vector-old-ctors 1434#' @export 1435node <- function(car, cdr = NULL) { 1436 warn_deprecated(paste_line( 1437 "`node()` is deprecated as of rlang 0.2.0.", 1438 "Please use `new_node()` instead." 1439 )) 1440 new_node(car, cdr) 1441} 1442 1443 1444# Environments ----------------------------------------------------- 1445 1446#' Coerce to an environment 1447#' 1448#' @description 1449#' 1450#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1451#' 1452#' This function is deprecated as it was renamed to [as_environment()] 1453#' in rlang 0.2.0. 1454#' 1455#' @keywords internal 1456#' @export 1457as_env <- function(x, parent = NULL) { 1458 warn_deprecated("`as_env()` is deprecated as of rlang 0.2.0.") 1459 as_environment(x, parent) 1460} 1461 1462#' Is an object an environment? 1463#' 1464#' @description 1465#' 1466#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1467#' 1468#' These functions were deprecated and renamed to [is_environment()] 1469#' and [is_bare_environment()] in rlang 0.2.0. This is for consistency 1470#' with other type predicates which are not abbreviated. 1471#' 1472#' @inheritParams is_environment 1473#' @keywords internal 1474#' @export 1475is_env <- function(x) { 1476 warn_deprecated(paste_line( 1477 "`is_env()` is deprecated as of rlang 0.2.0.", 1478 "Please use `is_environment()` instead." 1479 )) 1480 is_environment(x) 1481} 1482#' @rdname is_env 1483#' @export 1484is_bare_env <- function(x) { 1485 warn_deprecated(paste_line( 1486 "`is_bare_env()` is deprecated as of rlang 0.2.0.", 1487 "Please use `is_bare_environment()` instead." 1488 )) 1489 is_bare_environment(x) 1490} 1491 1492#' Bind a promise or active binding 1493#' 1494#' @description 1495#' 1496#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1497#' 1498#' As of rlang 0.3.0, `env_bind_exprs()` and `env_bind_fns()` have 1499#' been renamed to [env_bind_lazy()] and [env_bind_active()] for 1500#' consistency. 1501#' 1502#' @inheritParams env_bind 1503#' 1504#' @keywords internal 1505#' @export 1506env_bind_exprs <- function(.env, ..., .eval_env = caller_env()) { 1507 warn_deprecated(paste_line( 1508 "`env_bind_exprs()` is deprecated as of rlang 0.3.0.", 1509 "Please use `env_bind_lazy()` instead." 1510 )) 1511 env_bind_lazy(.env = .env, ..., .eval_env = .eval_env) 1512} 1513#' @rdname env_bind_exprs 1514#' @export 1515env_bind_fns <- function(.env, ...) { 1516 warn_deprecated(paste_line( 1517 "`env_bind_fns()` is deprecated as of rlang 0.3.0.", 1518 "Please use `env_bind_active()` instead." 1519 )) 1520 env_bind_active(.env = .env, ...) 1521} 1522 1523#' Retired `scoped` functions 1524#' 1525#' @description 1526#' 1527#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1528#' 1529#' These functions are deprecated as of rlang 0.3.0. They are replaced 1530#' by [is_attached()], ... 1531#' 1532#' @param nm The name of an environment attached to the search 1533#' path. Call [base::search()] to see what is currently on the path. 1534#' 1535#' @keywords internal 1536#' @export 1537scoped_env <- function(nm) { 1538 warn_deprecated(paste_line( 1539 "`scoped_env()` is deprecated as of rlang 0.3.0.", 1540 "Please use `search_env()` instead." 1541 )) 1542 local_options(lifecycle_disable_warnings = TRUE) 1543 1544 if (identical(nm, "NULL")) { 1545 return(empty_env()) 1546 } 1547 if (!is_scoped(nm)) { 1548 stop(paste0(nm, " is not in scope"), call. = FALSE) 1549 } 1550 as.environment(nm) 1551} 1552#' @rdname scoped_env 1553#' @export 1554is_scoped <- function(nm) { 1555 warn_deprecated(paste_line( 1556 "`is_scoped()` is deprecated as of rlang 0.3.0.", 1557 "Please use `is_attached()` instead." 1558 )) 1559 local_options(lifecycle_disable_warnings = TRUE) 1560 1561 if (!is_scalar_character(nm)) { 1562 stop("`nm` must be a string", call. = FALSE) 1563 } 1564 nm %in% scoped_names() 1565} 1566#' @rdname scoped_env 1567#' @export 1568scoped_envs <- function() { 1569 warn_deprecated(paste_line( 1570 "`scoped_envs()` is deprecated as of rlang 0.3.0.", 1571 "Please use `search_envs()` instead." 1572 )) 1573 local_options(lifecycle_disable_warnings = TRUE) 1574 1575 envs <- c(list(.GlobalEnv), env_parents(.GlobalEnv)) 1576 set_names(envs, scoped_names()) 1577} 1578#' @rdname scoped_env 1579#' @export 1580scoped_names <- function() { 1581 warn_deprecated(paste_line( 1582 "`scoped_names()` is deprecated as of rlang 0.3.0.", 1583 "Please use `base::search()` instead." 1584 )) 1585 c(search(), "NULL") 1586} 1587 1588 1589# Vectors ---------------------------------------------------------- 1590 1591#' Retired vector construction by length 1592#' 1593#' @description 1594#' 1595#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1596#' 1597#' These functions were deprecated and renamed with `new_` prefix in 1598#' rlang 0.2.0. This is for consistency with other non-variadic object 1599#' constructors. 1600#' 1601#' @param .x A vector. 1602#' @inheritParams new-vector 1603#' @inheritParams new-vector-along-retired 1604#' @name vector-old-ctors 1605#' @keywords internal 1606NULL 1607 1608#' @rdname vector-old-ctors 1609#' @export 1610lgl_len <- function(.n) { 1611 warn_deprecated(paste_line( 1612 "`lgl_len()` is deprecated as of rlang 0.2.0.", 1613 "Please use `new_logical()` instead." 1614 )) 1615 new_logical(.n) 1616} 1617#' @rdname vector-old-ctors 1618#' @export 1619int_len <- function(.n) { 1620 warn_deprecated(paste_line( 1621 "`int_len()` is deprecated as of rlang 0.2.0.", 1622 "Please use `new_integer()` instead." 1623 )) 1624 new_integer(.n) 1625} 1626#' @rdname vector-old-ctors 1627#' @export 1628dbl_len <- function(.n) { 1629 warn_deprecated(paste_line( 1630 "`dbl_len()` is deprecated as of rlang 0.2.0.", 1631 "Please use `new_double()` instead." 1632 )) 1633 new_double(.n) 1634} 1635#' @rdname vector-old-ctors 1636#' @export 1637chr_len <- function(.n) { 1638 warn_deprecated(paste_line( 1639 "`chr_len()` is deprecated as of rlang 0.2.0.", 1640 "Please use `new_character()` instead." 1641 )) 1642 new_character(.n) 1643} 1644#' @rdname vector-old-ctors 1645#' @export 1646cpl_len <- function(.n) { 1647 warn_deprecated(paste_line( 1648 "`cpl_len()` is deprecated as of rlang 0.2.0.", 1649 "Please use `new_complex()` instead." 1650 )) 1651 new_complex(.n) 1652} 1653#' @rdname vector-old-ctors 1654#' @export 1655raw_len <- function(.n) { 1656 warn_deprecated(paste_line( 1657 "`raw_len()` is deprecated as of rlang 0.2.0.", 1658 "Please use `new_raw()` instead." 1659 )) 1660 new_raw(.n) 1661} 1662#' @rdname vector-old-ctors 1663#' @export 1664bytes_len <- function(.n) { 1665 warn_deprecated(paste_line( 1666 "`bytes_len()` is deprecated as of rlang 0.2.0.", 1667 "Please use `new_raw()` instead." 1668 )) 1669 new_raw(.n) 1670} 1671#' @rdname vector-old-ctors 1672#' @export 1673list_len <- function(.n) { 1674 warn_deprecated(paste_line( 1675 "`list_len()` is deprecated as of rlang 0.2.0.", 1676 "Please use `new_list()` instead." 1677 )) 1678 new_list(.n) 1679} 1680 1681#' @rdname vector-old-ctors 1682#' @export 1683lgl_along <- function(.x) { 1684 warn_deprecated("`lgl_along()` is deprecated as of rlang 0.2.0.") 1685 local_options(lifecycle_disable_warnings = TRUE) 1686 new_logical_along(.x, NULL) 1687} 1688#' @rdname vector-old-ctors 1689#' @export 1690int_along <- function(.x) { 1691 warn_deprecated("`int_along()` is deprecated as of rlang 0.2.0.") 1692 local_options(lifecycle_disable_warnings = TRUE) 1693 new_integer_along(.x, NULL) 1694} 1695#' @rdname vector-old-ctors 1696#' @export 1697dbl_along <- function(.x) { 1698 warn_deprecated("`dbl_along()` is deprecated as of rlang 0.2.0.") 1699 local_options(lifecycle_disable_warnings = TRUE) 1700 new_double_along(.x, NULL) 1701} 1702#' @rdname vector-old-ctors 1703#' @export 1704chr_along <- function(.x) { 1705 warn_deprecated("`chr_along()` is deprecated as of rlang 0.2.0.") 1706 local_options(lifecycle_disable_warnings = TRUE) 1707 new_character_along(.x, NULL) 1708} 1709#' @rdname vector-old-ctors 1710#' @export 1711cpl_along <- function(.x) { 1712 warn_deprecated("`cpl_along()` is deprecated as of rlang 0.2.0.") 1713 local_options(lifecycle_disable_warnings = TRUE) 1714 new_complex_along(.x, NULL) 1715} 1716#' @rdname vector-old-ctors 1717#' @export 1718raw_along <- function(.x) { 1719 warn_deprecated("`raw_along()` is deprecated as of rlang 0.2.0.") 1720 local_options(lifecycle_disable_warnings = TRUE) 1721 new_raw_along(.x, NULL) 1722} 1723#' @rdname vector-old-ctors 1724#' @export 1725bytes_along <- function(.x) { 1726 warn_deprecated("`bytes_along()` is deprecated as of rlang 0.2.0.") 1727 local_options(lifecycle_disable_warnings = TRUE) 1728 new_raw_along(.x, NULL) 1729} 1730#' @rdname vector-old-ctors 1731#' @export 1732list_along <- function(.x) { 1733 warn_deprecated("`list_along()` is deprecated as of rlang 0.2.0.") 1734 local_options(lifecycle_disable_warnings = TRUE) 1735 new_list_along(.x, NULL) 1736} 1737 1738#' Create vectors matching the length of a given vector 1739#' 1740#' These functions are deprecated as of rlang 0.3.0 because they 1741#' are longer to type than the equivalent [rep_along()] or 1742#' [rep_named()] calls without added clarity. 1743#' 1744#' @param x A vector. 1745#' @param names Names for the new vector. 1746#' @name new-vector-along-retired 1747#' @keywords internal 1748 1749#' @export 1750#' @rdname new-vector-along-retired 1751new_logical_along <- function(x, names = base::names(x)) { 1752 warn_deprecated_along("logical", "NA") 1753 set_names_impl(rep_len(na_lgl, length(x)), x, names) 1754} 1755#' @export 1756#' @rdname new-vector-along-retired 1757new_integer_along <- function(x, names = base::names(x)) { 1758 warn_deprecated_along("integer", "na_int") 1759 set_names_impl(rep_len(na_int, length(x)), x, names) 1760} 1761#' @export 1762#' @rdname new-vector-along-retired 1763new_double_along <- function(x, names = base::names(x)) { 1764 warn_deprecated_along("double", "na_dbl") 1765 set_names_impl(rep_len(na_dbl, length(x)), x, names) 1766} 1767#' @export 1768#' @rdname new-vector-along-retired 1769new_character_along <- function(x, names = base::names(x)) { 1770 warn_deprecated_along("character", "na_chr") 1771 set_names_impl(rep_len(na_chr, length(x)), x, names) 1772} 1773#' @export 1774#' @rdname new-vector-along-retired 1775new_complex_along <- function(x, names = base::names(x)) { 1776 warn_deprecated_along("complex", "na_cpl") 1777 set_names_impl(rep_len(na_cpl, length(x)), x, names) 1778} 1779#' @export 1780#' @rdname new-vector-along-retired 1781new_raw_along <- function(x, names = base::names(x)) { 1782 warn_deprecated_along("raw", "new_raw(1)") 1783 set_names_impl(vector("raw", length(x)), x, names) 1784} 1785#' @export 1786#' @rdname new-vector-along-retired 1787new_list_along <- function(x, names = base::names(x)) { 1788 warn_deprecated_along("list", "list(NULL)") 1789 set_names_impl(vector("list", length(x)), x, names) 1790} 1791warn_deprecated_along <- function(type, na) { 1792 warn_deprecated(paste_line( 1793 sprintf("`new_%s_along()` is deprecated as of rlang 0.3.0.", type), 1794 sprintf("Please use `rep_along(x, %s)` or `rep_named(nms, %s)` instead.", na, na) 1795 )) 1796} 1797# FIXME: This can be simplified once the `_along` ctors are defunct 1798set_names_impl <- function(x, mold, nm, ...) { 1799 .Call(rlang_set_names, x, mold, nm, environment()) 1800} 1801 1802#' Prepend a vector 1803#' 1804#' @description 1805#' 1806#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1807#' 1808#' Vector functions are now out of scope for rlang. They might be 1809#' revived in the vctrs or funs packages. 1810#' 1811#' 1812#' @keywords internal 1813#' 1814#' @param x the vector to be modified. 1815#' @param values to be included in the modified vector. 1816#' @param before a subscript, before which the values are to be appended. 1817#' @export 1818prepend <- function(x, values, before = 1) { 1819 warn_deprecated_vector("prepend") 1820 1821 n <- length(x) 1822 stopifnot(before > 0 && before <= n) 1823 1824 if (before == 1) { 1825 c(values, x) 1826 } else { 1827 c(x[1:(before - 1)], values, x[before:n]) 1828 } 1829} 1830 1831#' @rdname prepend 1832#' @param .x A vector to modify. 1833#' @param ... <[dynamic][dyn-dots]> List of elements to merge into 1834#' `.x`. Named elements already existing in `.x` are used as 1835#' replacements. Elements that have new or no names are inserted at 1836#' the end. 1837#' @export 1838modify <- function(.x, ...) { 1839 warn_deprecated_vector("modify") 1840 1841 out <- as.list(.x) 1842 args <- list2(...) 1843 1844 args_nms <- names(args) 1845 exists <- have_name(args) & args_nms %in% names(out) 1846 1847 for (nm in args_nms[exists]) { 1848 out[[nm]] <- args[[nm]] 1849 } 1850 1851 c(out, args[!exists]) 1852} 1853 1854warn_deprecated_vector <- function(fn) { 1855 warn_deprecated(paste_line( 1856 sprintf("`%s()` is deprecated as of rlang 0.4.0.", fn), 1857 "", 1858 "Vector tools are now out of scope for rlang to make it a more", 1859 "focused package." 1860 )) 1861} 1862 1863 1864 1865# Attributes ------------------------------------------------------- 1866 1867#' Add attributes to an object 1868#' 1869#' @description 1870#' 1871#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("experimental")} 1872#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} 1873#' 1874#' `set_attrs()` adds, changes, or zaps attributes of objects. Pass a 1875#' single unnamed `NULL` argument to zap all attributes. For 1876#' [uncopyable][is_copyable] types, use `mut_attrs()`. 1877#' 1878#' @details 1879#' 1880#' Unlike [structure()], these setters have no special handling of 1881#' internal attributes names like `.Dim`, `.Dimnames` or `.Names`. 1882#' 1883#' 1884#' @section Life cycle: 1885#' 1886#' These functions are deprecated since rlang 0.3.0. 1887#' 1888#' @param .x An object to decorate with attributes. 1889#' @param ... <[dynamic][dyn-dots]> A list of named attributes. Pass 1890#' a single unnamed `NULL` argument to zap all attributes from `.x`. 1891#' @return `set_attrs()` returns a modified [shallow copy][duplicate] 1892#' of `.x`. `mut_attrs()` invisibly returns the original `.x` 1893#' modified in place. 1894#' 1895#' @keywords internal 1896#' @export 1897#' @examples 1898#' set_attrs(letters, names = 1:26, class = "my_chr") 1899#' 1900#' # Splice a list of attributes: 1901#' attrs <- list(attr = "attr", names = 1:26, class = "my_chr") 1902#' obj <- set_attrs(letters, splice(attrs)) 1903#' obj 1904#' 1905#' # Zap attributes by passing a single unnamed NULL argument: 1906#' set_attrs(obj, NULL) 1907#' set_attrs(obj, !!! list(NULL)) 1908#' 1909#' # Note that set_attrs() never modifies objects in place: 1910#' obj 1911#' 1912#' # For uncopyable types, mut_attrs() lets you modify in place: 1913#' env <- env() 1914#' mut_attrs(env, foo = "bar") 1915#' env 1916set_attrs <- function(.x, ...) { 1917 warn_deprecated("`set_attrs()` is deprecated as of rlang 0.3.0") 1918 1919 if (!is_copyable(.x)) { 1920 abort("`.x` is uncopyable: use `mut_attrs()` to change attributes in place") 1921 } 1922 set_attrs_impl(.x, ...) 1923} 1924#' @rdname set_attrs 1925#' @export 1926mut_attrs <- function(.x, ...) { 1927 warn_deprecated("`set_attrs()` is deprecated as of rlang 0.3.0") 1928 1929 if (is_copyable(.x)) { 1930 abort("`.x` is copyable: use `set_attrs()` to change attributes without side effect") 1931 } 1932 invisible(set_attrs_impl(.x, ...)) 1933} 1934set_attrs_impl <- function(.x, ...) { 1935 attrs <- dots_list(...) 1936 1937 # If passed a single unnamed NULL, zap attributes 1938 if (identical(attrs, set_attrs_null)) { 1939 attributes(.x) <- NULL 1940 } else { 1941 attributes(.x) <- c(attributes(.x), attrs) 1942 } 1943 1944 .x 1945} 1946set_attrs_null <- list(NULL) 1947names(set_attrs_null) <- "" 1948 1949 1950# Conditions -------------------------------------------------------- 1951 1952#' Exiting handler 1953#' 1954#' @description 1955#' 1956#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("soft-deprecated")} 1957#' 1958#' `exiting()` is no longer necessary as handlers are exiting by default. 1959#' 1960#' @keywords internal 1961#' @export 1962exiting <- function(handler) { 1963 signal_soft_deprecated(c( 1964 "`exiting()` is soft-deprecated as of rlang 0.4.0.", 1965 "Handlers are now treated as exiting by default." 1966 )) 1967 handler <- as_function(handler) 1968 structure(handler, class = c("rlang_handler_exiting", "rlang_handler", "function")) 1969} 1970 1971 1972# Scoped_ 1973 1974#' Questioning `scoped_` functions 1975#' 1976#' @description 1977#' 1978#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("questioning")} 1979#' 1980#' These functions have been renamed to use the conventional `local_` 1981#' prefix. They will be deprecated in the next minor version of rlang. 1982#' 1983#' @inheritParams local_interactive 1984#' @inheritParams local_options 1985#' @inheritParams local_bindings 1986#' 1987#' @export 1988scoped_interactive <- function(value = TRUE, frame = caller_env()) { 1989 local_interactive(value = value, frame = frame) 1990} 1991#' @rdname scoped_interactive 1992#' @export 1993scoped_options <- function(..., .frame = caller_env()) { 1994 local_options(..., .frame = .frame) 1995} 1996#' @rdname scoped_interactive 1997#' @export 1998scoped_bindings <- function(..., .env = .frame, .frame = caller_env()) { 1999 local_bindings(..., .env = .env, .frame = .frame) 2000} 2001 2002 2003# Superseded 2004 2005#' Mask bindings by defining symbols deeper in a scope 2006#' 2007#' @description 2008#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("superseded")} 2009#' 2010#' This function is superseded. Please use [env()] (and possibly 2011#' [set_env()] if you're masking the bindings for another object like 2012#' a closure or a formula) instead. 2013#' 2014#' `env_bury()` is like [env_bind()] but it creates the bindings in a 2015#' new child environment. This makes sure the new bindings have 2016#' precedence over old ones, without altering existing environments. 2017#' Unlike `env_bind()`, this function does not have side effects and 2018#' returns a new environment (or object wrapping that environment). 2019#' 2020#' @inheritParams env_bind 2021#' @return A copy of `.env` enclosing the new environment containing 2022#' bindings to `...` arguments. 2023#' @seealso [env_bind()], [env_unbind()] 2024#' 2025#' @keywords internal 2026#' @export 2027#' @examples 2028#' orig_env <- env(a = 10) 2029#' fn <- set_env(function() a, orig_env) 2030#' 2031#' # fn() currently sees `a` as the value `10`: 2032#' fn() 2033#' 2034#' # env_bury() will bury the current scope of fn() behind a new 2035#' # environment: 2036#' fn <- env_bury(fn, a = 1000) 2037#' fn() 2038#' 2039#' # Even though the symbol `a` is still defined deeper in the scope: 2040#' orig_env$a 2041env_bury <- function(.env, ...) { 2042 env_ <- get_env(.env) 2043 env_ <- child_env(env_, ...) 2044 set_env(.env, env_) 2045} 2046