blob: 41b86dc209154633d26ef49d691d543e7e6abf58 [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]
101 for name, value in e.params.items():
102 if not name in entry.params:
103 entry.params[name] = value
104 elif entry.params[name] != value:
105 raise Exception("Error unifying ir enum {} - adding version: param {} <-> {}".format(
106 self.name, entry.params[name], value))
107 for name, value in v_enum.params.items():
108 if not name in self.params:
109 self.params[name] = value
110 else:
111 if self.params[name] != value:
112 if name == "wire_type":
113 self.params[name] = None
114 else:
115 raise Exception("Error unifying ir enum {} - adding version: {} param {} <-> {}".format(
116 self.name, v_enum.protocol.version, self.params[name], value))
117
118 self.version_enums[version]=v_enum
119
120 u_name_classes = OrderedDict()
121 u_name_enums = OrderedDict()
122
123 for version, protocol in name_protocol_map.items():
124 assert isinstance(version, ir.OFVersion)
125 for v_class in protocol.classes:
126 name = v_class.name
127 if not name in u_name_classes:
128 u_name_classes[name] = UnifiedClassSpec(name)
129 spec = u_name_classes[name]
130 spec.add_class(version, v_class)
131
132 for v_enum in protocol.enums:
133 name = v_enum.name
134 if not name in u_name_enums:
135 u_name_enums[name] = UnifiedEnumSpec(name)
136 spec = u_name_enums[name]
137 spec.add_enum(version, v_enum)
138
139 unified_enums = tuple(ir.OFEnum(name=s.name, entries=tuple(s.entries.values()), params=s.params) for s in u_name_enums.values())
140 unified_classes = OrderedDict()
141 for name, spec in u_name_classes.items():
142 u = ir.OFUnifiedClass(
143 name = spec.name,
144 version_classes=spec.version_class,
145 superclass=None if not spec.superclass_name else unified_classes[spec.superclass_name],
146 members=spec.members.values(),
147 virtual=spec.virtual,
148 params=spec.params,
149 base_length=spec.base_length,
150 is_fixed_length=spec.is_fixed_length)
151 unified_classes[name] = u
152
153 unified = ir.OFProtocol(version=None, classes = tuple(unified_classes.values()), enums=unified_enums)
154 for e in chain(unified.classes, unified.enums):
155 e.protocol = unified
Andreas Wundsama85acd72013-11-15 15:18:54 -0800156 return unified