README.md

walkast

The objective

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.

OOP or Functional Style?

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.

Related functions that already exist

see vignette for a comparison among these functions.

Installation

## install.packages("devtools")
devtools::install_github("tobcap/walkast")
library("walkast")

Main functions

walk_ast(expr, visitor)

make_visitor(leaf, call, hd, tl, initial, final, ...)

A helper which creates visitor-class.

Other helper functions

Printing

Replacing

Conversion

Combination

Examples

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)
#> }

ToDo (someday)



TobCap/walkast documentation built on May 9, 2019, 4:51 p.m.