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

Allow parenthesis and backslash characters inside default values #977

Merged
merged 4 commits into from Jul 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions inst/unitTests/cpp/attributes.cpp
Expand Up @@ -20,3 +20,18 @@ std::string parse_declaration_test(std::string msg) {

// [[Rcpp::export]]
std::string parse_declaration_test(std::string msg = "Parse function declaration");

// [[Rcpp::export]]
std::string parse_default_values_with_str_parenthesis(const char* a = "(", const char* b= ")", std::string msg = "Parse function header with parenthis inside default string values.") {
return msg;
}

// [[Rcpp::export]]
std::string parse_default_values_with_chr_parenthesis(char a = '(', char b= ')', std::string msg = "Parse function header with parenthis inside default char values.") {
return msg;
}

// [[Rcpp::export]]
std::string parse_default_values_with_chr_backslash(char a = '\\', std::string msg = "Parse function header with backslash inside default char values.") {
return msg;
}
12 changes: 12 additions & 0 deletions inst/unitTests/runit.attributes.R
Expand Up @@ -32,6 +32,18 @@ if (.runThisTest) {
parse_declaration_test(),
"Parse function declaration"
)
checkEquals(
parse_default_values_with_str_parenthesis(),
"Parse function header with parenthis inside default string values."
)
checkEquals(
parse_default_values_with_chr_parenthesis(),
"Parse function header with parenthis inside default char values."
)
checkEquals(
parse_default_values_with_chr_backslash(),
"Parse function header with backslash inside default char values."
)
}

}
45 changes: 30 additions & 15 deletions src/attributes.cpp
Expand Up @@ -1165,7 +1165,7 @@ namespace attributes {

// Now read into a list of strings (which we can pass to regexec)
// First read into a std::deque (which will handle lots of append
// operations efficiently) then copy into an R chracter vector
// operations efficiently) then copy into an R character vector
std::deque<std::string> lines;
readLines(buffer, &lines);
lines_ = Rcpp::wrap(lines);
Expand Down Expand Up @@ -1590,27 +1590,44 @@ namespace attributes {

int templateCount = 0;
int parenCount = 0;
bool insideQuotes = false;
std::string currentArg;
std::vector<std::string> args;
char prevChar = 0;
for (std::string::const_iterator
it = argText.begin(); it != argText.end(); ++it) {
char ch = *it;
char quote = 0;
bool escaped = false;
typedef std::string::const_iterator it_t;
for (it_t it = argText.begin(); it != argText.end(); ++it) {

if (ch == '"' && prevChar != '\\') {
insideQuotes = !insideQuotes;
}
// Store current character
char ch = *it;

if ((ch == ',') &&
// Ignore quoted strings and character values in single quotes
if ( ! quote && (ch == '"' || ch == '\''))
quote = ch;
else if (quote && ch == quote && ! escaped)
quote = 0;

// Escaped character inside quotes
if (escaped)
escaped = false;
else if (quote && ch == '\\')
escaped = true;

// Detect end of argument declaration
if ( ! quote &&
(ch == ',') &&
(templateCount == 0) &&
(parenCount == 0) &&
!insideQuotes) {
(parenCount == 0)) {
args.push_back(currentArg);
currentArg.clear();
continue;
} else {
}

// Append current character if not a space at start
if ( ! currentArg.empty() || ch != ' ')
currentArg.push_back(ch);

// Count use of potentially enclosed brackets
if ( ! quote) {
switch(ch) {
case '<':
templateCount++;
Expand All @@ -1626,8 +1643,6 @@ namespace attributes {
break; // #nocov
}
}

prevChar = ch;
}

if (!currentArg.empty())
Expand Down