Back to index

rabbitmq-server  2.8.4
Classes | Functions | Variables
codegen Namespace Reference

Classes

class  PackedMethodBitField

Functions

def convertTable
def erlangize
def erlangConstantName
def multiLineFormat
def prettyType
def printFileHeader
def genErl
def genHrl
def generateErl
def generateHrl

Variables

dictionary erlangTypeMap
dictionary erlangDefaultValueTypeConvMap

Function Documentation

def codegen.convertTable (   d)

Definition at line 42 of file codegen.py.

00042 
00043 def convertTable(d):
00044     if len(d) == 0:
00045         return "[]"
00046     else:
00047         raise Exception('Non-empty table defaults not supported ' + d)

Definition at line 66 of file codegen.py.

00066 
00067 def erlangConstantName(s):
00068     return '_'.join(re.split('[- ]', s.upper()))

Here is the caller graph for this function:

def codegen.erlangize (   s)

Definition at line 57 of file codegen.py.

00057 
00058 def erlangize(s):
00059     s = s.replace('-', '_')
00060     s = s.replace(' ', '_')
00061     return s
00062 
00063 AmqpMethod.erlangName = lambda m: "'" + erlangize(m.klass.name) + '.' + erlangize(m.name) + "'"
00064 
00065 AmqpClass.erlangName = lambda c: "'" + erlangize(c.name) + "'"

Here is the caller graph for this function:

def codegen.generateErl (   specPath)

Definition at line 532 of file codegen.py.

00532 
00533 def generateErl(specPath):
00534     genErl(AmqpSpec(specPath))

Here is the call graph for this function:

def codegen.generateHrl (   specPath)

Definition at line 535 of file codegen.py.

00535 
00536 def generateHrl(specPath):
00537     genHrl(AmqpSpec(specPath))

Here is the call graph for this function:

def codegen.genErl (   spec)

Definition at line 124 of file codegen.py.

00124 
00125 def genErl(spec):
00126     def erlType(domain):
00127         return erlangTypeMap[spec.resolveDomain(domain)]
00128 
00129     def fieldTypeList(fields):
00130         return '[' + ', '.join([erlType(f.domain) for f in fields]) + ']'
00131 
00132     def fieldNameList(fields):
00133         return '[' + ', '.join([erlangize(f.name) for f in fields]) + ']'
00134 
00135     def fieldTempList(fields):
00136         return '[' + ', '.join(['F' + str(f.index) for f in fields]) + ']'
00137 
00138     def fieldMapList(fields):
00139         return ', '.join([erlangize(f.name) + " = F" + str(f.index) for f in fields])
00140 
00141     def genLookupMethodName(m):
00142         print "lookup_method_name({%d, %d}) -> %s;" % (m.klass.index, m.index, m.erlangName())
00143 
00144     def genLookupClassName(c):
00145         print "lookup_class_name(%d) -> %s;" % (c.index, c.erlangName())
00146 
00147     def genMethodId(m):
00148         print "method_id(%s) -> {%d, %d};" % (m.erlangName(), m.klass.index, m.index)
00149 
00150     def genMethodHasContent(m):
00151         print "method_has_content(%s) -> %s;" % (m.erlangName(), str(m.hasContent).lower())
00152 
00153     def genMethodIsSynchronous(m):
00154         hasNoWait = "nowait" in fieldNameList(m.arguments)
00155         if m.isSynchronous and hasNoWait:
00156           print "is_method_synchronous(#%s{nowait = NoWait}) -> not(NoWait);" % (m.erlangName())
00157         else:
00158           print "is_method_synchronous(#%s{}) -> %s;" % (m.erlangName(), str(m.isSynchronous).lower())
00159 
00160     def genMethodFieldTypes(m):
00161         """Not currently used - may be useful in future?"""
00162         print "method_fieldtypes(%s) -> %s;" % (m.erlangName(), fieldTypeList(m.arguments))
00163 
00164     def genMethodFieldNames(m):
00165         print "method_fieldnames(%s) -> %s;" % (m.erlangName(), fieldNameList(m.arguments))
00166 
00167     def packMethodFields(fields):
00168         packed = []
00169         bitfield = None
00170         for f in fields:
00171             if erlType(f.domain) == 'bit':
00172                 if not(bitfield) or bitfield.full():
00173                     bitfield = PackedMethodBitField(f.index)
00174                     packed.append(bitfield)
00175                 bitfield.extend(f)
00176             else:
00177                 bitfield = None
00178                 packed.append(f)
00179         return packed
00180 
00181     def methodFieldFragment(f):
00182         type = erlType(f.domain)
00183         p = 'F' + str(f.index)
00184         if type == 'shortstr':
00185             return p+'Len:8/unsigned, '+p+':'+p+'Len/binary'
00186         elif type == 'longstr':
00187             return p+'Len:32/unsigned, '+p+':'+p+'Len/binary'
00188         elif type == 'octet':
00189             return p+':8/unsigned'
00190         elif type == 'shortint':
00191             return p+':16/unsigned'
00192         elif type == 'longint':
00193             return p+':32/unsigned'
00194         elif type == 'longlongint':
00195             return p+':64/unsigned'
00196         elif type == 'timestamp':
00197             return p+':64/unsigned'
00198         elif type == 'bit':
00199             return p+'Bits:8'
00200         elif type == 'table':
00201             return p+'Len:32/unsigned, '+p+'Tab:'+p+'Len/binary'
00202 
00203     def genFieldPostprocessing(packed):
00204         for f in packed:
00205             type = erlType(f.domain)
00206             if type == 'bit':
00207                 for index in range(f.count()):
00208                     print "  F%d = ((F%dBits band %d) /= 0)," % \
00209                           (f.index + index,
00210                            f.index,
00211                            1 << index)
00212             elif type == 'table':
00213                 print "  F%d = rabbit_binary_parser:parse_table(F%dTab)," % \
00214                       (f.index, f.index)
00215             else:
00216                 pass
00217 
00218     def genMethodRecord(m):
00219         print "method_record(%s) -> #%s{};" % (m.erlangName(), m.erlangName())
00220 
00221     def genDecodeMethodFields(m):
00222         packedFields = packMethodFields(m.arguments)
00223         binaryPattern = ', '.join([methodFieldFragment(f) for f in packedFields])
00224         if binaryPattern:
00225             restSeparator = ', '
00226         else:
00227             restSeparator = ''
00228         recordConstructorExpr = '#%s{%s}' % (m.erlangName(), fieldMapList(m.arguments))
00229         print "decode_method_fields(%s, <<%s>>) ->" % (m.erlangName(), binaryPattern)
00230         genFieldPostprocessing(packedFields)
00231         print "  %s;" % (recordConstructorExpr,)
00232 
00233     def genDecodeProperties(c):
00234         def presentBin(fields):
00235             ps = ', '.join(['P' + str(f.index) + ':1' for f in fields])
00236             return '<<' + ps + ', _:%d, R0/binary>>' % (16 - len(fields),)
00237         def mkMacroName(field):
00238             return '?' + field.domain.upper() + '_PROP'
00239         def writePropFieldLine(field, bin_next = None):
00240             i = str(field.index)
00241             if not bin_next:
00242                 bin_next = 'R' + str(field.index + 1)
00243             if field.domain in ['octet', 'timestamp']:
00244                 print ("  {%s, %s} = %s(%s, %s, %s, %s)," %
00245                        ('F' + i, bin_next, mkMacroName(field), 'P' + i,
00246                         'R' + i, 'I' + i, 'X' + i))
00247             else:
00248                 print ("  {%s, %s} = %s(%s, %s, %s, %s, %s)," %
00249                        ('F' + i, bin_next, mkMacroName(field), 'P' + i,
00250                         'R' + i, 'L' + i, 'S' + i, 'X' + i))
00251 
00252         if len(c.fields) == 0:
00253             print "decode_properties(%d, _) ->" % (c.index,)
00254         else:
00255             print ("decode_properties(%d, %s) ->" %
00256                    (c.index, presentBin(c.fields)))
00257             for field in c.fields[:-1]:
00258                 writePropFieldLine(field)
00259             writePropFieldLine(c.fields[-1], "<<>>")
00260         print "  #'P_%s'{%s};" % (erlangize(c.name), fieldMapList(c.fields))
00261 
00262     def genFieldPreprocessing(packed):
00263         for f in packed:
00264             type = erlType(f.domain)
00265             if type == 'bit':
00266                 print "  F%dBits = (%s)," % \
00267                       (f.index,
00268                        ' bor '.join(['(bitvalue(F%d) bsl %d)' % (x.index, x.index - f.index)
00269                                      for x in f.contents]))
00270             elif type == 'table':
00271                 print "  F%dTab = rabbit_binary_generator:generate_table(F%d)," % (f.index, f.index)
00272                 print "  F%dLen = size(F%dTab)," % (f.index, f.index)
00273             elif type == 'shortstr':
00274                 print "  F%dLen = shortstr_size(F%d)," % (f.index, f.index)
00275             elif type == 'longstr':
00276                 print "  F%dLen = size(F%d)," % (f.index, f.index)
00277             else:
00278                 pass
00279 
00280     def genEncodeMethodFields(m):
00281         packedFields = packMethodFields(m.arguments)
00282         print "encode_method_fields(#%s{%s}) ->" % (m.erlangName(), fieldMapList(m.arguments))
00283         genFieldPreprocessing(packedFields)
00284         print "  <<%s>>;" % (', '.join([methodFieldFragment(f) for f in packedFields]))
00285 
00286     def genEncodeProperties(c):
00287         print "encode_properties(#'P_%s'{%s}) ->" % (erlangize(c.name), fieldMapList(c.fields))
00288         print "  rabbit_binary_generator:encode_properties(%s, %s);" % \
00289               (fieldTypeList(c.fields), fieldTempList(c.fields))
00290 
00291     def messageConstantClass(cls):
00292         # We do this because 0.8 uses "soft error" and 8.1 uses "soft-error".
00293         return erlangConstantName(cls)
00294 
00295     def genLookupException(c,v,cls):
00296         mCls = messageConstantClass(cls)
00297         if mCls == 'SOFT_ERROR': genLookupException1(c,'false')
00298         elif mCls == 'HARD_ERROR': genLookupException1(c, 'true')
00299         elif mCls == '': pass
00300         else: raise Exception('Unknown constant class' + cls)
00301 
00302     def genLookupException1(c,hardErrorBoolStr):
00303         n = erlangConstantName(c)
00304         print 'lookup_amqp_exception(%s) -> {%s, ?%s, <<"%s">>};' % \
00305               (n.lower(), hardErrorBoolStr, n, n)
00306 
00307     def genAmqpException(c,v,cls):
00308         n = erlangConstantName(c)
00309         print 'amqp_exception(?%s) -> %s;' % \
00310             (n, n.lower())
00311 
00312     methods = spec.allMethods()
00313 
00314     printFileHeader()
00315     module = "rabbit_framing_amqp_%d_%d" % (spec.major, spec.minor)
00316     if spec.revision != 0:
00317         module = "%s_%d" % (module, spec.revision)
00318     if module == "rabbit_framing_amqp_8_0":
00319         module = "rabbit_framing_amqp_0_8"
00320     print "-module(%s)." % module
00321     print """-include("rabbit_framing.hrl").
00322 
00323 -export([version/0]).
00324 -export([lookup_method_name/1]).
00325 -export([lookup_class_name/1]).
00326 
00327 -export([method_id/1]).
00328 -export([method_has_content/1]).
00329 -export([is_method_synchronous/1]).
00330 -export([method_record/1]).
00331 -export([method_fieldnames/1]).
00332 -export([decode_method_fields/2]).
00333 -export([decode_properties/2]).
00334 -export([encode_method_fields/1]).
00335 -export([encode_properties/1]).
00336 -export([lookup_amqp_exception/1]).
00337 -export([amqp_exception/1]).
00338 
00339 """
00340     print "%% Various types"
00341     print "-ifdef(use_specs)."
00342 
00343     print """-export_type([amqp_field_type/0, amqp_property_type/0,
00344               amqp_table/0, amqp_array/0, amqp_value/0,
00345               amqp_method_name/0, amqp_method/0, amqp_method_record/0,
00346               amqp_method_field_name/0, amqp_property_record/0,
00347               amqp_exception/0, amqp_exception_code/0, amqp_class_id/0]).
00348 
00349 -type(amqp_field_type() ::
00350       'longstr' | 'signedint' | 'decimal' | 'timestamp' |
00351       'table' | 'byte' | 'double' | 'float' | 'long' |
00352       'short' | 'bool' | 'binary' | 'void' | 'array').
00353 -type(amqp_property_type() ::
00354       'shortstr' | 'longstr' | 'octet' | 'shortint' | 'longint' |
00355       'longlongint' | 'timestamp' | 'bit' | 'table').
00356 
00357 -type(amqp_table() :: [{binary(), amqp_field_type(), amqp_value()}]).
00358 -type(amqp_array() :: [{amqp_field_type(), amqp_value()}]).
00359 -type(amqp_value() :: binary() |    % longstr
00360                       integer() |   % signedint
00361                       {non_neg_integer(), non_neg_integer()} | % decimal
00362                       amqp_table() |
00363                       amqp_array() |
00364                       byte() |      % byte
00365                       float() |     % double
00366                       integer() |   % long
00367                       integer() |   % short
00368                       boolean() |   % bool
00369                       binary() |    % binary
00370                       'undefined' | % void
00371                       non_neg_integer() % timestamp
00372      ).
00373 """
00374 
00375     print prettyType("amqp_method_name()",
00376                      [m.erlangName() for m in methods])
00377     print prettyType("amqp_method()",
00378                      ["{%s, %s}" % (m.klass.index, m.index) for m in methods],
00379                      6)
00380     print prettyType("amqp_method_record()",
00381                      ["#%s{}" % (m.erlangName()) for m in methods])
00382     fieldNames = set()
00383     for m in methods:
00384         fieldNames.update(m.arguments)
00385     fieldNames = [erlangize(f.name) for f in fieldNames]
00386     print prettyType("amqp_method_field_name()",
00387                      fieldNames)
00388     print prettyType("amqp_property_record()",
00389                      ["#'P_%s'{}" % erlangize(c.name) for c in spec.allClasses()])
00390     print prettyType("amqp_exception()",
00391                      ["'%s'" % erlangConstantName(c).lower() for (c, v, cls) in spec.constants])
00392     print prettyType("amqp_exception_code()",
00393                      ["%i" % v for (c, v, cls) in spec.constants])
00394     classIds = set()
00395     for m in spec.allMethods():
00396         classIds.add(m.klass.index)
00397     print prettyType("amqp_class_id()",
00398                      ["%i" % ci for ci in classIds])
00399     print prettyType("amqp_class_name()",
00400                      ["%s" % c.erlangName() for c in spec.allClasses()])
00401     print "-endif. % use_specs"
00402 
00403     print """
00404 %% Method signatures
00405 -ifdef(use_specs).
00406 -spec(version/0 :: () -> {non_neg_integer(), non_neg_integer(), non_neg_integer()}).
00407 -spec(lookup_method_name/1 :: (amqp_method()) -> amqp_method_name()).
00408 -spec(lookup_class_name/1 :: (amqp_class_id()) -> amqp_class_name()).
00409 -spec(method_id/1 :: (amqp_method_name()) -> amqp_method()).
00410 -spec(method_has_content/1 :: (amqp_method_name()) -> boolean()).
00411 -spec(is_method_synchronous/1 :: (amqp_method_record()) -> boolean()).
00412 -spec(method_record/1 :: (amqp_method_name()) -> amqp_method_record()).
00413 -spec(method_fieldnames/1 :: (amqp_method_name()) -> [amqp_method_field_name()]).
00414 -spec(decode_method_fields/2 ::
00415         (amqp_method_name(), binary()) -> amqp_method_record() | rabbit_types:connection_exit()).
00416 -spec(decode_properties/2 :: (non_neg_integer(), binary()) -> amqp_property_record()).
00417 -spec(encode_method_fields/1 :: (amqp_method_record()) -> binary()).
00418 -spec(encode_properties/1 :: (amqp_property_record()) -> binary()).
00419 -spec(lookup_amqp_exception/1 :: (amqp_exception()) -> {boolean(), amqp_exception_code(), binary()}).
00420 -spec(amqp_exception/1 :: (amqp_exception_code()) -> amqp_exception()).
00421 -endif. % use_specs
00422 
00423 bitvalue(true) -> 1;
00424 bitvalue(false) -> 0;
00425 bitvalue(undefined) -> 0.
00426 
00427 shortstr_size(S) ->
00428     case size(S) of
00429         Len when Len =< 255 -> Len;
00430         _                   -> exit(method_field_shortstr_overflow)
00431     end.
00432 
00433 -define(SHORTSTR_PROP(P, R, L, S, X),
00434         if P =:= 0 -> {undefined, R};
00435            true    -> <<L:8/unsigned, S:L/binary, X/binary>> = R,
00436                       {S, X}
00437         end).
00438 -define(TABLE_PROP(P, R, L, T, X),
00439         if P =:= 0 -> {undefined, R};
00440            true    -> <<L:32/unsigned, T:L/binary, X/binary>> = R,
00441                       {rabbit_binary_parser:parse_table(T), X}
00442         end).
00443 -define(OCTET_PROP(P, R, I, X),
00444         if P =:= 0 -> {undefined, R};
00445            true    -> <<I:8/unsigned, X/binary>> = R,
00446                       {I, X}
00447         end).
00448 -define(TIMESTAMP_PROP(P, R, I, X),
00449         if P =:= 0 -> {undefined, R};
00450            true    -> <<I:64/unsigned, X/binary>> = R,
00451                       {I, X}
00452         end).
00453 """
00454     version = "{%d, %d, %d}" % (spec.major, spec.minor, spec.revision)
00455     if version == '{8, 0, 0}': version = '{0, 8, 0}'
00456     print "version() -> %s." % (version)
00457 
00458     for m in methods: genLookupMethodName(m)
00459     print "lookup_method_name({_ClassId, _MethodId} = Id) -> exit({unknown_method_id, Id})."
00460 
00461     for c in spec.allClasses(): genLookupClassName(c)
00462     print "lookup_class_name(ClassId) -> exit({unknown_class_id, ClassId})."
00463 
00464     for m in methods: genMethodId(m)
00465     print "method_id(Name) -> exit({unknown_method_name, Name})."
00466 
00467     for m in methods: genMethodHasContent(m)
00468     print "method_has_content(Name) -> exit({unknown_method_name, Name})."
00469 
00470     for m in methods: genMethodIsSynchronous(m)
00471     print "is_method_synchronous(Name) -> exit({unknown_method_name, Name})."
00472 
00473     for m in methods: genMethodRecord(m)
00474     print "method_record(Name) -> exit({unknown_method_name, Name})."
00475 
00476     for m in methods: genMethodFieldNames(m)
00477     print "method_fieldnames(Name) -> exit({unknown_method_name, Name})."
00478 
00479     for m in methods: genDecodeMethodFields(m)
00480     print "decode_method_fields(Name, BinaryFields) ->"
00481     print "  rabbit_misc:frame_error(Name, BinaryFields)."
00482 
00483     for c in spec.allClasses(): genDecodeProperties(c)
00484     print "decode_properties(ClassId, _BinaryFields) -> exit({unknown_class_id, ClassId})."
00485 
00486     for m in methods: genEncodeMethodFields(m)
00487     print "encode_method_fields(Record) -> exit({unknown_method_name, element(1, Record)})."
00488 
00489     for c in spec.allClasses(): genEncodeProperties(c)
00490     print "encode_properties(Record) -> exit({unknown_properties_record, Record})."
00491 
00492     for (c,v,cls) in spec.constants: genLookupException(c,v,cls)
00493     print "lookup_amqp_exception(Code) ->"
00494     print "  rabbit_log:warning(\"Unknown AMQP error code '~p'~n\", [Code]),"
00495     print "  {true, ?INTERNAL_ERROR, <<\"INTERNAL_ERROR\">>}."
00496 
00497     for(c,v,cls) in spec.constants: genAmqpException(c,v,cls)
00498     print "amqp_exception(_Code) -> undefined."

Here is the call graph for this function:

Here is the caller graph for this function:

def codegen.genHrl (   spec)

Definition at line 499 of file codegen.py.

00499 
00500 def genHrl(spec):
00501     def erlType(domain):
00502         return erlangTypeMap[spec.resolveDomain(domain)]
00503 
00504     def fieldNameList(fields):
00505         return ', '.join([erlangize(f.name) for f in fields])
00506 
00507     def fieldNameListDefaults(fields):
00508         def fillField(field):
00509             result = erlangize(f.name)
00510             if field.defaultvalue != None:
00511                 conv_fn = erlangDefaultValueTypeConvMap[type(field.defaultvalue)]
00512                 result += ' = ' + conv_fn(field.defaultvalue)
00513             return result
00514         return ', '.join([fillField(f) for f in fields])
00515 
00516     methods = spec.allMethods()
00517 
00518     printFileHeader()
00519     print "-define(PROTOCOL_PORT, %d)." % (spec.port)
00520 
00521     for (c,v,cls) in spec.constants:
00522         print "-define(%s, %s)." % (erlangConstantName(c), v)
00523 
00524     print "%% Method field records."
00525     for m in methods:
00526         print "-record(%s, {%s})." % (m.erlangName(), fieldNameListDefaults(m.arguments))
00527 
00528     print "%% Class property records."
00529     for c in spec.allClasses():
00530         print "-record('P_%s', {%s})." % (erlangize(c.name), fieldNameList(c.fields))
00531 

Here is the call graph for this function:

Here is the caller graph for this function:

def codegen.multiLineFormat (   things,
  prologue,
  separator,
  lineSeparator,
  epilogue,
  thingsPerLine = 4 
)

Definition at line 84 of file codegen.py.

00084 
00085 def multiLineFormat(things, prologue, separator, lineSeparator, epilogue, thingsPerLine = 4):
00086     r = [prologue]
00087     i = 0
00088     for t in things:
00089         if i != 0:
00090             if i % thingsPerLine == 0:
00091                 r += [lineSeparator]
00092             else:
00093                 r += [separator]
00094         r += [t]
00095         i += 1
00096     r += [epilogue]
00097     return "".join(r)

Here is the caller graph for this function:

def codegen.prettyType (   typeName,
  subTypes,
  typesPerLine = 4 
)
Pretty print a type signature made up of many alternative subtypes

Definition at line 98 of file codegen.py.

00098 
00099 def prettyType(typeName, subTypes, typesPerLine = 4):
00100     """Pretty print a type signature made up of many alternative subtypes"""
00101     sTs = multiLineFormat(subTypes,
00102                           "( ", " | ", "\n       | ", " )",
00103                           thingsPerLine = typesPerLine)
00104     return "-type(%s ::\n       %s)." % (typeName, sTs)

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 105 of file codegen.py.

00105 
00106 def printFileHeader():
00107     print """%%   Autogenerated code. Do not edit.
00108 %%
00109 %%  The contents of this file are subject to the Mozilla Public License
00110 %%  Version 1.1 (the "License"); you may not use this file except in
00111 %%  compliance with the License. You may obtain a copy of the License
00112 %%  at http://www.mozilla.org/MPL/
00113 %%
00114 %%  Software distributed under the License is distributed on an "AS IS"
00115 %%  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
00116 %%  the License for the specific language governing rights and
00117 %%  limitations under the License.
00118 %%
00119 %%  The Original Code is RabbitMQ.
00120 %%
00121 %%  The Initial Developer of the Original Code is VMware, Inc.
00122 %%  Copyright (c) 2007-2012 VMware, Inc.  All rights reserved.
00123 %%"""

Here is the caller graph for this function:


Variable Documentation

Initial value:
00001 {
00002     bool : lambda x: str(x).lower(),
00003     str : lambda x: "<<\"" + x + "\">>",
00004     int : lambda x: str(x),
00005     float : lambda x: str(x),
00006     dict: convertTable,
00007     unicode: lambda x: "<<\"" + x.encode("utf-8") + "\">>"
00008 }

Definition at line 48 of file codegen.py.

Initial value:
00001 {
00002     'octet': 'octet',
00003     'shortstr': 'shortstr',
00004     'longstr': 'longstr',
00005     'short': 'shortint',
00006     'long': 'longint',
00007     'longlong': 'longlongint',
00008     'bit': 'bit',
00009     'table': 'table',
00010     'timestamp': 'timestamp',
00011 }

Definition at line 27 of file codegen.py.