require 'gir_ffi/builders/argument_builder' require 'gir_ffi/builders/return_value_builder' require 'gir_ffi/builders/error_argument_builder' require 'gir_ffi/builders/null_argument_builder' require 'gir_ffi/variable_name_generator' module GirFFI module Builders # Implements the creation of a Ruby function definition out of a GIR # IFunctionInfo. class FunctionBuilder def initialize info @info = info end def generate vargen = GirFFI::VariableNameGenerator.new @argument_builders = @info.args.map {|arg| ArgumentBuilder.new vargen, arg } @return_value_builder = ReturnValueBuilder.new(vargen, @info.return_type, @info.constructor?, @info.skip_return?) link_array_length_arguments setup_error_argument vargen return filled_out_template end private def libmodule Object.const_get(@info.safe_namespace)::Lib end def link_array_length_arguments alldata = @argument_builders.dup << @return_value_builder alldata.each {|data| idx = data.type_info.array_length if idx > -1 other_data = @argument_builders[idx] data.length_arg = other_data other_data.array_arg = data end } end def setup_error_argument vargen klass = @info.throws? ? ErrorArgumentBuilder : NullArgumentBuilder @errarg = klass.new vargen, nil, nil, :error end def filled_out_template meta = @info.method? ? '' : "self." code = "def #{meta}#{@info.safe_name} #{method_arguments.join(', ')}\n" code << method_body code << "\nend\n" end def method_body lines = preparation << function_call << post_processing << cleanup lines << "return #{return_values.join(', ')}" if has_return_values? lines.flatten.join("\n").indent end def function_call "#{capture}#{libmodule}.#{@info.symbol} #{function_call_arguments.join(', ')}" end def method_arguments @argument_builders.map(&:inarg).compact end def function_call_arguments ca = @argument_builders.map(&:callarg) ca << @errarg.callarg ca.unshift "self" if @info.method? ca.compact end def preparation pr = @argument_builders.map(&:pre) pr << @errarg.pre pr.flatten end def capture if has_capture? "#{@return_value_builder.callarg} = " else "" end end def post_processing # FIXME: Sorting knows too much about internals of ArgumentBuilder. args = @argument_builders.sort_by {|arg| arg.type_info.array_length} args << @return_value_builder args.unshift @errarg args.map {|arg| arg.post} end def cleanup @argument_builders.map {|item| item.cleanup} end def return_values @return_values ||= ([@return_value_builder.retval] + @argument_builders.map(&:retval)).compact end def has_return_values? !return_values.empty? end def has_capture? @return_value_builder.is_relevant? end end end end