yarv-diff:186
From: ko1 atdot.net
Date: 30 Dec 2005 10:19:19 -0000
Subject: [yarv-diff:186] r344 - in trunk: . benchmark yarvtest
Author: ko1
Date: 2005-12-30 19:19:18 +0900 (Fri, 30 Dec 2005)
New Revision: 344
Modified:
trunk/ChangeLog
trunk/benchmark/bmx_temp.rb
trunk/eval.c
trunk/eval_intern.h
trunk/eval_proc.c
trunk/test.rb
trunk/yarvcore.c
trunk/yarvcore.h
trunk/yarvtest/test_eval.rb
Log:
* yarvcore.c, yarvcore.h, eval.c, eval_proc.c : support
Ruby's Binding
* yarvcore.c : support TOPLEVEL_BINDING
* yarvtest/test_eval.rb : add tests for above
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2005-12-30 04:13:33 UTC (rev 343)
+++ trunk/ChangeLog 2005-12-30 10:19:18 UTC (rev 344)
@@ -4,6 +4,16 @@
# from Mon, 03 May 2004 01:24:19 +0900
#
+2005-12-30(Fri) 19:07:51 +0900 Koichi Sasada <ko1 atdot.net>
+
+ * yarvcore.c, yarvcore.h, eval.c, eval_proc.c : support
+ Ruby's Binding
+
+ * yarvcore.c : support TOPLEVEL_BINDING
+
+ * yarvtest/test_eval.rb : add tests for above
+
+
2005-12-30(Fri) 13:12:28 +0900 Minero Aoki <aamine loveruby.net>
* test/ruby/test_eval.rb: more tests for
Modified: trunk/benchmark/bmx_temp.rb
===================================================================
--- trunk/benchmark/bmx_temp.rb 2005-12-30 04:13:33 UTC (rev 343)
+++ trunk/benchmark/bmx_temp.rb 2005-12-30 10:19:18 UTC (rev 344)
@@ -1,9 +1,4 @@
-i=0
-while i<100000
- begin
- raise
- rescue
-
- end
- i+=1
-end
+require 'erb'
+50000.times{|e|
+ ERB.new('<%= e %>').result(binding)
+}
Modified: trunk/eval.c
===================================================================
--- trunk/eval.c 2005-12-30 04:13:33 UTC (rev 343)
+++ trunk/eval.c 2005-12-30 10:19:18 UTC (rev 344)
@@ -1141,7 +1141,7 @@
{
yarv_thread_t *th = GET_THREAD();
yarv_control_frame_t *cfp = th->cfp;
- cfp = YARV_PREVIOUS_CONTROL_FRAME(cfp);
+ cfp = th_get_ruby_level_cfp(th, YARV_PREVIOUS_CONTROL_FRAME(cfp));
if(GC_GUARDED_PTR_REF(cfp->lfp[0])){
return Qtrue;
}
@@ -1894,12 +1894,15 @@
return th_get_sourceline(th->cfp);
}
+VALUE th_set_eval_stack(yarv_thread_t *, VALUE iseq);
+
static VALUE
eval(VALUE self, VALUE src, VALUE scope, char *file, int line)
{
volatile int safe = ruby_safe_level;
int state;
VALUE result;
+ yarv_binding_t *bind = 0;
if (file == 0) {
ruby_set_current_source();
@@ -1911,11 +1914,13 @@
if((state = EXEC_TAG()) == 0){
yarv_thread_t *th = GET_THREAD();
yarv_iseq_t *iseq;
+ VALUE iseqval;
if(scope != Qnil){
yarv_env_t *env;
- if(CLASS_OF(scope) == cYarvEnv){
- /* do nothing */
+ if(CLASS_OF(scope) == cYarvBinding){
+ GetBindingVal(scope, bind);
+ scope = bind->env;
}
else if(CLASS_OF(scope) == cYarvProc){
yarv_proc_t *proc;
@@ -1930,17 +1935,28 @@
th->base_block = &env->block;
}
else{
-
yarv_control_frame_t *cfp =
th_get_ruby_level_cfp(th, YARV_PREVIOUS_CONTROL_FRAME(th->cfp));
th->base_block = GET_BLOCK_PTR_IN_CFP(cfp);
th->base_block->iseq = cfp->iseq;
}
-
+
+ /* make eval iseq */
iseq = th->base_block->iseq->local_iseq;
th->base_local_tbl = iseq->local_tbl;
th->base_local_size = iseq->local_size;
- result = yarvcore_eval(0, src, rb_str_new2(file), INT2FIX(line));
+ iseqval = th_compile(th, src, rb_str_new2(file), INT2FIX(line));
+ th_set_eval_stack(th, iseqval);
+ th->base_block = 0;
+
+ /* save new env */
+ GetISeqVal(iseqval, iseq);
+ if(bind && iseq->local_size > 0){
+ bind->env = th_make_env_object(th, th->cfp);
+ }
+
+ /* kick */
+ result = th_eval_body(th);
}
POP_TAG();
@@ -2714,7 +2730,8 @@
{
VALUE ary = rb_ary_new();
yarv_thread_t *th = GET_THREAD();
- yarv_control_frame_t *cfp = YARV_PREVIOUS_CONTROL_FRAME(th->cfp);
+ yarv_control_frame_t *cfp =
+ th_get_ruby_level_cfp(th, YARV_PREVIOUS_CONTROL_FRAME(th->cfp));
int i;
while(1){
@@ -2909,7 +2926,8 @@
}
int
-rb_dvar_current(){
+rb_dvar_current()
+{
yarv_thread_t *th = GET_THREAD();
if(th->base_block){
return 1;
Modified: trunk/eval_intern.h
===================================================================
--- trunk/eval_intern.h 2005-12-30 04:13:33 UTC (rev 343)
+++ trunk/eval_intern.h 2005-12-30 10:19:18 UTC (rev 344)
@@ -286,8 +286,8 @@
NORETURN(void print_undef _((VALUE, ID)));
rb_thread_t rb_vm_curr_thread();
+VALUE th_compile(yarv_thread_t *th, VALUE str, VALUE file, VALUE line);
-
VALUE th_get_cref(yarv_thread_t *th, yarv_iseq_t *iseq, yarv_control_frame_t *cfp);
static yarv_control_frame_t *
Modified: trunk/eval_proc.c
===================================================================
--- trunk/eval_proc.c 2005-12-30 04:13:33 UTC (rev 343)
+++ trunk/eval_proc.c 2005-12-30 10:19:18 UTC (rev 344)
@@ -59,11 +59,17 @@
*/
VALUE
-rb_f_binding(self)
- VALUE self;
+rb_f_binding(VALUE self)
{
- return th_make_env_object(GET_THREAD(),
- YARV_PREVIOUS_CONTROL_FRAME(GET_THREAD()->cfp));
+ yarv_thread_t *th = GET_THREAD();
+ yarv_control_frame_t *cfp =
+ th_get_ruby_level_cfp(th, th->cfp);
+ VALUE bindval = rb_obj_alloc(cYarvBinding);
+ yarv_binding_t *bind;
+
+ GetBindingVal(bindval, bind);
+ bind->env = th_make_env_object(th, cfp);
+ return bindval;
}
/*
@@ -150,11 +156,13 @@
rb_raise(rb_eArgError, "tried to create Proc object without a block");
}
}
- cfp = YARV_PREVIOUS_CONTROL_FRAME(cfp);
+ cfp = th_get_ruby_level_cfp(th, YARV_PREVIOUS_CONTROL_FRAME(cfp));
procval = th_make_proc(th, cfp, block);
if(is_lambda){
- // TODO: lambda or proc
+ yarv_proc_t *proc;
+ GetProcVal(procval, proc);
+ proc->is_lambda = Qtrue;
}
return procval;
}
Modified: trunk/test.rb
===================================================================
--- trunk/test.rb 2005-12-30 04:13:33 UTC (rev 343)
+++ trunk/test.rb 2005-12-30 10:19:18 UTC (rev 344)
@@ -1,5 +1,108 @@
+class C
+ def m
+ self.class.class_eval %q{
+ module M
+ a = 1
+ $b = binding
+ end
+ }
+ end
+end
+C.new.m
+p eval('a', $b)
+
+__END__
+Const = :top
class C
+ Const = :C
+ def m
+ binding
+ end
+end
+
+eval('Const', C.new.m)
+__END__
+$ans = []
+ def m
+ $b = binding
+ end
+ m
+ $ans << eval(%q{
+ $ans << eval(%q{
+ a
+ }, $b)
+ a = 1
+ }, $b)
+p $ans
+
+__END__
+
+class C
+ @@cvar = 1
+end
+
+C.new.instance_eval %{
+ p @@cvar
+}
+__END__
+class Fixnum
+ @@cvar = 1
+end
+
+1.instance_eval %{
+ p @@cvar
+}
+__END__
+
+class Base
+ def initialize(p1, p2 = 1)
+ p [p1, p2]
+ end
+end
+
+class Derived < Base
+ def initialize(p1, p2 = 2)
+ super
+ end
+end
+
+Derived.new(0)
+__END__
+require 'erb'
+
+ERB.new(<<EOS).run(binding)
+<% 3.times do |n| %>
+% n = 0
+* <%= n%>
+<% end %>
+EOS
+
+__END__
+
+
+class C
+end
+
+class D
+ C.class_eval{
+ def m1
+ p :OK
+ end
+ eval %{
+ def m2
+ p :OK
+ end
+ }
+ }
+end
+
+C.new.m1 #=> :OK
+#D.new.m2 #=> :OK
+C.new.m2 #=> NoMethodError
+
+__END__
+class C
# private
$pr = proc{
def m
Modified: trunk/yarvcore.c
===================================================================
--- trunk/yarvcore.c 2005-12-30 04:13:33 UTC (rev 343)
+++ trunk/yarvcore.c 2005-12-30 10:19:18 UTC (rev 344)
@@ -22,6 +22,7 @@
VALUE mYarvInsns;
VALUE cYarvEnv;
VALUE cYarvProc;
+VALUE cYarvBinding;
VALUE symIFUNC;
VALUE symCFUNC;
@@ -109,6 +110,7 @@
VALUE yarv_new_iseqval(VALUE node, VALUE name, VALUE file,
VALUE parent, VALUE type, VALUE opt);
+static VALUE th_eval(yarv_thread_t *th, VALUE iseq);
/************/
/* YARVCore */
@@ -183,8 +185,6 @@
RUBY_EXTERN int ruby_nerrs;
RUBY_EXTERN NODE* ruby_eval_tree;
-static VALUE vm_eval(VALUE self, VALUE iseq);
-
VALUE
yarv_load(char *file)
{
@@ -209,7 +209,7 @@
iseq = yarv_new_iseqval((VALUE)node, rb_str_new2("<top (required)>"),
rb_str_new2(file), Qfalse, ISEQ_TYPE_TOP, Qfalse);
- vm_eval(GET_VM()->self, iseq);
+ th_eval(GET_THREAD(), iseq);
return 0;
}
@@ -256,7 +256,6 @@
*var = val;
}
-
static VALUE
compile_string(VALUE str, VALUE file, VALUE line)
{
@@ -271,34 +270,41 @@
return (VALUE)node;
}
-
static VALUE
yarvcore_eval_iseq(VALUE iseq)
{
- VALUE vm;
- VALUE ret;
- vm = GET_VM()->self;
- ret = vm_eval(vm, iseq);
- return ret;
+ return th_eval(GET_THREAD(), iseq);
}
-VALUE
-yarvcore_eval_parsed(VALUE node, VALUE file)
+static VALUE
+th_compile_from_node(yarv_thread_t *th, NODE *node, VALUE file)
{
-
VALUE iseq;
-
- if(GET_THREAD()->base_block){
- iseq = yarv_new_iseqval(node,
- GET_THREAD()->base_block->iseq->name,
+ if(th->base_block){
+ iseq = yarv_new_iseqval((VALUE)node,
+ th->base_block->iseq->name,
file,
- GET_THREAD()->base_block->iseq->self,
+ th->base_block->iseq->self,
ISEQ_TYPE_EVAL, Qfalse);
}
else{
- iseq = yarv_new_iseqval(node, rb_str_new2("<main>"), file,
+ iseq = yarv_new_iseqval((VALUE)node, rb_str_new2("<main>"), file,
Qfalse, ISEQ_TYPE_TOP, Qfalse);
}
+ return iseq;
+}
+
+VALUE
+th_compile(yarv_thread_t *th, VALUE str, VALUE file, VALUE line)
+{
+ NODE *node = (NODE*)compile_string(str, file, line);
+ return th_compile_from_node(th, (NODE *)node, file);
+}
+
+VALUE
+yarvcore_eval_parsed(VALUE node, VALUE file)
+{
+ VALUE iseq = th_compile_from_node(GET_THREAD(), (NODE*)node, file);
return yarvcore_eval_iseq(iseq);
}
@@ -588,16 +594,10 @@
return self;
}
-static VALUE thread_eval(VALUE self, VALUE iseq);
-
static VALUE
vm_eval(VALUE self, VALUE iseq)
{
- yarv_vm_t *vm;
- VALUE val;
- GetVMVal(self, vm);
- val = thread_eval(vm->main_thread, iseq);
- return val;
+ return th_eval(GET_THREAD(), iseq);
}
@@ -737,26 +737,28 @@
VALUE th_eval_body(yarv_thread_t *th);
VALUE th_set_top_stack(yarv_thread_t *, VALUE iseq);
-VALUE th_set_eval_stack(yarv_thread_t *, VALUE iseq);
-static VALUE thread_eval(VALUE self, VALUE iseq){
+static VALUE
+th_eval(yarv_thread_t *th, VALUE iseq)
+{
VALUE val;
- yarv_thread_t *th;
- GetThreadVal(self, th);
-
- if(th->base_block){
- th_set_eval_stack(th, iseq);
- th->base_block = 0;
+ th_set_top_stack(th, iseq);
+ if(!rb_const_defined(rb_cObject, rb_intern("TOPLEVEL_BINDING"))){
+ rb_define_global_const("TOPLEVEL_BINDING", rb_f_binding(Qnil));
}
- else{
- th_set_top_stack(th, iseq);
- }
val = th_eval_body(th);
-
return val;
}
+static VALUE
+thread_eval(VALUE self, VALUE iseq)
+{
+ yarv_thread_t *th;
+ GetThreadVal(self, th);
+ return th_eval(th, iseq);
+}
+
/***************/
/* YarvEnv */
/***************/
@@ -843,9 +845,9 @@
MARK_UNLESS_NULL(proc->envval);
//GC_INFO("blockval\n");
MARK_UNLESS_NULL(proc->blockprocval);
-
+ MARK_UNLESS_NULL(proc->cref_stack);
//GC_INFO("iseq\n");
- if(proc->block.iseq && BUILTIN_TYPE(proc->block.iseq) == T_NODE){
+ if(proc->block.iseq && YARV_IFUNC_P(proc->block.iseq)){
MARK_UNLESS_NULL((VALUE)(proc->block.iseq));
}
}
@@ -862,6 +864,7 @@
proc->envval = 0;
proc->blockprocval = 0;
proc->block.iseq = 0;
+ proc->is_lambda = 0;
return obj;
}
@@ -919,6 +922,48 @@
return INT2FIX(-1);
}
}
+
+
+/***************/
+/* YarvBinding */
+/***************/
+
+static void
+binding_free(void *ptr)
+{
+ yarv_binding_t *bind;
+ FREE_REPORT("-> binding");
+ if(ptr){
+ bind = ptr;
+ ruby_xfree(ptr);
+ }
+ FREE_REPORT("<- binding");
+}
+
+static void
+binding_mark(void *ptr)
+{
+ yarv_binding_t *bind;
+ MARK_REPORT("-> binding", 1);
+ if(ptr){
+ bind = ptr;
+ MARK_UNLESS_NULL(bind->env);
+ MARK_UNLESS_NULL(bind->cref_stack);
+ }
+ MARK_REPORT("<- binding", 0);
+}
+
+static VALUE
+binding_alloc(VALUE klass)
+{
+ VALUE obj;
+ yarv_binding_t *bind;
+ obj = Data_Make_Struct(klass, yarv_binding_t,
+ binding_mark, binding_free, bind);
+ return obj;
+}
+
+
/********************************************************************/
static VALUE yarv_once(){
@@ -1042,6 +1087,10 @@
rb_define_method(cYarvProc, "arity", proc_arity, 0);
rb_define_singleton_method(cYarvProc, "new", rb_proc_s_new, -1);
+ /* declare YARVCore::VM::Binding */
+ cYarvBinding = rb_define_class_under(cYarvVM, "Binding", rb_cObject);
+ rb_define_alloc_func(cYarvBinding, binding_alloc);
+
/* misc */
Modified: trunk/yarvcore.h
===================================================================
--- trunk/yarvcore.h 2005-12-30 04:13:33 UTC (rev 343)
+++ trunk/yarvcore.h 2005-12-30 10:19:18 UTC (rev 344)
@@ -88,6 +88,7 @@
extern VALUE mYarvInsns;
extern VALUE cYarvEnv;
extern VALUE cYarvProc;
+extern VALUE cYarvBinding;
extern VALUE symIFUNC;
extern VALUE symCFUNC;
@@ -421,13 +422,15 @@
yarv_block_t block;
VALUE envval; /* for GC mark */
VALUE blockprocval;
+ VALUE cref_stack;
int safe_level;
+ int is_lambda;
+ int visibility;
} yarv_proc_t;
#define GetEnvVal(obj, iobj) \
Data_Get_Struct(obj, yarv_env_t, iobj)
-
typedef struct{
VALUE *env;
int env_size;
@@ -436,7 +439,15 @@
yarv_block_t block;
} yarv_env_t;
+#define GetBindingVal(obj, iobj) \
+ Data_Get_Struct(obj, yarv_binding_t, iobj)
+typedef struct{
+ VALUE env;
+ VALUE cref_stack;
+} yarv_binding_t;
+
+
/* used by compile time and send insn */
#define VM_CALL_ARGS_SPLAT_BIT 0x01
#define VM_CALL_ARGS_BLOCKARG_BIT 0x02
Modified: trunk/yarvtest/test_eval.rb
===================================================================
--- trunk/yarvtest/test_eval.rb 2005-12-30 04:13:33 UTC (rev 343)
+++ trunk/yarvtest/test_eval.rb 2005-12-30 10:19:18 UTC (rev 344)
@@ -106,7 +106,7 @@
$ans << Const
C.module_eval %{
$ans << Const
- Boo = false
+ Boo = false unless defined? Boo
unless $nest
$nest = true
m
@@ -135,5 +135,60 @@
$ans
}
end
+
+ def test_binding
+ ae %q{
+ def m
+ a = :ok
+ $b = binding
+ end
+ m
+ eval('a', $b)
+ }
+ ae %q{
+ def m
+ a = :ok
+ $b = binding
+ end
+ m
+ eval('b = :ok2', $b)
+ eval('[a, b]', $b)
+ }
+ ae %q{
+ $ans = []
+ def m
+ $b = binding
+ end
+ m
+ $ans << eval(%q{
+ $ans << eval(%q{
+ a
+ }, $b)
+ a = 1
+ }, $b)
+ $ans
+ }
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ def m
+ binding
+ end
+ end
+ eval('Const', C.new.m)
+ }
+ ae %q{
+ Const = :top
+ a = 1
+ class C
+ Const = :C
+ def m
+ eval('Const', TOPLEVEL_BINDING)
+ end
+ end
+ C.new.m
+ }
+ end
end
--
ML: yarv-diff quickml.atdot.net
Info: http://www.atdot.net/~ko1/quickml