futureverse / futureverse/globals
findGlobals(): Distinguish between functions and non-functions
- Dominant language
- R
- Stars
- 29
- Forks
- 3
- PR merge metrics
- No merged PRs in 30d
Description
Below is an example, where a local numeric variable `sum` is picked up by `globalsOf()`, despite the expression uses a function `sum()`.
```r
sum <- 42
expr <- quote( sum(1:10) )
names <- globals::findGlobals(expr)
print(names)
#> "{" "sum" ":"
objs <- globals::globalsOf(expr)
str(objs)
#> List of 3
#> $ { :.Primitive("{")
#> $ sum: num 42
#> $ : :.Primitive(":")
#> - attr(*, "where")=List of 3
#> ..$ { :
#> ..$ sum:
#> ..$ : :
#> - attr(*, "class")= chr [1:2] "Globals" "list"
```
Ideally, `globalsOf()` would pick up `base::sum()` instead. For that to happen, we need to refine `globals::findGlobals()` to record whether symbol `sum` refers to a function or not. That could be achieved by `findGlobals()` inspect the language object that `sum` is part of. For instance, from:
```
expr <- quote( sum(1:10) )
str(list(first = expr[[1]], class = class(expr), typeof = typeof(expr), length = length(expr)))
#> List of 4
#> $ first : symbol sum
#> $ class : chr "call"
#> $ typeof: chr "language"
#> $ length: int 2
expr <- quote( sum )
str(list(class = class(expr), typeof = typeof(expr), length = length(expr)))
#> List of 3
#> $ class : chr "name"
#> $ typeof: chr "symbol"
#> $ length: int 1
## But it's not that easy
expr <- quote( sum + 2 )
str(list(first = expr[[1]], class = class(expr), typeof = typeof(expr), length = length(expr)))
#> List of 4
$ first : symbol +
#> $ class : chr "call"
#> $ typeof: chr "language"
#> $ length: int 3
expr <- quote( -sum )
str(list(first = expr[[1]], class = class(expr), typeof = typeof(expr), length = length(expr)))
#> List of 4
$ first : symbol -
#> $ class : chr "call"
#> $ typeof: chr "language"
#> $ length: int 2
```
we see that we can infer when symbol `sum` is the name of a function call or not.
One could have `findGlobals(expr, annotate = TRUE)` return this information as well, e.g. as attributes. But, is that shoehorning the original design of **globals** to much, which is basically an enhancement of **codetools**? It would be worth investigating if there are better AST tools for what's trying to be achieved. OTH, the above improvement might be good enough for 99% of the use cases.
Contributor guide
Research direction
Start by reading the existing findGlobals() and globalsOf() entry points and tracing how symbols in quoted calls are classified. Compare function-position symbols with value-position symbols using the sum(), sum, sum + 2, and -sum examples from the issue. Done means the function call resolves to base::sum() without incorrectly treating a same-named local numeric variable as the global function.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- r
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100