From 51a1a0a48544cdc91b9cca751094b005d3c5e742 Mon Sep 17 00:00:00 2001 From: Dawid Kaledkowski Date: Tue, 4 Feb 2025 07:38:59 +0100 Subject: [PATCH 1/3] Fix infinite loop --- NEWS.md | 4 ++++ R/utils-get_code_dependency.R | 18 ++++++++++-------- tests/testthat/test-qenv_get_code.R | 7 +++++++ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/NEWS.md b/NEWS.md index ef7f770a..4d426037 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,9 @@ # teal.code 0.6.0.9001 +### Bug fixes + +* Fix an infinite recursion happening when lhs contains two or more symbols occurring in the rhs of the same call. + # teal.code 0.6.0 ### Enhancements diff --git a/R/utils-get_code_dependency.R b/R/utils-get_code_dependency.R index c94fdb2b..a137eccb 100644 --- a/R/utils-get_code_dependency.R +++ b/R/utils-get_code_dependency.R @@ -364,6 +364,7 @@ extract_dependency <- function(parsed_code) { #' @keywords internal #' @noRd graph_parser <- function(x, graph) { + # x occurrences (lhs) occurrence <- vapply( graph, function(call) { ind <- match("<-", call, nomatch = length(call) + 1L) @@ -372,20 +373,21 @@ graph_parser <- function(x, graph) { logical(1) ) + # x-dependent objects (rhs) dependencies <- lapply(graph[occurrence], function(call) { ind <- match("<-", call, nomatch = 0L) call[(ind + 1L):length(call)] }) dependencies <- setdiff(unlist(dependencies), x) - if (length(dependencies) && any(occurrence)) { - dependency_ids <- lapply(dependencies, function(dependency) { - graph_parser(dependency, graph[1:max(which(occurrence))]) - }) - sort(unique(c(which(occurrence), unlist(dependency_ids)))) - } else { - which(occurrence) - } + dependency_occurrences <- lapply(dependencies, function(dependency) { + # track down dependencies and where they occur on the lhs in previous calls + last_x_occurrence <- max(which(occurrence)) + reduced_graph <- head(graph[seq_len(last_x_occurrence)], -1) + c(graph_parser(dependency, reduced_graph), last_x_occurrence) + }) + + sort(unique(c(which(occurrence), unlist(dependency_occurrences)))) } diff --git a/tests/testthat/test-qenv_get_code.R b/tests/testthat/test-qenv_get_code.R index cf06f0ca..87f740fc 100644 --- a/tests/testthat/test-qenv_get_code.R +++ b/tests/testthat/test-qenv_get_code.R @@ -951,3 +951,10 @@ testthat::test_that("original formatting and comments are preserved when express expr <- parse(text = code, keep.source = TRUE) testthat::expect_identical(get_code(eval_code(qenv(), expr)), code) }) + +testthat::test_that("extracting code doesn't fail when lhs contains two or more symbols occurring in lhs", { + code <- "l <- list(a = 1, b = 2) + class(l) <- c('new class', class(l))" # l depends on class and class depends on l + q <- eval_code(qenv(), code) + testthat::expect_silent(get_code(q, names = "l")) +}) From 21d125dc529ca0711c52b43dde8026bc4a02305d Mon Sep 17 00:00:00 2001 From: Dawid Kaledkowski Date: Tue, 4 Feb 2025 07:51:36 +0100 Subject: [PATCH 2/3] fix rcmdcheck --- R/utils-get_code_dependency.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/utils-get_code_dependency.R b/R/utils-get_code_dependency.R index a137eccb..15dd7153 100644 --- a/R/utils-get_code_dependency.R +++ b/R/utils-get_code_dependency.R @@ -383,7 +383,7 @@ graph_parser <- function(x, graph) { dependency_occurrences <- lapply(dependencies, function(dependency) { # track down dependencies and where they occur on the lhs in previous calls last_x_occurrence <- max(which(occurrence)) - reduced_graph <- head(graph[seq_len(last_x_occurrence)], -1) + reduced_graph <- utils::head(graph[seq_len(last_x_occurrence)], -1) c(graph_parser(dependency, reduced_graph), last_x_occurrence) }) From 5cb2a9557050ad963c1ece18e23b178d571e060d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ka=C5=82=C4=99dkowski?= Date: Tue, 4 Feb 2025 13:23:03 +0100 Subject: [PATCH 3/3] Update tests/testthat/test-qenv_get_code.R MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Aleksander Chlebowski <114988527+chlebowa@users.noreply.github.com> Signed-off-by: Dawid Kałędkowski --- tests/testthat/test-qenv_get_code.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test-qenv_get_code.R b/tests/testthat/test-qenv_get_code.R index 87f740fc..825d9769 100644 --- a/tests/testthat/test-qenv_get_code.R +++ b/tests/testthat/test-qenv_get_code.R @@ -952,7 +952,7 @@ testthat::test_that("original formatting and comments are preserved when express testthat::expect_identical(get_code(eval_code(qenv(), expr)), code) }) -testthat::test_that("extracting code doesn't fail when lhs contains two or more symbols occurring in lhs", { +testthat::test_that("extracting code doesn't fail when lhs contains two or more symbols occurring in rhs", { code <- "l <- list(a = 1, b = 2) class(l) <- c('new class', class(l))" # l depends on class and class depends on l q <- eval_code(qenv(), code)