blob: 929526de0455ca3387913eb714c2eef41f00a75d [file] [log] [blame]
Sapan Bhatia3cfdf632017-06-08 05:14:03 +02001import plyxproto.model as m
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -07002import pdb
3import 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:
67 pdb.set_trace()
68 pass
Sapan Bhatia1e397df2017-05-24 12:17:28 +020069 except KeyError:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020070 rev_links[l['peer']['fqn']] = [rlink]
Sapan Bhatia1e397df2017-05-24 12:17:28 +020071
72 for m in messages:
73 try:
74 m['rlinks'] = rev_links[m['name']]
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +020075 message_dict[m['name']]['rlinks'] = m['rlinks']
Sapan Bhatia1e397df2017-05-24 12:17:28 +020076 except KeyError:
77 pass
78
Matteo Scandolo67654fa2017-06-09 09:33:17 -070079
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020080def name_to_value(obj):
81 try:
82 value = obj.value.value.pval
83 except AttributeError:
84 try:
85 value = obj.value.value
86 except AttributeError:
87 value = obj.value.pval
88
89 return value
90
Matteo Scandolo67654fa2017-06-09 09:33:17 -070091
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070092class Stack(list):
Matteo Scandolo67654fa2017-06-09 09:33:17 -070093 def push(self, x):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070094 self.append(x)
95
Matteo Scandolo67654fa2017-06-09 09:33:17 -070096
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070097''' XOS2Jinja overrides the underlying visitor pattern to transform the tree
98 in addition to traversing it '''
Matteo Scandolo67654fa2017-06-09 09:33:17 -070099
100
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700101class XOS2Jinja(m.Visitor):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700102
103 def get_stack(self):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700104 return self.stack
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700105
106 def __init__(self):
107 super(XOS2Jinja, self).__init__()
108
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700109 self.stack = Stack()
110 self.models = {}
111 self.options = {}
112 self.package = None
113 self.message_options = {}
114 self.count_stack = Stack()
115 self.content = ""
116 self.offset = 0
117 self.current_message_name = None
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700118 self.verbose = 0
119 self.first_field = True
120 self.first_method = True
121
122 def visit_PackageStatement(self, obj):
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200123 dotlist = obj.name.value
124 dotlist2 = [f.pval for f in dotlist]
125 dotstr = '.'.join(dotlist2)
126 self.package = dotstr
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700127 return True
128
129 def visit_ImportStatement(self, obj):
130 '''Ignore'''
131 return True
132
133 def visit_OptionStatement(self, obj):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700134 if not hasattr(obj, 'mark_for_deletion'):
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200135 if (self.current_message_name):
136 self.message_options[obj.name.value.pval] = obj.value.value.pval
137 else:
138 self.options[obj.name.value.pval] = obj.value.value.pval
Sapan Bhatia504cc972017-04-27 01:56:28 +0200139
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700140 return True
141
142 def visit_LU(self, obj):
143 return True
144
145 def visit_default(self, obj):
146 return True
147
148 def visit_FieldDirective(self, obj):
149 return True
150
151 def visit_FieldDirective_post(self, obj):
152
153 try:
154 name = obj.name.value.pval
155 except AttributeError:
156 name = obj.name.value
157
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700158 if type(obj.value) == list:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200159 value = dotname_to_name(obj.value)
160 else:
161 value = name_to_value(obj)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700162
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700163 self.stack.push([name, value])
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700164 return True
165
166 def visit_FieldType(self, obj):
167 '''Field type, if type is name, then it may need refactoring consistent with refactoring rules according to the table'''
168 return True
169
170 def visit_LinkDefinition(self, obj):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700171 s = {}
Sapan Bhatia8a57c662017-04-11 10:39:47 -0700172
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200173 try:
174 s['link_type'] = obj.link_type.pval
175 except AttributeError:
176 s['link_type'] = obj.link_type
177
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700178 s['src_port'] = obj.src_port.value.pval
179 s['name'] = obj.src_port.value.pval
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200180
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700181 try:
182 s['dst_port'] = obj.dst_port.value.pval
183 except AttributeError:
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200184 s['dst_port'] = obj.dst_port
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200185
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700186 if type(obj.through) == list:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200187 s['through'] = dotname_to_fqn(obj.through)
188 else:
189 try:
190 s['through'] = obj.through.pval
191 except AttributeError:
192 s['through'] = obj.through
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200193
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700194 if type(obj.name) == list:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200195 s['peer'] = dotname_to_fqn(obj.name)
196 else:
197 try:
198 s['peer'] = obj.name.pval
199 except AttributeError:
200 s['peer'] = obj.name
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200201
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700202 s['_type'] = 'link'
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700203 s['options'] = {'modifier': 'optional'}
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700204
205 self.stack.push(s)
206 return True
207
208 def visit_FieldDefinition(self, obj):
209 self.count_stack.push(len(obj.fieldDirective))
210 return True
211
212 def visit_FieldDefinition_post(self, obj):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700213 s = {}
214
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700215 if isinstance(obj.ftype, m.Name):
216 s['type'] = obj.ftype.value
217 else:
218 s['type'] = obj.ftype.name.pval
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200219
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700220 s['name'] = obj.name.value.pval
221 s['modifier'] = obj.field_modifier.pval
222 s['id'] = obj.fieldId.pval
223
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700224 opts = {'modifier': s['modifier']}
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700225 n = self.count_stack.pop()
226 for i in range(0, n):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700227 k, v = self.stack.pop()
Sapan Bhatia5769d932017-05-17 11:10:54 +0200228
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700229 # The two lines below may be added to eliminate "" around an option.
Sapan Bhatia5769d932017-05-17 11:10:54 +0200230 # Right now, this is handled in targets. FIXME
231 #
232 # if (v.startswith('"') and v.endswith('"')):
233 # v = v[1:-1]
234
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700235 opts[k] = v
236
237 s['options'] = opts
Sapan Bhatia8a57c662017-04-11 10:39:47 -0700238 try:
239 last_link = self.stack[-1]['_type']
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700240 if (last_link == 'link'):
Sapan Bhatia8a57c662017-04-11 10:39:47 -0700241 s['link'] = True
242 except:
243 pass
244 s['_type'] = 'field'
245
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700246 self.stack.push(s)
247 return True
248
249 def visit_EnumFieldDefinition(self, obj):
250 if self.verbose > 4:
251 print "\tEnumField: name=%s, %s" % (obj.name, obj)
252
253 return True
254
255 def visit_EnumDefinition(self, obj):
256 '''New enum definition, refactor name'''
257 if self.verbose > 3:
258 print "Enum, [%s] body=%s\n\n" % (obj.name, obj.body)
259
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700260 return True
261
262 def visit_MessageDefinition(self, obj):
Sapan Bhatia504cc972017-04-27 01:56:28 +0200263 self.current_message_name = obj.name.value.pval
264 self.message_options = {}
265 self.count_stack.push(count_fields(obj.body))
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700266 return True
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700267
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700268 def visit_MessageDefinition_post(self, obj):
269 stack_num = self.count_stack.pop()
270 fields = []
271 links = []
272 last_field = None
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200273 try:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200274 obj.bases = map(dotname_to_fqn, obj.bases)
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200275 except AttributeError:
276 pass
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700277
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200278 last_field = {}
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700279 for i in range(0, stack_num):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700280 f = self.stack.pop()
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700281 if (f['_type'] == 'link'):
282 f['options'] = {i: d[i] for d in [f['options'], last_field['options']] for i in d}
283 assert (last_field == fields[0])
Sapan Bhatiad022aeb2017-06-07 15:49:55 +0200284 fields[0].setdefault('options', {})['link_type'] = f['link_type']
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700285 links.insert(0, f)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700286 else:
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700287 fields.insert(0, f)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700288 last_field = f
289
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200290 if self.package:
291 model_name = '.'.join([self.package, obj.name.value.pval])
292 else:
293 model_name = obj.name.value.pval
294
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200295 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 Bhatia943dad52017-05-19 18:41:01 +0200296 self.stack.push(model_def)
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200297
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200298 self.models[model_name] = model_def
299
300 # Set message options
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700301 for k, v in self.options.iteritems():
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200302 try:
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200303 if k not in self.message_options:
304 self.message_options[k] = v
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200305 except KeyError:
306 pass
307
Sapan Bhatia504cc972017-04-27 01:56:28 +0200308 self.current_message_name = None
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700309 return True
310
311 def visit_MessageExtension(self, obj):
312 return True
313
314 def visit_MethodDefinition(self, obj):
315 return True
316
317 def visit_ServiceDefinition(self, obj):
318 return True
319
320 def visit_ExtensionsDirective(self, obj):
321 return True
322
323 def visit_Literal(self, obj):
324 return True
325
326 def visit_Name(self, obj):
327 return True
328
329 def visit_DotName(self, obj):
330 return True
331
332 def visit_Proto(self, obj):
Sapan Bhatia504cc972017-04-27 01:56:28 +0200333 self.count_stack.push(count_messages(obj.body))
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700334 return True
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700335
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700336 def visit_Proto_post(self, obj):
337 count = self.count_stack.pop()
338 messages = []
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700339 for i in range(0, count):
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200340 try:
341 m = self.stack.pop()
342 except IndexError:
Sapan Bhatia504cc972017-04-27 01:56:28 +0200343 pass
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200344
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700345 messages.insert(0, m)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700346
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200347 compute_rlinks(messages, self.models)
348
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700349 self.messages = messages
350 return True
351
352 def visit_LinkSpec(self, obj):
353 count = self.count_stack.pop()
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700354 self.count_stack.push(count + 1)
355 return True