@@ -181,10 +181,24 @@ parse_expr <- function(content, expr, env, level = 0L, srcref = attr(expr, "srcr
181
181
if (length(expr ) == 0L || is.symbol(expr )) {
182
182
return (env )
183
183
}
184
+ # We should handle base function specially as users may use base::fun form
185
+ # The reason that we only take care of `base` (not `utils`) is that only `base` calls can generate symbols
186
+ # Check if the lang is in base::fun form
187
+ is_base_call <- function (x ) {
188
+ length(x ) == 3L && as.character(x [[1L ]]) %in% c(" ::" , " :::" ) && as.character(x [[2L ]]) == " base"
189
+ }
190
+ # Be able to handle `pkg::name` case (note `::` is a function)
191
+ is_symbol <- function (x ) {
192
+ is.symbol(x ) || is_base_call(x )
193
+ }
194
+ # Handle `base` function specically by removing the `base::` prefix
195
+ fun_string <- function (x ) {
196
+ if (is_base_call(x )) as.character(x [[3L ]]) else as.character(x )
197
+ }
184
198
for (i in seq_along(expr )) {
185
199
e <- expr [[i ]]
186
- if (missing(e ) || ! is.call(e ) || ! is.symbol (e [[1L ]])) next
187
- f <- as.character (e [[1L ]])
200
+ if (missing(e ) || ! is.call(e ) || ! is_symbol (e [[1L ]])) next
201
+ f <- fun_string (e [[1L ]])
188
202
cur_srcref <- if (level == 0L ) srcref [[i ]] else srcref
189
203
if (f %in% c(" {" , " (" )) {
190
204
Recall(content , e [- 1L ], env , level + 1L , cur_srcref )
@@ -204,10 +218,53 @@ parse_expr <- function(content, expr, env, level = 0L, srcref = attr(expr, "srcr
204
218
Recall(content , e [[3L ]], env , level + 1L , cur_srcref )
205
219
} else if (f == " repeat" ) {
206
220
Recall(content , e [[2L ]], env , level + 1L , cur_srcref )
207
- } else if (f %in% c(" <-" , " =" ) && length(e ) == 3L && is.symbol(e [[2L ]])) {
208
- symbol <- as.character(e [[2L ]])
209
- value <- e [[3L ]]
210
- type <- get_expr_type(value )
221
+ } else if (f %in% c(" <-" , " =" , " delayedAssign" , " makeActiveBinding" , " assign" )) {
222
+ # to see the pos/env/assign.env of assigning functions is set or not
223
+ # if unset, it means using the default value, which is top-level
224
+ # if set, we should compare to a vector of known "top-level" candidates
225
+ is_top_level <- function (arg_env , ... ) {
226
+ if (is.null(arg_env )) return (TRUE )
227
+ default <- list (
228
+ quote(parent.frame(1 )), quote(parent.frame(1L )),
229
+ quote(environment()),
230
+ quote(.GlobalEnv ), quote(globalenv())
231
+ )
232
+ extra <- substitute(list (... ))[- 1L ]
233
+ top_level_envs <- c(default , as.list(extra ))
234
+ any(vapply(top_level_envs , identical , x = arg_env , FUN.VALUE = logical (1L )))
235
+ }
236
+
237
+ type <- NULL
238
+
239
+ if (f %in% c(" <-" , " =" )) {
240
+ if (length(e ) != 3L || ! is.symbol(e [[2L ]])) next
241
+ symbol <- as.character(e [[2L ]])
242
+ value <- e [[3L ]]
243
+ } else if (f == " delayedAssign" ) {
244
+ call <- match.call(base :: delayedAssign , as.call(e ))
245
+ if (! is.character(call $ x )) next
246
+ if (! is_top_level(call $ assign.env )) next
247
+ symbol <- call $ x
248
+ value <- call $ value
249
+ } else if (f == " assign" ) {
250
+ call <- match.call(base :: assign , as.call(e ))
251
+ if (! is.character(call $ x )) next
252
+ if (! is_top_level(call $ pos , - 1L , - 1 )) next # -1 is the default
253
+ if (! is_top_level(call $ envir )) next
254
+ symbol <- call $ x
255
+ value <- call $ value
256
+ } else if (f == " makeActiveBinding" ) {
257
+ call <- match.call(base :: makeActiveBinding , as.call(e ))
258
+ if (! is.character(call $ sym )) next
259
+ if (! is_top_level(call $ env )) next
260
+ symbol <- call $ sym
261
+ value <- call $ fun
262
+ type <- " variable"
263
+ }
264
+
265
+ if (is.null(type )) {
266
+ type <- get_expr_type(value )
267
+ }
211
268
212
269
env $ objects <- c(env $ objects , symbol )
213
270
0 commit comments