Need help to create nested struct macro (A.B.C)

Hello, I am developing a macro to create nested struct in a module or (module → module …), I took the original code from this repo, because it had been abandoned and I want many options for validation etc, I move it inside my project, you can see it in this link.

The problem:

To create a nested struct, I create a new module in one module. For example (A.B.C) is made. Since struct B cannot be called in A at compile time, I just want to create a field named module in its parent struct.
But it seems that the parent has already been compiled and does not allow me to do this.

Please see this part of code:

in this part I create another module, but how can define a filed which struct type with options

defmodule A do
  defstruct name: "", :b 
  
  defmodule B do
    defstruct name: ""
  end
end

I tried to use @before_compile {__CALLER__.module, :add_parent_field_of_sub_field} to add module attribute like using this

== Compilation error in file lib/macros/guarded_struct.ex ==
** (ArgumentError) cannot set attribute @before_compile inside function/macro

Even I use this macro inside sub_field macro, to define a field, but it has no effect on my code

Example code I want finally:

  defmodule TestNestedStruct do
    use GuardedStruct

    guardedstruct do
      field(:title, String.t())
      field(:subject, String.t())

      sub_field(:oop, struct(), enforce: true) do
        field(:title, String.t())
        field(:fam, String.t())

        sub_field(:soos, struct(), enforce: true) do
          field(:fam, String.t())
        end

        field(:site, String.t())
      end

      field(:site, String.t())
    end
  end

If I create a field has same name with module name, I can check it inside my builder function.

I have no idea how can do it, thank you in advance

I think it works for me, but I need more test, if my idea is good for this problem?

  defmacro sub_field(name, type, opts \\ [], do: block) do
    ast = register_struct(block, opts)
    type = Macro.escape(type)

    converted_name =
      name
      |> Atom.to_string()
      |> Macro.camelize()
      |> String.to_atom()
      |> then(&Module.concat(__CALLER__.module, &1))

    quote do
      GuardedStruct.__field__(unquote(name), unquote(type), unquote(opts), __ENV__)

      defmodule unquote(converted_name) do
        unquote(ast)
      end
    end
  end

Output

%MishkaDeveloperToolsTest.GuardedStructTest.TestNestedStruct{
  site: nil,
  oop: nil,
  subject: nil,
  title: nil
}
[:site, :oop, :subject, :title]
[
  __struct__: 0,
  __struct__: 1,
  builder: 1,
  enforce_keys: 0,
  enforce_keys: 1,
  keys: 0,
  keys: 1
]
--------------------------------
%MishkaDeveloperToolsTest.GuardedStructTest.TestNestedStruct.Oop{
  site: nil,
  soos: nil,
  fam: nil,
  title: nil
}
[:site, :soos, :fam, :title]
[
  __struct__: 0,
  __struct__: 1,
  builder: 1,
  enforce_keys: 0,
  enforce_keys: 1,
  keys: 0,
  keys: 1
]
--------------------------------
%MishkaDeveloperToolsTest.GuardedStructTest.TestNestedStruct.Oop.Soos{fam: nil}
[:fam]
[
  __struct__: 0,
  __struct__: 1,
  builder: 1,
  enforce_keys: 0,
  enforce_keys: 1,
  keys: 0,
  keys: 1
]

If you see I just create a field in parent struct and I will check it inside builder function, there is no way I think to load and call the B struct inside A struct field, I think, am I right?