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