frontend: add support for discrimiator fields
In an abstract base class (e.g., of_action), the dicriminator field
represents the field that distinguishes between different type of
subclasses. It is marked in the base class with a '== ?', as in
uint32_t type == ?
Each class may only define at most one discriminator field.
diff --git a/loxi_front_end/frontend.py b/loxi_front_end/frontend.py
index bba941c..70699e0 100644
--- a/loxi_front_end/frontend.py
+++ b/loxi_front_end/frontend.py
@@ -46,6 +46,8 @@
return OFFieldLengthMember(name=m_ast[2], oftype=m_ast[1], field_name='actions')
else:
return OFDataMember(name=m_ast[2], oftype=m_ast[1])
+ elif m_ast[0] == 'discriminator':
+ return OFDiscriminatorMember(name=m_ast[2], oftype=m_ast[1])
else:
raise Exception("Dont know how to create member: %s" % m_ast[0])
@@ -65,11 +67,17 @@
# 0: "enum"
# 1: name
# 2: potentially list of [param_name, param_value]
- # 3: super_class
+ # 3: super_class or None
# 4: list of [constant_name, constant_value]+
- super_class = decl_ast[3]
+ superclass = decl_ast[3]
members = [create_member(m_ast) for m_ast in decl_ast[4]]
- ofclass = OFClass(name=decl_ast[1], members=members, super_class=super_class,
+
+ discriminators = [ m for m in members if isinstance(m, OFDiscriminatorMember) ]
+ if len(discriminators) > 1:
+ raise Exception("%s: Cannot support more than one discriminator by class - got %s" %
+ (decl_ast[1], repr(discriminators)))
+ ofclass = OFClass(name=decl_ast[1], members=members, superclass=superclass,
+ virtual = len(discriminators) > 0,
params = { param: value for param, value in decl_ast[2] })
ofinput.classes.append(ofclass)
if decl_ast[0] == 'enum':
diff --git a/loxi_front_end/parser.py b/loxi_front_end/parser.py
index d5920e8..25bfde4 100644
--- a/loxi_front_end/parser.py
+++ b/loxi_front_end/parser.py
@@ -51,6 +51,7 @@
# Structs
pad_member = P.Group(kw('pad') - s('(') - integer - s(')'))
+discriminator_member = P.Group(tag('discriminator') + any_type + identifier + s('==') + s('?'))
type_member = P.Group(tag('type') + any_type + identifier + s('==') + integer)
data_member = P.Group(tag('data') + any_type - identifier)
@@ -59,7 +60,7 @@
struct_param_list = P.Forward()
struct_param_list << struct_param + P.Optional(s(',') - P.Optional(struct_param_list))
-struct_member = pad_member | type_member | data_member;
+struct_member = pad_member | type_member | discriminator_member | data_member;
parent = (s(':') - identifier) | tag(None)
struct = kw('struct') - identifier - P.Group(P.Optional(s('(') - struct_param_list - s(')'))) - parent - s('{') + \
P.Group(P.ZeroOrMore(struct_member - s(';'))) + \
diff --git a/loxi_ir.py b/loxi_ir.py
index 9e266eb..fefe770 100644
--- a/loxi_ir.py
+++ b/loxi_ir.py
@@ -36,6 +36,7 @@
'OFClass',
'OFDataMember',
'OFTypeMember',
+ 'OFDiscriminatorMember',
'OFLengthMember',
'OFFieldLengthMember',
'OFPadMember',
@@ -72,11 +73,11 @@
The members are in the same order as on the wire.
@param name
+@param superclass name of the super class
@param members List of *Member objects
-@param super_class name of the super class
@param params optional dictionary of parameters
"""
-class OFClass(namedtuple('OFClass', ['name', 'members', 'superclass', 'params'])):
+class OFClass(namedtuple('OFClass', ['name', 'superclass', 'members', 'virtual', 'params'])):
def member_by_name(self, name):
return find(self.members, lambda m: hasattr(m, "name") and m.name == name)
@@ -91,6 +92,16 @@
OFDataMember = namedtuple('OFDataMember', ['name', 'oftype'])
"""
+Field that declares that this is an abstract super-class and
+that the sub classes will be discriminated based on this field.
+E.g., 'type' is the discriminator member of the abstract superclass
+of_action.
+
+@param name
+"""
+OFDiscriminatorMember = namedtuple('OFDiscrminatorMember', ['name', 'oftype'])
+
+"""
Field used to determine the type of an OpenFlow object
@param name