qemu/scripts/qapi.py
<<
>>
Prefs
   1#
   2# QAPI helper library
   3#
   4# Copyright IBM, Corp. 2011
   5# Copyright (c) 2013-2016 Red Hat Inc.
   6#
   7# Authors:
   8#  Anthony Liguori <aliguori@us.ibm.com>
   9#  Markus Armbruster <armbru@redhat.com>
  10#
  11# This work is licensed under the terms of the GNU GPL, version 2.
  12# See the COPYING file in the top-level directory.
  13
  14import re
  15from ordereddict import OrderedDict
  16import errno
  17import getopt
  18import os
  19import sys
  20import string
  21
  22builtin_types = {
  23    'str':      'QTYPE_QSTRING',
  24    'int':      'QTYPE_QINT',
  25    'number':   'QTYPE_QFLOAT',
  26    'bool':     'QTYPE_QBOOL',
  27    'int8':     'QTYPE_QINT',
  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',
  35    'size':     'QTYPE_QINT',
  36    'any':      None,           # any QType possible, actually
  37    'QType':    'QTYPE_QSTRING',
  38}
  39
  40# Whitelist of commands allowed to return a non-dictionary
  41returns_whitelist = [
  42    # From QMP:
  43    'human-monitor-command',
  44    'qom-get',
  45    'query-migrate-cache-size',
  46    'query-tpm-models',
  47    'query-tpm-types',
  48    'ringbuf-read',
  49
  50    # From QGA:
  51    'guest-file-open',
  52    'guest-fsfreeze-freeze',
  53    'guest-fsfreeze-freeze-list',
  54    'guest-fsfreeze-status',
  55    'guest-fsfreeze-thaw',
  56    'guest-get-time',
  57    'guest-set-vcpus',
  58    'guest-sync',
  59    'guest-sync-delimited',
  60]
  61
  62# Whitelist of entities allowed to violate case conventions
  63case_whitelist = [
  64    # From QMP:
  65    'ACPISlotType',         # DIMM, visible through query-acpi-ospm-status
  66    'CpuInfoMIPS',          # PC, visible through query-cpu
  67    'CpuInfoTricore',       # PC, visible through query-cpu
  68    'QapiErrorClass',       # all members, visible through errors
  69    'UuidInfo',             # UUID, visible through query-uuid
  70    'X86CPURegister32',     # all members, visible indirectly through qom-get
  71    'q_obj_CpuInfo-base',   # CPU, visible through query-cpu
  72]
  73
  74enum_types = []
  75struct_types = []
  76union_types = []
  77events = []
  78all_names = {}
  79
  80#
  81# Parsing the schema into expressions
  82#
  83
  84
  85def error_path(parent):
  86    res = ""
  87    while parent:
  88        res = ("In file included from %s:%d:\n" % (parent['file'],
  89                                                   parent['line'])) + res
  90        parent = parent['parent']
  91    return res
  92
  93
  94class QAPISchemaError(Exception):
  95    def __init__(self, schema, msg):
  96        Exception.__init__(self)
  97        self.fname = schema.fname
  98        self.msg = msg
  99        self.col = 1
 100        self.line = schema.line
 101        for ch in schema.src[schema.line_pos:schema.pos]:
 102            if ch == '\t':
 103                self.col = (self.col + 7) % 8 + 1
 104            else:
 105                self.col += 1
 106        self.info = schema.incl_info
 107
 108    def __str__(self):
 109        return error_path(self.info) + \
 110            "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
 111
 112
 113class QAPIExprError(Exception):
 114    def __init__(self, expr_info, msg):
 115        Exception.__init__(self)
 116        assert expr_info
 117        self.info = expr_info
 118        self.msg = msg
 119
 120    def __str__(self):
 121        return error_path(self.info['parent']) + \
 122            "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
 123
 124
 125class QAPISchemaParser(object):
 126
 127    def __init__(self, fp, previously_included=[], incl_info=None):
 128        abs_fname = os.path.abspath(fp.name)
 129        fname = fp.name
 130        self.fname = fname
 131        previously_included.append(abs_fname)
 132        self.incl_info = incl_info
 133        self.src = fp.read()
 134        if self.src == '' or self.src[-1] != '\n':
 135            self.src += '\n'
 136        self.cursor = 0
 137        self.line = 1
 138        self.line_pos = 0
 139        self.exprs = []
 140        self.accept()
 141
 142        while self.tok is not None:
 143            expr_info = {'file': fname, 'line': self.line,
 144                         'parent': self.incl_info}
 145            expr = self.get_expr(False)
 146            if isinstance(expr, dict) and "include" in expr:
 147                if len(expr) != 1:
 148                    raise QAPIExprError(expr_info,
 149                                        "Invalid 'include' directive")
 150                include = expr["include"]
 151                if not isinstance(include, str):
 152                    raise QAPIExprError(expr_info,
 153                                        "Value of 'include' must be a string")
 154                incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
 155                                              include)
 156                # catch inclusion cycle
 157                inf = expr_info
 158                while inf:
 159                    if incl_abs_fname == os.path.abspath(inf['file']):
 160                        raise QAPIExprError(expr_info, "Inclusion loop for %s"
 161                                            % include)
 162                    inf = inf['parent']
 163                # skip multiple include of the same file
 164                if incl_abs_fname in previously_included:
 165                    continue
 166                try:
 167                    fobj = open(incl_abs_fname, 'r')
 168                except IOError as e:
 169                    raise QAPIExprError(expr_info,
 170                                        '%s: %s' % (e.strerror, include))
 171                exprs_include = QAPISchemaParser(fobj, previously_included,
 172                                                 expr_info)
 173                self.exprs.extend(exprs_include.exprs)
 174            else:
 175                expr_elem = {'expr': expr,
 176                             'info': expr_info}
 177                self.exprs.append(expr_elem)
 178
 179    def accept(self):
 180        while True:
 181            self.tok = self.src[self.cursor]
 182            self.pos = self.cursor
 183            self.cursor += 1
 184            self.val = None
 185
 186            if self.tok == '#':
 187                self.cursor = self.src.find('\n', self.cursor)
 188            elif self.tok in "{}:,[]":
 189                return
 190            elif self.tok == "'":
 191                string = ''
 192                esc = False
 193                while True:
 194                    ch = self.src[self.cursor]
 195                    self.cursor += 1
 196                    if ch == '\n':
 197                        raise QAPISchemaError(self,
 198                                              'Missing terminating "\'"')
 199                    if esc:
 200                        if ch == 'b':
 201                            string += '\b'
 202                        elif ch == 'f':
 203                            string += '\f'
 204                        elif ch == 'n':
 205                            string += '\n'
 206                        elif ch == 'r':
 207                            string += '\r'
 208                        elif ch == 't':
 209                            string += '\t'
 210                        elif ch == 'u':
 211                            value = 0
 212                            for _ in range(0, 4):
 213                                ch = self.src[self.cursor]
 214                                self.cursor += 1
 215                                if ch not in "0123456789abcdefABCDEF":
 216                                    raise QAPISchemaError(self,
 217                                                          '\\u escape needs 4 '
 218                                                          'hex digits')
 219                                value = (value << 4) + int(ch, 16)
 220                            # If Python 2 and 3 didn't disagree so much on
 221                            # how to handle Unicode, then we could allow
 222                            # Unicode string defaults.  But most of QAPI is
 223                            # ASCII-only, so we aren't losing much for now.
 224                            if not value or value > 0x7f:
 225                                raise QAPISchemaError(self,
 226                                                      'For now, \\u escape '
 227                                                      'only supports non-zero '
 228                                                      'values up to \\u007f')
 229                            string += chr(value)
 230                        elif ch in "\\/'\"":
 231                            string += ch
 232                        else:
 233                            raise QAPISchemaError(self,
 234                                                  "Unknown escape \\%s" % ch)
 235                        esc = False
 236                    elif ch == "\\":
 237                        esc = True
 238                    elif ch == "'":
 239                        self.val = string
 240                        return
 241                    else:
 242                        string += ch
 243            elif self.src.startswith("true", self.pos):
 244                self.val = True
 245                self.cursor += 3
 246                return
 247            elif self.src.startswith("false", self.pos):
 248                self.val = False
 249                self.cursor += 4
 250                return
 251            elif self.src.startswith("null", self.pos):
 252                self.val = None
 253                self.cursor += 3
 254                return
 255            elif self.tok == '\n':
 256                if self.cursor == len(self.src):
 257                    self.tok = None
 258                    return
 259                self.line += 1
 260                self.line_pos = self.cursor
 261            elif not self.tok.isspace():
 262                raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
 263
 264    def get_members(self):
 265        expr = OrderedDict()
 266        if self.tok == '}':
 267            self.accept()
 268            return expr
 269        if self.tok != "'":
 270            raise QAPISchemaError(self, 'Expected string or "}"')
 271        while True:
 272            key = self.val
 273            self.accept()
 274            if self.tok != ':':
 275                raise QAPISchemaError(self, 'Expected ":"')
 276            self.accept()
 277            if key in expr:
 278                raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
 279            expr[key] = self.get_expr(True)
 280            if self.tok == '}':
 281                self.accept()
 282                return expr
 283            if self.tok != ',':
 284                raise QAPISchemaError(self, 'Expected "," or "}"')
 285            self.accept()
 286            if self.tok != "'":
 287                raise QAPISchemaError(self, 'Expected string')
 288
 289    def get_values(self):
 290        expr = []
 291        if self.tok == ']':
 292            self.accept()
 293            return expr
 294        if self.tok not in "{['tfn":
 295            raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
 296                                  'boolean or "null"')
 297        while True:
 298            expr.append(self.get_expr(True))
 299            if self.tok == ']':
 300                self.accept()
 301                return expr
 302            if self.tok != ',':
 303                raise QAPISchemaError(self, 'Expected "," or "]"')
 304            self.accept()
 305
 306    def get_expr(self, nested):
 307        if self.tok != '{' and not nested:
 308            raise QAPISchemaError(self, 'Expected "{"')
 309        if self.tok == '{':
 310            self.accept()
 311            expr = self.get_members()
 312        elif self.tok == '[':
 313            self.accept()
 314            expr = self.get_values()
 315        elif self.tok in "'tfn":
 316            expr = self.val
 317            self.accept()
 318        else:
 319            raise QAPISchemaError(self, 'Expected "{", "[" or string')
 320        return expr
 321
 322#
 323# Semantic analysis of schema expressions
 324# TODO fold into QAPISchema
 325# TODO catching name collisions in generated code would be nice
 326#
 327
 328
 329def find_base_members(base):
 330    if isinstance(base, dict):
 331        return base
 332    base_struct_define = find_struct(base)
 333    if not base_struct_define:
 334        return None
 335    return base_struct_define['data']
 336
 337
 338# Return the qtype of an alternate branch, or None on error.
 339def find_alternate_member_qtype(qapi_type):
 340    if qapi_type in builtin_types:
 341        return builtin_types[qapi_type]
 342    elif find_struct(qapi_type):
 343        return "QTYPE_QDICT"
 344    elif find_enum(qapi_type):
 345        return "QTYPE_QSTRING"
 346    elif find_union(qapi_type):
 347        return "QTYPE_QDICT"
 348    return None
 349
 350
 351# Return the discriminator enum define if discriminator is specified as an
 352# enum type, otherwise return None.
 353def discriminator_find_enum_define(expr):
 354    base = expr.get('base')
 355    discriminator = expr.get('discriminator')
 356
 357    if not (discriminator and base):
 358        return None
 359
 360    base_members = find_base_members(base)
 361    if not base_members:
 362        return None
 363
 364    discriminator_type = base_members.get(discriminator)
 365    if not discriminator_type:
 366        return None
 367
 368    return find_enum(discriminator_type)
 369
 370
 371# Names must be letters, numbers, -, and _.  They must start with letter,
 372# except for downstream extensions which must start with __RFQDN_.
 373# Dots are only valid in the downstream extension prefix.
 374valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
 375                        '[a-zA-Z][a-zA-Z0-9_-]*$')
 376
 377
 378def check_name(expr_info, source, name, allow_optional=False,
 379               enum_member=False):
 380    global valid_name
 381    membername = name
 382
 383    if not isinstance(name, str):
 384        raise QAPIExprError(expr_info,
 385                            "%s requires a string name" % source)
 386    if name.startswith('*'):
 387        membername = name[1:]
 388        if not allow_optional:
 389            raise QAPIExprError(expr_info,
 390                                "%s does not allow optional name '%s'"
 391                                % (source, name))
 392    # Enum members can start with a digit, because the generated C
 393    # code always prefixes it with the enum name
 394    if enum_member and membername[0].isdigit():
 395        membername = 'D' + membername
 396    # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
 397    # and 'q_obj_*' implicit type names.
 398    if not valid_name.match(membername) or \
 399       c_name(membername, False).startswith('q_'):
 400        raise QAPIExprError(expr_info,
 401                            "%s uses invalid name '%s'" % (source, name))
 402
 403
 404def add_name(name, info, meta, implicit=False):
 405    global all_names
 406    check_name(info, "'%s'" % meta, name)
 407    # FIXME should reject names that differ only in '_' vs. '.'
 408    # vs. '-', because they're liable to clash in generated C.
 409    if name in all_names:
 410        raise QAPIExprError(info,
 411                            "%s '%s' is already defined"
 412                            % (all_names[name], name))
 413    if not implicit and (name.endswith('Kind') or name.endswith('List')):
 414        raise QAPIExprError(info,
 415                            "%s '%s' should not end in '%s'"
 416                            % (meta, name, name[-4:]))
 417    all_names[name] = meta
 418
 419
 420def add_struct(definition, info):
 421    global struct_types
 422    name = definition['struct']
 423    add_name(name, info, 'struct')
 424    struct_types.append(definition)
 425
 426
 427def find_struct(name):
 428    global struct_types
 429    for struct in struct_types:
 430        if struct['struct'] == name:
 431            return struct
 432    return None
 433
 434
 435def add_union(definition, info):
 436    global union_types
 437    name = definition['union']
 438    add_name(name, info, 'union')
 439    union_types.append(definition)
 440
 441
 442def find_union(name):
 443    global union_types
 444    for union in union_types:
 445        if union['union'] == name:
 446            return union
 447    return None
 448
 449
 450def add_enum(name, info, enum_values=None, implicit=False):
 451    global enum_types
 452    add_name(name, info, 'enum', implicit)
 453    enum_types.append({"enum_name": name, "enum_values": enum_values})
 454
 455
 456def find_enum(name):
 457    global enum_types
 458    for enum in enum_types:
 459        if enum['enum_name'] == name:
 460            return enum
 461    return None
 462
 463
 464def is_enum(name):
 465    return find_enum(name) is not None
 466
 467
 468def check_type(expr_info, source, value, allow_array=False,
 469               allow_dict=False, allow_optional=False,
 470               allow_metas=[]):
 471    global all_names
 472
 473    if value is None:
 474        return
 475
 476    # Check if array type for value is okay
 477    if isinstance(value, list):
 478        if not allow_array:
 479            raise QAPIExprError(expr_info,
 480                                "%s cannot be an array" % source)
 481        if len(value) != 1 or not isinstance(value[0], str):
 482            raise QAPIExprError(expr_info,
 483                                "%s: array type must contain single type name"
 484                                % source)
 485        value = value[0]
 486
 487    # Check if type name for value is okay
 488    if isinstance(value, str):
 489        if value not in all_names:
 490            raise QAPIExprError(expr_info,
 491                                "%s uses unknown type '%s'"
 492                                % (source, value))
 493        if not all_names[value] in allow_metas:
 494            raise QAPIExprError(expr_info,
 495                                "%s cannot use %s type '%s'"
 496                                % (source, all_names[value], value))
 497        return
 498
 499    if not allow_dict:
 500        raise QAPIExprError(expr_info,
 501                            "%s should be a type name" % source)
 502
 503    if not isinstance(value, OrderedDict):
 504        raise QAPIExprError(expr_info,
 505                            "%s should be a dictionary or type name" % source)
 506
 507    # value is a dictionary, check that each member is okay
 508    for (key, arg) in value.items():
 509        check_name(expr_info, "Member of %s" % source, key,
 510                   allow_optional=allow_optional)
 511        if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
 512            raise QAPIExprError(expr_info,
 513                                "Member of %s uses reserved name '%s'"
 514                                % (source, key))
 515        # Todo: allow dictionaries to represent default values of
 516        # an optional argument.
 517        check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
 518                   allow_array=True,
 519                   allow_metas=['built-in', 'union', 'alternate', 'struct',
 520                                'enum'])
 521
 522
 523def check_command(expr, expr_info):
 524    name = expr['command']
 525
 526    check_type(expr_info, "'data' for command '%s'" % name,
 527               expr.get('data'), allow_dict=True, allow_optional=True,
 528               allow_metas=['struct'])
 529    returns_meta = ['union', 'struct']
 530    if name in returns_whitelist:
 531        returns_meta += ['built-in', 'alternate', 'enum']
 532    check_type(expr_info, "'returns' for command '%s'" % name,
 533               expr.get('returns'), allow_array=True,
 534               allow_optional=True, allow_metas=returns_meta)
 535
 536
 537def check_event(expr, expr_info):
 538    global events
 539    name = expr['event']
 540
 541    events.append(name)
 542    check_type(expr_info, "'data' for event '%s'" % name,
 543               expr.get('data'), allow_dict=True, allow_optional=True,
 544               allow_metas=['struct'])
 545
 546
 547def check_union(expr, expr_info):
 548    name = expr['union']
 549    base = expr.get('base')
 550    discriminator = expr.get('discriminator')
 551    members = expr['data']
 552
 553    # Two types of unions, determined by discriminator.
 554
 555    # With no discriminator it is a simple union.
 556    if discriminator is None:
 557        enum_define = None
 558        allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
 559        if base is not None:
 560            raise QAPIExprError(expr_info,
 561                                "Simple union '%s' must not have a base"
 562                                % name)
 563
 564    # Else, it's a flat union.
 565    else:
 566        # The object must have a string or dictionary 'base'.
 567        check_type(expr_info, "'base' for union '%s'" % name,
 568                   base, allow_dict=True, allow_optional=True,
 569                   allow_metas=['struct'])
 570        if not base:
 571            raise QAPIExprError(expr_info,
 572                                "Flat union '%s' must have a base"
 573                                % name)
 574        base_members = find_base_members(base)
 575        assert base_members
 576
 577        # The value of member 'discriminator' must name a non-optional
 578        # member of the base struct.
 579        check_name(expr_info, "Discriminator of flat union '%s'" % name,
 580                   discriminator)
 581        discriminator_type = base_members.get(discriminator)
 582        if not discriminator_type:
 583            raise QAPIExprError(expr_info,
 584                                "Discriminator '%s' is not a member of base "
 585                                "struct '%s'"
 586                                % (discriminator, base))
 587        enum_define = find_enum(discriminator_type)
 588        allow_metas = ['struct']
 589        # Do not allow string discriminator
 590        if not enum_define:
 591            raise QAPIExprError(expr_info,
 592                                "Discriminator '%s' must be of enumeration "
 593                                "type" % discriminator)
 594
 595    # Check every branch; don't allow an empty union
 596    if len(members) == 0:
 597        raise QAPIExprError(expr_info,
 598                            "Union '%s' cannot have empty 'data'" % name)
 599    for (key, value) in members.items():
 600        check_name(expr_info, "Member of union '%s'" % name, key)
 601
 602        # Each value must name a known type
 603        check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
 604                   value, allow_array=not base, allow_metas=allow_metas)
 605
 606        # If the discriminator names an enum type, then all members
 607        # of 'data' must also be members of the enum type.
 608        if enum_define:
 609            if key not in enum_define['enum_values']:
 610                raise QAPIExprError(expr_info,
 611                                    "Discriminator value '%s' is not found in "
 612                                    "enum '%s'" %
 613                                    (key, enum_define["enum_name"]))
 614
 615
 616def check_alternate(expr, expr_info):
 617    name = expr['alternate']
 618    members = expr['data']
 619    types_seen = {}
 620
 621    # Check every branch; require at least two branches
 622    if len(members) < 2:
 623        raise QAPIExprError(expr_info,
 624                            "Alternate '%s' should have at least two branches "
 625                            "in 'data'" % name)
 626    for (key, value) in members.items():
 627        check_name(expr_info, "Member of alternate '%s'" % name, key)
 628
 629        # Ensure alternates have no type conflicts.
 630        check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
 631                   value,
 632                   allow_metas=['built-in', 'union', 'struct', 'enum'])
 633        qtype = find_alternate_member_qtype(value)
 634        if not qtype:
 635            raise QAPIExprError(expr_info,
 636                                "Alternate '%s' member '%s' cannot use "
 637                                "type '%s'" % (name, key, value))
 638        if qtype in types_seen:
 639            raise QAPIExprError(expr_info,
 640                                "Alternate '%s' member '%s' can't "
 641                                "be distinguished from member '%s'"
 642                                % (name, key, types_seen[qtype]))
 643        types_seen[qtype] = key
 644
 645
 646def check_enum(expr, expr_info):
 647    name = expr['enum']
 648    members = expr.get('data')
 649    prefix = expr.get('prefix')
 650
 651    if not isinstance(members, list):
 652        raise QAPIExprError(expr_info,
 653                            "Enum '%s' requires an array for 'data'" % name)
 654    if prefix is not None and not isinstance(prefix, str):
 655        raise QAPIExprError(expr_info,
 656                            "Enum '%s' requires a string for 'prefix'" % name)
 657    for member in members:
 658        check_name(expr_info, "Member of enum '%s'" % name, member,
 659                   enum_member=True)
 660
 661
 662def check_struct(expr, expr_info):
 663    name = expr['struct']
 664    members = expr['data']
 665
 666    check_type(expr_info, "'data' for struct '%s'" % name, members,
 667               allow_dict=True, allow_optional=True)
 668    check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
 669               allow_metas=['struct'])
 670
 671
 672def check_keys(expr_elem, meta, required, optional=[]):
 673    expr = expr_elem['expr']
 674    info = expr_elem['info']
 675    name = expr[meta]
 676    if not isinstance(name, str):
 677        raise QAPIExprError(info,
 678                            "'%s' key must have a string value" % meta)
 679    required = required + [meta]
 680    for (key, value) in expr.items():
 681        if key not in required and key not in optional:
 682            raise QAPIExprError(info,
 683                                "Unknown key '%s' in %s '%s'"
 684                                % (key, meta, name))
 685        if (key == 'gen' or key == 'success-response') and value is not False:
 686            raise QAPIExprError(info,
 687                                "'%s' of %s '%s' should only use false value"
 688                                % (key, meta, name))
 689    for key in required:
 690        if key not in expr:
 691            raise QAPIExprError(info,
 692                                "Key '%s' is missing from %s '%s'"
 693                                % (key, meta, name))
 694
 695
 696def check_exprs(exprs):
 697    global all_names
 698
 699    # Learn the types and check for valid expression keys
 700    for builtin in builtin_types.keys():
 701        all_names[builtin] = 'built-in'
 702    for expr_elem in exprs:
 703        expr = expr_elem['expr']
 704        info = expr_elem['info']
 705        if 'enum' in expr:
 706            check_keys(expr_elem, 'enum', ['data'], ['prefix'])
 707            add_enum(expr['enum'], info, expr['data'])
 708        elif 'union' in expr:
 709            check_keys(expr_elem, 'union', ['data'],
 710                       ['base', 'discriminator'])
 711            add_union(expr, info)
 712        elif 'alternate' in expr:
 713            check_keys(expr_elem, 'alternate', ['data'])
 714            add_name(expr['alternate'], info, 'alternate')
 715        elif 'struct' in expr:
 716            check_keys(expr_elem, 'struct', ['data'], ['base'])
 717            add_struct(expr, info)
 718        elif 'command' in expr:
 719            check_keys(expr_elem, 'command', [],
 720                       ['data', 'returns', 'gen', 'success-response'])
 721            add_name(expr['command'], info, 'command')
 722        elif 'event' in expr:
 723            check_keys(expr_elem, 'event', [], ['data'])
 724            add_name(expr['event'], info, 'event')
 725        else:
 726            raise QAPIExprError(expr_elem['info'],
 727                                "Expression is missing metatype")
 728
 729    # Try again for hidden UnionKind enum
 730    for expr_elem in exprs:
 731        expr = expr_elem['expr']
 732        if 'union' in expr:
 733            if not discriminator_find_enum_define(expr):
 734                add_enum('%sKind' % expr['union'], expr_elem['info'],
 735                         implicit=True)
 736        elif 'alternate' in expr:
 737            add_enum('%sKind' % expr['alternate'], expr_elem['info'],
 738                     implicit=True)
 739
 740    # Validate that exprs make sense
 741    for expr_elem in exprs:
 742        expr = expr_elem['expr']
 743        info = expr_elem['info']
 744
 745        if 'enum' in expr:
 746            check_enum(expr, info)
 747        elif 'union' in expr:
 748            check_union(expr, info)
 749        elif 'alternate' in expr:
 750            check_alternate(expr, info)
 751        elif 'struct' in expr:
 752            check_struct(expr, info)
 753        elif 'command' in expr:
 754            check_command(expr, info)
 755        elif 'event' in expr:
 756            check_event(expr, info)
 757        else:
 758            assert False, 'unexpected meta type'
 759
 760    return exprs
 761
 762
 763#
 764# Schema compiler frontend
 765#
 766
 767class QAPISchemaEntity(object):
 768    def __init__(self, name, info):
 769        assert isinstance(name, str)
 770        self.name = name
 771        # For explicitly defined entities, info points to the (explicit)
 772        # definition.  For builtins (and their arrays), info is None.
 773        # For implicitly defined entities, info points to a place that
 774        # triggered the implicit definition (there may be more than one
 775        # such place).
 776        self.info = info
 777
 778    def c_name(self):
 779        return c_name(self.name)
 780
 781    def check(self, schema):
 782        pass
 783
 784    def is_implicit(self):
 785        return not self.info
 786
 787    def visit(self, visitor):
 788        pass
 789
 790
 791class QAPISchemaVisitor(object):
 792    def visit_begin(self, schema):
 793        pass
 794
 795    def visit_end(self):
 796        pass
 797
 798    def visit_needed(self, entity):
 799        # Default to visiting everything
 800        return True
 801
 802    def visit_builtin_type(self, name, info, json_type):
 803        pass
 804
 805    def visit_enum_type(self, name, info, values, prefix):
 806        pass
 807
 808    def visit_array_type(self, name, info, element_type):
 809        pass
 810
 811    def visit_object_type(self, name, info, base, members, variants):
 812        pass
 813
 814    def visit_object_type_flat(self, name, info, members, variants):
 815        pass
 816
 817    def visit_alternate_type(self, name, info, variants):
 818        pass
 819
 820    def visit_command(self, name, info, arg_type, ret_type,
 821                      gen, success_response):
 822        pass
 823
 824    def visit_event(self, name, info, arg_type):
 825        pass
 826
 827
 828class QAPISchemaType(QAPISchemaEntity):
 829    # Return the C type for common use.
 830    # For the types we commonly box, this is a pointer type.
 831    def c_type(self):
 832        pass
 833
 834    # Return the C type to be used in a parameter list.
 835    def c_param_type(self):
 836        return self.c_type()
 837
 838    # Return the C type to be used where we suppress boxing.
 839    def c_unboxed_type(self):
 840        return self.c_type()
 841
 842    def json_type(self):
 843        pass
 844
 845    def alternate_qtype(self):
 846        json2qtype = {
 847            'string':  'QTYPE_QSTRING',
 848            'number':  'QTYPE_QFLOAT',
 849            'int':     'QTYPE_QINT',
 850            'boolean': 'QTYPE_QBOOL',
 851            'object':  'QTYPE_QDICT'
 852        }
 853        return json2qtype.get(self.json_type())
 854
 855
 856class QAPISchemaBuiltinType(QAPISchemaType):
 857    def __init__(self, name, json_type, c_type):
 858        QAPISchemaType.__init__(self, name, None)
 859        assert not c_type or isinstance(c_type, str)
 860        assert json_type in ('string', 'number', 'int', 'boolean', 'null',
 861                             'value')
 862        self._json_type_name = json_type
 863        self._c_type_name = c_type
 864
 865    def c_name(self):
 866        return self.name
 867
 868    def c_type(self):
 869        return self._c_type_name
 870
 871    def c_param_type(self):
 872        if self.name == 'str':
 873            return 'const ' + self._c_type_name
 874        return self._c_type_name
 875
 876    def json_type(self):
 877        return self._json_type_name
 878
 879    def visit(self, visitor):
 880        visitor.visit_builtin_type(self.name, self.info, self.json_type())
 881
 882
 883class QAPISchemaEnumType(QAPISchemaType):
 884    def __init__(self, name, info, values, prefix):
 885        QAPISchemaType.__init__(self, name, info)
 886        for v in values:
 887            assert isinstance(v, QAPISchemaMember)
 888            v.set_owner(name)
 889        assert prefix is None or isinstance(prefix, str)
 890        self.values = values
 891        self.prefix = prefix
 892
 893    def check(self, schema):
 894        seen = {}
 895        for v in self.values:
 896            v.check_clash(self.info, seen)
 897
 898    def is_implicit(self):
 899        # See QAPISchema._make_implicit_enum_type()
 900        return self.name.endswith('Kind')
 901
 902    def c_type(self):
 903        return c_name(self.name)
 904
 905    def member_names(self):
 906        return [v.name for v in self.values]
 907
 908    def json_type(self):
 909        return 'string'
 910
 911    def visit(self, visitor):
 912        visitor.visit_enum_type(self.name, self.info,
 913                                self.member_names(), self.prefix)
 914
 915
 916class QAPISchemaArrayType(QAPISchemaType):
 917    def __init__(self, name, info, element_type):
 918        QAPISchemaType.__init__(self, name, info)
 919        assert isinstance(element_type, str)
 920        self._element_type_name = element_type
 921        self.element_type = None
 922
 923    def check(self, schema):
 924        self.element_type = schema.lookup_type(self._element_type_name)
 925        assert self.element_type
 926
 927    def is_implicit(self):
 928        return True
 929
 930    def c_type(self):
 931        return c_name(self.name) + pointer_suffix
 932
 933    def json_type(self):
 934        return 'array'
 935
 936    def visit(self, visitor):
 937        visitor.visit_array_type(self.name, self.info, self.element_type)
 938
 939
 940class QAPISchemaObjectType(QAPISchemaType):
 941    def __init__(self, name, info, base, local_members, variants):
 942        # struct has local_members, optional base, and no variants
 943        # flat union has base, variants, and no local_members
 944        # simple union has local_members, variants, and no base
 945        QAPISchemaType.__init__(self, name, info)
 946        assert base is None or isinstance(base, str)
 947        for m in local_members:
 948            assert isinstance(m, QAPISchemaObjectTypeMember)
 949            m.set_owner(name)
 950        if variants is not None:
 951            assert isinstance(variants, QAPISchemaObjectTypeVariants)
 952            variants.set_owner(name)
 953        self._base_name = base
 954        self.base = None
 955        self.local_members = local_members
 956        self.variants = variants
 957        self.members = None
 958
 959    def check(self, schema):
 960        if self.members is False:               # check for cycles
 961            raise QAPIExprError(self.info,
 962                                "Object %s contains itself" % self.name)
 963        if self.members:
 964            return
 965        self.members = False                    # mark as being checked
 966        seen = OrderedDict()
 967        if self._base_name:
 968            self.base = schema.lookup_type(self._base_name)
 969            assert isinstance(self.base, QAPISchemaObjectType)
 970            self.base.check(schema)
 971            self.base.check_clash(schema, self.info, seen)
 972        for m in self.local_members:
 973            m.check(schema)
 974            m.check_clash(self.info, seen)
 975        self.members = seen.values()
 976        if self.variants:
 977            self.variants.check(schema, seen)
 978            assert self.variants.tag_member in self.members
 979            self.variants.check_clash(schema, self.info, seen)
 980
 981    # Check that the members of this type do not cause duplicate JSON members,
 982    # and update seen to track the members seen so far. Report any errors
 983    # on behalf of info, which is not necessarily self.info
 984    def check_clash(self, schema, info, seen):
 985        assert not self.variants       # not implemented
 986        for m in self.members:
 987            m.check_clash(info, seen)
 988
 989    def is_implicit(self):
 990        # See QAPISchema._make_implicit_object_type(), as well as
 991        # _def_predefineds()
 992        return self.name.startswith('q_')
 993
 994    def c_name(self):
 995        return QAPISchemaType.c_name(self)
 996
 997    def c_type(self):
 998        assert not self.is_implicit()
 999        return c_name(self.name) + pointer_suffix
1000
1001    def c_unboxed_type(self):
1002        return c_name(self.name)
1003
1004    def json_type(self):
1005        return 'object'
1006
1007    def visit(self, visitor):
1008        visitor.visit_object_type(self.name, self.info,
1009                                  self.base, self.local_members, self.variants)
1010        visitor.visit_object_type_flat(self.name, self.info,
1011                                       self.members, self.variants)
1012
1013
1014class QAPISchemaMember(object):
1015    role = 'member'
1016
1017    def __init__(self, name):
1018        assert isinstance(name, str)
1019        self.name = name
1020        self.owner = None
1021
1022    def set_owner(self, name):
1023        assert not self.owner
1024        self.owner = name
1025
1026    def check_clash(self, info, seen):
1027        cname = c_name(self.name)
1028        if cname.lower() != cname and self.owner not in case_whitelist:
1029            raise QAPIExprError(info,
1030                                "%s should not use uppercase" % self.describe())
1031        if cname in seen:
1032            raise QAPIExprError(info,
1033                                "%s collides with %s"
1034                                % (self.describe(), seen[cname].describe()))
1035        seen[cname] = self
1036
1037    def _pretty_owner(self):
1038        owner = self.owner
1039        if owner.startswith('q_obj_'):
1040            # See QAPISchema._make_implicit_object_type() - reverse the
1041            # mapping there to create a nice human-readable description
1042            owner = owner[6:]
1043            if owner.endswith('-arg'):
1044                return '(parameter of %s)' % owner[:-4]
1045            elif owner.endswith('-base'):
1046                return '(base of %s)' % owner[:-5]
1047            else:
1048                assert owner.endswith('-wrapper')
1049                # Unreachable and not implemented
1050                assert False
1051        if owner.endswith('Kind'):
1052            # See QAPISchema._make_implicit_enum_type()
1053            return '(branch of %s)' % owner[:-4]
1054        return '(%s of %s)' % (self.role, owner)
1055
1056    def describe(self):
1057        return "'%s' %s" % (self.name, self._pretty_owner())
1058
1059
1060class QAPISchemaObjectTypeMember(QAPISchemaMember):
1061    def __init__(self, name, typ, optional):
1062        QAPISchemaMember.__init__(self, name)
1063        assert isinstance(typ, str)
1064        assert isinstance(optional, bool)
1065        self._type_name = typ
1066        self.type = None
1067        self.optional = optional
1068
1069    def check(self, schema):
1070        assert self.owner
1071        self.type = schema.lookup_type(self._type_name)
1072        assert self.type
1073
1074
1075class QAPISchemaObjectTypeVariants(object):
1076    def __init__(self, tag_name, tag_member, variants):
1077        # Flat unions pass tag_name but not tag_member.
1078        # Simple unions and alternates pass tag_member but not tag_name.
1079        # After check(), tag_member is always set, and tag_name remains
1080        # a reliable witness of being used by a flat union.
1081        assert bool(tag_member) != bool(tag_name)
1082        assert (isinstance(tag_name, str) or
1083                isinstance(tag_member, QAPISchemaObjectTypeMember))
1084        assert len(variants) > 0
1085        for v in variants:
1086            assert isinstance(v, QAPISchemaObjectTypeVariant)
1087        self.tag_name = tag_name
1088        self.tag_member = tag_member
1089        self.variants = variants
1090
1091    def set_owner(self, name):
1092        for v in self.variants:
1093            v.set_owner(name)
1094
1095    def check(self, schema, seen):
1096        if not self.tag_member:    # flat union
1097            self.tag_member = seen[c_name(self.tag_name)]
1098            assert self.tag_name == self.tag_member.name
1099        assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1100        for v in self.variants:
1101            v.check(schema)
1102            # Union names must match enum values; alternate names are
1103            # checked separately. Use 'seen' to tell the two apart.
1104            if seen:
1105                assert v.name in self.tag_member.type.member_names()
1106                assert isinstance(v.type, QAPISchemaObjectType)
1107                v.type.check(schema)
1108
1109    def check_clash(self, schema, info, seen):
1110        for v in self.variants:
1111            # Reset seen map for each variant, since qapi names from one
1112            # branch do not affect another branch
1113            assert isinstance(v.type, QAPISchemaObjectType)
1114            v.type.check_clash(schema, info, dict(seen))
1115
1116
1117class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1118    role = 'branch'
1119
1120    def __init__(self, name, typ):
1121        QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1122
1123
1124class QAPISchemaAlternateType(QAPISchemaType):
1125    def __init__(self, name, info, variants):
1126        QAPISchemaType.__init__(self, name, info)
1127        assert isinstance(variants, QAPISchemaObjectTypeVariants)
1128        assert not variants.tag_name
1129        variants.set_owner(name)
1130        variants.tag_member.set_owner(self.name)
1131        self.variants = variants
1132
1133    def check(self, schema):
1134        self.variants.tag_member.check(schema)
1135        # Not calling self.variants.check_clash(), because there's nothing
1136        # to clash with
1137        self.variants.check(schema, {})
1138        # Alternate branch names have no relation to the tag enum values;
1139        # so we have to check for potential name collisions ourselves.
1140        seen = {}
1141        for v in self.variants.variants:
1142            v.check_clash(self.info, seen)
1143
1144    def c_type(self):
1145        return c_name(self.name) + pointer_suffix
1146
1147    def json_type(self):
1148        return 'value'
1149
1150    def visit(self, visitor):
1151        visitor.visit_alternate_type(self.name, self.info, self.variants)
1152
1153
1154class QAPISchemaCommand(QAPISchemaEntity):
1155    def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1156        QAPISchemaEntity.__init__(self, name, info)
1157        assert not arg_type or isinstance(arg_type, str)
1158        assert not ret_type or isinstance(ret_type, str)
1159        self._arg_type_name = arg_type
1160        self.arg_type = None
1161        self._ret_type_name = ret_type
1162        self.ret_type = None
1163        self.gen = gen
1164        self.success_response = success_response
1165
1166    def check(self, schema):
1167        if self._arg_type_name:
1168            self.arg_type = schema.lookup_type(self._arg_type_name)
1169            assert isinstance(self.arg_type, QAPISchemaObjectType)
1170            assert not self.arg_type.variants   # not implemented
1171        if self._ret_type_name:
1172            self.ret_type = schema.lookup_type(self._ret_type_name)
1173            assert isinstance(self.ret_type, QAPISchemaType)
1174
1175    def visit(self, visitor):
1176        visitor.visit_command(self.name, self.info,
1177                              self.arg_type, self.ret_type,
1178                              self.gen, self.success_response)
1179
1180
1181class QAPISchemaEvent(QAPISchemaEntity):
1182    def __init__(self, name, info, arg_type):
1183        QAPISchemaEntity.__init__(self, name, info)
1184        assert not arg_type or isinstance(arg_type, str)
1185        self._arg_type_name = arg_type
1186        self.arg_type = None
1187
1188    def check(self, schema):
1189        if self._arg_type_name:
1190            self.arg_type = schema.lookup_type(self._arg_type_name)
1191            assert isinstance(self.arg_type, QAPISchemaObjectType)
1192            assert not self.arg_type.variants   # not implemented
1193
1194    def visit(self, visitor):
1195        visitor.visit_event(self.name, self.info, self.arg_type)
1196
1197
1198class QAPISchema(object):
1199    def __init__(self, fname):
1200        try:
1201            self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1202            self._entity_dict = {}
1203            self._predefining = True
1204            self._def_predefineds()
1205            self._predefining = False
1206            self._def_exprs()
1207            self.check()
1208        except (QAPISchemaError, QAPIExprError) as err:
1209            print >>sys.stderr, err
1210            exit(1)
1211
1212    def _def_entity(self, ent):
1213        # Only the predefined types are allowed to not have info
1214        assert ent.info or self._predefining
1215        assert ent.name not in self._entity_dict
1216        self._entity_dict[ent.name] = ent
1217
1218    def lookup_entity(self, name, typ=None):
1219        ent = self._entity_dict.get(name)
1220        if typ and not isinstance(ent, typ):
1221            return None
1222        return ent
1223
1224    def lookup_type(self, name):
1225        return self.lookup_entity(name, QAPISchemaType)
1226
1227    def _def_builtin_type(self, name, json_type, c_type):
1228        self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
1229        # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1230        # qapi-types.h from a single .c, all arrays of builtins must be
1231        # declared in the first file whether or not they are used.  Nicer
1232        # would be to use lazy instantiation, while figuring out how to
1233        # avoid compilation issues with multiple qapi-types.h.
1234        self._make_array_type(name, None)
1235
1236    def _def_predefineds(self):
1237        for t in [('str',    'string',  'char' + pointer_suffix),
1238                  ('number', 'number',  'double'),
1239                  ('int',    'int',     'int64_t'),
1240                  ('int8',   'int',     'int8_t'),
1241                  ('int16',  'int',     'int16_t'),
1242                  ('int32',  'int',     'int32_t'),
1243                  ('int64',  'int',     'int64_t'),
1244                  ('uint8',  'int',     'uint8_t'),
1245                  ('uint16', 'int',     'uint16_t'),
1246                  ('uint32', 'int',     'uint32_t'),
1247                  ('uint64', 'int',     'uint64_t'),
1248                  ('size',   'int',     'uint64_t'),
1249                  ('bool',   'boolean', 'bool'),
1250                  ('any',    'value',   'QObject' + pointer_suffix)]:
1251            self._def_builtin_type(*t)
1252        self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1253                                                          None, [], None)
1254        self._def_entity(self.the_empty_object_type)
1255        qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1256                                                'qstring', 'qdict', 'qlist',
1257                                                'qfloat', 'qbool'])
1258        self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
1259                                            'QTYPE'))
1260
1261    def _make_enum_members(self, values):
1262        return [QAPISchemaMember(v) for v in values]
1263
1264    def _make_implicit_enum_type(self, name, info, values):
1265        # See also QAPISchemaObjectTypeMember._pretty_owner()
1266        name = name + 'Kind'   # Use namespace reserved by add_name()
1267        self._def_entity(QAPISchemaEnumType(
1268            name, info, self._make_enum_members(values), None))
1269        return name
1270
1271    def _make_array_type(self, element_type, info):
1272        name = element_type + 'List'   # Use namespace reserved by add_name()
1273        if not self.lookup_type(name):
1274            self._def_entity(QAPISchemaArrayType(name, info, element_type))
1275        return name
1276
1277    def _make_implicit_object_type(self, name, info, role, members):
1278        if not members:
1279            return None
1280        # See also QAPISchemaObjectTypeMember._pretty_owner()
1281        name = 'q_obj_%s-%s' % (name, role)
1282        if not self.lookup_entity(name, QAPISchemaObjectType):
1283            self._def_entity(QAPISchemaObjectType(name, info, None,
1284                                                  members, None))
1285        return name
1286
1287    def _def_enum_type(self, expr, info):
1288        name = expr['enum']
1289        data = expr['data']
1290        prefix = expr.get('prefix')
1291        self._def_entity(QAPISchemaEnumType(
1292            name, info, self._make_enum_members(data), prefix))
1293
1294    def _make_member(self, name, typ, info):
1295        optional = False
1296        if name.startswith('*'):
1297            name = name[1:]
1298            optional = True
1299        if isinstance(typ, list):
1300            assert len(typ) == 1
1301            typ = self._make_array_type(typ[0], info)
1302        return QAPISchemaObjectTypeMember(name, typ, optional)
1303
1304    def _make_members(self, data, info):
1305        return [self._make_member(key, value, info)
1306                for (key, value) in data.iteritems()]
1307
1308    def _def_struct_type(self, expr, info):
1309        name = expr['struct']
1310        base = expr.get('base')
1311        data = expr['data']
1312        self._def_entity(QAPISchemaObjectType(name, info, base,
1313                                              self._make_members(data, info),
1314                                              None))
1315
1316    def _make_variant(self, case, typ):
1317        return QAPISchemaObjectTypeVariant(case, typ)
1318
1319    def _make_simple_variant(self, case, typ, info):
1320        if isinstance(typ, list):
1321            assert len(typ) == 1
1322            typ = self._make_array_type(typ[0], info)
1323        typ = self._make_implicit_object_type(
1324            typ, info, 'wrapper', [self._make_member('data', typ, info)])
1325        return QAPISchemaObjectTypeVariant(case, typ)
1326
1327    def _def_union_type(self, expr, info):
1328        name = expr['union']
1329        data = expr['data']
1330        base = expr.get('base')
1331        tag_name = expr.get('discriminator')
1332        tag_member = None
1333        if isinstance(base, dict):
1334            base = (self._make_implicit_object_type(
1335                    name, info, 'base', self._make_members(base, info)))
1336        if tag_name:
1337            variants = [self._make_variant(key, value)
1338                        for (key, value) in data.iteritems()]
1339            members = []
1340        else:
1341            variants = [self._make_simple_variant(key, value, info)
1342                        for (key, value) in data.iteritems()]
1343            typ = self._make_implicit_enum_type(name, info,
1344                                                [v.name for v in variants])
1345            tag_member = QAPISchemaObjectTypeMember('type', typ, False)
1346            members = [tag_member]
1347        self._def_entity(
1348            QAPISchemaObjectType(name, info, base, members,
1349                                 QAPISchemaObjectTypeVariants(tag_name,
1350                                                              tag_member,
1351                                                              variants)))
1352
1353    def _def_alternate_type(self, expr, info):
1354        name = expr['alternate']
1355        data = expr['data']
1356        variants = [self._make_variant(key, value)
1357                    for (key, value) in data.iteritems()]
1358        tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
1359        self._def_entity(
1360            QAPISchemaAlternateType(name, info,
1361                                    QAPISchemaObjectTypeVariants(None,
1362                                                                 tag_member,
1363                                                                 variants)))
1364
1365    def _def_command(self, expr, info):
1366        name = expr['command']
1367        data = expr.get('data')
1368        rets = expr.get('returns')
1369        gen = expr.get('gen', True)
1370        success_response = expr.get('success-response', True)
1371        if isinstance(data, OrderedDict):
1372            data = self._make_implicit_object_type(
1373                name, info, 'arg', self._make_members(data, info))
1374        if isinstance(rets, list):
1375            assert len(rets) == 1
1376            rets = self._make_array_type(rets[0], info)
1377        self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1378                                           success_response))
1379
1380    def _def_event(self, expr, info):
1381        name = expr['event']
1382        data = expr.get('data')
1383        if isinstance(data, OrderedDict):
1384            data = self._make_implicit_object_type(
1385                name, info, 'arg', self._make_members(data, info))
1386        self._def_entity(QAPISchemaEvent(name, info, data))
1387
1388    def _def_exprs(self):
1389        for expr_elem in self.exprs:
1390            expr = expr_elem['expr']
1391            info = expr_elem['info']
1392            if 'enum' in expr:
1393                self._def_enum_type(expr, info)
1394            elif 'struct' in expr:
1395                self._def_struct_type(expr, info)
1396            elif 'union' in expr:
1397                self._def_union_type(expr, info)
1398            elif 'alternate' in expr:
1399                self._def_alternate_type(expr, info)
1400            elif 'command' in expr:
1401                self._def_command(expr, info)
1402            elif 'event' in expr:
1403                self._def_event(expr, info)
1404            else:
1405                assert False
1406
1407    def check(self):
1408        for ent in self._entity_dict.values():
1409            ent.check(self)
1410
1411    def visit(self, visitor):
1412        visitor.visit_begin(self)
1413        for (name, entity) in sorted(self._entity_dict.items()):
1414            if visitor.visit_needed(entity):
1415                entity.visit(visitor)
1416        visitor.visit_end()
1417
1418
1419#
1420# Code generation helpers
1421#
1422
1423def camel_case(name):
1424    new_name = ''
1425    first = True
1426    for ch in name:
1427        if ch in ['_', '-']:
1428            first = True
1429        elif first:
1430            new_name += ch.upper()
1431            first = False
1432        else:
1433            new_name += ch.lower()
1434    return new_name
1435
1436
1437# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1438# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1439# ENUM24_Name -> ENUM24_NAME
1440def camel_to_upper(value):
1441    c_fun_str = c_name(value, False)
1442    if value.isupper():
1443        return c_fun_str
1444
1445    new_name = ''
1446    l = len(c_fun_str)
1447    for i in range(l):
1448        c = c_fun_str[i]
1449        # When c is upper and no "_" appears before, do more checks
1450        if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
1451            if i < l - 1 and c_fun_str[i + 1].islower():
1452                new_name += '_'
1453            elif c_fun_str[i - 1].isdigit():
1454                new_name += '_'
1455        new_name += c
1456    return new_name.lstrip('_').upper()
1457
1458
1459def c_enum_const(type_name, const_name, prefix=None):
1460    if prefix is not None:
1461        type_name = prefix
1462    return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
1463
1464c_name_trans = string.maketrans('.-', '__')
1465
1466
1467# Map @name to a valid C identifier.
1468# If @protect, avoid returning certain ticklish identifiers (like
1469# C keywords) by prepending "q_".
1470#
1471# Used for converting 'name' from a 'name':'type' qapi definition
1472# into a generated struct member, as well as converting type names
1473# into substrings of a generated C function name.
1474# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1475# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1476def c_name(name, protect=True):
1477    # ANSI X3J11/88-090, 3.1.1
1478    c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1479                     'default', 'do', 'double', 'else', 'enum', 'extern',
1480                     'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1481                     'return', 'short', 'signed', 'sizeof', 'static',
1482                     'struct', 'switch', 'typedef', 'union', 'unsigned',
1483                     'void', 'volatile', 'while'])
1484    # ISO/IEC 9899:1999, 6.4.1
1485    c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1486    # ISO/IEC 9899:2011, 6.4.1
1487    c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1488                     '_Noreturn', '_Static_assert', '_Thread_local'])
1489    # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1490    # excluding _.*
1491    gcc_words = set(['asm', 'typeof'])
1492    # C++ ISO/IEC 14882:2003 2.11
1493    cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1494                     'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1495                     'namespace', 'new', 'operator', 'private', 'protected',
1496                     'public', 'reinterpret_cast', 'static_cast', 'template',
1497                     'this', 'throw', 'true', 'try', 'typeid', 'typename',
1498                     'using', 'virtual', 'wchar_t',
1499                     # alternative representations
1500                     'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1501                     'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1502    # namespace pollution:
1503    polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
1504    name = name.translate(c_name_trans)
1505    if protect and (name in c89_words | c99_words | c11_words | gcc_words
1506                    | cpp_words | polluted_words):
1507        return "q_" + name
1508    return name
1509
1510eatspace = '\033EATSPACE.'
1511pointer_suffix = ' *' + eatspace
1512
1513
1514def genindent(count):
1515    ret = ""
1516    for _ in range(count):
1517        ret += " "
1518    return ret
1519
1520indent_level = 0
1521
1522
1523def push_indent(indent_amount=4):
1524    global indent_level
1525    indent_level += indent_amount
1526
1527
1528def pop_indent(indent_amount=4):
1529    global indent_level
1530    indent_level -= indent_amount
1531
1532
1533# Generate @code with @kwds interpolated.
1534# Obey indent_level, and strip eatspace.
1535def cgen(code, **kwds):
1536    raw = code % kwds
1537    if indent_level:
1538        indent = genindent(indent_level)
1539        # re.subn() lacks flags support before Python 2.7, use re.compile()
1540        raw = re.subn(re.compile("^.", re.MULTILINE),
1541                      indent + r'\g<0>', raw)
1542        raw = raw[0]
1543    return re.sub(re.escape(eatspace) + ' *', '', raw)
1544
1545
1546def mcgen(code, **kwds):
1547    if code[0] == '\n':
1548        code = code[1:]
1549    return cgen(code, **kwds)
1550
1551
1552def guardname(filename):
1553    return c_name(filename, protect=False).upper()
1554
1555
1556def guardstart(name):
1557    return mcgen('''
1558
1559#ifndef %(name)s
1560#define %(name)s
1561
1562''',
1563                 name=guardname(name))
1564
1565
1566def guardend(name):
1567    return mcgen('''
1568
1569#endif /* %(name)s */
1570
1571''',
1572                 name=guardname(name))
1573
1574
1575def gen_enum_lookup(name, values, prefix=None):
1576    ret = mcgen('''
1577
1578const char *const %(c_name)s_lookup[] = {
1579''',
1580                c_name=c_name(name))
1581    for value in values:
1582        index = c_enum_const(name, value, prefix)
1583        ret += mcgen('''
1584    [%(index)s] = "%(value)s",
1585''',
1586                     index=index, value=value)
1587
1588    max_index = c_enum_const(name, '_MAX', prefix)
1589    ret += mcgen('''
1590    [%(max_index)s] = NULL,
1591};
1592''',
1593                 max_index=max_index)
1594    return ret
1595
1596
1597def gen_enum(name, values, prefix=None):
1598    # append automatically generated _MAX value
1599    enum_values = values + ['_MAX']
1600
1601    ret = mcgen('''
1602
1603typedef enum %(c_name)s {
1604''',
1605                c_name=c_name(name))
1606
1607    i = 0
1608    for value in enum_values:
1609        ret += mcgen('''
1610    %(c_enum)s = %(i)d,
1611''',
1612                     c_enum=c_enum_const(name, value, prefix),
1613                     i=i)
1614        i += 1
1615
1616    ret += mcgen('''
1617} %(c_name)s;
1618''',
1619                 c_name=c_name(name))
1620
1621    ret += mcgen('''
1622
1623extern const char *const %(c_name)s_lookup[];
1624''',
1625                 c_name=c_name(name))
1626    return ret
1627
1628
1629def gen_params(arg_type, extra):
1630    if not arg_type:
1631        return extra
1632    assert not arg_type.variants
1633    ret = ''
1634    sep = ''
1635    for memb in arg_type.members:
1636        ret += sep
1637        sep = ', '
1638        if memb.optional:
1639            ret += 'bool has_%s, ' % c_name(memb.name)
1640        ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name))
1641    if extra:
1642        ret += sep + extra
1643    return ret
1644
1645
1646def gen_err_check():
1647    return mcgen('''
1648    if (err) {
1649        goto out;
1650    }
1651''')
1652
1653
1654#
1655# Common command line parsing
1656#
1657
1658
1659def parse_command_line(extra_options="", extra_long_options=[]):
1660
1661    try:
1662        opts, args = getopt.gnu_getopt(sys.argv[1:],
1663                                       "chp:o:" + extra_options,
1664                                       ["source", "header", "prefix=",
1665                                        "output-dir="] + extra_long_options)
1666    except getopt.GetoptError as err:
1667        print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1668        sys.exit(1)
1669
1670    output_dir = ""
1671    prefix = ""
1672    do_c = False
1673    do_h = False
1674    extra_opts = []
1675
1676    for oa in opts:
1677        o, a = oa
1678        if o in ("-p", "--prefix"):
1679            match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1680            if match.end() != len(a):
1681                print >>sys.stderr, \
1682                    "%s: 'funny character '%s' in argument of --prefix" \
1683                    % (sys.argv[0], a[match.end()])
1684                sys.exit(1)
1685            prefix = a
1686        elif o in ("-o", "--output-dir"):
1687            output_dir = a + "/"
1688        elif o in ("-c", "--source"):
1689            do_c = True
1690        elif o in ("-h", "--header"):
1691            do_h = True
1692        else:
1693            extra_opts.append(oa)
1694
1695    if not do_c and not do_h:
1696        do_c = True
1697        do_h = True
1698
1699    if len(args) != 1:
1700        print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1701        sys.exit(1)
1702    fname = args[0]
1703
1704    return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1705
1706#
1707# Generate output files with boilerplate
1708#
1709
1710
1711def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1712                c_comment, h_comment):
1713    guard = guardname(prefix + h_file)
1714    c_file = output_dir + prefix + c_file
1715    h_file = output_dir + prefix + h_file
1716
1717    if output_dir:
1718        try:
1719            os.makedirs(output_dir)
1720        except os.error as e:
1721            if e.errno != errno.EEXIST:
1722                raise
1723
1724    def maybe_open(really, name, opt):
1725        if really:
1726            return open(name, opt)
1727        else:
1728            import StringIO
1729            return StringIO.StringIO()
1730
1731    fdef = maybe_open(do_c, c_file, 'w')
1732    fdecl = maybe_open(do_h, h_file, 'w')
1733
1734    fdef.write(mcgen('''
1735/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1736%(comment)s
1737''',
1738                     comment=c_comment))
1739
1740    fdecl.write(mcgen('''
1741/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1742%(comment)s
1743#ifndef %(guard)s
1744#define %(guard)s
1745
1746''',
1747                      comment=h_comment, guard=guard))
1748
1749    return (fdef, fdecl)
1750
1751
1752def close_output(fdef, fdecl):
1753    fdecl.write('''
1754#endif
1755''')
1756    fdecl.close()
1757    fdef.close()
1758