From 1e2cecfbbca29411963173053e016c4ecb4223ed Mon Sep 17 00:00:00 2001 From: travers Date: Sat, 9 Oct 2021 15:31:56 -0700 Subject: [PATCH 1/6] add signature attribute --- ChangeLog | 3 +++ DESCRIPTION | 2 +- src/attributes.cpp | 52 ++++++++++++++++++++++++++++++++++++---------- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9f056253c..0de4f6657 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,9 @@ * man/Rcpp-package.Rd: Idem * man/RcppLdFlags.Rd: Idem * inst/CITATION: Only use doi entries in three citEntry blocks +2021-10-10 Travers Ching + + * Added `signature` attribute to attributes.cpp 2021-10-02 Dirk Eddelbuettel diff --git a/DESCRIPTION b/DESCRIPTION index 4b09ca8f0..ab8d44449 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: Rcpp Title: Seamless R and C++ Integration -Version: 1.0.7.3 +Version: 1.0.7.4 Date: 2021-10-01 Author: Dirk Eddelbuettel, Romain Francois, JJ Allaire, Kevin Ushey, Qiang Kou, Nathan Russell, Inaki Ucar, Douglas Bates and John Chambers diff --git a/src/attributes.cpp b/src/attributes.cpp index 7288f4fba..be35345a0 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -154,6 +154,7 @@ namespace attributes { const char * const kExportName = "name"; const char * const kExportRng = "rng"; const char * const kExportInvisible = "invisible"; + const char * const kExportSignature = "signature"; const char * const kInitAttribute = "init"; const char * const kDependsAttribute = "depends"; const char * const kPluginsAttribute = "plugins"; @@ -164,6 +165,8 @@ namespace attributes { const char * const kParamValueTrue = "true"; const char * const kParamValueFALSE = "FALSE"; const char * const kParamValueTRUE = "TRUE"; + const char * const kParamBlockStart = "{;"; + const char * const kParamBlockEnd = "}"; // Type info class Type { @@ -390,8 +393,19 @@ namespace attributes { else return false; } - + const std::vector& roxygen() const { return roxygen_; } + + std::string customRSignature() const { + Param sigParam = paramNamed(kExportSignature); + std::string sig = sigParam.value(); + trimWhitespace(&sig); + if(sig.back() == '}') + sig = sig.substr(0, sig.size()-1); + if(sig.front() == '{') + sig.erase(0,1); + return sig; + } private: std::string name_; @@ -1312,7 +1326,6 @@ namespace attributes { Attribute SourceFileAttributesParser::parseAttribute( const std::vector& match, int lineNumber) { - // Attribute name std::string name = match[1]; @@ -1368,7 +1381,8 @@ namespace attributes { else if (!value.empty() && (name != kExportName) && (name != kExportRng) && - (name != kExportInvisible)) { + (name != kExportInvisible) && + (name != kExportSignature)) { rcppExportWarning("Unrecognized parameter '" + name + "'", lineNumber); } @@ -1422,9 +1436,10 @@ namespace attributes { // Parse attribute parameters std::vector SourceFileAttributesParser::parseParameters( const std::string& input) { - + std::string::size_type blockstart = input.find_first_of(kParamBlockStart); + std::string::size_type blockend = input.find_last_of(kParamBlockEnd); + const std::string delimiters(","); - std::vector params; std::string::size_type current; std::string::size_type next = -1; @@ -1432,9 +1447,11 @@ namespace attributes { next = input.find_first_not_of(delimiters, next + 1); if (next == std::string::npos) break; // #nocov - next -= 1; - current = next + 1; - next = input.find_first_of(delimiters, current); + current = next; + do { + next = input.find_first_of(delimiters, next + 1); + } while((next >= blockstart) && (next <= blockend) && + (next != std::string::npos)); params.push_back(Param(input.substr(current, next - current))); } while(next != std::string::npos); @@ -2443,7 +2460,12 @@ namespace attributes { // build the parameter list std::string args = generateRArgList(function); - + + // check if has a custom signature + if(attribute.hasParameter(kExportSignature)) { + args = attribute.customRSignature(); + } + // determine the function name std::string name = attribute.exportedName(); @@ -3352,11 +3374,19 @@ namespace { if (!attribute.isExportedFunction()) continue; const Function& function = attribute.function(); - + + // build the parameter list + std::string args = generateRArgList(function); + + // check if has a custom signature + if(attribute.hasParameter(kExportSignature)) { + args = attribute.customRSignature(); + } + // export the function ostr << attribute.exportedName() << " <- Rcpp:::sourceCppFunction(" - << "function(" << generateRArgList(function) << ") {}, " + << "function(" << args << ") {}, " << (function.type().isVoid() ? "TRUE" : "FALSE") << ", " << dllInfo << ", " << "'" << contextId_ + "_" + function.name() From 16979fa31b48bdfb68bef1aa383375b79b0f7b4c Mon Sep 17 00:00:00 2001 From: Dirk Eddelbuettel Date: Mon, 11 Oct 2021 07:13:33 -0500 Subject: [PATCH 2/6] roll minor version in config.h (to match DESCRIPTION) --- ChangeLog | 5 +++++ inst/include/Rcpp/config.h | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0de4f6657..8f4889c64 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,11 @@ * man/Rcpp-package.Rd: Idem * man/RcppLdFlags.Rd: Idem * inst/CITATION: Only use doi entries in three citEntry blocks +2021-10-11 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): Roll minor version + * inst/include/Rcpp/config.h: Idem + 2021-10-10 Travers Ching * Added `signature` attribute to attributes.cpp diff --git a/inst/include/Rcpp/config.h b/inst/include/Rcpp/config.h index dfbb98740..9262f27b1 100644 --- a/inst/include/Rcpp/config.h +++ b/inst/include/Rcpp/config.h @@ -30,7 +30,7 @@ #define RCPP_VERSION_STRING "1.0.7" // the current source snapshot (using four components, if a fifth is used in DESCRIPTION we ignore it) -#define RCPP_DEV_VERSION RcppDevVersion(1,0,7,3) -#define RCPP_DEV_VERSION_STRING "1.0.7.3" +#define RCPP_DEV_VERSION RcppDevVersion(1,0,7,4) +#define RCPP_DEV_VERSION_STRING "1.0.7.4" #endif From fbbc7df9baa0e5b091303b9796dfd5f2f15f7ab2 Mon Sep 17 00:00:00 2001 From: Dirk Eddelbuettel Date: Mon, 11 Oct 2021 12:10:49 -0500 Subject: [PATCH 3/6] disable codecov comments on PRs, lower threshold, increase delta --- .codecov.yml | 24 +++++++++++++++++------- ChangeLog | 2 ++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/.codecov.yml b/.codecov.yml index b1699134e..9ec352888 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,7 +1,17 @@ -comment: - layout: "header, diff, tree, changes" - behavior: default - require_changes: false # if true: only post the comment if coverage changes - branches: null - flags: null - paths: null +comment: false +coverage: + status: + project: + default: + target: 70% # the (on purpose low) required coverage value + threshold: 2% # the permitted delta in hitting the target + patch: + default: + target: 0% # the (on purpose low) required coverage value + +# layout: "header, diff, tree, changes" +# behavior: default +# require_changes: false # if true: only post the comment if coverage changes +# branches: null +# flags: null +# paths: null diff --git a/ChangeLog b/ChangeLog index 8f4889c64..688ae56ed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,8 @@ * DESCRIPTION (Version, Date): Roll minor version * inst/include/Rcpp/config.h: Idem + * .codecov.yml (comment): Disable codecov comments on PRs + 2021-10-10 Travers Ching * Added `signature` attribute to attributes.cpp From 27a072fab690e60706b6a8bcf6b8dd2b78808396 Mon Sep 17 00:00:00 2001 From: Travers Date: Sat, 16 Oct 2021 07:16:24 -0700 Subject: [PATCH 4/6] Pr/1183 (#1185) * add signature attribute * roll minor version in config.h (to match DESCRIPTION) * disable codecov comments on PRs, lower threshold, increase delta * add checks for proper syntax of signature attribute * add checks for proper syntax of signature attribute * adding tinytest for rcpp attributes * add checks for proper syntax of signature attribute * add checks for proper syntax of signature attribute * adding tinytest for rcpp attributes * cleanup and rebase for signature attribute pr * cleanup and rebase for signature attribute pr * cleanup and rebase for signature attribute pr * cleanup and rebase for signature attribute pr Co-authored-by: Dirk Eddelbuettel --- ChangeLog | 6 +- .../testRcppAttributePackage/DESCRIPTION | 11 ++ .../testRcppAttributePackage/NAMESPACE | 3 + .../src/rcpp_test.cpp | 95 +++++++++ inst/tinytest/test_attribute_package.R | 180 ++++++++++++++++++ src/attributes.cpp | 75 +++++++- 6 files changed, 358 insertions(+), 12 deletions(-) create mode 100644 inst/tinytest/testRcppAttributePackage/DESCRIPTION create mode 100644 inst/tinytest/testRcppAttributePackage/NAMESPACE create mode 100644 inst/tinytest/testRcppAttributePackage/src/rcpp_test.cpp create mode 100644 inst/tinytest/test_attribute_package.R diff --git a/ChangeLog b/ChangeLog index 688ae56ed..d78734bd4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,9 +11,11 @@ * .codecov.yml (comment): Disable codecov comments on PRs -2021-10-10 Travers Ching +2021-10-10 Travers Ching - * Added `signature` attribute to attributes.cpp + * src/attributes.cpp: Add `signature` attribute and syntax checks + * inst/tinytest/testRcppAttributePackage: Tests `signature` attribute + * inst/tinytest/test_attribute_package.R: Tests `signature` attribute 2021-10-02 Dirk Eddelbuettel diff --git a/inst/tinytest/testRcppAttributePackage/DESCRIPTION b/inst/tinytest/testRcppAttributePackage/DESCRIPTION new file mode 100644 index 000000000..5c9a88427 --- /dev/null +++ b/inst/tinytest/testRcppAttributePackage/DESCRIPTION @@ -0,0 +1,11 @@ +Package: testRcppAttributePackage +Type: Package +Title: Tests the signature attribute and other attributes in package compilation +Version: 1.0 +Date: 2021-10-09 +Author: Travers Ching +Maintainer: Dirk Eddelbuettel +Description: Small test package part of Rcpp unit tests +License: GPL (>= 2) +Imports: Rcpp (>= 1.0.7) +LinkingTo: Rcpp diff --git a/inst/tinytest/testRcppAttributePackage/NAMESPACE b/inst/tinytest/testRcppAttributePackage/NAMESPACE new file mode 100644 index 000000000..7d63c4e69 --- /dev/null +++ b/inst/tinytest/testRcppAttributePackage/NAMESPACE @@ -0,0 +1,3 @@ +useDynLib(testRcppAttributePackage, .registration=TRUE) +importFrom(Rcpp, evalCpp) +exportPattern("^[[:alpha:]]+") diff --git a/inst/tinytest/testRcppAttributePackage/src/rcpp_test.cpp b/inst/tinytest/testRcppAttributePackage/src/rcpp_test.cpp new file mode 100644 index 000000000..465c78889 --- /dev/null +++ b/inst/tinytest/testRcppAttributePackage/src/rcpp_test.cpp @@ -0,0 +1,95 @@ +#include +using namespace Rcpp; + +// [[Rcpp::interfaces(r, cpp)]] + +// [[Rcpp::export]] +List test_no_attributes(List x, bool verbose) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } +} + +// [[Rcpp::export( signature = {x = list("{A}", "B"), verbose = getOption("verbose")} )]] +List test_signature(List x, bool verbose) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } +} + +// [[Rcpp::export( rng = false, signature = {x = list("{A}", "B"), verbose = getOption("verbose")}, invisible = true )]] +List test_rng_false_signature_invisible_true(List x, bool verbose) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } +} + +// [[Rcpp::export( rng = false )]] +List test_rng_false(List x, bool verbose) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } +} + +// [[Rcpp::export( rng = true )]] +List test_rng_true(List x, bool verbose) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } +} + +// [[Rcpp::export( signature = {x = list("{A}", "B"), verbose = getOption("verbose")}, rng = true )]] +List test_rng_true_signature(List x, bool verbose) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } +} + + +// [[Rcpp::export( invisible = true, rng = true )]] +List test_invisible_true_rng_true(List x, bool verbose) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } +} + +// [[Rcpp::export( invisible = true )]] +List test_invisible_true(List x, bool verbose) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } +} + +// [[Rcpp::export( invisible = true, signature = {x = list("{A}", "B"), verbose = getOption("verbose")} )]] +List test_invisible_true_signature(List x, bool verbose) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } +} \ No newline at end of file diff --git a/inst/tinytest/test_attribute_package.R b/inst/tinytest/test_attribute_package.R new file mode 100644 index 000000000..563038149 --- /dev/null +++ b/inst/tinytest/test_attribute_package.R @@ -0,0 +1,180 @@ +## Copyright (C) 2010 - 2020 Dirk Eddelbuettel and Romain Francois +## Copyright (C) 2021 Dirk Eddelbuettel, Romain Francois and Travers Ching +## +## This file is part of Rcpp. +## +## Rcpp is free software: you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 2 of the License, or +## (at your option) any later version. +## +## Rcpp is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Rcpp. If not, see . + +.runThisTest <- Sys.getenv("RunAllRcppTests") == "yes" && Sys.getenv("RunVerboseRcppTests") == "yes" + +if (! .runThisTest) exit_file("Set 'RunVerboseRcppTests' and 'RunAllRcppTests' to 'yes' to run.") + +td <- tempfile() +cwd <- getwd() +dir.create(td) +pkg <- "testRcppAttributePackage" +file.copy(pkg, td, recursive = TRUE) # simpler direct path thanks to tinytest +setwd(td) +on.exit( { setwd(cwd); unlink(td, recursive = TRUE) } ) +R <- shQuote(file.path( R.home(component = "bin"), "R")) +Rcpp::compileAttributes(pkg) +cmd <- paste(R, "CMD build", pkg) +invisible(system(cmd, intern=TRUE)) +dir.create("templib") +pkgfile <- paste0(pkg, "_1.0.tar.gz") +install.packages(pkgfile, "templib", repos = NULL, type = "source") +require(pkg, lib.loc = "templib", character.only = TRUE) + +# Test Package +options(verbose=TRUE) +expect_equal(test_no_attributes(list("{A}"), FALSE),list("{A}", FALSE)) +expect_equal(test_signature(),list("{A}", TRUE)) +expect_equal(test_rng_false_signature_invisible_true(),list("{A}", TRUE)) +expect_equal(test_rng_false(list("{A}"), FALSE),list("{A}", FALSE)) +expect_equal(test_rng_true(list("{A}"), FALSE),list("{A}", FALSE)) +expect_equal(test_rng_true_signature(),list("{A}", TRUE)) +expect_equal(test_invisible_true_rng_true(list("{A}"), FALSE),list("{A}", FALSE)) +expect_equal(test_invisible_true(list("{A}"), FALSE),list("{A}", FALSE)) +expect_equal(test_invisible_true_signature(),list("{A}", TRUE)) +options(verbose=FALSE) + +# Test inline + +# test 0 +# This example should just run and not crash +Rcpp::sourceCpp(code=' +#include +using namespace Rcpp; +// [[Rcpp::export( rng = false, signature = {x=list("{A}", "B"), verbose = getOption("verbose")}, invisible = TRUE )]] +List test_inline(List x, bool verbose) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } +}') +expect_equal(test_inline(), list("{A}", FALSE)) +options(verbose=TRUE) +expect_equal(test_inline(), list("{A}", TRUE)) +options(verbose=FALSE) + +# test 1, from Enchufa2 +# The verbose argument should be replaced with FALSE +Rcpp::sourceCpp(code=' +#include +using namespace Rcpp; +// [[Rcpp::export( rng = false, signature = {x=list("{A}", "B"), verbose=FALSE} )]] +List test_inline(List x, bool verbose=true) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } +}') +expect_equal(test_inline(), list("{A}", FALSE)) + +# test 2, from Enchufa2 +# This second example should not compile because of missing parameter verbose +expect_error({ + Rcpp::sourceCpp(code=' + #include + using namespace Rcpp; + // [[Rcpp::export( rng = false, signature = {x=list("{A}", "B")} )]] + List test_inline(List x, bool verbose=true) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } + }') +}) + +# test 3, from Enchufa2 +# This third example should not compile because of missing end bracket } +# The bracket within the signature is taken as the end bracket, which results in +# invalid R code. There are some additional warnings due to the incorrect syntax +expect_warning({ + expect_error({ + Rcpp::sourceCpp(code=' + #include + using namespace Rcpp; + // [[Rcpp::export( rng = false, signature = {x=list("{A}", "B"), verbose=FALSE )]] + List test_inline(List x, bool verbose) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } + }', verbose=T) + }) +}) + +# test 4, from Enchufa2 +# This 4th example is missing the end bracket and will not compile +expect_error({ + Rcpp::sourceCpp(code=' + #include + using namespace Rcpp; + // [[Rcpp::export( rng = false, signature = {x=list("A", "B"), verbose=FALSE )]] + List test_inline(List x, bool verbose) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } + }') +}) + +# This 5th example has brackets but incorrect R syntax +expect_error({ + Rcpp::sourceCpp(code=' + #include + using namespace Rcpp; + // [[Rcpp::export( rng = false, signature = {x=list("A", ###, verbose=FALSE} )]] + List test_inline(List x, bool verbose) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } + }') +}) + +# This 6th example is missing a parameter in the signature +expect_error({ + Rcpp::sourceCpp(code=' + #include + using namespace Rcpp; + // [[Rcpp::export( rng = false, signature = {x=list("A", "B")} )]] + List test_inline(List x, bool verbose) { + if(x.size() > 0) { + CharacterVector first_element = x[0]; + return List::create(first_element, verbose); + } else { + return List::create(verbose); + } + }') +}) + + +remove.packages(pkg, lib="templib") +unlink("templib", recursive = TRUE) +setwd(cwd) +unlink(pkgfile) diff --git a/src/attributes.cpp b/src/attributes.cpp index be35345a0..7b3bc682c 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -2,7 +2,8 @@ // attributes.cpp: Rcpp R/C++ interface class library -- Rcpp attributes // // Copyright (C) 2012 - 2020 JJ Allaire, Dirk Eddelbuettel and Romain Francois -// Copyright (C) 2021 JJ Allaire, Dirk Eddelbuettel, Romain Francois and Iñaki Ucar +// Copyright (C) 2021 JJ Allaire, Dirk Eddelbuettel, Romain Francois, +// Iñaki Ucar and Travers Ching // // This file is part of Rcpp. // @@ -393,9 +394,9 @@ namespace attributes { else return false; } - + const std::vector& roxygen() const { return roxygen_; } - + std::string customRSignature() const { Param sigParam = paramNamed(kExportSignature); std::string sig = sigParam.value(); @@ -810,6 +811,10 @@ namespace attributes { std::string generateRArgList(const Function& function); + bool checkRSignature(const Function& function, std::string args); + + bool checkRSignature(const Function& function, std::string args); + void initializeGlobals(std::ostream& ostr); void generateCpp(std::ostream& ostr, @@ -1438,11 +1443,12 @@ namespace attributes { const std::string& input) { std::string::size_type blockstart = input.find_first_of(kParamBlockStart); std::string::size_type blockend = input.find_last_of(kParamBlockEnd); - + const std::string delimiters(","); std::vector params; std::string::size_type current; std::string::size_type next = -1; + std::string::size_type signature_param_start = -1; do { // #nocov next = input.find_first_not_of(delimiters, next + 1); if (next == std::string::npos) @@ -1450,11 +1456,26 @@ namespace attributes { current = next; do { next = input.find_first_of(delimiters, next + 1); - } while((next >= blockstart) && (next <= blockend) && + } while((next >= blockstart) && (next <= blockend) && (next != std::string::npos)); params.push_back(Param(input.substr(current, next - current))); + if(params.back().name() == kExportSignature) { + signature_param_start = current; + } } while(next != std::string::npos); + // if the signature param was found, then check that the name, + // start block and end block exist and are in the correct order + if(signature_param_start != static_cast(-1)) { + bool sigchecks = + signature_param_start < blockstart && + blockstart < blockend && + blockstart != std::string::npos && + blockend != std::string::npos; + if(!sigchecks) { + throw Rcpp::exception("signature parameter found but missing {}"); + } + } return params; } @@ -2460,12 +2481,14 @@ namespace attributes { // build the parameter list std::string args = generateRArgList(function); - // check if has a custom signature if(attribute.hasParameter(kExportSignature)) { args = attribute.customRSignature(); + if(!checkRSignature(function, args)) { + std::string rsig_err_msg = "Missing args in " + args; + throw Rcpp::exception(rsig_err_msg.c_str()); + } } - // determine the function name std::string name = attribute.exportedName(); @@ -2769,6 +2792,34 @@ namespace attributes { return argsOstr.str(); } + bool checkRSignature(const Function& function, + std::string args) { + std::vector required_args; + const std::vector& arguments = function.arguments(); + for (size_t i = 0; i parsed_args = + Rcpp::as>(pargs_cv); + + for(size_t i=0; i Date: Sat, 16 Oct 2021 09:27:48 -0500 Subject: [PATCH 5/6] minor cleanups --- ChangeLog | 10 +++++++--- src/attributes.cpp | 5 +---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index d78734bd4..17df141c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,15 @@ +2021-10-15 Travers Ching + + * inst/tinytest/testRcppAttributePackage: Tests `signature` attribute + * inst/tinytest/test_attribute_package.R: Tests `signature` attribute + 2021-10-13 Dirk Eddelbuettel * README.md: Switch JSS url to doi form per JSS request * man/Rcpp-package.Rd: Idem * man/RcppLdFlags.Rd: Idem * inst/CITATION: Only use doi entries in three citEntry blocks + 2021-10-11 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version @@ -11,11 +17,9 @@ * .codecov.yml (comment): Disable codecov comments on PRs -2021-10-10 Travers Ching +2021-10-10 Travers Ching * src/attributes.cpp: Add `signature` attribute and syntax checks - * inst/tinytest/testRcppAttributePackage: Tests `signature` attribute - * inst/tinytest/test_attribute_package.R: Tests `signature` attribute 2021-10-02 Dirk Eddelbuettel diff --git a/src/attributes.cpp b/src/attributes.cpp index 7b3bc682c..38bd73568 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -2,8 +2,7 @@ // attributes.cpp: Rcpp R/C++ interface class library -- Rcpp attributes // // Copyright (C) 2012 - 2020 JJ Allaire, Dirk Eddelbuettel and Romain Francois -// Copyright (C) 2021 JJ Allaire, Dirk Eddelbuettel, Romain Francois, -// Iñaki Ucar and Travers Ching +// Copyright (C) 2021 JJ Allaire, Dirk Eddelbuettel, Romain Francois, Iñaki Ucar and Travers Ching // // This file is part of Rcpp. // @@ -813,8 +812,6 @@ namespace attributes { bool checkRSignature(const Function& function, std::string args); - bool checkRSignature(const Function& function, std::string args); - void initializeGlobals(std::ostream& ostr); void generateCpp(std::ostream& ostr, From 2f4280ad0cce9177e8d6775f4772fb0c51993b53 Mon Sep 17 00:00:00 2001 From: Travers Date: Mon, 25 Oct 2021 17:04:52 -0700 Subject: [PATCH 6/6] signature attribute; small cleanup (#1187) --- src/attributes.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/attributes.cpp b/src/attributes.cpp index 38bd73568..bcb525ec8 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -400,8 +400,11 @@ namespace attributes { Param sigParam = paramNamed(kExportSignature); std::string sig = sigParam.value(); trimWhitespace(&sig); + if(sig.empty()) return sig; if(sig.back() == '}') sig = sig.substr(0, sig.size()-1); + // check sig.empty again since we deleted an element + if(sig.empty()) return sig; if(sig.front() == '{') sig.erase(0,1); return sig; @@ -1444,8 +1447,8 @@ namespace attributes { const std::string delimiters(","); std::vector params; std::string::size_type current; - std::string::size_type next = -1; - std::string::size_type signature_param_start = -1; + std::string::size_type next = std::string::npos; + std::string::size_type signature_param_start = std::string::npos; do { // #nocov next = input.find_first_not_of(delimiters, next + 1); if (next == std::string::npos) @@ -1463,7 +1466,7 @@ namespace attributes { // if the signature param was found, then check that the name, // start block and end block exist and are in the correct order - if(signature_param_start != static_cast(-1)) { + if(signature_param_start != std::string::npos) { bool sigchecks = signature_param_start < blockstart && blockstart < blockend &&