|
1 | 1 | #include "data.table.h" |
2 | 2 |
|
3 | 3 | static void substitute_call_arg_names(SEXP expr, SEXP env) { |
4 | | - R_len_t len = length(expr); |
5 | | - if (len && isLanguage(expr)) { // isLanguage is R's is.call |
6 | | - SEXP arg_names = getAttrib(expr, R_NamesSymbol); |
7 | | - if (!isNull(arg_names)) { |
8 | | - SEXP env_names = getAttrib(env, R_NamesSymbol); |
9 | | - int *imatches = INTEGER(PROTECT(chmatch(arg_names, env_names, 0))); |
10 | | - const SEXP *env_sub = SEXPPTR_RO(env); |
11 | | - SEXP tmp = expr; |
12 | | - for (int i=0; i<length(arg_names); i++, tmp=CDR(tmp)) { // substitute call arg names |
13 | | - if (imatches[i]) { |
14 | | - SEXP sym = env_sub[imatches[i]-1]; |
15 | | - if (!isSymbol(sym)) |
16 | | - error(_("Attempting to substitute '%s' element with object of type '%s' but it has to be 'symbol' type when substituting name of the call argument, functions 'as.name' and 'I' can be used to work out proper substitution, see ?substitute2 examples."), CHAR(STRING_ELT(arg_names, i)), type2char(TYPEOF(sym))); |
17 | | - SET_TAG(tmp, sym); |
18 | | - } |
19 | | - } |
20 | | - UNPROTECT(1); // chmatch |
21 | | - } |
22 | | - for (SEXP tmp=expr; tmp!=R_NilValue; tmp=CDR(tmp)) { // recursive call to substitute in nested expressions |
23 | | - substitute_call_arg_names(CADR(tmp), env); |
| 4 | + if (!length(expr) || !isLanguage(expr)) |
| 5 | + return; // isLanguage is R's is.call |
| 6 | + SEXP arg_names = getAttrib(expr, R_NamesSymbol); |
| 7 | + if (!isNull(arg_names)) { |
| 8 | + SEXP env_names = getAttrib(env, R_NamesSymbol); |
| 9 | + int *imatches = INTEGER(PROTECT(chmatch(arg_names, env_names, 0))); |
| 10 | + const SEXP *env_sub = SEXPPTR_RO(env); |
| 11 | + SEXP tmp = expr; |
| 12 | + for (int i=0; i<length(arg_names); i++, tmp=CDR(tmp)) { // substitute call arg names |
| 13 | + if (!imatches[i]) |
| 14 | + continue; |
| 15 | + SEXP sym = env_sub[imatches[i]-1]; |
| 16 | + if (!isSymbol(sym)) |
| 17 | + error(_("Attempting to substitute '%s' element with object of type '%s' but it has to be 'symbol' type when substituting name of the call argument, functions 'as.name' and 'I' can be used to work out proper substitution, see ?substitute2 examples."), CHAR(STRING_ELT(arg_names, i)), type2char(TYPEOF(sym))); |
| 18 | + SET_TAG(tmp, sym); |
24 | 19 | } |
| 20 | + UNPROTECT(1); // chmatch |
| 21 | + } |
| 22 | + for (SEXP tmp=expr; tmp!=R_NilValue; tmp=CDR(tmp)) { // recursive call to substitute in nested expressions |
| 23 | + substitute_call_arg_names(CADR(tmp), env); |
25 | 24 | } |
26 | 25 | } |
| 26 | + |
27 | 27 | SEXP substitute_call_arg_namesR(SEXP expr, SEXP env) { |
28 | 28 | SEXP ans = PROTECT(MAYBE_REFERENCED(expr) ? duplicate(expr) : expr); |
29 | 29 | substitute_call_arg_names(ans, env); // updates in-place |
|
0 commit comments