Skip to content

Commit e49187a

Browse files
committed
extract_side_effects and extract_occurrence can now work on a single object instead of a list
1 parent b04d078 commit e49187a

File tree

4 files changed

+28
-67
lines changed

4 files changed

+28
-67
lines changed

R/qenv-class.R

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@
1414
#' - `warnings` (`character`) the warnings output when evaluating the code element
1515
#' - `messages` (`character`) the messages output when evaluating the code element
1616
#' - `id (`integer`) random identifier of the code element to make sure uniqueness when joining
17-
#' - `side_effects` (`character`) names of objects that gets affected by this code call
18-
#' - `occurrence` (`character`) names of objects that appear in this call, separated by `<-`
19-
#' (objects on LHS of `<-` are affected by this line, and objects on RHS are affecting)
17+
#' - `dependency` (`character`) names of objects that appear in this call and gets affected by this call,
18+
#' separated by `<-` (objects on LHS of `<-` are affected by this line, and objects on RHS are affecting this line)
2019
#'
2120
#' @keywords internal
2221
#' @exportClass qenv

R/qenv-eval_code.R

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,9 @@ setMethod("eval_code", signature = c("qenv", "character"), function(object, code
8282

8383
pd <- utils::getParseData(current_call)
8484
pd <- normalize_pd(pd)
85-
calls_pd <- extract_calls(pd)
85+
call_pd <- extract_calls(pd)[[1]]
8686

87-
attr(current_code, "side_effects") <- extract_side_effects(calls_pd)[[1]]
88-
attr(current_code, "occurrence") <- extract_occurrence(calls_pd)[[1]]
87+
attr(current_code, "dependency") <- c(extract_side_effects(call_pd), extract_occurrence(call_pd))
8988
object@code <- c(object@code, list(current_code))
9089
}
9190

R/utils-get_code_dependency.R

Lines changed: 22 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ get_code_dependency <- function(code, names, check_names = TRUE) {
5353
}
5454
}
5555

56-
graph <- extract_code_graph(code)
56+
graph <- lapply(code, attr, "dependency")
5757
ind <- unlist(lapply(names, function(x) graph_parser(x, graph)))
5858

5959
lib_ind <- detect_libraries(calls_pd) # SHOULD BE REWRITTEN TO WORK ON code
@@ -182,52 +182,25 @@ sub_arrows <- function(call) {
182182

183183
# code_graph ----
184184

185-
#' Create object dependencies graph based on code
186-
#'
187-
#' Builds dependency graph that identifies dependencies between objects in code.
188-
#' Helps understand which objects depend on which.
189-
#'
190-
#' @param code (`list`) result of `get_code(eval_code(qenv()))`.
191-
#' List containing calls as characters in each element, extended with attributes `occurrence` and `side_effects`.
192-
#'
193-
#' @return
194-
#' A list (of length of input `code`) where each element represents one call.
195-
#' Each element is a character vector listing names of objects that depend on this call
196-
#' and names of objects that this call depends on.
197-
#' Dependencies are listed after the `"<-"` string, e.g. `c("a", "<-", "b", "c")` means that in this call object `a`
198-
#' depends on objects `b` and `c`.
199-
#' If a call is tagged with `@linksto a`, then object `a` is understood to depend on that call.
200-
#'
201-
#' @keywords internal
202-
#' @noRd
203-
extract_code_graph <- function(code) {
204-
cooccurrence <- lapply(code, attr, "occurrence")
205-
206-
side_effects <- lapply(code, attr, "side_effects")
207-
208-
mapply(c, side_effects, cooccurrence, SIMPLIFY = FALSE)
209-
}
210-
211185
#' Extract object occurrence
212186
#'
213-
#' Extracts objects occurrence within calls passed by `calls_pd`.
187+
#' Extracts objects occurrence within calls passed by `pd`.
214188
#' Also detects which objects depend on which within a call.
215189
#'
216-
#' @param calls_pd `list` of `data.frame`s;
217-
#' result of `utils::getParseData()` split into subsets representing individual calls;
190+
#' @param pd `data.frame`;
191+
#' one of the results of `utils::getParseData()` split into subsets representing individual calls;
218192
#' created by `extract_calls()` function
219193
#'
220194
#' @return
221-
#' A list (of length of input `calls_pd`) where each element represents one call.
222-
#' Each element is a character vector listing names of objects that depend on this call
195+
#' A character vector listing names of objects that depend on this call
223196
#' and names of objects that this call depends on.
224197
#' Dependencies are listed after the `"<-"` string, e.g. `c("a", "<-", "b", "c")` means that in this call object `a`
225198
#' depends on objects `b` and `c`.
226199
#' If a call is tagged with `@linksto a`, then object `a` is understood to depend on that call.
227200
#'
228201
#' @keywords internal
229202
#' @noRd
230-
extract_occurrence <- function(calls_pd) {
203+
extract_occurrence <- function(pd) {
231204
is_in_function <- function(x) {
232205
# If an object is a function parameter,
233206
# then in calls_pd there is a `SYMBOL_FORMALS` entry for that object.
@@ -245,23 +218,21 @@ extract_occurrence <- function(calls_pd) {
245218
x$text[x$token == "SYMBOL" & x$id > id_start & x$id < id_end]
246219
}
247220
}
248-
lapply(
249-
calls_pd,
250-
function(call_pd) {
221+
251222
# Handle data(object)/data("object")/data(object, envir = ) independently.
252-
data_call <- find_call(call_pd, "data")
223+
data_call <- find_call(pd, "data")
253224
if (data_call) {
254-
sym <- call_pd[data_call + 1, "text"]
225+
sym <- pd[data_call + 1, "text"]
255226
return(c(gsub("^['\"]|['\"]$", "", sym), "<-"))
256227
}
257228
# Handle assign(x = ).
258-
assign_call <- find_call(call_pd, "assign")
229+
assign_call <- find_call(pd, "assign")
259230
if (assign_call) {
260231
# Check if parameters were named.
261232
# "','" is for unnamed parameters, where "SYMBOL_SUB" is for named.
262233
# "EQ_SUB" is for `=` appearing after the name of the named parameter.
263-
if (any(call_pd$token == "SYMBOL_SUB")) {
264-
params <- call_pd[call_pd$token %in% c("SYMBOL_SUB", "','", "EQ_SUB"), "text"]
234+
if (any(pd$token == "SYMBOL_SUB")) {
235+
params <- pd[pd$token %in% c("SYMBOL_SUB", "','", "EQ_SUB"), "text"]
265236
# Remove sequence of "=", ",".
266237
if (length(params > 1)) {
267238
remove <- integer(0)
@@ -286,12 +257,12 @@ extract_occurrence <- function(calls_pd) {
286257
# Object is the first entry after 'assign'.
287258
pos <- 1
288259
}
289-
sym <- call_pd[assign_call + pos, "text"]
260+
sym <- pd[assign_call + pos, "text"]
290261
return(c(gsub("^['\"]|['\"]$", "", sym), "<-"))
291262
}
292263

293264
# What occurs in a function body is not tracked.
294-
x <- call_pd[!is_in_function(call_pd), ]
265+
x <- pd[!is_in_function(pd), ]
295266
sym_cond <- which(x$token %in% c("SPECIAL", "SYMBOL", "SYMBOL_FUNCTION_CALL"))
296267

297268
if (length(sym_cond) == 0) {
@@ -319,7 +290,7 @@ extract_occurrence <- function(calls_pd) {
319290

320291
after <- match(min(x$id[ass_cond]), sort(x$id[c(min(ass_cond), sym_cond)])) - 1
321292
ans <- append(x[sym_cond, "text"], "<-", after = max(1, after))
322-
roll <- in_parenthesis(call_pd)
293+
roll <- in_parenthesis(pd)
323294
if (length(roll)) {
324295
c(setdiff(ans, roll), roll)
325296
} else {
@@ -328,8 +299,6 @@ extract_occurrence <- function(calls_pd) {
328299

329300
### NOTE 2: What if there are 2 assignments: e.g. a <- b -> c.
330301
### NOTE 1: For cases like 'eval(expression(b <- b + 2))' removes 'eval(expression('.
331-
}
332-
)
333302
}
334303

335304
#' Extract side effects
@@ -342,24 +311,19 @@ extract_occurrence <- function(calls_pd) {
342311
#' With this tag a complete object dependency structure can be established.
343312
#' Read more about side effects and the usage of `@linksto` tag in [`get_code_dependencies()`] function.
344313
#'
345-
#' @param calls_pd `list` of `data.frame`s;
346-
#' result of `utils::getParseData()` split into subsets representing individual calls;
314+
#' @param pd `data.frame`;
315+
#' one of the results of `utils::getParseData()` split into subsets representing individual calls;
347316
#' created by `extract_calls()` function
348317
#'
349318
#' @return
350-
#' A list of length equal to that of `calls_pd`, where each element is a character vector of names of objects
351-
#' depending a call tagged with `@linksto` in a corresponding element of `calls_pd`.
319+
#' A character vector of names of objects
320+
#' depending a call tagged with `@linksto` in a corresponding element of `pd`.
352321
#'
353322
#' @keywords internal
354323
#' @noRd
355-
extract_side_effects <- function(calls_pd) {
356-
lapply(
357-
calls_pd,
358-
function(x) {
359-
linksto <- grep("@linksto", x[x$token == "COMMENT", "text"], value = TRUE)
360-
unlist(strsplit(sub("\\s*#\\s*@linksto\\s+", "", linksto), "\\s+"))
361-
}
362-
)
324+
extract_side_effects <- function(pd) {
325+
linksto <- grep("@linksto", pd[pd$token == "COMMENT", "text"], value = TRUE)
326+
unlist(strsplit(sub("\\s*#\\s*@linksto\\s+", "", linksto), "\\s+"))
363327
}
364328

365329
# graph_parser ----

man/qenv-class.Rd

Lines changed: 2 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)