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