Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 708 lines (621 sloc) 16.616 kb
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1 /**********************************************************************
2
3 vm_eval.c -
4
5 $Author: nobu $
6 created at: Sat May 24 16:02:32 JST 2008
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12 **********************************************************************/
13
14 #include "ruby/ruby.h"
15 #include "ruby/node.h"
16 #include "ruby/st.h"
17 #include "roxor.h"
18 #include "objc.h"
19 #include "id.h"
20
21 #include "vm_method.c"
22
23 static inline VALUE
24 rb_call(VALUE recv, ID mid, int argc, const VALUE *argv, int scope)
25 {
26 SEL sel;
27 if (mid == ID_ALLOCATOR) {
28 sel = selAlloc;
29 }
30 else {
31 const char *midstr = rb_id2name(mid);
32 if (argc > 0 && midstr[strlen(midstr) - 1] != ':') {
33 char buf[100];
34 snprintf(buf, sizeof buf, "%s:", midstr);
35 sel = sel_registerName(buf);
36 }
37 else {
38 sel = sel_registerName(midstr);
39 }
40 }
41 return rb_vm_call(recv, sel, argc, argv, false);
42 }
43
44 /*
45 * call-seq:
46 * obj.method_missing(symbol [, *args] ) => result
47 *
48 * Invoked by Ruby when <i>obj</i> is sent a message it cannot handle.
49 * <i>symbol</i> is the symbol for the method called, and <i>args</i>
50 * are any arguments that were passed to it. By default, the interpreter
51 * raises an error when this method is called. However, it is possible
52 * to override the method to provide more dynamic behavior.
53 * If it is decided that a particular method should not be handled, then
54 * <i>super</i> should be called, so that ancestors can pick up the
55 * missing method.
56 * The example below creates
57 * a class <code>Roman</code>, which responds to methods with names
58 * consisting of roman numerals, returning the corresponding integer
59 * values.
60 *
61 * class Roman
62 * def romanToInt(str)
63 * # ...
64 * end
65 * def method_missing(methId)
66 * str = methId.id2name
67 * romanToInt(str)
68 * end
69 * end
70 *
71 * r = Roman.new
72 * r.iv #=> 4
73 * r.xxiii #=> 23
74 * r.mm #=> 2000
75 */
76
77 static VALUE
78 rb_method_missing(VALUE obj, SEL sel, int argc, const VALUE *argv)
79 {
80 return rb_vm_method_missing(obj, argc, argv);
81 }
82
83 VALUE
84 rb_apply(VALUE recv, ID mid, VALUE args)
85 {
86 int argc;
87 VALUE *argv;
88
89 argc = RARRAY_LEN(args); /* Assigns LONG, but argc is INT */
90 argv = ALLOCA_N(VALUE, argc);
91 MEMCPY(argv, RARRAY_PTR(args), VALUE, argc);
92 return rb_call(/*CLASS_OF(recv),*/ recv, mid, argc, argv, CALL_FCALL);
93 }
94
95 VALUE
96 rb_funcall(VALUE recv, ID mid, int n, ...)
97 {
98 VALUE *argv;
99 va_list ar;
100 va_start(ar, n);
101
102 if (n > 0) {
103 long i;
104
105 argv = ALLOCA_N(VALUE, n);
106
107 for (i = 0; i < n; i++) {
108 argv[i] = va_arg(ar, VALUE);
109 }
110 va_end(ar);
111 }
112 else {
113 argv = 0;
114 }
115 return rb_call(recv, mid, n, argv, CALL_FCALL);
116 }
117
118 VALUE
119 rb_funcall2(VALUE recv, ID mid, int argc, const VALUE *argv)
120 {
121 return rb_call(recv, mid, argc, argv, CALL_FCALL);
122 }
123
124 VALUE
125 rb_funcall3(VALUE recv, ID mid, int argc, const VALUE *argv)
126 {
127 return rb_call(recv, mid, argc, argv, CALL_PUBLIC);
128 }
129
130 static VALUE
131 send_internal(int argc, VALUE *argv, VALUE recv, int scope)
132 {
133 VALUE vid;
134
135 if (argc == 0) {
136 rb_raise(rb_eArgError, "no method name given");
137 }
138
139 vid = *argv++; argc--;
140 return rb_call(recv, rb_to_id(vid), argc, argv, scope);
141 }
142
143 /*
144 * call-seq:
145 * obj.send(symbol [, args...]) => obj
146 * obj.__send__(symbol [, args...]) => obj
147 *
148 * Invokes the method identified by _symbol_, passing it any
149 * arguments specified. You can use <code>__send__</code> if the name
150 * +send+ clashes with an existing method in _obj_.
151 *
152 * class Klass
153 * def hello(*args)
154 * "Hello " + args.join(' ')
155 * end
156 * end
157 * k = Klass.new
158 * k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
159 */
160
161 static VALUE
162 rb_f_send(VALUE recv, SEL sel, int argc, VALUE *argv)
163 {
164 return send_internal(argc, argv, recv, NOEX_NOSUPER | NOEX_PRIVATE);
165 }
166
167 /*
168 * call-seq:
169 * obj.public_send(symbol [, args...]) => obj
170 *
171 * Invokes the method identified by _symbol_, passing it any
172 * arguments specified. Unlike send, public_send calls public
173 * methods only.
174 *
175 * 1.public_send(:puts, "hello") # causes NoMethodError
176 */
177
178 static VALUE
179 rb_f_public_send(VALUE recv, SEL sel, int argc, VALUE *argv)
180 {
181 return send_internal(argc, argv, recv, NOEX_PUBLIC);
182 }
183
184 /* yield */
185
186 static inline VALUE
187 rb_yield_0(int argc, const VALUE * argv)
188 {
189 return rb_vm_yield(argc, argv);
190 }
191
192 VALUE
193 rb_yield(VALUE val)
194 {
195 if (val == Qundef) {
196 return rb_yield_0(0, 0);
197 }
198 else {
199 return rb_yield_0(1, &val);
200 }
201 }
202
203 VALUE
204 rb_yield_values(int n, ...)
205 {
206 if (n == 0) {
207 return rb_yield_0(0, 0);
208 }
209 else {
210 int i;
211 VALUE *argv;
212 va_list args;
213 argv = ALLOCA_N(VALUE, n);
214
215 va_start(args, n);
216 for (i=0; i<n; i++) {
217 argv[i] = va_arg(args, VALUE);
218 }
219 va_end(args);
220
221 return rb_yield_0(n, argv);
222 }
223 }
224
225 VALUE
226 rb_yield_values2(int argc, const VALUE *argv)
227 {
228 return rb_yield_0(argc, argv);
229 }
230
231 VALUE
232 rb_yield_splat(VALUE values)
233 {
234 VALUE tmp = rb_check_array_type(values);
235 volatile VALUE v;
236 if (NIL_P(tmp)) {
237 rb_raise(rb_eArgError, "not an array");
238 }
239 v = rb_yield_0(RARRAY_LEN(tmp), RARRAY_PTR(tmp));
240 return v;
241 }
242
243 static VALUE
244 loop_i(void)
245 {
246 for (;;) {
247 rb_yield(Qundef);
248 RETURN_IF_BROKEN();
249 }
250 return Qnil;
251 }
252
253 /*
254 * call-seq:
255 * loop {|| block }
256 *
257 * Repeatedly executes the block.
258 *
259 * loop do
260 * print "Input: "
261 * line = gets
262 * break if !line or line =~ /^qQ/
263 * # ...
264 * end
265 *
266 * StopIteration raised in the block breaks the loop.
267 */
268
269 static VALUE
270 rb_f_loop(VALUE klass, SEL sel)
271 {
272 rb_rescue2(loop_i, (VALUE)0, 0, 0, rb_eStopIteration, (VALUE)0);
273 return Qnil; /* dummy */
274 }
275
276 VALUE
38a26b8 implemented NODE_IFUNC-type blocks
Laurent Sansonetti authored
277 rb_objc_block_call(VALUE obj, SEL sel, int argc, VALUE *argv,
278 VALUE (*bl_proc) (ANYARGS), VALUE data2)
279 {
280 NODE *node = NEW_IFUNC(bl_proc, data2);
281 rb_vm_block_t *b = rb_vm_block_create((IMP)bl_proc, node, obj, 0);
282
283 rb_vm_push_block(b);
284 VALUE val = rb_vm_call(obj, sel, argc, argv, false);
285 rb_vm_pop_block();
286
287 return val;
288 }
289
290 VALUE
291 rb_block_call(VALUE obj, ID mid, int argc, VALUE *argv,
9c1d230 committing experimental branch content
Laurent Sansonetti authored
292 VALUE (*bl_proc) (ANYARGS), VALUE data2)
293 {
38a26b8 implemented NODE_IFUNC-type blocks
Laurent Sansonetti authored
294 SEL sel;
295 if (argc == 0) {
296 sel = sel_registerName(rb_id2name(mid));
297 }
298 else {
299 char buf[100];
300 snprintf(buf, sizeof buf, "%s:", rb_id2name(mid));
301 sel = sel_registerName(buf);
302 }
303 return rb_objc_block_call(obj, sel, argc, argv, bl_proc, data2);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
304 }
305
306 VALUE
307 rb_each(VALUE obj)
308 {
309 return rb_call(obj, idEach, 0, 0, CALL_FCALL);
310 }
311
312 static VALUE
313 eval_string_with_cref(VALUE self, VALUE src, VALUE scope, NODE *cref, const char *file, int line)
314 {
315 // TODO honor scope
316 NODE *node = rb_compile_string(file, src, line);
317 assert(node != NULL);
318 return rb_vm_run_node(file, node);
319 }
320
321 static VALUE
322 eval_string(VALUE self, VALUE src, VALUE scope, const char *file, int line)
323 {
324 return eval_string_with_cref(self, src, scope, 0, file, line);
325 }
326
327 /*
328 * call-seq:
329 * eval(string [, binding [, filename [,lineno]]]) => obj
330 *
331 * Evaluates the Ruby expression(s) in <em>string</em>. If
332 * <em>binding</em> is given, the evaluation is performed in its
333 * context. The binding may be a <code>Binding</code> object or a
334 * <code>Proc</code> object. If the optional <em>filename</em> and
335 * <em>lineno</em> parameters are present, they will be used when
336 * reporting syntax errors.
337 *
338 * def getBinding(str)
339 * return binding
340 * end
341 * str = "hello"
342 * eval "str + ' Fred'" #=> "hello Fred"
343 * eval "str + ' Fred'", getBinding("bye") #=> "bye Fred"
344 */
345
346 VALUE
347 rb_f_eval(VALUE self, SEL sel, int argc, VALUE *argv)
348 {
349 VALUE src, scope, vfile, vline;
350 const char *file = "(eval)";
351 int line = 1;
352
353 rb_scan_args(argc, argv, "13", &src, &scope, &vfile, &vline);
354 if (rb_safe_level() >= 4) {
355 StringValue(src);
356 if (!NIL_P(scope) && !OBJ_TAINTED(scope)) {
357 rb_raise(rb_eSecurityError,
358 "Insecure: can't modify trusted binding");
359 }
360 }
361 else {
362 SafeStringValue(src);
363 }
364 if (argc >= 3) {
365 StringValue(vfile);
366 }
367 if (argc >= 4) {
368 line = NUM2INT(vline);
369 }
370
371 if (!NIL_P(vfile)) {
372 file = RSTRING_PTR(vfile);
373 }
374 return eval_string(self, src, scope, file, line);
375 }
376
377 VALUE
378 rb_eval_string(const char *str)
379 {
380 return eval_string(rb_vm_top_self(), rb_str_new2(str), Qnil, "(eval)", 1);
381 }
382
383 VALUE
384 rb_eval_cmd(VALUE cmd, VALUE arg, int level)
385 {
386 VALUE val = Qnil; /* OK */
387 volatile int safe = rb_safe_level();
388
389 if (OBJ_TAINTED(cmd)) {
390 level = 4;
391 }
392
393 if (TYPE(cmd) != T_STRING) {
394 rb_set_safe_level_force(level);
395 val = rb_funcall2(cmd, rb_intern("call"), RARRAY_LEN(arg),
396 RARRAY_PTR(arg));
397 rb_set_safe_level_force(safe);
398 return val;
399 }
400
401 val = eval_string(rb_vm_top_self(), cmd, Qnil, 0, 0);
402 rb_set_safe_level_force(safe);
403 return val;
404 }
405
406 /*
407 * call-seq:
408 * obj.instance_eval(string [, filename [, lineno]] ) => obj
409 * obj.instance_eval {| | block } => obj
410 *
411 * Evaluates a string containing Ruby source code, or the given block,
412 * within the context of the receiver (_obj_). In order to set the
413 * context, the variable +self+ is set to _obj_ while
414 * the code is executing, giving the code access to _obj_'s
415 * instance variables. In the version of <code>instance_eval</code>
416 * that takes a +String+, the optional second and third
417 * parameters supply a filename and starting line number that are used
418 * when reporting compilation errors.
419 *
420 * class KlassWithSecret
421 * def initialize
422 * @secret = 99
423 * end
424 * end
425 * k = KlassWithSecret.new
426 * k.instance_eval { @secret } #=> 99
427 */
428
429 static VALUE
430 rb_obj_instance_eval(VALUE self, SEL sel, int argc, VALUE *argv)
431 {
432 VALUE klass;
433
434 if (SPECIAL_CONST_P(self)) {
435 klass = Qnil;
436 }
437 else {
438 klass = rb_singleton_class(self);
439 }
440 // TODO
441 abort();
442 return Qnil;
443 }
444
445 /*
446 * call-seq:
447 * obj.instance_exec(arg...) {|var...| block } => obj
448 *
449 * Executes the given block within the context of the receiver
450 * (_obj_). In order to set the context, the variable +self+ is set
451 * to _obj_ while the code is executing, giving the code access to
452 * _obj_'s instance variables. Arguments are passed as block parameters.
453 *
454 * class KlassWithSecret
455 * def initialize
456 * @secret = 99
457 * end
458 * end
459 * k = KlassWithSecret.new
460 * k.instance_exec(5) {|x| @secret+x } #=> 104
461 */
462
463 static VALUE
464 rb_obj_instance_exec(VALUE self, SEL sel, int argc, VALUE *argv)
465 {
466 VALUE klass;
467
468 if (SPECIAL_CONST_P(self)) {
469 klass = Qnil;
470 }
471 else {
472 klass = rb_singleton_class(self);
473 }
474 // TODO
475 abort();
476 return Qnil;
477 }
478
479 /*
480 * call-seq:
481 * mod.class_eval(string [, filename [, lineno]]) => obj
482 * mod.module_eval {|| block } => obj
483 *
484 * Evaluates the string or block in the context of _mod_. This can
485 * be used to add methods to a class. <code>module_eval</code> returns
486 * the result of evaluating its argument. The optional _filename_
487 * and _lineno_ parameters set the text for error messages.
488 *
489 * class Thing
490 * end
491 * a = %q{def hello() "Hello there!" end}
492 * Thing.module_eval(a)
493 * puts Thing.new.hello()
494 * Thing.module_eval("invalid code", "dummy", 123)
495 *
496 * <em>produces:</em>
497 *
498 * Hello there!
499 * dummy:123:in `module_eval': undefined local variable
500 * or method `code' for Thing:Class
501 */
502
503 VALUE
504 rb_mod_module_eval(VALUE mod, SEL sel, int argc, VALUE *argv)
505 {
506 // TODO
507 abort();
508 return Qnil;
509 }
510
511 /*
512 * call-seq:
513 * mod.module_exec(arg...) {|var...| block } => obj
514 * mod.class_exec(arg...) {|var...| block } => obj
515 *
516 * Evaluates the given block in the context of the class/module.
517 * The method defined in the block will belong to the receiver.
518 *
519 * class Thing
520 * end
521 * Thing.class_exec{
522 * def hello() "Hello there!" end
523 * }
524 * puts Thing.new.hello()
525 *
526 * <em>produces:</em>
527 *
528 * Hello there!
529 */
530
531 VALUE
532 rb_mod_module_exec(VALUE recv, SEL sel, int argc, VALUE *argv)
533 {
534 // TODO
535 abort();
536 return Qnil;
537 }
538
539 /*
540 * call-seq:
541 * throw(symbol [, obj])
542 *
543 * Transfers control to the end of the active +catch+ block
544 * waiting for _symbol_. Raises +NameError+ if there
545 * is no +catch+ block for the symbol. The optional second
546 * parameter supplies a return value for the +catch+ block,
547 * which otherwise defaults to +nil+. For examples, see
548 * <code>Kernel::catch</code>.
549 */
550
551 static VALUE
552 rb_f_throw(VALUE rcv, SEL sel, int argc, VALUE *argv)
553 {
554 // TODO
555 return Qnil;
556 }
557
558 void
559 rb_throw(const char *tag, VALUE val)
560 {
561 VALUE argv[2];
562
563 argv[0] = ID2SYM(rb_intern(tag));
564 argv[1] = val;
565 rb_f_throw(Qnil, 0, 2, argv);
566 }
567
568 void
569 rb_throw_obj(VALUE tag, VALUE val)
570 {
571 VALUE argv[2];
572
573 argv[0] = tag;
574 argv[1] = val;
575 rb_f_throw(Qnil, 0, 2, argv);
576 }
577
578 /*
579 * call-seq:
580 * catch(symbol) {| | block } > obj
581 *
582 * +catch+ executes its block. If a +throw+ is
583 * executed, Ruby searches up its stack for a +catch+ block
584 * with a tag corresponding to the +throw+'s
585 * _symbol_. If found, that block is terminated, and
586 * +catch+ returns the value given to +throw+. If
587 * +throw+ is not called, the block terminates normally, and
588 * the value of +catch+ is the value of the last expression
589 * evaluated. +catch+ expressions may be nested, and the
590 * +throw+ call need not be in lexical scope.
591 *
592 * def routine(n)
593 * puts n
594 * throw :done if n <= 0
595 * routine(n-1)
596 * end
597 *
598 *
599 * catch(:done) { routine(3) }
600 *
601 * <em>produces:</em>
602 *
603 * 3
604 * 2
605 * 1
606 * 0
607 */
608
609 static VALUE
610 rb_f_catch(VALUE rcv, SEL sel, int argc, VALUE *argv)
611 {
612 // TODO
613 return Qnil;
614 }
615
616 /*
617 * call-seq:
618 * caller(start=1) => array
619 *
620 * Returns the current execution stack---an array containing strings in
621 * the form ``<em>file:line</em>'' or ``<em>file:line: in
622 * `method'</em>''. The optional _start_ parameter
623 * determines the number of initial stack entries to omit from the
624 * result.
625 *
626 * def a(skip)
627 * caller(skip)
628 * end
629 * def b(skip)
630 * a(skip)
631 * end
632 * def c(skip)
633 * b(skip)
634 * end
635 * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10"]
636 * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11"]
637 * c(2) #=> ["prog:8:in `c'", "prog:12"]
638 * c(3) #=> ["prog:13"]
639 */
640
641 static VALUE
642 rb_f_caller(VALUE klass, SEL sel, int argc, VALUE *argv)
643 {
644 VALUE level;
645 int lev;
646
647 rb_scan_args(argc, argv, "01", &level);
648
649 if (NIL_P(level)) {
650 lev = 1;
651 }
652 else {
653 lev = NUM2INT(level);
654 }
655
656 if (lev < 0) {
657 rb_raise(rb_eArgError, "negative level (%d)", lev);
658 }
659
660 return rb_vm_backtrace(lev);
661 }
662
663 void
664 rb_backtrace(void)
665 {
666 long i, count;
667 VALUE ary;
668
669 ary = rb_vm_backtrace(-1);
670 for (i = 0, count = RARRAY_LEN(ary); i < count; i++) {
671 printf("\tfrom %s\n", RSTRING_PTR(RARRAY_AT(ary, i)));
672 }
673 }
674
675 VALUE
676 rb_make_backtrace(void)
677 {
678 return rb_vm_backtrace(-1);
679 }
680
681 void
682 Init_vm_eval(void)
683 {
684 rb_objc_define_method(rb_mKernel, "catch", rb_f_catch, -1);
685 rb_objc_define_method(rb_mKernel, "throw", rb_f_throw, -1);
686
687 rb_objc_define_method(rb_mKernel, "loop", rb_f_loop, 0);
688
689 rb_objc_define_method(rb_cNSObject, "instance_eval", rb_obj_instance_eval, -1);
690 rb_objc_define_method(rb_cNSObject, "instance_exec", rb_obj_instance_exec, -1);
691 rb_objc_define_private_method(rb_cNSObject, "method_missing", rb_method_missing, -1);
692 rb_objc_define_method(rb_cNSObject, "__send__", rb_f_send, -1);
693
694 rb_objc_define_method(rb_cBasicObject, "instance_eval", rb_obj_instance_eval, -1);
695 rb_objc_define_method(rb_cBasicObject, "instance_exec", rb_obj_instance_exec, -1);
696 rb_objc_define_private_method(rb_cBasicObject, "method_missing", rb_method_missing, -1);
697 rb_objc_define_method(rb_cBasicObject, "__send__", rb_f_send, -1);
698
699 rb_objc_define_method(rb_mKernel, "send", rb_f_send, -1);
700 rb_objc_define_method(rb_mKernel, "public_send", rb_f_public_send, -1);
701
702 rb_objc_define_method(rb_cModule, "module_exec", rb_mod_module_exec, -1);
703 rb_objc_define_method(rb_cModule, "class_exec", rb_mod_module_exec, -1);
704
705 rb_objc_define_method(rb_mKernel, "caller", rb_f_caller, -1);
706 }
707
Something went wrong with that request. Please try again.