The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
TODO: reorganize, put failing alternatives on top, then really wrong stuff, then inaccuracies then readability.
constructive::deparse_call()
converts calls (language
objects) to code. It is an alternative to base::deparse()
or rlang::expr_deparse()
with a slightly different scope,
and 3 main differences:
deparse_call()
faisl if the call is not syntactic (if
it cannot be the output of parse(text=x)[[1]]
), for
instance if its AST contains elements that are not syntactic tokensx <- call('+', c(1, 2))
base::deparse(x)
#> [1] "+c(1, 2)"
rlang::expr_deparse(x)
#> [1] "+<dbl: 1, 2>"
constructive::deparse_call(x)
#> Error in `constructive::deparse_call()`:
#> ! `call` must only be made of symbols and syntactic literals
#> Caused by error in `deparse_call_impl()`:
#> ! Found element of type 'double' and length '2':
#> c(1, 2)
# this is different
y <- quote(+c(1, 2))
x[[2]]
#> [1] 1 2
y[[2]]
#> c(1, 2)
deparse_call()
never makes compromises to make code
more readable at the expense of accuracy.x <- quote(`*`(a + b, c))
base::deparse(x)
#> [1] "(a + b) * c"
rlang::expr_deparse(x)
#> [1] "(a + b) * c"
constructive::deparse_call(x)
#> `*`(a + b, c)
y <- quote((a + b) * c)
base::deparse(y)
#> [1] "(a + b) * c"
rlang::expr_deparse(y)
#> [1] "(a + b) * c"
constructive::deparse_call(y)
#> (a + b) * c
# x and y are different, parentheses are code!
x[[2]]
#> a + b
y[[2]]
#> (a + b)
deparse_call()
handles many more contrived cases. It
strives to provide an accurate syntactic representation for every
possible syntactic language object, however unprobable or unpractical
they might be.x <- call("[")
base::deparse(x)
#> [1] "NULL[]"
rlang::expr_deparse(x)
#> [1] "NULL[]"
constructive::deparse_call(x)
#> `[`()
deparse_call()
is more accurateWe present more differences below, where at least one of the alternatives is not deparsing faithfully.
deparse_call() | deparse() | expr_deparse() | |
---|---|---|---|
call('+', c(1, 2)) cannot be obtained by parsing
code |
ERROR | +c(1, 2) |
+<dbl: 1, 2> |
Infix :: and ::: can only be called on
symbols |
`::`(1, 2) |
1::2 |
1::2 |
Infix $ and @ can only have a symbol
rhs |
`$`("a", 1) |
`$`("a", 1) |
"a"$1 |
Infix $ and @ create different calls when
rhs is symbol or string |
a$"b" |
a$b |
a$"b" |
Binary ops cannot be used as prefixes | `*`(1) |
*1 |
`*`(1) |
Binary ops cannot be used infix with > 2 args | `*`(1, 2, 3) |
`*`(1, 2, 3) |
1 * 2 |
Binary ops cannot be used infix with empty args | `*`(1, ) |
1 * |
1 * |
Parentheses need function call notation if 0 arg | `(`() |
(NULL) |
(NULL) |
Parentheses need function call notation if > 1 arg | `(`(1, 2) |
(1) |
(1) |
Calling = is different from passing an arg |
list(`=`(x, 1)) |
list((x = 1)) |
list(x = 1) |
Precedence must be respected, but adding extra parentheses to respect precedence is not accurate | `-`(1 + 2) |
-(1 + 2) |
-1 + 2 |
`+`(repeat { }, 1) |
(repeat { }) + 1 |
repeat { } + 1 |
|
`<-`(x <- 1, 2) |
(x <- 1) <- 2 |
(x <- 1) <- 2 |
|
`*`(a + b, c) |
(a + b) * c |
(a + b) * c |
|
`+`(x, y)(z) |
(x + y)(z) |
`+`(x, y)(z) |
|
`^`(1^2, 4) |
(1^2)^4 |
(1^2)^4 |
|
`+`(1, 2 + 3) |
1 + (2 + 3) |
1 + (2 + 3) |
|
Brackets calling no arg is different from subsetting NULL | `[`() |
NULL[] |
NULL[] |
Empty bracket syntax means doesn’t mean no 2nd arg, it means 2nd arg is empty symbol, so for 1 arg we need function notation | `[`(x) |
x[] |
x[] |
Brackets with an empty first arg need function call notation | `[`(, ) |
[] |
[] |
Brackets taking a call to a lower precedence op as a first arg need function call notation | `[`(a + b, 1) |
(a + b)[1] |
a + b[1] |
Invalid function definitions can be valid code | `function`(1, 2) |
ERROR | SEGFAULT |
`function`(1(2), 3) |
function(1, 2) 3 |
ERROR | |
Curly braces need function call notation if they have empty args | `{`(1, ) |
{ 1
} |
{ 1
} |
Control flow constructs need function call notation if they’re used as callers | `if`(TRUE, { })(1) |
(if (TRUE) { })(1) |
`if`(TRUE, { })(1) |
Symbols with non syntactic names need backquotes | `*a*` |
*a* |
`*a*` |
This includes emojis | `\xf0\x9f\x90\xb6` |
🐶 |
`🐶` |
deparse_call()
is clearerIn the following base::deparse()
and
rlang::expr_deparse()
are not wrong, but
constructive::deparse_call()
is clearer.
constructive::deparse_call() | base::deparse() | rlang::expr_deparse() | |
---|---|---|---|
Simple quotes make strings that use double quotes more readable | '"oh" "hey" "there"' |
"\"oh\" \"hey\" \"there\"" |
"\"oh\" \"hey\" \"there\"" |
Raw strings make more complex strings more readable | r"["oh"\'hey'\"there"]" |
"\"oh\"\\'hey'\\\"there\"" |
"\"oh\"\\'hey'\\\"there\"" |
Homoglyphs are dangerous, we can use the \U{XX}
notation |
"\U{410} \U{A0} A" |
"А A" |
"А A" |
For symbols we need the \xXX notation |
c(`\xd0\x90`, "\U{A0}" = 1) |
c(А, ` ` = 1) |
c(А, ` ` = 1) |
Emojis depend on font so are ambiguous | "\U{1F436}" |
"🐶" |
"🐶" |
deparse_call()
fails rather than making things upx <- call("(", -1)
base::deparse(x)
#> [1] "(-1)"
rlang::expr_deparse(x)
#> [1] "(-1)"
constructive::deparse_call(x)
#> Error in `constructive::deparse_call()`:
#> ! `call` must only be made of symbols and syntactic literals
#> Caused by error in `deparse_call_impl()`:
#> ! Found element of type 'double' and length '1':
#> -1
# this is different! `-` is code!
y <- quote((-1))
base::deparse(y)
#> [1] "(-1)"
rlang::expr_deparse(y)
#> [1] "(-1)"
constructive::deparse_call(y)
#> (-1)
x <- call("fun", quote(expr = ))
base::deparse(x)
#> [1] "fun()"
rlang::expr_deparse(x)
#> [1] "fun()"
constructive::deparse_call(x) # this is wrong!
#> Error in `constructive::deparse_call()`:
#> ! `call` must only be made of symbols and syntactic literals
#> Caused by error in `deparse_call_impl()`:
#> ! Found empty symbol used as sole argument of a function:
#> as.call(list(quote(fun), quote(expr = )))
# no agument and 1 missing argument is not the same!
y <- call("fun")
base::deparse(y)
#> [1] "fun()"
rlang::expr_deparse(y)
#> [1] "fun()"
constructive::deparse_call(y)
#> fun()
x <- call("!", quote(expr = ))
base::deparse(x)
#> [1] "!"
rlang::expr_deparse(x)
#> [1] "!"
constructive::deparse_call(x)
#> Error in `constructive::deparse_call()`:
#> ! `call` must only be made of symbols and syntactic literals
#> Caused by error in `deparse_call_impl()`:
#> ! Found empty symbol used as sole argument of a function:
#> as.call(list(quote(`!`), quote(expr = )))
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.