Update and rename MantenerFIFO to MantenerFIFO.md
[vsorcdistro/.git] / ryu / tools / pyang_plugins / ryu.py
1 # Copyright (C) 2013,2014 Nippon Telegraph and Telephone Corporation.
2 # Copyright (C) 2013,2014 YAMAMOTO Takashi <yamamoto at valinux co jp>
3 #
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
7 #
8 #    http://www.apache.org/licenses/LICENSE-2.0
9 #
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
13 # implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # this is a pyang plugin to generate ryu/lib/of_config/generated_classes.py
18 # usage example:
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
20
21
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>
25 #
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
29 #
30 #    http://www.apache.org/licenses/LICENSE-2.0
31 #
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
35 # implied.
36 # See the License for the specific language governing permissions and
37 # limitations under the License.
38 """
39
40
41 import sys
42 import StringIO
43 import pyang
44 from pyang import plugin
45
46
47 def pyang_plugin_init():
48     plugin.register_plugin(RyuPlugin())
49
50
51 class RyuPlugin(plugin.PyangPlugin):
52     def add_output_format(self, fmts):
53         fmts['ryu'] = self
54
55     def emit(self, ctx, modules, fd):
56         emit_ryu(ctx, modules[0], fd)
57
58
59 def emit_ryu(ctx, module, fd):
60     ctx.i_ryu_queue = []
61     visit_children(ctx, module, fd, module.i_children)
62     ctx.i_ryu_queue.reverse()
63     generate_header(ctx)
64     done = set()
65     for s in ctx.i_ryu_queue:
66         name = generate_type_name(s)
67         if name in done:
68             continue
69         generate_class(s)
70         done.add(name)
71
72
73 def visit_children(ctx, module, fd, children, prefix=''):
74     for c in children:
75         if not is_leaf(c):
76             ctx.i_ryu_queue.append(c)
77         if hasattr(c, 'i_children'):
78             visit_children(ctx, module, fd, c.i_children, prefix + '  ')
79
80
81 def is_leaf(s):
82     return s.keyword in ['leaf', 'leaf-list']
83
84
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)
93     print ''
94     print 'from ryu.lib.of_config.base import _Base, _e, _ct'
95
96
97 def generate_class_def(s):
98     try:
99         return s.i_ryu_class_def
100     except AttributeError:
101         pass
102     s.i_ryu_class_def = _generate_class_def(s)
103     return s.i_ryu_class_def
104
105
106 def _generate_class_def(s):
107     if is_leaf(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:
113         if is_leaf(c):
114             print >> o, '        _e(\'%s\', is_list=%s),  # %s' % \
115                 (c.arg, c.keyword == 'leaf-list', generate_type_name(c),)
116         else:
117             print >> o, '        _ct(\'%s\',' % (c.arg,)
118             print >> o, '            %s,' % (generate_type_name(c),)
119             print >> o, '            is_list=%s),' % (c.keyword == 'list',)
120     print >> o, '    ]'
121     return o.getvalue()
122
123
124 def generate_class(s):
125     print ''
126     print ''
127     sys.stdout.write(generate_class_def(s))
128
129
130 def same_class_def(s1, s2):
131     return generate_class_def(s1) == generate_class_def(s2)
132
133
134 # 'hoge-hoge' -> 'HogeHoge'
135 def pythonify(name):
136     a = name.split('-')
137     a = map(lambda x: x.capitalize(), a)  # XXX locale sensitive
138     return ''.join(a)
139
140
141 def chop_suf(s, suf):
142     if not s.endswith(suf):
143         return s
144     return s[:-len(suf)]
145
146
147 _classes = {}
148
149
150 def generate_type_name(s):
151     try:
152         return s.i_ryu_class_name
153     except AttributeError:
154         pass
155     s.i_ryu_class_name = name = _generate_type_name(s)
156     assert (name not in _classes) or same_class_def(_classes[name], s)
157     _classes[name] = s
158     return name
159
160
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')
168     if t:
169         return t.arg
170     # 3. pick the name of yang type.
171     t = s.search_one('type')
172     if t:
173         return t.arg
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')
179             + pythonify(s.arg)
180             + 'Type')