1#!/usr/bin/python3 2# 3# Copyright (c) 2018-2019 Collabora, Ltd. 4# 5# SPDX-License-Identifier: Apache-2.0 6# 7# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com> 8# 9# Purpose: This file performs some basic checks of the custom macros 10# used in the AsciiDoctor source for the spec, especially 11# related to the validity of the entities linked-to. 12 13from pathlib import Path 14 15from reg import Registry 16from spec_tools.entity_db import EntityDatabase 17from spec_tools.macro_checker import MacroChecker 18from spec_tools.macro_checker_file import MacroCheckerFile 19from spec_tools.main import checkerMain 20from spec_tools.shared import (AUTO_FIX_STRING, EXTENSION_CATEGORY, MessageId, 21 MessageType) 22 23### 24# "Configuration" constants 25 26FREEFORM_CATEGORY = 'freeform' 27 28# defines mentioned in spec but not needed in registry 29EXTRA_DEFINES = ( 30 'VKAPI_ATTR', 31 'VKAPI_CALL', 32 'VKAPI_PTR', 33 'VK_NO_STDDEF_H', 34 'VK_NO_STDINT_H', 35 ) 36 37# Extra freeform refpages in addition to EXTRA_DEFINES 38EXTRA_REFPAGES = ( 39 'VK_VERSION_1_0', 40 'VK_VERSION_1_1', 41 'VK_VERSION_1_2', 42 'WSIheaders', 43 'provisional-headers', 44 ) 45 46# These are marked with the code: macro 47SYSTEM_TYPES = set(('void', 'char', 'float', 'size_t', 'uintptr_t', 48 'int8_t', 'uint8_t', 49 'int32_t', 'uint32_t', 50 'int64_t', 'uint64_t')) 51 52ROOT = Path(__file__).resolve().parent.parent 53DEFAULT_DISABLED_MESSAGES = set(( 54 MessageId.LEGACY, 55 MessageId.REFPAGE_MISSING, 56 MessageId.MISSING_MACRO, 57 MessageId.EXTENSION, 58 # TODO *text macro checking actually needs fixing for Vulkan 59 MessageId.MISUSED_TEXT, 60 MessageId.MISSING_TEXT 61)) 62 63CWD = Path('.').resolve() 64 65 66class VulkanEntityDatabase(EntityDatabase): 67 """Vulkan-specific subclass of EntityDatabase.""" 68 69 def __init__(self, *args, **kwargs): 70 super().__init__(*args, **kwargs) 71 self._conditionally_recognized = set(('fname', 'sname')) 72 73 def makeRegistry(self): 74 registryFile = str(ROOT / 'xml/vk.xml') 75 registry = Registry() 76 registry.loadFile(registryFile) 77 return registry 78 79 def getNamePrefix(self): 80 return "vk" 81 82 def getPlatformRequires(self): 83 return 'vk_platform' 84 85 def getSystemTypes(self): 86 return SYSTEM_TYPES 87 88 def populateMacros(self): 89 self.addMacros('t', ['link', 'name'], ['funcpointers', 'flags']) 90 91 def populateEntities(self): 92 # These are not mentioned in the XML 93 for name in EXTRA_DEFINES: 94 self.addEntity(name, 'dlink', 95 category=FREEFORM_CATEGORY, generates=False) 96 for name in EXTRA_REFPAGES: 97 self.addEntity(name, 'code', 98 category=FREEFORM_CATEGORY, generates=False) 99 100 def shouldBeRecognized(self, macro, entity_name): 101 """Determine, based on the macro and the name provided, if we should expect to recognize the entity.""" 102 if super().shouldBeRecognized(macro, entity_name): 103 return True 104 105 # The *name: macros in Vulkan should also be recognized if the entity name matches the pattern. 106 if macro in self._conditionally_recognized and self.likelyRecognizedEntity(entity_name): 107 return True 108 return False 109 110 111class VulkanMacroCheckerFile(MacroCheckerFile): 112 """Vulkan-specific subclass of MacroCheckerFile.""" 113 114 def handleWrongMacro(self, msg, data): 115 """Report an appropriate message when we found that the macro used is incorrect. 116 117 May be overridden depending on each API's behavior regarding macro misuse: 118 e.g. in some cases, it may be considered a MessageId.LEGACY warning rather than 119 a MessageId.WRONG_MACRO or MessageId.EXTENSION. 120 """ 121 message_type = MessageType.WARNING 122 message_id = MessageId.WRONG_MACRO 123 group = 'macro' 124 125 if data.category == EXTENSION_CATEGORY: 126 # Ah, this is an extension 127 msg.append( 128 'This is apparently an extension name, which should be marked up as a link.') 129 message_id = MessageId.EXTENSION 130 group = None # replace the whole thing 131 else: 132 # Non-extension, we found the macro though. 133 if data.macro[0] == self.macro[0] and data.macro[1:] == 'link' and self.macro[1:] == 'name': 134 # First letter matches, old is 'name', new is 'link': 135 # This is legacy markup 136 msg.append( 137 'This is legacy markup that has not been updated yet.') 138 message_id = MessageId.LEGACY 139 else: 140 # Not legacy, just wrong. 141 message_type = MessageType.ERROR 142 143 msg.append(AUTO_FIX_STRING) 144 self.diag(message_type, message_id, msg, 145 group=group, replacement=self.makeMacroMarkup(data=data), fix=self.makeFix(data=data)) 146 147 148def makeMacroChecker(enabled_messages): 149 """Create a correctly-configured MacroChecker instance.""" 150 entity_db = VulkanEntityDatabase() 151 return MacroChecker(enabled_messages, entity_db, VulkanMacroCheckerFile, ROOT) 152 153 154if __name__ == '__main__': 155 default_enabled_messages = set(MessageId).difference( 156 DEFAULT_DISABLED_MESSAGES) 157 158 all_docs = [str(fn) 159 for fn in sorted((ROOT / 'chapters/').glob('**/*.txt'))] 160 all_docs.extend([str(fn) 161 for fn in sorted((ROOT / 'appendices/').glob('**/*.txt'))]) 162 163 checkerMain(default_enabled_messages, makeMacroChecker, 164 all_docs) 165