Statistics
| Branch: | Revision:

root / scripts / qapi.py @ c7a3f252

History | View | Annotate | Download (8.4 kB)

1
#
2
# QAPI helper library
3
#
4
# Copyright IBM, Corp. 2011
5
# Copyright (c) 2013 Red Hat Inc.
6
#
7
# Authors:
8
#  Anthony Liguori <aliguori@us.ibm.com>
9
#  Markus Armbruster <armbru@redhat.com>
10
#
11
# This work is licensed under the terms of the GNU GPLv2.
12
# See the COPYING.LIB file in the top-level directory.
13

    
14
from ordereddict import OrderedDict
15

    
16
builtin_types = [
17
    'str', 'int', 'number', 'bool',
18
    'int8', 'int16', 'int32', 'int64',
19
    'uint8', 'uint16', 'uint32', 'uint64'
20
]
21

    
22
builtin_type_qtypes = {
23
    'str':      'QTYPE_QSTRING',
24
    'int':      'QTYPE_QINT',
25
    'number':   'QTYPE_QFLOAT',
26
    'bool':     'QTYPE_QBOOL',
27
    'int8':     'QTYPE_QINT',
28
    'int16':    'QTYPE_QINT',
29
    'int32':    'QTYPE_QINT',
30
    'int64':    'QTYPE_QINT',
31
    'uint8':    'QTYPE_QINT',
32
    'uint16':   'QTYPE_QINT',
33
    'uint32':   'QTYPE_QINT',
34
    'uint64':   'QTYPE_QINT',
35
}
36

    
37
class QAPISchema:
38

    
39
    def __init__(self, fp):
40
        self.fp = fp
41
        self.src = fp.read()
42
        if self.src == '' or self.src[-1] != '\n':
43
            self.src += '\n'
44
        self.cursor = 0
45
        self.exprs = []
46
        self.accept()
47

    
48
        while self.tok != None:
49
            self.exprs.append(self.get_expr())
50

    
51
    def accept(self):
52
        while True:
53
            bol = self.cursor == 0 or self.src[self.cursor-1] == '\n'
54
            self.tok = self.src[self.cursor]
55
            self.cursor += 1
56
            self.val = None
57

    
58
            if self.tok == '#' and bol:
59
                self.cursor = self.src.find('\n', self.cursor)
60
            elif self.tok in ['{', '}', ':', ',', '[', ']']:
61
                return
62
            elif self.tok == "'":
63
                string = ''
64
                esc = False
65
                while True:
66
                    ch = self.src[self.cursor]
67
                    self.cursor += 1
68
                    if ch == '\n':
69
                        raise Exception("Mismatched quotes")
70
                    if esc:
71
                        string += ch
72
                        esc = False
73
                    elif ch == "\\":
74
                        esc = True
75
                    elif ch == "'":
76
                        self.val = string
77
                        return
78
                    else:
79
                        string += ch
80
            elif self.tok == '\n':
81
                if self.cursor == len(self.src):
82
                    self.tok = None
83
                    return
84

    
85
    def get_members(self):
86
        expr = OrderedDict()
87
        while self.tok != '}':
88
            key = self.val
89
            self.accept()
90
            self.accept()        # :
91
            expr[key] = self.get_expr()
92
            if self.tok == ',':
93
                self.accept()
94
        self.accept()
95
        return expr
96

    
97
    def get_values(self):
98
        expr = []
99
        while self.tok != ']':
100
            expr.append(self.get_expr())
101
            if self.tok == ',':
102
                self.accept()
103
        self.accept()
104
        return expr
105

    
106
    def get_expr(self):
107
        if self.tok == '{':
108
            self.accept()
109
            expr = self.get_members()
110
        elif self.tok == '[':
111
            self.accept()
112
            expr = self.get_values()
113
        else:
114
            expr = self.val
115
            self.accept()
116
        return expr
117

    
118
def parse_schema(fp):
119
    schema = QAPISchema(fp)
120
    exprs = []
121

    
122
    for expr_eval in schema.exprs:
123
        if expr_eval.has_key('enum'):
124
            add_enum(expr_eval['enum'])
125
        elif expr_eval.has_key('union'):
126
            add_union(expr_eval)
127
            add_enum('%sKind' % expr_eval['union'])
128
        elif expr_eval.has_key('type'):
129
            add_struct(expr_eval)
130
        exprs.append(expr_eval)
131

    
132
    return exprs
133

    
134
def parse_args(typeinfo):
135
    if isinstance(typeinfo, basestring):
136
        struct = find_struct(typeinfo)
137
        assert struct != None
138
        typeinfo = struct['data']
139

    
140
    for member in typeinfo:
141
        argname = member
142
        argentry = typeinfo[member]
143
        optional = False
144
        structured = False
145
        if member.startswith('*'):
146
            argname = member[1:]
147
            optional = True
148
        if isinstance(argentry, OrderedDict):
149
            structured = True
150
        yield (argname, argentry, optional, structured)
151

    
152
def de_camel_case(name):
153
    new_name = ''
154
    for ch in name:
155
        if ch.isupper() and new_name:
156
            new_name += '_'
157
        if ch == '-':
158
            new_name += '_'
159
        else:
160
            new_name += ch.lower()
161
    return new_name
162

    
163
def camel_case(name):
164
    new_name = ''
165
    first = True
166
    for ch in name:
167
        if ch in ['_', '-']:
168
            first = True
169
        elif first:
170
            new_name += ch.upper()
171
            first = False
172
        else:
173
            new_name += ch.lower()
174
    return new_name
175

    
176
def c_var(name, protect=True):
177
    # ANSI X3J11/88-090, 3.1.1
178
    c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
179
                     'default', 'do', 'double', 'else', 'enum', 'extern', 'float',
180
                     'for', 'goto', 'if', 'int', 'long', 'register', 'return',
181
                     'short', 'signed', 'sizeof', 'static', 'struct', 'switch',
182
                     'typedef', 'union', 'unsigned', 'void', 'volatile', 'while'])
183
    # ISO/IEC 9899:1999, 6.4.1
184
    c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
185
    # ISO/IEC 9899:2011, 6.4.1
186
    c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic', '_Noreturn',
187
                     '_Static_assert', '_Thread_local'])
188
    # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
189
    # excluding _.*
190
    gcc_words = set(['asm', 'typeof'])
191
    # namespace pollution:
192
    polluted_words = set(['unix'])
193
    if protect and (name in c89_words | c99_words | c11_words | gcc_words | polluted_words):
194
        return "q_" + name
195
    return name.replace('-', '_').lstrip("*")
196

    
197
def c_fun(name, protect=True):
198
    return c_var(name, protect).replace('.', '_')
199

    
200
def c_list_type(name):
201
    return '%sList' % name
202

    
203
def type_name(name):
204
    if type(name) == list:
205
        return c_list_type(name[0])
206
    return name
207

    
208
enum_types = []
209
struct_types = []
210
union_types = []
211

    
212
def add_struct(definition):
213
    global struct_types
214
    struct_types.append(definition)
215

    
216
def find_struct(name):
217
    global struct_types
218
    for struct in struct_types:
219
        if struct['type'] == name:
220
            return struct
221
    return None
222

    
223
def add_union(definition):
224
    global union_types
225
    union_types.append(definition)
226

    
227
def find_union(name):
228
    global union_types
229
    for union in union_types:
230
        if union['union'] == name:
231
            return union
232
    return None
233

    
234
def add_enum(name):
235
    global enum_types
236
    enum_types.append(name)
237

    
238
def is_enum(name):
239
    global enum_types
240
    return (name in enum_types)
241

    
242
def c_type(name):
243
    if name == 'str':
244
        return 'char *'
245
    elif name == 'int':
246
        return 'int64_t'
247
    elif (name == 'int8' or name == 'int16' or name == 'int32' or
248
          name == 'int64' or name == 'uint8' or name == 'uint16' or
249
          name == 'uint32' or name == 'uint64'):
250
        return name + '_t'
251
    elif name == 'size':
252
        return 'uint64_t'
253
    elif name == 'bool':
254
        return 'bool'
255
    elif name == 'number':
256
        return 'double'
257
    elif type(name) == list:
258
        return '%s *' % c_list_type(name[0])
259
    elif is_enum(name):
260
        return name
261
    elif name == None or len(name) == 0:
262
        return 'void'
263
    elif name == name.upper():
264
        return '%sEvent *' % camel_case(name)
265
    else:
266
        return '%s *' % name
267

    
268
def genindent(count):
269
    ret = ""
270
    for i in range(count):
271
        ret += " "
272
    return ret
273

    
274
indent_level = 0
275

    
276
def push_indent(indent_amount=4):
277
    global indent_level
278
    indent_level += indent_amount
279

    
280
def pop_indent(indent_amount=4):
281
    global indent_level
282
    indent_level -= indent_amount
283

    
284
def cgen(code, **kwds):
285
    indent = genindent(indent_level)
286
    lines = code.split('\n')
287
    lines = map(lambda x: indent + x, lines)
288
    return '\n'.join(lines) % kwds + '\n'
289

    
290
def mcgen(code, **kwds):
291
    return cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
292

    
293
def basename(filename):
294
    return filename.split("/")[-1]
295

    
296
def guardname(filename):
297
    guard = basename(filename).rsplit(".", 1)[0]
298
    for substr in [".", " ", "-"]:
299
        guard = guard.replace(substr, "_")
300
    return guard.upper() + '_H'
301

    
302
def guardstart(name):
303
    return mcgen('''
304

305
#ifndef %(name)s
306
#define %(name)s
307

308
''',
309
                 name=guardname(name))
310

    
311
def guardend(name):
312
    return mcgen('''
313

314
#endif /* %(name)s */
315

316
''',
317
                 name=guardname(name))