Skip to content

Commit 4788f2e

Browse files
Using environments to manage parser versions
1 parent 7a387a0 commit 4788f2e

File tree

5 files changed

+122
-12
lines changed

5 files changed

+122
-12
lines changed

DESCRIPTION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Collate:
4040
'communicate.R'
4141
'compat-dplyr.R'
4242
'compat-tidyr.R'
43+
'environments.R'
4344
'expr-is.R'
4445
'indent.R'
4546
'initialize.R'

R/environments.R

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#' Work with parser versions
2+
#'
3+
#' The structure of the parse data affects many operations in styler. There was
4+
#' unexpected behaviour of the parser that styler was initially designed to work
5+
#' around. Examples are [#187](https://github.com/r-lib/styler/issues/187),
6+
#' [#216](https://github.com/r-lib/styler/issues/216),
7+
#' [#100](https://github.com/r-lib/styler/issues/100) and others. With
8+
#' [#419](https://github.com/r-lib/styler/issues/419), the structrure of the parse
9+
#' data changes and we need to dispatch for older versions. As it is inconvenient
10+
#' to pass a parser version down in the call stack in various places, the
11+
#' environment `env_current` is used to store the current version *globally*
12+
#' but internally.
13+
#'
14+
#' We version the parser as follows:
15+
#'
16+
#' * version 1: Before fix mentioned in #419.
17+
#' * version 2: After #419.
18+
#'
19+
#'The following utilities are available:
20+
#'
21+
#' * `parser_version_set()` sets the parser version in the environment
22+
#' `env_current`.
23+
#' * `parser_version_get()` retrieves the parser version from the
24+
#' environment `env_current`.
25+
#' * `parser_version_find()` determines the version of the parser from parse
26+
#' data. This does not necessarily mean that the version found is the
27+
#' actual version, but it *behaves* like it. For example, code that does not
28+
#' contain `EQ_ASSIGN` is parsed the same way with version 1 and 2. If the
29+
#' behaviour is identical, the version is set to 1.
30+
#' @param version The version of the parser to be used.
31+
#' @param pd A parse table such as the output from
32+
#' `utils::getParseData(parse(text = text))`.
33+
#' @keywords internal
34+
parser_version_set <- function(version) {
35+
env_current$parser_version <- version
36+
}
37+
38+
#' @rdname parser_version_set
39+
parser_version_get <- function() {
40+
env_current$parser_version
41+
}
42+
43+
#' @rdname parser_version_set
44+
parser_version_find <- function(pd) {
45+
ifelse(any(pd$token == "equal_assign"), 2, 1)
46+
}
47+
48+
49+
50+
env_current <- rlang::new_environment(parent = rlang::empty_env())

R/parse.R

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,10 @@ get_parse_data <- function(text, include_text = TRUE, ...) {
9191
# avoid https://bugs.r-project.org/bugzilla3/show_bug.cgi?id=16041
9292
parse_safely(text, keep.source = TRUE)
9393
parsed <- parse_safely(text, keep.source = TRUE)
94-
as_tibble(utils::getParseData(parsed, includeText = include_text)) %>%
94+
pd <- as_tibble(utils::getParseData(parsed, includeText = include_text)) %>%
9595
add_id_and_short()
96+
parser_version_set(parser_version_find(pd))
97+
pd
9698
}
9799

98100
#' Add column `pos_id` and `short`

R/relevel.R

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ flatten_operators <- function(pd_nested) {
2626
#' @keywords internal
2727
flatten_operators_one <- function(pd_nested) {
2828
pd_token_left <- c(special_token, math_token, "'$'")
29-
pd_token_right <- c(special_token, "LEFT_ASSIGN", "'+'", "'-'")
29+
pd_token_right <- c(
30+
special_token, "LEFT_ASSIGN", if (parser_version_get() > 1) "EQ_ASSIGN",
31+
"'+'", "'-'"
32+
)
3033
bound <- pd_nested %>%
3134
flatten_pd(pd_token_left, left = TRUE) %>%
3235
flatten_pd(pd_token_right, left = FALSE)
@@ -125,8 +128,13 @@ wrap_expr_in_expr <- function(pd) {
125128
#' )
126129
#' @keywords internal
127130
relocate_eq_assign <- function(pd) {
131+
if (parser_version_get() < 2) {
128132
pd %>%
129133
post_visit(c(relocate_eq_assign_nest))
134+
} else {
135+
pd
136+
}
137+
130138
}
131139

132140

@@ -152,17 +160,13 @@ relocate_eq_assign <- function(pd) {
152160
#' @importFrom rlang seq2
153161
#' @keywords internal
154162
relocate_eq_assign_nest <- function(pd) {
155-
if (any(pd$token == "equal_assign")) {
156-
pd
157-
} else {
158-
idx_eq_assign <- which(pd$token == "EQ_ASSIGN")
159-
if (length(idx_eq_assign) > 0) {
160-
block_id <- find_block_id(pd)
161-
blocks <- split(pd, block_id)
162-
pd <- map_dfr(blocks, relocate_eq_assign_one)
163-
}
164-
pd
163+
idx_eq_assign <- which(pd$token == "EQ_ASSIGN")
164+
if (length(idx_eq_assign) > 0) {
165+
block_id <- find_block_id(pd)
166+
blocks <- split(pd, block_id)
167+
pd <- map_dfr(blocks, relocate_eq_assign_one)
165168
}
169+
pd
166170
}
167171

168172
#' Find the block to which a token belongs

man/parser_version_set.Rd

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

0 commit comments

Comments
 (0)