Merge into master from pull request #65:
add more types in org.projectfloodlight.openflow.types (https://github.com/floodlight/loxigen/pull/65)
diff --git a/Makefile b/Makefile
index 5fee0c1..b9b25de 100644
--- a/Makefile
+++ b/Makefile
@@ -45,7 +45,7 @@
 TEST_DATA = $(shell find test_data -name '*.data')
 OPENFLOWJ_WORKSPACE = openflowj-loxi
 
-all: c python
+all: c python java
 
 c: .loxi_ts.c
 
@@ -98,6 +98,8 @@
 	@echo
 	@echo "INPUT_FILES=\"${INPUT_FILES}\""
 
+check-all: check check-c check-py check-java
+
 check:
 	./utest/test_parser.py
 	./utest/test_frontend.py
diff --git a/java_gen/codegen.py b/java_gen/codegen.py
index 1b9f445..b84556c 100644
--- a/java_gen/codegen.py
+++ b/java_gen/codegen.py
@@ -101,7 +101,11 @@
 
             for version in enum.versions:
                 clazz = java_model.OFGenericClass(package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version), name="{}SerializerVer{}".format(enum.name, version.of_version))
-                self.render_class(clazz=clazz, template="const_serializer.java", enum=enum, version=version)
+
+                if enum.is_bitmask:
+                    self.render_class(clazz=clazz, template="const_set_serializer.java", enum=enum, version=version)
+                else:
+                    self.render_class(clazz=clazz, template="const_serializer.java", enum=enum, version=version)
 
     def create_of_interfaces(self):
         """ Create the base interfaces for of classes"""
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index a882475..9fab422 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -130,14 +130,17 @@
                 "OFOxmMplsTcMasked":        OxmMapEntry("U8", "MPLS_TC", True)
                 }
 
-    class OFEnumMetadata(namedtuple("OFEnumMetadata", ("name", "type", "value"))):
+    class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
         @property
         def variable_name(self):
             return self.name[0].lower() + self.name[1:]
 
         @property
         def getter_name(self):
-            return "get"+self.name
+            prefix = "is" if self.type == java_type.boolean else "get"
+            return prefix+self.name
+
+    OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
 
     def gen_port_speed(enum_entry):
         splits = enum_entry.name.split("_")
@@ -147,8 +150,16 @@
                 return "PortSpeed.SPEED_{}".format(splits[1])
         return "PortSpeed.SPEED_NONE";
 
-    enum_metadata_map = defaultdict(lambda: (),
-            OFPortFeatures = ( OFEnumMetadata("PortSpeed", java_type.port_speed, gen_port_speed), )
+    def gen_stp_state(enum_entry):
+        splits = enum_entry.name.split("_")
+        if len(splits)>=1:
+            if splits[0] == "STP":
+                return "true"
+        return "false"
+
+    enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
+            OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
+            OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
     )
 
     @property
@@ -736,6 +747,8 @@
             return self.enum_value
         elif java_type == "OFOxmList":
             return "OFOxmList.EMPTY"
+        elif re.match(r'Set.*', java_type):
+            return "Collections.emptySet()"
         elif re.match(r'List.*', java_type):
             return "Collections.emptyList()"
         elif java_type == "boolean":
@@ -1010,6 +1023,11 @@
             return java_type.u8
 
     @property
+    @memoize
+    def is_bitmask(self):
+        return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
+
+    @property
     def versions(self):
         return self.version_enums.keys()
 
@@ -1046,7 +1064,7 @@
 
     @property
     def constructor_params(self):
-        return [ m.value(self) for m in self.enum.metadata ]
+        return [ m.value(self) for m in self.enum.metadata.properties ]
 
     def has_value(self, version):
         return version in self.values
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index 2369d01..d011c96 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -1,10 +1,13 @@
 import errno
-import loxi_utils.loxi_utils as loxi_utils
 import os
 import re
 import subprocess
 import time
 
+from generic_utils import memoize
+import loxi_utils.loxi_utils as loxi_utils
+import of_g
+
 def erase_type_annotation(class_name):
     m=re.match(r'(.*)<.*>', class_name)
     if m:
@@ -23,7 +26,9 @@
 def name_c_to_caps_camel(name):
     """ 'of_stats_reply' to 'OFStatsReply' """
     camel = name_c_to_camel(name.title())
-    if camel.startswith('Of'):
+    if camel.startswith('Ofp'):
+        return camel.replace('Ofp','OF',1)
+    elif camel.startswith('Of'):
         return camel.replace('Of','OF',1)
     else:
         return camel
@@ -230,8 +235,8 @@
             write='ChannelUtils.writeList(bb, $name)')
 buckets_list = JType('List<OFBucket>') \
         .op(read='ChannelUtils.readList(bb, $length, OFBucketVer$version.READER)', write='ChannelUtils.writeList(bb, $name)')
-port_desc_list = JType('List<OFPhysicalPort>') \
-        .op(read='ChannelUtils.readList(bb, $length, OFPhysicalPort.READER)', write='ChannelUtils.writeList(bb, $name)')
+port_desc_list = JType('List<OFPortDesc>') \
+        .op(read='ChannelUtils.readList(bb, $length, OFPortDescVer$version.READER)', write='ChannelUtils.writeList(bb, $name)')
 port_desc = JType('OFPortDesc') \
         .op(read='OFPortDescVer$version.READER.readFrom(bb)', \
             write='$name.writeTo(bb)')
@@ -394,6 +399,21 @@
         'of_oxm_mpls_tc_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
 }
 
+
+@memoize
+def enum_java_types():
+    enum_types = {}
+
+    for protocol in of_g.ir.values():
+        for enum in protocol.enums:
+            java_name = name_c_to_caps_camel(re.sub(r'_t$', "", enum.name))
+            java_type = java_name if not enum.is_bitmask else "Set<{}>".format(java_name)
+            enum_types[enum.name] = \
+                    JType(java_type)\
+                      .op(read = "{}SerializerVer$version.readFrom(bb)".format(java_name),
+                          write ="{}SerializerVer$version.writeTo(bb, $name)".format(java_name))
+    return enum_types
+
 def make_match_field_jtype(sub_type_name="?"):
     return JType("MatchField<{}>".format(sub_type_name))
 
@@ -415,6 +435,7 @@
             write='ChannelUtils.writeList(bb, $name)')
 
 
+
 #### main entry point for conversion of LOXI types (c_types) Java types.
 # FIXME: This badly needs a refactoring
 
@@ -437,6 +458,8 @@
         return default_mtype_to_jtype_convert_map[c_type]
     elif re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type):
         return make_standard_list_jtype(c_type)
+    elif c_type in enum_java_types():
+        return enum_java_types()[c_type]
     else:
         print "WARN: Couldn't find java type conversion for '%s' in %s:%s" % (c_type, obj_name, field_name)
         jtype = name_c_to_caps_camel(re.sub(r'_t$', "", c_type))
diff --git a/java_gen/templates/_imports.java b/java_gen/templates/_imports.java
index 669db00..2d93b22 100644
--- a/java_gen/templates/_imports.java
+++ b/java_gen/templates/_imports.java
@@ -1,6 +1,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 import java.util.Map;
 import org.projectfloodlight.openflow.protocol.*;
 import org.projectfloodlight.openflow.protocol.action.*;
@@ -15,3 +16,4 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.jboss.netty.buffer.ChannelBuffers;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
diff --git a/java_gen/templates/const.java b/java_gen/templates/const.java
index 7542d53..2cd0101 100644
--- a/java_gen/templates/const.java
+++ b/java_gen/templates/const.java
@@ -36,32 +36,42 @@
 //:: include("_imports.java", msg=enum)
 
 public enum ${class_name} {
+
 //:: for i, entry in enumerate(enum.entries):
-//::    if enum.metadata:
+//::    if enum.metadata.properties:
 //::        params = "({})".format(", ".join(entry.constructor_params))
 //::    else:
 //::        params = ""
 //::    #endif
-     ${entry.name}${params}${ ", " if i < len(enum.entries)-1 else ";" }
+//::    delimiter = ", " if i < len(enum.entries)-1 else ";"
+//::    to_string_value = enum.metadata.to_string(entry) if enum.metadata.to_string else None
+//::    if to_string_value:
+     ${entry.name}${params} {
+         @Override
+         public String toString() {
+            return "${to_string_value}";
+         }
+     }${delimiter}
+//::    else:
+     ${entry.name}${params}${delimiter}
+//::    #endif
+//:: #endfor
+//:: if enum.metadata.properties:
+
+//:: for property_metadata in enum.metadata.properties:
+     private final ${property_metadata.type.public_type} ${property_metadata.variable_name};
 //:: #endfor
 
-//:: if enum.metadata:
-//:: for metadata in enum.metadata:
-     private final ${metadata.type.public_type} ${metadata.variable_name};
-//:: #endfor
-
-     private ${class_name}(${", ".join("{} {}".format(m.type.public_type, m.variable_name) for m in enum.metadata)}) {
-     //:: for metadata in enum.metadata:
-        this.${metadata.variable_name} = ${metadata.variable_name};
+     private ${class_name}(${", ".join("{} {}".format(m.type.public_type, m.variable_name) for m in enum.metadata.properties)}) {
+     //:: for property_metadata in enum.metadata.properties:
+        this.${property_metadata.variable_name} = ${property_metadata.variable_name};
      //:: #endfor
      }
+//:: for property_metadata in enum.metadata.properties:
 
-//:: for metadata in enum.metadata:
-     public ${metadata.type.public_type} ${metadata.getter_name}() {
-         return ${metadata.variable_name};
+     public ${property_metadata.type.public_type} ${property_metadata.getter_name}() {
+         return ${property_metadata.variable_name};
      }
 //:: #endfor
-
-
 //:: #endif
 }
diff --git a/java_gen/templates/const_set_serializer.java b/java_gen/templates/const_set_serializer.java
new file mode 100644
index 0000000..641b0c8
--- /dev/null
+++ b/java_gen/templates/const_set_serializer.java
@@ -0,0 +1,93 @@
+//:: # Copyright 2013, Big Switch Networks, Inc.
+//:: #
+//:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+//:: # the following special exception:
+//:: #
+//:: # LOXI Exception
+//:: #
+//:: # As a special exception to the terms of the EPL, you may distribute libraries
+//:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+//:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+//:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+//:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+//:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+//:: #
+//:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//:: #
+//:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+//:: # a copy of the EPL at:
+//:: #
+//:: # http::: #www.eclipse.org/legal/epl-v10.html
+//:: #
+//:: # Unless required by applicable law or agreed to in writing, software
+//:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+//:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+//:: # EPL for the specific language governing permissions and limitations
+//:: # under the EPL.
+//::
+//:: import itertools
+//:: import of_g
+//:: include('_copyright.java')
+
+//:: include('_autogen.java')
+
+package ${package};
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.projectfloodlight.openflow.types.*;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.projectfloodlight.openflow.exceptions.OFParseError;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import ${enum.package}.${enum.name};
+
+public class ${class_name} {
+    //:: wire_type = enum.wire_type(version)
+    //:: int_wire_type = enum.wire_type(version).pub_type
+    //:: entries = sorted([ (entry, entry.value(version)) for entry in enum.entries if entry.has_value(version) ], lambda (_,va), (_2,vb): va.__cmp__(vb))
+
+    //:: for entry, _ in entries:
+    public final static ${int_wire_type} ${entry.name}_VAL = ${entry.format_value(version)};
+    //:: #endfor
+
+    public static Set<${enum.name}> readFrom(ChannelBuffer bb) throws OFParseError {
+        try {
+            return ofWireValue(${wire_type.read_op(version)});
+        } catch (IllegalArgumentException e) {
+            throw new OFParseError(e);
+        }
+    }
+
+    public static void writeTo(ChannelBuffer bb, Set<${enum.name}> set) {
+        ${wire_type.write_op(version=version, name="toWireValue(set)")};
+    }
+
+    public static Set<${enum.name}> ofWireValue(${int_wire_type} val) {
+        EnumSet<${enum.name}> set = EnumSet.noneOf(${enum.name}.class);
+
+        //:: for entry, _ in entries:
+        if((val & ${entry.name}_VAL) != 0)
+            set.add(${enum.name}.${entry.name});
+        //:: #endfor
+        return Collections.unmodifiableSet(set);
+    }
+
+    public static ${int_wire_type} toWireValue(Set<${enum.name}> set) {
+        ${int_wire_type} wireValue = 0;
+
+        for(${enum.name} e: set) {
+            switch(e) {
+                //:: for entry, _ in entries:
+                case ${entry.name}:
+                    wireValue |= ${entry.name}_VAL;
+                //:: #endfor
+                default:
+                    throw new IllegalArgumentException("Illegal enum value for type ${enum.name} in version ${version}: " + e);
+            }
+        }
+        return wireValue;
+    }
+
+}
diff --git a/loxi_front_end/frontend.py b/loxi_front_end/frontend.py
index c093a95..f4dece5 100644
--- a/loxi_front_end/frontend.py
+++ b/loxi_front_end/frontend.py
@@ -25,6 +25,8 @@
 # EPL for the specific language governing permissions and limitations
 # under the EPL.
 
+from generic_utils import find
+from collections import namedtuple
 import copy
 import of_g
 import loxi_front_end.type_maps as type_maps
@@ -33,25 +35,35 @@
 class InputError(Exception):
     pass
 
-def create_member(m_ast):
+
+FrontendCtx = namedtuple("FrontendCtx", ("used_enums"))
+
+def get_type(t_ast, ctx):
+    if t_ast[0] == "enum":
+        ctx.used_enums.add(t_ast[1])
+
+    return t_ast[1]
+
+def create_member(m_ast, ctx):
     if m_ast[0] == 'pad':
         return OFPadMember(length=m_ast[1])
     elif m_ast[0] == 'type':
-        return OFTypeMember(name=m_ast[2], oftype=m_ast[1], value=m_ast[3])
+        return OFTypeMember(name=m_ast[2], oftype=get_type(m_ast[1], ctx), value=m_ast[3])
     elif m_ast[0] == 'data':
         if m_ast[2] == 'length' or m_ast[2] == 'len': # Should be moved to parser
-            return OFLengthMember(name=m_ast[2], oftype=m_ast[1])
+            return OFLengthMember(name=m_ast[2], oftype=get_type(m_ast[1], ctx))
         elif m_ast[2] == 'actions_len':
             # HACK only usage so far
-            return OFFieldLengthMember(name=m_ast[2], oftype=m_ast[1], field_name='actions')
+            return OFFieldLengthMember(name=m_ast[2], oftype=get_type(m_ast[1], ctx), field_name='actions')
         else:
-            return OFDataMember(name=m_ast[2], oftype=m_ast[1])
+            return OFDataMember(name=m_ast[2], oftype=get_type(m_ast[1], ctx))
     elif m_ast[0] == 'discriminator':
-        return OFDiscriminatorMember(name=m_ast[2], oftype=m_ast[1])
+        return OFDiscriminatorMember(name=m_ast[2], oftype=get_type(m_ast[1], ctx))
     else:
         raise InputError("Dont know how to create member: %s" % m_ast[0])
 
 def create_ofinput(ast):
+
     """
     Create an OFInput from an AST
 
@@ -59,7 +71,7 @@
 
     @returns An OFInput object
     """
-
+    ctx = FrontendCtx(set())
     ofinput = OFInput(wire_versions=set(), classes=[], enums=[])
 
     for decl_ast in ast:
@@ -70,7 +82,7 @@
             # 3: super_class or None
             # 4: list of members
             superclass = decl_ast[3]
-            members = [create_member(m_ast) for m_ast in decl_ast[4]]
+            members = [create_member(m_ast, ctx) for m_ast in decl_ast[4]]
 
             discriminators = [ m for m in members if isinstance(m, OFDiscriminatorMember) ]
             if len(discriminators) > 1:
@@ -103,4 +115,8 @@
     if not ofinput.wire_versions:
         raise InputError("Missing #version metadata")
 
+    for used_enum in ctx.used_enums:
+        if not find(lambda e: e.name == used_enum, ofinput.enums):
+            raise Exception("Undeclared enum used in OFInput: {}".format(used_enum))
+
     return ofinput
diff --git a/loxi_front_end/parser.py b/loxi_front_end/parser.py
index 25bfde4..f2cf4b0 100644
--- a/loxi_front_end/parser.py
+++ b/loxi_front_end/parser.py
@@ -44,10 +44,11 @@
 identifier = word.copy().setName("identifier")
 
 # Type names
-scalar_type = word
-array_type = P.Combine(word + lit('[') - P.Word(P.alphanums + '_') - lit(']'))
-list_type = P.Combine(kw('list') - lit('(') - identifier - lit(')'))
-any_type = (array_type | list_type | scalar_type).setName("type name")
+enum_type = kw("enum") - word
+scalar_type = tag("scalar") + word
+array_type = tag("array") + P.Combine(word + lit('[') - P.Word(P.alphanums + '_') - lit(']'))
+list_type = tag("list") + P.Combine(kw('list') - lit('(') - identifier - lit(')'))
+any_type = P.Group(enum_type | array_type | list_type | scalar_type).setName("type name")
 
 # Structs
 pad_member = P.Group(kw('pad') - s('(') - integer - s(')'))
@@ -56,7 +57,7 @@
 data_member = P.Group(tag('data') + any_type - identifier)
 
 struct_param_name = kw("align")
-struct_param = P.Group(struct_param_name - s('=') - any_type)
+struct_param = P.Group(struct_param_name - s('=') - word)
 struct_param_list = P.Forward()
 struct_param_list << struct_param + P.Optional(s(',') - P.Optional(struct_param_list))
 
@@ -68,12 +69,12 @@
 
 # Enums
 enum_param_name = kw("wire_type") | kw("bitmask") | kw("complete")
-enum_param = P.Group(enum_param_name  - s('=') - any_type)
+enum_param = P.Group(enum_param_name  - s('=') - word)
 enum_param_list = P.Forward()
 enum_param_list << enum_param + P.Optional(s(',') + P.Optional(enum_param_list))
 
 enum_member_param_name = kw("virtual")
-enum_member_param = P.Group(enum_member_param_name  - s('=') - any_type)
+enum_member_param = P.Group(enum_member_param_name  - s('=') - word)
 enum_member_param_list = P.Forward()
 enum_member_param_list << enum_member_param + P.Optional(s(',') + P.Optional(enum_member_param_list))
 
diff --git a/loxi_ir.py b/loxi_ir.py
index 7bbe22f..ae89207 100644
--- a/loxi_ir.py
+++ b/loxi_ir.py
@@ -157,4 +157,9 @@
     def values(self):
         return [(e.name, e.value) for e in self.entries]
 
+    @property
+    def is_bitmask(self):
+        return "bitmask" in self.params and self.params['bitmask']
+
+
 OFEnumEntry = namedtuple('OFEnumEntry', ['name', 'value', 'params'])
diff --git a/loxi_utils/loxi_utils.py b/loxi_utils/loxi_utils.py
index f5f9b63..601a65d 100644
--- a/loxi_utils/loxi_utils.py
+++ b/loxi_utils/loxi_utils.py
@@ -36,6 +36,7 @@
 import sys
 import of_g
 import tenjin
+from generic_utils import find, memoize
 
 def class_signature(members):
     """
@@ -517,6 +518,17 @@
     with open(template_filename) as infile:
         out.write(infile.read())
 
+@memoize
+def lookup_ir_wiretype(oftype, version):
+    """ if of is a reference to an enum in ir, resolve it to the wiretype
+        declared in that enum. Else return oftype """
+    enums = of_g.ir[version].enums
+    enum = find(lambda e: e.name == oftype, enums)
+    if enum and 'wire_type' in enum.params:
+        return enum.params['wire_type']
+    else:
+        return oftype
+
 class TemplateEngine(tenjin.Engine):
     def include(self, template_name, **kwargs):
         """
diff --git a/loxigen.py b/loxigen.py
index dcd547e..f756dc0 100755
--- a/loxigen.py
+++ b/loxigen.py
@@ -442,7 +442,11 @@
                         if m.oftype == 'of_oxm_t':
                             m_type = 'of_octets_t'
                         else:
-                            m_type = m.oftype
+                            enum = find(lambda e: e.name == m.oftype, ofinput.enums)
+                            if enum and "wire_type" in enum.params:
+                                m_type = enum.params["wire_type"]
+                            else:
+                                m_type = m.oftype
                         legacy_members.append(dict(m_type=m_type, name=m.name))
                 versions[version_name]['classes'][ofclass.name] = legacy_members
 
diff --git a/openflow_input/standard-1.0 b/openflow_input/standard-1.0
index 5483ff4..4a73261 100644
--- a/openflow_input/standard-1.0
+++ b/openflow_input/standard-1.0
@@ -159,7 +159,7 @@
     OFPFW_NW_DST_MASK = 0xfc000,
     OFPFW_DL_VLAN_PCP = 0x100000,
     OFPFW_NW_TOS = 0x200000,
-    OFPFW_ALL = 0x3fffff,
+    OFPFW_ALL(virtual=True) = 0x3fffff,
 };
 
 enum ofp_action_type(wire_type=uint16_t) {
@@ -586,7 +586,7 @@
     uint16_t priority;
     uint32_t buffer_id;
     of_port_no_t out_port;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     list(of_action_t) actions;
 };
 
@@ -603,7 +603,7 @@
     uint16_t priority;
     uint32_t buffer_id;
     of_port_no_t out_port;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     list(of_action_t) actions;
 };
 
@@ -620,7 +620,7 @@
     uint16_t priority;
     uint32_t buffer_id;
     of_port_no_t out_port;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     list(of_action_t) actions;
 };
 
@@ -637,7 +637,7 @@
     uint16_t priority;
     uint32_t buffer_id;
     of_port_no_t out_port;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     list(of_action_t) actions;
 };
 
@@ -654,7 +654,7 @@
     uint16_t priority;
     uint32_t buffer_id;
     of_port_no_t out_port;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     list(of_action_t) actions;
 };
 
@@ -671,7 +671,7 @@
     uint16_t priority;
     uint32_t buffer_id;
     of_port_no_t out_port;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     list(of_action_t) actions;
 };
 
diff --git a/openflow_input/standard-1.1 b/openflow_input/standard-1.1
index a1127b1..9acbacf 100644
--- a/openflow_input/standard-1.1
+++ b/openflow_input/standard-1.1
@@ -856,7 +856,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
@@ -877,7 +877,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
@@ -898,7 +898,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
@@ -919,7 +919,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
@@ -940,7 +940,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
@@ -961,7 +961,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
diff --git a/openflow_input/standard-1.2 b/openflow_input/standard-1.2
index bfa9a64..9752b7d 100644
--- a/openflow_input/standard-1.2
+++ b/openflow_input/standard-1.2
@@ -772,7 +772,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
@@ -793,7 +793,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
@@ -814,7 +814,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
@@ -835,7 +835,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
@@ -856,7 +856,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
@@ -877,7 +877,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
diff --git a/openflow_input/standard-1.3 b/openflow_input/standard-1.3
index 119e7a4..afe371e 100644
--- a/openflow_input/standard-1.3
+++ b/openflow_input/standard-1.3
@@ -924,7 +924,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
@@ -945,7 +945,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
@@ -966,7 +966,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
@@ -987,7 +987,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
@@ -1008,7 +1008,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
@@ -1029,7 +1029,7 @@
     uint32_t buffer_id;
     of_port_no_t out_port;
     uint32_t out_group;
-    uint16_t flags;
+    enum ofp_flow_mod_flags flags;
     pad(2);
     of_match_t match;
     list(of_instruction_t) instructions;
diff --git a/py_gen/oftype.py b/py_gen/oftype.py
index 2399266..a6620ab 100644
--- a/py_gen/oftype.py
+++ b/py_gen/oftype.py
@@ -27,6 +27,9 @@
 
 from collections import namedtuple
 
+import loxi_utils.loxi_utils as loxi_utils
+import of_g
+
 OFTypeData = namedtuple("OFTypeData", ["init", "pack", "unpack"])
 
 # Map from LOXI type name to an object with templates for init, pack, and unpack
@@ -206,9 +209,12 @@
 
 ## Public interface
 
+def lookup_type_data(oftype, version):
+    return type_data_map.get(loxi_utils.lookup_ir_wiretype(oftype, version))
+
 # Return an initializer expression for the given oftype
-def gen_init_expr(oftype):
-    type_data = type_data_map.get(oftype)
+def gen_init_expr(oftype, version):
+    type_data = lookup_type_data(oftype, version)
     if type_data and type_data.init:
         return type_data.init
     else:
@@ -218,8 +224,8 @@
 #
 # 'value_expr' is a string of Python code which will evaluate to
 # the value to be packed.
-def gen_pack_expr(oftype, value_expr):
-    type_data = type_data_map.get(oftype)
+def gen_pack_expr(oftype, value_expr, version):
+    type_data = lookup_type_data(oftype, version)
     if type_data and type_data.pack:
         return type_data.pack % value_expr
     else:
@@ -229,8 +235,8 @@
 #
 # 'reader_expr' is a string of Python code which will evaluate to
 # the OFReader instance used for deserialization.
-def gen_unpack_expr(oftype, reader_expr):
-    type_data = type_data_map.get(oftype)
+def gen_unpack_expr(oftype, reader_expr, version):
+    type_data = lookup_type_data(oftype, version)
     if type_data and type_data.unpack:
         return type_data.unpack % reader_expr
     else:
diff --git a/py_gen/templates/_ofclass.py b/py_gen/templates/_ofclass.py
index ec6b04e..695cce6 100644
--- a/py_gen/templates/_ofclass.py
+++ b/py_gen/templates/_ofclass.py
@@ -11,7 +11,7 @@
         if ${m.name} != None:
             self.${m.name} = ${m.name}
         else:
-            self.${m.name} = ${py_gen.oftype.gen_init_expr(m.oftype)}
+            self.${m.name} = ${py_gen.oftype.gen_init_expr(m.oftype, version=version)}
 :: #endfor
         return
 
diff --git a/py_gen/templates/_pack.py b/py_gen/templates/_pack.py
index 9956cf6..0525ef2 100644
--- a/py_gen/templates/_pack.py
+++ b/py_gen/templates/_pack.py
@@ -37,19 +37,19 @@
 ::     if type(m) == OFLengthMember:
 ::         length_member = m
 ::         length_member_index = index
-        packed.append(${gen_pack_expr(m.oftype, '0')}) # placeholder for ${m.name} at index ${index}
+        packed.append(${gen_pack_expr(m.oftype, '0', version=version)}) # placeholder for ${m.name} at index ${index}
 ::     elif type(m) == OFFieldLengthMember:
 ::         field_length_members[m.field_name] = m
 ::         field_length_indexes[m.field_name] = index
-        packed.append(${gen_pack_expr(m.oftype, '0')}) # placeholder for ${m.name} at index ${index}
+        packed.append(${gen_pack_expr(m.oftype, '0', version=version)}) # placeholder for ${m.name} at index ${index}
 ::     elif type(m) == OFPadMember:
         packed.append('\x00' * ${m.length})
 ::     else:
-        packed.append(${gen_pack_expr(m.oftype, 'self.' + m.name)})
+        packed.append(${gen_pack_expr(m.oftype, 'self.' + m.name, version=version)})
 ::         if m.name in field_length_members:
 ::             field_length_member = field_length_members[m.name]
 ::             field_length_index = field_length_indexes[m.name]
-        packed[${field_length_index}] = ${gen_pack_expr(field_length_member.oftype, 'len(packed[-1])')}
+        packed[${field_length_index}] = ${gen_pack_expr(field_length_member.oftype, 'len(packed[-1])', version=version)}
 ::         #endif
 ::     #endif
 ::     index += 1
@@ -60,7 +60,7 @@
         packed.append(loxi.generic_util.pad_to(8, length))
         length += len(packed[-1])
 :: #endif
-        packed[${length_member_index}] = ${gen_pack_expr(length_member.oftype, 'length')}
+        packed[${length_member_index}] = ${gen_pack_expr(length_member.oftype, 'length', version=version)}
 :: #endif
 :: if ofclass.has_external_alignment:
         packed.append(loxi.generic_util.pad_to(8, length))
diff --git a/py_gen/templates/_pretty_print.py b/py_gen/templates/_pretty_print.py
index ed9d5cc..74e6d79 100644
--- a/py_gen/templates/_pretty_print.py
+++ b/py_gen/templates/_pretty_print.py
@@ -24,6 +24,7 @@
 :: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 :: # EPL for the specific language governing permissions and limitations
 :: # under the EPL.
+:: import loxi_utils.loxi_utils as loxi_utils
 ::
         q.text("${ofclass.pyname} {")
         with q.group():
@@ -52,7 +53,7 @@
                 q.text(util.pretty_wildcards(self.${m.name}))
 :: elif m.oftype == 'of_port_no_t':
                 q.text(util.pretty_port(self.${m.name}))
-:: elif m.oftype.startswith("uint"):
+:: elif loxi_utils.lookup_ir_wiretype(m.oftype, version=version).startswith("uint"):
                 q.text("%#x" % self.${m.name})
 :: else:
                 q.pp(self.${m.name})
diff --git a/py_gen/templates/_unpack.py b/py_gen/templates/_unpack.py
index 09a0e08..81efb21 100644
--- a/py_gen/templates/_unpack.py
+++ b/py_gen/templates/_unpack.py
@@ -37,12 +37,12 @@
 ::     if type(m) == OFPadMember:
         reader.skip(${m.length})
 ::     elif type(m) == OFLengthMember:
-        _${m.name} = ${gen_unpack_expr(m.oftype, 'reader')}
+        _${m.name} = ${gen_unpack_expr(m.oftype, 'reader', version=version)}
 ::     elif type(m) == OFFieldLengthMember:
 ::         field_length_members[m.field_name] = m
-        _${m.name} = ${gen_unpack_expr(m.oftype, 'reader')}
+        _${m.name} = ${gen_unpack_expr(m.oftype, 'reader', version=version)}
 ::     elif type(m) == OFTypeMember:
-        _${m.name} = ${gen_unpack_expr(m.oftype, 'reader')}
+        _${m.name} = ${gen_unpack_expr(m.oftype, 'reader', version=version)}
         assert(_${m.name} == ${m.value})
 ::     elif type(m) == OFDataMember:
 ::         if m.name in field_length_members:
@@ -50,7 +50,7 @@
 ::         else:
 ::             reader_expr = 'reader'
 ::         #endif
-        obj.${m.name} = ${gen_unpack_expr(m.oftype, reader_expr)}
+        obj.${m.name} = ${gen_unpack_expr(m.oftype, reader_expr, version=version)}
 ::     #endif
 :: #endfor
 :: if ofclass.has_external_alignment or ofclass.has_internal_alignment:
diff --git a/py_gen/templates/message.py b/py_gen/templates/message.py
index 7158545..4ec8c46 100644
--- a/py_gen/templates/message.py
+++ b/py_gen/templates/message.py
@@ -67,19 +67,19 @@
         if ${m.name} != None:
             self.${m.name} = ${m.name}
         else:
-            self.${m.name} = ${py_gen.oftype.gen_init_expr(m.oftype)}
+            self.${m.name} = ${py_gen.oftype.gen_init_expr(m.oftype, version=version)}
 :: #endfor
 
     def pack(self):
         packed = []
-:: include('_pack.py', ofclass=ofclass)
+:: include('_pack.py', ofclass=ofclass, version=version)
         return ''.join(packed)
 
     @staticmethod
     def unpack(buf):
         if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
         obj = ${ofclass.pyname}()
-:: include('_unpack.py', ofclass=ofclass)
+:: include('_unpack.py', ofclass=ofclass, version=version)
         return obj
 
     def __eq__(self, other):
diff --git a/py_gen/templates/oxm.py b/py_gen/templates/oxm.py
index 792c277..50eb4bd 100644
--- a/py_gen/templates/oxm.py
+++ b/py_gen/templates/oxm.py
@@ -67,18 +67,18 @@
         if ${m.name} != None:
             self.${m.name} = ${m.name}
         else:
-            self.${m.name} = ${py_gen.oftype.gen_init_expr(m.oftype)}
+            self.${m.name} = ${py_gen.oftype.gen_init_expr(m.oftype, version=version)}
 :: #endfor
 
     def pack(self):
         packed = []
-:: include("_pack.py", ofclass=ofclass)
+:: include("_pack.py", ofclass=ofclass, version=version)
         return ''.join(packed)
 
     @staticmethod
     def unpack(buf):
         obj = ${ofclass.pyname}()
-:: include("_unpack.py", ofclass=ofclass)
+:: include("_unpack.py", ofclass=ofclass, version=version)
         return obj
 
     def __eq__(self, other):
diff --git a/test_data/of13/flow_add.data b/test_data/of13/flow_add.data
index c9a6e35..049d797 100644
--- a/test_data/of13/flow_add.data
+++ b/test_data/of13/flow_add.data
@@ -83,7 +83,7 @@
     .setBufferId(50)
     .setOutPort(OFPort.of(6))
     .setOutGroup(8)
-    .setFlags(0)
+    .setFlags(ImmutableSet.<OFFlowModFlags>of())
     .setMatch(
         factory.buildMatch()
             .setMasked(MatchField.IN_PORT, OFPort.of(4), OFPort.of(5))
diff --git a/test_data/of13/flow_delete.data b/test_data/of13/flow_delete.data
index e1ee667..268304c 100644
--- a/test_data/of13/flow_delete.data
+++ b/test_data/of13/flow_delete.data
@@ -83,7 +83,7 @@
     .setBufferId(50)
     .setOutPort(OFPort.of(6))
     .setOutGroup(8)
-    .setFlags(0)
+    .setFlags(ImmutableSet.<OFFlowModFlags>of())
     .setMatch(
         factory.buildMatch()
             .setMasked(MatchField.IN_PORT, OFPort.of(4), OFPort.of(5))
diff --git a/test_data/of13/flow_delete_strict.data b/test_data/of13/flow_delete_strict.data
index 5bb0ef4..6165405 100644
--- a/test_data/of13/flow_delete_strict.data
+++ b/test_data/of13/flow_delete_strict.data
@@ -83,7 +83,7 @@
     .setBufferId(50)
     .setOutPort(OFPort.of(6))
     .setOutGroup(8)
-    .setFlags(0)
+    .setFlags(ImmutableSet.<OFFlowModFlags>of())
     .setMatch(
         factory.buildMatch()
             .setMasked(MatchField.IN_PORT, OFPort.of(4), OFPort.of(5))
diff --git a/test_data/of13/flow_modify.data b/test_data/of13/flow_modify.data
index 199eb59..188ab3d 100644
--- a/test_data/of13/flow_modify.data
+++ b/test_data/of13/flow_modify.data
@@ -83,7 +83,7 @@
     .setBufferId(50)
     .setOutPort(OFPort.of(6))
     .setOutGroup(8)
-    .setFlags(0)
+    .setFlags(ImmutableSet.<OFFlowModFlags>of())
     .setMatch(
         factory.buildMatch()
             .setMasked(MatchField.IN_PORT, OFPort.of(4), OFPort.of(5))
diff --git a/test_data/of13/flow_modify_strict.data b/test_data/of13/flow_modify_strict.data
index 42a3cee..a40210a 100644
--- a/test_data/of13/flow_modify_strict.data
+++ b/test_data/of13/flow_modify_strict.data
@@ -83,7 +83,7 @@
     .setBufferId(50)
     .setOutPort(OFPort.of(6))
     .setOutGroup(8)
-    .setFlags(0)
+    .setFlags(ImmutableSet.<OFFlowModFlags>of())
     .setMatch(
         factory.buildMatch()
             .setMasked(MatchField.IN_PORT, OFPort.of(4), OFPort.of(5))
diff --git a/utest/test_frontend.py b/utest/test_frontend.py
index 8799000..8febfde 100755
--- a/utest/test_frontend.py
+++ b/utest/test_frontend.py
@@ -91,21 +91,21 @@
                 ['OFPPC_NO_PACKET_IN', [], 64]]],
             ['metadata', 'version', '2'],
             ['struct', 'of_echo_reply', [['align', '8']], None, [
-                ['data', 'uint8_t', 'version'],
-                ['type', 'uint8_t', 'type', 3],
-                ['data', 'uint16_t', 'length'],
-                ['data', 'uint32_t', 'xid'],
-                ['data', 'of_octets_t', 'data']]],
+                ['data', ['scalar', 'uint8_t'], 'version'],
+                ['type', ['scalar', 'uint8_t'], 'type', 3],
+                ['data', ['scalar', 'uint16_t'], 'length'],
+                ['data', ['scalar', 'uint32_t'], 'xid'],
+                ['data', ['scalar', 'of_octets_t'], 'data']]],
             ['enum', 'ofp_queue_op_failed_code',
                 [['wire_type', 'uint32'], ['bitmask','False'], ['complete', 'True']], [
                 ['OFPQOFC_BAD_PORT', [], 0],
                 ['OFPQOFC_BAD_QUEUE', [], 1],
                 ['OFPQOFC_EPERM', [], 2]]],
             ['struct', 'of_packet_queue', [], None, [
-                ['data', 'uint32_t', 'queue_id'],
-                ['data', 'uint16_t', 'len'],
+                ['data', ['scalar', 'uint32_t'], 'queue_id'],
+                ['data', ['scalar', 'uint16_t'], 'len'],
                 ['pad', 2],
-                ['data', 'list(of_queue_prop_t)', 'properties']]],
+                ['data', ['list', 'list(of_queue_prop_t)'], 'properties']]],
         ]
         self.assertEquals(expected_ast, ast)
 
@@ -167,15 +167,15 @@
             ['metadata', 'version', '1'],
 
             ['struct', 'of_queue_prop', [], None, [
-                ['discriminator', 'uint16_t', 'type'],
-                ['data', 'uint16_t', 'len'],
+                ['discriminator', ['scalar', 'uint16_t'], 'type'],
+                ['data', ['scalar', 'uint16_t'], 'len'],
                 ['pad', 4]]],
 
             ['struct', 'of_queue_prop_min_rate', [], 'of_queue_prop', [
-                ['type', 'uint16_t', 'type', 1],
-                ['data', 'uint16_t', 'len'],
+                ['type', ['scalar', 'uint16_t'], 'type', 1],
+                ['data', ['scalar', 'uint16_t'], 'len'],
                 ['pad', 4],
-                ['data', 'uint16_t', 'rate'],
+                ['data', ['scalar', 'uint16_t'], 'rate'],
                 ['pad', 6]]],
         ]
         self.assertEquals(expected_ast, ast)
diff --git a/utest/test_parser.py b/utest/test_parser.py
index 9eb3764..8acfdda 100755
--- a/utest/test_parser.py
+++ b/utest/test_parser.py
@@ -52,7 +52,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', [], None, [['data', 'uint32_t', 'bar']]]])
+            [['struct', 'foo', [], None, [['data', ['scalar', 'uint32_t'], 'bar']]]])
 
     def test_struct_align_arg(self):
         src = """\
@@ -62,7 +62,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', [['align', '8']], None, [['data', 'uint32_t', 'bar']]]])
+            [['struct', 'foo', [['align', '8']], None, [['data', ['scalar', 'uint32_t'], 'bar']]]])
 
     def test_multiple_fields(self):
         src = """\
@@ -75,9 +75,9 @@
         ast = parser.parse(src)
         self.assertEquals(ast,
             [['struct', 'foo', [], None,
-                [['data', 'uint32_t', 'bar'],
-                 ['data', 'uint8_t', 'baz'],
-                 ['data', 'uint64_t', 'abc']]]])
+                [['data', ['scalar', 'uint32_t'], 'bar'],
+                 ['data', ['scalar', 'uint8_t'], 'baz'],
+                 ['data', ['scalar', 'uint64_t'], 'abc']]]])
 
     def test_array_type(self):
         src = """\
@@ -87,7 +87,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', [], None, [['data', 'uint32_t[4]', 'bar']]]])
+            [['struct', 'foo', [], None, [['data', ['array', 'uint32_t[4]'], 'bar']]]])
 
     def test_list_type(self):
         src = """\
@@ -97,7 +97,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', [], None, [['data', 'list(of_action_t)', 'bar']]]])
+            [['struct', 'foo', [], None, [['data', ['list', 'list(of_action_t)'], 'bar']]]])
 
     def test_pad_member(self):
         src = """\
@@ -117,7 +117,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', [], None, [['type', 'uint16_t', 'foo', 0x10]]]])
+            [['struct', 'foo', [], None, [['type', ['scalar', 'uint16_t'], 'foo', 0x10]]]])
 
     def test_inheritance(self):
         src = """\
@@ -127,7 +127,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', [], 'bar', [['type', 'uint16_t', 'foo', 0x10]]]])
+            [['struct', 'foo', [], 'bar', [['type', ['scalar', 'uint16_t'], 'foo', 0x10]]]])
 
     def test_discriminator(self):
         src = """\
@@ -137,7 +137,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', [], None, [['discriminator', 'uint16_t', 'foo']]]])
+            [['struct', 'foo', [], None, [['discriminator', ['scalar', 'uint16_t'], 'foo']]]])
 
 class EnumTests(unittest.TestCase):
     def test_empty(self):
@@ -220,7 +220,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', [], None, [['data', 'uint32_t', 'a']]]])
+            [['struct', 'foo', [], None, [['data', ['scalar', 'uint32_t'], 'a']]]])
 
     def test_mixed(self):
         src = """\