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.



12
13
14
15
16
17
18
19
# File 'lib/ruby2cext/c_function.rb', line 12

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.



10
11
12
# File 'lib/ruby2cext/c_function.rb', line 10

def closure_tbl
  @closure_tbl
end

#compilerObject (readonly)

Returns the value of attribute compiler.



10
11
12
# File 'lib/ruby2cext/c_function.rb', line 10

def compiler
  @compiler
end

#need_classObject

Returns the value of attribute need_class.



11
12
13
# File 'lib/ruby2cext/c_function.rb', line 11

def need_class
  @need_class
end

#need_crefObject

Returns the value of attribute need_cref.



11
12
13
# File 'lib/ruby2cext/c_function.rb', line 11

def need_cref
  @need_cref
end

#need_resObject

Returns the value of attribute need_res.



11
12
13
# File 'lib/ruby2cext/c_function.rb', line 11

def need_res
  @need_res
end

#need_selfObject

Returns the value of attribute need_self.



11
12
13
# File 'lib/ruby2cext/c_function.rb', line 11

def need_self
  @need_self
end

#need_wrapObject

Returns the value of attribute need_wrap.



11
12
13
# File 'lib/ruby2cext/c_function.rb', line 11

def need_wrap
  @need_wrap
end

#scopeObject (readonly)

Returns the value of attribute scope.



10
11
12
# File 'lib/ruby2cext/c_function.rb', line 10

def scope
  @scope
end

Instance Method Details

#add_closure_need(sym) ⇒ Object



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

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

#add_helper(str) ⇒ Object



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

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

#assign_res(str) ⇒ Object



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

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

#break_allowed?(with_value) ⇒ Boolean

Returns:

  • (Boolean)


66
67
68
# File 'lib/ruby2cext/c_function.rb', line 66

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

#closure_buid_c_codeObject



165
166
167
168
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
# File 'lib/ruby2cext/c_function.rb', line 165

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



69
70
71
72
73
74
75
76
77
# File 'lib/ruby2cext/c_function.rb', line 69

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



82
83
84
85
86
87
88
89
90
# File 'lib/ruby2cext/c_function.rb', line 82

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



95
96
97
98
99
100
101
102
# File 'lib/ruby2cext/c_function.rb', line 95

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



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

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

#comp_return(hash) ⇒ Object



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

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

#get_cbaseObject



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

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

#get_classObject



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

def get_class
	self.need_class = true
	"s_class"
end

#get_closure_ary_varObject



153
154
155
# File 'lib/ruby2cext/c_function.rb', line 153

def get_closure_ary_var
	"my_closure_ary"
end

#get_crefObject



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

def get_cref
	self.need_cref = true
	get_cref_impl # subclass
end

#get_cvar_cbaseObject



142
143
144
145
146
147
148
149
150
151
# File 'lib/ruby2cext/c_function.rb', line 142

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



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

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

#get_selfObject



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

def get_self
	self.need_self = true
	"self"
end

#get_wrap_ptrObject



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

def get_wrap_ptr
	"(&the_wrap)"
end

#global_const(str, register_gc = true) ⇒ Object



24
25
26
# File 'lib/ruby2cext/c_function.rb', line 24

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

#global_var(str) ⇒ Object



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

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

#in_while?(lbl_type = nil) ⇒ Boolean

Returns:

  • (Boolean)


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/ruby2cext/c_function.rb', line 50

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



219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/ruby2cext/c_function.rb', line 219

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



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

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



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

def need_closure_ptr
	false # only needed in Block
end

#next_allowed?Boolean

Returns:

  • (Boolean)


79
80
81
# File 'lib/ruby2cext/c_function.rb', line 79

def next_allowed?
	in_while?(:next)
end

#pop_whileObject



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

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



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

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

#redo_allowed?Boolean

Returns:

  • (Boolean)


92
93
94
# File 'lib/ruby2cext/c_function.rb', line 92

def redo_allowed?
	in_while?(:redo)
end

#return_allowed?Boolean

Returns:

  • (Boolean)


104
105
106
# File 'lib/ruby2cext/c_function.rb', line 104

def return_allowed?
	false
end

#sym(sym) ⇒ Object



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

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

#un(str) ⇒ Object

some redirects to compiler



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

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

#wrap_buid_c_codeObject



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/ruby2cext/c_function.rb', line 197

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