[Rcpp-commits] r3870 - in pkg/Rcpp: . src
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Wed Oct 31 14:20:13 CET 2012
Author: jjallaire
Date: 2012-10-31 14:20:12 +0100 (Wed, 31 Oct 2012)
New Revision: 3870
Added:
pkg/Rcpp/src/AttributesParser.cpp
pkg/Rcpp/src/AttributesParser.h
Modified:
pkg/Rcpp/ChangeLog
pkg/Rcpp/src/Attributes.cpp
Log:
factor attribute parser into it's own file; eliminate tranposition of roxygen comments
Modified: pkg/Rcpp/ChangeLog
===================================================================
--- pkg/Rcpp/ChangeLog 2012-10-31 13:12:09 UTC (rev 3869)
+++ pkg/Rcpp/ChangeLog 2012-10-31 13:20:12 UTC (rev 3870)
@@ -1,3 +1,10 @@
+2012-10-30 JJ Allaire <jj at rstudio.org>
+
+ * src/Attributes.cpp: factored parser into it's own file; eliminated
+ tranposition of roxygen comments.
+ * src/AttributesParser.h: attributes parser header
+ * src/AttributesParser.cpp: attributes parser implementation
+
2012-10-31 Romain Francois <romain at r-enthusiasts.com>
* include/Rcpp/module/class.h: factored out of Module.h which started to
Modified: pkg/Rcpp/src/Attributes.cpp
===================================================================
--- pkg/Rcpp/src/Attributes.cpp 2012-10-31 13:12:09 UTC (rev 3869)
+++ pkg/Rcpp/src/Attributes.cpp 2012-10-31 13:20:12 UTC (rev 3870)
@@ -32,1277 +32,568 @@
#include <Rcpp.h>
#include <Rcpp/exceptions.h>
-namespace {
+#include "AttributesParser.h"
-// Some parsing utilities
+using namespace Rcpp::attributes_parser;
-#define kWhitespaceChars " \f\n\r\t\v"
+namespace {
-// Query whether a character is whitespace
-bool isWhitespace(char ch) {
- return std::strchr(kWhitespaceChars, ch) != NULL;
-}
-
-// Trim a string
-void trimWhitespace(std::string* pStr) {
+ // Utility class for getting file existence and last modified time
+ class FileInfo {
+ public:
+ explicit FileInfo(const std::string& path)
+ : path_(path), exists_(false), lastModified_(0)
+ {
+ #ifdef _WIN32
+ struct _stat buffer;
+ int result = _stat(path.c_str(), &buffer);
+ #else
+ struct stat buffer;
+ int result = stat(path.c_str(), &buffer);
+ #endif
+ if (result != 0) {
+ if (errno == ENOENT)
+ exists_ = false;
+ else
+ throw Rcpp::file_io_error(errno, path);
+ } else {
+ exists_ = true;
+ lastModified_ = buffer.st_mtime;
+ }
+ }
+
+ std::string path() const { return path_; }
+ bool exists() const { return exists_; }
+ time_t lastModified() const { return lastModified_; }
+
+ private:
+ std::string path_;
+ bool exists_;
+ time_t lastModified_;
+ };
- // skip empty case
- if (pStr->empty())
- return;
-
- // trim right
- std::string::size_type pos = pStr->find_last_not_of(kWhitespaceChars);
- if (pos != std::string::npos)
- pStr->erase(pos + 1);
+ // Generate the preamble for a C++ file (headers and using directives)
+ std::string generateCppPreamble(const std::vector<std::string>& includes,
+ const std::vector<std::string>& namespaces){
+ std::ostringstream ostr;
+ for (std::size_t i=0;i<includes.size(); i++)
+ ostr << includes[i] << std::endl;
- // trim left
- pos = pStr->find_first_not_of(kWhitespaceChars);
- pStr->erase(0, pos);
-}
-
-// Strip balanced quotes from around a string (assumes already trimmed)
-void stripQuotes(std::string* pStr) {
- if (pStr->length() < 2)
- return;
- char quote = *(pStr->begin());
- if ( (quote == '\'' || quote == '\"') && (*(pStr->rbegin()) == quote) )
- *pStr = pStr->substr(1, pStr->length()-2);
-}
-
-// Utility class for getting file existence and last modified time
-class FileInfo {
-public:
- explicit FileInfo(const std::string& path)
- : path_(path), exists_(false), lastModified_(0)
- {
-#ifdef _WIN32
- struct _stat buffer;
- int result = _stat(path.c_str(), &buffer);
-#else
- struct stat buffer;
- int result = stat(path.c_str(), &buffer);
-#endif
- if (result != 0) {
- if (errno == ENOENT)
- exists_ = false;
- else
- throw Rcpp::file_io_error(errno, path);
- } else {
- exists_ = true;
- lastModified_ = buffer.st_mtime;
- }
+ ostr << std::endl;
+
+ for (std::size_t i=0;i<namespaces.size(); i++)
+ ostr << namespaces[i] << std::endl;
+
+ return ostr.str();
}
- std::string path() const { return path_; }
- bool exists() const { return exists_; }
- time_t lastModified() const { return lastModified_; }
-
-private:
- std::string path_;
- bool exists_;
- time_t lastModified_;
-};
-
-
-// Type info
-class Type {
-public:
- Type() {}
- Type(const std::string& name, bool isConst, bool isReference)
- : name_(name), isConst_(isConst), isReference_(isReference)
- {
- }
- bool empty() const { return name().empty(); }
-
- const std::string& name() const { return name_; }
-
- bool isVoid() const { return name() == "void"; }
- bool isConst() const { return isConst_; }
- bool isReference() const { return isReference_; }
-
-private:
- std::string name_;
- bool isConst_;
- bool isReference_;
-};
-
-std::ostream& operator<<(std::ostream& os, const Type& type) {
- if (!type.empty()) {
- if (type.isConst())
- os << "const ";
- os << type.name();
- if (type.isReference())
- os << "&";
- }
- return os;
-}
-
-// Argument info
-class Argument {
-public:
- Argument() {}
- Argument(const std::string& name, const Type& type)
- : name_(name), type_(type)
- {
- }
-
- bool empty() const { return type().empty(); }
-
- const std::string& name() const { return name_; }
- const Type& type() const { return type_; }
-
-private:
- std::string name_;
- Type type_;
-};
-
-std::ostream& operator<<(std::ostream& os, const Argument& argument) {
- if (!argument.empty()) {
- os << argument.type();
- if (!argument.name().empty()) {
- os << " ";
- os << argument.name();
+ // Generate the C++ code required to make [[Rcpp::export]] functions
+ // available as C symbols with SEXP parameters and return
+ std::string generateCpp(const SourceFileAttributes& attributes,
+ bool includePrototype,
+ const std::string& contextId,
+ bool verbose = false) {
+
+ // source code we will build up
+ std::ostringstream ostr;
+
+ // process each attribute
+ for(std::vector<Attribute>::const_iterator
+ it = attributes.begin(); it != attributes.end(); ++it) {
+
+ // alias the attribute (bail if not export)
+ const Attribute& attribute = *it;
+ if (attribute.name() != kExportAttribute)
+ continue;
+
+ // alias the function (bail if empty)
+ const Function& function = attribute.function();
+ if (function.empty())
+ continue;
+
+ // verbose output
+ if (verbose)
+ Rcpp::Rcout << " " << function << std::endl;
+
+ // include prototype if requested
+ if (includePrototype) {
+ ostr << "// " << function.name() << std::endl;
+ ostr << function << ";";
+ }
+
+ // write the SEXP-based function
+ ostr << std::endl << "RcppExport SEXP ";
+ if (!contextId.empty())
+ ostr << contextId << "_";
+ ostr << function.name() << "(";
+ const std::vector<Argument>& arguments = function.arguments();
+ for (size_t i = 0; i<arguments.size(); i++) {
+ const Argument& argument = arguments[i];
+ ostr << "SEXP " << argument.name() << "SEXP";
+ if (i != (arguments.size()-1))
+ ostr << ", ";
+ }
+ ostr << ") {" << std::endl;
+ ostr << "BEGIN_RCPP" << std::endl;
+ for (size_t i = 0; i<arguments.size(); i++) {
+ const Argument& argument = arguments[i];
+
+ // Rcpp::as to c++ type
+ ostr << " " << argument.type().name() << " " << argument.name()
+ << " = " << "Rcpp::as<" << argument.type().name() << " >("
+ << argument.name() << "SEXP);" << std::endl;
+ }
+
+ ostr << " ";
+ if (!function.type().isVoid())
+ ostr << function.type() << " result = ";
+ ostr << function.name() << "(";
+ for (size_t i = 0; i<arguments.size(); i++) {
+ const Argument& argument = arguments[i];
+ ostr << argument.name();
+ if (i != (arguments.size()-1))
+ ostr << ", ";
+ }
+ ostr << ");" << std::endl;
+
+ std::string res = function.type().isVoid() ? "R_NilValue" :
+ "Rcpp::wrap(result)";
+ ostr << " return " << res << ";" << std::endl;
+ ostr << "END_RCPP" << std::endl;
+ ostr << "}" << std::endl << std::endl;
}
+
+ return ostr.str();
}
- return os;
-}
-
-// Function info
-class Function {
-public:
- Function() {}
- Function(const Type& type,
- const std::string& name,
- const std::vector<Argument>& arguments,
- const std::string& source)
- : type_(type), name_(name), arguments_(arguments), source_(source)
- {
- }
- bool empty() const { return name().empty(); }
-
- const Type& type() const { return type_; }
- const std::string& name() const { return name_; }
- const std::vector<Argument>& arguments() const { return arguments_; }
- const std::string& source() const { return source_; }
-
-private:
- Type type_;
- std::string name_;
- std::vector<Argument> arguments_;
- std::string source_;
-};
-
-std::ostream& operator<<(std::ostream& os, const Function& function) {
- if (!function.empty()) {
- if (!function.type().empty()) {
- os << function.type();
- os << " ";
- }
- os << function.name();
- os << "(";
- const std::vector<Argument>& arguments = function.arguments();
- for (std::size_t i = 0; i<arguments.size(); i++) {
- os << arguments[i];
- if (i != (arguments.size()-1))
- os << ", ";
- }
- os << ")";
+ // Determine the exported name for a function
+ std::string exportedName(const Attribute& attribute) {
+ if (!attribute.params().empty())
+ return attribute.params()[0].name();
+ else
+ return attribute.function().name();
}
- return os;
-}
-
-// Attribute parameter (with optional value)
-class Param {
-public:
- Param() {}
- explicit Param(const std::string& paramText)
- {
- // parse out name/value pair if there is one
- std::string::size_type pos = paramText.find("=") ;
- if ( pos != std::string::npos ) {
- // name
- name_ = paramText.substr(0, pos);
- trimWhitespace(&name_);
- // value
- value_ = paramText.substr(pos + 1) ;
- trimWhitespace(&value_);
- stripQuotes(&value_);
- }
- else {
- name_ = paramText;
- stripQuotes(&name_);
- }
- }
- bool empty() const { return name().empty(); }
-
- const std::string& name() const { return name_; }
- const std::string& value() const { return value_; }
-
-private:
- std::string name_;
- std::string value_;
-};
-
-std::ostream& operator<<(std::ostream& os, const Param& param) {
- if (!param.empty()) {
- os << param.name();
- if (!param.value().empty())
- os << "=" << param.value();
- }
- return os;
-}
-
-// Attribute (w/ optional params and signature of function it qualifies)
-class Attribute {
-public:
- Attribute() {}
- Attribute(const std::string& name,
- const std::vector<Param>& params,
- const Function& function,
- const std::vector<std::string>& roxygen)
- : name_(name), params_(params), function_(function), roxygen_(roxygen)
- {
- }
-
- bool empty() const { return name().empty(); }
-
- const std::string& name() const { return name_; }
-
- const std::vector<Param>& params() const { return params_; }
+ // Generate R functions from the passed attributes
+ std::string generateRFunctions(const SourceFileAttributes& attributes,
+ const std::string& contextId,
+ const std::string& dllInfo = std::string()) {
- Param paramNamed(const std::string& name) const {
- for (std::vector<Param>::const_iterator
- it = params_.begin(); it != params_.end(); ++it) {
- if (it->name() == name)
- return *it;
- }
- return Param();
- }
-
- bool hasParameter(const std::string& name) const {
- return !paramNamed(name).empty();
- }
-
- const Function& function() const { return function_; }
-
- const std::vector<std::string>& roxygen() const { return roxygen_; }
-
-private:
- std::string name_;
- std::vector<Param> params_;
- Function function_;
- std::vector<std::string> roxygen_;
-};
-
-std::ostream& operator<<(std::ostream& os, const Attribute& attribute) {
- if (!attribute.empty()) {
- os << "[[Rcpp::" << attribute.name();
- const std::vector<Param>& params = attribute.params();
- if (params.size() > 0) {
- os << "(";
- for (std::size_t i = 0; i<params.size(); i++) {
- os << params[i];
- if (i != (params.size()-1))
- os << ",";
- }
- os << ")";
- }
- os << "]]";
-
- if (!attribute.function().empty())
- os << " " << attribute.function();
- }
- return os;
-}
-
-// Known attribute and param names
-#define kExportAttribute "export"
-#define kDependsAttribute "depends"
-
-// Class used to parse and return attribute information from a source file
-class SourceFileAttributes {
-public:
- explicit SourceFileAttributes(const std::string& sourceFile)
- : sourceFile_(sourceFile)
- {
- // First read the entire file into a std::stringstream so we can check
- // it for attributes (we don't want to do any of our more expensive
- // processing steps if there are no attributes to parse)
- std::ifstream ifs(sourceFile_.c_str());
- if (ifs.fail())
- throw Rcpp::file_io_error(sourceFile_);
- std::stringstream buffer;
- buffer << ifs.rdbuf();
- std::string contents = buffer.str();
-
- // Check for attribute signature
- if (contents.find("[[Rcpp::") != std::string::npos) {
+ // source code we will build up
+ std::ostringstream ostr;
+
+ // process each attribute
+ for(std::vector<Attribute>::const_iterator
+ it = attributes.begin(); it != attributes.end(); ++it) {
- // 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
- std::string line;
- std::deque<std::string> lines;
- while(std::getline(buffer, line)) {
- // strip \r (for the case of windows line terminators on posix)
- if (line.length() > 0 && *line.rbegin() == '\r')
- line.erase(line.length()-1, 1);
- lines.push_back(line);
- }
- lines_ = Rcpp::wrap(lines);
+ // alias the attribute (bail if not export)
+ const Attribute& attribute = *it;
+ if (attribute.name() != kExportAttribute)
+ continue;
- // Scan for attributes
- CommentState commentState;
- Rcpp::Environment base("package:base");
- Rcpp::Function regexec = base["regexec"];
- Rcpp::Function regmatches = base["regmatches"];
- Rcpp::RObject result = regexec(
- "^\\s*//\\s+\\[\\[Rcpp::(\\w+)(\\(.*?\\))?\\]\\]\\s*$", lines_);
- Rcpp::List matches = regmatches(lines_, result);
- for (int i = 0; i<matches.size(); i++) {
-
- // track whether we are in a comment and bail if we are in one
- std::string line = lines[i];
- commentState.submitLine(line);
- if (commentState.inComment())
- continue;
-
- // attribute line
- const Rcpp::CharacterVector match = matches[i];
- if (match.size() > 0) {
+ // alias the function (bail if empty)
+ const Function& function = attribute.function();
+ if (function.empty())
+ continue;
- // if the match size isn't 3 then regmatches has not behaved
- // as expected (it should return a vector of either 0 or 3
- // elements). we don't ever expect this to occur but if it
- // does let's not crash
- if (match.size() != 3)
- continue;
-
- // add the attribute
- attributes_.push_back(parseAttribute(
- Rcpp::as<std::vector<std::string> >(match), i));
- }
-
- // if it's not an attribute line then it could still be a
- // line of interest (using namespace or roxygen comment)
- else {
-
- // save global namespace imports (need to bring these over
- // to RcppExports.cpp to ensure type names all work)
- if (line.find("using namespace") == 0) {
- std::string namespaceLine = line;
- trimWhitespace(&namespaceLine);
- if (*(namespaceLine.rbegin()) == ';')
- namespaces_.push_back(namespaceLine);
- }
-
- // look for roxygen comments
- else if (line.find("//'") == 0) {
- std::string roxLine = "#" + line.substr(2);
- roxygenBuffer_.push_back(roxLine);
- }
- }
+ // build the parameter list
+ std::ostringstream argsOstr;
+ const std::vector<Argument>& arguments = function.arguments();
+ for (size_t i = 0; i<arguments.size(); i++) {
+ const Argument& argument = arguments[i];
+ argsOstr << argument.name();
+ if (i != (arguments.size()-1))
+ argsOstr << ", ";
}
- }
- }
-
-private:
- // prohibit copying
- SourceFileAttributes(const SourceFileAttributes&);
- SourceFileAttributes& operator=(const SourceFileAttributes&);
-
-public:
- const std::string& sourceFile() const {
- return sourceFile_;
- }
-
- // Iteration over attributes
- typedef std::vector<Attribute>::const_iterator const_iterator;
- const_iterator begin() const { return attributes_.begin(); }
- const_iterator end() const { return attributes_.end(); }
- bool empty() const { return attributes_.empty(); }
-
- // namespace imports
- const std::vector<std::string>& namespaces() const {
- return namespaces_;
- }
-
-private:
-
- // Parse an attribute from the vector returned by regmatches
- Attribute parseAttribute(const std::vector<std::string>& match,
- int lineNumber) {
+ std::string args = argsOstr.str();
- // Attribute name
- std::string name = match[1];
-
- // Warn if this is an unknown attribute
- if (!isKnownAttribute(name)) {
- attributeWarning("Unrecognized attribute Rcpp::" + name,
- lineNumber);
- }
-
- // Extract params if we've got them
- std::vector<Param> params;
- std::string paramsText = match[2];
- if (!paramsText.empty()) {
+ // determine the function name
+ std::string name = exportedName(attribute);
+
+ // write the function - use contextId to ensure symbol uniqueness
+ ostr << name << " <- function(" << args << ") {"
+ << std::endl;
+ ostr << " ";
+ if (function.type().isVoid())
+ ostr << "invisible(";
+ ostr << ".Call(";
- // we know from the regex that it's enclosed in parens so remove them
- // trim before we do this just in case someone updates the regex
- // to allow for whitespace around the call
- trimWhitespace(¶msText);
- paramsText = paramsText.substr(1, paramsText.size()-2);
+ // Two .Call styles are suppported -- if dllInfo is provided then
+ // do a direct call to getNativeSymbolInfo; otherwise we assume that
+ // the contextId is a package name and use the PACKAGE argument
+ if (!dllInfo.empty()) {
+ ostr << "getNativeSymbolInfo('"
+ << contextId << "_" << function.name()
+ << "', " << dllInfo << ")";
+ }
+ else {
+ ostr << "'" << contextId << "_" << function.name() << "', "
+ << "PACKAGE = '" << contextId << "'";
+ }
- // parse the parameters
- params = parseParameters(paramsText);
+ // add arguments
+ if (!args.empty())
+ ostr << ", " << args;
+ ostr << ")";
+ if (function.type().isVoid())
+ ostr << ")";
+ ostr << std::endl;
+
+ ostr << "}" << std::endl << std::endl;
}
- // Extract function signature if this is a function attribute
- // and it doesn't appear at the end of the file
- Function function;
-
- // special handling for export
- if (name == kExportAttribute) {
-
- // parse the function (unless we are at the end of the file in
- // which case we print a warning)
- if ((lineNumber + 1) < lines_.size())
- function = parseFunction(lineNumber + 1);
- else
- rcppExportWarning("No function found", lineNumber);
- }
-
- // Return attribute
- Attribute attribute = Attribute(name, params, function, roxygenBuffer_);
- roxygenBuffer_.clear();
- return attribute;
+ return ostr.str();
}
- // Parse attribute parameters
- std::vector<Param> parseParameters(const std::string& input) {
- const std::string delimiters(" ,");
+ // Generate the R code used to .Call the exported C symbols
+ std::string generateR(const SourceFileAttributes& attributes,
+ const std::string& contextId,
+ const std::string& dynlibPath) {
+
+ // source code we will build up
+ std::ostringstream ostr;
- std::vector<Param> params;
- std::string::size_type current;
- std::string::size_type next = -1;
- do {
- next = input.find_first_not_of(delimiters, next + 1);
- if (next == std::string::npos)
- break;
- next -= 1;
- current = next + 1;
- next = input.find_first_of(delimiters, current);
- params.push_back(Param(input.substr(current, next - current)));
- } while(next != std::string::npos);
+ // DLLInfo - hide using . and ensure uniqueness using contextId
+ std::string dllInfo = "`." + contextId + "_DLLInfo`";
+ ostr << dllInfo << " <- dyn.load('" << dynlibPath << "')"
+ << std::endl << std::endl;
- return params;
+ // Generate R functions and return
+ ostr << generateRFunctions(attributes, contextId, dllInfo);
+ return ostr.str();
}
-
- // Parse a function from the specified spot in the source file
- Function parseFunction(size_t lineNumber) {
+
+
+ // Class that manages generation of source code for the sourceCpp dynlib
+ class SourceCppDynlib {
+ public:
+ SourceCppDynlib() {}
- // Establish the text to parse for the signature
- std::string signature = parseSignature(lineNumber);
- if (signature.empty()) {
- rcppExportNoFunctionFoundWarning(lineNumber);
- return Function();
- }
-
- // Start at the end and look for the () that deliniates the arguments
- // (bail with an empty result if we can't find them)
- std::string::size_type endParenLoc = signature.find_last_of(')');
- std::string::size_type beginParenLoc = signature.find_last_of('(');
- if (endParenLoc == std::string::npos ||
- beginParenLoc == std::string::npos ||
- endParenLoc < beginParenLoc) {
-
- rcppExportNoFunctionFoundWarning(lineNumber);
- return Function();
- }
-
- // Find the type and name by scanning backwards for the whitespace that
- // delimites the type and name
- Type type;
- std::string name;
- std::string preambleText = signature.substr(0, beginParenLoc);
- for (std::string::const_reverse_iterator
- it = preambleText.rbegin(); it != preambleText.rend(); ++it) {
- char ch = *it;
- if (isWhitespace(ch)) {
- if (!name.empty()) {
- // we are at the break between type and name so we can also
- // extract the type
- std::string typeText;
- while (++it != preambleText.rend())
- typeText.insert(0, 1, *it);
- type = parseType(typeText);
+ SourceCppDynlib(const std::string& cppSourcePath, Rcpp::List platform)
+ : cppSourcePath_(cppSourcePath)
+ {
+ // get cpp source file info
+ FileInfo cppSourceFilenameInfo(cppSourcePath_);
+ if (!cppSourceFilenameInfo.exists())
+ throw Rcpp::file_not_found(cppSourcePath_);
- // break (since we now have the name and the type)
- break;
- }
- else
- continue;
- } else {
- name.insert(0, 1, ch);
- }
- }
-
- // If we didn't find a name then bail
- if (name.empty()) {
- rcppExportNoFunctionFoundWarning(lineNumber);
- return Function();
- }
-
- // If we didn't find a type then bail
- if (type.empty()) {
- rcppExportWarning("No function return type found", lineNumber);
- return Function();
- }
-
- // Now scan for arguments
- std::vector<Argument> arguments;
- std::string argsText = signature.substr(beginParenLoc + 1,
- endParenLoc-beginParenLoc-1);
- std::vector<std::string> args = parseArguments(argsText);
- for (std::vector<std::string>::const_iterator it =
- args.begin(); it != args.end(); ++it) {
-
- // Get argument sans whitespace (bail if the arg is empty)
- std::string arg = *it;
- trimWhitespace(&arg);
- if (arg.empty()) {
- // we don't warn here because the compilation will fail anyway
- continue;
- }
-
- // Scan backwards for whitespace to determine where the type ends
- // (we go backwards because whitespace is valid inside the type
- // identifier but invalid inside the variable name). Note that if
- // there is no whitespace we'll end up taking the whole string,
- // which allows us to capture a type with no variable (but note
- // we'll ultimately fail to parse types with no variable if they
- // have embedded whitespace)
- std::string::size_type pos = arg.find_last_of(kWhitespaceChars);
+ // get last modified time
+ cppSourceLastModified_ = cppSourceFilenameInfo.lastModified();
- // check for name
- std::string name;
- if (pos != std::string::npos) {
- name = arg.substr(pos);
- trimWhitespace(&name);
- }
- if (name.empty()) {
- rcppExportInvalidParameterWarning(arg, lineNumber);
- return Function();
- }
+ // record the base name of the source file
+ Rcpp::Function basename = Rcpp::Environment::base_env()["basename"];
+ cppSourceFilename_ = Rcpp::as<std::string>(basename(cppSourcePath_));
- // check for type string
- Type type = parseType(arg.substr(0, pos));
- if (type.empty()) {
- rcppExportInvalidParameterWarning(arg, lineNumber);
- return Function();
- }
+ // get platform info
+ fileSep_ = Rcpp::as<std::string>(platform["file.sep"]);
+ dynlibExt_ = Rcpp::as<std::string>(platform["dynlib.ext"]);
- // add argument
- arguments.push_back(Argument(name, type));
+ // generate temp directory
+ Rcpp::Function tempfile = Rcpp::Environment::base_env()["tempfile"];
+ buildDirectory_ = Rcpp::as<std::string>(tempfile("sourcecpp_"));
+ std::replace(buildDirectory_.begin(), buildDirectory_.end(), '\\', '/');
+ Rcpp::Function dircreate = Rcpp::Environment::base_env()["dir.create"];
+ dircreate(buildDirectory_);
+
+ // use the directory name as a unique context id (need this to uniquely
+ // name functions, DLLInfo objects, and the shared library itself)
+ contextId_ = Rcpp::as<std::string>(basename(buildDirectory_));
+
+ // regenerate the source code
+ regenerateSource();
}
- return Function(type, name, arguments, signature);
- }
-
-
- // Parse the text of a function signature from the specified line
- std::string parseSignature(size_t lineNumber) {
+ bool isEmpty() const { return cppSourcePath_.empty(); }
- // Look for the next {
- std::string signature;
- for (int i = lineNumber; i<lines_.size(); i++) {
- std::string line;
- line = lines_[i];
- std::string::size_type bracePos = line.find('{');
- if (bracePos == std::string::npos) {
- signature.append(line);
- signature.push_back(' ');
- } else {
- signature.append(line.substr(0, bracePos));
- return signature;
- }
+ bool isBuilt() const { return FileInfo(dynlibPath()).exists(); };
+
+ bool isSourceDirty() const {
+
+ // source file out of date means we're dirty
+ if (FileInfo(cppSourcePath_).lastModified() != cppSourceLastModified_)
+ return true;
+
+ // no dynlib means we're dirty
+ if (!FileInfo(dynlibPath()).exists())
+ return true;
+
+ // not dirty
+ return false;
}
- // Not found
- return std::string();
- }
-
-
- // Parse arguments from function signature. This is tricky because commas
- // are used to delimit arguments but are also valid inside template type
- // qualifiers.
- std::vector<std::string> parseArguments(const std::string& argText) {
+ void regenerateSource() {
+
+ // copy the source file to the build dir
+ Rcpp::Function filecopy = Rcpp::Environment::base_env()["file.copy"];
+ filecopy(cppSourcePath_, generatedCppSourcePath(), true);
+
+ // parse attributes
+ SourceFileAttributes sourceAttributes(cppSourcePath_);
- int templateCount = 0;
- std::string currentArg;
- std::vector<std::string> args;
- for (std::string::const_iterator
[TRUNCATED]
To get the complete diff run:
svnlook diff /svnroot/rcpp -r 3870
More information about the Rcpp-commits
mailing list