blob: c58260e457bba867f1d9061e2815d12b43599795 [file] [log] [blame]
Sapan Bhatia3cfdf632017-06-08 05:14:03 +02001import plyxproto.model as m
Sapan Bhatiadb183c22017-06-23 02:47:42 -07002from plyxproto.helpers import Visitor
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -07003import argparse
Sapan Bhatia3cfdf632017-06-08 05:14:03 +02004import plyxproto.parser as plyxproto
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -07005import traceback
6import sys
7import jinja2
8import os
Sapan Bhatia1e397df2017-05-24 12:17:28 +02009import copy
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070010
Matteo Scandolo67654fa2017-06-09 09:33:17 -070011
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020012def dotname_to_fqn(dotname):
13 b_names = [part.pval for part in dotname]
14 package = '.'.join(b_names[:-1])
15 name = b_names[-1]
16 if package:
17 fqn = package + '.' + name
18 else:
19 fqn = name
Matteo Scandolo67654fa2017-06-09 09:33:17 -070020 return {'name': name, 'fqn': fqn, 'package': package}
21
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020022
23def dotname_to_name(dotname):
24 b_names = [part.pval for part in dotname]
25 return '.'.join(b_names)
26
27
Sapan Bhatia504cc972017-04-27 01:56:28 +020028def count_messages(body):
29 count = 0
30 for e in body:
Matteo Scandolo67654fa2017-06-09 09:33:17 -070031 if (type(e) == m.MessageDefinition):
32 count += 1
Sapan Bhatia504cc972017-04-27 01:56:28 +020033 return count
34
Matteo Scandolo67654fa2017-06-09 09:33:17 -070035
Sapan Bhatia504cc972017-04-27 01:56:28 +020036def count_fields(body):
37 count = 0
38 for e in body:
Matteo Scandolo67654fa2017-06-09 09:33:17 -070039 if (type(e) in [m.LinkDefinition, m.FieldDefinition, m.LinkSpec]):
40 count += 1
Sapan Bhatia504cc972017-04-27 01:56:28 +020041 return count
42
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +020043def compute_rlinks(messages, message_dict):
Sapan Bhatia1e397df2017-05-24 12:17:28 +020044 rev_links = {}
45
46 link_opposite = {
Matteo Scandolo67654fa2017-06-09 09:33:17 -070047 'manytomany': 'manytomany',
48 'manytoone': 'onetomany',
49 'onetoone': 'onetoone',
50 'onetomany': 'manytoone'
Sapan Bhatia1e397df2017-05-24 12:17:28 +020051 }
52
53 for m in messages:
54 for l in m['links']:
55 rlink = copy.deepcopy(l)
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020056
Matteo Scandolo67654fa2017-06-09 09:33:17 -070057 rlink['_type'] = 'rlink' # An implicit link, not declared in the model
Sapan Bhatia1e397df2017-05-24 12:17:28 +020058 rlink['src_port'] = l['dst_port']
59 rlink['dst_port'] = l['src_port']
Matteo Scandolo67654fa2017-06-09 09:33:17 -070060 rlink['peer'] = {'name': m['name'], 'package': m['package'], 'fqn': m['fqn']}
Sapan Bhatia1e397df2017-05-24 12:17:28 +020061 rlink['link_type'] = link_opposite[l['link_type']]
62
63 try:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020064 try:
65 rev_links[l['peer']['fqn']].append(rlink)
66 except TypeError:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020067 pass
Sapan Bhatia1e397df2017-05-24 12:17:28 +020068 except KeyError:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020069 rev_links[l['peer']['fqn']] = [rlink]
Sapan Bhatia1e397df2017-05-24 12:17:28 +020070
71 for m in messages:
72 try:
73 m['rlinks'] = rev_links[m['name']]
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +020074 message_dict[m['name']]['rlinks'] = m['rlinks']
Sapan Bhatia1e397df2017-05-24 12:17:28 +020075 except KeyError:
76 pass
77
Matteo Scandolo67654fa2017-06-09 09:33:17 -070078
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020079def name_to_value(obj):
80 try:
81 value = obj.value.value.pval
82 except AttributeError:
83 try:
84 value = obj.value.value
85 except AttributeError:
86 value = obj.value.pval
87
88 return value
89
Matteo Scandolo67654fa2017-06-09 09:33:17 -070090
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070091class Stack(list):
Matteo Scandolo67654fa2017-06-09 09:33:17 -070092 def push(self, x):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070093 self.append(x)
94
Matteo Scandolo67654fa2017-06-09 09:33:17 -070095
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070096''' XOS2Jinja overrides the underlying visitor pattern to transform the tree
97 in addition to traversing it '''
Matteo Scandolo67654fa2017-06-09 09:33:17 -070098
Sapan Bhatiadb183c22017-06-23 02:47:42 -070099class XOS2Jinja(Visitor):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700100 def __init__(self):
101 super(XOS2Jinja, self).__init__()
102
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700103 self.stack = Stack()
104 self.models = {}
105 self.options = {}
106 self.package = None
107 self.message_options = {}
108 self.count_stack = Stack()
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700109 self.policies = {}
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700110 self.content = ""
111 self.offset = 0
112 self.current_message_name = None
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700113 self.verbose = 0
114 self.first_field = True
115 self.first_method = True
116
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700117 def visit_PolicyDefinition(self, obj):
118 if self.package:
119 pname = '.'.join([self.package, obj.name.value.pval])
120 else:
121 pname = obj.name.value.pval
122
123 self.policies[pname] = obj.body
124
125 return True
126
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700127 def visit_PackageStatement(self, obj):
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200128 dotlist = obj.name.value
129 dotlist2 = [f.pval for f in dotlist]
130 dotstr = '.'.join(dotlist2)
131 self.package = dotstr
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700132 return True
133
134 def visit_ImportStatement(self, obj):
135 '''Ignore'''
136 return True
137
138 def visit_OptionStatement(self, obj):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700139 if not hasattr(obj, 'mark_for_deletion'):
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200140 if (self.current_message_name):
141 self.message_options[obj.name.value.pval] = obj.value.value.pval
142 else:
143 self.options[obj.name.value.pval] = obj.value.value.pval
Sapan Bhatia504cc972017-04-27 01:56:28 +0200144
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700145 return True
146
147 def visit_LU(self, obj):
148 return True
149
150 def visit_default(self, obj):
151 return True
152
153 def visit_FieldDirective(self, obj):
154 return True
155
156 def visit_FieldDirective_post(self, obj):
157
158 try:
159 name = obj.name.value.pval
160 except AttributeError:
161 name = obj.name.value
162
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700163 if type(obj.value) == list:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200164 value = dotname_to_name(obj.value)
165 else:
166 value = name_to_value(obj)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700167
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700168 self.stack.push([name, value])
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700169 return True
170
171 def visit_FieldType(self, obj):
172 '''Field type, if type is name, then it may need refactoring consistent with refactoring rules according to the table'''
173 return True
174
175 def visit_LinkDefinition(self, obj):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700176 s = {}
Sapan Bhatia8a57c662017-04-11 10:39:47 -0700177
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200178 try:
179 s['link_type'] = obj.link_type.pval
180 except AttributeError:
181 s['link_type'] = obj.link_type
182
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700183 s['src_port'] = obj.src_port.value.pval
184 s['name'] = obj.src_port.value.pval
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700185 try:
186 s['policy'] = obj.policy.pval
187 except AttributeError:
188 s['policy'] = None
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200189
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700190 try:
191 s['dst_port'] = obj.dst_port.value.pval
192 except AttributeError:
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200193 s['dst_port'] = obj.dst_port
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200194
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700195 if type(obj.through) == list:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200196 s['through'] = dotname_to_fqn(obj.through)
197 else:
198 try:
199 s['through'] = obj.through.pval
200 except AttributeError:
201 s['through'] = obj.through
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200202
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700203 if type(obj.name) == list:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200204 s['peer'] = dotname_to_fqn(obj.name)
205 else:
206 try:
207 s['peer'] = obj.name.pval
208 except AttributeError:
209 s['peer'] = obj.name
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200210
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700211 s['_type'] = 'link'
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700212 s['options'] = {'modifier': 'optional'}
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700213
214 self.stack.push(s)
215 return True
216
217 def visit_FieldDefinition(self, obj):
218 self.count_stack.push(len(obj.fieldDirective))
219 return True
220
221 def visit_FieldDefinition_post(self, obj):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700222 s = {}
223
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700224 if isinstance(obj.ftype, m.Name):
225 s['type'] = obj.ftype.value
226 else:
227 s['type'] = obj.ftype.name.pval
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200228
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700229 s['name'] = obj.name.value.pval
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700230
231 try:
232 s['policy'] = obj.policy.pval
233 except AttributeError:
234 s['policy'] = None
235
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700236 s['modifier'] = obj.field_modifier.pval
237 s['id'] = obj.fieldId.pval
238
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700239 opts = {'modifier': s['modifier']}
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700240 n = self.count_stack.pop()
241 for i in range(0, n):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700242 k, v = self.stack.pop()
Sapan Bhatia5769d932017-05-17 11:10:54 +0200243
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700244 # The two lines below may be added to eliminate "" around an option.
Sapan Bhatia5769d932017-05-17 11:10:54 +0200245 # Right now, this is handled in targets. FIXME
246 #
247 # if (v.startswith('"') and v.endswith('"')):
248 # v = v[1:-1]
249
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700250 opts[k] = v
251
252 s['options'] = opts
Sapan Bhatia8a57c662017-04-11 10:39:47 -0700253 try:
254 last_link = self.stack[-1]['_type']
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700255 if (last_link == 'link'):
Sapan Bhatia8a57c662017-04-11 10:39:47 -0700256 s['link'] = True
257 except:
258 pass
259 s['_type'] = 'field'
260
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700261 self.stack.push(s)
262 return True
263
264 def visit_EnumFieldDefinition(self, obj):
265 if self.verbose > 4:
266 print "\tEnumField: name=%s, %s" % (obj.name, obj)
267
268 return True
269
270 def visit_EnumDefinition(self, obj):
271 '''New enum definition, refactor name'''
272 if self.verbose > 3:
273 print "Enum, [%s] body=%s\n\n" % (obj.name, obj.body)
274
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700275 return True
276
277 def visit_MessageDefinition(self, obj):
Sapan Bhatia504cc972017-04-27 01:56:28 +0200278 self.current_message_name = obj.name.value.pval
279 self.message_options = {}
280 self.count_stack.push(count_fields(obj.body))
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700281 return True
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700282
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700283 def visit_MessageDefinition_post(self, obj):
284 stack_num = self.count_stack.pop()
285 fields = []
286 links = []
287 last_field = None
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200288 try:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200289 obj.bases = map(dotname_to_fqn, obj.bases)
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200290 except AttributeError:
291 pass
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700292
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200293 last_field = {}
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700294 for i in range(0, stack_num):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700295 f = self.stack.pop()
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700296 if (f['_type'] == 'link'):
297 f['options'] = {i: d[i] for d in [f['options'], last_field['options']] for i in d}
298 assert (last_field == fields[0])
Sapan Bhatiad022aeb2017-06-07 15:49:55 +0200299 fields[0].setdefault('options', {})['link_type'] = f['link_type']
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700300 links.insert(0, f)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700301 else:
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700302 fields.insert(0, f)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700303 last_field = f
304
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200305 if self.package:
306 model_name = '.'.join([self.package, obj.name.value.pval])
307 else:
308 model_name = obj.name.value.pval
309
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200310 model_def = {'name':obj.name.value.pval,'fields':fields,'links':links, 'bases':obj.bases, 'options':self.message_options, 'package':self.package, 'fqn': model_name, 'rlinks': []}
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700311 try:
312 model_def['policy'] = obj.policy.pval
313 except AttributeError:
314 model_def['policy'] = None
315
Sapan Bhatia943dad52017-05-19 18:41:01 +0200316 self.stack.push(model_def)
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200317
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200318 self.models[model_name] = model_def
319
320 # Set message options
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700321 for k, v in self.options.iteritems():
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200322 try:
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200323 if k not in self.message_options:
324 self.message_options[k] = v
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200325 except KeyError:
326 pass
327
Sapan Bhatia504cc972017-04-27 01:56:28 +0200328 self.current_message_name = None
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700329 return True
330
331 def visit_MessageExtension(self, obj):
332 return True
333
334 def visit_MethodDefinition(self, obj):
335 return True
336
337 def visit_ServiceDefinition(self, obj):
338 return True
339
340 def visit_ExtensionsDirective(self, obj):
341 return True
342
343 def visit_Literal(self, obj):
344 return True
345
346 def visit_Name(self, obj):
347 return True
348
349 def visit_DotName(self, obj):
350 return True
351
352 def visit_Proto(self, obj):
Sapan Bhatia504cc972017-04-27 01:56:28 +0200353 self.count_stack.push(count_messages(obj.body))
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700354 return True
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700355
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700356 def visit_Proto_post(self, obj):
357 count = self.count_stack.pop()
358 messages = []
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700359 for i in range(0, count):
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200360 try:
361 m = self.stack.pop()
362 except IndexError:
Sapan Bhatia504cc972017-04-27 01:56:28 +0200363 pass
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200364
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700365 messages.insert(0, m)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700366
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200367 compute_rlinks(messages, self.models)
368
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700369 self.messages = messages
370 return True
371
372 def visit_LinkSpec(self, obj):
373 count = self.count_stack.pop()
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700374 self.count_stack.push(count + 1)
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700375 return True