Merge commit 'quintela/migration-next-v5' into staging
[sdk/emulator/qemu.git] / scripts / qapi.py
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 def tokenize(data):
15     while len(data):
16         if data[0] in ['{', '}', ':', ',', '[', ']']:
17             yield data[0]
18             data = data[1:]
19         elif data[0] in ' \n':
20             data = data[1:]
21         elif data[0] == "'":
22             data = data[1:]
23             string = ''
24             while data[0] != "'":
25                 string += data[0]
26                 data = data[1:]
27             data = data[1:]
28             yield string
29
30 def parse(tokens):
31     if tokens[0] == '{':
32         ret = OrderedDict()
33         tokens = tokens[1:]
34         while tokens[0] != '}':
35             key = tokens[0]
36             tokens = tokens[1:]
37
38             tokens = tokens[1:] # :
39
40             value, tokens = parse(tokens)
41
42             if tokens[0] == ',':
43                 tokens = tokens[1:]
44
45             ret[key] = value
46         tokens = tokens[1:]
47         return ret, tokens
48     elif tokens[0] == '[':
49         ret = []
50         tokens = tokens[1:]
51         while tokens[0] != ']':
52             value, tokens = parse(tokens)
53             if tokens[0] == ',':
54                 tokens = tokens[1:]
55             ret.append(value)
56         tokens = tokens[1:]
57         return ret, tokens
58     else:
59         return tokens[0], tokens[1:]
60
61 def evaluate(string):
62     return parse(map(lambda x: x, tokenize(string)))[0]
63
64 def parse_schema(fp):
65     exprs = []
66     expr = ''
67     expr_eval = None
68
69     for line in fp:
70         if line.startswith('#') or line == '\n':
71             continue
72
73         if line.startswith(' '):
74             expr += line
75         elif expr:
76             expr_eval = evaluate(expr)
77             if expr_eval.has_key('enum'):
78                 add_enum(expr_eval['enum'])
79             elif expr_eval.has_key('union'):
80                 add_enum('%sKind' % expr_eval['union'])
81             exprs.append(expr_eval)
82             expr = line
83         else:
84             expr += line
85
86     if expr:
87         expr_eval = evaluate(expr)
88         if expr_eval.has_key('enum'):
89             add_enum(expr_eval['enum'])
90         elif expr_eval.has_key('union'):
91             add_enum('%sKind' % expr_eval['union'])
92         exprs.append(expr_eval)
93
94     return exprs
95
96 def parse_args(typeinfo):
97     for member in typeinfo:
98         argname = member
99         argentry = typeinfo[member]
100         optional = False
101         structured = False
102         if member.startswith('*'):
103             argname = member[1:]
104             optional = True
105         if isinstance(argentry, OrderedDict):
106             structured = True
107         yield (argname, argentry, optional, structured)
108
109 def de_camel_case(name):
110     new_name = ''
111     for ch in name:
112         if ch.isupper() and new_name:
113             new_name += '_'
114         if ch == '-':
115             new_name += '_'
116         else:
117             new_name += ch.lower()
118     return new_name
119
120 def camel_case(name):
121     new_name = ''
122     first = True
123     for ch in name:
124         if ch in ['_', '-']:
125             first = True
126         elif first:
127             new_name += ch.upper()
128             first = False
129         else:
130             new_name += ch.lower()
131     return new_name
132
133 def c_var(name):
134     return name.replace('-', '_').lstrip("*")
135
136 def c_fun(name):
137     return c_var(name).replace('.', '_')
138
139 def c_list_type(name):
140     return '%sList' % name
141
142 def type_name(name):
143     if type(name) == list:
144         return c_list_type(name[0])
145     return name
146
147 enum_types = []
148
149 def add_enum(name):
150     global enum_types
151     enum_types.append(name)
152
153 def is_enum(name):
154     global enum_types
155     return (name in enum_types)
156
157 def c_type(name):
158     if name == 'str':
159         return 'char *'
160     elif name == 'int':
161         return 'int64_t'
162     elif (name == 'int8' or name == 'int16' or name == 'int32' or
163           name == 'int64' or name == 'uint8' or name == 'uint16' or
164           name == 'uint32' or name == 'uint64'):
165         return name + '_t'
166     elif name == 'size':
167         return 'uint64_t'
168     elif name == 'bool':
169         return 'bool'
170     elif name == 'number':
171         return 'double'
172     elif type(name) == list:
173         return '%s *' % c_list_type(name[0])
174     elif is_enum(name):
175         return name
176     elif name == None or len(name) == 0:
177         return 'void'
178     elif name == name.upper():
179         return '%sEvent *' % camel_case(name)
180     else:
181         return '%s *' % name
182
183 def genindent(count):
184     ret = ""
185     for i in range(count):
186         ret += " "
187     return ret
188
189 indent_level = 0
190
191 def push_indent(indent_amount=4):
192     global indent_level
193     indent_level += indent_amount
194
195 def pop_indent(indent_amount=4):
196     global indent_level
197     indent_level -= indent_amount
198
199 def cgen(code, **kwds):
200     indent = genindent(indent_level)
201     lines = code.split('\n')
202     lines = map(lambda x: indent + x, lines)
203     return '\n'.join(lines) % kwds + '\n'
204
205 def mcgen(code, **kwds):
206     return cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
207
208 def basename(filename):
209     return filename.split("/")[-1]
210
211 def guardname(filename):
212     guard = basename(filename).rsplit(".", 1)[0]
213     for substr in [".", " ", "-"]:
214         guard = guard.replace(substr, "_")
215     return guard.upper() + '_H'