[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(&paramsText);
-            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