[Template-haskell] TH question

Tim Newsham newsham at lava.net
Wed Jan 18 20:27:50 EST 2006


Hi,  I have yet to write anything in TH, although I've been toying with
it a little bit and asking some questions on IRC.  I have come across
a problem that doesn't seem to have a good solution without using
some sort of preprocessor.  I want to take a simple spec and generate
some marshalling code using a straighforward transformation.

The spec should look something like:

> $(declPkt "ip" [
>               ("Word8", "v_hl", "0x45"),
>               ("Word8", "tos", "0"),
>               ("Word16", "len", "0"),
>               ("Word16", "id", "0"),
>               ("Word16", "off", "0"),
>               ("Word8", "ttl", "64"),
>               ("Word8", "p", "6"),
>               ("Word16", "sum", "0"),
>               ("Word32", "src", "0"),
>               ("Word32", "dst", "0")])


and should generate something like:

> data IP = IP {
>       ip_v_hl :: Word8,
>       ip_tos :: Word8,
>       ip_len :: Word16,
>       ip_id :: Word16,
>       ip_off :: Word16,
>       ip_ttl :: Word8,
>       ip_p :: Word8,
>       ip_sum :: Word16,
>       ip_src :: Word32,
>       ip_dst :: Word32
>       } deriving Show
> newIP = IP 0x45 0 20 0 0 64 6 0 0 0
>
> instance ByteContainer IP where
>       getByteAt b 0 = getByteAt (ip_v_hl b) 0
>       getByteAt b 1 = getByteAt (ip_tos b) 0
>       getByteAt b 2 = getByteAt (ip_len b) 0
>       getByteAt b 3 = getByteAt (ip_len b) 1
>       getByteAt b 4 = getByteAt (ip_id b) 0
>       getByteAt b 5 = getByteAt (ip_id b) 1
>       getByteAt b 6 = getByteAt (ip_off b) 0
>       getByteAt b 7 = getByteAt (ip_off b) 1
>       getByteAt b 8 = getByteAt (ip_ttl b) 0
>       getByteAt b 9 = getByteAt (ip_p b) 0
>       getByteAt b 10 = getByteAt (ip_sum b) 0
>       getByteAt b 11 = getByteAt (ip_sum b) 1
>       getByteAt b 12 = getByteAt (ip_src b) 0
>       getByteAt b 13 = getByteAt (ip_src b) 1
>       getByteAt b 14 = getByteAt (ip_src b) 2
>       getByteAt b 15 = getByteAt (ip_src b) 3
>       getByteAt b 16 = getByteAt (ip_dst b) 0
>       getByteAt b 17 = getByteAt (ip_dst b) 1
>       getByteAt b 18 = getByteAt (ip_dst b) 2
>       getByteAt b 19 = getByteAt (ip_dst b) 3
>
>       containerLength b = 20
>
>       makeContainer b = IP {
>               ip_v_hl = makeContainer (Slice b 0),
>               ip_tos = makeContainer (Slice b 1),
>               ip_len = makeContainer (Slice b 2),
>               ip_id = makeContainer (Slice b 4),
>               ip_off = makeContainer (Slice b 6),
>               ip_ttl = makeContainer (Slice b 8),
>               ip_p = makeContainer (Slice b 9),
>               ip_sum = makeContainer (Slice b 10),
>               ip_src = makeContainer (Slice b 12),
>               ip_dst = makeContainer (Slice b 16)
>               }


This definitely looks feasible using TH.  However, it looks like I
might have to mess with ASTs manually.

My questions is -- is there an easy way to perform this transformation
making use of quasi-quotes for much of the code, or will it be necessary
to construct all of the ASTs manually?

This seems like something that should have a fairly simple solution but
so far I haven't been able to come up with one :(.

Tim Newsham
http://www.lava.net/~newsham/


More information about the template-haskell mailing list