Statistics
| Branch: | Revision:

root / scripts / qapi.py @ f53ec699

History | View | Annotate | Download (7.8 kB)

1
#
2
# QAPI helper library
3
#
4
# Copyright IBM, Corp. 2011
5
#
6
# Authors:
7
#  Anthony Liguori <aliguori@us.ibm.com>
8
#
9
# This work is licensed under the terms of the GNU GPLv2.
10
# See the COPYING.LIB file in the top-level directory.
11

    
12
from ordereddict import OrderedDict
13

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

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

    
35
def tokenize(data):
36
    while len(data):
37
        ch = data[0]
38
        data = data[1:]
39
        if ch in ['{', '}', ':', ',', '[', ']']:
40
            yield ch
41
        elif ch in ' \n':
42
            None
43
        elif ch == "'":
44
            string = ''
45
            esc = False
46
            while True:
47
                if (data == ''):
48
                    raise Exception("Mismatched quotes")
49
                ch = data[0]
50
                data = data[1:]
51
                if esc:
52
                    string += ch
53
                    esc = False
54
                elif ch == "\\":
55
                    esc = True
56
                elif ch == "'":
57
                    break
58
                else:
59
                    string += ch
60
            yield string
61

    
62
def parse(tokens):
63
    if tokens[0] == '{':
64
        ret = OrderedDict()
65
        tokens = tokens[1:]
66
        while tokens[0] != '}':
67
            key = tokens[0]
68
            tokens = tokens[1:]
69

    
70
            tokens = tokens[1:] # :
71

    
72
            value, tokens = parse(tokens)
73

    
74
            if tokens[0] == ',':
75
                tokens = tokens[1:]
76

    
77
            ret[key] = value
78
        tokens = tokens[1:]
79
        return ret, tokens
80
    elif tokens[0] == '[':
81
        ret = []
82
        tokens = tokens[1:]
83
        while tokens[0] != ']':
84
            value, tokens = parse(tokens)
85
            if tokens[0] == ',':
86
                tokens = tokens[1:]
87
            ret.append(value)
88
        tokens = tokens[1:]
89
        return ret, tokens
90
    else:
91
        return tokens[0], tokens[1:]
92

    
93
def evaluate(string):
94
    return parse(map(lambda x: x, tokenize(string)))[0]
95

    
96
def get_expr(fp):
97
    expr = ''
98

    
99
    for line in fp:
100
        if line.startswith('#') or line == '\n':
101
            continue
102

    
103
        if line.startswith(' '):
104
            expr += line
105
        elif expr:
106
            yield expr
107
            expr = line
108
        else:
109
            expr += line
110

    
111
    if expr:
112
        yield expr
113

    
114
def parse_schema(fp):
115
    exprs = []
116

    
117
    for expr in get_expr(fp):
118
        expr_eval = evaluate(expr)
119

    
120
        if expr_eval.has_key('enum'):
121
            add_enum(expr_eval['enum'])
122
        elif expr_eval.has_key('union'):
123
            add_union(expr_eval)
124
            add_enum('%sKind' % expr_eval['union'])
125
        elif expr_eval.has_key('type'):
126
            add_struct(expr_eval)
127
        exprs.append(expr_eval)
128

    
129
    return exprs
130

    
131
def parse_args(typeinfo):
132
    if isinstance(typeinfo, basestring):
133
        struct = find_struct(typeinfo)
134
        assert struct != None
135
        typeinfo = struct['data']
136

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

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

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

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

    
194
def c_fun(name, protect=True):
195
    return c_var(name, protect).replace('.', '_')
196

    
197
def c_list_type(name):
198
    return '%sList' % name
199

    
200
def type_name(name):
201
    if type(name) == list:
202
        return c_list_type(name[0])
203
    return name
204

    
205
enum_types = []
206
struct_types = []
207
union_types = []
208

    
209
def add_struct(definition):
210
    global struct_types
211
    struct_types.append(definition)
212

    
213
def find_struct(name):
214
    global struct_types
215
    for struct in struct_types:
216
        if struct['type'] == name:
217
            return struct
218
    return None
219

    
220
def add_union(definition):
221
    global union_types
222
    union_types.append(definition)
223

    
224
def find_union(name):
225
    global union_types
226
    for union in union_types:
227
        if union['union'] == name:
228
            return union
229
    return None
230

    
231
def add_enum(name):
232
    global enum_types
233
    enum_types.append(name)
234

    
235
def is_enum(name):
236
    global enum_types
237
    return (name in enum_types)
238

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

    
265
def genindent(count):
266
    ret = ""
267
    for i in range(count):
268
        ret += " "
269
    return ret
270

    
271
indent_level = 0
272

    
273
def push_indent(indent_amount=4):
274
    global indent_level
275
    indent_level += indent_amount
276

    
277
def pop_indent(indent_amount=4):
278
    global indent_level
279
    indent_level -= indent_amount
280

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

    
287
def mcgen(code, **kwds):
288
    return cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
289

    
290
def basename(filename):
291
    return filename.split("/")[-1]
292

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

    
299
def guardstart(name):
300
    return mcgen('''
301

302
#ifndef %(name)s
303
#define %(name)s
304

305
''',
306
                 name=guardname(name))
307

    
308
def guardend(name):
309
    return mcgen('''
310

311
#endif /* %(name)s */
312

313
''',
314
                 name=guardname(name))