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