qapi: add qapi.py helper libraries
[qemu.git] / scripts / qapi.py
blob56af2329bb4a4db772a3930e9c6a33d7a1e75211
2 # QAPI helper library
4 # Copyright IBM, Corp. 2011
6 # Authors:
7 # Anthony Liguori <aliguori@us.ibm.com>
9 # This work is licensed under the terms of the GNU GPLv2.
10 # See the COPYING.LIB file in the top-level directory.
12 from ordereddict import OrderedDict
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
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:]
38 tokens = tokens[1:] # :
40 value, tokens = parse(tokens)
42 if tokens[0] == ',':
43 tokens = tokens[1:]
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:]
61 def evaluate(string):
62 return parse(map(lambda x: x, tokenize(string)))[0]
64 def parse_schema(fp):
65 exprs = []
66 expr = ''
67 expr_eval = None
69 for line in fp:
70 if line.startswith('#') or line == '\n':
71 continue
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
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)
94 return exprs
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)
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
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
133 def c_var(name):
134 return '_'.join(name.split('-')).lstrip("*")
136 def c_list_type(name):
137 return '%sList' % name
139 def type_name(name):
140 if type(name) == list:
141 return c_list_type(name[0])
142 return name
144 enum_types = []
146 def add_enum(name):
147 global enum_types
148 enum_types.append(name)
150 def is_enum(name):
151 global enum_types
152 return (name in enum_types)
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
174 def genindent(count):
175 ret = ""
176 for i in range(count):
177 ret += " "
178 return ret
180 indent_level = 0
182 def push_indent(indent_amount=4):
183 global indent_level
184 indent_level += indent_amount
186 def pop_indent(indent_amount=4):
187 global indent_level
188 indent_level -= indent_amount
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'
196 def mcgen(code, **kwds):
197 return cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
199 def basename(filename):
200 return filename.split("/")[-1]
202 def guardname(filename):
203 return filename.replace("/", "_").replace("-", "_").split(".")[0].upper()