Is something like this possible? I would need to be able to quote msg1_length::16, msg1::size(msg1_length) from a macro, right? However, I see no way how I could do this since it (by itself) is no valid statement.
Yes, that is something I am playing around with in the meantime, but I hoped to keep the syntax a bit cleaner since I will need to define quite a few of those bitstrings.
defmodule M do
defmacro str(num) do
{:<<>>, [],
[{:::, [], [{:"msg#{num}_length", [], Elixir}, 16]},
{:::, [],
[{:var!, [context: Elixir, import: Kernel], [{:"msg#{num}", [], Elixir}]},
{:size, [], [{:"msg#{num}_length", [], Elixir}]} ]}
]}
end
end
require M
<<id::32, M.str(1)>> = <<0,0,0,0>> <> <<0,8>> <> "A"
<<0, 0, 0, 0, 0, 8, 65>>
msg1
#⇒ 65
It’s up to you to get it back from AST to more readable view I did quote do: <<msg1_length::16, var!(msg1)::size(msg1_length)>> and copy-pasted the result.
@doc """
Macro for generating a match of an string in a bitstream
## Examples
iex> ManaElixir.Networking.Enet.Macros.string(msg) = <<5::16, "Hello">>
...> msg
"Hello"
"""
defmacro string(name) do
varname = elem(name, 0) |> Atom.to_string()
length = :"length_#{varname}" |> Macro.var(nil)
quote do
<<unquote(length)::16, unquote(name)::binary-size(unquote(length))>>
end
end
It works without var!. I am just not 100% sure about the Macro.var(nil). but it seems to work fine