This package aims to provide a simple way to access a language object and you can manipulate it as you want by passing a visitor-function for printing, transforming, analyzing, and generating a new code.
It is natural for an OOP language to use visitor-pattern, and it is common for a functional language to use pattern-matching. R, I think, is not suitable for the use of those ideas because semantics itself does not support those functionalities.
codetools::walkCode
by Luke Tierneypryr::call_tree
(NSE version is pryr::ast
) by Hadley Wickhamsee vignette for a comparison among these functions.
## install.packages("devtools")
devtools::install_github("tobcap/walkast")
library("walkast")
walk_ast(expr, visitor)
make_visitor(leaf, call, hd, tl, initial, final, ...)
A helper which creates visitor-class.
leaf()
: a function that manipulates leaf part of langauge object (a symbol or an atomic)call()
: a function that manipulates call part of langauge object (call object)hd()
: a function that manipulates caller part (head of call object)tl()
: a function that manipulates arguments part of call (tail of call object)initial()
: a function that manipulates expr before running ASTfinal()
: a function that manipulates expr after running AST...
: arbitrary functions or variables that you want to use
``` r
visitor()
if you wantv0 <- make_visitor(leaf = function(x) if (is.numeric(x)) x * 2 else x)
library(R6) v1 <- R6Class( "visitor" , public = list( leaf = function(x) if (is.numeric(x)) x * 2 else x , call = identity , hd = identity , tl = identity , initial = identity , final = identity ) )$new()
walk_ast(quote(1 + 2 * 3), v0) walk_ast(quote(1 + 2 * 3), v1) ```
show_tree()
show_lisp(quote_bin = FALSE)
show_r()
replace(before, after)
nest_expr(expr, target, count)
this recursively calls walk_ast()to_list()
to_call()
%then%
library("walkast")
e1 <- quote(1 + x * 2 - y)
walk_ast(e1)
#> 1 + x * 2 - y
walk_ast(e1, show_tree())
#> List of 3
#> $ : symbol -
#> $ :List of 3
#> ..$ : symbol +
#> ..$ : num 1
#> ..$ :List of 3
#> .. ..$ : symbol *
#> .. ..$ : symbol x
#> .. ..$ : num 2
#> $ : symbol y
walk_ast(e1, show_lisp())
#> [1] (- (+ 1 (* x 2)) y)
walk_ast(e1, show_lisp(quote_bin = TRUE))
#> [1] (`-` (`+` 1 (`*` x 2)) y)
# this is parsable
walk_ast(e1, show_r())
#> [1] `-`(`+`(1, `*`(x, 2)), y)
mult2 <- make_visitor(leaf = function(x) if (is.numeric(x)) x * 2 else x)
walk_ast(e1, mult2)
#> 2 + x * 4 - y
add1 <- make_visitor(leaf = function(x) if (is.numeric(x)) x + 1 else x)
walk_ast(e1, add1)
#> 2 + x * 3 - y
walk_ast(e1, add1 %then% mult2)
#> 4 + x * 6 - y
walk_ast(e1, mult2 %then% add1)
#> 3 + x * 5 - y
walk_ast(e1, replace(quote(`+`), quote(`-`)))
#> 1 - x * 2 - y
walk_ast(e1, replace(2, quote(x)))
#> 1 + x * x - y
e2 <- quote((1 + x) ^ 2)
nest_expr(e2, quote(x), 3)
#> (1 + (1 + (1 + x)^2)^2)^2
nest_expr(e2, quote(1 + x), 3)
#> (((1 + x)^2)^2)^2
nest_expr(quote(1 + 1 / x), quote(x), 5)
#> 1 + 1/(1 + 1/(1 + 1/(1 + 1/(1 + 1/x))))
e3 <- quote({
x <- 1
++x
print(x)
})
plus_plus <- make_visitor(
call = function(x)
if (length(x) == 2 && identical(x[[1]], quote(`+`)) &&
length(x[[2]]) == 2 && identical(x[[2]][[1]], quote(`+`)) &&
is.symbol(sym <- x[[2]][[2]]))
base::call("<-", sym, base::call("+", sym, 1)) else x
)
walk_ast(e3, plus_plus)
#> {
#> x <- 1
#> x <- x + 1
#> print(x)
#> }
plus_plus2 <- make_visitor(
call = function(x) {
syms <- all.names(x)
if (length(syms) == 3 &&
syms[1:2] == c("+", "+") &&
is.symbol(sym <- x[[2]][[2]]))
base::call("<-", sym, base::call("+", sym, 1)) else x
}
)
walk_ast(e3, plus_plus2)
#> {
#> x <- 1
#> x <- x + 1
#> print(x)
#> }
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.