/ / Macros d'élixir, citant les types de correspondance de motif de chaînes de bits - macros, élixir, décompresser, forme spéciale

Macros d'élixir, citant les types de correspondance de motif de chaînes de bits - macros, élixir, décompresser, forme spéciale

Je travaille sur un projet dans lequel je suis susceptible d'écrire beaucoup de code de la forme

defmodule Kind
defstruct [name1, name2, name3]
@type t :: %Kind{name1: integer(), name2: integer(), name3: binary()}
def unpack(input) do
with <<name1::integer-8>> <- Enum.take(input, 1),
<<name2::integer-little-32>> <- Enum.take(input, 4),
<<name3::binary-10>> <- Enum.take(input, 10),
do: %Kind{name1: name1, name2: name2, name3: name3>>
end
end

(pour des ensembles arbitraires de noms et de types d’entrée, input étant un flux binaire produisant un octet à la fois)

Il serait très utile de pouvoir gérer cela dans une macro, pour que je puisse simplement écrire (par exemple) use Unpack quote([{name1, integer-8}, {name2, integer-little-32}, {name3, binary-10}]) et générer automatiquement la structure nécessaire,typedef, et la fonction de décompression, pour les champs nommés arbitraires de tailles fixes. Pourrait même le développer, ajoutez un troisième champ dans les n-uplets afin de transmettre une fonction permettant de gérer des types de tailles variables. Malheureusement, lorsque j'essaie de faire une version plus simple de cela (en prenant uniquement un champ de taille, et en ne faisant correspondre que 1):

defmodule Unpack do
defmacro testmacro({name, kind}) do
quote do
<<unquote(name)::unqote(kind)>> = 1
end
end
end

Le système me dit qu’il a des arguments non valides pour quote/1. Je suppose que cela est dû au fait que les "types" utilisés dans la correspondance de modèle de chaîne de bits sont une forme spéciale, tout comme les littéraux de chaîne de bits en général, et que ces éléments particuliers ne sont utilisés nulle part ailleurs.

Alors, comment puis-je contourner cela? J'ai plus d'une douzaine de sortes de structures à décompresser, chacune comprenant entre cinq et vingt champs différents. Si je ne le fais pas, je vais probablement recourir aux macros Vim pour au moins sauver mes mains ... mais ça ne sera pas vraiment utile d'avoir à maintenir de grandes quantités de code extrêmement répétitif.

Réponses:

1 pour la réponse № 1

Deux choses: vous avez une faute de frappe unquote et le RHS doit être un binaire pour que le modèle corresponde. Avec ces changements, votre code fonctionne pour moi:

defmodule Unpack do
defmacro unpack({name, kind}) do
quote do
<<unquote(name)::unquote(kind)>> = "a"
end
end
end

defmodule Main do
import Unpack

def main do
unpack({foo, integer-8})
IO.inspect foo
end
end

Main.main

Sortie:

97