1#' Create a symbol or list of symbols
2#'
3#' These functions take strings as input and turn them into symbols.
4#'
5#' @param x A string or list of strings.
6#' @return A symbol for `sym()` and a list of symbols for `syms()`.
7#' @export
8#' @examples
9#' # The empty string returns the missing argument:
10#' sym("")
11#'
12#' # This way sym() and as_string() are inverse of each other:
13#' as_string(missing_arg())
14#' sym(as_string(missing_arg()))
15sym <- function(x) {
16  if (is_symbol(x)) {
17    return(x)
18  }
19  if (identical(x, "")) {
20    return(missing_arg())
21  }
22  if (!is_string(x)) {
23    abort("Only strings can be converted to symbols")
24  }
25  .Call(rlang_symbol, x)
26}
27#' @rdname sym
28#' @export
29syms <- function(x) {
30  map(x, sym)
31}
32
33#' Is object a symbol?
34#' @param x An object to test.
35#' @param name An optional name or vector of names that the symbol
36#'   should match.
37#' @export
38is_symbol <- function(x, name = NULL) {
39  if (typeof(x) != "symbol") {
40    return(FALSE)
41  }
42  if (is_null(name)) {
43    return(TRUE)
44  }
45  as_string(x) %in% name
46}
47
48#' Cast symbol to string
49#'
50#' `as_string()` converts [symbols][sym] to character strings.
51#'
52#' @param x A string or symbol. If a string, the attributes are
53#'   removed, if any.
54#' @return A character vector of length 1.
55#'
56#' @section Unicode tags:
57#'
58#' Unlike [base::as.symbol()] and [base::as.name()], `as_string()`
59#' automatically transforms unicode tags such as `"<U+5E78>"` to the
60#' proper UTF-8 character. This is important on Windows because:
61#'
62#' * R on Windows has no UTF-8 support, and uses native encoding instead.
63#'
64#' * The native encodings do not cover all Unicode characters. For
65#'   example, Western encodings do not support CKJ characters.
66#'
67#' * When a lossy UTF-8 -> native transformation occurs, uncovered
68#'   characters are transformed to an ASCII unicode tag like `"<U+5E78>"`.
69#'
70#' * Symbols are always encoded in native. This means that
71#'   transforming the column names of a data frame to symbols might be
72#'   a lossy operation.
73#'
74#' * This operation is very common in the tidyverse because of data
75#'   masking APIs like dplyr where data frames are transformed to
76#'   environments. While the names of a data frame are stored as a
77#'   character vector, the bindings of environments are stored as
78#'   symbols.
79#'
80#' Because it reencodes the ASCII unicode tags to their UTF-8
81#' representation, the string -> symbol -> string roundtrip is
82#' more stable with `as_string()`.
83#'
84#' @seealso [as_name()] for a higher-level variant of `as_string()`
85#'   that automatically unwraps quosures.
86#' @examples
87#' # Let's create some symbols:
88#' foo <- quote(foo)
89#' bar <- sym("bar")
90#'
91#' # as_string() converts symbols to strings:
92#' foo
93#' as_string(foo)
94#'
95#' typeof(bar)
96#' typeof(as_string(bar))
97#' @export
98as_string <- function(x) {
99  if (is_string(x)) {
100    attributes(x) <- NULL
101    return(x)
102  }
103
104  if (is_symbol(x)) {
105    return(.Call(rlang_sym_as_character, x))
106  }
107
108  abort_coercion(x, "a string")
109}
110
111namespace_sym <- quote(`::`)
112namespace2_sym <- quote(`:::`)
113dollar_sym <- quote(`$`)
114dot_data_sym <- quote(.data)
115dots_sym <- quote(...)
116at_sym <- quote(`@`)
117tilde_sym <- quote(`~`)
118colon_equals_sym <- quote(`:=`)
119brace_sym <- quote(`{`)
120dots_sym <- quote(...)
121function_sym <- quote(`function`)
122dot_sym <- quote(.)
123pipe_sym <- quote(`%>%`)
124