4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2015 Red Hat Inc.
8 # Anthony Liguori <aliguori@us.ibm.com>
9 # Markus Armbruster <armbru@redhat.com>
11 # This work is licensed under the terms of the GNU GPL, version 2.
12 # See the COPYING file in the top-level directory.
15 from ordereddict
import OrderedDict
23 'str': 'QTYPE_QSTRING',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
28 'int16': 'QTYPE_QINT',
29 'int32': 'QTYPE_QINT',
30 'int64': 'QTYPE_QINT',
31 'uint8': 'QTYPE_QINT',
32 'uint16': 'QTYPE_QINT',
33 'uint32': 'QTYPE_QINT',
34 'uint64': 'QTYPE_QINT',
38 # Whitelist of commands allowed to return a non-dictionary
41 'human-monitor-command',
42 'query-migrate-cache-size',
49 'guest-fsfreeze-freeze',
50 'guest-fsfreeze-freeze-list',
51 'guest-fsfreeze-status',
52 'guest-fsfreeze-thaw',
56 'guest-sync-delimited',
58 # From qapi-schema-test:
69 # Parsing the schema into expressions
72 def error_path(parent
):
75 res
= ("In file included from %s:%d:\n" % (parent
['file'],
76 parent
['line'])) + res
77 parent
= parent
['parent']
80 class QAPISchemaError(Exception):
81 def __init__(self
, schema
, msg
):
82 self
.fname
= schema
.fname
85 self
.line
= schema
.line
86 for ch
in schema
.src
[schema
.line_pos
:schema
.pos
]:
88 self
.col
= (self
.col
+ 7) % 8 + 1
91 self
.info
= schema
.incl_info
94 return error_path(self
.info
) + \
95 "%s:%d:%d: %s" % (self
.fname
, self
.line
, self
.col
, self
.msg
)
97 class QAPIExprError(Exception):
98 def __init__(self
, expr_info
, msg
):
103 return error_path(self
.info
['parent']) + \
104 "%s:%d: %s" % (self
.info
['file'], self
.info
['line'], self
.msg
)
106 class QAPISchemaParser(object):
108 def __init__(self
, fp
, previously_included
= [], incl_info
= None):
109 abs_fname
= os
.path
.abspath(fp
.name
)
112 previously_included
.append(abs_fname
)
113 self
.incl_info
= incl_info
115 if self
.src
== '' or self
.src
[-1] != '\n':
123 while self
.tok
!= None:
124 expr_info
= {'file': fname
, 'line': self
.line
,
125 'parent': self
.incl_info
}
126 expr
= self
.get_expr(False)
127 if isinstance(expr
, dict) and "include" in expr
:
129 raise QAPIExprError(expr_info
, "Invalid 'include' directive")
130 include
= expr
["include"]
131 if not isinstance(include
, str):
132 raise QAPIExprError(expr_info
,
133 'Expected a file name (string), got: %s'
135 incl_abs_fname
= os
.path
.join(os
.path
.dirname(abs_fname
),
137 # catch inclusion cycle
140 if incl_abs_fname
== os
.path
.abspath(inf
['file']):
141 raise QAPIExprError(expr_info
, "Inclusion loop for %s"
144 # skip multiple include of the same file
145 if incl_abs_fname
in previously_included
:
148 fobj
= open(incl_abs_fname
, 'r')
150 raise QAPIExprError(expr_info
,
151 '%s: %s' % (e
.strerror
, include
))
152 exprs_include
= QAPISchemaParser(fobj
, previously_included
,
154 self
.exprs
.extend(exprs_include
.exprs
)
156 expr_elem
= {'expr': expr
,
158 self
.exprs
.append(expr_elem
)
162 self
.tok
= self
.src
[self
.cursor
]
163 self
.pos
= self
.cursor
168 self
.cursor
= self
.src
.find('\n', self
.cursor
)
169 elif self
.tok
in ['{', '}', ':', ',', '[', ']']:
171 elif self
.tok
== "'":
175 ch
= self
.src
[self
.cursor
]
178 raise QAPISchemaError(self
,
179 'Missing terminating "\'"')
193 for x
in range(0, 4):
194 ch
= self
.src
[self
.cursor
]
196 if ch
not in "0123456789abcdefABCDEF":
197 raise QAPISchemaError(self
,
198 '\\u escape needs 4 '
200 value
= (value
<< 4) + int(ch
, 16)
201 # If Python 2 and 3 didn't disagree so much on
202 # how to handle Unicode, then we could allow
203 # Unicode string defaults. But most of QAPI is
204 # ASCII-only, so we aren't losing much for now.
205 if not value
or value
> 0x7f:
206 raise QAPISchemaError(self
,
207 'For now, \\u escape '
208 'only supports non-zero '
209 'values up to \\u007f')
214 raise QAPISchemaError(self
,
215 "Unknown escape \\%s" %ch
)
224 elif self
.src
.startswith("true", self
.pos
):
228 elif self
.src
.startswith("false", self
.pos
):
232 elif self
.src
.startswith("null", self
.pos
):
236 elif self
.tok
== '\n':
237 if self
.cursor
== len(self
.src
):
241 self
.line_pos
= self
.cursor
242 elif not self
.tok
.isspace():
243 raise QAPISchemaError(self
, 'Stray "%s"' % self
.tok
)
245 def get_members(self
):
251 raise QAPISchemaError(self
, 'Expected string or "}"')
256 raise QAPISchemaError(self
, 'Expected ":"')
259 raise QAPISchemaError(self
, 'Duplicate key "%s"' % key
)
260 expr
[key
] = self
.get_expr(True)
265 raise QAPISchemaError(self
, 'Expected "," or "}"')
268 raise QAPISchemaError(self
, 'Expected string')
270 def get_values(self
):
275 if not self
.tok
in "{['tfn":
276 raise QAPISchemaError(self
, 'Expected "{", "[", "]", string, '
279 expr
.append(self
.get_expr(True))
284 raise QAPISchemaError(self
, 'Expected "," or "]"')
287 def get_expr(self
, nested
):
288 if self
.tok
!= '{' and not nested
:
289 raise QAPISchemaError(self
, 'Expected "{"')
292 expr
= self
.get_members()
293 elif self
.tok
== '[':
295 expr
= self
.get_values()
296 elif self
.tok
in "'tfn":
300 raise QAPISchemaError(self
, 'Expected "{", "[" or string')
304 # Semantic analysis of schema expressions
305 # TODO fold into QAPISchema
306 # TODO catching name collisions in generated code would be nice
309 def find_base_fields(base
):
310 base_struct_define
= find_struct(base
)
311 if not base_struct_define
:
313 return base_struct_define
['data']
315 # Return the qtype of an alternate branch, or None on error.
316 def find_alternate_member_qtype(qapi_type
):
317 if builtin_types
.has_key(qapi_type
):
318 return builtin_types
[qapi_type
]
319 elif find_struct(qapi_type
):
321 elif find_enum(qapi_type
):
322 return "QTYPE_QSTRING"
323 elif find_union(qapi_type
):
327 # Return the discriminator enum define if discriminator is specified as an
328 # enum type, otherwise return None.
329 def discriminator_find_enum_define(expr
):
330 base
= expr
.get('base')
331 discriminator
= expr
.get('discriminator')
333 if not (discriminator
and base
):
336 base_fields
= find_base_fields(base
)
340 discriminator_type
= base_fields
.get(discriminator
)
341 if not discriminator_type
:
344 return find_enum(discriminator_type
)
346 # FIXME should enforce "other than downstream extensions [...], all
347 # names should begin with a letter".
348 valid_name
= re
.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
349 def check_name(expr_info
, source
, name
, allow_optional
= False,
350 enum_member
= False):
354 if not isinstance(name
, str):
355 raise QAPIExprError(expr_info
,
356 "%s requires a string name" % source
)
357 if name
.startswith('*'):
358 membername
= name
[1:]
359 if not allow_optional
:
360 raise QAPIExprError(expr_info
,
361 "%s does not allow optional name '%s'"
363 # Enum members can start with a digit, because the generated C
364 # code always prefixes it with the enum name
366 membername
= '_' + membername
367 if not valid_name
.match(membername
):
368 raise QAPIExprError(expr_info
,
369 "%s uses invalid name '%s'" % (source
, name
))
371 def add_name(name
, info
, meta
, implicit
= False):
373 check_name(info
, "'%s'" % meta
, name
)
374 # FIXME should reject names that differ only in '_' vs. '.'
375 # vs. '-', because they're liable to clash in generated C.
376 if name
in all_names
:
377 raise QAPIExprError(info
,
378 "%s '%s' is already defined"
379 % (all_names
[name
], name
))
380 if not implicit
and name
[-4:] == 'Kind':
381 raise QAPIExprError(info
,
382 "%s '%s' should not end in 'Kind'"
384 all_names
[name
] = meta
386 def add_struct(definition
, info
):
388 name
= definition
['struct']
389 add_name(name
, info
, 'struct')
390 struct_types
.append(definition
)
392 def find_struct(name
):
394 for struct
in struct_types
:
395 if struct
['struct'] == name
:
399 def add_union(definition
, info
):
401 name
= definition
['union']
402 add_name(name
, info
, 'union')
403 union_types
.append(definition
)
405 def find_union(name
):
407 for union
in union_types
:
408 if union
['union'] == name
:
412 def add_enum(name
, info
, enum_values
= None, implicit
= False):
414 add_name(name
, info
, 'enum', implicit
)
415 enum_types
.append({"enum_name": name
, "enum_values": enum_values
})
419 for enum
in enum_types
:
420 if enum
['enum_name'] == name
:
425 return find_enum(name
) != None
427 def check_type(expr_info
, source
, value
, allow_array
= False,
428 allow_dict
= False, allow_optional
= False,
429 allow_star
= False, allow_metas
= []):
435 if allow_star
and value
== '**':
438 # Check if array type for value is okay
439 if isinstance(value
, list):
441 raise QAPIExprError(expr_info
,
442 "%s cannot be an array" % source
)
443 if len(value
) != 1 or not isinstance(value
[0], str):
444 raise QAPIExprError(expr_info
,
445 "%s: array type must contain single type name"
449 # Check if type name for value is okay
450 if isinstance(value
, str):
452 raise QAPIExprError(expr_info
,
453 "%s uses '**' but did not request 'gen':false"
455 if not value
in all_names
:
456 raise QAPIExprError(expr_info
,
457 "%s uses unknown type '%s'"
459 if not all_names
[value
] in allow_metas
:
460 raise QAPIExprError(expr_info
,
461 "%s cannot use %s type '%s'"
462 % (source
, all_names
[value
], value
))
466 raise QAPIExprError(expr_info
,
467 "%s should be a type name" % source
)
469 if not isinstance(value
, OrderedDict
):
470 raise QAPIExprError(expr_info
,
471 "%s should be a dictionary or type name" % source
)
473 # value is a dictionary, check that each member is okay
474 for (key
, arg
) in value
.items():
475 check_name(expr_info
, "Member of %s" % source
, key
,
476 allow_optional
=allow_optional
)
477 # Todo: allow dictionaries to represent default values of
478 # an optional argument.
479 check_type(expr_info
, "Member '%s' of %s" % (key
, source
), arg
,
480 allow_array
=True, allow_star
=allow_star
,
481 allow_metas
=['built-in', 'union', 'alternate', 'struct',
484 def check_member_clash(expr_info
, base_name
, data
, source
= ""):
485 base
= find_struct(base_name
)
487 base_members
= base
['data']
488 for key
in data
.keys():
489 if key
.startswith('*'):
491 if key
in base_members
or "*" + key
in base_members
:
492 raise QAPIExprError(expr_info
,
493 "Member name '%s'%s clashes with base '%s'"
494 % (key
, source
, base_name
))
496 check_member_clash(expr_info
, base
['base'], data
, source
)
498 def check_command(expr
, expr_info
):
499 name
= expr
['command']
500 allow_star
= expr
.has_key('gen')
502 check_type(expr_info
, "'data' for command '%s'" % name
,
503 expr
.get('data'), allow_dict
=True, allow_optional
=True,
504 allow_metas
=['struct'], allow_star
=allow_star
)
505 returns_meta
= ['union', 'struct']
506 if name
in returns_whitelist
:
507 returns_meta
+= ['built-in', 'alternate', 'enum']
508 check_type(expr_info
, "'returns' for command '%s'" % name
,
509 expr
.get('returns'), allow_array
=True,
510 allow_optional
=True, allow_metas
=returns_meta
,
511 allow_star
=allow_star
)
513 def check_event(expr
, expr_info
):
517 if name
.upper() == 'MAX':
518 raise QAPIExprError(expr_info
, "Event name 'MAX' cannot be created")
520 check_type(expr_info
, "'data' for event '%s'" % name
,
521 expr
.get('data'), allow_dict
=True, allow_optional
=True,
522 allow_metas
=['struct'])
524 def check_union(expr
, expr_info
):
526 base
= expr
.get('base')
527 discriminator
= expr
.get('discriminator')
528 members
= expr
['data']
529 values
= { 'MAX': '(automatic)' }
531 # Two types of unions, determined by discriminator.
533 # With no discriminator it is a simple union.
534 if discriminator
is None:
536 allow_metas
=['built-in', 'union', 'alternate', 'struct', 'enum']
538 raise QAPIExprError(expr_info
,
539 "Simple union '%s' must not have a base"
542 # Else, it's a flat union.
544 # The object must have a string member 'base'.
545 if not isinstance(base
, str):
546 raise QAPIExprError(expr_info
,
547 "Flat union '%s' must have a string base field"
549 base_fields
= find_base_fields(base
)
551 raise QAPIExprError(expr_info
,
552 "Base '%s' is not a valid struct"
555 # The value of member 'discriminator' must name a non-optional
556 # member of the base struct.
557 check_name(expr_info
, "Discriminator of flat union '%s'" % name
,
559 discriminator_type
= base_fields
.get(discriminator
)
560 if not discriminator_type
:
561 raise QAPIExprError(expr_info
,
562 "Discriminator '%s' is not a member of base "
564 % (discriminator
, base
))
565 enum_define
= find_enum(discriminator_type
)
566 allow_metas
=['struct']
567 # Do not allow string discriminator
569 raise QAPIExprError(expr_info
,
570 "Discriminator '%s' must be of enumeration "
571 "type" % discriminator
)
574 for (key
, value
) in members
.items():
575 check_name(expr_info
, "Member of union '%s'" % name
, key
)
577 # Each value must name a known type; furthermore, in flat unions,
578 # branches must be a struct with no overlapping member names
579 check_type(expr_info
, "Member '%s' of union '%s'" % (key
, name
),
580 value
, allow_array
=not base
, allow_metas
=allow_metas
)
582 branch_struct
= find_struct(value
)
584 check_member_clash(expr_info
, base
, branch_struct
['data'],
585 " of branch '%s'" % key
)
587 # If the discriminator names an enum type, then all members
588 # of 'data' must also be members of the enum type.
590 if not key
in enum_define
['enum_values']:
591 raise QAPIExprError(expr_info
,
592 "Discriminator value '%s' is not found in "
594 (key
, enum_define
["enum_name"]))
596 # Otherwise, check for conflicts in the generated enum
598 c_key
= camel_to_upper(key
)
600 raise QAPIExprError(expr_info
,
601 "Union '%s' member '%s' clashes with '%s'"
602 % (name
, key
, values
[c_key
]))
605 def check_alternate(expr
, expr_info
):
606 name
= expr
['alternate']
607 members
= expr
['data']
608 values
= { 'MAX': '(automatic)' }
612 for (key
, value
) in members
.items():
613 check_name(expr_info
, "Member of alternate '%s'" % name
, key
)
615 # Check for conflicts in the generated enum
616 c_key
= camel_to_upper(key
)
618 raise QAPIExprError(expr_info
,
619 "Alternate '%s' member '%s' clashes with '%s'"
620 % (name
, key
, values
[c_key
]))
623 # Ensure alternates have no type conflicts.
624 check_type(expr_info
, "Member '%s' of alternate '%s'" % (key
, name
),
626 allow_metas
=['built-in', 'union', 'struct', 'enum'])
627 qtype
= find_alternate_member_qtype(value
)
629 if qtype
in types_seen
:
630 raise QAPIExprError(expr_info
,
631 "Alternate '%s' member '%s' can't "
632 "be distinguished from member '%s'"
633 % (name
, key
, types_seen
[qtype
]))
634 types_seen
[qtype
] = key
636 def check_enum(expr
, expr_info
):
638 members
= expr
.get('data')
639 prefix
= expr
.get('prefix')
640 values
= { 'MAX': '(automatic)' }
642 if not isinstance(members
, list):
643 raise QAPIExprError(expr_info
,
644 "Enum '%s' requires an array for 'data'" % name
)
645 if prefix
is not None and not isinstance(prefix
, str):
646 raise QAPIExprError(expr_info
,
647 "Enum '%s' requires a string for 'prefix'" % name
)
648 for member
in members
:
649 check_name(expr_info
, "Member of enum '%s'" %name
, member
,
651 key
= camel_to_upper(member
)
653 raise QAPIExprError(expr_info
,
654 "Enum '%s' member '%s' clashes with '%s'"
655 % (name
, member
, values
[key
]))
658 def check_struct(expr
, expr_info
):
659 name
= expr
['struct']
660 members
= expr
['data']
662 check_type(expr_info
, "'data' for struct '%s'" % name
, members
,
663 allow_dict
=True, allow_optional
=True)
664 check_type(expr_info
, "'base' for struct '%s'" % name
, expr
.get('base'),
665 allow_metas
=['struct'])
667 check_member_clash(expr_info
, expr
['base'], expr
['data'])
669 def check_keys(expr_elem
, meta
, required
, optional
=[]):
670 expr
= expr_elem
['expr']
671 info
= expr_elem
['info']
673 if not isinstance(name
, str):
674 raise QAPIExprError(info
,
675 "'%s' key must have a string value" % meta
)
676 required
= required
+ [ meta
]
677 for (key
, value
) in expr
.items():
678 if not key
in required
and not key
in optional
:
679 raise QAPIExprError(info
,
680 "Unknown key '%s' in %s '%s'"
682 if (key
== 'gen' or key
== 'success-response') and value
!= False:
683 raise QAPIExprError(info
,
684 "'%s' of %s '%s' should only use false value"
687 if not expr
.has_key(key
):
688 raise QAPIExprError(info
,
689 "Key '%s' is missing from %s '%s'"
692 def check_exprs(exprs
):
695 # Learn the types and check for valid expression keys
696 for builtin
in builtin_types
.keys():
697 all_names
[builtin
] = 'built-in'
698 for expr_elem
in exprs
:
699 expr
= expr_elem
['expr']
700 info
= expr_elem
['info']
701 if expr
.has_key('enum'):
702 check_keys(expr_elem
, 'enum', ['data'], ['prefix'])
703 add_enum(expr
['enum'], info
, expr
['data'])
704 elif expr
.has_key('union'):
705 check_keys(expr_elem
, 'union', ['data'],
706 ['base', 'discriminator'])
707 add_union(expr
, info
)
708 elif expr
.has_key('alternate'):
709 check_keys(expr_elem
, 'alternate', ['data'])
710 add_name(expr
['alternate'], info
, 'alternate')
711 elif expr
.has_key('struct'):
712 check_keys(expr_elem
, 'struct', ['data'], ['base'])
713 add_struct(expr
, info
)
714 elif expr
.has_key('command'):
715 check_keys(expr_elem
, 'command', [],
716 ['data', 'returns', 'gen', 'success-response'])
717 add_name(expr
['command'], info
, 'command')
718 elif expr
.has_key('event'):
719 check_keys(expr_elem
, 'event', [], ['data'])
720 add_name(expr
['event'], info
, 'event')
722 raise QAPIExprError(expr_elem
['info'],
723 "Expression is missing metatype")
725 # Try again for hidden UnionKind enum
726 for expr_elem
in exprs
:
727 expr
= expr_elem
['expr']
728 if expr
.has_key('union'):
729 if not discriminator_find_enum_define(expr
):
730 add_enum('%sKind' % expr
['union'], expr_elem
['info'],
732 elif expr
.has_key('alternate'):
733 add_enum('%sKind' % expr
['alternate'], expr_elem
['info'],
736 # Validate that exprs make sense
737 for expr_elem
in exprs
:
738 expr
= expr_elem
['expr']
739 info
= expr_elem
['info']
741 if expr
.has_key('enum'):
742 check_enum(expr
, info
)
743 elif expr
.has_key('union'):
744 check_union(expr
, info
)
745 elif expr
.has_key('alternate'):
746 check_alternate(expr
, info
)
747 elif expr
.has_key('struct'):
748 check_struct(expr
, info
)
749 elif expr
.has_key('command'):
750 check_command(expr
, info
)
751 elif expr
.has_key('event'):
752 check_event(expr
, info
)
754 assert False, 'unexpected meta type'
760 # Schema compiler frontend
763 class QAPISchemaEntity(object):
764 def __init__(self
, name
, info
):
765 assert isinstance(name
, str)
770 return c_name(self
.name
)
772 def check(self
, schema
):
775 def visit(self
, visitor
):
779 class QAPISchemaVisitor(object):
780 def visit_begin(self
, schema
):
786 def visit_builtin_type(self
, name
, info
, json_type
):
789 def visit_enum_type(self
, name
, info
, values
, prefix
):
792 def visit_array_type(self
, name
, info
, element_type
):
795 def visit_object_type(self
, name
, info
, base
, members
, variants
):
798 def visit_alternate_type(self
, name
, info
, variants
):
801 def visit_command(self
, name
, info
, arg_type
, ret_type
,
802 gen
, success_response
):
805 def visit_event(self
, name
, info
, arg_type
):
809 class QAPISchemaType(QAPISchemaEntity
):
810 def c_type(self
, is_param
=False):
811 return c_name(self
.name
) + pointer_suffix
819 def alternate_qtype(self
):
821 'string': 'QTYPE_QSTRING',
822 'number': 'QTYPE_QFLOAT',
824 'boolean': 'QTYPE_QBOOL',
825 'object': 'QTYPE_QDICT'
827 return json2qtype
.get(self
.json_type())
830 class QAPISchemaBuiltinType(QAPISchemaType
):
831 def __init__(self
, name
, json_type
, c_type
, c_null
):
832 QAPISchemaType
.__init
__(self
, name
, None)
833 assert not c_type
or isinstance(c_type
, str)
834 assert json_type
in ('string', 'number', 'int', 'boolean', 'null',
836 self
._json
_type
_name
= json_type
837 self
._c
_type
_name
= c_type
838 self
._c
_null
_val
= c_null
843 def c_type(self
, is_param
=False):
844 if is_param
and self
.name
== 'str':
845 return 'const ' + self
._c
_type
_name
846 return self
._c
_type
_name
849 return self
._c
_null
_val
852 return self
._json
_type
_name
854 def visit(self
, visitor
):
855 visitor
.visit_builtin_type(self
.name
, self
.info
, self
.json_type())
858 class QAPISchemaEnumType(QAPISchemaType
):
859 def __init__(self
, name
, info
, values
, prefix
):
860 QAPISchemaType
.__init
__(self
, name
, info
)
862 assert isinstance(v
, str)
863 assert prefix
is None or isinstance(prefix
, str)
867 def check(self
, schema
):
868 assert len(set(self
.values
)) == len(self
.values
)
870 def c_type(self
, is_param
=False):
871 return c_name(self
.name
)
874 return c_enum_const(self
.name
, (self
.values
+ ['MAX'])[0],
880 def visit(self
, visitor
):
881 visitor
.visit_enum_type(self
.name
, self
.info
,
882 self
.values
, self
.prefix
)
885 class QAPISchemaArrayType(QAPISchemaType
):
886 def __init__(self
, name
, info
, element_type
):
887 QAPISchemaType
.__init
__(self
, name
, info
)
888 assert isinstance(element_type
, str)
889 self
._element
_type
_name
= element_type
890 self
.element_type
= None
892 def check(self
, schema
):
893 self
.element_type
= schema
.lookup_type(self
._element
_type
_name
)
894 assert self
.element_type
899 def visit(self
, visitor
):
900 visitor
.visit_array_type(self
.name
, self
.info
, self
.element_type
)
903 class QAPISchemaObjectType(QAPISchemaType
):
904 def __init__(self
, name
, info
, base
, local_members
, variants
):
905 QAPISchemaType
.__init
__(self
, name
, info
)
906 assert base
is None or isinstance(base
, str)
907 for m
in local_members
:
908 assert isinstance(m
, QAPISchemaObjectTypeMember
)
909 assert (variants
is None or
910 isinstance(variants
, QAPISchemaObjectTypeVariants
))
911 self
._base
_name
= base
913 self
.local_members
= local_members
914 self
.variants
= variants
917 def check(self
, schema
):
918 assert self
.members
is not False # not running in cycles
921 self
.members
= False # mark as being checked
923 self
.base
= schema
.lookup_type(self
._base
_name
)
924 assert isinstance(self
.base
, QAPISchemaObjectType
)
925 assert not self
.base
.variants
# not implemented
926 self
.base
.check(schema
)
927 members
= list(self
.base
.members
)
933 for m
in self
.local_members
:
934 m
.check(schema
, members
, seen
)
936 self
.variants
.check(schema
, members
, seen
)
937 self
.members
= members
941 return QAPISchemaType
.c_name(self
)
943 def c_type(self
, is_param
=False):
945 return QAPISchemaType
.c_type(self
)
950 def visit(self
, visitor
):
951 visitor
.visit_object_type(self
.name
, self
.info
,
952 self
.base
, self
.local_members
, self
.variants
)
955 class QAPISchemaObjectTypeMember(object):
956 def __init__(self
, name
, typ
, optional
):
957 assert isinstance(name
, str)
958 assert isinstance(typ
, str)
959 assert isinstance(optional
, bool)
961 self
._type
_name
= typ
963 self
.optional
= optional
965 def check(self
, schema
, all_members
, seen
):
966 assert self
.name
not in seen
967 self
.type = schema
.lookup_type(self
._type
_name
)
969 all_members
.append(self
)
970 seen
[self
.name
] = self
973 class QAPISchemaObjectTypeVariants(object):
974 def __init__(self
, tag_name
, tag_enum
, variants
):
975 assert tag_name
is None or isinstance(tag_name
, str)
976 assert tag_enum
is None or isinstance(tag_enum
, str)
978 assert isinstance(v
, QAPISchemaObjectTypeVariant
)
979 self
.tag_name
= tag_name
982 self
.tag_member
= None
984 self
.tag_member
= QAPISchemaObjectTypeMember('type', tag_enum
,
986 self
.variants
= variants
988 def check(self
, schema
, members
, seen
):
990 self
.tag_member
= seen
[self
.tag_name
]
992 self
.tag_member
.check(schema
, members
, seen
)
993 assert isinstance(self
.tag_member
.type, QAPISchemaEnumType
)
994 for v
in self
.variants
:
996 v
.check(schema
, self
.tag_member
.type, vseen
)
999 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember
):
1000 def __init__(self
, name
, typ
):
1001 QAPISchemaObjectTypeMember
.__init
__(self
, name
, typ
, False)
1003 def check(self
, schema
, tag_type
, seen
):
1004 QAPISchemaObjectTypeMember
.check(self
, schema
, [], seen
)
1005 assert self
.name
in tag_type
.values
1008 class QAPISchemaAlternateType(QAPISchemaType
):
1009 def __init__(self
, name
, info
, variants
):
1010 QAPISchemaType
.__init
__(self
, name
, info
)
1011 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
1012 assert not variants
.tag_name
1013 self
.variants
= variants
1015 def check(self
, schema
):
1016 self
.variants
.check(schema
, [], {})
1018 def json_type(self
):
1021 def visit(self
, visitor
):
1022 visitor
.visit_alternate_type(self
.name
, self
.info
, self
.variants
)
1025 class QAPISchemaCommand(QAPISchemaEntity
):
1026 def __init__(self
, name
, info
, arg_type
, ret_type
, gen
, success_response
):
1027 QAPISchemaEntity
.__init
__(self
, name
, info
)
1028 assert not arg_type
or isinstance(arg_type
, str)
1029 assert not ret_type
or isinstance(ret_type
, str)
1030 self
._arg
_type
_name
= arg_type
1031 self
.arg_type
= None
1032 self
._ret
_type
_name
= ret_type
1033 self
.ret_type
= None
1035 self
.success_response
= success_response
1037 def check(self
, schema
):
1038 if self
._arg
_type
_name
:
1039 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1040 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1041 assert not self
.arg_type
.variants
# not implemented
1042 if self
._ret
_type
_name
:
1043 self
.ret_type
= schema
.lookup_type(self
._ret
_type
_name
)
1044 assert isinstance(self
.ret_type
, QAPISchemaType
)
1046 def visit(self
, visitor
):
1047 visitor
.visit_command(self
.name
, self
.info
,
1048 self
.arg_type
, self
.ret_type
,
1049 self
.gen
, self
.success_response
)
1052 class QAPISchemaEvent(QAPISchemaEntity
):
1053 def __init__(self
, name
, info
, arg_type
):
1054 QAPISchemaEntity
.__init
__(self
, name
, info
)
1055 assert not arg_type
or isinstance(arg_type
, str)
1056 self
._arg
_type
_name
= arg_type
1057 self
.arg_type
= None
1059 def check(self
, schema
):
1060 if self
._arg
_type
_name
:
1061 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1062 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1063 assert not self
.arg_type
.variants
# not implemented
1065 def visit(self
, visitor
):
1066 visitor
.visit_event(self
.name
, self
.info
, self
.arg_type
)
1069 class QAPISchema(object):
1070 def __init__(self
, fname
):
1072 self
.exprs
= check_exprs(QAPISchemaParser(open(fname
, "r")).exprs
)
1073 except (QAPISchemaError
, QAPIExprError
), err
:
1074 print >>sys
.stderr
, err
1076 self
._entity
_dict
= {}
1077 self
._def
_predefineds
()
1081 def get_exprs(self
):
1082 return [expr_elem
['expr'] for expr_elem
in self
.exprs
]
1084 def _def_entity(self
, ent
):
1085 assert ent
.name
not in self
._entity
_dict
1086 self
._entity
_dict
[ent
.name
] = ent
1088 def lookup_entity(self
, name
, typ
=None):
1089 ent
= self
._entity
_dict
.get(name
)
1090 if typ
and not isinstance(ent
, typ
):
1094 def lookup_type(self
, name
):
1095 return self
.lookup_entity(name
, QAPISchemaType
)
1097 def _def_builtin_type(self
, name
, json_type
, c_type
, c_null
):
1098 self
._def
_entity
(QAPISchemaBuiltinType(name
, json_type
,
1101 self
._make
_array
_type
(name
) # TODO really needed?
1103 def _def_predefineds(self
):
1104 for t
in [('str', 'string', 'char' + pointer_suffix
, 'NULL'),
1105 ('number', 'number', 'double', '0'),
1106 ('int', 'int', 'int64_t', '0'),
1107 ('int8', 'int', 'int8_t', '0'),
1108 ('int16', 'int', 'int16_t', '0'),
1109 ('int32', 'int', 'int32_t', '0'),
1110 ('int64', 'int', 'int64_t', '0'),
1111 ('uint8', 'int', 'uint8_t', '0'),
1112 ('uint16', 'int', 'uint16_t', '0'),
1113 ('uint32', 'int', 'uint32_t', '0'),
1114 ('uint64', 'int', 'uint64_t', '0'),
1115 ('size', 'int', 'uint64_t', '0'),
1116 ('bool', 'boolean', 'bool', 'false'),
1117 ('**', 'value', None, None)]:
1118 self
._def
_builtin
_type
(*t
)
1120 def _make_implicit_enum_type(self
, name
, values
):
1121 name
= name
+ 'Kind'
1122 self
._def
_entity
(QAPISchemaEnumType(name
, None, values
, None))
1125 def _make_array_type(self
, element_type
):
1126 name
= element_type
+ 'List'
1127 if not self
.lookup_type(name
):
1128 self
._def
_entity
(QAPISchemaArrayType(name
, None, element_type
))
1131 def _make_implicit_object_type(self
, name
, role
, members
):
1134 name
= ':obj-%s-%s' % (name
, role
)
1135 if not self
.lookup_entity(name
, QAPISchemaObjectType
):
1136 self
._def
_entity
(QAPISchemaObjectType(name
, None, None,
1140 def _def_enum_type(self
, expr
, info
):
1143 prefix
= expr
.get('prefix')
1144 self
._def
_entity
(QAPISchemaEnumType(name
, info
, data
, prefix
))
1145 self
._make
_array
_type
(name
) # TODO really needed?
1147 def _make_member(self
, name
, typ
):
1149 if name
.startswith('*'):
1152 if isinstance(typ
, list):
1153 assert len(typ
) == 1
1154 typ
= self
._make
_array
_type
(typ
[0])
1155 return QAPISchemaObjectTypeMember(name
, typ
, optional
)
1157 def _make_members(self
, data
):
1158 return [self
._make
_member
(key
, value
)
1159 for (key
, value
) in data
.iteritems()]
1161 def _def_struct_type(self
, expr
, info
):
1162 name
= expr
['struct']
1163 base
= expr
.get('base')
1165 self
._def
_entity
(QAPISchemaObjectType(name
, info
, base
,
1166 self
._make
_members
(data
),
1168 self
._make
_array
_type
(name
) # TODO really needed?
1170 def _make_variant(self
, case
, typ
):
1171 return QAPISchemaObjectTypeVariant(case
, typ
)
1173 def _make_simple_variant(self
, case
, typ
):
1174 if isinstance(typ
, list):
1175 assert len(typ
) == 1
1176 typ
= self
._make
_array
_type
(typ
[0])
1177 typ
= self
._make
_implicit
_object
_type
(typ
, 'wrapper',
1178 [self
._make
_member
('data', typ
)])
1179 return QAPISchemaObjectTypeVariant(case
, typ
)
1181 def _make_tag_enum(self
, type_name
, variants
):
1182 return self
._make
_implicit
_enum
_type
(type_name
,
1183 [v
.name
for v
in variants
])
1185 def _def_union_type(self
, expr
, info
):
1186 name
= expr
['union']
1188 base
= expr
.get('base')
1189 tag_name
= expr
.get('discriminator')
1192 variants
= [self
._make
_variant
(key
, value
)
1193 for (key
, value
) in data
.iteritems()]
1195 variants
= [self
._make
_simple
_variant
(key
, value
)
1196 for (key
, value
) in data
.iteritems()]
1197 tag_enum
= self
._make
_tag
_enum
(name
, variants
)
1199 QAPISchemaObjectType(name
, info
, base
,
1200 self
._make
_members
(OrderedDict()),
1201 QAPISchemaObjectTypeVariants(tag_name
,
1204 self
._make
_array
_type
(name
) # TODO really needed?
1206 def _def_alternate_type(self
, expr
, info
):
1207 name
= expr
['alternate']
1209 variants
= [self
._make
_variant
(key
, value
)
1210 for (key
, value
) in data
.iteritems()]
1211 tag_enum
= self
._make
_tag
_enum
(name
, variants
)
1213 QAPISchemaAlternateType(name
, info
,
1214 QAPISchemaObjectTypeVariants(None,
1217 self
._make
_array
_type
(name
) # TODO really needed?
1219 def _def_command(self
, expr
, info
):
1220 name
= expr
['command']
1221 data
= expr
.get('data')
1222 rets
= expr
.get('returns')
1223 gen
= expr
.get('gen', True)
1224 success_response
= expr
.get('success-response', True)
1225 if isinstance(data
, OrderedDict
):
1226 data
= self
._make
_implicit
_object
_type
(name
, 'arg',
1227 self
._make
_members
(data
))
1228 if isinstance(rets
, list):
1229 assert len(rets
) == 1
1230 rets
= self
._make
_array
_type
(rets
[0])
1231 self
._def
_entity
(QAPISchemaCommand(name
, info
, data
, rets
, gen
,
1234 def _def_event(self
, expr
, info
):
1235 name
= expr
['event']
1236 data
= expr
.get('data')
1237 if isinstance(data
, OrderedDict
):
1238 data
= self
._make
_implicit
_object
_type
(name
, 'arg',
1239 self
._make
_members
(data
))
1240 self
._def
_entity
(QAPISchemaEvent(name
, info
, data
))
1242 def _def_exprs(self
):
1243 for expr_elem
in self
.exprs
:
1244 expr
= expr_elem
['expr']
1245 info
= expr_elem
['info']
1247 self
._def
_enum
_type
(expr
, info
)
1248 elif 'struct' in expr
:
1249 self
._def
_struct
_type
(expr
, info
)
1250 elif 'union' in expr
:
1251 self
._def
_union
_type
(expr
, info
)
1252 elif 'alternate' in expr
:
1253 self
._def
_alternate
_type
(expr
, info
)
1254 elif 'command' in expr
:
1255 self
._def
_command
(expr
, info
)
1256 elif 'event' in expr
:
1257 self
._def
_event
(expr
, info
)
1262 for ent
in self
._entity
_dict
.values():
1265 def visit(self
, visitor
):
1266 visitor
.visit_begin(self
)
1267 for name
in sorted(self
._entity
_dict
.keys()):
1268 self
._entity
_dict
[name
].visit(visitor
)
1273 # Code generation helpers
1276 def parse_args(typeinfo
):
1277 if isinstance(typeinfo
, str):
1278 struct
= find_struct(typeinfo
)
1279 assert struct
!= None
1280 typeinfo
= struct
['data']
1282 for member
in typeinfo
:
1284 argentry
= typeinfo
[member
]
1286 if member
.startswith('*'):
1287 argname
= member
[1:]
1289 # Todo: allow argentry to be OrderedDict, for providing the
1290 # value of an optional argument.
1291 yield (argname
, argentry
, optional
)
1293 def camel_case(name
):
1297 if ch
in ['_', '-']:
1300 new_name
+= ch
.upper()
1303 new_name
+= ch
.lower()
1306 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1307 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1308 # ENUM24_Name -> ENUM24_NAME
1309 def camel_to_upper(value
):
1310 c_fun_str
= c_name(value
, False)
1318 # When c is upper and no "_" appears before, do more checks
1319 if c
.isupper() and (i
> 0) and c_fun_str
[i
- 1] != "_":
1320 # Case 1: next string is lower
1321 # Case 2: previous string is digit
1322 if (i
< (l
- 1) and c_fun_str
[i
+ 1].islower()) or \
1323 c_fun_str
[i
- 1].isdigit():
1326 return new_name
.lstrip('_').upper()
1328 def c_enum_const(type_name
, const_name
, prefix
=None):
1329 if prefix
is not None:
1331 return camel_to_upper(type_name
+ '_' + const_name
)
1333 c_name_trans
= string
.maketrans('.-', '__')
1335 # Map @name to a valid C identifier.
1336 # If @protect, avoid returning certain ticklish identifiers (like
1337 # C keywords) by prepending "q_".
1339 # Used for converting 'name' from a 'name':'type' qapi definition
1340 # into a generated struct member, as well as converting type names
1341 # into substrings of a generated C function name.
1342 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1343 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1344 def c_name(name
, protect
=True):
1345 # ANSI X3J11/88-090, 3.1.1
1346 c89_words
= set(['auto', 'break', 'case', 'char', 'const', 'continue',
1347 'default', 'do', 'double', 'else', 'enum', 'extern', 'float',
1348 'for', 'goto', 'if', 'int', 'long', 'register', 'return',
1349 'short', 'signed', 'sizeof', 'static', 'struct', 'switch',
1350 'typedef', 'union', 'unsigned', 'void', 'volatile', 'while'])
1351 # ISO/IEC 9899:1999, 6.4.1
1352 c99_words
= set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1353 # ISO/IEC 9899:2011, 6.4.1
1354 c11_words
= set(['_Alignas', '_Alignof', '_Atomic', '_Generic', '_Noreturn',
1355 '_Static_assert', '_Thread_local'])
1356 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1358 gcc_words
= set(['asm', 'typeof'])
1359 # C++ ISO/IEC 14882:2003 2.11
1360 cpp_words
= set(['bool', 'catch', 'class', 'const_cast', 'delete',
1361 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1362 'namespace', 'new', 'operator', 'private', 'protected',
1363 'public', 'reinterpret_cast', 'static_cast', 'template',
1364 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1365 'using', 'virtual', 'wchar_t',
1366 # alternative representations
1367 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1368 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1369 # namespace pollution:
1370 polluted_words
= set(['unix', 'errno'])
1371 if protect
and (name
in c89_words | c99_words | c11_words | gcc_words | cpp_words | polluted_words
):
1373 return name
.translate(c_name_trans
)
1375 # Map type @name to the C typedef name for the list form.
1377 # ['Name'] -> 'NameList', ['x-Foo'] -> 'x_FooList', ['int'] -> 'intList'
1378 def c_list_type(name
):
1379 return type_name(name
) + 'List'
1381 # Map type @value to the C typedef form.
1383 # Used for converting 'type' from a 'member':'type' qapi definition
1384 # into the alphanumeric portion of the type for a generated C parameter,
1385 # as well as generated C function names. See c_type() for the rest of
1386 # the conversion such as adding '*' on pointer types.
1387 # 'int' -> 'int', '[x-Foo]' -> 'x_FooList', '__a.b_c' -> '__a_b_c'
1388 def type_name(value
):
1389 if type(value
) == list:
1390 return c_list_type(value
[0])
1391 if value
in builtin_types
.keys():
1393 return c_name(value
)
1395 eatspace
= '\033EATSPACE.'
1396 pointer_suffix
= ' *' + eatspace
1398 # Map type @name to its C type expression.
1399 # If @is_param, const-qualify the string type.
1401 # This function is used for computing the full C type of 'member':'name'.
1402 # A special suffix is added in c_type() for pointer types, and it's
1403 # stripped in mcgen(). So please notice this when you check the return
1404 # value of c_type() outside mcgen().
1405 def c_type(value
, is_param
=False):
1408 return 'const char' + pointer_suffix
1409 return 'char' + pointer_suffix
1411 elif value
== 'int':
1413 elif (value
== 'int8' or value
== 'int16' or value
== 'int32' or
1414 value
== 'int64' or value
== 'uint8' or value
== 'uint16' or
1415 value
== 'uint32' or value
== 'uint64'):
1417 elif value
== 'size':
1419 elif value
== 'bool':
1421 elif value
== 'number':
1423 elif type(value
) == list:
1424 return c_list_type(value
[0]) + pointer_suffix
1425 elif is_enum(value
):
1426 return c_name(value
)
1429 elif value
in events
:
1430 return camel_case(value
) + 'Event' + pointer_suffix
1433 assert isinstance(value
, str) and value
!= ""
1434 return c_name(value
) + pointer_suffix
1436 def is_c_ptr(value
):
1437 return c_type(value
).endswith(pointer_suffix
)
1439 def genindent(count
):
1441 for i
in range(count
):
1447 def push_indent(indent_amount
=4):
1449 indent_level
+= indent_amount
1451 def pop_indent(indent_amount
=4):
1453 indent_level
-= indent_amount
1455 # Generate @code with @kwds interpolated.
1456 # Obey indent_level, and strip eatspace.
1457 def cgen(code
, **kwds
):
1460 indent
= genindent(indent_level
)
1461 # re.subn() lacks flags support before Python 2.7, use re.compile()
1462 raw
= re
.subn(re
.compile("^.", re
.MULTILINE
),
1463 indent
+ r
'\g<0>', raw
)
1465 return re
.sub(re
.escape(eatspace
) + ' *', '', raw
)
1467 def mcgen(code
, **kwds
):
1470 return cgen(code
, **kwds
)
1473 def guardname(filename
):
1474 return c_name(filename
, protect
=False).upper()
1476 def guardstart(name
):
1483 name
=guardname(name
))
1488 #endif /* %(name)s */
1491 name
=guardname(name
))
1494 # Common command line parsing
1497 def parse_command_line(extra_options
= "", extra_long_options
= []):
1500 opts
, args
= getopt
.gnu_getopt(sys
.argv
[1:],
1501 "chp:o:" + extra_options
,
1502 ["source", "header", "prefix=",
1503 "output-dir="] + extra_long_options
)
1504 except getopt
.GetoptError
, err
:
1505 print >>sys
.stderr
, "%s: %s" % (sys
.argv
[0], str(err
))
1516 if o
in ("-p", "--prefix"):
1517 match
= re
.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a
)
1518 if match
.end() != len(a
):
1519 print >>sys
.stderr
, \
1520 "%s: 'funny character '%s' in argument of --prefix" \
1521 % (sys
.argv
[0], a
[match
.end()])
1524 elif o
in ("-o", "--output-dir"):
1525 output_dir
= a
+ "/"
1526 elif o
in ("-c", "--source"):
1528 elif o
in ("-h", "--header"):
1531 extra_opts
.append(oa
)
1533 if not do_c
and not do_h
:
1538 print >>sys
.stderr
, "%s: need exactly one argument" % sys
.argv
[0]
1542 return (fname
, output_dir
, do_c
, do_h
, prefix
, extra_opts
)
1545 # Generate output files with boilerplate
1548 def open_output(output_dir
, do_c
, do_h
, prefix
, c_file
, h_file
,
1549 c_comment
, h_comment
):
1550 guard
= guardname(prefix
+ h_file
)
1551 c_file
= output_dir
+ prefix
+ c_file
1552 h_file
= output_dir
+ prefix
+ h_file
1556 os
.makedirs(output_dir
)
1558 if e
.errno
!= errno
.EEXIST
:
1561 def maybe_open(really
, name
, opt
):
1563 return open(name
, opt
)
1566 return StringIO
.StringIO()
1568 fdef
= maybe_open(do_c
, c_file
, 'w')
1569 fdecl
= maybe_open(do_h
, h_file
, 'w')
1571 fdef
.write(mcgen('''
1572 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1575 comment
= c_comment
))
1577 fdecl
.write(mcgen('''
1578 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1584 comment
= h_comment
, guard
= guard
))
1586 return (fdef
, fdecl
)
1588 def close_output(fdef
, fdecl
):