elixir is primarily a package for working with what it calls
"expressions", in the sense of any R object for which
rlang::is_expression() returns TRUE. This includes calls, like the
results of evaluating quote(f(x)) or quote(a:b), symbols like
quote(z), and syntactic literals like 2.5, "hello", NULL, FALSE,
and so on.
This is not to be confused with the built-in type base::expression, which
is essentially a special way of storing a vector of multiple "expressions".
elixir does not use this type; see expr_list() instead.
Specifying expressions in elixir
The elixir package functions starting with expr_ work with expressions.
These functions all accept a special (optional) syntax for specifying
expressions which involves the symbols {}, ?, and ~, as well as the
rlang injection operator, !! and
splice operator, !!!).
With base R, if you want to store an expression such as x + y in a
variable or pass it to a function, you need to use base::quote() or
rlang::expr(), but any Elixir expr_ function will also accept an
"expression literal" wrapped in braces, {}.
So, for example, rather than
translate(quote(x ^ y), "C++")
you can write
translate({ x ^ y }, "C++").
This only works if the braces are provided "directly"; that is, in
expr <- quote({ x ^ y }); translate(expr, "C++"),
the braces are not interpreted in any special way.
Anything between the braces essentially gets put through rlang::expr(), so
you can use !! (i.e. rlang::injection-operator) and !!! (i.e.
rlang::splice-operator). There is an env parameter to all relevant
elixir functions, defaulting to parent.frame(), in which these injection
operations are evaluated.
Special syntax for patterns and replacements
Additionally, some functions (expr_match(), expr_count(),
expr_detect(), expr_extract(), expr_locate(), and expr_replace())
take pattern and/or replacement arguments to specify patterns to match
to an expression and/or replacement expressions to replace those matches
with.
For both pattern and replacement arguments, you can use the question
mark operator ? to specify alternatives. For example, to match either
the token cat or dog, you can use
expr_match(expr, { cat } ? { dog }).
You can chain together as many alternatives as are needed. Alternatively,
if you have a list of expressions z, you can use a single question mark
before the name of the list, like so:
expr_match(expr, ?z)
and elixir will treat the list as a set of alternatives. When using
expr_replace() with a set of alternatives as the pattern, the replacement
needs to be either a single expression, or a set of alternative expressions
which has the same number of alternatives as in the pattern.
You can also use the tilde operator ~ to specify that a given pattern
should be "anchored" at the top level of an expression, and will not
"recurse into" the expression. For example, in
only the numbers 2 and 5 will match. However, in
all numbers 2, 5, 1 and 4 will match, because the pattern can
recurse into the third expression 1 + 4.