Class: RubyNode

Inherits:
Object
  • Object
show all
Defined in:
lib/rubynode.rb,
ext/rubynode_ext/rubynode_ext.c

Constant Summary collapse

VERSION =
"0.1.5"
NODE_ATTRIBS =
{
	:alias        =>
		lambda { |node|
			{ # ruby >1.8.4 doesn't have nd_new and nd_old
				:new => ((node.respond_to?(:nd_new) && node.nd_new) || node.u1_node),
				:old => ((node.respond_to?(:nd_old) && node.nd_old) || node.u2_node),
			}
		},
	:alloca       => [], # not supported
	:and          => {:first=>:nd_1st, :second=>:nd_2nd},
	:args         => [:cnt, :rest, :opt],
	:argscat      => [:body, :head],
	:argspush     => [:body, :head],
	:array        => [:head, :alen, :next],
	:attrasgn     => [:mid, :args, :recv],
	:attrset      => [:vid],
	:back_ref     => [:nth, :cnt],
	:begin        => [:body],
	:block        => [:head, :next],
	:block_arg    => [:vid, :cnt],
	:block_pass   => [:body, :iter],
	:bmethod      => [:cval],
	:break        => [:stts],
	:call         => [:mid, :args, :recv],
	:case         => [:body, :head],
	:cdecl        => [:vid, :value, :else],
	:cfunc        => [:argc, :cfnc],
	:class        => [:super, :cpath, :body],
	:colon2       => [:head, :mid],
	:colon3       => [:mid],
	:const        => [:vid],
	:cref         => [:next, :clss],
	:cvar         => [:vid],
	:cvasgn       => [:vid, :value],
	:cvdecl       => [:vid, :value],
	:dasgn        => [:vid, :value],
	:dasgn_curr   => [:vid, :value],
	:defined      => [:head],
	:defn         => [:mid, :defn, :noex], # noex seems unused and always NOEX_PRIVATE in 1.8.4
	:defs         => [:mid, :defn, :recv],
	:dmethod      => [:cval],
	:dot2         => [:beg, :end],
	:dot3         => [:beg, :end],
	:dregx        => [:next, :lit, :cflag],
	:dregx_once   => [:next, :lit, :cflag],
	:dstr         => [:next, :lit],
	:dsym         => [:next, :lit],
	:dvar         => [:vid],
	:dxstr        => [:next, :lit],
	:ensure       => [:head, :ensr],
	:evstr        => [:body],
	:false        => [],
	:fbody        => [:orig, :mid, :head],
	:fcall        => [:mid, :args],
	:flip2        => [:cnt, :beg, :end],
	:flip3        => [:cnt, :beg, :end],
	:for          => [:body, :iter, :var],
	:gasgn        => [:vid, :value], # entry not supported
	:gvar         => [:vid], # entry not supported
	:hash         => [:head],
	:iasgn        => [:vid, :value],
	:if           => [:body, :cond, :else],
	:ifunc        => [:tval, :state, :cfnc],
	:iter         => [:body, :iter, :var],
	:ivar         => [:vid],
	:lasgn        => [:vid, :cnt, :value],
	:last         => [],
	:lit          => [:lit],
	:lvar         => [:vid, :cnt],
	:masgn        => [:head, :value, :args],
	:match        => [:lit],
	:match2       => [:value, :recv],
	:match3       => [:value, :recv],
	:memo         => {:u1_value=>:u1_value}, # different uses in enum.c, variabe.c and eval.c ...
	:method       => [:body, :noex, :cnt], # cnt seems to be always 0 in 1.8.4
	:module       => [:cpath, :body],
	:newline      => [:next],
	:next         => [:stts],
	:nil          => [],
	:not          => [:body],
	:nth_ref      => [:nth, :cnt],
	:op_asgn1     => [:mid, :args, :recv],
	:op_asgn2     =>
		lambda { |node|
			if ((v = node.nd_vid) && (m = node.nd_mid) && (a = node.nd_aid))
				{:vid => v, :mid => m, :aid => a}
			else
				{:recv => node.nd_recv, :value => node.nd_value, :next => node.nd_next}
			end
		},
	:op_asgn_and  => [:head, :value],
	:op_asgn_or   => [:head, :aid, :value],
	:opt_n        => [:body],
	:or           => {:first=>:nd_1st, :second=>:nd_2nd},
	:postexe      => [],
	:redo         => [],
	:resbody      => [:body, :head, :args],
	:rescue       => [:head, :else, :resq],
	:retry        => [],
	:return       => [:stts],
	:sclass       => [:recv, :body],
	:scope        => [:rval, :next, :tbl],
	:self         => [],
	:splat        => [:head],
	:str          => [:lit],
	:super        => [:args],
	:svalue       => [:head],
	:to_ary       => [:head],
	:true         => [],
	:undef        =>
		lambda { |node|
			# ruby >1.8.4 uses u2.node instead of nd_mid
			{:mid => (node.u2_node || node.nd_mid)}
		},
	:until        => [:body, :cond, :state],
	:valias       =>
		lambda { |node|
			{ # ruby >1.8.4 doesn't have nd_new and nd_old
				:new => ((node.respond_to?(:nd_new) && node.nd_new) || node.u1_id),
				:old => ((node.respond_to?(:nd_old) && node.nd_old) || node.u2_id),
			}
		},
	:vcall        => [:mid],
	:when         => [:body, :head, :next],
	:while        => [:body, :cond, :state],
	:xstr         => [:lit],
	:yield        => [:head, :state],
	:zarray       => [],
	:zsuper       => [],
}

Instance Method Summary collapse

Instance Method Details

#attribs_hashObject



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/rubynode.rb', line 152

def attribs_hash
	if (t = NODE_ATTRIBS[type])
		case t
		when Array
			res = {}
			t.each { |s| res[s] = send("nd_#{s}") }
			res
		when Hash
			res = {}
			t.each { |k, v| res[k] = send(v) }
			res
		else
			t.call(self)
		end
	else
		# guess by trying
		u1 = u1_value || u1_id || u1_tbl || u1_as_long
		u2 = u2_value || u2_id || u2_argc
		u3 = u3_value || u3_id || u3_cnt
		{:u1 => u1, :u2 => u2, :u3 => u3}
	end
end

#fileObject



33
34
35
36
37
38
# File 'ext/rubynode_ext/rubynode_ext.c', line 33

static VALUE rnode_file(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	if (node->nd_file) return rb_str_new2(node->nd_file);
	else return Qnil;
}

#flagsObject



27
28
29
30
31
# File 'ext/rubynode_ext/rubynode_ext.c', line 27

static VALUE rnode_flags(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return ULONG2NUM(node->flags);
}

#inspectObject



199
200
201
# File 'lib/rubynode.rb', line 199

def inspect
	"#<#{self.class} #{type.inspect}>"
end

#lineObject



40
41
42
43
44
# File 'ext/rubynode_ext/rubynode_ext.c', line 40

static VALUE rnode_line(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return UINT2NUM(nd_line(node));
}

#to_sObject



203
204
205
# File 'lib/rubynode.rb', line 203

def to_s
	"#{self.class}(#{type.inspect}, #{attribs_hash.inspect})"
end

#transform(opts = {}) ⇒ Object



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/rubynode.rb', line 175

def transform(opts = {})
	if type == :newline && !opts[:keep_newline_nodes]
		tmp = nd_next
		return tmp && tmp.transform(opts)
	end
	if (type == :array && !opts[:keep_array_nodes]) || (type == :block && !opts[:keep_block_nodes])
		arr = []
		tmp = self
		begin
			tmp_head = tmp.nd_head
			tmp_head = tmp_head.transform(opts) if RubyNode === tmp_head
			arr << tmp_head
		end while tmp = tmp.nd_next
		[type, arr]
	else
		ah = attribs_hash
		ah.each { |k, v|
			ah[k] = v.transform(opts) if RubyNode === v
		}
		ah[:node] = self if opts[:include_node]
		[type, ah]
	end
end

#typeObject



21
22
23
24
25
# File 'ext/rubynode_ext/rubynode_ext.c', line 21

static VALUE rnode_type(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return node_type_to_sym(nd_type(node));
}

#u1_as_longObject



166
167
168
169
170
# File 'ext/rubynode_ext/rubynode_ext.c', line 166

static VALUE rnode_u1_as_long(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return LONG2NUM((long)(node->u1.id));
}

#u1_cfuncObject



171
172
173
174
175
# File 'ext/rubynode_ext/rubynode_ext.c', line 171

static VALUE rnode_u1_cfunc(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return ULONG2NUM((unsigned long)(node->u1.cfunc));
}

#u1_idObject



150
151
152
153
154
# File 'ext/rubynode_ext/rubynode_ext.c', line 150

static VALUE rnode_u1_id(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return id_to_value(node->u1.id);
}

#u1_nodeObject



134
135
136
137
138
# File 'ext/rubynode_ext/rubynode_ext.c', line 134

static VALUE rnode_u1_value_or_node(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return value_or_node_to_value(node->u1.value, nd_type(node), 1, node);
}

#u1_tblObject



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'ext/rubynode_ext/rubynode_ext.c', line 187

static VALUE rnode_u1_tbl(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	/* only allowed for SCOPE */
	if (nd_type(node) == NODE_SCOPE) {
		ID * tbl = node->u1.tbl;
		if (tbl) {
			size_t i;
			VALUE arr = rb_ary_new();
			/* 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 (i = 3; i <= tbl[0]; ++i) {
				if (tbl[i] == 0 || !rb_is_local_id(tbl[i]))
					/* flip state */
					rb_ary_push(arr, Qnil);
				else
					rb_ary_push(arr, ID2SYM(tbl[i]));
			}
			return arr;
		}
	}
	return Qnil;
}

#u1_valueObject



134
135
136
137
138
# File 'ext/rubynode_ext/rubynode_ext.c', line 134

static VALUE rnode_u1_value_or_node(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return value_or_node_to_value(node->u1.value, nd_type(node), 1, node);
}

#u2_argcObject



176
177
178
179
180
# File 'ext/rubynode_ext/rubynode_ext.c', line 176

static VALUE rnode_u2_argc(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return LONG2NUM(node->u2.argc);
}

#u2_idObject



155
156
157
158
159
# File 'ext/rubynode_ext/rubynode_ext.c', line 155

static VALUE rnode_u2_id(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return id_to_value(node->u2.id);
}

#u2_nodeObject



139
140
141
142
143
# File 'ext/rubynode_ext/rubynode_ext.c', line 139

static VALUE rnode_u2_value_or_node(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return value_or_node_to_value(node->u2.value, nd_type(node), 2, node);
}

#u2_valueObject



139
140
141
142
143
# File 'ext/rubynode_ext/rubynode_ext.c', line 139

static VALUE rnode_u2_value_or_node(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return value_or_node_to_value(node->u2.value, nd_type(node), 2, node);
}

#u3_cntObject



181
182
183
184
185
# File 'ext/rubynode_ext/rubynode_ext.c', line 181

static VALUE rnode_u3_state_or_cnt(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return LONG2NUM(node->u3.state);
}

#u3_idObject



160
161
162
163
164
# File 'ext/rubynode_ext/rubynode_ext.c', line 160

static VALUE rnode_u3_id(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return id_to_value(node->u3.id);
}

#u3_nodeObject



144
145
146
147
148
# File 'ext/rubynode_ext/rubynode_ext.c', line 144

static VALUE rnode_u3_value_or_node(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return value_or_node_to_value(node->u3.value, nd_type(node), 3, node);
}

#u3_stateObject



181
182
183
184
185
# File 'ext/rubynode_ext/rubynode_ext.c', line 181

static VALUE rnode_u3_state_or_cnt(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return LONG2NUM(node->u3.state);
}

#u3_valueObject



144
145
146
147
148
# File 'ext/rubynode_ext/rubynode_ext.c', line 144

static VALUE rnode_u3_value_or_node(VALUE self) {
	NODE * node;
	Data_Get_Struct(self, NODE, node);
	return value_or_node_to_value(node->u3.value, nd_type(node), 3, node);
}