1 #include "rlang.h"
2 #include <Rversion.h>
3
4 sexp* eval_with_x(sexp* call, sexp* x);
5 sexp* eval_with_xy(sexp* call, sexp* x, sexp* y);
6 sexp* eval_with_xyz(sexp* call, sexp* x, sexp* y, sexp* z);
7
8
r_ns_env(const char * pkg)9 sexp* r_ns_env(const char* pkg) {
10 sexp* ns = r_env_find(R_NamespaceRegistry, r_sym(pkg));
11 if (ns == r_syms_unbound) {
12 r_abort("Can't find namespace `%s`", pkg);
13 }
14 return ns;
15 }
16
ns_env_get(sexp * env,const char * name)17 static sexp* ns_env_get(sexp* env, const char* name) {
18 sexp* obj = KEEP(r_env_find(env, r_sym(name)));
19
20 // Can be a promise to a lazyLoadDBfetch() call
21 if (r_typeof(obj) == PROMSXP) {
22 obj = r_eval(obj, r_empty_env);
23 }
24 if (obj != r_syms_unbound) {
25 FREE(1);
26 return obj;
27 }
28
29 // Trigger object not found error
30 r_eval(r_sym(name), env);
31 r_abort("Internal error: `ns_env_get()` should have failed earlier");
32 }
r_base_ns_get(const char * name)33 sexp* r_base_ns_get(const char* name) {
34 return ns_env_get(r_base_env, name);
35 }
36
37
38 sexp* rlang_ns_env = NULL;
39
rlang_ns_get(const char * name)40 sexp* rlang_ns_get(const char* name) {
41 return ns_env_get(rlang_ns_env, name);
42 }
43
44
45 static sexp* new_env_call = NULL;
46 static sexp* new_env__parent_node = NULL;
47 static sexp* new_env__size_node = NULL;
48
r_new_environment(sexp * parent,r_ssize size)49 sexp* r_new_environment(sexp* parent, r_ssize size) {
50 parent = parent ? parent : r_empty_env;
51 r_node_poke_car(new_env__parent_node, parent);
52
53 size = size ? size : 29;
54 r_node_poke_car(new_env__size_node, r_int(size));
55
56 sexp* env = r_eval(new_env_call, r_base_env);
57
58 // Free for gc
59 r_node_poke_car(new_env__parent_node, r_null);
60
61 return env;
62 }
63
64
65 static sexp* env2list_call = NULL;
66 static sexp* list2env_call = NULL;
67
68 sexp* r_env_as_list_compat(sexp* env, sexp* out);
69
r_env_as_list(sexp * env)70 sexp* r_env_as_list(sexp* env) {
71 sexp* out = KEEP(eval_with_x(env2list_call, env));
72
73 #if R_VERSION < R_Version(4, 0, 0)
74 out = r_env_as_list_compat(env, out);
75 #endif
76
77 FREE(1);
78 return out;
79 }
80
81 // On R < 4.0, the active binding function is returned instead of
82 // its value. We invoke the active bindings here to get consistent
83 // behaviour in all supported R versions.
r_env_as_list_compat(sexp * env,sexp * out)84 sexp* r_env_as_list_compat(sexp* env, sexp* out) {
85 sexp* nms = KEEP(r_env_names(env));
86 sexp* types = KEEP(r_env_binding_types(env, nms));
87
88 if (types == R_NilValue) {
89 FREE(2);
90 return out;
91 }
92
93 r_ssize n = r_length(nms);
94 sexp* const * p_nms = r_chr_deref_const(nms);
95 const int* p_types = r_int_deref_const(types);
96
97 for (r_ssize i = 0; i < n; ++i) {
98 enum r_env_binding_type type = p_types[i];
99 if (type == R_ENV_BINDING_ACTIVE) {
100 r_ssize fn_idx = r_chr_detect_index(nms, r_str_deref(p_nms[i]));
101 if (fn_idx < 0) {
102 r_abort("Internal error: Can't find active binding in list");
103 }
104
105 sexp* fn = r_list_get(out, fn_idx);
106 sexp* value = r_eval(KEEP(r_call(fn)), r_empty_env);
107 r_list_poke(out, fn_idx, value);
108 FREE(1);
109 }
110 }
111
112 FREE(2);
113 return out;
114 }
115
r_list_as_environment(sexp * x,sexp * parent)116 sexp* r_list_as_environment(sexp* x, sexp* parent) {
117 parent = parent ? parent : r_empty_env;
118 return eval_with_xy(list2env_call, x, parent);
119 }
120
r_env_clone(sexp * env,sexp * parent)121 sexp* r_env_clone(sexp* env, sexp* parent) {
122 if (parent == NULL) {
123 parent = r_env_parent(env);
124 }
125
126 sexp* out = KEEP(r_env_as_list(env));
127 out = r_list_as_environment(out, parent);
128
129 FREE(1);
130 return out;
131 }
132
133
134 static sexp* poke_lazy_call = NULL;
135 static sexp* poke_lazy_value_node = NULL;
136
r_env_poke_lazy(sexp * env,sexp * sym,sexp * expr,sexp * eval_env)137 void r_env_poke_lazy(sexp* env, sexp* sym, sexp* expr, sexp* eval_env) {
138 sexp* name = KEEP(r_sym_as_character(sym));
139
140 r_node_poke_car(poke_lazy_value_node, expr);
141 r_eval_with_xyz(poke_lazy_call, rlang_ns_env, name, env, eval_env);
142 r_node_poke_car(poke_lazy_value_node, r_null);
143
144 FREE(1);
145 }
146
147
148 static sexp* remove_call = NULL;
149
150 #if (R_VERSION < R_Version(4, 0, 0))
r__env_unbind(sexp * env,sexp * sym)151 void r__env_unbind(sexp* env, sexp* sym) {
152 // Check if binding exists to avoid `rm()` warning
153 if (r_env_has(env, sym)) {
154 sexp* nm = KEEP(r_sym_as_character(sym));
155 eval_with_xyz(remove_call, env, nm, r_shared_false);
156 FREE(1);
157 }
158 }
159 #endif
160
r_env_unbind_anywhere(sexp * env,sexp * sym)161 void r_env_unbind_anywhere(sexp* env, sexp* sym) {
162 while (env != r_empty_env) {
163 if (r_env_has(env, sym)) {
164 r_env_unbind(env, sym);
165 return;
166 }
167
168 env = r_env_parent(env);
169 }
170 }
171
r_env_unbind_syms(sexp * env,sexp ** syms)172 void r_env_unbind_syms(sexp* env, sexp** syms) {
173 while (syms) {
174 r_env_unbind(env, *syms++);
175 }
176 }
177
178 static
env_unbind_names(sexp * env,sexp * names,bool inherit)179 void env_unbind_names(sexp* env, sexp* names, bool inherit) {
180 sexp* const * p_names = r_chr_deref_const(names);
181 r_ssize n = r_length(names);
182
183 if (inherit) {
184 for (r_ssize i = 0; i < n; ++i) {
185 sexp* sym = r_str_as_symbol(p_names[i]);
186 r_env_unbind_anywhere(env, sym);
187 }
188 } else {
189 for (r_ssize i = 0; i < n; ++i) {
190 sexp* sym = r_str_as_symbol(p_names[i]);
191 r_env_unbind(env, sym);
192 }
193 }
194 }
195
r_env_unbind_names(sexp * env,sexp * names)196 void r_env_unbind_names(sexp* env, sexp* names) {
197 env_unbind_names(env, names, false);
198 }
r_env_unbind_anywhere_names(sexp * env,sexp * names)199 void r_env_unbind_anywhere_names(sexp* env, sexp* names) {
200 env_unbind_names(env, names, true);
201 }
202
r_env_unbind_strings(sexp * env,const char ** names)203 void r_env_unbind_strings(sexp* env, const char** names) {
204 sexp* nms = KEEP(r_new_character(names));
205 r_env_unbind_names(env, nms);
206 FREE(1);
207 }
r_env_unbind_anywhere_strings(sexp * env,const char ** names)208 void r_env_unbind_anywhere_strings(sexp* env, const char** names) {
209 sexp* nms = KEEP(r_new_character(names));
210 r_env_unbind_anywhere_names(env, nms);
211 FREE(1);
212 }
213
r_env_unbind_string(sexp * env,const char * name)214 void r_env_unbind_string(sexp* env, const char* name) {
215 static const char* names[2] = { "", NULL };
216 names[0] = name;
217 r_env_unbind_strings(env, names);
218 }
r_env_unbind_string_anywhere(sexp * env,const char * name)219 void r_env_unbind_string_anywhere(sexp* env, const char* name) {
220 static const char* names[2] = { "", NULL };
221 names[0] = name;
222 r_env_unbind_anywhere_strings(env, names);
223 }
224
r_env_inherits(sexp * env,sexp * ancestor,sexp * top)225 bool r_env_inherits(sexp* env, sexp* ancestor, sexp* top) {
226 top = top ? top : r_empty_env;
227
228 if (r_typeof(env) != r_type_environment) {
229 r_abort("`env` must be an environment");
230 }
231 if (r_typeof(ancestor) != r_type_environment) {
232 r_abort("`ancestor` must be an environment");
233 }
234 if (r_typeof(top) != r_type_environment) {
235 r_abort("`top` must be an environment");
236 }
237
238 if (env == r_empty_env) {
239 return false;
240 }
241
242 while (env != top && env != r_empty_env) {
243 if (env == ancestor) {
244 return true;
245 }
246 env = r_env_parent(env);;
247 }
248
249 return env == ancestor;
250 }
251
r_init_rlang_ns_env()252 void r_init_rlang_ns_env() {
253 rlang_ns_env = r_ns_env("rlang");
254 }
255
256 sexp* r_methods_ns_env = NULL;
257
r_init_library_env()258 void r_init_library_env() {
259 new_env_call = r_parse_eval("as.call(list(new.env, TRUE, NULL, NULL))", r_base_env);
260 r_mark_precious(new_env_call);
261
262 new_env__parent_node = r_node_cddr(new_env_call);
263 new_env__size_node = r_node_cdr(new_env__parent_node);
264
265 env2list_call = r_parse("as.list.environment(x, all.names = TRUE)");
266 r_mark_precious(env2list_call);
267
268 list2env_call = r_parse("list2env(x, envir = NULL, parent = y, hash = TRUE)");
269 r_mark_precious(list2env_call);
270
271 poke_lazy_call = r_parse("delayedAssign(x, value = NULL, assign.env = y, eval.env = z)");
272 r_mark_precious(poke_lazy_call);
273
274 poke_lazy_value_node = r_node_cddr(poke_lazy_call);
275
276 remove_call = r_parse("remove(list = y, envir = x, inherits = z)");
277 r_mark_precious(remove_call);
278
279 r_methods_ns_env = r_parse_eval("asNamespace('methods')", r_base_env);
280 }
281