blob: 6157aee15aa57ac36013331b55614dbf32667d0d [file] [log] [blame]
Matteo Scandolod2044a42017-08-07 16:08:28 -07001# Copyright 2017-present Open Networking Foundation
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
Zack Williams9a42f872019-02-15 17:56:04 -070015from __future__ import absolute_import
Matteo Scandolod2044a42017-08-07 16:08:28 -070016
Sapan Bhatiaea6ff752017-07-14 01:52:18 -040017import ply.lex as lex
18import ply.yacc as yacc
Zack Williams9a42f872019-02-15 17:56:04 -070019import plyxproto.model as m
20from plyxproto.helpers import Visitor
21from plyxproto.logicparser import FOLLexer, FOLParser
22from six.moves import map
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070023
Zack Williams045b63d2019-01-22 16:30:57 -070024
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070025class Stack(list):
Zack Williams045b63d2019-01-22 16:30:57 -070026 def push(self, x):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070027 self.append(x)
28
Zack Williams045b63d2019-01-22 16:30:57 -070029
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020030def str_to_dict(s):
Zack Williams045b63d2019-01-22 16:30:57 -070031 lst = s.rsplit(".", 1)
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020032 name = lst[-1]
33
Zack Williams045b63d2019-01-22 16:30:57 -070034 if len(lst) == 2:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020035 package = lst[0]
36 else:
Zack Williams045b63d2019-01-22 16:30:57 -070037 package = ""
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020038
Zack Williams045b63d2019-01-22 16:30:57 -070039 return {"name": name, "package": package, "fqn": s}
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020040
Sapan Bhatiaea6ff752017-07-14 01:52:18 -040041
Sapan Bhatiaae9645c2017-05-05 15:35:54 +020042def replace_link(obj):
Zack Williams045b63d2019-01-22 16:30:57 -070043 try:
44 link = obj.link
Sapan Bhatiaae9645c2017-05-05 15:35:54 +020045 try:
Zack Williams045b63d2019-01-22 16:30:57 -070046 through = link["through"]
47 except KeyError:
48 through = None
Sapan Bhatiaae9645c2017-05-05 15:35:54 +020049
Zack Williams045b63d2019-01-22 16:30:57 -070050 try:
51 through_str = through[1:-1]
52 except TypeError:
53 through_str = None
Sapan Bhatiaae9645c2017-05-05 15:35:54 +020054
Zack Williams045b63d2019-01-22 16:30:57 -070055 if through_str:
56 through_dict = str_to_dict(through_str)
57 else:
58 through_dict = {}
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020059
Zack Williams045b63d2019-01-22 16:30:57 -070060 model_dict = str_to_dict(link["model"][1:-1])
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020061
Zack Williams045b63d2019-01-22 16:30:57 -070062 ls = m.LinkSpec(
63 obj,
64 m.LinkDefinition(
65 link["link"][1:-1],
66 obj.name,
67 model_dict,
68 link["port"][1:-1],
69 through_dict,
70 ),
71 )
72 return ls
73 except BaseException:
74 return obj
75
Sapan Bhatiaae9645c2017-05-05 15:35:54 +020076
Sapan Bhatiadb183c22017-06-23 02:47:42 -070077class Proto2XProto(Visitor):
Sapan Bhatiaea6ff752017-07-14 01:52:18 -040078 fol_lexer = lex.lex(module=FOLLexer())
Zack Williams045b63d2019-01-22 16:30:57 -070079 fol_parser = yacc.yacc(module=FOLParser(), start="goal", debug=0, outputdir="/tmp")
Sapan Bhatiaea6ff752017-07-14 01:52:18 -040080
Matteo Scandolo67654fa2017-06-09 09:33:17 -070081 def __init__(self):
82 super(Proto2XProto, self).__init__()
83
84 self.stack = Stack()
85 self.count_stack = Stack()
Zack Williams045b63d2019-01-22 16:30:57 -070086 self.content = ""
87 self.offset = 0
88 self.statementsChanged = 0
Matteo Scandolo67654fa2017-06-09 09:33:17 -070089 self.message_options = {}
90 self.options = {}
91 self.current_message_name = None
92
Zack Williams045b63d2019-01-22 16:30:57 -070093 self.xproto_message_options = ["bases"]
94 self.xproto_field_options = ["model"]
Matteo Scandolo67654fa2017-06-09 09:33:17 -070095 self.verbose = 0
96 self.first_field = True
97 self.first_method = True
Zack Williams045b63d2019-01-22 16:30:57 -070098
Sapan Bhatiaea6ff752017-07-14 01:52:18 -040099 def replace_policy(self, obj):
100 if isinstance(obj, m.OptionStatement):
101 rhs = obj.value.value.pval
102 if rhs.startswith('"') and rhs.endswith('"'):
103 rhs = rhs[1:-1]
104
Zack Williams045b63d2019-01-22 16:30:57 -0700105 if rhs.startswith("policy:"):
106 str = rhs.split(":", 1)[1]
107 val = self.fol_parser.parse(str, lexer=self.fol_lexer)
Sapan Bhatiaea6ff752017-07-14 01:52:18 -0400108
109 return m.PolicyDefinition(obj.name, val)
110
111 return obj
112
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200113 def proto_to_xproto_field(self, obj):
114 try:
115 opts = {}
116 for fd in obj.fieldDirective:
117 k = fd.pval.name.value.pval
118 v = fd.pval.value.value.pval
Zack Williams045b63d2019-01-22 16:30:57 -0700119 opts[k] = v
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200120
Zack Williams045b63d2019-01-22 16:30:57 -0700121 if "model" in opts and "link" in opts and "port" in opts:
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200122 obj.link = opts
123 pass
124 except KeyError:
125 raise
126
127 def proto_to_xproto_message(self, obj):
128 try:
Sapan Bhatiaea6ff752017-07-14 01:52:18 -0400129 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700130 bases = self.message_options["bases"].split(",")
Sapan Bhatiaea6ff752017-07-14 01:52:18 -0400131 except KeyError:
132 bases = []
133
Zack Williams9a42f872019-02-15 17:56:04 -0700134 bases = [str_to_dict(x[1:-1]) for x in bases]
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200135 obj.bases = bases
136 except KeyError:
137 raise
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700138
139 def map_field(self, obj, s):
Zack Williams045b63d2019-01-22 16:30:57 -0700140 if "model" in s:
141 link = m.LinkDefinition(
142 "onetoone", "src", "name", "dst", obj.linespan, obj.lexspan, obj.p
143 )
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700144 lspec = m.LinkSpec(link, obj)
145 else:
146 lspec = obj
147 return lspec
148
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700149 def get_stack(self):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700150 return self.stack
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700151
152 def visit_PackageStatement(self, obj):
Zack Williams045b63d2019-01-22 16:30:57 -0700153 """Ignore"""
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700154 return True
155
156 def visit_ImportStatement(self, obj):
Zack Williams045b63d2019-01-22 16:30:57 -0700157 """Ignore"""
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700158 return True
159
160 def visit_OptionStatement(self, obj):
Zack Williams045b63d2019-01-22 16:30:57 -0700161 if self.current_message_name:
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200162 k = obj.name.value.pval
163 self.message_options[k] = obj.value.value.pval
Zack Williams045b63d2019-01-22 16:30:57 -0700164 if k in self.xproto_message_options:
165 obj.mark_for_deletion = True
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200166 else:
167 self.options[obj.name.value.pval] = obj.value.value.pval
168
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700169 return True
170
171 def visit_LU(self, obj):
172 return True
173
174 def visit_default(self, obj):
175 return True
176
177 def visit_FieldDirective(self, obj):
178 return True
179
180 def visit_FieldDirective_post(self, obj):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700181 return True
182
183 def visit_FieldType(self, obj):
184 return True
185
186 def visit_LinkDefinition(self, obj):
187 return True
188
189 def visit_FieldDefinition(self, obj):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700190 return True
191
192 def visit_FieldDefinition_post(self, obj):
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200193 self.proto_to_xproto_field(obj)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700194 return True
195
196 def visit_EnumFieldDefinition(self, obj):
197 return True
198
199 def visit_EnumDefinition(self, obj):
200 return True
201
202 def visit_MessageDefinition(self, obj):
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200203 self.current_message_name = obj.name.value.pval
204 self.message_options = {}
205
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700206 return True
Zack Williams045b63d2019-01-22 16:30:57 -0700207
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700208 def visit_MessageDefinition_post(self, obj):
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200209 self.proto_to_xproto_message(obj)
Zack Williams9a42f872019-02-15 17:56:04 -0700210 obj.body = [x for x in obj.body if not hasattr(x, "mark_for_deletion")]
211 obj.body = list(map(replace_link, obj.body))
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700212
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200213 self.current_message_name = None
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700214 return True
215
216 def visit_MessageExtension(self, obj):
217 return True
218
219 def visit_MethodDefinition(self, obj):
220 return True
221
222 def visit_ServiceDefinition(self, obj):
223 return True
224
225 def visit_ExtensionsDirective(self, obj):
226 return True
227
228 def visit_Literal(self, obj):
229 return True
230
231 def visit_Name(self, obj):
232 return True
233
234 def visit_DotName(self, obj):
235 return True
236
237 def visit_Proto(self, obj):
238 self.count_stack.push(len(obj.body))
239 return True
Zack Williams045b63d2019-01-22 16:30:57 -0700240
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700241 def visit_Proto_post(self, obj):
Sapan Bhatiaea6ff752017-07-14 01:52:18 -0400242
243 obj.body = [self.replace_policy(o) for o in obj.body]
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700244 return True
245
246 def visit_LinkSpec(self, obj):
247 return False