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