diff options
Diffstat (limited to 'codegen/vulkan/scripts/spec_tools/macro_checker.py')
-rw-r--r-- | codegen/vulkan/scripts/spec_tools/macro_checker.py | 220 |
1 files changed, 0 insertions, 220 deletions
diff --git a/codegen/vulkan/scripts/spec_tools/macro_checker.py b/codegen/vulkan/scripts/spec_tools/macro_checker.py deleted file mode 100644 index a8a75aa8..00000000 --- a/codegen/vulkan/scripts/spec_tools/macro_checker.py +++ /dev/null @@ -1,220 +0,0 @@ -"""Provides the MacroChecker class.""" - -# Copyright (c) 2018-2019 Collabora, Ltd. -# -# SPDX-License-Identifier: Apache-2.0 -# -# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com> - -from io import StringIO -import re - - -class MacroChecker(object): - """Perform and track checking of one or more files in an API spec. - - This does not necessarily need to be subclassed per-API: it is sufficiently - parameterized in the constructor for expected usage. - """ - - def __init__(self, enabled_messages, entity_db, - macro_checker_file_type, root_path): - """Construct an object that tracks checking one or more files in an API spec. - - enabled_messages -- a set of MessageId that should be enabled. - entity_db -- an object of a EntityDatabase subclass for this API. - macro_checker_file_type -- Type to instantiate to create the right - MacroCheckerFile subclass for this API. - root_path -- A Path object for the root of this repository. - """ - self.enabled_messages = enabled_messages - self.entity_db = entity_db - self.macro_checker_file_type = macro_checker_file_type - self.root_path = root_path - - self.files = [] - - self.refpages = set() - - # keys: entity names. values: MessageContext - self.links = {} - self.apiIncludes = {} - self.validityIncludes = {} - self.headings = {} - - # Regexes that are members because they depend on the name prefix. - - # apiPrefix, followed by some word characters or * as many times as desired, - # NOT followed by >> and NOT preceded by one of the characters in that first character class. - # (which distinguish "names being used somewhere other than prose"). - self.suspected_missing_macro_re = re.compile( - r'\b(?<![-=:/[\.`+,])(?P<entity_name>{}[\w*]+)\b(?!>>)'.format( - self.entity_db.case_insensitive_name_prefix_pattern) - ) - self.heading_command_re = re.compile( - r'=+ (?P<command>{}[\w]+)'.format(self.entity_db.name_prefix) - ) - - macros_pattern = '|'.join((re.escape(macro) - for macro in self.entity_db.macros)) - # the "formatting" group is to strip matching */**/_/__ - # surrounding an entire macro. - self.macro_re = re.compile( - r'(?P<formatting>\**|_*)(?P<macro>{}):(?P<entity_name>[\w*]+((?P<subscript>[\[][^\]]*[\]]))?)(?P=formatting)'.format(macros_pattern)) - - def haveLinkTarget(self, entity): - """Report if we have parsed an API include (or heading) for an entity. - - None if there is no entity with that name. - """ - if not self.findEntity(entity): - return None - if entity in self.apiIncludes: - return True - return entity in self.headings - - def hasFixes(self): - """Report if any files have auto-fixes.""" - for f in self.files: - if f.hasFixes(): - return True - return False - - def addLinkToEntity(self, entity, context): - """Record seeing a link to an entity's docs from a context.""" - if entity not in self.links: - self.links[entity] = [] - self.links[entity].append(context) - - def seenRefPage(self, entity): - """Check if a ref-page markup block has been seen for an entity.""" - return entity in self.refpages - - def addRefPage(self, entity): - """Record seeing a ref-page markup block for an entity.""" - self.refpages.add(entity) - - def findMacroAndEntity(self, macro, entity): - """Look up EntityData by macro and entity pair. - - Forwards to the EntityDatabase. - """ - return self.entity_db.findMacroAndEntity(macro, entity) - - def findEntity(self, entity): - """Look up EntityData by entity name (case-sensitive). - - Forwards to the EntityDatabase. - """ - return self.entity_db.findEntity(entity) - - def findEntityCaseInsensitive(self, entity): - """Look up EntityData by entity name (case-insensitive). - - Forwards to the EntityDatabase. - """ - return self.entity_db.findEntityCaseInsensitive(entity) - - def getMemberNames(self, commandOrStruct): - """Given a command or struct name, retrieve the names of each member/param. - - Returns an empty list if the entity is not found or doesn't have members/params. - - Forwards to the EntityDatabase. - """ - return self.entity_db.getMemberNames(commandOrStruct) - - def likelyRecognizedEntity(self, entity_name): - """Guess (based on name prefix alone) if an entity is likely to be recognized. - - Forwards to the EntityDatabase. - """ - return self.entity_db.likelyRecognizedEntity(entity_name) - - def isLinkedMacro(self, macro): - """Identify if a macro is considered a "linked" macro. - - Forwards to the EntityDatabase. - """ - return self.entity_db.isLinkedMacro(macro) - - def processFile(self, filename): - """Parse an .adoc file belonging to the spec and check it for errors.""" - class FileStreamMaker(object): - def __init__(self, filename): - self.filename = filename - - def make_stream(self): - return open(self.filename, 'r', encoding='utf-8') - - f = self.macro_checker_file_type(self, filename, self.enabled_messages, - FileStreamMaker(filename)) - f.process() - self.files.append(f) - - def processString(self, s): - """Process a string as if it were a spec file. - - Used for testing purposes. - """ - if "\n" in s.rstrip(): - # remove leading spaces from each line to allow easier - # block-quoting in tests - s = "\n".join((line.lstrip() for line in s.split("\n"))) - # fabricate a "filename" that will display better. - filename = "string{}\n****START OF STRING****\n{}\n****END OF STRING****\n".format( - len(self.files), s.rstrip()) - - else: - filename = "string{}: {}".format( - len(self.files), s.rstrip()) - - class StringStreamMaker(object): - def __init__(self, string): - self.string = string - - def make_stream(self): - return StringIO(self.string) - - f = self.macro_checker_file_type(self, filename, self.enabled_messages, - StringStreamMaker(s)) - f.process() - self.files.append(f) - return f - - def numDiagnostics(self): - """Return the total number of diagnostics (warnings and errors) over all the files processed.""" - return sum((f.numDiagnostics() for f in self.files)) - - def numErrors(self): - """Return the total number of errors over all the files processed.""" - return sum((f.numErrors() for f in self.files)) - - def getMissingUnreferencedApiIncludes(self): - """Return the unreferenced entity names that we expected to see an API include or link target for, but did not. - - Counterpart to getBrokenLinks(): This method returns the entity names - that were not used in a linking macro (and thus wouldn't create a broken link), - but were nevertheless expected and not seen. - """ - return (entity for entity in self.entity_db.generating_entities - if (not self.haveLinkTarget(entity)) and entity not in self.links) - - def getBrokenLinks(self): - """Return the entity names and usage contexts that we expected to see an API include or link target for, but did not. - - Counterpart to getMissingUnreferencedApiIncludes(): This method returns only the - entity names that were used in a linking macro (and thus create a broken link), - but were not seen. The values of the dictionary are a list of MessageContext objects - for each linking macro usage for this entity name. - """ - return {entity: contexts for entity, contexts in self.links.items() - if self.entity_db.entityGenerates(entity) and not self.haveLinkTarget(entity)} - - def getMissingRefPages(self): - """Return a list of entities that we expected, but did not see, a ref page block for. - - The heuristics here are rather crude: we expect a ref page for every generating entry. - """ - return (entity for entity in sorted(self.entity_db.generating_entities) - if entity not in self.refpages) |