/src/r-source/src/main/envir.c
Line | Count | Source |
1 | | /* |
2 | | * R : A Computer Language for Statistical Data Analysis |
3 | | * Copyright (C) 1999--2026 The R Core Team. |
4 | | * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, a copy is available at |
18 | | * https://www.R-project.org/Licenses/ |
19 | | * |
20 | | * |
21 | | * |
22 | | * Environments: |
23 | | * |
24 | | * All the action of associating values with symbols happens |
25 | | * in this code. An environment is (essentially) a list of |
26 | | * environment "frames" of the form |
27 | | * |
28 | | * FRAME(envir) = environment frame |
29 | | * ENCLOS(envir) = parent environment |
30 | | * HASHTAB(envir) = (optional) hash table |
31 | | * |
32 | | * Each frame is a (tagged) list with |
33 | | * |
34 | | * TAG(item) = symbol |
35 | | * CAR(item) = value bound to symbol in this frame |
36 | | * CDR(item) = next value on the list |
37 | | * |
38 | | * When the value of a symbol is required, the environment is |
39 | | * traversed frame-by-frame until a value is found. |
40 | | * |
41 | | * If a value is not found during the traversal, the symbol's |
42 | | * "value" slot is inspected for a value. This "top-level" |
43 | | * environment is where system functions and variables reside. |
44 | | * |
45 | | * Environments with the NO_SPECIAL_SYMBOLS flag set are known to not |
46 | | * contain any special symbols, as indicated by the IS_SPECIAL_SYMBOL |
47 | | * macro. Lookup for such a symbol can then bypass this environment |
48 | | * without searching it. |
49 | | */ |
50 | | |
51 | | /* R 1.8.0: namespaces are no longer experimental, so the following |
52 | | * are no longer 'experimental options', but rather three sections |
53 | | * describing the API: |
54 | | * |
55 | | * NAMESPACES: |
56 | | * R_BaseNamespace holds an environment that has R_GlobalEnv as |
57 | | * its parent. This environment does not actually contain any |
58 | | * bindings of its own. Instead, it redirects all fetches and |
59 | | * assignments to the SYMVALUE fields of the base (R_BaseEnv) |
60 | | * environment. If evaluation occurs in R_BaseNamespace, then |
61 | | * base is searched before R_GlobalEnv. |
62 | | * |
63 | | * ENVIRONMENT_LOCKING: Locking an environment prevents new bindings |
64 | | * from being created and existing bindings from being removed. |
65 | | * |
66 | | * FANCY_BINDINGS: We have binding locking and "active bindings". |
67 | | * When a binding is locked, its value cannot be changed. It may |
68 | | * still be removed from the environment if the environment is not |
69 | | * locked. |
70 | | * |
71 | | * Active bindings contain a function in their value cell. |
72 | | * Getting the value of an active binding calls this function with |
73 | | * no arguments and returns the result. Assigning to an active |
74 | | * binding calls this function with one argument, the new value. |
75 | | * Active bindings may be useful for mapping external variables, |
76 | | * such as C variables or data base entries, to R variables. They |
77 | | * may also be useful for making some globals thread-safe. |
78 | | * |
79 | | * Bindings are marked as locked or active using bits 14 and 15 in |
80 | | * their gp fields. Since the save/load code writes out this |
81 | | * field it means the value will be preserved across save/load. |
82 | | * But older versions of R will interpret the entire gp field as |
83 | | * the MISSING field, which may cause confusion. If we keep this |
84 | | * code, then we will need to make sure that there are no |
85 | | * locked/active bindings in workspaces written for older versions |
86 | | * of R to read. |
87 | | * |
88 | | * LT */ |
89 | | |
90 | | #ifdef HAVE_CONFIG_H |
91 | | # include <config.h> |
92 | | #endif |
93 | | |
94 | | #define R_USE_SIGNALS 1 |
95 | | #include <Defn.h> |
96 | | #include <Internal.h> |
97 | | #include <R_ext/ObjectTable.h> |
98 | | |
99 | | #define FAST_BASE_CACHE_LOOKUP /* Define to enable fast lookups of symbols */ |
100 | | /* in global cache from base environment */ |
101 | | |
102 | 63.2M | #define IS_USER_DATABASE(rho) (OBJECT((rho)) && inherits((rho), "UserDefinedDatabase")) |
103 | | |
104 | | /* various definitions of macros/functions in Defn.h */ |
105 | | |
106 | 9.70M | #define FRAME_LOCK_MASK (1<<14) |
107 | 9.70M | #define FRAME_IS_LOCKED(e) (ENVFLAGS(e) & FRAME_LOCK_MASK) |
108 | 330 | #define LOCK_FRAME(e) SET_ENVFLAGS(e, ENVFLAGS(e) | FRAME_LOCK_MASK) |
109 | | /*#define UNLOCK_FRAME(e) SET_ENVFLAGS(e, ENVFLAGS(e) & (~ FRAME_LOCK_MASK))*/ |
110 | | |
111 | | /* use the same bits (15 and 14) in symbols and bindings */ |
112 | | static SEXP getActiveValue(SEXP); |
113 | | static R_INLINE SEXP BINDING_VALUE(SEXP b) |
114 | 6.69M | { |
115 | 6.69M | if (BNDCELL_TAG(b)) { |
116 | 72 | R_expand_binding_value(b); |
117 | 72 | return CAR0(b); |
118 | 72 | } |
119 | 6.69M | if (IS_ACTIVE_BINDING(b)) return getActiveValue(CAR(b)); |
120 | 6.69M | else return CAR(b); |
121 | 6.69M | } |
122 | | |
123 | 12.8M | #define SYMBOL_BINDING_VALUE(s) ((IS_ACTIVE_BINDING(s) ? getActiveValue(SYMVALUE(s)) : SYMVALUE(s))) |
124 | 12 | #define SYMBOL_HAS_BINDING(s) (IS_ACTIVE_BINDING(s) || (SYMVALUE(s) != R_UnboundValue)) |
125 | | |
126 | 644k | #define SET_BINDING_VALUE(b,val) do { \ |
127 | 644k | SEXP __b__ = (b); \ |
128 | 644k | SEXP __val__ = (val); \ |
129 | 644k | if (BINDING_IS_LOCKED(__b__)) \ |
130 | 644k | error(_("cannot change value of locked binding for '%s'"), \ |
131 | 0 | CHAR(PRINTNAME(TAG(__b__)))); \ |
132 | 644k | if (IS_ACTIVE_BINDING(__b__)) { \ |
133 | 0 | PROTECT(__val__); \ |
134 | 0 | setActiveValue(CAR(__b__), __val__); \ |
135 | 0 | UNPROTECT(1); \ |
136 | 0 | } else \ |
137 | 644k | SET_BNDCELL(__b__, __val__); \ |
138 | 644k | } while (0) |
139 | | |
140 | 14.6k | #define SET_SYMBOL_BINDING_VALUE(sym, val) do { \ |
141 | 14.6k | SEXP __sym__ = (sym); \ |
142 | 14.6k | SEXP __val__ = (val); \ |
143 | 14.6k | if (BINDING_IS_LOCKED(__sym__)) \ |
144 | 14.6k | error(_("cannot change value of locked binding for '%s'"), \ |
145 | 0 | CHAR(PRINTNAME(__sym__))); \ |
146 | 14.6k | if (IS_ACTIVE_BINDING(__sym__)) { \ |
147 | 36 | PROTECT(__val__); \ |
148 | 36 | setActiveValue(SYMVALUE(__sym__), __val__); \ |
149 | 36 | UNPROTECT(1); \ |
150 | 36 | } else \ |
151 | 14.6k | SET_SYMVALUE(__sym__, __val__); \ |
152 | 14.6k | } while (0) |
153 | | |
154 | | static void setActiveValue(SEXP fun, SEXP val) |
155 | 36 | { |
156 | 36 | SEXP qfun = lang3(R_DoubleColonSymbol, R_BaseSymbol, R_QuoteSymbol); |
157 | 36 | SEXP arg = lang2(qfun, val); |
158 | 36 | SEXP expr = lang2(fun, arg); |
159 | 36 | PROTECT(expr); |
160 | 36 | eval(expr, R_BaseEnv); |
161 | 36 | UNPROTECT(1); |
162 | 36 | } |
163 | | |
164 | | static SEXP getActiveValue(SEXP fun) |
165 | 72 | { |
166 | 72 | SEXP expr = LCONS(fun, R_NilValue); |
167 | 72 | PROTECT(expr); |
168 | 72 | expr = eval(expr, R_GlobalEnv); |
169 | 72 | UNPROTECT(1); |
170 | | /* mark unmutable to prevent mutations in complex assignments */ |
171 | 72 | MARK_NOT_MUTABLE(expr); |
172 | 72 | return expr; |
173 | 72 | } |
174 | | |
175 | | /* Macro version of isNull for only the test against R_NilValue */ |
176 | 5.83M | #define ISNULL(x) ((x) == R_NilValue) |
177 | | |
178 | | /* Function to determine whethr an environment contains special symbols */ |
179 | | attribute_hidden Rboolean R_envHasNoSpecialSymbols (SEXP env) |
180 | 5.29M | { |
181 | 5.29M | SEXP frame; |
182 | | |
183 | 5.29M | if (HASHTAB(env) != R_NilValue) |
184 | 0 | return FALSE; |
185 | | |
186 | 18.0M | for (frame = FRAME(env); frame != R_NilValue; frame = CDR(frame)) |
187 | 12.7M | if (IS_SPECIAL_SYMBOL(TAG(frame))) |
188 | 0 | return FALSE; |
189 | | |
190 | 5.29M | return TRUE; |
191 | 5.29M | } |
192 | | |
193 | | /*---------------------------------------------------------------------- |
194 | | |
195 | | Hash Tables |
196 | | |
197 | | We use a basic separate chaining algorithm. A hash table consists |
198 | | of SEXP (vector) which contains a number of SEXPs (lists). |
199 | | |
200 | | The only non-static function is R_NewHashedEnv, which allows code to |
201 | | request a hashed environment. All others are static to allow |
202 | | internal changes of implementation without affecting client code. |
203 | | */ |
204 | | |
205 | 5.17M | #define HASHSIZE(x) ((int) STDVEC_LENGTH(x)) |
206 | 271k | #define HASHPRI(x) ((int) STDVEC_TRUELENGTH(x)) |
207 | 3.54k | #define HASHTABLEGROWTHRATE 1.2 |
208 | 216 | #define HASHMINSIZE 29 |
209 | 573k | #define SET_HASHPRI(x,v) SET_TRUELENGTH(x,v) |
210 | 4.10M | #define HASHCHAIN(table, i) ((SEXP *) STDVEC_DATAPTR(table))[i] |
211 | | |
212 | 335 | #define IS_HASHED(x) (HASHTAB(x) != R_NilValue) |
213 | | |
214 | | /*---------------------------------------------------------------------- |
215 | | |
216 | | String Hashing |
217 | | |
218 | | This is taken from the second edition of the "Dragon Book" by |
219 | | Aho, Ullman and Sethi. |
220 | | |
221 | | */ |
222 | | |
223 | | /* was extern: used in this file and names.c (for the symbol table). |
224 | | |
225 | | This hash function seems to work well enough for symbol tables, |
226 | | and hash tables get saved as part of environments so changing it |
227 | | is a major decision. |
228 | | */ |
229 | | attribute_hidden int R_Newhashpjw(const char *s) |
230 | 5.55M | { |
231 | 5.55M | char *p; |
232 | 5.55M | unsigned h = 0, g; |
233 | 57.0M | for (p = (char *) s; *p; p++) { |
234 | 51.5M | h = (h << 4) + (*p); |
235 | 51.5M | if ((g = h & 0xf0000000) != 0) { |
236 | 23.0M | h = h ^ (g >> 24); |
237 | 23.0M | h = h ^ g; |
238 | 23.0M | } |
239 | 51.5M | } |
240 | 5.55M | return h; |
241 | 5.55M | } |
242 | | |
243 | | /*---------------------------------------------------------------------- |
244 | | |
245 | | R_HashSet |
246 | | |
247 | | Hashtable set function. Sets 'symbol' in 'table' to be 'value'. |
248 | | 'hashcode' must be provided by user. Allocates some memory for list |
249 | | entries. |
250 | | |
251 | | */ |
252 | | |
253 | | static void R_HashSet(int hashcode, SEXP symbol, SEXP table, SEXP value, |
254 | | Rboolean frame_locked) |
255 | 119k | { |
256 | 119k | SEXP chain; |
257 | | |
258 | | /* Grab the chain from the hashtable */ |
259 | 119k | chain = VECTOR_ELT(table, hashcode); |
260 | | |
261 | | /* Search for the value in the chain */ |
262 | 239k | for (; !ISNULL(chain); chain = CDR(chain)) |
263 | 120k | if (TAG(chain) == symbol) { |
264 | 426 | SET_BINDING_VALUE(chain, value); |
265 | 426 | SET_MISSING(chain, 0); /* Over-ride for new value */ |
266 | 426 | return; |
267 | 426 | } |
268 | 119k | if (frame_locked) |
269 | 0 | error(_("cannot add bindings to a locked environment")); |
270 | 119k | if (ISNULL(chain)) |
271 | 119k | SET_HASHPRI(table, HASHPRI(table) + 1); |
272 | | /* Add the value into the chain */ |
273 | 119k | SET_VECTOR_ELT(table, hashcode, CONS(value, VECTOR_ELT(table, hashcode))); |
274 | 119k | SET_TAG(VECTOR_ELT(table, hashcode), symbol); |
275 | 119k | return; |
276 | 119k | } |
277 | | |
278 | | |
279 | | |
280 | | /*---------------------------------------------------------------------- |
281 | | |
282 | | R_HashGet |
283 | | |
284 | | Hashtable get function. Returns 'value' from 'table' indexed by |
285 | | 'symbol'. 'hashcode' must be provided by user. Returns |
286 | | 'R_UnboundValue' if value is not present. |
287 | | |
288 | | */ |
289 | | |
290 | | static SEXP R_HashGet(int hashcode, SEXP symbol, SEXP table) |
291 | 4.10M | { |
292 | 4.10M | SEXP chain; |
293 | | |
294 | | /* Grab the chain from the hashtable */ |
295 | 4.10M | chain = HASHCHAIN(table, hashcode); |
296 | | /* Retrieve the value from the chain */ |
297 | 6.10M | for (; chain != R_NilValue ; chain = CDR(chain)) |
298 | 2.54M | if (TAG(chain) == symbol) return BINDING_VALUE(chain); |
299 | | /* If not found */ |
300 | 3.55M | return R_UnboundValue; |
301 | 4.10M | } |
302 | | |
303 | | static Rboolean R_HashExists(int hashcode, SEXP symbol, SEXP table) |
304 | 13.4k | { |
305 | 13.4k | SEXP chain; |
306 | | |
307 | | /* Grab the chain from the hashtable */ |
308 | 13.4k | chain = VECTOR_ELT(table, hashcode); |
309 | | /* Find the binding in the chain */ |
310 | 23.5k | for (; chain != R_NilValue ; chain = CDR(chain)) |
311 | 14.8k | if (TAG(chain) == symbol) return TRUE; |
312 | | /* If not found */ |
313 | 8.65k | return FALSE; |
314 | 13.4k | } |
315 | | |
316 | | |
317 | | |
318 | | /*---------------------------------------------------------------------- |
319 | | |
320 | | R_HashGetLoc |
321 | | |
322 | | Hashtable get location function. Just like R_HashGet, but returns |
323 | | location of variable, rather than its value. Returns R_NilValue |
324 | | if not found. |
325 | | |
326 | | */ |
327 | | |
328 | | static SEXP R_HashGetLoc(int hashcode, SEXP symbol, SEXP table) |
329 | 171k | { |
330 | 171k | SEXP chain; |
331 | | |
332 | | /* Grab the chain from the hashtable */ |
333 | 171k | chain = VECTOR_ELT(table, hashcode); |
334 | | /* Retrieve the value from the chain */ |
335 | 233k | for (; !ISNULL(chain); chain = CDR(chain)) |
336 | 200k | if (TAG(chain) == symbol) return chain; |
337 | | /* If not found */ |
338 | 32.9k | return R_NilValue; |
339 | 171k | } |
340 | | |
341 | | |
342 | | |
343 | | /*---------------------------------------------------------------------- |
344 | | |
345 | | R_NewHashTable |
346 | | |
347 | | Hash table initialisation function. Creates a table of size 'size' |
348 | | that increases in size by 'growth_rate' after a threshold is met. |
349 | | |
350 | | */ |
351 | | |
352 | | static SEXP R_NewHashTable(int size) |
353 | 8.08k | { |
354 | 8.08k | SEXP table; |
355 | | |
356 | 8.08k | if (size <= 0) size = HASHMINSIZE; |
357 | | |
358 | | /* Allocate hash table in the form of a vector */ |
359 | 8.08k | PROTECT(table = allocVector(VECSXP, size)); |
360 | 8.08k | SET_HASHPRI(table, 0); |
361 | 8.08k | UNPROTECT(1); |
362 | 8.08k | return(table); |
363 | 8.08k | } |
364 | | |
365 | | /*---------------------------------------------------------------------- |
366 | | |
367 | | R_NewHashedEnv |
368 | | |
369 | | Returns a new environment with a hash table initialized with default |
370 | | size. The only non-static hash table function. |
371 | | */ |
372 | | |
373 | | SEXP R_NewHashedEnv(SEXP enclos, int size) |
374 | 4.44k | { |
375 | 4.44k | SEXP s; |
376 | | |
377 | 4.44k | PROTECT(enclos); |
378 | 4.44k | PROTECT(s = NewEnvironment(R_NilValue, R_NilValue, enclos)); |
379 | 4.44k | SET_HASHTAB(s, R_NewHashTable(size)); |
380 | 4.44k | UNPROTECT(2); |
381 | 4.44k | return s; |
382 | 4.44k | } |
383 | | |
384 | | |
385 | | /*---------------------------------------------------------------------- |
386 | | |
387 | | R_HashDelete |
388 | | |
389 | | Hash table delete function. Symbols are completely removed from the table; |
390 | | there is no way to mark a symbol as not present without actually removing |
391 | | it. |
392 | | */ |
393 | | |
394 | | static SEXP RemoveFromList(SEXP thing, SEXP list, int *found); |
395 | | |
396 | | static void R_HashDelete(int hashcode, SEXP symbol, SEXP env, int *found) |
397 | 12 | { |
398 | 12 | int idx; |
399 | 12 | SEXP list, hashtab; |
400 | | |
401 | 12 | hashtab = HASHTAB(env); |
402 | 12 | idx = hashcode % HASHSIZE(hashtab); |
403 | 12 | list = RemoveFromList(symbol, VECTOR_ELT(hashtab, idx), found); |
404 | 12 | if (*found) { |
405 | 12 | if (env == R_GlobalEnv) |
406 | 12 | R_DirtyImage = 1; |
407 | 12 | if (list == R_NilValue) |
408 | 12 | SET_HASHPRI(hashtab, HASHPRI(hashtab) - 1); |
409 | 12 | SET_VECTOR_ELT(hashtab, idx, list); |
410 | 12 | } |
411 | 12 | } |
412 | | |
413 | | |
414 | | |
415 | | |
416 | | /*---------------------------------------------------------------------- |
417 | | |
418 | | R_HashResize |
419 | | |
420 | | Hash table resizing function Increase the size of the hash table by |
421 | | the growth_rate of the table. The vector is reallocated, however |
422 | | the lists with in the hash table have their pointers shuffled around |
423 | | so that they are not reallocated. |
424 | | |
425 | | */ |
426 | | |
427 | | static SEXP R_HashResize(SEXP table) |
428 | 3.54k | { |
429 | | /* Do some checking */ |
430 | 3.54k | if (TYPEOF(table) != VECSXP) |
431 | 0 | error("first argument ('table') not of type VECSXP, from R_HashResize"); |
432 | | |
433 | | /* This may have to change. The growth rate should |
434 | | be independent of the size (not implemented yet) */ |
435 | | /* hash_grow = HASHSIZE(table); */ |
436 | | |
437 | | /* Allocate the new hash table */ |
438 | 3.54k | SEXP new_table = R_NewHashTable(1 + (int)(HASHSIZE(table) * HASHTABLEGROWTHRATE)); |
439 | 406k | for (int counter = 0; counter < length(table); counter++) { |
440 | 403k | SEXP chain = VECTOR_ELT(table, counter); |
441 | 892k | while (!ISNULL(chain)) { |
442 | 489k | int new_hashcode = R_Newhashpjw(CHAR(PRINTNAME(TAG(chain)))) % |
443 | 489k | HASHSIZE(new_table); |
444 | 489k | SEXP new_chain = VECTOR_ELT(new_table, new_hashcode); |
445 | | /* If using a primary slot then increase HASHPRI */ |
446 | 489k | if (ISNULL(new_chain)) |
447 | 307k | SET_HASHPRI(new_table, HASHPRI(new_table) + 1); |
448 | 489k | SEXP tmp_chain = chain; |
449 | 489k | chain = CDR(chain); |
450 | 489k | SETCDR(tmp_chain, new_chain); |
451 | 489k | SET_VECTOR_ELT(new_table, new_hashcode, tmp_chain); |
452 | | #ifdef MIKE_DEBUG |
453 | | fprintf(stdout, "HASHSIZE = %d\nHASHPRI = %d\ncounter = %d\nHASHCODE = %d\n", |
454 | | HASHSIZE(table), HASHPRI(table), counter, new_hashcode); |
455 | | #endif |
456 | 489k | } |
457 | 403k | } |
458 | | /* Some debugging statements */ |
459 | | #ifdef MIKE_DEBUG |
460 | | fprintf(stdout, "Resized O.K.\n"); |
461 | | fprintf(stdout, "Old size: %d, New size: %d\n", |
462 | | HASHSIZE(table), HASHSIZE(new_table)); |
463 | | fprintf(stdout, "Old pri: %d, New pri: %d\n", |
464 | | HASHPRI(table), HASHPRI(new_table)); |
465 | | #endif |
466 | 3.54k | return new_table; |
467 | 3.54k | } /* end R_HashResize */ |
468 | | |
469 | | |
470 | | |
471 | | /*---------------------------------------------------------------------- |
472 | | |
473 | | R_HashSizeCheck |
474 | | |
475 | | Hash table size rechecking function. Compares the load factor |
476 | | (size/# of primary slots used) to a particular threshold value. |
477 | | Returns true if the table needs to be resized. |
478 | | |
479 | | */ |
480 | | |
481 | | static int R_HashSizeCheck(SEXP table) |
482 | 271k | { |
483 | 271k | int resize; |
484 | 271k | double thresh_val; |
485 | | |
486 | | /* Do some checking */ |
487 | 271k | if (TYPEOF(table) != VECSXP) |
488 | 0 | error("first argument ('table') not of type VECSXP, R_HashSizeCheck"); |
489 | 271k | resize = 0; thresh_val = 0.85; |
490 | 271k | if ((double)HASHPRI(table) > (double)HASHSIZE(table) * thresh_val) |
491 | 3.54k | resize = 1; |
492 | 271k | return resize; |
493 | 271k | } |
494 | | |
495 | | |
496 | | |
497 | | /*---------------------------------------------------------------------- |
498 | | |
499 | | R_HashFrame |
500 | | |
501 | | Hashing for environment frames. This function ensures that the |
502 | | first frame in the given environment has been hashed. Ultimately |
503 | | all enironments should be created in hashed form. At that point |
504 | | this function will be redundant. |
505 | | |
506 | | */ |
507 | | |
508 | | static SEXP R_HashFrame(SEXP rho) |
509 | 84 | { |
510 | 84 | int hashcode; |
511 | 84 | SEXP frame, chain, tmp_chain, table; |
512 | | |
513 | | /* Do some checking */ |
514 | 84 | if (TYPEOF(rho) != ENVSXP) |
515 | 0 | error("first argument ('table') not of type ENVSXP, from R_HashVector2Hash"); |
516 | 84 | table = HASHTAB(rho); |
517 | 84 | frame = FRAME(rho); |
518 | 84 | while (!ISNULL(frame)) { |
519 | 0 | if( !HASHASH(PRINTNAME(TAG(frame))) ) { |
520 | 0 | SET_HASHVALUE(PRINTNAME(TAG(frame)), |
521 | 0 | R_Newhashpjw(CHAR(PRINTNAME(TAG(frame))))); |
522 | 0 | SET_HASHASH(PRINTNAME(TAG(frame)), 1); |
523 | 0 | } |
524 | 0 | hashcode = HASHVALUE(PRINTNAME(TAG(frame))) % HASHSIZE(table); |
525 | 0 | chain = VECTOR_ELT(table, hashcode); |
526 | | /* If using a primary slot then increase HASHPRI */ |
527 | 0 | if (ISNULL(chain)) SET_HASHPRI(table, HASHPRI(table) + 1); |
528 | 0 | tmp_chain = frame; |
529 | 0 | frame = CDR(frame); |
530 | 0 | SETCDR(tmp_chain, chain); |
531 | 0 | SET_VECTOR_ELT(table, hashcode, tmp_chain); |
532 | 0 | } |
533 | 84 | SET_FRAME(rho, R_NilValue); |
534 | 84 | return rho; |
535 | 84 | } |
536 | | |
537 | | |
538 | | /* --------------------------------------------------------------------- |
539 | | |
540 | | R_HashProfile |
541 | | |
542 | | Profiling tool for analyzing hash table performance. Returns a |
543 | | three element list with components: |
544 | | |
545 | | size: the total size of the hash table |
546 | | |
547 | | nchains: the number of non-null chains in the table (as reported by |
548 | | HASHPRI()) |
549 | | |
550 | | counts: an integer vector the same length as size giving the length of |
551 | | each chain (or zero if no chain is present). This allows |
552 | | for assessing collisions in the hash table. |
553 | | */ |
554 | | |
555 | | static SEXP R_HashProfile(SEXP table) |
556 | 0 | { |
557 | 0 | SEXP chain, ans, chain_counts, nms; |
558 | 0 | int i, count; |
559 | |
|
560 | 0 | PROTECT(ans = allocVector(VECSXP, 3)); |
561 | 0 | PROTECT(nms = allocVector(STRSXP, 3)); |
562 | 0 | SET_STRING_ELT(nms, 0, mkChar("size")); /* size of hashtable */ |
563 | 0 | SET_STRING_ELT(nms, 1, mkChar("nchains")); /* number of non-null chains */ |
564 | 0 | SET_STRING_ELT(nms, 2, mkChar("counts")); /* length of each chain */ |
565 | 0 | setAttrib(ans, R_NamesSymbol, nms); |
566 | 0 | UNPROTECT(1); |
567 | |
|
568 | 0 | SET_VECTOR_ELT(ans, 0, ScalarInteger(length(table))); |
569 | 0 | SET_VECTOR_ELT(ans, 1, ScalarInteger(HASHPRI(table))); |
570 | |
|
571 | 0 | PROTECT(chain_counts = allocVector(INTSXP, length(table))); |
572 | 0 | for (i = 0; i < length(table); i++) { |
573 | 0 | chain = VECTOR_ELT(table, i); |
574 | 0 | count = 0; |
575 | 0 | for (; chain != R_NilValue ; chain = CDR(chain)) { |
576 | 0 | count++; |
577 | 0 | } |
578 | 0 | INTEGER(chain_counts)[i] = count; |
579 | 0 | } |
580 | |
|
581 | 0 | SET_VECTOR_ELT(ans, 2, chain_counts); |
582 | |
|
583 | 0 | UNPROTECT(2); |
584 | 0 | return ans; |
585 | 0 | } |
586 | | |
587 | | |
588 | | |
589 | | /*---------------------------------------------------------------------- |
590 | | |
591 | | Environments |
592 | | |
593 | | The following code implements variable searching for environments. |
594 | | |
595 | | */ |
596 | | |
597 | | |
598 | | /*---------------------------------------------------------------------- |
599 | | |
600 | | InitGlobalEnv |
601 | | |
602 | | Create the initial global environment. The global environment is |
603 | | no longer a linked list of environment frames. Instead it is a |
604 | | vector of environments which is searched from beginning to end. |
605 | | |
606 | | Note that only the first frame of each of these environments is |
607 | | searched. This is intended to make it possible to implement |
608 | | namespaces at some (indeterminate) point in the future. |
609 | | |
610 | | We hash the initial environment. 100 is a magic number discovered |
611 | | by Ross. Change it if you feel inclined. |
612 | | |
613 | | */ |
614 | | |
615 | | #define USE_GLOBAL_CACHE |
616 | | #ifdef USE_GLOBAL_CACHE /* NB leave in place: see below */ |
617 | | /* Global variable caching. A cache is maintained in a hash table, |
618 | | R_GlobalCache. The entry values are either R_UnboundValue (a |
619 | | flushed cache entry), the binding LISTSXP cell from the environment |
620 | | containing the binding found in a search from R_GlobalEnv, or a |
621 | | symbol if the globally visible binding lives in the base package. |
622 | | The cache for a variable is flushed if a new binding for it is |
623 | | created in a global frame or if the variable is removed from any |
624 | | global frame. |
625 | | |
626 | | Symbols in the global cache with values from the base environment |
627 | | are flagged with BASE_SYM_CACHED, so that their value can be |
628 | | returned immediately without needing to look in the hash table. |
629 | | They must still have entries in the hash table, however, so that |
630 | | they can be flushed as needed. |
631 | | |
632 | | To make sure the cache is valid, all binding creations and removals |
633 | | from global frames must go through the interface functions in this |
634 | | file. |
635 | | |
636 | | Initially only the R_GlobalEnv frame is a global frame. Additional |
637 | | global frames can only be created by attach. All other frames are |
638 | | considered local. Whether a frame is local or not is recorded in |
639 | | the highest order bit of the ENVFLAGS field (the gp field of |
640 | | sxpinfo). |
641 | | |
642 | | It is possible that the benefit of caching may be significantly |
643 | | reduced if we introduce namespace management. Since maintaining |
644 | | cache integrity is a bit tricky and since it might complicate |
645 | | threading a bit (I'm not sure it will but it needs to be thought |
646 | | through if nothing else) it might make sense to remove caching at |
647 | | that time. To make that easier, the ifdef's should probably be |
648 | | left in place. |
649 | | |
650 | | L. T. */ |
651 | | |
652 | 10.2M | #define GLOBAL_FRAME_MASK (1<<15) |
653 | 10.2M | #define IS_GLOBAL_FRAME(e) (ENVFLAGS(e) & GLOBAL_FRAME_MASK) |
654 | | #define MARK_AS_GLOBAL_FRAME(e) \ |
655 | 96 | SET_ENVFLAGS(e, ENVFLAGS(e) | GLOBAL_FRAME_MASK) |
656 | | #define MARK_AS_LOCAL_FRAME(e) \ |
657 | 0 | SET_ENVFLAGS(e, ENVFLAGS(e) & (~ GLOBAL_FRAME_MASK)) |
658 | | |
659 | 12 | #define INITIAL_CACHE_SIZE 1000 |
660 | | |
661 | | static SEXP R_GlobalCache, R_GlobalCachePreserve; |
662 | | #endif |
663 | | static SEXP R_BaseNamespaceName; |
664 | | static SEXP R_NamespaceSymbol; |
665 | | |
666 | | attribute_hidden void InitBaseEnv(void) |
667 | 12 | { |
668 | 12 | R_EmptyEnv = NewEnvironment(R_NilValue, R_NilValue, R_NilValue); |
669 | 12 | R_BaseEnv = NewEnvironment(R_NilValue, R_NilValue, R_EmptyEnv); |
670 | 12 | } |
671 | | |
672 | | attribute_hidden void InitGlobalEnv(void) |
673 | 12 | { |
674 | 12 | R_NamespaceSymbol = install(".__NAMESPACE__."); |
675 | | |
676 | 12 | R_GlobalEnv = R_NewHashedEnv(R_BaseEnv, 0); |
677 | 12 | R_MethodsNamespace = R_GlobalEnv; // so it is initialized. |
678 | | #ifdef NEW_CODE /* Not used */ |
679 | | HASHTAB(R_GlobalEnv) = R_NewHashTable(100); |
680 | | #endif |
681 | 12 | #ifdef USE_GLOBAL_CACHE |
682 | 12 | MARK_AS_GLOBAL_FRAME(R_GlobalEnv); |
683 | 12 | R_GlobalCache = R_NewHashTable(INITIAL_CACHE_SIZE); |
684 | 12 | R_GlobalCachePreserve = CONS(R_GlobalCache, R_NilValue); |
685 | 12 | R_PreserveObject(R_GlobalCachePreserve); |
686 | 12 | #endif |
687 | 12 | R_BaseNamespace = NewEnvironment(R_NilValue, R_NilValue, R_GlobalEnv); |
688 | 12 | R_PreserveObject(R_BaseNamespace); |
689 | 12 | SET_SYMVALUE(install(".BaseNamespaceEnv"), R_BaseNamespace); |
690 | 12 | R_BaseNamespaceName = ScalarString(mkChar("base")); |
691 | 12 | R_PreserveObject(R_BaseNamespaceName); |
692 | 12 | R_NamespaceRegistry = R_NewHashedEnv(R_NilValue, 0); |
693 | 12 | R_PreserveObject(R_NamespaceRegistry); |
694 | 12 | defineVar(R_BaseSymbol, R_BaseNamespace, R_NamespaceRegistry); |
695 | | /**** needed to properly initialize the base namespace */ |
696 | 12 | } |
697 | | |
698 | | #ifdef USE_GLOBAL_CACHE |
699 | | static int hashIndex(SEXP symbol, SEXP table) |
700 | 33.4k | { |
701 | 33.4k | SEXP c = PRINTNAME(symbol); |
702 | 33.4k | if( !HASHASH(c) ) { |
703 | 0 | SET_HASHVALUE(c, R_Newhashpjw(CHAR(c))); |
704 | 0 | SET_HASHASH(c, 1); |
705 | 0 | } |
706 | 33.4k | return HASHVALUE(c) % HASHSIZE(table); |
707 | 33.4k | } |
708 | | |
709 | | static void R_FlushGlobalCache(SEXP sym) |
710 | 31.4k | { |
711 | 31.4k | SEXP entry = R_HashGetLoc(hashIndex(sym, R_GlobalCache), sym, |
712 | 31.4k | R_GlobalCache); |
713 | 31.4k | if (entry != R_NilValue) { |
714 | 0 | SETCAR(entry, R_UnboundValue); |
715 | 0 | #ifdef FAST_BASE_CACHE_LOOKUP |
716 | 0 | UNSET_BASE_SYM_CACHED(sym); |
717 | 0 | #endif |
718 | 0 | } |
719 | 31.4k | } |
720 | | |
721 | | static void R_FlushGlobalCacheFromTable(SEXP table) |
722 | 84 | { |
723 | 84 | int i, size; |
724 | 84 | SEXP chain; |
725 | 84 | size = HASHSIZE(table); |
726 | 2.52k | for (i = 0; i < size; i++) { |
727 | 2.43k | for (chain = VECTOR_ELT(table, i); chain != R_NilValue; chain = CDR(chain)) |
728 | 0 | R_FlushGlobalCache(TAG(chain)); |
729 | 2.43k | } |
730 | 84 | } |
731 | | |
732 | | /** |
733 | | Flush the cache based on the names provided by the user defined |
734 | | table, specifically returned from calling objects() for that |
735 | | table. |
736 | | */ |
737 | | static void R_FlushGlobalCacheFromUserTable(SEXP udb) |
738 | 0 | { |
739 | 0 | int n, i; |
740 | 0 | R_ObjectTable *tb; |
741 | 0 | SEXP names; |
742 | 0 | tb = (R_ObjectTable*) R_ExternalPtrAddr(udb); |
743 | 0 | names = tb->objects(tb); |
744 | 0 | n = length(names); |
745 | 0 | for(i = 0; i < n ; i++) |
746 | 0 | R_FlushGlobalCache(Rf_installTrChar(STRING_ELT(names,i))); |
747 | 0 | } |
748 | | |
749 | | static void R_AddGlobalCache(SEXP symbol, SEXP place) |
750 | 48 | { |
751 | 48 | int oldpri = HASHPRI(R_GlobalCache); |
752 | 48 | R_HashSet(hashIndex(symbol, R_GlobalCache), symbol, R_GlobalCache, place, |
753 | 48 | FALSE); |
754 | 48 | #ifdef FAST_BASE_CACHE_LOOKUP |
755 | 48 | if (symbol == place) |
756 | 46 | SET_BASE_SYM_CACHED(symbol); |
757 | 2 | else |
758 | 2 | UNSET_BASE_SYM_CACHED(symbol); |
759 | 48 | #endif |
760 | 48 | if (oldpri != HASHPRI(R_GlobalCache) && |
761 | 48 | HASHPRI(R_GlobalCache) > 0.85 * HASHSIZE(R_GlobalCache)) { |
762 | 0 | R_GlobalCache = R_HashResize(R_GlobalCache); |
763 | 0 | SETCAR(R_GlobalCachePreserve, R_GlobalCache); |
764 | 0 | } |
765 | 48 | } |
766 | | |
767 | | static SEXP R_GetGlobalCacheLoc(SEXP symbol) |
768 | 1.95k | { |
769 | 1.95k | #ifdef FAST_BASE_CACHE_LOOKUP |
770 | 1.95k | if (BASE_SYM_CACHED(symbol)) |
771 | 0 | return symbol; |
772 | 1.95k | #endif |
773 | | |
774 | 1.95k | return R_HashGet(hashIndex(symbol, R_GlobalCache), symbol, R_GlobalCache); |
775 | 1.95k | } |
776 | | #endif /* USE_GLOBAL_CACHE */ |
777 | | |
778 | | |
779 | | /*---------------------------------------------------------------------- |
780 | | R_GetBindingType |
781 | | */ |
782 | | |
783 | | /* Unwrap nested promises to the innermost one. |
784 | | Sets `*forced` to TRUE if the innermost promise has been evaluated. |
785 | | Uses Floyd's cycle detection to guard against promise loops. */ |
786 | | static SEXP promiseUnwrap(SEXP x, Rboolean *forced) |
787 | 0 | { |
788 | 0 | SEXP slow = x; |
789 | 0 | Rboolean advance_slow = FALSE; |
790 | 0 | while (TRUE) { |
791 | 0 | SEXP code = PRCODE(x); |
792 | 0 | if (TYPEOF(code) != PROMSXP) { |
793 | 0 | *forced = PROMISE_IS_EVALUATED(x); |
794 | 0 | return x; |
795 | 0 | } |
796 | | |
797 | 0 | x = code; |
798 | 0 | if (x == slow) |
799 | 0 | error(_("cycle detected in promise chain")); |
800 | |
|
801 | 0 | if (advance_slow) |
802 | 0 | slow = PRCODE(slow); |
803 | 0 | advance_slow = !advance_slow; |
804 | 0 | } |
805 | 0 | } |
806 | | |
807 | | static R_BindingType_t BINDING_TYPE(SEXP cell) |
808 | 0 | { |
809 | 0 | if (BNDCELL_TAG(cell)) |
810 | | // avoid expanding immediate values |
811 | 0 | return R_BindingTypeValue; |
812 | 0 | else if (IS_ACTIVE_BINDING(cell)) |
813 | 0 | return R_BindingTypeActive; |
814 | 0 | else { |
815 | 0 | SEXP value = CAR(cell); |
816 | 0 | if (value == R_MissingArg) |
817 | 0 | return R_BindingTypeMissing; |
818 | 0 | else if (TYPEOF(value) == PROMSXP) { |
819 | 0 | Rboolean forced; |
820 | 0 | promiseUnwrap(value, &forced); |
821 | 0 | if (forced) |
822 | 0 | return R_BindingTypeForced; |
823 | 0 | else |
824 | 0 | return R_BindingTypeDelayed; |
825 | 0 | } |
826 | 0 | else |
827 | 0 | return R_BindingTypeValue; |
828 | 0 | } |
829 | 0 | } |
830 | | |
831 | | static R_BindingType_t SYMBOL_BINDING_TYPE(SEXP cell) |
832 | 0 | { |
833 | 0 | if (IS_ACTIVE_BINDING(cell)) |
834 | 0 | return R_BindingTypeActive; |
835 | | |
836 | 0 | SEXP value = SYMVALUE(cell); |
837 | 0 | if (value == R_UnboundValue) |
838 | 0 | return R_BindingTypeUnbound; |
839 | | |
840 | | /* Shouldn't happen but for completeness */ |
841 | 0 | if (value == R_MissingArg) |
842 | 0 | return R_BindingTypeMissing; |
843 | | |
844 | | /* There really shouldn't be any promise chains here but we unwrap |
845 | | for consistency with BINDING_TYPE */ |
846 | 0 | if (TYPEOF(value) == PROMSXP) { |
847 | 0 | Rboolean forced; |
848 | 0 | promiseUnwrap(value, &forced); |
849 | 0 | if (forced) |
850 | 0 | return R_BindingTypeForced; |
851 | 0 | else |
852 | 0 | return R_BindingTypeDelayed; |
853 | 0 | } |
854 | | |
855 | 0 | return R_BindingTypeValue; |
856 | 0 | } |
857 | | |
858 | | attribute_hidden |
859 | | R_BindingType_t R_GetVarLocType(R_varloc_t vl) |
860 | 0 | { |
861 | 0 | SEXP cell = vl.cell; |
862 | 0 | if (cell == NULL || cell == R_UnboundValue) |
863 | 0 | return R_BindingTypeUnbound; |
864 | 0 | else if (TYPEOF(cell) == SYMSXP) |
865 | 0 | return SYMBOL_BINDING_TYPE(cell); |
866 | 0 | else |
867 | 0 | return BINDING_TYPE(cell); |
868 | 0 | } |
869 | | |
870 | | static R_varloc_t R_findVarLocInFrameCheck(SEXP env, SEXP sym) |
871 | 0 | { |
872 | 0 | if (TYPEOF(sym) != SYMSXP) |
873 | 0 | error(_("not a symbol")); |
874 | 0 | if (TYPEOF(env) != ENVSXP) |
875 | 0 | error(_("not an environment")); |
876 | 0 | return R_findVarLocInFrame(env, sym); |
877 | 0 | } |
878 | | |
879 | 0 | R_BindingType_t R_GetBindingType(SEXP sym, SEXP env) { |
880 | 0 | R_varloc_t loc = R_findVarLocInFrameCheck(env, sym); |
881 | 0 | return R_GetVarLocType(loc); |
882 | 0 | } |
883 | | |
884 | | attribute_hidden SEXP do_bindingType(SEXP call, SEXP op, SEXP args, SEXP rho) |
885 | 0 | { |
886 | 0 | checkArity(op, args); |
887 | 0 | SEXP sym = CAR(args); |
888 | 0 | SEXP env = CADR(args); |
889 | 0 | switch(R_GetBindingType(sym, env)) { |
890 | 0 | case R_BindingTypeUnbound: return mkString("unbound"); |
891 | 0 | case R_BindingTypeValue: return mkString("value"); |
892 | 0 | case R_BindingTypeMissing: return mkString("missing"); |
893 | 0 | case R_BindingTypeDelayed: return mkString("delayed"); |
894 | 0 | case R_BindingTypeForced: return mkString("forced"); |
895 | 0 | case R_BindingTypeActive: return mkString("active"); |
896 | 0 | default: error("unknown binding type; should not happen"); |
897 | 0 | } |
898 | 0 | } |
899 | | |
900 | | attribute_hidden |
901 | | SEXP do_delayedBindingExpr(SEXP call, SEXP op, SEXP args, SEXP rho) |
902 | 0 | { |
903 | 0 | checkArity(op, args); |
904 | 0 | SEXP sym = CAR(args); |
905 | 0 | SEXP env = CADR(args); |
906 | 0 | return R_DelayedBindingExpression(sym, env); |
907 | 0 | } |
908 | | |
909 | | attribute_hidden |
910 | | SEXP do_delayedBindingEnv(SEXP call, SEXP op, SEXP args, SEXP rho) |
911 | 0 | { |
912 | 0 | checkArity(op, args); |
913 | 0 | SEXP sym = CAR(args); |
914 | 0 | SEXP env = CADR(args); |
915 | 0 | return R_DelayedBindingEnvironment(sym, env); |
916 | 0 | } |
917 | | |
918 | | attribute_hidden |
919 | | SEXP do_forcedBindingExpr(SEXP call, SEXP op, SEXP args, SEXP rho) |
920 | 0 | { |
921 | 0 | checkArity(op, args); |
922 | 0 | SEXP sym = CAR(args); |
923 | 0 | SEXP env = CADR(args); |
924 | 0 | return R_ForcedBindingExpression(sym, env); |
925 | 0 | } |
926 | | |
927 | | |
928 | | /*---------------------------------------------------------------------- |
929 | | |
930 | | unbindVar |
931 | | |
932 | | Remove a value from an environment. This happens only in the frame |
933 | | of the specified environment. |
934 | | |
935 | | FIXME ? should this also unbind the symbol value slot when rho is |
936 | | R_BaseEnv. |
937 | | This is only called from eval.c in applydefine and bcEval |
938 | | (and applydefine only works for unhashed environments, so not base). |
939 | | */ |
940 | | |
941 | | static SEXP RemoveFromList(SEXP thing, SEXP list, int *found) |
942 | 25.7k | { |
943 | 25.7k | if (list == R_NilValue) { |
944 | 0 | *found = 0; |
945 | 0 | return R_NilValue; |
946 | 0 | } |
947 | 25.7k | else if (TAG(list) == thing) { |
948 | 25.6k | *found = 1; |
949 | 25.6k | SET_BNDCELL(list, R_UnboundValue); /* in case binding is cached */ |
950 | 25.6k | LOCK_BINDING(list); /* in case binding is cached */ |
951 | 25.6k | SEXP rest = CDR(list); |
952 | 25.6k | SETCDR(list, R_NilValue); /* to fix refcnt on 'rest' */ |
953 | 25.6k | return rest; |
954 | 25.6k | } |
955 | 97 | else { |
956 | 97 | SEXP last = list; |
957 | 97 | SEXP next = CDR(list); |
958 | 97 | while (next != R_NilValue) { |
959 | 97 | if (TAG(next) == thing) { |
960 | 97 | *found = 1; |
961 | 97 | SETCAR(next, R_UnboundValue); /* in case binding is cached */ |
962 | 97 | LOCK_BINDING(next); /* in case binding is cached */ |
963 | 97 | SETCDR(last, CDR(next)); |
964 | 97 | SETCDR(next, R_NilValue); /* to fix refcnt on 'list' */ |
965 | 97 | return list; |
966 | 97 | } |
967 | 0 | else { |
968 | 0 | last = next; |
969 | 0 | next = CDR(next); |
970 | 0 | } |
971 | 97 | } |
972 | 0 | *found = 0; |
973 | 0 | return list; |
974 | 97 | } |
975 | 25.7k | } |
976 | | |
977 | | attribute_hidden void unbindVar(SEXP symbol, SEXP rho) |
978 | 25.7k | { |
979 | 25.7k | int hashcode; |
980 | 25.7k | int found; |
981 | 25.7k | SEXP c; |
982 | | |
983 | 25.7k | if (rho == R_BaseNamespace) |
984 | 0 | error(_("cannot unbind in the base namespace")); |
985 | 25.7k | if (rho == R_BaseEnv) |
986 | 0 | error(_("unbind in the base environment is unimplemented")); |
987 | 25.7k | if (FRAME_IS_LOCKED(rho)) |
988 | 0 | error(_("cannot remove bindings from a locked environment")); |
989 | 25.7k | if (HASHTAB(rho) == R_NilValue) { |
990 | 25.7k | SEXP list; |
991 | 25.7k | list = RemoveFromList(symbol, FRAME(rho), &found); |
992 | 25.7k | if (found) { |
993 | 25.7k | if (rho == R_GlobalEnv) R_DirtyImage = 1; |
994 | 25.7k | SET_FRAME(rho, list); |
995 | 25.7k | #ifdef USE_GLOBAL_CACHE |
996 | 25.7k | if (IS_GLOBAL_FRAME(rho)) |
997 | 0 | R_FlushGlobalCache(symbol); |
998 | 25.7k | #endif |
999 | 25.7k | } |
1000 | 25.7k | } |
1001 | 0 | else { |
1002 | | /* This branch is used e.g. via sys.source, utils::data */ |
1003 | 0 | c = PRINTNAME(symbol); |
1004 | 0 | if( !HASHASH(c) ) { |
1005 | 0 | SET_HASHVALUE(c, R_Newhashpjw(CHAR(c))); |
1006 | 0 | SET_HASHASH(c, 1); |
1007 | 0 | } |
1008 | 0 | hashcode = HASHVALUE(c) % HASHSIZE(HASHTAB(rho)); |
1009 | 0 | R_HashDelete(hashcode, symbol, rho, &found); |
1010 | 0 | #ifdef USE_GLOBAL_CACHE |
1011 | 0 | if (found && IS_GLOBAL_FRAME(rho)) |
1012 | 0 | R_FlushGlobalCache(symbol); |
1013 | 0 | #endif |
1014 | 0 | } |
1015 | 25.7k | } |
1016 | | |
1017 | | |
1018 | | |
1019 | | /*---------------------------------------------------------------------- |
1020 | | |
1021 | | findVarLocInFrame |
1022 | | |
1023 | | Look up the location of the value of a symbol in a |
1024 | | single environment frame. Almost like R_findVarInFrame, but |
1025 | | does not return the value. R_NilValue if not found. |
1026 | | |
1027 | | Callers set *canCache = TRUE or NULL |
1028 | | */ |
1029 | | |
1030 | | static SEXP findVarLocInFrame(SEXP rho, SEXP symbol, Rboolean *canCache) |
1031 | 22.6M | { |
1032 | 22.6M | int hashcode; |
1033 | 22.6M | SEXP frame, c; |
1034 | | |
1035 | 22.6M | if (rho == R_BaseEnv || rho == R_BaseNamespace) |
1036 | 84.4k | return (SYMVALUE(symbol) == R_UnboundValue) ? R_NilValue : symbol; |
1037 | | |
1038 | 22.5M | if (rho == R_EmptyEnv) |
1039 | 0 | return R_NilValue; |
1040 | | |
1041 | 22.5M | if(IS_USER_DATABASE(rho)) { |
1042 | 0 | R_ObjectTable *table; |
1043 | 0 | SEXP val, tmp = R_NilValue; |
1044 | 0 | table = (R_ObjectTable *) R_ExternalPtrAddr(HASHTAB(rho)); |
1045 | | /* Better to use exists() here if we don't actually need the value! */ |
1046 | 0 | val = table->get(CHAR(PRINTNAME(symbol)), canCache, table); |
1047 | 0 | if(val != R_UnboundValue) { |
1048 | | /* The result should probably be identified as being from |
1049 | | a user database, or maybe use an active binding |
1050 | | mechanism to allow setting a new value to get back to |
1051 | | the data base. */ |
1052 | 0 | tmp = allocSExp(LISTSXP); |
1053 | 0 | SETCAR(tmp, val); |
1054 | 0 | SET_TAG(tmp, symbol); |
1055 | | /* If the database has a canCache method, then call that. |
1056 | | Otherwise, we believe the setting for canCache. */ |
1057 | 0 | if(canCache && table->canCache) { |
1058 | 0 | PROTECT(tmp); |
1059 | 0 | *canCache = table->canCache(CHAR(PRINTNAME(symbol)), table); |
1060 | 0 | UNPROTECT(1); |
1061 | 0 | } |
1062 | 0 | MARK_NOT_MUTABLE(val); /* to keep complex assignment code sane */ |
1063 | 0 | } |
1064 | 0 | return(tmp); |
1065 | 0 | } |
1066 | | |
1067 | 22.5M | if (HASHTAB(rho) == R_NilValue) { |
1068 | 22.3M | frame = FRAME(rho); |
1069 | 58.9M | while (frame != R_NilValue && TAG(frame) != symbol) |
1070 | 36.5M | frame = CDR(frame); |
1071 | 22.3M | return frame; |
1072 | 22.3M | } |
1073 | 140k | else { |
1074 | 140k | c = PRINTNAME(symbol); |
1075 | 140k | if( !HASHASH(c) ) { |
1076 | 0 | SET_HASHVALUE(c, R_Newhashpjw(CHAR(c))); |
1077 | 0 | SET_HASHASH(c, 1); |
1078 | 0 | } |
1079 | 140k | hashcode = HASHVALUE(c) % HASHSIZE(HASHTAB(rho)); |
1080 | | /* Will return 'R_NilValue' if not found */ |
1081 | 140k | return R_HashGetLoc(hashcode, symbol, HASHTAB(rho)); |
1082 | 140k | } |
1083 | 22.5M | } |
1084 | | |
1085 | | |
1086 | | /* |
1087 | | External version and accessor functions. Returned value is cast as |
1088 | | an opaque pointer to insure it is only used by routines in this |
1089 | | group. This allows the implementation to be changed without needing |
1090 | | to change other files. |
1091 | | */ |
1092 | | |
1093 | | R_varloc_t R_findVarLocInFrame(SEXP rho, SEXP symbol) |
1094 | 21.7M | { |
1095 | 21.7M | SEXP binding = findVarLocInFrame(rho, symbol, NULL); |
1096 | 21.7M | R_varloc_t val; |
1097 | 21.7M | val.cell = binding == R_NilValue ? NULL : binding; |
1098 | 21.7M | return val; |
1099 | 21.7M | } |
1100 | | |
1101 | | attribute_hidden |
1102 | | SEXP R_GetVarLocValue(R_varloc_t vl) |
1103 | 323k | { |
1104 | 323k | SEXP cell = vl.cell; |
1105 | 323k | if (cell == NULL || cell == R_UnboundValue) |
1106 | 0 | return R_UnboundValue; |
1107 | 323k | else if (TYPEOF(cell) == SYMSXP) |
1108 | 84.4k | return SYMBOL_BINDING_VALUE(cell); |
1109 | 238k | else return BINDING_VALUE(cell); |
1110 | 323k | } |
1111 | | |
1112 | | attribute_hidden |
1113 | | SEXP R_GetVarLocSymbol(R_varloc_t vl) |
1114 | 0 | { |
1115 | 0 | return TAG(vl.cell); |
1116 | 0 | } |
1117 | | |
1118 | | /* used in methods */ |
1119 | | Rboolean R_GetVarLocMISSING(R_varloc_t vl) |
1120 | 0 | { |
1121 | 0 | return MISSING(vl.cell); |
1122 | 0 | } |
1123 | | |
1124 | | attribute_hidden |
1125 | | void R_SetVarLocValue(R_varloc_t vl, SEXP value) |
1126 | 25.7k | { |
1127 | 25.7k | SET_BINDING_VALUE(vl.cell, value); |
1128 | 25.7k | } |
1129 | | |
1130 | | |
1131 | | /*---------------------------------------------------------------------- |
1132 | | |
1133 | | R_findVarInFrame |
1134 | | |
1135 | | Look up the value of a symbol in a single environment frame. This |
1136 | | is the basic building block of all variable lookups. |
1137 | | |
1138 | | It is important that this be as efficient as possible. |
1139 | | |
1140 | | The final argument is usually TRUE and indicates whether the |
1141 | | lookup is being done in order to get the value (TRUE) or |
1142 | | simply to check whether there is a value bound to the specified |
1143 | | symbol in this frame (FALSE). This is used for get() and exists(). |
1144 | | */ |
1145 | | |
1146 | | // In Rinternals.h |
1147 | | SEXP findVarInFrame3(SEXP rho, SEXP symbol, Rboolean doGet) |
1148 | 39.0M | { |
1149 | 39.0M | int hashcode; |
1150 | 39.0M | SEXP frame, c; |
1151 | | |
1152 | 39.0M | if (TYPEOF(rho) == NILSXP) |
1153 | 0 | error(_("use of NULL environment is defunct")); |
1154 | | |
1155 | 39.0M | if (rho == R_BaseNamespace || rho == R_BaseEnv) |
1156 | 12.7M | return SYMBOL_BINDING_VALUE(symbol); |
1157 | | |
1158 | 26.3M | if (rho == R_EmptyEnv) |
1159 | 0 | return R_UnboundValue; |
1160 | | |
1161 | 26.3M | if(IS_USER_DATABASE(rho)) { |
1162 | | /* Use the objects function pointer for this symbol. */ |
1163 | 0 | R_ObjectTable *table; |
1164 | 0 | SEXP val = R_UnboundValue; |
1165 | 0 | table = (R_ObjectTable *) R_ExternalPtrAddr(HASHTAB(rho)); |
1166 | 0 | if(table->active) { |
1167 | 0 | if(doGet) |
1168 | 0 | val = table->get(CHAR(PRINTNAME(symbol)), NULL, table); |
1169 | 0 | else { |
1170 | 0 | if(table->exists(CHAR(PRINTNAME(symbol)), NULL, table)) |
1171 | 0 | val = table->get(CHAR(PRINTNAME(symbol)), NULL, table); |
1172 | 0 | else |
1173 | 0 | val = R_UnboundValue; |
1174 | 0 | } |
1175 | 0 | MARK_NOT_MUTABLE(val); /* to keep complex assignment code sane */ |
1176 | 0 | } |
1177 | 0 | return(val); |
1178 | 26.3M | } else if (HASHTAB(rho) == R_NilValue) { |
1179 | 22.2M | frame = FRAME(rho); |
1180 | 123M | while (frame != R_NilValue) { |
1181 | 106M | if (TAG(frame) == symbol) |
1182 | 5.90M | return BINDING_VALUE(frame); |
1183 | 100M | frame = CDR(frame); |
1184 | 100M | } |
1185 | 22.2M | } |
1186 | 4.10M | else { |
1187 | 4.10M | c = PRINTNAME(symbol); |
1188 | 4.10M | if( !HASHASH(c) ) { |
1189 | 0 | SET_HASHVALUE(c, R_Newhashpjw(CHAR(c))); |
1190 | 0 | SET_HASHASH(c, 1); |
1191 | 0 | } |
1192 | 4.10M | hashcode = HASHVALUE(c) % HASHSIZE(HASHTAB(rho)); |
1193 | | /* Will return 'R_UnboundValue' if not found */ |
1194 | 4.10M | return(R_HashGet(hashcode, symbol, HASHTAB(rho))); |
1195 | 4.10M | } |
1196 | 16.3M | return R_UnboundValue; |
1197 | 26.3M | } |
1198 | | |
1199 | | /* This variant of findVarinFrame3 is needed to avoid running active |
1200 | | binding functions in calls to exists() with mode = "any" */ |
1201 | | Rboolean R_existsVarInFrame(SEXP rho, SEXP symbol) |
1202 | 4.13M | { |
1203 | 4.13M | int hashcode; |
1204 | 4.13M | SEXP frame, c; |
1205 | | |
1206 | 4.13M | if (TYPEOF(rho) == NILSXP) |
1207 | 0 | error(_("use of NULL environment is defunct")); |
1208 | | |
1209 | 4.13M | if (rho == R_BaseNamespace || rho == R_BaseEnv) |
1210 | 12 | return SYMBOL_HAS_BINDING(symbol); |
1211 | | |
1212 | 4.13M | if (rho == R_EmptyEnv) |
1213 | 0 | return FALSE; |
1214 | | |
1215 | 4.13M | if(IS_USER_DATABASE(rho)) { |
1216 | | /* Use the objects function pointer for this symbol. */ |
1217 | 0 | R_ObjectTable *table; |
1218 | 0 | Rboolean val = FALSE; |
1219 | 0 | table = (R_ObjectTable *) R_ExternalPtrAddr(HASHTAB(rho)); |
1220 | 0 | if(table->active) { |
1221 | 0 | if(table->exists(CHAR(PRINTNAME(symbol)), NULL, table)) |
1222 | 0 | val = TRUE; |
1223 | 0 | else |
1224 | 0 | val = FALSE; |
1225 | 0 | } |
1226 | 0 | return(val); |
1227 | 4.13M | } else if (HASHTAB(rho) == R_NilValue) { |
1228 | 4.12M | frame = FRAME(rho); |
1229 | 27.3M | while (frame != R_NilValue) { |
1230 | 23.2M | if (TAG(frame) == symbol) |
1231 | 0 | return TRUE; |
1232 | 23.2M | frame = CDR(frame); |
1233 | 23.2M | } |
1234 | 4.12M | } |
1235 | 13.4k | else { |
1236 | 13.4k | c = PRINTNAME(symbol); |
1237 | 13.4k | if( !HASHASH(c) ) { |
1238 | 0 | SET_HASHVALUE(c, R_Newhashpjw(CHAR(c))); |
1239 | 0 | SET_HASHASH(c, 1); |
1240 | 0 | } |
1241 | 13.4k | hashcode = HASHVALUE(c) % HASHSIZE(HASHTAB(rho)); |
1242 | 13.4k | return R_HashExists(hashcode, symbol, HASHTAB(rho)); |
1243 | 13.4k | } |
1244 | 4.12M | return FALSE; |
1245 | 4.13M | } |
1246 | | |
1247 | | attribute_hidden SEXP R_findVarInFrame(SEXP rho, SEXP symbol) |
1248 | 38.8M | { |
1249 | 38.8M | return findVarInFrame3(rho, symbol, TRUE); |
1250 | 38.8M | } |
1251 | | |
1252 | | SEXP findVarInFrame(SEXP rho, SEXP symbol) |
1253 | 11.4k | { |
1254 | 11.4k | return R_findVarInFrame(rho, symbol); |
1255 | 11.4k | } |
1256 | | |
1257 | | /*---------------------------------------------------------------------- |
1258 | | |
1259 | | readS3VarsFromFrame |
1260 | | |
1261 | | Reads the S3 meta-variables from a given (single) frame. |
1262 | | R_UnboundValue marks that respective variable is not present. |
1263 | | This function is optimized to be fast in the common case when the |
1264 | | S3 meta-variables are in the expected order and that the frame is |
1265 | | represented by a pairlist. |
1266 | | */ |
1267 | | |
1268 | | attribute_hidden |
1269 | | void readS3VarsFromFrame(SEXP rho, |
1270 | | SEXP *dotGeneric, SEXP *dotGroup, SEXP *dotClass, SEXP *dotMethod, |
1271 | 327 | SEXP *dotGenericCallEnv, SEXP *dotGenericDefEnv) { |
1272 | | |
1273 | 327 | if (TYPEOF(rho) == NILSXP || |
1274 | 327 | rho == R_BaseNamespace || rho == R_BaseEnv || rho == R_EmptyEnv || |
1275 | 327 | IS_USER_DATABASE(rho) || HASHTAB(rho) != R_NilValue) goto slowpath; |
1276 | | |
1277 | 327 | SEXP frame = FRAME(rho); |
1278 | | |
1279 | | /* |
1280 | | This code speculates there is a specific order of S3 meta-variables. It |
1281 | | holds in most (perhaps all non-fabricated) cases. If at any time this |
1282 | | ceased to hold, this code will fall back to the slowpath, which may be |
1283 | | slow but still correct. |
1284 | | */ |
1285 | | |
1286 | 327 | for(;TAG(frame) != R_dot_Generic; frame = CDR(frame)) |
1287 | 0 | if (frame == R_NilValue) goto slowpath; |
1288 | 327 | *dotGeneric = BINDING_VALUE(frame); |
1289 | 327 | frame = CDR(frame); |
1290 | | |
1291 | 327 | if (TAG(frame) != R_dot_Class) goto slowpath; |
1292 | 327 | *dotClass = BINDING_VALUE(frame); |
1293 | 327 | frame = CDR(frame); |
1294 | | |
1295 | 327 | if (TAG(frame) != R_dot_Method) goto slowpath; |
1296 | 327 | *dotMethod = BINDING_VALUE(frame); |
1297 | 327 | frame = CDR(frame); |
1298 | | |
1299 | 327 | if (TAG(frame) != R_dot_Group) goto slowpath; |
1300 | 327 | *dotGroup = BINDING_VALUE(frame); |
1301 | 327 | frame = CDR(frame); |
1302 | | |
1303 | 327 | if (TAG(frame) != R_dot_GenericCallEnv) goto slowpath; |
1304 | 327 | *dotGenericCallEnv = BINDING_VALUE(frame); |
1305 | 327 | frame = CDR(frame); |
1306 | | |
1307 | 327 | if (TAG(frame) != R_dot_GenericDefEnv) goto slowpath; |
1308 | 327 | *dotGenericDefEnv = BINDING_VALUE(frame); |
1309 | | |
1310 | 327 | return; |
1311 | | |
1312 | 0 | slowpath: |
1313 | | /* fall back to the slow but general implementation */ |
1314 | |
|
1315 | 0 | *dotGeneric = R_findVarInFrame(rho, R_dot_Generic); |
1316 | 0 | *dotClass = R_findVarInFrame(rho, R_dot_Class); |
1317 | 0 | *dotMethod = R_findVarInFrame(rho, R_dot_Method); |
1318 | 0 | *dotGroup = R_findVarInFrame(rho, R_dot_Group); |
1319 | 0 | *dotGenericCallEnv = R_findVarInFrame(rho, R_dot_GenericCallEnv); |
1320 | 0 | *dotGenericDefEnv = R_findVarInFrame(rho, R_dot_GenericDefEnv); |
1321 | 0 | } |
1322 | | |
1323 | | |
1324 | | /*---------------------------------------------------------------------- |
1325 | | |
1326 | | findVar |
1327 | | |
1328 | | Look up a symbol in an environment. |
1329 | | |
1330 | | */ |
1331 | | |
1332 | | #ifdef USE_GLOBAL_CACHE |
1333 | | /* findGlobalVar searches for a symbol value starting at R_GlobalEnv, |
1334 | | so the cache can be used. */ |
1335 | | static SEXP findGlobalVarLoc(SEXP symbol) |
1336 | 1.95k | { |
1337 | 1.95k | SEXP vl, rho; |
1338 | 1.95k | Rboolean canCache = TRUE; |
1339 | 1.95k | vl = R_GetGlobalCacheLoc(symbol); |
1340 | 1.95k | if (vl != R_UnboundValue) |
1341 | 1.89k | return vl; |
1342 | 400 | for (rho = R_GlobalEnv; rho != R_EmptyEnv; rho = ENCLOS(rho)) { |
1343 | 400 | if (rho != R_BaseEnv) { /* we won't have R_BaseNamespace */ |
1344 | 342 | vl = findVarLocInFrame(rho, symbol, &canCache); |
1345 | 342 | if (vl != R_NilValue) { |
1346 | 2 | if(canCache) |
1347 | 2 | R_AddGlobalCache(symbol, vl); |
1348 | 2 | return vl; |
1349 | 2 | } |
1350 | 342 | } |
1351 | 58 | else { |
1352 | 58 | if (SYMVALUE(symbol) != R_UnboundValue) |
1353 | 46 | R_AddGlobalCache(symbol, symbol); |
1354 | 58 | return symbol; |
1355 | 58 | } |
1356 | 400 | } |
1357 | 0 | return R_NilValue; |
1358 | 60 | } |
1359 | | |
1360 | | static R_INLINE SEXP findGlobalVar(SEXP symbol) |
1361 | 1.95k | { |
1362 | 1.95k | SEXP loc = findGlobalVarLoc(symbol); |
1363 | 1.95k | switch (TYPEOF(loc)) { |
1364 | 0 | case NILSXP: return R_UnboundValue; |
1365 | 58 | case SYMSXP: return SYMBOL_BINDING_VALUE(symbol); |
1366 | 1.89k | default: return BINDING_VALUE(loc); |
1367 | | /* loc is protected by callee when needed */ |
1368 | 1.95k | } |
1369 | 1.95k | } |
1370 | | #endif |
1371 | | |
1372 | | attribute_hidden SEXP R_findVar(SEXP symbol, SEXP rho) |
1373 | 3.17M | { |
1374 | 3.17M | SEXP vl; |
1375 | | |
1376 | 3.17M | if (TYPEOF(rho) == NILSXP) |
1377 | 0 | error(_("use of NULL environment is defunct")); |
1378 | | |
1379 | 3.17M | if (!isEnvironment(rho)) |
1380 | 0 | error(_("argument to '%s' is not an environment"), "findVar"); |
1381 | | |
1382 | 3.17M | #ifdef USE_GLOBAL_CACHE |
1383 | | /* This first loop handles local frames, if there are any. It |
1384 | | will also handle all frames if rho is a global frame other than |
1385 | | R_GlobalEnv */ |
1386 | 3.22M | while (rho != R_GlobalEnv && rho != R_EmptyEnv) { |
1387 | 3.22M | vl = R_findVarInFrame(rho, symbol); |
1388 | 3.22M | if (vl != R_UnboundValue) return (vl); |
1389 | 51.1k | rho = ENCLOS(rho); |
1390 | 51.1k | } |
1391 | 24 | if (rho == R_GlobalEnv) |
1392 | 24 | return findGlobalVar(symbol); |
1393 | 0 | else |
1394 | 0 | return R_UnboundValue; |
1395 | | #else |
1396 | | while (rho != R_EmptyEnv) { |
1397 | | vl = R_findVarInFrame(rho, symbol); |
1398 | | if (vl != R_UnboundValue) return (vl); |
1399 | | rho = ENCLOS(rho); |
1400 | | } |
1401 | | return R_UnboundValue; |
1402 | | #endif |
1403 | 24 | } |
1404 | | |
1405 | | SEXP findVar(SEXP symbol, SEXP rho) |
1406 | 24 | { |
1407 | 24 | return R_findVar(symbol, rho); |
1408 | 24 | } |
1409 | | |
1410 | | static SEXP findVarLoc(SEXP symbol, SEXP rho) |
1411 | 300k | { |
1412 | 300k | SEXP vl; |
1413 | | |
1414 | 300k | if (TYPEOF(rho) == NILSXP) |
1415 | 0 | error(_("use of NULL environment is defunct")); |
1416 | | |
1417 | 300k | if (!isEnvironment(rho)) |
1418 | 0 | error(_("argument to '%s' is not an environment"), "findVarLoc"); |
1419 | | |
1420 | 300k | #ifdef USE_GLOBAL_CACHE |
1421 | | /* This first loop handles local frames, if there are any. It |
1422 | | will also handle all frames if rho is a global frame other than |
1423 | | R_GlobalEnv */ |
1424 | 650k | while (rho != R_GlobalEnv && rho != R_EmptyEnv) { |
1425 | 650k | vl = findVarLocInFrame(rho, symbol, NULL); |
1426 | 650k | if (vl != R_NilValue) return vl; |
1427 | 349k | rho = ENCLOS(rho); |
1428 | 349k | } |
1429 | 0 | if (rho == R_GlobalEnv) |
1430 | 0 | return findGlobalVarLoc(symbol); |
1431 | 0 | else |
1432 | 0 | return R_NilValue; |
1433 | | #else |
1434 | | while (rho != R_EmptyEnv) { |
1435 | | vl = R_findVarInLocFrame(rho, symbol, NULL); |
1436 | | if (vl != R_NilValue) return vl; |
1437 | | rho = ENCLOS(rho); |
1438 | | } |
1439 | | return R_NilValue; |
1440 | | #endif |
1441 | 0 | } |
1442 | | |
1443 | | R_varloc_t R_findVarLoc(SEXP symbol, SEXP rho) |
1444 | 300k | { |
1445 | 300k | SEXP binding = findVarLoc(symbol, rho); |
1446 | 300k | R_varloc_t val; |
1447 | 300k | val.cell = binding == R_NilValue ? NULL : binding; |
1448 | 300k | return val; |
1449 | 300k | } |
1450 | | |
1451 | | |
1452 | | /*---------------------------------------------------------------------- |
1453 | | |
1454 | | findVar1 |
1455 | | |
1456 | | Look up a symbol in an environment. Ignore any values which are |
1457 | | not of the specified type. |
1458 | | |
1459 | | */ |
1460 | | |
1461 | | attribute_hidden SEXP |
1462 | | findVar1(SEXP symbol, SEXP rho, SEXPTYPE mode, int inherits) |
1463 | 0 | { |
1464 | 0 | SEXP vl; |
1465 | 0 | while (rho != R_EmptyEnv) { |
1466 | 0 | vl = R_findVarInFrame(rho, symbol); |
1467 | 0 | if (vl != R_UnboundValue) { |
1468 | 0 | if (mode == ANYSXP) return vl; |
1469 | 0 | if (TYPEOF(vl) == PROMSXP) { |
1470 | 0 | PROTECT(vl); |
1471 | 0 | vl = eval(vl, rho); |
1472 | 0 | UNPROTECT(1); |
1473 | 0 | } |
1474 | 0 | if (TYPEOF(vl) == mode) return vl; |
1475 | 0 | if (mode == FUNSXP && (TYPEOF(vl) == CLOSXP || |
1476 | 0 | TYPEOF(vl) == BUILTINSXP || |
1477 | 0 | TYPEOF(vl) == SPECIALSXP)) |
1478 | 0 | return (vl); |
1479 | 0 | } |
1480 | 0 | if (inherits) |
1481 | 0 | rho = ENCLOS(rho); |
1482 | 0 | else |
1483 | 0 | return (R_UnboundValue); |
1484 | 0 | } |
1485 | 0 | return (R_UnboundValue); |
1486 | 0 | } |
1487 | | |
1488 | | /* |
1489 | | * ditto, but check *mode* not *type* |
1490 | | */ |
1491 | | |
1492 | | static SEXP |
1493 | | findVar1mode(SEXP symbol, SEXP rho, SEXPTYPE mode, Rboolean wants_S4, |
1494 | | int inherits, Rboolean doGet) |
1495 | 187k | { |
1496 | 187k | SEXP vl; |
1497 | 187k | int tl; |
1498 | 187k | if (mode == INTSXP) mode = REALSXP; |
1499 | 187k | if (mode == FUNSXP || mode == BUILTINSXP || mode == SPECIALSXP) |
1500 | 276 | mode = CLOSXP; |
1501 | 188k | while (rho != R_EmptyEnv) { |
1502 | 188k | if (! doGet && mode == ANYSXP) |
1503 | 12.9k | vl = R_existsVarInFrame(rho, symbol) ? R_NilValue : R_UnboundValue; |
1504 | 175k | else |
1505 | 175k | vl = findVarInFrame3(rho, symbol, doGet); |
1506 | | |
1507 | 188k | if (vl != R_UnboundValue) { |
1508 | 29.6k | if (mode == ANYSXP) return vl; |
1509 | 276 | if (TYPEOF(vl) == PROMSXP) { |
1510 | 24 | PROTECT(vl); |
1511 | 24 | vl = eval(vl, rho); |
1512 | 24 | UNPROTECT(1); |
1513 | 24 | } |
1514 | 276 | tl = TYPEOF(vl); |
1515 | 276 | if (tl == INTSXP) tl = REALSXP; |
1516 | 276 | if (tl == FUNSXP || tl == BUILTINSXP || tl == SPECIALSXP) |
1517 | 252 | tl = CLOSXP; |
1518 | 276 | if (tl == mode) { |
1519 | 276 | if (tl == OBJSXP) { |
1520 | 0 | if ((wants_S4 && IS_S4_OBJECT(vl)) || |
1521 | 0 | (! wants_S4 && ! IS_S4_OBJECT(vl))) |
1522 | 0 | return vl; |
1523 | 0 | } |
1524 | 276 | else return vl; |
1525 | 276 | } |
1526 | 276 | } |
1527 | 158k | if (inherits) |
1528 | 1.12k | rho = ENCLOS(rho); |
1529 | 157k | else |
1530 | 157k | return (R_UnboundValue); |
1531 | 158k | } |
1532 | 0 | return (R_UnboundValue); |
1533 | 187k | } |
1534 | | |
1535 | | |
1536 | | /* |
1537 | | ddVal ("dot-dot-value"): |
1538 | | a function to take a name and determine if it is of the form |
1539 | | ..x where x is an integer; if so x is returned otherwise 0 is returned |
1540 | | */ |
1541 | | static int ddVal(SEXP symbol) |
1542 | 49.0k | { |
1543 | 49.0k | const char *buf; |
1544 | 49.0k | char *endp; |
1545 | 49.0k | int rval; |
1546 | | |
1547 | 49.0k | buf = CHAR(PRINTNAME(symbol)); |
1548 | 49.0k | if( !strncmp(buf,"..",2) && strlen(buf) > 2 ) { |
1549 | 49.0k | buf += 2; |
1550 | 49.0k | rval = (int) strtol(buf, &endp, 10); |
1551 | 49.0k | if( *endp != '\0') |
1552 | 0 | return 0; |
1553 | 49.0k | else |
1554 | 49.0k | return rval; |
1555 | 49.0k | } |
1556 | 0 | return 0; |
1557 | 49.0k | } |
1558 | | |
1559 | | /*---------------------------------------------------------------------- |
1560 | | ddfindVar |
1561 | | |
1562 | | This function fetches the variables ..1, ..2, etc from the first |
1563 | | frame of the environment passed as the second argument to ddfindVar. |
1564 | | These variables are implicitly defined whenever a ... object is |
1565 | | created. |
1566 | | |
1567 | | To determine values for the variables we first search for an |
1568 | | explicit definition of the symbol, them we look for a ... object in |
1569 | | the frame and then walk through it to find the appropriate values. |
1570 | | |
1571 | | If no value is obtained we return R_UnboundValue. |
1572 | | |
1573 | | It is an error to specify a .. index longer than the length of the |
1574 | | ... object the value is sought in. |
1575 | | |
1576 | | */ |
1577 | | |
1578 | 80.3k | #define length_DOTS(_v_) (TYPEOF(_v_) == DOTSXP ? length(_v_) : 0) |
1579 | | |
1580 | | /* Walk parent environments to find the first one containing a proper `...` */ |
1581 | | SEXP R_findDotsEnv(SEXP env) |
1582 | 80.3k | { |
1583 | 80.3k | while (env != R_EmptyEnv) { |
1584 | 80.3k | SEXP vl = R_findVarInFrame(env, R_DotsSymbol); |
1585 | 80.3k | if (vl != R_UnboundValue && |
1586 | 80.3k | (vl == R_MissingArg || TYPEOF(vl) == DOTSXP)) |
1587 | 80.3k | return env; |
1588 | 0 | env = ENCLOS(env); |
1589 | 0 | } |
1590 | 0 | return R_EmptyEnv; |
1591 | 80.3k | } |
1592 | | |
1593 | | Rboolean R_DotsExist(SEXP env) |
1594 | 0 | { |
1595 | 0 | SEXP vl = R_findVarInFrame(env, R_DotsSymbol); |
1596 | 0 | return vl != R_UnboundValue && |
1597 | 0 | (vl == R_MissingArg || TYPEOF(vl) == DOTSXP); |
1598 | 0 | } |
1599 | | |
1600 | | static SEXP resolveDotsEnv(SEXP env, Rboolean inherits) |
1601 | 0 | { |
1602 | 0 | return inherits ? R_findDotsEnv(env) : env; |
1603 | 0 | } |
1604 | | |
1605 | | attribute_hidden SEXP do_dotsExist(SEXP call, SEXP op, SEXP args, SEXP env) |
1606 | 0 | { |
1607 | 0 | checkArity(op, args); |
1608 | 0 | SEXP rho = resolveDotsEnv(CAR(args), asLogical(CADR(args))); |
1609 | 0 | return ScalarLogical(R_DotsExist(rho)); |
1610 | 0 | } |
1611 | | |
1612 | | /* Frame-only: does not search parent environments */ |
1613 | | static SEXP ddfindInFrame(int i, SEXP rho) |
1614 | 54.7k | { |
1615 | 54.7k | if(i <= 0) |
1616 | 0 | error(_("indexing '...' with non-positive index %d"), i); |
1617 | 54.7k | SEXP vl = R_findVarInFrame(rho, R_DotsSymbol); |
1618 | 54.7k | if (vl != R_UnboundValue) { |
1619 | 54.7k | if (TYPEOF(vl) != DOTSXP && vl != R_MissingArg) |
1620 | 0 | error(_("bad ... value")); |
1621 | 54.7k | if (length_DOTS(vl) >= i) { |
1622 | 54.7k | vl = nthcdr(vl, i - 1); |
1623 | 54.7k | return(CAR(vl)); |
1624 | 54.7k | } |
1625 | 0 | else // length(...) < i |
1626 | 0 | error(ngettext("the ... list contains fewer than %d element", |
1627 | 0 | "the ... list contains fewer than %d elements", i), |
1628 | 0 | i); |
1629 | 54.7k | } |
1630 | 0 | else error(_("..%d used in an incorrect context, no ... to look in"), i); |
1631 | | |
1632 | 0 | return R_NilValue; |
1633 | 54.7k | } |
1634 | | |
1635 | | static SEXP ddfind(int i, SEXP rho) |
1636 | 49.0k | { |
1637 | 49.0k | return ddfindInFrame(i, R_findDotsEnv(rho)); |
1638 | 49.0k | } |
1639 | | |
1640 | | attribute_hidden |
1641 | | SEXP ddfindVar(SEXP symbol, SEXP rho) |
1642 | 49.0k | { |
1643 | 49.0k | int i = ddVal(symbol); |
1644 | 49.0k | return ddfind(i, rho); |
1645 | 49.0k | } |
1646 | | |
1647 | | SEXP R_DotsElt(int i, SEXP env) |
1648 | 5.71k | { |
1649 | 5.71k | SEXP val = ddfindInFrame(i, env); |
1650 | 5.71k | if (TYPEOF(val) == PROMSXP || val == R_MissingArg) |
1651 | 5.71k | return eval(val, env); |
1652 | 0 | else |
1653 | 0 | return val; |
1654 | 5.71k | } |
1655 | | |
1656 | | attribute_hidden SEXP do_dotsElt(SEXP call, SEXP op, SEXP args, SEXP env) |
1657 | 5.71k | { |
1658 | 5.71k | checkArity(op, args); |
1659 | 5.71k | check1arg(args, call, "n"); |
1660 | | |
1661 | 5.71k | SEXP si = CAR(args); |
1662 | 5.71k | if (! isNumeric(si) || XLENGTH(si) != 1) |
1663 | 0 | errorcall(call, _("indexing '...' with an invalid index")); |
1664 | 5.71k | int i = asInteger(si); |
1665 | 5.71k | return R_DotsElt(i, R_findDotsEnv(env)); |
1666 | 5.71k | } |
1667 | | |
1668 | | int R_DotsLength(SEXP env) |
1669 | 25.3k | { |
1670 | 25.3k | SEXP vl = R_findVarInFrame(env, R_DotsSymbol); |
1671 | 25.3k | if (vl == R_UnboundValue) |
1672 | 0 | error(_("incorrect context: the current call has no '...' to look in")); |
1673 | 25.3k | return length_DOTS(vl); |
1674 | 25.3k | } |
1675 | | |
1676 | | attribute_hidden SEXP do_dotsLength(SEXP call, SEXP op, SEXP args, SEXP env) |
1677 | 25.3k | { |
1678 | 25.3k | checkArity(op, args); |
1679 | 25.3k | return ScalarInteger(R_DotsLength(R_findDotsEnv(env))); |
1680 | 25.3k | } |
1681 | | |
1682 | | SEXP R_DotsNames(SEXP env) |
1683 | 240 | { |
1684 | 240 | SEXP vl = R_findVarInFrame(env, R_DotsSymbol); |
1685 | 240 | PROTECT(vl); |
1686 | 240 | if (vl == R_UnboundValue) |
1687 | 0 | error(_("incorrect context: the current call has no '...' to look in")); |
1688 | 240 | SEXP out = R_NilValue; |
1689 | 240 | int n = length_DOTS(vl); |
1690 | 420 | for(int i = 0; i < n; i++) { |
1691 | 180 | if(TAG(vl) != R_NilValue) { |
1692 | 180 | if(out == R_NilValue) { |
1693 | | // this fills 'out' with "" |
1694 | 180 | PROTECT(out = allocVector(STRSXP, n)); |
1695 | 180 | } |
1696 | 180 | SET_STRING_ELT(out, i, PRINTNAME(TAG(vl))); |
1697 | 180 | } |
1698 | 180 | vl = CDR(vl); |
1699 | 180 | } |
1700 | 240 | if(out != R_NilValue) |
1701 | 180 | UNPROTECT(1); // out |
1702 | 240 | UNPROTECT(1); // vl |
1703 | 240 | return out; |
1704 | 240 | } |
1705 | | |
1706 | | attribute_hidden SEXP do_dotsNames(SEXP call, SEXP op, SEXP args, SEXP env) |
1707 | 240 | { |
1708 | 240 | checkArity(op, args); |
1709 | 240 | return R_DotsNames(R_findDotsEnv(env)); |
1710 | 240 | } |
1711 | | |
1712 | | R_DotType_t R_GetDotType(int i, SEXP env) |
1713 | 0 | { |
1714 | 0 | SEXP value = ddfindInFrame(i, env); |
1715 | |
|
1716 | 0 | if (value == R_MissingArg) |
1717 | 0 | return R_DotTypeMissing; |
1718 | | |
1719 | 0 | if (TYPEOF(value) == PROMSXP) { |
1720 | 0 | Rboolean forced; |
1721 | 0 | promiseUnwrap(value, &forced); |
1722 | 0 | if (forced) |
1723 | 0 | return R_DotTypeForced; |
1724 | 0 | else |
1725 | 0 | return R_DotTypeDelayed; |
1726 | 0 | } |
1727 | | |
1728 | 0 | return R_DotTypeValue; |
1729 | 0 | } |
1730 | | |
1731 | | SEXP R_DotDelayedExpression(int i, SEXP env) |
1732 | 0 | { |
1733 | 0 | SEXP value = ddfindInFrame(i, env); |
1734 | 0 | if (TYPEOF(value) != PROMSXP) |
1735 | 0 | error(_("not a delayed ... element")); |
1736 | |
|
1737 | 0 | Rboolean forced; |
1738 | 0 | SEXP inner = promiseUnwrap(value, &forced); |
1739 | 0 | if (forced) |
1740 | 0 | error(_("not a delayed ... element")); |
1741 | |
|
1742 | 0 | return R_PromiseExpr(inner); |
1743 | 0 | } |
1744 | | |
1745 | | SEXP R_DotDelayedEnvironment(int i, SEXP env) |
1746 | 0 | { |
1747 | 0 | SEXP value = ddfindInFrame(i, env); |
1748 | 0 | if (TYPEOF(value) != PROMSXP) |
1749 | 0 | error(_("not a delayed ... element")); |
1750 | |
|
1751 | 0 | Rboolean forced; |
1752 | 0 | SEXP inner = promiseUnwrap(value, &forced); |
1753 | 0 | if (forced) |
1754 | 0 | error(_("not a delayed ... element")); |
1755 | |
|
1756 | 0 | return PRENV(inner); |
1757 | 0 | } |
1758 | | |
1759 | | SEXP R_DotForcedExpression(int i, SEXP env) |
1760 | 0 | { |
1761 | 0 | SEXP value = ddfindInFrame(i, env); |
1762 | 0 | if (TYPEOF(value) != PROMSXP) |
1763 | 0 | error(_("not a forced ... element")); |
1764 | |
|
1765 | 0 | Rboolean forced; |
1766 | 0 | SEXP inner = promiseUnwrap(value, &forced); |
1767 | 0 | if (!forced) |
1768 | 0 | error(_("not a forced ... element")); |
1769 | |
|
1770 | 0 | return R_PromiseExpr(inner); |
1771 | 0 | } |
1772 | | |
1773 | | attribute_hidden SEXP do_dotType(SEXP call, SEXP op, SEXP args, SEXP rho) |
1774 | 0 | { |
1775 | 0 | checkArity(op, args); |
1776 | 0 | int i = asInteger(CAR(args)); |
1777 | 0 | SEXP env = resolveDotsEnv(CADR(args), asLogical(CADDR(args))); |
1778 | 0 | switch(R_GetDotType(i, env)) { |
1779 | 0 | case R_DotTypeValue: return mkString("value"); |
1780 | 0 | case R_DotTypeMissing: return mkString("missing"); |
1781 | 0 | case R_DotTypeDelayed: return mkString("delayed"); |
1782 | 0 | case R_DotTypeForced: return mkString("forced"); |
1783 | 0 | default: error("unknown dot type; should not happen"); |
1784 | 0 | } |
1785 | 0 | } |
1786 | | |
1787 | | attribute_hidden SEXP do_dotDelayedExpr(SEXP call, SEXP op, SEXP args, SEXP rho) |
1788 | 0 | { |
1789 | 0 | checkArity(op, args); |
1790 | 0 | int i = asInteger(CAR(args)); |
1791 | 0 | SEXP env = resolveDotsEnv(CADR(args), asLogical(CADDR(args))); |
1792 | 0 | return R_DotDelayedExpression(i, env); |
1793 | 0 | } |
1794 | | |
1795 | | attribute_hidden SEXP do_dotDelayedEnv(SEXP call, SEXP op, SEXP args, SEXP rho) |
1796 | 0 | { |
1797 | 0 | checkArity(op, args); |
1798 | 0 | int i = asInteger(CAR(args)); |
1799 | 0 | SEXP env = resolveDotsEnv(CADR(args), asLogical(CADDR(args))); |
1800 | 0 | return R_DotDelayedEnvironment(i, env); |
1801 | 0 | } |
1802 | | |
1803 | | attribute_hidden SEXP do_dotForcedExpr(SEXP call, SEXP op, SEXP args, SEXP rho) |
1804 | 0 | { |
1805 | 0 | checkArity(op, args); |
1806 | 0 | int i = asInteger(CAR(args)); |
1807 | 0 | SEXP env = resolveDotsEnv(CADR(args), asLogical(CADDR(args))); |
1808 | 0 | return R_DotForcedExpression(i, env); |
1809 | 0 | } |
1810 | | |
1811 | | /* .Internal wrappers for dots accessors taking explicit `env` and `inherits` */ |
1812 | | |
1813 | | attribute_hidden SEXP do_CDotsLength(SEXP call, SEXP op, SEXP args, SEXP rho) |
1814 | 0 | { |
1815 | 0 | checkArity(op, args); |
1816 | 0 | SEXP env = resolveDotsEnv(CAR(args), asLogical(CADR(args))); |
1817 | 0 | return ScalarInteger(R_DotsLength(env)); |
1818 | 0 | } |
1819 | | |
1820 | | attribute_hidden SEXP do_CDotsNames(SEXP call, SEXP op, SEXP args, SEXP rho) |
1821 | 0 | { |
1822 | 0 | checkArity(op, args); |
1823 | 0 | SEXP env = resolveDotsEnv(CAR(args), asLogical(CADR(args))); |
1824 | 0 | return R_DotsNames(env); |
1825 | 0 | } |
1826 | | |
1827 | | attribute_hidden SEXP do_CDotsElt(SEXP call, SEXP op, SEXP args, SEXP rho) |
1828 | 0 | { |
1829 | 0 | checkArity(op, args); |
1830 | 0 | int i = asInteger(CAR(args)); |
1831 | 0 | SEXP env = resolveDotsEnv(CADR(args), asLogical(CADDR(args))); |
1832 | 0 | return R_DotsElt(i, env); |
1833 | 0 | } |
1834 | | |
1835 | | #undef length_DOTS |
1836 | | |
1837 | | /*---------------------------------------------------------------------- |
1838 | | |
1839 | | dynamicfindVar |
1840 | | |
1841 | | This function does a variable lookup, but uses dynamic scoping rules |
1842 | | rather than the lexical scoping rules used in findVar. |
1843 | | |
1844 | | Return R_UnboundValue if the symbol isn't located and the calling |
1845 | | function needs to handle the errors. |
1846 | | |
1847 | | */ |
1848 | | |
1849 | | #ifdef UNUSED |
1850 | | SEXP dynamicfindVar(SEXP symbol, RCNTXT *cptr) |
1851 | | { |
1852 | | SEXP vl; |
1853 | | while (cptr != R_ToplevelContext) { |
1854 | | if (cptr->callflag & CTXT_FUNCTION) { |
1855 | | vl = R_findVarInFrame(cptr->cloenv, symbol); |
1856 | | if (vl != R_UnboundValue) return vl; |
1857 | | } |
1858 | | cptr = cptr->nextcontext; |
1859 | | } |
1860 | | return R_UnboundValue; |
1861 | | } |
1862 | | #endif |
1863 | | |
1864 | | |
1865 | | |
1866 | | /*---------------------------------------------------------------------- |
1867 | | |
1868 | | findFun |
1869 | | |
1870 | | Search for a function in an environment This is a specially modified |
1871 | | version of findVar which ignores values its finds if they are not |
1872 | | functions. |
1873 | | |
1874 | | [ NEEDED: This needs to be modified so that a search for an arbitrary mode can |
1875 | | be made. Then findVar and findFun could become same function.] |
1876 | | |
1877 | | This could call findVar1. NB: they behave differently on failure. |
1878 | | */ |
1879 | | |
1880 | | attribute_hidden |
1881 | | SEXP findFun3(SEXP symbol, SEXP rho, SEXP call) |
1882 | 8.62M | { |
1883 | 8.62M | SEXP vl; |
1884 | | |
1885 | | /* If the symbol is marked as special, skip to the first |
1886 | | environment that might contain such a symbol. */ |
1887 | 8.62M | if (IS_SPECIAL_SYMBOL(symbol)) { |
1888 | 1.98M | while (rho != R_EmptyEnv && NO_SPECIAL_SYMBOLS(rho)) |
1889 | 998k | rho = ENCLOS(rho); |
1890 | 982k | } |
1891 | | |
1892 | 16.6M | while (rho != R_EmptyEnv) { |
1893 | | /* This is not really right. Any variable can mask a function */ |
1894 | 16.6M | #ifdef USE_GLOBAL_CACHE |
1895 | 16.6M | if (rho == R_GlobalEnv) |
1896 | 38.0k | #ifdef FAST_BASE_CACHE_LOOKUP |
1897 | 38.0k | if (BASE_SYM_CACHED(symbol)) |
1898 | 36.0k | vl = SYMBOL_BINDING_VALUE(symbol); |
1899 | 1.92k | else |
1900 | 1.92k | vl = findGlobalVar(symbol); |
1901 | | #else |
1902 | | vl = findGlobalVar(symbol); |
1903 | | #endif |
1904 | 16.6M | else |
1905 | 16.6M | vl = R_findVarInFrame(rho, symbol); |
1906 | | #else |
1907 | | vl = R_findVarInFrame(rho, symbol); |
1908 | | #endif |
1909 | 16.6M | if (vl != R_UnboundValue) { |
1910 | 8.62M | if (TYPEOF(vl) == PROMSXP) { |
1911 | 3.60M | if (PROMISE_IS_EVALUATED(vl)) |
1912 | 3.59M | vl = PRVALUE(vl); |
1913 | 2.49k | else { |
1914 | 2.49k | PROTECT(vl); |
1915 | 2.49k | vl = eval(vl, rho); |
1916 | 2.49k | UNPROTECT(1); |
1917 | 2.49k | } |
1918 | 3.60M | } |
1919 | 8.62M | if (TYPEOF(vl) == CLOSXP || TYPEOF(vl) == BUILTINSXP || |
1920 | 1.02M | TYPEOF(vl) == SPECIALSXP) |
1921 | 8.62M | return (vl); |
1922 | 84 | if (vl == R_MissingArg) |
1923 | 0 | R_MissingArgError(symbol, call, "getMissingError"); |
1924 | | |
1925 | 84 | } |
1926 | 8.01M | rho = ENCLOS(rho); |
1927 | 8.01M | } |
1928 | 0 | R_FunctionNotFoundError(symbol, call); |
1929 | | /* NOT REACHED */ |
1930 | 0 | return R_UnboundValue; |
1931 | 8.62M | } |
1932 | | |
1933 | | SEXP findFun(SEXP symbol, SEXP rho) |
1934 | 6.79M | { |
1935 | 6.79M | return findFun3(symbol, rho, R_CurrentExpression); |
1936 | 6.79M | } |
1937 | | |
1938 | | /*---------------------------------------------------------------------- |
1939 | | |
1940 | | defineVar |
1941 | | |
1942 | | Assign a value in a specific environment frame. |
1943 | | |
1944 | | */ |
1945 | | |
1946 | | void defineVar(SEXP symbol, SEXP value, SEXP rho) |
1947 | 10.2M | { |
1948 | 10.2M | int hashcode; |
1949 | 10.2M | SEXP frame, c; |
1950 | | |
1951 | 10.2M | if (value == R_UnboundValue) |
1952 | 0 | error("attempt to bind a variable to R_UnboundValue"); |
1953 | | /* R_DirtyImage should only be set if assigning to R_GlobalEnv. */ |
1954 | 10.2M | if (rho == R_GlobalEnv) R_DirtyImage = 1; |
1955 | | |
1956 | 10.2M | if (rho == R_EmptyEnv) |
1957 | 0 | error(_("cannot assign values in the empty environment")); |
1958 | | |
1959 | 10.2M | if(IS_USER_DATABASE(rho)) { |
1960 | 0 | R_ObjectTable *table; |
1961 | 0 | table = (R_ObjectTable *) R_ExternalPtrAddr(HASHTAB(rho)); |
1962 | 0 | if(table->assign == NULL) |
1963 | 0 | error(_("cannot assign variables to this database")); |
1964 | 0 | PROTECT(value); |
1965 | 0 | table->assign(CHAR(PRINTNAME(symbol)), value, table); |
1966 | 0 | UNPROTECT(1); |
1967 | 0 | #ifdef USE_GLOBAL_CACHE |
1968 | 0 | if (IS_GLOBAL_FRAME(rho)) R_FlushGlobalCache(symbol); |
1969 | 0 | #endif |
1970 | 0 | return; |
1971 | 0 | } |
1972 | | |
1973 | 10.2M | if (rho == R_BaseNamespace || rho == R_BaseEnv) { |
1974 | 14.5k | gsetVar(symbol, value, rho); |
1975 | 10.2M | } else { |
1976 | 10.2M | #ifdef USE_GLOBAL_CACHE |
1977 | 10.2M | if (IS_GLOBAL_FRAME(rho)) R_FlushGlobalCache(symbol); |
1978 | 10.2M | #endif |
1979 | | |
1980 | 10.2M | if (IS_SPECIAL_SYMBOL(symbol)) |
1981 | 612 | UNSET_NO_SPECIAL_SYMBOLS(rho); |
1982 | | |
1983 | 10.2M | if (HASHTAB(rho) == R_NilValue) { |
1984 | | /* First check for an existing binding */ |
1985 | 10.1M | frame = FRAME(rho); |
1986 | 51.3M | while (frame != R_NilValue) { |
1987 | 41.8M | if (TAG(frame) == symbol) { |
1988 | 609k | SET_BINDING_VALUE(frame, value); |
1989 | 609k | SET_MISSING(frame, 0); /* Over-ride */ |
1990 | 609k | return; |
1991 | 609k | } |
1992 | 41.2M | frame = CDR(frame); |
1993 | 41.2M | } |
1994 | 9.53M | if (FRAME_IS_LOCKED(rho)) |
1995 | 0 | error(_("cannot add bindings to a locked environment")); |
1996 | 9.53M | SET_FRAME(rho, CONS(value, FRAME(rho))); |
1997 | 9.53M | SET_TAG(FRAME(rho), symbol); |
1998 | 9.53M | } |
1999 | 119k | else { |
2000 | 119k | c = PRINTNAME(symbol); |
2001 | 119k | if( !HASHASH(c) ) { |
2002 | 0 | SET_HASHVALUE(c, R_Newhashpjw(CHAR(c))); |
2003 | 0 | SET_HASHASH(c, 1); |
2004 | 0 | } |
2005 | 119k | hashcode = HASHVALUE(c) % HASHSIZE(HASHTAB(rho)); |
2006 | 119k | R_HashSet(hashcode, symbol, HASHTAB(rho), value, |
2007 | 119k | (Rboolean) FRAME_IS_LOCKED(rho)); |
2008 | 119k | if (R_HashSizeCheck(HASHTAB(rho))) |
2009 | 3.54k | SET_HASHTAB(rho, R_HashResize(HASHTAB(rho))); |
2010 | 119k | } |
2011 | 10.2M | } |
2012 | 10.2M | } |
2013 | | |
2014 | | /*---------------------------------------------------------------------- |
2015 | | |
2016 | | addMissingVarsToNewEnv |
2017 | | |
2018 | | Add given variables (addVars - list) to given environment (env) unless |
2019 | | they are already there. Env is a "new" environment, created by |
2020 | | NewEnvironment, as in applyClosure (so it list-based). Slots for vars are |
2021 | | re-used. The addVars list itself can have duplicit variables. |
2022 | | |
2023 | | The implementation is performance optimized towards the common case that |
2024 | | the variables from addVars are not present in env and that addVars does |
2025 | | not have duplicit variables. |
2026 | | */ |
2027 | | |
2028 | | attribute_hidden |
2029 | | void addMissingVarsToNewEnv(SEXP env, SEXP addVars) |
2030 | 144k | { |
2031 | 144k | if (addVars == R_NilValue) return; |
2032 | | |
2033 | | /* temporary sanity check */ |
2034 | 144k | if (TYPEOF(addVars) == ENVSXP) |
2035 | 0 | error("additional variables should now be passed as a list, " |
2036 | 0 | "not in an environment"); |
2037 | | |
2038 | | /* append variables from env after addVars */ |
2039 | 144k | SEXP aprev = addVars; |
2040 | 144k | SEXP a = CDR(addVars); |
2041 | 868k | while (a != R_NilValue) { |
2042 | 723k | aprev = a; |
2043 | 723k | a = CDR(a); |
2044 | 723k | } |
2045 | 144k | SETCDR(aprev, FRAME(env)); |
2046 | 144k | SET_FRAME(env, addVars); |
2047 | | |
2048 | | /* remove duplicates - a variable listed later has precedence over a |
2049 | | variable listed sooner */ |
2050 | 144k | SEXP end; |
2051 | 1.17M | for(end = CDR(addVars); end != R_NilValue; end = CDR(end)) { |
2052 | 1.02M | SEXP endTag = TAG(end); |
2053 | 1.02M | SEXP sprev = R_NilValue; |
2054 | 1.02M | SEXP s; |
2055 | 5.29M | for(s = addVars; s != end; s = CDR(s)) { |
2056 | 4.26M | if (TAG(s) == endTag) { |
2057 | | /* remove variable s from the list, because it is overridden by "end" */ |
2058 | 0 | if (sprev == R_NilValue) { |
2059 | 0 | addVars = CDR(s); |
2060 | 0 | SET_FRAME(env, addVars); |
2061 | 0 | } else |
2062 | 0 | SETCDR(sprev, CDR(s)); |
2063 | 0 | } else |
2064 | 4.26M | sprev = s; |
2065 | 4.26M | } |
2066 | 1.02M | } |
2067 | 144k | } |
2068 | | |
2069 | | /*---------------------------------------------------------------------- |
2070 | | |
2071 | | setVarInFrame |
2072 | | |
2073 | | Assign a new value to an existing symbol in a frame. |
2074 | | Return the symbol if successful and R_NilValue if not. |
2075 | | |
2076 | | [ Taken static in 2.4.0: not called for emptyenv or baseenv. ] |
2077 | | */ |
2078 | | |
2079 | | static SEXP setVarInFrame(SEXP rho, SEXP symbol, SEXP value) |
2080 | 17.4k | { |
2081 | 17.4k | int hashcode; |
2082 | 17.4k | SEXP frame, c; |
2083 | | |
2084 | | /* R_DirtyImage should only be set if assigning to R_GlobalEnv. */ |
2085 | 17.4k | if (rho == R_GlobalEnv) R_DirtyImage = 1; |
2086 | 17.4k | if (rho == R_EmptyEnv) return R_NilValue; |
2087 | | |
2088 | 17.4k | if(IS_USER_DATABASE(rho)) { |
2089 | | /* FIXME: This does not behave as described */ |
2090 | 0 | R_ObjectTable *table; |
2091 | 0 | table = (R_ObjectTable *) R_ExternalPtrAddr(HASHTAB(rho)); |
2092 | 0 | if(table->assign == NULL) |
2093 | 0 | error(_("cannot assign variables to this database")); |
2094 | 0 | PROTECT(value); |
2095 | 0 | SEXP result = table->assign(CHAR(PRINTNAME(symbol)), value, table); |
2096 | 0 | UNPROTECT(1); |
2097 | 0 | return(result); |
2098 | 0 | } |
2099 | | |
2100 | 17.4k | if (rho == R_BaseNamespace || rho == R_BaseEnv) { |
2101 | 0 | if (SYMVALUE(symbol) == R_UnboundValue) return R_NilValue; |
2102 | 0 | SET_SYMBOL_BINDING_VALUE(symbol, value); |
2103 | 0 | return symbol; |
2104 | 0 | } |
2105 | | |
2106 | 17.4k | if (HASHTAB(rho) == R_NilValue) { |
2107 | 17.3k | frame = FRAME(rho); |
2108 | 48.2k | while (frame != R_NilValue) { |
2109 | 40.0k | if (TAG(frame) == symbol) { |
2110 | 9.09k | SET_BINDING_VALUE(frame, value); |
2111 | 9.09k | SET_MISSING(frame, 0); /* same as defineVar */ |
2112 | 9.09k | return symbol; |
2113 | 9.09k | } |
2114 | 30.9k | frame = CDR(frame); |
2115 | 30.9k | } |
2116 | 17.3k | } else { |
2117 | | /* Do the hash table thing */ |
2118 | 108 | c = PRINTNAME(symbol); |
2119 | 108 | if( !HASHASH(c) ) { |
2120 | 0 | SET_HASHVALUE(c, R_Newhashpjw(CHAR(c))); |
2121 | 0 | SET_HASHASH(c, 1); |
2122 | 0 | } |
2123 | 108 | hashcode = HASHVALUE(c) % HASHSIZE(HASHTAB(rho)); |
2124 | 108 | frame = R_HashGetLoc(hashcode, symbol, HASHTAB(rho)); |
2125 | 108 | if (frame != R_NilValue) { |
2126 | 108 | SET_BINDING_VALUE(frame, value); |
2127 | 108 | SET_MISSING(frame, 0); /* same as defineVar */ |
2128 | 108 | return symbol; |
2129 | 108 | } |
2130 | 108 | } |
2131 | 8.20k | return R_NilValue; /* -Wall */ |
2132 | 17.4k | } |
2133 | | |
2134 | | |
2135 | | /*---------------------------------------------------------------------- |
2136 | | |
2137 | | setVar |
2138 | | |
2139 | | Assign a new value to bound symbol. Note this does the "inherits" |
2140 | | case. I.e. it searches frame-by-frame for a symbol and binds the |
2141 | | given value to the first symbol encountered. If no symbol is |
2142 | | found then a binding is created in the global environment. |
2143 | | |
2144 | | Changed in R 2.4.0 to look in the base environment (previously the |
2145 | | search stopped befor the base environment, but would (and still |
2146 | | does) assign into the base namespace if that is on the search and |
2147 | | the symbol existed there). |
2148 | | |
2149 | | */ |
2150 | | |
2151 | | void setVar(SEXP symbol, SEXP value, SEXP rho) |
2152 | 9.20k | { |
2153 | 9.20k | SEXP vl; |
2154 | 17.4k | while (rho != R_EmptyEnv) { |
2155 | 17.4k | vl = setVarInFrame(rho, symbol, value); |
2156 | 17.4k | if (vl != R_NilValue) return; |
2157 | 8.20k | rho = ENCLOS(rho); |
2158 | 8.20k | } |
2159 | 0 | defineVar(symbol, value, R_GlobalEnv); |
2160 | 0 | } |
2161 | | |
2162 | | |
2163 | | |
2164 | | /*---------------------------------------------------------------------- |
2165 | | |
2166 | | gsetVar |
2167 | | |
2168 | | Assignment in the base environment. Here we assign directly into |
2169 | | the base environment. |
2170 | | |
2171 | | */ |
2172 | | |
2173 | | void gsetVar(SEXP symbol, SEXP value, SEXP rho) |
2174 | 14.6k | { |
2175 | 14.6k | if (FRAME_IS_LOCKED(rho)) { |
2176 | 0 | if(SYMVALUE(symbol) == R_UnboundValue) |
2177 | 0 | error(_("cannot add binding of '%s' to the base environment"), |
2178 | 0 | CHAR(PRINTNAME(symbol))); |
2179 | 0 | } |
2180 | 14.6k | #ifdef USE_GLOBAL_CACHE |
2181 | 14.6k | R_FlushGlobalCache(symbol); |
2182 | 14.6k | #endif |
2183 | 14.6k | SET_SYMBOL_BINDING_VALUE(symbol, value); |
2184 | 14.6k | } |
2185 | | |
2186 | | /* get environment from a subclass if possible; else return NULL */ |
2187 | 0 | #define simple_as_environment(arg) (IS_S4_OBJECT(arg) && (TYPEOF(arg) == OBJSXP) ? R_getS4DataSlot(arg, ENVSXP) : R_NilValue) |
2188 | | |
2189 | | |
2190 | | |
2191 | | /*---------------------------------------------------------------------- |
2192 | | |
2193 | | do_assign : .Internal(assign(x, value, envir, inherits)) |
2194 | | |
2195 | | */ |
2196 | | attribute_hidden SEXP do_assign(SEXP call, SEXP op, SEXP args, SEXP rho) |
2197 | 624 | { |
2198 | 624 | SEXP name=R_NilValue, val, aenv; |
2199 | 624 | int ginherits = 0; |
2200 | 624 | checkArity(op, args); |
2201 | | |
2202 | 624 | if (!isString(CAR(args)) || length(CAR(args)) == 0) |
2203 | 0 | error(_("invalid first argument")); |
2204 | 624 | else { |
2205 | 624 | if (length(CAR(args)) > 1) |
2206 | 0 | warning(_("only the first element is used as variable name")); |
2207 | 624 | name = installTrChar(STRING_ELT(CAR(args), 0)); |
2208 | 624 | } |
2209 | 624 | PROTECT(val = CADR(args)); |
2210 | 624 | aenv = CADDR(args); |
2211 | 624 | if (TYPEOF(aenv) == NILSXP) |
2212 | 0 | error(_("use of NULL environment is defunct")); |
2213 | 624 | if (TYPEOF(aenv) != ENVSXP && |
2214 | 0 | TYPEOF((aenv = simple_as_environment(aenv))) != ENVSXP) |
2215 | 0 | error(_("invalid '%s' argument"), "envir"); |
2216 | 624 | ginherits = asLogical(CADDDR(args)); |
2217 | 624 | if (ginherits == NA_LOGICAL) |
2218 | 0 | error(_("invalid '%s' argument"), "inherits"); |
2219 | 624 | if (ginherits) |
2220 | 0 | setVar(name, val, aenv); |
2221 | 624 | else |
2222 | 624 | defineVar(name, val, aenv); |
2223 | 624 | UNPROTECT(1); |
2224 | 624 | return val; |
2225 | 624 | } |
2226 | | |
2227 | | |
2228 | | /** |
2229 | | * do_list2env : .Internal(list2env(x, envir)) |
2230 | | */ |
2231 | | attribute_hidden SEXP do_list2env(SEXP call, SEXP op, SEXP args, SEXP rho) |
2232 | 3.62k | { |
2233 | 3.62k | SEXP x, xnms, envir; |
2234 | 3.62k | int n; |
2235 | 3.62k | checkArity(op, args); |
2236 | | |
2237 | 3.62k | if (TYPEOF(CAR(args)) != VECSXP) |
2238 | 0 | error(_("first argument must be a named list")); |
2239 | 3.62k | x = CAR(args); |
2240 | 3.62k | n = LENGTH(x); |
2241 | 3.62k | xnms = getAttrib(x, R_NamesSymbol); |
2242 | 3.62k | PROTECT(xnms); |
2243 | 3.62k | if (n && (TYPEOF(xnms) != STRSXP || LENGTH(xnms) != n)) |
2244 | 0 | error(_("names(x) must be a character vector of the same length as x")); |
2245 | 3.62k | envir = CADR(args); |
2246 | 3.62k | if (TYPEOF(envir) != ENVSXP) |
2247 | 0 | error(_("'envir' argument must be an environment")); |
2248 | | |
2249 | 44.0k | for(int i = 0; i < n; i++) { |
2250 | 40.4k | SEXP name = installTrChar(STRING_ELT(xnms, i)); |
2251 | 40.4k | defineVar(name, lazy_duplicate(VECTOR_ELT(x, i)), envir); |
2252 | 40.4k | } |
2253 | 3.62k | UNPROTECT(1); /* xnms */ |
2254 | | |
2255 | 3.62k | return envir; |
2256 | 3.62k | } |
2257 | | |
2258 | | |
2259 | | /*---------------------------------------------------------------------- |
2260 | | |
2261 | | do_remove |
2262 | | |
2263 | | There are three arguments to do_remove; a list of names to remove, |
2264 | | an optional environment (if missing set it to R_GlobalEnv) and |
2265 | | inherits, a logical indicating whether to look in the parent env if |
2266 | | a symbol is not found in the supplied env. This is ignored if |
2267 | | environment is not specified. |
2268 | | |
2269 | | */ |
2270 | | |
2271 | | static int RemoveVariable(SEXP name, int hashcode, SEXP env) |
2272 | 12 | { |
2273 | 12 | int found; |
2274 | 12 | SEXP list; |
2275 | | |
2276 | 12 | if (env == R_BaseNamespace) |
2277 | 0 | error(_("cannot remove variables from base namespace")); |
2278 | 12 | if (env == R_BaseEnv) |
2279 | 0 | error(_("cannot remove variables from the base environment")); |
2280 | 12 | if (env == R_EmptyEnv) |
2281 | 0 | error(_("cannot remove variables from the empty environment")); |
2282 | 12 | if (FRAME_IS_LOCKED(env)) |
2283 | 0 | error(_("cannot remove bindings from a locked environment")); |
2284 | | |
2285 | 12 | if(IS_USER_DATABASE(env)) { |
2286 | 0 | R_ObjectTable *table; |
2287 | 0 | table = (R_ObjectTable *) R_ExternalPtrAddr(HASHTAB(env)); |
2288 | 0 | if(table->remove == NULL) |
2289 | 0 | error(_("cannot remove variables from this database")); |
2290 | 0 | return(table->remove(CHAR(PRINTNAME(name)), table)); |
2291 | 0 | } |
2292 | | |
2293 | 12 | if (IS_HASHED(env)) { |
2294 | 12 | R_HashDelete(hashcode, name, env, &found); |
2295 | 12 | #ifdef USE_GLOBAL_CACHE |
2296 | 12 | if (found && IS_GLOBAL_FRAME(env)) |
2297 | 12 | R_FlushGlobalCache(name); |
2298 | 12 | #endif |
2299 | 12 | } else { |
2300 | 0 | list = RemoveFromList(name, FRAME(env), &found); |
2301 | 0 | if (found) { |
2302 | 0 | if(env == R_GlobalEnv) R_DirtyImage = 1; |
2303 | 0 | SET_FRAME(env, list); |
2304 | 0 | #ifdef USE_GLOBAL_CACHE |
2305 | 0 | if (IS_GLOBAL_FRAME(env)) |
2306 | 0 | R_FlushGlobalCache(name); |
2307 | 0 | #endif |
2308 | 0 | } |
2309 | 0 | } |
2310 | 12 | return found; |
2311 | 12 | } |
2312 | | |
2313 | | attribute_hidden SEXP do_remove(SEXP call, SEXP op, SEXP args, SEXP rho) |
2314 | 0 | { |
2315 | | /* .Internal(remove(list, envir, inherits)) */ |
2316 | |
|
2317 | 0 | checkArity(op, args); |
2318 | |
|
2319 | 0 | SEXP name = CAR(args); |
2320 | 0 | if(TYPEOF(name) == NILSXP) return R_NilValue; |
2321 | 0 | if (!isString(name)) |
2322 | 0 | error(_("invalid first argument")); |
2323 | 0 | args = CDR(args); |
2324 | |
|
2325 | 0 | SEXP envarg = CAR(args); |
2326 | 0 | if (TYPEOF(envarg) == NILSXP) |
2327 | 0 | error(_("use of NULL environment is defunct")); |
2328 | 0 | if (TYPEOF(envarg) != ENVSXP && |
2329 | 0 | TYPEOF((envarg = simple_as_environment(envarg))) != ENVSXP) |
2330 | 0 | error(_("invalid '%s' argument"), "envir"); |
2331 | 0 | args = CDR(args); |
2332 | |
|
2333 | 0 | int ginherits = asLogical(CAR(args)); |
2334 | 0 | if (ginherits == NA_LOGICAL) |
2335 | 0 | error(_("invalid '%s' argument"), "inherits"); |
2336 | |
|
2337 | 0 | for (int i = 0, done = 0; i < LENGTH(name); i++) { |
2338 | 0 | SEXP tsym = installTrChar(STRING_ELT(name, i)); |
2339 | 0 | int hashcode; |
2340 | 0 | if( !HASHASH(PRINTNAME(tsym)) ) |
2341 | 0 | hashcode = R_Newhashpjw(CHAR(PRINTNAME(tsym))); |
2342 | 0 | else |
2343 | 0 | hashcode = HASHVALUE(PRINTNAME(tsym)); |
2344 | 0 | SEXP tenv = envarg; |
2345 | 0 | while (tenv != R_EmptyEnv) { |
2346 | 0 | done = RemoveVariable(tsym, hashcode, tenv); |
2347 | 0 | if (done || !ginherits) |
2348 | 0 | break; |
2349 | 0 | tenv = CDR(tenv); |
2350 | 0 | } |
2351 | 0 | if (!done) |
2352 | 0 | warning(_("object '%s' not found"), EncodeChar(PRINTNAME(tsym))); |
2353 | 0 | } |
2354 | 0 | return R_NilValue; |
2355 | 0 | } |
2356 | | |
2357 | | void R_removeVarFromFrame(SEXP name, SEXP env) |
2358 | 12 | { |
2359 | 12 | int hashcode = -1; |
2360 | | |
2361 | 12 | if (TYPEOF(env) == NILSXP) |
2362 | 0 | error(_("use of NULL environment is defunct")); |
2363 | | |
2364 | 12 | if (!isEnvironment(env)) |
2365 | 0 | error(_("argument to '%s' is not an environment"), "R_removeVarFromFrame"); |
2366 | | |
2367 | 12 | if (TYPEOF(name) != SYMSXP) |
2368 | 0 | error(_("not a symbol")); |
2369 | | |
2370 | 12 | if (IS_HASHED(env)) { |
2371 | 12 | if( !HASHASH(PRINTNAME(name))) |
2372 | 0 | hashcode = R_Newhashpjw(CHAR(PRINTNAME(name))); |
2373 | 12 | else |
2374 | 12 | hashcode = HASHVALUE(PRINTNAME(name)); |
2375 | 12 | } |
2376 | 12 | RemoveVariable(name, hashcode, env); |
2377 | 12 | } |
2378 | | |
2379 | | |
2380 | | /*---------------------------------------------------------------------- |
2381 | | |
2382 | | do_get |
2383 | | |
2384 | | This function returns the SEXP associated with the character |
2385 | | argument. It needs the environment of the calling function as a |
2386 | | default. |
2387 | | |
2388 | | exists (x, envir, mode, inherits) |
2389 | | get (x, envir, mode, inherits) |
2390 | | get0 (x, envir, mode, inherits, value_if_not_exists) |
2391 | | */ |
2392 | | |
2393 | | static SEXPTYPE str2mode(const char *modestr, Rboolean *pS4) |
2394 | 187k | { |
2395 | 187k | if (!strcmp(modestr, "function")) |
2396 | 276 | return FUNSXP; |
2397 | 186k | else if (!strcmp(modestr, "S4")) { |
2398 | 0 | if (pS4 != NULL) |
2399 | 0 | *pS4 = TRUE; |
2400 | 0 | return OBJSXP; |
2401 | 0 | } |
2402 | 186k | else { |
2403 | 186k | SEXPTYPE gmode = str2type(modestr); |
2404 | 186k | if(gmode == (SEXPTYPE) (-1)) |
2405 | 0 | error(_("invalid '%s' argument '%s'"), "mode", modestr); |
2406 | 186k | return gmode; |
2407 | 186k | } |
2408 | 187k | } |
2409 | | |
2410 | | attribute_hidden SEXP do_get(SEXP call, SEXP op, SEXP args, SEXP rho) |
2411 | 168k | { |
2412 | 168k | SEXP rval, genv, t1 = R_NilValue; |
2413 | 168k | int ginherits = 0, where; |
2414 | 168k | checkArity(op, args); |
2415 | | |
2416 | | /* The first arg is the object name */ |
2417 | | /* It must be present and a non-empty string */ |
2418 | | |
2419 | 168k | if (TYPEOF(CAR(args)) == SYMSXP) |
2420 | 0 | t1 = CAR(args); |
2421 | 168k | else if (isValidStringF(CAR(args))) { |
2422 | 168k | if (XLENGTH(CAR(args)) > 1) |
2423 | 0 | error(_("first argument has length > 1")); |
2424 | 168k | t1 = installTrChar(STRING_ELT(CAR(args), 0)); |
2425 | 168k | } |
2426 | 0 | else |
2427 | 0 | error(_("invalid first argument")); |
2428 | | |
2429 | | /* envir : originally, the "where=" argument */ |
2430 | | |
2431 | 168k | if (TYPEOF(CADR(args)) == ENVSXP) |
2432 | 168k | genv = CADR(args); |
2433 | 0 | else if (TYPEOF(CADR(args)) == REALSXP || TYPEOF(CADR(args)) == INTSXP) { |
2434 | 0 | where = asInteger(CADR(args)); |
2435 | 0 | genv = R_sysframe(where, R_GlobalContext); |
2436 | 0 | } |
2437 | 0 | else if (TYPEOF(CADR(args)) == NILSXP) { |
2438 | 0 | error(_("use of NULL environment is defunct")); |
2439 | 0 | genv = R_NilValue; /* -Wall */ |
2440 | 0 | } |
2441 | 0 | else if(TYPEOF((genv = simple_as_environment(CADR(args)))) != ENVSXP) { |
2442 | 0 | error(_("invalid '%s' argument"), "envir"); |
2443 | 0 | genv = R_NilValue; /* -Wall */ |
2444 | 0 | } |
2445 | | |
2446 | | /* mode : The mode of the object being sought */ |
2447 | | |
2448 | | /* as from R 1.2.0, this is the *mode*, not the *typeof* aka |
2449 | | storage.mode. |
2450 | | */ |
2451 | | |
2452 | 168k | SEXPTYPE gmode; |
2453 | 168k | Rboolean wants_S4 = FALSE; |
2454 | 168k | if (isString(CADDR(args))) |
2455 | 168k | gmode = str2mode(CHAR(STRING_ELT(CADDR(args), 0)), &wants_S4); |
2456 | 0 | else { |
2457 | 0 | error(_("invalid '%s' argument"), "mode"); |
2458 | 0 | gmode = FUNSXP;/* -Wall */ |
2459 | 0 | } |
2460 | | |
2461 | 168k | ginherits = asLogical(CADDDR(args)); |
2462 | 168k | if (ginherits == NA_LOGICAL) |
2463 | 0 | error(_("invalid '%s' argument"), "inherits"); |
2464 | | |
2465 | | /* Search for the object */ |
2466 | 168k | rval = findVar1mode(t1, genv, gmode, wants_S4, ginherits, |
2467 | 168k | (Rboolean) PRIMVAL(op)); |
2468 | 168k | if (rval == R_MissingArg) { // signal a *classed* error: |
2469 | 0 | R_MissingArgError(t1, call, "getMissingError"); |
2470 | 0 | } |
2471 | | |
2472 | 168k | switch (PRIMVAL(op) ) { |
2473 | 12.9k | case 0: // exists(.) : |
2474 | 12.9k | return ScalarLogical(rval != R_UnboundValue); |
2475 | 0 | break; |
2476 | | |
2477 | 5.52k | case 1: // have get(.) |
2478 | 5.52k | if (rval == R_UnboundValue) { |
2479 | 0 | if (gmode == ANYSXP) |
2480 | 0 | R_ObjectNotFoundError(t1, R_CurrentExpression, NULL); |
2481 | 0 | else |
2482 | 0 | R_ObjectNotFoundError(t1, R_CurrentExpression, |
2483 | 0 | CHAR(STRING_ELT(CADDR(args), 0))); /* ASCII */ |
2484 | 0 | } |
2485 | | |
2486 | 6.40k | # define GET_VALUE(rval) do { \ |
2487 | | /* We need to evaluate if it is a promise */ \ |
2488 | 6.40k | if (TYPEOF(rval) == PROMSXP) { \ |
2489 | 5.39k | PROTECT(rval); \ |
2490 | 5.39k | rval = eval(rval, genv); \ |
2491 | 5.39k | UNPROTECT(1); \ |
2492 | 5.39k | } \ |
2493 | 6.40k | ENSURE_NAMED(rval); \ |
2494 | 6.40k | } while (0) |
2495 | | |
2496 | 5.52k | GET_VALUE(rval); |
2497 | 5.52k | break; |
2498 | | |
2499 | 150k | case 2: // get0(.) |
2500 | 150k | if (rval == R_UnboundValue) |
2501 | 149k | return CAD4R(args);// i.e. value_if_not_exists |
2502 | 876 | GET_VALUE(rval); |
2503 | 876 | break; |
2504 | 168k | } |
2505 | 6.40k | return rval; |
2506 | 168k | } |
2507 | | #undef GET_VALUE |
2508 | | |
2509 | | static SEXP gfind(const char *name, SEXP env, |
2510 | | SEXPTYPE mode, Rboolean wants_S4, |
2511 | | SEXP ifnotfound, int inherits, SEXP enclos) |
2512 | 18.4k | { |
2513 | 18.4k | SEXP rval, t1, R_fcall, var; |
2514 | | |
2515 | 18.4k | t1 = install(name); |
2516 | | |
2517 | | /* Search for the object - last arg is 1 to 'get' */ |
2518 | 18.4k | rval = findVar1mode(t1, env, mode, wants_S4, inherits, 1); |
2519 | | |
2520 | 18.4k | if (rval == R_UnboundValue) { |
2521 | 0 | if( isFunction(ifnotfound) ) { |
2522 | 0 | PROTECT(var = mkString(name)); |
2523 | 0 | PROTECT(R_fcall = LCONS(ifnotfound, LCONS(var, R_NilValue))); |
2524 | 0 | rval = eval(R_fcall, enclos); |
2525 | 0 | UNPROTECT(2); |
2526 | 0 | } else |
2527 | 0 | rval = ifnotfound; |
2528 | 0 | } |
2529 | | |
2530 | | /* We need to evaluate if it is a promise */ |
2531 | 18.4k | if (TYPEOF(rval) == PROMSXP) { |
2532 | 0 | PROTECT(rval); |
2533 | 0 | rval = eval(rval, env); |
2534 | 0 | UNPROTECT(1); |
2535 | 0 | } |
2536 | 18.4k | ENSURE_NAMED(rval); |
2537 | 18.4k | return rval; |
2538 | 18.4k | } |
2539 | | |
2540 | | |
2541 | | /** mget(): get multiple values from an environment |
2542 | | * |
2543 | | * .Internal(mget(x, envir, mode, ifnotfound, inherits)) |
2544 | | * |
2545 | | * @return a list of the same length as x, a character vector (of names). |
2546 | | */ |
2547 | | attribute_hidden SEXP do_mget(SEXP call, SEXP op, SEXP args, SEXP rho) |
2548 | 120 | { |
2549 | 120 | SEXP ans, env, x, mode, ifnotfound; |
2550 | 120 | int ginherits = 0, nvals, nmode, nifnfnd; |
2551 | | |
2552 | 120 | checkArity(op, args); |
2553 | | |
2554 | 120 | x = CAR(args); |
2555 | | |
2556 | 120 | nvals = length(x); |
2557 | | |
2558 | | /* The first arg is the object name */ |
2559 | | /* It must be present and a string */ |
2560 | 120 | if (!isString(x) ) |
2561 | 0 | error(_("invalid first argument")); |
2562 | 18.5k | for(int i = 0; i < nvals; i++) |
2563 | 18.4k | if( isNull(STRING_ELT(x, i)) || !CHAR(STRING_ELT(x, 0))[0] ) |
2564 | 0 | error(_("invalid name in position %d"), i+1); |
2565 | | |
2566 | 120 | env = CADR(args); |
2567 | 120 | if (ISNULL(env)) { |
2568 | 0 | error(_("use of NULL environment is defunct")); |
2569 | 120 | } else if( !isEnvironment(env) ) |
2570 | 0 | error(_("second argument must be an environment")); |
2571 | | |
2572 | 120 | mode = CADDR(args); |
2573 | 120 | nmode = length(mode); |
2574 | 120 | if( !isString(mode) ) |
2575 | 0 | error(_("invalid '%s' argument"), "mode"); |
2576 | | |
2577 | 120 | if( nmode != nvals && nmode != 1 ) |
2578 | 0 | error(_("wrong length for '%s' argument"), "mode"); |
2579 | | |
2580 | 120 | PROTECT(ifnotfound = coerceVector(CADDDR(args), VECSXP)); |
2581 | 120 | nifnfnd = length(ifnotfound); |
2582 | 120 | if( !isVector(ifnotfound) ) |
2583 | 0 | error(_("invalid '%s' argument"), "ifnotfound"); |
2584 | | |
2585 | 120 | if( nifnfnd != nvals && nifnfnd != 1 ) |
2586 | 0 | error(_("wrong length for '%s' argument"), "ifnotfound"); |
2587 | | |
2588 | 120 | ginherits = asLogical(CAD4R(args)); |
2589 | 120 | if (ginherits == NA_LOGICAL) |
2590 | 0 | error(_("invalid '%s' argument"), "inherits"); |
2591 | | |
2592 | 120 | PROTECT(ans = allocVector(VECSXP, nvals)); |
2593 | | |
2594 | 18.5k | for(int i = 0; i < nvals; i++) { |
2595 | 18.4k | Rboolean wants_S4 = FALSE; |
2596 | 18.4k | const char *modestr = CHAR(STRING_ELT(CADDR(args), i % nmode)); |
2597 | 18.4k | SEXPTYPE gmode = str2mode(modestr, &wants_S4); |
2598 | 18.4k | SEXP nf = VECTOR_ELT(ifnotfound, i % nifnfnd); |
2599 | 18.4k | SEXP ans_i = gfind(translateChar(STRING_ELT(x, i % nvals)), env, |
2600 | 18.4k | gmode, wants_S4, nf, ginherits, rho); |
2601 | 18.4k | SET_VECTOR_ELT(ans, i, lazy_duplicate(ans_i)); |
2602 | 18.4k | } |
2603 | | |
2604 | 120 | setAttrib(ans, R_NamesSymbol, lazy_duplicate(x)); |
2605 | 120 | UNPROTECT(2); |
2606 | 120 | return(ans); |
2607 | 120 | } |
2608 | | |
2609 | | // In Rinternals.h |
2610 | | SEXP R_getVarEx(SEXP sym, SEXP rho, Rboolean inherits, SEXP ifnotfound) |
2611 | 0 | { |
2612 | 0 | if (TYPEOF(sym) != SYMSXP) |
2613 | 0 | error(_("first argument to '%s' must be a symbol"), __func__); |
2614 | 0 | if (TYPEOF(rho) != ENVSXP) |
2615 | 0 | error(_("second argument to '%s' must be an environment"), __func__); |
2616 | |
|
2617 | 0 | SEXP val = inherits ? R_findVar(sym, rho) : R_findVarInFrame(rho, sym); |
2618 | 0 | if (val == R_MissingArg) |
2619 | 0 | R_MissingArgError(sym, getLexicalCall(rho), "getVarExError"); |
2620 | 0 | else if (val == R_UnboundValue) |
2621 | 0 | return ifnotfound; |
2622 | 0 | else if (TYPEOF(val) == PROMSXP) { |
2623 | 0 | PROTECT(val); |
2624 | 0 | val = eval(val, rho); |
2625 | 0 | UNPROTECT(1); |
2626 | 0 | } |
2627 | 0 | return val; |
2628 | 0 | } |
2629 | | |
2630 | | // In Rinternals.h |
2631 | | SEXP R_getVar(SEXP sym, SEXP rho, Rboolean inherits) |
2632 | 0 | { |
2633 | 0 | SEXP val = R_getVarEx(sym, rho, inherits, R_UnboundValue); |
2634 | 0 | if (val == R_UnboundValue) |
2635 | 0 | R_ObjectNotFoundError(sym, R_CurrentExpression, NULL); |
2636 | 0 | return val; |
2637 | 0 | } |
2638 | | |
2639 | | |
2640 | | /*---------------------------------------------------------------------- |
2641 | | |
2642 | | do_missing |
2643 | | |
2644 | | This function tests whether the symbol passed as its first argument |
2645 | | is a missing argument to the current closure. rho is the |
2646 | | environment that missing was called from. |
2647 | | |
2648 | | R_isMissing is called on the not-yet-evaluated value of an argument, |
2649 | | if this is a symbol, as it could be a missing argument that has been |
2650 | | passed down. So 'symbol' is the promise value, and 'rho' its |
2651 | | evaluation argument. |
2652 | | |
2653 | | It is also called in arithmetic.c. for e.g. do_log |
2654 | | */ |
2655 | | |
2656 | 45.8k | static SEXP findRootPromise(SEXP p) { |
2657 | 45.8k | if (TYPEOF(p) == PROMSXP) { |
2658 | 21.9k | while(TYPEOF(PREXPR(p)) == PROMSXP) { |
2659 | 0 | p = PREXPR(p); |
2660 | 0 | } |
2661 | 21.9k | } |
2662 | 45.8k | return p; |
2663 | 45.8k | } |
2664 | | |
2665 | | // missing() for the case of promise aka *un*evaluated symbol: |
2666 | | attribute_hidden |
2667 | | Rboolean R_isMissing(SEXP symbol, SEXP rho) |
2668 | 31.2k | { |
2669 | 31.2k | int ddv=0; |
2670 | 31.2k | SEXP vl, s; |
2671 | | |
2672 | 31.2k | if (symbol == R_MissingArg) /* Yes, this can happen */ |
2673 | 0 | return TRUE; |
2674 | | |
2675 | | /* check for infinite recursion */ |
2676 | 31.2k | R_CheckStack(); |
2677 | | |
2678 | 31.2k | if (DDVAL(symbol)) { |
2679 | 0 | s = R_DotsSymbol; |
2680 | 0 | ddv = ddVal(symbol); |
2681 | 0 | } |
2682 | 31.2k | else |
2683 | 31.2k | s = symbol; |
2684 | | |
2685 | 31.2k | if (rho == R_BaseEnv || rho == R_BaseNamespace) |
2686 | 0 | return FALSE; /* is this really the right thing to do? LT */ |
2687 | | |
2688 | 31.2k | vl = findVarLocInFrame(rho, s, NULL); |
2689 | 31.2k | if (vl != R_NilValue) { |
2690 | 31.2k | if (DDVAL(symbol)) { |
2691 | 0 | if (length(CAR(vl)) < ddv || CAR(vl) == R_MissingArg) |
2692 | 0 | return TRUE; |
2693 | | /* defineVar(symbol, value, R_GlobalEnv); */ |
2694 | 0 | else |
2695 | 0 | vl = nthcdr(CAR(vl), ddv-1); |
2696 | 0 | } |
2697 | 31.2k | if (MISSING(vl) == 1 || |
2698 | 30.9k | (BNDCELL_TAG(vl) == 0 && CAR(vl) == R_MissingArg)) |
2699 | 312 | return TRUE; |
2700 | 30.9k | if (IS_ACTIVE_BINDING(vl)) |
2701 | 0 | return FALSE; |
2702 | 30.9k | if (BNDCELL_TAG(vl)) |
2703 | 72 | return FALSE; |
2704 | 30.9k | SETCAR(vl, findRootPromise(CAR(vl))); |
2705 | 30.9k | if (TYPEOF(CAR(vl)) == PROMSXP && |
2706 | 7.02k | ! PROMISE_IS_EVALUATED(CAR(vl)) && |
2707 | 6.13k | TYPEOF(PREXPR(CAR(vl))) == SYMSXP) { |
2708 | | /* This code uses the PRSEEN value to detect cycles. If a |
2709 | | cycle occurs then a missing argument was encountered, |
2710 | | so the return value is TRUE. It would be a little |
2711 | | safer to use the promise stack to ensure unsetting of |
2712 | | the bits in the event of a longjump, but doing so would |
2713 | | require distinguishing between evaluating promises and |
2714 | | checking for missingness. Because of the test above |
2715 | | for an active binding a longjmp should only happen if |
2716 | | the stack check fails. LT */ |
2717 | 96 | if (PRSEEN(CAR(vl)) == 1) |
2718 | 0 | return TRUE; |
2719 | 96 | else { |
2720 | 96 | int oldseen = PRSEEN(CAR(vl)); |
2721 | 96 | SET_PRSEEN(CAR(vl), 1); |
2722 | 96 | PROTECT(vl); |
2723 | 96 | Rboolean val = R_isMissing(PREXPR(CAR(vl)), PRENV(CAR(vl))); |
2724 | 96 | UNPROTECT(1); /* vl */ |
2725 | | /* The oldseen value will usually be 0, but might be 2 |
2726 | | from an interrupted evaluation. LT */ |
2727 | 96 | SET_PRSEEN(CAR(vl), oldseen); |
2728 | 96 | return val; |
2729 | 96 | } |
2730 | 96 | } |
2731 | 30.8k | else |
2732 | 30.8k | return FALSE; |
2733 | 30.9k | } |
2734 | 0 | return FALSE; |
2735 | 31.2k | } |
2736 | | |
2737 | | // workhorse of do_missing() == R's missing(); more generally useful -> ./bind.c |
2738 | | attribute_hidden |
2739 | | Rboolean R_missing(SEXP var, SEXP rho) |
2740 | 146k | { |
2741 | 146k | int ddv = 0; |
2742 | 146k | SEXP s = var; |
2743 | 146k | if (DDVAL(var)) { |
2744 | 0 | ddv = ddVal(var); |
2745 | 0 | var = R_DotsSymbol; |
2746 | 0 | } |
2747 | | |
2748 | 146k | SEXP t = findVarLocInFrame(rho, var, NULL); |
2749 | 146k | if (t != R_NilValue) { |
2750 | 146k | if (DDVAL(s)) { |
2751 | 0 | if (length(CAR(t)) < ddv || CAR(t) == R_MissingArg) { |
2752 | 0 | return TRUE; |
2753 | 0 | } |
2754 | 0 | else |
2755 | 0 | t = nthcdr(CAR(t), ddv-1); |
2756 | 0 | } |
2757 | 146k | if (BNDCELL_TAG(t)) return FALSE; |
2758 | 146k | if (MISSING(t) || CAR(t) == R_MissingArg) { |
2759 | 125k | return TRUE; |
2760 | 125k | } |
2761 | 146k | } |
2762 | 0 | else /* it wasn't an argument to the function */ |
2763 | 0 | error(_("'missing(%s)' did not find an argument"), CHAR(PRINTNAME(var))); |
2764 | | |
2765 | 21.0k | t = CAR(t); |
2766 | 21.0k | if (TYPEOF(t) != PROMSXP) { |
2767 | 6.09k | return FALSE; |
2768 | 6.09k | } |
2769 | | // deal with promise : |
2770 | 14.9k | t = findRootPromise(t); |
2771 | 14.9k | if (!isSymbol(PREXPR(t))) |
2772 | 13.2k | return FALSE; |
2773 | 1.68k | else { |
2774 | 1.68k | return R_isMissing(PREXPR(t), PRENV(t)); |
2775 | 1.68k | } |
2776 | 14.9k | } |
2777 | | |
2778 | | /* this is primitive and a SPECIALSXP */ |
2779 | | attribute_hidden SEXP do_missing(SEXP call, SEXP op, SEXP args, SEXP rho) |
2780 | 146k | { |
2781 | 146k | checkArity(op, args); |
2782 | 146k | check1arg(args, call, "x"); |
2783 | 146k | SEXP sym = CAR(args); |
2784 | 146k | if( isString(sym) && length(sym)==1 ) |
2785 | 0 | sym = installTrChar(STRING_ELT(CAR(args), 0)); |
2786 | 146k | if (!isSymbol(sym)) |
2787 | 0 | errorcall(call, _("invalid use of 'missing'")); |
2788 | | |
2789 | 146k | SEXP rval = PROTECT(allocVector(LGLSXP, 1)); |
2790 | 146k | LOGICAL(rval)[0] = R_missing(sym, rho); |
2791 | 146k | UNPROTECT(1); |
2792 | 146k | return rval; |
2793 | 146k | } |
2794 | | |
2795 | | /*---------------------------------------------------------------------- |
2796 | | |
2797 | | do_globalenv |
2798 | | |
2799 | | Returns the current global environment. |
2800 | | |
2801 | | */ |
2802 | | |
2803 | | |
2804 | | attribute_hidden SEXP do_globalenv(SEXP call, SEXP op, SEXP args, SEXP rho) |
2805 | 24 | { |
2806 | 24 | checkArity(op, args); |
2807 | 24 | return R_GlobalEnv; |
2808 | 24 | } |
2809 | | |
2810 | | /*---------------------------------------------------------------------- |
2811 | | |
2812 | | do_baseenv |
2813 | | |
2814 | | Returns the current base environment. |
2815 | | |
2816 | | */ |
2817 | | |
2818 | | |
2819 | | attribute_hidden SEXP do_baseenv(SEXP call, SEXP op, SEXP args, SEXP rho) |
2820 | 16.2k | { |
2821 | 16.2k | checkArity(op, args); |
2822 | 16.2k | return R_BaseEnv; |
2823 | 16.2k | } |
2824 | | |
2825 | | /*---------------------------------------------------------------------- |
2826 | | |
2827 | | do_emptyenv |
2828 | | |
2829 | | Returns the current empty environment. |
2830 | | |
2831 | | */ |
2832 | | |
2833 | | |
2834 | | attribute_hidden SEXP do_emptyenv(SEXP call, SEXP op, SEXP args, SEXP rho) |
2835 | 0 | { |
2836 | 0 | checkArity(op, args); |
2837 | 0 | return R_EmptyEnv; |
2838 | 0 | } |
2839 | | |
2840 | | |
2841 | | /*---------------------------------------------------------------------- |
2842 | | |
2843 | | do_attach |
2844 | | |
2845 | | To attach a list we make up an environment and insert components |
2846 | | of the list in as the values of this env and install the tags from |
2847 | | the list as the names. |
2848 | | |
2849 | | */ |
2850 | | |
2851 | | static void set_attach_frame_value(SEXP p, SEXP s) |
2852 | 0 | { |
2853 | 0 | if (IS_ACTIVE_BINDING(p)) |
2854 | 0 | R_MakeActiveBinding(TAG(p), CAR(p), s); |
2855 | 0 | else |
2856 | 0 | defineVar(TAG(p), lazy_duplicate(CAR(p)), s); |
2857 | 0 | } |
2858 | | |
2859 | | attribute_hidden SEXP do_attach(SEXP call, SEXP op, SEXP args, SEXP env) |
2860 | 84 | { |
2861 | 84 | SEXP name, s, t, x; |
2862 | 84 | int pos, hsize; |
2863 | 84 | Rboolean isSpecial; |
2864 | | |
2865 | 84 | checkArity(op, args); |
2866 | | |
2867 | 84 | pos = asInteger(CADR(args)); |
2868 | 84 | if (pos == NA_INTEGER) |
2869 | 0 | error(_("'pos' must be an integer")); |
2870 | | |
2871 | 84 | name = CADDR(args); |
2872 | 84 | if (!isValidStringF(name)) |
2873 | 0 | error(_("invalid '%s' argument"), "name"); |
2874 | | |
2875 | 84 | isSpecial = IS_USER_DATABASE(CAR(args)); |
2876 | | |
2877 | 84 | if(!isSpecial) { |
2878 | 84 | if (isNewList(CAR(args))) { |
2879 | 84 | SETCAR(args, VectorToPairList(CAR(args))); |
2880 | | |
2881 | 84 | for (x = CAR(args); x != R_NilValue; x = CDR(x)) |
2882 | 0 | if (TAG(x) == R_NilValue) |
2883 | 0 | error(_("all elements of a list must be named")); |
2884 | 84 | PROTECT(s = allocSExp(ENVSXP)); |
2885 | 84 | SET_FRAME(s, shallow_duplicate(CAR(args))); |
2886 | 84 | } else if (isEnvironment(CAR(args))) { |
2887 | 0 | SEXP p, loadenv = CAR(args); |
2888 | |
|
2889 | 0 | PROTECT(s = allocSExp(ENVSXP)); |
2890 | 0 | if (HASHTAB(loadenv) != R_NilValue) { |
2891 | 0 | int i, n; |
2892 | 0 | n = length(HASHTAB(loadenv)); |
2893 | 0 | for (i = 0; i < n; i++) { |
2894 | 0 | p = VECTOR_ELT(HASHTAB(loadenv), i); |
2895 | 0 | while (p != R_NilValue) { |
2896 | 0 | set_attach_frame_value(p, s); |
2897 | 0 | p = CDR(p); |
2898 | 0 | } |
2899 | 0 | } |
2900 | | /* FIXME: duplicate the hash table and assign here */ |
2901 | 0 | } else { |
2902 | 0 | for(p = FRAME(loadenv); p != R_NilValue; p = CDR(p)) |
2903 | 0 | set_attach_frame_value(p, s); |
2904 | 0 | } |
2905 | 0 | } else { |
2906 | 0 | error(_("'attach' only works for lists, data frames and environments")); |
2907 | 0 | s = R_NilValue; /* -Wall */ |
2908 | 0 | } |
2909 | | |
2910 | | /* Connect FRAME(s) into HASHTAB(s) */ |
2911 | 84 | if (length(s) < HASHMINSIZE) |
2912 | 84 | hsize = HASHMINSIZE; |
2913 | 0 | else |
2914 | 0 | hsize = length(s); |
2915 | | |
2916 | 84 | SET_HASHTAB(s, R_NewHashTable(hsize)); |
2917 | 84 | s = R_HashFrame(s); |
2918 | | |
2919 | | /* FIXME: A little inefficient */ |
2920 | 84 | while (R_HashSizeCheck(HASHTAB(s))) |
2921 | 0 | SET_HASHTAB(s, R_HashResize(HASHTAB(s))); |
2922 | | |
2923 | 84 | } else { /* is a user object */ |
2924 | | /* Having this here (rather than below) means that the onAttach routine |
2925 | | is called before the table is attached. This may not be necessary or |
2926 | | desirable. */ |
2927 | 0 | R_ObjectTable *tb = (R_ObjectTable*) R_ExternalPtrAddr(CAR(args)); |
2928 | 0 | if(tb->onAttach) |
2929 | 0 | tb->onAttach(tb); |
2930 | 0 | PROTECT(s = allocSExp(ENVSXP)); |
2931 | 0 | SET_HASHTAB(s, CAR(args)); |
2932 | 0 | setAttrib(s, R_ClassSymbol, getAttrib(HASHTAB(s), R_ClassSymbol)); |
2933 | 0 | } |
2934 | | |
2935 | 84 | setAttrib(s, R_NameSymbol, name); |
2936 | 84 | for (t = R_GlobalEnv; ENCLOS(t) != R_BaseEnv && pos > 2; t = ENCLOS(t)) |
2937 | 0 | pos--; |
2938 | | |
2939 | 84 | if (ENCLOS(t) == R_BaseEnv) { |
2940 | 12 | SET_ENCLOS(t, s); |
2941 | 12 | SET_ENCLOS(s, R_BaseEnv); |
2942 | 12 | } |
2943 | 72 | else { |
2944 | 72 | x = ENCLOS(t); |
2945 | 72 | SET_ENCLOS(t, s); |
2946 | 72 | SET_ENCLOS(s, x); |
2947 | 72 | } |
2948 | | |
2949 | 84 | if(!isSpecial) { /* Temporary: need to remove the elements identified by objects(CAR(args)) */ |
2950 | 84 | #ifdef USE_GLOBAL_CACHE |
2951 | 84 | R_FlushGlobalCacheFromTable(HASHTAB(s)); |
2952 | 84 | MARK_AS_GLOBAL_FRAME(s); |
2953 | 84 | #endif |
2954 | 84 | } else { |
2955 | 0 | #ifdef USE_GLOBAL_CACHE |
2956 | 0 | R_FlushGlobalCacheFromUserTable(HASHTAB(s)); |
2957 | 0 | MARK_AS_GLOBAL_FRAME(s); |
2958 | 0 | #endif |
2959 | 0 | } |
2960 | | |
2961 | 84 | UNPROTECT(1); /* s */ |
2962 | 84 | return s; |
2963 | 84 | } |
2964 | | |
2965 | | |
2966 | | |
2967 | | /*---------------------------------------------------------------------- |
2968 | | |
2969 | | do_detach |
2970 | | |
2971 | | detach the specified environment. Detachment only takes place by |
2972 | | position. |
2973 | | |
2974 | | */ |
2975 | | |
2976 | | attribute_hidden SEXP do_detach(SEXP call, SEXP op, SEXP args, SEXP env) |
2977 | 0 | { |
2978 | 0 | SEXP s, t, x; |
2979 | 0 | int pos, n; |
2980 | 0 | Rboolean isSpecial = FALSE; |
2981 | |
|
2982 | 0 | checkArity(op, args); |
2983 | 0 | pos = asInteger(CAR(args)); |
2984 | |
|
2985 | 0 | for (n = 2, t = ENCLOS(R_GlobalEnv); t != R_BaseEnv; t = ENCLOS(t)) |
2986 | 0 | n++; |
2987 | |
|
2988 | 0 | if (pos == n) /* n is the length of the search list */ |
2989 | 0 | error(_("detaching \"package:base\" is not allowed")); |
2990 | |
|
2991 | 0 | for (t = R_GlobalEnv ; ENCLOS(t) != R_BaseEnv && pos > 2 ; t = ENCLOS(t)) |
2992 | 0 | pos--; |
2993 | 0 | if (pos != 2) { |
2994 | 0 | error(_("invalid '%s' argument"), "pos"); |
2995 | 0 | s = t; /* for -Wall */ |
2996 | 0 | } |
2997 | 0 | else { |
2998 | 0 | PROTECT(s = ENCLOS(t)); |
2999 | 0 | x = ENCLOS(s); |
3000 | 0 | SET_ENCLOS(t, x); |
3001 | 0 | isSpecial = IS_USER_DATABASE(s); |
3002 | 0 | if(isSpecial) { |
3003 | 0 | R_ObjectTable *tb = (R_ObjectTable*) R_ExternalPtrAddr(HASHTAB(s)); |
3004 | 0 | if(tb->onDetach) tb->onDetach(tb); |
3005 | 0 | } |
3006 | |
|
3007 | 0 | SET_ENCLOS(s, R_BaseEnv); |
3008 | 0 | } |
3009 | 0 | #ifdef USE_GLOBAL_CACHE |
3010 | 0 | if(!isSpecial) { |
3011 | 0 | R_FlushGlobalCacheFromTable(HASHTAB(s)); |
3012 | 0 | MARK_AS_LOCAL_FRAME(s); |
3013 | 0 | } else { |
3014 | 0 | R_FlushGlobalCacheFromUserTable(HASHTAB(s)); |
3015 | 0 | MARK_AS_LOCAL_FRAME(s); /* was _GLOBAL_ prior to 2.4.0 */ |
3016 | 0 | } |
3017 | 0 | #endif |
3018 | 0 | UNPROTECT(1); |
3019 | 0 | return s; |
3020 | 0 | } |
3021 | | |
3022 | | |
3023 | | |
3024 | | /*---------------------------------------------------------------------- |
3025 | | |
3026 | | do_search |
3027 | | |
3028 | | Print out the current search path. |
3029 | | |
3030 | | */ |
3031 | | |
3032 | | attribute_hidden SEXP do_search(SEXP call, SEXP op, SEXP args, SEXP env) |
3033 | 314 | { |
3034 | 314 | SEXP ans, name, t; |
3035 | 314 | int i, n; |
3036 | | |
3037 | 314 | checkArity(op, args); |
3038 | 314 | n = 2; |
3039 | 1.50k | for (t = ENCLOS(R_GlobalEnv); t != R_BaseEnv ; t = ENCLOS(t)) |
3040 | 1.19k | n++; |
3041 | 314 | PROTECT(ans = allocVector(STRSXP, n)); |
3042 | | /* TODO - what should the name of this be? */ |
3043 | 314 | SET_STRING_ELT(ans, 0, mkChar(".GlobalEnv")); |
3044 | 314 | SET_STRING_ELT(ans, n-1, mkChar("package:base")); |
3045 | 314 | i = 1; |
3046 | 1.50k | for (t = ENCLOS(R_GlobalEnv); t != R_BaseEnv ; t = ENCLOS(t)) { |
3047 | 1.19k | name = getAttrib(t, R_NameSymbol); |
3048 | 1.19k | if (!isString(name) || length(name) < 1) |
3049 | 0 | SET_STRING_ELT(ans, i, mkChar("(unknown)")); |
3050 | 1.19k | else |
3051 | 1.19k | SET_STRING_ELT(ans, i, STRING_ELT(name, 0)); |
3052 | 1.19k | i++; |
3053 | 1.19k | } |
3054 | 314 | UNPROTECT(1); |
3055 | 314 | return ans; |
3056 | 314 | } |
3057 | | |
3058 | | |
3059 | | /*---------------------------------------------------------------------- |
3060 | | |
3061 | | do_ls |
3062 | | |
3063 | | This code implements the functionality of the "ls" and "objects" |
3064 | | functions. [ ls(envir, all.names, sorted) ] |
3065 | | |
3066 | | */ |
3067 | | #define NONEMPTY_(_FRAME_) \ |
3068 | 0 | CHAR(PRINTNAME(TAG(_FRAME_)))[0] != '.' |
3069 | | |
3070 | | static int FrameSize(SEXP frame, int all) |
3071 | 182k | { |
3072 | 182k | int count = 0; |
3073 | 182k | if (all) { |
3074 | 378k | while (frame != R_NilValue) { |
3075 | 195k | count += 1; |
3076 | 195k | frame = CDR(frame); |
3077 | 195k | } |
3078 | 182k | } else { |
3079 | 0 | while (frame != R_NilValue) { |
3080 | 0 | if (NONEMPTY_(frame)) |
3081 | 0 | count += 1; |
3082 | 0 | frame = CDR(frame); |
3083 | 0 | } |
3084 | 0 | } |
3085 | 182k | return count; |
3086 | 182k | } |
3087 | | |
3088 | | static void FrameNames(SEXP frame, int all, SEXP names, int *indx) |
3089 | 182k | { |
3090 | 182k | if (all) { |
3091 | 378k | while (frame != R_NilValue) { |
3092 | 195k | SET_STRING_ELT(names, *indx, PRINTNAME(TAG(frame))); |
3093 | 195k | (*indx)++; |
3094 | 195k | frame = CDR(frame); |
3095 | 195k | } |
3096 | 182k | } else { |
3097 | 0 | while (frame != R_NilValue) { |
3098 | 0 | if (NONEMPTY_(frame)) { |
3099 | 0 | SET_STRING_ELT(names, *indx, PRINTNAME(TAG(frame))); |
3100 | 0 | (*indx)++; |
3101 | 0 | } |
3102 | 0 | frame = CDR(frame); |
3103 | 0 | } |
3104 | 0 | } |
3105 | 182k | } |
3106 | | |
3107 | | static void FrameValues(SEXP frame, int all, SEXP values, int *indx) |
3108 | 0 | { |
3109 | 0 | if (all) { |
3110 | 0 | while (frame != R_NilValue) { |
3111 | 0 | # define DO_FrameValues \ |
3112 | 0 | SEXP value = BINDING_VALUE(frame); \ |
3113 | 0 | if (TYPEOF(value) == PROMSXP) { \ |
3114 | 0 | PROTECT(value); \ |
3115 | 0 | value = eval(value, R_GlobalEnv); \ |
3116 | 0 | UNPROTECT(1); \ |
3117 | 0 | } \ |
3118 | 0 | SET_VECTOR_ELT(values, *indx, lazy_duplicate(value)); \ |
3119 | 0 | (*indx)++ |
3120 | |
|
3121 | 0 | DO_FrameValues; |
3122 | 0 | frame = CDR(frame); |
3123 | 0 | } |
3124 | 0 | } else { |
3125 | 0 | while (frame != R_NilValue) { |
3126 | 0 | if (NONEMPTY_(frame)) { |
3127 | 0 | DO_FrameValues; |
3128 | 0 | } |
3129 | 0 | frame = CDR(frame); |
3130 | 0 | } |
3131 | 0 | } |
3132 | 0 | } |
3133 | | #undef DO_FrameValues |
3134 | | #undef NONEMPTY_ |
3135 | | |
3136 | 1.89k | #define CHECK_HASH_TABLE(table) do { \ |
3137 | 1.89k | if (TYPEOF(table) != VECSXP) \ |
3138 | 1.89k | error("bad hash table contents"); \ |
3139 | 1.89k | } while (0) |
3140 | | |
3141 | | static int HashTableSize(SEXP table, int all) |
3142 | 948 | { |
3143 | 948 | CHECK_HASH_TABLE(table); |
3144 | 948 | int count = 0; |
3145 | 948 | int n = length(table); |
3146 | 948 | int i; |
3147 | 183k | for (i = 0; i < n; i++) |
3148 | 182k | count += FrameSize(VECTOR_ELT(table, i), all); |
3149 | 948 | return count; |
3150 | 948 | } |
3151 | | |
3152 | | static void HashTableNames(SEXP table, int all, SEXP names, int *indx) |
3153 | 948 | { |
3154 | 948 | CHECK_HASH_TABLE(table); |
3155 | 948 | int n = length(table); |
3156 | 948 | int i; |
3157 | 183k | for (i = 0; i < n; i++) |
3158 | 182k | FrameNames(VECTOR_ELT(table, i), all, names, indx); |
3159 | 948 | } |
3160 | | |
3161 | | static void HashTableValues(SEXP table, int all, SEXP values, int *indx) |
3162 | 0 | { |
3163 | 0 | CHECK_HASH_TABLE(table); |
3164 | 0 | int n = length(table); |
3165 | 0 | int i; |
3166 | 0 | for (i = 0; i < n; i++) |
3167 | 0 | FrameValues(VECTOR_ELT(table, i), all, values, indx); |
3168 | 0 | } |
3169 | | |
3170 | | static int BuiltinSize(int all, int intern) |
3171 | 84 | { |
3172 | 84 | int count = 0; |
3173 | 84 | SEXP s; |
3174 | 84 | int j; |
3175 | 4.12M | for (j = 0; j < HSIZE; j++) { |
3176 | 4.51M | for (s = R_SymbolTable[j]; s != R_NilValue; s = CDR(s)) { |
3177 | 390k | if (intern) { |
3178 | 0 | if (INTERNAL(CAR(s)) != R_NilValue) |
3179 | 0 | count++; |
3180 | 0 | } |
3181 | 390k | else { |
3182 | 390k | if ((all || CHAR(PRINTNAME(CAR(s)))[0] != '.') |
3183 | 390k | && SYMVALUE(CAR(s)) != R_UnboundValue) |
3184 | 118k | count++; |
3185 | 390k | } |
3186 | 390k | } |
3187 | 4.12M | } |
3188 | 84 | return count; |
3189 | 84 | } |
3190 | | |
3191 | | static void |
3192 | | BuiltinNames(int all, int intern, SEXP names, int *indx) |
3193 | 84 | { |
3194 | 84 | SEXP s; |
3195 | 84 | int j; |
3196 | 4.12M | for (j = 0; j < HSIZE; j++) { |
3197 | 4.51M | for (s = R_SymbolTable[j]; s != R_NilValue; s = CDR(s)) { |
3198 | 390k | if (intern) { |
3199 | 0 | if (INTERNAL(CAR(s)) != R_NilValue) |
3200 | 0 | SET_STRING_ELT(names, (*indx)++, PRINTNAME(CAR(s))); |
3201 | 0 | } |
3202 | 390k | else { |
3203 | 390k | if ((all || CHAR(PRINTNAME(CAR(s)))[0] != '.') |
3204 | 390k | && SYMVALUE(CAR(s)) != R_UnboundValue) |
3205 | 118k | SET_STRING_ELT(names, (*indx)++, PRINTNAME(CAR(s))); |
3206 | 390k | } |
3207 | 390k | } |
3208 | 4.12M | } |
3209 | 84 | } |
3210 | | |
3211 | | static void |
3212 | | BuiltinValues(int all, int intern, SEXP values, int *indx) |
3213 | 0 | { |
3214 | 0 | SEXP s, vl; |
3215 | 0 | int j; |
3216 | 0 | for (j = 0; j < HSIZE; j++) { |
3217 | 0 | for (s = R_SymbolTable[j]; s != R_NilValue; s = CDR(s)) { |
3218 | 0 | if (intern) { |
3219 | 0 | if (INTERNAL(CAR(s)) != R_NilValue) { |
3220 | 0 | vl = SYMVALUE(CAR(s)); |
3221 | 0 | if (TYPEOF(vl) == PROMSXP) { |
3222 | 0 | PROTECT(vl); |
3223 | 0 | vl = eval(vl, R_BaseEnv); |
3224 | 0 | UNPROTECT(1); |
3225 | 0 | } |
3226 | 0 | SET_VECTOR_ELT(values, (*indx)++, lazy_duplicate(vl)); |
3227 | 0 | } |
3228 | 0 | } |
3229 | 0 | else { |
3230 | 0 | if ((all || CHAR(PRINTNAME(CAR(s)))[0] != '.') |
3231 | 0 | && SYMVALUE(CAR(s)) != R_UnboundValue) { |
3232 | 0 | vl = SYMVALUE(CAR(s)); |
3233 | 0 | if (TYPEOF(vl) == PROMSXP) { |
3234 | 0 | PROTECT(vl); |
3235 | 0 | vl = eval(vl, R_BaseEnv); |
3236 | 0 | UNPROTECT(1); |
3237 | 0 | } |
3238 | 0 | SET_VECTOR_ELT(values, (*indx)++, lazy_duplicate(vl)); |
3239 | 0 | } |
3240 | 0 | } |
3241 | 0 | } |
3242 | 0 | } |
3243 | 0 | } |
3244 | | |
3245 | | // .Internal(ls(envir, all.names, sorted)) : |
3246 | | attribute_hidden SEXP do_ls(SEXP call, SEXP op, SEXP args, SEXP rho) |
3247 | 36 | { |
3248 | 36 | checkArity(op, args); |
3249 | | |
3250 | 36 | if(IS_USER_DATABASE(CAR(args))) { |
3251 | 0 | R_ObjectTable *tb = (R_ObjectTable*) |
3252 | 0 | R_ExternalPtrAddr(HASHTAB(CAR(args))); |
3253 | 0 | return(tb->objects(tb)); |
3254 | 0 | } |
3255 | | |
3256 | 36 | SEXP env = CAR(args); |
3257 | | |
3258 | | /* if (env == R_BaseNamespace) env = R_BaseEnv; */ |
3259 | | |
3260 | 36 | int all = asLogical(CADR(args)); |
3261 | 36 | if (all == NA_LOGICAL) all = 0; |
3262 | | |
3263 | 36 | int sort_nms = asLogical(CADDR(args)); /* sorted = TRUE/FALSE */ |
3264 | 36 | if (sort_nms == NA_LOGICAL) sort_nms = 0; |
3265 | | |
3266 | 36 | return R_lsInternal3(env, (Rboolean) all, (Rboolean) sort_nms); |
3267 | 36 | } |
3268 | | |
3269 | | /* takes an environment, a boolean indicating whether to get all |
3270 | | names and a boolean if sorted is desired */ |
3271 | | // In Rinternals.h |
3272 | | SEXP R_lsInternal3(SEXP env, Rboolean all, Rboolean sorted) |
3273 | 1.03k | { |
3274 | 1.03k | if(IS_USER_DATABASE(env)) { |
3275 | 0 | R_ObjectTable *tb = (R_ObjectTable*) |
3276 | 0 | R_ExternalPtrAddr(HASHTAB(env)); |
3277 | 0 | return(tb->objects(tb)); |
3278 | 0 | } |
3279 | | |
3280 | | /* Step 1 : Compute the Vector Size */ |
3281 | 1.03k | int k = 0; |
3282 | 1.03k | if (env == R_BaseEnv || env == R_BaseNamespace) |
3283 | 84 | k += BuiltinSize(all, 0); |
3284 | 948 | else if (isEnvironment(env) || |
3285 | 948 | isEnvironment(env = simple_as_environment(env))) { |
3286 | 948 | if (HASHTAB(env) != R_NilValue) |
3287 | 948 | k += HashTableSize(HASHTAB(env), all); |
3288 | 0 | else |
3289 | 0 | k += FrameSize(FRAME(env), all); |
3290 | 948 | } |
3291 | 0 | else |
3292 | 0 | error(_("invalid '%s' argument"), "envir"); |
3293 | | |
3294 | | /* Step 2 : Allocate and Fill the Result */ |
3295 | 1.03k | SEXP ans = PROTECT(allocVector(STRSXP, k)); |
3296 | 1.03k | k = 0; |
3297 | 1.03k | if (env == R_BaseEnv || env == R_BaseNamespace) |
3298 | 84 | BuiltinNames(all, 0, ans, &k); |
3299 | 948 | else if (isEnvironment(env)) { |
3300 | 948 | if (HASHTAB(env) != R_NilValue) |
3301 | 948 | HashTableNames(HASHTAB(env), all, ans, &k); |
3302 | 0 | else |
3303 | 0 | FrameNames(FRAME(env), all, ans, &k); |
3304 | 948 | } |
3305 | | |
3306 | 1.03k | if(sorted) sortVector(ans, FALSE); |
3307 | 1.03k | UNPROTECT(1); |
3308 | 1.03k | return ans; |
3309 | 1.03k | } |
3310 | | |
3311 | | /* non-API version used in several packages */ |
3312 | | // in Rinternals.h |
3313 | | SEXP R_lsInternal(SEXP env, Rboolean all) |
3314 | 0 | { |
3315 | 0 | return R_lsInternal3(env, all, TRUE); |
3316 | 0 | } |
3317 | | |
3318 | | SEXP R_envSymbols(SEXP env) |
3319 | 0 | { |
3320 | | // this could be rewritten to avoid allocating the intermediate STRSXP |
3321 | | // this would be mor efficient for non-USER-DATABASE environments |
3322 | 0 | SEXP names = PROTECT(R_lsInternal3(env, TRUE, FALSE)); |
3323 | 0 | R_xlen_t n = XLENGTH(names); |
3324 | 0 | SEXP val = PROTECT(allocVector(VECSXP, n)); |
3325 | 0 | for (R_xlen_t i = 0; i < n; i++) |
3326 | 0 | SET_VECTOR_ELT(val, i, installChar(STRING_ELT(names, i))); |
3327 | 0 | UNPROTECT(2); // names, val |
3328 | 0 | return val; |
3329 | 0 | } |
3330 | | |
3331 | | /* transform an environment into a named list: as.list.environment(.) */ |
3332 | | |
3333 | | attribute_hidden SEXP do_env2list(SEXP call, SEXP op, SEXP args, SEXP rho) |
3334 | 0 | { |
3335 | 0 | SEXP env, ans, names; |
3336 | 0 | int k, all; |
3337 | |
|
3338 | 0 | checkArity(op, args); |
3339 | |
|
3340 | 0 | env = CAR(args); |
3341 | 0 | if (ISNULL(env)) |
3342 | 0 | error(_("use of NULL environment is defunct")); |
3343 | 0 | if( !isEnvironment(env) ) { |
3344 | 0 | SEXP xdata; |
3345 | 0 | if( IS_S4_OBJECT(env) && TYPEOF(env) == OBJSXP && |
3346 | 0 | (xdata = R_getS4DataSlot(env, ENVSXP)) != R_NilValue) |
3347 | 0 | env = xdata; |
3348 | 0 | else |
3349 | 0 | error(_("argument must be an environment")); |
3350 | 0 | } |
3351 | |
|
3352 | 0 | all = asLogical(CADR(args)); /* all.names = TRUE/FALSE */ |
3353 | 0 | if (all == NA_LOGICAL) all = 0; |
3354 | |
|
3355 | 0 | int sort_nms = asLogical(CADDR(args)); /* sorted = TRUE/FALSE */ |
3356 | 0 | if (sort_nms == NA_LOGICAL) sort_nms = 0; |
3357 | | |
3358 | | // k := length(env) = envxlength(env) : |
3359 | 0 | if (env == R_BaseEnv || env == R_BaseNamespace) |
3360 | 0 | k = BuiltinSize(all, 0); |
3361 | 0 | else if (HASHTAB(env) != R_NilValue) |
3362 | 0 | k = HashTableSize(HASHTAB(env), all); |
3363 | 0 | else |
3364 | 0 | k = FrameSize(FRAME(env), all); |
3365 | |
|
3366 | 0 | PROTECT(names = allocVector(STRSXP, k)); |
3367 | 0 | PROTECT(ans = allocVector(VECSXP, k)); |
3368 | |
|
3369 | 0 | k = 0; |
3370 | 0 | if (env == R_BaseEnv || env == R_BaseNamespace) |
3371 | 0 | BuiltinValues(all, 0, ans, &k); |
3372 | 0 | else if (HASHTAB(env) != R_NilValue) |
3373 | 0 | HashTableValues(HASHTAB(env), all, ans, &k); |
3374 | 0 | else |
3375 | 0 | FrameValues(FRAME(env), all, ans, &k); |
3376 | |
|
3377 | 0 | k = 0; |
3378 | 0 | if (env == R_BaseEnv || env == R_BaseNamespace) |
3379 | 0 | BuiltinNames(all, 0, names, &k); |
3380 | 0 | else if (HASHTAB(env) != R_NilValue) |
3381 | 0 | HashTableNames(HASHTAB(env), all, names, &k); |
3382 | 0 | else |
3383 | 0 | FrameNames(FRAME(env), all, names, &k); |
3384 | |
|
3385 | 0 | if(k == 0) { // no sorting, keep NULL names |
3386 | 0 | UNPROTECT(2); |
3387 | 0 | return(ans); |
3388 | 0 | } |
3389 | 0 | if(sort_nms) { |
3390 | | // return list with *sorted* names |
3391 | 0 | SEXP sind = PROTECT(allocVector(INTSXP, k)); |
3392 | 0 | int *indx = INTEGER(sind); |
3393 | 0 | for (int i = 0; i < k; i++) indx[i] = i; |
3394 | 0 | orderVector1(indx, k, names, /* nalast */ true, /* decreasing */ false, |
3395 | 0 | R_NilValue); |
3396 | 0 | SEXP ans2 = PROTECT(allocVector(VECSXP, k)); |
3397 | 0 | SEXP names2 = PROTECT(allocVector(STRSXP, k)); |
3398 | 0 | for(int i = 0; i < k; i++) { |
3399 | 0 | SET_STRING_ELT(names2, i, STRING_ELT(names, indx[i])); |
3400 | 0 | SET_VECTOR_ELT(ans2, i, VECTOR_ELT(ans, indx[i])); |
3401 | 0 | } |
3402 | 0 | setAttrib(ans2, R_NamesSymbol, names2); |
3403 | 0 | UNPROTECT(5); |
3404 | 0 | return(ans2); |
3405 | 0 | } |
3406 | 0 | else { |
3407 | 0 | setAttrib(ans, R_NamesSymbol, names); |
3408 | 0 | UNPROTECT(2); |
3409 | 0 | return(ans); |
3410 | 0 | } |
3411 | 0 | } |
3412 | | |
3413 | | /* |
3414 | | * apply a function to all objects in an environment and return the |
3415 | | * results in a list. |
3416 | | * Equivalent to lapply(as.list(env, all.names=all.names), FUN, ...) |
3417 | | */ |
3418 | | /* This is a special .Internal */ |
3419 | | attribute_hidden SEXP do_eapply(SEXP call, SEXP op, SEXP args, SEXP rho) |
3420 | 0 | { |
3421 | 0 | SEXP env, ans, R_fcall, FUN, tmp, tmp2, ind; |
3422 | 0 | int i, k, k2; |
3423 | 0 | int /* boolean */ all, useNms; |
3424 | |
|
3425 | 0 | checkArity(op, args); |
3426 | |
|
3427 | 0 | PROTECT(env = eval(CAR(args), rho)); |
3428 | 0 | if (ISNULL(env)) |
3429 | 0 | error(_("use of NULL environment is defunct")); |
3430 | 0 | if( !isEnvironment(env) ) |
3431 | 0 | error(_("argument must be an environment")); |
3432 | |
|
3433 | 0 | FUN = CADR(args); |
3434 | 0 | if (!isSymbol(FUN)) |
3435 | 0 | error(_("arguments must be symbolic")); |
3436 | | |
3437 | | /* 'all.names' : */ |
3438 | 0 | all = asLogical(PROTECT(eval(CADDR(args), rho))); |
3439 | 0 | UNPROTECT(1); |
3440 | 0 | if (all == NA_LOGICAL) all = 0; |
3441 | | |
3442 | | /* 'USE.NAMES' : */ |
3443 | 0 | useNms = asLogical(PROTECT(eval(CADDDR(args), rho))); |
3444 | 0 | UNPROTECT(1); |
3445 | 0 | if (useNms == NA_LOGICAL) useNms = 0; |
3446 | |
|
3447 | 0 | if (env == R_BaseEnv || env == R_BaseNamespace) |
3448 | 0 | k = BuiltinSize(all, 0); |
3449 | 0 | else if (HASHTAB(env) != R_NilValue) |
3450 | 0 | k = HashTableSize(HASHTAB(env), all); |
3451 | 0 | else |
3452 | 0 | k = FrameSize(FRAME(env), all); |
3453 | |
|
3454 | 0 | PROTECT(ans = allocVector(VECSXP, k)); |
3455 | 0 | PROTECT(tmp2 = allocVector(VECSXP, k)); |
3456 | |
|
3457 | 0 | k2 = 0; |
3458 | 0 | if (env == R_BaseEnv || env == R_BaseNamespace) |
3459 | 0 | BuiltinValues(all, 0, tmp2, &k2); |
3460 | 0 | else if (HASHTAB(env) != R_NilValue) |
3461 | 0 | HashTableValues(HASHTAB(env), all, tmp2, &k2); |
3462 | 0 | else |
3463 | 0 | FrameValues(FRAME(env), all, tmp2, &k2); |
3464 | |
|
3465 | 0 | SEXP Xsym = install("X"); |
3466 | 0 | SEXP isym = install("i"); |
3467 | 0 | PROTECT(ind = allocVector(INTSXP, 1)); |
3468 | | /* tmp := `[`(<elist>, i) */ |
3469 | 0 | PROTECT(tmp = LCONS(R_Bracket2Symbol, |
3470 | 0 | LCONS(Xsym, LCONS(isym, R_NilValue)))); |
3471 | | /* fcall := <FUN>( tmp, ... ) */ |
3472 | 0 | PROTECT(R_fcall = LCONS(FUN, LCONS(tmp, LCONS(R_DotsSymbol, R_NilValue)))); |
3473 | |
|
3474 | 0 | defineVar(Xsym, tmp2, rho); |
3475 | 0 | INCREMENT_NAMED(tmp2); |
3476 | 0 | defineVar(isym, ind, rho); |
3477 | 0 | INCREMENT_NAMED(ind); |
3478 | |
|
3479 | 0 | for(i = 0; i < k2; i++) { |
3480 | 0 | INTEGER(ind)[0] = i+1; |
3481 | 0 | SEXP tmp = R_forceAndCall(R_fcall, 1, rho); |
3482 | 0 | if (MAYBE_REFERENCED(tmp)) |
3483 | 0 | tmp = lazy_duplicate(tmp); |
3484 | 0 | SET_VECTOR_ELT(ans, i, tmp); |
3485 | 0 | } |
3486 | |
|
3487 | 0 | if (useNms) { |
3488 | 0 | SEXP names; |
3489 | 0 | PROTECT(names = allocVector(STRSXP, k)); |
3490 | 0 | k = 0; |
3491 | 0 | if (env == R_BaseEnv || env == R_BaseNamespace) |
3492 | 0 | BuiltinNames(all, 0, names, &k); |
3493 | 0 | else if(HASHTAB(env) != R_NilValue) |
3494 | 0 | HashTableNames(HASHTAB(env), all, names, &k); |
3495 | 0 | else |
3496 | 0 | FrameNames(FRAME(env), all, names, &k); |
3497 | |
|
3498 | 0 | setAttrib(ans, R_NamesSymbol, names); |
3499 | 0 | UNPROTECT(1); |
3500 | 0 | } |
3501 | 0 | UNPROTECT(6); |
3502 | 0 | return(ans); |
3503 | 0 | } |
3504 | | |
3505 | | /* Leaks out via inlining in ../library/tools/src/ */ |
3506 | | #define R_ENVLENGTH(NAME_, LENGTH_FN_, TYPE_) \ |
3507 | 84 | TYPE_ NAME_(SEXP rho) \ |
3508 | 84 | { \ |
3509 | 84 | if(IS_USER_DATABASE(rho)) { \ |
3510 | 0 | R_ObjectTable *tb = (R_ObjectTable*) R_ExternalPtrAddr(HASHTAB(rho)); \ |
3511 | 0 | return LENGTH_FN_(tb->objects(tb)); \ |
3512 | 84 | } else if( HASHTAB(rho) != R_NilValue) \ |
3513 | 84 | return HashTableSize(HASHTAB(rho), 1); \ |
3514 | 84 | else if (rho == R_BaseEnv || rho == R_BaseNamespace) \ |
3515 | 84 | return BuiltinSize(1, 0); \ |
3516 | 84 | else \ |
3517 | 84 | return FrameSize(FRAME(rho), 1); \ |
3518 | 84 | } Line | Count | Source | 3507 | 84 | TYPE_ NAME_(SEXP rho) \ | 3508 | 84 | { \ | 3509 | 84 | if(IS_USER_DATABASE(rho)) { \ | 3510 | 0 | R_ObjectTable *tb = (R_ObjectTable*) R_ExternalPtrAddr(HASHTAB(rho)); \ | 3511 | 0 | return LENGTH_FN_(tb->objects(tb)); \ | 3512 | 84 | } else if( HASHTAB(rho) != R_NilValue) \ | 3513 | 84 | return HashTableSize(HASHTAB(rho), 1); \ | 3514 | 84 | else if (rho == R_BaseEnv || rho == R_BaseNamespace) \ | 3515 | 84 | return BuiltinSize(1, 0); \ | 3516 | 84 | else \ | 3517 | 84 | return FrameSize(FRAME(rho), 1); \ | 3518 | 84 | } |
Unexecuted instantiation: Rf_envxlength |
3519 | | |
3520 | 0 | R_ENVLENGTH(Rf_envlength, length, int) |
3521 | | |
3522 | 0 | R_ENVLENGTH(Rf_envxlength, xlength, R_xlen_t) |
3523 | | |
3524 | | /*---------------------------------------------------------------------- |
3525 | | |
3526 | | do_builtins |
3527 | | |
3528 | | Return the names of all the built in functions. These are fetched |
3529 | | directly from the symbol table. |
3530 | | |
3531 | | */ |
3532 | | |
3533 | | attribute_hidden SEXP do_builtins(SEXP call, SEXP op, SEXP args, SEXP rho) |
3534 | 0 | { |
3535 | 0 | SEXP ans; |
3536 | 0 | int intern, nelts; |
3537 | 0 | checkArity(op, args); |
3538 | 0 | intern = asLogical(CAR(args)); |
3539 | 0 | if (intern == NA_INTEGER) intern = 0; |
3540 | 0 | nelts = BuiltinSize(1, intern); |
3541 | 0 | PROTECT(ans = allocVector(STRSXP, nelts)); |
3542 | 0 | nelts = 0; |
3543 | 0 | BuiltinNames(1, intern, ans, &nelts); |
3544 | 0 | sortVector(ans, TRUE); |
3545 | 0 | UNPROTECT(1); /* ans */ |
3546 | 0 | return ans; |
3547 | 0 | } |
3548 | | |
3549 | | |
3550 | | /*---------------------------------------------------------------------- |
3551 | | |
3552 | | do_pos2env |
3553 | | |
3554 | | This function returns the environment at a specified position in the |
3555 | | search path or the environment of the caller of |
3556 | | pos.to.env (? but pos.to.env is usually used in arg lists and hence |
3557 | | is evaluated in the calling environment so this is one higher). |
3558 | | |
3559 | | When pos = -1 the environment of the closure that pos2env is |
3560 | | evaluated in is obtained. Note: this relies on pos.to.env being |
3561 | | a primitive. |
3562 | | |
3563 | | */ |
3564 | | static SEXP pos2env(int pos, SEXP call) |
3565 | 840 | { |
3566 | 840 | SEXP env; |
3567 | 840 | RCNTXT *cptr; |
3568 | | |
3569 | 840 | if (pos == NA_INTEGER || pos < -1 || pos == 0) { |
3570 | 0 | errorcall(call, _("invalid '%s' argument"), "pos"); |
3571 | 0 | env = call;/* just for -Wall */ |
3572 | 0 | } |
3573 | 840 | else if (pos == -1) { |
3574 | | /* make sure the context is a funcall */ |
3575 | 228 | cptr = R_GlobalContext; |
3576 | 228 | while( !(cptr->callflag & CTXT_FUNCTION) && cptr->nextcontext |
3577 | 0 | != NULL ) |
3578 | 0 | cptr = cptr->nextcontext; |
3579 | 228 | if( !(cptr->callflag & CTXT_FUNCTION) ) |
3580 | 0 | errorcall(call, _("no enclosing environment")); |
3581 | | |
3582 | 228 | env = cptr->sysparent; |
3583 | 228 | if (R_GlobalEnv != R_NilValue && env == R_NilValue) |
3584 | 0 | errorcall(call, _("invalid '%s' argument"), "pos"); |
3585 | 228 | } |
3586 | 612 | else { |
3587 | 1.81k | for (env = R_GlobalEnv; env != R_EmptyEnv && pos > 1; |
3588 | 1.20k | env = ENCLOS(env)) |
3589 | 1.20k | pos--; |
3590 | 612 | if (pos != 1) |
3591 | 0 | errorcall(call, _("invalid '%s' argument"), "pos"); |
3592 | 612 | } |
3593 | 840 | return env; |
3594 | 840 | } |
3595 | | |
3596 | | /* this is primitive */ |
3597 | | attribute_hidden SEXP do_pos2env(SEXP call, SEXP op, SEXP args, SEXP rho) |
3598 | 840 | { |
3599 | 840 | SEXP env, pos; |
3600 | 840 | int i, npos; |
3601 | 840 | checkArity(op, args); |
3602 | 840 | check1arg(args, call, "x"); |
3603 | | |
3604 | 840 | PROTECT(pos = coerceVector(CAR(args), INTSXP)); |
3605 | 840 | npos = length(pos); |
3606 | 840 | if (npos <= 0) |
3607 | 0 | errorcall(call, _("invalid '%s' argument"), "pos"); |
3608 | 840 | if (npos == 1) |
3609 | 840 | env = pos2env(INTEGER(pos)[0], call); |
3610 | 0 | else { |
3611 | 0 | PROTECT(env = allocVector(VECSXP, npos)); |
3612 | 0 | for (i = 0; i < npos; i++) { |
3613 | 0 | SET_VECTOR_ELT(env, i, pos2env(INTEGER(pos)[i], call)); |
3614 | 0 | } |
3615 | 0 | UNPROTECT(1); /* env */ |
3616 | 0 | } |
3617 | 840 | UNPROTECT(1); /* pos */ |
3618 | 840 | return env; |
3619 | 840 | } |
3620 | | |
3621 | | static SEXP matchEnvir(SEXP call, const char *what) |
3622 | 0 | { |
3623 | 0 | SEXP t, name; |
3624 | 0 | const void *vmax = vmaxget(); |
3625 | 0 | if(!strcmp(".GlobalEnv", what)) |
3626 | 0 | return R_GlobalEnv; |
3627 | 0 | if(!strcmp("package:base", what)) |
3628 | 0 | return R_BaseEnv; |
3629 | 0 | for (t = ENCLOS(R_GlobalEnv); t != R_EmptyEnv ; t = ENCLOS(t)) { |
3630 | 0 | name = getAttrib(t, R_NameSymbol); |
3631 | 0 | if(isString(name) && length(name) > 0 && |
3632 | 0 | !strcmp(translateChar(STRING_ELT(name, 0)), what)) { |
3633 | 0 | vmaxset(vmax); |
3634 | 0 | return t; |
3635 | 0 | } |
3636 | 0 | } |
3637 | 0 | errorcall(call, _("no item called \"%s\" on the search list"), what); |
3638 | | /* not reached */ |
3639 | 0 | vmaxset(vmax); |
3640 | 0 | return R_NilValue; |
3641 | 0 | } |
3642 | | |
3643 | | /* This is primitive */ |
3644 | | attribute_hidden SEXP |
3645 | | do_as_environment(SEXP call, SEXP op, SEXP args, SEXP rho) |
3646 | 996 | { |
3647 | 996 | SEXP arg = CAR(args), ans; |
3648 | 996 | checkArity(op, args); |
3649 | 996 | check1arg(args, call, "x"); |
3650 | 996 | if(isEnvironment(arg)) |
3651 | 156 | return arg; |
3652 | | /* DispatchOrEval internal generic: as.environment */ |
3653 | 840 | if(isObject(arg) && |
3654 | 0 | DispatchOrEval(call, op, "as.environment", args, rho, &ans, 0, 1)) |
3655 | 0 | return ans; |
3656 | 840 | switch(TYPEOF(arg)) { |
3657 | 0 | case STRSXP: |
3658 | 0 | return matchEnvir(call, translateChar(asChar(arg))); |
3659 | 12 | case REALSXP: |
3660 | 840 | case INTSXP: |
3661 | 840 | return do_pos2env(call, op, args, rho); |
3662 | 0 | case NILSXP: |
3663 | 0 | errorcall(call,_("using 'as.environment(NULL)' is defunct")); |
3664 | 0 | return R_BaseEnv; /* -Wall */ |
3665 | 0 | case OBJSXP: { |
3666 | | /* dispatch was tried above already */ |
3667 | 0 | SEXP dot_xData = R_getS4DataSlot(arg, ENVSXP); |
3668 | 0 | if(!isEnvironment(dot_xData)) |
3669 | 0 | errorcall(call, _("S4 object does not extend class \"environment\"")); |
3670 | 0 | else |
3671 | 0 | return(dot_xData); |
3672 | 0 | } |
3673 | 0 | case VECSXP: { |
3674 | | /* implement as.environment.list() {isObject(.) is false for a list} */ |
3675 | 0 | SEXP call, val; |
3676 | 0 | PROTECT(call = lang4(install("list2env"), arg, |
3677 | 0 | /* envir = */R_NilValue, |
3678 | 0 | /* parent = */R_EmptyEnv)); |
3679 | 0 | val = eval(call, rho); |
3680 | 0 | UNPROTECT(1); |
3681 | 0 | return val; |
3682 | 0 | } |
3683 | 0 | default: |
3684 | 0 | errorcall(call, _("invalid object for 'as.environment'")); |
3685 | 0 | return R_NilValue; /* -Wall */ |
3686 | 840 | } |
3687 | 840 | } |
3688 | | |
3689 | | void R_LockEnvironment(SEXP env, Rboolean bindings) |
3690 | 330 | { |
3691 | 330 | if(IS_S4_OBJECT(env) && (TYPEOF(env) == OBJSXP)) |
3692 | 0 | env = R_getS4DataSlot(env, ANYSXP); /* better be an ENVSXP */ |
3693 | 330 | if (env == R_BaseEnv || env == R_BaseNamespace) { |
3694 | 24 | if (bindings) { |
3695 | 12 | SEXP s; |
3696 | 12 | int j; |
3697 | 589k | for (j = 0; j < HSIZE; j++) |
3698 | 614k | for (s = R_SymbolTable[j]; s != R_NilValue; s = CDR(s)) |
3699 | 24.8k | if(SYMVALUE(CAR(s)) != R_UnboundValue) |
3700 | 16.9k | LOCK_BINDING(CAR(s)); |
3701 | 12 | } |
3702 | 24 | LOCK_FRAME(env); |
3703 | 24 | return; |
3704 | 24 | } |
3705 | | |
3706 | 306 | if (TYPEOF(env) != ENVSXP) |
3707 | 0 | error(_("not an environment")); |
3708 | 306 | if (bindings) { |
3709 | 264 | if (IS_HASHED(env)) { |
3710 | 264 | SEXP table, chain; |
3711 | 264 | int i, size; |
3712 | 264 | table = HASHTAB(env); |
3713 | 264 | size = HASHSIZE(table); |
3714 | 56.9k | for (i = 0; i < size; i++) |
3715 | 56.6k | for (chain = VECTOR_ELT(table, i); |
3716 | 118k | chain != R_NilValue; |
3717 | 62.0k | chain = CDR(chain)) |
3718 | 62.0k | LOCK_BINDING(chain); |
3719 | 264 | } |
3720 | 0 | else { |
3721 | 0 | SEXP frame; |
3722 | 0 | for (frame = FRAME(env); frame != R_NilValue; frame = CDR(frame)) |
3723 | 0 | LOCK_BINDING(frame); |
3724 | 0 | } |
3725 | 264 | } |
3726 | 306 | LOCK_FRAME(env); |
3727 | 306 | } |
3728 | | |
3729 | | Rboolean R_EnvironmentIsLocked(SEXP env) |
3730 | 7.10k | { |
3731 | 7.10k | if (TYPEOF(env) == NILSXP) |
3732 | 0 | error(_("use of NULL environment is defunct")); |
3733 | 7.10k | if (TYPEOF(env) != ENVSXP && |
3734 | 0 | TYPEOF((env = simple_as_environment(env))) != ENVSXP) |
3735 | 0 | error(_("not an environment")); |
3736 | 7.10k | return FRAME_IS_LOCKED(env) != 0; |
3737 | 7.10k | } |
3738 | | |
3739 | | attribute_hidden SEXP do_lockEnv(SEXP call, SEXP op, SEXP args, SEXP rho) |
3740 | 264 | { |
3741 | 264 | SEXP frame; |
3742 | 264 | Rboolean bindings; |
3743 | 264 | checkArity(op, args); |
3744 | 264 | frame = CAR(args); |
3745 | 264 | bindings = asRbool(CADR(args), call); |
3746 | 264 | R_LockEnvironment(frame, bindings); |
3747 | 264 | return R_NilValue; |
3748 | 264 | } |
3749 | | |
3750 | | attribute_hidden SEXP do_envIsLocked(SEXP call, SEXP op, SEXP args, SEXP rho) |
3751 | 216 | { |
3752 | 216 | checkArity(op, args); |
3753 | 216 | return ScalarLogical(R_EnvironmentIsLocked(CAR(args))); |
3754 | 216 | } |
3755 | | |
3756 | | void R_LockBinding(SEXP sym, SEXP env) |
3757 | 0 | { |
3758 | 0 | if (TYPEOF(sym) != SYMSXP) |
3759 | 0 | error(_("not a symbol")); |
3760 | 0 | if (TYPEOF(env) == NILSXP) |
3761 | 0 | error(_("use of NULL environment is defunct")); |
3762 | 0 | if (TYPEOF(env) != ENVSXP && |
3763 | 0 | TYPEOF((env = simple_as_environment(env))) != ENVSXP) |
3764 | 0 | error(_("not an environment")); |
3765 | 0 | if (env == R_BaseEnv || env == R_BaseNamespace) |
3766 | | /* It is a symbol, so must have a binding even if it is |
3767 | | R_UnboundSymbol */ |
3768 | 0 | LOCK_BINDING(sym); |
3769 | 0 | else { |
3770 | 0 | SEXP binding = findVarLocInFrame(env, sym, NULL); |
3771 | 0 | if (binding == R_NilValue) |
3772 | 0 | error(_("no binding for \"%s\""), EncodeChar(PRINTNAME(sym))); |
3773 | 0 | LOCK_BINDING(binding); |
3774 | 0 | } |
3775 | 0 | } |
3776 | | |
3777 | | void R_unLockBinding(SEXP sym, SEXP env) |
3778 | 36 | { |
3779 | 36 | if (TYPEOF(sym) != SYMSXP) |
3780 | 0 | error(_("not a symbol")); |
3781 | 36 | if (TYPEOF(env) == NILSXP) |
3782 | 0 | error(_("use of NULL environment is defunct")); |
3783 | 36 | if (TYPEOF(env) != ENVSXP && |
3784 | 0 | TYPEOF((env = simple_as_environment(env))) != ENVSXP) |
3785 | 0 | error(_("not an environment")); |
3786 | 36 | if (env == R_BaseEnv || env == R_BaseNamespace) |
3787 | | /* It is a symbol, so must have a binding even if it is |
3788 | | R_UnboundSymbol */ |
3789 | 24 | UNLOCK_BINDING(sym); |
3790 | 12 | else { |
3791 | 12 | SEXP binding = findVarLocInFrame(env, sym, NULL); |
3792 | 12 | if (binding == R_NilValue) |
3793 | 0 | error(_("no binding for \"%s\""), EncodeChar(PRINTNAME(sym))); |
3794 | 12 | UNLOCK_BINDING(binding); |
3795 | 12 | } |
3796 | 36 | } |
3797 | | |
3798 | 0 | void R_MakeDelayedBinding(SEXP sym, SEXP expr, SEXP evalEnv, SEXP env) { |
3799 | 0 | if (TYPEOF(sym) != SYMSXP) |
3800 | 0 | error(_("not a symbol")); |
3801 | 0 | if (TYPEOF(env) != ENVSXP) |
3802 | 0 | error(_("not an environment")); |
3803 | 0 | if (TYPEOF(evalEnv) != ENVSXP) |
3804 | 0 | error(_("not an environment")); |
3805 | 0 | defineVar(sym, Rf_mkPROMISE(expr, evalEnv), env); |
3806 | 0 | } |
3807 | | |
3808 | 0 | void R_MakeForcedBinding(SEXP sym, SEXP expr, SEXP value, SEXP env) { |
3809 | 0 | if (TYPEOF(sym) != SYMSXP) |
3810 | 0 | error(_("not a symbol")); |
3811 | 0 | if (TYPEOF(env) != ENVSXP) |
3812 | 0 | error(_("not an environment")); |
3813 | 0 | defineVar(sym, R_mkEVPROMISE(expr, value), env); |
3814 | 0 | } |
3815 | | |
3816 | 0 | void R_MakeMissingBinding(SEXP sym, SEXP env) { |
3817 | 0 | if (TYPEOF(sym) != SYMSXP) |
3818 | 0 | error(_("not a symbol")); |
3819 | 0 | if (TYPEOF(env) != ENVSXP) |
3820 | 0 | error(_("not an environment")); |
3821 | 0 | defineVar(sym, R_MissingArg, env); |
3822 | 0 | } |
3823 | | |
3824 | | void R_MakeActiveBinding(SEXP sym, SEXP fun, SEXP env) |
3825 | 24 | { |
3826 | 24 | if (TYPEOF(sym) != SYMSXP) |
3827 | 0 | error(_("not a symbol")); |
3828 | 24 | if (! isFunction(fun)) |
3829 | 0 | error(_("not a function")); |
3830 | 24 | if (TYPEOF(env) == NILSXP) |
3831 | 0 | error(_("use of NULL environment is defunct")); |
3832 | 24 | if (TYPEOF(env) != ENVSXP && |
3833 | 0 | TYPEOF((env = simple_as_environment(env))) != ENVSXP) |
3834 | 0 | error(_("not an environment")); |
3835 | 24 | if (env == R_BaseEnv || env == R_BaseNamespace) { |
3836 | 12 | if (SYMVALUE(sym) != R_UnboundValue && ! IS_ACTIVE_BINDING(sym)) |
3837 | 0 | error(_("symbol already has a regular binding")); |
3838 | 12 | else if (BINDING_IS_LOCKED(sym)) |
3839 | 0 | error(_("cannot change active binding if binding is locked")); |
3840 | 12 | SET_SYMVALUE(sym, fun); |
3841 | 12 | SET_ACTIVE_BINDING_BIT(sym); |
3842 | | /* we don't need to worry about the global cache here as |
3843 | | a regular binding cannot be changed */ |
3844 | 12 | } |
3845 | 12 | else { |
3846 | 12 | SEXP binding = findVarLocInFrame(env, sym, NULL); |
3847 | 12 | if (binding == R_NilValue) { |
3848 | 12 | defineVar(sym, fun, env); /* fails if env is locked */ |
3849 | 12 | binding = findVarLocInFrame(env, sym, NULL); |
3850 | 12 | SET_ACTIVE_BINDING_BIT(binding); |
3851 | 12 | } |
3852 | 0 | else if (! IS_ACTIVE_BINDING(binding)) |
3853 | 0 | error(_("symbol already has a regular binding")); |
3854 | 0 | else if (BINDING_IS_LOCKED(binding)) |
3855 | 0 | error(_("cannot change active binding if binding is locked")); |
3856 | 0 | else |
3857 | 0 | SETCAR(binding, fun); |
3858 | 12 | } |
3859 | 24 | } |
3860 | | |
3861 | | Rboolean R_BindingIsLocked(SEXP sym, SEXP env) |
3862 | 12 | { |
3863 | 12 | if (TYPEOF(sym) != SYMSXP) |
3864 | 0 | error(_("not a symbol")); |
3865 | 12 | if (TYPEOF(env) == NILSXP) |
3866 | 0 | error(_("use of NULL environment is defunct")); |
3867 | 12 | if (TYPEOF(env) != ENVSXP && |
3868 | 0 | TYPEOF((env = simple_as_environment(env))) != ENVSXP) |
3869 | 0 | error(_("not an environment")); |
3870 | 12 | if (env == R_BaseEnv || env == R_BaseNamespace) |
3871 | | /* It is a symbol, so must have a binding even if it is |
3872 | | R_UnboundSymbol */ |
3873 | 12 | return BINDING_IS_LOCKED(sym) != 0; |
3874 | 0 | else { |
3875 | 0 | SEXP binding = findVarLocInFrame(env, sym, NULL); |
3876 | 0 | if (binding == R_NilValue) |
3877 | 0 | error(_("no binding for \"%s\""), EncodeChar(PRINTNAME(sym))); |
3878 | 0 | return BINDING_IS_LOCKED(binding) != 0; |
3879 | 0 | } |
3880 | 12 | } |
3881 | | |
3882 | | Rboolean R_BindingIsActive(SEXP sym, SEXP env) |
3883 | 12 | { |
3884 | 12 | if (TYPEOF(sym) != SYMSXP) |
3885 | 0 | error(_("not a symbol")); |
3886 | 12 | if (TYPEOF(env) == NILSXP) |
3887 | 0 | error(_("use of NULL environment is defunct")); |
3888 | 12 | if (TYPEOF(env) != ENVSXP && |
3889 | 0 | TYPEOF((env = simple_as_environment(env))) != ENVSXP) |
3890 | 0 | error(_("not an environment")); |
3891 | 12 | if (env == R_BaseEnv || env == R_BaseNamespace) |
3892 | | /* It is a symbol, so must have a binding even if it is |
3893 | | R_UnboundSymbol */ |
3894 | 12 | return IS_ACTIVE_BINDING(sym) != 0; |
3895 | 0 | else { |
3896 | 0 | SEXP binding = findVarLocInFrame(env, sym, NULL); |
3897 | 0 | if (binding == R_NilValue) |
3898 | 0 | error(_("no binding for \"%s\""), EncodeChar(PRINTNAME(sym))); |
3899 | 0 | return IS_ACTIVE_BINDING(binding) != 0; |
3900 | 0 | } |
3901 | 12 | } |
3902 | | |
3903 | | attribute_hidden Rboolean R_HasFancyBindings(SEXP rho) |
3904 | 0 | { |
3905 | 0 | if (IS_HASHED(rho)) { |
3906 | 0 | SEXP table, chain; |
3907 | 0 | int i, size; |
3908 | |
|
3909 | 0 | table = HASHTAB(rho); |
3910 | 0 | size = HASHSIZE(table); |
3911 | 0 | for (i = 0; i < size; i++) |
3912 | 0 | for (chain = VECTOR_ELT(table, i); |
3913 | 0 | chain != R_NilValue; |
3914 | 0 | chain = CDR(chain)) |
3915 | 0 | if (IS_ACTIVE_BINDING(chain) || BINDING_IS_LOCKED(chain)) |
3916 | 0 | return TRUE; |
3917 | 0 | return FALSE; |
3918 | 0 | } |
3919 | 0 | else { |
3920 | 0 | SEXP frame; |
3921 | |
|
3922 | 0 | for (frame = FRAME(rho); frame != R_NilValue; frame = CDR(frame)) |
3923 | 0 | if (IS_ACTIVE_BINDING(frame) || BINDING_IS_LOCKED(frame)) |
3924 | 0 | return TRUE; |
3925 | 0 | return FALSE; |
3926 | 0 | } |
3927 | 0 | } |
3928 | | |
3929 | | /* Like BINDING_VALUE but handles symbol cells (base namespace) via |
3930 | | SYMVALUE instead of CAR. Also signals an error for active bindings. */ |
3931 | | static R_INLINE SEXP BINDING_OR_SYMBOL_VALUE(SEXP cell) |
3932 | 0 | { |
3933 | 0 | if (IS_ACTIVE_BINDING(cell)) |
3934 | 0 | error("BINDING_OR_SYMBOL_VALUE called on active binding"); |
3935 | |
|
3936 | 0 | if (TYPEOF(cell) == SYMSXP) |
3937 | 0 | return SYMVALUE(cell); |
3938 | | |
3939 | 0 | if (BNDCELL_TAG(cell)) { |
3940 | 0 | R_expand_binding_value(cell); |
3941 | 0 | return CAR0(cell); |
3942 | 0 | } |
3943 | | |
3944 | 0 | return CAR(cell); |
3945 | 0 | } |
3946 | | |
3947 | | // get the expression for a delayed or forced binding |
3948 | | static SEXP R_GetVarLocExpression(R_varloc_t loc) |
3949 | 0 | { |
3950 | 0 | SEXP cell = loc.cell; |
3951 | 0 | if (cell == NULL || cell == R_UnboundValue) |
3952 | 0 | error(_("unbound variable")); |
3953 | |
|
3954 | 0 | SEXP value = BINDING_OR_SYMBOL_VALUE(cell); |
3955 | 0 | if (TYPEOF(value) != PROMSXP) |
3956 | 0 | error(_("not a delayed or forced binding")); |
3957 | |
|
3958 | 0 | Rboolean forced; |
3959 | 0 | SEXP inner = promiseUnwrap(value, &forced); |
3960 | | |
3961 | | /* This has special handling for bytecode, unlike `PREXPR()` */ |
3962 | 0 | return R_PromiseExpr(inner); |
3963 | |
|
3964 | 0 | } |
3965 | | |
3966 | | SEXP R_DelayedBindingExpression(SEXP sym, SEXP env) |
3967 | 0 | { |
3968 | 0 | R_varloc_t loc = R_findVarLocInFrameCheck(env, sym); |
3969 | 0 | if (R_GetVarLocType(loc) != R_BindingTypeDelayed) |
3970 | 0 | error(_("not a delayed binding")); |
3971 | 0 | return R_GetVarLocExpression(loc); |
3972 | 0 | } |
3973 | | |
3974 | | SEXP R_ForcedBindingExpression(SEXP sym, SEXP env) |
3975 | 0 | { |
3976 | 0 | R_varloc_t loc = R_findVarLocInFrameCheck(env, sym); |
3977 | 0 | if (R_GetVarLocType(loc) != R_BindingTypeForced) |
3978 | 0 | error(_("not a forced binding")); |
3979 | 0 | return R_GetVarLocExpression(loc); |
3980 | 0 | } |
3981 | | |
3982 | | // get the environment for a delayed binding |
3983 | 0 | SEXP R_DelayedBindingEnvironment(SEXP sym, SEXP env) { |
3984 | 0 | R_varloc_t loc = R_findVarLocInFrameCheck(env, sym); |
3985 | 0 | SEXP cell = loc.cell; |
3986 | 0 | if (cell == NULL || cell == R_UnboundValue) |
3987 | 0 | error(_("unbound variable")); |
3988 | |
|
3989 | 0 | SEXP value = BINDING_OR_SYMBOL_VALUE(cell); |
3990 | 0 | if (TYPEOF(value) != PROMSXP) |
3991 | 0 | error(_("not a delayed binding")); |
3992 | |
|
3993 | 0 | Rboolean forced; |
3994 | 0 | SEXP inner = promiseUnwrap(value, &forced); |
3995 | 0 | if (forced) |
3996 | 0 | error(_("not a delayed binding")); |
3997 | |
|
3998 | 0 | return PRENV(inner); |
3999 | 0 | } |
4000 | | |
4001 | | SEXP R_ActiveBindingFunction(SEXP sym, SEXP env) |
4002 | 0 | { |
4003 | 0 | if (TYPEOF(sym) != SYMSXP) |
4004 | 0 | error(_("not a symbol")); |
4005 | 0 | if (TYPEOF(env) == NILSXP) |
4006 | 0 | error(_("use of NULL environment is defunct")); |
4007 | 0 | if (TYPEOF(env) != ENVSXP && |
4008 | 0 | TYPEOF((env = simple_as_environment(env))) != ENVSXP) |
4009 | 0 | error(_("not an environment")); |
4010 | 0 | if (env == R_BaseEnv || env == R_BaseNamespace) { |
4011 | 0 | SEXP val = SYMVALUE(sym); |
4012 | 0 | if (val == R_UnboundValue) |
4013 | 0 | error(_("no binding for \"%s\""), EncodeChar(PRINTNAME(sym))); |
4014 | 0 | if (! IS_ACTIVE_BINDING(sym)) |
4015 | 0 | error(_("no active binding for \"%s\""), |
4016 | 0 | EncodeChar(PRINTNAME(sym))); |
4017 | 0 | return val; |
4018 | 0 | } |
4019 | 0 | else { |
4020 | 0 | SEXP binding = findVarLocInFrame(env, sym, NULL); |
4021 | 0 | if (binding == R_NilValue) |
4022 | 0 | error(_("no binding for \"%s\""), EncodeChar(PRINTNAME(sym))); |
4023 | 0 | if (! IS_ACTIVE_BINDING(binding)) |
4024 | 0 | error(_("no active binding for \"%s\""), |
4025 | 0 | EncodeChar(PRINTNAME(sym))); |
4026 | 0 | return CAR(binding); |
4027 | 0 | } |
4028 | 0 | } |
4029 | | |
4030 | | attribute_hidden SEXP do_lockBnd(SEXP call, SEXP op, SEXP args, SEXP rho) |
4031 | 12 | { |
4032 | 12 | SEXP sym, env; |
4033 | 12 | checkArity(op, args); |
4034 | 12 | sym = CAR(args); |
4035 | 12 | env = CADR(args); |
4036 | 12 | switch(PRIMVAL(op)) { |
4037 | 0 | case 0: |
4038 | 0 | R_LockBinding(sym, env); |
4039 | 0 | break; |
4040 | 12 | case 1: |
4041 | 12 | R_unLockBinding(sym, env); |
4042 | 12 | break; |
4043 | 0 | default: |
4044 | 0 | error(_("unknown op")); |
4045 | 12 | } |
4046 | 12 | return R_NilValue; |
4047 | 12 | } |
4048 | | |
4049 | | attribute_hidden SEXP do_bndIsLocked(SEXP call, SEXP op, SEXP args, SEXP rho) |
4050 | 0 | { |
4051 | 0 | SEXP sym, env; |
4052 | 0 | checkArity(op, args); |
4053 | 0 | sym = CAR(args); |
4054 | 0 | env = CADR(args); |
4055 | 0 | return ScalarLogical(R_BindingIsLocked(sym, env)); |
4056 | 0 | } |
4057 | | |
4058 | | attribute_hidden SEXP do_mkActiveBnd(SEXP call, SEXP op, SEXP args, SEXP rho) |
4059 | 24 | { |
4060 | 24 | SEXP sym, fun, env; |
4061 | 24 | checkArity(op, args); |
4062 | 24 | sym = CAR(args); |
4063 | 24 | fun = CADR(args); |
4064 | 24 | env = CADDR(args); |
4065 | 24 | R_MakeActiveBinding(sym, fun, env); |
4066 | 24 | return R_NilValue; |
4067 | 24 | } |
4068 | | |
4069 | | attribute_hidden SEXP do_bndIsActive(SEXP call, SEXP op, SEXP args, SEXP rho) |
4070 | 0 | { |
4071 | 0 | SEXP sym, env; |
4072 | 0 | checkArity(op, args); |
4073 | 0 | sym = CAR(args); |
4074 | 0 | env = CADR(args); |
4075 | 0 | return ScalarLogical(R_BindingIsActive(sym, env)); |
4076 | 0 | } |
4077 | | |
4078 | | attribute_hidden SEXP do_activeBndFun(SEXP call, SEXP op, SEXP args, SEXP rho) |
4079 | 0 | { |
4080 | 0 | SEXP sym, env; |
4081 | 0 | checkArity(op, args); |
4082 | 0 | sym = CAR(args); |
4083 | 0 | env = CADR(args); |
4084 | 0 | return R_ActiveBindingFunction(sym, env); |
4085 | 0 | } |
4086 | | |
4087 | | /* This is a .Internal with no wrapper */ |
4088 | | attribute_hidden SEXP do_mkUnbound(SEXP call, SEXP op, SEXP args, SEXP rho) |
4089 | 12 | { |
4090 | 12 | SEXP sym; |
4091 | 12 | checkArity(op, args); |
4092 | 12 | sym = CAR(args); |
4093 | | |
4094 | 12 | if (TYPEOF(sym) != SYMSXP) error(_("not a symbol")); |
4095 | | /* This is not quite the same as SET_SYMBOL_BINDING_VALUE as it |
4096 | | does not allow active bindings to be unbound */ |
4097 | 12 | if (FRAME_IS_LOCKED(R_BaseEnv)) |
4098 | 0 | error(_("cannot remove bindings from a locked environment")); |
4099 | 12 | if (R_BindingIsLocked(sym, R_BaseEnv)) |
4100 | 0 | error(_("cannot unbind a locked binding")); |
4101 | 12 | if (R_BindingIsActive(sym, R_BaseEnv)) |
4102 | 0 | error(_("cannot unbind an active binding")); |
4103 | 12 | SET_SYMVALUE(sym, R_UnboundValue); |
4104 | 12 | #ifdef USE_GLOBAL_CACHE |
4105 | 12 | R_FlushGlobalCache(sym); |
4106 | 12 | #endif |
4107 | 12 | return R_NilValue; |
4108 | 12 | } |
4109 | | |
4110 | | /* C version of new.env */ |
4111 | | SEXP R_NewEnv(SEXP enclos, int hash, int size) |
4112 | 4.39k | { |
4113 | 4.39k | if (hash) |
4114 | 4.38k | return R_NewHashedEnv(enclos, size); |
4115 | 12 | else |
4116 | 12 | return NewEnvironment(R_NilValue, R_NilValue, enclos); |
4117 | 4.39k | } |
4118 | | |
4119 | | attribute_hidden void R_RestoreHashCount(SEXP rho) |
4120 | 47 | { |
4121 | 47 | if (IS_HASHED(rho)) { |
4122 | 5 | SEXP table; |
4123 | 5 | int i, count, size; |
4124 | | |
4125 | 5 | table = HASHTAB(rho); |
4126 | 5 | size = HASHSIZE(table); |
4127 | 6 | for (i = 0, count = 0; i < size; i++) |
4128 | 1 | if (VECTOR_ELT(table, i) != R_NilValue) |
4129 | 0 | count++; |
4130 | 5 | SET_HASHPRI(table, count); |
4131 | 5 | } |
4132 | 47 | } |
4133 | | |
4134 | | Rboolean R_IsPackageEnv(SEXP rho) |
4135 | 4.12M | { |
4136 | 4.12M | if (TYPEOF(rho) == ENVSXP) { |
4137 | 4.12M | SEXP name = getAttrib(rho, R_NameSymbol); |
4138 | 4.12M | char *packprefix = "package:"; |
4139 | 4.12M | size_t pplen = strlen(packprefix); |
4140 | 4.12M | if(isString(name) && length(name) > 0 && |
4141 | 0 | ! strncmp(packprefix, CHAR(STRING_ELT(name, 0)), pplen)) /* ASCII */ |
4142 | 0 | return TRUE; |
4143 | 4.12M | else |
4144 | 4.12M | return FALSE; |
4145 | 4.12M | } |
4146 | 0 | else |
4147 | 0 | return FALSE; |
4148 | 4.12M | } |
4149 | | |
4150 | | SEXP R_PackageEnvName(SEXP rho) |
4151 | 0 | { |
4152 | 0 | if (TYPEOF(rho) == ENVSXP) { |
4153 | 0 | SEXP name = getAttrib(rho, R_NameSymbol); |
4154 | 0 | char *packprefix = "package:"; |
4155 | 0 | size_t pplen = strlen(packprefix); |
4156 | 0 | if(isString(name) && length(name) > 0 && |
4157 | 0 | ! strncmp(packprefix, CHAR(STRING_ELT(name, 0)), pplen)) /* ASCII */ |
4158 | 0 | return name; |
4159 | 0 | else |
4160 | 0 | return R_NilValue; |
4161 | 0 | } |
4162 | 0 | else |
4163 | 0 | return R_NilValue; |
4164 | 0 | } |
4165 | | |
4166 | | attribute_hidden SEXP R_FindPackageEnv(SEXP info) |
4167 | 2 | { |
4168 | 2 | SEXP expr, val; |
4169 | 2 | PROTECT(info); |
4170 | 2 | SEXP s_findPackageEnv = install("findPackageEnv"); |
4171 | 2 | PROTECT(expr = LCONS(s_findPackageEnv, LCONS(info, R_NilValue))); |
4172 | 2 | val = eval(expr, R_BaseEnv); |
4173 | 2 | UNPROTECT(2); |
4174 | 2 | return val; |
4175 | 2 | } |
4176 | | |
4177 | | Rboolean R_IsNamespaceEnv(SEXP rho) |
4178 | 4.83M | { |
4179 | 4.83M | if (rho == R_BaseNamespace) |
4180 | 348k | return TRUE; |
4181 | 4.48M | else if (TYPEOF(rho) == ENVSXP) { |
4182 | 4.15M | SEXP info = R_findVarInFrame(rho, R_NamespaceSymbol); |
4183 | 4.15M | if (info != R_UnboundValue && TYPEOF(info) == ENVSXP) { |
4184 | 9.93k | PROTECT(info); |
4185 | 9.93k | SEXP spec = R_findVarInFrame(info, install("spec")); |
4186 | 9.93k | UNPROTECT(1); |
4187 | 9.93k | if (spec != R_UnboundValue && |
4188 | 9.93k | TYPEOF(spec) == STRSXP && LENGTH(spec) > 0) |
4189 | 9.93k | return TRUE; |
4190 | 0 | else |
4191 | 0 | return FALSE; |
4192 | 9.93k | } |
4193 | 4.14M | else return FALSE; |
4194 | 4.15M | } |
4195 | 334k | else return FALSE; |
4196 | 4.83M | } |
4197 | | |
4198 | | attribute_hidden SEXP do_isNSEnv(SEXP call, SEXP op, SEXP args, SEXP rho) |
4199 | 4.00k | { |
4200 | 4.00k | checkArity(op, args); |
4201 | 4.00k | return R_IsNamespaceEnv(CAR(args)) ? mkTrue() : mkFalse(); |
4202 | 4.00k | } |
4203 | | |
4204 | | SEXP R_NamespaceEnvSpec(SEXP rho) |
4205 | 17.2k | { |
4206 | | /* The namespace spec is a character vector that specifies the |
4207 | | namespace. The first element is the namespace name. The |
4208 | | second element, if present, is the namespace version. Further |
4209 | | elements may be added later. */ |
4210 | 17.2k | if (rho == R_BaseNamespace) |
4211 | 17.2k | return R_BaseNamespaceName; |
4212 | 0 | else if (TYPEOF(rho) == ENVSXP) { |
4213 | 0 | SEXP info = R_findVarInFrame(rho, R_NamespaceSymbol); |
4214 | 0 | if (info != R_UnboundValue && TYPEOF(info) == ENVSXP) { |
4215 | 0 | PROTECT(info); |
4216 | 0 | SEXP spec = R_findVarInFrame(info, install("spec")); |
4217 | 0 | UNPROTECT(1); |
4218 | 0 | if (spec != R_UnboundValue && |
4219 | 0 | TYPEOF(spec) == STRSXP && LENGTH(spec) > 0) |
4220 | 0 | return spec; |
4221 | 0 | else |
4222 | 0 | return R_NilValue; |
4223 | 0 | } |
4224 | 0 | else return R_NilValue; |
4225 | 0 | } |
4226 | 0 | else return R_NilValue; |
4227 | 17.2k | } |
4228 | | |
4229 | | SEXP R_FindNamespace(SEXP info) |
4230 | 25.5k | { |
4231 | 25.5k | SEXP expr, val; |
4232 | 25.5k | PROTECT(info); |
4233 | 25.5k | SEXP s_getNamespace = install("getNamespace"); |
4234 | 25.5k | PROTECT(expr = LCONS(s_getNamespace, LCONS(info, R_NilValue))); |
4235 | 25.5k | val = eval(expr, R_BaseEnv); |
4236 | 25.5k | UNPROTECT(2); |
4237 | 25.5k | return val; |
4238 | 25.5k | } |
4239 | | |
4240 | | static SEXP checkNSname(SEXP call, SEXP name) |
4241 | 395k | { |
4242 | 395k | switch (TYPEOF(name)) { |
4243 | 395k | case SYMSXP: |
4244 | 395k | break; |
4245 | 84 | case STRSXP: |
4246 | 84 | if (LENGTH(name) >= 1) { |
4247 | 84 | name = installTrChar(STRING_ELT(name, 0)); |
4248 | 84 | break; |
4249 | 84 | } |
4250 | | /* else fall through */ |
4251 | 0 | default: |
4252 | 0 | errorcall(call, _("bad namespace name")); |
4253 | 395k | } |
4254 | 395k | return name; |
4255 | 395k | } |
4256 | | |
4257 | | // .Internal(registerNamespace(name, env)) |
4258 | | attribute_hidden SEXP do_regNS(SEXP call, SEXP op, SEXP args, SEXP rho) |
4259 | 84 | { |
4260 | 84 | SEXP name, val; |
4261 | 84 | checkArity(op, args); |
4262 | 84 | name = checkNSname(call, CAR(args)); |
4263 | 84 | val = CADR(args); |
4264 | 84 | if (R_findVarInFrame(R_NamespaceRegistry, name) != R_UnboundValue) |
4265 | 0 | errorcall(call, _("namespace already registered")); |
4266 | 84 | defineVar(name, val, R_NamespaceRegistry); |
4267 | 84 | return R_NilValue; |
4268 | 84 | } |
4269 | | |
4270 | | // .Internal(unregisterNamespace(nsname)) |
4271 | | attribute_hidden SEXP do_unregNS(SEXP call, SEXP op, SEXP args, SEXP rho) |
4272 | 0 | { |
4273 | 0 | SEXP name; |
4274 | 0 | int hashcode; |
4275 | 0 | checkArity(op, args); |
4276 | 0 | name = checkNSname(call, CAR(args)); |
4277 | 0 | if (R_findVarInFrame(R_NamespaceRegistry, name) == R_UnboundValue) |
4278 | 0 | errorcall(call, _("namespace not registered")); |
4279 | 0 | if( !HASHASH(PRINTNAME(name))) |
4280 | 0 | hashcode = R_Newhashpjw(CHAR(PRINTNAME(name))); |
4281 | 0 | else |
4282 | 0 | hashcode = HASHVALUE(PRINTNAME(name)); |
4283 | 0 | RemoveVariable(name, hashcode, R_NamespaceRegistry); |
4284 | 0 | return R_NilValue; |
4285 | 0 | } |
4286 | | |
4287 | | // .Internal(getRegisteredNamespace(name)) == .getNamespace(name) |
4288 | | // .Internal(isRegisteredNamespace (name)) == isNamespaceLoaded(name) |
4289 | | attribute_hidden SEXP do_getRegNS(SEXP call, SEXP op, SEXP args, SEXP rho) |
4290 | 61.1k | { |
4291 | 61.1k | checkArity(op, args); |
4292 | 61.1k | SEXP name = checkNSname(call, PROTECT(coerceVector(CAR(args), SYMSXP))); |
4293 | 61.1k | UNPROTECT(1); |
4294 | 61.1k | SEXP val = R_findVarInFrame(R_NamespaceRegistry, name); |
4295 | | |
4296 | 61.1k | switch(PRIMVAL(op)) { |
4297 | 46.3k | case 0: // get..() |
4298 | 46.3k | if (val == R_UnboundValue) |
4299 | 29.7k | return R_NilValue; |
4300 | 16.6k | else |
4301 | 16.6k | return val; |
4302 | 14.7k | case 1: // is..() |
4303 | 14.7k | return ScalarLogical(val == R_UnboundValue ? FALSE : TRUE); |
4304 | | |
4305 | 0 | default: error(_("unknown op")); |
4306 | 61.1k | } |
4307 | 0 | return R_NilValue; // -Wall |
4308 | 61.1k | } |
4309 | | |
4310 | | SEXP R_getRegisteredNamespace(const char *name) |
4311 | 0 | { |
4312 | 0 | SEXP sym = install(name); |
4313 | 0 | SEXP val = R_findVarInFrame(R_NamespaceRegistry, sym); |
4314 | 0 | if (val == R_UnboundValue) |
4315 | 0 | return R_NilValue; |
4316 | 0 | else |
4317 | 0 | return val; |
4318 | 0 | } |
4319 | | |
4320 | | // .Internal(getNamespaceRegistry()) |
4321 | | attribute_hidden SEXP do_getNSRegistry(SEXP call, SEXP op, SEXP args, SEXP rho) |
4322 | 0 | { |
4323 | 0 | checkArity(op, args); |
4324 | 0 | return R_NamespaceRegistry; |
4325 | 0 | } |
4326 | | |
4327 | | static SEXP getVarValInFrame(SEXP rho, SEXP sym, int unbound_ok) |
4328 | 346k | { |
4329 | 346k | SEXP val = R_findVarInFrame(rho, sym); |
4330 | 346k | if (! unbound_ok && val == R_UnboundValue) |
4331 | 0 | R_ObjectNotFoundError(sym, R_CurrentExpression, NULL); |
4332 | 346k | if (TYPEOF(val) == PROMSXP) { |
4333 | 96 | PROTECT(val); |
4334 | 96 | val = eval(val, R_EmptyEnv); |
4335 | 96 | UNPROTECT(1); |
4336 | 96 | } |
4337 | 346k | return val; |
4338 | 346k | } |
4339 | | |
4340 | | static SEXP checkVarName(SEXP call, SEXP name) |
4341 | 340k | { |
4342 | 340k | switch(TYPEOF(name)) { |
4343 | 334k | case SYMSXP: break; |
4344 | 5.71k | case STRSXP: |
4345 | 5.71k | if (LENGTH(name) >= 1) { |
4346 | 5.71k | name = installTrChar(STRING_ELT(name, 0)); |
4347 | 5.71k | break; |
4348 | 5.71k | } |
4349 | | /* else fall through */ |
4350 | 0 | default: |
4351 | 0 | errorcall(call, _("bad variable name")); |
4352 | 340k | } |
4353 | 340k | return name; |
4354 | 340k | } |
4355 | | |
4356 | | static SEXP callR1(SEXP fun, SEXP arg) |
4357 | 0 | { |
4358 | 0 | static SEXP R_xSymbol = NULL; |
4359 | 0 | if (R_xSymbol == NULL) |
4360 | 0 | R_xSymbol = install("x"); |
4361 | |
|
4362 | 0 | SEXP rho = PROTECT(NewEnvironment(R_NilValue, R_NilValue, R_BaseNamespace)); |
4363 | 0 | defineVar(R_xSymbol, arg, rho); |
4364 | 0 | SEXP expr = PROTECT(lang2(fun, R_xSymbol)); |
4365 | 0 | SEXP val = eval(expr, rho); |
4366 | | /**** ideally this should clear out rho if it isn't captured - LT */ |
4367 | 0 | UNPROTECT(2); /* rho, expr */ |
4368 | 0 | return val; |
4369 | 0 | } |
4370 | | |
4371 | | attribute_hidden SEXP R_getNSValue(SEXP call, SEXP ns, SEXP name, int exported) |
4372 | 334k | { |
4373 | 334k | static SEXP R_loadNamespaceSymbol = NULL; |
4374 | 334k | static SEXP R_exportsSymbol = NULL; |
4375 | 334k | static SEXP R_lazydataSymbol = NULL; |
4376 | 334k | static SEXP R_getNamespaceNameSymbol = NULL; |
4377 | 334k | if (R_loadNamespaceSymbol == NULL) { |
4378 | 12 | R_loadNamespaceSymbol = install("loadNamespace"); |
4379 | 12 | R_exportsSymbol = install("exports"); |
4380 | 12 | R_lazydataSymbol = install("lazydata"); |
4381 | 12 | R_getNamespaceNameSymbol = install("getNamespaceName"); |
4382 | 12 | } |
4383 | | |
4384 | 334k | if (R_IsNamespaceEnv(ns)) |
4385 | 0 | PROTECT(ns); |
4386 | 334k | else { |
4387 | 334k | SEXP pkg = checkNSname(call, ns); |
4388 | 334k | ns = R_findVarInFrame(R_NamespaceRegistry, pkg); |
4389 | 334k | if (ns == R_UnboundValue) |
4390 | 0 | ns = callR1(R_loadNamespaceSymbol, pkg); |
4391 | 334k | PROTECT(ns); |
4392 | 334k | if (! R_IsNamespaceEnv(ns)) |
4393 | 0 | errorcall(call, _("bad namespace")); |
4394 | 334k | } |
4395 | | |
4396 | 334k | name = checkVarName(call, name); |
4397 | | |
4398 | 334k | SEXP val; |
4399 | | |
4400 | | /* base or non-exported variables */ |
4401 | 334k | if (ns == R_BaseNamespace || ! exported) { |
4402 | 328k | val = getVarValInFrame(ns, name, FALSE); |
4403 | 328k | UNPROTECT(1); /* ns */ |
4404 | 328k | return val; |
4405 | 328k | } |
4406 | | |
4407 | | /* exported variables */ |
4408 | 5.71k | SEXP info = PROTECT(getVarValInFrame(ns, R_NamespaceSymbol, FALSE)); |
4409 | 5.71k | SEXP exports = PROTECT(getVarValInFrame(info, R_exportsSymbol, FALSE)); |
4410 | 5.71k | SEXP exportName = PROTECT(getVarValInFrame(exports, name, TRUE)); |
4411 | 5.71k | if (exportName != R_UnboundValue) { |
4412 | 5.71k | val = eval(checkVarName(call, exportName), ns); |
4413 | 5.71k | UNPROTECT(4); /* ns, info, exports, exportName */ |
4414 | 5.71k | return val; |
4415 | 5.71k | } |
4416 | | |
4417 | | /* lazydata */ |
4418 | 0 | SEXP ld = PROTECT(getVarValInFrame(info, R_lazydataSymbol, FALSE)); |
4419 | 0 | val = getVarValInFrame(ld, name, TRUE); |
4420 | 0 | if (val != R_UnboundValue) { |
4421 | 0 | UNPROTECT(5); /* ns, info, exports, exportName, ld */ |
4422 | 0 | return val; |
4423 | 0 | } |
4424 | | |
4425 | 0 | SEXP nsname = PROTECT(callR1(R_getNamespaceNameSymbol, ns)); |
4426 | 0 | if (TYPEOF(nsname) != STRSXP || LENGTH(nsname) != 1) |
4427 | 0 | errorcall(call, "bad value returned by `getNamespaceName'"); |
4428 | 0 | errorcall_cpy(call, |
4429 | 0 | _("'%s' is not an exported object from 'namespace:%s'"), |
4430 | 0 | EncodeChar(PRINTNAME(name)), |
4431 | 0 | CHAR(STRING_ELT(nsname, 0))); |
4432 | 0 | return NULL; /* not reached */ |
4433 | 0 | } |
4434 | | |
4435 | | attribute_hidden SEXP do_getNSValue(SEXP call, SEXP op, SEXP args, SEXP rho) |
4436 | 0 | { |
4437 | 0 | checkArity(op, args); |
4438 | 0 | SEXP ns = CAR(args); |
4439 | 0 | SEXP name = CADR(args); |
4440 | 0 | int exported = asLogical(CADDR(args)); |
4441 | |
|
4442 | 0 | return R_getNSValue(R_NilValue, ns, name, exported); |
4443 | 0 | } |
4444 | | |
4445 | | attribute_hidden |
4446 | | SEXP do_colon2(SEXP call, SEXP op, SEXP args, SEXP rho) |
4447 | 334k | { |
4448 | 334k | checkArity(op, args); |
4449 | | /* use R_NilValue for the call to avoid changing the error message */ |
4450 | 334k | return R_getNSValue(R_NilValue, CAR(args), CADR(args), TRUE); |
4451 | 334k | } |
4452 | | |
4453 | | attribute_hidden |
4454 | | SEXP do_colon3(SEXP call, SEXP op, SEXP args, SEXP rho) |
4455 | 96 | { |
4456 | 96 | checkArity(op, args); |
4457 | 96 | return R_getNSValue(call, CAR(args), CADR(args), FALSE); |
4458 | 96 | } |
4459 | | |
4460 | | attribute_hidden SEXP do_importIntoEnv(SEXP call, SEXP op, SEXP args, SEXP rho) |
4461 | 240 | { |
4462 | | /* This function copies values of variables from one environment |
4463 | | to another environment, possibly with different names. |
4464 | | Promises are not forced and active bindings are preserved. */ |
4465 | 240 | SEXP impenv, impnames, expenv, expnames; |
4466 | 240 | SEXP impsym, expsym, val; |
4467 | 240 | int i, n; |
4468 | | |
4469 | 240 | checkArity(op, args); |
4470 | | |
4471 | 240 | impenv = CAR(args); args = CDR(args); |
4472 | 240 | impnames = CAR(args); args = CDR(args); |
4473 | 240 | expenv = CAR(args); args = CDR(args); |
4474 | 240 | expnames = CAR(args); args = CDR(args); |
4475 | | |
4476 | 240 | if (TYPEOF(impenv) == NILSXP) |
4477 | 0 | error(_("use of NULL environment is defunct")); |
4478 | 240 | if (TYPEOF(impenv) != ENVSXP && |
4479 | 0 | TYPEOF((impenv = simple_as_environment(impenv))) != ENVSXP) |
4480 | 0 | error(_("bad import environment argument")); |
4481 | 240 | if (TYPEOF(expenv) == NILSXP) |
4482 | 0 | error(_("use of NULL environment is defunct")); |
4483 | 240 | if (TYPEOF(expenv) != ENVSXP && |
4484 | 0 | TYPEOF((expenv = simple_as_environment(expenv))) != ENVSXP) |
4485 | 0 | error(_("bad export environment argument")); |
4486 | 240 | if (TYPEOF(impnames) != STRSXP || TYPEOF(expnames) != STRSXP) |
4487 | 0 | error(_("invalid '%s' argument"), "names"); |
4488 | 240 | if (LENGTH(impnames) != LENGTH(expnames)) |
4489 | 0 | error(_("length of import and export names must match")); |
4490 | | |
4491 | 240 | n = LENGTH(impnames); |
4492 | 24.9k | for (i = 0; i < n; i++) { |
4493 | 24.6k | impsym = installTrChar(STRING_ELT(impnames, i)); |
4494 | 24.6k | expsym = installTrChar(STRING_ELT(expnames, i)); |
4495 | | |
4496 | | /* find the binding--may be a CONS cell or a symbol */ |
4497 | 24.6k | SEXP binding = R_NilValue; |
4498 | 24.6k | for (SEXP env = expenv; |
4499 | 49.3k | env != R_EmptyEnv && binding == R_NilValue; |
4500 | 24.7k | env = ENCLOS(env)) |
4501 | 24.7k | if (env == R_BaseNamespace) { |
4502 | 24 | if (SYMVALUE(expsym) != R_UnboundValue) |
4503 | 24 | binding = expsym; |
4504 | 24 | } else |
4505 | 24.6k | binding = findVarLocInFrame(env, expsym, NULL); |
4506 | 24.6k | if (binding == R_NilValue) |
4507 | 0 | binding = expsym; |
4508 | | |
4509 | | /* get value of the binding; do not force promises */ |
4510 | 24.6k | if (TYPEOF(binding) == SYMSXP) { |
4511 | 24 | if (SYMVALUE(expsym) == R_UnboundValue) |
4512 | 0 | error(_("exported symbol '%s' has no value"), |
4513 | 0 | CHAR(PRINTNAME(expsym))); |
4514 | 24 | val = SYMVALUE(expsym); |
4515 | 24 | } |
4516 | 24.6k | else val = CAR(binding); |
4517 | | |
4518 | | /* import the binding */ |
4519 | 24.6k | if (IS_ACTIVE_BINDING(binding)) |
4520 | 0 | R_MakeActiveBinding(impsym, val, impenv); |
4521 | | /* This is just a tiny optimization */ |
4522 | 24.6k | else if (impenv == R_BaseNamespace || impenv == R_BaseEnv) |
4523 | 0 | gsetVar(impsym, val, impenv); |
4524 | 24.6k | else |
4525 | 24.6k | defineVar(impsym, val, impenv); |
4526 | 24.6k | } |
4527 | 240 | return R_NilValue; |
4528 | 240 | } |
4529 | | |
4530 | | |
4531 | | attribute_hidden SEXP do_envprofile(SEXP call, SEXP op, SEXP args, SEXP rho) |
4532 | 0 | { |
4533 | | /* Return a list containing profiling information given a hashed |
4534 | | environment. For non-hashed environments, this function |
4535 | | returns R_NilValue. This seems appropriate since there is no |
4536 | | way to test whether an environment is hashed at the R level. |
4537 | | */ |
4538 | 0 | checkArity(op, args); |
4539 | 0 | SEXP env, ans = R_NilValue /* -Wall */; |
4540 | 0 | env = CAR(args); |
4541 | 0 | if (isEnvironment(env)) { |
4542 | 0 | if (IS_HASHED(env)) |
4543 | 0 | ans = R_HashProfile(HASHTAB(env)); |
4544 | 0 | } else |
4545 | 0 | error("argument must be a hashed environment"); |
4546 | 0 | return ans; |
4547 | 0 | } |
4548 | | |
4549 | | SEXP mkCharCE(const char *name, cetype_t enc) |
4550 | 1.23M | { |
4551 | 1.23M | size_t len = strlen(name); |
4552 | 1.23M | if (len > INT_MAX) |
4553 | 0 | error("R character strings are limited to 2^31-1 bytes"); |
4554 | 1.23M | return mkCharLenCE(name, (int) len, enc); |
4555 | 1.23M | } |
4556 | | |
4557 | | /* no longer used in R but documented in 2.7.x */ |
4558 | | SEXP mkCharLen(const char *name, int len) |
4559 | 0 | { |
4560 | 0 | return mkCharLenCE(name, len, CE_NATIVE); |
4561 | 0 | } |
4562 | | |
4563 | | SEXP mkChar(const char *name) |
4564 | 1.40M | { |
4565 | 1.40M | size_t len = strlen(name); |
4566 | 1.40M | if (len > INT_MAX) |
4567 | 0 | error("R character strings are limited to 2^31-1 bytes"); |
4568 | 1.40M | return mkCharLenCE(name, (int) len, CE_NATIVE); |
4569 | 1.40M | } |
4570 | | |
4571 | | attribute_hidden SEXP mkCharWUTF8(const wchar_t *wname) |
4572 | 0 | { |
4573 | 0 | const void *vmax = vmaxget(); |
4574 | 0 | size_t nb = wcstoutf8(NULL, wname, (size_t)INT_MAX + 2); |
4575 | 0 | if (nb-1 > INT_MAX) { |
4576 | 0 | error("R character strings are limited to 2^31-1 bytes"); |
4577 | 0 | } |
4578 | 0 | char *name = R_alloc(nb, 1); |
4579 | 0 | nb = wcstoutf8(name, wname, nb); |
4580 | 0 | SEXP ans = mkCharLenCE(name, (int)(nb-1), CE_UTF8); |
4581 | 0 | vmaxset(vmax); |
4582 | 0 | return ans; |
4583 | 0 | } |
4584 | | |
4585 | | /* Global CHARSXP cache and code for char-based hash tables */ |
4586 | | |
4587 | | /* We can reuse the hash structure, but need separate code for get/set |
4588 | | of values since our keys are char* and not SEXP symbol types. |
4589 | | |
4590 | | Experience has shown that it is better to use a different hash function, |
4591 | | and a power of 2 for the hash size. |
4592 | | */ |
4593 | | |
4594 | | /* char_hash_size MUST be a power of 2 and char_hash_mask == |
4595 | | char_hash_size - 1 for x & char_hash_mask to be equivalent to x % |
4596 | | char_hash_size. |
4597 | | */ |
4598 | | static unsigned int char_hash_size = 65536; |
4599 | | static unsigned int char_hash_mask = 65535; |
4600 | | |
4601 | | static unsigned int char_hash(const char *s, int len) |
4602 | 3.57M | { |
4603 | | /* djb2 as from http://www.cse.yorku.ca/~oz/hash.html */ |
4604 | 3.57M | char *p; |
4605 | 3.57M | int i; |
4606 | 3.57M | unsigned int h = 5381; |
4607 | 104M | for (p = (char *) s, i = 0; i < len; p++, i++) |
4608 | 101M | h = ((h << 5) + h) + (*p); |
4609 | 3.57M | return h; |
4610 | 3.57M | } |
4611 | | |
4612 | | attribute_hidden void InitStringHash(void) |
4613 | 12 | { |
4614 | 12 | R_StringHash = R_NewHashTable(char_hash_size); |
4615 | 12 | } |
4616 | | |
4617 | | /* #define DEBUG_GLOBAL_STRING_HASH 1 */ |
4618 | | |
4619 | | /* Resize the global R_StringHash CHARSXP cache */ |
4620 | | static void R_StringHash_resize(unsigned int newsize) |
4621 | 0 | { |
4622 | 0 | SEXP old_table = R_StringHash; |
4623 | 0 | SEXP new_table, chain, new_chain, val, next; |
4624 | 0 | unsigned int counter, new_hashcode, newmask; |
4625 | | #ifdef DEBUG_GLOBAL_STRING_HASH |
4626 | | unsigned int oldsize = HASHSIZE(R_StringHash); |
4627 | | unsigned int oldpri = HASHPRI(R_StringHash); |
4628 | | unsigned int newsize, newpri; |
4629 | | #endif |
4630 | | |
4631 | | /* Allocate the new hash table. This could fail to allocate |
4632 | | enough memory, and ideally we would recover from that and |
4633 | | carry over with a table that was getting full. |
4634 | | */ |
4635 | | /* When using the ATTRIB fields to maintain the chains the chain |
4636 | | moving is destructive and does not involve allocation. This is |
4637 | | therefore the only point where GC can occur. */ |
4638 | 0 | new_table = R_NewHashTable(newsize); |
4639 | 0 | newmask = newsize - 1; |
4640 | | |
4641 | | /* transfer chains from old table to new table */ |
4642 | 0 | for (counter = 0; counter < LENGTH(old_table); counter++) { |
4643 | 0 | chain = VECTOR_ELT(old_table, counter); |
4644 | 0 | while (!ISNULL(chain)) { |
4645 | 0 | val = CXHEAD(chain); |
4646 | 0 | next = CXTAIL(chain); |
4647 | 0 | new_hashcode = char_hash(CHAR(val), LENGTH(val)) & newmask; |
4648 | 0 | new_chain = VECTOR_ELT(new_table, new_hashcode); |
4649 | | /* If using a primary slot then increase HASHPRI */ |
4650 | 0 | if (ISNULL(new_chain)) |
4651 | 0 | SET_HASHPRI(new_table, HASHPRI(new_table) + 1); |
4652 | | /* move the current chain link to the new chain */ |
4653 | | /* this is a destructive modification */ |
4654 | 0 | new_chain = SET_CXTAIL(val, new_chain); |
4655 | 0 | SET_VECTOR_ELT(new_table, new_hashcode, new_chain); |
4656 | 0 | chain = next; |
4657 | 0 | } |
4658 | 0 | } |
4659 | 0 | R_StringHash = new_table; |
4660 | 0 | char_hash_size = newsize; |
4661 | 0 | char_hash_mask = newmask; |
4662 | | #ifdef DEBUG_GLOBAL_STRING_HASH |
4663 | | newsize = HASHSIZE(new_table); |
4664 | | newpri = HASHPRI(new_table); |
4665 | | Rprintf("Resized: size %d => %d\tpri %d => %d\n", |
4666 | | oldsize, newsize, oldpri, newpri); |
4667 | | #endif |
4668 | 0 | } |
4669 | | |
4670 | | static void reportInvalidString(SEXP cval, int actionWhenInvalid) |
4671 | 0 | { |
4672 | 0 | int oldout = R_OutputCon; |
4673 | 0 | int olderr = R_ErrorCon; |
4674 | 0 | R_OutputCon = 2; |
4675 | 0 | R_ErrorCon = 2; |
4676 | 0 | REprintf(" ----------- FAILURE REPORT -------------- \n"); |
4677 | 0 | REprintf(" --- failure: %s ---\n", "invalid string was created"); |
4678 | 0 | REprintf(" --- srcref --- \n"); |
4679 | 0 | SrcrefPrompt("", R_getCurrentSrcref()); |
4680 | 0 | REprintf("\n"); |
4681 | 0 | REprintf(" --- call from context --- \n"); |
4682 | 0 | PrintValue(R_GlobalContext->call); |
4683 | 0 | REprintf(" --- R stacktrace ---\n"); |
4684 | 0 | printwhere(); |
4685 | 0 | REprintf(" --- current native encoding: %s ---\n", |
4686 | 0 | R_nativeEncoding()); |
4687 | 0 | char *enc = "native/unknown"; |
4688 | 0 | if (IS_LATIN1(cval)) |
4689 | 0 | enc = "latin1"; |
4690 | 0 | else if (IS_UTF8(cval)) |
4691 | 0 | enc = "UTF-8"; |
4692 | 0 | else if (IS_BYTES(cval)) |
4693 | 0 | enc = "bytes"; // called in error |
4694 | 0 | REprintf(" --- declared string encoding: %s ---\n", enc); |
4695 | 0 | REprintf(" --- string (printed):\n"); |
4696 | 0 | PrintValue(cval); |
4697 | 0 | REprintf(" --- string (bytes with ASCII chars):\n"); |
4698 | 0 | for(int i = 0; i < LENGTH(cval); i++) { |
4699 | 0 | if (i > 0) |
4700 | 0 | REprintf(" "); |
4701 | 0 | unsigned char b = (unsigned char) CHAR(cval)[i]; |
4702 | 0 | REprintf("%2x", b); |
4703 | 0 | if (b > 0 && b <= 127) REprintf("(%c) ", b); |
4704 | 0 | } |
4705 | 0 | REprintf("\n"); |
4706 | 0 | REprintf(" --- function from context --- \n"); |
4707 | 0 | if (R_GlobalContext->callfun != NULL && |
4708 | 0 | TYPEOF(R_GlobalContext->callfun) == CLOSXP) |
4709 | 0 | PrintValue(R_GlobalContext->callfun); |
4710 | 0 | REprintf(" --- function search by body ---\n"); |
4711 | 0 | if (R_GlobalContext->callfun != NULL && |
4712 | 0 | TYPEOF(R_GlobalContext->callfun) == CLOSXP) |
4713 | 0 | findFunctionForBody(R_ClosureExpr(R_GlobalContext->callfun)); |
4714 | 0 | REprintf(" ----------- END OF FAILURE REPORT -------------- \n"); |
4715 | 0 | R_OutputCon = oldout; |
4716 | 0 | R_ErrorCon = olderr; |
4717 | |
|
4718 | 0 | if (actionWhenInvalid == 3) |
4719 | 0 | R_Suicide("invalid string was created"); |
4720 | 0 | else if (actionWhenInvalid > 0) { |
4721 | 0 | const void *vmax = vmaxget(); |
4722 | 0 | const char *native_str; |
4723 | 0 | const char *from = ""; |
4724 | 0 | if (IS_UTF8(cval)) |
4725 | 0 | from = "UTF-8"; |
4726 | 0 | else if (IS_LATIN1(cval)) |
4727 | 0 | from = "CP1252"; |
4728 | |
|
4729 | 0 | native_str = reEnc3(CHAR(cval), from, "", 1); |
4730 | 0 | if (actionWhenInvalid == 1) |
4731 | 0 | warning("invalid string %s", native_str); |
4732 | 0 | else if (actionWhenInvalid == 2) |
4733 | 0 | error("invalid string %s", native_str); |
4734 | 0 | vmaxset(vmax); |
4735 | 0 | } |
4736 | 0 | } |
4737 | | |
4738 | | /* mkCharLenCE - make a character (CHARSXP) variable and set its |
4739 | | encoding bit. If a CHARSXP with the same string already exists in |
4740 | | the global CHARSXP cache, R_StringHash, it is returned. Otherwise, |
4741 | | a new CHARSXP is created, added to the cache and then returned. */ |
4742 | | |
4743 | | SEXP mkCharLenCE(const char *name, int len, cetype_t enc) |
4744 | 3.57M | { |
4745 | 3.57M | SEXP cval, chain; |
4746 | 3.57M | unsigned int hashcode; |
4747 | 3.57M | int need_enc; |
4748 | 3.57M | Rboolean embedNul = FALSE, is_ascii = TRUE; |
4749 | 3.57M | static int checkValid = -1; |
4750 | 3.57M | static int actionWhenInvalid = 0; |
4751 | | |
4752 | 3.57M | switch(enc){ |
4753 | 2.44M | case CE_NATIVE: |
4754 | 3.57M | case CE_UTF8: |
4755 | 3.57M | case CE_LATIN1: |
4756 | 3.57M | case CE_BYTES: |
4757 | 3.57M | case CE_SYMBOL: |
4758 | 3.57M | case CE_ANY: |
4759 | 3.57M | break; |
4760 | 0 | default: |
4761 | 0 | error(_("unknown encoding: %d"), enc); |
4762 | 3.57M | } |
4763 | 105M | for (int slen = 0; slen < len; slen++) { |
4764 | 101M | if ((unsigned int) name[slen] > 127) is_ascii = FALSE; |
4765 | 101M | if (!name[slen]) embedNul = TRUE; |
4766 | 101M | } |
4767 | 3.57M | if (embedNul) { |
4768 | 583 | SEXP c; |
4769 | | /* This is tricky: we want to make a reasonable job of |
4770 | | representing this string, and EncodeString() is the most |
4771 | | comprehensive */ |
4772 | 583 | c = allocCharsxp(len); |
4773 | 583 | if (len) memcpy(CHAR_RW(c), name, len); |
4774 | 583 | switch(enc) { |
4775 | 348 | case CE_UTF8: SET_UTF8(c); break; |
4776 | 32 | case CE_LATIN1: SET_LATIN1(c); break; |
4777 | 41 | case CE_BYTES: SET_BYTES(c); break; |
4778 | 162 | default: break; |
4779 | 583 | } |
4780 | 583 | if (is_ascii) SET_ASCII(c); |
4781 | 583 | error(_("embedded nul in string: '%s'"), |
4782 | 583 | EncodeString(c, 0, 0, Rprt_adj_none)); |
4783 | 583 | } |
4784 | | |
4785 | 3.57M | if (enc && is_ascii) enc = CE_NATIVE; |
4786 | 3.57M | switch(enc) { |
4787 | 1.37k | case CE_UTF8: need_enc = UTF8_MASK; break; |
4788 | 67 | case CE_LATIN1: need_enc = LATIN1_MASK; break; |
4789 | 3 | case CE_BYTES: need_enc = BYTES_MASK; break; |
4790 | 3.57M | default: need_enc = 0; |
4791 | 3.57M | } |
4792 | | |
4793 | 3.57M | hashcode = char_hash(name, len) & char_hash_mask; |
4794 | | |
4795 | | /* Search for a cached value */ |
4796 | 3.57M | cval = R_NilValue; |
4797 | 3.57M | chain = VECTOR_ELT(R_StringHash, hashcode); |
4798 | 3.70M | for (; !ISNULL(chain) ; chain = CXTAIL(chain)) { |
4799 | 3.55M | SEXP val = CXHEAD(chain); |
4800 | 3.55M | if (TYPEOF(val) != CHARSXP) break; /* sanity check */ |
4801 | 3.55M | if (need_enc == (ENC_KNOWN(val) | IS_BYTES(val)) && |
4802 | 3.55M | LENGTH(val) == len && /* quick pretest */ |
4803 | 3.43M | (!len || (memcmp(CHAR(val), name, len) == 0))) { // called with len = 0 |
4804 | 3.42M | cval = val; |
4805 | 3.42M | break; |
4806 | 3.42M | } |
4807 | 3.55M | } |
4808 | 3.57M | if (cval == R_NilValue) { |
4809 | | /* no cached value; need to allocate one and add to the cache */ |
4810 | 151k | PROTECT(cval = allocCharsxp(len)); |
4811 | 151k | if (len) memcpy(CHAR_RW(cval), name, len); |
4812 | 151k | switch(enc) { |
4813 | 150k | case CE_NATIVE: |
4814 | 150k | break; /* don't set encoding */ |
4815 | 801 | case CE_UTF8: |
4816 | 801 | SET_UTF8(cval); |
4817 | 801 | break; |
4818 | 63 | case CE_LATIN1: |
4819 | 63 | SET_LATIN1(cval); |
4820 | 63 | break; |
4821 | 3 | case CE_BYTES: |
4822 | 3 | SET_BYTES(cval); |
4823 | 3 | break; |
4824 | 0 | default: |
4825 | 0 | error("unknown encoding mask: %d", enc); |
4826 | 151k | } |
4827 | 151k | if (is_ascii) SET_ASCII(cval); |
4828 | 151k | SET_CACHED(cval); /* Mark it */ |
4829 | | /* add the new value to the cache */ |
4830 | 151k | chain = VECTOR_ELT(R_StringHash, hashcode); |
4831 | 151k | if (ISNULL(chain)) |
4832 | 138k | SET_HASHPRI(R_StringHash, HASHPRI(R_StringHash) + 1); |
4833 | | /* this is a destructive modification */ |
4834 | 151k | chain = SET_CXTAIL(cval, chain); |
4835 | 151k | SET_VECTOR_ELT(R_StringHash, hashcode, chain); |
4836 | | |
4837 | | /* resize the hash table if necessary with the new entry still |
4838 | | protected. |
4839 | | Maximum possible power of two is 2^30 for a VECSXP. |
4840 | | FIXME: this has changed with long vectors. |
4841 | | */ |
4842 | 151k | if (R_HashSizeCheck(R_StringHash) |
4843 | 0 | && char_hash_size < 1073741824 /* 2^30 */) |
4844 | 0 | R_StringHash_resize(char_hash_size * 2); |
4845 | | |
4846 | 151k | if (checkValid && !IS_ASCII(cval)) { |
4847 | 5 | if (checkValid == -1) { |
4848 | 5 | checkValid = 0; |
4849 | | /* _R_CHECK_STRING_VALIDITY_ = XY (decimal) |
4850 | | |
4851 | | Y = 0 ... no checks |
4852 | | Y = 1 ... check marked strings |
4853 | | Y = 2 ... check also native strings |
4854 | | |
4855 | | X = 0 ... just print |
4856 | | X = 1 ... print + issue a warning |
4857 | | X = 2 ... print + throw R error |
4858 | | X = 3 ... print + abort R |
4859 | | |
4860 | | This is experimental and will be likely changed or |
4861 | | removed. |
4862 | | */ |
4863 | 5 | const char *p = getenv("_R_CHECK_STRING_VALIDITY_"); |
4864 | 5 | if (p) { |
4865 | 0 | checkValid = atoi(p); |
4866 | 0 | actionWhenInvalid = checkValid / 10; |
4867 | 0 | checkValid -= actionWhenInvalid * 10; |
4868 | |
|
4869 | 0 | if (checkValid < 0 || checkValid > 2) { |
4870 | 0 | checkValid = 0; |
4871 | 0 | actionWhenInvalid = 0; |
4872 | 0 | } |
4873 | 0 | if (actionWhenInvalid < 0 || actionWhenInvalid > 3) |
4874 | 0 | actionWhenInvalid = 0; |
4875 | 0 | } |
4876 | 5 | } |
4877 | 5 | if (checkValid >= 1) { |
4878 | | /* check strings flagged UTF-8 and latin1 */ |
4879 | 0 | if (IS_UTF8(cval)) { |
4880 | 0 | if (!utf8Valid(CHAR(cval))) |
4881 | 0 | reportInvalidString(cval, actionWhenInvalid); |
4882 | 0 | UNPROTECT(1); |
4883 | 0 | return cval; |
4884 | 0 | } else if (IS_LATIN1(cval)) { |
4885 | 0 | const void *vmax = vmaxget(); |
4886 | 0 | const wchar_t *dummy = wtransChar2(cval); |
4887 | 0 | if (!dummy) |
4888 | 0 | reportInvalidString(cval, actionWhenInvalid); |
4889 | 0 | vmaxset(vmax); |
4890 | 0 | UNPROTECT(1); |
4891 | 0 | return cval; |
4892 | 0 | } |
4893 | 0 | } |
4894 | 5 | if (checkValid >= 2 && !IS_BYTES(cval)) { |
4895 | | /* check strings flagged native/unknown */ |
4896 | 0 | if (known_to_be_utf8) { |
4897 | 0 | if (!utf8Valid(CHAR(cval))) |
4898 | 0 | reportInvalidString(cval, actionWhenInvalid); |
4899 | 0 | UNPROTECT(1); |
4900 | 0 | return cval; |
4901 | 0 | } else if (!mbcsValid(CHAR(cval))) { |
4902 | 0 | reportInvalidString(cval, actionWhenInvalid); |
4903 | 0 | UNPROTECT(1); |
4904 | 0 | return cval; |
4905 | 0 | } |
4906 | 0 | } |
4907 | 5 | } |
4908 | | |
4909 | 151k | UNPROTECT(1); |
4910 | 151k | } |
4911 | 3.57M | return cval; |
4912 | 3.57M | } |
4913 | | |
4914 | | |
4915 | | #ifdef DEBUG_SHOW_CHARSXP_CACHE |
4916 | | /* Call this from gdb with |
4917 | | |
4918 | | call do_show_cache(10) |
4919 | | |
4920 | | for the first 10 cache chains in use. */ |
4921 | | void do_show_cache(int n) |
4922 | | { |
4923 | | int i, j; |
4924 | | Rprintf("Cache size: %d\n", LENGTH(R_StringHash)); |
4925 | | Rprintf("Cache pri: %d\n", HASHPRI(R_StringHash)); |
4926 | | for (i = 0, j = 0; j < n && i < LENGTH(R_StringHash); i++) { |
4927 | | SEXP chain = VECTOR_ELT(R_StringHash, i); |
4928 | | if (! ISNULL(chain)) { |
4929 | | Rprintf("Line %d: ", i); |
4930 | | do { |
4931 | | if (IS_UTF8(CXHEAD(chain))) |
4932 | | Rprintf("U"); |
4933 | | else if (IS_LATIN1(CXHEAD(chain))) |
4934 | | Rprintf("L"); |
4935 | | else if (IS_BYTES(CXHEAD(chain))) |
4936 | | Rprintf("B"); |
4937 | | Rprintf("|%s| ", CHAR(CXHEAD(chain))); |
4938 | | chain = CXTAIL(chain); |
4939 | | } while(! ISNULL(chain)); |
4940 | | Rprintf("\n"); |
4941 | | j++; |
4942 | | } |
4943 | | } |
4944 | | } |
4945 | | |
4946 | | void do_write_cache() |
4947 | | { |
4948 | | int i; |
4949 | | FILE *f = fopen("/tmp/CACHE", "w"); |
4950 | | if (f != NULL) { |
4951 | | fprintf(f, "Cache size: %d\n", LENGTH(R_StringHash)); |
4952 | | fprintf(f, "Cache pri: %d\n", HASHPRI(R_StringHash)); |
4953 | | for (i = 0; i < LENGTH(R_StringHash); i++) { |
4954 | | SEXP chain = VECTOR_ELT(R_StringHash, i); |
4955 | | if (! ISNULL(chain)) { |
4956 | | fprintf(f, "Line %d: ", i); |
4957 | | do { |
4958 | | if (IS_UTF8(CXHEAD(chain))) |
4959 | | fprintf(f, "U"); |
4960 | | else if (IS_LATIN1(CXHEAD(chain))) |
4961 | | fprintf(f, "L"); |
4962 | | else if (IS_BYTES(CXHEAD(chain))) |
4963 | | fprintf(f, "B"); |
4964 | | fprintf(f, "|%s| ", CHAR(CXHEAD(chain))); |
4965 | | chain = CXTAIL(chain); |
4966 | | } while(! ISNULL(chain)); |
4967 | | fprintf(f, "\n"); |
4968 | | } |
4969 | | } |
4970 | | fclose(f); |
4971 | | } |
4972 | | } |
4973 | | #endif /* DEBUG_SHOW_CHARSXP_CACHE */ |
4974 | | |
4975 | | // topenv |
4976 | | |
4977 | 1.99M | SEXP topenv(SEXP target, SEXP envir) { |
4978 | 1.99M | SEXP env = envir; |
4979 | 6.11M | while (env != R_EmptyEnv) { |
4980 | 6.11M | if (env == target || env == R_GlobalEnv || |
4981 | 6.10M | env == R_BaseEnv || env == R_BaseNamespace || |
4982 | 4.12M | R_IsPackageEnv(env) || R_IsNamespaceEnv(env) || |
4983 | 4.12M | R_existsVarInFrame(env, R_dot_packageName)) { |
4984 | 1.99M | return env; |
4985 | 4.12M | } else { |
4986 | 4.12M | env = ENCLOS(env); |
4987 | 4.12M | } |
4988 | 6.11M | } |
4989 | 0 | return R_GlobalEnv; |
4990 | 1.99M | } |
4991 | | |
4992 | | /** topenv(): |
4993 | | * |
4994 | | * .Internal(topenv(envir, matchThisEnv)) |
4995 | | * |
4996 | | * @return |
4997 | | */ |
4998 | 0 | attribute_hidden SEXP do_topenv(SEXP call, SEXP op, SEXP args, SEXP rho) { |
4999 | 0 | checkArity(op, args); |
5000 | 0 | SEXP envir = CAR(args); |
5001 | 0 | SEXP target = CADR(args); // = matchThisEnv, typically NULL (R_NilValue) |
5002 | 0 | if (TYPEOF(envir) != ENVSXP) envir = rho; // envir = parent.frame() |
5003 | 0 | if (target != R_NilValue && TYPEOF(target) != ENVSXP) target = R_NilValue; |
5004 | 0 | return topenv(target, envir); |
5005 | 0 | } |
5006 | | |
5007 | 0 | attribute_hidden Rboolean isUnmodifiedSpecSym(SEXP sym, SEXP env) { |
5008 | 0 | if (!IS_SPECIAL_SYMBOL(sym)) |
5009 | 0 | return FALSE; |
5010 | 0 | for(;env != R_EmptyEnv; env = ENCLOS(env)) |
5011 | 0 | if (!NO_SPECIAL_SYMBOLS(env) && env != R_BaseEnv |
5012 | 0 | && env != R_BaseNamespace && R_existsVarInFrame(env, sym)) |
5013 | 0 | return FALSE; |
5014 | 0 | return TRUE; |
5015 | 0 | } |
5016 | | |
5017 | | attribute_hidden |
5018 | 0 | void findFunctionForBodyInNamespace(SEXP body, SEXP nsenv, SEXP nsname) { |
5019 | 0 | if (R_IsNamespaceEnv(nsenv) != TRUE) |
5020 | 0 | error("argument 'nsenv' is not a namespace"); |
5021 | 0 | SEXP args = PROTECT(list3(nsenv /* x */, |
5022 | 0 | R_TrueValue /* all.names */, |
5023 | 0 | R_FalseValue /* sorted */)); |
5024 | 0 | SEXP env2listOp = INTERNAL(install("env2list")); |
5025 | |
|
5026 | 0 | SEXP elist = do_env2list(R_NilValue, env2listOp, args, R_NilValue); |
5027 | 0 | PROTECT(elist); |
5028 | 0 | R_xlen_t n = xlength(elist); |
5029 | 0 | R_xlen_t i; |
5030 | 0 | SEXP names = PROTECT(getAttrib(elist, R_NamesSymbol)); |
5031 | 0 | for(i = 0; i < n; i++) { |
5032 | 0 | SEXP value = VECTOR_ELT(elist, i); |
5033 | 0 | const char *vname = CHAR(STRING_ELT(names, i)); |
5034 | | /* the constants checking requires shallow comparison */ |
5035 | 0 | if (TYPEOF(value) == CLOSXP && R_ClosureExpr(value) == body) |
5036 | 0 | REprintf("Function %s in namespace %s has this body.\n", |
5037 | 0 | vname, |
5038 | 0 | CHAR(PRINTNAME(nsname))); |
5039 | | /* search S4 registry */ |
5040 | 0 | const char *s4prefix = ".__T__"; |
5041 | 0 | if (TYPEOF(value) == ENVSXP && |
5042 | 0 | !strncmp(vname, s4prefix, strlen(s4prefix))) { |
5043 | 0 | SETCAR(args, value); /* re-use args */ |
5044 | 0 | SEXP rlist = do_env2list(R_NilValue, env2listOp, args, R_NilValue); |
5045 | 0 | PROTECT(rlist); |
5046 | 0 | R_xlen_t rn = xlength(rlist); |
5047 | 0 | R_xlen_t ri; |
5048 | 0 | SEXP rnames = PROTECT(getAttrib(rlist, R_NamesSymbol)); |
5049 | 0 | for(ri = 0; ri < rn; ri++) { |
5050 | 0 | SEXP rvalue = VECTOR_ELT(rlist, ri); |
5051 | | /* the constants checking requires shallow comparison */ |
5052 | 0 | if (TYPEOF(rvalue) == CLOSXP && |
5053 | 0 | R_ClosureExpr(rvalue) == body) |
5054 | 0 | REprintf("S4 Method %s defined in namespace %s with " |
5055 | 0 | "signature %s has this body.\n", |
5056 | 0 | vname + strlen(s4prefix), |
5057 | 0 | CHAR(PRINTNAME(nsname)), |
5058 | 0 | CHAR(STRING_ELT(rnames, ri))); |
5059 | 0 | } |
5060 | 0 | UNPROTECT(2); /* rlist, rnames */ |
5061 | 0 | } |
5062 | 0 | } |
5063 | 0 | UNPROTECT(3); /* names, elist, args */ |
5064 | 0 | } |
5065 | | |
5066 | | /* findFunctionForBody - for a given function body, try to find a closure and |
5067 | | the name of its binding (and the name of the package). For debugging. */ |
5068 | 0 | attribute_hidden void findFunctionForBody(SEXP body) { |
5069 | 0 | SEXP nstable = HASHTAB(R_NamespaceRegistry); |
5070 | 0 | CHECK_HASH_TABLE(nstable); |
5071 | 0 | int n = length(nstable); |
5072 | 0 | int i; |
5073 | 0 | for(i = 0; i < n; i++) { |
5074 | 0 | SEXP frame = VECTOR_ELT(nstable, i); |
5075 | 0 | while (frame != R_NilValue) { |
5076 | 0 | findFunctionForBodyInNamespace(body, CAR(frame), TAG(frame)); |
5077 | 0 | frame = CDR(frame); |
5078 | 0 | } |
5079 | 0 | } |
5080 | 0 | } |