def beginFile(self, genOpts): AutomaticSourceOutputGenerator.beginFile(self, genOpts) self.conventions = self.genOpts.conventions self.env.globals['filename'] = genOpts.filename self.env.tests['cpp_hidden_member'] = self._cpp_hidden_member self.env.tests['struct_output'] = self._is_struct_output self.env.tests['struct_input'] = self._is_struct_input self.template = JinjaTemplate(self.env, "template_{}".format(genOpts.filename))
class ConformanceGenerator(AutomaticSourceOutputGenerator): """Generate conformance source using XML element attributes from registry""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.env = make_jinja_environment(file_with_templates_as_sibs=__file__) def outputGeneratedAuthorNote(self): pass # Override the base class header warning so the comment indicates this file. # self the AutomaticSourceOutputGenerator object def outputGeneratedHeaderWarning(self): # File Comment generated_warning = '// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********\n' generated_warning += '// See conformance_generator.py for modifications\n' generated_warning += '// ************************************************************\n' write(generated_warning, file=self.outFile) # Call the base class to properly begin the file, and then add # the file-specific header information. # self the ConformanceLayerHeaderGenerator object # gen_opts the ConformanceLayerHeaderGeneratorOptions object def beginFile(self, genOpts): AutomaticSourceOutputGenerator.beginFile(self, genOpts) self.template = JinjaTemplate( self.env, "template_{}".format(genOpts.filename)) def extensionReturnCodesForCommand(self, cur_cmd): return (x for x in self.registry.commandextensionerrors + self.registry.commandextensionsuccesses if x.command == cur_cmd.name) def allReturnCodesForCommand(self, cur_cmd): return cur_cmd.return_values + list(self.extensionReturnCodesForCommand(cur_cmd)) # Write out all the information for the appropriate file, # and then call down to the base class to wrap everything up. # self the ConformanceLayerBaseGenerator object def endFile(self): sorted_cmds = self.core_commands + self.ext_commands null_ok=set() file_data = self.template.render( gen=self, registry=self.registry, null_instance_ok=VALID_FOR_NULL_INSTANCE, sorted_cmds=sorted_cmds) write(file_data, file=self.outFile) # Finish processing in superclass AutomaticSourceOutputGenerator.endFile(self)
class ConformanceLayerGenerator(AutomaticSourceOutputGenerator): """Generate conformance layer source using XML element attributes from registry""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.env = make_environment() def outputGeneratedAuthorNote(self): pass # Override the base class header warning so the comment indicates this file. # self the AutomaticSourceOutputGenerator object def outputGeneratedHeaderWarning(self): # File Comment generated_warning = '// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********\n' generated_warning += '// See conformance_layer_generator.py for modifications\n' generated_warning += '// ************************************************************\n' write(generated_warning, file=self.outFile) # Call the base class to properly begin the file, and then add # the file-specific header information. # self the ConformanceLayerHeaderGenerator object # gen_opts the ConformanceLayerHeaderGeneratorOptions object def beginFile(self, genOpts): AutomaticSourceOutputGenerator.beginFile(self, genOpts) self.template = JinjaTemplate(self.env, "template_{}".format(genOpts.filename)) def extensionReturnCodesForCommand(self, cur_cmd): return (x for x in self.registry.commandextensionerrors + self.registry.commandextensionsuccesses if x.command == cur_cmd.name) # Write out all the information for the appropriate file, # and then call down to the base class to wrap everything up. # self the ConformanceLayerBaseGenerator object def endFile(self): sorted_cmds = self.core_commands + self.ext_commands skip_hooks = set(self.no_trampoline_or_terminator).union( set(MANUALLY_DEFINED_IN_LAYER)) file_data = self.template.render( gen=self, registry=self.registry, sorted_cmds=sorted_cmds, skip_hooks=skip_hooks) write(file_data, file=self.outFile) # Finish processing in superclass AutomaticSourceOutputGenerator.endFile(self)
def beginFile(self, genOpts): OutputGenerator.beginFile(self, genOpts) self.template = JinjaTemplate(self.env, "template_{}".format(genOpts.filename))
class CReflectionOutputGenerator(OutputGenerator): """Generate specified API interfaces in a specific style, such as a C header""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.env = make_jinja_environment(file_with_templates_as_sibs=__file__) self.structs = [] self.enums = [] self.bitmasks = [] def beginFile(self, genOpts): OutputGenerator.beginFile(self, genOpts) self.template = JinjaTemplate(self.env, "template_{}".format(genOpts.filename)) def endFile(self): file_data = '' try: file_data += self.template.render(structs=self.structs, enums=self.enums, bitmasks=self.bitmasks) except TemplateSyntaxError as e: print("{}:{} error: {}".format(e.filename, e.lineno, e.message)) raise e write(file_data, file=self.outFile) # Finish processing in superclass OutputGenerator.endFile(self) def genType(self, typeinfo, name, alias): OutputGenerator.genType(self, typeinfo, name, alias) typeElem = typeinfo.elem category = typeElem.get('category') if category in ('struct', 'union'): # If the type is a struct type, generate it using the # special-purpose generator. self.genStruct(typeinfo, name, alias) def genStruct(self, typeinfo, typeName, alias): OutputGenerator.genStruct(self, typeinfo, typeName, alias) typeElem = typeinfo.elem if alias: return structTypeName = None members = [] for member in typeinfo.getMembers(): memberName = getElemName(member) memberType = getElemType(member) if self.conventions.is_structure_type_member( memberType, memberName): structTypeName = member.get("values") members.append(memberName) self.structs.append( CStruct(typeName, structTypeName, members, typeinfo.elem.get('protect'))) def genGroup(self, groupinfo, groupName, alias=None): OutputGenerator.genGroup(self, groupinfo, groupName, alias) if alias: return if getElemType(groupinfo.elem) == 'bitmask': bitmaskTypeName = getElemName(groupinfo.flagType.elem) bitmaskTuples = [] for elem in groupinfo.elem.findall('enum'): (numVal, strVal) = self.enumToValue(elem, True) bitmaskTuples.append((getElemName(elem), strVal)) self.bitmasks.append(CBitmask(bitmaskTypeName, bitmaskTuples)) else: groupElem = groupinfo.elem expandName = re.sub(r'([0-9a-z_])([A-Z0-9][^A-Z0-9]?)', r'\1_\2', groupName).upper() expandPrefix = expandName expandSuffix = '' expandSuffixMatch = re.search(r'[A-Z][A-Z]+$', groupName) if expandSuffixMatch: expandSuffix = '_' + expandSuffixMatch.group() # Strip off the suffix from the prefix expandPrefix = expandName.rsplit(expandSuffix, 1)[0] enumTuples = [] for elem in groupElem.findall('enum'): (numVal, strVal) = self.enumToValue(elem, True) enumTuples.append((getElemName(elem), strVal)) self.enums.append( CEnum(groupName, expandPrefix, expandSuffix, enumTuples))
class CppGenerator(AutomaticSourceOutputGenerator): """Generate C++ wrapper header using XML element attributes from registry""" def __init__(self, *args, **kwargs): self.quiet = kwargs.pop('quiet', False) super().__init__(*args, **kwargs) self.env = make_jinja_environment(file_with_templates_as_sibs=__file__, trim_blocks=False) self.env.filters['block_doxygen_comment'] = _block_doxygen_comment def outputGeneratedAuthorNote(self): # Disabled pass def outputCopywriteHeader(self): # Disabled - there is one in the template. pass def computeNullAtom(self, typename): null_atom = self.conventions.generate_structure_type_from_name( typename) return null_atom.replace('XR_TYPE', 'XR_NULL') def findVendorSuffix(self, name): for vendor in self.vendor_tags: if name.endswith(vendor): return vendor def getEnumValuePrefixSuffix(self, typename): if typename in RULE_BREAKING_ENUMS: prefix = RULE_BREAKING_ENUMS[typename] else: prefix = self.conventions.generate_structure_type_from_name( typename) prefix = prefix.replace('XR_TYPE', 'XR') suffix = self.findVendorSuffix(prefix) if suffix: prefix = _strip_suffix(prefix, '_' + suffix) return prefix, suffix def createEnumValue(self, name, typename): prefix, type_suffix = self.getEnumValuePrefixSuffix(typename) name = _strip_prefix(name, prefix + '_') suffix = None if type_suffix: name = _strip_suffix(name, '_' + type_suffix) suffix = self.findVendorSuffix(name) if suffix: name = _strip_suffix(name, '_' + suffix) enum_name = _to_camel_case(name) if suffix: enum_name += suffix return enum_name def getFlagValuePrefixSuffix(self, typename): prefix = self.conventions.generate_structure_type_from_name(typename) prefix = prefix.replace('XR_TYPE', 'XR') suffix = self.findVendorSuffix(prefix) if suffix: prefix = _strip_suffix(prefix, '_' + suffix) suffix = 'BIT_' + suffix else: suffix = 'BIT' prefix = prefix[:-len('_FLAG_BITS')] return prefix, suffix def createFlagValue(self, name, typename): prefix, type_suffix = self.getFlagValuePrefixSuffix(typename) name = _strip_prefix(name, prefix + '_') suffix = None if type_suffix: name = _strip_suffix(name, '_' + type_suffix) suffix = self.findVendorSuffix(name) if suffix: name = _strip_suffix(name, '_' + suffix) enum_name = _to_camel_case(name) if suffix: enum_name += suffix return enum_name def createEnumException(self, name): enum_val = self.createEnumValue(name, 'XrResult') suffix = self.findVendorSuffix(name) if suffix: enum_val = _strip_suffix(enum_val, suffix) result = enum_val.replace('Error', '') + 'Error' if suffix: result += suffix return result def _basic_method_projection(self, method): """Perform the basic manipulation of a MethodProjection to convert it from C to C++.""" is_two_call = self._enhanced_method_detect_twocall(method) # Free function to method if method.handle: handle = method.params[0] method.decl_params.pop(0) method.is_member_function = True method.decl_dict[handle.name] = None method.access_dict[handle.name] = "this->get()" # if method.cpp_name.endswith(method.cpp_handle): # method.cpp_name = _strip_suffix(method.cpp_name, method.cpp_handle) # Convert handles for param in method.decl_params: if param.type in self.dict_handles: name = param.name cpp_type = _project_type_name(param.type) if param.pointer_count == 0: # Input handle method.decl_dict[name] = "{} {}".format(cpp_type, name) method.access_dict[name] = "{}.get()".format(name.strip()) elif param.pointer_count == 1: # Output handle method.decl_dict[name] = "{}& {}".format(cpp_type, name) method.access_dict[name] = "{}.put()".format(name.strip()) # Convert enums for param in method.decl_params: if param.type in self.dict_enums: name = param.name cpp_type = _project_type_name(param.type) if param.pointer_count == 0: # Input enum method.decl_dict[name] = "{} {}".format(cpp_type, name) method.access_dict[ name] = "OPENXR_HPP_NAMESPACE::get({})".format( name.strip()) elif param.pointer_count == 1 and not is_two_call: # Output enum method.decl_dict[name] = "{}& {}".format(cpp_type, name) method.pre_statements.append("{} {}_tmp;".format( param.type, name.strip())) method.access_dict[name] = "{}_tmp".format(name.strip()) method.post_statements.append( "{name} = static_cast<{t}>({name}_tmp);".format( name=name.strip(), t=cpp_type)) # Convert structs for param in method.decl_params: if param.type not in self.dict_structs: continue if self._is_base_only(self.dict_structs[param.type]): # This is a polymorphic parameter: skip conversion for now. continue if param.type in SKIP_PROJECTION: # This is a mess to project. continue name = param.name cpp_type = _project_type_name(param.type) if param.is_const: # Input struct method.decl_dict[name] = "const {}& {}".format(cpp_type, name) method.access_dict[name] = "{}.get()".format(name.strip()) elif param.pointer_count == 1 and not is_two_call: # Output struct method.decl_dict[name] = "{}& {}".format(cpp_type, name) method.access_dict[name] = "{}.put()".format(name.strip()) # Convert atoms, plus XrTime and XrDuration as special case (promoted from raw ints to constexpr wrapper classes) for param in method.decl_params: if param.type not in MANUALLY_PROJECTED_SCALARS and param.type not in self.dict_atoms: continue name = param.name cpp_type = _project_type_name(param.type) method.decl_dict[name] = "{} {}".format(cpp_type, name) method.access_dict[name] = "{}.get()".format(name.strip()) def _update_enhanced_return_type(self, method): """Set the return type based on the bare return type. Used by _enhanced_method_projection and _unique_method_projection.""" if method.multiple_success_codes or not method.exceptions_permitted: # If we aren't allowed exceptions, or have some extra success results, # we always have to return the Result. if method.bare_return_type == "void": method.return_type = "Result" method.return_statement = 'return {};'.format( method.returns[0]) else: method.return_type = "ResultValue<{}>".format( method.bare_return_type) method.return_statement = 'return { %s, std::move(%s) };' % ( method.returns[0], method.returns[1]) else: # OK, we will throw an exception if allowed and just directly return the output. method.explicit_result_elided = True method.return_type = method.bare_return_type if method.bare_return_type == "void": method.return_statement = 'return;' else: method.return_statement = 'return {};'.format( method.returns[1]) if method.return_template_params: # tmpl = "<{}>".format(",".join(method.return_template_params)) return_val = "{}({})".format(method.bare_return_type, ", ".join(method.returns[1:])) if method.multiple_success_codes or not method.exceptions_permitted: method.return_statement = 'return { %s, %s };' % ( method.returns[0], return_val) else: method.return_statement = 'return %s;' % return_val # method.return_statement = 'return impl::createResultValue{tmpl}({rets}, OPENXR_HPP_NAMESPACE_STRING "::{name}"{successes});'.format( # tmpl=tmpl, # rets=",".join(method.returns), # name=method.qualified_name, successes=method.successes_arg) # else: # tmpl = "" def _is_tagged_type(self, typename): if typename not in self.dict_structs: return False return any( (x.name == "type" for x in self.dict_structs[typename].members)) def _get_tag(self, typename): if typename not in self.dict_structs: return None tag_member = [ x for x in self.dict_structs[typename].members if x.name == "type" ] if not tag_member: return None raw_tag = tag_member[0].values if not raw_tag: return None return "StructureType::" + self.createEnumValue( raw_tag, "XrStructureType") def _enhanced_method_detect_twocall(self, method): # Find the three important parameters capacity_input_param_name = None count_output_param_name = None array_param_name = None for i, p in enumerate(method.decl_params): if p.no_auto_validity: continue param_name = p.name match = CAPACITY_INPUT_RE.match(param_name) if match: capacity_input_param_name = param_name continue match = COUNT_OUTPUT_RE.match(param_name) if match: count_output_param_name = param_name continue # Try detecting the output array using its length field if capacity_input_param_name is not None \ and p.pointer_count_var == capacity_input_param_name: array_param_name = param_name return capacity_input_param_name and count_output_param_name and array_param_name def _enhanced_method_projection_twocall(self, method): # Find the three important parameters capacity_input_param = None capacity_input_param_name = None count_output_param = None count_output_param_name = None array_param = None array_param_name = None for i, p in enumerate(method.decl_params): if p.no_auto_validity: continue param_name = p.name match = CAPACITY_INPUT_RE.match(param_name) if match: capacity_input_param = {"param": p, "index": i, "match": match} capacity_input_param_name = param_name continue match = COUNT_OUTPUT_RE.match(param_name) if match: count_output_param = {"param": p, "index": i, "match": match} count_output_param_name = param_name continue # Try detecting the output array using its length field if capacity_input_param_name is not None \ and p.pointer_count_var == capacity_input_param_name: array_param = {"param": p, "index": i, "match": match} array_param_name = param_name if not capacity_input_param_name or \ not count_output_param_name or \ not array_param_name: # If we're missing at least one, stop checking two-call stuff here. return False method.is_two_call = True method.masks_simple = False # Should we put "ToVector" on the method name? needs_name_decoration = True item_type = array_param['param'].type method.item_type = item_type item_type_cpp = _project_type_name(item_type) method.item_type_cpp = item_type_cpp templated = method.name in TEMPLATED_TWO_CALL method.templated = templated vector_member_type = item_type_cpp if templated: vector_member_type = 'ResultItemType' vec_type = "std::vector<{}, Allocator>".format(vector_member_type) method.vec_type = vec_type method.template_decl_list.insert( 0, "typename Allocator = std::allocator<{}>".format( vector_member_type)) method.template_defn_list.insert(0, "typename Allocator") if templated: method.template_decl_list.insert(0, "typename ResultItemType") method.template_defn_list.insert(0, "typename ResultItemType") method.capacity_input_param_name = capacity_input_param_name method.count_output_param_name = count_output_param_name method.array_param_name = array_param_name method.capacity_input_param = capacity_input_param method.count_output_param = count_output_param method.array_param = array_param method.decl_dict[capacity_input_param_name] = None method.decl_dict[count_output_param_name] = None method.decl_dict[array_param_name] = None method.access_dict[ count_output_param_name] = "&" + count_output_param_name if item_type == "char": method.bare_return_type = "string_with_allocator<Allocator>" method.return_constructor = method.bare_return_type + "{%s.begin(), %s.end(), vectorAllocator}" % ( array_param_name, array_param_name) method.returns.append("str") needs_name_decoration = False else: method.bare_return_type = vec_type method.return_constructor = array_param_name method.returns.append(array_param_name) if needs_name_decoration: self._append_to_method_name_before_vendor(method, "ToVector") self._update_enhanced_return_type(method) def _method_has_single_output(self, method): if len(method.get_success_codes()) > 1: return False last_param = method.params[-1] if last_param.is_const or last_param.pointer_count != 1 or last_param.array_count_var != '': return False for param in method.params[:-1]: if param.is_handle: continue if param.pointer_count > 0 and not param.is_const: return False if not self.quiet: print("method " + method.name + " has output parameter " + last_param.name + " of type " + last_param.type) return True def _enhanced_method_projection(self, method): """Perform the manipulation of a MethodProjection to convert it from C to C++ for "enhanced mode".""" method.masks_simple = True self._basic_method_projection(method) method.bare_return_type = "void" successes = method.get_success_codes() method.multiple_success_codes = len(successes) > 1 if len(successes) > 1: method.successes_arg = ", {%s}" % (", ".join(successes)) else: method.successes_arg = "" outhandles = [ x for x in reversed(method.decl_params) if x.is_handle and x.pointer_count ] if method.is_create and len(outhandles) != 1: # This isn't really a create from our point of view method.is_create = False if method.is_create: method.masks_simple = False outparam = outhandles[0] cpp_outtype = _project_type_name(outparam.type) method.bare_return_type = cpp_outtype # Filter out the one we're returning. method.decl_params = [ x for x in method.decl_params if x != outparam ] method.decl_dict[outparam.name] = None method.pre_statements.append("{} handle;".format(cpp_outtype)) method.access_dict[outparam.name] = "handle.put()" method.returns.append("handle") elif method.is_destroy: # Clear the handle method.post_statements.append("val_ = XR_NULL_HANDLE;") elif self._method_has_single_output(method): method.masks_simple = False outparam = method.decl_params[-1] cpp_outtype = _project_type_name(outparam.type) method.bare_return_type = cpp_outtype method.decl_params.pop() method.decl_dict[outparam.name] = None method.pre_statements.append("{} returnVal;".format(cpp_outtype)) if outparam.type in self.projected_types: method.access_dict[ outparam.name] = "OPENXR_HPP_NAMESPACE::put(returnVal)" else: method.access_dict[outparam.name] = "&returnVal" method.returns.append("returnVal") self._update_enhanced_return_type(method) # Look for two-call if self._enhanced_method_projection_twocall(method): # No further enhancements. return def _unique_method_projection(self, method): """Perform the manipulation of a MethodProjection for a creation function to convert it from C to C++ returning a UniqueHandle.""" self._enhanced_method_projection(method) self._append_to_method_name_before_vendor(method, "Unique") method.returns.append("deleter") method.return_template_params = [ method.bare_return_type, "impl::RemoveRefConst<Dispatch>" ] method.post_statements.append( 'ObjectDestroy<impl::RemoveRefConst<Dispatch>> deleter{d};') method.handle_return_type = method.bare_return_type method.bare_return_type = "UniqueHandle<{}, impl::RemoveRefConst<Dispatch>>".format( method.bare_return_type) # method.returns[1] = "{}({}, {})" self._update_enhanced_return_type(method) def _append_to_method_name_before_vendor(self, method, s): "Append a string to the end of the cpp_name of a method, but before any vendor suffix." vendor = self.findVendorSuffix(method.cpp_name) if vendor: # Keep the vendor suffix on the end. method.cpp_name = _strip_suffix(method.cpp_name, vendor) method.cpp_name += s if vendor: method.cpp_name += vendor def outputGeneratedHeaderWarning(self): # File Comment generated_warning = '// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********\n' generated_warning += '// See cpp_generator.py for modifications\n' generated_warning += '// ************************************************************\n' assert (self.createEnumValue( "XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT", "XrStructureType") == "SpatialAnchorSpaceCreateInfoMSFT") assert (self.createEnumValue( "XR_PERF_SETTINGS_SUB_DOMAIN_COMPOSITING_EXT", "XrPerfSettingsSubDomainEXT") == "Compositing") write(generated_warning, file=self.outFile) # Call the base class to properly begin the file, and then add # the file-specific header information. # self the ConformanceLayerHeaderGenerator object # gen_opts the ConformanceLayerHeaderGeneratorOptions object def beginFile(self, genOpts): AutomaticSourceOutputGenerator.beginFile(self, genOpts) self.conventions = self.genOpts.conventions self.env.globals['filename'] = genOpts.filename self.env.tests['cpp_hidden_member'] = self._cpp_hidden_member self.env.tests['struct_output'] = self._is_struct_output self.env.tests['struct_input'] = self._is_struct_input self.template = JinjaTemplate(self.env, "template_{}".format(genOpts.filename)) def extensionReturnCodesForCommand(self, cur_cmd): return (x for x in self.registry.commandextensionerrors + self.registry.commandextensionsuccesses if x.command == cur_cmd.name) def allReturnCodesForCommand(self, cur_cmd): return cur_cmd.return_values + list( self.extensionReturnCodesForCommand(cur_cmd)) def _is_base_only(self, struct): if not struct: return False tag_member = [x for x in struct.members if x.name == "type"] if not tag_member: return False return tag_member[0].values is None def _cpp_hidden_member(self, member): return member.name == "type" or member.name == "next" def _struct_member_count(self, struct): return len(struct.members) def _bitmask_for_flags(self, flags): return self.dict_bitmasks[flags.valid_flags] def _is_struct_input(self, struct): nextptr = [x.cdecl for x in struct.members if x.name == 'next'] return nextptr and 'const' in nextptr[0] def _is_struct_output(self, struct): if struct.returned_only: return True nextptr = [x.cdecl for x in struct.members if x.name == 'next'] if not nextptr: return False return 'const' not in nextptr[0] def _is_member_defaultable(self, member): if member.pointer_count > 0 or (member.type == 'char' and member.is_array): return True if member.type.startswith("uint") or member.type.startswith( "int") or member.type.startswith("float"): return True if member.type == "XrBool32": return True if not self._is_tagged_type(member.type): # Might be an exaggeration? return True if member.type in self.dict_structs: member_struct = self.dict_structs[member.type] if self._is_struct_output(member_struct): return True return False # assert(False) return True def _get_default_for_member(self, member, struct_name=None, default_val="{}"): defaultValue = default_val if member.pointer_count > 0 or (member.type == 'char' and member.is_array): defaultValue = "nullptr" elif member.type.startswith("uint") or member.type.startswith("int"): defaultValue = "0" elif member.type.startswith("float"): # special case XrQuaternionf::w so a default constructor xr::Quaternionf is an identity if struct_name == 'XrQuaternionf' and member.name == 'w': defaultValue = '1.0f' else: defaultValue = '0.0f' elif member.type == "XrBool32": defaultValue = "false" elif not self._is_tagged_type(member.type): defaultValue = default_val elif member.type in self.dict_structs: member_struct = self.dict_structs[member.type] if self._is_struct_output(member_struct): defaultValue = default_val else: defaultValue = default_val return defaultValue def _index0_of_first_visible_defaultable_member(self, members): for i, member in reversed( tuple( enumerate(x for x in members if not self._cpp_hidden_member(x)))): if not self._is_member_defaultable(member): raise RuntimeError( "Found a non-defaultable member, errors possible elsewhere due to untested codepath." ) return i + 1 return 0 def _project_cppdecl(self, struct, member, defaulted=False, suffix="", input=False): result = member.cdecl.strip() if "[" in result: # Insert the suffix before the array decl pos = result.find("[") result = result[:pos] + suffix + result[pos:] else: result += suffix # Kind of hacky, perhaps switch _project_type_name to a regex based approach? if (member.is_const): result = _strip_prefix(result, "const").strip() if member.type.startswith("Xr"): result = _project_type_name(result) if (member.is_const): result = "const " + result if input: if member.type == 'char' and member.is_array and member.pointer_count == 0: # We'll initialize a fixed-size string with a cstring. result = "const char* " + member.name + suffix elif member.type.startswith("Xr") and member.pointer_count == 0: result = "const " + _project_type_name( member.type) + "& " + member.name + suffix if defaulted: defaultValue = self._get_default_for_member(member, struct.name) result = result + " = " + defaultValue return result def requires_platform_header(self, entity): if not hasattr(entity, "extname"): return False extname = entity.extname if self.isCoreExtensionName(extname): return False return self.dict_extensions[extname].protect_value is not None # Write out all the information for the appropriate file, # and then call down to the base class to wrap everything up. # self the ConformanceLayerBaseGenerator object def endFile(self): sorted_cmds = self.core_commands + self.ext_commands self.dict_extensions = {} for ext in self.extensions: self.dict_extensions[ext.name] = ext self.dict_handles = {} for handle in self.api_handles: self.dict_handles[handle.name] = handle self.dict_enums = {} for enum in self.api_enums: self.dict_enums[enum.name] = enum if enum.name == 'XrResult': result_enum = enum self.dict_structs = {} for struct in self.api_structures: self.dict_structs[struct.name] = struct self.dict_bitmasks = {} for bitmask in self.api_bitmasks: self.dict_bitmasks[bitmask.name] = bitmask self.dict_atoms = {} for basetype in self.api_base_types: if basetype.type == "XR_DEFINE_ATOM": self.dict_atoms[basetype.name] = basetype self.projected_types = MANUALLY_PROJECTED.union( self.dict_handles.keys()) self.projected_types.update(self.dict_enums.keys()) self.projected_types.update(self.dict_structs.keys()) self.projected_types.update(self.dict_bitmasks.keys()) self.projected_types.update(self.dict_atoms.keys()) self.projected_types.difference_update(SKIP_PROJECTION) # Every type mentioned in some other type's parentstruct attribute. struct_parents = ((otherType, otherType.elem.get('parentstruct')) for otherType in self.registry.typedict.values()) self.struct_parents = { child.elem.get('name'): parent for child, parent in struct_parents if parent is not None } self.parents = set(self.struct_parents.values()) self.skip_projection = SKIP_PROJECTION def children_of(t): return set(child for child, parent in self.struct_parents.items() if parent == t) self.struct_children = { parent: children_of(parent) for parent in self.parents } def fields_of(t): struct = self.dict_structs[t] members = struct.members return set(field.name for field in members if not self._cpp_hidden_member(field)) self.struct_fields = { parent: fields_of(parent) for parent in self.parents if parent in self.dict_structs } basic_cmds = {} enhanced_cmds = {} enhanced_cmds_no_exceptions = {} unique_cmds = {} unique_cmds_no_exceptions = {} for cmd in sorted_cmds: basic = MethodProjection(cmd, self) self._basic_method_projection(basic) basic_cmds[cmd.name] = basic enhanced = MethodProjection(cmd, self) self._enhanced_method_projection(enhanced) enhanced_cmds[cmd.name] = enhanced if enhanced.explicit_result_elided: # Now try again to make one without exceptions. enhanced_noexcept = MethodProjection(cmd, self) enhanced_noexcept.exceptions_permitted = False self._enhanced_method_projection(enhanced_noexcept) enhanced_cmds_no_exceptions[cmd.name] = enhanced_noexcept if enhanced.is_create: unique = MethodProjection(cmd, self) self._unique_method_projection(unique) unique_cmds[cmd.name] = unique # Now try again to make one without exceptions, if unique.explicit_result_elided: # all creation calls can elide the result. unique_noexcept = MethodProjection(cmd, self) unique_noexcept.exceptions_permitted = False self._unique_method_projection(unique_noexcept) unique_cmds_no_exceptions[cmd.name] = unique_noexcept else: # assumption violated assert (False) # Verify self.selftests() file_data = self.template.render( gen=self, registry=self.registry, null_instance_ok=VALID_FOR_NULL_INSTANCE, sorted_cmds=sorted_cmds, create_enum_value=self.createEnumValue, create_flag_value=self.createFlagValue, project_type_name=_project_type_name, result_enum=result_enum, create_enum_exception=self.createEnumException, basic_cmds=basic_cmds, enhanced_cmds=enhanced_cmds, enhanced_cmds_no_exceptions=enhanced_cmds_no_exceptions, unique_cmds=unique_cmds, unique_cmds_no_exceptions=unique_cmds_no_exceptions, discouraged_begin=_discouraged_begin, discouraged_end=_discouraged_end, generate_structure_type_from_name=self.conventions. generate_structure_type_from_name, is_tagged_type=self._is_tagged_type, project_cppdecl=self._project_cppdecl, bitmask_for_flags=self._bitmask_for_flags, is_static_length_array=_is_static_length_array, is_static_length_string=_is_static_length_string, struct_parents=self.struct_parents, struct_children=self.struct_children, struct_fields=self.struct_fields, project_struct=(lambda s: StructProjection(s, self)), get_default_for_member=self._get_default_for_member, index0_of_first_visible_defaultable_member=self. _index0_of_first_visible_defaultable_member, manually_projected=MANUALLY_PROJECTED, skip=SKIP, ) write(file_data, file=self.outFile) # Finish processing in superclass AutomaticSourceOutputGenerator.endFile(self) def selftests(self): assert (self._is_struct_input( self.dict_structs['XrCompositionLayerProjection'])) assert (self._is_struct_input( self.dict_structs['XrCompositionLayerBaseHeader'])) assert (not self._is_struct_input( self.dict_structs['XrApplicationInfo'])) assert (not self._is_struct_output( self.dict_structs['XrApplicationInfo'])) # index = self._index0_of_first_visible_defaultable_member(self.dict_structs['XrApplicationInfo'].members) # print(index) assert (self._index0_of_first_visible_defaultable_member( self.dict_structs['XrApplicationInfo'].members) == 0)
class CReflectionOutputGenerator(OutputGenerator): """Generate specified API interfaces in a specific style, such as a C header""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.env = make_jinja_environment(file_with_templates_as_sibs=__file__) self.structs = [] self.enums = [] self.bitmasks = [] self.protects = set() def beginFile(self, genOpts): OutputGenerator.beginFile(self, genOpts) self.template = JinjaTemplate(self.env, "template_{}".format(genOpts.filename)) def getStructsForProtect(self, protect=None): return [x for x in self.structs if x.protect == protect and x.structTypeName is not None] def endFile(self): file_data = '' unprotected_structs = self.getStructsForProtect() protected_structs = [(x, self.getStructsForProtect(x)) for x in sorted(self.protects)] extensions = list( ((name, data) for name, data in self.registry.extdict.items() if data.supported != 'disabled')) def getNumber(x): return int(x[1].number) extensions.sort(key=getNumber) file_data += self.template.render( unprotectedStructs=unprotected_structs, protectedStructs=protected_structs, structs=self.structs, enums=self.enums, bitmasks=self.bitmasks, extensions=extensions) write(file_data, file=self.outFile) # Finish processing in superclass OutputGenerator.endFile(self) def genType(self, typeinfo, name, alias): OutputGenerator.genType(self, typeinfo, name, alias) typeElem = typeinfo.elem if alias: return category = typeElem.get('category') if category in ('struct', 'union'): # If the type is a struct type, generate it using the # special-purpose generator. self.genStruct(typeinfo, name, alias) def genStruct(self, typeinfo, typeName, alias): OutputGenerator.genStruct(self, typeinfo, typeName, alias) if alias: return structTypeName = None members = [] for member in typeinfo.getMembers(): memberName = getElemName(member) memberType = getElemType(member) if self.conventions.is_structure_type_member(memberType, memberName): structTypeName = member.get("values") members.append(memberName) protect = set() if self.featureExtraProtect: protect.update(self.featureExtraProtect.split(',')) localProtect = typeinfo.elem.get('protect') if localProtect: protect.update(localProtect.split(',')) if protect: protect = tuple(protect) else: protect = None self.structs.append(CStruct(typeName, structTypeName, members, protect)) if protect: self.protects.add(protect) def genGroup(self, groupinfo, groupName, alias=None): OutputGenerator.genGroup(self, groupinfo, groupName, alias) if alias: return if getElemType(groupinfo.elem) == 'bitmask': bitmaskTypeName = getElemName(groupinfo.flagType.elem) bitmaskTuples = [] for elem in groupinfo.elem.findall('enum'): (numVal, strVal) = self.enumToValue(elem, True) bitmaskTuples.append((getElemName(elem), strVal)) self.bitmasks.append(CBitmask(bitmaskTypeName, bitmaskTuples)) else: groupElem = groupinfo.elem expandName = re.sub(r'([0-9a-z_])([A-Z0-9][^A-Z0-9]?)', r'\1_\2', groupName).upper() expandPrefix = expandName expandSuffix = '' expandSuffixMatch = re.search(r'[A-Z][A-Z]+$', groupName) if expandSuffixMatch: expandSuffix = '_' + expandSuffixMatch.group() # Strip off the suffix from the prefix expandPrefix = expandName.rsplit(expandSuffix, 1)[0] enumTuples = [] for elem in groupElem.findall('enum'): (numVal, strVal) = self.enumToValue(elem, True) if numVal is None: # then this is an alias or something continue enumTuples.append((getElemName(elem), strVal)) self.enums.append(CEnum(groupName, expandPrefix, expandSuffix, enumTuples))
def beginFile(self, genOpts): AutomaticSourceOutputGenerator.beginFile(self, genOpts) self.conventions = self.genOpts.conventions self.template = JinjaTemplate( self.env, "template_{}".format(genOpts.filename))
class CppGenerator(AutomaticSourceOutputGenerator): """Generate C++ wrapper header using XML element attributes from registry""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.env = make_jinja_environment(file_with_templates_as_sibs=__file__) self.env.filters['block_doxygen_comment'] = _block_doxygen_comment def outputGeneratedAuthorNote(self): # Disabled pass def outputCopywriteHeader(self): # Disabled - there is one in the template. pass def findVendorSuffix(self, name): for vendor in self.vendor_tags: if name.endswith(vendor): return vendor def getEnumValuePrefixSuffix(self, typename): if typename in RULE_BREAKING_ENUMS: prefix = RULE_BREAKING_ENUMS[typename] else: prefix = self.conventions.generate_structure_type_from_name(typename) prefix = prefix.replace('XR_TYPE', 'XR') suffix = self.findVendorSuffix(prefix) if suffix: prefix = _strip_suffix(prefix, '_' + suffix) return prefix, suffix def createEnumValue(self, name, typename): prefix, type_suffix = self.getEnumValuePrefixSuffix(typename) name = _strip_prefix(name, prefix + '_') suffix = None if type_suffix: name = _strip_suffix(name, '_' + type_suffix) suffix = self.findVendorSuffix(name) if suffix: name = _strip_suffix(name, '_' + suffix) enum_name = _to_camel_case(name) if suffix: enum_name += suffix return enum_name def getFlagValuePrefixSuffix(self, typename): prefix = self.conventions.generate_structure_type_from_name(typename) prefix = prefix.replace('XR_TYPE', 'XR') suffix = self.findVendorSuffix(prefix) if suffix: prefix = _strip_suffix(prefix, '_' + suffix) suffix = 'BIT_' + suffix else: suffix = 'BIT' prefix = prefix[:-len('_FLAG_BITS')] return prefix, suffix def createFlagValue(self, name, typename): prefix, type_suffix = self.getFlagValuePrefixSuffix(typename) name = _strip_prefix(name, prefix + '_') suffix = None if type_suffix: name = _strip_suffix(name, '_' + type_suffix) suffix = self.findVendorSuffix(name) if suffix: name = _strip_suffix(name, '_' + suffix) enum_name = _to_camel_case(name) if suffix: enum_name += suffix return enum_name def createEnumException(self, name): enum_val = self.createEnumValue(name, 'XrResult') return enum_val.replace('Error', '') + 'Error' def _basic_method_projection(self, method): """Perform the basic manipulation of a MethodProjection to convert it from C to C++.""" is_two_call = self._enhanced_method_detect_twocall(method) # Free function to method if method.handle: handle = method.params[0] method.decl_params.pop(0) method.decl_dict[handle.name] = None method.access_dict[handle.name] = "this->get()" # if method.cpp_name.endswith(method.cpp_handle): # method.cpp_name = _strip_suffix(method.cpp_name, method.cpp_handle) method.qualified_name = "{}::{}".format(method.cpp_handle, method.cpp_name) # Convert handles for param in method.decl_params: if param.type in self.dict_handles: name = param.name cpp_type = _project_type_name(param.type) if param.pointer_count == 0: # Input handle method.decl_dict[name] = "{} {}".format( cpp_type, name) method.access_dict[name] = "{}.get()".format(name.strip()) elif param.pointer_count == 1: # Output handle method.decl_dict[name] = "{}& {}".format( cpp_type, name) method.access_dict[name] = "{}.put()".format(name.strip()) # Convert enums for param in method.decl_params: if param.type in self.dict_enums: name = param.name cpp_type = _project_type_name(param.type) if param.pointer_count == 0: # Input enum method.decl_dict[name] = "{} {}".format( cpp_type, name) method.access_dict[name] = "OPENXR_HPP_NAMESPACE::get({})".format(name.strip()) elif param.pointer_count == 1 and not is_two_call: # Output enum method.decl_dict[name] = "{}& {}".format( cpp_type, name) method.pre_statements.append( "{} {}_tmp;".format(param.type, name.strip())) method.access_dict[name] = "{}_tmp".format(name.strip()) method.post_statements.append( "{name} = static_cast<{t}>({name}_tmp);".format(name=name.strip(), t=cpp_type)) # Convert structs for param in method.decl_params: if param.type not in self.dict_structs: continue if self._is_base_only(self.dict_structs[param.type]): # This is a polymorphic parameter: skip conversion for now. continue name = param.name cpp_type = _project_type_name(param.type) if param.is_const: # Input struct method.decl_dict[name] = "const {}& {}".format(cpp_type, name) method.access_dict[name] = "OPENXR_HPP_NAMESPACE::get({})".format(name.strip()) elif param.pointer_count == 1 and not is_two_call: # Output struct method.decl_dict[name] = "{}& {}".format(cpp_type, name) method.access_dict[name] = "OPENXR_HPP_NAMESPACE::put({})".format(name.strip()) # Convert XrTime and XrDuration as special case (promoted from raw ints to constexpr wrapper classes) for param in method.decl_params: if param.type not in MANUALLY_PROJECTED: continue name = param.name cpp_type = _project_type_name(param.type) method.decl_dict[name] = "const {}& {}".format(cpp_type, name) method.access_dict[name] = "OPENXR_HPP_NAMESPACE::get({})".format(name.strip()) def _update_enhanced_return_type(self, method): """Set the return type based on the bare return type. Used by _enhanced_method_projection and _unique_method_projection.""" if method.successes_arg: if method.bare_return_type == "void": method.return_type = "Result" else: method.return_type = "ResultValue<{}>".format(method.bare_return_type) else: method.return_type = "ResultValueType<{}>::type".format(method.bare_return_type) if method.bare_return_type != "void": method.return_type = "typename " + method.return_type if method.return_template_params: tmpl = "<{}>".format(",".join(method.return_template_params)) else: tmpl = "" method.return_statement = 'return impl::createResultValue{tmpl}({rets}, OPENXR_HPP_NAMESPACE_STRING "::{name}"{successes});'.format( tmpl=tmpl, rets=",".join(method.returns), name=method.qualified_name, successes=method.successes_arg) def _is_tagged_type(self, typename): if typename not in self.dict_structs: return False return any((x.name == "type" for x in self.dict_structs[typename].members)) def _get_tag(self, typename): if typename not in self.dict_structs: return None tag_member = [x for x in self.dict_structs[typename].members if x.name == "type"] if not tag_member: return None raw_tag = tag_member[0].values if not raw_tag: return None return "StructureType::" + self.createEnumValue(raw_tag, "XrStructureType") def _enhanced_method_detect_twocall(self, method): # Find the three important parameters capacity_input_param_name = None count_output_param_name = None array_param_name = None for i, p in enumerate(method.decl_params): if p.no_auto_validity: continue param_name = p.name match = CAPACITY_INPUT_RE.match(param_name) if match: capacity_input_param_name = param_name continue match = COUNT_OUTPUT_RE.match(param_name) if match: count_output_param_name = param_name continue # Try detecting the output array using its length field if capacity_input_param_name is not None \ and p.pointer_count_var == capacity_input_param_name: array_param_name = param_name return capacity_input_param_name and count_output_param_name and array_param_name def _enhanced_method_projection_twocall(self, method): # Find the three important parameters capacity_input_param = None capacity_input_param_name = None count_output_param = None count_output_param_name = None array_param = None array_param_name = None for i, p in enumerate(method.decl_params): if p.no_auto_validity: continue param_name = p.name match = CAPACITY_INPUT_RE.match(param_name) if match: capacity_input_param = { "param": p, "index": i, "match": match } capacity_input_param_name = param_name continue match = COUNT_OUTPUT_RE.match(param_name) if match: count_output_param = { "param": p, "index": i, "match": match } count_output_param_name = param_name continue # Try detecting the output array using its length field if capacity_input_param_name is not None \ and p.pointer_count_var == capacity_input_param_name: array_param = { "param": p, "index": i, "match": match } array_param_name = param_name if not capacity_input_param_name or \ not count_output_param_name or \ not array_param_name: # If we're missing at least one, stop checking two-call stuff here. return False method.is_two_call = True method.masks_simple = False item_type = array_param['param'].type method.item_type = item_type item_type_cpp = _project_type_name(item_type) method.item_type_cpp = item_type_cpp templated = method.name in TEMPLATED_TWO_CALL method.templated = templated vector_member_type = item_type_cpp if templated: vector_member_type = 'ResultItemType' vec_type = "std::vector<{}, Allocator>".format(vector_member_type) method.vec_type = vec_type method.template_decl_list.insert(0, "typename Allocator = std::allocator<{}>".format(vector_member_type)) method.template_defn_list.insert(0, "typename Allocator") if templated: method.template_decl_list.insert(0, "typename ResultItemType") method.template_defn_list.insert(0, "typename ResultItemType") method.capacity_input_param_name = capacity_input_param_name method.count_output_param_name = count_output_param_name method.array_param_name = array_param_name method.capacity_input_param = capacity_input_param method.count_output_param = count_output_param method.array_param = array_param method.decl_dict[capacity_input_param_name] = None method.decl_dict[count_output_param_name] = None method.decl_dict[array_param_name] = None method.access_dict[count_output_param_name] = "&" + count_output_param_name if item_type == "char": method.bare_return_type = "string_with_allocator<Allocator>" method.return_constructor = method.bare_return_type + "{%s.begin(), %s.end(), vectorAllocator}" % (array_param_name, array_param_name) method.returns.append("str") else: method.bare_return_type = vec_type method.return_constructor = array_param_name method.returns.append(array_param_name) self._update_enhanced_return_type(method) print(method.name, "is a two-call") def _method_has_single_output(self, method): if len(method.get_success_codes()) > 1: return False last_param = method.params[-1] if last_param.is_const or last_param.pointer_count != 1 or last_param.array_count_var != '': return False for param in method.params[:-1]: if param.is_handle: continue if param.pointer_count > 0 and not param.is_const: return False print("method " + method.name + " has output parameter " + last_param.name + " of type " + last_param.type) return True def _enhanced_method_projection(self, method): """Perform the manipulation of a MethodProjection to convert it from C to C++ for "enhanced mode".""" method.masks_simple = True self._basic_method_projection(method) method.bare_return_type = "void" successes = method.get_success_codes() if len(successes) > 1: method.successes_arg = ", {%s}" % (", ".join(successes)) else: method.successes_arg = "" if method.is_create: method.masks_simple = False outparam = method.decl_params[-1] cpp_outtype = _project_type_name(outparam.type) method.bare_return_type = cpp_outtype method.decl_params.pop() method.decl_dict[outparam.name] = None method.pre_statements.append("{} handle;".format(cpp_outtype)) method.access_dict[outparam.name] = "handle.put()" method.returns.append("handle") elif self._method_has_single_output(method): method.masks_simple = False outparam = method.decl_params[-1] cpp_outtype = _project_type_name(outparam.type) method.bare_return_type = cpp_outtype method.decl_params.pop() method.decl_dict[outparam.name] = None method.pre_statements.append("{} returnVal;".format(cpp_outtype)) if outparam.type in self.projected_types: method.access_dict[outparam.name] = "OPENXR_HPP_NAMESPACE::put(returnVal)" else: method.access_dict[outparam.name] = "&returnVal" method.returns.append("returnVal") self._update_enhanced_return_type(method) # Look for two-call if self._enhanced_method_projection_twocall(method): # No further enhancements. return def _unique_method_projection(self, method): """Perform the manipulation of a MethodProjection for a creation function to convert it from C to C++ returning a UniqueHandle.""" self._enhanced_method_projection(method) vendor = self.findVendorSuffix(method.cpp_name) if vendor: # Keep the vendor suffix on the end. method.cpp_name = _strip_suffix(method.cpp_name, vendor) method.cpp_name += "Unique" if vendor: method.cpp_name += vendor if method.handle: method.qualified_name = "{}::{}".format(method.cpp_handle, method.cpp_name) else: method.qualified_name = method.cpp_name method.returns.append("deleter") method.return_template_params = [method.bare_return_type, "impl::RemoveRefConst<Dispatch>"] method.post_statements.append('ObjectDestroy<impl::RemoveRefConst<Dispatch>> deleter{d};') method.bare_return_type = "UniqueHandle<{}, impl::RemoveRefConst<Dispatch>>".format(method.bare_return_type) self._update_enhanced_return_type(method) def outputGeneratedHeaderWarning(self): # File Comment generated_warning = '// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********\n' generated_warning += '// See cpp_generator.py for modifications\n' generated_warning += '// ************************************************************\n' assert(self.createEnumValue("XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT", "XrStructureType") == "SpatialAnchorSpaceCreateInfoMSFT") assert(self.createEnumValue("XR_PERF_SETTINGS_SUB_DOMAIN_COMPOSITING_EXT", "XrPerfSettingsSubDomainEXT") == "Compositing") write(generated_warning, file=self.outFile) # Call the base class to properly begin the file, and then add # the file-specific header information. # self the ConformanceLayerHeaderGenerator object # gen_opts the ConformanceLayerHeaderGeneratorOptions object def beginFile(self, genOpts): AutomaticSourceOutputGenerator.beginFile(self, genOpts) self.conventions = self.genOpts.conventions self.template = JinjaTemplate( self.env, "template_{}".format(genOpts.filename)) def extensionReturnCodesForCommand(self, cur_cmd): return (x for x in self.registry.commandextensionerrors + self.registry.commandextensionsuccesses if x.command == cur_cmd.name) def allReturnCodesForCommand(self, cur_cmd): return cur_cmd.return_values + list(self.extensionReturnCodesForCommand(cur_cmd)) def _is_base_only(self, struct): if not struct: return False tag_member = [x for x in struct.members if x.name == "type"] if not tag_member: return False return tag_member[0].values is None def _cpp_hidden_member(self, member): return member.name == "type" or member.name == "next" def _struct_member_count(self, struct): return len(struct.members) def _bitmask_for_flags(self, flags): return self.dict_bitmasks[flags.valid_flags] def _project_cppdecl(self, struct, member, defaulted=False, suffix="", input=False): result = member.cdecl.strip() + suffix # Kind of hacky, perhaps switch _project_type_name to a regex based approach? if (member.is_const): result = _strip_prefix(result, "const").strip() if member.type.startswith("Xr"): result = _project_type_name(result) if (member.is_const): result = "const " + result if input: if member.type == 'char' and member.is_array and member.pointer_count == 0: result = "const char* " + member.name + suffix elif member.type.startswith("Xr") and member.pointer_count == 0: result = "const " + _project_type_name(member.type) + "& " + member.name + suffix if defaulted: defaultValue = "{}" if member.pointer_count > 0 or (member.type == 'char' and member.is_array): defaultValue = "nullptr" elif member.type.startswith("uint") or member.type.startswith("int"): defaultValue = "0" elif member.type.startswith("float"): # special case XrQuaternionf::w so a default constructor xr::Quaternionf is an identity if struct.name == 'XrQuaternionf' and member.name == 'w': defaultValue = '1.0f' else: defaultValue = '0.0f' elif member.type == "XrBool32": defaultValue = "XR_FALSE" result = result + " = " + defaultValue return result # Write out all the information for the appropriate file, # and then call down to the base class to wrap everything up. # self the ConformanceLayerBaseGenerator object def endFile(self): sorted_cmds = self.core_commands + self.ext_commands self.dict_handles = {} for handle in self.api_handles: self.dict_handles[handle.name] = handle self.dict_enums = {} for enum in self.api_enums: self.dict_enums[enum.name] = enum if enum.name == 'XrResult': result_enum = enum self.dict_structs = {} for struct in self.api_structures: self.dict_structs[struct.name] = struct self.dict_bitmasks = {} for bitmask in self.api_bitmasks: self.dict_bitmasks[bitmask.name] = bitmask self.projected_types = MANUALLY_PROJECTED.union(self.dict_handles.keys()) self.projected_types.update(self.dict_enums.keys()) self.projected_types.update(self.dict_structs.keys()) self.projected_types.update(self.dict_bitmasks.keys()) # Every type mentioned in some other type's parentstruct attribute. struct_parents = ((otherType, otherType.elem.get('parentstruct')) for otherType in self.registry.typedict.values()) self.struct_parents = {child.elem.get('name'): parent for child, parent in struct_parents if parent is not None} self.parents = set(self.struct_parents.values()) def children_of(t): return set(child for child, parent in self.struct_parents.items() if parent == t) self.struct_children = {parent: children_of(parent) for parent in self.parents} def fields_of(t): struct = self.dict_structs[t] members = struct.members return set(field.name for field in members if not self._cpp_hidden_member(field)) self.struct_fields = {parent: fields_of(parent) for parent in self.parents} basic_cmds = {} enhanced_cmds = {} unique_cmds = {} for cmd in sorted_cmds: basic = MethodProjection(cmd, self) self._basic_method_projection(basic) basic_cmds[cmd.name] = basic enhanced = MethodProjection(cmd, self) self._enhanced_method_projection(enhanced) enhanced_cmds[cmd.name] = enhanced if enhanced.is_create: unique = MethodProjection(cmd, self) self._unique_method_projection(unique) unique_cmds[cmd.name] = unique file_data = self.template.render( gen=self, registry=self.registry, null_instance_ok=VALID_FOR_NULL_INSTANCE, sorted_cmds=sorted_cmds, create_enum_value=self.createEnumValue, create_flag_value=self.createFlagValue, project_type_name=_project_type_name, result_enum=result_enum, create_enum_exception=self.createEnumException, basic_cmds=basic_cmds, enhanced_cmds=enhanced_cmds, unique_cmds=unique_cmds, discouraged_begin=_discouraged_begin, discouraged_end=_discouraged_end, generate_structure_type_from_name=self.conventions.generate_structure_type_from_name, is_tagged_type=self._is_tagged_type, project_cppdecl=self._project_cppdecl, cpp_hidden_member=self._cpp_hidden_member, struct_member_count=self._struct_member_count, bitmask_for_flags=self._bitmask_for_flags, is_static_length_string=_is_static_length_string, parents=self.parents, struct_parents=self.struct_parents, struct_children=self.struct_children, struct_fields=self.struct_fields, get_tag=self._get_tag, is_base_only=self._is_base_only ) write(file_data, file=self.outFile) # Finish processing in superclass AutomaticSourceOutputGenerator.endFile(self)