From 24ba42e49f78fa9db482ecb967aca9b924f65fbf Mon Sep 17 00:00:00 2001 From: realtradam Date: Fri, 26 May 2023 01:02:14 -0400 Subject: broken struct binding --- ideas/stuff.rb | 2 +- lib/FelBind.rb | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 134 insertions(+), 3 deletions(-) diff --git a/ideas/stuff.rb b/ideas/stuff.rb index 276a101..9e4cba7 100644 --- a/ideas/stuff.rb +++ b/ideas/stuff.rb @@ -56,7 +56,7 @@ mgem = BindGem.new mgem.add_class("Color") -mgem.add_struct(class: "Color") do |struct| +mgem.add_struct(class: "Color", cstruct_name: "Color") do |struct| struct.initializer = true struct.member( name: "r", diff --git a/lib/FelBind.rb b/lib/FelBind.rb index 1ca1cff..51562fa 100644 --- a/lib/FelBind.rb +++ b/lib/FelBind.rb @@ -27,6 +27,117 @@ module FelBind block.call(functions.last) end + def add_struct(class_name:, cstruct_name:, &block) + structs.push StructObj.new(class_name, cstruct_name) + block.call(structs.last) + end + + # structs + class StructObj + attr_accessor :class_name, :cstruct_name, :initializer + + # declaring the C struct + def build_struct_init + "static const struct mrb_data_type felbind_struct_#{class_name} = { \"#{class_name}\", mrb_free };\n" + end + + # building the C functions + def build_funcs + init_result = "" + init_vars = "" + init_get_args_types = "" + init_get_args_addresses = "" + init_set_vars = "" + accessor_result = "" + if initializer + init_result += "static mrb_value felbind_struct_init_#{class_name}(mrb_state* mrb, mrb_value self) {\n" + init_result += "#{cstruct_name} *felbind_struct_wrapped_#{class_name} = (#{cstruct_name} *)DATA_PTR(self);\n" + init_result += "if(felbind_struct_wrapped_#{class_name}) { mrb_free(mrb, felbind_struct_wrapped_#{class_name}); }\n" + init_result += "mrb_data_init(self, NULL, &felbind_struct_#{class_name});\n" + init_result += "felbind_struct_wrapped_#{class_name} = (#{cstruct_name} *)mrb_malloc(mrb, sizeof(#{cstruct_name}));\n" + end + members.each do |mem| + next if !mem.accessor + next if !initializer + + if mem.rtype == "int" + init_vars += "mrb_int felbind_param_#{mem.name};\n" + init_get_args_types += "i" + init_get_args_addresses += ", &felbind_param_#{mem.name}" + init_set_vars += "felbind_struct_wrapped_#{class_name}->#{mem.name} = (#{mem.ctype})felbind_param_#{mem.name};\n" + + accessor_result += "static mrb_value felbind_getter_#{class_name}_#{mem.name}(mrb_state *mrb, mrb_value self) {\n" + accessor_result += "struct #{cstruct_name} *felbind_struct_get = DATA_GET_PTR(mrb, self, &felbind_struct_#{class_name}, #{cstruct_name});\n" + #accessor_result += "return mrb_fixnum_value(felbind_getter_#{class_name}_#{mem.name});\n" + accessor_result += "return mrb_fixnum_value(felbind_struct_get->#{mem.name});\n" + accessor_result += "}\n" + + accessor_result += "static mrb_value felbind_setter_#{class_name}_#{mem.name}(mrb_state *mrb, mrb_value self) {\n" + accessor_result += "mrb_int felbind_param_#{mem.name};\n" + accessor_result += "mrb_get_args(mrb, \"i\", &felbind_param_#{mem.name});\n" + accessor_result += "struct #{cstruct_name} *felbind_struct_set = DATA_GET_PTR(mrb, self, &felbind_struct_#{class_name}, #{cstruct_name});\n" + accessor_result += "felbind_struct_set->#{mem.name} = (#{mem.ctype})felbind_param_#{mem.name};\n" + accessor_result += "return mrb_fixnum_value(felbind_struct_set->#{mem.name});\n" + accessor_result += "}\n" + end + end + result = init_result + result += init_vars + result += "mrb_get_args(mrb, \"#{init_get_args_types}\"#{init_get_args_addresses});\n" + result += init_set_vars + result += "mrb_data_init(self, felbind_struct_wrapped_#{class_name}, &felbind_struct_#{class_name});\n" + result += "return self;\n" + result += "}\n" + result + accessor_result + end + + # binding instance after class is defined + def build_set_instance(def_class_name) + "MRB_SET_INSTANCE_TT(#{def_class_name}, MRB_TT_DATA);\n" + end + + # binding the C funcs to Ruby + def build_def_funcs(def_class_name) + result = "" + if initializer + result += "mrb_define_method(mrb, #{def_class_name}, \"initialize\", felbind_struct_init_#{class_name}, MRB_ARGS_ANY());\n" + end + members.each do |mem| + next if !initializer + next if !mem.accessor + + result += "mrb_define_method(mrb, #{def_class_name}, \"#{mem.name}\", felbind_getter_#{class_name}_#{mem.name}, MRB_ARGS_NONE());\n" + result += "mrb_define_method(mrb, #{def_class_name}, \"#{mem.name}=\", felbind_setter_#{class_name}_#{mem.name}, MRB_ARGS_ANY());\n" + end + result + end + + def initialize(class_name, cstruct_name) + self.class_name = class_name + self.cstruct_name = cstruct_name + end + + def members + @members ||= [] + end + + def member(name:, ctype:, rtype:, accessor:) + members.push MemberObj.new(name, ctype, rtype, accessor) + end + + # members + class MemberObj + attr_accessor :name, :ctype, :rtype, :accessor + + def initialize(name, ctype, rtype, accessor) + self.name = name + self.ctype = ctype + self.rtype = rtype + self.accessor = accessor + end + end + end + private def functions @@ -37,6 +148,10 @@ module FelBind @class_names ||= [] end + def structs + @structs ||= [] + end + # function class Function attr_accessor :content, :name, :class_name, :return_call_val, :args @@ -77,7 +192,7 @@ module FelBind end def arg(name) - "felflame_var_#{name}" + "felbind_var_#{name}" end def get_args(&block) @@ -116,9 +231,16 @@ module FelBind def build result = "" result += insert_includes + + structs.each do |strct| + result += strct.build_struct_init + result += strct.build_funcs + end + functions.each do |func_obj| result += func_obj.build end + result += build_init result += build_final result @@ -127,7 +249,11 @@ module FelBind private def insert_includes - "#include \n#include \n" + "#include \n" + + "#include \n" + + "#include \n" + + "#include \n" + + "#include \n" end def build_init @@ -136,6 +262,11 @@ module FelBind class_names.each do |class_name| result += "struct RClass *#{class_name}_class = mrb_define_module(mrb, \"#{class_name}\");\n" end + structs.each do |strct| + result += strct.build_set_instance("#{strct.class_name}_class") + result += strct.build_def_funcs("#{strct.class_name}_class") + end + functions.each do |func| result += "mrb_define_class_method(mrb, #{func.class_name}_class, \"#{func.name}\", felbind_#{func.name}," if(func.args.arguments.size.zero?) -- cgit v1.2.3