blob: fa97c8793bacf6a67dedec7cfde5c3154a706455 [file] [log] [blame]
Andreas Wundsamd30c1072013-11-15 13:36:57 -08001#!/usr/bin/env python
2# Copyright 2013, Big Switch Networks, Inc.
3#
4# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
5# the following special exception:
6#
7# LOXI Exception
8#
9# As a special exception to the terms of the EPL, you may distribute libraries
10# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
11# that copyright and licensing notices generated by LoxiGen are not altered or removed
12# from the LoxiGen Libraries and the notice provided below is (i) included in
13# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
14# documentation for the LoxiGen Libraries, if distributed in binary form.
15#
16# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
17#
18# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
19# a copy of the EPL at:
20#
21# http://www.eclipse.org/legal/epl-v10.html
22#
23# Unless required by applicable law or agreed to in writing, software
24# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
25# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
26# EPL for the specific language governing permissions and limitations
27# under the EPL.
28
29import copy
30from collections import OrderedDict
31from itertools import chain
32import logging
33
34import ir
35
36def build_unified_ir(name_protocol_map):
37 class UnifiedClassSpec(object):
38 def __init__(self, name):
39 self.name = name
40 self.members = OrderedDict()
41 self.superclass_name = None
42 self.superclass_set = False
43 self.params = OrderedDict()
44 self.version_class = OrderedDict()
45 self.virtual = False
46 self.base_length = None
47 self.is_fixed_length = True
48
49 def add_class(self, version, v_class):
50 for v_member in v_class.members:
51 if hasattr(v_member, "name"):
52 if not v_member.name in self.members:
53 self.members[v_member.name] = v_member
54 else:
55 if not type(self.members[v_member.name]) == type(v_member):
Andreas Wundsam343abd92013-11-16 13:16:07 -080056 raise Exception("Error unifying ir class {} - adding version: {} - member_type {} <-> {}".format(
57 self.name, v_class.protocol.version, self.members[v_member.name], v_member))
Andreas Wundsamd30c1072013-11-15 13:36:57 -080058
59 if not self.superclass_set:
60 self.superclass_name = v_class.superclass.name if v_class.superclass else None
61 else:
62 if self.superclass_name != v_class.superclass_name:
Andreas Wundsam343abd92013-11-16 13:16:07 -080063 raise Exception("Error unifying ir class {} - adding version {} - superclass: param {} <-> {}".format(
Andreas Wundsamd30c1072013-11-15 13:36:57 -080064 self.name, v_class.protocol.version, self.superclass_name, v_class.superclass_name))
65
66 for name, value in v_class.params.items():
67 if not name in self.params:
68 self.params[name] = value
69 else:
70 if self.params[name] != value:
Andreas Wundsam343abd92013-11-16 13:16:07 -080071 raise Exception("Error unifying ir class {} - adding version: {} - param {} <-> {}".format(
Andreas Wundsamd30c1072013-11-15 13:36:57 -080072 self.name, v_class.protocol.version, self.params[name], value))
73
74 if v_class.virtual:
75 self.virtual = True
76
77 if not v_class.is_fixed_length:
78 self.is_fixed_length = False
79
80 if self.base_length is None:
81 self.base_length = v_class.base_length
82 elif self.base_length != v_class.base_length:
83 self.is_fixed_length = False
84 if self.base_length > v_class.base_length:
85 self.base_length = v_class.base_length
86 self.version_class[version] = v_class
87
88 class UnifiedEnumSpec(object):
89 def __init__(self, name):
90 self.name = name
91 self.entries = {}
92 self.params = {}
93 self.version_enums = OrderedDict()
94
95 def add_enum(self, version, v_enum):
96 for e in v_enum.entries:
97 if not e.name in self.entries:
98 self.entries[e.name] = ir.OFEnumEntry(e.name, e.value, copy.copy(e.params))
99 else:
100 entry = self.entries[e.name]
Rich Lanefcc1c3b2014-10-22 11:34:54 -0700101 if v_enum.params.get('stable') == 'True' and e.value != entry.value:
102 raise Exception("Error unifying stable ir enum {} - adding entry {} version {} value {} <-> {}".format(
103 self.name, e.name, version, entry.value, e.value))
Andreas Wundsamd30c1072013-11-15 13:36:57 -0800104 for name, value in e.params.items():
105 if not name in entry.params:
106 entry.params[name] = value
107 elif entry.params[name] != value:
108 raise Exception("Error unifying ir enum {} - adding version: param {} <-> {}".format(
109 self.name, entry.params[name], value))
110 for name, value in v_enum.params.items():
111 if not name in self.params:
112 self.params[name] = value
113 else:
114 if self.params[name] != value:
115 if name == "wire_type":
116 self.params[name] = None
117 else:
118 raise Exception("Error unifying ir enum {} - adding version: {} param {} <-> {}".format(
119 self.name, v_enum.protocol.version, self.params[name], value))
120
121 self.version_enums[version]=v_enum
122
123 u_name_classes = OrderedDict()
124 u_name_enums = OrderedDict()
125
126 for version, protocol in name_protocol_map.items():
127 assert isinstance(version, ir.OFVersion)
128 for v_class in protocol.classes:
129 name = v_class.name
130 if not name in u_name_classes:
131 u_name_classes[name] = UnifiedClassSpec(name)
132 spec = u_name_classes[name]
133 spec.add_class(version, v_class)
134
135 for v_enum in protocol.enums:
136 name = v_enum.name
137 if not name in u_name_enums:
138 u_name_enums[name] = UnifiedEnumSpec(name)
139 spec = u_name_enums[name]
140 spec.add_enum(version, v_enum)
141
142 unified_enums = tuple(ir.OFEnum(name=s.name, entries=tuple(s.entries.values()), params=s.params) for s in u_name_enums.values())
143 unified_classes = OrderedDict()
144 for name, spec in u_name_classes.items():
145 u = ir.OFUnifiedClass(
146 name = spec.name,
147 version_classes=spec.version_class,
148 superclass=None if not spec.superclass_name else unified_classes[spec.superclass_name],
149 members=spec.members.values(),
150 virtual=spec.virtual,
151 params=spec.params,
152 base_length=spec.base_length,
153 is_fixed_length=spec.is_fixed_length)
154 unified_classes[name] = u
155
156 unified = ir.OFProtocol(version=None, classes = tuple(unified_classes.values()), enums=unified_enums)
157 for e in chain(unified.classes, unified.enums):
158 e.protocol = unified
Andreas Wundsama85acd72013-11-15 15:18:54 -0800159 return unified