Class: Ruby2CExtension::CFunction::Base

Inherits:
Object
  • Object
show all
Extended by:
Tools::EnsureNodeTypeMixin
Includes:
Ruby2CExtension::CommonNodeComp
Defined in:
lib/ruby2cext/c_function.rb

Overview

contains all different Types of C functions that are compiled from ruby nodes

Direct Known Subclasses

Block, ClassModuleScope, Method, Wrap

Constant Summary

Constants included from Ruby2CExtension::CommonNodeComp

Ruby2CExtension::CommonNodeComp::NON_ITER_PROC

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Tools::EnsureNodeTypeMixin

ensure_node_type

Methods included from Ruby2CExtension::CommonNodeComp

#build_args, #build_c_arr, #c_else, #c_for, #c_if, #c_scope, #c_scope_res, #c_static_once, #comp, #comp_alias, #comp_and, #comp_argscat, #comp_argspush, #comp_array, #comp_attrasgn, #comp_back_ref, #comp_begin, #comp_block, #comp_block_pass, #comp_call, #comp_case, #comp_cdecl, #comp_class, #comp_colon2, #comp_colon3, #comp_const, #comp_cvar, #comp_cvasgn, #comp_cvdecl, #comp_dasgn, #comp_dasgn_curr, #comp_defined, #comp_defn, #comp_defs, #comp_dot2, #comp_dot3, #comp_dregx, #comp_dregx_once, #comp_dstr, #comp_dsym, #comp_dvar, #comp_dxstr, #comp_ensure, #comp_evstr, #comp_false, #comp_fcall, #comp_flip2, #comp_flip3, #comp_for, #comp_gasgn, #comp_gvar, #comp_hash, #comp_iasgn, #comp_if, #comp_iter, #comp_ivar, #comp_lasgn, #comp_lit, #comp_lvar, #comp_masgn, #comp_match, #comp_match2, #comp_match3, #comp_module, #comp_nil, #comp_not, #comp_nth_ref, #comp_op_asgn1, #comp_op_asgn2, #comp_op_asgn_and, #comp_op_asgn_or, #comp_or, #comp_postexe, #comp_rescue, #comp_sclass, #comp_self, #comp_splat, #comp_str, #comp_super, #comp_svalue, #comp_to_ary, #comp_true, #comp_undef, #comp_until, #comp_valias, #comp_vcall, #comp_when, #comp_while, #comp_xstr, #comp_yield, #comp_zarray, #comp_zsuper, #do_funcall, #get_global_entry, #handle_assign, #handle_dot, #handle_dyn_str, #handle_flip, #handle_iter, #handle_method_args, #handle_when, #helper_class_module_check, #helper_super_allowed_check, #make_block, #make_class_prefix

Constructor Details

#initialize(compiler, scope) ⇒ Base

Returns a new instance of Base.



18
19
20
21
22
23
24
25
# File 'lib/ruby2cext/c_function.rb', line 18

def initialize(compiler, scope)
	@compiler = compiler
	@scope = scope
	@closure_tbl = []
	@scope.closure_tbl = @closure_tbl
	@lines = []
	@while_stack = []
end

Instance Attribute Details

#closure_tblObject (readonly)

Returns the value of attribute closure_tbl.



16
17
18
# File 'lib/ruby2cext/c_function.rb', line 16

def closure_tbl
  @closure_tbl
end

#compilerObject (readonly)

Returns the value of attribute compiler.



16
17
18
# File 'lib/ruby2cext/c_function.rb', line 16

def compiler
  @compiler
end

#need_classObject

Returns the value of attribute need_class.



17
18
19
# File 'lib/ruby2cext/c_function.rb', line 17

def need_class
  @need_class
end

#need_crefObject

Returns the value of attribute need_cref.



17
18
19
# File 'lib/ruby2cext/c_function.rb', line 17

def need_cref
  @need_cref
end

#need_resObject

Returns the value of attribute need_res.



17
18
19
# File 'lib/ruby2cext/c_function.rb', line 17

def need_res
  @need_res
end

#need_selfObject

Returns the value of attribute need_self.



17
18
19
# File 'lib/ruby2cext/c_function.rb', line 17

def need_self
  @need_self
end

#need_wrapObject

Returns the value of attribute need_wrap.



17
18
19
# File 'lib/ruby2cext/c_function.rb', line 17

def need_wrap
  @need_wrap
end

#scopeObject (readonly)

Returns the value of attribute scope.



16
17
18
# File 'lib/ruby2cext/c_function.rb', line 16

def scope
  @scope
end

Instance Method Details

#add_closure_need(sym) ⇒ Object



165
166
167
# File 'lib/ruby2cext/c_function.rb', line 165

def add_closure_need(sym)
	closure_tbl << sym unless closure_tbl.include? sym
end

#add_helper(str) ⇒ Object



36
# File 'lib/ruby2cext/c_function.rb', line 36

def add_helper(str); compiler.add_helper(str); end

#assign_res(str) ⇒ Object



125
126
127
128
129
130
# File 'lib/ruby2cext/c_function.rb', line 125

def assign_res(str)
	self.need_res = true
	unless str.strip == "res"
		l "res = #{str};"
	end
end

#break_allowed?(with_value) ⇒ Boolean

Returns:

  • (Boolean)


71
72
73
# File 'lib/ruby2cext/c_function.rb', line 71

def break_allowed?(with_value)
	in_while?(:break)
end

#closure_buid_c_codeObject



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/ruby2cext/c_function.rb', line 169

def closure_buid_c_code
	if closure_tbl.empty?
		nil
	else
		res = ["#{get_closure_ary_var} = rb_ary_new2(#{closure_tbl.size});"]
		closure_tbl.each_with_index { |entry, idx|
			case entry
			when Integer
				res << "RARRAY(#{get_closure_ary_var})->ptr[#{idx}] = #{scope.get_dvar_ary(entry)};"
			when :lvar
				res << "RARRAY(#{get_closure_ary_var})->ptr[#{idx}] = #{scope.get_lvar_ary};"
			when :self
				res << "RARRAY(#{get_closure_ary_var})->ptr[#{idx}] = #{get_self};"
			when :class
				res << "RARRAY(#{get_closure_ary_var})->ptr[#{idx}] = #{get_class};"
			when :cref
				add_helper <<-EOC
					static void cref_data_mark(NODE *n) {
						rb_gc_mark((VALUE)n);
					}
				EOC
				res << "RARRAY(#{get_closure_ary_var})->ptr[#{idx}] = " +
					"Data_Wrap_Struct(rb_cObject, cref_data_mark, 0, #{get_cref});"
			else
				raise Ruby2CExtError::Bug, "unexpected closure_tbl entry: #{entry.inspect}"
			end
		}
		res << "RARRAY(#{get_closure_ary_var})->len = #{closure_tbl.size};"
		res.join("\n")
	end
end

#comp_break(hash) ⇒ Object



74
75
76
77
78
79
80
81
82
# File 'lib/ruby2cext/c_function.rb', line 74

def comp_break(hash)
	if (lbl = in_while?(:break))
		l "while_res = #{comp(hash[:stts])};"
		l "goto #{lbl};"
		"Qnil"
	else
		raise Ruby2CExtError::NotSupported, "break is not supported here"
	end
end

#comp_next(hash) ⇒ Object



87
88
89
90
91
92
93
94
95
# File 'lib/ruby2cext/c_function.rb', line 87

def comp_next(hash)
	if (lbl = in_while?(:next))
		# hash[:stts] is silently ignored (as ruby does)
		l "goto #{lbl};"
		"Qnil"
	else
		raise Ruby2CExtError::NotSupported, "next is not supported here"
	end
end

#comp_redo(hash) ⇒ Object



100
101
102
103
104
105
106
107
# File 'lib/ruby2cext/c_function.rb', line 100

def comp_redo(hash)
	if (lbl = in_while?(:redo))
		l "goto #{lbl};"
		"Qnil"
	else
		raise Ruby2CExtError::NotSupported, "redo is not supported here"
	end
end

#comp_retry(hash) ⇒ Object



116
117
118
119
# File 'lib/ruby2cext/c_function.rb', line 116

def comp_retry(hash)
	l "rb_jump_tag(0x4 /* TAG_RETRY */);"
	"Qnil"
end

#comp_return(hash) ⇒ Object



112
113
114
# File 'lib/ruby2cext/c_function.rb', line 112

def comp_return(hash)
	raise Ruby2CExtError::NotSupported, "return is not supported here"
end

#get_cbaseObject



143
144
145
# File 'lib/ruby2cext/c_function.rb', line 143

def get_cbase
	"(#{get_cref}->nd_clss)"
end

#get_classObject



139
140
141
142
# File 'lib/ruby2cext/c_function.rb', line 139

def get_class
	self.need_class = true
	"s_class"
end

#get_closure_ary_varObject



157
158
159
# File 'lib/ruby2cext/c_function.rb', line 157

def get_closure_ary_var
	"my_closure_ary"
end

#get_crefObject



135
136
137
138
# File 'lib/ruby2cext/c_function.rb', line 135

def get_cref
	self.need_cref = true
	get_cref_impl # subclass
end

#get_cvar_cbaseObject



146
147
148
149
150
151
152
153
154
155
# File 'lib/ruby2cext/c_function.rb', line 146

def get_cvar_cbase
	# there is always at least one real class in the cref chain
	add_helper <<-EOC
		static VALUE cvar_cbase(NODE *cref) {
			while (FL_TEST(cref->nd_clss, FL_SINGLETON)) { cref = cref->nd_next; }
			return cref->nd_clss;
		}
	EOC
	"cvar_cbase(#{get_cref})"
end

#get_linesObject



38
39
40
# File 'lib/ruby2cext/c_function.rb', line 38

def get_lines
	@lines.join("\n")
end

#get_selfObject



131
132
133
134
# File 'lib/ruby2cext/c_function.rb', line 131

def get_self
	self.need_self = true
	"self"
end

#get_wrap_ptrObject



161
162
163
# File 'lib/ruby2cext/c_function.rb', line 161

def get_wrap_ptr
	"(&the_wrap)"
end

#global_const(str, register_gc = true) ⇒ Object



30
31
32
# File 'lib/ruby2cext/c_function.rb', line 30

def global_const(str, register_gc = true)
	compiler.global_const(str, register_gc)
end

#global_var(str) ⇒ Object



33
34
35
# File 'lib/ruby2cext/c_function.rb', line 33

def global_var(str)
	compiler.global_var(str)
end

#in_while?(lbl_type = nil) ⇒ Boolean

Returns:

  • (Boolean)


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/ruby2cext/c_function.rb', line 55

def in_while?(lbl_type = nil)
	return false if @while_stack.empty?
	case lbl_type
	when nil
		true
	when :redo
		@while_stack.last[0]
	when :next
		@while_stack.last[1]
	when :break
		@while_stack.last[2]
	else
		false
	end
end

#init_c_codeObject



223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/ruby2cext/c_function.rb', line 223

def init_c_code
	cb_c_code = closure_buid_c_code # must be called before the rest because it might change self or scope
	res = []
	res << "VALUE res;" if need_res
	res << "VALUE s_class = (#{get_cref})->nd_clss;" if need_class
	res << "VALUE #{get_closure_ary_var};" if cb_c_code
	res << "struct wrap the_wrap;" if need_wrap
	res << scope.init_c_code
	res << cb_c_code if cb_c_code
	res << wrap_buid_c_code if need_wrap
	res.compact.join("\n")
end

#l(line) ⇒ Object

add_line



41
42
43
44
45
46
# File 'lib/ruby2cext/c_function.rb', line 41

def l(line) # add_line
	# ignore lines with only whitespace or only alnum chars (variable name)
	unless line =~ /\A\s*\z/ || (line =~ /\A(\w*);?\z/ && !(%w[break continue].include? $1))
		@lines << line
	end
end

#need_closure_ptrObject



121
122
123
# File 'lib/ruby2cext/c_function.rb', line 121

def need_closure_ptr
	false # only needed in Block
end

#next_allowed?Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/ruby2cext/c_function.rb', line 84

def next_allowed?
	in_while?(:next)
end

#pop_whileObject



51
52
53
54
# File 'lib/ruby2cext/c_function.rb', line 51

def pop_while
	raise Ruby2CExtError::Bug, "popped from empty while stack" if @while_stack.empty?
	@while_stack.pop
end

#push_while(redo_lbl, next_lbl, break_lbl) ⇒ Object



48
49
50
# File 'lib/ruby2cext/c_function.rb', line 48

def push_while(redo_lbl, next_lbl, break_lbl)
	@while_stack << [redo_lbl, next_lbl, break_lbl]
end

#redo_allowed?Boolean

Returns:

  • (Boolean)


97
98
99
# File 'lib/ruby2cext/c_function.rb', line 97

def redo_allowed?
	in_while?(:redo)
end

#return_allowed?Boolean

Returns:

  • (Boolean)


109
110
111
# File 'lib/ruby2cext/c_function.rb', line 109

def return_allowed?
	false
end

#sym(sym) ⇒ Object



29
# File 'lib/ruby2cext/c_function.rb', line 29

def sym(sym); compiler.sym(sym); end

#un(str) ⇒ Object

some redirects to compiler



28
# File 'lib/ruby2cext/c_function.rb', line 28

def un(str); compiler.un(str); end

#wrap_buid_c_codeObject



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/ruby2cext/c_function.rb', line 201

def wrap_buid_c_code
	add_helper <<-EOC
		struct wrap {
			VALUE self;
			VALUE s_class;
			NODE *cref;
			VALUE my_closure_ary;
			VALUE *closure;
			VALUE *var;
			long state;
		};
	EOC
	res = []
	res << "the_wrap.self = #{get_self};" if need_self
	res << "the_wrap.s_class = #{get_class};" if need_class
	res << "the_wrap.cref = #{get_cref};" if need_cref
	res << "the_wrap.my_closure_ary = #{get_closure_ary_var};" unless closure_tbl.empty?
	res << "the_wrap.closure = closure;" if need_closure_ptr
	res << "the_wrap.var = #{scope.var_ptr_for_wrap};" if scope.var_ptr_for_wrap
	res.compact.join("\n")
end