diff options
Diffstat (limited to 'templates.rb')
| -rw-r--r-- | templates.rb | 415 |
1 files changed, 333 insertions, 82 deletions
diff --git a/templates.rb b/templates.rb index b4ca43c..1846a0e 100644 --- a/templates.rb +++ b/templates.rb @@ -1,46 +1,317 @@ -module Tplt # Template - class << self - def base(gem_name, init_body, final_body) - %{ -void -mrb_mruby_#{gem_name}_gem_init(mrb_state* mrb) { -#{init_body} -} +module Template # Template + # methods that convert something from ruby-land to c-land + module C + class << self + def to_c_function_name(function_name:) + "mrb_#{function_name}" + end -void -mrb_mruby_#{gem_name}_gem_final(mrb_state* mrb) { -#{final_body} + def to_getter_name(struct_name:, variable_name:) + "mrb_#{struct_name}_get_#{variable_name}" + end + + def to_setter_name(struct_name:, variable_name:) + "mrb_#{struct_name}_set_#{variable_name}" + end + + def to_initializer_name(struct_name:) + "mrb_#{struct_name}_initialize" + end + + def format_type(param_datatype) + if Template.treated_as_int =~ param_datatype + 'int' + elsif Template.treated_as_int_pointer =~ param_datatype + 'int' + elsif Template.treated_as_bool =~ param_datatype + 'bool' + elsif Template.treated_as_bool_pointer =~ param_datatype + 'bool' + elsif Template.treated_as_float =~ param_datatype + 'float' + elsif Template.treated_as_float_pointer =~ param_datatype + 'float' + elsif Template.treated_as_string =~ param_datatype + 'char *' + # Ignore for now + #elsif Template.treated_as_string_pointer =~ param_datatype + # 'char *' + elsif Template.struct_types =~ param_datatype + "#{param_datatype}" + elsif Template.struct_types_pointer =~ param_datatype + "#{param_datatype.gsub(/ *\*+$/,'')}" + else + nil # cannot be formated + end + end + + def convention_parameter(param) + "parameter_#{param}" + end + + def convention_return_variable(func_name) + "return_of_#{func_name}" + end + + def initialize_variables(params, structs, func_name=nil) + + result = '' + return result if params.first == 'void' + params.each do |param| + rpart = param.rpartition(' ') + format = Template::C.format_type(rpart.first) + if format + result += format + " #{'*' if Template.struct_types =~ rpart.first.gsub(/ *\*+$/,'')}#{Template::C.convention_parameter(rpart.last)};\n" + elsif !func_name.nil? + puts "// \"#{rpart.first}\" is not a parameter datatype that can be currently autobound. From function: \"#{func_name}\" and param: #{rpart.last}\n\n" + #raise + end + end + result + "\n" + end + + def initialize_return_var(func_datatype, func_name) + return '' if func_datatype == 'void' + result = '' + depointer_datatype = func_datatype.delete_suffix(' *') + if Template.struct_types =~ depointer_datatype + result += Template.get_module('Test') + result += Template.get_class(depointer_datatype, 'Test') + result += "#{depointer_datatype} *#{Template::C.convention_return_variable(func_name)} = (#{depointer_datatype} *)mrb_malloc(mrb, sizeof(#{depointer_datatype}));\n" + else + result += "#{func_datatype} #{Template::C.convention_return_variable(func_name)};\n" + end + result + end + + def get_kwargs(params) + init_array_body = '' + params.each do |param| + rpart = param.rpartition(' ') + init_array_body += "mrb_intern_lit(mrb, \"#{rpart.last}\"),\n" + end + init_array_body.delete_suffix!(",\n") + %{uint32_t kw_num = #{params.length}; +const mrb_sym kw_names[] = { +#{init_array_body} +}; +mrb_value kw_values[kw_num]; +const mrb_kwargs kwargs = { kw_num, 0, kw_names, kw_values, NULL }; +mrb_get_args(mrb, "|:", &kwargs); + } + end + + def parse_kwargs(params) + result = '' + skipped = 0 + params.each_with_index do |param, index| + rpart = param.rpartition(' ') + if Template.struct_types =~ rpart.first + + unwrap = Template.unwrap_struct(Template::C.convention_parameter(rpart.last), "kw_values[#{index - skipped}]", "mrb_#{rpart.first}_struct", rpart.first) + + result += Template::C.unwrap_kwarg(index - skipped,unwrap) + elsif Template.non_struct_types =~ rpart.first + unwrap = "#{Template::C.convention_parameter(rpart.last)} = #{Template.to_c(rpart.first, "kw_values[#{index - skipped}]")};" + result += Template::C.unwrap_kwarg(index - skipped,unwrap) + else + skipped += 1 + next + end + end + result + end + + def unwrap_kwarg(kwarg_iter, body_if_defined, body_if_undefined = nil, no_argument_error_message = 'Missing Keyword Argument') + %{ +if (mrb_undef_p(kw_values[#{kwarg_iter}])) { +#{body_if_undefined || "mrb_load_string(mrb, \"raise ArgumentError.new \\\"#{no_argument_error_message}\\\"\");"} +} else { +#{body_if_defined} } - } + } + end + end + end + + # methods that convert something from c-land to ruby-land + module MRuby + class << self + # convert a C function name to be + # formatted like a Ruby method name + def rubify_func_name(function) + func = function.underscore + if func.start_with? 'is_' + func = func.delete_prefix('is_') + '?' + elsif func.start_with? 'set_' + func = func.delete_prefix('set_') + '=' + else + func.delete_prefix('get_') + end + func + end + + def to_c_function_name(function_name:) + rubify_func_name(function_name) + end + + def to_getter_name(struct_name:, variable_name: nil) + rubify_func_name(variable_name) + end + def to_setter_name(struct_name:, variable_name: nil) + rubify_func_name(variable_name) + '=' + end + + def to_initializer_name(struct_name: nil) + "initialize" + end + end + end + + + class << self + + # could be unsigned attr_writer :treated_as_int def treated_as_int - @treated_as_int ||= ['int', 'unsigned int', 'long', 'short'] + @treated_as_int ||= /^((un)?signed )?int$|^((un)?signed )?long$|^((un)?signed )?short$|^((un)?signed )char$/ + end + attr_writer :treated_as_int_pointer + def treated_as_int_pointer + @treated_as_int_pointer ||= /^((un)?signed )?int \*$|^((un)?signed )?long \*$|^((un)?signed )?short \*$|^((un)?signed )char \*$/ end attr_writer :treated_as_bool def treated_as_bool - @treated_as_bool ||= ['bool'] + @treated_as_bool ||= /^bool$/ + end + attr_writer :treated_as_bool_pointer + def treated_as_bool_pointer + @treated_as_bool_pointer ||= /^bool \*$/ end attr_writer :treated_as_float def treated_as_float - @treated_as_float ||= ['float', 'double'] + @treated_as_float ||= /^float$|^double$/ + end + attr_writer :treated_as_float_pointer + def treated_as_float_pointer + @treated_as_float_pointer ||= /^float \*$|^double \*$/ end attr_writer :treated_as_string def treated_as_string - @treated_as_string ||= ['char *', 'const char *'] + @treated_as_string ||= /^(const )?char \*$/ end + # Ignore for now + #attr_writer :treated_as_string_pointer + #def treated_as_string_pointer + # @treated_as_string_pointer ||= /^(const )?char \*\*$/ + #end attr_writer :treated_as_void def treated_as_void - @treated_as_void ||= ['void'] + @treated_as_void ||= /^void$/ end def non_struct_types - treated_as_int | treated_as_bool | treated_as_float | treated_as_string | treated_as_void + @non_struct_types ||= Regexp.union(treated_as_int, treated_as_bool, treated_as_float, treated_as_string, treated_as_void) + end + def non_struct_types_pointer + @non_struct_types_pointer ||= Regexp.union(treated_as_int_pointer, treated_as_bool_pointer, treated_as_float_pointer)#, treated_as_string_pointer) + end + + attr_writer :struct_types + def struct_types + if @struct_types + @struct_types + else + raise "Struct types were not parsed\nRun 'parse_struct_types' first" + end + end + attr_writer :struct_types_pointer + def struct_types_pointer + if @struct_types_pointer + @struct_types_pointer + else + raise "Struct types were not parsed\nRun 'parse_struct_types' first" + end + end + + def parse_struct_types(structs) + struct_types = structs.keys + struct_types_pointer = struct_types.map do |string| + "^#{string} \\*$" + end + struct_types.map! do |string| + "^#{string}$" + end + @struct_types_pointer = /#{struct_types_pointer.join('|')}/ + @struct_types = /#{struct_types.join('|')}/ + end + + def valid_types + @valid_types ||= Regexp.union(non_struct_types, struct_types) + end + def valid_types_pointer + @valid_types_pointer ||= Regexp.union(non_struct_types_pointer, struct_types_pointer) + end + def all_valid_types + @all_valid_types ||= Regexp.union(valid_types, valid_types_pointer) + end + + def base(gem_name, init_body, final_body) + %{ + void + mrb_mruby_#{gem_name}_gem_init(mrb_state* mrb) { + #{init_body} +} + +void +mrb_mruby_#{gem_name}_gem_final(mrb_state* mrb) { +#{final_body} +} + } + end + + def format_method_call(func_datatype, func_name, params, is_struct=false) + result = '' + #if params.first == 'void' + # result += "return #{'*' if is_struct}#{Template::C.convention_return_variable(func_name)} = " + #end + result += "#{func_name}(" + puts '//| --- |' + puts "//#{func_name}" + unless params.first == 'void' + params.each do |param| + rpart = param.rpartition(' ') + puts '//--' + puts "//#{rpart.first}" + puts "//#{Template.struct_types =~ rpart.first}" + result += "#{'*' if Template.struct_types =~ rpart.first}#{"(#{rpart.first})&" if Template.non_struct_types_pointer =~ rpart.first}#{Template::C.convention_parameter(rpart.last)}, " + end + end + result.delete_suffix(', ') + ")" + end + + def format_set_method_call(func_datatype, func_name, params, is_struct=false) + result = format_method_call(func_datatype, func_name, params, is_struct) + ";\n" + unless func_datatype == 'void' + if Template.struct_types_pointer =~ func_datatype + result = '*' + result + end + result = "#{Template::C.convention_return_variable(func_name)} = #{result}" + if is_struct + result = '*' + result + end + end + result + end + + def format_return(func_datatype, func_name) + "return #{Template.to_mrb(func_datatype, Template::C.convention_return_variable(func_name))};" end def init_module(module_name) @@ -64,11 +335,11 @@ mrb_mruby_#{gem_name}_gem_final(mrb_state* mrb) { # define under needs the C name, not the ruby name which may be confusing def init_class(class_name, define_under, is_struct_wrapper = true) %{ -struct RClass *#{class_name.downcase}_class = mrb_define_class_under(mrb, #{define_under}, \"#{class_name}\", mrb->object_class);#{ + struct RClass *#{class_name.downcase}_class = mrb_define_class_under(mrb, #{define_under}, \"#{class_name}\", mrb->object_class);#{ if is_struct_wrapper "\nMRB_SET_INSTANCE_TT(#{class_name.downcase}_class, MRB_TT_DATA);" end - } +} } end @@ -86,56 +357,35 @@ mrb_#{function_name}(mrb_state* mrb, mrb_value self) { } end - def get_kwargs(kwarg_num, init_var_body, init_array_body) - %{ -#{init_var_body} - -uint32_t kw_num = #{kwarg_num}; -const mrb_sym kw_names[] = { -#{init_array_body} -}; -mrb_value kw_values[kw_num]; -const mrb_kwargs kwargs = { kw_num, 0, kw_names, kw_values, NULL }; -mrb_get_args(mrb, "|:", &kwargs); - } - end - - def unwrap_kwarg(kwarg_iter, body_if_defined, body_if_undefined = nil, no_argument_error_message = 'Missing Keyword Argument') - %{ -if (mrb_undef_p(kw_values[#{kwarg_iter}])) { -#{body_if_undefined || "mrb_load_string(mrb, \"raise ArgumentError.new \\\"#{no_argument_error_message}\\\"\");"} -} else { -#{body_if_defined} -} - } - end - def get_args(req_arg_hash, opt_arg_hash=nil) - raise if opt_arg_hash + raise 'opt_arg_hash feature not implemented yet' if opt_arg_hash result = '' tail = '' flags = '' req_arg_hash.each do |var_name, var_datatype| - if var_datatype != 'unsigned char' - result += "#{var_datatype} #{var_name};\n" - else - result += "mrb_int #{var_name};\n" + #if var_datatype != 'unsigned char' + if Template.non_struct_types =~ var_datatype + result += "#{Template::C.format_type(var_datatype)} #{Template::C.convention_parameter(var_name)};\n" + #else + # result += "mrb_int #{var_name};\n" end - tail += ", &#{var_name}" + tail += ", &#{Template::C.convention_parameter(var_name)}" flags += datatype_to_arg_flag(var_datatype) end result += "mrb_get_args(mrb, \"#{flags}\"#{tail});\n" end def datatype_to_arg_flag(datatype) - if treated_as_int.include? datatype + if Template.treated_as_int =~ datatype 'i' - elsif treated_as_bool.include? datatype + elsif Template.treated_as_bool =~ datatype 'b' - elsif treated_as_float.include? datatype + elsif Template.treated_as_float =~ datatype 'f' - elsif treated_as_string.include? datatype + elsif Template.treated_as_string =~ datatype 'z' + elsif Template.struct_types =~ datatype + 'o' end end @@ -145,9 +395,9 @@ if (mrb_undef_p(kw_values[#{kwarg_iter}])) { def wrap_struct(var_name, target, mrb_type, type) %{ - #{var_name} = (#{type} *)DATA_PTR(#{target}); - if(#{var_name}) #{'{'} mrb_free(mrb, #{var_name}); #{'}'} -mrb_data_init(#{target}, NULL, &#{mrb_type}); + #{var_name} = (#{type} *)DATA_PTR(#{target}); + if(#{var_name}) #{'{'} mrb_free(mrb, #{var_name}); #{'}'} + mrb_data_init(#{target}, NULL, &#{mrb_type}); #{var_name} = (#{type} *)mrb_malloc(mrb, sizeof(#{type})); } end @@ -159,39 +409,40 @@ mrb_data_init(#{target}, NULL, &#{mrb_type}); # for converting mrb to C def to_c(type, variable) - if treated_as_int.include?(type) || treated_as_bool.include?(type) + if (Template.treated_as_int =~ type) || (Template.treated_as_bool =~ type) "mrb_as_int(mrb, #{variable})" - elsif treated_as_float.include? type + elsif Template.treated_as_float =~ type "mrb_as_float(mrb, #{variable})" - elsif treated_as_string.include? type + elsif Template.treated_as_string =~ type "mrb_str_to_cstr(mrb, #{variable})" end end # for converting C to mrb def to_mrb(type, variable) - if treated_as_int.include? type + if Template.treated_as_int =~ type "mrb_fixnum_value(#{variable})" - elsif treated_as_float.include? type + elsif Template.treated_as_float =~ type "mrb_float_value(mrb, #{variable})" - elsif treated_as_bool.include? type + elsif Template.treated_as_bool =~ type "mrb_bool_value(#{variable})" - elsif treated_as_string.include? type + elsif Template.treated_as_int_pointer =~ type + "mrb_fixnum_value(*#{variable})" + elsif Template.treated_as_float_pointer =~ type + "mrb_float_value(mrb, *#{variable})" + elsif Template.treated_as_bool_pointer =~ type + "mrb_bool_value(*#{variable})" + elsif Template.treated_as_string =~ type "mrb_str_new_cstr(mrb, #{variable})" - elsif treated_as_void.include? type + elsif Template.treated_as_void =~ type 'mrb_nil_value()' + elsif Template.struct_types =~ type + "mrb_obj_value(Data_Wrap_Struct(mrb, #{type.downcase}_mrb_class, &mrb_#{type}_struct, #{variable}))" + elsif Template.struct_types_pointer =~ type + "mrb_obj_value(Data_Wrap_Struct(mrb, #{type.delete_suffix(' *').downcase}_mrb_class, &mrb_#{type.delete_suffix(' *')}_struct, #{variable}))" end end - # convert a C function name to be - # formatted like a Ruby method name - def rubify_func_name(function) - func = function.underscore - if func.start_with? 'is_' - func = func.delete_prefix('is_') + '?' - end - func.delete_prefix('get_') - end # generate a return of a ruby bound C function def return_format(function, params) @@ -242,31 +493,31 @@ mrb_data_init(#{target}, NULL, &#{mrb_type}); # wrapping an existing struct to be used by ruby def init_struct_wrapper(struct, free_body = nil) %{ - #{"void mrb_helper_#{struct}_free(mrb_state*, void*);" if free_body} + #{"void mrb_helper_#{struct}_free(mrb_state*, void*);" if free_body} -static const struct mrb_data_type mrb_#{struct}_struct = { -"#{struct}", -#{ + static const struct mrb_data_type mrb_#{struct}_struct = { + "#{struct}", + #{ if free_body "mrb_helper_#{struct}_free" else "mrb_free" end } - }; - #{ + }; + #{ if free_body %{ void mrb_helper_#{struct}_free(mrb_state* mrb, void*ptr) { #{struct} *struct_data = (#{struct}*)ptr; -#{free_body} + #{free_body} mrb_free(mrb, ptr); } } end - } + } } end |
