summaryrefslogtreecommitdiff
path: root/codegen.py
diff options
context:
space:
mode:
Diffstat (limited to 'codegen.py')
-rw-r--r--codegen.py595
1 files changed, 0 insertions, 595 deletions
diff --git a/codegen.py b/codegen.py
deleted file mode 100644
index b2356bbc..00000000
--- a/codegen.py
+++ /dev/null
@@ -1,595 +0,0 @@
-## The contents of this file are subject to the Mozilla Public License
-## Version 1.1 (the "License"); you may not use this file except in
-## compliance with the License. You may obtain a copy of the License
-## at http://www.mozilla.org/MPL/
-##
-## Software distributed under the License is distributed on an "AS IS"
-## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-## the License for the specific language governing rights and
-## limitations under the License.
-##
-## The Original Code is RabbitMQ.
-##
-## The Initial Developer of the Original Code is GoPivotal, Inc.
-## Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved.
-##
-
-from __future__ import nested_scopes
-
-import sys
-sys.path.append("../rabbitmq-codegen") # in case we're next to an experimental revision
-sys.path.append("codegen") # in case we're building from a distribution package
-
-from amqp_codegen import *
-import string
-import re
-
-# Coming up with a proper encoding of AMQP tables in JSON is too much
-# hassle at this stage. Given that the only default value we are
-# interested in is for the empty table, we only support that.
-def convertTable(d):
- if len(d) == 0:
- return "[]"
- else:
- raise Exception('Non-empty table defaults not supported ' + d)
-
-erlangDefaultValueTypeConvMap = {
- bool : lambda x: str(x).lower(),
- str : lambda x: "<<\"" + x + "\">>",
- int : lambda x: str(x),
- float : lambda x: str(x),
- dict: convertTable,
- unicode: lambda x: "<<\"" + x.encode("utf-8") + "\">>"
-}
-
-def erlangize(s):
- s = s.replace('-', '_')
- s = s.replace(' ', '_')
- return s
-
-AmqpMethod.erlangName = lambda m: "'" + erlangize(m.klass.name) + '.' + erlangize(m.name) + "'"
-
-AmqpClass.erlangName = lambda c: "'" + erlangize(c.name) + "'"
-
-def erlangConstantName(s):
- return '_'.join(re.split('[- ]', s.upper()))
-
-class PackedMethodBitField:
- def __init__(self, index):
- self.index = index
- self.domain = 'bit'
- self.contents = []
-
- def extend(self, f):
- self.contents.append(f)
-
- def count(self):
- return len(self.contents)
-
- def full(self):
- return self.count() == 8
-
-def multiLineFormat(things, prologue, separator, lineSeparator, epilogue, thingsPerLine = 4):
- r = [prologue]
- i = 0
- for t in things:
- if i != 0:
- if i % thingsPerLine == 0:
- r += [lineSeparator]
- else:
- r += [separator]
- r += [t]
- i += 1
- r += [epilogue]
- return "".join(r)
-
-def prettyType(typeName, subTypes, typesPerLine = 4):
- """Pretty print a type signature made up of many alternative subtypes"""
- sTs = multiLineFormat(subTypes,
- "( ", " | ", "\n | ", " )",
- thingsPerLine = typesPerLine)
- return "-type(%s ::\n %s)." % (typeName, sTs)
-
-def printFileHeader():
- print """%% Autogenerated code. Do not edit.
-%%
-%% The contents of this file are subject to the Mozilla Public License
-%% Version 1.1 (the "License"); you may not use this file except in
-%% compliance with the License. You may obtain a copy of the License
-%% at http://www.mozilla.org/MPL/
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and
-%% limitations under the License.
-%%
-%% The Original Code is RabbitMQ.
-%%
-%% The Initial Developer of the Original Code is GoPivotal, Inc.
-%% Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved.
-%%"""
-
-def genErl(spec):
- def erlType(domain):
- return erlangize(spec.resolveDomain(domain))
-
- def fieldTypeList(fields):
- return '[' + ', '.join([erlType(f.domain) for f in fields]) + ']'
-
- def fieldNameList(fields):
- return '[' + ', '.join([erlangize(f.name) for f in fields]) + ']'
-
- def fieldTempList(fields):
- return '[' + ', '.join(['F' + str(f.index) for f in fields]) + ']'
-
- def fieldMapList(fields):
- return ', '.join([erlangize(f.name) + " = F" + str(f.index) for f in fields])
-
- def genLookupMethodName(m):
- print "lookup_method_name({%d, %d}) -> %s;" % (m.klass.index, m.index, m.erlangName())
-
- def genLookupClassName(c):
- print "lookup_class_name(%d) -> %s;" % (c.index, c.erlangName())
-
- def genMethodId(m):
- print "method_id(%s) -> {%d, %d};" % (m.erlangName(), m.klass.index, m.index)
-
- def genMethodHasContent(m):
- print "method_has_content(%s) -> %s;" % (m.erlangName(), str(m.hasContent).lower())
-
- def genMethodIsSynchronous(m):
- hasNoWait = "nowait" in fieldNameList(m.arguments)
- if m.isSynchronous and hasNoWait:
- print "is_method_synchronous(#%s{nowait = NoWait}) -> not(NoWait);" % (m.erlangName())
- else:
- print "is_method_synchronous(#%s{}) -> %s;" % (m.erlangName(), str(m.isSynchronous).lower())
-
- def genMethodFieldTypes(m):
- """Not currently used - may be useful in future?"""
- print "method_fieldtypes(%s) -> %s;" % (m.erlangName(), fieldTypeList(m.arguments))
-
- def genMethodFieldNames(m):
- print "method_fieldnames(%s) -> %s;" % (m.erlangName(), fieldNameList(m.arguments))
-
- def packMethodFields(fields):
- packed = []
- bitfield = None
- for f in fields:
- if erlType(f.domain) == 'bit':
- if not(bitfield) or bitfield.full():
- bitfield = PackedMethodBitField(f.index)
- packed.append(bitfield)
- bitfield.extend(f)
- else:
- bitfield = None
- packed.append(f)
- return packed
-
- def methodFieldFragment(f):
- type = erlType(f.domain)
- p = 'F' + str(f.index)
- if type == 'shortstr':
- return p+'Len:8/unsigned, '+p+':'+p+'Len/binary'
- elif type == 'longstr':
- return p+'Len:32/unsigned, '+p+':'+p+'Len/binary'
- elif type == 'octet':
- return p+':8/unsigned'
- elif type == 'short':
- return p+':16/unsigned'
- elif type == 'long':
- return p+':32/unsigned'
- elif type == 'longlong':
- return p+':64/unsigned'
- elif type == 'timestamp':
- return p+':64/unsigned'
- elif type == 'bit':
- return p+'Bits:8'
- elif type == 'table':
- return p+'Len:32/unsigned, '+p+'Tab:'+p+'Len/binary'
-
- def genFieldPostprocessing(packed, hasContent):
- for f in packed:
- type = erlType(f.domain)
- if type == 'bit':
- for index in range(f.count()):
- print " F%d = ((F%dBits band %d) /= 0)," % \
- (f.index + index,
- f.index,
- 1 << index)
- elif type == 'table':
- print " F%d = rabbit_binary_parser:parse_table(F%dTab)," % \
- (f.index, f.index)
- # We skip the check on content-bearing methods for
- # speed. This is a sanity check, not a security thing.
- elif type == 'shortstr' and not hasContent:
- print " rabbit_binary_parser:assert_utf8(F%d)," % (f.index)
- else:
- pass
-
- def genMethodRecord(m):
- print "method_record(%s) -> #%s{};" % (m.erlangName(), m.erlangName())
-
- def genDecodeMethodFields(m):
- packedFields = packMethodFields(m.arguments)
- binaryPattern = ', '.join([methodFieldFragment(f) for f in packedFields])
- if binaryPattern:
- restSeparator = ', '
- else:
- restSeparator = ''
- recordConstructorExpr = '#%s{%s}' % (m.erlangName(), fieldMapList(m.arguments))
- print "decode_method_fields(%s, <<%s>>) ->" % (m.erlangName(), binaryPattern)
- genFieldPostprocessing(packedFields, m.hasContent)
- print " %s;" % (recordConstructorExpr,)
-
- def genDecodeProperties(c):
- def presentBin(fields):
- ps = ', '.join(['P' + str(f.index) + ':1' for f in fields])
- return '<<' + ps + ', _:%d, R0/binary>>' % (16 - len(fields),)
- def writePropFieldLine(field):
- i = str(field.index)
- if field.domain == 'bit':
- print " {F%s, R%s} = {P%s =/= 0, R%s}," % \
- (i, str(field.index + 1), i, i)
- else:
- print " {F%s, R%s} = if P%s =:= 0 -> {undefined, R%s}; true -> ?%s_VAL(R%s, L%s, V%s, X%s) end," % \
- (i, str(field.index + 1), i, i, erlType(field.domain).upper(), i, i, i, i)
-
- if len(c.fields) == 0:
- print "decode_properties(%d, <<>>) ->" % (c.index,)
- else:
- print ("decode_properties(%d, %s) ->" %
- (c.index, presentBin(c.fields)))
- for field in c.fields:
- writePropFieldLine(field)
- print " <<>> = %s," % ('R' + str(len(c.fields)))
- print " #'P_%s'{%s};" % (erlangize(c.name), fieldMapList(c.fields))
-
- def genFieldPreprocessing(packed):
- for f in packed:
- type = erlType(f.domain)
- if type == 'bit':
- print " F%dBits = (%s)," % \
- (f.index,
- ' bor '.join(['(bitvalue(F%d) bsl %d)' % (x.index, x.index - f.index)
- for x in f.contents]))
- elif type == 'table':
- print " F%dTab = rabbit_binary_generator:generate_table(F%d)," % (f.index, f.index)
- print " F%dLen = size(F%dTab)," % (f.index, f.index)
- elif type == 'shortstr':
- print " F%dLen = shortstr_size(F%d)," % (f.index, f.index)
- elif type == 'longstr':
- print " F%dLen = size(F%d)," % (f.index, f.index)
- else:
- pass
-
- def genEncodeMethodFields(m):
- packedFields = packMethodFields(m.arguments)
- print "encode_method_fields(#%s{%s}) ->" % (m.erlangName(), fieldMapList(m.arguments))
- genFieldPreprocessing(packedFields)
- print " <<%s>>;" % (', '.join([methodFieldFragment(f) for f in packedFields]))
-
- def genEncodeProperties(c):
- def presentBin(fields):
- ps = ', '.join(['P' + str(f.index) + ':1' for f in fields])
- return '<<' + ps + ', 0:%d>>' % (16 - len(fields),)
- def writePropFieldLine(field):
- i = str(field.index)
- if field.domain == 'bit':
- print " {P%s, R%s} = {F%s =:= 1, R%s}," % \
- (i, str(field.index + 1), i, i)
- else:
- print " {P%s, R%s} = if F%s =:= undefined -> {0, R%s}; true -> {1, [?%s_PROP(F%s, L%s) | R%s]} end," % \
- (i, str(field.index + 1), i, i, erlType(field.domain).upper(), i, i, i)
-
- print "encode_properties(#'P_%s'{%s}) ->" % (erlangize(c.name), fieldMapList(c.fields))
- if len(c.fields) == 0:
- print " <<>>;"
- else:
- print " R0 = [<<>>],"
- for field in c.fields:
- writePropFieldLine(field)
- print " list_to_binary([%s | lists:reverse(R%s)]);" % \
- (presentBin(c.fields), str(len(c.fields)))
-
- def messageConstantClass(cls):
- # We do this because 0.8 uses "soft error" and 8.1 uses "soft-error".
- return erlangConstantName(cls)
-
- def genLookupException(c,v,cls):
- mCls = messageConstantClass(cls)
- if mCls == 'SOFT_ERROR': genLookupException1(c,'false')
- elif mCls == 'HARD_ERROR': genLookupException1(c, 'true')
- elif mCls == '': pass
- else: raise Exception('Unknown constant class' + cls)
-
- def genLookupException1(c,hardErrorBoolStr):
- n = erlangConstantName(c)
- print 'lookup_amqp_exception(%s) -> {%s, ?%s, <<"%s">>};' % \
- (n.lower(), hardErrorBoolStr, n, n)
-
- def genAmqpException(c,v,cls):
- n = erlangConstantName(c)
- print 'amqp_exception(?%s) -> %s;' % \
- (n, n.lower())
-
- methods = spec.allMethods()
-
- printFileHeader()
- module = "rabbit_framing_amqp_%d_%d" % (spec.major, spec.minor)
- if spec.revision != 0:
- module = "%s_%d" % (module, spec.revision)
- if module == "rabbit_framing_amqp_8_0":
- module = "rabbit_framing_amqp_0_8"
- print "-module(%s)." % module
- print """-include("rabbit_framing.hrl").
-
--export([version/0]).
--export([lookup_method_name/1]).
--export([lookup_class_name/1]).
-
--export([method_id/1]).
--export([method_has_content/1]).
--export([is_method_synchronous/1]).
--export([method_record/1]).
--export([method_fieldnames/1]).
--export([decode_method_fields/2]).
--export([decode_properties/2]).
--export([encode_method_fields/1]).
--export([encode_properties/1]).
--export([lookup_amqp_exception/1]).
--export([amqp_exception/1]).
-
-"""
- print "%% Various types"
- print "-ifdef(use_specs)."
-
- print """-export_type([amqp_field_type/0, amqp_property_type/0,
- amqp_table/0, amqp_array/0, amqp_value/0,
- amqp_method_name/0, amqp_method/0, amqp_method_record/0,
- amqp_method_field_name/0, amqp_property_record/0,
- amqp_exception/0, amqp_exception_code/0, amqp_class_id/0]).
-
--type(amqp_field_type() ::
- 'longstr' | 'signedint' | 'decimal' | 'timestamp' |
- 'table' | 'byte' | 'double' | 'float' | 'long' |
- 'short' | 'bool' | 'binary' | 'void' | 'array').
--type(amqp_property_type() ::
- 'shortstr' | 'longstr' | 'octet' | 'short' | 'long' |
- 'longlong' | 'timestamp' | 'bit' | 'table').
-
--type(amqp_table() :: [{binary(), amqp_field_type(), amqp_value()}]).
--type(amqp_array() :: [{amqp_field_type(), amqp_value()}]).
--type(amqp_value() :: binary() | % longstr
- integer() | % signedint
- {non_neg_integer(), non_neg_integer()} | % decimal
- amqp_table() |
- amqp_array() |
- byte() | % byte
- float() | % double
- integer() | % long
- integer() | % short
- boolean() | % bool
- binary() | % binary
- 'undefined' | % void
- non_neg_integer() % timestamp
- ).
-"""
-
- print prettyType("amqp_method_name()",
- [m.erlangName() for m in methods])
- print prettyType("amqp_method()",
- ["{%s, %s}" % (m.klass.index, m.index) for m in methods],
- 6)
- print prettyType("amqp_method_record()",
- ["#%s{}" % (m.erlangName()) for m in methods])
- fieldNames = set()
- for m in methods:
- fieldNames.update(m.arguments)
- fieldNames = [erlangize(f.name) for f in fieldNames]
- print prettyType("amqp_method_field_name()",
- fieldNames)
- print prettyType("amqp_property_record()",
- ["#'P_%s'{}" % erlangize(c.name) for c in spec.allClasses()])
- print prettyType("amqp_exception()",
- ["'%s'" % erlangConstantName(c).lower() for (c, v, cls) in spec.constants])
- print prettyType("amqp_exception_code()",
- ["%i" % v for (c, v, cls) in spec.constants])
- classIds = set()
- for m in spec.allMethods():
- classIds.add(m.klass.index)
- print prettyType("amqp_class_id()",
- ["%i" % ci for ci in classIds])
- print prettyType("amqp_class_name()",
- ["%s" % c.erlangName() for c in spec.allClasses()])
- print "-endif. % use_specs"
-
- print """
-%% Method signatures
--ifdef(use_specs).
--spec(version/0 :: () -> {non_neg_integer(), non_neg_integer(), non_neg_integer()}).
--spec(lookup_method_name/1 :: (amqp_method()) -> amqp_method_name()).
--spec(lookup_class_name/1 :: (amqp_class_id()) -> amqp_class_name()).
--spec(method_id/1 :: (amqp_method_name()) -> amqp_method()).
--spec(method_has_content/1 :: (amqp_method_name()) -> boolean()).
--spec(is_method_synchronous/1 :: (amqp_method_record()) -> boolean()).
--spec(method_record/1 :: (amqp_method_name()) -> amqp_method_record()).
--spec(method_fieldnames/1 :: (amqp_method_name()) -> [amqp_method_field_name()]).
--spec(decode_method_fields/2 ::
- (amqp_method_name(), binary()) -> amqp_method_record() | rabbit_types:connection_exit()).
--spec(decode_properties/2 :: (non_neg_integer(), binary()) -> amqp_property_record()).
--spec(encode_method_fields/1 :: (amqp_method_record()) -> binary()).
--spec(encode_properties/1 :: (amqp_property_record()) -> binary()).
--spec(lookup_amqp_exception/1 :: (amqp_exception()) -> {boolean(), amqp_exception_code(), binary()}).
--spec(amqp_exception/1 :: (amqp_exception_code()) -> amqp_exception()).
--endif. % use_specs
-
-bitvalue(true) -> 1;
-bitvalue(false) -> 0;
-bitvalue(undefined) -> 0.
-
-shortstr_size(S) ->
- case size(S) of
- Len when Len =< 255 -> Len;
- _ -> exit(method_field_shortstr_overflow)
- end.
-
--define(SHORTSTR_VAL(R, L, V, X),
- begin
- <<L:8/unsigned, V:L/binary, X/binary>> = R,
- {V, X}
- end).
-
--define(LONGSTR_VAL(R, L, V, X),
- begin
- <<L:32/unsigned, V:L/binary, X/binary>> = R,
- {V, X}
- end).
-
--define(SHORT_VAL(R, L, V, X),
- begin
- <<V:8/unsigned, X/binary>> = R,
- {V, X}
- end).
-
--define(LONG_VAL(R, L, V, X),
- begin
- <<V:32/unsigned, X/binary>> = R,
- {V, X}
- end).
-
--define(LONGLONG_VAL(R, L, V, X),
- begin
- <<V:64/unsigned, X/binary>> = R,
- {V, X}
- end).
-
--define(OCTET_VAL(R, L, V, X),
- begin
- <<V:8/unsigned, X/binary>> = R,
- {V, X}
- end).
-
--define(TABLE_VAL(R, L, V, X),
- begin
- <<L:32/unsigned, V:L/binary, X/binary>> = R,
- {rabbit_binary_parser:parse_table(V), X}
- end).
-
--define(TIMESTAMP_VAL(R, L, V, X),
- begin
- <<V:64/unsigned, X/binary>> = R,
- {V, X}
- end).
-
--define(SHORTSTR_PROP(X, L),
- begin
- L = size(X),
- if L < 256 -> <<L:8, X:L/binary>>;
- true -> exit(content_properties_shortstr_overflow)
- end
- end).
-
--define(LONGSTR_PROP(X, L),
- begin
- L = size(X),
- <<L:32, X:L/binary>>
- end).
-
--define(OCTET_PROP(X, L), <<X:8/unsigned>>).
--define(SHORT_PROP(X, L), <<X:16/unsigned>>).
--define(LONG_PROP(X, L), <<X:32/unsigned>>).
--define(LONGLONG_PROP(X, L), <<X:64/unsigned>>).
--define(TIMESTAMP_PROP(X, L), <<X:64/unsigned>>).
-
--define(TABLE_PROP(X, T),
- begin
- T = rabbit_binary_generator:generate_table(X),
- <<(size(T)):32, T/binary>>
- end).
-"""
- version = "{%d, %d, %d}" % (spec.major, spec.minor, spec.revision)
- if version == '{8, 0, 0}': version = '{0, 8, 0}'
- print "version() -> %s." % (version)
-
- for m in methods: genLookupMethodName(m)
- print "lookup_method_name({_ClassId, _MethodId} = Id) -> exit({unknown_method_id, Id})."
-
- for c in spec.allClasses(): genLookupClassName(c)
- print "lookup_class_name(ClassId) -> exit({unknown_class_id, ClassId})."
-
- for m in methods: genMethodId(m)
- print "method_id(Name) -> exit({unknown_method_name, Name})."
-
- for m in methods: genMethodHasContent(m)
- print "method_has_content(Name) -> exit({unknown_method_name, Name})."
-
- for m in methods: genMethodIsSynchronous(m)
- print "is_method_synchronous(Name) -> exit({unknown_method_name, Name})."
-
- for m in methods: genMethodRecord(m)
- print "method_record(Name) -> exit({unknown_method_name, Name})."
-
- for m in methods: genMethodFieldNames(m)
- print "method_fieldnames(Name) -> exit({unknown_method_name, Name})."
-
- for m in methods: genDecodeMethodFields(m)
- print "decode_method_fields(Name, BinaryFields) ->"
- print " rabbit_misc:frame_error(Name, BinaryFields)."
-
- for c in spec.allClasses(): genDecodeProperties(c)
- print "decode_properties(ClassId, _BinaryFields) -> exit({unknown_class_id, ClassId})."
-
- for m in methods: genEncodeMethodFields(m)
- print "encode_method_fields(Record) -> exit({unknown_method_name, element(1, Record)})."
-
- for c in spec.allClasses(): genEncodeProperties(c)
- print "encode_properties(Record) -> exit({unknown_properties_record, Record})."
-
- for (c,v,cls) in spec.constants: genLookupException(c,v,cls)
- print "lookup_amqp_exception(Code) ->"
- print " rabbit_log:warning(\"Unknown AMQP error code '~p'~n\", [Code]),"
- print " {true, ?INTERNAL_ERROR, <<\"INTERNAL_ERROR\">>}."
-
- for(c,v,cls) in spec.constants: genAmqpException(c,v,cls)
- print "amqp_exception(_Code) -> undefined."
-
-def genHrl(spec):
- def fieldNameList(fields):
- return ', '.join([erlangize(f.name) for f in fields])
-
- def fieldNameListDefaults(fields):
- def fillField(field):
- result = erlangize(f.name)
- if field.defaultvalue != None:
- conv_fn = erlangDefaultValueTypeConvMap[type(field.defaultvalue)]
- result += ' = ' + conv_fn(field.defaultvalue)
- return result
- return ', '.join([fillField(f) for f in fields])
-
- methods = spec.allMethods()
-
- printFileHeader()
- print "-define(PROTOCOL_PORT, %d)." % (spec.port)
-
- for (c,v,cls) in spec.constants:
- print "-define(%s, %s)." % (erlangConstantName(c), v)
-
- print "%% Method field records."
- for m in methods:
- print "-record(%s, {%s})." % (m.erlangName(), fieldNameListDefaults(m.arguments))
-
- print "%% Class property records."
- for c in spec.allClasses():
- print "-record('P_%s', {%s})." % (erlangize(c.name), fieldNameList(c.fields))
-
-
-def generateErl(specPath):
- genErl(AmqpSpec(specPath))
-
-def generateHrl(specPath):
- genHrl(AmqpSpec(specPath))
-
-if __name__ == "__main__":
- do_main_dict({"header": generateHrl,
- "body": generateErl})
-