#include "nodeinfo.h" #include "version.h" #include "global_entry.h" #include "builtins.h" static int is_flip_state(ID id) { if(id == 0) { return 1; } #ifdef HAVE_RB_IS_LOCAL_ID if(!rb_is_local_id(id)) { return 1; } #endif return 0; } static VALUE variable_names(ID * tbl) { if(tbl) { size_t j; VALUE arr = rb_ary_new(); /* A tbl contains the names of local variables. The first * element is the size of the table. The next two elements * are $_ and $~. The rest of the elements are the names of * the variables themselves. */ for(j = 3; j <= tbl[0]; ++j) { if(is_flip_state(tbl[j])) { /* flip state */ rb_ary_push(arr, Qnil); } else { rb_ary_push(arr, ID2SYM(tbl[j])); } } return arr; } else { return Qnil; } } /* Every node contains three elements. This function takes any one of * those elements, converts it to a Ruby object that can be dumped * (since nodes can't be dumped), and puts the resulting object into * node_hash. */ VALUE dump_node_elem(enum Node_Elem_Name nen, NODE * n, VALUE node_hash) { switch(nen) { case NEN_NONE: return Qnil; #ruby <nd_#{node_elem_name}) { int node_type; if(#{node_elem_name == "next" ? 1 : 0} && nd_type(n) == NODE_OP_ASGN2) { /* All children of NODE_OP_ASGN2 are NODE_OP_ASGN2_ARG */ node_type = NODE_OP_ASGN2_ARG; } else { node_type = nd_type(n->nd_#{node_elem_name}); } dump_node_or_iseq_to_hash( (VALUE)n->nd_#{node_elem_name}, node_type, node_hash); return node_id(n->nd_#{node_elem_name}); } else { return Qnil; } END when /\.value$/ puts <<-END switch(TYPE(n->nd_#{node_elem_name})) { case T_CLASS: case T_MODULE: { /* When dumping a class, we dump just the name (otherwise we'd * get multiple copies of the class each time we load a method * on the other side). */ VALUE klass = (VALUE)n->nd_#{node_elem_name}; VALUE path; if(FL_TEST(klass, FL_SINGLETON)) { VALUE singleton = rb_iv_get(klass, "__attached__"); path = rb_class_path(singleton); } else { path = rb_class_path(klass); if(STR2CSTR(path)[0] == '#') { rb_raise(rb_eArgError, "cannot dump anonymous class"); } } return rb_assoc_new( INT2NUM(((struct RBasic *)(n->nd_#{node_elem_name}))->flags), path); } case T_NODE: rb_raise( rb_eRuntimeError, "Wrong node elem #{node_elem_name} for node type %d", nd_type(n)); default: /* TODO: would like to dump flags, not type */ return rb_assoc_new( INT2NUM(TYPE((VALUE)n->nd_#{node_elem_name})), (VALUE)n->nd_#{node_elem_name}); } END when /\.id$/ puts <<-END if(n->nd_#{node_elem_name} == 0) { return Qfalse; } else if(n->nd_#{node_elem_name} == 1) { return Qtrue; } else { return ID2SYM(n->nd_#{node_elem_name}); } END when /\.(argc|state|cnt)$/ puts <<-END { return LONG2NUM((long)n->nd_#{node_elem_name}); } END when /\.(tbl)$/ puts <<-END { VALUE v = variable_names(n->nd_#{node_elem_name}); return v; } END when /\.(entry)$/ puts <<-END if(n->nd_#{node_elem_name}->id == 0) { return Qfalse; } else { return ID2SYM(n->nd_#{node_elem_name}->id); } END when /\.(cfunc)$/ puts <<-END /* rb_funcall(rb_cObject, rb_intern("pp"), wrap_node(n), 0); */ rb_raise(rb_eArgError, "Cannot dump #{$1}"); END end end nil END } rb_raise(rb_eArgError, "Invalid Node_Elem_Name %d", nen); } void load_node_elem(enum Node_Elem_Name nen, VALUE v, NODE * n, VALUE node_hash, VALUE id_hash) { switch(nen) { case NEN_NONE: return; #ruby <nd_#{node_elem_name} = 0; } else { VALUE nid = rb_hash_aref(id_hash, v); if(RTEST(nid)) { n->nd_#{node_elem_name} = id_to_node(nid); } else { n->#{node_elem_ref} = (NODE *)load_node_or_iseq_from_hash( v, node_hash, id_hash); if(nd_type(n->#{node_elem_ref}) == NODE_OP_ASGN2_ARG) { nd_set_type(n->#{node_elem_ref}, NODE_OP_ASGN2); } } } return; END when /\.value$/ puts <<-END Check_Type(v, T_ARRAY); if(RARRAY_LEN(v) != 2) { rb_raise(rb_eArgError, "wrong size for array"); } int flags = NUM2INT(RARRAY_PTR(v)[0]); switch(flags & T_MASK) { case T_CLASS: case T_MODULE: { VALUE str = RARRAY_PTR(v)[1]; Check_Type(str, T_STRING); VALUE klass = rb_path2class(STR2CSTR(str)); if(flags & FL_SINGLETON) { *(VALUE *)(&n->nd_#{node_elem_name}) = rb_singleton_class(klass); } else { *(VALUE *)(&n->nd_#{node_elem_name}) = klass; } break; } default: *(VALUE *)(&n->nd_#{node_elem_name}) = RARRAY_PTR(v)[1]; break; } return; END when /\.id$/ puts <<-END if(v == Qfalse) { n->nd_#{node_elem_name} = 0; } else if(v == Qfalse) { n->nd_#{node_elem_name} = 1; } else { n->nd_#{node_elem_name} = SYM2ID(v); } return; END when /\.(argc|state|cnt)$/ puts <<-END n->nd_#{node_elem_name} = NUM2LONG(v); return; END when /\.(tbl)$/ puts <<-END if(v == Qnil) { n->nd_#{node_elem_name} = 0; } else { size_t len, j; ID * tmp_tbl; Check_Type(v, T_ARRAY); len = RARRAY_LEN(v); tmp_tbl = ALLOCA_N(ID, len + 3); tmp_tbl[0] = (ID)(len + 2); tmp_tbl[1] = (ID)('_'); tmp_tbl[2] = (ID)('~'); for(j = 0; j < len; ++j) { VALUE e = RARRAY_PTR(v)[j]; if(e == Qnil) { /* flip state */ tmp_tbl[j + 3] = 0; } else { tmp_tbl[j + 3] = SYM2ID(e); } } n->nd_#{node_elem_name} = ALLOC_N(ID, len + 3); memcpy(n->nd_#{node_elem_name}, tmp_tbl, sizeof(ID) * (len + 3)); } return; END when /\.(entry)$/ puts <<-END n->nd_#{node_elem_name} = rb_global_entry(SYM2ID(v)); return; END when /\.(cfunc)$/ puts <<-END rb_raise(rb_eRuntimeError, "Cannot load #{$1}"); END end puts <<-END } END end nil END } rb_raise(rb_eRuntimeError, "Internal error: invalid Node_Elem_Name %d", nen); } #ruby <nd_#{node_elem_name}) == T_NODE) { if(#{node_elem_name == "next" ? 1 : 0} && nd_type(n) == NODE_OP_ASGN2) { return wrap_node_as( (NODE *)n->nd_#{node_elem_name}, rb_cNodeSubclass[NODE_OP_ASGN2_ARG]); } else { return wrap_node((NODE *)n->nd_#{node_elem_name}); } } else { return (VALUE)n->nd_#{node_elem_name}; } } END when /\.id$/ puts <<-END /* * Return the Node's _#{node_elem_name}_ member. The return type is a * Symbol. */ static VALUE node_#{node_elem_name}(VALUE self) { NODE * n; Data_Get_Struct(self, NODE, n); if(n->nd_#{node_elem_name} == 0) { return Qfalse; } else if(n->nd_#{node_elem_name} == 1) { return Qtrue; } else { return ID2SYM(n->nd_#{node_elem_name}); } } END when /\.(argc|state|cnt)$/ puts <<-END /* * Return the Node's _#{node_elem_name}_ member. The return type is an * Integer. */ static VALUE node_#{node_elem_name}(VALUE self) { NODE * n; Data_Get_Struct(self, NODE, n); return LONG2NUM(n->nd_#{node_elem_name}); } END when /\.(tbl)$/ puts <<-END /* * Return the Node's _#{node_elem_name}_ member. The return value is an * Array holding names of variables. */ static VALUE node_#{node_elem_name}(VALUE self) { NODE * n; Data_Get_Struct(self, NODE, n); return variable_names(n->nd_#{node_elem_name}); } END when /\.(entry)$/ puts <<-END /* * Return the Node's _#{node_elem_name}_ member. The return type is * either a Node or an Object. */ static VALUE node_#{node_elem_name}(VALUE self) { NODE * n; Data_Get_Struct(self, NODE, n); if(n->nd_#{node_elem_name}->id == 0) { return Qfalse; } else { return ID2SYM(n->nd_#{node_elem_name}->id); } } END when /\.(cfunc)$/ puts <<-END static VALUE node_#{node_elem_name}(VALUE self) { NODE * n; Data_Get_Struct(self, NODE, n); return LONG2NUM((long)(n->nd_#{node_elem_name})); } END end end nil END /* * Return an array of strings containing the names of the node class's * members. */ VALUE node_s_members(VALUE klass) { return rb_iv_get(klass, "__member__"); } #ruby <