Skip to content

Commit ec214d0

Browse files
authored
Merge pull request #977 from pkrog/allow_parenthesis_characters_inside_default_values
Allow parenthesis and backslash characters inside default values
2 parents d04eae8 + 798ebb8 commit ec214d0

File tree

3 files changed

+57
-15
lines changed

3 files changed

+57
-15
lines changed

inst/unitTests/cpp/attributes.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,18 @@ std::string parse_declaration_test(std::string msg) {
2020

2121
// [[Rcpp::export]]
2222
std::string parse_declaration_test(std::string msg = "Parse function declaration");
23+
24+
// [[Rcpp::export]]
25+
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.") {
26+
return msg;
27+
}
28+
29+
// [[Rcpp::export]]
30+
std::string parse_default_values_with_chr_parenthesis(char a = '(', char b= ')', std::string msg = "Parse function header with parenthis inside default char values.") {
31+
return msg;
32+
}
33+
34+
// [[Rcpp::export]]
35+
std::string parse_default_values_with_chr_backslash(char a = '\\', std::string msg = "Parse function header with backslash inside default char values.") {
36+
return msg;
37+
}

inst/unitTests/runit.attributes.R

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,18 @@ if (.runThisTest) {
3232
parse_declaration_test(),
3333
"Parse function declaration"
3434
)
35+
checkEquals(
36+
parse_default_values_with_str_parenthesis(),
37+
"Parse function header with parenthis inside default string values."
38+
)
39+
checkEquals(
40+
parse_default_values_with_chr_parenthesis(),
41+
"Parse function header with parenthis inside default char values."
42+
)
43+
checkEquals(
44+
parse_default_values_with_chr_backslash(),
45+
"Parse function header with backslash inside default char values."
46+
)
3547
}
3648

3749
}

src/attributes.cpp

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,7 +1165,7 @@ namespace attributes {
11651165

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

15911591
int templateCount = 0;
15921592
int parenCount = 0;
1593-
bool insideQuotes = false;
15941593
std::string currentArg;
15951594
std::vector<std::string> args;
1596-
char prevChar = 0;
1597-
for (std::string::const_iterator
1598-
it = argText.begin(); it != argText.end(); ++it) {
1599-
char ch = *it;
1595+
char quote = 0;
1596+
bool escaped = false;
1597+
typedef std::string::const_iterator it_t;
1598+
for (it_t it = argText.begin(); it != argText.end(); ++it) {
16001599

1601-
if (ch == '"' && prevChar != '\\') {
1602-
insideQuotes = !insideQuotes;
1603-
}
1600+
// Store current character
1601+
char ch = *it;
16041602

1605-
if ((ch == ',') &&
1603+
// Ignore quoted strings and character values in single quotes
1604+
if ( ! quote && (ch == '"' || ch == '\''))
1605+
quote = ch;
1606+
else if (quote && ch == quote && ! escaped)
1607+
quote = 0;
1608+
1609+
// Escaped character inside quotes
1610+
if (escaped)
1611+
escaped = false;
1612+
else if (quote && ch == '\\')
1613+
escaped = true;
1614+
1615+
// Detect end of argument declaration
1616+
if ( ! quote &&
1617+
(ch == ',') &&
16061618
(templateCount == 0) &&
1607-
(parenCount == 0) &&
1608-
!insideQuotes) {
1619+
(parenCount == 0)) {
16091620
args.push_back(currentArg);
16101621
currentArg.clear();
16111622
continue;
1612-
} else {
1623+
}
1624+
1625+
// Append current character if not a space at start
1626+
if ( ! currentArg.empty() || ch != ' ')
16131627
currentArg.push_back(ch);
1628+
1629+
// Count use of potentially enclosed brackets
1630+
if ( ! quote) {
16141631
switch(ch) {
16151632
case '<':
16161633
templateCount++;
@@ -1626,8 +1643,6 @@ namespace attributes {
16261643
break; // #nocov
16271644
}
16281645
}
1629-
1630-
prevChar = ch;
16311646
}
16321647

16331648
if (!currentArg.empty())

0 commit comments

Comments
 (0)