1e5c31af7Sopenharmony_ci#!/usr/bin/python3 -i
2e5c31af7Sopenharmony_ci#
3e5c31af7Sopenharmony_ci# Copyright 2013-2024 The Khronos Group Inc.
4e5c31af7Sopenharmony_ci#
5e5c31af7Sopenharmony_ci# SPDX-License-Identifier: Apache-2.0
6e5c31af7Sopenharmony_ci
7e5c31af7Sopenharmony_ciimport re
8e5c31af7Sopenharmony_cifrom generator import OutputGenerator, write
9e5c31af7Sopenharmony_cifrom parse_dependency import dependencyLanguageSpecMacros
10e5c31af7Sopenharmony_ci
11e5c31af7Sopenharmony_cidef interfaceDocSortKey(item):
12e5c31af7Sopenharmony_ci    if item == None:
13e5c31af7Sopenharmony_ci        return '\0'
14e5c31af7Sopenharmony_ci    else:
15e5c31af7Sopenharmony_ci        return item.casefold()
16e5c31af7Sopenharmony_ci
17e5c31af7Sopenharmony_ciclass InterfaceDocGenerator(OutputGenerator):
18e5c31af7Sopenharmony_ci    """InterfaceDocGenerator - subclass of OutputGenerator.
19e5c31af7Sopenharmony_ci    Generates AsciiDoc includes of the interfaces added by a an API version
20e5c31af7Sopenharmony_ci    or extension."""
21e5c31af7Sopenharmony_ci
22e5c31af7Sopenharmony_ci    def __init__(self, *args, **kwargs):
23e5c31af7Sopenharmony_ci        super().__init__(*args, **kwargs)
24e5c31af7Sopenharmony_ci        self.features = []
25e5c31af7Sopenharmony_ci
26e5c31af7Sopenharmony_ci    def beginFile(self, genOpts):
27e5c31af7Sopenharmony_ci        OutputGenerator.beginFile(self, genOpts)
28e5c31af7Sopenharmony_ci
29e5c31af7Sopenharmony_ci        # Create subdirectory, if needed
30e5c31af7Sopenharmony_ci        self.makeDir(self.genOpts.directory)
31e5c31af7Sopenharmony_ci
32e5c31af7Sopenharmony_ci    def beginFeature(self, interface, emit):
33e5c31af7Sopenharmony_ci        # Start processing in superclass
34e5c31af7Sopenharmony_ci        OutputGenerator.beginFeature(self, interface, emit)
35e5c31af7Sopenharmony_ci
36e5c31af7Sopenharmony_ci        self.features.append( self.featureName )
37e5c31af7Sopenharmony_ci
38e5c31af7Sopenharmony_ci    def endFeature(self):
39e5c31af7Sopenharmony_ci        # Finish processing in superclass
40e5c31af7Sopenharmony_ci        OutputGenerator.endFeature(self)
41e5c31af7Sopenharmony_ci
42e5c31af7Sopenharmony_ci    def writeNewInterfaces(self, feature, key, title, markup, fp):
43e5c31af7Sopenharmony_ci        dict = self.featureDictionary[feature][key]
44e5c31af7Sopenharmony_ci
45e5c31af7Sopenharmony_ci        parentmarkup = markup
46e5c31af7Sopenharmony_ci        if key == 'enumconstant':
47e5c31af7Sopenharmony_ci            parentmarkup = 'elink:'
48e5c31af7Sopenharmony_ci
49e5c31af7Sopenharmony_ci        if dict:
50e5c31af7Sopenharmony_ci            write('=== ' + title, file=fp)
51e5c31af7Sopenharmony_ci            write('',file=fp)
52e5c31af7Sopenharmony_ci
53e5c31af7Sopenharmony_ci            # Loop through required blocks, sorted so they start with "core" features
54e5c31af7Sopenharmony_ci            for required in sorted(dict, key = interfaceDocSortKey):
55e5c31af7Sopenharmony_ci                # 'required' may be a boolean expression of extension
56e5c31af7Sopenharmony_ci                # names.
57e5c31af7Sopenharmony_ci                # Currently this syntax is the same as asciidoc conditional
58e5c31af7Sopenharmony_ci                # syntax, but will eventually become more complex.
59e5c31af7Sopenharmony_ci                if required is not None:
60e5c31af7Sopenharmony_ci                    # Rewrite with spec macros and xrefs applied to names
61e5c31af7Sopenharmony_ci                    requiredlink = dependencyLanguageSpecMacros(required)
62e5c31af7Sopenharmony_ci
63e5c31af7Sopenharmony_ci                    # @@ A better approach would be to actually evaluate the
64e5c31af7Sopenharmony_ci                    # logical expression at generation time.
65e5c31af7Sopenharmony_ci                    # If the extensions required are not in the spec build,
66e5c31af7Sopenharmony_ci                    # then do not include these requirements.
67e5c31af7Sopenharmony_ci                    # This would support arbitrarily complex expressions,
68e5c31af7Sopenharmony_ci                    # unlike asciidoc ifdef syntax.
69e5c31af7Sopenharmony_ci                    write('ifdef::' + required + '[]', file=fp)
70e5c31af7Sopenharmony_ci                    write(f'If {requiredlink} is supported:', file=fp)
71e5c31af7Sopenharmony_ci                    write('',file=fp)
72e5c31af7Sopenharmony_ci
73e5c31af7Sopenharmony_ci                # Commands are relatively straightforward
74e5c31af7Sopenharmony_ci                if key == 'command':
75e5c31af7Sopenharmony_ci                    for api in sorted(dict[required]):
76e5c31af7Sopenharmony_ci                        write('  * ' + markup + api, file=fp)
77e5c31af7Sopenharmony_ci                # Types and constants are potentially parented, so need to handle that
78e5c31af7Sopenharmony_ci                else:
79e5c31af7Sopenharmony_ci                    # Loop through parents, sorted so they start with unparented items
80e5c31af7Sopenharmony_ci                    for parent in sorted(dict[required], key = interfaceDocSortKey):
81e5c31af7Sopenharmony_ci                        parentstring = ''
82e5c31af7Sopenharmony_ci                        if parent:
83e5c31af7Sopenharmony_ci                            parentstring = parentmarkup + (', ' + markup).join(parent.split(','))
84e5c31af7Sopenharmony_ci                            write('  * Extending ' + parentstring + ':', file=fp)
85e5c31af7Sopenharmony_ci                            for api in sorted(dict[required][parent]):
86e5c31af7Sopenharmony_ci                                write('  ** ' + markup + api, file=fp)
87e5c31af7Sopenharmony_ci                        else:
88e5c31af7Sopenharmony_ci                            for api in sorted(dict[required][parent]):
89e5c31af7Sopenharmony_ci                                write('  * ' + markup + api, file=fp)
90e5c31af7Sopenharmony_ci
91e5c31af7Sopenharmony_ci                if required is not None:
92e5c31af7Sopenharmony_ci                    write('endif::' + required + '[]', file=fp)
93e5c31af7Sopenharmony_ci                write('',file=fp)
94e5c31af7Sopenharmony_ci
95e5c31af7Sopenharmony_ci    def makeInterfaceFile(self, feature):
96e5c31af7Sopenharmony_ci        """Generate a file containing feature interface documentation in
97e5c31af7Sopenharmony_ci           asciidoctor markup form.
98e5c31af7Sopenharmony_ci
99e5c31af7Sopenharmony_ci        - feature - name of the feature being generated"""
100e5c31af7Sopenharmony_ci
101e5c31af7Sopenharmony_ci        filename = feature + self.genOpts.conventions.file_suffix
102e5c31af7Sopenharmony_ci        fp = open(self.genOpts.directory + '/' + filename, 'w', encoding='utf-8')
103e5c31af7Sopenharmony_ci
104e5c31af7Sopenharmony_ci        # Write out the lists of new interfaces added by the feature
105e5c31af7Sopenharmony_ci        self.writeNewInterfaces(feature, 'define',      'New Macros',           'dlink:',   fp)
106e5c31af7Sopenharmony_ci        self.writeNewInterfaces(feature, 'basetype',    'New Base Types',       'basetype:',fp)
107e5c31af7Sopenharmony_ci        self.writeNewInterfaces(feature, 'handle',      'New Object Types',     'slink:',   fp)
108e5c31af7Sopenharmony_ci        self.writeNewInterfaces(feature, 'command',     'New Commands',         'flink:',   fp)
109e5c31af7Sopenharmony_ci        self.writeNewInterfaces(feature, 'struct',      'New Structures',       'slink:',   fp)
110e5c31af7Sopenharmony_ci        self.writeNewInterfaces(feature, 'union',       'New Unions',           'slink:',   fp)
111e5c31af7Sopenharmony_ci        self.writeNewInterfaces(feature, 'funcpointer', 'New Function Pointers','tlink:',   fp)
112e5c31af7Sopenharmony_ci        self.writeNewInterfaces(feature, 'enum',        'New Enums',            'elink:',   fp)
113e5c31af7Sopenharmony_ci        self.writeNewInterfaces(feature, 'bitmask',     'New Bitmasks',         'tlink:',   fp)
114e5c31af7Sopenharmony_ci        self.writeNewInterfaces(feature, 'include',     'New Headers',          'code:',    fp)
115e5c31af7Sopenharmony_ci        self.writeNewInterfaces(feature, 'enumconstant','New Enum Constants',   'ename:',   fp)
116e5c31af7Sopenharmony_ci
117e5c31af7Sopenharmony_ci        fp.close()
118e5c31af7Sopenharmony_ci
119e5c31af7Sopenharmony_ci    def endFile(self):
120e5c31af7Sopenharmony_ci        # Generate metadoc feature files, in refpage and non-refpage form
121e5c31af7Sopenharmony_ci        for feature in self.features:
122e5c31af7Sopenharmony_ci            self.makeInterfaceFile(feature)
123e5c31af7Sopenharmony_ci
124e5c31af7Sopenharmony_ci        OutputGenerator.endFile(self)
125