• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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