Rcpp Version 1.0.7
attributes.cpp
Go to the documentation of this file.
1 //
2 // attributes.cpp: Rcpp R/C++ interface class library -- Rcpp attributes
3 //
4 // Copyright (C) 2012 - 2020 JJ Allaire, Dirk Eddelbuettel and Romain Francois
5 // Copyright (C) 2021 JJ Allaire, Dirk Eddelbuettel, Romain Francois and IƱaki Ucar
6 //
7 // This file is part of Rcpp.
8 //
9 // Rcpp is free software: you can redistribute it and/or modify it
10 // under the terms of the GNU General Public License as published by
11 // the Free Software Foundation, either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // Rcpp is distributed in the hope that it will be useful, but
15 // WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Rcpp. If not, see <http://www.gnu.org/licenses/>.
21 
22 #define COMPILING_RCPP
23 
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <errno.h>
27 
28 #include <cstring>
29 
30 #include <string>
31 #include <vector>
32 #include <map>
33 #include <set>
34 #include <algorithm>
35 #include <fstream>
36 #include <sstream>
37 
38 #define RCPP_NO_SUGAR
39 #include <Rcpp.h>
40 
41 /*******************************************************************
42  * AttributesUtil.h
43  *******************************************************************/
44 
45 namespace Rcpp {
46 namespace attributes {
47 
48  // Utility class for getting file existence and last modified time
49  class FileInfo {
50  public:
51 
52  // create from path
53  explicit FileInfo(const std::string& path);
54 
55  // create from R list
56  explicit FileInfo(const List& fileInfo) { // #nocov start
57  path_ = as<std::string>(fileInfo["path"]);
58  exists_ = as<bool>(fileInfo["exists"]);
59  lastModified_ = as<double>(fileInfo["lastModified"]);
60  } // #nocov end
61 
62  // convert to R list
63  List toList() const {
64  List fileInfo;
65  fileInfo["path"] = path_;
66  fileInfo["exists"] = exists_;
67  fileInfo["lastModified"] = lastModified_;
68  return fileInfo;
69  }
70 
71  std::string path() const { return path_; }
72  bool exists() const { return exists_; }
73  double lastModified() const { return lastModified_; }
74 
75  std::string extension() const {
76  std::string::size_type pos = path_.find_last_of('.');
77  if (pos != std::string::npos)
78  return path_.substr(pos);
79  else
80  return ""; // #nocov
81  }
82 
83  bool operator<(const FileInfo& other) const {
84  return path_ < other.path_;
85  };
86 
87  bool operator==(const FileInfo& other) const {
88  return path_ == other.path_ &&
89  exists_ == other.exists_ &&
91  };
92 
93  bool operator!=(const FileInfo& other) const {
94  return ! (*this == other);
95  };
96 
97  std::ostream& operator<<(std::ostream& os) const {
98  os << path_;
99  return os;
100  }
101 
102  private:
103  std::string path_;
104  bool exists_;
105  double lastModified_;
106  };
107 
108  // Remove a file
109  bool removeFile(const std::string& path);
110 
111  // Recursively create a directory
112  void createDirectory(const std::string& path);
113 
114  // Known whitespace chars
115  extern const char * const kWhitespaceChars;
116 
117  // Query whether a character is whitespace
118  bool isWhitespace(char ch);
119 
120  // Trim a string
121  void trimWhitespace(std::string* pStr);
122 
123  // Strip trailing line comments
124  void stripTrailingLineComments(std::string* pStr);
125 
126  // Strip balanced quotes from around a string (assumes already trimmed)
127  void stripQuotes(std::string* pStr);
128 
129  // is the passed string quoted?
130  bool isQuoted(const std::string& str);
131 
132  // does a string end with another string?
133  bool endsWith(const std::string& str, const std::string& suffix);
134 
135  // show a warning message
136  void showWarning(const std::string& msg);
137 
138  // is the line a C++ roxygen comment? (started with //')
139  bool isRoxygenCpp(const std::string& str);
140 
141 } // namespace attributes
142 } // namespace Rcpp
143 
144 
145 /*******************************************************************
146  * AttributesTypes.h
147  *******************************************************************/
148 
149 namespace Rcpp {
150 namespace attributes {
151 
152  // Known attribute names & parameters
153  const char * const kExportAttribute = "export";
154  const char * const kExportName = "name";
155  const char * const kExportRng = "rng";
156  const char * const kExportInvisible = "invisible";
157  const char * const kInitAttribute = "init";
158  const char * const kDependsAttribute = "depends";
159  const char * const kPluginsAttribute = "plugins";
160  const char * const kInterfacesAttribute = "interfaces";
161  const char * const kInterfaceR = "r";
162  const char * const kInterfaceCpp = "cpp";
163  const char * const kParamValueFalse = "false";
164  const char * const kParamValueTrue = "true";
165  const char * const kParamValueFALSE = "FALSE";
166  const char * const kParamValueTRUE = "TRUE";
167 
168  // Type info
169  class Type {
170  public:
171  Type(): isConst_(false), isReference_(false) {}
172  Type(const std::string& name, bool isConst, bool isReference)
174  {
175  }
176  bool empty() const { return name().empty(); }
177 
178  bool operator==(const Type& other) const { // #nocov start
179  return name_ == other.name_ &&
180  isConst_ == other.isConst_ &&
181  isReference_ == other.isReference_;
182  }; // #nocov end
183 
184  bool operator!=(const Type& other) const {
185  return !(*this == other);
186  };
187 
188  const std::string& name() const { return name_; }
189  std::string full_name() const {
190  std::string res ;
191  if( isConst() ) res += "const " ;
192  res += name() ;
193  if( isReference() ) res += "&" ;
194  return res ;
195  }
196 
197  bool isVoid() const { return name() == "void"; }
198  bool isConst() const { return isConst_; }
199  bool isReference() const { return isReference_; }
200 
201  private:
202  std::string name_;
203  bool isConst_;
204  bool isReference_;
205  };
206 
207  // Argument info
208  class Argument {
209  public:
210  Argument() {}
211  Argument(const std::string& name,
212  const Type& type,
213  const std::string& defaultValue)
215  {
216  }
217 
218  bool empty() const { return type().empty(); }
219 
220  bool operator==(const Argument& other) const { // #nocov start
221  return name_ == other.name_ &&
222  type_ == other.type_ &&
223  defaultValue_ == other.defaultValue_;
224  }; // #nocov end
225 
226  bool operator!=(const Argument& other) const {
227  return !(*this == other);
228  };
229 
230 
231  const std::string& name() const { return name_; }
232  const Type& type() const { return type_; }
233  const std::string& defaultValue() const { return defaultValue_; }
234 
235  private:
236  std::string name_;
238  std::string defaultValue_;
239  };
240 
241  // Function info
242  class Function {
243  public:
244  Function() {}
245  Function(const Type& type,
246  const std::string& name,
247  const std::vector<Argument>& arguments)
249  {
250  }
251 
252  Function renamedTo(const std::string& name) const { // #nocov start
253  return Function(type(), name, arguments());
254  }
255 
256  std::string signature() const { return signature(name()); }
257  std::string signature(const std::string& name) const;
258 
259  bool isHidden() const {
260  return name().find_first_of('.') == 0;
261  } // #nocov end
262 
263  bool empty() const { return name().empty(); }
264 
265  bool operator==(const Function& other) const { // #nocov start
266  return type_ == other.type_ &&
267  name_ == other.name_ &&
268  arguments_ == other.arguments_;
269  }; // #nocov end
270 
271  bool operator!=(const Function& other) const {
272  return !(*this == other);
273  };
274 
275  const Type& type() const { return type_; }
276  const std::string& name() const { return name_; }
277  const std::vector<Argument>& arguments() const { return arguments_; }
278 
279  private:
281  std::string name_;
282  std::vector<Argument> arguments_;
283  };
284 
285  // Attribute parameter (with optional value)
286  class Param {
287  public:
288  Param() {}
289  explicit Param(const std::string& paramText);
290  bool empty() const { return name().empty(); }
291 
292  bool operator==(const Param& other) const { // #nocov start
293  return name_ == other.name_ &&
294  value_ == other.value_;
295  }; // #nocov end
296 
297  bool operator!=(const Param& other) const {
298  return !(*this == other);
299  };
300 
301 
302  const std::string& name() const { return name_; }
303  const std::string& value() const { return value_; } // #nocov
304 
305  private:
306  std::string name_;
307  std::string value_;
308  };
309 
310  // Attribute (w/ optional params and signature of function it qualifies)
311  class Attribute {
312  public:
313  Attribute() {}
314  Attribute(const std::string& name,
315  const std::vector<Param>& params,
316  const Function& function,
317  const std::vector<std::string>& roxygen)
319  {
320  }
321 
322  bool empty() const { return name().empty(); } // #nocov start
323 
324  bool operator==(const Attribute& other) const {
325  return name_ == other.name_ &&
326  params_ == other.params_ &&
327  function_ == other.function_ &&
328  roxygen_ == other.roxygen_;
329  }; // #nocov end
330 
331  bool operator!=(const Attribute& other) const {
332  return !(*this == other);
333  };
334 
335 
336  const std::string& name() const { return name_; }
337 
338  const std::vector<Param>& params() const { return params_; }
339 
340  Param paramNamed(const std::string& name) const;
341 
342  bool hasParameter(const std::string& name) const {
343  return !paramNamed(name).empty();
344  }
345 
346  const Function& function() const { return function_; }
347 
348  bool isExportedFunction() const {
349  return (name() == kExportAttribute) && !function().empty();
350  }
351 
352  std::string exportedName() const {
353 
354  // check for explicit name parameter
356  {
357  return paramNamed(kExportName).value(); // #nocov
358  }
359  // otherwise un-named parameter in the first slot
360  else if (!params().empty() && params()[0].value().empty())
361  {
362  return params()[0].name(); // #nocov
363  }
364  // otherwise the actual function name
365  {
366  return function().name();
367  }
368  }
369 
370  std::string exportedCppName() const { // #nocov start
371  std::string name = exportedName();
372  std::replace(name.begin(), name.end(), '.', '_');
373  return name;
374  } // #nocov end
375 
376  bool rng() const {
377  Param rngParam = paramNamed(kExportRng);
378  if (!rngParam.empty())
379  return rngParam.value() == kParamValueTrue || // #nocov
380  rngParam.value() == kParamValueTRUE; // #nocov
381  else
382  return true;
383  }
384 
385  bool invisible() const {
386  Param invisibleParam = paramNamed(kExportInvisible);
387  if (!invisibleParam.empty())
388  return invisibleParam.value() == kParamValueTrue || // #nocov
389  invisibleParam.value() == kParamValueTRUE; // #nocov
390  else
391  return false;
392  }
393 
394  const std::vector<std::string>& roxygen() const { return roxygen_; }
395 
396  private:
397  std::string name_;
398  std::vector<Param> params_;
400  std::vector<std::string> roxygen_;
401  };
402 
403  // Operator << for parsed types
404  std::ostream& operator<<(std::ostream& os, const Type& type);
405  std::ostream& operator<<(std::ostream& os, const Argument& argument);
406  std::ostream& operator<<(std::ostream& os, const Function& function);
407  std::ostream& operator<<(std::ostream& os, const Param& param);
408  std::ostream& operator<<(std::ostream& os, const Attribute& attribute);
409 
410  // interface to source file attributes
412  {
413  public:
414  virtual ~SourceFileAttributes() {};
415  virtual const std::string& sourceFile() const = 0;
416  virtual bool hasInterface(const std::string& name) const = 0;
417 
418  typedef std::vector<Attribute>::const_iterator const_iterator;
419  virtual const_iterator begin() const = 0;
420  virtual const_iterator end() const = 0;
421 
422  virtual const std::vector<std::string>& modules() const = 0;
423 
424  virtual const std::vector<std::vector<std::string> >& roxygenChunks() const = 0;
425 
426  virtual bool hasGeneratorOutput() const = 0;
427 
428  virtual bool hasPackageInit() const = 0;
429  };
430 
431 
432 } // namespace attributes
433 } // namespace Rcpp
434 
435 
436 
437 /*******************************************************************
438  * AttributesParser.h
439  *******************************************************************/
440 
441 namespace Rcpp {
442 namespace attributes {
443 
444  // Helper class for determining whether we are in a comment
445  class CommentState {
446  public:
447  CommentState() : inComment_(false) {}
448  private:
449  // prohibit copying
450  CommentState(const CommentState&);
452  public:
453  bool inComment() const { return inComment_; }
454  void submitLine(const std::string& line);
455  void reset() { inComment_ = false; }
456  private:
458  };
459 
460  // Class used to parse and return attribute information from a source file
462  public:
463  explicit SourceFileAttributesParser(const std::string& sourceFile,
464  const std::string& packageFile,
465  bool parseDependencies);
466 
467  private:
468  // prohibit copying
471 
472  public:
473  // implemetnation of SourceFileAttributes interface
474  virtual const std::string& sourceFile() const { // #nocov
475  return sourceFile_; // #nocov
476  }
477  virtual const_iterator begin() const { return attributes_.begin(); }
478  virtual const_iterator end() const { return attributes_.end(); }
479 
480  virtual const std::vector<std::string>& modules() const
481  {
482  return modules_;
483  }
484 
485  virtual const std::vector<std::vector<std::string> >& roxygenChunks() const {
486  return roxygenChunks_;
487  }
488 
489  virtual bool hasGeneratorOutput() const
490  {
491  return !attributes_.empty() ||
492  !modules_.empty() ||
493  !roxygenChunks_.empty();
494  }
495 
496  virtual bool hasInterface(const std::string& name) const {
497 
498  for (const_iterator it=begin(); it != end(); ++it) {
499  if (it->name() == kInterfacesAttribute) {
500  return it->hasParameter(name); // #nocov
501  }
502  }
503 
504  // if there's no interfaces attrbute we default to R
505  if (name == kInterfaceR)
506  return true;
507  else
508  return false;
509  }
510 
511  // Was a package init function found?
512  bool hasPackageInit() const {
513  return hasPackageInit_;
514  }
515 
516  // Get lines of embedded R code
517  const std::vector<std::string>& embeddedR() const {
518  return embeddedR_;
519  }
520 
521  // Get source dependencies
522  const std::vector<FileInfo>& sourceDependencies() const {
523  return sourceDependencies_;
524  };
525 
526  private:
527 
528  // Parsing helpers
529  Attribute parseAttribute(const std::vector<std::string>& match,
530  int lineNumber);
531  std::vector<Param> parseParameters(const std::string& input);
532  Function parseFunction(size_t lineNumber);
533  std::string parseSignature(size_t lineNumber);
534  std::vector<std::string> parseArguments(const std::string& argText);
535  Type parseType(const std::string& text);
536 
537  // Validation helpers
538  bool isKnownAttribute(const std::string& name) const;
539  void attributeWarning(const std::string& message,
540  const std::string& attribute,
541  size_t lineNumber);
542  void attributeWarning(const std::string& message, size_t lineNumber);
543  void rcppExportWarning(const std::string& message, size_t lineNumber);
544  void rcppExportNoFunctionFoundWarning(size_t lineNumber);
545  void rcppExportInvalidParameterWarning(const std::string& param,
546  size_t lineNumber);
547  void rcppInterfacesWarning(const std::string& message,
548  size_t lineNumber);
549 
550  private:
551  std::string sourceFile_;
553  std::vector<Attribute> attributes_;
554  std::vector<std::string> modules_;
556  std::vector<std::string> embeddedR_;
557  std::vector<FileInfo> sourceDependencies_;
558  std::vector<std::vector<std::string> > roxygenChunks_;
559  std::vector<std::string> roxygenBuffer_;
560  };
561 
562 } // namespace attributes
563 } // namespace Rcpp
564 
565 
566 /*******************************************************************
567  * AttributesGen.h
568  *******************************************************************/
569 
570 namespace Rcpp {
571 namespace attributes {
572 
573  // Abstract class which manages writing of code for compileAttributes
574  class ExportsGenerator {
575  protected:
576  ExportsGenerator(const std::string& targetFile,
577  const std::string& package,
578  const std::string& commentPrefix);
579 
580  private:
581  // prohibit copying
584 
585  public:
586  virtual ~ExportsGenerator() {}
587 
588  // Name of target file and package
589  const std::string& targetFile() const { return targetFile_; }
590  const std::string& package() const { return package_; }
591  const std::string& packageCpp() const { return packageCpp_; }
592  const std::string packageCppPrefix() const { return "_" + packageCpp(); }
593 
594  // Abstract interface for code generation
595  virtual void writeBegin() = 0;
596  void writeFunctions(const SourceFileAttributes& attributes,
597  bool verbose); // see doWriteFunctions below
598  virtual void writeEnd(bool hasPackageInit) = 0;
599 
600  virtual bool commit(const std::vector<std::string>& includes) = 0;
601 
602  // Remove the generated file entirely
603  bool remove();
604 
605  // Allow generator to appear as a std::ostream&
606  operator std::ostream&() {
607  return codeStream_;
608  }
609 
610  protected:
611 
612  // Allow access to the output stream
613  std::ostream& ostr() {
614  return codeStream_;
615  }
616 
617  bool hasCppInterface() const {
618  return hasCppInterface_;
619  }
620 
621  // Shared knowledge about function namees
622  std::string exportValidationFunction() {
623  return "RcppExport_validate";
624  }
626  return packageCppPrefix() + "_" + exportValidationFunction();
627  }
628  std::string registerCCallableExportedName() { // #nocov
629  return packageCppPrefix() + "_RcppExport_registerCCallable"; // #nocov
630  }
631 
632  // Commit the stream -- is a no-op if the existing code is identical
633  // to the generated code. Returns true if data was written and false
634  // if it wasn't (throws exception on io error)
635  bool commit(const std::string& preamble = std::string());
636 
637  // Convert a dot in package name to underscore for use in header file name
638  std::string dotNameHelper(const std::string & name) const;
639 
640  private:
641 
642  // Private virtual for doWriteFunctions so the base class
643  // can always intercept writeFunctions
644  virtual void doWriteFunctions(const SourceFileAttributes& attributes,
645  bool verbose) = 0;
646 
647  // Check whether it's safe to overwrite this file (i.e. whether we
648  // generated the file in the first place)
649  bool isSafeToOverwrite() const {
650  return existingCode_.empty() ||
651  (existingCode_.find(generatorToken()) != std::string::npos);
652  }
653 
654  // UUID that we write into a comment within the file (so that we can
655  // strongly identify that a file was generated by us before overwriting it)
656  std::string generatorToken() const {
657  return "10BE3573-1514-4C36-9D1C-5A225CD40393";
658  }
659 
660  private:
661  std::string targetFile_;
662  std::string package_;
663  std::string packageCpp_;
664  std::string commentPrefix_;
665  std::string existingCode_;
666  std::ostringstream codeStream_;
668  };
669 
670  // Class which manages generating RcppExports.cpp
672  public:
673  explicit CppExportsGenerator(const std::string& packageDir,
674  const std::string& package,
675  const std::string& fileSep);
676 
677  virtual void writeBegin() {};
678  virtual void writeEnd(bool hasPackageInit);
679  virtual bool commit(const std::vector<std::string>& includes);
680 
681  private:
682  virtual void doWriteFunctions(const SourceFileAttributes& attributes,
683  bool verbose);
684 
685  std::string registerCCallable(size_t indent,
686  const std::string& exportedName,
687  const std::string& name) const;
688 
689  private:
690  // for generating calls to init functions
691  std::vector<Attribute> initFunctions_;
692 
693  // for generating C++ interfaces
694  std::vector<Attribute> cppExports_;
695 
696  // for generating Rcpp::export native routine registration
697  std::vector<Attribute> nativeRoutines_;
698 
699  // for generating module native routine registration
700  std::vector<std::string> modules_;
701  };
702 
703  // Class which manages generating PackageName_RcppExports.h header file
705  public:
706  CppExportsIncludeGenerator(const std::string& packageDir,
707  const std::string& package,
708  const std::string& fileSep);
709 
710  virtual void writeBegin();
711  virtual void writeEnd(bool hasPackageInit);
712  virtual bool commit(const std::vector<std::string>& includes);
713 
714  private:
715  virtual void doWriteFunctions(const SourceFileAttributes& attributes,
716  bool verbose);
717  std::string getCCallable(const std::string& function) const;
718  std::string getHeaderGuard() const;
719 
720  private:
721  std::string includeDir_;
722  };
723 
724  // Class which manages generating PackageName.h header file
726  public:
727  CppPackageIncludeGenerator(const std::string& packageDir,
728  const std::string& package,
729  const std::string& fileSep);
730 
731  virtual void writeBegin() {}
732  virtual void writeEnd(bool hasPackageInit);
733  virtual bool commit(const std::vector<std::string>& includes);
734 
735  private:
736  virtual void doWriteFunctions(const SourceFileAttributes&, bool) {}
737  std::string getHeaderGuard() const;
738 
739  private:
740  std::string includeDir_;
741  };
742 
743 
744  // Class which manages generator RcppExports.R
745  class RExportsGenerator : public ExportsGenerator {
746  public:
747  RExportsGenerator(const std::string& packageDir,
748  const std::string& package,
749  bool registration,
750  const std::string& fileSep);
751 
752  virtual void writeBegin() {}
753  virtual void writeEnd(bool hasPackageInit);
754  virtual bool commit(const std::vector<std::string>& includes);
755 
756  private:
757  virtual void doWriteFunctions(const SourceFileAttributes& attributes,
758  bool verbose);
759 
760  bool registration_;
761 
762  };
763 
764  // Class to manage and dispatch to a list of generators
765  class ExportsGenerators {
766  public:
767  typedef std::vector<ExportsGenerator*>::iterator Itr;
768 
770  virtual ~ExportsGenerators();
771 
772  void add(ExportsGenerator* pGenerator);
773 
774  void writeBegin();
775  void writeFunctions(const SourceFileAttributes& attributes,
776  bool verbose);
777  void writeEnd(bool hasPackageInit);
778 
779  // Commit and return a list of the files that were updated
780  std::vector<std::string> commit(
781  const std::vector<std::string>& includes);
782 
783  // Remove and return a list of files that were removed
784  std::vector<std::string> remove();
785 
786  private:
787  // prohibit copying
790 
791  private:
792  std::vector<ExportsGenerator*> generators_;
793  };
794 
795  // Standalone generation helpers (used by sourceCpp)
796 
797  std::string generateRArgList(const Function& function);
798 
799  void initializeGlobals(std::ostream& ostr);
800 
801  void generateCpp(std::ostream& ostr,
802  const SourceFileAttributes& attributes,
803  bool includePrototype,
804  bool cppInterface,
805  const std::string& contextId);
806 
807 } // namespace attributes
808 } // namespace Rcpp
809 
810 
811 /*******************************************************************
812  * AttributesParser.cpp
813  *******************************************************************/
814 
815 namespace Rcpp {
816 namespace attributes {
817 
818  namespace {
819 
820  Rcpp::List regexMatches(Rcpp::CharacterVector lines,
821  const std::string& regex)
822  {
823  Rcpp::Environment base("package:base");
824  Rcpp::Function regexec = base["regexec"];
825  Rcpp::Function regmatches = base["regmatches"];
826  Rcpp::RObject result = regexec(regex, lines);
827  Rcpp::List matches = regmatches(lines, result);
828  return matches;
829  }
830 
831  template <typename Stream>
832  void readFile(const std::string& file, Stream& os) {
833  std::ifstream ifs(file.c_str());
834  if (ifs.fail())
835  throw Rcpp::file_io_error(file); // #nocov
836  os << ifs.rdbuf();
837  ifs.close();
838  }
839 
840  template <typename Collection>
841  void readLines(std::istream& is, Collection* pLines) {
842  pLines->clear();
843  std::string line;
844  while(std::getline(is, line)) {
845  // strip \r (for the case of windows line terminators on posix)
846  if (line.length() > 0 && *line.rbegin() == '\r')
847  line.erase(line.length()-1, 1);
849  pLines->push_back(line);
850  }
851  }
852 
853  bool addUniqueDependency(Rcpp::CharacterVector include,
854  std::vector<FileInfo>* pDependencies) {
855 
856  // return false if we already have this include
857  std::string path = Rcpp::as<std::string>(include);
858  for (size_t i = 0; i<pDependencies->size(); ++i) {
859  if (pDependencies->at(i).path() == path)
860  return false;
861  }
862 
863  // add it and return true
864  pDependencies->push_back(FileInfo(path));
865  return true;
866  }
867 
868  void parseSourceDependencies(const std::string& sourceFile,
869  std::vector<FileInfo>* pDependencies) {
870 
871  // import R functions
873  Rcpp::Function dirname = baseEnv["dirname"];
874  Rcpp::Function filepath = baseEnv["file.path"];
875  Rcpp::Function normalizePath = baseEnv["normalizePath"];
876  Rcpp::Function fileExists = baseEnv["file.exists"];
878  "tools");
879  Rcpp::Function filePathSansExt = toolsEnv["file_path_sans_ext"];
880 
881  // get the path to the source file's directory
882  Rcpp::CharacterVector sourceDir = dirname(sourceFile);
883 
884  // read the source file into a buffer
885  std::stringstream buffer;
886  readFile(sourceFile, buffer);
887 
888  // Now read into a list of strings (which we can pass to regexec)
889  // First read into a std::deque (which will handle lots of append
890  // operations efficiently) then copy into an R chracter vector
891  std::deque<std::string> lines;
892  readLines(buffer, &lines);
893  Rcpp::CharacterVector linesVector = Rcpp::wrap(lines);
894 
895  // look for local includes
896  Rcpp::List matches = regexMatches(
897  linesVector, "^\\s*#include\\s*\"([^\"]+)\"\\s*$");
898 
899  // accumulate local includes (skip commented sections)
900  CommentState commentState;
901  std::vector<FileInfo> newDependencies;
902  for (int i = 0; i<matches.size(); i++) {
903  std::string line = lines[i];
904  commentState.submitLine(line);
905  if (!commentState.inComment()) {
906  // get the match
907  const Rcpp::CharacterVector match = matches[i];
908  if (match.size() == 2) {
909  // compose a full file path for the match
910  Rcpp::CharacterVector include =
911  filepath(sourceDir, std::string(match[1]));
912  // if it exists then normalize and add to our list
913  LogicalVector exists = fileExists(include);
914  if (exists[0]) {
915  include = normalizePath(include, "/");
916  if (addUniqueDependency(include, pDependencies)) {
917  newDependencies.push_back(
918  FileInfo(Rcpp::as<std::string>(include)));
919  }
920 
921  std::vector<std::string> exts;
922  exts.push_back(".cc");
923  exts.push_back(".cpp");
924  for (size_t i = 0; i<exts.size(); ++i) {
925 
926  // look for corresponding cpp file and add it
927  std::string file = Rcpp::as<std::string>( // #nocov
928  filePathSansExt(include)) + exts[i];
929 
930  exists = fileExists(file);
931  if (exists[0]) {
932  if (addUniqueDependency(file,
933  pDependencies)) {
934  FileInfo fileInfo(file);
935  newDependencies.push_back(fileInfo);
936  }
937  }
938  }
939  }
940  }
941  }
942  }
943 
944  // look for dependencies recursively
945  for (size_t i = 0; i<newDependencies.size(); i++) {
946  FileInfo dependency = newDependencies[i];
947  parseSourceDependencies(dependency.path(), pDependencies);
948  }
949  }
950 
951  // parse the source dependencies from the passed lines
952  std::vector<FileInfo> parseSourceDependencies(
953  std::string sourceFile) {
954 
955  // normalize source file
957  Rcpp::Function normalizePath = baseEnv["normalizePath"];
958  sourceFile = Rcpp::as<std::string>(normalizePath(sourceFile, "/"));
959 
960  // parse dependencies
961  std::vector<FileInfo> dependencies;
962  parseSourceDependencies(sourceFile, &dependencies);
963 
964  // remove main source file
965  dependencies.erase(std::remove(dependencies.begin(), // #nocov
966  dependencies.end(),
967  FileInfo(sourceFile)),
968  dependencies.end());
969 
970  return dependencies;
971  }
972 
973  // Parse embedded R code chunks from a file (receives the lines of the
974  // file as a CharcterVector for using with regexec and as a standard
975  // stl vector for traversal/insepection)
976  std::vector<std::string> parseEmbeddedR(
977  Rcpp::CharacterVector linesVector,
978  const std::deque<std::string>& lines) {
979  Rcpp::List matches = regexMatches(linesVector,
980  "^\\s*/\\*{3,}\\s*[Rr]\\s*$");
981  bool withinRBlock = false;
982  CommentState commentState;
983  std::vector<std::string> embeddedR;
984 
985  for (int i = 0; i<matches.size(); i++) {
986 
987  // track comment state
988  std::string line = lines[i];
989  commentState.submitLine(line);
990 
991  // is this a line that begins an R code block?
992  const Rcpp::CharacterVector match = matches[i];
993  bool beginRBlock = match.size() > 0;
994 
995  // check state and do the right thing
996  if (beginRBlock) {
997  withinRBlock = true; // #nocov
998  }
999  else if (withinRBlock) {
1000  if (commentState.inComment()) // #nocov start
1001  embeddedR.push_back(line);
1002  else
1003  withinRBlock = false; // #nocov end
1004  }
1005  }
1006 
1007  return embeddedR;
1008  }
1009 
1010  } // anonymous namespace
1011 
1012 
1013  // Generate a type signature for the function with the provided name
1014  // (type signature == function pointer declaration)
1015  std::string Function::signature(const std::string& name) const { // #nocov start
1016 
1017  std::ostringstream ostr;
1018 
1019  ostr << type() << "(*" << name << ")(";
1020 
1021  const std::vector<Argument>& args = arguments();
1022  for (std::size_t i = 0; i<args.size(); i++) {
1023  ostr << args[i].type();
1024  if (i != (args.size()-1))
1025  ostr << ",";
1026  }
1027  ostr << ")";
1028 
1029  return ostr.str(); // #nocov end
1030  }
1031 
1032 
1033  // Parse attribute parameter from parameter text
1034  Param::Param(const std::string& paramText)
1035  {
1036  // parse out name/value pair if there is one
1037  std::string::size_type pos = paramText.find("=") ;
1038  if ( pos != std::string::npos ) {
1039  // name
1040  name_ = paramText.substr(0, pos); // #nocov start
1042  // value
1043  value_ = paramText.substr(pos + 1) ;
1045  stripQuotes(&value_); // #nocov end
1046  }
1047  else {
1048  name_ = paramText;
1050  stripQuotes(&name_);
1051  }
1052  }
1053 
1054  // Check if the attribute has a parameter of a paricular name
1055  Param Attribute::paramNamed(const std::string& name) const {
1056  for (std::vector<Param>::const_iterator
1057  it = params_.begin(); it != params_.end(); ++it) {
1058  if (it->name() == name) // #nocov
1059  return *it; // #nocov
1060  }
1061  return Param();
1062  }
1063 
1064  // Type operator <<
1065  std::ostream& operator<<(std::ostream& os, const Type& type) {
1066  if (!type.empty()) {
1067  if (type.isConst())
1068  os << "const ";
1069  os << type.name();
1070  if (type.isReference())
1071  os << "&";
1072  }
1073  return os;
1074  }
1075 
1076  // Print argument
1077  void printArgument(std::ostream& os,
1078  const Argument& argument,
1079  bool printDefault = true) {
1080  if (!argument.empty()) {
1081  os << argument.type();
1082  if (!argument.name().empty()) {
1083  os << " ";
1084  os << argument.name();
1085  if (printDefault && !argument.defaultValue().empty())
1086  os << " = " << argument.defaultValue(); // #nocov
1087  }
1088  }
1089  }
1090 
1091  // Argument operator <<
1092  std::ostream& operator<<(std::ostream& os, const Argument& argument) {// #nocov start
1093  printArgument(os, argument);
1094  return os; // #nocov end
1095  }
1097  // Print function
1098  void printFunction(std::ostream& os,
1099  const Function& function,
1100  bool printArgDefaults = true) {
1101 
1102  if (!function.empty()) {
1103  if (!function.type().empty()) {
1104  os << function.type();
1105  os << " ";
1106  }
1107  os << function.name();
1108  os << "(";
1109  const std::vector<Argument>& arguments = function.arguments();
1110  for (std::size_t i = 0; i<arguments.size(); i++) {
1111  printArgument(os, arguments[i], printArgDefaults);
1112  if (i != (arguments.size()-1))
1113  os << ", ";
1114  }
1115  os << ")";
1116  }
1117  }
1118 
1119  // Function operator <<
1120  std::ostream& operator<<(std::ostream& os, const Function& function) {// #nocov start
1121  printFunction(os, function);
1122  return os;
1123  }
1125  // Param operator <<
1126  std::ostream& operator<<(std::ostream& os, const Param& param) {
1127  if (!param.empty()) {
1128  os << param.name();
1129  if (!param.value().empty())
1130  os << "=" << param.value();
1131  }
1132  return os;
1133  }
1134 
1135  // Attribute operator <<
1136  std::ostream& operator<<(std::ostream& os, const Attribute& attribute) {
1137  if (!attribute.empty()) {
1138  os << "[[Rcpp::" << attribute.name();
1139  const std::vector<Param>& params = attribute.params();
1140  if (params.size() > 0) {
1141  os << "(";
1142  for (std::size_t i = 0; i<params.size(); i++) {
1143  os << params[i];
1144  if (i != (params.size()-1))
1145  os << ",";
1146  }
1147  os << ")";
1148  }
1149  os << "]]";
1150 
1151  if (!attribute.function().empty())
1152  os << " " << attribute.function();
1153  }
1154  return os; // #nocov end
1155  }
1156 
1157  // Parse the attributes from a source file
1159  const std::string& sourceFile,
1160  const std::string& packageName,
1161  bool parseDependencies)
1162  : sourceFile_(sourceFile), hasPackageInit_(false)
1163  {
1164 
1165  // transform packageName to valid C++ symbol
1166  std::string packageNameCpp = packageName;
1167  std::replace(packageNameCpp.begin(), packageNameCpp.end(), '.', '_');
1168 
1169  // First read the entire file into a std::stringstream so we can check
1170  // it for attributes (we don't want to do any of our more expensive
1171  // processing steps if there are no attributes to parse)
1172  std::stringstream buffer;
1173  readFile(sourceFile_, buffer);
1174  std::string contents = buffer.str();
1175 
1176  // Check for attribute signature
1177  if (contents.find("[[Rcpp::") != std::string::npos ||
1178  contents.find("RCPP_MODULE") != std::string::npos ||
1179  contents.find("R_init_" + packageNameCpp) != std::string::npos) {
1180 
1181  // Now read into a list of strings (which we can pass to regexec)
1182  // First read into a std::deque (which will handle lots of append
1183  // operations efficiently) then copy into an R character vector
1184  std::deque<std::string> lines;
1185  readLines(buffer, &lines);
1186  lines_ = Rcpp::wrap(lines);
1187 
1188  // Scan for attributes
1189  CommentState commentState;
1190  Rcpp::List matches = regexMatches(lines_,
1191  "^\\s*//\\s*\\[\\[Rcpp::(\\w+)(\\(.*?\\))?\\]\\]\\s*$");
1192  for (int i = 0; i<matches.size(); i++) {
1193 
1194  // track whether we are in a comment and bail if we are in one
1195  std::string line = lines[i];
1196  commentState.submitLine(line);
1197  if (commentState.inComment())
1198  continue;
1199 
1200  // attribute line
1201  const Rcpp::CharacterVector match = matches[i];
1202  if (match.size() > 0) {
1203 
1204  // if the match size isn't 3 then regmatches has not behaved
1205  // as expected (it should return a vector of either 0 or 3
1206  // elements). we don't ever expect this to occur but if it
1207  // does let's not crash
1208  if (match.size() != 3)
1209  continue; // #nocov
1210 
1211  // add the attribute
1212  Attribute attr = parseAttribute(
1213  Rcpp::as<std::vector<std::string> >(match), i);
1214  attributes_.push_back(attr);
1215  }
1216 
1217  // if it's not an attribute line then it could still be a
1218  // line of interest (e.g. roxygen comment)
1219  else {
1220 
1221  // save roxygen comments
1222  if (line.find("//'") == 0) {
1223  std::string roxLine = "#" + line.substr(2);
1224  roxygenBuffer_.push_back(roxLine);
1225  }
1226 
1227  // a non-roxygen line causes us to clear the roxygen buffer
1228  else if (!roxygenBuffer_.empty()) {
1229  roxygenChunks_.push_back(roxygenBuffer_); // #nocov
1230  roxygenBuffer_.clear(); // #nocov
1231  }
1232  }
1233  }
1234 
1235  // Scan for Rcpp modules
1236  commentState.reset();
1237  Rcpp::List modMatches = regexMatches(lines_,
1238  "^\\s*RCPP_MODULE\\s*\\(\\s*(\\w+)\\s*\\).*$");
1239  for (int i = 0; i<modMatches.size(); i++) {
1240 
1241  // track whether we are in a comment and bail if we are in one
1242  std::string line = lines[i];
1243  commentState.submitLine(line);
1244  if (commentState.inComment())
1245  continue;
1246 
1247  // get the module declaration
1248  Rcpp::CharacterVector match = modMatches[i];
1249  if (match.size() > 0) {
1250  const char * name = match[1];
1251  modules_.push_back(name);
1252  }
1253  }
1254 
1255  // Scan for package init function
1256  hasPackageInit_ = false;
1257  commentState.reset();
1258  std::string pkgInit = "R_init_" + packageNameCpp;
1259  Rcpp::List initMatches = regexMatches(lines_, "^[^/]+" + pkgInit + ".*DllInfo.*$");
1260  for (int i = 0; i<initMatches.size(); i++) {
1261 
1262  // track whether we are in a comment and bail if we are in one
1263  std::string line = lines[i];
1264  commentState.submitLine(line);
1265  if (commentState.inComment())
1266  continue;
1267 
1268  // check for a match
1269  Rcpp::CharacterVector match = initMatches[i];
1270  if (match.size() > 0) {
1271  hasPackageInit_ = true; // #nocov start
1272  break;
1273  } // #nocov end
1274  }
1275 
1276  // Parse embedded R
1277  embeddedR_ = parseEmbeddedR(lines_, lines);
1278 
1279  // Recursively parse dependencies if requested
1280  if (parseDependencies) {
1281 
1282  // get source dependencies
1283  sourceDependencies_ = parseSourceDependencies(sourceFile);
1284 
1285  // parse attributes and modules from each dependent file
1286  for (size_t i = 0; i<sourceDependencies_.size(); i++) {
1287 
1288  // perform parse
1289  std::string dependency = sourceDependencies_[i].path();
1290  SourceFileAttributesParser parser(dependency, packageName, false);
1291 
1292  // copy to base attributes (if it's a new attribute)
1293  for (SourceFileAttributesParser::const_iterator // #nocov start
1294  it = parser.begin(); it != parser.end(); ++it) {
1295  if (std::find(attributes_.begin(),
1296  attributes_.end(),
1297  *it) == attributes_.end()) {
1298  attributes_.push_back(*it); // #nocov end
1299  }
1300  }
1301 
1302  // copy to base modules
1303  std::copy(parser.modules().begin(),
1304  parser.modules().end(),
1305  std::back_inserter(modules_));
1306  }
1307  }
1308  }
1309  }
1310 
1311  // Parse an attribute from the vector returned by regmatches
1312  Attribute SourceFileAttributesParser::parseAttribute(
1313  const std::vector<std::string>& match,
1314  int lineNumber) {
1315 
1316  // Attribute name
1317  std::string name = match[1];
1318 
1319  // Warn if this is an unknown attribute
1320  if (!isKnownAttribute(name)) {
1321  attributeWarning("Unrecognized attribute Rcpp::" + name, // #nocov
1322  lineNumber); // #nocov
1323  }
1324 
1325  // Extract params if we've got them
1326  std::vector<Param> params;
1327  std::string paramsText = match[2];
1328  if (!paramsText.empty()) {
1329 
1330  // we know from the regex that it's enclosed in parens so remove
1331  // trim before we do this just in case someone updates the regex
1332  // to allow for whitespace around the call
1333  trimWhitespace(&paramsText);
1334 
1335  paramsText = paramsText.substr(1, paramsText.size()-2);
1336 
1337  // parse the parameters
1338  params = parseParameters(paramsText);
1339  }
1340 
1341  // Extract function signature if this is a function attribute
1342  // and it doesn't appear at the end of the file
1343  Function function;
1344 
1345  // special handling for export and init
1346  if (name == kExportAttribute || name == kInitAttribute) {
1347 
1348  // parse the function (unless we are at the end of the file in
1349  // which case we print a warning)
1350  if ((lineNumber + 1) < lines_.size())
1351  function = parseFunction(lineNumber + 1);
1352  else
1353  rcppExportWarning("No function found", lineNumber); // #nocov
1354 
1355  // validate parameters
1356  for (std::size_t i=0; i<params.size(); i++) {
1357 
1358  std::string name = params[i].name(); // #nocov start
1359  std::string value = params[i].value();
1360 
1361  // un-named parameter that isn't the first parameter
1362  if (value.empty() && (i > 0)) {
1363  rcppExportWarning("No value specified for parameter '" +
1364  name + "'",
1365  lineNumber);
1366  }
1367  // parameter that isn't name or rng
1368  else if (!value.empty() &&
1369  (name != kExportName) &&
1370  (name != kExportRng) &&
1371  (name != kExportInvisible)) {
1372  rcppExportWarning("Unrecognized parameter '" + name + "'",
1373  lineNumber);
1374  }
1375  // rng that isn't true or false
1376  else if (name == kExportRng) {
1377  if (value != kParamValueFalse &&
1378  value != kParamValueTrue &&
1379  value != kParamValueFALSE &&
1380  value != kParamValueTRUE) {
1381  rcppExportWarning("rng value must be true or false",
1382  lineNumber);
1383  }
1384  }
1385  // invisible that isn't true of false
1386  else if (name == kExportInvisible) {
1387  if (value != kParamValueFalse &&
1388  value != kParamValueTrue &&
1389  value != kParamValueFALSE &&
1390  value != kParamValueTRUE) {
1391  rcppExportWarning("invisible value must be true or false",
1392  lineNumber); // #nocov end
1393  }
1394  }
1395  }
1396  }
1397 
1398  // validate interfaces parameter
1399  else if (name == kInterfacesAttribute) {
1400  if (params.empty()) { // #nocov start
1401  rcppInterfacesWarning("No interfaces specified", lineNumber);//
1402  }
1403  else {
1404  for (std::size_t i=0; i<params.size(); i++) {
1405  std::string param = params[i].name();
1406  if (param != kInterfaceR && param != kInterfaceCpp) {
1407  rcppInterfacesWarning(
1408  "Unknown interface '" + param + "'", lineNumber);
1409  } // #nocov end
1410  }
1411  }
1412 
1413 
1414  }
1415 
1416  // Return attribute
1417  Attribute attribute = Attribute(name, params, function, roxygenBuffer_);
1418  roxygenBuffer_.clear();
1419  return attribute;
1420  }
1421 
1422  // Parse attribute parameters
1423  std::vector<Param> SourceFileAttributesParser::parseParameters(
1424  const std::string& input) {
1425 
1426  const std::string delimiters(",");
1427 
1428  std::vector<Param> params;
1429  std::string::size_type current;
1430  std::string::size_type next = -1;
1431  do { // #nocov
1432  next = input.find_first_not_of(delimiters, next + 1);
1433  if (next == std::string::npos)
1434  break; // #nocov
1435  next -= 1;
1436  current = next + 1;
1437  next = input.find_first_of(delimiters, current);
1438  params.push_back(Param(input.substr(current, next - current)));
1439  } while(next != std::string::npos);
1440 
1441  return params;
1442  }
1443 
1444  // Parse a function from the specified spot in the source file
1445  Function SourceFileAttributesParser::parseFunction(size_t lineNumber) {
1446 
1447  // Establish the text to parse for the signature
1448  std::string signature = parseSignature(lineNumber);
1449  if (signature.empty()) {
1450  rcppExportNoFunctionFoundWarning(lineNumber); // #nocov
1451  return Function(); // #nocov
1452  }
1453 
1454  // Start at the end and look for the () that deliniates the arguments
1455  // (bail with an empty result if we can't find them)
1456  std::string::size_type endParenLoc = signature.find_last_of(')');
1457  std::string::size_type beginParenLoc = signature.find_first_of('(');
1458  if (endParenLoc == std::string::npos ||
1459  beginParenLoc == std::string::npos ||
1460  endParenLoc < beginParenLoc) {
1461 
1462  rcppExportNoFunctionFoundWarning(lineNumber); // #nocov
1463  return Function(); // #nocov
1464  }
1465 
1466  // Find the type and name by scanning backwards for the whitespace that
1467  // delimites the type and name
1468  Type type;
1469  std::string name;
1470  const std::string preambleText = signature.substr(0, beginParenLoc);
1471  for (std::string::const_reverse_iterator
1472  it = preambleText.rbegin(); it != preambleText.rend(); ++it) {
1473  char ch = *it;
1474  if (isWhitespace(ch)) {
1475  if (!name.empty()) {
1476  // we are at the break between type and name so we can also
1477  // extract the type
1478  std::string typeText;
1479  while (++it != preambleText.rend())
1480  typeText.insert(0U, 1U, *it);
1481  type = parseType(typeText);
1482 
1483  // break (since we now have the name and the type)
1484  break;
1485  }
1486  else
1487  continue; // #nocov
1488  } else {
1489  name.insert(0U, 1U, ch);
1490  }
1491  }
1492 
1493  // If we didn't find a name then bail
1494  if (name.empty()) {
1495  rcppExportNoFunctionFoundWarning(lineNumber); // #nocov
1496  return Function(); // #nocov
1497  }
1498 
1499  // If we didn't find a type then bail
1500  if (type.empty()) { // #nocov start
1501  rcppExportWarning("No function return type found", lineNumber);
1502  return Function(); // #nocov end
1503  }
1504 
1505  // Now scan for arguments
1506  std::vector<Argument> arguments;
1507  std::string argsText = signature.substr(beginParenLoc + 1,
1508  endParenLoc-beginParenLoc-1);
1509  std::vector<std::string> args = parseArguments(argsText);
1510  for (std::vector<std::string>::const_iterator it =
1511  args.begin(); it != args.end(); ++it) {
1512 
1513  // Get argument sans whitespace (bail if the arg is empty)
1514  std::string arg = *it;
1515  trimWhitespace(&arg);
1516  if (arg.empty()) {
1517  // we don't warn here because the compilation will fail anyway
1518  continue; // #nocov
1519  }
1520 
1521  // If the argument has an = within it then it has a default value
1522  std::string defaultValue;
1523  std::string::size_type eqPos = arg.find_first_of('=');
1524  if ( (eqPos != std::string::npos) && ((eqPos + 1) < arg.size()) ) {
1525  defaultValue = arg.substr(eqPos+1);
1526  trimWhitespace(&defaultValue);
1527  arg = arg.substr(0, eqPos);
1528  trimWhitespace(&arg);
1529  }
1530 
1531  // Scan backwards for whitespace to determine where the type ends
1532  // (we go backwards because whitespace is valid inside the type
1533  // identifier but invalid inside the variable name). Note that if
1534  // there is no whitespace we'll end up taking the whole string,
1535  // which allows us to capture a type with no variable (but note
1536  // we'll ultimately fail to parse types with no variable if they
1537  // have embedded whitespace)
1538  std::string::size_type pos = arg.find_last_of(kWhitespaceChars);
1539 
1540  // check for name
1541  std::string name;
1542  if (pos != std::string::npos) {
1543  // insert whitespace if variables are joint with '&'
1544  std::string::size_type ref_pos = arg.substr(pos).find_last_of("&");
1545  if (ref_pos != std::string::npos) {
1546  pos += ref_pos + 1; // #nocov
1547  arg.insert(pos, " "); // #nocov
1548  }
1549 
1550  name = arg.substr(pos);
1551  trimWhitespace(&name);
1552  }
1553  if (name.empty()) { // #nocov start
1554  rcppExportInvalidParameterWarning(arg, lineNumber);
1555  return Function(); // #nocov end
1556  }
1557 
1558  // check for type string
1559  Type type = parseType(arg.substr(0, pos));
1560  if (type.empty()) { // #nocov start
1561  rcppExportInvalidParameterWarning(arg, lineNumber);
1562  return Function(); // #nocov end
1563  }
1564 
1565  // add argument
1566  arguments.push_back(Argument(name, type, defaultValue));
1567  }
1568 
1569  return Function(type, name, arguments);
1570  }
1571 
1572 
1573  // Parse the text of a function signature from the specified line
1574  std::string SourceFileAttributesParser::parseSignature(size_t lineNumber) {
1575 
1576  // Look for the signature termination ({ or ; not inside quotes)
1577  // on this line and then subsequent lines if necessary
1578  std::string signature;
1579  for (int i = lineNumber; i<lines_.size(); i++) {
1580  std::string line;
1581  line = lines_[i];
1582  bool insideQuotes = false;
1583  char prevChar = 0;
1584  // scan for { or ; not inside quotes
1585  for (size_t c = 0; c < line.length(); ++c) {
1586  // alias character
1587  char ch = line.at(c);
1588  // update quotes state
1589  if (ch == '"' && prevChar != '\\')
1590  insideQuotes = !insideQuotes;
1591  // found signature termination, append and return
1592  if (!insideQuotes && ((ch == '{') || (ch == ';'))) {
1593  signature.append(line.substr(0, c));
1594  return signature;
1595  }
1596  // record prev char (used to check for escaped quote i.e. \")
1597  prevChar = ch;
1598  }
1599 
1600  // if we didn't find a terminator on this line then just append the line
1601  // and move on to the next line
1602  signature.append(line);
1603  signature.push_back(' ');
1604  }
1605 
1606  // Not found
1607  return std::string(); // #nocov
1608  }
1609 
1610 
1611  // Parse arguments from function signature. This is tricky because commas
1612  // are used to delimit arguments but are also valid inside template type
1613  // qualifiers.
1614  std::vector<std::string> SourceFileAttributesParser::parseArguments(
1615  const std::string& argText) {
1616 
1617  int templateCount = 0;
1618  int parenCount = 0;
1619  std::string currentArg;
1620  std::vector<std::string> args;
1621  char quote = 0;
1622  bool escaped = false;
1623  typedef std::string::const_iterator it_t;
1624  for (it_t it = argText.begin(); it != argText.end(); ++it) {
1625 
1626  // Store current character
1627  char ch = *it;
1628 
1629  // Ignore quoted strings and character values in single quotes
1630  if ( ! quote && (ch == '"' || ch == '\''))
1631  quote = ch;
1632  else if (quote && ch == quote && ! escaped)
1633  quote = 0;
1634 
1635  // Escaped character inside quotes
1636  if (escaped)
1637  escaped = false;
1638  else if (quote && ch == '\\')
1639  escaped = true;
1640 
1641  // Detect end of argument declaration
1642  if ( ! quote &&
1643  (ch == ',') &&
1644  (templateCount == 0) &&
1645  (parenCount == 0)) {
1646  args.push_back(currentArg);
1647  currentArg.clear();
1648  continue;
1649  }
1650 
1651  // Append current character if not a space at start
1652  if ( ! currentArg.empty() || ch != ' ')
1653  currentArg.push_back(ch);
1654 
1655  // Count use of potentially enclosed brackets
1656  if ( ! quote) {
1657  switch(ch) {
1658  case '<':
1659  templateCount++;
1660  break;
1661  case '>':
1662  templateCount--;
1663  break;
1664  case '(': // #nocov start
1665  parenCount++;
1666  break;
1667  case ')':
1668  parenCount--;
1669  break; // #nocov end
1670  }
1671  }
1672  }
1673 
1674  if (!currentArg.empty())
1675  args.push_back(currentArg);
1676 
1677  return args;
1678  }
1679 
1680  Type SourceFileAttributesParser::parseType(const std::string& text) {
1681 
1682  const std::string constQualifier("const");
1683  const std::string referenceQualifier("&");
1684 
1685  // trim whitespace
1686  std::string type = text;
1687  trimWhitespace(&type);
1688 
1689  // check for const and reference
1690  bool isConst = false;
1691  bool isReference = false;
1692  if (type.find(constQualifier) == 0) {
1693  isConst = true;
1694  type.erase(0, constQualifier.length());
1695  }
1696 
1697  // if the type is now empty (because it was detected as only const)
1698  // then this is an invalid state so we bail
1699  if (type.empty())
1700  return Type(); // #nocov
1701 
1702  if (type.find(referenceQualifier) ==
1703  (type.length() - referenceQualifier.length())) {
1704  isReference = true;
1705  type.erase(type.length() - referenceQualifier.length());
1706  }
1707  trimWhitespace(&type);
1708 
1709  // if the type is now empty because of some strange parse then bail
1710  if (type.empty())
1711  return Type(); // #nocov
1712 
1713  return Type(type, isConst, isReference);
1714  }
1715 
1716  // Validation helpers
1717 
1718  bool SourceFileAttributesParser::isKnownAttribute(const std::string& name)
1719  const {
1720  return name == kExportAttribute ||
1721  name == kInitAttribute ||
1722  name == kDependsAttribute ||
1723  name == kPluginsAttribute ||
1724  name == kInterfacesAttribute;
1725  }
1726 
1727  // Print an attribute parsing related warning
1728  void SourceFileAttributesParser::attributeWarning( // #nocov start
1729  const std::string& message,
1730  const std::string& attribute,
1731  size_t lineNumber) {
1732 
1733  // get basename of source file for warning message
1734  Rcpp::Function basename = Rcpp::Environment::base_env()["basename"];
1735  std::string file = Rcpp::as<std::string>(basename(sourceFile_));
1736 
1737  std::ostringstream ostr;
1738  ostr << message;
1739  if (!attribute.empty())
1740  ostr << " for " << attribute << " attribute";
1741  ostr << " at " << file << ":" << lineNumber;
1742 
1743  showWarning(ostr.str());
1744  }
1745 
1746  void SourceFileAttributesParser::attributeWarning(
1747  const std::string& message,
1748  size_t lineNumber) {
1749  attributeWarning(message, "", lineNumber);
1750  }
1751 
1752  void SourceFileAttributesParser::rcppExportWarning(
1753  const std::string& message,
1754  size_t lineNumber) {
1755  attributeWarning(message, "Rcpp::export", lineNumber);
1756  }
1757 
1758  void SourceFileAttributesParser::rcppExportNoFunctionFoundWarning(
1759  size_t lineNumber) {
1760  rcppExportWarning("No function found", lineNumber);
1761  }
1762 
1763  void SourceFileAttributesParser::rcppExportInvalidParameterWarning(
1764  const std::string& param,
1765  size_t lineNumber) {
1766  rcppExportWarning("Invalid parameter: "
1767  "'" + param + "'", lineNumber);
1768  }
1769 
1770  void SourceFileAttributesParser::rcppInterfacesWarning(
1771  const std::string& message,
1772  size_t lineNumber) {
1773  attributeWarning(message + " (valid interfaces are 'r' and 'cpp')",
1774  "Rcpp::interfaces", lineNumber);
1775  } // #nocov end
1776 
1777 
1778  // Track /* */ comment state
1779  void CommentState::submitLine(const std::string& line) {
1780  std::size_t pos = 0;
1781  while (pos != std::string::npos) {
1782 
1783  // check for a // which would invalidate any other token found
1784  std::size_t lineCommentPos = line.find("//", pos);
1785 
1786  // look for the next token
1787  std::string token = inComment() ? "*/" : "/*";
1788  pos = line.find(token, pos);
1789 
1790  // process the comment token if found
1791  if (pos != std::string::npos) {
1792 
1793  // break if the line comment precedes the comment token
1794  if (lineCommentPos != std::string::npos && lineCommentPos < pos)
1795  break; // #nocov
1796 
1797  inComment_ = !inComment_;
1798  pos += token.size();
1799  }
1800  }
1801  }
1802 
1803 } // namespace attributes
1804 } // namespace Rcpp
1805 
1806 
1807 /*******************************************************************
1808  * AttributesGen.cpp
1809  *******************************************************************/
1810 
1811 namespace Rcpp {
1812 namespace attributes {
1813 
1814  // constants
1815  namespace {
1816  const char * const kRcppExportsSuffix = "_RcppExports.h";
1817  const char * const kTrySuffix = "_try";
1818  }
1819 
1820  ExportsGenerator::ExportsGenerator(const std::string& targetFile,
1821  const std::string& package,
1822  const std::string& commentPrefix)
1823  : targetFile_(targetFile),
1824  package_(package),
1825  packageCpp_(package),
1826  commentPrefix_(commentPrefix),
1827  hasCppInterface_(false) {
1828 
1829  // read the existing target file if it exists
1830  if (FileInfo(targetFile_).exists()) {
1831  std::ifstream ifs(targetFile_.c_str()); // #nocov start
1832  if (ifs.fail())
1833  throw Rcpp::file_io_error(targetFile_);
1834  std::stringstream buffer;
1835  buffer << ifs.rdbuf();
1836  existingCode_ = buffer.str(); // #nocov end
1837  }
1838 
1839  std::replace(packageCpp_.begin(), packageCpp_.end(), '.', '_');
1840 
1841  // see if this is safe to overwite and throw if it isn't
1842  if (!isSafeToOverwrite())
1843  throw Rcpp::file_exists(targetFile_); // #nocov
1844  }
1845 
1847  const SourceFileAttributes& attributes,
1848  bool verbose) {
1849 
1850  if (attributes.hasInterface(kInterfaceCpp))
1851  hasCppInterface_ = true; // #nocov
1852 
1853  doWriteFunctions(attributes, verbose);
1854  }
1855 
1856  // Commit the stream -- is a no-op if the existing code is identical
1857  // to the generated code. Returns true if data was written and false
1858  // if it wasn't (throws exception on io error)
1859  bool ExportsGenerator::commit(const std::string& preamble) {
1860 
1861  // get the generated code
1862  std::string code = codeStream_.str();
1864  // if there is no generated code AND the exports file does not
1865  // currently exist then do nothing
1866  if (code.empty() && !FileInfo(targetFile_).exists())
1867  return false; // #nocov
1868 
1869  // write header/preamble
1870  std::ostringstream headerStream;
1871  headerStream << commentPrefix_ << " Generated by using "
1872  << "Rcpp::compileAttributes()"
1873  << " -> do not edit by hand" << std::endl;
1874  headerStream << commentPrefix_ << " Generator token: "
1875  << generatorToken() << std::endl << std::endl;
1876  if (!preamble.empty())
1877  headerStream << preamble;
1878 
1879  // get generated code and only write it if there was a change
1880  std::string generatedCode = headerStream.str() + code;
1881  if (generatedCode != existingCode_) {
1882  // open the file
1883  std::ofstream ofs(targetFile_.c_str(),
1884  std::ofstream::out | std::ofstream::trunc);
1885  if (ofs.fail())
1886  throw Rcpp::file_io_error(targetFile_); // #nocov
1887 
1888  // write generated code and return
1889  ofs << generatedCode;
1890  ofs.close();
1891  return true;
1892  }
1893  else {
1894  return false; // #nocov
1895  }
1896  }
1897 
1898  // Remove the generated file entirely
1899  bool ExportsGenerator::remove() {
1900  return removeFile(targetFile_);
1901  }
1902 
1903  // Convert a possible dot in package name to underscore as needed for header file
1904  std::string ExportsGenerator::dotNameHelper(const std::string & name) const {
1905  std::string newname(name);
1906  std::replace(newname.begin(), newname.end(), '.', '_');
1907  return newname;
1908  }
1909 
1910  CppExportsGenerator::CppExportsGenerator(const std::string& packageDir,
1911  const std::string& package,
1912  const std::string& fileSep)
1913  : ExportsGenerator(
1914  packageDir + fileSep + "src" + fileSep + "RcppExports.cpp",
1915  package,
1916  "//")
1917  {
1918  }
1919 
1921  const SourceFileAttributes& attributes,
1922  bool verbose) {
1923 
1924  // generate functions
1925  generateCpp(ostr(),
1926  attributes,
1927  true,
1928  attributes.hasInterface(kInterfaceCpp),
1929  packageCppPrefix());
1930 
1931  // track cppExports, signatures, and native routines (we use these
1932  // at the end to generate the ValidateSignature and RegisterCCallable
1933  // functions, and to generate a package init function with native
1934  // routine registration)
1935  for (SourceFileAttributes::const_iterator // #nocov start
1936  it = attributes.begin(); it != attributes.end(); ++it) {
1937 
1938  if (it->isExportedFunction()) {
1939 
1940  // add it to the cpp exports list if we are generating
1941  // a C++ interface and it's not hidden
1942  if (attributes.hasInterface(kInterfaceCpp)) {
1943  Function fun = it->function().renamedTo(it->exportedCppName());
1944  if (!fun.isHidden())
1945  cppExports_.push_back(*it);
1946  }
1947 
1948  // add it to the native routines list
1949  nativeRoutines_.push_back(*it);
1950  } else if (it->name() == kInitAttribute) {
1951  initFunctions_.push_back(*it);
1952  }
1953  } // #nocov end
1954 
1955  // record modules
1956  const std::vector<std::string>& modules = attributes.modules();
1957  modules_.insert(modules_.end(), modules.begin(), modules.end());
1958 
1959  // verbose if requested
1960  if (verbose) { // #nocov start
1961  Rcpp::Rcout << "Exports from " << attributes.sourceFile() << ":"
1962  << std::endl;
1963  for (std::vector<Attribute>::const_iterator
1964  it = attributes.begin(); it != attributes.end(); ++it) {
1965  if (it->isExportedFunction())
1966  Rcpp::Rcout << " " << it->function() << std::endl;
1967  }
1968  Rcpp::Rcout << std::endl; // #nocov end
1969  }
1970  }
1971 
1972  void CppExportsGenerator::writeEnd(bool hasPackageInit)
1973  {
1974  // generate a function that can be used to validate exported
1975  // functions and their signatures prior to looking up with
1976  // GetCppCallable (otherwise inconsistent signatures between
1977  // client and library would cause a crash)
1978  if (hasCppInterface()) {
1979 
1980  ostr() << std::endl; // #nocov start
1981  ostr() << "// validate"
1982  << " (ensure exported C++ functions exist before "
1983  << "calling them)" << std::endl;
1984  ostr() << "static int " << exportValidationFunctionRegisteredName()
1985  << "(const char* sig) { " << std::endl;
1986  ostr() << " static std::set<std::string> signatures;"
1987  << std::endl;
1988  ostr() << " if (signatures.empty()) {" << std::endl;
1989 
1990  for (std::size_t i=0;i<cppExports_.size(); i++) {
1991  const Attribute& attr = cppExports_[i];
1992  ostr() << " signatures.insert(\""
1993  << attr.function().signature(attr.exportedName())
1994  << "\");" << std::endl;
1995  }
1996  ostr() << " }" << std::endl;
1997  ostr() << " return signatures.find(sig) != signatures.end();"
1998  << std::endl;
1999  ostr() << "}" << std::endl;
2000 
2001  // generate a function that will register all of our C++
2002  // exports as C-callable from other packages
2003  ostr() << std::endl;
2004  ostr() << "// registerCCallable (register entry points for "
2005  "exported C++ functions)" << std::endl;
2006  ostr() << "RcppExport SEXP " << registerCCallableExportedName()
2007  << "() { " << std::endl;
2008  for (std::size_t i=0;i<cppExports_.size(); i++) {
2009  const Attribute& attr = cppExports_[i];
2010  ostr() << registerCCallable(
2011  4,
2012  attr.exportedName(),
2013  attr.function().name() + kTrySuffix);
2014  ostr() << std::endl;
2015  }
2016  ostr() << registerCCallable(4,
2019  ostr() << std::endl;
2020  ostr() << " return R_NilValue;" << std::endl;
2021  ostr() << "}" << std::endl;
2022  }
2023 
2024  // write native routines
2025  if (!hasPackageInit && (!nativeRoutines_.empty() || !modules_.empty() || !initFunctions_.empty())) {
2026 
2027  // build list of routines we will register
2028  std::vector<std::string> routineNames;
2029  std::vector<std::size_t> routineArgs;
2030  for (std::size_t i=0;i<nativeRoutines_.size(); i++) {
2031  const Attribute& attr = nativeRoutines_[i];
2032  routineNames.push_back(packageCppPrefix() + "_" + attr.function().name());
2033  routineArgs.push_back(attr.function().arguments().size());
2034  }
2035  std::string kRcppModuleBoot = "_rcpp_module_boot_";
2036  for (std::size_t i=0;i<modules_.size(); i++) {
2037  routineNames.push_back(kRcppModuleBoot + modules_[i]);
2038  routineArgs.push_back(0);
2039  }
2040  if (hasCppInterface()) {
2041  routineNames.push_back(registerCCallableExportedName());
2042  routineArgs.push_back(0);
2043  }
2044 
2045  // see if there are additional registrations to perform
2046  Rcpp::Function extraRoutinesFunc = Environment::namespace_env("Rcpp")[".extraRoutineRegistrations"];
2047  List extraRoutines = extraRoutinesFunc(targetFile(), routineNames);
2048  std::vector<std::string> declarations = extraRoutines["declarations"];
2049  std::vector<std::string> callEntries = extraRoutines["call_entries"];
2050 
2051  // add declarations for modules
2052  for (std::size_t i=0;i<modules_.size(); i++) {
2053  declarations.push_back("RcppExport SEXP " + kRcppModuleBoot + modules_[i] + "();");
2054  }
2055 
2056  // generate declarations
2057  if (declarations.size() > 0) {
2058  ostr() << std::endl;
2059  for (std::size_t i = 0; i<declarations.size(); i++)
2060  ostr() << declarations[i] << std::endl;
2061  }
2062 
2063  // generate registration code
2064  ostr() << std::endl;
2065  ostr() << "static const R_CallMethodDef CallEntries[] = {" << std::endl;
2066  for (std::size_t i=0;i<routineNames.size(); i++) {
2067  ostr() << " {\"" << routineNames[i] << "\", " <<
2068  "(DL_FUNC) &" << routineNames[i] << ", " <<
2069  routineArgs[i] << "}," << std::endl;
2070  }
2071  if (callEntries.size() > 0) {
2072  for (std::size_t i = 0; i<callEntries.size(); i++)
2073  ostr() << callEntries[i] << std::endl;
2074  }
2075  ostr() << " {NULL, NULL, 0}" << std::endl;
2076  ostr() << "};" << std::endl;
2077 
2078  ostr() << std::endl;
2079 
2080  // write prototypes for init functions
2081  for (std::size_t i = 0; i<initFunctions_.size(); i++) {
2082  const Function& function = initFunctions_[i].function();
2083  printFunction(ostr(), function, false);
2084  ostr() << ";" << std::endl;
2085  }
2086 
2087  ostr() << "RcppExport void R_init_" << packageCpp() << "(DllInfo *dll) {" << std::endl;
2088  ostr() << " R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);" << std::endl;
2089  ostr() << " R_useDynamicSymbols(dll, FALSE);" << std::endl;
2090  // call init functions
2091  for (std::size_t i = 0; i<initFunctions_.size(); i++) {
2092  const Function& function = initFunctions_[i].function();
2093  ostr() << " " << function.name() << "(dll);" << std::endl;
2094  }
2095  ostr() << "}" << std::endl;
2096  }
2097 
2098  // warn if both a hand-written package init function and Rcpp::init are used
2099  if (hasPackageInit && !initFunctions_.empty()) {
2100  showWarning("[[Rcpp::init]] attribute used in a package with an explicit "
2101  "R_init function (Rcpp::init functions will not be called)");
2102  }
2103  }
2104 
2106  size_t indent,
2107  const std::string& exportedName,
2108  const std::string& name) const {
2109  std::ostringstream ostr;
2110  std::string indentStr(indent, ' ');
2111  ostr << indentStr << "R_RegisterCCallable(\"" << package() << "\", "
2112  << "\"" << packageCppPrefix() << "_" << exportedName << "\", "
2113  << "(DL_FUNC)" << packageCppPrefix() << "_" << name << ");";
2114  return ostr.str(); // #nocov end
2115  }
2116 
2117  bool CppExportsGenerator::commit(const std::vector<std::string>& includes) {
2118 
2119  // includes
2120  std::ostringstream ostr;
2121  if (!includes.empty()) {
2122  for (std::size_t i=0;i<includes.size(); i++)
2123  ostr << includes[i] << std::endl;
2124  }
2125  if (hasCppInterface()) {
2126  ostr << "#include <string>" << std::endl; // #nocov
2127  ostr << "#include <set>" << std::endl; // #nocov
2128  }
2129  ostr << std::endl;
2130 
2131  // always bring in Rcpp
2132  ostr << "using namespace Rcpp;" << std::endl << std::endl;
2133  // initialize references to global Rostreams
2135 
2136  // commit with preamble
2137  return ExportsGenerator::commit(ostr.str());
2138  }
2139 
2141  const std::string& packageDir,
2142  const std::string& package,
2143  const std::string& fileSep)
2145  packageDir + fileSep + "inst" + fileSep + "include" +
2146  fileSep + dotNameHelper(package) + kRcppExportsSuffix,
2147  package,
2148  "//")
2149  {
2150  includeDir_ = packageDir + fileSep + "inst" + fileSep + "include";
2151  }
2152 
2154 
2155  ostr() << "namespace " << packageCpp() << " {"
2156  << std::endl << std::endl;
2158  // Import Rcpp into this namespace. This allows declarations to
2159  // be written without fully qualifying all Rcpp types. The only
2160  // negative side-effect is that when this package's namespace
2161  // is imported it will also pull in Rcpp. However since this is
2162  // opt-in and represents a general desire to do namespace aliasing
2163  // this seems okay
2164  ostr() << " using namespace Rcpp;" << std::endl << std::endl;
2165 
2166  // Write our export validation helper function. Putting it in
2167  // an anonymous namespace will hide it from callers and give
2168  // it per-translation unit linkage
2169  ostr() << " namespace {" << std::endl;
2170  ostr() << " void validateSignature(const char* sig) {"
2171  << std::endl;
2172  ostr() << " Rcpp::Function require = "
2173  << "Rcpp::Environment::base_env()[\"require\"];"
2174  << std::endl;
2175  ostr() << " require(\"" << package() << "\", "
2176  << "Rcpp::Named(\"quietly\") = true);"
2177  << std::endl;
2178 
2179  std::string validate = "validate";
2180  std::string fnType = "Ptr_" + validate;
2181  ostr() << " typedef int(*" << fnType << ")(const char*);"
2182  << std::endl;
2183 
2184  std::string ptrName = "p_" + validate;
2185  ostr() << " static " << fnType << " " << ptrName << " = "
2186  << "(" << fnType << ")" << std::endl
2187  << " "
2189  << ";" << std::endl;
2190  ostr() << " if (!" << ptrName << "(sig)) {" << std::endl;
2191  ostr() << " throw Rcpp::function_not_exported("
2192  << std::endl
2193  << " "
2194  << "\"C++ function with signature '\" + std::string(sig) + \"' not found in " << package()
2195  << "\");" << std::endl;
2196  ostr() << " }" << std::endl;
2197  ostr() << " }" << std::endl;
2198 
2199  ostr() << " }" << std::endl << std::endl;
2200  }
2201 
2203  const SourceFileAttributes& attributes,
2204  bool) {
2205 
2206  // don't write anything if there is no C++ interface
2207  if (!attributes.hasInterface(kInterfaceCpp))
2208  return;
2209 
2210  for(std::vector<Attribute>::const_iterator // #nocov start
2211  it = attributes.begin(); it != attributes.end(); ++it) {
2212 
2213  if (it->isExportedFunction()) {
2214 
2215  Function function =
2216  it->function().renamedTo(it->exportedCppName());
2217 
2218  // if it's hidden then don't generate a C++ interface
2219  if (function.isHidden())
2220  continue;
2221 
2222  ostr() << " inline " << function << " {"
2223  << std::endl;
2224 
2225  std::string fnType = "Ptr_" + function.name();
2226  ostr() << " typedef SEXP(*" << fnType << ")(";
2227  for (size_t i=0; i<function.arguments().size(); i++) {
2228  ostr() << "SEXP";
2229  if (i != (function.arguments().size()-1))
2230  ostr() << ",";
2231  }
2232  ostr() << ");" << std::endl;
2233 
2234  std::string ptrName = "p_" + function.name();
2235  ostr() << " static " << fnType << " "
2236  << ptrName << " = NULL;"
2237  << std::endl;
2238  ostr() << " if (" << ptrName << " == NULL) {"
2239  << std::endl;
2240  ostr() << " validateSignature"
2241  << "(\"" << function.signature() << "\");"
2242  << std::endl;
2243  ostr() << " " << ptrName << " = "
2244  << "(" << fnType << ")"
2245  << getCCallable(packageCppPrefix() + "_" + function.name()) << ";"
2246  << std::endl;
2247  ostr() << " }" << std::endl;
2248  ostr() << " RObject rcpp_result_gen;" << std::endl;
2249  ostr() << " {" << std::endl;
2250  if (it->rng())
2251  ostr() << " RNGScope RCPP_rngScope_gen;" << std::endl;
2252  ostr() << " rcpp_result_gen = " << ptrName << "(";
2253 
2254  const std::vector<Argument>& args = function.arguments();
2255  for (std::size_t i = 0; i<args.size(); i++) {
2256  ostr() << "Shield<SEXP>(Rcpp::wrap(" << args[i].name() << "))";
2257  if (i != (args.size()-1))
2258  ostr() << ", ";
2259  }
2260 
2261  ostr() << ");" << std::endl;
2262  ostr() << " }" << std::endl;
2263 
2264  ostr() << " if (rcpp_result_gen.inherits(\"interrupted-error\"))"
2265  << std::endl
2266  << " throw Rcpp::internal::InterruptedException();"
2267  << std::endl;
2268  ostr() << " if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen))"
2269  << std::endl
2270  << " throw Rcpp::LongjumpException(rcpp_result_gen);"
2271  << std::endl;
2272  ostr() << " if (rcpp_result_gen.inherits(\"try-error\"))"
2273  << std::endl
2274  << " throw Rcpp::exception(Rcpp::as<std::string>("
2275  << "rcpp_result_gen).c_str());"
2276  << std::endl;
2277  if (!function.type().isVoid()) {
2278  ostr() << " return Rcpp::as<" << function.type() << " >"
2279  << "(rcpp_result_gen);" << std::endl;
2280  }
2281 
2282  ostr() << " }" << std::endl << std::endl; // #nocov end
2283  }
2284  }
2285  }
2286 
2288  ostr() << "}" << std::endl;
2289  ostr() << std::endl;
2290  ostr() << "#endif // " << getHeaderGuard() << std::endl;
2291  }
2292 
2294  const std::vector<std::string>& includes) {
2295 
2296  if (hasCppInterface()) {
2298  // create the include dir if necessary
2299  createDirectory(includeDir_); // #nocov start
2300 
2301  // generate preamble
2302  std::ostringstream ostr;
2303 
2304  // header guard
2305  std::string guard = getHeaderGuard();
2306  ostr << "#ifndef " << guard << std::endl;
2307  ostr << "#define " << guard << std::endl << std::endl;
2308 
2309  // includes
2310  if (!includes.empty()) {
2311  for (std::size_t i=0;i<includes.size(); i++)
2312  {
2313  // some special processing is required here. we exclude
2314  // the package header file (since it includes this file)
2315  // and we transorm _types includes into local includes
2316  std::string preamble = "#include \"../inst/include/";
2317  std::string pkgInclude = preamble + packageCpp() + ".h\"";
2318  if (includes[i] == pkgInclude)
2319  continue;
2320 
2321  // check for _types
2322  std::string typesInclude = preamble + packageCpp() + "_types.h";
2323  if (includes[i].find(typesInclude) != std::string::npos)
2324  {
2325  std::string include = "#include \"" +
2326  includes[i].substr(preamble.length());
2327  ostr << include << std::endl;
2328  }
2329  else
2330  {
2331  ostr << includes[i] << std::endl;
2332  }
2333  }
2334  ostr << std::endl;
2335  }
2336 
2337  // commit with preamble
2338  return ExportsGenerator::commit(ostr.str()); // #nocov end
2339  }
2340  else {
2341  return ExportsGenerator::remove();
2342  }
2343  }
2344 
2346  const std::string& function) const {
2347  std::ostringstream ostr;
2348  ostr << "R_GetCCallable"
2349  << "(\"" << package() << "\", "
2350  << "\"" << function << "\")";
2351  return ostr.str();
2352  }
2353 
2354  std::string CppExportsIncludeGenerator::getHeaderGuard() const {
2355  return "RCPP_" + packageCpp() + "_RCPPEXPORTS_H_GEN_";
2356  }
2357 
2359  const std::string& packageDir,
2360  const std::string& package,
2361  const std::string& fileSep)
2363  packageDir + fileSep + "inst" + fileSep + "include" +
2364  fileSep + dotNameHelper(package) + ".h",
2365  package,
2366  "//")
2367  {
2368  includeDir_ = packageDir + fileSep + "inst" + fileSep + "include";
2369  }
2370 
2372  if (hasCppInterface()) {
2373  // header guard
2374  std::string guard = getHeaderGuard(); // #nocov start
2375  ostr() << "#ifndef " << guard << std::endl;
2376  ostr() << "#define " << guard << std::endl << std::endl;
2377  ostr() << "#include \"" << packageCpp() << kRcppExportsSuffix
2378  << "\"" << std::endl;
2379 
2380  ostr() << std::endl;
2381  ostr() << "#endif // " << getHeaderGuard() << std::endl; // #nocov end
2382  }
2383  }
2384 
2385  bool CppPackageIncludeGenerator::commit(const std::vector<std::string>&) {
2386  if (hasCppInterface()) {
2387 
2388  // create the include dir if necessary
2390 
2391  // commit
2392  return ExportsGenerator::commit(); // #nocov
2393  }
2394  else {
2395  return ExportsGenerator::remove();
2396  }
2397  }
2398 
2399  std::string CppPackageIncludeGenerator::getHeaderGuard() const { // #nocov
2400  return "RCPP_" + packageCpp() + "_H_GEN_"; // #nocov
2401  }
2402 
2403  RExportsGenerator::RExportsGenerator(const std::string& packageDir,
2404  const std::string& package,
2405  bool registration,
2406  const std::string& fileSep)
2408  packageDir + fileSep + "R" + fileSep + "RcppExports.R",
2409  package,
2410  "#"),
2411  registration_(registration)
2412  {
2413  }
2414 
2416  const SourceFileAttributes& attributes,
2417  bool) {
2418  // write standalone roxygen chunks
2419  const std::vector<std::vector<std::string> >& roxygenChunks =
2420  attributes.roxygenChunks();
2421  for (std::size_t i = 0; i<roxygenChunks.size(); i++) {
2422  const std::vector<std::string>& chunk = roxygenChunks[i]; // #nocov start
2423  for (std::size_t l = 0; l < chunk.size(); l++)
2424  ostr() << chunk[l] << std::endl;
2425  ostr() << "NULL" << std::endl << std::endl; // #nocov end
2426  }
2427 
2428  // write exported functions
2429  if (attributes.hasInterface(kInterfaceR)) {
2430  // process each attribute
2431  for(std::vector<Attribute>::const_iterator
2432  it = attributes.begin(); it != attributes.end(); ++it) {
2433 
2434  // alias the attribute and function (bail if not export)
2435  const Attribute& attribute = *it;
2436  if (!attribute.isExportedFunction())
2437  continue; // #nocov
2438  const Function& function = attribute.function();
2439 
2440  // print roxygen lines
2441  for (size_t i=0; i<attribute.roxygen().size(); i++)
2442  ostr() << attribute.roxygen()[i] << std::endl; // #nocov
2443 
2444  // build the parameter list
2445  std::string args = generateRArgList(function);
2446 
2447  // determine the function name
2448  std::string name = attribute.exportedName();
2449 
2450  // determine if return invisible
2451  bool isInvisibleOrVoid = function.type().isVoid() || attribute.invisible();
2452 
2453  // write the function
2454  ostr() << name << " <- function(" << args << ") {"
2455  << std::endl;
2456  ostr() << " ";
2457  if (isInvisibleOrVoid)
2458  ostr() << "invisible("; // #nocov
2459  ostr() << ".Call(";
2460  if (!registration_)
2461  ostr() << "'"; // #nocov
2462  else
2463  ostr() << "`";
2464  ostr() << packageCppPrefix() << "_" << function.name();
2465  if (!registration_)
2466  ostr() << "', " << "PACKAGE = '" << package() << "'"; // #nocov
2467  else
2468  ostr() << "`";
2469 
2470  // add arguments
2471  const std::vector<Argument>& arguments = function.arguments();
2472  for (size_t i = 0; i<arguments.size(); i++)
2473  ostr() << ", " << arguments[i].name(); // #nocov
2474  ostr() << ")";
2475  if (isInvisibleOrVoid)
2476  ostr() << ")"; // #nocov
2477  ostr() << std::endl;
2478 
2479  ostr() << "}" << std::endl << std::endl;
2480  }
2481  }
2482  }
2483 
2484  void RExportsGenerator::writeEnd(bool) {
2485  if (hasCppInterface()) { // #nocov start
2486  // register all C-callable functions
2487  ostr() << "# Register entry points for exported C++ functions"
2488  << std::endl;
2489  ostr() << "methods::setLoadAction(function(ns) {" << std::endl;
2490  ostr() << " .Call('" << registerCCallableExportedName()
2491  << "', PACKAGE = '" << package() << "')"
2492  << std::endl << "})" << std::endl; // #nocov end
2493  }
2494  }
2495 
2496  bool RExportsGenerator::commit(const std::vector<std::string>&) {
2497  return ExportsGenerator::commit();
2498  }
2499 
2501  try {
2502  for(Itr it = generators_.begin(); it != generators_.end(); ++it)
2503  delete *it;
2504  generators_.clear();
2505  }
2506  catch(...) {}
2507  }
2508 
2509  void ExportsGenerators::add(ExportsGenerator* pGenerator) {
2510  generators_.push_back(pGenerator);
2511  }
2512 
2514  for(Itr it = generators_.begin(); it != generators_.end(); ++it)
2515  (*it)->writeBegin();
2516  }
2519  const SourceFileAttributes& attributes,
2520  bool verbose) {
2521  for(Itr it = generators_.begin(); it != generators_.end(); ++it)
2522  (*it)->writeFunctions(attributes, verbose);
2523  }
2524 
2525  void ExportsGenerators::writeEnd(bool hasPackageInit) {
2526  for(Itr it = generators_.begin(); it != generators_.end(); ++it)
2527  (*it)->writeEnd(hasPackageInit);
2528  }
2530  // Commit and return a list of the files that were updated
2531  std::vector<std::string> ExportsGenerators::commit(
2532  const std::vector<std::string>& includes) {
2533 
2534  std::vector<std::string> updated;
2536  for(Itr it = generators_.begin(); it != generators_.end(); ++it) {
2537  if ((*it)->commit(includes))
2538  updated.push_back((*it)->targetFile());
2539  }
2540 
2541  return updated;
2542  }
2543 
2544  // Remove and return a list of files that were removed
2545  std::vector<std::string> ExportsGenerators::remove() { // #nocov start
2546  std::vector<std::string> removed;
2547  for(Itr it = generators_.begin(); it != generators_.end(); ++it) {
2548  if ((*it)->remove())
2549  removed.push_back((*it)->targetFile());
2550  }
2551  return removed;
2552  }
2553 
2554 
2555  // Helpers for converting C++ default arguments to R default arguments
2556  namespace {
2557 
2558  // convert a C++ numeric argument to an R argument value
2559  // (returns empty string if no conversion is possible)
2560  std::string cppNumericArgToRArg(const std::string& type,
2561  const std::string& cppArg) {
2562  // check for a number
2563  double num;
2564  std::stringstream argStream(cppArg);
2565  if ((argStream >> num)) {
2566 
2567  // L suffix means return the value literally
2568  if (!argStream.eof()) {
2569  std::string suffix;
2570  argStream >> suffix;
2571  if (argStream.eof() && suffix == "L")
2572  return cppArg;
2573  }
2574 
2575  // no decimal and the type isn't explicitly double or
2576  // float means integer
2577  if (cppArg.find('.') == std::string::npos &&
2578  type != "double" && type != "float")
2579  return cppArg + "L";
2580 
2581  // otherwise return arg literally
2582  else
2583  return cppArg;
2584  }
2585  else {
2586  return std::string();
2587  }
2588  }
2589 
2590  // convert a C++ ::create style argument value to an R argument
2591  // value (returns empty string if no conversion is possible)
2592  std::string cppCreateArgToRArg(const std::string& cppArg) {
2593 
2594  std::string create = "::create";
2595  size_t createLoc = cppArg.find(create);
2596  if (createLoc == std::string::npos ||
2597  ((createLoc + create.length()) >= cppArg.size())) {
2598  return std::string();
2599  }
2600 
2601  std::string type = cppArg.substr(0, createLoc);
2602  std::string rcppScope = "Rcpp::";
2603  size_t rcppLoc = type.find(rcppScope);
2604  if (rcppLoc == 0 && type.size() > rcppScope.length())
2605  type = type.substr(rcppScope.length());
2606 
2607  std::string args = cppArg.substr(createLoc + create.length());
2608  if (type == "CharacterVector")
2609  return "as.character( c" + args + ")";
2610  if (type == "IntegerVector")
2611  return "as.integer( c" + args + ")";
2612  if (type == "NumericVector")
2613  return "as.numeric( c" + args + ")";
2614  if (type == "LogicalVector")
2615  return "as.logical( c" + args + ")";
2616 
2617  return std::string();
2618  }
2619 
2620  // convert a C++ Matrix to an R argument (returns empty string
2621  // if no conversion possible)
2622  std::string cppMatrixArgToRArg(const std::string& cppArg) {
2623 
2624  // look for Matrix
2625  std::string matrix = "Matrix";
2626  size_t matrixLoc = cppArg.find(matrix);
2627  if (matrixLoc == std::string::npos ||
2628  ((matrixLoc + matrix.length()) >= cppArg.size())) {
2629  return std::string();
2630  }
2631 
2632  std::string args = cppArg.substr(matrixLoc + matrix.length());
2633  return "matrix" + args; // #nocov end
2634  }
2635 
2636  // convert a C++ literal to an R argument (returns empty string
2637  // if no conversion possible)
2638  std::string cppLiteralArgToRArg(const std::string& cppArg) {
2639  if (cppArg == "true")
2640  return "TRUE";
2641  else if (cppArg == "false")
2642  return "FALSE";
2643  else if (cppArg == "R_NilValue")
2644  return "NULL";
2645  else if (cppArg == "NA_STRING") // #nocov start
2646  return "NA_character_";
2647  else if (cppArg == "NA_INTEGER")
2648  return "NA_integer_";
2649  else if (cppArg == "NA_LOGICAL")
2650  return "NA_integer_";
2651  else if (cppArg == "NA_REAL")
2652  return "NA_real_";
2653  else
2654  return std::string();
2655  }
2656 
2657  // convert an Rcpp container constructor to an R argument
2658  // (returns empty string if no conversion possible)
2659  std::string cppConstructorArgToRArg(const std::string& cppArg) {
2660 
2661  // map Rcpp containers to R default initializers
2662  static std::map<std::string, std::string> RcppContainerToR;
2663  RcppContainerToR.insert(std::make_pair("NumericVector", "numeric"));
2664  RcppContainerToR.insert(std::make_pair("DoubleVector", "numeric"));
2665  RcppContainerToR.insert(std::make_pair("CharacterVector", "character"));
2666  RcppContainerToR.insert(std::make_pair("IntegerVector", "integer"));
2667  RcppContainerToR.insert(std::make_pair("LogicalVector", "logical"));
2668  RcppContainerToR.insert(std::make_pair("ComplexVector", "complex"));
2669 
2670  // for each entry in the map above, see if we find it; if we do,
2671  // return the R version
2672  typedef std::map<std::string, std::string>::const_iterator Iterator;
2673  for (Iterator it = RcppContainerToR.begin(); it != RcppContainerToR.end(); ++it) {
2674  size_t loc = cppArg.find(it->first);
2675  if (loc != std::string::npos) {
2676  return it->second + cppArg.substr(it->first.size(), std::string::npos);
2677  }
2678  }
2679 
2680  return std::string(); // #nocov end
2681 
2682  }
2683 
2684  // convert a C++ argument value to an R argument value (returns empty
2685  // string if no conversion is possible)
2686  std::string cppArgToRArg(const std::string& type,
2687  const std::string& cppArg) {
2688 
2689  // try for quoted string
2690  if (isQuoted(cppArg))
2691  return cppArg;
2692 
2693  // try for literal
2694  std::string rArg = cppLiteralArgToRArg(cppArg);
2695  if (!rArg.empty())
2696  return rArg;
2697 
2698  // try for a create arg
2699  rArg = cppCreateArgToRArg(cppArg); // #nocov start
2700  if (!rArg.empty())
2701  return rArg;
2702 
2703  // try for a matrix arg
2704  rArg = cppMatrixArgToRArg(cppArg);
2705  if (!rArg.empty())
2706  return rArg;
2707 
2708  // try for a numeric arg
2709  rArg = cppNumericArgToRArg(type, cppArg);
2710  if (!rArg.empty())
2711  return rArg;
2712 
2713  // try for a constructor arg
2714  rArg = cppConstructorArgToRArg(cppArg);
2715  if (!rArg.empty())
2716  return rArg;
2717 
2718  // couldn't parse the arg
2719  return std::string(); // #nocov end
2720  }
2721 
2722  } // anonymous namespace
2723 
2724  // Generate an R argument list for a function
2725  std::string generateRArgList(const Function& function) {
2726  std::ostringstream argsOstr;
2727  const std::vector<Argument>& arguments = function.arguments();
2728  for (size_t i = 0; i<arguments.size(); i++) {
2729  const Argument& argument = arguments[i];
2730  argsOstr << argument.name();
2731  if (!argument.defaultValue().empty()) {
2732  std::string rArg = cppArgToRArg(argument.type().name(),
2733  argument.defaultValue());
2734  if (!rArg.empty()) {
2735  argsOstr << " = " << rArg;
2736  } else {
2737  showWarning("Unable to parse C++ default value '" + // #nocov start
2738  argument.defaultValue() + "' for argument "+
2739  argument.name() + " of function " +
2740  function.name()); // #nocov end
2741  }
2742  }
2743 
2744  if (i != (arguments.size()-1))
2745  argsOstr << ", ";
2746  }
2747  return argsOstr.str();
2748  }
2749 
2750  // Generate the C++ code required to initialize global objects
2751  void initializeGlobals(std::ostream& ostr) {
2752  ostr << "#ifdef RCPP_USE_GLOBAL_ROSTREAM" << std::endl;
2753  ostr << "Rcpp::Rostream<true>& Rcpp::Rcout = Rcpp::Rcpp_cout_get();";
2754  ostr << std::endl;
2755  ostr << "Rcpp::Rostream<false>& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get();";
2756  ostr << std::endl;
2757  ostr << "#endif" << std::endl << std::endl;
2758  }
2759 
2760  // Generate the C++ code required to make [[Rcpp::export]] functions
2761  // available as C symbols with SEXP parameters and return
2762  void generateCpp(std::ostream& ostr,
2763  const SourceFileAttributes& attributes,
2764  bool includePrototype,
2765  bool cppInterface,
2766  const std::string& contextId) {
2767 
2768  // process each attribute
2769  for(std::vector<Attribute>::const_iterator
2770  it = attributes.begin(); it != attributes.end(); ++it) {
2771 
2772  // alias the attribute and function (bail if not export)
2773  const Attribute& attribute = *it;
2774  if (!attribute.isExportedFunction())
2775  continue;
2776  const Function& function = attribute.function();
2777 
2778  // include prototype if requested
2779  if (includePrototype) {
2780  ostr << "// " << function.name() << std::endl;
2781  printFunction(ostr, function, false);
2782  ostr << ";";
2783  }
2784 
2785  // write the C++ callable SEXP-based function (this version
2786  // returns errors via "try-error")
2787  ostr << std::endl;
2788  ostr << (cppInterface ? "static" : "RcppExport");
2789  ostr << " SEXP ";
2790  std::string funcName = contextId + "_" + function.name();
2791  ostr << funcName;
2792  if (cppInterface)
2793  ostr << kTrySuffix; // #nocov
2794  ostr << "(";
2795  std::ostringstream ostrArgs;
2796  const std::vector<Argument>& arguments = function.arguments();
2797  for (size_t i = 0; i<arguments.size(); i++) {
2798  const Argument& argument = arguments[i];
2799  ostrArgs << "SEXP " << argument.name() << "SEXP";
2800  if (i != (arguments.size()-1))
2801  ostrArgs << ", ";
2802  }
2803  std::string args = ostrArgs.str();
2804  ostr << args << ") {" << std::endl;
2805  ostr << "BEGIN_RCPP" << std::endl;
2806  if (!function.type().isVoid())
2807  ostr << " Rcpp::RObject rcpp_result_gen;" << std::endl;
2808  if (!cppInterface && attribute.rng())
2809  ostr << " Rcpp::RNGScope rcpp_rngScope_gen;" << std::endl;
2810  for (size_t i = 0; i<arguments.size(); i++) {
2811  const Argument& argument = arguments[i];
2812 
2813  ostr << " Rcpp::traits::input_parameter< "
2814  << argument.type().full_name() << " >::type " << argument.name()
2815  << "(" << argument.name() << "SEXP);" << std::endl;
2816  }
2817 
2818  ostr << " ";
2819  if (!function.type().isVoid())
2820  ostr << "rcpp_result_gen = Rcpp::wrap(";
2821  ostr << function.name() << "(";
2822  for (size_t i = 0; i<arguments.size(); i++) {
2823  const Argument& argument = arguments[i];
2824  ostr << argument.name();
2825  if (i != (arguments.size()-1))
2826  ostr << ", ";
2827  }
2828  if (!function.type().isVoid())
2829  ostr << ")";
2830  ostr << ");" << std::endl;
2831 
2832  if (!function.type().isVoid())
2833  {
2834  ostr << " return rcpp_result_gen;" << std::endl;
2835  }
2836  else
2837  {
2838  ostr << " return R_NilValue;" << std::endl;
2839  }
2840  ostr << (cppInterface ? "END_RCPP_RETURN_ERROR" : "END_RCPP")
2841  << std::endl;
2842  ostr << "}" << std::endl;
2843 
2844  // Now write an R wrapper that returns error via Rf_error
2845  if (cppInterface) {
2846  ostr << "RcppExport SEXP " << funcName << "(" << args << ") {" // #nocov start
2847  << std::endl;
2848  ostr << " SEXP rcpp_result_gen;" << std::endl;
2849  ostr << " {" << std::endl;
2850  if (attribute.rng())
2851  ostr << " Rcpp::RNGScope rcpp_rngScope_gen;" << std::endl;
2852  ostr << " rcpp_result_gen = PROTECT(" << funcName
2853  << kTrySuffix << "(";
2854  for (size_t i = 0; i<arguments.size(); i++) {
2855  const Argument& argument = arguments[i];
2856  ostr << argument.name() << "SEXP";
2857  if (i != (arguments.size()-1))
2858  ostr << ", ";
2859  }
2860  ostr << "));" << std::endl;
2861  ostr << " }" << std::endl;
2862  ostr << " Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, \"interrupted-error\");"
2863  << std::endl
2864  << " if (rcpp_isInterrupt_gen) {" << std::endl
2865  << " UNPROTECT(1);" << std::endl
2866  << " Rf_onintr();" << std::endl
2867  << " }" << std::endl
2868  << " bool rcpp_isLongjump_gen = Rcpp::internal::isLongjumpSentinel(rcpp_result_gen);" << std::endl
2869  << " if (rcpp_isLongjump_gen) {" << std::endl
2870  // No need to unprotect before jump
2871  << " Rcpp::internal::resumeJump(rcpp_result_gen);" << std::endl
2872  << " }" << std::endl
2873  << " Rboolean rcpp_isError_gen = Rf_inherits(rcpp_result_gen, \"try-error\");"
2874  << std::endl
2875  << " if (rcpp_isError_gen) {" << std::endl
2876  << " SEXP rcpp_msgSEXP_gen = Rf_asChar(rcpp_result_gen);" << std::endl
2877  << " UNPROTECT(1);" << std::endl
2878  << " Rf_error(CHAR(rcpp_msgSEXP_gen));" << std::endl
2879  << " }" << std::endl
2880  << " UNPROTECT(1);" << std::endl
2881  << " return rcpp_result_gen;" << std::endl
2882  << "}" << std::endl; // #nocov end
2883  }
2884  }
2885  }
2886 
2887 } // namespace attributes
2888 } // namespace Rcpp
2889 
2890 
2891 
2892 
2893 
2894 // provide implementations for util
2895 namespace Rcpp {
2896 namespace attributes {
2897 
2898  // Utility class for getting file existence and last modified time
2899  FileInfo::FileInfo(const std::string& path)
2900  : path_(path), exists_(false), lastModified_(0)
2901  {
2902  #ifdef _WIN32
2903  struct _stat buffer;
2904  int result = _stat(path.c_str(), &buffer);
2905  #else
2906  struct stat buffer;
2907  int result = stat(path.c_str(), &buffer);
2908  #endif
2909  if (result != 0) {
2910  if (errno == ENOENT)
2911  exists_ = false;
2912  else
2913  throw Rcpp::file_io_error(errno, path); // #nocov
2914  } else {
2915  exists_ = true;
2916  lastModified_ = static_cast<double>(buffer.st_mtime);
2917  }
2918  }
2919 
2920  // Remove a file (call back into R for this)
2921  bool removeFile(const std::string& path) {
2922  if (FileInfo(path).exists()) {
2923  Rcpp::Function rm = Rcpp::Environment::base_env()["file.remove"]; // #nocov start
2924  rm(path);
2925  return true; // #nocov end
2926  }
2927  else {
2928  return false;
2929  }
2930  }
2931 
2932  // Recursively create a directory (call back into R for this)
2933  void createDirectory(const std::string& path) { // #nocov start
2934  if (!FileInfo(path).exists()) {
2935  Rcpp::Function mkdir = Rcpp::Environment::base_env()["dir.create"];
2936  mkdir(path, Rcpp::Named("recursive") = true);
2937  }
2938  } // #nocov end
2939 
2940  // Known whitespace chars
2941  const char * const kWhitespaceChars = " \f\n\r\t\v";
2942 
2943  // Query whether a character is whitespace
2944  bool isWhitespace(char ch) {
2945  return std::strchr(kWhitespaceChars, ch) != NULL;
2946  }
2947 
2948  // Remove trailing line comments -- ie, find comments that don't begin
2949  // a line, and remove them. We avoid stripping attributes.
2950  void stripTrailingLineComments(std::string* pStr) {
2951 
2952  if (pStr->empty()) return;
2953 
2954  size_t len = pStr->length();
2955  bool inString = false;
2956  size_t idx = 0;
2957 
2958  // if this is an roxygen comment, then bail
2959  if (isRoxygenCpp(*pStr)) return;
2960 
2961  // skip over initial whitespace
2962  idx = pStr->find_first_not_of(kWhitespaceChars);
2963  if (idx == std::string::npos) return;
2964 
2965  // skip over a first comment
2966  if (idx + 1 < len && pStr->at(idx) == '/' && pStr->at(idx + 1) == '/') {
2967  idx = idx + 2;
2968  }
2969 
2970  // since we are searching for "//", we iterate up to 2nd last character
2971  while (idx < len - 1) {
2972 
2973  if (inString) {
2974  if (pStr->at(idx) == '"' && pStr->at(idx - 1) != '\\') {
2975  inString = false;
2976  }
2977  } else {
2978  if (pStr->at(idx) == '"') {
2979  inString = true;
2980  }
2981  }
2982 
2983  if (!inString &&
2984  pStr->at(idx) == '/' &&
2985  pStr->at(idx + 1) == '/') {
2986  pStr->erase(idx);
2987  return;
2988  }
2989  ++idx;
2990  }
2991  }
2992 
2993  // Trim a string
2994  void trimWhitespace(std::string* pStr) {
2995 
2996  // skip empty case
2997  if (pStr->empty())
2998  return; // #nocov
2999 
3000  // trim right
3001  std::string::size_type pos = pStr->find_last_not_of(kWhitespaceChars);
3002  if (pos != std::string::npos)
3003  pStr->erase(pos + 1);
3004 
3005  // trim left
3006  pos = pStr->find_first_not_of(kWhitespaceChars);
3007  pStr->erase(0, pos);
3008  }
3009 
3010  // Strip balanced quotes from around a string (assumes already trimmed)
3011  void stripQuotes(std::string* pStr) {
3012  if (pStr->length() < 2)
3013  return;
3014  char quote = *(pStr->begin());
3015  if ( (quote == '\'' || quote == '\"') && (*(pStr->rbegin()) == quote) )
3016  *pStr = pStr->substr(1, pStr->length()-2); // #nocov
3017  }
3018 
3019  // is the passed string quoted?
3020  bool isQuoted(const std::string& str) {
3021  if (str.length() < 2)
3022  return false; // #nocov
3023  char quote = *(str.begin());
3024  return (quote == '\'' || quote == '\"') && (*(str.rbegin()) == quote);
3025  }
3026 
3027  // does a string end with another string?
3028  bool endsWith(const std::string& str, const std::string& suffix)
3029  {
3030  return str.size() >= suffix.size() &&
3031  str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
3032  }
3033 
3034  // show a warning message
3035  void showWarning(const std::string& msg) { // #nocov start
3037  warning(msg, Rcpp::Named("call.") = false);
3038  } // #nocov end
3039 
3040  bool isRoxygenCpp(const std::string& str) {
3041  size_t len = str.length();
3042  if (len < 3) return false;
3043  size_t idx = str.find_first_not_of(kWhitespaceChars);
3044  if (idx == std::string::npos) return false;
3045 
3046  // make sure there are characters to check
3047  if (len - 2 < idx) return false;
3048 
3049  if (str[idx] == '/' &&
3050  str[idx + 1] == '/' &&
3051  str[idx + 2] == '\'') {
3052  return true;
3053  }
3054 
3055  return false;
3056 
3057  }
3058 
3059 } // namespace attributes
3060 } // namespace Rcpp
3061 
3062 
3063 /*******************************************************************
3064  * Attributes.cpp
3065  *******************************************************************/
3066 
3067 using namespace Rcpp::attributes;
3068 
3069 // Implementation helpers for sourceCppContext
3070 namespace {
3071 
3072  // Class that manages generation of source code for the sourceCpp dynlib
3073  class SourceCppDynlib {
3074  public:
3075  SourceCppDynlib() {}
3076 
3077  SourceCppDynlib(const std::string& cacheDir,
3078  const std::string& cppSourcePath,
3079  Rcpp::List platform)
3080  : cppSourcePath_(cppSourcePath)
3081 
3082  {
3083  // get cpp source file info
3084  FileInfo cppSourceFilenameInfo(cppSourcePath_);
3085  if (!cppSourceFilenameInfo.exists())
3086  throw Rcpp::file_not_found(cppSourcePath_); // #nocov
3087 
3088  // record the base name of the source file
3089  Rcpp::Function basename = Rcpp::Environment::base_env()["basename"];
3090  cppSourceFilename_ = Rcpp::as<std::string>(basename(cppSourcePath_));
3091 
3092  // get platform info
3093  fileSep_ = Rcpp::as<std::string>(platform["file.sep"]);
3094  dynlibExt_ = Rcpp::as<std::string>(platform["dynlib.ext"]);
3095 
3096  // generate temp directory
3097  Rcpp::Function tempfile = Rcpp::Environment::base_env()["tempfile"];
3098  buildDirectory_ = Rcpp::as<std::string>(tempfile("sourcecpp_", cacheDir));
3099  std::replace(buildDirectory_.begin(), buildDirectory_.end(), '\\', '/');
3100  Rcpp::Function dircreate = Rcpp::Environment::base_env()["dir.create"];
3101  dircreate(buildDirectory_);
3102 
3103  // generate a random context id
3104  contextId_ = "sourceCpp_" + uniqueToken(cacheDir);
3105 
3106  // regenerate the source code
3107  regenerateSource(cacheDir);
3108  }
3109 
3110  // create from list
3111  explicit SourceCppDynlib(const Rcpp::List& dynlib)
3112  {
3113  using namespace Rcpp;
3114 
3115  cppSourcePath_ = as<std::string>(dynlib["cppSourcePath"]);
3116  generatedCpp_ = as<std::string>(dynlib["generatedCpp"]);
3117  cppSourceFilename_ = as<std::string>(dynlib["cppSourceFilename"]);
3118  contextId_ = as<std::string>(dynlib["contextId"]);
3119  buildDirectory_ = as<std::string>(dynlib["buildDirectory"]);
3120  fileSep_ = as<std::string>(dynlib["fileSep"]);
3121  dynlibFilename_ = as<std::string>(dynlib["dynlibFilename"]);
3122  previousDynlibFilename_ = as<std::string>(dynlib["previousDynlibFilename"]);
3123  dynlibExt_ = as<std::string>(dynlib["dynlibExt"]);
3124  exportedFunctions_ = as<std::vector<std::string> >(dynlib["exportedFunctions"]);
3125  modules_ = as<std::vector<std::string> >(dynlib["modules"]);
3126  depends_ = as<std::vector<std::string> >(dynlib["depends"]);
3127  plugins_ = as<std::vector<std::string> >(dynlib["plugins"]);
3128  embeddedR_ = as<std::vector<std::string> >(dynlib["embeddedR"]);
3129  List sourceDependencies = as<List>(dynlib["sourceDependencies"]);
3130  for (R_xlen_t i = 0; i<sourceDependencies.length(); i++) {
3131  List fileInfo = as<List>(sourceDependencies.at(i)); // #nocov
3132  sourceDependencies_.push_back(FileInfo(fileInfo)); // #nocov
3133  }
3134  }
3135 
3136  // convert to list
3137  Rcpp::List toList() const {
3138  using namespace Rcpp;
3139  List dynlib;
3140  dynlib["cppSourcePath"] = cppSourcePath_;
3141  dynlib["generatedCpp"] = generatedCpp_;
3142  dynlib["cppSourceFilename"] = cppSourceFilename_;
3143  dynlib["contextId"] = contextId_;
3144  dynlib["buildDirectory"] = buildDirectory_;
3145  dynlib["fileSep"] = fileSep_;
3146  dynlib["dynlibFilename"] = dynlibFilename_;
3147  dynlib["previousDynlibFilename"] = previousDynlibFilename_;
3148  dynlib["dynlibExt"] = dynlibExt_;
3149  dynlib["exportedFunctions"] = exportedFunctions_;
3150  dynlib["modules"] = modules_;
3151  dynlib["depends"] = depends_;
3152  dynlib["plugins"] = plugins_;
3153  dynlib["embeddedR"] = embeddedR_;
3154  List sourceDependencies;
3155  for (std::size_t i = 0; i<sourceDependencies_.size(); i++) {
3156  FileInfo fileInfo = sourceDependencies_.at(i);
3157  sourceDependencies.push_back(fileInfo.toList());
3158  }
3159  dynlib["sourceDependencies"] = sourceDependencies;
3160 
3161  return dynlib;
3162  }
3163 
3164  bool isEmpty() const { return cppSourcePath_.empty(); }
3165 
3166  bool isBuilt() const { return FileInfo(dynlibPath()).exists(); };
3167 
3168  bool isSourceDirty() const {
3169  // source file out of date means we're dirty
3170  if (FileInfo(cppSourcePath_).lastModified() >
3171  FileInfo(generatedCppSourcePath()).lastModified())
3172  return true; // #nocov
3173 
3174  // no dynlib means we're dirty
3175  if (!FileInfo(dynlibPath()).exists())
3176  return true; // #nocov
3177 
3178  // variation in source dependencies means we're dirty
3179  std::vector<FileInfo> sourceDependencies = parseSourceDependencies(
3180  cppSourcePath_);
3181  if (sourceDependencies != sourceDependencies_)
3182  return true; // #nocov
3183 
3184  // not dirty
3185  return false;
3186  }
3187 
3188  void regenerateSource(const std::string& cacheDir) {
3189 
3190  // create new dynlib filename
3191  previousDynlibFilename_ = dynlibFilename_;
3192  dynlibFilename_ = "sourceCpp_" + uniqueToken(cacheDir) + dynlibExt_;
3193 
3194  // copy the source file to the build dir
3195  Rcpp::Function filecopy = Rcpp::Environment::base_env()["file.copy"];
3196  filecopy(cppSourcePath_, generatedCppSourcePath(), true);
3197 
3198  // parse attributes
3199  SourceFileAttributesParser sourceAttributes(cppSourcePath_, "", true);
3200 
3201  // generate cpp for attributes and append them
3202  std::ostringstream ostr;
3203  // always include Rcpp.h in case the user didn't
3204  ostr << std::endl << std::endl;
3205  ostr << "#include <Rcpp.h>" << std::endl;
3206  // initialize references to global Rostreams
3207  initializeGlobals(ostr);
3208  generateCpp(ostr, sourceAttributes, true, false, contextId_);
3209  generatedCpp_ = ostr.str();
3210  std::ofstream cppOfs(generatedCppSourcePath().c_str(),
3211  std::ofstream::out | std::ofstream::app);
3212  if (cppOfs.fail())
3213  throw Rcpp::file_io_error(generatedCppSourcePath()); // #nocov
3214  cppOfs << generatedCpp_;
3215  cppOfs.close();
3216 
3217  // generate R for attributes and write it into the build directory
3218  std::ofstream rOfs(generatedRSourcePath().c_str(),
3219  std::ofstream::out | std::ofstream::trunc);
3220  if (rOfs.fail())
3221  throw Rcpp::file_io_error(generatedRSourcePath()); // #nocov
3222 
3223  // DLLInfo - hide using . and ensure uniqueness using contextId
3224  std::string dllInfo = "`." + contextId_ + "_DLLInfo`";
3225  rOfs << dllInfo << " <- dyn.load('" << dynlibPath() << "')"
3226  << std::endl << std::endl;
3227 
3228  // Generate R functions
3229  generateR(rOfs, sourceAttributes, dllInfo);
3230 
3231  // remove the DLLInfo
3232  rOfs << std::endl << "rm(" << dllInfo << ")"
3233  << std::endl;
3234 
3235  rOfs.close();
3236 
3237  // discover exported functions and dependencies
3238  exportedFunctions_.clear();
3239  depends_.clear();
3240  plugins_.clear();
3242  it = sourceAttributes.begin(); it != sourceAttributes.end(); ++it) {
3243 
3244  if (it->name() == kExportAttribute && !it->function().empty())
3245  exportedFunctions_.push_back(it->exportedName());
3246 
3247  else if (it->name() == kDependsAttribute) {
3248  for (size_t i = 0; i<it->params().size(); ++i) // #nocov
3249  depends_.push_back(it->params()[i].name()); // #nocov
3250  }
3251 
3252  else if (it->name() == kPluginsAttribute) {
3253  for (size_t i = 0; i<it->params().size(); ++i)
3254  plugins_.push_back(it->params()[i].name());
3255  }
3256  }
3257 
3258  // capture modules
3259  modules_ = sourceAttributes.modules();
3260 
3261  // capture embededded R
3262  embeddedR_ = sourceAttributes.embeddedR();
3263 
3264  // capture source dependencies
3265  sourceDependencies_ = sourceAttributes.sourceDependencies();
3266  }
3267 
3268  const std::string& contextId() const {
3269  return contextId_;
3270  }
3271 
3272  const std::string& cppSourcePath() const {
3273  return cppSourcePath_;
3274  }
3275 
3276  const std::vector<std::string> cppDependencySourcePaths() {
3277  std::vector<std::string> dependencies;
3278  for (size_t i = 0; i<sourceDependencies_.size(); ++i) {
3279  FileInfo dep = sourceDependencies_[i];
3280  if (dep.extension() == ".cc" || dep.extension() == ".cpp") {
3281  dependencies.push_back(dep.path()); // #nocov
3282  }
3283  }
3284  return dependencies;
3285  }
3286 
3287  std::string buildDirectory() const {
3288  return buildDirectory_;
3289  }
3290 
3291  std::string generatedCpp() const {
3292  return generatedCpp_;
3293  }
3294 
3295  std::string cppSourceFilename() const {
3296  return cppSourceFilename_;
3297  }
3298 
3299  std::string rSourceFilename() const {
3300  return cppSourceFilename() + ".R";
3301  }
3302 
3303  std::string dynlibFilename() const {
3304  return dynlibFilename_;
3305  }
3306 
3307  std::string dynlibPath() const {
3308  return buildDirectory_ + fileSep_ + dynlibFilename();
3309  }
3310 
3311  std::string previousDynlibPath() const {
3312  if (!previousDynlibFilename_.empty())
3313  return buildDirectory_ + fileSep_ + previousDynlibFilename_; // #nocov
3314  else
3315  return std::string();
3316  }
3317 
3318  const std::vector<std::string>& exportedFunctions() const {
3319  return exportedFunctions_;
3320  }
3321 
3322  const std::vector<std::string>& modules() const {
3323  return modules_;
3324  }
3325 
3326  const std::vector<std::string>& depends() const { return depends_; };
3327 
3328  const std::vector<std::string>& plugins() const { return plugins_; };
3329 
3330  const std::vector<std::string>& embeddedR() const { return embeddedR_; }
3331 
3332  private:
3333 
3334  std::string generatedCppSourcePath() const {
3335  return buildDirectory_ + fileSep_ + cppSourceFilename();
3336  }
3337 
3338  std::string generatedRSourcePath() const {
3339  return buildDirectory_ + fileSep_ + rSourceFilename();
3340  }
3341 
3342  void generateR(std::ostream& ostr,
3343  const SourceFileAttributes& attributes,
3344  const std::string& dllInfo) const
3345  {
3346  // process each attribute
3347  for(std::vector<Attribute>::const_iterator
3348  it = attributes.begin(); it != attributes.end(); ++it) {
3349 
3350  // alias the attribute and function (bail if not export)
3351  const Attribute& attribute = *it;
3352  if (!attribute.isExportedFunction())
3353  continue;
3354  const Function& function = attribute.function();
3355 
3356  // export the function
3357  ostr << attribute.exportedName()
3358  << " <- Rcpp:::sourceCppFunction("
3359  << "function(" << generateRArgList(function) << ") {}, "
3360  << (function.type().isVoid() ? "TRUE" : "FALSE") << ", "
3361  << dllInfo << ", "
3362  << "'" << contextId_ + "_" + function.name()
3363  << "')" << std::endl;
3364  }
3365 
3366  // modules
3367  std::vector<std::string> modules = attributes.modules();
3368  if (modules.size() > 0)
3369  {
3370  // modules require definition of C++Object to be loaded
3371  ostr << "library(Rcpp)" << std::endl;
3372 
3373  // load each module
3374  for (std::vector<std::string>::const_iterator
3375  it = modules.begin(); it != modules.end(); ++it)
3376  {
3377  ostr << " populate( Rcpp::Module(\"" << *it << "\","
3378  << dllInfo << "), environment() ) " << std::endl;
3379  }
3380  }
3381 
3382  }
3383 
3384  std::string uniqueToken(const std::string& cacheDir) {
3386  Rcpp::Function uniqueTokenFunc = rcppEnv[".sourceCppDynlibUniqueToken"];
3387  return Rcpp::as<std::string>(uniqueTokenFunc(cacheDir));
3388  }
3389 
3390  private:
3391  std::string cppSourcePath_;
3392  std::string generatedCpp_;
3393  std::string cppSourceFilename_;
3394  std::string contextId_;
3395  std::string buildDirectory_;
3396  std::string fileSep_;
3397  std::string dynlibFilename_;
3398  std::string previousDynlibFilename_;
3399  std::string dynlibExt_;
3400  std::vector<std::string> exportedFunctions_;
3401  std::vector<std::string> modules_;
3402  std::vector<std::string> depends_;
3403  std::vector<std::string> plugins_;
3404  std::vector<std::string> embeddedR_;
3405  std::vector<FileInfo> sourceDependencies_;
3406  };
3407 
3408  // Dynlib cache that allows lookup by either file path or code contents
3409 
3410  void dynlibCacheInsert(const std::string& cacheDir,
3411  const std::string& file,
3412  const std::string& code,
3413  const SourceCppDynlib& dynlib)
3414  {
3416  Rcpp::Function dynlibInsertFunc = rcppEnv[".sourceCppDynlibInsert"];
3417  dynlibInsertFunc(cacheDir, file, code, dynlib.toList());
3418  }
3419 
3420  void dynlibCacheInsertFile(const std::string& cacheDir,
3421  const std::string& file,
3422  const SourceCppDynlib& dynlib)
3423  {
3424  dynlibCacheInsert(cacheDir, file, "", dynlib);
3425  }
3426 
3427  void dynlibCacheInsertCode(const std::string& cacheDir,
3428  const std::string& code,
3429  const SourceCppDynlib& dynlib)
3430  {
3431  dynlibCacheInsert(cacheDir, "", code, dynlib);
3432  }
3433 
3434  SourceCppDynlib dynlibCacheLookup(const std::string& cacheDir,
3435  const std::string& file,
3436  const std::string& code)
3437  {
3439  Rcpp::Function dynlibLookupFunc = rcppEnv[".sourceCppDynlibLookup"];
3440  Rcpp::List dynlibList = dynlibLookupFunc(cacheDir, file, code);
3441  if (dynlibList.length() > 0)
3442  return SourceCppDynlib(dynlibList);
3443  else
3444  return SourceCppDynlib();
3445  }
3446 
3447  SourceCppDynlib dynlibCacheLookupByFile(const std::string& cacheDir,
3448  const std::string& file)
3449  {
3450  return dynlibCacheLookup(cacheDir, file, "");
3451  }
3452 
3453  SourceCppDynlib dynlibCacheLookupByCode(const std::string& cacheDir,
3454  const std::string& code)
3455  {
3456  return dynlibCacheLookup(cacheDir, "", code);
3457  }
3458 
3459 } // anonymous namespace
3460 
3461 // Create temporary build directory, generate code as necessary, and return
3462 // the context required for the sourceCpp function to complete it's work
3463 RcppExport SEXP sourceCppContext(SEXP sFile, SEXP sCode,
3464  SEXP sRebuild, SEXP sCacheDir, SEXP sPlatform) {
3465 BEGIN_RCPP
3466  // parameters
3467  std::string file = Rcpp::as<std::string>(sFile);
3468  std::string code = sCode != R_NilValue ? Rcpp::as<std::string>(sCode) : "";
3469  bool rebuild = Rcpp::as<bool>(sRebuild);
3470  std::string cacheDir = Rcpp::as<std::string>(sCacheDir);
3471  Rcpp::List platform = Rcpp::as<Rcpp::List>(sPlatform);
3472 
3473  // get dynlib (using cache if possible)
3474  SourceCppDynlib dynlib = !code.empty() ? dynlibCacheLookupByCode(cacheDir, code)
3475  : dynlibCacheLookupByFile(cacheDir, file);
3476 
3477  // check dynlib build state
3478  bool buildRequired = false;
3479 
3480  // if there is no dynlib in the cache then create a new one
3481  if (dynlib.isEmpty()) {
3482  buildRequired = true;
3483  dynlib = SourceCppDynlib(cacheDir, file, platform);
3484  }
3485 
3486  // if the cached dynlib is dirty then regenerate the source
3487  else if (rebuild || dynlib.isSourceDirty()) {
3488  buildRequired = true; // #nocov
3489  dynlib.regenerateSource(cacheDir); // #nocov
3490  }
3491 
3492  // if the dynlib hasn't yet been built then note that
3493  else if (!dynlib.isBuilt()) {
3494  buildRequired = true; // #nocov
3495  }
3496 
3497  // save the dynlib to the cache
3498  if (!code.empty())
3499  dynlibCacheInsertCode(cacheDir, code, dynlib);
3500  else
3501  dynlibCacheInsertFile(cacheDir, file, dynlib);
3502 
3503  // return context as a list
3504  using namespace Rcpp;
3505  return List::create(
3506  _["contextId"] = dynlib.contextId(),
3507  _["cppSourcePath"] = dynlib.cppSourcePath(),
3508  _["cppDependencySourcePaths"] = dynlib.cppDependencySourcePaths(),
3509  _["buildRequired"] = buildRequired,
3510  _["buildDirectory"] = dynlib.buildDirectory(),
3511  _["generatedCpp"] = dynlib.generatedCpp(),
3512  _["exportedFunctions"] = dynlib.exportedFunctions(),
3513  _["modules"] = dynlib.modules(),
3514  _["cppSourceFilename"] = dynlib.cppSourceFilename(),
3515  _["rSourceFilename"] = dynlib.rSourceFilename(),
3516  _["dynlibFilename"] = dynlib.dynlibFilename(),
3517  _["dynlibPath"] = dynlib.dynlibPath(),
3518  _["previousDynlibPath"] = dynlib.previousDynlibPath(),
3519  _["depends"] = dynlib.depends(),
3520  _["plugins"] = dynlib.plugins(),
3521  _["embeddedR"] = dynlib.embeddedR());
3522 END_RCPP
3523 }
3524 
3525 // Compile the attributes within the specified package directory into
3526 // RcppExports.cpp and RcppExports.R
3527 RcppExport SEXP compileAttributes(SEXP sPackageDir,
3528  SEXP sPackageName,
3529  SEXP sDepends,
3530  SEXP sRegistration,
3531  SEXP sCppFiles,
3532  SEXP sCppFileBasenames,
3533  SEXP sIncludes,
3534  SEXP sVerbose,
3535  SEXP sPlatform) {
3536 BEGIN_RCPP
3537  // arguments
3538  std::string packageDir = Rcpp::as<std::string>(sPackageDir);
3539  std::string packageName = Rcpp::as<std::string>(sPackageName);
3540 
3541  Rcpp::CharacterVector vDepends = Rcpp::as<Rcpp::CharacterVector>(sDepends);
3542  std::set<std::string> depends;
3544  it = vDepends.begin(); it != vDepends.end(); ++it) {
3545  depends.insert(std::string(*it));
3546  }
3547 
3548  bool registration = Rcpp::as<bool>(sRegistration);
3549 
3550  std::vector<std::string> cppFiles =
3551  Rcpp::as<std::vector<std::string> >(sCppFiles);
3552  std::vector<std::string> cppFileBasenames =
3553  Rcpp::as<std::vector<std::string> >(sCppFileBasenames);
3554  std::vector<std::string> includes =
3555  Rcpp::as<std::vector<std::string> >(sIncludes);
3556  bool verbose = Rcpp::as<bool>(sVerbose);
3557  Rcpp::List platform = Rcpp::as<Rcpp::List>(sPlatform);
3558  std::string fileSep = Rcpp::as<std::string>(platform["file.sep"]);
3559 
3560  // initialize generators
3561  ExportsGenerators generators;
3562  generators.add(new CppExportsGenerator(packageDir, packageName, fileSep));
3563  generators.add(new RExportsGenerator(packageDir, packageName, registration, fileSep));
3564 
3565  // catch file exists exception if the include file already exists
3566  // and we are unable to overwrite it
3567  try {
3568  generators.add(new CppExportsIncludeGenerator(packageDir,
3569  packageName,
3570  fileSep));
3571  }
3572  catch(const Rcpp::file_exists& e) {
3573  std::string msg =
3574  "The header file '" + e.filePath() + "' already exists so "
3575  "cannot be overwritten by Rcpp::interfaces";
3576  throw Rcpp::exception(msg.c_str(), __FILE__, __LINE__);
3577  }
3578 
3579  // catch file exists exception for package include (because if it
3580  // already exists we simply leave it alone)
3581  try {
3582  generators.add(new CppPackageIncludeGenerator(packageDir,
3583  packageName,
3584  fileSep));
3585  }
3586  catch(const Rcpp::file_exists& e) {}
3587 
3588  // write begin
3589  generators.writeBegin();
3590 
3591  // Parse attributes from each file and generate code as required.
3592  bool hasPackageInit = false;
3593  bool haveAttributes = false;
3594  std::set<std::string> dependsAttribs;
3595  for (std::size_t i=0; i<cppFiles.size(); i++) {
3596 
3597  // don't process RcppExports.cpp
3598  std::string cppFile = cppFiles[i];
3599  if (endsWith(cppFile, "RcppExports.cpp"))
3600  continue; // #nocov
3601 
3602  // parse file
3603  SourceFileAttributesParser attributes(cppFile, packageName, false);
3604 
3605  // note if we found a package init function
3606  if (!hasPackageInit && attributes.hasPackageInit())
3607  hasPackageInit = true; // #nocov
3608 
3609  // continue if no generator output
3610  if (!attributes.hasGeneratorOutput())
3611  continue; // #nocov
3612 
3613  // confirm we have attributes
3614  haveAttributes = true;
3615 
3616  // write functions
3617  generators.writeFunctions(attributes, verbose);
3618 
3619  // track depends
3621  it = attributes.begin(); it != attributes.end(); ++it) {
3622  if (it->name() == kDependsAttribute) {
3623  for (size_t i = 0; i<it->params().size(); ++i) // #nocov
3624  dependsAttribs.insert(it->params()[i].name()); // #nocov
3625  }
3626  }
3627  }
3628 
3629  // write end
3630  generators.writeEnd(hasPackageInit);
3631 
3632  // commit or remove
3633  std::vector<std::string> updated;
3634  if (haveAttributes)
3635  updated = generators.commit(includes);
3636  else
3637  updated = generators.remove(); // #nocov
3638 
3639  // print warning if there are depends attributes that don't have
3640  // corresponding entries in the DESCRIPTION file
3641  std::vector<std::string> diff;
3642  std::set_difference(dependsAttribs.begin(), dependsAttribs.end(),
3643  depends.begin(), depends.end(),
3644  std::back_inserter(diff));
3645  if (!diff.empty()) {
3646  std::string msg = // #nocov start
3647  "The following packages are referenced using Rcpp::depends "
3648  "attributes however are not listed in the Depends, Imports or "
3649  "LinkingTo fields of the package DESCRIPTION file: ";
3650  for (size_t i=0; i<diff.size(); i++) {
3651  msg += diff[i];
3652  if (i != (diff.size()-1))
3653  msg += ", ";
3654  }
3655  showWarning(msg);
3656  }
3657 
3658  // verbose output
3659  if (verbose) {
3660  for (size_t i=0; i<updated.size(); i++)
3661  Rcpp::Rcout << updated[i] << " updated." << std::endl; // #nocov end
3662  }
3663 
3664  // return files updated
3665  return Rcpp::wrap<std::vector<std::string> >(updated);
3666 END_RCPP
3667 }
Rcpp::attributes::Type::operator!=
bool operator!=(const Type &other) const
Definition: attributes.cpp:188
Rcpp::attributes::createDirectory
void createDirectory(const std::string &path)
Definition: attributes.cpp:2933
Rcpp::attributes::kInterfacesAttribute
const char *const kInterfacesAttribute
Definition: attributes.cpp:164
Rcpp::attributes::ExportsGenerators::operator=
ExportsGenerators & operator=(const ExportsGenerators &)
Rcpp::attributes::Argument::type
const Type & type() const
Definition: attributes.cpp:236
Rcpp::attributes::Argument::empty
bool empty() const
Definition: attributes.cpp:222
Rcpp::attributes::Attribute::operator==
bool operator==(const Attribute &other) const
Definition: attributes.cpp:328
Rcpp::attributes::SourceFileAttributesParser::parseArguments
std::vector< std::string > parseArguments(const std::string &argText)
Rcpp::attributes::CommentState::inComment
bool inComment() const
Definition: attributes.cpp:459
Rcpp::file_exists
Definition: exceptions.h:104
Rcpp::attributes::ExportsGenerator::writeBegin
virtual void writeBegin()=0
Rcpp::attributes::Attribute::empty
bool empty() const
Definition: attributes.cpp:326
Rcpp::attributes::SourceFileAttributes::hasGeneratorOutput
virtual bool hasGeneratorOutput() const =0
Rcpp::attributes::FileInfo::operator<
bool operator<(const FileInfo &other) const
Definition: attributes.cpp:89
Rcpp::attributes::RExportsGenerator
Definition: attributes.cpp:749
Rcpp::file_io_error::filePath
std::string filePath() const
Definition: exceptions.h:92
Rcpp::attributes::FileInfo::lastModified
double lastModified() const
Definition: attributes.cpp:79
Rcpp::attributes::Argument::name_
std::string name_
Definition: attributes.cpp:240
Rcpp::attributes::SourceFileAttributesParser
Definition: attributes.cpp:465
Rcpp::attributes::Type::name_
std::string name_
Definition: attributes.cpp:206
Rcpp::attributes::SourceFileAttributesParser::rcppInterfacesWarning
void rcppInterfacesWarning(const std::string &message, size_t lineNumber)
Rcpp::attributes::CppExportsGenerator::writeBegin
virtual void writeBegin()
Definition: attributes.cpp:681
Rcpp::attributes::Attribute::rng
bool rng() const
Definition: attributes.cpp:380
Rcpp::attributes::Param
Definition: attributes.cpp:290
Rcpp::attributes::ExportsGenerator::registerCCallableExportedName
std::string registerCCallableExportedName()
Definition: attributes.cpp:634
Rcpp::attributes::Function::arguments
const std::vector< Argument > & arguments() const
Definition: attributes.cpp:281
Rcpp::attributes::SourceFileAttributes::hasPackageInit
virtual bool hasPackageInit() const =0
Rcpp::attributes
Definition: attributes.cpp:48
Rcpp::namespace_env
static Environment_Impl namespace_env(const std::string &package)
Definition: Environment.h:371
Rcpp::attributes::SourceFileAttributesParser::roxygenChunks_
std::vector< std::vector< std::string > > roxygenChunks_
Definition: attributes.cpp:562
Rcpp::attributes::stripQuotes
void stripQuotes(std::string *pStr)
Definition: attributes.cpp:3011
Rcpp::attributes::ExportsGenerator::generatorToken
std::string generatorToken() const
Definition: attributes.cpp:662
Rcpp::attributes::removeFile
bool removeFile(const std::string &path)
Definition: attributes.cpp:2921
Rcpp::attributes::Param::name
const std::string & name() const
Definition: attributes.cpp:306
Rcpp::attributes::Argument::defaultValue_
std::string defaultValue_
Definition: attributes.cpp:242
Rcpp::Vector::push_back
void push_back(const T &object)
Definition: Vector.h:452
Rcpp::attributes::ExportsGenerators::ExportsGenerators
ExportsGenerators()
Definition: attributes.cpp:773
Rcpp::attributes::Attribute::name
const std::string & name() const
Definition: attributes.cpp:340
Rcpp::attributes::ExportsGenerator::package
const std::string & package() const
Definition: attributes.cpp:596
Rcpp::_
static internal::NamedPlaceHolder _
Definition: Named.h:64
Rcpp::attributes::Function::type
const Type & type() const
Definition: attributes.cpp:279
Rcpp::attributes::CommentState::CommentState
CommentState()
Definition: attributes.cpp:453
Rcpp::Named
Argument Named(const std::string &name)
Definition: Named.h:40
Rcpp::attributes::SourceFileAttributesParser::embeddedR_
std::vector< std::string > embeddedR_
Definition: attributes.cpp:560
Rcpp::Vector::length
R_xlen_t length() const
Definition: Vector.h:269
Rcpp::attributes::Function::operator==
bool operator==(const Function &other) const
Definition: attributes.cpp:269
Rcpp::attributes::CppExportsGenerator::initFunctions_
std::vector< Attribute > initFunctions_
Definition: attributes.cpp:695
Rcpp::attributes::CppPackageIncludeGenerator::doWriteFunctions
virtual void doWriteFunctions(const SourceFileAttributes &, bool)
Definition: attributes.cpp:740
Rcpp::attributes::SourceFileAttributesParser::attributes_
std::vector< Attribute > attributes_
Definition: attributes.cpp:557
Rcpp::result
Definition: Module.h:56
Rcpp::attributes::SourceFileAttributesParser::hasPackageInit_
bool hasPackageInit_
Definition: attributes.cpp:559
Rcpp::Function
Function_Impl< PreserveStorage > Function
Definition: Function.h:122
Rcpp::attributes::ExportsGenerator::targetFile_
std::string targetFile_
Definition: attributes.cpp:667
Rcpp::attributes::CppExportsGenerator::commit
virtual bool commit(const std::vector< std::string > &includes)
Definition: attributes.cpp:2121
Rcpp::attributes::SourceFileAttributesParser::hasGeneratorOutput
virtual bool hasGeneratorOutput() const
Definition: attributes.cpp:493
Rcpp::attributes::ExportsGenerator::~ExportsGenerator
virtual ~ExportsGenerator()
Definition: attributes.cpp:592
Rcpp::attributes::Attribute::params
const std::vector< Param > & params() const
Definition: attributes.cpp:342
Rcpp::attributes::ExportsGenerator::writeEnd
virtual void writeEnd(bool hasPackageInit)=0
BEGIN_RCPP
#define BEGIN_RCPP
Definition: macros.h:49
Rcpp::attributes::CppExportsGenerator::modules_
std::vector< std::string > modules_
Definition: attributes.cpp:704
Rcpp::attributes::CppExportsGenerator::registerCCallable
std::string registerCCallable(size_t indent, const std::string &exportedName, const std::string &name) const
Definition: attributes.cpp:2109
Rcpp::attributes::SourceFileAttributes::sourceFile
virtual const std::string & sourceFile() const =0
Rcpp::attributes::CppExportsIncludeGenerator::CppExportsIncludeGenerator
CppExportsIncludeGenerator(const std::string &packageDir, const std::string &package, const std::string &fileSep)
Definition: attributes.cpp:2144
Rcpp::attributes::initializeGlobals
void initializeGlobals(std::ostream &ostr)
Definition: attributes.cpp:2755
Rcpp::attributes::Attribute::exportedName
std::string exportedName() const
Definition: attributes.cpp:356
Rcpp::attributes::ExportsGenerator::codeStream_
std::ostringstream codeStream_
Definition: attributes.cpp:672
Rcpp::attributes::CppPackageIncludeGenerator::CppPackageIncludeGenerator
CppPackageIncludeGenerator(const std::string &packageDir, const std::string &package, const std::string &fileSep)
Definition: attributes.cpp:2362
Rcpp::attributes::SourceFileAttributesParser::isKnownAttribute
bool isKnownAttribute(const std::string &name) const
Rcpp::attributes::SourceFileAttributes::begin
virtual const_iterator begin() const =0
Rcpp::attributes::CppPackageIncludeGenerator::writeBegin
virtual void writeBegin()
Definition: attributes.cpp:735
Rcpp::attributes::ExportsGenerator::dotNameHelper
std::string dotNameHelper(const std::string &name) const
Definition: attributes.cpp:1908
Rcpp::attributes::SourceFileAttributesParser::parseAttribute
Attribute parseAttribute(const std::vector< std::string > &match, int lineNumber)
Rcpp::attributes::Type::operator==
bool operator==(const Type &other) const
Definition: attributes.cpp:182
Rcpp::attributes::Attribute::hasParameter
bool hasParameter(const std::string &name) const
Definition: attributes.cpp:346
Rcpp::attributes::Attribute::invisible
bool invisible() const
Definition: attributes.cpp:389
Rcpp::attributes::ExportsGenerators::remove
std::vector< std::string > remove()
Definition: attributes.cpp:2549
Rcpp::attributes::RExportsGenerator::RExportsGenerator
RExportsGenerator(const std::string &packageDir, const std::string &package, bool registration, const std::string &fileSep)
Definition: attributes.cpp:2407
Rcpp::attributes::Attribute
Definition: attributes.cpp:315
Rcpp::attributes::SourceFileAttributes::end
virtual const_iterator end() const =0
Rcpp::attributes::ExportsGenerator::remove
bool remove()
Definition: attributes.cpp:1903
Rcpp::Vector< VECSXP >::create
static Vector create()
Definition: Vector.h:1122
Rcpp::attributes::SourceFileAttributesParser::sourceDependencies_
std::vector< FileInfo > sourceDependencies_
Definition: attributes.cpp:561
Rcpp::attributes::SourceFileAttributesParser::modules_
std::vector< std::string > modules_
Definition: attributes.cpp:558
Rcpp::attributes::CppExportsIncludeGenerator::writeEnd
virtual void writeEnd(bool hasPackageInit)
Definition: attributes.cpp:2291
Rcpp::attributes::Attribute::roxygen_
std::vector< std::string > roxygen_
Definition: attributes.cpp:404
Rcpp::attributes::SourceFileAttributesParser::roxygenChunks
virtual const std::vector< std::vector< std::string > > & roxygenChunks() const
Definition: attributes.cpp:489
Rcpp::attributes::kExportAttribute
const char *const kExportAttribute
Definition: attributes.cpp:157
Rcpp::attributes::SourceFileAttributesParser::operator=
SourceFileAttributesParser & operator=(const SourceFileAttributesParser &)
Rcpp::attributes::CppPackageIncludeGenerator::writeEnd
virtual void writeEnd(bool hasPackageInit)
Definition: attributes.cpp:2375
Rcpp::attributes::SourceFileAttributesParser::parseSignature
std::string parseSignature(size_t lineNumber)
Rcpp::attributes::generateCpp
void generateCpp(std::ostream &ostr, const SourceFileAttributes &attributes, bool includePrototype, bool cppInterface, const std::string &contextId)
Definition: attributes.cpp:2766
Rcpp::attributes::Param::empty
bool empty() const
Definition: attributes.cpp:294
Rcpp::attributes::ExportsGenerators::~ExportsGenerators
virtual ~ExportsGenerators()
Definition: attributes.cpp:2504
Rcpp::attributes::CppExportsIncludeGenerator::doWriteFunctions
virtual void doWriteFunctions(const SourceFileAttributes &attributes, bool verbose)
Definition: attributes.cpp:2206
Rcpp::attributes::RExportsGenerator::commit
virtual bool commit(const std::vector< std::string > &includes)
Definition: attributes.cpp:2500
Rcpp::attributes::generateRArgList
std::string generateRArgList(const Function &function)
Definition: attributes.cpp:2729
Rcpp::attributes::CppExportsGenerator::cppExports_
std::vector< Attribute > cppExports_
Definition: attributes.cpp:698
Rcpp::attributes::Attribute::function_
Function function_
Definition: attributes.cpp:403
Rcpp::attributes::ExportsGenerators::writeBegin
void writeBegin()
Definition: attributes.cpp:2517
Rcpp::attributes::ExportsGenerator::commit
virtual bool commit(const std::vector< std::string > &includes)=0
Rcpp::attributes::SourceFileAttributesParser::sourceFile
virtual const std::string & sourceFile() const
Definition: attributes.cpp:478
Rcpp::attributes::Attribute::params_
std::vector< Param > params_
Definition: attributes.cpp:402
Rcpp::file_not_found
Definition: exceptions.h:98
Rcpp::attributes::isWhitespace
bool isWhitespace(char ch)
Definition: attributes.cpp:2944
Rcpp::attributes::SourceFileAttributesParser::modules
virtual const std::vector< std::string > & modules() const
Definition: attributes.cpp:484
Rcpp::attributes::ExportsGenerator::operator=
ExportsGenerator & operator=(const ExportsGenerator &)
END_RCPP
#define END_RCPP
Definition: macros.h:99
Rcpp::attributes::SourceFileAttributesParser::sourceDependencies
const std::vector< FileInfo > & sourceDependencies() const
Definition: attributes.cpp:526
Rcpp::attributes::SourceFileAttributesParser::roxygenBuffer_
std::vector< std::string > roxygenBuffer_
Definition: attributes.cpp:563
Rcpp::attributes::ExportsGenerator::isSafeToOverwrite
bool isSafeToOverwrite() const
Definition: attributes.cpp:655
Rcpp::attributes::Argument::Argument
Argument()
Definition: attributes.cpp:214
Rcpp::attributes::FileInfo::extension
std::string extension() const
Definition: attributes.cpp:81
Rcpp::attributes::Function::isHidden
bool isHidden() const
Definition: attributes.cpp:263
RcppExport
#define RcppExport
Definition: RcppCommon.h:139
Rcpp::Vector::size
R_xlen_t size() const
Definition: Vector.h:276
Rcpp::attributes::Function::empty
bool empty() const
Definition: attributes.cpp:267
Rcpp::attributes::kDependsAttribute
const char *const kDependsAttribute
Definition: attributes.cpp:162
Rcpp::attributes::ExportsGenerator::doWriteFunctions
virtual void doWriteFunctions(const SourceFileAttributes &attributes, bool verbose)=0
Rcpp::attributes::SourceFileAttributesParser::embeddedR
const std::vector< std::string > & embeddedR() const
Definition: attributes.cpp:521
Rcpp::attributes::Argument::type_
Type type_
Definition: attributes.cpp:241
Rcpp::Vector::end
iterator end()
Definition: Vector.h:335
Rcpp::attributes::SourceFileAttributesParser::SourceFileAttributesParser
SourceFileAttributesParser(const std::string &sourceFile, const std::string &packageFile, bool parseDependencies)
Rcpp::attributes::FileInfo::operator<<
std::ostream & operator<<(std::ostream &os) const
Definition: attributes.cpp:103
Rcpp::attributes::ExportsGenerator::ExportsGenerator
ExportsGenerator(const std::string &targetFile, const std::string &package, const std::string &commentPrefix)
Definition: attributes.cpp:1824
Rcpp::attributes::CppExportsIncludeGenerator
Definition: attributes.cpp:708
Rcpp::attributes::Type::Type
Type()
Definition: attributes.cpp:175
Rcpp
Rcpp API.
Definition: algo.h:28
Rcpp::attributes::Type::empty
bool empty() const
Definition: attributes.cpp:180
Rcpp::attributes::Type::isReference_
bool isReference_
Definition: attributes.cpp:208
Rcpp::attributes::stripTrailingLineComments
void stripTrailingLineComments(std::string *pStr)
Definition: attributes.cpp:2950
Rcpp::attributes::Param::value_
std::string value_
Definition: attributes.cpp:311
Rcpp::attributes::SourceFileAttributesParser::rcppExportNoFunctionFoundWarning
void rcppExportNoFunctionFoundWarning(size_t lineNumber)
Rcpp::attributes::RExportsGenerator::registration_
bool registration_
Definition: attributes.cpp:764
Rcpp::attributes::Function::renamedTo
Function renamedTo(const std::string &name) const
Definition: attributes.cpp:256
Rcpp::Vector::begin
iterator begin()
Definition: Vector.h:334
Rcpp::attributes::Type::isVoid
bool isVoid() const
Definition: attributes.cpp:201
Rcpp::attributes::CppPackageIncludeGenerator::getHeaderGuard
std::string getHeaderGuard() const
Definition: attributes.cpp:2403
Rcpp::attributes::ExportsGenerator
Definition: attributes.cpp:578
Rcpp::Rcout
static Rostream< true > Rcout
Definition: Rstreambuf.h:89
Rcpp::attributes::ExportsGenerators::commit
std::vector< std::string > commit(const std::vector< std::string > &includes)
Definition: attributes.cpp:2535
Rcpp::attributes::operator<<
std::ostream & operator<<(std::ostream &os, const Type &type)
Definition: attributes.cpp:1069
Rcpp::attributes::SourceFileAttributesParser::begin
virtual const_iterator begin() const
Definition: attributes.cpp:481
Rcpp::message
void message(SEXP s)
Definition: message.h:26
Rcpp::attributes::SourceFileAttributesParser::end
virtual const_iterator end() const
Definition: attributes.cpp:482
Rcpp::Vector< VECSXP >
Rcpp::attributes::RExportsGenerator::doWriteFunctions
virtual void doWriteFunctions(const SourceFileAttributes &attributes, bool verbose)
Definition: attributes.cpp:2419
Rcpp::attributes::Function
Definition: attributes.cpp:246
Rcpp::attributes::kParamValueTrue
const char *const kParamValueTrue
Definition: attributes.cpp:168
Rcpp::attributes::printFunction
void printFunction(std::ostream &os, const Function &function, bool printArgDefaults=true)
Definition: attributes.cpp:1102
Rcpp::attributes::Param::Param
Param()
Definition: attributes.cpp:292
Rcpp::attributes::ExportsGenerator::hasCppInterface_
bool hasCppInterface_
Definition: attributes.cpp:673
Rcpp::attributes::Attribute::roxygen
const std::vector< std::string > & roxygen() const
Definition: attributes.cpp:398
Rcpp::attributes::CppExportsGenerator::doWriteFunctions
virtual void doWriteFunctions(const SourceFileAttributes &attributes, bool verbose)
Definition: attributes.cpp:1924
Rcpp::attributes::SourceFileAttributes
Definition: attributes.cpp:416
Rcpp::Vector< STRSXP >::iterator
traits::r_vector_iterator< RTYPE, PreserveStorage >::type iterator
Definition: Vector.h:46
Rcpp::attributes::SourceFileAttributesParser::hasPackageInit
bool hasPackageInit() const
Definition: attributes.cpp:516
Rcpp::attributes::ExportsGenerators::writeFunctions
void writeFunctions(const SourceFileAttributes &attributes, bool verbose)
Definition: attributes.cpp:2522
Rcpp::attributes::FileInfo
Definition: attributes.cpp:53
Rcpp::attributes::ExportsGenerators::add
void add(ExportsGenerator *pGenerator)
Definition: attributes.cpp:2513
Rcpp::attributes::CppExportsIncludeGenerator::includeDir_
std::string includeDir_
Definition: attributes.cpp:725
Rcpp::attributes::Type::isConst_
bool isConst_
Definition: attributes.cpp:207
Rcpp::attributes::ExportsGenerator::exportValidationFunction
std::string exportValidationFunction()
Definition: attributes.cpp:628
Rcpp::attributes::kInitAttribute
const char *const kInitAttribute
Definition: attributes.cpp:161
Rcpp::attributes::CppExportsGenerator::nativeRoutines_
std::vector< Attribute > nativeRoutines_
Definition: attributes.cpp:701
Rcpp::attributes::FileInfo::exists
bool exists() const
Definition: attributes.cpp:78
Rcpp::attributes::Argument::name
const std::string & name() const
Definition: attributes.cpp:235
Rcpp::attributes::Type
Definition: attributes.cpp:173
Rcpp::is
bool is(SEXP x)
Definition: is.h:53
Rcpp::base_env
static Environment_Impl base_env()
Definition: Environment.h:346
Rcpp::attributes::Param::operator!=
bool operator!=(const Param &other) const
Definition: attributes.cpp:301
Rcpp::List
Vector< VECSXP > List
Definition: instantiation.h:37
Rcpp::attributes::Function::name_
std::string name_
Definition: attributes.cpp:285
Rcpp::attributes::CppPackageIncludeGenerator::includeDir_
std::string includeDir_
Definition: attributes.cpp:744
Rcpp::attributes::CppExportsGenerator::writeEnd
virtual void writeEnd(bool hasPackageInit)
Definition: attributes.cpp:1976
Rcpp::attributes::FileInfo::path_
std::string path_
Definition: attributes.cpp:109
Rcpp::attributes::Argument::defaultValue
const std::string & defaultValue() const
Definition: attributes.cpp:237
Rcpp::attributes::Attribute::isExportedFunction
bool isExportedFunction() const
Definition: attributes.cpp:352
Rcpp::attributes::Type::isConst
bool isConst() const
Definition: attributes.cpp:202
Rcpp::Argument
Definition: Named.h:27
Rcpp::attributes::ExportsGenerators::writeEnd
void writeEnd(bool hasPackageInit)
Definition: attributes.cpp:2529
Rcpp::attributes::SourceFileAttributesParser::parseType
Type parseType(const std::string &text)
Rcpp::attributes::ExportsGenerator::packageCpp_
std::string packageCpp_
Definition: attributes.cpp:669
Rcpp::attributes::Function::Function
Function()
Definition: attributes.cpp:248
Rcpp::attributes::SourceFileAttributesParser::lines_
CharacterVector lines_
Definition: attributes.cpp:556
Rcpp::remove
bool remove(const std::string &name)
Definition: Environment.h:240
Rcpp::attributes::trimWhitespace
void trimWhitespace(std::string *pStr)
Definition: attributes.cpp:2994
Rcpp::attributes::Param::name_
std::string name_
Definition: attributes.cpp:310
Rcpp::attributes::printArgument
void printArgument(std::ostream &os, const Argument &argument, bool printDefault=true)
Definition: attributes.cpp:1081
Rcpp::warning
void warning(const char *fmt, Args &&... args)
Definition: exceptions.h:46
Rcpp::wrap
SEXP wrap(const Date &date)
Definition: Date.h:38
Rcpp::file_io_error
Definition: exceptions.h:82
Rcpp::attributes::SourceFileAttributesParser::parseFunction
Function parseFunction(size_t lineNumber)
Rcpp::attributes::Attribute::paramNamed
Param paramNamed(const std::string &name) const
Definition: attributes.cpp:1059
Rcpp::attributes::SourceFileAttributesParser::rcppExportInvalidParameterWarning
void rcppExportInvalidParameterWarning(const std::string &param, size_t lineNumber)
Rcpp::attributes::RExportsGenerator::writeBegin
virtual void writeBegin()
Definition: attributes.cpp:756
Rcpp::attributes::kExportRng
const char *const kExportRng
Definition: attributes.cpp:159
Rcpp::attributes::ExportsGenerator::targetFile
const std::string & targetFile() const
Definition: attributes.cpp:595
Rcpp::exists
bool exists(const std::string &name) const
Definition: Environment.h:190
sourceCppContext
RcppExport SEXP sourceCppContext(SEXP sFile, SEXP sCode, SEXP sRebuild, SEXP sCacheDir, SEXP sPlatform)
Definition: attributes.cpp:3463
Rcpp::attributes::ExportsGenerator::writeFunctions
void writeFunctions(const SourceFileAttributes &attributes, bool verbose)
Definition: attributes.cpp:1850
Rcpp::attributes::showWarning
void showWarning(const std::string &msg)
Definition: attributes.cpp:3035
Rcpp::attributes::SourceFileAttributesParser::sourceFile_
std::string sourceFile_
Definition: attributes.cpp:555
Rcpp::attributes::CppExportsIncludeGenerator::getHeaderGuard
std::string getHeaderGuard() const
Definition: attributes.cpp:2358
Rcpp::attributes::FileInfo::toList
List toList() const
Definition: attributes.cpp:69
Rcpp::attributes::CommentState
Definition: attributes.cpp:449
Rcpp::match
IntegerVector match(const VectorBase< RTYPE, NA, T > &x, const VectorBase< RTYPE, RHS_NA, RHS_T > &table_)
Definition: match.h:28
Rcpp::attributes::SourceFileAttributesParser::parseParameters
std::vector< Param > parseParameters(const std::string &input)
Rcpp::attributes::kExportName
const char *const kExportName
Definition: attributes.cpp:158
Rcpp::LogicalVector
Vector< LGLSXP > LogicalVector
Definition: instantiation.h:29
Rcpp::attributes::kWhitespaceChars
const char *const kWhitespaceChars
Definition: attributes.cpp:2941
Rcpp::attributes::Type::full_name
std::string full_name() const
Definition: attributes.cpp:193
Rcpp::attributes::Argument
Definition: attributes.cpp:212
Rcpp::attributes::kParamValueTRUE
const char *const kParamValueTRUE
Definition: attributes.cpp:170
Rcpp::attributes::ExportsGenerators::Itr
std::vector< ExportsGenerator * >::iterator Itr
Definition: attributes.cpp:771
Rcpp::attributes::SourceFileAttributes::modules
virtual const std::vector< std::string > & modules() const =0
Rcpp::attributes::Attribute::operator!=
bool operator!=(const Attribute &other) const
Definition: attributes.cpp:335
Rcpp::attributes::kExportInvisible
const char *const kExportInvisible
Definition: attributes.cpp:160
Rcpp::attributes::kInterfaceCpp
const char *const kInterfaceCpp
Definition: attributes.cpp:166
Rcpp::RObject
RObject_Impl< PreserveStorage > RObject
Definition: RObject.h:56
Rcpp::attributes::CppExportsGenerator
Definition: attributes.cpp:675
Rcpp::attributes::ExportsGenerator::packageCpp
const std::string & packageCpp() const
Definition: attributes.cpp:597
Rcpp::attributes::CommentState::reset
void reset()
Definition: attributes.cpp:461
Rcpp::attributes::ExportsGenerator::existingCode_
std::string existingCode_
Definition: attributes.cpp:671
Rcpp::attributes::Function::type_
Type type_
Definition: attributes.cpp:284
Rcpp::attributes::RExportsGenerator::writeEnd
virtual void writeEnd(bool hasPackageInit)
Definition: attributes.cpp:2488
Rcpp::attributes::SourceFileAttributesParser::rcppExportWarning
void rcppExportWarning(const std::string &message, size_t lineNumber)
Rcpp::attributes::Argument::operator!=
bool operator!=(const Argument &other) const
Definition: attributes.cpp:230
Rcpp::attributes::kPluginsAttribute
const char *const kPluginsAttribute
Definition: attributes.cpp:163
Rcpp::attributes::CppExportsIncludeGenerator::writeBegin
virtual void writeBegin()
Definition: attributes.cpp:2157
Rcpp::attributes::FileInfo::operator!=
bool operator!=(const FileInfo &other) const
Definition: attributes.cpp:99
Rcpp::attributes::FileInfo::path
std::string path() const
Definition: attributes.cpp:77
Rcpp::attributes::ExportsGenerator::package_
std::string package_
Definition: attributes.cpp:668
Rcpp::attributes::FileInfo::FileInfo
FileInfo(const std::string &path)
Definition: attributes.cpp:2899
Rcpp::attributes::SourceFileAttributes::~SourceFileAttributes
virtual ~SourceFileAttributes()
Definition: attributes.cpp:418
Rcpp::find
SEXP find(const std::string &name) const
Definition: Environment.h:145
Rcpp::attributes::Param::operator==
bool operator==(const Param &other) const
Definition: attributes.cpp:296
Rcpp::attributes::Function::operator!=
bool operator!=(const Function &other) const
Definition: attributes.cpp:275
callEntries
static R_CallMethodDef callEntries[]
Definition: rcpp_init.cpp:31
Rcpp::attributes::CppPackageIncludeGenerator
Definition: attributes.cpp:729
Rcpp::attributes::FileInfo::lastModified_
double lastModified_
Definition: attributes.cpp:111
Rcpp::attributes::kParamValueFALSE
const char *const kParamValueFALSE
Definition: attributes.cpp:169
Rcpp::attributes::Attribute::name_
std::string name_
Definition: attributes.cpp:401
Rcpp::attributes::kInterfaceR
const char *const kInterfaceR
Definition: attributes.cpp:165
Rcpp::attributes::Type::isReference
bool isReference() const
Definition: attributes.cpp:203
Rcpp::attributes::ExportsGenerator::exportValidationFunctionRegisteredName
std::string exportValidationFunctionRegisteredName()
Definition: attributes.cpp:631
Rcpp::attributes::endsWith
bool endsWith(const std::string &str, const std::string &suffix)
Definition: attributes.cpp:3028
Rcpp::attributes::Argument::operator==
bool operator==(const Argument &other) const
Definition: attributes.cpp:224
Rcpp::attributes::FileInfo::operator==
bool operator==(const FileInfo &other) const
Definition: attributes.cpp:93
Rcpp::attributes::SourceFileAttributes::const_iterator
std::vector< Attribute >::const_iterator const_iterator
Definition: attributes.cpp:422
Rcpp::attributes::ExportsGenerators::generators_
std::vector< ExportsGenerator * > generators_
Definition: attributes.cpp:796
Rcpp::attributes::FileInfo::exists_
bool exists_
Definition: attributes.cpp:110
Rcpp::attributes::kParamValueFalse
const char *const kParamValueFalse
Definition: attributes.cpp:167
Rcpp::attributes::Type::name
const std::string & name() const
Definition: attributes.cpp:192
Rcpp::attributes::Param::value
const std::string & value() const
Definition: attributes.cpp:307
Rcpp::attributes::Function::name
const std::string & name() const
Definition: attributes.cpp:280
Rcpp::attributes::CppPackageIncludeGenerator::commit
virtual bool commit(const std::vector< std::string > &includes)
Definition: attributes.cpp:2389
Rcpp::diff
sugar::Diff< INTSXP, LHS_NA, LHS_T > diff(const VectorBase< INTSXP, LHS_NA, LHS_T > &lhs)
Definition: diff.h:124
Rcpp::attributes::isQuoted
bool isQuoted(const std::string &str)
Definition: attributes.cpp:3020
Rcpp::exception
Definition: exceptions.h:36
compileAttributes
RcppExport SEXP compileAttributes(SEXP sPackageDir, SEXP sPackageName, SEXP sDepends, SEXP sRegistration, SEXP sCppFiles, SEXP sCppFileBasenames, SEXP sIncludes, SEXP sVerbose, SEXP sPlatform)
Definition: attributes.cpp:3527
Rcpp::attributes::Function::signature
std::string signature() const
Definition: attributes.cpp:260
Rcpp::attributes::ExportsGenerator::ostr
std::ostream & ostr()
Definition: attributes.cpp:619
Rcpp::attributes::ExportsGenerator::commentPrefix_
std::string commentPrefix_
Definition: attributes.cpp:670
Rcpp::attributes::ExportsGenerator::packageCppPrefix
const std::string packageCppPrefix() const
Definition: attributes.cpp:598
Rcpp::attributes::ExportsGenerator::hasCppInterface
bool hasCppInterface() const
Definition: attributes.cpp:623
Rcpp::attributes::SourceFileAttributesParser::attributeWarning
void attributeWarning(const std::string &message, const std::string &attribute, size_t lineNumber)
Rcpp.h
Rcpp::attributes::isRoxygenCpp
bool isRoxygenCpp(const std::string &str)
Definition: attributes.cpp:3040
Rcpp::attributes::CommentState::inComment_
bool inComment_
Definition: attributes.cpp:463
Rcpp::attributes::ExportsGenerators
Definition: attributes.cpp:769
Rcpp::attributes::CppExportsGenerator::CppExportsGenerator
CppExportsGenerator(const std::string &packageDir, const std::string &package, const std::string &fileSep)
Definition: attributes.cpp:1914
Rcpp::Environment
Environment_Impl< PreserveStorage > Environment
Definition: Environment.h:401
Rcpp::attributes::CppExportsIncludeGenerator::getCCallable
std::string getCCallable(const std::string &function) const
Definition: attributes.cpp:2349
Rcpp::attributes::Attribute::exportedCppName
std::string exportedCppName() const
Definition: attributes.cpp:374
Rcpp::attributes::Attribute::function
const Function & function() const
Definition: attributes.cpp:350
Rcpp::attributes::SourceFileAttributes::roxygenChunks
virtual const std::vector< std::vector< std::string > > & roxygenChunks() const =0
Rcpp::attributes::SourceFileAttributes::hasInterface
virtual bool hasInterface(const std::string &name) const =0
Rcpp::attributes::CommentState::submitLine
void submitLine(const std::string &line)
Rcpp::as
T as(SEXP x)
Definition: as.h:151
Rcpp::attributes::CommentState::operator=
CommentState & operator=(const CommentState &)
Rcpp::attributes::CppExportsIncludeGenerator::commit
virtual bool commit(const std::vector< std::string > &includes)
Definition: attributes.cpp:2297
Rcpp::attributes::SourceFileAttributesParser::hasInterface
virtual bool hasInterface(const std::string &name) const
Definition: attributes.cpp:500
Rcpp::attributes::Attribute::Attribute
Attribute()
Definition: attributes.cpp:317
Rcpp::attributes::Function::arguments_
std::vector< Argument > arguments_
Definition: attributes.cpp:286