Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix deparsing of cflow bodies burried deep through LHS #13

Open
wants to merge 1 commit into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 40 additions & 14 deletions src/main/deparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ typedef struct {
Rboolean startline; /* = TRUE; */
int indent;
SEXP strvec;
int left;

DeparseBuffer buffer;

Expand Down Expand Up @@ -232,17 +233,28 @@ static SEXP deparse1WithCutoff(SEXP call, Rboolean abbrev, int cutoff,
SEXP svec;
int savedigits;
Rboolean need_ellipses = FALSE;
LocalParseData localData =
{/* linenumber */ 0,
0, 0, 0, /*startline = */TRUE, 0,
NULL,
/* DeparseBuffer= */ {NULL, 0, BUFSIZE},
DEFAULT_Cutoff, FALSE, 0, TRUE,
LocalParseData localData = {
.linenumber = 0,
.len = 0,
.incurly = 0,
.inlist = 0,
.startline = TRUE,
.indent = 0,
.strvec = NULL,
.left = 0,
.buffer = { NULL, 0, BUFSIZE },
.cutoff = DEFAULT_Cutoff,
.backtick = FALSE,
.opts = 0,
.sourceable = TRUE,
#ifdef longstring_WARN
FALSE,
.longstring = FALSE,
#endif
/* maxlines = */ INT_MAX,
/* active = */TRUE, 0, FALSE};
.maxlines = INT_MAX,
.active = TRUE,
.isS4 = 0,
.fnarg = FALSE
};
localData.cutoff = cutoff;
localData.backtick = backtick;
localData.opts = opts;
Expand Down Expand Up @@ -853,6 +865,11 @@ static void deparse2buff(SEXP s, LocalParseData *d)

d->fnarg = FALSE;

/* This flag should only be set when recursing through the LHS
of binary ops, so by default we reset to zero */
int prevLeft = d->left;
d->left = 0;

if (!d->active) return;

Rboolean hasS4_t = TYPEOF(s) == S4SXP;
Expand Down Expand Up @@ -1081,6 +1098,7 @@ static void deparse2buff(SEXP s, LocalParseData *d)
d->opts &= ~QUOTEEXPRESSIONS;
}
}

if (TYPEOF(op) == SYMSXP) {
int userbinop = 0;
if ((TYPEOF(SYMVALUE(op)) == BUILTINSXP) ||
Expand Down Expand Up @@ -1257,7 +1275,7 @@ static void deparse2buff(SEXP s, LocalParseData *d)
print2buff(" ", d);
print2buff(CHAR(PRINTNAME(op)), d); /* ASCII */
print2buff(" ", d);
if ((parens = needsparens(fop, CADR(s), 0)))
if ((parens = needsparens(fop, CADR(s), prevLeft)))
print2buff("(", d);
deparse2buff(CADR(s), d);
if (parens)
Expand All @@ -1278,7 +1296,7 @@ static void deparse2buff(SEXP s, LocalParseData *d)
isValidName(CHAR(STRING_ELT(CADR(s), 0))))
deparse2buff(STRING_ELT(CADR(s), 0), d);
else {
if ((parens = needsparens(fop, CADR(s), 0)))
if ((parens = needsparens(fop, CADR(s), prevLeft)))
print2buff("(", d);
deparse2buff(CADR(s), d);
if (parens)
Expand All @@ -1288,14 +1306,17 @@ static void deparse2buff(SEXP s, LocalParseData *d)
case PP_BINARY:
if ((parens = needsparens(fop, CAR(s), 1)))
print2buff("(", d);
d->left = 1;
deparse2buff(CAR(s), d);
d->left = 0;
if (parens)
print2buff(")", d);
print2buff(" ", d);
print2buff(CHAR(PRINTNAME(op)), d); /* ASCII */
print2buff(" ", d);
linebreak(&lbreak, d);
if ((parens = needsparens(fop, CADR(s), 0)))

if ((parens = needsparens(fop, CADR(s), prevLeft)))
print2buff("(", d);
deparse2buff(CADR(s), d);
if (parens)
Expand All @@ -1308,19 +1329,22 @@ static void deparse2buff(SEXP s, LocalParseData *d)
case PP_BINARY2: /* no space between op and args */
if ((parens = needsparens(fop, CAR(s), 1)))
print2buff("(", d);
d->left = 1;
deparse2buff(CAR(s), d);
d->left = 0;
if (parens)
print2buff(")", d);

print2buff(CHAR(PRINTNAME(op)), d); /* ASCII */
if ((parens = needsparens(fop, CADR(s), 0)))
if ((parens = needsparens(fop, CADR(s), prevLeft)))
print2buff("(", d);
deparse2buff(CADR(s), d);
if (parens)
print2buff(")", d);
break;
case PP_UNARY:
print2buff(CHAR(PRINTNAME(op)), d); /* ASCII */
if ((parens = needsparens(fop, CAR(s), 0)))
if ((parens = needsparens(fop, CAR(s), prevLeft)))
print2buff("(", d);
deparse2buff(CAR(s), d);
if (parens)
Expand Down Expand Up @@ -1448,6 +1472,8 @@ static void deparse2buff(SEXP s, LocalParseData *d)
d->sourceable = FALSE;
UNIMPLEMENTED_TYPE("deparse2buff", s);
}

d->left = prevLeft;
}


Expand Down
19 changes: 19 additions & 0 deletions tests/reg-tests-2.R
Original file line number Diff line number Diff line change
Expand Up @@ -3196,3 +3196,22 @@ stopifnot( identical(ddd, dd2) )
##cm <- summary(lm(c(0,0,0) ~ 1))$coefficients
cm <- cbind(Estimate = 0, SE = 0, t = NaN, "Pr(>|t|)" = NaN)
printCoefmat(cm) # NaN's were replaced by NA in R < 4.1.0


## deparse() wraps cflow bodies when deeply burried through a LHS (PR#18232)
##
## These didn't print the same before fix, the bquote() expression
## missed parentheses
quote(1 + (if (TRUE) 2) + 3)
bquote(1 + .(quote(if (TRUE) 2)) + 3)
##
bquote(1 + .(quote(if (TRUE) 2)) ^ 3)
##
## Other constructs cancel the LHS state so that the `if` call isn't
## wrapped here
bquote(1 + .(quote(f(if (TRUE) 2))) + 3)
bquote(1 + .(quote((2 + if (TRUE) 3))) + 4)
##
## cflow bodies are only wrapped if needed, there should be no
## parentheses here
quote(a <- if (TRUE) 1)
25 changes: 25 additions & 0 deletions tests/reg-tests-2.Rout.save
Original file line number Diff line number Diff line change
Expand Up @@ -8115,3 +8115,28 @@ mean of x
Estimate SE t Pr(>|t|)
[1,] 0 0 NaN NaN
>
>
> ## deparse() wraps cflow bodies when deeply burried through a LHS (PR#18232)
> ##
> ## These didn't print the same before fix, the bquote() expression
> ## missed parentheses
> quote(1 + (if (TRUE) 2) + 3)
1 + (if (TRUE) 2) + 3
> bquote(1 + .(quote(if (TRUE) 2)) + 3)
1 + (if (TRUE) 2) + 3
> ##
> bquote(1 + .(quote(if (TRUE) 2)) ^ 3)
1 + (if (TRUE) 2)^3
> ##
> ## Other constructs cancel the LHS state so that the `if` call isn't
> ## wrapped here
> bquote(1 + .(quote(f(if (TRUE) 2))) + 3)
1 + f(if (TRUE) 2) + 3
> bquote(1 + .(quote((2 + if (TRUE) 3))) + 4)
1 + (2 + if (TRUE) 3) + 4
> ##
> ## cflow bodies are only wrapped if needed, there should be no
> ## parentheses here
> quote(a <- if (TRUE) 1)
a <- if (TRUE) 1
>