summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorrealtradam <[email protected]>2022-04-01 04:02:25 -0400
committerrealtradam <[email protected]>2022-04-01 04:02:25 -0400
commit2ae12787183ceb253e8f6abfc57de009d5e71aab (patch)
treedb3d0cd6b3f310b09ecfbddc9d627fdbd3a40a0d
parent2f93334dc43f92f50196f1c39c7fb9ce40f4c562 (diff)
downloadFelBind-2ae12787183ceb253e8f6abfc57de009d5e71aab.tar.gz
FelBind-2ae12787183ceb253e8f6abfc57de009d5e71aab.zip
working function bindings
-rw-r--r--Readme.mdown16
-rw-r--r--generate.rb56
-rw-r--r--templates.rb147
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 @@
[![Ko-Fi](https://img.shields.io/static/v1?message=Buy%20me%20a%20coffee&logo=kofi&labelColor=ff5e5b&color=434B57&logoColor=white&label=%20)](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