1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
#!/usr/bin/env python3
from __future__ import print_function
import sys
import os
import re
from xml.dom.minidom import parse
def safe(str):
return str.replace('-', '_')
class AMQPType:
def __init__(self, dom):
self.name = safe(dom.getAttribute('name'))
self.source = dom.getAttribute('source')
self.desc = dom.getElementsByTagName('descriptor')[0].getAttribute('name')
self.code = dom.getElementsByTagName('descriptor')[0].getAttribute('code')
self.number = parse_code(self.code)
self.fields = [safe(el.getAttribute('name')) for el in
dom.getElementsByTagName('field')]
# These are 'restricted' types, rather than composite, so they
# do not have defined fields.
if self.desc in ['amqp:data:binary', 'amqp:amqp-sequence:list',
'amqp:amqp-value:*', 'amqp:application-properties:map',
'amqp:delivery-annotations:map',
'amqp:message-annotations:map', 'amqp:footer:map']:
self.fields = ['content']
def define(self):
return ('SYMBOL_%s' % self.name.upper(), self.desc)
class AMQPDefines:
def __init__(self, dom):
self.name = safe(dom.getAttribute('name'))
self.source = dom.getAttribute('source')
self.options = [(self.name.upper() + '_' +
(safe(el.getAttribute('name')).upper()),
el.getAttribute('value')) for el in
dom.getElementsByTagName('choice')]
def print_erl(types):
print("""-module(amqp10_framing0).
-export([record_for/1, fields/1, encode/1, symbol_for/1, number_for/1]).
-include("amqp10_framing.hrl").""")
for t in types:
print("""record_for({symbol, <<"%s">>}) ->
#'v1_0.%s'{};""" % (t.desc, t.name))
if t.code:
print("""record_for({_, %d}) ->
#'v1_0.%s'{};""" % (t.number, t.name))
print("%% %s\n" % t.code)
print("""record_for(Other) -> exit({unknown, Other}).
""")
for t in types:
print("""fields(#'v1_0.%s'{}) -> record_info(fields, 'v1_0.%s');""" % (t.name, t.name))
print("""fields(_Other) -> unknown.
""")
for t in types:
print("""encode(Frame = #'v1_0.%s'{}) ->
amqp10_framing:encode_described('%s', %s, Frame);""" % (t.name, t.source, t.number))
print("""encode(undefined) -> null;
encode(Other) -> Other.
""")
for t in types:
print("""symbol_for(#'v1_0.%s'{}) ->
{symbol, <<"%s">>};""" % (t.name, t.desc))
print("""symbol_for(Other) -> exit({unknown, Other}).
""")
for t in types:
print("""number_for(#'v1_0.%s'{}) ->
{ulong, %s};""" % (t.name, t.number))
print("""number_for(Other) -> exit({unknown, Other}).""")
def print_hrl(types, defines):
for t in types:
print("""-record('v1_0.%s', {%s}).""" % (t.name, ", ".join(t.fields)))
print_define(t.define(), 'symbol')
for d in defines:
if len(d.options) > 0:
print(""" %% %s""" % (d.name))
for opt in d.options:
print_define(opt, d.source)
print("""
-define(DESCRIBED, 0).
""")
def print_define(opt, source):
(name, value) = opt
if source == 'symbol':
quoted = '<<"%s">>' % value
else:
quoted = value
print("""-define(V_1_0_%s, {%s, %s}).""" % (name, source, quoted))
def want_type(el):
descriptors = el.getElementsByTagName('descriptor')
return len(descriptors) > 0
def want_define(el):
klass = el.getAttribute('class')
return klass == 'restricted'
def parse_code(code):
res = re.match('0x([0-9a-fA-F]{8,8}):0x([0-9a-fA-F]{8,8})', code)
return res and int(res.group(1) + res.group(2), 16)
types = []
defines = []
mode = sys.argv[1]
for file in sys.argv[2:]:
tree = parse(file)
types.extend([AMQPType(el) for el in tree.getElementsByTagName('type')
if want_type(el)])
defines.extend([AMQPDefines(el) for el in tree.getElementsByTagName('type')
if want_define(el)])
if mode == 'erl':
print_erl(types)
elif mode == 'hrl':
print_hrl(types, defines)
else:
raise "Mode != erl or hrl"
|