blob: edd80efa890127a31028c1c7687ab9afb534a8a3 [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 Bhatia3e3c1cd2017-07-15 01:35:44 -0400127 def visit_PolicyDefinition(self, obj):
128 if self.package:
129 pname = '.'.join([self.package, obj.name.value.pval])
130 else:
131 pname = obj.name.value.pval
132
133 self.policies[pname] = obj.body
134
135 return True
136
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700137 def visit_PackageStatement(self, obj):
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200138 dotlist = obj.name.value
139 dotlist2 = [f.pval for f in dotlist]
140 dotstr = '.'.join(dotlist2)
141 self.package = dotstr
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700142 return True
143
144 def visit_ImportStatement(self, obj):
145 '''Ignore'''
146 return True
147
148 def visit_OptionStatement(self, obj):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700149 if not hasattr(obj, 'mark_for_deletion'):
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200150 if (self.current_message_name):
151 self.message_options[obj.name.value.pval] = obj.value.value.pval
152 else:
153 self.options[obj.name.value.pval] = obj.value.value.pval
Sapan Bhatia504cc972017-04-27 01:56:28 +0200154
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700155 return True
156
157 def visit_LU(self, obj):
158 return True
159
160 def visit_default(self, obj):
161 return True
162
163 def visit_FieldDirective(self, obj):
164 return True
165
166 def visit_FieldDirective_post(self, obj):
167
168 try:
169 name = obj.name.value.pval
170 except AttributeError:
171 name = obj.name.value
172
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700173 if type(obj.value) == list:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200174 value = dotname_to_name(obj.value)
175 else:
176 value = name_to_value(obj)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700177
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700178 self.stack.push([name, value])
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700179 return True
180
181 def visit_FieldType(self, obj):
182 '''Field type, if type is name, then it may need refactoring consistent with refactoring rules according to the table'''
183 return True
184
185 def visit_LinkDefinition(self, obj):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700186 s = {}
Sapan Bhatia8a57c662017-04-11 10:39:47 -0700187
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200188 try:
189 s['link_type'] = obj.link_type.pval
190 except AttributeError:
191 s['link_type'] = obj.link_type
192
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700193 s['src_port'] = obj.src_port.value.pval
194 s['name'] = obj.src_port.value.pval
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700195 try:
196 s['policy'] = obj.policy.pval
197 except AttributeError:
198 s['policy'] = None
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200199
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700200 try:
201 s['dst_port'] = obj.dst_port.value.pval
202 except AttributeError:
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200203 s['dst_port'] = obj.dst_port
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200204
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700205 if type(obj.through) == list:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200206 s['through'] = dotname_to_fqn(obj.through)
207 else:
208 try:
209 s['through'] = obj.through.pval
210 except AttributeError:
211 s['through'] = obj.through
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200212
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700213 if type(obj.name) == list:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200214 s['peer'] = dotname_to_fqn(obj.name)
215 else:
216 try:
217 s['peer'] = obj.name.pval
218 except AttributeError:
219 s['peer'] = obj.name
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200220
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700221 s['_type'] = 'link'
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700222 s['options'] = {'modifier': 'optional'}
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700223
224 self.stack.push(s)
225 return True
226
227 def visit_FieldDefinition(self, obj):
228 self.count_stack.push(len(obj.fieldDirective))
229 return True
230
231 def visit_FieldDefinition_post(self, obj):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700232 s = {}
233
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700234 if isinstance(obj.ftype, m.Name):
235 s['type'] = obj.ftype.value
236 else:
237 s['type'] = obj.ftype.name.pval
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200238
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700239 s['name'] = obj.name.value.pval
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700240
241 try:
242 s['policy'] = obj.policy.pval
243 except AttributeError:
244 s['policy'] = None
245
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700246 s['modifier'] = obj.field_modifier.pval
247 s['id'] = obj.fieldId.pval
248
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700249 opts = {'modifier': s['modifier']}
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700250 n = self.count_stack.pop()
251 for i in range(0, n):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700252 k, v = self.stack.pop()
Sapan Bhatia5769d932017-05-17 11:10:54 +0200253
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700254 # The two lines below may be added to eliminate "" around an option.
Sapan Bhatia5769d932017-05-17 11:10:54 +0200255 # Right now, this is handled in targets. FIXME
256 #
257 # if (v.startswith('"') and v.endswith('"')):
258 # v = v[1:-1]
259
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700260 opts[k] = v
261
262 s['options'] = opts
Sapan Bhatia8a57c662017-04-11 10:39:47 -0700263 try:
264 last_link = self.stack[-1]['_type']
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700265 if (last_link == 'link'):
Sapan Bhatia8a57c662017-04-11 10:39:47 -0700266 s['link'] = True
267 except:
268 pass
269 s['_type'] = 'field'
270
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700271 self.stack.push(s)
272 return True
273
274 def visit_EnumFieldDefinition(self, obj):
275 if self.verbose > 4:
276 print "\tEnumField: name=%s, %s" % (obj.name, obj)
277
278 return True
279
280 def visit_EnumDefinition(self, obj):
281 '''New enum definition, refactor name'''
282 if self.verbose > 3:
283 print "Enum, [%s] body=%s\n\n" % (obj.name, obj.body)
284
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700285 return True
286
287 def visit_MessageDefinition(self, obj):
Sapan Bhatia504cc972017-04-27 01:56:28 +0200288 self.current_message_name = obj.name.value.pval
289 self.message_options = {}
290 self.count_stack.push(count_fields(obj.body))
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700291 return True
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700292
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700293 def visit_MessageDefinition_post(self, obj):
294 stack_num = self.count_stack.pop()
295 fields = []
296 links = []
297 last_field = None
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200298 try:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200299 obj.bases = map(dotname_to_fqn, obj.bases)
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200300 except AttributeError:
301 pass
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700302
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200303 last_field = {}
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700304 for i in range(0, stack_num):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700305 f = self.stack.pop()
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700306 if (f['_type'] == 'link'):
307 f['options'] = {i: d[i] for d in [f['options'], last_field['options']] for i in d}
308 assert (last_field == fields[0])
Sapan Bhatiad022aeb2017-06-07 15:49:55 +0200309 fields[0].setdefault('options', {})['link_type'] = f['link_type']
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700310 links.insert(0, f)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700311 else:
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700312 fields.insert(0, f)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700313 last_field = f
314
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200315 if self.package:
316 model_name = '.'.join([self.package, obj.name.value.pval])
317 else:
318 model_name = obj.name.value.pval
319
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200320 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 -0700321 try:
322 model_def['policy'] = obj.policy.pval
323 except AttributeError:
324 model_def['policy'] = None
325
Sapan Bhatia943dad52017-05-19 18:41:01 +0200326 self.stack.push(model_def)
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200327
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200328 self.models[model_name] = model_def
329
330 # Set message options
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700331 for k, v in self.options.iteritems():
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200332 try:
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200333 if k not in self.message_options:
334 self.message_options[k] = v
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200335 except KeyError:
336 pass
337
Sapan Bhatia504cc972017-04-27 01:56:28 +0200338 self.current_message_name = None
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700339 return True
340
341 def visit_MessageExtension(self, obj):
342 return True
343
344 def visit_MethodDefinition(self, obj):
345 return True
346
347 def visit_ServiceDefinition(self, obj):
348 return True
349
350 def visit_ExtensionsDirective(self, obj):
351 return True
352
353 def visit_Literal(self, obj):
354 return True
355
356 def visit_Name(self, obj):
357 return True
358
359 def visit_DotName(self, obj):
360 return True
361
362 def visit_Proto(self, obj):
Sapan Bhatia504cc972017-04-27 01:56:28 +0200363 self.count_stack.push(count_messages(obj.body))
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700364 return True
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700365
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700366 def visit_Proto_post(self, obj):
367 count = self.count_stack.pop()
368 messages = []
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700369 for i in range(0, count):
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200370 try:
371 m = self.stack.pop()
372 except IndexError:
Sapan Bhatia504cc972017-04-27 01:56:28 +0200373 pass
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200374
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700375 messages.insert(0, m)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700376
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200377 compute_rlinks(messages, self.models)
378
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700379 self.messages = messages
380 return True
381
382 def visit_LinkSpec(self, obj):
383 count = self.count_stack.pop()
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700384 self.count_stack.push(count + 1)
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700385 return True