source: EcnlProtoTool/trunk/mruby-1.2.0/mrbgems/mruby-eval/src/eval.c@ 270

Last change on this file since 270 was 270, checked in by coas-nagasima, 7 years ago

mruby版ECNLプロトタイピング・ツールを追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 6.2 KB
Line 
1#include "mruby.h"
2#include "mruby/class.h"
3#include "mruby/compile.h"
4#include "mruby/irep.h"
5#include "mruby/proc.h"
6#include "mruby/opcode.h"
7
8static struct mrb_irep *
9get_closure_irep(mrb_state *mrb, int level)
10{
11 struct mrb_context *c = mrb->c;
12 struct REnv *e = c->ci[-1].proc->env;
13 struct RProc *proc;
14
15 if (level == 0) {
16 proc = c->ci[-1].proc;
17 if (MRB_PROC_CFUNC_P(proc)) {
18 return NULL;
19 }
20 return proc->body.irep;
21 }
22
23 while (--level) {
24 e = (struct REnv*)e->c;
25 if (!e) return NULL;
26 }
27
28 if (!e) return NULL;
29 proc = c->cibase[e->cioff].proc;
30
31 if (!proc || MRB_PROC_CFUNC_P(proc)) {
32 return NULL;
33 }
34 return proc->body.irep;
35}
36
37static inline mrb_code
38search_variable(mrb_state *mrb, mrb_sym vsym, int bnest)
39{
40 mrb_irep *virep;
41 int level;
42 int pos;
43
44 for (level = 0; (virep = get_closure_irep(mrb, level)); level++) {
45 if (!virep || virep->lv == NULL) {
46 continue;
47 }
48 for (pos = 0; pos < virep->nlocals - 1; pos++) {
49 if (vsym == virep->lv[pos].name) {
50 return (MKARG_B(pos + 1) | MKARG_C(level + bnest));
51 }
52 }
53 }
54
55 return 0;
56}
57
58static mrb_bool
59potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals)
60{
61 if (v >= nlocals) return FALSE;
62 /* skip arguments */
63 if (v < argc+1) return FALSE;
64 return TRUE;
65}
66
67static void
68patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest)
69{
70 size_t i;
71 mrb_code c;
72 int argc = 0;
73
74 for (i = 0; i < irep->ilen; i++) {
75 c = irep->iseq[i];
76 switch(GET_OPCODE(c)){
77 case OP_ENTER:
78 {
79 mrb_aspec ax = GETARG_Ax(c);
80 /* extra 1 means a slot for block */
81 argc = MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1;
82 }
83 break;
84
85 case OP_EPUSH:
86 patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1);
87 break;
88
89 case OP_LAMBDA:
90 {
91 int arg_c = GETARG_c(c);
92 if (arg_c & OP_L_CAPTURE) {
93 patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1);
94 }
95 }
96 break;
97
98 case OP_SEND:
99 if (GETARG_C(c) != 0) {
100 break;
101 }
102 {
103 mrb_code arg = search_variable(mrb, irep->syms[GETARG_B(c)], bnest);
104 if (arg != 0) {
105 /* must replace */
106 irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
107 }
108 }
109 break;
110
111 case OP_MOVE:
112 /* src part */
113 if (potential_upvar_p(irep->lv, GETARG_B(c), argc, irep->nlocals)) {
114 mrb_code arg = search_variable(mrb, irep->lv[GETARG_B(c) - 1].name, bnest);
115 if (arg != 0) {
116 /* must replace */
117 irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
118 }
119 }
120 /* dst part */
121 if (potential_upvar_p(irep->lv, GETARG_A(c), argc, irep->nlocals)) {
122 mrb_code arg = search_variable(mrb, irep->lv[GETARG_A(c) - 1].name, bnest);
123 if (arg != 0) {
124 /* must replace */
125 irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_B(c)) | arg;
126 }
127 }
128 break;
129 }
130 }
131}
132
133static struct RProc*
134create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, char *file, mrb_int line)
135{
136 mrbc_context *cxt;
137 struct mrb_parser_state *p;
138 struct RProc *proc;
139 struct REnv *e;
140 struct mrb_context *c = mrb->c;
141
142 if (!mrb_nil_p(binding)) {
143 mrb_raise(mrb, E_ARGUMENT_ERROR, "Binding of eval must be nil.");
144 }
145
146 cxt = mrbc_context_new(mrb);
147 cxt->lineno = line;
148 if (file) {
149 mrbc_filename(mrb, cxt, file);
150 }
151 cxt->capture_errors = TRUE;
152 cxt->no_optimize = TRUE;
153
154 p = mrb_parse_nstring(mrb, s, len, cxt);
155
156 /* only occur when memory ran out */
157 if (!p) {
158 mrb_raise(mrb, E_RUNTIME_ERROR, "Failed to create parser state.");
159 }
160
161 if (0 < p->nerr) {
162 /* parse error */
163 char buf[256];
164 int n;
165 n = snprintf(buf, sizeof(buf), "line %d: %s\n", p->error_buffer[0].lineno, p->error_buffer[0].message);
166 mrb_parser_free(p);
167 mrbc_context_free(mrb, cxt);
168 mrb_exc_raise(mrb, mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n));
169 }
170
171 proc = mrb_generate_code(mrb, p);
172 if (proc == NULL) {
173 /* codegen error */
174 mrb_parser_free(p);
175 mrbc_context_free(mrb, cxt);
176 mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error");
177 }
178 if (c->ci[-1].proc->target_class) {
179 proc->target_class = c->ci[-1].proc->target_class;
180 }
181 e = c->ci[-1].proc->env;
182 if (!e) e = c->ci[-1].env;
183 e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)e);
184 e->mid = c->ci[-1].mid;
185 e->cioff = c->ci - c->cibase - 1;
186 e->stack = c->ci->stackent;
187 MRB_SET_ENV_STACK_LEN(e, c->ci[-1].proc->body.irep->nlocals);
188 c->ci->env = e;
189 proc->env = e;
190 patch_irep(mrb, proc->body.irep, 0);
191
192 mrb_parser_free(p);
193 mrbc_context_free(mrb, cxt);
194
195 return proc;
196}
197
198static mrb_value
199f_eval(mrb_state *mrb, mrb_value self)
200{
201 char *s;
202 mrb_int len;
203 mrb_value binding = mrb_nil_value();
204 char *file = NULL;
205 mrb_int line = 1;
206 mrb_value ret;
207 struct RProc *proc;
208
209 mrb_get_args(mrb, "s|ozi", &s, &len, &binding, &file, &line);
210
211 proc = create_proc_from_string(mrb, s, len, binding, file, line);
212 ret = mrb_toplevel_run(mrb, proc);
213 if (mrb->exc) {
214 mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
215 }
216
217 return ret;
218}
219
220mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self);
221
222#define CI_ACC_SKIP -1
223
224static mrb_value
225f_instance_eval(mrb_state *mrb, mrb_value self)
226{
227 struct mrb_context *c = mrb->c;
228 mrb_value b;
229 mrb_int argc; mrb_value *argv;
230
231 mrb_get_args(mrb, "*&", &argv, &argc, &b);
232
233 if (mrb_nil_p(b)) {
234 char *s;
235 mrb_int len;
236 char *file = NULL;
237 mrb_int line = 1;
238 mrb_value cv;
239
240 mrb_get_args(mrb, "s|zi", &s, &len, &file, &line);
241 c->ci->acc = CI_ACC_SKIP;
242 cv = mrb_singleton_class(mrb, self);
243 c->ci->target_class = mrb_class_ptr(cv);
244 return mrb_run(mrb, create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line), self);
245 }
246 else {
247 mrb_get_args(mrb, "&", &b);
248 return mrb_obj_instance_eval(mrb, self);
249 }
250}
251
252void
253mrb_mruby_eval_gem_init(mrb_state* mrb)
254{
255 mrb_define_module_function(mrb, mrb->kernel_module, "eval", f_eval, MRB_ARGS_ARG(1, 3));
256 mrb_define_method(mrb, mrb->kernel_module, "instance_eval", f_instance_eval, MRB_ARGS_ARG(1, 2));
257}
258
259void
260mrb_mruby_eval_gem_final(mrb_state* mrb)
261{
262}
Note: See TracBrowser for help on using the repository browser.