crystalruby 0.2.3 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -0
- data/Dockerfile +23 -2
- data/README.md +395 -198
- data/Rakefile +4 -3
- data/crystalruby.gemspec +2 -2
- data/examples/adder/adder.rb +1 -1
- data/exe/crystalruby +1 -0
- data/lib/crystalruby/adapter.rb +143 -73
- data/lib/crystalruby/arc_mutex.rb +47 -0
- data/lib/crystalruby/compilation.rb +32 -3
- data/lib/crystalruby/config.rb +41 -37
- data/lib/crystalruby/function.rb +216 -73
- data/lib/crystalruby/library.rb +157 -51
- data/lib/crystalruby/reactor.rb +63 -44
- data/lib/crystalruby/source_reader.rb +92 -0
- data/lib/crystalruby/template.rb +16 -5
- data/lib/crystalruby/templates/function.cr +11 -10
- data/lib/crystalruby/templates/index.cr +53 -66
- data/lib/crystalruby/templates/inline_chunk.cr +1 -1
- data/lib/crystalruby/templates/ruby_interface.cr +34 -0
- data/lib/crystalruby/templates/top_level_function.cr +62 -0
- data/lib/crystalruby/templates/top_level_ruby_interface.cr +33 -0
- data/lib/crystalruby/typebuilder.rb +11 -55
- data/lib/crystalruby/typemaps.rb +92 -67
- data/lib/crystalruby/types/concerns/allocator.rb +80 -0
- data/lib/crystalruby/types/fixed_width/named_tuple.cr +80 -0
- data/lib/crystalruby/types/fixed_width/named_tuple.rb +86 -0
- data/lib/crystalruby/types/fixed_width/proc.cr +45 -0
- data/lib/crystalruby/types/fixed_width/proc.rb +79 -0
- data/lib/crystalruby/types/fixed_width/tagged_union.cr +53 -0
- data/lib/crystalruby/types/fixed_width/tagged_union.rb +113 -0
- data/lib/crystalruby/types/fixed_width/tuple.cr +82 -0
- data/lib/crystalruby/types/fixed_width/tuple.rb +92 -0
- data/lib/crystalruby/types/fixed_width.cr +138 -0
- data/lib/crystalruby/types/fixed_width.rb +205 -0
- data/lib/crystalruby/types/primitive.cr +21 -0
- data/lib/crystalruby/types/primitive.rb +117 -0
- data/lib/crystalruby/types/primitive_types/bool.cr +34 -0
- data/lib/crystalruby/types/primitive_types/bool.rb +11 -0
- data/lib/crystalruby/types/primitive_types/nil.cr +35 -0
- data/lib/crystalruby/types/primitive_types/nil.rb +16 -0
- data/lib/crystalruby/types/primitive_types/numbers.cr +37 -0
- data/lib/crystalruby/types/primitive_types/numbers.rb +28 -0
- data/lib/crystalruby/types/primitive_types/symbol.cr +55 -0
- data/lib/crystalruby/types/primitive_types/symbol.rb +35 -0
- data/lib/crystalruby/types/primitive_types/time.cr +35 -0
- data/lib/crystalruby/types/primitive_types/time.rb +25 -0
- data/lib/crystalruby/types/type.cr +64 -0
- data/lib/crystalruby/types/type.rb +249 -30
- data/lib/crystalruby/types/variable_width/array.cr +74 -0
- data/lib/crystalruby/types/variable_width/array.rb +88 -0
- data/lib/crystalruby/types/variable_width/hash.cr +146 -0
- data/lib/crystalruby/types/variable_width/hash.rb +117 -0
- data/lib/crystalruby/types/variable_width/string.cr +36 -0
- data/lib/crystalruby/types/variable_width/string.rb +18 -0
- data/lib/crystalruby/types/variable_width.cr +23 -0
- data/lib/crystalruby/types/variable_width.rb +46 -0
- data/lib/crystalruby/types.rb +32 -13
- data/lib/crystalruby/version.rb +2 -2
- data/lib/crystalruby.rb +13 -6
- metadata +42 -22
- data/lib/crystalruby/types/array.rb +0 -15
- data/lib/crystalruby/types/bool.rb +0 -3
- data/lib/crystalruby/types/hash.rb +0 -17
- data/lib/crystalruby/types/named_tuple.rb +0 -28
- data/lib/crystalruby/types/nil.rb +0 -3
- data/lib/crystalruby/types/numbers.rb +0 -5
- data/lib/crystalruby/types/string.rb +0 -3
- data/lib/crystalruby/types/symbol.rb +0 -3
- data/lib/crystalruby/types/time.rb +0 -8
- data/lib/crystalruby/types/tuple.rb +0 -17
- data/lib/crystalruby/types/type_serializer/json.rb +0 -41
- data/lib/crystalruby/types/type_serializer.rb +0 -37
- data/lib/crystalruby/types/typedef.rb +0 -57
- data/lib/crystalruby/types/union_type.rb +0 -43
- data/lib/module.rb +0 -3
data/lib/crystalruby/function.rb
CHANGED
@@ -1,16 +1,22 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
1
3
|
module CrystalRuby
|
2
4
|
# This class represents a single Crystalized function.
|
3
5
|
# Each such function belongs a shared lib (See: CrystalRuby::Library)
|
4
6
|
# and is attached to a single owner (a class or a module).
|
5
7
|
class Function
|
8
|
+
extend Forwardable
|
6
9
|
include Typemaps
|
7
10
|
include Config
|
8
11
|
|
9
|
-
attr_accessor :
|
12
|
+
attr_accessor :original_method, :owner, :args, :returns, :function_body, :arity,
|
13
|
+
:lib, :async, :block, :attached, :ruby, :instance_method, :class_method
|
14
|
+
|
15
|
+
def_delegators :@original_method, :name
|
10
16
|
|
11
|
-
def initialize(method:, args:, returns:,
|
17
|
+
def initialize(method:, args:, returns:, lib:, function_body: nil, async: false, ruby: false, &block)
|
18
|
+
self.original_method = method
|
12
19
|
self.owner = method.owner
|
13
|
-
self.method_name = method.name
|
14
20
|
self.args = args
|
15
21
|
self.returns = returns
|
16
22
|
self.function_body = function_body
|
@@ -18,75 +24,94 @@ module CrystalRuby
|
|
18
24
|
self.async = async
|
19
25
|
self.block = block
|
20
26
|
self.attached = false
|
27
|
+
self.class_method = owner.singleton_class? && owner.attached_object.class == Class
|
28
|
+
self.instance_method = original_method.is_a?(UnboundMethod) && original_method.owner.ancestors.include?(CrystalRuby::Types::Type)
|
29
|
+
self.ruby = ruby
|
30
|
+
self.arity = args.keys.-([:__yield_to]).size
|
31
|
+
end
|
32
|
+
|
33
|
+
def crystal_supertype
|
34
|
+
return nil unless original_method.owner.ancestors.include?(CrystalRuby::Types::Type)
|
35
|
+
|
36
|
+
original_method.owner.crystal_supertype
|
21
37
|
end
|
22
38
|
|
23
39
|
# This is where we write/overwrite the class and instance methods
|
24
|
-
# with their
|
40
|
+
# with their crystallized equivalents.
|
25
41
|
# We also perform JIT compilation and JIT attachment of the FFI functions.
|
26
42
|
# Crystalized methods can be redefined without restarting, if running in a live-reloading environment.
|
27
43
|
# If they are redefined with a different function body, the new function body
|
28
44
|
# will result in a new digest and the FFI function will be recompiled and reattached.
|
29
|
-
def
|
45
|
+
def define_crystallized_methods!(lib)
|
30
46
|
func = self
|
31
|
-
[owner, owner.singleton_class]
|
32
|
-
|
33
|
-
receiver.
|
34
|
-
|
35
|
-
lib.build!
|
36
|
-
return send(func.method_name, *args)
|
37
|
-
end
|
47
|
+
receivers = instance_method ? [owner] : [owner, owner.singleton_class]
|
48
|
+
receivers.each do |receiver|
|
49
|
+
receiver.undef_method(name) if receiver.method_defined?(name)
|
50
|
+
receiver.define_method(name) do |*args, &blk|
|
38
51
|
unless func.attached?
|
39
|
-
should_reenter = func.
|
40
|
-
|
52
|
+
should_reenter = func.unwrapped?
|
53
|
+
lib.build! unless lib.compiled?
|
54
|
+
lib.attach! unless func.attached?
|
55
|
+
return send(func.name, *args, &blk) if should_reenter
|
41
56
|
end
|
42
57
|
# All crystalruby functions are executed on the reactor to ensure Crystal/Ruby interop code is executed
|
43
58
|
# from a single same thread. (Needed to make GC and Fiber scheduler happy)
|
44
59
|
# Type mapping (if required) is applied on arguments and on return values.
|
45
|
-
func.
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
60
|
+
if args.length != func.arity
|
61
|
+
raise ArgumentError,
|
62
|
+
"wrong number of arguments (given #{args.length}, expected #{func.arity})"
|
63
|
+
end
|
64
|
+
|
65
|
+
raise ArgumentError, "block given but function does not accept block" if blk && !func.takes_block?
|
66
|
+
raise ArgumentError, "no block given but function expects block" if !blk && func.takes_block?
|
67
|
+
|
68
|
+
args << blk if blk
|
69
|
+
func.map_args!(args)
|
70
|
+
args.unshift(memory) if func.instance_method
|
71
|
+
|
72
|
+
ret_val = Reactor.schedule_work!(
|
73
|
+
func.owner,
|
74
|
+
func.ffi_name,
|
75
|
+
*args,
|
76
|
+
func.ffi_ret_type,
|
77
|
+
async: func.async,
|
78
|
+
lib: lib
|
54
79
|
)
|
80
|
+
|
81
|
+
func.map_retval(ret_val)
|
55
82
|
end
|
56
83
|
end
|
57
84
|
end
|
58
85
|
|
59
|
-
|
60
|
-
|
61
|
-
# We also initialize the shared object (needed to start the GC) and
|
62
|
-
# start the reactor, unless we are in single-thread mode.
|
63
|
-
def attach_ffi_lib_functions!
|
64
|
-
should_reenter = unwrapped?
|
65
|
-
lib_file = lib.lib_file
|
66
|
-
lib.methods.each_value(&:attach_ffi_func!)
|
67
|
-
lib.singleton_class.class_eval do
|
68
|
-
extend FFI::Library
|
69
|
-
ffi_lib lib_file
|
70
|
-
%i[yield init].each do |method_name|
|
71
|
-
singleton_class.undef_method(method_name) if singleton_class.method_defined?(method_name)
|
72
|
-
undef_method(method_name) if method_defined?(method_name)
|
73
|
-
end
|
74
|
-
attach_function :init, %i[string pointer], :void
|
75
|
-
attach_function :yield, %i[], :int
|
76
|
-
end
|
86
|
+
def register_callback!
|
87
|
+
return unless ruby
|
77
88
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
89
|
+
@callback_func = FFI::Function.new(ffi_ret_type, ffi_types) do |*args|
|
90
|
+
receiver = instance_method ? owner.new(args.shift) : owner
|
91
|
+
ret_val = if takes_block?
|
92
|
+
block_arg = arg_type_map[:__yield_to][:crystalruby_type].new(args.pop)
|
93
|
+
receiver.send(name, *unmap_args(args)) do |*args|
|
94
|
+
args = args.map.with_index do |arg, i|
|
95
|
+
arg = block_arg.inner_types[i].new(arg) unless arg.is_a?(block_arg.inner_types[i])
|
96
|
+
arg.memory
|
97
|
+
end
|
98
|
+
return_val = block_arg.invoke(*args)
|
99
|
+
unless return_val.is_a?(block_arg.inner_types[-1])
|
100
|
+
return_val = block_arg.inner_types[-1].new(return_val)
|
101
|
+
end
|
102
|
+
block_arg.inner_types[-1].anonymous? ? return_val.value : return_val
|
103
|
+
end
|
104
|
+
else
|
105
|
+
receiver.send(name, *unmap_args(args))
|
106
|
+
end
|
107
|
+
unmap_retval(ret_val)
|
82
108
|
end
|
83
|
-
Reactor.schedule_work!(lib, :
|
84
|
-
should_reenter
|
109
|
+
Reactor.schedule_work!(lib, :"register_#{name.to_s.gsub("?", "q").gsub("=", "eq").gsub("!", "bang")}_callback", @callback_func, :void, blocking: true, async: false)
|
85
110
|
end
|
86
111
|
|
87
|
-
# Attaches the
|
88
|
-
# If a wrapper block has been passed to the
|
89
|
-
# then the we also wrap the
|
112
|
+
# Attaches the crystallized FFI functions to their related Ruby modules and classes.
|
113
|
+
# If a wrapper block has been passed to the crystallize function,
|
114
|
+
# then the we also wrap the crystallized function using a prepended Module.
|
90
115
|
def attach_ffi_func!
|
91
116
|
argtypes = ffi_types
|
92
117
|
rettype = ffi_ret_type
|
@@ -111,7 +136,7 @@ module CrystalRuby
|
|
111
136
|
|
112
137
|
owner.attach_function ffi_name, argtypes, rettype, blocking: true
|
113
138
|
around_wrapper_block = block
|
114
|
-
method_name =
|
139
|
+
method_name = name
|
115
140
|
@attached = true
|
116
141
|
return unless around_wrapper_block
|
117
142
|
|
@@ -124,10 +149,6 @@ module CrystalRuby
|
|
124
149
|
end
|
125
150
|
@around_wrapper.undef_method(method_name) if @around_wrapper.method_defined?(method_name)
|
126
151
|
@around_wrapper.define_method(method_name, &around_wrapper_block)
|
127
|
-
rescue StandardError => e
|
128
|
-
CrystalRuby.log_error("Error attaching #{method_name} as #{ffi_name} to #{owner.name}")
|
129
|
-
CrystalRuby.log_error(e.message)
|
130
|
-
CrystalRuby.log_error(e.backtrace.join("\n"))
|
131
152
|
end
|
132
153
|
|
133
154
|
def unwrapped?
|
@@ -142,12 +163,22 @@ module CrystalRuby
|
|
142
163
|
@attached = false
|
143
164
|
end
|
144
165
|
|
166
|
+
def owner
|
167
|
+
class_method ? @owner.attached_object : @owner
|
168
|
+
end
|
169
|
+
|
170
|
+
def owner_name
|
171
|
+
owner.name
|
172
|
+
end
|
173
|
+
|
145
174
|
def ffi_name
|
146
175
|
lib_fn_name + (async && !config.single_thread_mode ? "_async" : "")
|
147
176
|
end
|
148
177
|
|
149
178
|
def lib_fn_name
|
150
|
-
@lib_fn_name ||= "#{
|
179
|
+
@lib_fn_name ||= "#{owner_name.downcase.gsub("::",
|
180
|
+
"_")}_#{name.to_s.gsub("?", "query").gsub("!", "bang").gsub("=",
|
181
|
+
"eq")}_#{Digest::MD5.hexdigest(function_body.to_s)}"
|
151
182
|
end
|
152
183
|
|
153
184
|
def arg_type_map
|
@@ -155,15 +186,29 @@ module CrystalRuby
|
|
155
186
|
end
|
156
187
|
|
157
188
|
def lib_fn_args
|
158
|
-
@lib_fn_args ||=
|
159
|
-
|
160
|
-
|
189
|
+
@lib_fn_args ||= begin
|
190
|
+
lib_fn_args = arg_type_map.map do |k, arg_type|
|
191
|
+
"_#{k} : #{arg_type[:lib_type]}"
|
192
|
+
end
|
193
|
+
lib_fn_args.unshift("_self : Pointer(::UInt8)") if instance_method
|
194
|
+
lib_fn_args.join(",") + (lib_fn_args.empty? ? "" : ", ")
|
195
|
+
end
|
161
196
|
end
|
162
197
|
|
163
|
-
def lib_fn_arg_names
|
164
|
-
@lib_fn_arg_names ||=
|
165
|
-
"_#{k}"
|
166
|
-
|
198
|
+
def lib_fn_arg_names(skip_blocks = false)
|
199
|
+
@lib_fn_arg_names ||= begin
|
200
|
+
names = arg_type_map.keys.reject { |k, _v| skip_blocks && is_block_arg?(k) }.map { |k| "_#{k}" }
|
201
|
+
names.unshift("self.memory") if instance_method
|
202
|
+
names.join(",") + (names.empty? ? "" : ", ")
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def lib_fn_types
|
207
|
+
@lib_fn_types ||= begin
|
208
|
+
lib_fn_types = arg_type_map.map { |_k, v| v[:lib_type] }
|
209
|
+
lib_fn_types.unshift("Pointer(::UInt8)") if instance_method
|
210
|
+
lib_fn_types.join(",") + (lib_fn_types.empty? ? "" : ", ")
|
211
|
+
end
|
167
212
|
end
|
168
213
|
|
169
214
|
def return_type_map
|
@@ -171,31 +216,69 @@ module CrystalRuby
|
|
171
216
|
end
|
172
217
|
|
173
218
|
def ffi_types
|
174
|
-
@ffi_types ||=
|
219
|
+
@ffi_types ||= begin
|
220
|
+
ffi_types = arg_type_map.map { |_k, arg_type| arg_type[:ffi_type] }
|
221
|
+
ffi_types.unshift(:pointer) if instance_method
|
222
|
+
ffi_types
|
223
|
+
end
|
175
224
|
end
|
176
225
|
|
177
226
|
def arg_maps
|
178
227
|
@arg_maps ||= arg_type_map.map { |_k, arg_type| arg_type[:arg_mapper] }
|
179
228
|
end
|
180
229
|
|
230
|
+
def arg_unmaps
|
231
|
+
@arg_unmaps ||= arg_type_map.reject { |k, _v| is_block_arg?(k) }.map { |_k, arg_type| arg_type[:retval_mapper] }
|
232
|
+
end
|
233
|
+
|
181
234
|
def ffi_ret_type
|
182
235
|
@ffi_ret_type ||= return_type_map[:ffi_ret_type]
|
183
236
|
end
|
184
237
|
|
238
|
+
def custom_types
|
239
|
+
@custom_types ||= begin
|
240
|
+
types = [*arg_type_map.values, return_type_map].map { |t| t[:crystalruby_type] }
|
241
|
+
types.unshift(owner) if instance_method
|
242
|
+
types
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
185
246
|
def register_custom_types!(lib)
|
186
|
-
|
187
|
-
|
188
|
-
|
247
|
+
custom_types.each do |crystalruby_type|
|
248
|
+
next unless crystalruby_type.is_a?(Class) && crystalruby_type < Types::Type
|
249
|
+
|
250
|
+
[*crystalruby_type.nested_types].uniq.each do |type|
|
251
|
+
lib.register_type!(type)
|
189
252
|
end
|
190
253
|
end
|
191
254
|
end
|
192
255
|
|
193
|
-
def map_args(args)
|
256
|
+
def map_args!(args)
|
194
257
|
return args unless arg_maps.any?
|
195
258
|
|
259
|
+
refs = nil
|
260
|
+
|
196
261
|
arg_maps.each_with_index do |argmap, index|
|
197
262
|
next unless argmap
|
198
263
|
|
264
|
+
mapped = argmap[args[index]]
|
265
|
+
case mapped
|
266
|
+
when CrystalRuby::Types::Type then
|
267
|
+
args[index] = mapped.memory
|
268
|
+
(refs ||= []) << mapped
|
269
|
+
else
|
270
|
+
args[index] = mapped
|
271
|
+
end
|
272
|
+
end
|
273
|
+
refs
|
274
|
+
end
|
275
|
+
|
276
|
+
def unmap_args(args)
|
277
|
+
return args unless args.any?
|
278
|
+
|
279
|
+
arg_unmaps.each_with_index do |argmap, index|
|
280
|
+
next unless argmap
|
281
|
+
|
199
282
|
args[index] = argmap[args[index]]
|
200
283
|
end
|
201
284
|
args
|
@@ -207,16 +290,76 @@ module CrystalRuby
|
|
207
290
|
return_type_map[:retval_mapper][retval]
|
208
291
|
end
|
209
292
|
|
293
|
+
def unmap_retval(retval)
|
294
|
+
return retval unless return_type_map[:arg_mapper]
|
295
|
+
|
296
|
+
retval = return_type_map[:arg_mapper][retval]
|
297
|
+
retval = retval.memory if retval.kind_of?(CrystalRuby::Types::Type)
|
298
|
+
retval
|
299
|
+
end
|
300
|
+
|
301
|
+
def takes_block?
|
302
|
+
is_block_arg?(:__yield_to)
|
303
|
+
end
|
304
|
+
|
305
|
+
def is_block_arg?(arg_name)
|
306
|
+
arg_name == :__yield_to && arg_type_map[arg_name] && arg_type_map[arg_name][:crystalruby_type].ancestors.select do |a|
|
307
|
+
a < Types::Type
|
308
|
+
end.map(&:typename).any?(:Proc)
|
309
|
+
end
|
310
|
+
|
311
|
+
def ruby_interface
|
312
|
+
template = owner == Object ? Template::TopLevelRubyInterface : Template::RubyInterface
|
313
|
+
@ruby_interface ||= template.render(
|
314
|
+
{
|
315
|
+
module_or_class: instance_method || class_method ? "class" : "module",
|
316
|
+
receiver: instance_method ? "#{owner_name}.new(_self)" : owner_name,
|
317
|
+
fn_scope: instance_method ? "" : "self.",
|
318
|
+
superclass: instance_method || class_method ? "< #{crystal_supertype}" : nil,
|
319
|
+
module_name: owner_name,
|
320
|
+
lib_fn_name: lib_fn_name,
|
321
|
+
fn_name: name,
|
322
|
+
callback_name: "#{name.to_s.gsub("?", "q").gsub("=", "eq").gsub("!", "bang")}_callback",
|
323
|
+
fn_body: function_body,
|
324
|
+
block_converter: takes_block? ? arg_type_map[:__yield_to][:crystalruby_type].block_converter : "",
|
325
|
+
callback_call: returns == :void ? "callback.call(thread_id)" : "callback.call(thread_id, converted)",
|
326
|
+
callback_type: return_type_map[:ffi_type] == :void ? "UInt32 -> Void" : " UInt32, #{return_type_map[:lib_type]} -> Void",
|
327
|
+
fn_args: arg_type_map
|
328
|
+
.map { |k, arg_type| "#{is_block_arg?(k) ? "&" : ""}#{k} : #{arg_type[:crystal_type]}" }.join(","),
|
329
|
+
fn_ret_type: return_type_map[:crystal_type],
|
330
|
+
lib_fn_args: lib_fn_args,
|
331
|
+
lib_fn_types: lib_fn_types,
|
332
|
+
lib_fn_arg_names: lib_fn_arg_names,
|
333
|
+
lib_fn_ret_type: return_type_map[:lib_type],
|
334
|
+
convert_lib_args: arg_type_map.map do |k, arg_type|
|
335
|
+
"_#{k} = #{arg_type[:convert_crystal_to_lib_type]["#{k}"]}"
|
336
|
+
end.join("\n "),
|
337
|
+
arg_names: args.keys.reject(&method(:is_block_arg?)).join(", "),
|
338
|
+
convert_return_type: return_type_map[:convert_lib_to_crystal_type]["return_value"],
|
339
|
+
error_value: return_type_map[:error_value]
|
340
|
+
}
|
341
|
+
)
|
342
|
+
end
|
343
|
+
|
210
344
|
def chunk
|
211
|
-
|
345
|
+
template = owner == Object ? Template::TopLevelFunction : Template::Function
|
346
|
+
@chunk ||= template.render(
|
212
347
|
{
|
213
|
-
|
348
|
+
module_or_class: instance_method || class_method ? "class" : "module",
|
349
|
+
receiver: instance_method ? "#{owner_name}.new(_self)" : owner_name,
|
350
|
+
fn_scope: instance_method ? "" : "self.",
|
351
|
+
superclass: instance_method || class_method ? "< #{crystal_supertype}" : nil,
|
352
|
+
module_name: owner_name,
|
214
353
|
lib_fn_name: lib_fn_name,
|
215
|
-
fn_name:
|
354
|
+
fn_name: name,
|
355
|
+
callback_name: "#{name.to_s.gsub("?", "q").gsub("=", "eq").gsub("!", "bang")}_callback",
|
216
356
|
fn_body: function_body,
|
357
|
+
block_converter: takes_block? ? arg_type_map[:__yield_to][:crystalruby_type].block_converter : "",
|
217
358
|
callback_call: returns == :void ? "callback.call(thread_id)" : "callback.call(thread_id, converted)",
|
218
359
|
callback_type: return_type_map[:ffi_type] == :void ? "UInt32 -> Void" : " UInt32, #{return_type_map[:lib_type]} -> Void",
|
219
|
-
fn_args: arg_type_map
|
360
|
+
fn_args: arg_type_map
|
361
|
+
.reject { |k, _v| is_block_arg?(k) }
|
362
|
+
.map { |k, arg_type| "#{k} : #{arg_type[:crystal_type]}" }.join(","),
|
220
363
|
fn_ret_type: return_type_map[:crystal_type],
|
221
364
|
lib_fn_args: lib_fn_args,
|
222
365
|
lib_fn_arg_names: lib_fn_arg_names,
|
@@ -224,7 +367,7 @@ module CrystalRuby
|
|
224
367
|
convert_lib_args: arg_type_map.map do |k, arg_type|
|
225
368
|
"#{k} = #{arg_type[:convert_lib_to_crystal_type]["_#{k}"]}"
|
226
369
|
end.join("\n "),
|
227
|
-
arg_names: args.keys.join(","),
|
370
|
+
arg_names: args.keys.reject(&method(:is_block_arg?)).join(", "),
|
228
371
|
convert_return_type: return_type_map[:convert_crystal_to_lib_type]["return_value"],
|
229
372
|
error_value: return_type_map[:error_value]
|
230
373
|
}
|