Parse the attributes from a source file
| 1175 | |
| 1176 | // Parse the attributes from a source file |
| 1177 | SourceFileAttributesParser::SourceFileAttributesParser( |
| 1178 | const std::string& sourceFile, |
| 1179 | const std::string& packageName, |
| 1180 | bool parseDependencies) |
| 1181 | : sourceFile_(sourceFile), hasPackageInit_(false) |
| 1182 | { |
| 1183 | |
| 1184 | // transform packageName to valid C++ symbol |
| 1185 | std::string packageNameCpp = packageName; |
| 1186 | std::replace(packageNameCpp.begin(), packageNameCpp.end(), '.', '_'); |
| 1187 | |
| 1188 | // First read the entire file into a std::stringstream so we can check |
| 1189 | // it for attributes (we don't want to do any of our more expensive |
| 1190 | // processing steps if there are no attributes to parse) |
| 1191 | std::stringstream buffer; |
| 1192 | readFile(sourceFile_, buffer); |
| 1193 | std::string contents = buffer.str(); |
| 1194 | |
| 1195 | // Check for attribute signature |
| 1196 | if (contents.find("[[Rcpp::") != std::string::npos || |
| 1197 | contents.find("RCPP_MODULE") != std::string::npos || |
| 1198 | contents.find("R_init_" + packageNameCpp) != std::string::npos) { |
| 1199 | |
| 1200 | // Now read into a list of strings (which we can pass to regexec) |
| 1201 | // First read into a std::deque (which will handle lots of append |
| 1202 | // operations efficiently) then copy into an R character vector |
| 1203 | std::deque<std::string> lines; |
| 1204 | readLines(buffer, &lines); |
| 1205 | lines_ = Rcpp::wrap(lines); |
| 1206 | |
| 1207 | // Scan for attributes |
| 1208 | CommentState commentState; |
| 1209 | Rcpp::List matches = regexMatches(lines_, |
| 1210 | "^\\s*//\\s*\\[\\[Rcpp::(\\w+)(\\(.*?\\))?\\]\\]\\s*$"); |
| 1211 | for (int i = 0; i<matches.size(); i++) { |
| 1212 | |
| 1213 | // track whether we are in a comment and bail if we are in one |
| 1214 | std::string line = lines[i]; |
| 1215 | commentState.submitLine(line); |
| 1216 | if (commentState.inComment()) |
| 1217 | continue; |
| 1218 | |
| 1219 | // attribute line |
| 1220 | const Rcpp::CharacterVector match = matches[i]; |
| 1221 | if (match.size() > 0) { |
| 1222 | |
| 1223 | // if the match size isn't 3 then regmatches has not behaved |
| 1224 | // as expected (it should return a vector of either 0 or 3 |
| 1225 | // elements). we don't ever expect this to occur but if it |
| 1226 | // does let's not crash |
| 1227 | if (match.size() != 3) |
| 1228 | continue; // #nocov |
| 1229 | |
| 1230 | // add the attribute |
| 1231 | Attribute attr = parseAttribute( |
| 1232 | Rcpp::as<std::vector<std::string> >(match), i); |
| 1233 | attributes_.push_back(attr); |
| 1234 | } |
nothing calls this directly
no test coverage detected