Skip to content

Commit 8a451d2

Browse files
committed
Correct parsing of default values in fct parsing.
Now we can use parenthesis characters inside quoted strings for default values, without disturbing the arguments parser.
1 parent d04eae8 commit 8a451d2

File tree

3 files changed

+70
-26
lines changed

3 files changed

+70
-26
lines changed

inst/unitTests/cpp/attributes.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,13 @@ 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+
}

inst/unitTests/runit.attributes.R

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ 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+
)
3543
}
3644

3745
}

src/attributes.cpp

Lines changed: 52 additions & 26 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);
@@ -1420,6 +1420,7 @@ namespace attributes {
14201420

14211421
// Establish the text to parse for the signature
14221422
std::string signature = parseSignature(lineNumber);
1423+
std::cerr << "-------------------------------- SourceFileAttributesParser::parseFunction 10" << std::endl << signature << std::endl;
14231424
if (signature.empty()) {
14241425
rcppExportNoFunctionFoundWarning(lineNumber); // #nocov
14251426
return Function(); // #nocov
@@ -1429,6 +1430,7 @@ namespace attributes {
14291430
// (bail with an empty result if we can't find them)
14301431
std::string::size_type endParenLoc = signature.find_last_of(')');
14311432
std::string::size_type beginParenLoc = signature.find_first_of('(');
1433+
std::cerr << "-------------------------------- SourceFileAttributesParser::parseFunction 20" << std::endl << beginParenLoc << std::endl << endParenLoc << std::endl;
14321434
if (endParenLoc == std::string::npos ||
14331435
beginParenLoc == std::string::npos ||
14341436
endParenLoc < beginParenLoc) {
@@ -1481,6 +1483,8 @@ namespace attributes {
14811483
std::string argsText = signature.substr(beginParenLoc + 1,
14821484
endParenLoc-beginParenLoc-1);
14831485
std::vector<std::string> args = parseArguments(argsText);
1486+
for(auto arg: args)
1487+
std::cerr << "-------------------------------- SourceFileAttributesParser::parseFunction 30" << std::endl << arg << std::endl;
14841488
for (std::vector<std::string>::const_iterator it =
14851489
args.begin(); it != args.end(); ++it) {
14861490

@@ -1588,44 +1592,66 @@ namespace attributes {
15881592
std::vector<std::string> SourceFileAttributesParser::parseArguments(
15891593
const std::string& argText) {
15901594

1595+
std::cerr << "-------------------------------- SourceFileAttributesParser::SourceFileAttributesParser::parseArguments 1" << std::endl << argText << std::endl;
15911596
int templateCount = 0;
15921597
int parenCount = 0;
1593-
bool insideQuotes = false;
1598+
bool endOfArg = false;
15941599
std::string currentArg;
15951600
std::vector<std::string> args;
1601+
char quote = 0;
15961602
char prevChar = 0;
1597-
for (std::string::const_iterator
1598-
it = argText.begin(); it != argText.end(); ++it) {
1603+
typedef std::string::const_iterator it_t;
1604+
for (it_t it = argText.begin(); it != argText.end(); ++it) {
1605+
1606+
endOfArg = false;
1607+
1608+
// Store current character
15991609
char ch = *it;
16001610

1601-
if (ch == '"' && prevChar != '\\') {
1602-
insideQuotes = !insideQuotes;
1603-
}
1611+
// Ignore quoted strings and character values in single quotes
1612+
if ( ! quote && (ch == '"' || ch == '\''))
1613+
quote = ch;
1614+
else if (quote && ch == quote && prevChar != '\\')
1615+
quote = 0;
16041616

1605-
if ((ch == ',') &&
1617+
std::cerr << "-------------------------------- SourceFileAttributesParser::SourceFileAttributesParser::parseArguments 10" << std::endl << "'" << prevChar << "' '" << ch << "' #" << quote << "#" << std::endl;
1618+
// Detect end of argument declaration
1619+
if ( ! quote &&
1620+
(ch == ',') &&
16061621
(templateCount == 0) &&
1607-
(parenCount == 0) &&
1608-
!insideQuotes) {
1622+
(parenCount == 0)) {
16091623
args.push_back(currentArg);
16101624
currentArg.clear();
1611-
continue;
1612-
} else {
1613-
currentArg.push_back(ch);
1614-
switch(ch) {
1615-
case '<':
1616-
templateCount++;
1617-
break;
1618-
case '>':
1619-
templateCount--;
1620-
break;
1621-
case '(':
1622-
parenCount++; // #nocov
1623-
break; // #nocov
1624-
case ')':
1625-
parenCount--; // #nocov
1626-
break; // #nocov
1625+
endOfArg = true;
1626+
}
1627+
1628+
std::cerr << "-------------------------------- SourceFileAttributesParser::SourceFileAttributesParser::parseArguments 20" << std::endl << endOfArg << std::endl;
1629+
if ( ! endOfArg) {
1630+
1631+
// Append current character if not a space at start
1632+
if ( ! currentArg.empty() || ch != ' ')
1633+
currentArg.push_back(ch);
1634+
1635+
// Count use of potentially enclosed brackets
1636+
if ( ! quote) {
1637+
switch(ch) {
1638+
case '<':
1639+
templateCount++;
1640+
break;
1641+
case '>':
1642+
templateCount--;
1643+
break;
1644+
case '(':
1645+
parenCount++; // #nocov
1646+
break; // #nocov
1647+
case ')':
1648+
parenCount--; // #nocov
1649+
break; // #nocov
1650+
}
16271651
}
16281652
}
1653+
std::cerr << "-------------------------------- SourceFileAttributesParser::SourceFileAttributesParser::parseArguments 30" << std::endl << templateCount << " " << parenCount << std::endl;
1654+
std::cerr << "-------------------------------- SourceFileAttributesParser::SourceFileAttributesParser::parseArguments 40" << std::endl << currentArg << std::endl;
16291655

16301656
prevChar = ch;
16311657
}

0 commit comments

Comments
 (0)