bindgen icon indicating copy to clipboard operation
bindgen copied to clipboard

Support nested anonymous types

Open HertzDevil opened this issue 3 years ago • 0 comments

Currently, Bindgen doesn't support nested anonymous types at all:

struct T {
  struct { int x, y; } point;
  struct { float u, v; };
};
classes: { T: T }
types:
  T: { copy_structure: true }
lib Binding
  struct T
    point : T::(anonymous)*
    unnamed_arg_0 : T::(anonymous)*
  end

  # SanityCheck will complain about the inaccessible (anonymous) types
  # x, y, u, and v are entirely missing
end

There are many examples of these types in the wild, mostly C struct / union compounds: (union support would be in a separate issue)

/**
 *  Get the SDL joystick layer binding for this controller button/axis mapping
 */
typedef struct SDL_GameControllerButtonBind
{
    SDL_GameControllerBindType bindType;
    
    union
    {
        int button;
        int axis;
        struct {
            int hat;
            int hat_mask;
        } hat;
    } value;

} SDL_GameControllerButtonBind;

Successfully parsing the nested types is the first step to supporting these classes, whether they are wrapped or not. This issue could be broken down into several tasks:

  • [x] Allow the Clang parser to emit nested anonymous types. The only chance to emit those types is while parsing the outer type, otherwise it would be quite difficult to map them to data members (point and unnamed_arg_0 end up having the same generated type name). #84 is a step towards this.
  • [x] These anonymous types obviously cannot be named inside the YAML configuration files, so Bindgen needs to generate appropriate rules for them (my guess is either copy the structure only, or derive from the parent type's rules).
  • [x] If an anonymous type does not define a data member, its structure should be copied to the parent type.
  • [ ] C/C++ methods cannot reference anonymous types, but the property methods from Crystal wrappers can, so something has to be done about it.

At the end, Binding::T should look like the following:

lib Binding
  struct T
    point : T_Unnamed0
    u : Float32
    v : Float32
  end
  struct T_Unnamed0
    x : Int32
    y : Int32
  end
end

Or if there is a Crystal wrapper:

class T
  @unwrap : Binding::T*

  def point : ??? end
  def point=(point : ???) end

  def u : Int32 end
  def u=(u : Int32) : Void end
  def v : Int32 end
  def v=(v : Int32) : Void end
end

HertzDevil avatar Aug 30 '20 20:08 HertzDevil