def check(self, schema, seen): if not self.tag_member: # flat union self.tag_member = seen.get(c_name(self._tag_name)) base = "'base'" # Pointing to the base type when not implicit would be # nice, but we don't know it here if not self.tag_member or self._tag_name != self.tag_member.name: raise QAPISemError( self.info, "discriminator '%s' is not a member of %s" % (self._tag_name, base)) # Here we do: base_type = schema.lookup_type(self.tag_member.defined_in) assert base_type if not base_type.is_implicit(): base = "base type '%s'" % self.tag_member.defined_in if not isinstance(self.tag_member.type, QAPISchemaEnumType): raise QAPISemError( self.info, "discriminator member '%s' of %s must be of enum type" % (self._tag_name, base)) if self.tag_member.optional: raise QAPISemError( self.info, "discriminator member '%s' of %s must not be optional" % (self._tag_name, base)) if self.tag_member.ifcond: raise QAPISemError( self.info, "discriminator member '%s' of %s must not be conditional" % (self._tag_name, base)) else: # simple union assert isinstance(self.tag_member.type, QAPISchemaEnumType) assert not self.tag_member.optional assert self.tag_member.ifcond == [] if self._tag_name: # flat union # branches that are not explicitly covered get an empty type cases = set([v.name for v in self.variants]) for m in self.tag_member.type.members: if m.name not in cases: v = QAPISchemaObjectTypeVariant(m.name, self.info, 'q_empty', m.ifcond) v.set_defined_in(self.tag_member.defined_in) self.variants.append(v) if not self.variants: raise QAPISemError(self.info, "union has no branches") for v in self.variants: v.check(schema) # Union names must match enum values; alternate names are # checked separately. Use 'seen' to tell the two apart. if seen: if v.name not in self.tag_member.type.member_names(): raise QAPISemError( self.info, "branch '%s' is not a value of %s" % (v.name, self.tag_member.type.describe())) if (not isinstance(v.type, QAPISchemaObjectType) or v.type.variants): raise QAPISemError( self.info, "%s cannot use %s" % (v.describe(self.info), v.type.describe())) v.type.check(schema)
def check_clash(self, info, seen): cname = c_name(self.name) if cname in seen: raise QAPISemError( info, "%s collides with %s" % (self.describe(info), seen[cname].describe(info))) seen[cname] = self
def check_type(value, info, source, allow_array=False, allow_dict=False): if value is None: return # Array type if isinstance(value, list): if not allow_array: raise QAPISemError(info, "%s cannot be an array" % source) if len(value) != 1 or not isinstance(value[0], str): raise QAPISemError( info, "%s: array type must contain single type name" % source) return # Type name if isinstance(value, str): return # Anonymous type if not allow_dict: raise QAPISemError(info, "%s should be a type name" % source) if not isinstance(value, OrderedDict): raise QAPISemError(info, "%s should be an object or type name" % source) permit_upper = allow_dict in info.pragma.name_case_whitelist # value is a dictionary, check that each member is okay for (key, arg) in value.items(): key_source = "%s member '%s'" % (source, key) check_name_str(key, info, key_source, allow_optional=True, permit_upper=permit_upper) if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'): raise QAPISemError(info, "%s uses reserved name" % key_source) check_keys(arg, info, key_source, ['type'], ['if', 'features']) check_if(arg, info, key_source) check_features(arg.get('features'), info) check_type(arg['type'], info, key_source, allow_array=True)
def check_name_str(name, info, source, allow_optional=False, enum_member=False, permit_upper=False): membername = name if allow_optional and name.startswith('*'): membername = name[1:] # Enum members can start with a digit, because the generated C # code always prefixes it with the enum name if enum_member and membername[0].isdigit(): membername = 'D' + membername # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty' # and 'q_obj_*' implicit type names. if not valid_name.match(membername) or \ c_name(membername, False).startswith('q_'): raise QAPISemError(info, "%s has an invalid name" % source) if not permit_upper and name.lower() != name: raise QAPISemError( info, "%s uses uppercase in name" % source) assert not membername.startswith('*')
def c_type(self): return c_name(self.name) + pointer_suffix
def c_name(self): return c_name(self.name)
def c_unboxed_type(self): return c_name(self.name)
def c_type(self): assert not self.is_implicit() return c_name(self.name) + pointer_suffix