Skip to content

Commit 5dad8f4

Browse files
author
maechler
committed
terms(<formula>, specials = "<non-syntactic>") now works
git-svn-id: https://svn.r-project.org/R/trunk@88066 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent bd7ef3f commit 5dad8f4

File tree

3 files changed

+40
-16
lines changed

3 files changed

+40
-16
lines changed

doc/NEWS.Rd

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
\subsection{BUG FIXES}{
5353
\itemize{
54-
\item Setting \code{\link{attributes}} on primitive functions is an
54+
\item Setting \code{attributes} on primitive functions is an
5555
error now; previously, it modified without copying, as noticed by
5656
\I{Henrik Bengtsson} on the R-devel mailing list.
5757
}
@@ -270,6 +270,9 @@
270270
\item \code{selectMethod(f, ..)} now keeps the function name if the
271271
function belongs to a group generic and the method is for the
272272
generic.
273+
274+
\item \code{terms(<formula>, specials = *)} now treats non-syntactic
275+
specials more gracefully, thanks to \I{Mikael Jagan}'s \PR{18568}.
273276
}
274277
}
275278

src/library/stats/src/model.c

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,35 +2092,36 @@ SEXP termsform(SEXP args)
20922092
/* If there are specials stick them in here */
20932093

20942094
if (specials != R_NilValue) {
2095-
R_xlen_t j;
2095+
int j; // R_xlen_t? but j < i which is int
20962096
const void *vmax = vmaxget();
20972097
int i = length(specials);
2098-
SEXP t;
2099-
PROTECT(v = allocList(i));
2100-
for (j = 0, t = v; j < i; j++, t = CDR(t)) {
2098+
SEXP t, t_ = PROTECT(allocList(i));
2099+
for (j = 0, t = t_; j < i; j++, t = CDR(t)) {
21012100
const char *ss = translateChar(STRING_ELT(specials, j));
21022101
SET_TAG(t, install(ss));
2103-
R_xlen_t n = (int) strlen(ss);
21042102
SETCAR(t, allocVector(INTSXP, 0));
21052103
R_xlen_t k = 0;
2106-
for (R_xlen_t l = 0; l < nvar; l++) {
2107-
if (!strncmp(CHAR(STRING_ELT(varnames, l)), ss, n))
2108-
if (CHAR(STRING_ELT(varnames, l))[n] == '(')
2109-
k++;
2104+
for (v = CDR(varlist); v != R_NilValue; v = CDR(v)) {
2105+
call = CAR(v);
2106+
if (TYPEOF(call) == LANGSXP && TYPEOF(CAR(call)) == SYMSXP &&
2107+
!strcmp(CHAR(PRINTNAME(CAR(call))), ss))
2108+
k++;
21102109
}
21112110
if (k > 0) {
21122111
SETCAR(t, allocVector(INTSXP, k));
21132112
k = 0;
2114-
for (int l = 0; l < nvar; l++) {
2115-
if (!strncmp(CHAR(STRING_ELT(varnames, l)), ss, n))
2116-
if (CHAR(STRING_ELT(varnames, l))[n] == '('){
2117-
INTEGER(CAR(t))[k++] = l+1;
2118-
}
2113+
int l = 1;
2114+
for (v = CDR(varlist); v != R_NilValue; v = CDR(v)) {
2115+
call = CAR(v);
2116+
if (TYPEOF(call) == LANGSXP && TYPEOF(CAR(call)) == SYMSXP &&
2117+
!strcmp(CHAR(PRINTNAME(CAR(call))), ss))
2118+
INTEGER(CAR(t))[k++] = l;
2119+
l++;
21192120
}
21202121
}
21212122
else SETCAR(t, R_NilValue);
21222123
}
2123-
SETCAR(a, v);
2124+
SETCAR(a, t_);
21242125
SET_TAG(a, install("specials"));
21252126
a = CDR(a);
21262127
UNPROTECT(1);

tests/reg-tests-1e.R

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1922,6 +1922,26 @@ stopifnot(identical(sum, msum), is.null(attributes(msum)))
19221922
## all 3 examples, the first a special case of the 2nd, did not error, but *modified* the base::sum primitive
19231923

19241924

1925+
## terms.formula(*, specials="<non-syntactic>") -- PR#18568
1926+
f1 <- y ~ x1 + `|`(x2, f)
1927+
t1 <- terms(f1, specials = "|")
1928+
(cs <- colSums(attr(t1, "factors")[attr(t1, "specials")[["|"]], , drop=FALSE]))
1929+
(drp <- which(as.logical(cs))) # 2
1930+
(dt1 <- drop.terms(t1, drp, keep.response = TRUE))
1931+
stopifnot(identical(attr(t1, "specials"), pairlist(`|` = 3L)),
1932+
inherits(dt1, "terms"), dt1 == (y ~ x1))
1933+
f3 <- y ~ x1 + (x2 | f) + (x3 | g)
1934+
t3 <- terms(f3, specials = "|")
1935+
str(t3)
1936+
dropx <- which(as.logical(colSums(attr(t3, "factors")[attr(t3, "specials")[["|"]], ])))
1937+
dt3 <- drop.terms(t3, dropx, keep.response = as.logical(attr(t3, "response")))
1938+
stopifnot(identical(attr(t3, "specials"),
1939+
pairlist(`|` = 3:4)),
1940+
dt3 == (y ~ x1))
1941+
## was unchanged y ~ x1 + (x2 | f) + (x3 | g)
1942+
1943+
1944+
19251945

19261946
## keep at end
19271947
rbind(last = proc.time() - .pt,

0 commit comments

Comments
 (0)