rewrite_with {foolbox} | R Documentation |
Functions for applying a sequence of rewrites.
Description
The rewrite()
function applies a series of transformations to an input
function, fn
and returns the result. This result can then be used in a
pipeline of rewrite_with()
calls for further analysis.
Usage
rewrite_with(fn, callbacks, ...)
rewrite(fn)
analyse(fn)
analyse_with(fn, callbacks, ...)
rewrite_expr(expr)
rewrite_expr_with(expr, callbacks, ...)
analyse_expr(expr)
analyse_expr_with(expr, callbacks, ...)
Arguments
fn |
The function to rewrite |
callbacks |
The callbacks that should do the rewriting |
... |
Additional parameters passed along to the callbacks. |
expr |
When invoked on expressions, in |
Details
The flow of transformations goes starts with rewrite()
and is followed by a
series of rewrite_with()
for additional rewrite callbacks. For analysis, it
starts with analyse()
and is followed by a pipeline of analyse_with()
.
This functions will annotate a function's body with two attributes for each
sub-expression in the body. Each call
expression in the body will be
annotated with these two attributes:
-
assigned_symbols: Variables that appear to the left of an assignment in a sub-expression of the call that is likely to affect the scope of the call.
-
bound: Variables that are either assigned to, thus potentially local in the scope, or function parameters from an enclosing scope, which will definitely be bound at this position.
Since R does not require that we declare local variables, and since the variables that are assigned to a local scope depend on the runtime execution of functions, we cannot determine with any certainty which variables will be assigned to in any given scope at any given program point. So the best we can do is figure out which variables are potentially assigned to. Which is what this function does.
The rules for when we are assigning to a local variable are a bit
complicated. For control structures, we can assume that assignments will
be to the local scope. People can change the implementation of these so it
isn't, but then they are only hurting themselves and deserve the extra
pain we can give them. For other call arguments, it gets a little more
complicated. With standard-evaluation, if we have an arrow assignment in a
function argument, then the assignment happens in the calling scope. So we
will assume this happens unless we are handling cases we know have NSE,
such as with
. If an assignment is inside a block, however, we will
assume that NSE is in play, by default, and not consider it a local
assignment.
Value
A rewritten function
Functions
-
rewrite_with
: Applycallbacks
overfn
to rewrite it. -
rewrite
: Function for starting a rewrite. -
analyse
: Function for running analysis callbacks -
analyse_with
: Applycallbacks
overfn
to analyse it. -
rewrite_expr
: Expression version ofrewrite()
-
rewrite_expr_with
: Expression version ofrewrite_with()
-
analyse_expr
: Expression version ofanalyse()
-
analyse_expr_with
: Expression version ofanalyse_with()
See Also
rewrite_callbacks
Examples
f <- function(x) 2 + x
cb <- rewrite_callbacks() %>%
add_call_callback(f, function(expr, ...) {
quote(2 + x)
})
tr_f <- . %>% rewrite() %>% rewrite_with(cb)
g <- function(y) y + f(y)
tr_f(g)
collect_symbols <- function(expr, ...) {
list(symbols = as.character(expr))
}
callbacks <- analysis_callbacks() %>% with_symbol_callback(collect_symbols)
f %>% analyse() %>% analyse_with(callbacks)