Mercurial > games > semicongine
diff fuhtark_test/Vulkan-Headers-1.4.334/registry/spec_tools/conventions.py @ 1501:f40d9d814c08 default tip main
did: correct vulkan-api generator
| author | sam <sam@basx.dev> |
|---|---|
| date | Wed, 26 Nov 2025 23:34:29 +0700 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fuhtark_test/Vulkan-Headers-1.4.334/registry/spec_tools/conventions.py Wed Nov 26 23:34:29 2025 +0700 @@ -0,0 +1,563 @@ +#!/usr/bin/env python3 -i +# +# Copyright 2013-2025 The Khronos Group Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +# Base class for working-group-specific style conventions, +# used in generation. + +from enum import Enum +import abc +import re + +# Type categories that respond "False" to isStructAlwaysValid +# basetype is home to typedefs like ..Bool32 +CATEGORIES_REQUIRING_VALIDATION = set(('handle', + 'enum', + 'bitmask', + 'basetype', + None)) + +# These are basic C types pulled in via openxr_platform_defines.h +TYPES_KNOWN_ALWAYS_VALID = set(('char', + 'float', + 'int8_t', 'uint8_t', + 'int16_t', 'uint16_t', + 'int32_t', 'uint32_t', + 'int64_t', 'uint64_t', + 'size_t', + 'intptr_t', 'uintptr_t', + 'int', + )) + +# Split an extension name into vendor ID and name portions +EXT_NAME_DECOMPOSE_RE = re.compile(r'(?P<prefix>[A-Za-z]+)_(?P<vendor>[A-Za-z]+)_(?P<name>[\w_]+)') + +# Match an API version name. +# Match object includes API prefix, major, and minor version numbers. +# This could be refined further for specific APIs. +# Handles both simple versions (VK_VERSION_1_0) and component-specific versions (VK_BASE_VERSION_1_0) +API_VERSION_NAME_RE = re.compile(r'(?P<apivariant>[A-Za-z]+)(?:_(?:BASE|COMPUTE|GRAPHICS))?_VERSION_(?P<major>[0-9]+)_(?P<minor>[0-9]+)') + +class ProseListFormats(Enum): + """A connective, possibly with a quantifier.""" + AND = 0 + EACH_AND = 1 + OR = 2 + ANY_OR = 3 + + @classmethod + def from_string(cls, s): + if s == 'or': + return cls.OR + if s == 'and': + return cls.AND + raise RuntimeError(f"Unrecognized string connective: {s}") + + @property + def connective(self): + if self in (ProseListFormats.OR, ProseListFormats.ANY_OR): + return 'or' + return 'and' + + def quantifier(self, n): + """Return the desired quantifier for a list of a given length.""" + if self == ProseListFormats.ANY_OR: + if n > 1: + return 'any of ' + elif self == ProseListFormats.EACH_AND: + if n > 2: + return 'each of ' + if n == 2: + return 'both of ' + return '' + + +class ConventionsBase(abc.ABC): + """WG-specific conventions.""" + + def __init__(self): + self._command_prefix = None + self._type_prefix = None + + def formatVersionOrExtension(self, name): + """Mark up an API version or extension name as a link in the spec.""" + + # Is this a version name? + match = API_VERSION_NAME_RE.match(name) + if match is not None: + return self.formatVersion(name, + match.group('apivariant'), + match.group('major'), + match.group('minor')) + else: + # If not, assumed to be an extension name. Might be worth checking. + return self.formatExtension(name) + + def formatVersion(self, name, apivariant, major, minor): + """Mark up an API version name as a link in the spec.""" + return f'`<<{name}>>`' + + def formatExtension(self, name): + """Mark up an extension name as a link in the spec.""" + return f'`<<{name}>>`' + + def formatSPIRVlink(self, name): + """Mark up a SPIR-V extension name as an external link in the spec. + Since these are external links, the formatting probably will be + the same for all APIs creating such links, so long as they use + the asciidoctor {spirv} attribute for the base path to the SPIR-V + extensions.""" + + (vendor, _) = self.extension_name_split(name) + + return f'{{spirv}}/{vendor}/{name}.html[{name}]' + + @property + @abc.abstractmethod + def null(self): + """Preferred spelling of NULL.""" + raise NotImplementedError + + def makeProseList(self, elements, fmt=ProseListFormats.AND, with_verb=False, *args, **kwargs): + """Make a (comma-separated) list for use in prose. + + Adds a connective (by default, 'and') + before the last element if there are more than 1. + + Adds the right one of "is" or "are" to the end if with_verb is true. + + Optionally adds a quantifier (like 'any') before a list of 2 or more, + if specified by fmt. + + Override with a different method or different call to + _implMakeProseList if you want to add a comma for two elements, + or not use a serial comma. + """ + return self._implMakeProseList(elements, fmt, with_verb, *args, **kwargs) + + @property + def struct_macro(self): + """Get the appropriate format macro for a structure. + + May override. + """ + return 'slink:' + + @property + def external_macro(self): + """Get the appropriate format macro for an external type like uint32_t. + + May override. + """ + return 'code:' + + @property + def allows_x_number_suffix(self): + """Whether vendor tags can be suffixed with X and a number to mark experimental extensions.""" + return False + + @property + @abc.abstractmethod + def structtype_member_name(self): + """Return name of the structure type member. + + Must implement. + """ + raise NotImplementedError() + + @property + @abc.abstractmethod + def nextpointer_member_name(self): + """Return name of the structure pointer chain member. + + Must implement. + """ + raise NotImplementedError() + + @property + @abc.abstractmethod + def xml_api_name(self): + """Return the name used in the default API XML registry for the default API""" + raise NotImplementedError() + + @abc.abstractmethod + def generate_structure_type_from_name(self, structname): + """Generate a structure type name, like XR_TYPE_CREATE_INSTANCE_INFO. + + Must implement. + """ + raise NotImplementedError() + + def makeStructName(self, name): + """Prepend the appropriate format macro for a structure to a structure type name. + + Uses struct_macro, so just override that if you want to change behavior. + """ + return self.struct_macro + name + + def makeExternalTypeName(self, name): + """Prepend the appropriate format macro for an external type like uint32_t to a type name. + + Uses external_macro, so just override that if you want to change behavior. + """ + return self.external_macro + name + + def _implMakeProseList(self, elements, fmt, with_verb, comma_for_two_elts=False, serial_comma=True): + """Internal-use implementation to make a (comma-separated) list for use in prose. + + Adds a connective (by default, 'and') + before the last element if there are more than 1, + and only includes commas if there are more than 2 + (if comma_for_two_elts is False). + + Adds the right one of "is" or "are" to the end if with_verb is true. + + Optionally adds a quantifier (like 'any') before a list of 2 or more, + if specified by fmt. + + Do not edit these defaults, override self.makeProseList(). + """ + assert serial_comma # did not implement what we did not need + if isinstance(fmt, str): + fmt = ProseListFormats.from_string(fmt) + + my_elts = list(elements) + if len(my_elts) > 1: + my_elts[-1] = f'{fmt.connective} {my_elts[-1]}' + + if not comma_for_two_elts and len(my_elts) <= 2: + prose = ' '.join(my_elts) + else: + prose = ', '.join(my_elts) + + quantifier = fmt.quantifier(len(my_elts)) + + parts = [quantifier, prose] + + if with_verb: + if len(my_elts) > 1: + parts.append(' are') + else: + parts.append(' is') + return ''.join(parts) + + @property + @abc.abstractmethod + def file_suffix(self): + """Return suffix of generated Asciidoctor files""" + raise NotImplementedError + + @abc.abstractmethod + def api_name(self, spectype=None): + """Return API or specification name for citations in ref pages. + + spectype is the spec this refpage is for. + 'api' (the default value) is the main API Specification. + If an unrecognized spectype is given, returns None. + + Must implement.""" + raise NotImplementedError + + def should_insert_may_alias_macro(self, genOpts): + """Return true if we should insert a "may alias" macro in this file. + + Only used by OpenXR right now.""" + return False + + @property + def command_prefix(self): + """Return the expected prefix of commands/functions. + + Implemented in terms of api_prefix.""" + if not self._command_prefix: + self._command_prefix = self.api_prefix[:].replace('_', '').lower() + return self._command_prefix + + @property + def type_prefix(self): + """Return the expected prefix of type names. + + Implemented in terms of command_prefix (and in turn, api_prefix).""" + if not self._type_prefix: + self._type_prefix = ''.join( + (self.command_prefix[0:1].upper(), self.command_prefix[1:])) + return self._type_prefix + + @property + @abc.abstractmethod + def api_prefix(self): + """Return API token prefix. + + Typically two uppercase letters followed by an underscore. + + Must implement.""" + raise NotImplementedError + + @property + def extension_name_prefix(self): + """Return extension name prefix. + + Typically two uppercase letters followed by an underscore. + + Assumed to be the same as api_prefix, but some APIs use different + case conventions.""" + + return self.api_prefix + + def extension_short_description(self, elem): + """Return a short description of an extension for use in refpages. + + elem is an ElementTree for the <extension> tag in the XML. + The default behavior is to use the 'type' field of this tag, but not + all APIs support this field.""" + + ext_type = elem.get('type') + + if ext_type is not None: + return f'{ext_type} extension' + else: + return '' + + @property + def write_contacts(self): + """Return whether contact list should be written to extension appendices""" + return False + + @property + def write_extension_type(self): + """Return whether extension type should be written to extension appendices""" + return True + + @property + def write_extension_number(self): + """Return whether extension number should be written to extension appendices""" + return True + + @property + def write_extension_revision(self): + """Return whether extension revision number should be written to extension appendices""" + return True + + @property + def write_refpage_include(self): + """Return whether refpage include should be written to extension appendices""" + return True + + @property + def api_version_prefix(self): + """Return API core version token prefix. + + Implemented in terms of api_prefix. + + May override.""" + return f"{self.api_prefix}VERSION_" + + @property + def KHR_prefix(self): + """Return extension name prefix for KHR extensions. + + Implemented in terms of api_prefix. + + May override.""" + return f"{self.api_prefix}KHR_" + + @property + def EXT_prefix(self): + """Return extension name prefix for EXT extensions. + + Implemented in terms of api_prefix. + + May override.""" + return f"{self.api_prefix}EXT_" + + def writeFeature(self, featureName, featureExtraProtect, filename): + """Return True if OutputGenerator.endFeature should write this feature. + + Defaults to always True. + Used in COutputGenerator. + + May override.""" + return True + + def requires_error_validation(self, return_type): + """Return True if the return_type element is an API result code + requiring error validation. + + Defaults to always False. + + May override.""" + return False + + @property + def required_errors(self): + """Return a list of required error codes for validation. + + Defaults to an empty list. + + May override.""" + return [] + + def is_voidpointer_alias(self, tag, text, tail): + """Return True if the declaration components (tag,text,tail) of an + element represents a void * type. + + Defaults to a reasonable implementation. + + May override.""" + return tag == 'type' and text == 'void' and tail.startswith('*') + + def make_voidpointer_alias(self, tail): + """Reformat a void * declaration to include the API alias macro. + + Defaults to a no-op. + + Must override if you actually want to use this feature in your project.""" + return tail + + def category_requires_validation(self, category): + """Return True if the given type 'category' always requires validation. + + Defaults to a reasonable implementation. + + May override.""" + return category in CATEGORIES_REQUIRING_VALIDATION + + def type_always_valid(self, typename): + """Return True if the given type name is always valid (never requires validation). + + This is for things like integers. + + Defaults to a reasonable implementation. + + May override.""" + return typename in TYPES_KNOWN_ALWAYS_VALID + + @property + def should_skip_checking_codes(self): + """Return True if more than the basic validation of return codes should + be skipped for a command.""" + + return False + + @property + def generate_index_terms(self): + """Return True if asiidoctor index terms should be generated as part + of an API interface from the docgenerator.""" + + return False + + @property + def generate_enum_table(self): + """Return True if asciidoctor tables describing enumerants in a + group should be generated as part of group generation.""" + return False + + @property + def generate_max_enum_in_docs(self): + """Return True if MAX_ENUM tokens should be generated in + documentation includes.""" + return False + + def extension_name_split(self, name): + """Split an extension name, returning (vendor, rest of name). + The API prefix of the name is ignored.""" + + match = EXT_NAME_DECOMPOSE_RE.match(name) + vendor = match.group('vendor') + bare_name = match.group('name') + + return (vendor, bare_name) + + @abc.abstractmethod + def extension_file_path(self, name): + """Return file path to an extension appendix relative to a directory + containing all such appendices. + - name - extension name + + Must implement.""" + raise NotImplementedError + + def extension_include_string(self, name): + """Return format string for include:: line for an extension appendix + file. + - name - extension name""" + + return f'include::{{appendices}}/{self.extension_file_path(name)}[]' + + @property + def provisional_extension_warning(self): + """Return True if a warning should be included in extension + appendices for provisional extensions.""" + return True + + @property + def generated_include_path(self): + """Return path relative to the generated reference pages, to the + generated API include files.""" + + return '{generated}' + + @property + def include_extension_appendix_in_refpage(self): + """Return True if generating extension refpages by embedding + extension appendix content (default), False otherwise + (OpenXR).""" + + return True + + def valid_flag_bit(self, bitpos): + """Return True if bitpos is an allowed numeric bit position for + an API flag. + + Behavior depends on the data type used for flags (which may be 32 + or 64 bits), and may depend on assumptions about compiler + handling of sign bits in enumerated types, as well.""" + return True + + @property + def duplicate_aliased_structs(self): + """ + Should aliased structs have the original struct definition listed in the + generated docs snippet? + """ + return False + + @property + def protectProtoComment(self): + """Return True if generated #endif should have a comment matching + the protection symbol used in the opening #ifdef/#ifndef.""" + return False + + @property + def extra_refpage_headers(self): + """Return any extra headers (preceding the title) for generated + reference pages.""" + return '' + + @property + def extra_refpage_body(self): + """Return any extra text (following the title) for generated + reference pages.""" + return '' + + def is_api_version_name(self, name): + """Return True if name is an API version name.""" + + return API_VERSION_NAME_RE.match(name) is not None + + @property + def docgen_language(self): + """Return the language to be used in docgenerator [source] + blocks.""" + + return 'c++' + + @property + def docgen_source_options(self): + """Return block options to be used in docgenerator [source] blocks, + which are appended to the 'source' block type. + Can be empty.""" + + return '%unbreakable'
