Coverage Report

Created: 2024-02-29 06:24

/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
}