/src/mruby/mrbgems/mruby-eval/src/eval.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include <mruby.h> |
2 | | #include <mruby/array.h> |
3 | | #include <mruby/class.h> |
4 | | #include <mruby/compile.h> |
5 | | #include <mruby/irep.h> |
6 | | #include <mruby/proc.h> |
7 | | #include <mruby/opcode.h> |
8 | | #include <mruby/error.h> |
9 | | #include <mruby/presym.h> |
10 | | #include <mruby/variable.h> |
11 | | #include <mruby/internal.h> |
12 | | |
13 | | /* provided by mruby-binding */ |
14 | | mrb_bool mrb_binding_p(mrb_state *mrb, mrb_value binding); |
15 | | const struct RProc * mrb_binding_extract_proc(mrb_state *mrb, mrb_value binding); |
16 | | struct REnv * mrb_binding_extract_env(mrb_state *mrb, mrb_value binding); |
17 | | |
18 | | /* provided by mruby-compiler */ |
19 | | typedef mrb_bool mrb_parser_foreach_top_variable_func(mrb_state *mrb, mrb_sym sym, void *user); |
20 | | void mrb_parser_foreach_top_variable(mrb_state *mrb, struct mrb_parser_state *p, mrb_parser_foreach_top_variable_func *func, void *user); |
21 | | |
22 | | static struct RProc* |
23 | | create_proc_from_string(mrb_state *mrb, const char *s, mrb_int len, mrb_value binding, const char *file, mrb_int line) |
24 | 0 | { |
25 | 0 | mrb_ccontext *cxt; |
26 | 0 | struct mrb_parser_state *p; |
27 | 0 | struct RProc *proc; |
28 | 0 | const struct RProc *scope; |
29 | 0 | struct REnv *e; |
30 | 0 | mrb_callinfo *ci; /* callinfo of eval caller */ |
31 | 0 | struct RClass *target_class = NULL; |
32 | 0 | struct mrb_context *c = mrb->c; |
33 | |
|
34 | 0 | if (!mrb_nil_p(binding)) { |
35 | 0 | if (!mrb_binding_p(mrb, binding)) { |
36 | 0 | mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %C (expected binding)", |
37 | 0 | mrb_obj_class(mrb, binding)); |
38 | 0 | } |
39 | 0 | scope = mrb_binding_extract_proc(mrb, binding); |
40 | 0 | if (MRB_PROC_CFUNC_P(scope)) { |
41 | 0 | e = NULL; |
42 | 0 | } |
43 | 0 | else { |
44 | 0 | e = mrb_binding_extract_env(mrb, binding); |
45 | 0 | mrb_assert(e != NULL); |
46 | 0 | } |
47 | 0 | } |
48 | 0 | else { |
49 | 0 | ci = (c->ci > c->cibase) ? c->ci - 1 : c->cibase; |
50 | 0 | scope = ci->proc; |
51 | 0 | e = NULL; |
52 | 0 | } |
53 | | |
54 | 0 | if (file) { |
55 | 0 | if (strlen(file) >= UINT16_MAX) { |
56 | 0 | mrb_raise(mrb, E_ARGUMENT_ERROR, "filename too long"); |
57 | 0 | } |
58 | 0 | } |
59 | 0 | else { |
60 | 0 | file = "(eval)"; |
61 | 0 | } |
62 | | |
63 | 0 | cxt = mrb_ccontext_new(mrb); |
64 | 0 | cxt->lineno = (uint16_t)line; |
65 | |
|
66 | 0 | mrb_ccontext_filename(mrb, cxt, file); |
67 | 0 | cxt->capture_errors = TRUE; |
68 | 0 | cxt->no_optimize = TRUE; |
69 | 0 | cxt->upper = scope && MRB_PROC_CFUNC_P(scope) ? NULL : scope; |
70 | |
|
71 | 0 | p = mrb_parse_nstring(mrb, s, len, cxt); |
72 | | |
73 | | /* only occur when memory ran out */ |
74 | 0 | if (!p) { |
75 | 0 | mrb_ccontext_free(mrb, cxt); |
76 | 0 | mrb_raise(mrb, E_RUNTIME_ERROR, "Failed to create parser state (out of memory)"); |
77 | 0 | } |
78 | | |
79 | 0 | if (0 < p->nerr) { |
80 | | /* parse error */ |
81 | 0 | mrb_value str; |
82 | |
|
83 | 0 | mrb_ccontext_free(mrb, cxt); |
84 | 0 | if (!p->error_buffer[0].message) { |
85 | 0 | mrb_parser_free(p); |
86 | 0 | mrb_raise(mrb, E_SYNTAX_ERROR, "compile error"); |
87 | 0 | } |
88 | 0 | if (file) { |
89 | 0 | str = mrb_format(mrb, "file %s line %d: %s", |
90 | 0 | file, |
91 | 0 | p->error_buffer[0].lineno, |
92 | 0 | p->error_buffer[0].message); |
93 | 0 | } |
94 | 0 | else { |
95 | 0 | str = mrb_format(mrb, "line %d: %s", |
96 | 0 | p->error_buffer[0].lineno, |
97 | 0 | p->error_buffer[0].message); |
98 | 0 | } |
99 | 0 | mrb_parser_free(p); |
100 | 0 | mrb_exc_raise(mrb, mrb_exc_new_str(mrb, E_SYNTAX_ERROR, str)); |
101 | 0 | } |
102 | | |
103 | 0 | proc = mrb_generate_code(mrb, p); |
104 | 0 | if (proc == NULL) { |
105 | | /* codegen error */ |
106 | 0 | mrb_parser_free(p); |
107 | 0 | mrb_ccontext_free(mrb, cxt); |
108 | 0 | mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error"); |
109 | 0 | } |
110 | 0 | if (c->ci > c->cibase) { |
111 | 0 | ci = &c->ci[-1]; |
112 | 0 | } |
113 | 0 | else { |
114 | 0 | ci = c->cibase; |
115 | 0 | } |
116 | 0 | if (scope) { |
117 | 0 | target_class = MRB_PROC_TARGET_CLASS(scope); |
118 | 0 | if (!MRB_PROC_CFUNC_P(scope)) { |
119 | 0 | if (e == NULL) { |
120 | | /* when `binding` is nil */ |
121 | 0 | e = mrb_vm_ci_env(ci); |
122 | 0 | if (e == NULL) { |
123 | 0 | e = mrb_env_new(mrb, c, ci, ci->proc->body.irep->nlocals, ci->stack, target_class); |
124 | 0 | ci->u.env = e; |
125 | 0 | } |
126 | 0 | } |
127 | 0 | proc->e.env = e; |
128 | 0 | proc->flags |= MRB_PROC_ENVSET; |
129 | 0 | mrb_field_write_barrier(mrb, (struct RBasic*)proc, (struct RBasic*)e); |
130 | 0 | } |
131 | 0 | } |
132 | 0 | proc->upper = scope; |
133 | 0 | mrb_vm_ci_target_class_set(mrb->c->ci, target_class); |
134 | | /* mrb_codedump_all(mrb, proc); */ |
135 | |
|
136 | 0 | mrb_parser_free(p); |
137 | 0 | mrb_ccontext_free(mrb, cxt); |
138 | |
|
139 | 0 | return proc; |
140 | 0 | } |
141 | | |
142 | | static mrb_value |
143 | | exec_irep(mrb_state *mrb, mrb_value self, struct RProc *proc) |
144 | 0 | { |
145 | | /* no argument passed from eval() */ |
146 | 0 | mrb->c->ci->n = 0; |
147 | 0 | mrb->c->ci->nk = 0; |
148 | | /* clear block */ |
149 | 0 | mrb->c->ci->stack[1] = mrb_nil_value(); |
150 | 0 | return mrb_exec_irep(mrb, self, proc); |
151 | 0 | } |
152 | | |
153 | | static void |
154 | | binding_eval_error_check(mrb_state *mrb, struct mrb_parser_state *p, const char *file) |
155 | 0 | { |
156 | 0 | if (!p) { |
157 | 0 | mrb_raise(mrb, E_RUNTIME_ERROR, "Failed to create parser state (out of memory)"); |
158 | 0 | } |
159 | | |
160 | 0 | if (0 < p->nerr) { |
161 | 0 | mrb_value str; |
162 | |
|
163 | 0 | if (file) { |
164 | 0 | str = mrb_format(mrb, "file %s line %d: %s", |
165 | 0 | file, |
166 | 0 | p->error_buffer[0].lineno, |
167 | 0 | p->error_buffer[0].message); |
168 | 0 | } |
169 | 0 | else { |
170 | 0 | str = mrb_format(mrb, "line %d: %s", |
171 | 0 | p->error_buffer[0].lineno, |
172 | 0 | p->error_buffer[0].message); |
173 | 0 | } |
174 | 0 | mrb_exc_raise(mrb, mrb_exc_new_str(mrb, E_SYNTAX_ERROR, str)); |
175 | 0 | } |
176 | 0 | } |
177 | | |
178 | 0 | #define LV_BUFFERS 8 |
179 | | |
180 | | struct expand_lvspace { |
181 | | mrb_irep *irep; |
182 | | struct REnv *env; |
183 | | int numvar; |
184 | | mrb_sym syms[LV_BUFFERS]; |
185 | | }; |
186 | | |
187 | | static mrb_bool |
188 | | expand_lvspace(mrb_state *mrb, mrb_sym sym, void *user) |
189 | 0 | { |
190 | 0 | struct expand_lvspace *p = (struct expand_lvspace*)user; |
191 | 0 | mrb_int symlen; |
192 | 0 | const char *symname = mrb_sym_name_len(mrb, sym, &symlen); |
193 | |
|
194 | 0 | if (symname && symlen > 0) { |
195 | 0 | if (symname[0] != '&' && symname[0] != '*') { |
196 | 0 | p->syms[p->numvar++] = sym; |
197 | 0 | if (p->numvar >= LV_BUFFERS) { |
198 | 0 | mrb_proc_merge_lvar(mrb, p->irep, p->env, p->numvar, p->syms, NULL); |
199 | 0 | p->numvar = 0; |
200 | 0 | } |
201 | 0 | } |
202 | 0 | } |
203 | |
|
204 | 0 | return TRUE; |
205 | 0 | } |
206 | | |
207 | | struct binding_eval_prepare_body { |
208 | | mrb_value binding; |
209 | | const char *file; |
210 | | mrb_ccontext *cxt; |
211 | | struct mrb_parser_state *pstate; |
212 | | }; |
213 | | |
214 | | static mrb_value |
215 | | binding_eval_prepare_body(mrb_state *mrb, void *opaque) |
216 | 0 | { |
217 | 0 | struct binding_eval_prepare_body *p = (struct binding_eval_prepare_body*)opaque; |
218 | |
|
219 | 0 | const struct RProc *proc = mrb_binding_extract_proc(mrb, p->binding); |
220 | 0 | mrb_assert(!MRB_PROC_CFUNC_P(proc)); |
221 | 0 | p->cxt->upper = proc; |
222 | 0 | binding_eval_error_check(mrb, p->pstate, p->file); |
223 | |
|
224 | 0 | struct expand_lvspace args = { |
225 | 0 | (mrb_irep*)proc->body.irep, |
226 | 0 | mrb_binding_extract_env(mrb, p->binding), |
227 | 0 | 0, |
228 | 0 | { 0 } |
229 | 0 | }; |
230 | 0 | mrb_parser_foreach_top_variable(mrb, p->pstate, expand_lvspace, &args); |
231 | 0 | if (args.numvar > 0) { |
232 | 0 | mrb_proc_merge_lvar(mrb, args.irep, args.env, args.numvar, args.syms, NULL); |
233 | 0 | } |
234 | |
|
235 | 0 | return mrb_nil_value(); |
236 | 0 | } |
237 | | |
238 | | static void |
239 | | binding_eval_prepare(mrb_state *mrb, mrb_value binding, const char *expr, mrb_int exprlen, const char *file) |
240 | 0 | { |
241 | 0 | struct binding_eval_prepare_body d = { binding }; |
242 | |
|
243 | 0 | d.cxt = mrb_ccontext_new(mrb); |
244 | 0 | d.file = mrb_ccontext_filename(mrb, d.cxt, file ? file : "(eval)"); |
245 | 0 | d.cxt->capture_errors = TRUE; |
246 | 0 | d.pstate = mrb_parse_nstring(mrb, expr, exprlen, d.cxt); |
247 | |
|
248 | 0 | mrb_bool error; |
249 | 0 | mrb_value ret = mrb_protect_error(mrb, binding_eval_prepare_body, &d, &error); |
250 | 0 | if (d.pstate) mrb_parser_free(d.pstate); |
251 | 0 | if (d.cxt) mrb_ccontext_free(mrb, d.cxt); |
252 | 0 | if (error) mrb_exc_raise(mrb, ret); |
253 | 0 | } |
254 | | |
255 | | static mrb_value |
256 | | f_eval(mrb_state *mrb, mrb_value self) |
257 | 0 | { |
258 | 0 | const char *s; |
259 | 0 | mrb_int len; |
260 | 0 | mrb_value binding = mrb_nil_value(); |
261 | 0 | const char *file = NULL; |
262 | 0 | mrb_int line = 1; |
263 | 0 | struct RProc *proc; |
264 | |
|
265 | 0 | mrb_get_args(mrb, "s|ozi", &s, &len, &binding, &file, &line); |
266 | |
|
267 | 0 | if (!mrb_nil_p(binding)) { |
268 | 0 | binding_eval_prepare(mrb, binding, s, len, file); |
269 | 0 | } |
270 | 0 | proc = create_proc_from_string(mrb, s, len, binding, file, line); |
271 | 0 | if (!mrb_nil_p(binding)) { |
272 | 0 | self = mrb_iv_get(mrb, binding, MRB_SYM(recv)); |
273 | 0 | } |
274 | 0 | mrb_assert(!MRB_PROC_CFUNC_P(proc)); |
275 | 0 | return exec_irep(mrb, self, proc); |
276 | 0 | } |
277 | | |
278 | | static mrb_value |
279 | | f_instance_eval(mrb_state *mrb, mrb_value self) |
280 | 0 | { |
281 | 0 | if (!mrb_block_given_p(mrb)) { |
282 | 0 | const char *s; |
283 | 0 | mrb_int len; |
284 | 0 | const char *file = NULL; |
285 | 0 | mrb_int line = 1; |
286 | 0 | struct RClass *c; |
287 | 0 | struct RProc *proc; |
288 | |
|
289 | 0 | mrb_get_args(mrb, "s|zi", &s, &len, &file, &line); |
290 | 0 | c = mrb_singleton_class_ptr(mrb, self); |
291 | 0 | proc = create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line); |
292 | 0 | MRB_PROC_SET_TARGET_CLASS(proc, c); |
293 | 0 | mrb_assert(!MRB_PROC_CFUNC_P(proc)); |
294 | 0 | mrb_vm_ci_target_class_set(mrb->c->ci, c); |
295 | 0 | return exec_irep(mrb, self, proc); |
296 | 0 | } |
297 | 0 | else { |
298 | 0 | mrb_get_args(mrb, ""); |
299 | 0 | return mrb_obj_instance_eval(mrb, self); |
300 | 0 | } |
301 | 0 | } |
302 | | |
303 | | static mrb_value |
304 | | f_class_eval(mrb_state *mrb, mrb_value self) |
305 | 0 | { |
306 | 0 | if (!mrb_block_given_p(mrb)) { |
307 | 0 | const char *s; |
308 | 0 | mrb_int len; |
309 | 0 | const char *file = NULL; |
310 | 0 | mrb_int line = 1; |
311 | 0 | struct RProc *proc; |
312 | |
|
313 | 0 | mrb_get_args(mrb, "s|zi", &s, &len, &file, &line); |
314 | 0 | proc = create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line); |
315 | 0 | MRB_PROC_SET_TARGET_CLASS(proc, mrb_class_ptr(self)); |
316 | 0 | mrb_assert(!MRB_PROC_CFUNC_P(proc)); |
317 | 0 | mrb_vm_ci_target_class_set(mrb->c->ci, mrb_class_ptr(self)); |
318 | 0 | return exec_irep(mrb, self, proc); |
319 | 0 | } |
320 | 0 | else { |
321 | 0 | mrb_get_args(mrb, ""); |
322 | 0 | return mrb_mod_module_eval(mrb, self); |
323 | 0 | } |
324 | 0 | } |
325 | | |
326 | | static mrb_value |
327 | | mrb_binding_eval(mrb_state *mrb, mrb_value binding) |
328 | 0 | { |
329 | 0 | mrb_callinfo *ci = mrb->c->ci; |
330 | 0 | int argc = ci->n; |
331 | 0 | mrb_value *argv = ci->stack + 1; |
332 | |
|
333 | 0 | if (argc < 15) { |
334 | 0 | argv[0] = mrb_ary_new_from_values(mrb, argc, argv); |
335 | 0 | argv[1] = argv[argc]; /* copy block */ |
336 | 0 | ci->n = 15; |
337 | 0 | } |
338 | 0 | mrb_ary_splice(mrb, argv[0], 1, 0, binding); /* insert binding as 2nd argument */ |
339 | 0 | return f_eval(mrb, binding); |
340 | 0 | } |
341 | | |
342 | | void |
343 | | mrb_mruby_eval_gem_init(mrb_state* mrb) |
344 | 2.84k | { |
345 | 2.84k | mrb_define_module_function(mrb, mrb->kernel_module, "eval", f_eval, MRB_ARGS_ARG(1, 3)); |
346 | 2.84k | mrb_define_method_id(mrb, mrb_class_get_id(mrb, MRB_SYM(BasicObject)), MRB_SYM(instance_eval), f_instance_eval, MRB_ARGS_OPT(3)|MRB_ARGS_BLOCK()); |
347 | 2.84k | mrb_define_method_id(mrb, mrb->module_class, MRB_SYM(module_eval), f_class_eval, MRB_ARGS_OPT(3)|MRB_ARGS_BLOCK()); |
348 | 2.84k | mrb_define_method_id(mrb, mrb->module_class, MRB_SYM(class_eval), f_class_eval, MRB_ARGS_OPT(3)|MRB_ARGS_BLOCK()); |
349 | | |
350 | 2.84k | struct RClass *binding = mrb_class_get_id(mrb, MRB_SYM(Binding)); |
351 | 2.84k | mrb_define_method(mrb, binding, "eval", mrb_binding_eval, MRB_ARGS_ANY()); |
352 | 2.84k | } |
353 | | |
354 | | void |
355 | | mrb_mruby_eval_gem_final(mrb_state* mrb) |
356 | 2.84k | { |
357 | 2.84k | } |