1 # Copyright (C) 2013,2014 Nippon Telegraph and Telephone Corporation.
2 # Copyright (C) 2013,2014 YAMAMOTO Takashi <yamamoto at valinux co jp>
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # this is a pyang plugin to generate ryu/lib/of_config/generated_classes.py
19 # PYTHONPATH=. ./bin/pyang --plugindir ~/git/ryu/tools/pyang_plugins -f ryu ~/git/ryu/tools/of-config1.1.1.yang > ~/git/ryu/lib/of_config/generated_classes.py
22 _COPYRIGHT_NOTICE = """
23 # Copyright (C) 2013,2014 Nippon Telegraph and Telephone Corporation.
24 # Copyright (C) 2013,2014 YAMAMOTO Takashi <yamamoto at valinux co jp>
26 # Licensed under the Apache License, Version 2.0 (the "License");
27 # you may not use this file except in compliance with the License.
28 # You may obtain a copy of the License at
30 # http://www.apache.org/licenses/LICENSE-2.0
32 # Unless required by applicable law or agreed to in writing, software
33 # distributed under the License is distributed on an "AS IS" BASIS,
34 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
36 # See the License for the specific language governing permissions and
37 # limitations under the License.
44 from pyang import plugin
47 def pyang_plugin_init():
48 plugin.register_plugin(RyuPlugin())
51 class RyuPlugin(plugin.PyangPlugin):
52 def add_output_format(self, fmts):
55 def emit(self, ctx, modules, fd):
56 emit_ryu(ctx, modules[0], fd)
59 def emit_ryu(ctx, module, fd):
61 visit_children(ctx, module, fd, module.i_children)
62 ctx.i_ryu_queue.reverse()
65 for s in ctx.i_ryu_queue:
66 name = generate_type_name(s)
73 def visit_children(ctx, module, fd, children, prefix=''):
76 ctx.i_ryu_queue.append(c)
77 if hasattr(c, 'i_children'):
78 visit_children(ctx, module, fd, c.i_children, prefix + ' ')
82 return s.keyword in ['leaf', 'leaf-list']
85 def generate_header(ctx):
86 print _COPYRIGHT_NOTICE
87 print '# do not edit.'
88 print '# this file was mechanically generated with:'
89 print '# pyang %s' % pyang.__version__
90 print '# ryu.tools.pyang_plugins.ryu'
91 for mod, ver in sorted(ctx.modules):
92 print '# %s@%s' % (mod, ver)
94 print 'from ryu.lib.of_config.base import _Base, _e, _ct'
97 def generate_class_def(s):
99 return s.i_ryu_class_def
100 except AttributeError:
102 s.i_ryu_class_def = _generate_class_def(s)
103 return s.i_ryu_class_def
106 def _generate_class_def(s):
108 return generate_type_name(s)
109 o = StringIO.StringIO()
110 print >> o, 'class %s(_Base):' % (generate_type_name(s),)
111 print >> o, ' _ELEMENTS = ['
112 for c in s.i_children:
114 print >> o, ' _e(\'%s\', is_list=%s), # %s' % \
115 (c.arg, c.keyword == 'leaf-list', generate_type_name(c),)
117 print >> o, ' _ct(\'%s\',' % (c.arg,)
118 print >> o, ' %s,' % (generate_type_name(c),)
119 print >> o, ' is_list=%s),' % (c.keyword == 'list',)
124 def generate_class(s):
127 sys.stdout.write(generate_class_def(s))
130 def same_class_def(s1, s2):
131 return generate_class_def(s1) == generate_class_def(s2)
134 # 'hoge-hoge' -> 'HogeHoge'
137 a = map(lambda x: x.capitalize(), a) # XXX locale sensitive
141 def chop_suf(s, suf):
142 if not s.endswith(suf):
150 def generate_type_name(s):
152 return s.i_ryu_class_name
153 except AttributeError:
155 s.i_ryu_class_name = name = _generate_type_name(s)
156 assert (name not in _classes) or same_class_def(_classes[name], s)
161 def _generate_type_name(s):
162 # 1. use the hardcoded name for the top level capable-switch.
163 if s.arg == 'capable-switch':
164 return 'OFCapableSwitchType'
165 # 2. pick the name from the first yang grouping.
166 # this relies on the way OF-Config yang specification is written.
167 t = s.search_one('uses')
170 # 3. pick the name of yang type.
171 t = s.search_one('type')
174 # 4. infer from the parent's name.
175 # if the parent is 'OFFooType' and our name is 'bar-baz',
176 # use 'OFFooBarBazType'.
177 # again, this relies on the way OF-Config yang specification is written.
178 return (chop_suf(generate_type_name(s.parent), 'Type')