Merge remote-tracking branch 'mst/for_anthony' 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 '_'.join(name.split('-')).lstrip("*")
135
136 def c_list_type(name):
137     return '%sList' % name
138
139 def type_name(name):
140     if type(name) == list:
141         return c_list_type(name[0])
142     return name
143
144 enum_types = []
145
146 def add_enum(name):
147     global enum_types
148     enum_types.append(name)
149
150 def is_enum(name):
151     global enum_types
152     return (name in enum_types)
153
154 def c_type(name):
155     if name == 'str':
156         return 'char *'
157     elif name == 'int':
158         return 'int64_t'
159     elif name == 'bool':
160         return 'bool'
161     elif name == 'number':
162         return 'double'
163     elif type(name) == list:
164         return '%s *' % c_list_type(name[0])
165     elif is_enum(name):
166         return name
167     elif name == None or len(name) == 0:
168         return 'void'
169     elif name == name.upper():
170         return '%sEvent *' % camel_case(name)
171     else:
172         return '%s *' % name
173
174 def genindent(count):
175     ret = ""
176     for i in range(count):
177         ret += " "
178     return ret
179
180 indent_level = 0
181
182 def push_indent(indent_amount=4):
183     global indent_level
184     indent_level += indent_amount
185
186 def pop_indent(indent_amount=4):
187     global indent_level
188     indent_level -= indent_amount
189
190 def cgen(code, **kwds):
191     indent = genindent(indent_level)
192     lines = code.split('\n')
193     lines = map(lambda x: indent + x, lines)
194     return '\n'.join(lines) % kwds + '\n'
195
196 def mcgen(code, **kwds):
197     return cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
198
199 def basename(filename):
200     return filename.split("/")[-1]
201
202 def guardname(filename):
203     return filename.replace("/", "_").replace("-", "_").split(".")[0].upper()