]>
Commit | Line | Data |
---|---|---|
06d64c62 MR |
1 | # |
2 | # QAPI visitor generator | |
3 | # | |
4 | # Copyright IBM, Corp. 2011 | |
5 | # | |
6 | # Authors: | |
7 | # Anthony Liguori <aliguori@us.ibm.com> | |
8 | # Michael Roth <mdroth@linux.vnet.ibm.com> | |
9 | # | |
678e48a2 MA |
10 | # This work is licensed under the terms of the GNU GPL, version 2. |
11 | # See the COPYING file in the top-level directory. | |
06d64c62 MR |
12 | |
13 | from ordereddict import OrderedDict | |
14 | from qapi import * | |
15 | import sys | |
16 | import os | |
17 | import getopt | |
18 | import errno | |
19 | ||
be3c7717 MA |
20 | implicit_structs = [] |
21 | ||
22 | def generate_visit_implicit_struct(type): | |
23 | global implicit_structs | |
24 | if type in implicit_structs: | |
25 | return '' | |
26 | implicit_structs.append(type) | |
27 | return mcgen(''' | |
28 | ||
29 | static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp) | |
30 | { | |
31 | Error *err = NULL; | |
32 | ||
33 | visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err); | |
34 | if (!err) { | |
35 | visit_type_%(c_type)s_fields(m, obj, &err); | |
36 | error_propagate(errp, err); | |
37 | err = NULL; | |
38 | visit_end_implicit_struct(m, &err); | |
39 | } | |
40 | error_propagate(errp, err); | |
41 | } | |
42 | ''', | |
43 | c_type=type_name(type)) | |
44 | ||
622f557f | 45 | def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = None): |
50f2bdc7 | 46 | substructs = [] |
d131c897 | 47 | ret = '' |
7b75d9d6 RH |
48 | if not fn_prefix: |
49 | full_name = name | |
50 | else: | |
51 | full_name = "%s_%s" % (name, fn_prefix) | |
50f2bdc7 KW |
52 | |
53 | for argname, argentry, optional, structured in parse_args(members): | |
54 | if structured: | |
55 | if not fn_prefix: | |
56 | nested_fn_prefix = argname | |
57 | else: | |
58 | nested_fn_prefix = "%s_%s" % (fn_prefix, argname) | |
59 | ||
60 | nested_field_prefix = "%s%s." % (field_prefix, argname) | |
61 | ret += generate_visit_struct_fields(name, nested_field_prefix, | |
62 | nested_fn_prefix, argentry) | |
4fa953f2 MA |
63 | ret += mcgen(''' |
64 | ||
65 | static void visit_type_%(full_name)s_field_%(c_name)s(Visitor *m, %(name)s **obj, Error **errp) | |
66 | { | |
67 | Error *err = NULL; | |
68 | ''', | |
69 | name=name, full_name=full_name, c_name=c_var(argname)) | |
70 | push_indent() | |
71 | ret += generate_visit_struct_body(full_name, argname, argentry) | |
72 | pop_indent() | |
73 | ret += mcgen(''' | |
74 | } | |
75 | ''') | |
50f2bdc7 | 76 | |
be3c7717 MA |
77 | if base: |
78 | ret += generate_visit_implicit_struct(base) | |
79 | ||
50f2bdc7 KW |
80 | ret += mcgen(''' |
81 | ||
82 | static void visit_type_%(full_name)s_fields(Visitor *m, %(name)s ** obj, Error **errp) | |
83 | { | |
84 | Error *err = NULL; | |
85 | ''', | |
86 | name=name, full_name=full_name) | |
87 | push_indent() | |
d195325b | 88 | |
622f557f KW |
89 | if base: |
90 | ret += mcgen(''' | |
be3c7717 | 91 | visit_type_implicit_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, &err); |
622f557f KW |
92 | ''', |
93 | c_prefix=c_var(field_prefix), | |
94 | type=type_name(base), c_name=c_var('base')) | |
95 | ||
06d64c62 MR |
96 | for argname, argentry, optional, structured in parse_args(members): |
97 | if optional: | |
98 | ret += mcgen(''' | |
e2cd0f4f | 99 | visit_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err); |
949ceeb3 | 100 | if ((*obj)->%(prefix)shas_%(c_name)s) { |
06d64c62 MR |
101 | ''', |
102 | c_prefix=c_var(field_prefix), prefix=field_prefix, | |
103 | c_name=c_var(argname), name=argname) | |
104 | push_indent() | |
105 | ||
106 | if structured: | |
4fa953f2 MA |
107 | ret += mcgen(''' |
108 | visit_type_%(full_name)s_field_%(c_name)s(m, obj, &err); | |
109 | ''', | |
110 | full_name=full_name, c_name=c_var(argname)) | |
06d64c62 MR |
111 | else: |
112 | ret += mcgen(''' | |
949ceeb3 | 113 | visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err); |
06d64c62 MR |
114 | ''', |
115 | c_prefix=c_var(field_prefix), prefix=field_prefix, | |
116 | type=type_name(argentry), c_name=c_var(argname), | |
117 | name=argname) | |
118 | ||
119 | if optional: | |
120 | pop_indent() | |
121 | ret += mcgen(''' | |
122 | } | |
d195325b PB |
123 | ''') |
124 | ||
50f2bdc7 KW |
125 | pop_indent() |
126 | ret += mcgen(''' | |
127 | ||
128 | error_propagate(errp, err); | |
129 | } | |
130 | ''') | |
d131c897 KW |
131 | return ret |
132 | ||
133 | ||
134 | def generate_visit_struct_body(field_prefix, name, members): | |
135 | ret = mcgen(''' | |
136 | if (!error_is_set(errp)) { | |
137 | ''') | |
138 | push_indent() | |
139 | ||
7b75d9d6 RH |
140 | if not field_prefix: |
141 | full_name = name | |
142 | else: | |
143 | full_name = "%s_%s" % (field_prefix, name) | |
50f2bdc7 | 144 | |
d131c897 | 145 | if len(field_prefix): |
d131c897 | 146 | ret += mcgen(''' |
d131c897 KW |
147 | visit_start_struct(m, NULL, "", "%(name)s", 0, &err); |
148 | ''', | |
149 | name=name) | |
150 | else: | |
151 | ret += mcgen(''' | |
152 | Error *err = NULL; | |
153 | visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); | |
154 | ''', | |
155 | name=name) | |
156 | ||
d195325b | 157 | ret += mcgen(''' |
d131c897 | 158 | if (!err) { |
949ceeb3 | 159 | if (*obj) { |
50f2bdc7 KW |
160 | visit_type_%(name)s_fields(m, obj, &err); |
161 | error_propagate(errp, err); | |
162 | err = NULL; | |
163 | } | |
164 | ''', | |
165 | name=full_name) | |
d195325b | 166 | |
468866b8 MA |
167 | ret += mcgen(''' |
168 | /* Always call end_struct if start_struct succeeded. */ | |
169 | visit_end_struct(m, &err); | |
170 | } | |
171 | error_propagate(errp, err); | |
172 | ''') | |
d195325b PB |
173 | pop_indent() |
174 | ret += mcgen(''' | |
d195325b | 175 | } |
06d64c62 MR |
176 | ''') |
177 | return ret | |
178 | ||
14d36307 KW |
179 | def generate_visit_struct(expr): |
180 | ||
181 | name = expr['type'] | |
182 | members = expr['data'] | |
622f557f | 183 | base = expr.get('base') |
14d36307 | 184 | |
622f557f | 185 | ret = generate_visit_struct_fields(name, "", "", members, base) |
50f2bdc7 KW |
186 | |
187 | ret += mcgen(''' | |
06d64c62 MR |
188 | |
189 | void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp) | |
190 | { | |
06d64c62 MR |
191 | ''', |
192 | name=name) | |
d195325b | 193 | |
06d64c62 | 194 | push_indent() |
d195325b | 195 | ret += generate_visit_struct_body("", name, members) |
06d64c62 MR |
196 | pop_indent() |
197 | ||
198 | ret += mcgen(''' | |
06d64c62 MR |
199 | } |
200 | ''') | |
201 | return ret | |
202 | ||
203 | def generate_visit_list(name, members): | |
204 | return mcgen(''' | |
205 | ||
206 | void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp) | |
207 | { | |
3a86a0fa | 208 | GenericList *i, **prev = (GenericList **)obj; |
d195325b | 209 | Error *err = NULL; |
06d64c62 | 210 | |
d195325b PB |
211 | if (!error_is_set(errp)) { |
212 | visit_start_list(m, name, &err); | |
213 | if (!err) { | |
214 | for (; (i = visit_next_list(m, prev, &err)) != NULL; prev = &i) { | |
215 | %(name)sList *native_i = (%(name)sList *)i; | |
216 | visit_type_%(name)s(m, &native_i->value, NULL, &err); | |
217 | } | |
218 | error_propagate(errp, err); | |
219 | err = NULL; | |
220 | ||
221 | /* Always call end_list if start_list succeeded. */ | |
222 | visit_end_list(m, &err); | |
223 | } | |
224 | error_propagate(errp, err); | |
06d64c62 | 225 | } |
06d64c62 MR |
226 | } |
227 | ''', | |
228 | name=name) | |
229 | ||
230 | def generate_visit_enum(name, members): | |
231 | return mcgen(''' | |
232 | ||
233 | void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp) | |
234 | { | |
235 | visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp); | |
236 | } | |
237 | ''', | |
238 | name=name) | |
239 | ||
69dd62df KW |
240 | def generate_visit_anon_union(name, members): |
241 | ret = mcgen(''' | |
242 | ||
243 | void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp) | |
244 | { | |
245 | Error *err = NULL; | |
246 | ||
247 | if (!error_is_set(errp)) { | |
248 | visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err); | |
249 | visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err); | |
250 | switch ((*obj)->kind) { | |
251 | ''', | |
252 | name=name) | |
253 | ||
b0b58195 WX |
254 | # For anon union, always use the default enum type automatically generated |
255 | # as "'%sKind' % (name)" | |
256 | disc_type = '%sKind' % (name) | |
257 | ||
69dd62df KW |
258 | for key in members: |
259 | assert (members[key] in builtin_types | |
260 | or find_struct(members[key]) | |
261 | or find_union(members[key])), "Invalid anonymous union member" | |
262 | ||
b0b58195 | 263 | enum_full_value = generate_enum_full_value(disc_type, key) |
69dd62df | 264 | ret += mcgen(''' |
b0b58195 | 265 | case %(enum_full_value)s: |
69dd62df KW |
266 | visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); |
267 | break; | |
268 | ''', | |
b0b58195 | 269 | enum_full_value = enum_full_value, |
69dd62df KW |
270 | c_type = type_name(members[key]), |
271 | c_name = c_fun(key)) | |
272 | ||
273 | ret += mcgen(''' | |
274 | default: | |
275 | abort(); | |
276 | } | |
277 | error_propagate(errp, err); | |
278 | err = NULL; | |
279 | visit_end_implicit_struct(m, &err); | |
280 | } | |
281 | } | |
282 | ''') | |
283 | ||
284 | return ret | |
285 | ||
286 | ||
0aef92b9 KW |
287 | def generate_visit_union(expr): |
288 | ||
289 | name = expr['union'] | |
290 | members = expr['data'] | |
291 | ||
292 | base = expr.get('base') | |
50f2bdc7 | 293 | discriminator = expr.get('discriminator') |
0aef92b9 | 294 | |
69dd62df KW |
295 | if discriminator == {}: |
296 | assert not base | |
297 | return generate_visit_anon_union(name, members) | |
298 | ||
bceae769 WX |
299 | enum_define = discriminator_find_enum_define(expr) |
300 | if enum_define: | |
301 | # Use the enum type as discriminator | |
302 | ret = "" | |
303 | disc_type = enum_define['enum_name'] | |
304 | else: | |
305 | # There will always be a discriminator in the C switch code, by default it | |
306 | # is an enum type generated silently as "'%sKind' % (name)" | |
307 | ret = generate_visit_enum('%sKind' % name, members.keys()) | |
308 | disc_type = '%sKind' % (name) | |
06d64c62 | 309 | |
50f2bdc7 KW |
310 | if base: |
311 | base_fields = find_struct(base)['data'] | |
312 | if discriminator: | |
313 | base_fields = base_fields.copy() | |
314 | del base_fields[discriminator] | |
315 | ret += generate_visit_struct_fields(name, "", "", base_fields) | |
316 | ||
be3c7717 MA |
317 | if discriminator: |
318 | for key in members: | |
319 | ret += generate_visit_implicit_struct(members[key]) | |
320 | ||
06d64c62 MR |
321 | ret += mcgen(''' |
322 | ||
323 | void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp) | |
324 | { | |
dc8fb6df PB |
325 | Error *err = NULL; |
326 | ||
d195325b PB |
327 | if (!error_is_set(errp)) { |
328 | visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); | |
329 | if (!err) { | |
949ceeb3 | 330 | if (*obj) { |
06d64c62 MR |
331 | ''', |
332 | name=name) | |
333 | ||
d195325b | 334 | push_indent() |
0aef92b9 KW |
335 | push_indent() |
336 | ||
337 | if base: | |
50f2bdc7 | 338 | ret += mcgen(''' |
468866b8 | 339 | visit_type_%(name)s_fields(m, obj, &err); |
50f2bdc7 KW |
340 | ''', |
341 | name=name) | |
0aef92b9 | 342 | |
7b75d9d6 | 343 | if not discriminator: |
bceae769 | 344 | disc_key = "type" |
7b75d9d6 | 345 | else: |
bceae769 | 346 | disc_key = discriminator |
0aef92b9 | 347 | ret += mcgen(''' |
bceae769 | 348 | visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err); |
0aef92b9 KW |
349 | if (!err) { |
350 | switch ((*obj)->kind) { | |
351 | ''', | |
bceae769 WX |
352 | disc_type = disc_type, |
353 | disc_key = disc_key) | |
0aef92b9 | 354 | |
dc8fb6df | 355 | for key in members: |
50f2bdc7 KW |
356 | if not discriminator: |
357 | fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);' | |
358 | else: | |
be3c7717 | 359 | fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);' |
50f2bdc7 | 360 | |
b0b58195 | 361 | enum_full_value = generate_enum_full_value(disc_type, key) |
dc8fb6df | 362 | ret += mcgen(''' |
b0b58195 | 363 | case %(enum_full_value)s: |
50f2bdc7 | 364 | ''' + fmt + ''' |
d195325b | 365 | break; |
dc8fb6df | 366 | ''', |
b0b58195 | 367 | enum_full_value = enum_full_value, |
c664aef5 | 368 | c_type=type_name(members[key]), |
c9da228b | 369 | c_name=c_fun(key)) |
dc8fb6df PB |
370 | |
371 | ret += mcgen(''' | |
d195325b PB |
372 | default: |
373 | abort(); | |
374 | } | |
375 | } | |
376 | error_propagate(errp, err); | |
377 | err = NULL; | |
d195325b PB |
378 | ''') |
379 | pop_indent() | |
468866b8 | 380 | pop_indent() |
d195325b | 381 | |
d195325b | 382 | ret += mcgen(''' |
468866b8 MA |
383 | } |
384 | /* Always call end_struct if start_struct succeeded. */ | |
385 | visit_end_struct(m, &err); | |
386 | } | |
387 | error_propagate(errp, err); | |
388 | } | |
dc8fb6df PB |
389 | } |
390 | ''') | |
391 | ||
06d64c62 MR |
392 | return ret |
393 | ||
7c946bc4 MR |
394 | def generate_declaration(name, members, genlist=True, builtin_type=False): |
395 | ret = "" | |
396 | if not builtin_type: | |
397 | ret += mcgen(''' | |
06d64c62 MR |
398 | |
399 | void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp); | |
400 | ''', | |
7c946bc4 | 401 | name=name) |
06d64c62 MR |
402 | |
403 | if genlist: | |
404 | ret += mcgen(''' | |
405 | void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp); | |
406 | ''', | |
407 | name=name) | |
408 | ||
409 | return ret | |
410 | ||
b9c4b48d AK |
411 | def generate_enum_declaration(name, members, genlist=True): |
412 | ret = "" | |
413 | if genlist: | |
414 | ret += mcgen(''' | |
415 | void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp); | |
416 | ''', | |
417 | name=name) | |
418 | ||
419 | return ret | |
420 | ||
06d64c62 MR |
421 | def generate_decl_enum(name, members, genlist=True): |
422 | return mcgen(''' | |
423 | ||
424 | void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp); | |
425 | ''', | |
426 | name=name) | |
427 | ||
428 | try: | |
33aaad52 | 429 | opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:", |
7c946bc4 | 430 | ["source", "header", "builtins", "prefix=", |
33aaad52 | 431 | "input-file=", "output-dir="]) |
06d64c62 MR |
432 | except getopt.GetoptError, err: |
433 | print str(err) | |
434 | sys.exit(1) | |
435 | ||
33aaad52 | 436 | input_file = "" |
06d64c62 MR |
437 | output_dir = "" |
438 | prefix = "" | |
439 | c_file = 'qapi-visit.c' | |
440 | h_file = 'qapi-visit.h' | |
441 | ||
8d3bc517 AK |
442 | do_c = False |
443 | do_h = False | |
7c946bc4 | 444 | do_builtins = False |
8d3bc517 | 445 | |
06d64c62 MR |
446 | for o, a in opts: |
447 | if o in ("-p", "--prefix"): | |
448 | prefix = a | |
33aaad52 LV |
449 | elif o in ("-i", "--input-file"): |
450 | input_file = a | |
06d64c62 MR |
451 | elif o in ("-o", "--output-dir"): |
452 | output_dir = a + "/" | |
8d3bc517 | 453 | elif o in ("-c", "--source"): |
8d3bc517 | 454 | do_c = True |
19bf7c87 AK |
455 | elif o in ("-h", "--header"): |
456 | do_h = True | |
7c946bc4 MR |
457 | elif o in ("-b", "--builtins"): |
458 | do_builtins = True | |
8d3bc517 AK |
459 | |
460 | if not do_c and not do_h: | |
461 | do_c = True | |
462 | do_h = True | |
06d64c62 MR |
463 | |
464 | c_file = output_dir + prefix + c_file | |
465 | h_file = output_dir + prefix + h_file | |
466 | ||
467 | try: | |
468 | os.makedirs(output_dir) | |
469 | except os.error, e: | |
470 | if e.errno != errno.EEXIST: | |
471 | raise | |
472 | ||
8d3bc517 | 473 | def maybe_open(really, name, opt): |
8d3bc517 AK |
474 | if really: |
475 | return open(name, opt) | |
19bf7c87 AK |
476 | else: |
477 | import StringIO | |
478 | return StringIO.StringIO() | |
8d3bc517 AK |
479 | |
480 | fdef = maybe_open(do_c, c_file, 'w') | |
481 | fdecl = maybe_open(do_h, h_file, 'w') | |
06d64c62 MR |
482 | |
483 | fdef.write(mcgen(''' | |
484 | /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ | |
485 | ||
486 | /* | |
487 | * schema-defined QAPI visitor functions | |
488 | * | |
489 | * Copyright IBM, Corp. 2011 | |
490 | * | |
491 | * Authors: | |
492 | * Anthony Liguori <aliguori@us.ibm.com> | |
493 | * | |
494 | * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. | |
495 | * See the COPYING.LIB file in the top-level directory. | |
496 | * | |
497 | */ | |
498 | ||
79ee7df8 | 499 | #include "qemu-common.h" |
06d64c62 MR |
500 | #include "%(header)s" |
501 | ''', | |
502 | header=basename(h_file))) | |
503 | ||
504 | fdecl.write(mcgen(''' | |
505 | /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ | |
506 | ||
507 | /* | |
508 | * schema-defined QAPI visitor function | |
509 | * | |
510 | * Copyright IBM, Corp. 2011 | |
511 | * | |
512 | * Authors: | |
513 | * Anthony Liguori <aliguori@us.ibm.com> | |
514 | * | |
515 | * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. | |
516 | * See the COPYING.LIB file in the top-level directory. | |
517 | * | |
518 | */ | |
519 | ||
520 | #ifndef %(guard)s | |
521 | #define %(guard)s | |
522 | ||
7b1b5d19 | 523 | #include "qapi/visitor.h" |
06d64c62 | 524 | #include "%(prefix)sqapi-types.h" |
7c946bc4 | 525 | |
06d64c62 MR |
526 | ''', |
527 | prefix=prefix, guard=guardname(h_file))) | |
528 | ||
33aaad52 | 529 | exprs = parse_schema(input_file) |
06d64c62 | 530 | |
7c946bc4 MR |
531 | # to avoid header dependency hell, we always generate declarations |
532 | # for built-in types in our header files and simply guard them | |
533 | fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL")) | |
534 | for typename in builtin_types: | |
535 | fdecl.write(generate_declaration(typename, None, genlist=True, | |
536 | builtin_type=True)) | |
537 | fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL")) | |
538 | ||
539 | # ...this doesn't work for cases where we link in multiple objects that | |
540 | # have the functions defined, so we use -b option to provide control | |
541 | # over these cases | |
542 | if do_builtins: | |
7c946bc4 MR |
543 | for typename in builtin_types: |
544 | fdef.write(generate_visit_list(typename, None)) | |
7c946bc4 | 545 | |
06d64c62 MR |
546 | for expr in exprs: |
547 | if expr.has_key('type'): | |
14d36307 | 548 | ret = generate_visit_struct(expr) |
06d64c62 MR |
549 | ret += generate_visit_list(expr['type'], expr['data']) |
550 | fdef.write(ret) | |
551 | ||
552 | ret = generate_declaration(expr['type'], expr['data']) | |
553 | fdecl.write(ret) | |
554 | elif expr.has_key('union'): | |
0aef92b9 | 555 | ret = generate_visit_union(expr) |
dc8fb6df | 556 | ret += generate_visit_list(expr['union'], expr['data']) |
06d64c62 MR |
557 | fdef.write(ret) |
558 | ||
bceae769 WX |
559 | enum_define = discriminator_find_enum_define(expr) |
560 | ret = "" | |
561 | if not enum_define: | |
562 | ret = generate_decl_enum('%sKind' % expr['union'], | |
563 | expr['data'].keys()) | |
06d64c62 MR |
564 | ret += generate_declaration(expr['union'], expr['data']) |
565 | fdecl.write(ret) | |
566 | elif expr.has_key('enum'): | |
b9c4b48d AK |
567 | ret = generate_visit_list(expr['enum'], expr['data']) |
568 | ret += generate_visit_enum(expr['enum'], expr['data']) | |
06d64c62 MR |
569 | fdef.write(ret) |
570 | ||
571 | ret = generate_decl_enum(expr['enum'], expr['data']) | |
b9c4b48d | 572 | ret += generate_enum_declaration(expr['enum'], expr['data']) |
06d64c62 MR |
573 | fdecl.write(ret) |
574 | ||
575 | fdecl.write(''' | |
576 | #endif | |
577 | ''') | |
578 | ||
579 | fdecl.flush() | |
580 | fdecl.close() | |
581 | ||
582 | fdef.flush() | |
583 | fdef.close() |