1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
#!/usr/bin/env python3
#
# Copyright (c) 2018-2019 Collabora, Ltd.
#
# SPDX-License-Identifier: Apache-2.0
#
# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
#
# Purpose: This file performs some basic checks of the custom macros
# used in the AsciiDoctor source for the spec, especially
# related to the validity of the entities linked-to.
from pathlib import Path
from reg import Registry
from spec_tools.entity_db import EntityDatabase
from spec_tools.macro_checker import MacroChecker
from spec_tools.macro_checker_file import BlockType, MacroCheckerFile
from spec_tools.main import checkerMain
from spec_tools.shared import MessageId
###
# "Configuration" constants
EXTRA_DEFINES = ('XRAPI_ATTR', 'XRAPI_CALL', 'XRAPI_PTR', 'XR_NO_STDINT_H')
# These are marked with the code: macro
SYSTEM_TYPES = set(('void', 'char', 'float', 'size_t', 'uintptr_t',
'int8_t', 'uint8_t',
'int32_t', 'uint32_t',
'int64_t', 'uint64_t'))
ROOT = Path(__file__).resolve().parent.parent.parent
DEFAULT_DISABLED_MESSAGES = set((MessageId.REFPAGE_MISSING,))
CWD = Path('.').resolve()
class XREntityDatabase(EntityDatabase):
"""OpenXR-specific subclass of EntityDatabase."""
def makeRegistry(self):
root = Path(__file__).resolve().parent.parent.parent
registryFile = str(root / 'specification/registry/xr.xml')
registry = Registry()
registry.loadFile(registryFile)
return registry
def getNamePrefix(self):
return "xr"
def getPlatformRequires(self):
return "openxr_platform_defines"
def getSystemTypes(self):
return SYSTEM_TYPES
def populateMacros(self):
# TODO: Where should flags actually go?
# #Not mentioned in the style guide.
# TODO: What about flag wildcards? There are a few such uses...
self.addMacro('basetype', ('basetypes',), link=True)
def populateEntities(self):
# These are not mentioned in the XML
for name in EXTRA_DEFINES:
self.addEntity(name, 'dlink', category='configdefines',
generates=False)
def handleType(self, name, info, requires):
"""Extend superclass implementation for OpenXR bitmasks."""
cat = info.elem.get('category')
if cat == 'bitmask':
# OpenXR uses elink, not tlink, for flags.
self.addEntity(
name,
'elink',
elem=info.elem,
category='flags')
else:
super().handleType(name, info, requires)
class XRMacroCheckerFile(MacroCheckerFile):
"""OpenXR-specific subclass of MacroCheckerFile."""
def processBlockOpen(self, block_type, context=None, delimiter=None):
"""Do any block-type-specific processing and push the new block.
Extends the superclass to warn if a ref-page-like block is opened
without a ref page tag.
Must call self.pushBlock().
Called by self.processBlockDelimiter().
"""
# OpenXR only uses '--' blocks for ref pages.
if block_type == BlockType.REF_PAGE_LIKE and \
not self.prev_line_ref_page_tag:
self.error(MessageId.REFPAGE_BLOCK,
["Found a line containing only -- outside of a reference page block, not preceded by a reference page tag,",
"Pretending there was one and opening refpage block for unknown entity anyway, for more readable messages."],
group=None)
self.current_ref_page = '?missing-refpage-tag?'
self.prev_line_ref_page_tag = None
self.in_ref_page = True
# Manually pushing the block here, to force a refpage block.
# Not going to superclass method in this case.
self.pushBlock(block_type, refpage=self.current_ref_page,
context=context, delimiter=delimiter)
return
# Everything else about block opening is standard.
super().processBlockOpen(block_type, context=context,
delimiter=delimiter)
def handleIncludeMissingRefPage(self, entity, generated_type):
"""Report a message about an include outside of a ref-page block."""
# TODO is it reasonable that we just stuck all the Flags includes in
# the appendix?
if entity.endswith('Flags'):
# OK, it's a flag, no worries.
return
super().handleIncludeMissingRefPage(entity, generated_type)
def computeExpectedRefPageFromInclude(self, entity):
"""Compute the expected ref page entity based on an include entity name."""
# TODO use registry associations between FlagBits and Flags to do this
# better?
if entity.endswith('FlagBits'):
return entity.replace('FlagBits', 'Flags')
return entity
def makeMacroChecker(enabled_messages):
"""Create a correctly-configured MacroChecker instance."""
entity_db = XREntityDatabase()
return MacroChecker(enabled_messages, entity_db, XRMacroCheckerFile, ROOT)
if __name__ == '__main__':
available_messages = set(MessageId)
# LEGACY messages are Vulkan-only.
available_messages.remove(MessageId.LEGACY)
default_enabled_messages = available_messages.difference(
DEFAULT_DISABLED_MESSAGES)
all_docs = sorted((str(fn)
for fn in (ROOT / 'specification/sources/').glob('**/*.adoc')
if "styleguide" not in str(fn)))
checkerMain(default_enabled_messages, makeMacroChecker,
all_docs, available_messages=available_messages)
|