1e5c31af7Sopenharmony_ci#!/usr/bin/python3 -i 2e5c31af7Sopenharmony_ci# 3e5c31af7Sopenharmony_ci# Copyright 2013-2021 The Khronos Group Inc. 4e5c31af7Sopenharmony_ci# 5e5c31af7Sopenharmony_ci# SPDX-License-Identifier: Apache-2.0 6e5c31af7Sopenharmony_ci 7e5c31af7Sopenharmony_ci# Base class for working-group-specific style conventions, 8e5c31af7Sopenharmony_ci# used in generation. 9e5c31af7Sopenharmony_ci 10e5c31af7Sopenharmony_cifrom enum import Enum 11e5c31af7Sopenharmony_ci 12e5c31af7Sopenharmony_ci# Type categories that respond "False" to isStructAlwaysValid 13e5c31af7Sopenharmony_ci# basetype is home to typedefs like ..Bool32 14e5c31af7Sopenharmony_ciCATEGORIES_REQUIRING_VALIDATION = set(('handle', 15e5c31af7Sopenharmony_ci 'enum', 16e5c31af7Sopenharmony_ci 'bitmask', 17e5c31af7Sopenharmony_ci 'basetype', 18e5c31af7Sopenharmony_ci None)) 19e5c31af7Sopenharmony_ci 20e5c31af7Sopenharmony_ci# These are basic C types pulled in via openxr_platform_defines.h 21e5c31af7Sopenharmony_ciTYPES_KNOWN_ALWAYS_VALID = set(('char', 22e5c31af7Sopenharmony_ci 'float', 23e5c31af7Sopenharmony_ci 'int8_t', 'uint8_t', 24e5c31af7Sopenharmony_ci 'int32_t', 'uint32_t', 25e5c31af7Sopenharmony_ci 'int64_t', 'uint64_t', 26e5c31af7Sopenharmony_ci 'size_t', 27e5c31af7Sopenharmony_ci 'uintptr_t', 28e5c31af7Sopenharmony_ci 'int', 29e5c31af7Sopenharmony_ci )) 30e5c31af7Sopenharmony_ci 31e5c31af7Sopenharmony_ci 32e5c31af7Sopenharmony_ciclass ProseListFormats(Enum): 33e5c31af7Sopenharmony_ci """A connective, possibly with a quantifier.""" 34e5c31af7Sopenharmony_ci AND = 0 35e5c31af7Sopenharmony_ci EACH_AND = 1 36e5c31af7Sopenharmony_ci OR = 2 37e5c31af7Sopenharmony_ci ANY_OR = 3 38e5c31af7Sopenharmony_ci 39e5c31af7Sopenharmony_ci @classmethod 40e5c31af7Sopenharmony_ci def from_string(cls, s): 41e5c31af7Sopenharmony_ci if s == 'or': 42e5c31af7Sopenharmony_ci return cls.OR 43e5c31af7Sopenharmony_ci if s == 'and': 44e5c31af7Sopenharmony_ci return cls.AND 45e5c31af7Sopenharmony_ci return None 46e5c31af7Sopenharmony_ci 47e5c31af7Sopenharmony_ci @property 48e5c31af7Sopenharmony_ci def connective(self): 49e5c31af7Sopenharmony_ci if self in (ProseListFormats.OR, ProseListFormats.ANY_OR): 50e5c31af7Sopenharmony_ci return 'or' 51e5c31af7Sopenharmony_ci return 'and' 52e5c31af7Sopenharmony_ci 53e5c31af7Sopenharmony_ci def quantifier(self, n): 54e5c31af7Sopenharmony_ci """Return the desired quantifier for a list of a given length.""" 55e5c31af7Sopenharmony_ci if self == ProseListFormats.ANY_OR: 56e5c31af7Sopenharmony_ci if n > 1: 57e5c31af7Sopenharmony_ci return 'any of ' 58e5c31af7Sopenharmony_ci elif self == ProseListFormats.EACH_AND: 59e5c31af7Sopenharmony_ci if n > 2: 60e5c31af7Sopenharmony_ci return 'each of ' 61e5c31af7Sopenharmony_ci if n == 2: 62e5c31af7Sopenharmony_ci return 'both of ' 63e5c31af7Sopenharmony_ci return '' 64e5c31af7Sopenharmony_ci 65e5c31af7Sopenharmony_ci 66e5c31af7Sopenharmony_ciclass ConventionsBase: 67e5c31af7Sopenharmony_ci """WG-specific conventions.""" 68e5c31af7Sopenharmony_ci 69e5c31af7Sopenharmony_ci def __init__(self): 70e5c31af7Sopenharmony_ci self._command_prefix = None 71e5c31af7Sopenharmony_ci self._type_prefix = None 72e5c31af7Sopenharmony_ci 73e5c31af7Sopenharmony_ci def formatExtension(self, name): 74e5c31af7Sopenharmony_ci """Mark up an extension name as a link the spec.""" 75e5c31af7Sopenharmony_ci return '`apiext:{}`'.format(name) 76e5c31af7Sopenharmony_ci 77e5c31af7Sopenharmony_ci @property 78e5c31af7Sopenharmony_ci def null(self): 79e5c31af7Sopenharmony_ci """Preferred spelling of NULL.""" 80e5c31af7Sopenharmony_ci raise NotImplementedError 81e5c31af7Sopenharmony_ci 82e5c31af7Sopenharmony_ci def makeProseList(self, elements, fmt=ProseListFormats.AND, with_verb=False, *args, **kwargs): 83e5c31af7Sopenharmony_ci """Make a (comma-separated) list for use in prose. 84e5c31af7Sopenharmony_ci 85e5c31af7Sopenharmony_ci Adds a connective (by default, 'and') 86e5c31af7Sopenharmony_ci before the last element if there are more than 1. 87e5c31af7Sopenharmony_ci 88e5c31af7Sopenharmony_ci Adds the right one of "is" or "are" to the end if with_verb is true. 89e5c31af7Sopenharmony_ci 90e5c31af7Sopenharmony_ci Optionally adds a quantifier (like 'any') before a list of 2 or more, 91e5c31af7Sopenharmony_ci if specified by fmt. 92e5c31af7Sopenharmony_ci 93e5c31af7Sopenharmony_ci Override with a different method or different call to 94e5c31af7Sopenharmony_ci _implMakeProseList if you want to add a comma for two elements, 95e5c31af7Sopenharmony_ci or not use a serial comma. 96e5c31af7Sopenharmony_ci """ 97e5c31af7Sopenharmony_ci return self._implMakeProseList(elements, fmt, with_verb, *args, **kwargs) 98e5c31af7Sopenharmony_ci 99e5c31af7Sopenharmony_ci @property 100e5c31af7Sopenharmony_ci def struct_macro(self): 101e5c31af7Sopenharmony_ci """Get the appropriate format macro for a structure. 102e5c31af7Sopenharmony_ci 103e5c31af7Sopenharmony_ci May override. 104e5c31af7Sopenharmony_ci """ 105e5c31af7Sopenharmony_ci return 'slink:' 106e5c31af7Sopenharmony_ci 107e5c31af7Sopenharmony_ci @property 108e5c31af7Sopenharmony_ci def external_macro(self): 109e5c31af7Sopenharmony_ci """Get the appropriate format macro for an external type like uint32_t. 110e5c31af7Sopenharmony_ci 111e5c31af7Sopenharmony_ci May override. 112e5c31af7Sopenharmony_ci """ 113e5c31af7Sopenharmony_ci return 'code:' 114e5c31af7Sopenharmony_ci 115e5c31af7Sopenharmony_ci def makeStructName(self, name): 116e5c31af7Sopenharmony_ci """Prepend the appropriate format macro for a structure to a structure type name. 117e5c31af7Sopenharmony_ci 118e5c31af7Sopenharmony_ci Uses struct_macro, so just override that if you want to change behavior. 119e5c31af7Sopenharmony_ci """ 120e5c31af7Sopenharmony_ci return self.struct_macro + name 121e5c31af7Sopenharmony_ci 122e5c31af7Sopenharmony_ci def makeExternalTypeName(self, name): 123e5c31af7Sopenharmony_ci """Prepend the appropriate format macro for an external type like uint32_t to a type name. 124e5c31af7Sopenharmony_ci 125e5c31af7Sopenharmony_ci Uses external_macro, so just override that if you want to change behavior. 126e5c31af7Sopenharmony_ci """ 127e5c31af7Sopenharmony_ci return self.external_macro + name 128e5c31af7Sopenharmony_ci 129e5c31af7Sopenharmony_ci def _implMakeProseList(self, elements, fmt, with_verb, comma_for_two_elts=False, serial_comma=True): 130e5c31af7Sopenharmony_ci """Internal-use implementation to make a (comma-separated) list for use in prose. 131e5c31af7Sopenharmony_ci 132e5c31af7Sopenharmony_ci Adds a connective (by default, 'and') 133e5c31af7Sopenharmony_ci before the last element if there are more than 1, 134e5c31af7Sopenharmony_ci and only includes commas if there are more than 2 135e5c31af7Sopenharmony_ci (if comma_for_two_elts is False). 136e5c31af7Sopenharmony_ci 137e5c31af7Sopenharmony_ci Adds the right one of "is" or "are" to the end if with_verb is true. 138e5c31af7Sopenharmony_ci 139e5c31af7Sopenharmony_ci Optionally adds a quantifier (like 'any') before a list of 2 or more, 140e5c31af7Sopenharmony_ci if specified by fmt. 141e5c31af7Sopenharmony_ci 142e5c31af7Sopenharmony_ci Do not edit these defaults, override self.makeProseList(). 143e5c31af7Sopenharmony_ci """ 144e5c31af7Sopenharmony_ci assert(serial_comma) # did not implement what we did not need 145e5c31af7Sopenharmony_ci if isinstance(fmt, str): 146e5c31af7Sopenharmony_ci fmt = ProseListFormats.from_string(fmt) 147e5c31af7Sopenharmony_ci 148e5c31af7Sopenharmony_ci my_elts = list(elements) 149e5c31af7Sopenharmony_ci if len(my_elts) > 1: 150e5c31af7Sopenharmony_ci my_elts[-1] = '{} {}'.format(fmt.connective, my_elts[-1]) 151e5c31af7Sopenharmony_ci 152e5c31af7Sopenharmony_ci if not comma_for_two_elts and len(my_elts) <= 2: 153e5c31af7Sopenharmony_ci prose = ' '.join(my_elts) 154e5c31af7Sopenharmony_ci else: 155e5c31af7Sopenharmony_ci prose = ', '.join(my_elts) 156e5c31af7Sopenharmony_ci 157e5c31af7Sopenharmony_ci quantifier = fmt.quantifier(len(my_elts)) 158e5c31af7Sopenharmony_ci 159e5c31af7Sopenharmony_ci parts = [quantifier, prose] 160e5c31af7Sopenharmony_ci 161e5c31af7Sopenharmony_ci if with_verb: 162e5c31af7Sopenharmony_ci if len(my_elts) > 1: 163e5c31af7Sopenharmony_ci parts.append(' are') 164e5c31af7Sopenharmony_ci else: 165e5c31af7Sopenharmony_ci parts.append(' is') 166e5c31af7Sopenharmony_ci return ''.join(parts) 167e5c31af7Sopenharmony_ci 168e5c31af7Sopenharmony_ci @property 169e5c31af7Sopenharmony_ci def file_suffix(self): 170e5c31af7Sopenharmony_ci """Return suffix of generated Asciidoctor files""" 171e5c31af7Sopenharmony_ci raise NotImplementedError 172e5c31af7Sopenharmony_ci 173e5c31af7Sopenharmony_ci def api_name(self, spectype=None): 174e5c31af7Sopenharmony_ci """Return API or specification name for citations in ref pages. 175e5c31af7Sopenharmony_ci 176e5c31af7Sopenharmony_ci spectype is the spec this refpage is for. 177e5c31af7Sopenharmony_ci 'api' (the default value) is the main API Specification. 178e5c31af7Sopenharmony_ci If an unrecognized spectype is given, returns None. 179e5c31af7Sopenharmony_ci 180e5c31af7Sopenharmony_ci Must implement.""" 181e5c31af7Sopenharmony_ci raise NotImplementedError 182e5c31af7Sopenharmony_ci 183e5c31af7Sopenharmony_ci def should_insert_may_alias_macro(self, genOpts): 184e5c31af7Sopenharmony_ci """Return true if we should insert a "may alias" macro in this file. 185e5c31af7Sopenharmony_ci 186e5c31af7Sopenharmony_ci Only used by OpenXR right now.""" 187e5c31af7Sopenharmony_ci return False 188e5c31af7Sopenharmony_ci 189e5c31af7Sopenharmony_ci @property 190e5c31af7Sopenharmony_ci def command_prefix(self): 191e5c31af7Sopenharmony_ci """Return the expected prefix of commands/functions. 192e5c31af7Sopenharmony_ci 193e5c31af7Sopenharmony_ci Implemented in terms of api_prefix.""" 194e5c31af7Sopenharmony_ci if not self._command_prefix: 195e5c31af7Sopenharmony_ci self._command_prefix = self.api_prefix[:].replace('_', '').lower() 196e5c31af7Sopenharmony_ci return self._command_prefix 197e5c31af7Sopenharmony_ci 198e5c31af7Sopenharmony_ci @property 199e5c31af7Sopenharmony_ci def type_prefix(self): 200e5c31af7Sopenharmony_ci """Return the expected prefix of type names. 201e5c31af7Sopenharmony_ci 202e5c31af7Sopenharmony_ci Implemented in terms of command_prefix (and in turn, api_prefix).""" 203e5c31af7Sopenharmony_ci if not self._type_prefix: 204e5c31af7Sopenharmony_ci self._type_prefix = ''.join( 205e5c31af7Sopenharmony_ci (self.command_prefix[0:1].upper(), self.command_prefix[1:])) 206e5c31af7Sopenharmony_ci return self._type_prefix 207e5c31af7Sopenharmony_ci 208e5c31af7Sopenharmony_ci @property 209e5c31af7Sopenharmony_ci def api_prefix(self): 210e5c31af7Sopenharmony_ci """Return API token prefix. 211e5c31af7Sopenharmony_ci 212e5c31af7Sopenharmony_ci Typically two uppercase letters followed by an underscore. 213e5c31af7Sopenharmony_ci 214e5c31af7Sopenharmony_ci Must implement.""" 215e5c31af7Sopenharmony_ci raise NotImplementedError 216e5c31af7Sopenharmony_ci 217e5c31af7Sopenharmony_ci @property 218e5c31af7Sopenharmony_ci def api_version_prefix(self): 219e5c31af7Sopenharmony_ci """Return API core version token prefix. 220e5c31af7Sopenharmony_ci 221e5c31af7Sopenharmony_ci Implemented in terms of api_prefix. 222e5c31af7Sopenharmony_ci 223e5c31af7Sopenharmony_ci May override.""" 224e5c31af7Sopenharmony_ci return self.api_prefix + 'VERSION_' 225e5c31af7Sopenharmony_ci 226e5c31af7Sopenharmony_ci @property 227e5c31af7Sopenharmony_ci def KHR_prefix(self): 228e5c31af7Sopenharmony_ci """Return extension name prefix for KHR extensions. 229e5c31af7Sopenharmony_ci 230e5c31af7Sopenharmony_ci Implemented in terms of api_prefix. 231e5c31af7Sopenharmony_ci 232e5c31af7Sopenharmony_ci May override.""" 233e5c31af7Sopenharmony_ci return self.api_prefix + 'KHR_' 234e5c31af7Sopenharmony_ci 235e5c31af7Sopenharmony_ci @property 236e5c31af7Sopenharmony_ci def EXT_prefix(self): 237e5c31af7Sopenharmony_ci """Return extension name prefix for EXT extensions. 238e5c31af7Sopenharmony_ci 239e5c31af7Sopenharmony_ci Implemented in terms of api_prefix. 240e5c31af7Sopenharmony_ci 241e5c31af7Sopenharmony_ci May override.""" 242e5c31af7Sopenharmony_ci return self.api_prefix + 'EXT_' 243e5c31af7Sopenharmony_ci 244e5c31af7Sopenharmony_ci def writeFeature(self, featureExtraProtect, filename): 245e5c31af7Sopenharmony_ci """Return True if OutputGenerator.endFeature should write this feature. 246e5c31af7Sopenharmony_ci 247e5c31af7Sopenharmony_ci Defaults to always True. 248e5c31af7Sopenharmony_ci Used in COutputGenerator. 249e5c31af7Sopenharmony_ci 250e5c31af7Sopenharmony_ci May override.""" 251e5c31af7Sopenharmony_ci return True 252e5c31af7Sopenharmony_ci 253e5c31af7Sopenharmony_ci def requires_error_validation(self, return_type): 254e5c31af7Sopenharmony_ci """Return True if the return_type element is an API result code 255e5c31af7Sopenharmony_ci requiring error validation. 256e5c31af7Sopenharmony_ci 257e5c31af7Sopenharmony_ci Defaults to always False. 258e5c31af7Sopenharmony_ci 259e5c31af7Sopenharmony_ci May override.""" 260e5c31af7Sopenharmony_ci return False 261e5c31af7Sopenharmony_ci 262e5c31af7Sopenharmony_ci @property 263e5c31af7Sopenharmony_ci def required_errors(self): 264e5c31af7Sopenharmony_ci """Return a list of required error codes for validation. 265e5c31af7Sopenharmony_ci 266e5c31af7Sopenharmony_ci Defaults to an empty list. 267e5c31af7Sopenharmony_ci 268e5c31af7Sopenharmony_ci May override.""" 269e5c31af7Sopenharmony_ci return [] 270e5c31af7Sopenharmony_ci 271e5c31af7Sopenharmony_ci def is_voidpointer_alias(self, tag, text, tail): 272e5c31af7Sopenharmony_ci """Return True if the declaration components (tag,text,tail) of an 273e5c31af7Sopenharmony_ci element represents a void * type. 274e5c31af7Sopenharmony_ci 275e5c31af7Sopenharmony_ci Defaults to a reasonable implementation. 276e5c31af7Sopenharmony_ci 277e5c31af7Sopenharmony_ci May override.""" 278e5c31af7Sopenharmony_ci return tag == 'type' and text == 'void' and tail.startswith('*') 279e5c31af7Sopenharmony_ci 280e5c31af7Sopenharmony_ci def make_voidpointer_alias(self, tail): 281e5c31af7Sopenharmony_ci """Reformat a void * declaration to include the API alias macro. 282e5c31af7Sopenharmony_ci 283e5c31af7Sopenharmony_ci Defaults to a no-op. 284e5c31af7Sopenharmony_ci 285e5c31af7Sopenharmony_ci Must override if you actually want to use this feature in your project.""" 286e5c31af7Sopenharmony_ci return tail 287e5c31af7Sopenharmony_ci 288e5c31af7Sopenharmony_ci def category_requires_validation(self, category): 289e5c31af7Sopenharmony_ci """Return True if the given type 'category' always requires validation. 290e5c31af7Sopenharmony_ci 291e5c31af7Sopenharmony_ci Defaults to a reasonable implementation. 292e5c31af7Sopenharmony_ci 293e5c31af7Sopenharmony_ci May override.""" 294e5c31af7Sopenharmony_ci return category in CATEGORIES_REQUIRING_VALIDATION 295e5c31af7Sopenharmony_ci 296e5c31af7Sopenharmony_ci def type_always_valid(self, typename): 297e5c31af7Sopenharmony_ci """Return True if the given type name is always valid (never requires validation). 298e5c31af7Sopenharmony_ci 299e5c31af7Sopenharmony_ci This is for things like integers. 300e5c31af7Sopenharmony_ci 301e5c31af7Sopenharmony_ci Defaults to a reasonable implementation. 302e5c31af7Sopenharmony_ci 303e5c31af7Sopenharmony_ci May override.""" 304e5c31af7Sopenharmony_ci return typename in TYPES_KNOWN_ALWAYS_VALID 305e5c31af7Sopenharmony_ci 306e5c31af7Sopenharmony_ci @property 307e5c31af7Sopenharmony_ci def should_skip_checking_codes(self): 308e5c31af7Sopenharmony_ci """Return True if more than the basic validation of return codes should 309e5c31af7Sopenharmony_ci be skipped for a command.""" 310e5c31af7Sopenharmony_ci 311e5c31af7Sopenharmony_ci return False 312e5c31af7Sopenharmony_ci 313e5c31af7Sopenharmony_ci @property 314e5c31af7Sopenharmony_ci def generate_index_terms(self): 315e5c31af7Sopenharmony_ci """Return True if asiidoctor index terms should be generated as part 316e5c31af7Sopenharmony_ci of an API interface from the docgenerator.""" 317e5c31af7Sopenharmony_ci 318e5c31af7Sopenharmony_ci return False 319e5c31af7Sopenharmony_ci 320e5c31af7Sopenharmony_ci @property 321e5c31af7Sopenharmony_ci def generate_enum_table(self): 322e5c31af7Sopenharmony_ci """Return True if asciidoctor tables describing enumerants in a 323e5c31af7Sopenharmony_ci group should be generated as part of group generation.""" 324e5c31af7Sopenharmony_ci return False 325e5c31af7Sopenharmony_ci 326e5c31af7Sopenharmony_ci @property 327e5c31af7Sopenharmony_ci def generate_max_enum_in_docs(self): 328e5c31af7Sopenharmony_ci """Return True if MAX_ENUM tokens should be generated in 329e5c31af7Sopenharmony_ci documentation includes.""" 330e5c31af7Sopenharmony_ci return False 331e5c31af7Sopenharmony_ci 332e5c31af7Sopenharmony_ci 333e5c31af7Sopenharmony_ci def extension_include_string(self, ext): 334e5c31af7Sopenharmony_ci """Return format string for include:: line for an extension appendix 335e5c31af7Sopenharmony_ci file. ext is an object with the following members: 336e5c31af7Sopenharmony_ci - name - extension string string 337e5c31af7Sopenharmony_ci - vendor - vendor portion of name 338e5c31af7Sopenharmony_ci - barename - remainder of name 339e5c31af7Sopenharmony_ci 340e5c31af7Sopenharmony_ci Must implement.""" 341e5c31af7Sopenharmony_ci raise NotImplementedError 342e5c31af7Sopenharmony_ci 343e5c31af7Sopenharmony_ci @property 344e5c31af7Sopenharmony_ci def refpage_generated_include_path(self): 345e5c31af7Sopenharmony_ci """Return path relative to the generated reference pages, to the 346e5c31af7Sopenharmony_ci generated API include files. 347e5c31af7Sopenharmony_ci 348e5c31af7Sopenharmony_ci Must implement.""" 349e5c31af7Sopenharmony_ci raise NotImplementedError 350e5c31af7Sopenharmony_ci 351e5c31af7Sopenharmony_ci def valid_flag_bit(self, bitpos): 352e5c31af7Sopenharmony_ci """Return True if bitpos is an allowed numeric bit position for 353e5c31af7Sopenharmony_ci an API flag. 354e5c31af7Sopenharmony_ci 355e5c31af7Sopenharmony_ci Behavior depends on the data type used for flags (which may be 32 356e5c31af7Sopenharmony_ci or 64 bits), and may depend on assumptions about compiler 357e5c31af7Sopenharmony_ci handling of sign bits in enumerated types, as well.""" 358e5c31af7Sopenharmony_ci return True 359