diff options
| -rw-r--r-- | Readme.mdown | 16 | ||||
| -rw-r--r-- | generate.rb | 56 | ||||
| -rw-r--r-- | templates.rb | 147 |
3 files changed, 160 insertions, 59 deletions
diff --git a/Readme.mdown b/Readme.mdown index 8ca731b..0bacf4d 100644 --- a/Readme.mdown +++ b/Readme.mdown @@ -4,7 +4,7 @@ [](https://ko-fi.com/tradam) -A binding assistant and generator for C/C++ to mruby(Under heavy WIP) +A binding assistant and generator for C(and maybe C++ later?) to mruby [Under heavy WIP] --- @@ -28,8 +28,11 @@ The defaults of FelBind make some assumptions on how you would like the resultin - `Test.some_function` - Structs are defined as classes under a module(by default `Test`) - `Test::MyStruct` +- Struct values are read or written to by using the snake_case version of their respective members + - `my_struct_object.value_example` + - `my_struct_object.value_example = 5` - Functions beginning with `Set` get bound as a method with `=` - - `SetSomeFunction(value)` => `some_function = value` + - `SetSomeFunction(value)` => `Test.some_function = value` - Functions beginning with `Get` get bound as a method without it - `GetSomeFunction()` => `some_function` @@ -37,16 +40,15 @@ The defaults of FelBind make some assumptions on how you would like the resultin - Wrapping functions that return or have parameters that are of the basic C types(int, float, char \*, etc) or their pointers(int \*, float \*, etc[except char *]) - Wrapping function that return or have parameters that are structs or their pointers -- Wrapping structs +- Wrapping structs into objects - Giving struct objects initializers and accessers ### What Doesn't Work: -- Binding C functions that begin with `Set` are bound incorrectly -- Making accessors for structs that contain structs -- kwargs should follow snake_case naming conventions +- Binding accessors for structs that contain structs or pointers +- Cloning struct objects - The config system -- Struct Aliases(might make this manually done) +- Struct Aliases(might make this manually done in the config system) ### What isnt currently planned to make work: diff --git a/generate.rb b/generate.rb index 93545d1..6a8fa7a 100644 --- a/generate.rb +++ b/generate.rb @@ -126,7 +126,6 @@ $bound_params = [] glue.last.each do |struct, params| $defines += Template.init_struct_wrapper(struct) $init_body += Template.init_class(struct, LibraryName.downcase) - init_vars = '' params.each do |param| @@ -145,7 +144,7 @@ glue.last.each do |struct, params| body = Template.unwrap_struct("#{struct} *struct_#{struct.downcase}", 'self', "mrb_#{struct}_struct", struct) body += "return #{Template.to_mrb(param_datatype, "struct_#{struct.downcase}->#{param_name}")};\n" $defines += Template.function("#{struct}_get_#{param_name}", body) - $init_body += Template.init_function("#{struct.downcase}_class", param_name, "#{struct}_get_#{param_name}", "MRB_ARGS_NONE()") + $init_body += Template.init_function("#{struct.downcase}_class", Template::MRuby.rubify_func_name(param_name), "#{struct}_get_#{param_name}", "MRB_ARGS_NONE()") # setter # init var of correct type @@ -153,12 +152,14 @@ glue.last.each do |struct, params| # unwrap struct # set value in struct # return same value - body = Template.get_args({ "#{param_name}": "#{param_datatype}" }) + body = '' + body += Template::C.initialize_variables_for_kwargs([param], glue.last, "Struct: #{struct}") + body += Template.get_args({ "#{param_name}": "#{param_datatype}" }) body += Template.unwrap_struct("#{struct} *struct_#{struct.downcase}", 'self', "mrb_#{struct}_struct", struct) body += "struct_#{struct.downcase}->#{param_name} = #{Template::C.convention_parameter(param_name)};\n" body += "return #{Template.to_mrb(param_datatype, Template::C.convention_parameter(param_name))};\n" $defines += Template.function("#{struct}_set_#{param_name}", body) - $init_body += Template.init_function("#{struct.downcase}_class", "#{param_name}=", "#{struct}_set_#{param_name}", "MRB_ARGS_REQ(1)") + $init_body += Template.init_function("#{struct.downcase}_class", "#{Template::MRuby.rubify_func_name(param_name)}=", "#{struct}_set_#{param_name}", "MRB_ARGS_REQ(1)") end @@ -203,7 +204,6 @@ glue.last.each do |struct, params| $defines += Template.function("#{struct}_initialize", body) $init_body += Template.init_function("#{struct.downcase}_class", "initialize", "#{struct}_initialize", "MRB_ARGS_OPT(1)") - end # generates functions @@ -246,12 +246,21 @@ glue.first.each do |func, params| body = '' - body += Template::C.initialize_variables(params, glue.last, func_name) + # use kwargs + if params.count > 1 + body += Template::C.initialize_variables_for_kwargs(params, glue.last, func_name) - body += Template::C.get_kwargs(params) + body += Template::C.get_kwargs(params) - body += Template::C.parse_kwargs(params) - body += "\n" # formatting + body += Template::C.parse_kwargs(params) + body += "\n" # formatting + # use args + elsif params.first != 'void' + body += Template::C.initialize_variables_for_args(params, glue.last, func_name) + param_rpart = params.first.rpartition(' ') + body += Template.get_args({ "#{param_rpart.last}": "#{param_rpart.first}" }) + body += Template::C.parse_args(params) + end body += Template::C.initialize_return_var(func_datatype, func_name) body += "\n" # formatting @@ -262,7 +271,7 @@ glue.first.each do |func, params| $defines += "\n//#{func}" $defines += Template.function(func_name, body) - $init_body += Template.init_module_function(LibraryName.downcase, Template::MRuby.rubify_func_name(func_name), func_name, "MRB_ARGS_OPT(1)") + $init_body += Template.init_module_function(LibraryName.downcase, Template::MRuby.rubify_func_name(func_name, params), func_name, "MRB_ARGS_OPT(1)") debug_mark_binding(func, params) #puts body @@ -356,15 +365,6 @@ $result = %{ #{Template.base(LibraryName.downcase, $init_body, nil)} } -$result += "//Bound Functions: #{$complete_phase1.length + $complete_phase2.length + $complete_phase3.length + $complete_phase4.length + $complete_phase5.length} / #{$phase1.length + $phase2.length + $phase3.length + $phase4.length + $phase5.length}\n//---\n" - -$result += "//Phase 1 Functions: #{$complete_phase1.length} / #{$phase1.length}\n" -$result += "//Phase 2 Functions: #{$complete_phase2.length} / #{$phase2.length}\n" -$result += "//Phase 3 Functions: #{$complete_phase3.length} / #{$phase3.length}\n" -$result += "//Phase 4 Functions: #{$complete_phase4.length} / #{$phase4.length}\n" -$result += "//Phase 5 Functions: #{$complete_phase5.length} / #{$phase5.length}\n" -$result += "\n" -#$result += "//Struct Accessors: #{$bound_params.length} / #{$all_params.length}\n" #pp ($phase3.keys - $complete_phase3.keys) #puts @@ -379,14 +379,16 @@ $result += "/* Unbound:\n" end $result += "*/\n" -($phase4.keys - $complete_phase4.keys).each do |ye| - #puts ye -end +$result += "//Bound Functions: #{$complete_phase1.length + $complete_phase2.length + $complete_phase3.length + $complete_phase4.length + $complete_phase5.length} / #{$phase1.length + $phase2.length + $phase3.length + $phase4.length + $phase5.length}\n//---\n" +$result += "//Struct Accessors: #{$bound_params.length} / #{$all_params.length}\n//---\n" + +$result += "\n" puts $result -#$phase4.reverse_each do |key, elem| -# puts '---' -# puts key -# pp elem -#end +puts '/*' +pp $all_params - $bound_params +puts +pp $bound_params +puts '*/' + diff --git a/templates.rb b/templates.rb index 1846a0e..5232a6e 100644 --- a/templates.rb +++ b/templates.rb @@ -45,16 +45,46 @@ module Template # Template end end + def format_mrb_type(param_datatype) + if Template.treated_as_int =~ param_datatype + 'mrb_int' + elsif Template.treated_as_int_pointer =~ param_datatype + 'mrb_int' + elsif Template.treated_as_bool =~ param_datatype + 'mrb_bool' + elsif Template.treated_as_bool_pointer =~ param_datatype + 'mrb_bool' + elsif Template.treated_as_float =~ param_datatype + 'mrb_float' + elsif Template.treated_as_float_pointer =~ param_datatype + 'mrb_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 + "mrb_value" #"#{param_datatype}" + elsif Template.struct_types_pointer =~ param_datatype + "mrb_value" #"#{param_datatype.gsub(/ *\*+$/,'')}" + else + nil # cannot be formated + end + end + def convention_parameter(param) "parameter_#{param}" end + def convention_mrb_parameter(param) + "parameter_mrb_#{param}" + end + def convention_return_variable(func_name) "return_of_#{func_name}" end - def initialize_variables(params, structs, func_name=nil) - + def initialize_variables_for_kwargs(params, structs, func_name=nil) result = '' return result if params.first == 'void' params.each do |param| @@ -70,6 +100,37 @@ module Template # Template result + "\n" end + #def needs_mrb_conversion?(datatype) + # test = Template::C.datatype_to_arg_flag(datatype) + # if ['i','b','z','f'].include? test + # false + # elsif ['o'].include? test + # true + # else + # nil + # end + #end + + def initialize_variables_for_args(params, structs, func_name=nil) + result = '' + return result if params.first == 'void' + params.each do |param| + rpart = param.rpartition(' ') + format = Template::C.format_mrb_type(rpart.first) + if format + if Template.struct_types =~ rpart.first || Template.struct_types_pointer =~ rpart.first + result += format + " #{Template::C.convention_mrb_parameter(rpart.last)};\n" + else + result += format + " #{Template::C.convention_parameter(rpart.last)};\n" + end + 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 = '' @@ -106,14 +167,15 @@ mrb_get_args(mrb, "|:", &kwargs); skipped = 0 params.each_with_index do |param, index| rpart = param.rpartition(' ') - if Template.struct_types =~ rpart.first + datatype, _space, var_name = param.rpartition(' ') + if Template.struct_types_all =~ datatype - unwrap = Template.unwrap_struct(Template::C.convention_parameter(rpart.last), "kw_values[#{index - skipped}]", "mrb_#{rpart.first}_struct", rpart.first) + unwrap = Template.unwrap_struct(Template::C.convention_parameter(var_name), "kw_values[#{index - skipped}]", "mrb_#{datatype.delete_suffix(' *')}_struct", datatype.delete_suffix(' *')) 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) + elsif Template.non_struct_types_all =~ datatype + unwrap = "#{Template::C.convention_parameter(var_name)} = #{Template.to_c(datatype, "kw_values[#{index - skipped}]")};" + result += Template::C.unwrap_kwarg(index - skipped, unwrap) else skipped += 1 next @@ -122,6 +184,29 @@ mrb_get_args(mrb, "|:", &kwargs); result end + # unwrap structs + # convert floats? + # ignore string + # ignore boolean + # ignore int + def parse_args(params) + result = '' + params.each do |param| + datatype, _space, var_name = param.rpartition(' ') + next unless Template.struct_types =~ datatype || Template.struct_types_pointer =~ datatype + format = Template::C.format_type(datatype) + if format + # init var + result += format + " *#{Template::C.convention_parameter(var_name)};\n" + # unwrap var + result += Template.unwrap_struct(Template::C.convention_parameter(var_name), Template::C.convention_mrb_parameter(var_name), "mrb_#{datatype.delete_suffix(' *')}_struct", datatype.delete_suffix(' *')) + else + # error + 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}])) { @@ -140,16 +225,14 @@ if (mrb_undef_p(kw_values[#{kwarg_iter}])) { class << self # convert a C function name to be # formatted like a Ruby method name - def rubify_func_name(function) + def rubify_func_name(function, params=[]) 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_') + func = func.delete_prefix('set_') + '=' if params.count == 1 && params.first != 'void' end - func + func.delete_prefix('get_') end def to_c_function_name(function_name:) @@ -222,6 +305,9 @@ if (mrb_undef_p(kw_values[#{kwarg_iter}])) { 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 + def non_struct_types_all + @non_struct_types_all ||= Regexp.union(non_struct_types, non_struct_types_pointer) + end attr_writer :struct_types def struct_types @@ -239,6 +325,10 @@ if (mrb_undef_p(kw_values[#{kwarg_iter}])) { raise "Struct types were not parsed\nRun 'parse_struct_types' first" end end + attr_writer :struct_types_all + def struct_types_all + @struct_types_all ||= Regexp.union(struct_types, struct_types_pointer) + end def parse_struct_types(structs) struct_types = structs.keys @@ -282,14 +372,9 @@ mrb_mruby_#{gem_name}_gem_final(mrb_state* mrb) { # 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 @@ -304,7 +389,7 @@ mrb_mruby_#{gem_name}_gem_final(mrb_state* mrb) { end result = "#{Template::C.convention_return_variable(func_name)} = #{result}" if is_struct - result = '*' + result + result = '*' + result end end result @@ -364,28 +449,34 @@ mrb_#{function_name}(mrb_state* mrb, mrb_value self) { flags = '' req_arg_hash.each do |var_name, var_datatype| #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" + #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 + if Template.struct_types_all =~ var_datatype + tail += ", &#{Template::C.convention_mrb_parameter(var_name)}" + else + tail += ", &#{Template::C.convention_parameter(var_name)}" end - 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 Template.treated_as_int =~ datatype + if Template.treated_as_int =~ datatype || Template.treated_as_int_pointer =~ datatype 'i' - elsif Template.treated_as_bool =~ datatype + elsif Template.treated_as_bool =~ datatype || Template.treated_as_bool_pointer =~ datatype 'b' - elsif Template.treated_as_float =~ datatype + elsif Template.treated_as_float =~ datatype || Template.treated_as_float_pointer =~ datatype 'f' elsif Template.treated_as_string =~ datatype 'z' - elsif Template.struct_types =~ datatype + elsif Template.struct_types =~ datatype || Template.struct_types_pointer =~ datatype 'o' + else # failed to match + nil end end @@ -411,10 +502,16 @@ mrb_#{function_name}(mrb_state* mrb, mrb_value self) { def to_c(type, variable) if (Template.treated_as_int =~ type) || (Template.treated_as_bool =~ type) "mrb_as_int(mrb, #{variable})" + elsif (Template.treated_as_int_pointer =~ type) || (Template.treated_as_bool_pointer =~ type) + "mrb_as_int(mrb, #{variable})" elsif Template.treated_as_float =~ type "mrb_as_float(mrb, #{variable})" + elsif Template.treated_as_float_pointer =~ type + "mrb_as_float(mrb, #{variable})" elsif Template.treated_as_string =~ type "mrb_str_to_cstr(mrb, #{variable})" + else + "#{type} and #{variable}" end end |
