Skip to content

Commit

Permalink
More progress towards tail-recursive cases
Browse files Browse the repository at this point in the history
Progress on #5 and mailund/pmatch#19. I need a non-local `next` when calling recursively in `with` expressions to make this work.
  • Loading branch information
mailund committed Feb 9, 2018
1 parent de4eced commit 7ff5271
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 1 deletion.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Package: tailr
Version: 0.0.0.9001
Version: 0.0.0.9002
Title: Automatic Tail Recursion Optimisation
Description: This package implements meta-programming functions for automatically
translating recursive functions into looping functions or trampolines.
Expand Down
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# tailr 0.0.0.9002

* Handle `with` expressions.
* Make explicit that we cannot handle `eval`.

# tailr 0.0.0.9001

* Added framework for user-defined transformations.
Expand Down
29 changes: 29 additions & 0 deletions R/loop-transformation.R
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,23 @@ can_call_be_transformed <- function(call_name, call_arguments,
}
},

# Eval is really just evaluation of an expression in the calling scope,
# so we shouldn't consider those function calls either... I'm not sure how to
# handle them when it comes to what they return, though, since it depends
# on the expression they will evaluate
"eval" = {
warning("We can't yet handle eval expressions.")
cc(FALSE)
},

# With expressions are a bit like eval, I guess... don't consider them
# function calls.
"with" = {
for (arg in call_arguments) {
can_transform_rec(arg, fun_name, fun_call_allowed, cc)
}
},

# Selection
"if" = {
can_transform_rec(call_arguments[[1]], fun_name, fun_call_allowed, cc)
Expand Down Expand Up @@ -201,6 +218,18 @@ make_returns_explicit_call <- function(call_expr, in_function_parameter) {
call_expr[[n]] <- make_returns_explicit(call_expr[[n]], in_function_parameter)
},

# Not sure how to handle eval, exactly...
# The problem here is that I need to return the expression if it is not a recursive call
# but not if it is...
"eval" = {
stop("FIXME")
},

# With should just be left alone and we can deal with the expression it evaluates
"with" = {
call_expr[[3]] <- make_returns_explicit(call_expr[[3]], in_function_parameter)
},

# For all other calls we transform the arguments inside a call context.
{
for (i in seq_along(call_args)) {
Expand Down
16 changes: 16 additions & 0 deletions tests/testthat/test-loop-transformation.R
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,19 @@ test_that("we cannot transform a non-tail-recursive function", {
"Could not build .*"
)
})

test_that("we can handle `with` expressions", {
f <- function(x) {
if (x < 0) x
else with(list(y = -1), f(x + y))
}

expect_true(can_loop_transform(f))
transformed_f <- loop_transform(f)

skip("this doesn't work because we cannot use `next` inside `with`.")
for (x in 1:5) {
expect_equal(f(x), transformed_f(x))
}

})

0 comments on commit 7ff5271

Please sign in to comment.