From: Joakim Andersson Date: 2002-02-19T23:54:03+09:00 Subject: Re: Problems with Ruby in C --AqsLC8rIMeq19msA Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Tue, Feb 19, 2002 at 01:21:31PM +0900, Yukihiro Matsumoto wrote: Thanks for the answers matz, they helped me understand this a bit better. Though they, of course, resulted in my questions :) > the assignemnt to the variable a is done in the scope of the execute > method, whic vaporized every time execute called. On the other hand, > > |static VALUE cContext_execute(VALUE self, VALUE str) > |{ > | return rb_funcall(self, rb_intern("instance_eval"), 1, str); > |} > > this case, the assignment is done at the toplevel scope, which is used > again and again. That's the difference. Ah, I understand now. So is there an easy and nice way to make something execute inside a scope from C? What I did now was to rip out PUSH_SCOPE and POP_SCOPE from eval.c and put them around the eval like this: PUSH_SCOPE(); v = rb_funcall(self, rb_intern("eval"), 1, str); POP_SCOPE(); so I now get " 5 undefined local variable or method `a' for # " when I run the program, which is what I want. But it feels a bit like language abuse to do it the way I'm doing it now. (I've attached the whole program to this mail if someone wants to see it.) The next problem I'm having is that I want to be able to return from the the eval. I.e. I want to be able to evaluate something like this: a = 1 if a == 1 return "a is one" else return "a is not one" end which means it has to be evaluated inside a method somehow. That's why I put the eval/instance_eval call inside the execute method, which I define in the Context class, because I thought that it might then be evaluated inside that method. But it's not working. If I remove rb_protect which is protecting the call to cContext_execute_helper I get segmentation faults. So I'm obviously doing something wrong, the question is what? Is this even possible? /joakim -- Joakim Andersson ; tyrak@borgship.net ; http://borgship.net/~tyrak/ --AqsLC8rIMeq19msA Content-Type: text/x-csrc; charset=us-ascii Content-Disposition: attachment; filename="testi.c" #include "ruby.h" #include "env.h" static void scope_dup _((struct SCOPE *)); static int scope_vmode = 0; #define SCOPE_PUBLIC 0 #define PUSH_SCOPE() { \ volatile int _vmode = scope_vmode; \ struct SCOPE * volatile _old; \ NEWOBJ(_scope, struct SCOPE); \ OBJSETUP(_scope, 0, T_SCOPE); \ _scope->local_tbl = 0; \ _scope->local_vars = 0; \ _scope->flag = 0; \ _old = ruby_scope; \ ruby_scope = _scope; \ scope_vmode = SCOPE_PUBLIC; /* from eval.c with minor modifications */ #define POP_SCOPE() \ if (ruby_scope->flag & SCOPE_DONT_RECYCLE) {\ if (_old) scope_dup(_old); \ } \ if (!(ruby_scope->flag & SCOPE_MALLOC)) {\ ruby_scope->local_vars = 0; \ ruby_scope->local_tbl = 0; \ if (!(ruby_scope->flag & SCOPE_DONT_RECYCLE)) { \ rb_gc_force_recycle((VALUE)ruby_scope);\ } \ } \ ruby_scope->flag |= SCOPE_NOSTACK; \ ruby_scope = _old; \ scope_vmode = _vmode; \ } static void scope_dup(scope) struct SCOPE *scope; { ID *tbl; VALUE *vars; scope->flag |= SCOPE_DONT_RECYCLE; if (scope->flag & SCOPE_MALLOC) return; if (scope->local_tbl) { tbl = scope->local_tbl; vars = ALLOC_N(VALUE, tbl[0]+1); *vars++ = scope->local_vars[-1]; MEMCPY(vars, scope->local_vars, VALUE, tbl[0]); scope->local_vars = vars; scope->flag |= SCOPE_MALLOC; } } static VALUE cContext_execute_helper(VALUE ary) { VALUE self, str, v; self = rb_funcall(ary, rb_intern("at"), 1, INT2FIX(0)); str = rb_funcall(ary, rb_intern("at"), 1, INT2FIX(1)); PUSH_SCOPE(); v = rb_funcall(self, rb_intern("eval"), 1, str); POP_SCOPE(); return v; } static VALUE cContext_execute(VALUE self, VALUE str) { VALUE v, ary; int state = 0; ary = rb_ary_new3(2, self, str); v = rb_protect(cContext_execute_helper, ary, &state); if (state) { /* we got an exception */ v = rb_gv_get("$!"); v = rb_funcall(v, rb_intern("to_s"), 0); printf("%s\n", RSTRING(v)->ptr); return Qnil; } else { return v; } } int main(void) { VALUE cContext, a, b; ruby_init(); cContext = rb_define_class("Context", rb_cObject); rb_define_method(cContext, "execute", cContext_execute, 1); a = rb_class_new_instance(0, NULL, cContext); rb_funcall(a, rb_intern("execute"), 1, rb_str_new2("a = 5 ; puts a")); b = rb_class_new_instance(0, NULL, cContext); rb_funcall(b, rb_intern("execute"), 1, rb_str_new2("puts a")); return 0; } --AqsLC8rIMeq19msA--