Commit 526f42ab authored by Radford Neal's avatar Radford Neal

implement git add mods-dir and ! operators

parent d4e1a83b
......@@ -6,18 +6,23 @@
\encoding{UTF-8}
\section{CHANGES IN VERSION RELEASED 2018-08-23}{
\section{CHANGES IN VERSION RELEASED 2018-10-08}{
\subsection{INTRODUCTION}{
\itemize{
\item This release has many significant performance improvements.
It also has some feature changes, including some from later R
Core versions, and some bug fixes. One notable new feature is
It also has some new or changed features, including some from
later R Core versions, and some bug fixes.
\item One notable change is
that when code is read with \code{source}, or done with \code{Rscript},
or parsed from text strings or a file, an error is no longer produced
when an \code{else} at the top level appears at the beginning
of a line. See below for more details.
\item New binary operators \code{!!} and \code{!} have been introduced
as more concise ways of writing \code{paste} and \code{paste0}.
\item With the performance improvements in this release, it is
generally no longer desirable to use the bytecode compiler.
Defaults during configuration and use have therefore been
......@@ -254,6 +259,10 @@
on a new line, since in that context checking whether an \code{else}
is on the next line would require waiting for the user to input a
line which they may not intend to enter.
\item Character pasting operations can now be written more concisely using
new binary operators \code{!} and \code{!!}, with \code{a !! b}
equivalent to \code{paste(a,b)} and \code{a ! b} equivalent
to \code{paste0(a,b)}.
\item The \code{along}, \code{across}, and \code{down} forms of
the \code{for} statement (introduced in pqR-2016-06-24 and
pqR-2016-10-05) now set the loop variable(s) to the
......
Implements the new binary operators !! and ! as concise ways of
calling paste and paste0.
......@@ -157,6 +157,7 @@ extern0 SEXP R_And2Symbol; /* "&&" */
extern0 SEXP R_OrSymbol; /* "|" */
extern0 SEXP R_Or2Symbol; /* "||" */
extern0 SEXP R_NotSymbol; /* "!" */
extern0 SEXP R_BangBangSymbol; /* "!!" */
extern0 SEXP R_TildeSymbol; /* "~" */
extern0 SEXP R_QuerySymbol; /* "?" */
extern0 SEXP R_ColonAssignSymbol; /* ":=" */
......
......@@ -110,6 +110,7 @@ SEXP do_machine(SEXP, SEXP, SEXP, SEXP);
SEXP do_not(SEXP, SEXP, SEXP, SEXP, int);
SEXP do_pack(SEXP, SEXP, SEXP, SEXP);
SEXP do_pause(SEXP, SEXP, SEXP, SEXP);
SEXP do_paste_bang(SEXP, SEXP, SEXP, SEXP);
SEXP do_printdf(SEXP, SEXP, SEXP, SEXP);
SEXP do_restoreb(SEXP, SEXP, SEXP, SEXP);
SEXP do_rownames(SEXP, SEXP, SEXP, SEXP);
......
......@@ -19,6 +19,10 @@ paste <- function (..., sep = " ", collapse = NULL)
paste0 <- function(..., collapse = NULL)
.Internal(paste("",collapse,...))
`!!` <- function (e1, e2)
.Internal(paste(" ",NULL,e1,e2))
##=== Could we extend paste(.) to (optionally) accept a
## 2-vector for collapse ? With the following functionality
......
......@@ -24,7 +24,8 @@ isTRUE(x)
\alias{Logic}
\alias{isTRUE}
\description{
These operators act on logical and number-like vectors.
These operators act on logical and number-like vectors. For the
binary version of \code{!}, see \code{\link{paste0}}.
}
\arguments{
\item{x, y}{logical or \sQuote{number-like} vectors (i.e., of type
......@@ -79,7 +80,8 @@ isTRUE(x)
For \code{!}, the result is a logical or raw vector of the same
length as \code{x}. If no coercion is done, all attributes are
preserved; if \code{x} is coerced to logical, names, dims, and
dimnames (but not other attributes) are copied from \code{x}.
dimnames (but not other attributes) are copied from \code{x}. Note
that \code{!} is also a binary operator (see \code{\link{paste0}}).
For \code{|}, \code{&} and \code{xor},
elements of shorter vectors are recycled as necessary (with a
......
......@@ -24,9 +24,10 @@
\code{*} \code{/}\tab multiply, divide\cr
\code{+} \code{-}\tab (binary) add, subtract\cr
\code{..}\tab upward sequence operator (no ordering)\cr
\code{!} \code{!!}\tab (binary) string concatenation\cr
\code{<} \code{>} \code{<=} \code{>=} \code{==} \code{!=}\tab
ordering and comparison (no ordering)\cr
\code{!}\tab negation\cr
\code{!}\tab (unary) negation \cr
\code{&} \code{&&}\tab and\cr
\code{|} \code{||}\tab or\cr
\code{~}\tab (unary and binary) as in formulae\cr
......
% File src/library/base/man/paste.Rd
% Part of the R package, http://www.R-project.org
% Copyright 1995-2011 R Core Team
% Modifications for pqR Copyright (c) 2018 Radford M. Neal.
% Distributed under GPL 2 or later
\name{paste}
......@@ -9,11 +10,16 @@
\usage{
paste (\dots, sep = " ", collapse = NULL)
paste0(\dots, collapse = NULL)
e1 !! e2
e1 ! e2
}
\alias{paste}
\alias{paste0}
\alias{!!}
\arguments{
\item{\dots}{one or more \R objects, to be converted to character vectors.}
\item{e1, e2}{two \R objects, to be converted to character vectors.}
\item{sep}{a character string to separate the terms. Not
\code{\link{NA_character_}}.}
\item{collapse}{an optional character string to separate the results. Not
......@@ -41,6 +47,11 @@ paste0(\dots, collapse = NULL)
If a value is specified for \code{collapse}, the values in the result
are then concatenated into a single string, with the elements being
separated by the value of \code{collapse}.
\code{e1 !! e2} is a short form for \code{paste(e1,e2)}, and
\code{e1 ! e2} is a short form for \code{paste0(e1,e2)}. Both
of these operators are left-associate with precedence just above
relational operators (see \link{Syntax}).
}
\value{
A character vector of the concatenated values. This will be of length
......@@ -76,6 +87,10 @@ paste0(\dots, collapse = NULL)
\sQuote{\link{plotmath}} for the use of \code{paste} in plot annotation.
}
\examples{
"Hello" ! "World" # has no space between words
"Hello" !! "World" # has a space between words
paste("Hello","World",sep="_") # has _ between words
paste(1:12) # same as as.character(1:12)
paste("A", 1:6, sep = "")
stopifnot(identical(paste ("A", 1:6, sep = ""),
......
......@@ -1106,6 +1106,8 @@ static void deparse2buff(SEXP s, LocalParseData *d)
|| op == R_And2Symbol
|| op == R_Or2Symbol
|| op == R_TildeSymbol
|| op == R_NotSymbol
|| op == R_BangBangSymbol
|| op == R_EqSymbol
|| op == R_NeSymbol
|| op == R_LtSymbol
......
......@@ -4035,16 +4035,19 @@ static SEXP do_fast_not(SEXP call, SEXP op, SEXP arg, SEXP env, int variant)
return x;
}
SEXP attribute_hidden do_not(SEXP call, SEXP op, SEXP args, SEXP env,
int variant)
SEXP attribute_hidden do_not (SEXP call, SEXP op, SEXP args, SEXP env,
int variant)
{
if (CDR(args) != R_NilValue) /* more than one arg, so paste, not not */
return do_paste_bang (call, op, args, env);
SEXP ans;
if (DispatchGroup("Ops", call, op, args, env, &ans)) {
return ans;
}
if (args == R_NilValue || CDR(args) != R_NilValue)
if (args == R_NilValue)
checkArity(op,args); /* to report the error */
return do_fast_not (call, op, CAR(args), env, variant);
......
......@@ -408,6 +408,7 @@ static void SymbolShortcuts(void)
R_DivSymbol = install("/");
R_ExptSymbol = install("^");
R_Expt2Symbol = install("**");
R_BangBangSymbol = install("!!");
R_EqSymbol = install("==");
R_NeSymbol = install("!=");
R_LtSymbol = install("<");
......
......@@ -283,12 +283,13 @@ cr :
ps->ParseContext (later copied to R_ParseContext).
The get_next_token function obtains the next token, calling xxgetc
as required, and returning 1 if end of file is encountered immediately.
Its argument is 1 if a symbol is not expected (allowing ".." to be seen),
though it will get a symbol anyway, as long as it doesn't start with "..".
The convention for get_next_token is that a "lookahead" token after
what has been parsed so far is normally present (the opposite of the
convention for xxgetc). */
as required, and returning 1 if end of file is encountered
immediately. Its argument is 1 if a symbol or unary operator is
not expected (allowing ".." and "!!" to be seen), though it will
get a symbol or unary op anyway, as long as it doesn't start with
".." and isn't "!". The convention for get_next_token is that a
"lookahead" token after what has been parsed so far is normally
present (the opposite of the convention for xxgetc). */
static int xxgetc(void); /* Return next input character, or EOF */
......@@ -314,7 +315,7 @@ enum token_type {
GT, GE, LT, LE, EQ,
NE, AND, OR, AND2, OR2,
NS_GET, NS_GET_INT, EXPT2, SPECIAL, COLON_ASSIGN,
DOTDOT,
DOTDOT, BANGBANG,
};
/* Names for tokens with codes >= 256. These must correspond in order
......@@ -327,8 +328,8 @@ static const char *const token_name[] = {
"'else'", "'while'", "'next'", "'break'", "'repeat'",
"'>'", "'>='", "'<'", "'<='", "'=='",
"'!='", "'&'", "'|'", "'&&'", "'||'",
"'::'", "':::'", "**", "SPECIAL", "':='",
".."
"'::'", "':::'", "'**'", "SPECIAL", "':='",
"'..'", "'!!'"
};
#define NUM_TRANSLATED 7 /* Number above (at front) that are translated */
......@@ -354,7 +355,7 @@ static const char *const pdata_token_name[] = {
"GT", "GE", "LT", "LE", "EQ",
"NE", "AND", "OR", "AND2", "OR2",
"NS_GET", "NS_GET_INT", "^", "SPECIAL", "COLON_ASSIGN",
"DOTDOT"
"DOTDOT", "BANGBANG"
};
......@@ -984,7 +985,7 @@ static void error_msg(const char *s)
} while (0)
/* Version of EXPECT that scans the next token with no_symbol set. */
/* Version of EXPECT that scans the next token with no_sym_un set. */
#define EXPECT_NO_SYMBOL_AFTER(tk) \
do { \
......@@ -1085,7 +1086,9 @@ static struct { SEXP *sym_ptr; int prec; } binary_prec_tbl[] =
{ &R_DivSymbol, /* / */ 0xa1 },
{ &R_AddSymbol, /* + */ 0x91 },
{ &R_SubSymbol, /* - */ 0x91 },
{ &R_DotDotSymbol, /* .. */ 0x84 },
{ &R_DotDotSymbol, /* .. */ 0x88 },
{ &R_NotSymbol, /* ! */ 0x85 },
{ &R_BangBangSymbol, /* !! */ 0x85 },
{ &R_EqSymbol, /* == */ 0x80 },
{ &R_NeSymbol, /* != */ 0x80 },
{ &R_LtSymbol, /* < */ 0x80 },
......@@ -1481,9 +1484,9 @@ static SEXP parse_sublist (int flags)
be parenthesized, but `(`(x) is not, even though they produce the same
expression. If 'paren' is the C NULL pointer, this information isn't stored.
The token after the expression is scanned with no_symbol set to 1, since
symbols are not allowed in that context, and we wish the .. operator
to be recognized.
The token after the expression is scanned with no_sym_un set to 1,
since symbols and unary operators are not allowed in that context,
and we wish the .. and !! operators to be recognized.
An attempt is made to make the last operand of an operator be a constant
object. */
......@@ -3321,14 +3324,14 @@ static int nextchar(int expect)
the token code (or ERROR if the next token is malformed). Will also
set next_token_val to an associated SEXP (R_NilValue if none).
If no_symbol is non-zero, symbols are not expected, which therefore
If no_sym_un is non-zero, symbols are not expected, which therefore
allows the .. operator to be recognized. (But no error is signaled
here if a symbol is seen.)
The character after the token may have been looked at, but if so xxungetc
will have been called to put it back. */
static int token (int c, int no_symbol)
static int token (int c, int no_sym_un)
{
wchar_t wc;
......@@ -3360,10 +3363,10 @@ static int token (int c, int no_symbol)
if (c == '%')
return SpecialValue(c);
/* The .. operator. Only recognized if no_symbol is true (and if
/* The .. operator. Only recognized if no_sym_un is true (and if
parse_dotdot is enabled). */
if (ps->parse_dotdot && no_symbol && c == '.' && nextchar('.')) {
if (ps->parse_dotdot && no_sym_un && c == '.' && nextchar('.')) {
strcpy(yytext,"..");
ps->next_token_val = R_DotDotSymbol;
return DOTDOT;
......@@ -3432,6 +3435,10 @@ static int token (int c, int no_symbol)
ps->next_token_val = R_NeSymbol;
return NE;
}
if (no_sym_un && nextchar('!')) {
ps->next_token_val = R_BangBangSymbol;
return BANGBANG;
}
ps->next_token_val = R_NotSymbol;
return '!';
case '=':
......@@ -3536,9 +3543,10 @@ static int token (int c, int no_symbol)
to 1 when returning END_OF_INPUT or '\n', regardless of
whether a newline was actually present before.
If no_symbol is non-zero, symbols are not expected, which therefore
allows the .. operator to be recognized. (But no error is signaled
here if a symbol is seen.)
If no_sym_un is non-zero, symbols and unary operators are not
expected, which therefore allows the .. and !! operators to be
recognized. (But no error is signaled here if a symbol or unary
operator is seen anyway.)
Returns 0 if end of file was immediately encountered, with no
whitespace before, and 1 if not (even when END_OF_INPUT is the
......@@ -3548,7 +3556,7 @@ static int token (int c, int no_symbol)
via the ps->sr->TokenValProt index, but must be protected by the
caller if it will be used after the following token is obtained. */
static int get_next_token(int no_symbol)
static int get_next_token(int no_sym_un)
{
int c, val;
......@@ -3570,7 +3578,7 @@ static int get_next_token(int no_symbol)
ps->token_loc.first_byte = ps->sr->xxbyteno;
ps->token_loc.first_parsed = ps->sr->xxparseno;
ps->next_token = token(c,no_symbol);
ps->next_token = token(c,no_sym_un);
REPROTECT (ps->next_token_val, ps->sr->TokenValProt);
......
......@@ -818,6 +818,19 @@ static SEXP do_formatinfo(SEXP call, SEXP op, SEXP args, SEXP env)
return x;
}
/* Binary ! operator. */
SEXP do_paste_bang(SEXP call, SEXP op, SEXP args, SEXP env)
{
SEXP args2 = CONS (R_BlankScalarString, CONS (R_NilValue, args));
PROTECT(args2);
SEXP res = do_paste (call, op, args2, env);
UNPROTECT(1);
return res;
}
/* FUNTAB entries defined in this source file. See names.c for documentation. */
attribute_hidden FUNTAB R_FunTab_paste[] =
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment