2017-12-13 4 views
0

ich an einem Projekt arbeite, in der ich bin wahrscheinlich eine Menge Code der Form zu schreiben:Elixir Makros unter Angabe von Bitstring patternmatch Typen

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 

(für beliebige Sätze von Eingangsnamen und -typen, input Da es sich um einen binären Datenstrom handelt, der ein Byte nach dem anderen erzeugt)

Es wäre sehr nützlich, dies in einem Makro zu handhaben, so dass ich einfach schreiben könnte (zum Beispiel) use Unpack quote([{name1, integer-8}, {name2, integer-little-32}, {name3, binary-10}]) und automatisch die notwendige struct, typedef erzeugt. und Entpackfunktion für beliebige benannte Felder fester Größe. Könnte es sogar erweitern, fügen Sie ein drittes Feld in den Tupeln hinzu, um eine Funktion zu übergeben, um unterschiedlich große Typen zu behandeln. Leider, wenn ich versuche, eine einfachere Version von, das zu tun (nur eine Größe Feld nehmen, und nur 1 bis es passend):

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

Das System sagt mir es ungültige Argumente für quote/1 bekommt ist. Ich nehme an, das liegt daran, dass die „Typen“ verwendet in Bitstring Pattern-Matching eine spezielle Form sind, wie sie von Bitstring Literale im Allgemeinen, und diese bestimmten Gegenstände sind nicht anderswo verwendet. So

, wie komme ich um das? Ich habe mehr als ein Dutzend Arten von gepackten Strukturen zum Auspacken mit jeweils fünf bis zwanzig verschiedenen Feldern. Wenn ich das nicht tun werde ich wahrscheinlich zu Vim-Makros greifen zumindest meine Hände zu retten ... aber das wird mit mit großen Mengen an äußerst repetitiven Code nicht wirklich helfen zu halten.

+1

Können Sie den vollständigen Code schreiben, die diesen Fehler gibt? Der zweite Snippet funktioniert für mich, wenn ich den Tippfehler (unqote) behebe und eine Binärdatei auf dem RHS benutze (das Muster kann nicht mit einer Ganzzahl verglichen werden). – Dogbert

+0

... Nein, wurde dieser Code direkt aus der IEX-Sitzung Getestet habe ich es in. Offensichtlich ich einen Tippfehler verpasst copypasted. Nun, das ist ziemlich peinlich. Löschen. –

+0

@Dogbert Es kommt mir vor, dass, selbst wenn das Problem klein war, Sie es immer noch beantwortet haben. Gehen Sie weiter, fügen Sie es als Antwort ein und ich werde zustimmen. –

Antwort

1

Zwei Dinge: Sie haben einen Tippfehler in unquote und die RHS muss ein binäres sein, so dass das Muster übereinstimmt. Mit diesen Änderungen, funktioniert der Code für mich:

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 

Ausgang:

97 
Verwandte Themen