loxigen: allow structs to refer to enums in other input files
Do a first pass over the input files to extract the enums.
Also hoists the OFProtocol construction from the loop over inputs. It only
needs to be done once.
diff --git a/loxi_front_end/frontend.py b/loxi_front_end/frontend.py
index 6746584..35c1e44 100644
--- a/loxi_front_end/frontend.py
+++ b/loxi_front_end/frontend.py
@@ -115,8 +115,4 @@
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/loxigen.py b/loxigen.py
index 31214ba..ac5d536 100755
--- a/loxigen.py
+++ b/loxigen.py
@@ -417,13 +417,35 @@
# Ignore emacs backup files
filenames = [x for x in filenames if not x.endswith('~')]
+ # Read input files
+ all_ofinputs = []
for filename in filenames:
log("Processing struct file: " + filename)
ofinput = process_input_file(filename)
-
- # Populate global state
+ all_ofinputs.append(ofinput)
for wire_version in ofinput.wire_versions:
ofinputs_by_version[wire_version].append(ofinput)
+
+ # Merge input files into per-version IR
+ for wire_version, ofinputs in ofinputs_by_version.items():
+ ofprotocol = OFProtocol(wire_version=wire_version, classes=[], enums=[])
+ for ofinput in ofinputs:
+ ofprotocol.classes.extend(ofinput.classes)
+ ofprotocol.enums.extend(ofinput.enums)
+ ofprotocol.classes.sort(key=lambda ofclass: ofclass.name)
+ of_g.ir[wire_version] = ofprotocol
+
+ # Extract enums
+ # An input file can refer to an enum in another file
+ enums_by_version = { ver: {} for ver in ofinputs_by_version }
+ for ofinput in all_ofinputs:
+ for wire_version in ofinput.wire_versions:
+ for enum in ofinput.enums:
+ enums_by_version[wire_version][enum.name] = enum
+
+ # Populate legacy maps
+ for ofinput in all_ofinputs:
+ for wire_version in ofinput.wire_versions:
version_name = of_g.of_version_wire2name[wire_version]
for ofclass in ofinput.classes:
@@ -442,7 +464,7 @@
if m.oftype == 'of_oxm_t':
m_type = 'of_octets_t'
else:
- enum = find(lambda e: e.name == m.oftype, ofinput.enums)
+ enum = enums_by_version[wire_version].get(m.oftype)
if enum and "wire_type" in enum.params:
m_type = enum.params["wire_type"]
else:
@@ -457,14 +479,6 @@
entry.name, enum.name, entry.value, wire_version,
of_g.identifiers, of_g.identifiers_by_group)
- for wire_version, ofinputs in ofinputs_by_version.items():
- ofprotocol = OFProtocol(wire_version=wire_version, classes=[], enums=[])
- for ofinput in ofinputs:
- ofprotocol.classes.extend(ofinput.classes)
- ofprotocol.enums.extend(ofinput.enums)
- ofprotocol.classes.sort(key=lambda ofclass: ofclass.name)
- of_g.ir[wire_version] = ofprotocol
-
def populate_type_maps():
"""
Use the type members in the IR to fill out the legacy type_maps.