/ / Macro di elisir, citando i tipi di patternmatch a bit di bit: macro, elisir, disimballaggio, forma speciale

Macro di elisir, citando i tipi di patternmatch a bit di bit: macro, elisir, decompressione, forma speciale

Sto lavorando a un progetto in cui probabilmente scriverò molto codice del modulo:

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

(per insiemi arbitrari di nomi e tipi di input, input essendo un flusso binario producendo un byte alla volta)

Sarebbe molto utile essere in grado di gestirlo in una macro, in modo che potessi semplicemente scrivere (per esempio) use Unpack quote([{name1, integer-8}, {name2, integer-little-32}, {name3, binary-10}]) e genera automaticamente la struttura necessaria,typedef e funzione di disimballaggio, per campi con nome arbitrario di dimensioni fisse. Potrebbe anche espandersi, aggiungere un terzo campo nelle tuple per passare una funzione per gestire tipi di dimensioni variabili. Sfortunatamente, quando provo a fare una versione più semplice di quella (solo prendendo un campo di dimensioni e solo 1 corrispondente):

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

Il sistema mi dice che ha argomenti non validi per quote/1. Presumo che questo sia dovuto al fatto che i "tipi" utilizzati nella corrispondenza del pattern di bitstring sono una forma speciale, così come i valori letterali di bitstring in generale, e quegli elementi particolari non sono usati da nessun'altra parte.

Quindi, come faccio ad aggirarlo? Ho più di una dozzina di tipi di strutture imballate da disfare, ognuna con un numero di campi compreso tra cinque e venti. Se non lo faccio, probabilmente userò i macro di Vim almeno per salvare le mie mani ... ma che non può essere di grande aiuto nell'avere grandi quantità di codice estremamente ripetitivo da mantenere.

risposte:

1 per risposta № 1

Due cose: hai un errore di battitura unquote e l'RHS deve essere un file binario in modo che il modello corrisponda. Con queste modifiche, il tuo codice funziona per me:

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

Produzione:

97