summaryrefslogtreecommitdiff
path: root/codegen/vulkan/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'codegen/vulkan/scripts')
-rw-r--r--codegen/vulkan/scripts/README.adoc74
-rwxr-xr-xcodegen/vulkan/scripts/Retired/checkLinks.py353
-rw-r--r--codegen/vulkan/scripts/Retired/extensionStubSource.py327
-rwxr-xr-xcodegen/vulkan/scripts/Retired/findBalance.py162
-rwxr-xr-xcodegen/vulkan/scripts/Retired/fixupRef.py202
-rwxr-xr-xcodegen/vulkan/scripts/Retired/insertTags.py102
-rwxr-xr-xcodegen/vulkan/scripts/Retired/realign.py48
-rw-r--r--codegen/vulkan/scripts/Retired/refDesc.py356
-rw-r--r--codegen/vulkan/scripts/__init__.py.docs36
-rw-r--r--codegen/vulkan/scripts/asciidoctor-chunker/LICENSE21
-rw-r--r--codegen/vulkan/scripts/asciidoctor-chunker/README.md123
-rwxr-xr-xcodegen/vulkan/scripts/asciidoctor-chunker/asciidoctor-chunker.js4
-rw-r--r--codegen/vulkan/scripts/cereal/__init__.py20
-rw-r--r--codegen/vulkan/scripts/cereal/api_log_decoder.py338
-rw-r--r--codegen/vulkan/scripts/cereal/common/__init__.py2
-rw-r--r--codegen/vulkan/scripts/cereal/common/codegen.py1061
-rw-r--r--codegen/vulkan/scripts/cereal/common/vulkantypes.py1216
-rw-r--r--codegen/vulkan/scripts/cereal/counting.py698
-rw-r--r--codegen/vulkan/scripts/cereal/decoder.py912
-rw-r--r--codegen/vulkan/scripts/cereal/decodersnapshot.py267
-rw-r--r--codegen/vulkan/scripts/cereal/deepcopy.py383
-rw-r--r--codegen/vulkan/scripts/cereal/dispatch.py499
-rw-r--r--codegen/vulkan/scripts/cereal/encoder.py717
-rw-r--r--codegen/vulkan/scripts/cereal/extensionstructs.py125
-rw-r--r--codegen/vulkan/scripts/cereal/frontend.py102
-rw-r--r--codegen/vulkan/scripts/cereal/functable.py360
-rw-r--r--codegen/vulkan/scripts/cereal/handlemap.py264
-rw-r--r--codegen/vulkan/scripts/cereal/marshaling.py1037
-rw-r--r--codegen/vulkan/scripts/cereal/marshalingdefs.py528
-rw-r--r--codegen/vulkan/scripts/cereal/reservedmarshaling.py1055
-rw-r--r--codegen/vulkan/scripts/cereal/subdecode.py395
-rw-r--r--codegen/vulkan/scripts/cereal/testing.py399
-rw-r--r--codegen/vulkan/scripts/cereal/transform.py348
-rw-r--r--codegen/vulkan/scripts/cereal/unbox.py81
-rw-r--r--codegen/vulkan/scripts/cereal/vkextensionstructuretype.py46
-rw-r--r--codegen/vulkan/scripts/cereal/wrapperdefs.py108
-rw-r--r--codegen/vulkan/scripts/cerealgenerator.py802
-rw-r--r--codegen/vulkan/scripts/cgenerator.py420
-rwxr-xr-xcodegen/vulkan/scripts/checkXrefs26
-rwxr-xr-xcodegen/vulkan/scripts/check_html_xrefs.py93
-rwxr-xr-xcodegen/vulkan/scripts/check_spec_links.py164
-rwxr-xr-xcodegen/vulkan/scripts/ci/check_undefined22
-rwxr-xr-xcodegen/vulkan/scripts/comment_convert.py203
-rwxr-xr-xcodegen/vulkan/scripts/compImages.sh127
-rw-r--r--codegen/vulkan/scripts/conventions.py358
-rwxr-xr-xcodegen/vulkan/scripts/deperiodize_vuids.py40
-rw-r--r--codegen/vulkan/scripts/docgenerator.py482
-rw-r--r--codegen/vulkan/scripts/extensionmetadocgenerator.py665
-rwxr-xr-xcodegen/vulkan/scripts/genRef.py1087
-rwxr-xr-xcodegen/vulkan/scripts/genRelease211
-rw-r--r--codegen/vulkan/scripts/genanchorlinks.py26
-rw-r--r--codegen/vulkan/scripts/generator.py1204
-rw-r--r--codegen/vulkan/scripts/genspec.py164
-rwxr-xr-xcodegen/vulkan/scripts/genvk.py854
-rwxr-xr-xcodegen/vulkan/scripts/globalizeIncludes22
-rw-r--r--codegen/vulkan/scripts/hostsyncgenerator.py154
-rwxr-xr-xcodegen/vulkan/scripts/htmldiff/htmldiff135
-rwxr-xr-xcodegen/vulkan/scripts/htmldiff/htmldiff.pl581
-rwxr-xr-xcodegen/vulkan/scripts/indexExt.py90
-rw-r--r--codegen/vulkan/scripts/interfacedocgenerator.py118
-rwxr-xr-xcodegen/vulkan/scripts/linkcheck.py84
-rwxr-xr-xcodegen/vulkan/scripts/make_ext_dependency.py243
-rwxr-xr-xcodegen/vulkan/scripts/makemanaliases.py57
-rwxr-xr-xcodegen/vulkan/scripts/promote.py173
-rw-r--r--codegen/vulkan/scripts/pygenerator.py94
-rw-r--r--codegen/vulkan/scripts/reflib.py666
-rwxr-xr-xcodegen/vulkan/scripts/reflow.py912
-rw-r--r--codegen/vulkan/scripts/reg.py1466
-rw-r--r--codegen/vulkan/scripts/rubygenerator.py120
-rw-r--r--codegen/vulkan/scripts/scriptgenerator.py380
-rw-r--r--codegen/vulkan/scripts/spec_tools/__init__.py7
-rw-r--r--codegen/vulkan/scripts/spec_tools/algo.py69
-rw-r--r--codegen/vulkan/scripts/spec_tools/attributes.py114
-rw-r--r--codegen/vulkan/scripts/spec_tools/base_printer.py213
-rw-r--r--codegen/vulkan/scripts/spec_tools/consistency_tools.py697
-rw-r--r--codegen/vulkan/scripts/spec_tools/console_printer.py274
-rw-r--r--codegen/vulkan/scripts/spec_tools/data_structures.py58
-rw-r--r--codegen/vulkan/scripts/spec_tools/entity_db.py659
-rw-r--r--codegen/vulkan/scripts/spec_tools/file_process.py119
-rw-r--r--codegen/vulkan/scripts/spec_tools/html_printer.py436
-rw-r--r--codegen/vulkan/scripts/spec_tools/macro_checker.py220
-rw-r--r--codegen/vulkan/scripts/spec_tools/macro_checker_file.py1592
-rw-r--r--codegen/vulkan/scripts/spec_tools/main.py244
-rw-r--r--codegen/vulkan/scripts/spec_tools/shared.py257
-rw-r--r--codegen/vulkan/scripts/spec_tools/util.py58
-rw-r--r--codegen/vulkan/scripts/spec_tools/validity.py216
-rw-r--r--codegen/vulkan/scripts/spirvcapgenerator.py308
-rwxr-xr-xcodegen/vulkan/scripts/testSpecVersion.py75
-rw-r--r--codegen/vulkan/scripts/test_check_spec_links.py643
-rw-r--r--codegen/vulkan/scripts/test_check_spec_links_api_specific.py122
-rw-r--r--codegen/vulkan/scripts/test_entity_db.py32
-rw-r--r--codegen/vulkan/scripts/translate_math.js33
-rwxr-xr-xcodegen/vulkan/scripts/validitygenerator.py1497
-rw-r--r--codegen/vulkan/scripts/vkconventions.py274
-rwxr-xr-xcodegen/vulkan/scripts/xml_consistency.py390
95 files changed, 0 insertions, 33619 deletions
diff --git a/codegen/vulkan/scripts/README.adoc b/codegen/vulkan/scripts/README.adoc
deleted file mode 100644
index 0a60629a..00000000
--- a/codegen/vulkan/scripts/README.adoc
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2014-2021 The Khronos Group Inc.
-//
-// SPDX-License-Identifier: CC-BY-4.0
-
-= Vulkan^(R)^ Specification Repository Scripts
-
-This directory contains scripts used in building the Vulkan API
-specification and related artifacts. For the most part, these scripts are
-invoked from the top-level directory or from the API Registry in
-../xml to build generated components of the specification.
-
-Scripts in this directory include:
-
- * `genvk.py` - Python script to generate Vulkan headers and some other
- targets, using the generators described below.
- * `reg.py` - Python tools to read a registry XML file and call into
- generators to create headers and other types of output.
- * `conventions.py`, `vkconventions.py` - API-specific parameters and
- formatting / style conventions used by generators.
- * `generator.py` - output generator base class.
- ** `cgenerator.py` - C header output generator.
- ** `docgenerator.py` - Asciidoc interface language include generator.
- ** `extensionmetadocgenerator.py` - Generator for Asciidoc extension
- descriptions in spec appendices.
- ** `hostsyncgenerator.py` - Asciidoc host sync table generator.
- ** `pygenerator.py` - Generates python encoding of the API description.
- ** `validitygenerator.py` - Asciidoc validity language generator.
-
- * `check_spec_links.py` - validates a variety of markup and content in the
- Asciidoctor specification source.
- * `make_ext_dependency.py` - generate extension dependencies in Bash and
- Python form for use when building the specification.
- * `genRelease`, `genspec.py` - build HTML and PDF Specifications with a
- variety of options to control target directories, extensions included
- while building, etc.
- * `genRef.py`, `reflib.py` - extract API reference pages from specification
- source into single-page source documents.
- * `indexExt.py` - generate HTML index of all extensions for inclusion into
- the Vulkan registry index page.
- * `reflow.py`, `reflow_count.py` - reflow specification source text to follow
- style guidelines, and insert Valid Usage statements where they're
- needed.
- * `test_check_spec_links.py`, `test_check_spec_links_api_specific.py`,
- `test_entity_db.py` - these are from another Khronos WG repository and
- are unused by Vulkan at present.
-
- * `compImages.sh` - compare images in two branches.
- * `htmldiff/htmldiff` - HTML diff script (see below).
- * `Retired/` - contains obsolete, unused, or single-purpose scripts. Not
- maintained.
-
-HTML Diff Script for Vulkan
-===========================
-
-This is a first cut at a script to compare Vulkan HTML specifications. Usage
-is simply 'htmldiff file1.html file2.html > diff.html'. The script does not
-copy CSS and images required by the input specs, so it's best to generate
-the output in the same directory as one of the inputs. However, the script
-must be invoked from the directory it is located within.
-
-The scripts used require Python and Perl. Additionally, the python
-'utidylib' module and the underlying libtidy C library are required.
-On Debian Linux, it may be necessary to install the 'python-utidylib' and
-'libtidy' packages if they are not already present.
-
-The scripts are taken from the code backing the
-
- http://services.w3.org/htmldiff
-
-website. `htmldiff` is the Python driver script. `htmldiff.pl` is the
-Perl script which generates the diff after preprocessing of the input
-HTML by `htmldiff`. `htmldiff.orig` is the original Python script from
-the website, modified to run at the command line instead of as a CGI
-script.
diff --git a/codegen/vulkan/scripts/Retired/checkLinks.py b/codegen/vulkan/scripts/Retired/checkLinks.py
deleted file mode 100755
index 35103a80..00000000
--- a/codegen/vulkan/scripts/Retired/checkLinks.py
+++ /dev/null
@@ -1,353 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2015-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# checkLinks.py - validate link/reference API constructs in files
-#
-# Usage: checkLinks.py [options] files > logfile
-#
-# Options:
-# -follow attempt to follow include:: directives. This script isn't # an
-# Asciidoctor processor, so only literal relative paths can # be followed.
-# -info print some internal diagnostics.
-# -paramcheck attempt to validate param: names against the surrounding
-# context (the current structure/function being validated, for example).
-# This generates many false positives, so is not enabled by default.
-# -fatal unvalidatable links cause immediate error exit from the script.
-# Otherwise, errors are accumulated and summarized at the end.
-#
-# Depends on vkapi.py, which is a Python representation of relevant parts
-# of the Vulkan API. Only works when vkapi.py is generated for the full
-# API, e.g. 'makeAllExts checklinks'; otherwise many false-flagged errors
-# will occur.
-
-import copy, os, pdb, re, string, sys
-from vkapi import *
-
-global curFile, curLine, sectionDepth
-global errCount, warnCount, emittedPrefix, printInfo
-
-curFile = '???'
-curLine = -1
-sectionDepth = 0
-emittedPrefix = {}
-printInfo = False
-
-# Called before printing a warning or error. Only prints once prior
-# to output for a given file.
-def emitPrefix():
- global curFile, curLine, emittedPrefix
- if (curFile not in emittedPrefix.keys()):
- emittedPrefix[curFile] = None
- print('Checking file:', curFile)
- print('-------------------------------')
-
-def info(*args, **kwargs):
- global curFile, curLine, printInfo
- if (printInfo):
-
- emitPrefix()
- print('INFO: %s line %d:' % (curFile, curLine),
- ' '.join([str(arg) for arg in args]))
-
-# Print a validation warning found in a file
-def warning(*args, **kwargs):
- global curFile, curLine, warnCount
-
- warnCount = warnCount + 1
- emitPrefix()
- print('WARNING: %s line %d:' % (curFile, curLine),
- ' '.join([str(arg) for arg in args]))
-
-# Print a validation error found in a file
-def error(*args, **kwargs):
- global curFile, curLine, errCount
-
- errCount = errCount + 1
- emitPrefix()
- print('ERROR: %s line %d:' % (curFile, curLine),
- ' '.join([str(arg) for arg in args]))
-
-# See if a tag value exists in the specified dictionary and
-# suggest it as an alternative if so.
-def checkTag(tag, value, dict, dictName, tagName):
- if (value in dict.keys()):
- warning(value, 'exists in the API but not as a',
- tag + ': .', 'Try using the', tagName + ': tag.')
-
-# Report an error due to an asciidoc tag which doesn't match
-# a corresponding API entity.
-def foundError(errType, tag, value, fatal):
- global curFile, curLine
- error('no such', errType, tag + ':' + value)
- # Try some heuristics to detect likely problems such as missing vk
- # prefixes or the wrong tag.
-
- # Look in all the dictionaries in vkapi.py to see if the tag
- # is just wrong but the API entity actually exists.
- checkTag(tag, value, flags, 'flags', 'tlink/tname')
- checkTag(tag, value, enums, 'enums', 'elink')
- checkTag(tag, value, structs, 'structs', 'slink/sname')
- checkTag(tag, value, handles, 'handles', 'slink/sname')
- checkTag(tag, value, defines, 'defines', 'slink/sname')
- checkTag(tag, value, consts, 'consts', 'ename')
- checkTag(tag, value, protos, 'protos', 'flink/fname')
- checkTag(tag, value, funcpointers, 'funcpointers', 'tlink/tname')
-
- # Look for missing vk prefixes (quirky since it's case-dependent)
- # NOT DONE YET
-
- if fatal:
- print('ERROR: %s line %d:' % (curFile, curLine),
- ' '.join(['no such', errType, tag + ':' + value]), file=sys.stderr)
- sys.exit(1)
-
-# Look for param in the list of all parameters of the specified functions
-# Returns True if found, False otherwise
-def findParam(param, funclist):
- for f in funclist:
- if (param in protos[f]):
- info('parameter:', param, 'found in function:', f)
- return True
- return False
-
-# Initialize tracking state for checking links/includes
-def initChecks():
- global curFile, curLine, curFuncs, curStruct, accumFunc, sectionDepth
- global errCount, warnCount
- global incPat, linkPat, pathPat, sectionPat
-
- # Matches asciidoc single-line section tags
- sectionPat = re.compile('^(=+) ')
-
- # Matches any asciidoc include:: directive
- pathPat = re.compile('^include::([\w./_]+)\[\]')
-
- # Matches asciidoc include:: directives used in spec/ref pages (and also
- # others such as validity). This is specific to the layout of the api/
- # includes and allows any path precding 'api/' followed by the category
- # (protos, structs, enums, etc.) followed by the name of the proto,
- # struct, etc. file.
- incPat = re.compile('^.*api/(\w+)/(\w+)\.txt')
-
- # Lists of current /protos/ (functions) and /structs/ includes. There
- # can be several protos contiguously for different forms of a command
- curFuncs = []
- curStruct = None
-
- # Tag if we should accumulate funcs or start a new list. Any intervening
- # pname: tags or struct includes will restart the list.
- accumFunc = False
-
- # Matches all link names in the current spec/man pages. Assumes these
- # macro names are not trailing subsets of other macros. Used to
- # precede the regexp with [^A-Za-z], but this didn't catch macros
- # at start of line.
- linkPat = re.compile('([efpst](name|link)):(\w*)')
-
- # Total error/warning counters
- errCount = 0
- warnCount = 0
-
-# Validate asciidoc internal links in specified file.
-# infile - filename to validate
-# follow - if True, recursively follow include:: directives
-# paramCheck - if True, try to verify pname: refers to valid
-# parameter/member names. This generates many false flags currently
-# included - if True, function was called recursively
-# fatalExit - if True, validation errors cause an error exit immediately
-# Links checked are:
-# fname:vkBlah - Vulkan command name (generates internal link)
-# flink:vkBlah - Vulkan command name
-# sname:VkBlah - Vulkan struct name (generates internal link)
-# slink:VkBlah - Vulkan struct name
-# elink:VkEnumName - Vulkan enumeration ('enum') type name (generates internal link)
-# ename:VK_BLAH - Vulkan enumerant token name
-# pname:name - parameter name to a command or a struct member
-# tlink:name - Other Vulkan type name (generates internal link)
-# tname:name - Other Vulkan type name
-def checkLinks(infile, follow = False, paramCheck = True, included = False, fatalExit = False):
- global curFile, curLine, curFuncs, curStruct, accumFunc, sectionDepth
- global errCount, warnCount
- global incPat, linkPat, pathPat, sectionPat
-
- # Global state which gets saved and restored by this function
- oldCurFile = curFile
- oldCurLine = curLine
- curFile = infile
- curLine = 0
-
- # N.b. dirname() returns an empty string for a path with no directories,
- # unlike the shell dirname(1).
- if (not os.path.exists(curFile)):
- error('No such file', curFile, '- skipping check')
- # Restore global state before exiting the function
- curFile = oldCurFile
- curLine = oldCurLine
- return
-
- inPath = os.path.dirname(curFile)
- fp = open(curFile, 'r', encoding='utf-8')
-
- for line in fp:
- curLine = curLine + 1
-
- # Track changes up and down section headers, and forget
- # the current functions/structure when popping up a level
- match = sectionPat.search(line)
- if (match):
- info('Match sectionPat for line:', line)
- depth = len(match.group(1))
- if (depth < sectionDepth):
- info('Resetting current function/structure for section:', line)
- curFuncs = []
- curStruct = None
- sectionDepth = depth
-
- match = pathPat.search(line)
- if (match):
- incpath = match.group(1)
- info('Match pathPat for line:', line)
- info(' incpath =', incpath)
- # An include:: directive. First check if it looks like a
- # function or struct include file, and modify the corresponding
- # current function or struct state accordingly.
- match = incPat.search(incpath)
- if (match):
- info('Match incPat for line:', line)
- # For prototypes, if it is preceded by
- # another include:: directive with no intervening link: tags,
- # add to the current function list. Otherwise start a new list.
- # There is only one current structure.
- category = match.group(1)
- tag = match.group(2)
- # @ Validate tag!
- # @ Arguably, any intervening text should shift to accumFuncs = False,
- # e.g. only back-to-back includes separated by blank lines would be
- # accumulated.
- if (category == 'protos'):
- if (tag in protos.keys()):
- if (accumFunc):
- curFuncs.append(tag)
- else:
- curFuncs = [ tag ]
- # Restart accumulating functions
- accumFunc = True
- info('curFuncs =', curFuncs, 'accumFunc =', accumFunc)
- else:
- error('include of nonexistent function', tag)
- elif (category == 'structs'):
- if (tag in structs.keys()):
- curStruct = tag
- # Any /structs/ include means to stop accumulating /protos/
- accumFunc = False
- info('curStruct =', curStruct)
- else:
- error('include of nonexistent struct', tag)
- if (follow):
- # Actually process the included file now, recursively
- newpath = os.path.normpath(os.path.join(inPath, incpath))
- info(curFile, ': including file:', newpath)
- checkLinks(newpath, follow, paramCheck, included = True, fatalExit = fatalExit)
-
- matches = linkPat.findall(line)
- for match in matches:
- # Start actual validation work. Depending on what the
- # asciidoc tag name is, look up the value in the corresponding
- # dictionary.
- tag = match[0]
- value = match[2]
- if (tag == 'fname' or tag == 'flink'):
- if (value not in protos.keys()):
- foundError('function', tag, value, False)
- elif (tag == 'sname' or tag == 'slink'):
- if (value not in structs.keys() and
- value not in handles.keys()):
- foundError('aggregate/scalar/handle/define type', tag, value, False)
- elif (tag == 'ename'):
- if (value not in consts.keys() and value not in defines.keys()):
- foundError('enumerant/constant', tag, value, False)
- elif (tag == 'elink'):
- if (value not in enums.keys() and value not in flags.keys()):
- foundError('enum/bitflag type', tag, value, fatalExit)
- # tname and tlink are the same except if the errors are treated as fatal
- # They can be recombined once both are error-clean
- elif (tag == 'tname'):
- if (value not in funcpointers.keys() and value not in flags.keys()):
- foundError('function pointer/other type', tag, value, fatalExit)
- elif (tag == 'tlink'):
- if (value not in funcpointers.keys() and value not in flags.keys()):
- foundError('function pointer/other type', tag, value, False)
- elif (tag == 'pname'):
- # Any pname: tag means to stop accumulating /protos/
- accumFunc = False
- # See if this parameter is in the current proto(s) and struct
- foundParam = False
- if (curStruct and value in structs[curStruct]):
- info('parameter', value, 'found in struct', curStruct)
- elif (curFuncs and findParam(value, curFuncs)):
- True
- else:
- if paramCheck:
- warning('parameter', value, 'not found. curStruct =',
- curStruct, 'curFuncs =', curFuncs)
- else:
- # This is a logic error
- error('unknown tag', tag + ':' + value)
- fp.close()
-
- if (errCount > 0 or warnCount > 0):
- if (not included):
- print('Errors found:', errCount, 'Warnings found:', warnCount)
- print('')
-
- if (included):
- info('----- returning from:', infile, 'to parent file', '-----')
-
- # Don't generate any output for files without errors
- # else:
- # print(curFile + ': No errors found')
-
- # Restore global state before exiting the function
- curFile = oldCurFile
- curLine = oldCurLine
-
-if __name__ == '__main__':
- follow = False
- paramCheck = False
- included = False
- fatalExit = False
-
- totalErrCount = 0
- totalWarnCount = 0
-
- if (len(sys.argv) > 1):
- for file in sys.argv[1:]:
- if (file == '-follow'):
- follow = True
- elif (file == '-info'):
- printInfo = True
- elif file == '-paramcheck':
- paramCheck = True
- elif (file == '-fatal'):
- fatalExit = True
- else:
- initChecks()
- checkLinks(file,
- follow,
- paramCheck = paramCheck,
- included = included,
- fatalExit = fatalExit)
- totalErrCount = totalErrCount + errCount
- totalWarnCount = totalWarnCount + warnCount
- else:
- print('Need arguments: [-follow] [-info] [-paramcheck] [-fatal] infile [infile...]', file=sys.stderr)
-
- if (totalErrCount > 0 or totalWarnCount > 0):
- if (not included):
- print('TOTAL Errors found:', totalErrCount, 'Warnings found:',
- totalWarnCount)
- if totalErrCount > 0:
- sys.exit(1)
diff --git a/codegen/vulkan/scripts/Retired/extensionStubSource.py b/codegen/vulkan/scripts/Retired/extensionStubSource.py
deleted file mode 100644
index b9ff837e..00000000
--- a/codegen/vulkan/scripts/Retired/extensionStubSource.py
+++ /dev/null
@@ -1,327 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-import os,re,sys
-from generator import *
-
-doc = """
-/*
-** This target is no longer maintained and supported.
-** See README.adoc for discussion.
-**
-** This is a simple extension loader which provides the implementations for the
-** extension prototypes declared in vulkan header. It supports loading extensions either
-** for a single instance or a single device. Multiple instances are not yet supported.
-**
-** To use the loader add vulkan_ext.c to your solution and include <vulkan/vulkan_ext.h>.
-**
-** If your application is using a single instance, but multiple devices callParam
-**
-** vkExtInitInstance(instance);
-**
-** after initializing the instance. This way the extension loader will use the loaders
-** trampoline functions to call the correct driver for each call. This method is safe
-** if your application might use more than one device at the cost of one additional
-** indirection, the dispatch table of each dispatchable object.
-**
-** If your application uses only a single device it's better to use
-**
-** vkExtInitDevice(device);
-**
-** once the device has been initialized. This will resolve the function pointers
-** upfront and thus removes one indirection for each call into the driver. This *can*
-** result in slightly more performance for calling overhead limited cases.
-*/
-"""
-
-# StubExtGeneratorOptions - subclass of GeneratorOptions.
-#
-# Adds options used by COutputGenerator objects during C language header
-# generation.
-#
-# Additional members
-# prefixText - list of strings to prefix generated header with
-# (usually a copyright statement + calling convention macros).
-# alignFuncParam - if nonzero and parameters are being put on a
-# separate line, align parameter names at the specified column
-class StubExtGeneratorOptions(GeneratorOptions):
- """Represents options during C interface generation for headers"""
- def __init__(self,
- filename = None,
- directory = '.',
- apiname = None,
- profile = None,
- versions = '.*',
- emitversions = '.*',
- defaultExtensions = None,
- addExtensions = None,
- removeExtensions = None,
- emitExtensions = None,
- sortProcedure = regSortFeatures,
- prefixText = "",
- alignFuncParam = 0):
- GeneratorOptions.__init__(self, filename, directory, apiname, profile,
- versions, emitversions, defaultExtensions,
- addExtensions, removeExtensions,
- emitExtensions, sortProcedure)
- self.prefixText = prefixText
- self.alignFuncParam = alignFuncParam
-
-# ExtensionStubSourceOutputGenerator - subclass of OutputGenerator.
-# Generates C-language extension wrapper interface sources.
-#
-# ---- methods ----
-# ExtensionStubSourceOutputGenerator(errFile, warnFile, diagFile) - args as for
-# OutputGenerator. Defines additional internal state.
-# ---- methods overriding base class ----
-# beginFile(genOpts)
-# endFile()
-# beginFeature(interface, emit)
-# endFeature()
-# genType(typeinfo,name)
-# genStruct(typeinfo,name)
-# genGroup(groupinfo,name)
-# genEnum(enuminfo, name)
-# genCmd(cmdinfo)
-class ExtensionStubSourceOutputGenerator(OutputGenerator):
- """Generate specified API interfaces in a specific style, such as a C header"""
- # This is an ordered list of sections in the header file.
- TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum',
- 'group', 'bitmask', 'funcpointer', 'struct']
- ALL_SECTIONS = TYPE_SECTIONS + ['commandPointer', 'command']
- def __init__(self,
- errFile = sys.stderr,
- warnFile = sys.stderr,
- diagFile = sys.stdout):
- OutputGenerator.__init__(self, errFile, warnFile, diagFile)
- #
- def beginFile(self, genOpts):
- OutputGenerator.beginFile(self, genOpts)
- # C-specific
- #
- # Multiple inclusion protection & C++ wrappers.
-
- # Internal state - accumulators for function pointers and function
- # pointer initializatoin
- self.pointers = [];
- self.pointerInitializersInstance = [];
- self.pointerInitializersDevice = [];
-
- #
- # Write header protection
- filename = self.genOpts.directory + '/' + 'vulkan_ext.h'
- self.outFileHeader = open(filename, 'w', encoding='utf-8')
-
- write('#ifndef VULKAN_EXT_H', file=self.outFileHeader)
- write('#define VULKAN_EXT_H', file=self.outFileHeader)
- write('', file=self.outFileHeader)
- write('#ifdef __cplusplus', file=self.outFileHeader)
- write('extern "C" {', file=self.outFileHeader)
- write('#endif', file=self.outFileHeader)
-
- #
- # User-supplied prefix text, if any (list of strings)
- if (genOpts.prefixText):
- for s in genOpts.prefixText:
- write(s, file=self.outFile)
- write(s, file=self.outFileHeader)
-
- write(doc, file=self.outFileHeader)
-
- write('#include <vulkan/vulkan.h>', file=self.outFile)
- self.newline()
-
- write('#include <vulkan/vulkan_core.h>', file=self.outFileHeader)
- write('', file=self.outFileHeader)
-
- write('void vkExtInitInstance(VkInstance instance);', file=self.outFileHeader)
- write('void vkExtInitDevice(VkDevice device);', file=self.outFileHeader)
- write('', file=self.outFileHeader)
-
- def endFile(self):
- for pointer in self.pointers:
- write(pointer, file=self.outFile)
-
- self.newline()
-
- write('void vkExtInitInstance(VkInstance instance)\n{', file=self.outFile)
- for pointerInitializer in self.pointerInitializersInstance:
- write(pointerInitializer, file=self.outFile)
- write('}', file=self.outFile)
-
- self.newline()
-
- write('void vkExtInitDevice(VkDevice device)\n{', file=self.outFile)
- for pointerInitializer in self.pointerInitializersDevice:
- write(pointerInitializer, file=self.outFile)
- write('}', file=self.outFile)
-
- self.newline()
-
- #Finish header file
- write('#ifdef __cplusplus', file=self.outFileHeader)
- write('}', file=self.outFileHeader)
- write('#endif', file=self.outFileHeader)
- write('', file=self.outFileHeader)
- write('#endif', file=self.outFileHeader)
- self.outFileHeader.close()
-
- # Finish processing in superclass
- OutputGenerator.endFile(self)
-
- def beginFeature(self, interface, emit):
- # Start processing in superclass
- OutputGenerator.beginFeature(self, interface, emit)
-
- # Accumulate function pointers and function pointer initialization
- self.featurePointers = []
- self.featurePointerInitializersInstance = []
- self.featurePointerInitializersDevice = []
-
- def endFeature(self):
- # Add feature to global list with protectFeature
- if (self.emit and self.featurePointers):
- if (self.genOpts.protectFeature):
- self.pointers.append('#ifdef ' + self.featureName)
- self.pointerInitializersInstance.append('#ifdef ' + self.featureName)
- self.pointerInitializersDevice.append('#ifdef ' + self.featureName)
-
- if (self.featureExtraProtect != None):
- self.pointers.append('#ifdef ' + self.featureExtraProtect)
- self.pointerInitializersInstance.append('#ifndef ' + self.featureName)
- self.pointerInitializersDevice.append('#ifndef ' + self.featureName)
-
- self.pointers += self.featurePointers;
- self.pointerInitializersInstance += self.featurePointerInitializersInstance;
- self.pointerInitializersDevice += self.featurePointerInitializersDevice;
-
- if (self.featureExtraProtect != None):
- self.pointers.append('#endif /* ' + self.featureExtraProtect + ' */')
- self.pointerInitializersInstance.append('#endif /* ' + self.featureExtraProtect + ' */')
- self.pointerInitializersDevice.append('#endif /* ' + self.featureExtraProtect + ' */')
- if (self.genOpts.protectFeature):
- self.pointers.append('#endif /* ' + self.featureName + ' */')
- self.pointerInitializersInstance.append('#endif /* ' + self.featureName + ' */')
- self.pointerInitializersDevice.append('#endif /* ' + self.featureName + ' */')
-
- # Finish processing in superclass
- OutputGenerator.endFeature(self)
- #
- # Type generation
- def genType(self, typeinfo, name, alias):
- pass
-
- def genStruct(self, typeinfo, typeName, alias):
- pass
-
- def genGroup(self, groupinfo, groupName, alias):
- pass
-
- def genEnum(self, enuminfo, name, alias):
- pass
-
- #
- # Command generation
- def genCmd(self, cmdinfo, name, alias):
- OutputGenerator.genCmd(self, cmdinfo, name, alias)
-
- #
- decls = self.makeStub(cmdinfo.elem)
- self.featurePointerInitializersInstance.append(decls[0])
- self.featurePointerInitializersDevice.append(decls[1])
- self.featurePointers.append(decls[2])
-
- #
- # makeStub - return static declaration for function pointer and initialization of function pointer
- # as a two-element list of strings.
- # cmd - Element containing a <command> tag
- def makeStub(self, cmd):
- """Generate a stub function pointer <command> Element"""
- proto = cmd.find('proto')
- params = cmd.findall('param')
- name = cmd.find('name')
-
- # Begin accumulating prototype and typedef strings
- pfnDecl = 'static '
- pfnDecl += noneStr(proto.text)
-
- # Find the name tag and generate the function pointer and function pointer initialization code
- nameTag = proto.find('name')
- tail = noneStr(nameTag.tail)
- returnType = noneStr(proto.find('type').text)
-
- type = self.makeFunctionPointerType(nameTag.text, tail)
-
- # For each child element, if it's a <name> wrap in appropriate
- # declaration. Otherwise append its contents and tail con#tents.
- stubDecl = ''
- for elem in proto:
- text = noneStr(elem.text)
- tail = noneStr(elem.tail)
- if (elem.tag == 'name'):
- name = self.makeProtoName(text, tail)
- stubDecl += name
- else:
- stubDecl += text + tail
-
- pfnName = self.makeFunctionPointerName(nameTag.text, noneStr(tail));
- pfnDecl += type + ' ' + pfnName + ';'
-
- # Now generate the stub function
- pfnDecl += '\n'
-
- # Now add the parameter declaration list, which is identical
- # for prototypes and typedefs. Concatenate all the text from
- # a <param> node without the tags. No tree walking required
- # since all tags are ignored.
- n = len(params)
- paramdecl = '(\n'
-
- pfnCall = '\n{\n ' + ('return ', '')[returnType == 'void'] + pfnName + '(\n'
- # Indented parameters
- if n > 0:
- indentCallParam = '(\n'
- indentdecl = '(\n'
- for i in range(0,n):
- callParam = ''
-
- paramdecl += self.makeCParamDecl(params[i], self.genOpts.alignFuncParam)
- pfnCall += self.makeCCallParam(params[i], self.genOpts.alignFuncParam)
- if (i < n - 1):
- paramdecl += ',\n'
- pfnCall += ',\n'
- else:
- paramdecl += ')'
- pfnCall += '\n );\n'
- indentdecl += paramdecl
- indentCallParam += pfnCall
- else:
- indentdecl = '(void);'
-
- pfnCall += '}\n'
-
- featureInstance = ' ' + pfnName + ' = ('+type+')vkGetInstanceProcAddr(instance, "' + name + '");'
- featureDevice = ' ' + pfnName + ' = ('+type+')vkGetDeviceProcAddr(device, "' + name + '");'
- return [featureInstance, featureDevice , pfnDecl + stubDecl + paramdecl + pfnCall]
-
- # Return function pointer type for given function
- def makeFunctionPointerType(self, name, tail):
- return 'PFN_' + name + tail
-
- # Return name of static variable which stores the function pointer for the given function
- def makeFunctionPointerName(self, name, tail):
- return 'pfn_' + name + tail
-
- #
- # makeCParamDecl - return a string which is an indented, formatted
- # declaration for a <param> or <member> block (e.g. function parameter
- # or structure/union member).
- # param - Element (<param> or <member>) to format
- # aligncol - if non-zero, attempt to align the nested <name> element
- # at this column
- def makeCCallParam(self, param, aligncol):
- return ' ' + param.find('name').text
-
diff --git a/codegen/vulkan/scripts/Retired/findBalance.py b/codegen/vulkan/scripts/Retired/findBalance.py
deleted file mode 100755
index 2a9efe1f..00000000
--- a/codegen/vulkan/scripts/Retired/findBalance.py
+++ /dev/null
@@ -1,162 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2016-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# fixupRef.py - replace old // refBegin .. // refEnd syntax with new
-# open block syntax
-#
-# Usage: fixupRef.py [-outdir path] [-overwrite] files
-
-from reflib import *
-import argparse, copy, io, os, pdb, re, string, sys
-
-def prefix(depth):
- return ' ' * depth
-
-openPat = re.compile('^\[open,(?P<attribs>refpage=.*)\]')
-ifdefPat = re.compile('^if(n|)def::(?P<condition>.*)\[(?P<text>.*)\]')
-endifPat = re.compile('^endif::(?P<condition>.*)\[\]')
-
-# Look for imbalanced block delimiters and conditionals
-# specFile - filename to examine
-def findBalance(specFile):
- file = loadFile(specFile)
- if file == None:
- return
-
- # blocks[] is a stack of nesting constructs, each of which is
- # [ '--', line, None ] for a -- delimiter on line
- # [ 'ifdef', line, condition] for an ifdef or ifndef on line
- blocks = []
-
- line = 1
-
- for str in file:
- blockDepth = len(blocks)
- if blockDepth > 0:
- thisBlock = blocks[blockDepth-1]
- blockType = thisBlock[0]
- blockLine = thisBlock[1]
- blockCondition = thisBlock[2]
- else:
- thisBlock = None
- blockType = None
- blockLine = None
- blockCondition = None
-
- if str.rstrip() == '--':
- if (blockDepth > 0 and blockType == '--'):
- print(prefix(blockDepth - 1) +
- 'Closing -- block opened @', blockLine,
- '-> new block depth =', blockDepth - 1)
- blocks.pop()
- else:
- print(prefix(blockDepth) +
- 'Opening -- block @', line,
- '-> new block depth:', blockDepth + 1)
- blocks.append([ '--', line, None ])
- line = line + 1
- continue
-
- matches = beginPat.search(str)
- if matches != None:
- # print('Matched [open pattern @', line, ':', str.rstrip())
- line = line + 1
- continue
-
- matches = ifdefPat.search(str)
- if matches != None:
- condition = matches.group('condition')
- text = matches.group('text')
-
- if text != '':
- print('Matched self-closing if(n)def pattern @', line,
- 'condition:', condition, 'text:', text)
- else:
- print(prefix(blockDepth) +
- 'Opening if(n)def block @', line,
- '-> new block depth =', blockDepth + 1,
- 'condition:', condition)
- blocks.append([ 'ifdef', line, condition ])
-
- line = line + 1
- continue
-
- matches = endifPat.search(str)
- if matches != None:
- condition = matches.group('condition')
-
- if (blockDepth > 0):
- if blockType == 'ifdef':
- # Try closing an ifdef/ifndef block
- if blockCondition != condition:
- print('** WARNING:', specFile,
- 'endif @', blockLine,
- 'block depth:', blockDepth,
- 'condition', condition,
- 'does not match ifdef/ifndef @',
- blockLine, 'condition', blockCondition)
-
- print(prefix(blockDepth - 1) +
- 'Closing endif block @', line,
- '-> new block depth =', blockDepth - 1)
- blocks.pop()
- elif blockType == '--':
- # An overlap!
- print('** ERROR:', specFile, 'endif @', line,
- 'block depth:', blockDepth,
- 'overlaps -- block start @', blockLine)
- else:
- # Should never get here
- print('** ERROR:', specFile,
- 'block depth:', blockDepth,
- 'unknown open block type:', blockType)
- else:
- # Unlikely error condition from bad markup
- print('** ERROR:', specFile,
- 'block depth:', blockDepth,
- 'endif @', line, 'with no matching open block')
-
- line = line + 1
- continue
-
- line = line + 1
-
- blockDepth = len(blocks)
- if blockDepth > 0:
- print('** ERROR:', specFile, 'still in open block at EOF:',
- 'block depth =', blockDepth,
- 'block type:', blocks[blockDepth-1][0])
-
-if __name__ == '__main__':
- global genDict
- genDict = {}
-
- parser = argparse.ArgumentParser()
-
- parser.add_argument('-diag', action='store', dest='diagFile',
- help='Set the diagnostic file')
- parser.add_argument('-warn', action='store', dest='warnFile',
- help='Set the warning file')
- parser.add_argument('-log', action='store', dest='logFile',
- help='Set the log file for both diagnostics and warnings')
- parser.add_argument('files', metavar='filename', nargs='*',
- help='a filename to extract ref pages from')
- parser.add_argument('--version', action='version', version='%(prog)s 1.0')
-
- results = parser.parse_args()
-
- setLogFile(True, True, results.logFile)
- setLogFile(True, False, results.diagFile)
- setLogFile(False, True, results.warnFile)
-
- skipped = set()
- for file in results.files:
- findBalance(file)
-
- if len(skipped) > 0:
- print('Files containing skipped feature blocks:')
- for file in sorted(skipped):
- print('\t' + file)
diff --git a/codegen/vulkan/scripts/Retired/fixupRef.py b/codegen/vulkan/scripts/Retired/fixupRef.py
deleted file mode 100755
index 4a9b792a..00000000
--- a/codegen/vulkan/scripts/Retired/fixupRef.py
+++ /dev/null
@@ -1,202 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2016-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# fixupRef.py - replace old // refBegin .. // refEnd syntax with new
-# open block syntax
-#
-# Usage: fixupRef.py [-outdir path] [-overwrite] files
-
-from reflib import *
-from vkapi import *
-import argparse, copy, io, os, pdb, re, string, sys
-
-# Return 'None' for None, the string otherwise
-def noneStr(str):
- if str == None:
- return '(None)'
- else:
- return str
-
-# Escape single quotes in a string for asciidoc
-def escapeQuote(str):
- return str.replace("'", "\'")
-
-# Start a refpage open block
-def openBlock(pi, fp):
- if pi.refs != '':
- print("[open,refpage='" + pi.name +
- "',desc='" + pi.desc +
- "',type='" + pi.type +
- "',xrefs='" + pi.refs + "']",
- file=fp)
- else:
- print("[open,refpage='" + pi.name +
- "',desc='" + pi.desc +
- "',type='" + pi.type + "']",
- file=fp)
- print('--', file=fp)
-
-# End a refpage open block
-def closeBlock(pi, fp):
- print('--', file=fp)
- # Just for finding block ends while debugging
- # print("// end [open,refpage='" + pi.name + "']", file=fp)
-
-# Replace old // refBegin .. // refEnd references in an asciidoc
-# file with open blocks, per # ??? .
-# specFile - filename to extract from
-# outDir - output directory to write updated file to, if not overwritten
-# overwrite - True if the file should be overwritten in place
-# skipped - set of filenames containing commands which weren't
-# rewritten with open blocks (e.g. enums). Updated in place.
-def replaceRef(specFile, outDir, overwrite = False, skipped = set()):
- file = loadFile(specFile)
- if file == None:
- return
-
- # Save the path to this file for later use in rewriting relative includes
- specDir = os.path.dirname(os.path.abspath(specFile))
-
- pageMap = findRefs(file)
- logDiag(specFile + ': found', len(pageMap.keys()), 'potential pages')
-
- sys.stderr.flush()
-
- # Fix up references in pageMap
- fixupRefs(pageMap, specFile, file)
-
- # Map the page info dictionary into a dictionary of actions
- # keyed by line number they're performed on/after:
- # 'action' : 'begin' or 'end'. What to do on a refBegin or refEnd line
- # 'replace': True if this line needs to be replaced
- # 'name' : Name of the ref page being defined
- # 'desc' : One-line description of the ref page being defined
- # 'type' : Type of the ref page being defined, 'structs', 'protos', etc.
- # 'refs' : Space-separated string of crossreferenced pages
-
- actions = { }
-
- for name in pageMap.keys():
- pi = pageMap[name]
-
- # Cleanup parameters for output
- pi.name = noneStr(pi.name)
- pi.desc = escapeQuote(noneStr(pi.desc))
-
- if pi.extractPage:
- if (file[pi.begin][0:11] == '// refBegin'):
- # Replace line
- actions[pi.begin] = {
- 'action' : 'begin',
- 'replace' : True,
- 'pageinfo' : pi
- }
- else:
- # Insert line
- actions[pi.begin] = {
- 'action' : 'begin',
- 'replace' : False,
- 'pageinfo' : pi
- }
-
- if (file[pi.end][0:9] == '// refEnd'):
- # Replace line
- actions[pi.end] = {
- 'action' : 'end',
- 'replace' : True,
- 'pageinfo' : pi
- }
- else:
- # Insert line
- actions[pi.end] = {
- 'action' : 'end',
- 'replace' : False,
- 'pageinfo' : pi
- }
- else:
- logWarn('Skipping replacement for', pi.name, 'at', specFile,
- 'line', pi.begin)
- print('Skipping replacement for', pi.name, 'at', specFile,
- 'line', pi.begin)
- printPageInfo(pi, file)
- skipped.add(specFile)
-
- if overwrite:
- pageName = specFile
- else:
- pageName = outDir + '/' + os.path.basename(specFile)
-
- fp = open(pageName, 'w', encoding='utf-8')
-
- line = 0
- for text in file:
- if line in actions.keys():
- action = actions[line]['action']
- replace = actions[line]['replace']
- pi = actions[line]['pageinfo']
-
- logDiag('ACTION:', action, 'REPLACE:', replace, 'at line', line)
- logDiag('PageInfo of action:')
- printPageInfo(pi, file)
-
- if action == 'begin':
- openBlock(pi, fp)
- if not replace:
- print(text, file=fp, end='')
- elif action == 'end':
- if not replace:
- print(text, file=fp, end='')
- closeBlock(pi, fp)
- else:
- print('ERROR: unrecognized action:', action, 'in',
- specFile, 'at line', line)
- print(text, file=fp, end='')
- else:
- print(text, file=fp, end='')
- line = line + 1
-
- fp.close()
-
- #for line in sorted(actions.keys()):
- # action = actions[line]
- # print('action at line', line, '\t',
- # action[0], action[1], action[2])
-
-if __name__ == '__main__':
- global genDict
- genDict = {}
-
- parser = argparse.ArgumentParser()
-
- parser.add_argument('-diag', action='store', dest='diagFile',
- help='Set the diagnostic file')
- parser.add_argument('-warn', action='store', dest='warnFile',
- help='Set the warning file')
- parser.add_argument('-log', action='store', dest='logFile',
- help='Set the log file for both diagnostics and warnings')
- parser.add_argument('-outdir', action='store', dest='outDir',
- default='out',
- help='Set the base directory in which pages are generated')
- parser.add_argument('-overwrite', action='store_true',
- help='Overwrite input filenames instead of writing different output filenames')
- parser.add_argument('files', metavar='filename', nargs='*',
- help='a filename to extract ref pages from')
- parser.add_argument('--version', action='version', version='%(prog)s 1.0')
-
- results = parser.parse_args()
-
- setLogFile(True, True, results.logFile)
- setLogFile(True, False, results.diagFile)
- setLogFile(False, True, results.warnFile)
-
- skipped = set()
- for file in results.files:
- replaceRef(file, results.outDir, results.overwrite, skipped)
-
- if len(skipped) > 0:
- print('Files containing skipped feature blocks:')
- for file in sorted(skipped):
- print('\t' + file)
diff --git a/codegen/vulkan/scripts/Retired/insertTags.py b/codegen/vulkan/scripts/Retired/insertTags.py
deleted file mode 100755
index a8c494c1..00000000
--- a/codegen/vulkan/scripts/Retired/insertTags.py
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2016-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# insertTags.py - insert // refBegin and // refEnd tags in Vulkan
-# spec source files.
-#
-# Usage: insertTags.py output-dir files
-
-# Short descriptions of ref pages, if not found
-from refDesc import *
-
-# Utility functions
-from reflib import *
-import copy, os, pdb, re, string, sys
-
-# Insert informative tags in a spec asciidoc source file
-# specFile - filename to add tags to
-# baseDir - output directory to generate page in
-def insertTags(specFile, baseDir):
- file = loadFile(specFile)
- if (file == None):
- return
- pageMap = findRefs(file)
- logDiag(specFile + ': found', len(pageMap.keys()), 'potential pages')
-
- # Fix up references in pageMap
- fixupRefs(pageMap, specFile, file)
-
- # Proceed backwards through the file, inserting
- # // refBegin name desc
- # lines where they're meaningful
-
- logDiag('Table of pages found:')
- logDiag('---------------------')
- for name in pageMap.keys():
- printPageInfo(pageMap[name], file)
-
- line = len(file) - 1
- while (line >= 0):
- # If this is a valid begin line without a description, and a
- # description exists in refDesc, add it.
- for name in pageMap.keys():
- pi = pageMap[name]
- if (pi.begin == line):
- if (not name in refDesc.keys()):
- if (pi.desc != None):
- logDiag('Description already exists, but no refDesc found for', name, 'at', specFile + ':' + str(line))
- else:
- if (pi.embed):
- logDiag('No refDesc found (this is OK) for embedded', name, 'at', specFile + ':' + str(line))
- else:
- logWarn('No refDesc found for', name, 'at', specFile + ':' + str(line))
- continue
-
- # New or replacement refBegin line, with short description
- newLine = '// refBegin ' + name + ' - ' + refDesc[name] + '\n'
-
- if (pi.desc == None):
- logDiag('Adding description for', name, 'at', specFile + ':' + str(line))
-
- # If there's already a refBegin on this line, replace it.
- # Otherwise, insert one.
- if (file[line].find('// refBegin') == 0):
- logDiag('Replacing existing refBegin without description for', name, 'at', specFile + ':' + str(line))
- file[line] = newLine
- else:
- logDiag('Inserting new refBegin at', specFile + ':' + str(line))
- # Add a blank line after the comment if it's new
- file.insert(line, newLine)
- file.insert(line, '\n')
- else:
- if (pi.desc[-1] == '.'):
- pi.desc = pi.desc[0:-1]
- if (pi.desc == refDesc[name]):
- logDiag('Not replacing description for', name, 'at', specFile + ':' + str(line), '- MATCHES existing one')
- else:
- logWarn('Replacing existing refBegin WITH description for', name, 'at', specFile + ':' + str(line))
- file[line] = newLine
- # logWarn('\t refDesc: ', refDesc[name])
- # logWarn('\tfile desc: ', pi.desc)
-
- line = line - 1
-
- pageName = baseDir + '/' + os.path.basename(specFile)
- logDiag('Creating output file', pageName)
- fp = open(pageName, 'w', encoding='utf-8')
- fp.writelines(file)
- fp.close()
-
-
-if __name__ == '__main__':
- logDiag('In main!')
-
- baseDir = 'man'
- follow = False
- if (len(sys.argv) > 2):
- baseDir = sys.argv[1]
- for file in sys.argv[2:]:
- insertTags(file, baseDir)
diff --git a/codegen/vulkan/scripts/Retired/realign.py b/codegen/vulkan/scripts/Retired/realign.py
deleted file mode 100755
index c2780d4c..00000000
--- a/codegen/vulkan/scripts/Retired/realign.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# Usage: realign [infile] > outfile
-# Used to realign XML tags in the Vulkan registry after it's operated on by
-# some other filter, since whitespace inside a tag isn't part of the
-# internal representation.
-
-import copy, sys, string, re
-
-def realignXML(fp):
- patterns = [
- [ r'(^ *\<type .*)(category=[\'"]bitmask[\'"].*)', 58 ],
- [ r'(^ *\<enum [bv].*)(name=.*)', 28 ],
- [ r'(^ *\<enum [bv].*)(comment=.*)', 85 ]
- ]
-
- # Assemble compiled expressions to match and alignment columns
- numpat = len(patterns)
- regexp = [ re.compile(patterns[i][0]) for i in range(0,numpat)]
- column = [ patterns[i][1] for i in range(0,numpat)]
-
- lines = fp.readlines()
- for line in lines:
- emitted = False
- for i in range(0,len(patterns)):
- match = regexp[i].match(line)
- if (match):
- if (not emitted):
- #print('# While processing line: ' + line, end='')
- emitted = True
- #print('# matched expression: ' + patterns[i][0])
- #print('# clause 1 = ' + match.group(1))
- #print('# clause 2 = ' + match.group(2))
- line = match.group(1).ljust(column[i]) + match.group(2)
- if (emitted):
- print(line)
- else:
- print(line, end='')
-
-if __name__ == '__main__':
- if (len(sys.argv) > 1):
- realignXML(open(sys.argv[1], 'r', encoding='utf-8'))
- else:
- realignXML(sys.stdin)
diff --git a/codegen/vulkan/scripts/Retired/refDesc.py b/codegen/vulkan/scripts/Retired/refDesc.py
deleted file mode 100644
index be05a4bb..00000000
--- a/codegen/vulkan/scripts/Retired/refDesc.py
+++ /dev/null
@@ -1,356 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2016-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-refDesc = {}
-
-# These are extracted from the original handwritten ref pages
-# This is a one-time measure to inject // refBegin markup into the spec.
-
-refDesc['vkAcquireNextImageKHR'] = 'Retrieve the index of the next available presentable image'
-refDesc['vkAllocateCommandBuffers'] = 'Allocate command buffers from an existing command pool'
-refDesc['vkAllocateDescriptorSets'] = 'Allocate one or more descriptor sets'
-refDesc['vkAllocateMemory'] = 'Allocate GPU memory'
-refDesc['VkAllocationCallbacks'] = 'Structure containing callback function pointers for memory allocation'
-refDesc['vkBeginCommandBuffer'] = 'Start recording a command buffer'
-refDesc['vkBindBufferMemory'] = 'Bind device memory to a buffer object'
-refDesc['vkBindImageMemory'] = 'Bind device memory to an image object'
-refDesc['VkBufferCreateFlags'] = 'Buffer object creation flags'
-refDesc['VkBufferCreateInfo'] = 'Structure specifying the parameters of a newly created buffer object'
-refDesc['VkBufferMemoryBarrier'] = 'Structure specifying the parameters of a buffer memory barrier'
-refDesc['VkBufferUsageFlags'] = 'Buffer object usage flags'
-refDesc['vkCmdBeginQuery'] = 'Begin a query'
-refDesc['vkCmdBeginRenderPass'] = 'Begin a new render pass'
-refDesc['vkCmdBindDescriptorSets'] = 'Binds descriptor sets to a command buffer'
-refDesc['vkCmdBindIndexBuffer'] = 'Bind an index buffer to a command buffer'
-refDesc['vkCmdBindPipeline'] = 'Bind a pipeline object to a command buffer'
-refDesc['vkCmdBindVertexBuffers'] = 'Bind vertex buffers to a command buffer'
-refDesc['vkCmdBlitImage'] = 'Copy regions of an image, potentially performing format conversion,'
-refDesc['vkCmdClearAttachments'] = 'Clear regions within currently bound framebuffer attachments'
-refDesc['vkCmdClearColorImage'] = 'Clear regions of a color image'
-refDesc['vkCmdClearDepthStencilImage'] = 'Fill regions of a combined depth-stencil image'
-refDesc['vkCmdCopyBufferToImage'] = 'Copy data from a buffer into an image'
-refDesc['vkCmdCopyBuffer'] = 'Copy data between buffer regions'
-refDesc['vkCmdCopyImageToBuffer'] = 'Copy image data into a buffer'
-refDesc['vkCmdCopyImage'] = 'Copy data between images'
-refDesc['vkCmdCopyQueryPoolResults'] = 'Copy the results of queries in a query pool to a buffer object'
-refDesc['vkCmdDispatchIndirect'] = 'Dispatch compute work items using indirect parameters'
-refDesc['vkCmdDispatch'] = 'Dispatch compute work items'
-refDesc['vkCmdDrawIndexedIndirect'] = 'Perform an indexed indirect draw'
-refDesc['vkCmdDrawIndexed'] = 'Issue an indexed draw into a command buffer'
-refDesc['vkCmdDrawIndirect'] = 'Issue an indirect draw into a command buffer'
-refDesc['vkCmdDraw'] = 'Draw primitives'
-refDesc['vkCmdEndQuery'] = 'Ends a query'
-refDesc['vkCmdEndRenderPass'] = 'End the current render pass'
-refDesc['vkCmdExecuteCommands'] = 'Execute a secondary command buffer from a primary command buffer'
-refDesc['vkCmdFillBuffer'] = 'Fill a region of a buffer with a fixed value'
-refDesc['vkCmdNextSubpass'] = 'Transition to the next subpass of a render pass'
-refDesc['vkCmdPipelineBarrier'] = 'Insert a set of execution and memory barriers'
-refDesc['vkCmdPushConstants'] = 'Update the values of push constants'
-refDesc['vkCmdResetEvent'] = 'Reset an event object to non-signaled state'
-refDesc['vkCmdResetQueryPool'] = 'Reset queries in a query pool'
-refDesc['vkCmdResolveImage'] = 'Resolve regions of an image'
-refDesc['vkCmdSetBlendConstants'] = 'Set the values of blend constants'
-refDesc['vkCmdSetDepthBias'] = 'Set the depth bias dynamic state'
-refDesc['vkCmdSetDepthBounds'] = 'Set the depth bounds test values for a command buffer'
-refDesc['vkCmdSetEvent'] = 'Set an event object to signaled state'
-refDesc['vkCmdSetLineWidth'] = 'Set the dynamic line width state'
-refDesc['vkCmdSetScissor'] = 'Set the dynamic scissor rectangles on a command buffer'
-refDesc['vkCmdSetStencilCompareMask'] = 'Set the stencil compare mask dynamic state'
-refDesc['vkCmdSetStencilReference'] = 'Set the stencil reference dynamic state'
-refDesc['vkCmdSetStencilWriteMask'] = 'Set the stencil write mask dynamic state'
-refDesc['vkCmdSetViewport'] = 'Set the viewport on a command buffer'
-refDesc['vkCmdUpdateBuffer'] = 'Update a buffer\'s contents from host memory'
-refDesc['vkCmdWaitEvents'] = 'Wait for one or more events and insert a set of memory'
-refDesc['vkCmdWriteTimestamp'] = 'Write a device timestamp into a query object'
-refDesc['VkCommandBufferAllocateInfo'] = 'Structure specifying the allocation parameters for command buffer object'
-refDesc['vkCreateAndroidSurfaceKHR'] = 'Create a slink:VkSurfaceKHR object for an Android native window'
-refDesc['vkCreateBuffer'] = 'Create a new buffer object'
-refDesc['vkCreateBufferView'] = 'Create a new buffer view object'
-refDesc['vkCreateCommandPool'] = 'Create a new command pool object'
-refDesc['vkCreateComputePipelines'] = 'Creates a new compute pipeline object'
-refDesc['vkCreateDescriptorPool'] = 'Creates a descriptor pool object'
-refDesc['vkCreateDescriptorSetLayout'] = 'Create a new descriptor set layout'
-refDesc['vkCreateDevice'] = 'Create a new device instance'
-refDesc['vkCreateDisplayModeKHR'] = 'Create a display mode'
-refDesc['vkCreateDisplayPlaneSurfaceKHR'] = 'Create a slink:VkSurfaceKHR structure representing a display plane and mode'
-refDesc['vkCreateEvent'] = 'Create a new event object'
-refDesc['vkCreateFence'] = 'Create a new fence object'
-refDesc['vkCreateFramebuffer'] = 'Create a new framebuffer object'
-refDesc['vkCreateGraphicsPipelines'] = 'Create graphics pipelines'
-refDesc['vkCreateImage'] = 'Create a new image object'
-refDesc['vkCreateImageView'] = 'Create an image view from an existing image'
-refDesc['vkCreateInstance'] = 'Create a new Vulkan instance'
-refDesc['vkCreateMirSurfaceKHR'] = 'Create a slink:VkSurfaceKHR object for a Mir window'
-refDesc['vkCreatePipelineCache'] = 'Creates a new pipeline cache'
-refDesc['vkCreatePipelineLayout'] = 'Creates a new pipeline layout object'
-refDesc['vkCreateQueryPool'] = 'Create a new query pool object'
-refDesc['vkCreateRenderPass'] = 'Create a new render pass object'
-refDesc['vkCreateSampler'] = 'Create a new sampler object'
-refDesc['vkCreateSemaphore'] = 'Create a new queue semaphore object'
-refDesc['vkCreateShaderModule'] = 'Creates a new shader module object'
-refDesc['vkCreateSharedSwapchainsKHR'] = 'Create multiple swapchains that share presentable images'
-refDesc['vkCreateSwapchainKHR'] = 'Create a swapchain'
-refDesc['vkCreateWaylandSurfaceKHR'] = 'Create a slink:VkSurfaceKHR object for a Wayland window'
-refDesc['vkCreateXcbSurfaceKHR'] = 'Create a slink:VkSurfaceKHR object for a X11 window, using the XCB client-side library'
-refDesc['vkCreateXlibSurfaceKHR'] = 'Create a slink:VkSurfaceKHR object for an X11 window, using the Xlib client-side library'
-refDesc['VkDescriptorSetAllocateInfo'] = 'Structure specifying the allocation parameters for descriptor sets'
-refDesc['VkDescriptorType'] = 'Specifies the type of a descriptor in a descriptor set'
-refDesc['vkDestroyBuffer'] = 'Destroy a buffer object'
-refDesc['vkDestroyBufferView'] = 'Destroy a buffer view object'
-refDesc['vkDestroyCommandPool'] = 'Destroy a command pool object'
-refDesc['vkDestroyDescriptorPool'] = 'Destroy a descriptor pool object'
-refDesc['vkDestroyDescriptorSetLayout'] = 'Destroy a descriptor set layout object'
-refDesc['vkDestroyDevice'] = 'Destroy a logical device'
-refDesc['vkDestroyEvent'] = 'Destroy an event object'
-refDesc['vkDestroyFence'] = 'Destroy a fence object'
-refDesc['vkDestroyFramebuffer'] = 'Destroy a framebuffer object'
-refDesc['vkDestroyImage'] = 'Destroy an image object'
-refDesc['vkDestroyImageView'] = 'Destroy an image view object'
-refDesc['vkDestroyInstance'] = 'Destroy an instance of Vulkan'
-refDesc['vkDestroyPipelineCache'] = 'Destroy a pipeline cache object'
-refDesc['vkDestroyPipelineLayout'] = 'Destroy a pipeline layout object'
-refDesc['vkDestroyPipeline'] = 'Destroy a pipeline object'
-refDesc['vkDestroyQueryPool'] = 'Destroy a query pool object'
-refDesc['vkDestroyRenderPass'] = 'Destroy a render pass object'
-refDesc['vkDestroySampler'] = 'Destroy a sampler object'
-refDesc['vkDestroySemaphore'] = 'Destroy a semaphore object'
-refDesc['vkDestroyShaderModule'] = 'Destroy a shader module'
-refDesc['vkDestroySurfaceKHR'] = 'Destroy a VkSurfaceKHR object'
-refDesc['vkDestroySwapchainKHR'] = 'Destroy a swapchain object'
-refDesc['vkDeviceWaitIdle'] = 'Wait for a device to become idle'
-refDesc['vkEndCommandBuffer'] = 'Finish recording a command buffer'
-refDesc['vkEnumerateDeviceExtensionProperties'] = 'Returns properties of available physical device extensions'
-refDesc['vkEnumerateDeviceLayerProperties'] = 'Returns properties of available physical device layers'
-refDesc['vkEnumerateInstanceExtensionProperties'] = 'Returns up to requested number of global extension properties'
-refDesc['vkEnumerateInstanceLayerProperties'] = 'Returns up to requested number of global layer properties'
-refDesc['vkEnumeratePhysicalDevices'] = 'Enumerates the physical devices accessible to a Vulkan instance'
-refDesc['vkFlushMappedMemoryRanges'] = 'Flush mapped memory ranges'
-refDesc['VkFormatFeatureFlags'] = 'Capability flags of a particular format'
-refDesc['vkFreeCommandBuffers'] = 'Free command buffers'
-refDesc['vkFreeDescriptorSets'] = 'Free one or more descriptor sets'
-refDesc['vkFreeMemory'] = 'Free GPU memory'
-refDesc['vkGetBufferMemoryRequirements'] = 'Returns the memory requirements for specified Vulkan object'
-refDesc['vkGetDeviceMemoryCommitment'] = 'Query the current commitment for a VkDeviceMemory'
-refDesc['vkGetDeviceProcAddr'] = 'Return a function pointer for a command'
-refDesc['vkGetDeviceQueue'] = 'Get a queue handle from a device'
-refDesc['vkGetDisplayModePropertiesKHR'] = 'Query the set of mode properties supported by the display'
-refDesc['vkGetDisplayPlaneCapabilitiesKHR'] = 'Query capabilities of a mode and plane combination'
-refDesc['vkGetDisplayPlaneSupportedDisplaysKHR'] = 'Query the list of displays a plane supports'
-refDesc['vkGetEventStatus'] = 'Retrieve the status of an event object'
-refDesc['vkGetFenceStatus'] = 'Return the status of a fence'
-refDesc['vkGetImageMemoryRequirements'] = 'Returns the memory requirements for specified Vulkan object'
-refDesc['vkGetImageSparseMemoryRequirements'] = 'Query the memory requirements for a sparse image'
-refDesc['vkGetImageSubresourceLayout'] = 'Retrieve information about an image subresource'
-refDesc['vkGetInstanceProcAddr'] = 'Return a function pointer for a command'
-refDesc['vkGetPhysicalDeviceDisplayPlanePropertiesKHR'] = 'Query the plane properties'
-refDesc['vkGetPhysicalDeviceDisplayPropertiesKHR'] = 'Query information about the available displays'
-refDesc['vkGetPhysicalDeviceFeatures'] = 'Reports capabilities of a physical device'
-refDesc['vkGetPhysicalDeviceFormatProperties'] = 'Lists physical device\'s format capabilities'
-refDesc['vkGetPhysicalDeviceImageFormatProperties'] = 'Lists physical device\'s image format capabilities'
-refDesc['vkGetPhysicalDeviceMemoryProperties'] = 'Reports memory information for the specified physical device'
-refDesc['vkGetPhysicalDeviceMirPresentationSupportKHR'] = 'Query physical device for presentation to Mir'
-refDesc['vkGetPhysicalDeviceProperties'] = 'Returns properties of a physical device'
-refDesc['vkGetPhysicalDeviceQueueFamilyProperties'] = 'Reports properties of the queues of the specified physical device'
-refDesc['vkGetPhysicalDeviceSparseImageFormatProperties'] = 'Retrieve properties of an image format applied to sparse images'
-refDesc['vkGetPhysicalDeviceSurfaceCapabilitiesKHR'] = 'Query surface capabilities'
-refDesc['vkGetPhysicalDeviceSurfaceFormatsKHR'] = 'Query color formats supported by surface'
-refDesc['vkGetPhysicalDeviceSurfacePresentModesKHR'] = 'Query supported presentation modes'
-refDesc['vkGetPhysicalDeviceSurfaceSupportKHR'] = 'Query if presentation is supported'
-refDesc['vkGetPhysicalDeviceWaylandPresentationSupportKHR'] = 'Query physical device for presentation to Wayland'
-refDesc['vkGetPhysicalDeviceXcbPresentationSupportKHR'] = 'Query physical device for presentation to X11 server using XCB'
-refDesc['vkGetPhysicalDeviceXlibPresentationSupportKHR'] = 'Query physical device for presentation to X11 server using Xlib'
-refDesc['vkGetPipelineCacheData'] = 'Get the data store from a pipeline cache'
-refDesc['vkGetQueryPoolResults'] = 'Copy results of queries in a query pool to a host memory region'
-refDesc['vkGetRenderAreaGranularity'] = 'Returns the granularity for optimal render area'
-refDesc['vkGetSwapchainImagesKHR'] = 'Obtain the array of presentable images associated with a swapchain'
-refDesc['VkImageCreateFlags'] = 'Image object creation flags'
-refDesc['VkImageCreateInfo'] = 'Structure specifying the parameters of a newly created image object'
-refDesc['VkImageLayout'] = 'Layout of image and image subresources'
-refDesc['VkImageMemoryBarrier'] = 'Structure specifying the parameters of an image memory barrier'
-refDesc['VkImageType'] = 'Specifies the type of an image object'
-refDesc['VkImageUsageFlags'] = 'Image object usage flags'
-refDesc['VkImageViewType'] = 'Image view types'
-refDesc['vkInvalidateMappedMemoryRanges'] = 'Invalidate ranges of mapped memory objects'
-refDesc['vkMapMemory'] = 'Map a memory object into application address space'
-refDesc['VkMemoryAllocateInfo'] = 'Structure containing parameters of a memory allocation'
-refDesc['VkMemoryPropertyFlags'] = 'Memory pool properties'
-refDesc['vkMergePipelineCaches'] = 'Combine the data stores of pipeline caches'
-refDesc['VkPhysicalDeviceFeatures'] = 'Structure describing the fine-grained features that can be supported by an implementation'
-refDesc['VkPhysicalDeviceLimits'] = 'Structure'
-refDesc['VkPipelineLayoutCreateInfo'] = 'Structure specifying the parameters of a newly created pipeline layout object'
-refDesc['VkPipelineStageFlags'] = 'Pipeline stage identifiers'
-refDesc['VkQueryControlFlags'] = 'Query control flags'
-refDesc['VkQueryResultFlags'] = 'Query result flags'
-refDesc['vkQueueBindSparse'] = 'Bind device memory to a sparse resource object'
-refDesc['VkQueueFamilyProperties'] = 'Structure providing information about a queue family'
-refDesc['VkQueueFlags'] = 'Queue capability flags'
-refDesc['vkQueuePresentKHR'] = 'Queue an image for presentation'
-refDesc['vkQueueSubmit'] = 'Submits a sequence of semaphores or command buffers to a queue'
-refDesc['vkQueueWaitIdle'] = 'Wait for a queue to become idle'
-refDesc['vkResetCommandBuffer'] = 'Reset a command buffer'
-refDesc['vkResetCommandPool'] = 'Reset a command pool'
-refDesc['vkResetDescriptorPool'] = 'Resets a descriptor pool object'
-refDesc['vkResetEvent'] = 'Reset an event to non-signaled state'
-refDesc['vkResetFences'] = 'Resets one or more fence objects'
-refDesc['vkSetEvent'] = 'Set an event to signaled state'
-refDesc['VkSharingMode'] = 'Buffer and image sharing modes'
-refDesc['vkUnmapMemory'] = 'Unmap a previously mapped memory object'
-refDesc['vkUpdateDescriptorSets'] = 'Update the contents of a descriptor set object'
-refDesc['vkWaitForFences'] = 'Wait for one or more fences to become signaled'
-refDesc['VkWriteDescriptorSet'] = 'Structure specifying the parameters of a descriptor set write operation'
-refDesc['VkAndroidSurfaceCreateInfoKHR'] = 'Structure specifying parameters of a newly created Android surface object'
-refDesc['VkDebugReportCallbackCreateInfoEXT'] = 'Structure specifying parameters of a newly created debug report object'
-refDesc['VkDisplayModeCreateInfoKHR'] = 'Structure specifying parameters of a newly created display mode object'
-refDesc['VkDisplayModeParametersKHR'] = 'Structure describing display parameters associated with a display mode'
-refDesc['VkDisplayModePropertiesKHR'] = 'Structure describing display mode properties'
-refDesc['VkDisplayPlaneCapabilitiesKHR'] = 'Structure describing capabilities of a mode and plane combination'
-refDesc['VkDisplayPlanePropertiesKHR'] = 'Structure describing display plane properties'
-refDesc['VkDisplayPresentInfoKHR'] = 'Structure describing parameters of a queue presentation to a swapchain'
-refDesc['VkDisplayPropertiesKHR'] = 'Structure describing an available display device'
-refDesc['VkDisplaySurfaceCreateInfoKHR'] = 'Structure specifying parameters of a newly created display plane surface object'
-refDesc['VkMirSurfaceCreateInfoKHR'] = 'Structure specifying parameters of a newly created Mir surface object'
-refDesc['VkPresentInfoKHR'] = 'Structure describing parameters of a queue presentation'
-refDesc['VkSurfaceCapabilitiesKHR'] = 'Structure describing capabilities of a surface'
-refDesc['VkSurfaceFormatKHR'] = 'Structure describing a supported swapchain format-colorspace pair'
-refDesc['VkSwapchainCreateInfoKHR'] = 'Structure specifying parameters of a newly created swapchain object'
-refDesc['VkWaylandSurfaceCreateInfoKHR'] = 'Structure specifying parameters of a newly created Wayland surface object'
-refDesc['VkWin32SurfaceCreateInfoKHR'] = 'Structure specifying parameters of a newly created Win32 surface object'
-refDesc['VkXcbSurfaceCreateInfoKHR'] = 'Structure specifying parameters of a newly created Xcb surface object'
-refDesc['VkXlibSurfaceCreateInfoKHR'] = 'Structure specifying parameters of a newly created Xlib surface object'
-
-# These are generated based on the structure name
-
-refDesc['VkBufferViewCreateInfo'] = 'Structure specifying parameters of a newly created buffer view'
-refDesc['VkCommandPoolCreateInfo'] = 'Structure specifying parameters of a newly created command pool'
-refDesc['VkComputePipelineCreateInfo'] = 'Structure specifying parameters of a newly created compute pipeline'
-refDesc['VkDescriptorPoolCreateInfo'] = 'Structure specifying parameters of a newly created descriptor pool'
-refDesc['VkDescriptorSetLayoutCreateInfo'] = 'Structure specifying parameters of a newly created descriptor set layout'
-refDesc['VkDeviceCreateInfo'] = 'Structure specifying parameters of a newly created device'
-refDesc['VkDeviceQueueCreateInfo'] = 'Structure specifying parameters of a newly created device queue'
-refDesc['VkEventCreateInfo'] = 'Structure specifying parameters of a newly created event'
-refDesc['VkExtent2D'] = 'Structure specifying a two-dimensional extent'
-refDesc['VkExtent3D'] = 'Structure specifying a three-dimensional extent'
-refDesc['VkFenceCreateInfo'] = 'Structure specifying parameters of a newly created fence'
-refDesc['VkFramebufferCreateInfo'] = 'Structure specifying parameters of a newly created framebuffer'
-refDesc['VkGraphicsPipelineCreateInfo'] = 'Structure specifying parameters of a newly created graphics pipeline'
-refDesc['VkImageViewCreateInfo'] = 'Structure specifying parameters of a newly created image view'
-refDesc['VkInstanceCreateInfo'] = 'Structure specifying parameters of a newly created instance'
-refDesc['VkOffset2D'] = 'Structure specifying a two-dimensional offset'
-refDesc['VkOffset3D'] = 'Structure specifying a three-dimensional offset'
-refDesc['VkPipelineCacheCreateInfo'] = 'Structure specifying parameters of a newly created pipeline cache'
-refDesc['VkPipelineColorBlendStateCreateInfo'] = 'Structure specifying parameters of a newly created pipeline color blend state'
-refDesc['VkPipelineDepthStencilStateCreateInfo'] = 'Structure specifying parameters of a newly created pipeline depth stencil state'
-refDesc['VkPipelineDynamicStateCreateInfo'] = 'Structure specifying parameters of a newly created pipeline dynamic state'
-refDesc['VkPipelineInputAssemblyStateCreateInfo'] = 'Structure specifying parameters of a newly created pipeline input assembly state'
-refDesc['VkPipelineMultisampleStateCreateInfo'] = 'Structure specifying parameters of a newly created pipeline multisample state'
-refDesc['VkPipelineRasterizationStateCreateInfo'] = 'Structure specifying parameters of a newly created pipeline rasterization state'
-refDesc['VkPipelineShaderStageCreateInfo'] = 'Structure specifying parameters of a newly created pipeline shader stage'
-refDesc['VkPipelineTessellationStateCreateInfo'] = 'Structure specifying parameters of a newly created pipeline tessellation state'
-refDesc['VkPipelineVertexInputStateCreateInfo'] = 'Structure specifying parameters of a newly created pipeline vertex input state'
-refDesc['VkPipelineViewportStateCreateInfo'] = 'Structure specifying parameters of a newly created pipeline viewport state'
-refDesc['VkQueryPoolCreateInfo'] = 'Structure specifying parameters of a newly created query pool'
-refDesc['VkRect2D'] = 'Structure specifying a two-dimensional subregion'
-refDesc['VkRenderPassCreateInfo'] = 'Structure specifying parameters of a newly created render pass'
-refDesc['VkSamplerCreateInfo'] = 'Structure specifying parameters of a newly created sampler'
-refDesc['VkSemaphoreCreateInfo'] = 'Structure specifying parameters of a newly created semaphore'
-refDesc['VkShaderModuleCreateInfo'] = 'Structure specifying parameters of a newly created shader module'
-
-# These are TBD
-
-refDesc['VkApplicationInfo'] = 'Structure specifying application info'
-refDesc['VkAttachmentDescription'] = 'Structure specifying an attachment description'
-refDesc['VkAttachmentReference'] = 'Structure specifying an attachment reference'
-refDesc['VkBindSparseInfo'] = 'Structure specifying a sparse binding operation'
-refDesc['VkBufferCopy'] = 'Structure specifying a buffer copy operation'
-refDesc['VkBufferImageCopy'] = 'Structure specifying a buffer image copy operation'
-refDesc['VkClearAttachment'] = 'Structure specifying a clear attachment'
-refDesc['VkClearColorValue'] = 'Structure specifying a clear color value'
-refDesc['VkClearDepthStencilValue'] = 'Structure specifying a clear depth stencil value'
-refDesc['VkClearRect'] = 'Structure specifying a clear rectangle'
-refDesc['VkClearValue'] = 'Structure specifying a clear value'
-refDesc['VkCommandBufferBeginInfo'] = 'Structure specifying a command buffer begin operation'
-refDesc['VkCommandBufferInheritanceInfo'] = 'Structure specifying command buffer inheritance info'
-refDesc['VkCommandBufferLevel'] = 'Structure specifying a command buffer level'
-refDesc['VkComponentMapping'] = 'Structure specifying a color component mapping'
-refDesc['VkCopyDescriptorSet'] = 'Structure specifying a copy descriptor set operation'
-refDesc['VkDescriptorBufferInfo'] = 'Structure specifying descriptor buffer info'
-refDesc['VkDescriptorImageInfo'] = 'Structure specifying descriptor image info'
-refDesc['VkDescriptorPoolSize'] = 'Structure specifying descriptor pool size'
-refDesc['VkDescriptorSetLayoutBinding'] = 'Structure specifying a descriptor set layout binding'
-refDesc['VkDispatchIndirectCommand'] = 'Structure specifying a dispatch indirect command'
-refDesc['VkDrawIndexedIndirectCommand'] = 'Structure specifying a draw indexed indirect command'
-refDesc['VkDrawIndirectCommand'] = 'Structure specifying a draw indirect command'
-refDesc['VkExtensionProperties'] = 'Structure specifying a extension properties'
-refDesc['VkFormatProperties'] = 'Structure specifying image format properties'
-refDesc['VkImageBlit'] = 'Structure specifying an image blit operation'
-refDesc['VkImageCopy'] = 'Structure specifying an image copy operation'
-refDesc['VkImageFormatProperties'] = 'Structure specifying a image format properties'
-refDesc['VkImageResolve'] = 'Structure specifying an image resolve operation'
-refDesc['VkImageSubresource'] = 'Structure specifying a image subresource'
-refDesc['VkImageSubresourceLayers'] = 'Structure specifying a image subresource layers'
-refDesc['VkImageSubresourceRange'] = 'Structure specifying a image subresource range'
-refDesc['VkLayerProperties'] = 'Structure specifying layer properties'
-refDesc['VkMappedMemoryRange'] = 'Structure specifying a mapped memory range'
-refDesc['VkMemoryBarrier'] = 'Structure specifying a memory barrier'
-refDesc['VkMemoryHeap'] = 'Structure specifying a memory heap'
-refDesc['VkMemoryRequirements'] = 'Structure specifying memory requirements'
-refDesc['VkMemoryType'] = 'Structure specifying memory type'
-refDesc['VkPhysicalDeviceMemoryProperties'] = 'Structure specifying physical device memory properties'
-refDesc['VkPhysicalDeviceProperties'] = 'Structure specifying physical device properties'
-refDesc['VkPhysicalDeviceSparseProperties'] = 'Structure specifying physical device sparse memory properties'
-refDesc['VkPipelineColorBlendAttachmentState'] = 'Structure specifying a pipeline color blend attachment state'
-refDesc['VkPushConstantRange'] = 'Structure specifying a push constant range'
-refDesc['VkRenderPassBeginInfo'] = 'Structure specifying render pass begin info'
-refDesc['VkSparseBufferMemoryBindInfo'] = 'Structure specifying a sparse buffer memory bind operation'
-refDesc['VkSparseImageFormatProperties'] = 'Structure specifying sparse image format properties'
-refDesc['VkSparseImageMemoryBind'] = 'Structure specifying sparse image memory bind'
-refDesc['VkSparseImageMemoryBindInfo'] = 'Structure specifying sparse image memory bind info'
-refDesc['VkSparseImageMemoryRequirements'] = 'Structure specifying sparse image memory requirements'
-refDesc['VkSparseImageOpaqueMemoryBindInfo'] = 'Structure specifying sparse image opaque memory bind info'
-refDesc['VkSparseMemoryBind'] = 'Structure specifying a sparse memory bind operation'
-refDesc['VkSpecializationInfo'] = 'Structure specifying specialization info'
-refDesc['VkSpecializationMapEntry'] = 'Structure specifying a specialization map entry'
-refDesc['VkStencilOpState'] = 'Structure specifying stencil operation state'
-refDesc['VkSubmitInfo'] = 'Structure specifying a queue submit operation'
-refDesc['VkSubpassDependency'] = 'Structure specifying a subpass dependency'
-refDesc['VkSubpassDescription'] = 'Structure specifying a subpass description'
-refDesc['VkSubresourceLayout'] = 'Structure specifying subresource layout'
-refDesc['VkVertexInputAttributeDescription'] = 'Structure specifying vertex input attribute description'
-refDesc['VkVertexInputBindingDescription'] = 'Structure specifying vertex input binding description'
-refDesc['VkViewport'] = 'Structure specifying a viewport'
-
-# These are constructed from spec text
-
-refDesc['VkAccessFlagBits'] = 'Bitmask specifying classes of memory access the will participate in a memory barrier dependency'
-refDesc['VkAttachmentDescriptionFlagBits'] = 'Bitmask specifying additional properties of an attachment'
-refDesc['VkBufferCreateFlagBits'] = 'Bitmask specifying additional parameters of a buffer'
-refDesc['VkBufferUsageFlagBits'] = 'Bitmask specifying allowed usage of a buffer'
-refDesc['VkColorComponentFlagBits'] = 'Bitmask controlling which components are written to the framebuffer'
-refDesc['VkCommandBufferResetFlagBits'] = 'Bitmask controlling behavior of a command buffer reset'
-refDesc['VkCommandBufferUsageFlagBits'] = 'Bitmask specifying usage behavior for command buffer'
-refDesc['VkCommandPoolCreateFlagBits'] = 'Bitmask specifying usage behavior for a command pool'
-refDesc['VkCommandPoolResetFlagBits'] = 'Bitmask controlling behavior of a command pool reset'
-refDesc['VkCullModeFlagBits'] = 'Bitmask controlling triangle culling'
-refDesc['VkDependencyFlagBits'] = 'Bitmask specifying dependencies between subpasses'
-refDesc['VkDescriptorPoolCreateFlagBits'] = 'Bitmask specifying certain supported operations on a descriptor pool'
-refDesc['VkFenceCreateFlagBits'] = 'Bitmask specifying initial state and behavior of a fence'
-refDesc['VkFormatFeatureFlagBits'] = 'Bitmask specifying features supported by a buffer'
-refDesc['VkImageAspectFlagBits'] = 'Bitmask specifying which aspects of an image are included in a view'
-refDesc['VkImageCreateFlagBits'] = 'Bitmask specifying additional parameters of an image'
-refDesc['VkImageUsageFlagBits'] = 'Bitmask specifying intended usage of an image'
-refDesc['VkMemoryHeapFlagBits'] = 'Bitmask specifying attribute flags for a heap'
-refDesc['VkMemoryPropertyFlagBits'] = 'Bitmask specifying properties for a memory type'
-refDesc['VkPipelineCreateFlagBits'] = 'Bitmask controlling how a pipeline is generated'
-refDesc['VkPipelineStageFlagBits'] = 'Bitmask specifying pipeline stages'
-refDesc['VkQueryControlFlagBits'] = 'Bitmask specifying constraints on a query'
-refDesc['VkQueryPipelineStatisticFlagBits'] = 'Bitmask specifying queried pipeline statistics'
-refDesc['VkQueryResultFlagBits'] = 'Bitmask specifying how and when query results are returned'
-refDesc['VkQueueFlagBits'] = 'Bitmask specifying capabilities of queues in a queue family'
-refDesc['VkSampleCountFlagBits'] = 'Bitmask specifying sample counts supported for an image used for storage operations'
-refDesc['VkShaderStageFlagBits'] = 'Bitmask specifying a pipeline stage'
-refDesc['VkSparseImageFormatFlagBits'] = 'Bitmask specifying additional information about a sparse image resource'
-refDesc['VkSparseMemoryBindFlagBits'] = 'Bitmask specifying usage of a sparse memory binding operation'
-refDesc['VkStencilFaceFlagBits'] = 'Bitmask specifying sets of stencil state for which to update the compare mask'
diff --git a/codegen/vulkan/scripts/__init__.py.docs b/codegen/vulkan/scripts/__init__.py.docs
deleted file mode 100644
index e4c30759..00000000
--- a/codegen/vulkan/scripts/__init__.py.docs
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright 2019-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-"""Scripts for building the Vulkan specification and artifacts."""
-
-# This is only used during doc builds, hence the weird file extension.
-# It messes up scripts at other times.
-
-# __all__ = [
-# "cgenerator",
-# "check_spec_links",
-# "comment_convert",
-# "conventions",
-# "docgenerator",
-# "extensionmetadocgenerator",
-# "generator",
-# "genRef",
-# "genspec",
-# "genvk",
-# "hostsyncgenerator",
-# "indexExt",
-# "make_ext_dependency",
-# "pygenerator",
-# "reflib",
-# "reflow_count",
-# "reflow",
-# "reg",
-# "test_check_spec_links_api_specific",
-# "test_check_spec_links",
-# "test_entity_db",
-# "validitygenerator",
-# "vkconventions",
-# "xml_consistency",
-# "spec_tools",
-# ]
diff --git a/codegen/vulkan/scripts/asciidoctor-chunker/LICENSE b/codegen/vulkan/scripts/asciidoctor-chunker/LICENSE
deleted file mode 100644
index ab602974..00000000
--- a/codegen/vulkan/scripts/asciidoctor-chunker/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2018
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/codegen/vulkan/scripts/asciidoctor-chunker/README.md b/codegen/vulkan/scripts/asciidoctor-chunker/README.md
deleted file mode 100644
index 022c8f1c..00000000
--- a/codegen/vulkan/scripts/asciidoctor-chunker/README.md
+++ /dev/null
@@ -1,123 +0,0 @@
-# asciidoctor-chunker
-
-[![npm version](https://badge.fury.io/js/asciidoctor-chunker.svg)](https://badge.fury.io/js/asciidoctor-chunker)
-[![Node.js CI](https://github.com/wshito/asciidoctor-chunker/actions/workflows/node.js.yml/badge.svg)](https://github.com/wshito/asciidoctor-chunker/actions/workflows/node.js.yml)
-[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
-
-Generates chunked (multi-page) HTML from Asciidoctor's single HTML file with the support of fine-tuned splits by chapters, sections, or any depth of subsections. Here is [the sample output.](http://www.seinan-gu.ac.jp/~shito/asciidoctor/html_chunk/index.html) Each chapter can have different levels of extraction depth. See [What it does](#what-it-does) for details.
-
-## News
-
-- 2021/8/3 [Ver 1.0.4](https://github.com/wshito/asciidoctor-chunker/releases) Added the keyboard shotcuts for the page navigation with arrow keys. Added the accessibility labels on the page navigation for screen readers.
-- 2021/6/25 [Ver 1.0.3](https://github.com/wshito/asciidoctor-chunker/releases) Fixed the security vulnerabilities in the dependencies.
-- 2021/5/9 [Ver 1.0.2](https://github.com/wshito/asciidoctor-chunker/releases) The toc item for the titlepage can be configured with `--titlePage` option (thanks to [@johnthad](https://github.com/johnthad)).
-- 2021/3/17 [Ver 1.0.1](https://github.com/wshito/asciidoctor-chunker/releases) The script contains shebang and can be invoked directly. Published on [npm](https://www.npmjs.com/package/asciidoctor-chunker). You can install via npm. See [Installation](#installation).
-- 2021/2/27 [Ver 1.0.0 Released!](https://github.com/wshito/asciidoctor-chunker/releases)
- - Non opinionated page navigation at the bottom of each page is available.
- - You can insert custom css from the command line with `--css` option.
- - If you have any custom elements inserted in the source html, they are handled in non-strict mode by setting `--no-strictMode` option.
- - Gives warning if no relative links are available in tocs.
- - The current page toc is highlighted and scrolled into view.
-- 2021/2/20 Ver 0.9 is released! This is a complete re-write from the previous Lisp version. **It is re-implemented in JavaScript!** So it is super easy to setup with NodeJS! The fine tuned split options are available. Oh, and it runs a lot faster than the previous version!😊
-- 2021/2/10 Started work on the more enhanced version in `javascript` branch. Please wait a couple of weeks. The new version can control any depth of sections to split. And even more, each chapter can have a different depth extraction level. The new version is written in JavaScript so it will be a lot easier to install!
-- 2018/7/11 Locally linked files with `link` and `script` tags with relative paths are copied to the destination directory keeping the structure of the relative path. So the custom CSS and script files should be properly copied by `asciidoctor-chunker`.
-
-## What it does
-
-Asciidoctor-Chunker generates chunked HTML from a single HTML generated by Asciidoctor.
-
-1. Splits part preambles and chapters (or any depth of section level) into separate files. Each chapter can be configured to have a different depth for extractions.
-1. Extracts css inside the style element into a separate file so the browser can cache and share it among all the pages.
-1. Places footnotes in the file they belong to. This also means that the multiply referred footnotes are placed in every referrer's files and sets the link back to the referrer's id within the page.
-1. Re-writes the relative links in order to point to the appropriate chunked files.
-1. Copies the local images and linked files (with `link`, `script` and `img` tags) whose paths are relative, to the directory relative to the chunked html output. Files are only copied if they are new or modified compared to the previously copied one.
-1. Adds a titlepage link in the toc and page navigation at the bottom of each page.
-1. Adds non-opinionated page navigation.
-1. Highlights the current page toc items and they get scrolled into the viewport.
-
-Here is [the sample output](http://www.seinan-gu.ac.jp/~shito/asciidoctor/html_chunk/index.html) created from the [Asciidoctor User Manual](https://asciidoctor.org/docs/user-manual/). The footer on the sample page is added by setting the asciidoctor attribute and is not added by asciidoctor-chunker.
-
-
-## Installation
-
-Asciidoctor-Chunker is written in JavaScript and runs with NodeJS.
-
-1. Install [Node.js](https://nodejs.org/), the JavaScript runtime. This will install `npm`, the package manager CLI for Node.js.
-1. If you want to install globally, invoke the following;
- ```
- npm install -g asciidoctor-chunker
- ```
- You can install locally under the current directory as;
- ```
- npm install asciidoctor-chunker
- ```
-1. Or alternatively you can download the pre-built program from the [release](https://github.com/wshito/asciidoctor-chunker/releases).
-
-## Usage
-
-If you installed globally:
- ```
- asiidoctor-chunker [single-html-file] -o [output-directory]
- ```
-If you installed locally invoke the following under the directory you installed:
- ```
- npx asciidoctor-chunker [single-html-file] -o [output-directory]
- ```
-If you installed the prebuild program simply run the script as:
- ```
- ./asciidoctor-chunker.js [single-html-file] -o [output-directory]
- ```
-`[single-html-file]` is the single HTML file generated by [Asciidoctor](https://asciidoctor.org) from the book doctype. If the output directory is not specified, the default is `html_chunks` under the current directory.
-
-More discription of usage is available with `--help` option.
-
-## How to Configure the Depth of Extraction
-
-You can list the multiple settings by connecting each specifier with a comma. Each specifier is consisted of either a single number or a collon separated with two numbers.
-
-The single number sets the default level of extraction. Number 1 is the application's default and it extracts the chapter level. Number 2 for section extraction, 3 for subsection, and so on to 6 which is the maximum section level of Asciidoctor.
-
-The list of collon separated numbers, `chap:level`, can change the extraction depth for specific chapters, so `3:2` means chapter 3 is extracted down to 2 levels (ie. section level). You can use a hyphen to specify the range of chapters to set as `chapFrom-chapTo:level`, so `1-3:5` means chapter 1 through 5 should be extracted with the depth level 5.
-
-Example:
-```
- --depth 2 The default level 2, all the chapters and
- sections will be extracted.
- --depth 3,1:2,8:5 The default level 3, level 2 for Chap 1,
- level 5 for Chap 8.
- --depth 1,3-8:2 The default level 1, level 2 for Chap 3 to 8.
- --depth 3-8:3 No default is set so default level is 1, and
- level 3 for chap3 to 8.`
-```
-
-## Custom CSS
-
-By default `asciidoctor-chunker.css` is included in the output directory. It provides the non-opinionated page navigation at the bottom of every chunked page. You can override this by giving a comma separated list of paths to your custom css files. They are copied into the output directory so the paths must be accessible by `asciidoctor-chunker`.
-
-## About Strict Mode
-
-If you have any custom elements inserted under `<div id=#content></div>` in the source single html, `asciidoctor-chunker` ignores it by default. If you want them to be included into the chunked html, set the option `--no-strictMode`.
-The element will be copied to every chunked page.
-
-## Customizing Titlepage
-
-The `index.html` created by `asciidoctor-chunker` is selected by clicking the word **Titlepage** in the table of contents. To change the default value, use the option `--titlePage [string]` where `[string]` is the desired text.
-
-## Example
-
-The project contains the `example` directory where you can generate the chunked html for the [Asciidoctor User Manual](https://asciidoctor.org/docs/user-manual/) by invoking `make`. Simply go into the `example` directory and invoke `make`. This will clone the asciidoctor project from the github for the first time, then the chunked html will be generated under `test/output-chunk/html_chunk/` directory. The `index.html` is the first page.
-
-```
-$ cd example
-$ make
-```
-
-## License
-
-MIT
-
-## Developer's Memo
-
-- Unit test uses `test/resources/output/single/sample.html` generated from `test/resources/sample.adoc`.
-- `npm install cheerio commander`
-- `npm install --save-dev ava webpack webpack-cli webpack-shebang-plugin`
diff --git a/codegen/vulkan/scripts/asciidoctor-chunker/asciidoctor-chunker.js b/codegen/vulkan/scripts/asciidoctor-chunker/asciidoctor-chunker.js
deleted file mode 100755
index dd35f4e9..00000000
--- a/codegen/vulkan/scripts/asciidoctor-chunker/asciidoctor-chunker.js
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/env node
-
-/*! For license information please see asciidoctor-chunker.js.LICENSE.txt */
-(()=>{var e,t,n={1073:e=>{e.exports={trueFunc:function(){return!0},falseFunc:function(){return!1}}},9125:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.groupSelectors=t.getDocumentRoot=void 0;var r=n(2515);t.getDocumentRoot=function(e){for(;e.parent;)e=e.parent;return e},t.groupSelectors=function(e){for(var t=[],n=[],i=0,s=e;i<s.length;i++){var o=s[i];o.some(r.isFilter)?t.push(o):n.push(o)}return[n,t]}},7248:function(e,t,n){"use strict";var r=this&&this.__assign||function(){return(r=Object.assign||function(e){for(var t,n=1,r=arguments.length;n<r;n++)for(var i in t=arguments[n])Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e}).apply(this,arguments)},i=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n),Object.defineProperty(e,r,{enumerable:!0,get:function(){return t[n]}})}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&i(t,e,n);return s(t,e),t},a=this&&this.__spreadArray||function(e,t){for(var n=0,r=t.length,i=e.length;n<r;n++,i++)e[i]=t[n];return e};Object.defineProperty(t,"__esModule",{value:!0}),t.select=t.filter=t.some=t.is=t.aliases=t.pseudos=t.filters=void 0;var c=n(9751),l=n(5366),u=o(n(9432)),h=n(9125),p=n(2515),d=n(5366);Object.defineProperty(t,"filters",{enumerable:!0,get:function(){return d.filters}}),Object.defineProperty(t,"pseudos",{enumerable:!0,get:function(){return d.pseudos}}),Object.defineProperty(t,"aliases",{enumerable:!0,get:function(){return d.aliases}});var f={type:"pseudo",name:"scope",data:null},m=r({},f),T={type:"universal",namespace:null};function E(e,t,n){if(void 0===n&&(n={}),"function"==typeof t)return e.some(t);var r=h.groupSelectors(c.parse(t,n)),i=r[0],s=r[1];return i.length>0&&e.some(l._compileToken(i,n))||s.some((function(t){return g(t,e,n).length>0}))}function _(e,t,n){if(0===t.length)return[];var r,i=h.groupSelectors(e),s=i[0],o=i[1];if(s.length){var a=S(t,s,n);if(0===o.length)return a;a.length&&(r=new Set(a))}for(var c=0;c<o.length&&(null==r?void 0:r.size)!==t.length;c++){var l=o[c];if(0===(r?t.filter((function(e){return u.isTag(e)&&!r.has(e)})):t).length)break;if((a=g(l,t,n)).length)if(r)a.forEach((function(e){return r.add(e)}));else{if(c===o.length-1)return a;r=new Set(a)}}return void 0!==r?r.size===t.length?t:t.filter((function(e){return r.has(e)})):[]}function g(e,t,n){var r;return e.some(c.isTraversal)?v(null!==(r=n.root)&&void 0!==r?r:h.getDocumentRoot(t[0]),a(a([],e),[m]),n,!0,t):v(t,e,n,!1)}t.is=function(e,t,n){return void 0===n&&(n={}),E([e],t,n)},t.some=E,t.filter=function(e,t,n){return void 0===n&&(n={}),_(c.parse(e,n),t,n)},t.select=function(e,t,n){if(void 0===n&&(n={}),"function"==typeof e)return b(t,e);var r=h.groupSelectors(c.parse(e,n)),i=r[0],s=r[1].map((function(e){return v(t,e,n,!0)}));return i.length&&s.push(O(t,i,n,1/0)),1===s.length?s[0]:u.uniqueSort(s.reduce((function(e,t){return a(a([],e),t)})))};var A=new Set(["descendant","adjacent"]);function C(e){return e!==f&&"pseudo"===e.type&&("scope"===e.name||Array.isArray(e.data)&&e.data.some((function(e){return e.some(C)})))}function N(e,t,n){return n&&e.some(C)?r(r({},t),{context:n}):t}function v(e,t,n,r,i){var s=t.findIndex(p.isFilter),o=t.slice(0,s),a=t[s],l=p.getLimit(a.name,a.data);if(0===l)return[];var h=N(o,n,i),d=(0!==o.length||Array.isArray(e)?0===o.length||1===o.length&&o[0]===f?(Array.isArray(e)?e:[e]).filter(u.isTag):r||o.some(c.isTraversal)?O(e,[o],h,l):S(e,[o],h):u.getChildren(e).filter(u.isTag)).slice(0,l),m=function(e,t,n,r){var i="string"==typeof n?parseInt(n,10):NaN;switch(e){case"first":case"lt":return t;case"last":return t.length>0?[t[t.length-1]]:t;case"nth":case"eq":return isFinite(i)&&Math.abs(i)<t.length?[i<0?t[t.length+i]:t[i]]:[];case"gt":return isFinite(i)?t.slice(i+1):[];case"even":return t.filter((function(e,t){return t%2==0}));case"odd":return t.filter((function(e,t){return t%2==1}));case"not":var s=new Set(_(n,t,r));return t.filter((function(e){return!s.has(e)}))}}(a.name,d,a.data,n);if(0===m.length||t.length===s+1)return m;var E=t.slice(s+1),g=E.some(c.isTraversal),C=N(E,n,i);return g&&(A.has(E[0].type)&&E.unshift(T),E.unshift(f)),E.some(p.isFilter)?v(m,E,n,!1,i):g?O(m,[E],C,1/0):S(m,[E],C)}function O(e,t,n,r){return 0===r?[]:b(e,l._compileToken(t,n,e),r)}function b(e,t,n){void 0===n&&(n=1/0);var r=l.prepareContext(e,u,t.shouldTestNextSiblings);return u.find((function(e){return u.isTag(e)&&t(e)}),r,!0,n)}function S(e,t,n){var r=(Array.isArray(e)?e:[e]).filter(u.isTag);if(0===r.length)return r;var i=l._compileToken(t,n);return r.filter(i)}},2515:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getLimit=t.isFilter=t.filterNames=void 0,t.filterNames=new Set(["first","last","eq","gt","nth","lt","even","odd"]),t.isFilter=function e(n){return"pseudo"===n.type&&(!!t.filterNames.has(n.name)||!("not"!==n.name||!Array.isArray(n.data))&&n.data.some((function(t){return t.some(e)})))},t.getLimit=function(e,t){var n=null!=t?parseInt(t,10):NaN;switch(e){case"first":return 1;case"nth":case"eq":return isFinite(n)?n>=0?n+1:1/0:0;case"lt":return isFinite(n)?n>=0?n:1/0:0;case"gt":return isFinite(n)?1/0:0;default:return 1/0}}},6451:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.toggleClass=t.removeClass=t.addClass=t.hasClass=t.removeAttr=t.val=t.data=t.prop=t.attr=void 0;var r=n(6634),i=n(5633),s=Object.prototype.hasOwnProperty,o=/\s+/,a="data-",c={null:null,true:!0,false:!1},l=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,u=/^{[^]*}$|^\[[^]*]$/;function h(e,t,n){var o;if(e&&i.isTag(e))return null!==(o=e.attribs)&&void 0!==o||(e.attribs={}),t?s.call(e.attribs,t)?!n&&l.test(t)?t:e.attribs[t]:"option"===e.name&&"value"===t?r.text(e.children):"input"!==e.name||"radio"!==e.attribs.type&&"checkbox"!==e.attribs.type||"value"!==t?void 0:"on":e.attribs}function p(e,t,n){null===n?E(e,t):e.attribs[t]=""+n}function d(e,t,n){if(e&&i.isTag(e))return t in e?e[t]:!n&&l.test(t)?void 0!==h(e,t,!1):h(e,t,n)}function f(e,t,n,r){t in e?e[t]=n:p(e,t,!r&&l.test(t)?n?"":null:""+n)}function m(e,t,n){var r,i=e;null!==(r=i.data)&&void 0!==r||(i.data={}),"object"==typeof t?Object.assign(i.data,t):"string"==typeof t&&void 0!==n&&(i.data[t]=n)}function T(e,t){var n,r,o;null==t?r=(n=Object.keys(e.attribs).filter((function(e){return e.startsWith(a)}))).map((function(e){return i.camelCase(e.slice(a.length))})):(n=[a+i.cssCase(t)],r=[t]);for(var l=0;l<n.length;++l){var h=n[l],p=r[l];if(s.call(e.attribs,h)&&!s.call(e.data,p)){if(o=e.attribs[h],s.call(c,o))o=c[o];else if(o===String(Number(o)))o=Number(o);else if(u.test(o))try{o=JSON.parse(o)}catch(e){}e.data[p]=o}}return null==t?e.data:o}function E(e,t){e.attribs&&s.call(e.attribs,t)&&delete e.attribs[t]}function _(e){return e?e.trim().split(o):[]}t.attr=function(e,t){if("object"==typeof e||void 0!==t){if("function"==typeof t){if("string"!=typeof e)throw new Error("Bad combination of arguments.");return i.domEach(this,(function(n,r){i.isTag(n)&&p(n,e,t.call(n,r,n.attribs[e]))}))}return i.domEach(this,(function(n){i.isTag(n)&&("object"==typeof e?Object.keys(e).forEach((function(t){var r=e[t];p(n,t,r)})):p(n,e,t))}))}return arguments.length>1?this:h(this[0],e,this.options.xmlMode)},t.prop=function(e,t){var n=this;if("string"==typeof e&&void 0===t)switch(e){case"style":var r=this.css(),s=Object.keys(r);return s.forEach((function(e,t){r[t]=e})),r.length=s.length,r;case"tagName":case"nodeName":var o=this[0];return i.isTag(o)?o.name.toUpperCase():void 0;case"outerHTML":return this.clone().wrap("<container />").parent().html();case"innerHTML":return this.html();default:return d(this[0],e,this.options.xmlMode)}if("object"==typeof e||void 0!==t){if("function"==typeof t){if("object"==typeof e)throw new Error("Bad combination of arguments.");return i.domEach(this,(function(r,s){i.isTag(r)&&f(r,e,t.call(r,s,d(r,e,n.options.xmlMode)),n.options.xmlMode)}))}return i.domEach(this,(function(r){i.isTag(r)&&("object"==typeof e?Object.keys(e).forEach((function(t){var i=e[t];f(r,t,i,n.options.xmlMode)})):f(r,e,t,n.options.xmlMode))}))}},t.data=function(e,t){var n,r=this[0];if(r&&i.isTag(r)){var o=r;return null!==(n=o.data)&&void 0!==n||(o.data={}),e?"object"==typeof e||void 0!==t?(i.domEach(this,(function(n){i.isTag(n)&&("object"==typeof e?m(n,e):m(n,e,t))})),this):s.call(o.data,e)?o.data[e]:T(o,e):T(o)}},t.val=function(e){var t=0===arguments.length,n=this[0];if(!n||!i.isTag(n))return t?void 0:this;switch(n.name){case"textarea":return this.text(e);case"select":var s=this.find("option:selected");if(!t){if(null==this.attr("multiple")&&"object"==typeof e)return this;this.find("option").removeAttr("selected");for(var o="object"!=typeof e?[e]:e,a=0;a<o.length;a++)this.find('option[value="'+o[a]+'"]').attr("selected","");return this}return this.attr("multiple")?s.toArray().map((function(e){return r.text(e.children)})):s.attr("value");case"input":case"option":return t?this.attr("value"):this.attr("value",e)}},t.removeAttr=function(e){for(var t=_(e),n=function(e){i.domEach(r,(function(n){i.isTag(n)&&E(n,t[e])}))},r=this,s=0;s<t.length;s++)n(s);return this},t.hasClass=function(e){return this.toArray().some((function(t){var n=i.isTag(t)&&t.attribs.class,r=-1;if(n&&e.length)for(;(r=n.indexOf(e,r+1))>-1;){var s=r+e.length;if((0===r||o.test(n[r-1]))&&(s===n.length||o.test(n[s])))return!0}return!1}))},t.addClass=function e(t){if("function"==typeof t)return i.domEach(this,(function(n,r){if(i.isTag(n)){var s=n.attribs.class||"";e.call([n],t.call(n,r,s))}}));if(!t||"string"!=typeof t)return this;for(var n=t.split(o),r=this.length,s=0;s<r;s++){var a=this[s];if(i.isTag(a)){var c=h(a,"class",!1);if(c){for(var l=" "+c+" ",u=0;u<n.length;u++){var d=n[u]+" ";l.includes(" "+d)||(l+=d)}p(a,"class",l.trim())}else p(a,"class",n.join(" ").trim())}}return this},t.removeClass=function e(t){if("function"==typeof t)return i.domEach(this,(function(n,r){i.isTag(n)&&e.call([n],t.call(n,r,n.attribs.class||""))}));var n=_(t),r=n.length,s=0===arguments.length;return i.domEach(this,(function(e){if(i.isTag(e))if(s)e.attribs.class="";else{for(var t=_(e.attribs.class),o=!1,a=0;a<r;a++){var c=t.indexOf(n[a]);c>=0&&(t.splice(c,1),o=!0,a--)}o&&(e.attribs.class=t.join(" "))}}))},t.toggleClass=function e(t,n){if("function"==typeof t)return i.domEach(this,(function(r,s){i.isTag(r)&&e.call([r],t.call(r,s,r.attribs.class||"",n),n)}));if(!t||"string"!=typeof t)return this;for(var r=t.split(o),s=r.length,a="boolean"==typeof n?n?1:-1:0,c=this.length,l=0;l<c;l++){var u=this[l];if(i.isTag(u)){for(var h=_(u.attribs.class),p=0;p<s;p++){var d=h.indexOf(r[p]);a>=0&&d<0?h.push(r[p]):a<=0&&d>=0&&h.splice(d,1)}u.attribs.class=h.join(" ")}}return this}},9806:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.css=void 0;var r=n(5633);function i(e,t,n,r){if("string"==typeof t){var o=s(e),a="function"==typeof n?n.call(e,r,o[t]):n;""===a?delete o[t]:null!=a&&(o[t]=a),e.attribs.style=(c=o,Object.keys(c).reduce((function(e,t){return e+(e?" ":"")+t+": "+c[t]+";"}),""))}else"object"==typeof t&&Object.keys(t).forEach((function(n,r){i(e,n,t[n],r)}));var c}function s(e,t){if(e&&r.isTag(e)){var n=function(e){return(e=(e||"").trim())?e.split(";").reduce((function(e,t){var n=t.indexOf(":");return n<1||n===t.length-1||(e[t.slice(0,n).trim()]=t.slice(n+1).trim()),e}),{}):{}}(e.attribs.style);if("string"==typeof t)return n[t];if(Array.isArray(t)){var i={};return t.forEach((function(e){null!=n[e]&&(i[e]=n[e])})),i}return n}}t.css=function(e,t){return null!=e&&null!=t||"object"==typeof e&&!Array.isArray(e)?r.domEach(this,(function(n,s){r.isTag(n)&&i(n,e,t,s)})):s(this[0],e)}},3432:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.serializeArray=t.serialize=void 0;var r=n(5633),i="input,select,textarea,keygen",s=/%20/g,o=/\r?\n/g;t.serialize=function(){return this.serializeArray().map((function(e){return encodeURIComponent(e.name)+"="+encodeURIComponent(e.value)})).join("&").replace(s,"+")},t.serializeArray=function(){var e=this;return this.map((function(t,n){var s=e._make(n);return r.isTag(n)&&"form"===n.name?s.find(i).toArray():s.filter(i).toArray()})).filter('[name!=""]:enabled:not(:submit, :button, :image, :reset, :file):matches([checked], :not(:checkbox, :radio))').map((function(t,n){var r,i=e._make(n),s=i.attr("name"),a=null!==(r=i.val())&&void 0!==r?r:"";return Array.isArray(a)?a.map((function(e){return{name:s,value:e.replace(o,"\r\n")}})):{name:s,value:a.replace(o,"\r\n")}})).toArray()}},848:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.clone=t.text=t.toString=t.html=t.empty=t.replaceWith=t.remove=t.insertBefore=t.before=t.insertAfter=t.after=t.wrapAll=t.unwrap=t.wrapInner=t.wrap=t.prepend=t.append=t.prependTo=t.appendTo=t._makeDomArray=void 0;var r=n(9698),i=n(7915),s=n(7915),o=r.__importStar(n(5012)),a=n(6634),c=n(5633),l=n(3719);function u(e){return function(){for(var t=this,n=[],r=0;r<arguments.length;r++)n[r]=arguments[r];var s=this.length-1;return c.domEach(this,(function(r,o){if(i.hasChildren(r)){var c="function"==typeof n[0]?n[0].call(r,o,a.html(r.children)):n,l=t._makeDomArray(c,o<s);e(l,r.children,r)}}))}}function h(e,t,n,i,s){for(var o,a,c=r.__spreadArray([t,n],i),l=e[t-1]||null,u=e[t+n]||null,h=0;h<i.length;++h){var p=i[h],d=p.parent;if(d){var f=d.children.indexOf(i[h]);f>-1&&(d.children.splice(f,1),s===d&&t>f&&c[0]--)}p.parent=s,p.prev&&(p.prev.next=null!==(o=p.next)&&void 0!==o?o:null),p.next&&(p.next.prev=null!==(a=p.prev)&&void 0!==a?a:null),p.prev=i[h-1]||l,p.next=i[h+1]||u}return l&&(l.next=i[0]),u&&(u.prev=i[i.length-1]),e.splice.apply(e,c)}function p(e){return function(t){for(var n=this.length-1,r=this.parents().last(),i=0;i<this.length;i++){var s=this[i],o="function"==typeof t?t.call(s,i,s):"string"!=typeof t||c.isHtml(t)?t:r.find(t).clone(),a=this._makeDomArray(o,i<n)[0];if(a&&l.DomUtils.hasChildren(a)){for(var u=a,h=0;h<u.children.length;){var p=u.children[h];c.isTag(p)?(u=p,h=0):h++}e(s,u,[a])}}return this}}t._makeDomArray=function(e,t){var n=this;return null==e?[]:c.isCheerio(e)?t?c.cloneDom(e.get()):e.get():Array.isArray(e)?e.reduce((function(e,r){return e.concat(n._makeDomArray(r,t))}),[]):"string"==typeof e?o.default(e,this.options,!1).children:t?c.cloneDom([e]):[e]},t.appendTo=function(e){return(c.isCheerio(e)?e:this._make(e)).append(this),this},t.prependTo=function(e){return(c.isCheerio(e)?e:this._make(e)).prepend(this),this},t.append=u((function(e,t,n){h(t,t.length,0,e,n)})),t.prepend=u((function(e,t,n){h(t,0,0,e,n)})),t.wrap=p((function(e,t,n){var r=e.parent;if(r){var i=r.children,s=i.indexOf(e);o.update([e],t),h(i,s,0,n,r)}})),t.wrapInner=p((function(e,t,n){i.hasChildren(e)&&(o.update(e.children,t),o.update(n,e))})),t.unwrap=function(e){var t=this;return this.parent(e).not("body").each((function(e,n){t._make(n).replaceWith(n.children)})),this},t.wrapAll=function(e){var t=this[0];if(t){for(var n=this._make("function"==typeof e?e.call(t,0,t):e).insertBefore(t),r=void 0,i=0;i<n.length;i++)"tag"===n[i].type&&(r=n[i]);for(var s=0;r&&s<r.children.length;){var o=r.children[s];"tag"===o.type?(r=o,s=0):s++}r&&this._make(r).append(this)}return this},t.after=function(){for(var e=this,t=[],n=0;n<arguments.length;n++)t[n]=arguments[n];var r=this.length-1;return c.domEach(this,(function(n,i){var s=n.parent;if(l.DomUtils.hasChildren(n)&&s){var o=s.children,c=o.indexOf(n);if(!(c<0)){var u="function"==typeof t[0]?t[0].call(n,i,a.html(n.children)):t;h(o,c+1,0,e._makeDomArray(u,i<r),s)}}}))},t.insertAfter=function(e){var t=this;"string"==typeof e&&(e=this._make(e)),this.remove();var n=[];return this._makeDomArray(e).forEach((function(e){var r=t.clone().toArray(),i=e.parent;if(i){var s=i.children,o=s.indexOf(e);o<0||(h(s,o+1,0,r,i),n.push.apply(n,r))}})),this._make(n)},t.before=function(){for(var e=this,t=[],n=0;n<arguments.length;n++)t[n]=arguments[n];var r=this.length-1;return c.domEach(this,(function(n,i){var s=n.parent;if(l.DomUtils.hasChildren(n)&&s){var o=s.children,c=o.indexOf(n);if(!(c<0)){var u="function"==typeof t[0]?t[0].call(n,i,a.html(n.children)):t;h(o,c,0,e._makeDomArray(u,i<r),s)}}}))},t.insertBefore=function(e){var t=this,n=this._make(e);this.remove();var r=[];return c.domEach(n,(function(e){var n=t.clone().toArray(),i=e.parent;if(i){var s=i.children,o=s.indexOf(e);o<0||(h(s,o,0,n,i),r.push.apply(r,n))}})),this._make(r)},t.remove=function(e){var t=e?this.filter(e):this;return c.domEach(t,(function(e){l.DomUtils.removeElement(e),e.prev=e.next=e.parent=null})),this},t.replaceWith=function(e){var t=this;return c.domEach(this,(function(n,r){var i=n.parent;if(i){var s=i.children,a="function"==typeof e?e.call(n,r,n):e,c=t._makeDomArray(a);o.update(c,null);var l=s.indexOf(n);h(s,l,1,c,i),c.includes(n)||(n.parent=n.prev=n.next=null)}}))},t.empty=function(){return c.domEach(this,(function(e){l.DomUtils.hasChildren(e)&&(e.children.forEach((function(e){e.next=e.prev=e.parent=null})),e.children.length=0)}))},t.html=function(e){if(void 0===e){var t=this[0];return t&&l.DomUtils.hasChildren(t)?a.html(t.children,this.options):null}var n=r.__assign(r.__assign({},this.options),{context:null});return c.domEach(this,(function(t){if(l.DomUtils.hasChildren(t)){t.children.forEach((function(e){e.next=e.prev=e.parent=null})),n.context=t;var r=c.isCheerio(e)?e.toArray():o.default(""+e,n,!1).children;o.update(r,t)}}))},t.toString=function(){return a.html(this,this.options)},t.text=function e(t){var n=this;return void 0===t?a.text(this):"function"==typeof t?c.domEach(this,(function(r,i){e.call(n._make(r),t.call(r,i,a.text([r])))})):c.domEach(this,(function(e){if(l.DomUtils.hasChildren(e)){e.children.forEach((function(e){e.next=e.prev=e.parent=null}));var n=new s.Text(t);o.update(n,e)}}))},t.clone=function(){return this._make(c.cloneDom(this.get()))}},1042:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.addBack=t.add=t.end=t.slice=t.index=t.toArray=t.get=t.eq=t.last=t.first=t.has=t.not=t.is=t.filterArray=t.filter=t.map=t.each=t.contents=t.children=t.siblings=t.prevUntil=t.prevAll=t.prev=t.nextUntil=t.nextAll=t.next=t.closest=t.parentsUntil=t.parents=t.parent=t.find=void 0;var r=n(9698),i=n(7915),s=r.__importStar(n(7248)),o=n(5633),a=n(6634),c=n(3719),l=c.DomUtils.uniqueSort,u=/^\s*[~+]/;function h(e){return function(t){for(var n=[],r=1;r<arguments.length;r++)n[r-1]=arguments[r];return function(r){var i,s=e(t,this);return r&&(s=E(s,r,this.options.xmlMode,null===(i=this._root)||void 0===i?void 0:i[0])),this._make(this.length>1&&s.length>1?n.reduce((function(e,t){return t(e)}),s):s)}}}t.find=function(e){var t;if(!e)return this._make([]);var n=this.toArray();if("string"!=typeof e){var r=o.isCheerio(e)?e.toArray():[e];return this._make(r.filter((function(e){return n.some((function(t){return a.contains(t,e)}))})))}var i=u.test(e)?n:this.children().toArray(),c={context:n,root:null===(t=this._root)||void 0===t?void 0:t[0],xmlMode:this.options.xmlMode};return this._make(s.select(e,i,c))};var p=h((function(e,t){for(var n,r=[],i=0;i<t.length;i++){var s=e(t[i]);r.push(s)}return(n=new Array).concat.apply(n,r)})),d=h((function(e,t){for(var n=[],r=0;r<t.length;r++){var i=e(t[r]);null!==i&&n.push(i)}return n}));function f(e){for(var t=[],n=1;n<arguments.length;n++)t[n-1]=arguments[n];var i=null,a=h((function(e,t){var n=[];return o.domEach(t,(function(t){for(var r;(r=e(t))&&!(null==i?void 0:i(r,n.length));t=r)n.push(r)})),n})).apply(void 0,r.__spreadArray([e],t));return function(e,t){var n=this;i="string"==typeof e?function(t){return s.is(t,e,n.options)}:e?T(e):null;var r=a.call(this,t);return i=null,r}}function m(e){return Array.from(new Set(e))}function T(e){return"function"==typeof e?function(t,n){return e.call(t,n,t)}:o.isCheerio(e)?function(t){return Array.prototype.includes.call(e,t)}:function(t){return e===t}}function E(e,t,n,r){return"string"==typeof t?s.filter(t,e,{xmlMode:n,root:r}):e.filter(T(t))}t.parent=d((function(e){var t=e.parent;return t&&!i.isDocument(t)?t:null}),m),t.parents=p((function(e){for(var t=[];e.parent&&!i.isDocument(e.parent);)t.push(e.parent),e=e.parent;return t}),l,(function(e){return e.reverse()})),t.parentsUntil=f((function(e){var t=e.parent;return t&&!i.isDocument(t)?t:null}),l,(function(e){return e.reverse()})),t.closest=function(e){var t=this,n=[];return e?(o.domEach(this,(function(r){for(var i;r&&"root"!==r.type;){if(!e||E([r],e,t.options.xmlMode,null===(i=t._root)||void 0===i?void 0:i[0]).length){r&&!n.includes(r)&&n.push(r);break}r=r.parent}})),this._make(n)):this._make(n)},t.next=d((function(e){return c.DomUtils.nextElementSibling(e)})),t.nextAll=p((function(e){for(var t=[];e.next;)e=e.next,o.isTag(e)&&t.push(e);return t}),m),t.nextUntil=f((function(e){return c.DomUtils.nextElementSibling(e)}),m),t.prev=d((function(e){return c.DomUtils.prevElementSibling(e)})),t.prevAll=p((function(e){for(var t=[];e.prev;)e=e.prev,o.isTag(e)&&t.push(e);return t}),m),t.prevUntil=f((function(e){return c.DomUtils.prevElementSibling(e)}),m),t.siblings=p((function(e){return c.DomUtils.getSiblings(e).filter((function(t){return o.isTag(t)&&t!==e}))}),l),t.children=p((function(e){return c.DomUtils.getChildren(e).filter(o.isTag)}),m),t.contents=function(){var e=this.toArray().reduce((function(e,t){return i.hasChildren(t)?e.concat(t.children):e}),[]);return this._make(e)},t.each=function(e){for(var t=0,n=this.length;t<n&&!1!==e.call(this[t],t,this[t]);)++t;return this},t.map=function(e){for(var t=[],n=0;n<this.length;n++){var r=this[n],i=e.call(r,n,r);null!=i&&(t=t.concat(i))}return this._make(t)},t.filter=function(e){var t;return this._make(E(this.toArray(),e,this.options.xmlMode,null===(t=this._root)||void 0===t?void 0:t[0]))},t.filterArray=E,t.is=function(e){var t=this.toArray();return"string"==typeof e?s.some(t.filter(o.isTag),e,this.options):!!e&&t.some(T(e))},t.not=function(e){var t=this.toArray();if("string"==typeof e){var n=new Set(s.filter(e,t,this.options));t=t.filter((function(e){return!n.has(e)}))}else{var r=T(e);t=t.filter((function(e,t){return!r(e,t)}))}return this._make(t)},t.has=function(e){var t=this;return this.filter("string"==typeof e?":has("+e+")":function(n,r){return t._make(r).find(e).length>0})},t.first=function(){return this.length>1?this._make(this[0]):this},t.last=function(){return this.length>0?this._make(this[this.length-1]):this},t.eq=function(e){var t;return 0==(e=+e)&&this.length<=1?this:(e<0&&(e=this.length+e),this._make(null!==(t=this[e])&&void 0!==t?t:[]))},t.get=function(e){return null==e?this.toArray():this[e<0?this.length+e:e]},t.toArray=function(){return Array.prototype.slice.call(this)},t.index=function(e){var t,n;return null==e?(t=this.parent().children(),n=this[0]):"string"==typeof e?(t=this._make(e),n=this[0]):(t=this,n=o.isCheerio(e)?e[0]:e),Array.prototype.indexOf.call(t,n)},t.slice=function(e,t){return this._make(Array.prototype.slice.call(this,e,t))},t.end=function(){var e;return null!==(e=this.prevObject)&&void 0!==e?e:this._make([])},t.add=function(e,t){var n=this._make(e,t),i=l(r.__spreadArray(r.__spreadArray([],this.get()),n.get()));return this._make(i)},t.addBack=function(e){return this.prevObject?this.add(e?this.prevObject.filter(e):this.prevObject):this}},7911:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Cheerio=void 0;var r=n(9698),i=r.__importDefault(n(5012)),s=r.__importDefault(n(2754)),o=n(5633),a=r.__importStar(n(6451)),c=r.__importStar(n(1042)),l=r.__importStar(n(848)),u=r.__importStar(n(9806)),h=r.__importStar(n(3432)),p=function(){function e(e,t,n,r){var a=this;if(void 0===r&&(r=s.default),this.length=0,this.options=r,!e)return this;if(n&&("string"==typeof n&&(n=i.default(n,this.options,!1)),this._root=new this.constructor(n,null,null,this.options),this._root._root=this._root),o.isCheerio(e))return e;var c,l="string"==typeof e&&o.isHtml(e)?i.default(e,this.options,!1).children:(c=e).name||"root"===c.type||"text"===c.type||"comment"===c.type?[e]:Array.isArray(e)?e:null;if(l)return l.forEach((function(e,t){a[t]=e})),this.length=l.length,this;var u=e,h=t?"string"==typeof t?o.isHtml(t)?this._make(i.default(t,this.options,!1)):(u=t+" "+u,this._root):o.isCheerio(t)?t:this._make(t):this._root;return h?h.find(u):this}return e.prototype._make=function(e,t){var n=new this.constructor(e,t,this._root,this.options);return n.prevObject=this,n},e}();t.Cheerio=p,p.prototype.cheerio="[cheerio object]",p.prototype.splice=Array.prototype.splice,p.prototype[Symbol.iterator]=Array.prototype[Symbol.iterator],Object.assign(p.prototype,a,c,l,u,h)},7503:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.root=t.parseHTML=t.merge=t.contains=void 0;var r=n(9698);r.__exportStar(n(8701),t),r.__exportStar(n(3434),t);var i=n(3434);t.default=i.load([]);var s=r.__importStar(n(6634));t.contains=s.contains,t.merge=s.merge,t.parseHTML=s.parseHTML,t.root=s.root},3434:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.load=void 0;var r=n(9698),i=r.__importStar(n(2754)),s=r.__importStar(n(6634)),o=n(7911),a=r.__importDefault(n(5012));t.load=function e(t,n,c){if(void 0===c&&(c=!0),null==t)throw new Error("cheerio.load() expects a string");var l=r.__assign(r.__assign({},i.default),i.flatten(n)),u=a.default(t,l,c),h=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return r.__extends(t,e),t}(o.Cheerio);function p(e,t,n,s){return void 0===n&&(n=u),new h(e,t,n,r.__assign(r.__assign({},l),i.flatten(s)))}return Object.assign(p,s,{load:e,_root:u,_options:l,fn:h.prototype,prototype:h.prototype}),p}},2754:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.flatten=void 0;var r=n(9698);t.default={xml:!1,decodeEntities:!0};var i={_useHtmlParser2:!0,xmlMode:!0};t.flatten=function(e){return(null==e?void 0:e.xml)?"boolean"==typeof e.xml?i:r.__assign(r.__assign({},i),e.xml):null!=e?e:void 0}},5012:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.update=void 0;var r=n(3719),i=n(8585),s=n(7957),o=n(7915);function a(e,t){var n=Array.isArray(e)?e:[e];t?t.children=n:t=null;for(var i=0;i<n.length;i++){var s=n[i];s.parent&&s.parent.children!==n&&r.DomUtils.removeElement(s),t?(s.prev=n[i-1]||null,s.next=n[i+1]||null):s.prev=s.next=null,s.parent=t}return t}t.default=function(e,t,n){if("undefined"!=typeof Buffer&&Buffer.isBuffer(e)&&(e=e.toString()),"string"==typeof e)return t.xmlMode||t._useHtmlParser2?i.parse(e,t):s.parse(e,t,n);var r=e;if(!Array.isArray(r)&&o.isDocument(r))return r;var c=new o.Document([]);return a(r,c),c},t.update=a},8585:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.render=t.parse=void 0;var i=n(3719);Object.defineProperty(t,"parse",{enumerable:!0,get:function(){return i.parseDocument}});var s=n(7220);Object.defineProperty(t,"render",{enumerable:!0,get:function(){return r(s).default}})},7957:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.render=t.parse=void 0;var r=n(9698),i=n(7915),s=n(2394),o=r.__importDefault(n(1906));t.parse=function(e,t,n){var r={scriptingEnabled:"boolean"!=typeof t.scriptingEnabled||t.scriptingEnabled,treeAdapter:o.default,sourceCodeLocationInfo:t.sourceCodeLocationInfo},i=t.context;return n?s.parse(e,r):s.parseFragment(i,e,r)},t.render=function(e){for(var t,n=("length"in e?e:[e]),a=0;a<n.length;a+=1){var c=n[a];i.isDocument(c)&&(t=Array.prototype.splice).call.apply(t,r.__spreadArray([n,a,1],c.children))}return s.serialize({children:n},{treeAdapter:o.default})}},6634:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.merge=t.contains=t.root=t.parseHTML=t.text=t.xml=t.html=void 0;var r=n(9698),i=r.__importStar(n(2754)),s=n(7248),o=n(3719),a=n(7957),c=n(8585);function l(e,t,n){var r,i=t?"string"==typeof t?s.select(t,null!==(r=null==e?void 0:e._root)&&void 0!==r?r:[],n):t:null==e?void 0:e._root.children;return i?n.xmlMode||n._useHtmlParser2?c.render(i,n):a.render(i):""}function u(e){if(Array.isArray(e))return!0;if("object"!=typeof e||!Object.prototype.hasOwnProperty.call(e,"length")||"number"!=typeof e.length||e.length<0)return!1;for(var t=0;t<e.length;t++)if(!(t in e))return!1;return!0}t.html=function(e,t){return!t&&function(e){return"object"==typeof e&&null!=e&&!("length"in e)&&!("type"in e)}(e)&&(t=e,e=void 0),l(this||void 0,e,r.__assign(r.__assign(r.__assign({},i.default),this?this._options:{}),i.flatten(null!=t?t:{})))},t.xml=function(e){return l(this,e,r.__assign(r.__assign({},this._options),{xmlMode:!0}))},t.text=function e(t){for(var n=t||(this?this.root():[]),r="",i=0;i<n.length;i++){var s=n[i];o.DomUtils.isText(s)?r+=s.data:o.DomUtils.hasChildren(s)&&s.type!==o.ElementType.Comment&&s.type!==o.ElementType.Script&&s.type!==o.ElementType.Style&&(r+=e(s.children))}return r},t.parseHTML=function(e,t,n){if(void 0===n&&(n="boolean"==typeof t&&t),!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t);var r=this.load(e,i.default,!1);return n||r("script").remove(),r.root()[0].children.slice()},t.root=function(){return this(this._root)},t.contains=function(e,t){if(t===e)return!1;for(var n=t;n&&n!==n.parent;)if((n=n.parent)===e)return!0;return!1},t.merge=function(e,t){if(u(e)&&u(t)){for(var n=e.length,r=+t.length,i=0;i<r;i++)e[n++]=t[i];return e.length=n,e}}},8701:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0})},5633:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.isHtml=t.cloneDom=t.domEach=t.cssCase=t.camelCase=t.isCheerio=t.isTag=void 0;var r=n(3719),i=n(7915);t.isTag=r.DomUtils.isTag,t.isCheerio=function(e){return null!=e.cheerio},t.camelCase=function(e){return e.replace(/[_.-](\w|$)/g,(function(e,t){return t.toUpperCase()}))},t.cssCase=function(e){return e.replace(/[A-Z]/g,"-$&").toLowerCase()},t.domEach=function(e,t){for(var n=e.length,r=0;r<n;r++)t(e[r],r);return e},t.cloneDom=function(e){var t="length"in e?Array.prototype.map.call(e,(function(e){return i.cloneNode(e,!0)})):[i.cloneNode(e,!0)],n=new i.Document(t);return t.forEach((function(e){e.parent=n})),t};var s=/<[a-zA-Z][^]*>/;t.isHtml=function(e){return s.test(e)}},9698:(e,t,n)=>{"use strict";n.r(t),n.d(t,{__extends:()=>i,__assign:()=>s,__rest:()=>o,__decorate:()=>a,__param:()=>c,__metadata:()=>l,__awaiter:()=>u,__generator:()=>h,__createBinding:()=>p,__exportStar:()=>d,__values:()=>f,__read:()=>m,__spread:()=>T,__spreadArrays:()=>E,__spreadArray:()=>_,__await:()=>g,__asyncGenerator:()=>A,__asyncDelegator:()=>C,__asyncValues:()=>N,__makeTemplateObject:()=>v,__importStar:()=>b,__importDefault:()=>S,__classPrivateFieldGet:()=>y,__classPrivateFieldSet:()=>I});var r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var s=function(){return(s=Object.assign||function(e){for(var t,n=1,r=arguments.length;n<r;n++)for(var i in t=arguments[n])Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e}).apply(this,arguments)};function o(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var i=0;for(r=Object.getOwnPropertySymbols(e);i<r.length;i++)t.indexOf(r[i])<0&&Object.prototype.propertyIsEnumerable.call(e,r[i])&&(n[r[i]]=e[r[i]])}return n}function a(e,t,n,r){var i,s=arguments.length,o=s<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,n):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,n,r);else for(var a=e.length-1;a>=0;a--)(i=e[a])&&(o=(s<3?i(o):s>3?i(t,n,o):i(t,n))||o);return s>3&&o&&Object.defineProperty(t,n,o),o}function c(e,t){return function(n,r){t(n,r,e)}}function l(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}function u(e,t,n,r){return new(n||(n=Promise))((function(i,s){function o(e){try{c(r.next(e))}catch(e){s(e)}}function a(e){try{c(r.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(o,a)}c((r=r.apply(e,t||[])).next())}))}function h(e,t){var n,r,i,s,o={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return s={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(s[Symbol.iterator]=function(){return this}),s;function a(s){return function(a){return function(s){if(n)throw new TypeError("Generator is already executing.");for(;o;)try{if(n=1,r&&(i=2&s[0]?r.return:s[0]?r.throw||((i=r.return)&&i.call(r),0):r.next)&&!(i=i.call(r,s[1])).done)return i;switch(r=0,i&&(s=[2&s[0],i.value]),s[0]){case 0:case 1:i=s;break;case 4:return o.label++,{value:s[1],done:!1};case 5:o.label++,r=s[1],s=[0];continue;case 7:s=o.ops.pop(),o.trys.pop();continue;default:if(!((i=(i=o.trys).length>0&&i[i.length-1])||6!==s[0]&&2!==s[0])){o=0;continue}if(3===s[0]&&(!i||s[1]>i[0]&&s[1]<i[3])){o.label=s[1];break}if(6===s[0]&&o.label<i[1]){o.label=i[1],i=s;break}if(i&&o.label<i[2]){o.label=i[2],o.ops.push(s);break}i[2]&&o.ops.pop(),o.trys.pop();continue}s=t.call(e,o)}catch(e){s=[6,e],r=0}finally{n=i=0}if(5&s[0])throw s[1];return{value:s[0]?s[1]:void 0,done:!0}}([s,a])}}}var p=Object.create?function(e,t,n,r){void 0===r&&(r=n),Object.defineProperty(e,r,{enumerable:!0,get:function(){return t[n]}})}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]};function d(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||p(t,e,n)}function f(e){var t="function"==typeof Symbol&&Symbol.iterator,n=t&&e[t],r=0;if(n)return n.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&r>=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function m(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var r,i,s=n.call(e),o=[];try{for(;(void 0===t||t-- >0)&&!(r=s.next()).done;)o.push(r.value)}catch(e){i={error:e}}finally{try{r&&!r.done&&(n=s.return)&&n.call(s)}finally{if(i)throw i.error}}return o}function T(){for(var e=[],t=0;t<arguments.length;t++)e=e.concat(m(arguments[t]));return e}function E(){for(var e=0,t=0,n=arguments.length;t<n;t++)e+=arguments[t].length;var r=Array(e),i=0;for(t=0;t<n;t++)for(var s=arguments[t],o=0,a=s.length;o<a;o++,i++)r[i]=s[o];return r}function _(e,t,n){if(n||2===arguments.length)for(var r,i=0,s=t.length;i<s;i++)!r&&i in t||(r||(r=Array.prototype.slice.call(t,0,i)),r[i]=t[i]);return e.concat(r||t)}function g(e){return this instanceof g?(this.v=e,this):new g(e)}function A(e,t,n){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var r,i=n.apply(e,t||[]),s=[];return r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r;function o(e){i[e]&&(r[e]=function(t){return new Promise((function(n,r){s.push([e,t,n,r])>1||a(e,t)}))})}function a(e,t){try{(n=i[e](t)).value instanceof g?Promise.resolve(n.value.v).then(c,l):u(s[0][2],n)}catch(e){u(s[0][3],e)}var n}function c(e){a("next",e)}function l(e){a("throw",e)}function u(e,t){e(t),s.shift(),s.length&&a(s[0][0],s[0][1])}}function C(e){var t,n;return t={},r("next"),r("throw",(function(e){throw e})),r("return"),t[Symbol.iterator]=function(){return this},t;function r(r,i){t[r]=e[r]?function(t){return(n=!n)?{value:g(e[r](t)),done:"return"===r}:i?i(t):t}:i}}function N(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,n=e[Symbol.asyncIterator];return n?n.call(e):(e=f(e),t={},r("next"),r("throw"),r("return"),t[Symbol.asyncIterator]=function(){return this},t);function r(n){t[n]=e[n]&&function(t){return new Promise((function(r,i){!function(e,t,n,r){Promise.resolve(r).then((function(t){e({value:t,done:n})}),t)}(r,i,(t=e[n](t)).done,t.value)}))}}}function v(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e}var O=Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t};function b(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&p(t,e,n);return O(t,e),t}function S(e){return e&&e.__esModule?e:{default:e}}function y(e,t,n,r){if("a"===n&&!r)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?r:"a"===n?r.call(e):r?r.value:t.get(e)}function I(e,t,n,r,i){if("m"===r)throw new TypeError("Private method is not writable");if("a"===r&&!i)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!i:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===r?i.call(e,n):i?i.value=n:t.set(e,n),n}},8783:(e,t,n)=>{var r=n(8614).EventEmitter,i=n(3129).spawn,s=n(5622),o=s.dirname,a=s.basename,c=n(5747);function l(e,t){this.flags=e,this.required=e.indexOf("<")>=0,this.optional=e.indexOf("[")>=0,this.bool=-1===e.indexOf("-no-"),(e=e.split(/[ ,|]+/)).length>1&&!/^[[<]/.test(e[1])&&(this.short=e.shift()),this.long=e.shift(),this.description=t||""}function u(e){this.commands=[],this.options=[],this._execs={},this._allowUnknownOption=!1,this._args=[],this._name=e||""}function h(e,t){var n=Math.max(0,t-e.length);return e+Array(n+1).join(" ")}function p(e,t){t=t||[];for(var n=0;n<t.length;n++)"--help"!==t[n]&&"-h"!==t[n]||(e.outputHelp(),process.exit(0))}function d(e){var t=e.name+(!0===e.variadic?"...":"");return e.required?"<"+t+">":"["+t+"]"}function f(e){try{if(c.statSync(e).isFile())return!0}catch(e){return!1}}n(1669).inherits(u,r),(t=e.exports=new u).Command=u,t.Option=l,l.prototype.name=function(){return this.long.replace("--","").replace("no-","")},l.prototype.attributeName=function(){return this.name().split("-").reduce((function(e,t){return e+t[0].toUpperCase()+t.slice(1)}))},l.prototype.is=function(e){return this.short===e||this.long===e},u.prototype.command=function(e,t,n){"object"==typeof t&&null!==t&&(n=t,t=null),n=n||{};var r=e.split(/ +/),i=new u(r.shift());return t&&(i.description(t),this.executables=!0,this._execs[i._name]=!0,n.isDefault&&(this.defaultExecutable=i._name)),i._noHelp=!!n.noHelp,this.commands.push(i),i.parseExpectedArgs(r),i.parent=this,t?this:i},u.prototype.arguments=function(e){return this.parseExpectedArgs(e.split(/ +/))},u.prototype.addImplicitHelpCommand=function(){this.command("help [cmd]","display help for [cmd]")},u.prototype.parseExpectedArgs=function(e){if(e.length){var t=this;return e.forEach((function(e){var n={required:!1,name:"",variadic:!1};switch(e[0]){case"<":n.required=!0,n.name=e.slice(1,-1);break;case"[":n.name=e.slice(1,-1)}n.name.length>3&&"..."===n.name.slice(-3)&&(n.variadic=!0,n.name=n.name.slice(0,-3)),n.name&&t._args.push(n)})),this}},u.prototype.action=function(e){var t=this,n=function(n,r){n=n||[],r=r||[];var i=t.parseOptions(r);p(t,i.unknown),i.unknown.length>0&&t.unknownOption(i.unknown[0]),i.args.length&&(n=i.args.concat(n)),t._args.forEach((function(e,r){e.required&&null==n[r]?t.missingArgument(e.name):e.variadic&&(r!==t._args.length-1&&t.variadicArgNotLast(e.name),n[r]=n.splice(r))})),t._args.length?n[t._args.length]=t:n.push(t),e.apply(t,n)},r=this.parent||this,i=r===this?"*":this._name;return r.on("command:"+i,n),this._alias&&r.on("command:"+this._alias,n),this},u.prototype.option=function(e,t,n,r){var i=this,s=new l(e,t),o=s.name(),a=s.attributeName();if("function"!=typeof n)if(n instanceof RegExp){var c=n;n=function(e,t){var n=c.exec(e);return n?n[0]:t}}else r=n,n=null;return(!s.bool||s.optional||s.required)&&(s.bool||(r=!0),void 0!==r&&(i[a]=r,s.defaultValue=r)),this.options.push(s),this.on("option:"+o,(function(e){null!==e&&n&&(e=n(e,void 0===i[a]?r:i[a])),"boolean"==typeof i[a]||void 0===i[a]?i[a]=null==e?!!s.bool&&(r||!0):e:null!==e&&(i[a]=e)})),this},u.prototype.allowUnknownOption=function(e){return this._allowUnknownOption=0===arguments.length||e,this},u.prototype.parse=function(e){this.executables&&this.addImplicitHelpCommand(),this.rawArgs=e,this._name=this._name||a(e[1],".js"),this.executables&&e.length<3&&!this.defaultExecutable&&e.push("--help");var t=this.parseOptions(this.normalize(e.slice(2))),n=this.args=t.args,r=this.parseArgs(this.args,t.unknown),i=r.args[0],s=null;return i&&(s=this.commands.filter((function(e){return e.alias()===i}))[0]),!0===this._execs[i]?this.executeSubCommand(e,n,t.unknown):s?(n[0]=s._name,this.executeSubCommand(e,n,t.unknown)):this.defaultExecutable?(n.unshift(this.defaultExecutable),this.executeSubCommand(e,n,t.unknown)):r},u.prototype.executeSubCommand=function(e,t,n){(t=t.concat(n)).length||this.help(),"help"===t[0]&&1===t.length&&this.help(),"help"===t[0]&&(t[0]=t[1],t[1]="--help");var r,l=e[1],u=a(l,s.extname(l))+"-"+t[0],h=c.realpathSync(l);r=o(h);var p,d=s.join(r,u),m=!1;f(d+".js")?(u=d+".js",m=!0):f(d+".ts")?(u=d+".ts",m=!0):f(d)&&(u=d),t=t.slice(1),"win32"!==process.platform?m?(t.unshift(u),t=(process.execArgv||[]).concat(t),p=i(process.argv[0],t,{stdio:"inherit",customFds:[0,1,2]})):p=i(u,t,{stdio:"inherit",customFds:[0,1,2]}):(t.unshift(u),p=i(process.execPath,t,{stdio:"inherit"})),["SIGUSR1","SIGUSR2","SIGTERM","SIGINT","SIGHUP"].forEach((function(e){process.on(e,(function(){!1===p.killed&&null===p.exitCode&&p.kill(e)}))})),p.on("close",process.exit.bind(process)),p.on("error",(function(e){"ENOENT"===e.code?console.error("error: %s(1) does not exist, try --help",u):"EACCES"===e.code&&console.error("error: %s(1) not executable. try chmod or run with root",u),process.exit(1)})),this.runningCommand=p},u.prototype.normalize=function(e){for(var t,n,r,i=[],s=0,o=e.length;s<o;++s){if(t=e[s],s>0&&(n=this.optionFor(e[s-1])),"--"===t){i=i.concat(e.slice(s));break}n&&n.required?i.push(t):t.length>1&&"-"===t[0]&&"-"!==t[1]?t.slice(1).split("").forEach((function(e){i.push("-"+e)})):/^--/.test(t)&&~(r=t.indexOf("="))?i.push(t.slice(0,r),t.slice(r+1)):i.push(t)}return i},u.prototype.parseArgs=function(e,t){var n;return e.length?(n=e[0],this.listeners("command:"+n).length?this.emit("command:"+e.shift(),e,t):this.emit("command:*",e)):(p(this,t),t.length>0&&this.unknownOption(t[0]),0===this.commands.length&&0===this._args.filter((function(e){return e.required})).length&&this.emit("command:*")),this},u.prototype.optionFor=function(e){for(var t=0,n=this.options.length;t<n;++t)if(this.options[t].is(e))return this.options[t]},u.prototype.parseOptions=function(e){for(var t,n,r,i=[],s=e.length,o=[],a=0;a<s;++a)if(r=e[a],t)i.push(r);else if("--"!==r)if(n=this.optionFor(r))if(n.required){if(null==(r=e[++a]))return this.optionMissingArgument(n);this.emit("option:"+n.name(),r)}else n.optional?(null==(r=e[a+1])||"-"===r[0]&&"-"!==r?r=null:++a,this.emit("option:"+n.name(),r)):this.emit("option:"+n.name());else r.length>1&&"-"===r[0]?(o.push(r),a+1<e.length&&"-"!==e[a+1][0]&&o.push(e[++a])):i.push(r);else t=!0;return{args:i,unknown:o}},u.prototype.opts=function(){for(var e={},t=this.options.length,n=0;n<t;n++){var r=this.options[n].attributeName();e[r]=r===this._versionOptionName?this._version:this[r]}return e},u.prototype.missingArgument=function(e){console.error("error: missing required argument `%s'",e),process.exit(1)},u.prototype.optionMissingArgument=function(e,t){t?console.error("error: option `%s' argument missing, got `%s'",e.flags,t):console.error("error: option `%s' argument missing",e.flags),process.exit(1)},u.prototype.unknownOption=function(e){this._allowUnknownOption||(console.error("error: unknown option `%s'",e),process.exit(1))},u.prototype.variadicArgNotLast=function(e){console.error("error: variadic arguments must be last `%s'",e),process.exit(1)},u.prototype.version=function(e,t){if(0===arguments.length)return this._version;this._version=e;var n=new l(t=t||"-V, --version","output the version number");return this._versionOptionName=n.long.substr(2)||"version",this.options.push(n),this.on("option:"+this._versionOptionName,(function(){process.stdout.write(e+"\n"),process.exit(0)})),this},u.prototype.description=function(e,t){return 0===arguments.length?this._description:(this._description=e,this._argsDescription=t,this)},u.prototype.alias=function(e){var t=this;if(0!==this.commands.length&&(t=this.commands[this.commands.length-1]),0===arguments.length)return t._alias;if(e===t._name)throw new Error("Command alias can't be the same as its name");return t._alias=e,this},u.prototype.usage=function(e){var t=this._args.map((function(e){return d(e)})),n="[options]"+(this.commands.length?" [command]":"")+(this._args.length?" "+t.join(" "):"");return 0===arguments.length?this._usage||n:(this._usage=e,this)},u.prototype.name=function(e){return 0===arguments.length?this._name:(this._name=e,this)},u.prototype.prepareCommands=function(){return this.commands.filter((function(e){return!e._noHelp})).map((function(e){var t=e._args.map((function(e){return d(e)})).join(" ");return[e._name+(e._alias?"|"+e._alias:"")+(e.options.length?" [options]":"")+(t?" "+t:""),e._description]}))},u.prototype.largestCommandLength=function(){return this.prepareCommands().reduce((function(e,t){return Math.max(e,t[0].length)}),0)},u.prototype.largestOptionLength=function(){var e=[].slice.call(this.options);return e.push({flags:"-h, --help"}),e.reduce((function(e,t){return Math.max(e,t.flags.length)}),0)},u.prototype.largestArgLength=function(){return this._args.reduce((function(e,t){return Math.max(e,t.name.length)}),0)},u.prototype.padWidth=function(){var e=this.largestOptionLength();return this._argsDescription&&this._args.length&&this.largestArgLength()>e&&(e=this.largestArgLength()),this.commands&&this.commands.length&&this.largestCommandLength()>e&&(e=this.largestCommandLength()),e},u.prototype.optionHelp=function(){var e=this.padWidth();return this.options.map((function(t){return h(t.flags,e)+" "+t.description+(t.bool&&void 0!==t.defaultValue?" (default: "+JSON.stringify(t.defaultValue)+")":"")})).concat([h("-h, --help",e)+" output usage information"]).join("\n")},u.prototype.commandHelp=function(){if(!this.commands.length)return"";var e=this.prepareCommands(),t=this.padWidth();return["Commands:",e.map((function(e){var n=e[1]?" "+e[1]:"";return(n?h(e[0],t):e[0])+n})).join("\n").replace(/^/gm," "),""].join("\n")},u.prototype.helpInformation=function(){var e=[];if(this._description){e=[this._description,""];var t=this._argsDescription;if(t&&this._args.length){var n=this.padWidth();e.push("Arguments:"),e.push(""),this._args.forEach((function(r){e.push(" "+h(r.name,n)+" "+t[r.name])})),e.push("")}}var r=this._name;this._alias&&(r=r+"|"+this._alias);var i=["Usage: "+r+" "+this.usage(),""],s=[],o=this.commandHelp();o&&(s=[o]);var a=["Options:",""+this.optionHelp().replace(/^/gm," "),""];return i.concat(e).concat(a).concat(s).join("\n")},u.prototype.outputHelp=function(e){e||(e=function(e){return e}),process.stdout.write(e(this.helpInformation())),this.emit("--help")},u.prototype.help=function(e){this.outputHelp(e),process.exit()}},996:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.attributeRules=void 0;var r=n(1073),i=/[-[\]{}()*+?.,\\^$|#\s]/g;function s(e){return e.replace(i,"\\$&")}t.attributeRules={equals:function(e,t,n){var r=n.adapter,i=t.name,s=t.value;return t.ignoreCase?(s=s.toLowerCase(),function(t){var n=r.getAttributeValue(t,i);return null!=n&&n.length===s.length&&n.toLowerCase()===s&&e(t)}):function(t){return r.getAttributeValue(t,i)===s&&e(t)}},hyphen:function(e,t,n){var r=n.adapter,i=t.name,s=t.value,o=s.length;return t.ignoreCase?(s=s.toLowerCase(),function(t){var n=r.getAttributeValue(t,i);return null!=n&&(n.length===o||"-"===n.charAt(o))&&n.substr(0,o).toLowerCase()===s&&e(t)}):function(t){var n=r.getAttributeValue(t,i);return null!=n&&(n.length===o||"-"===n.charAt(o))&&n.substr(0,o)===s&&e(t)}},element:function(e,t,n){var i=t.name,o=t.value,a=t.ignoreCase,c=n.adapter;if(/\s/.test(o))return r.falseFunc;var l=new RegExp("(?:^|\\s)"+s(o)+"(?:$|\\s)",a?"i":"");return function(t){var n=c.getAttributeValue(t,i);return null!=n&&n.length>=o.length&&l.test(n)&&e(t)}},exists:function(e,t,n){var r=t.name,i=n.adapter;return function(t){return i.hasAttrib(t,r)&&e(t)}},start:function(e,t,n){var i=n.adapter,s=t.name,o=t.value,a=o.length;return 0===a?r.falseFunc:t.ignoreCase?(o=o.toLowerCase(),function(t){var n=i.getAttributeValue(t,s);return null!=n&&n.length>=a&&n.substr(0,a).toLowerCase()===o&&e(t)}):function(t){var n;return!!(null===(n=i.getAttributeValue(t,s))||void 0===n?void 0:n.startsWith(o))&&e(t)}},end:function(e,t,n){var i=n.adapter,s=t.name,o=t.value,a=-o.length;return 0===a?r.falseFunc:t.ignoreCase?(o=o.toLowerCase(),function(t){var n;return(null===(n=i.getAttributeValue(t,s))||void 0===n?void 0:n.substr(a).toLowerCase())===o&&e(t)}):function(t){var n;return!!(null===(n=i.getAttributeValue(t,s))||void 0===n?void 0:n.endsWith(o))&&e(t)}},any:function(e,t,n){var i=n.adapter,o=t.name,a=t.value;if(""===a)return r.falseFunc;if(t.ignoreCase){var c=new RegExp(s(a),"i");return function(t){var n=i.getAttributeValue(t,o);return null!=n&&n.length>=a.length&&c.test(n)&&e(t)}}return function(t){var n;return!!(null===(n=i.getAttributeValue(t,o))||void 0===n?void 0:n.includes(a))&&e(t)}},not:function(e,t,n){var r=n.adapter,i=t.name,s=t.value;return""===s?function(t){return!!r.getAttributeValue(t,i)&&e(t)}:t.ignoreCase?(s=s.toLowerCase(),function(t){var n=r.getAttributeValue(t,i);return(null==n||n.length!==s.length||n.toLowerCase()!==s)&&e(t)}):function(t){return r.getAttributeValue(t,i)!==s&&e(t)}}}},8866:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.compileToken=t.compileUnsafe=t.compile=void 0;var i=n(9751),s=n(1073),o=r(n(7353)),a=n(7177),c=n(3621),l=n(1768);function u(e,t,n){return m("string"==typeof e?i.parse(e,t):e,t,n)}function h(e){return"pseudo"===e.type&&("scope"===e.name||Array.isArray(e.data)&&e.data.some((function(e){return e.some(h)})))}t.compile=function(e,t,n){var r=u(e,t,n);return l.ensureIsTag(r,t.adapter)},t.compileUnsafe=u;var p={type:"descendant"},d={type:"_flexibleDescendant"},f={type:"pseudo",name:"scope",data:null};function m(e,t,n){var r;(e=e.filter((function(e){return e.length>0}))).forEach(o.default),n=null!==(r=t.context)&&void 0!==r?r:n;var i=Array.isArray(n),u=n&&(Array.isArray(n)?n:[n]);!function(e,t,n){for(var r=t.adapter,i=!!(null==n?void 0:n.every((function(e){var t=r.isTag(e)&&r.getParent(e);return e===l.PLACEHOLDER_ELEMENT||t&&r.isTag(t)}))),s=0,o=e;s<o.length;s++){var c=o[s];if(c.length>0&&a.isTraversal(c[0])&&"descendant"!==c[0].type);else{if(!i||c.some(h))continue;c.unshift(p)}c.unshift(f)}}(e,t,u);var E=!1,_=e.map((function(e){if(e.length>=2){var n=e[0],r=e[1];"pseudo"!==n.type||"scope"!==n.name||(i&&"descendant"===r.type?e[1]=d:"adjacent"!==r.type&&"sibling"!==r.type||(E=!0))}return function(e,t,n){var r;return e.reduce((function(e,r){return e===s.falseFunc?s.falseFunc:c.compileGeneralSelector(e,r,t,n,m)}),null!==(r=t.rootFunc)&&void 0!==r?r:s.trueFunc)}(e,t,u)})).reduce(T,s.falseFunc);return _.shouldTestNextSiblings=E,_}function T(e,t){return t===s.falseFunc||e===s.trueFunc?e:e===s.falseFunc||t===s.trueFunc?t:function(n){return e(n)||t(n)}}t.compileToken=m},3621:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.compileGeneralSelector=void 0;var r=n(996),i=n(8677);t.compileGeneralSelector=function(e,t,n,s,o){var a=n.adapter,c=n.equals;switch(t.type){case"pseudo-element":throw new Error("Pseudo-elements are not supported by css-select");case"attribute":return r.attributeRules[t.action](e,t,n);case"pseudo":return i.compilePseudoSelector(e,t,n,s,o);case"tag":return function(n){return a.getName(n)===t.name&&e(n)};case"descendant":if(!1===n.cacheResults||"undefined"==typeof WeakSet)return function(t){for(var n=t;n=a.getParent(n);)if(a.isTag(n)&&e(n))return!0;return!1};var l=new WeakSet;return function(t){for(var n=t;n=a.getParent(n);)if(!l.has(n)){if(a.isTag(n)&&e(n))return!0;l.add(n)}return!1};case"_flexibleDescendant":return function(t){var n=t;do{if(a.isTag(n)&&e(n))return!0}while(n=a.getParent(n));return!1};case"parent":return function(t){return a.getChildren(t).some((function(t){return a.isTag(t)&&e(t)}))};case"child":return function(t){var n=a.getParent(t);return null!=n&&a.isTag(n)&&e(n)};case"sibling":return function(t){for(var n=a.getSiblings(t),r=0;r<n.length;r++){var i=n[r];if(c(t,i))break;if(a.isTag(i)&&e(i))return!0}return!1};case"adjacent":return function(t){for(var n,r=a.getSiblings(t),i=0;i<r.length;i++){var s=r[i];if(c(t,s))break;a.isTag(s)&&(n=s)}return!!n&&e(n)};case"universal":return e}}},5366:function(e,t,n){"use strict";var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n),Object.defineProperty(e,r,{enumerable:!0,get:function(){return t[n]}})}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),s=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return i(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.aliases=t.pseudos=t.filters=t.is=t.selectOne=t.selectAll=t.prepareContext=t._compileToken=t._compileUnsafe=t.compile=void 0;var o=s(n(9432)),a=n(1073),c=n(8866),l=n(1768),u=function(e,t){return e===t},h={adapter:o,equals:u};function p(e){var t,n,r,i,s=null!=e?e:h;return null!==(t=s.adapter)&&void 0!==t||(s.adapter=o),null!==(n=s.equals)&&void 0!==n||(s.equals=null!==(i=null===(r=s.adapter)||void 0===r?void 0:r.equals)&&void 0!==i?i:u),s}function d(e){return function(t,n,r){var i=p(n);return e(t,i,r)}}function f(e){return function(t,n,r){var i=p(r);"function"!=typeof t&&(t=c.compileUnsafe(t,i,n));var s=m(n,i.adapter,t.shouldTestNextSiblings);return e(t,s,i)}}function m(e,t,n){return void 0===n&&(n=!1),n&&(e=function(e,t){for(var n=Array.isArray(e)?e.slice(0):[e],r=0;r<n.length;r++){var i=l.getNextSiblings(n[r],t);n.push.apply(n,i)}return n}(e,t)),Array.isArray(e)?t.removeSubsets(e):t.getChildren(e)}t.compile=d(c.compile),t._compileUnsafe=d(c.compileUnsafe),t._compileToken=d(c.compileToken),t.prepareContext=m,t.selectAll=f((function(e,t,n){return e!==a.falseFunc&&t&&0!==t.length?n.adapter.findAll(e,t):[]})),t.selectOne=f((function(e,t,n){return e!==a.falseFunc&&t&&0!==t.length?n.adapter.findOne(e,t):null})),t.is=function(e,t,n){var r=p(n);return("function"==typeof t?t:c.compile(t,r))(e)},t.default=t.selectAll;var T=n(8677);Object.defineProperty(t,"filters",{enumerable:!0,get:function(){return T.filters}}),Object.defineProperty(t,"pseudos",{enumerable:!0,get:function(){return T.pseudos}}),Object.defineProperty(t,"aliases",{enumerable:!0,get:function(){return T.aliases}})},7177:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.isTraversal=t.procedure=void 0,t.procedure={universal:50,tag:30,attribute:1,pseudo:0,"pseudo-element":0,descendant:-1,child:-1,parent:-1,sibling:-1,adjacent:-1,_flexibleDescendant:-1},t.isTraversal=function(e){return t.procedure[e.type]<0}},2968:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.aliases=void 0,t.aliases={"any-link":":is(a, area, link)[href]",link:":any-link:not(:visited)",disabled:":is(\n :is(button, input, select, textarea, optgroup, option)[disabled],\n optgroup[disabled] > option,\n fieldset[disabled]:not(fieldset[disabled] legend:first-of-type *)\n )",enabled:":not(:disabled)",checked:":is(:is(input[type=radio], input[type=checkbox])[checked], option:selected)",required:":is(input, select, textarea)[required]",optional:":is(input, select, textarea):not([required])",selected:"option:is([selected], select:not([multiple]):not(:has(> option[selected])) > :first-of-type)",checkbox:"[type=checkbox]",file:"[type=file]",password:"[type=password]",radio:"[type=radio]",reset:"[type=reset]",image:"[type=image]",submit:"[type=submit]",parent:":not(:empty)",header:":is(h1, h2, h3, h4, h5, h6)",button:":is(button, input[type=button])",input:":is(input, textarea, select, button)",text:"input:is(:not([type!='']), [type=text])"}},7689:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.filters=void 0;var i=r(n(7540)),s=n(1073);function o(e,t){return function(n){var r=t.getParent(n);return null!=r&&t.isTag(r)&&e(n)}}function a(e){return function(t,n,r){var i=r.adapter[e];return"function"!=typeof i?s.falseFunc:function(e){return i(e)&&t(e)}}}t.filters={contains:function(e,t,n){var r=n.adapter;return function(n){return e(n)&&r.getText(n).includes(t)}},icontains:function(e,t,n){var r=n.adapter,i=t.toLowerCase();return function(t){return e(t)&&r.getText(t).toLowerCase().includes(i)}},"nth-child":function(e,t,n){var r=n.adapter,a=n.equals,c=i.default(t);return c===s.falseFunc?s.falseFunc:c===s.trueFunc?o(e,r):function(t){for(var n=r.getSiblings(t),i=0,s=0;s<n.length&&!a(t,n[s]);s++)r.isTag(n[s])&&i++;return c(i)&&e(t)}},"nth-last-child":function(e,t,n){var r=n.adapter,a=n.equals,c=i.default(t);return c===s.falseFunc?s.falseFunc:c===s.trueFunc?o(e,r):function(t){for(var n=r.getSiblings(t),i=0,s=n.length-1;s>=0&&!a(t,n[s]);s--)r.isTag(n[s])&&i++;return c(i)&&e(t)}},"nth-of-type":function(e,t,n){var r=n.adapter,a=n.equals,c=i.default(t);return c===s.falseFunc?s.falseFunc:c===s.trueFunc?o(e,r):function(t){for(var n=r.getSiblings(t),i=0,s=0;s<n.length;s++){var o=n[s];if(a(t,o))break;r.isTag(o)&&r.getName(o)===r.getName(t)&&i++}return c(i)&&e(t)}},"nth-last-of-type":function(e,t,n){var r=n.adapter,a=n.equals,c=i.default(t);return c===s.falseFunc?s.falseFunc:c===s.trueFunc?o(e,r):function(t){for(var n=r.getSiblings(t),i=0,s=n.length-1;s>=0;s--){var o=n[s];if(a(t,o))break;r.isTag(o)&&r.getName(o)===r.getName(t)&&i++}return c(i)&&e(t)}},root:function(e,t,n){var r=n.adapter;return function(t){var n=r.getParent(t);return(null==n||!r.isTag(n))&&e(t)}},scope:function(e,n,r,i){var s=r.equals;return i&&0!==i.length?1===i.length?function(t){return s(i[0],t)&&e(t)}:function(t){return i.includes(t)&&e(t)}:t.filters.root(e,n,r)},hover:a("isHovered"),visited:a("isVisited"),active:a("isActive")}},8677:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.compilePseudoSelector=t.aliases=t.pseudos=t.filters=void 0;var r=n(1073),i=n(9751),s=n(7689);Object.defineProperty(t,"filters",{enumerable:!0,get:function(){return s.filters}});var o=n(7221);Object.defineProperty(t,"pseudos",{enumerable:!0,get:function(){return o.pseudos}});var a=n(2968);Object.defineProperty(t,"aliases",{enumerable:!0,get:function(){return a.aliases}});var c=n(1768);t.compilePseudoSelector=function(e,t,n,l,u){var h=t.name,p=t.data;if(Array.isArray(p))return c.subselects[h](e,p,n,l,u);if(h in a.aliases){if(null!=p)throw new Error("Pseudo "+h+" doesn't have any arguments");var d=i.parse(a.aliases[h],n);return c.subselects.is(e,d,n,l,u)}if(h in s.filters)return s.filters[h](e,p,n,l);if(h in o.pseudos){var f=o.pseudos[h];return o.verifyPseudoArgs(f,h,p),f===r.falseFunc?r.falseFunc:e===r.trueFunc?function(e){return f(e,n,p)}:function(t){return f(t,n,p)&&e(t)}}throw new Error("unmatched pseudo-class :"+h)}},7221:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.verifyPseudoArgs=t.pseudos=void 0,t.pseudos={empty:function(e,t){var n=t.adapter;return!n.getChildren(e).some((function(e){return n.isTag(e)||""!==n.getText(e)}))},"first-child":function(e,t){var n=t.adapter,r=t.equals,i=n.getSiblings(e).find((function(e){return n.isTag(e)}));return null!=i&&r(e,i)},"last-child":function(e,t){for(var n=t.adapter,r=t.equals,i=n.getSiblings(e),s=i.length-1;s>=0;s--){if(r(e,i[s]))return!0;if(n.isTag(i[s]))break}return!1},"first-of-type":function(e,t){for(var n=t.adapter,r=t.equals,i=n.getSiblings(e),s=n.getName(e),o=0;o<i.length;o++){var a=i[o];if(r(e,a))return!0;if(n.isTag(a)&&n.getName(a)===s)break}return!1},"last-of-type":function(e,t){for(var n=t.adapter,r=t.equals,i=n.getSiblings(e),s=n.getName(e),o=i.length-1;o>=0;o--){var a=i[o];if(r(e,a))return!0;if(n.isTag(a)&&n.getName(a)===s)break}return!1},"only-of-type":function(e,t){var n=t.adapter,r=t.equals,i=n.getName(e);return n.getSiblings(e).every((function(t){return r(e,t)||!n.isTag(t)||n.getName(t)!==i}))},"only-child":function(e,t){var n=t.adapter,r=t.equals;return n.getSiblings(e).every((function(t){return r(e,t)||!n.isTag(t)}))}},t.verifyPseudoArgs=function(e,t,n){if(null===n){if(e.length>2)throw new Error("pseudo-selector :"+t+" requires an argument")}else if(2===e.length)throw new Error("pseudo-selector :"+t+" doesn't have any arguments")}},1768:function(e,t,n){"use strict";var r=this&&this.__spreadArray||function(e,t){for(var n=0,r=t.length,i=e.length;n<r;n++,i++)e[i]=t[n];return e};Object.defineProperty(t,"__esModule",{value:!0}),t.subselects=t.getNextSiblings=t.ensureIsTag=t.PLACEHOLDER_ELEMENT=void 0;var i=n(1073),s=n(7177);function o(e,t){return e===i.falseFunc?i.falseFunc:function(n){return t.isTag(n)&&e(n)}}function a(e,t){var n=t.getSiblings(e);if(n.length<=1)return[];var r=n.indexOf(e);return r<0||r===n.length-1?[]:n.slice(r+1).filter(t.isTag)}t.PLACEHOLDER_ELEMENT={},t.ensureIsTag=o,t.getNextSiblings=a;var c=function(e,t,n,r,i){var s=i(t,{xmlMode:!!n.xmlMode,adapter:n.adapter,equals:n.equals},r);return function(t){return s(t)&&e(t)}};t.subselects={is:c,matches:c,not:function(e,t,n,r,s){var o=s(t,{xmlMode:!!n.xmlMode,adapter:n.adapter,equals:n.equals},r);return o===i.falseFunc?e:o===i.trueFunc?i.falseFunc:function(t){return!o(t)&&e(t)}},has:function(e,n,c,l,u){var h=c.adapter,p={xmlMode:!!c.xmlMode,adapter:h,equals:c.equals},d=n.some((function(e){return e.some(s.isTraversal)}))?[t.PLACEHOLDER_ELEMENT]:void 0,f=u(n,p,d);if(f===i.falseFunc)return i.falseFunc;if(f===i.trueFunc)return function(t){return h.getChildren(t).some(h.isTag)&&e(t)};var m=o(f,h),T=f.shouldTestNextSiblings,E=void 0!==T&&T;return d?function(t){d[0]=t;var n=h.getChildren(t),i=E?r(r([],n),a(t,h)):n;return e(t)&&h.existsOne(m,i)}:function(t){return e(t)&&h.existsOne(m,h.getChildren(t))}}}},7353:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(7177),i={exists:10,equals:8,not:7,start:6,end:6,any:5,hyphen:4,element:4};function s(e){var t=r.procedure[e.type];if("attribute"===e.type)(t=i[e.action])===i.equals&&"id"===e.name&&(t=9),e.ignoreCase&&(t>>=1);else if("pseudo"===e.type)if(e.data)if("has"===e.name||"contains"===e.name)t=0;else if(Array.isArray(e.data)){t=0;for(var n=0;n<e.data.length;n++)if(1===e.data[n].length){var o=s(e.data[n][0]);if(0===o){t=0;break}o>t&&(t=o)}e.data.length>1&&t>0&&(t-=1)}else t=1;else t=3;return t}t.default=function(e){for(var t=e.map(s),n=1;n<e.length;n++){var r=t[n];if(!(r<0))for(var i=n-1;i>=0&&r<t[i];i--){var o=e[i+1];e[i+1]=e[i],e[i]=o,t[i+1]=t[i],t[i]=r}}}},9751:function(e,t,n){"use strict";var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n),Object.defineProperty(e,r,{enumerable:!0,get:function(){return t[n]}})}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),i=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||r(t,e,n)},s=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.stringify=t.parse=void 0,i(n(675),t);var o=n(675);Object.defineProperty(t,"parse",{enumerable:!0,get:function(){return s(o).default}});var a=n(6868);Object.defineProperty(t,"stringify",{enumerable:!0,get:function(){return s(a).default}})},675:function(e,t){"use strict";var n=this&&this.__spreadArray||function(e,t){for(var n=0,r=t.length,i=e.length;n<r;n++,i++)e[i]=t[n];return e};Object.defineProperty(t,"__esModule",{value:!0}),t.isTraversal=void 0;var r=/^[^\\#]?(?:\\(?:[\da-f]{1,6}\s?|.)|[\w\-\u00b0-\uFFFF])+/,i=/\\([\da-f]{1,6}\s?|(\s)|.)/gi,s=new Map([["~","element"],["^","start"],["$","end"],["*","any"],["!","not"],["|","hyphen"]]),o={">":"child","<":"parent","~":"sibling","+":"adjacent"},a={"#":["id","equals"],".":["class","element"]},c=new Set(["has","not","matches","is","host","host-context"]),l=new Set(n(["descendant"],Object.keys(o).map((function(e){return o[e]})))),u=new Set(["accept","accept-charset","align","alink","axis","bgcolor","charset","checked","clear","codetype","color","compact","declare","defer","dir","direction","disabled","enctype","face","frame","hreflang","http-equiv","lang","language","link","media","method","multiple","nohref","noresize","noshade","nowrap","readonly","rel","rev","rules","scope","scrolling","selected","shape","target","text","type","valign","valuetype","vlink"]);function h(e){return l.has(e.type)}t.isTraversal=h;var p=new Set(["contains","icontains"]),d=new Set(['"',"'"]);function f(e,t,n){var r=parseInt(t,16)-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)}function m(e){return e.replace(i,f)}function T(e){return" "===e||"\n"===e||"\t"===e||"\f"===e||"\r"===e}function E(e,t,n,i){var l,f;void 0===n&&(n={});var g=[],A=!1;function C(e){var n=t.slice(i+e).match(r);if(!n)throw new Error("Expected name, found "+t.slice(i));var s=n[0];return i+=e+s.length,m(s)}function N(e){for(;T(t.charAt(i+e));)e++;i+=e}function v(e){for(var n=0;"\\"===t.charAt(--e);)n++;return 1==(1&n)}function O(){if(g.length>0&&h(g[g.length-1]))throw new Error("Did not expect successive traversals.")}for(N(0);""!==t;){var b=t.charAt(i);if(T(b))A=!0,N(1);else if(b in o)O(),g.push({type:o[b]}),A=!1,N(1);else if(","===b){if(0===g.length)throw new Error("Empty sub-selector");e.push(g),g=[],A=!1,N(1)}else if(t.startsWith("/*",i)){var S=t.indexOf("*/",i+2);if(S<0)throw new Error("Comment was not terminated");i=S+2}else if(A&&(O(),g.push({type:"descendant"}),A=!1),b in a){var y=a[b],I=y[0],R=y[1];g.push({type:"attribute",name:I,action:R,value:C(1),namespace:null,ignoreCase:!!n.xmlMode&&null})}else if("["===b){N(1);var k=void 0,L=null;"|"===t.charAt(i)&&(L="",i+=1),t.startsWith("*|",i)&&(L="*",i+=2),k=C(0),null===L&&"|"===t.charAt(i)&&"="!==t.charAt(i+1)&&(L=k,k=C(1)),(null!==(l=n.lowerCaseAttributeNames)&&void 0!==l?l:!n.xmlMode)&&(k=k.toLowerCase()),N(0),R="exists";var M=s.get(t.charAt(i));if(M){if(R=M,"="!==t.charAt(i+1))throw new Error("Expected `=`");N(2)}else"="===t.charAt(i)&&(R="equals",N(1));var x="",P=null;if("exists"!==R){if(d.has(t.charAt(i))){for(var D=t.charAt(i),w=i+1;w<t.length&&(t.charAt(w)!==D||v(w));)w+=1;if(t.charAt(w)!==D)throw new Error("Attribute value didn't end");x=m(t.slice(i+1,w)),i=w+1}else{for(var H=i;i<t.length&&(!T(t.charAt(i))&&"]"!==t.charAt(i)||v(i));)i+=1;x=m(t.slice(H,i))}N(0);var F=t.charAt(i);"s"===F||"S"===F?(P=!1,N(1)):"i"!==F&&"I"!==F||(P=!0,N(1))}if(n.xmlMode||null!=P||(P=u.has(k)),"]"!==t.charAt(i))throw new Error("Attribute selector didn't terminate");i+=1;var U={type:"attribute",name:k,action:R,value:x,namespace:L,ignoreCase:P};g.push(U)}else if(":"===b){if(":"===t.charAt(i+1)){g.push({type:"pseudo-element",name:C(2).toLowerCase()});continue}var B=C(1).toLowerCase(),G=null;if("("===t.charAt(i))if(c.has(B)){if(d.has(t.charAt(i+1)))throw new Error("Pseudo-selector "+B+" cannot be quoted");if(i=E(G=[],t,n,i+1),")"!==t.charAt(i))throw new Error("Missing closing parenthesis in :"+B+" ("+t+")");i+=1}else{for(var j=i+=1,K=1;K>0&&i<t.length;i++)"("!==t.charAt(i)||v(i)?")"!==t.charAt(i)||v(i)||K--:K++;if(K)throw new Error("Parenthesis not matched");if(G=t.slice(j,i-1),p.has(B)){var q=G.charAt(0);q===G.slice(-1)&&d.has(q)&&(G=G.slice(1,-1)),G=m(G)}}g.push({type:"pseudo",name:B,data:G})}else{L=null;var Y=void 0;if("*"===b)i+=1,Y="*";else{if(!r.test(t.slice(i)))return g.length&&"descendant"===g[g.length-1].type&&g.pop(),_(e,g),i;"|"===t.charAt(i)&&(L="",i+=1),Y=C(0)}"|"===t.charAt(i)&&(L=Y,"*"===t.charAt(i+1)?(Y="*",i+=2):Y=C(1)),"*"===Y?g.push({type:"universal",namespace:L}):((null!==(f=n.lowerCaseTags)&&void 0!==f?f:!n.xmlMode)&&(Y=Y.toLowerCase()),g.push({type:"tag",name:Y,namespace:L}))}}return _(e,g),i}function _(e,t){if(e.length>0&&0===t.length)throw new Error("Empty sub-selector");e.push(t)}t.default=function(e,t){var n=[],r=E(n,""+e,t,0);if(r<e.length)throw new Error("Unmatched selector: "+e.slice(r));return n}},6868:function(e,t){"use strict";var n=this&&this.__spreadArray||function(e,t){for(var n=0,r=t.length,i=e.length;n<r;n++,i++)e[i]=t[n];return e};Object.defineProperty(t,"__esModule",{value:!0});var r={equals:"",element:"~",start:"^",end:"$",any:"*",not:"!",hyphen:"|"},i=new Set(n(n([],Object.keys(r).map((function(e){return r[e]})).filter(Boolean)),[":","[","]"," ","\\","(",")","'"]));function s(e){return e.map(o).join(", ")}function o(e){return e.map(a).join("")}function a(e){switch(e.type){case"child":return" > ";case"parent":return" < ";case"sibling":return" ~ ";case"adjacent":return" + ";case"descendant":return" ";case"universal":return l(e.namespace)+"*";case"tag":return c(e);case"pseudo-element":return"::"+u(e.name);case"pseudo":return null===e.data?":"+u(e.name):"string"==typeof e.data?":"+u(e.name)+"("+u(e.data)+")":":"+u(e.name)+"("+s(e.data)+")";case"attribute":if("id"===e.name&&"equals"===e.action&&!e.ignoreCase&&!e.namespace)return"#"+u(e.value);if("class"===e.name&&"element"===e.action&&!e.ignoreCase&&!e.namespace)return"."+u(e.value);var t=c(e);return"exists"===e.action?"["+t+"]":"["+t+r[e.action]+"='"+u(e.value)+"'"+(e.ignoreCase?"i":!1===e.ignoreCase?"s":"")+"]"}}function c(e){return""+l(e.namespace)+u(e.name)}function l(e){return null!==e?("*"===e?"*":u(e))+"|":""}function u(e){return e.split("").map((function(e){return i.has(e)?"\\"+e:e})).join("")}t.default=s},7837:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.attributeNames=t.elementNames=void 0,t.elementNames=new Map([["altglyph","altGlyph"],["altglyphdef","altGlyphDef"],["altglyphitem","altGlyphItem"],["animatecolor","animateColor"],["animatemotion","animateMotion"],["animatetransform","animateTransform"],["clippath","clipPath"],["feblend","feBlend"],["fecolormatrix","feColorMatrix"],["fecomponenttransfer","feComponentTransfer"],["fecomposite","feComposite"],["feconvolvematrix","feConvolveMatrix"],["fediffuselighting","feDiffuseLighting"],["fedisplacementmap","feDisplacementMap"],["fedistantlight","feDistantLight"],["fedropshadow","feDropShadow"],["feflood","feFlood"],["fefunca","feFuncA"],["fefuncb","feFuncB"],["fefuncg","feFuncG"],["fefuncr","feFuncR"],["fegaussianblur","feGaussianBlur"],["feimage","feImage"],["femerge","feMerge"],["femergenode","feMergeNode"],["femorphology","feMorphology"],["feoffset","feOffset"],["fepointlight","fePointLight"],["fespecularlighting","feSpecularLighting"],["fespotlight","feSpotLight"],["fetile","feTile"],["feturbulence","feTurbulence"],["foreignobject","foreignObject"],["glyphref","glyphRef"],["lineargradient","linearGradient"],["radialgradient","radialGradient"],["textpath","textPath"]]),t.attributeNames=new Map([["definitionurl","definitionURL"],["attributename","attributeName"],["attributetype","attributeType"],["basefrequency","baseFrequency"],["baseprofile","baseProfile"],["calcmode","calcMode"],["clippathunits","clipPathUnits"],["diffuseconstant","diffuseConstant"],["edgemode","edgeMode"],["filterunits","filterUnits"],["glyphref","glyphRef"],["gradienttransform","gradientTransform"],["gradientunits","gradientUnits"],["kernelmatrix","kernelMatrix"],["kernelunitlength","kernelUnitLength"],["keypoints","keyPoints"],["keysplines","keySplines"],["keytimes","keyTimes"],["lengthadjust","lengthAdjust"],["limitingconeangle","limitingConeAngle"],["markerheight","markerHeight"],["markerunits","markerUnits"],["markerwidth","markerWidth"],["maskcontentunits","maskContentUnits"],["maskunits","maskUnits"],["numoctaves","numOctaves"],["pathlength","pathLength"],["patterncontentunits","patternContentUnits"],["patterntransform","patternTransform"],["patternunits","patternUnits"],["pointsatx","pointsAtX"],["pointsaty","pointsAtY"],["pointsatz","pointsAtZ"],["preservealpha","preserveAlpha"],["preserveaspectratio","preserveAspectRatio"],["primitiveunits","primitiveUnits"],["refx","refX"],["refy","refY"],["repeatcount","repeatCount"],["repeatdur","repeatDur"],["requiredextensions","requiredExtensions"],["requiredfeatures","requiredFeatures"],["specularconstant","specularConstant"],["specularexponent","specularExponent"],["spreadmethod","spreadMethod"],["startoffset","startOffset"],["stddeviation","stdDeviation"],["stitchtiles","stitchTiles"],["surfacescale","surfaceScale"],["systemlanguage","systemLanguage"],["tablevalues","tableValues"],["targetx","targetX"],["targety","targetY"],["textlength","textLength"],["viewbox","viewBox"],["viewtarget","viewTarget"],["xchannelselector","xChannelSelector"],["ychannelselector","yChannelSelector"],["zoomandpan","zoomAndPan"]])},7220:function(e,t,n){"use strict";var r=this&&this.__assign||function(){return(r=Object.assign||function(e){for(var t,n=1,r=arguments.length;n<r;n++)for(var i in t=arguments[n])Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e}).apply(this,arguments)},i=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n),Object.defineProperty(e,r,{enumerable:!0,get:function(){return t[n]}})}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&i(t,e,n);return s(t,e),t};Object.defineProperty(t,"__esModule",{value:!0});var a=o(n(9960)),c=n(5863),l=n(7837),u=new Set(["style","script","xmp","iframe","noembed","noframes","plaintext","noscript"]),h=new Set(["area","base","basefont","br","col","command","embed","frame","hr","img","input","isindex","keygen","link","meta","param","source","track","wbr"]);function p(e,t){void 0===t&&(t={});for(var n=("length"in e?e:[e]),r="",i=0;i<n.length;i++)r+=d(n[i],t);return r}function d(e,t){switch(e.type){case a.Root:return p(e.children,t);case a.Directive:case a.Doctype:return"<"+e.data+">";case a.Comment:return"\x3c!--"+e.data+"--\x3e";case a.CDATA:return function(e){return"<![CDATA["+e.children[0].data+"]]>"}(e);case a.Script:case a.Style:case a.Tag:return function(e,t){var n;"foreign"===t.xmlMode&&(e.name=null!==(n=l.elementNames.get(e.name))&&void 0!==n?n:e.name,e.parent&&f.has(e.parent.name)&&(t=r(r({},t),{xmlMode:!1}))),!t.xmlMode&&m.has(e.name)&&(t=r(r({},t),{xmlMode:"foreign"}));var i="<"+e.name,s=function(e,t){if(e)return Object.keys(e).map((function(n){var r,i,s=null!==(r=e[n])&&void 0!==r?r:"";return"foreign"===t.xmlMode&&(n=null!==(i=l.attributeNames.get(n))&&void 0!==i?i:n),t.emptyAttrs||t.xmlMode||""!==s?n+'="'+(!1!==t.decodeEntities?c.encodeXML(s):s.replace(/"/g,"&quot;"))+'"':n})).join(" ")}(e.attribs,t);return s&&(i+=" "+s),0===e.children.length&&(t.xmlMode?!1!==t.selfClosingTags:t.selfClosingTags&&h.has(e.name))?(t.xmlMode||(i+=" "),i+="/>"):(i+=">",e.children.length>0&&(i+=p(e.children,t)),!t.xmlMode&&h.has(e.name)||(i+="</"+e.name+">")),i}(e,t);case a.Text:return function(e,t){var n=e.data||"";return!1===t.decodeEntities||!t.xmlMode&&e.parent&&u.has(e.parent.name)||(n=c.encodeXML(n)),n}(e,t)}}t.default=p;var f=new Set(["mi","mo","mn","ms","mtext","annotation-xml","foreignObject","desc","title"]),m=new Set(["svg","math"])},9960:(e,t)=>{"use strict";var n;Object.defineProperty(t,"__esModule",{value:!0}),t.Doctype=t.CDATA=t.Tag=t.Style=t.Script=t.Comment=t.Directive=t.Text=t.Root=t.isTag=t.ElementType=void 0,function(e){e.Root="root",e.Text="text",e.Directive="directive",e.Comment="comment",e.Script="script",e.Style="style",e.Tag="tag",e.CDATA="cdata",e.Doctype="doctype"}(n=t.ElementType||(t.ElementType={})),t.isTag=function(e){return e.type===n.Tag||e.type===n.Script||e.type===n.Style},t.Root=n.Root,t.Text=n.Text,t.Directive=n.Directive,t.Comment=n.Comment,t.Script=n.Script,t.Style=n.Style,t.Tag=n.Tag,t.CDATA=n.CDATA,t.Doctype=n.Doctype},7915:function(e,t,n){"use strict";var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n),Object.defineProperty(e,r,{enumerable:!0,get:function(){return t[n]}})}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),i=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||r(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),t.DomHandler=void 0;var s=n(9960),o=n(7790);i(n(7790),t);var a=/\s+/g,c={normalizeWhitespace:!1,withStartIndices:!1,withEndIndices:!1},l=function(){function e(e,t,n){this.dom=[],this.root=new o.Document(this.dom),this.done=!1,this.tagStack=[this.root],this.lastNode=null,this.parser=null,"function"==typeof t&&(n=t,t=c),"object"==typeof e&&(t=e,e=void 0),this.callback=null!=e?e:null,this.options=null!=t?t:c,this.elementCB=null!=n?n:null}return e.prototype.onparserinit=function(e){this.parser=e},e.prototype.onreset=function(){var e;this.dom=[],this.root=new o.Document(this.dom),this.done=!1,this.tagStack=[this.root],this.lastNode=null,this.parser=null!==(e=this.parser)&&void 0!==e?e:null},e.prototype.onend=function(){this.done||(this.done=!0,this.parser=null,this.handleCallback(null))},e.prototype.onerror=function(e){this.handleCallback(e)},e.prototype.onclosetag=function(){this.lastNode=null;var e=this.tagStack.pop();this.options.withEndIndices&&(e.endIndex=this.parser.endIndex),this.elementCB&&this.elementCB(e)},e.prototype.onopentag=function(e,t){var n=this.options.xmlMode?s.ElementType.Tag:void 0,r=new o.Element(e,t,void 0,n);this.addNode(r),this.tagStack.push(r)},e.prototype.ontext=function(e){var t=this.options.normalizeWhitespace,n=this.lastNode;if(n&&n.type===s.ElementType.Text)t?n.data=(n.data+e).replace(a," "):n.data+=e;else{t&&(e=e.replace(a," "));var r=new o.Text(e);this.addNode(r),this.lastNode=r}},e.prototype.oncomment=function(e){if(this.lastNode&&this.lastNode.type===s.ElementType.Comment)this.lastNode.data+=e;else{var t=new o.Comment(e);this.addNode(t),this.lastNode=t}},e.prototype.oncommentend=function(){this.lastNode=null},e.prototype.oncdatastart=function(){var e=new o.Text(""),t=new o.NodeWithChildren(s.ElementType.CDATA,[e]);this.addNode(t),e.parent=t,this.lastNode=e},e.prototype.oncdataend=function(){this.lastNode=null},e.prototype.onprocessinginstruction=function(e,t){var n=new o.ProcessingInstruction(e,t);this.addNode(n)},e.prototype.handleCallback=function(e){if("function"==typeof this.callback)this.callback(e,this.dom);else if(e)throw e},e.prototype.addNode=function(e){var t=this.tagStack[this.tagStack.length-1],n=t.children[t.children.length-1];this.options.withStartIndices&&(e.startIndex=this.parser.startIndex),this.options.withEndIndices&&(e.endIndex=this.parser.endIndex),t.children.push(e),n&&(e.prev=n,n.next=e),e.parent=t,this.lastNode=null},e}();t.DomHandler=l,t.default=l},7790:function(e,t,n){"use strict";var r,i=this&&this.__extends||(r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),s=this&&this.__assign||function(){return(s=Object.assign||function(e){for(var t,n=1,r=arguments.length;n<r;n++)for(var i in t=arguments[n])Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e}).apply(this,arguments)};Object.defineProperty(t,"__esModule",{value:!0}),t.cloneNode=t.hasChildren=t.isDocument=t.isDirective=t.isComment=t.isText=t.isCDATA=t.isTag=t.Element=t.Document=t.NodeWithChildren=t.ProcessingInstruction=t.Comment=t.Text=t.DataNode=t.Node=void 0;var o=n(9960),a=new Map([[o.ElementType.Tag,1],[o.ElementType.Script,1],[o.ElementType.Style,1],[o.ElementType.Directive,1],[o.ElementType.Text,3],[o.ElementType.CDATA,4],[o.ElementType.Comment,8],[o.ElementType.Root,9]]),c=function(){function e(e){this.type=e,this.parent=null,this.prev=null,this.next=null,this.startIndex=null,this.endIndex=null}return Object.defineProperty(e.prototype,"nodeType",{get:function(){var e;return null!==(e=a.get(this.type))&&void 0!==e?e:1},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"parentNode",{get:function(){return this.parent},set:function(e){this.parent=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"previousSibling",{get:function(){return this.prev},set:function(e){this.prev=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"nextSibling",{get:function(){return this.next},set:function(e){this.next=e},enumerable:!1,configurable:!0}),e.prototype.cloneNode=function(e){return void 0===e&&(e=!1),N(this,e)},e}();t.Node=c;var l=function(e){function t(t,n){var r=e.call(this,t)||this;return r.data=n,r}return i(t,e),Object.defineProperty(t.prototype,"nodeValue",{get:function(){return this.data},set:function(e){this.data=e},enumerable:!1,configurable:!0}),t}(c);t.DataNode=l;var u=function(e){function t(t){return e.call(this,o.ElementType.Text,t)||this}return i(t,e),t}(l);t.Text=u;var h=function(e){function t(t){return e.call(this,o.ElementType.Comment,t)||this}return i(t,e),t}(l);t.Comment=h;var p=function(e){function t(t,n){var r=e.call(this,o.ElementType.Directive,n)||this;return r.name=t,r}return i(t,e),t}(l);t.ProcessingInstruction=p;var d=function(e){function t(t,n){var r=e.call(this,t)||this;return r.children=n,r}return i(t,e),Object.defineProperty(t.prototype,"firstChild",{get:function(){var e;return null!==(e=this.children[0])&&void 0!==e?e:null},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"lastChild",{get:function(){return this.children.length>0?this.children[this.children.length-1]:null},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"childNodes",{get:function(){return this.children},set:function(e){this.children=e},enumerable:!1,configurable:!0}),t}(c);t.NodeWithChildren=d;var f=function(e){function t(t){return e.call(this,o.ElementType.Root,t)||this}return i(t,e),t}(d);t.Document=f;var m=function(e){function t(t,n,r,i){void 0===r&&(r=[]),void 0===i&&(i="script"===t?o.ElementType.Script:"style"===t?o.ElementType.Style:o.ElementType.Tag);var s=e.call(this,i,r)||this;return s.name=t,s.attribs=n,s}return i(t,e),Object.defineProperty(t.prototype,"tagName",{get:function(){return this.name},set:function(e){this.name=e},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"attributes",{get:function(){var e=this;return Object.keys(this.attribs).map((function(t){var n,r;return{name:t,value:e.attribs[t],namespace:null===(n=e["x-attribsNamespace"])||void 0===n?void 0:n[t],prefix:null===(r=e["x-attribsPrefix"])||void 0===r?void 0:r[t]}}))},enumerable:!1,configurable:!0}),t}(d);function T(e){return o.isTag(e)}function E(e){return e.type===o.ElementType.CDATA}function _(e){return e.type===o.ElementType.Text}function g(e){return e.type===o.ElementType.Comment}function A(e){return e.type===o.ElementType.Directive}function C(e){return e.type===o.ElementType.Root}function N(e,t){var n;if(void 0===t&&(t=!1),_(e))n=new u(e.data);else if(g(e))n=new h(e.data);else if(T(e)){var r=t?v(e.children):[],i=new m(e.name,s({},e.attribs),r);r.forEach((function(e){return e.parent=i})),e["x-attribsNamespace"]&&(i["x-attribsNamespace"]=s({},e["x-attribsNamespace"])),e["x-attribsPrefix"]&&(i["x-attribsPrefix"]=s({},e["x-attribsPrefix"])),n=i}else if(E(e)){r=t?v(e.children):[];var a=new d(o.ElementType.CDATA,r);r.forEach((function(e){return e.parent=a})),n=a}else if(C(e)){r=t?v(e.children):[];var c=new f(r);r.forEach((function(e){return e.parent=c})),e["x-mode"]&&(c["x-mode"]=e["x-mode"]),n=c}else{if(!A(e))throw new Error("Not implemented yet: "+e.type);var l=new p(e.name,e.data);null!=e["x-name"]&&(l["x-name"]=e["x-name"],l["x-publicId"]=e["x-publicId"],l["x-systemId"]=e["x-systemId"]),n=l}return n.startIndex=e.startIndex,n.endIndex=e.endIndex,n}function v(e){for(var t=e.map((function(e){return N(e,!0)})),n=1;n<t.length;n++)t[n].prev=t[n-1],t[n-1].next=t[n];return t}t.Element=m,t.isTag=T,t.isCDATA=E,t.isText=_,t.isComment=g,t.isDirective=A,t.isDocument=C,t.hasChildren=function(e){return Object.prototype.hasOwnProperty.call(e,"children")},t.cloneNode=N},4975:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.uniqueSort=t.compareDocumentPosition=t.removeSubsets=void 0;var r=n(7915);function i(e,t){var n=[],i=[];if(e===t)return 0;for(var s=r.hasChildren(e)?e:e.parent;s;)n.unshift(s),s=s.parent;for(s=r.hasChildren(t)?t:t.parent;s;)i.unshift(s),s=s.parent;for(var o=Math.min(n.length,i.length),a=0;a<o&&n[a]===i[a];)a++;if(0===a)return 1;var c=n[a-1],l=c.children,u=n[a],h=i[a];return l.indexOf(u)>l.indexOf(h)?c===t?20:4:c===e?10:2}t.removeSubsets=function(e){for(var t=e.length;--t>=0;){var n=e[t];if(t>0&&e.lastIndexOf(n,t-1)>=0)e.splice(t,1);else for(var r=n.parent;r;r=r.parent)if(e.includes(r)){e.splice(t,1);break}}return e},t.compareDocumentPosition=i,t.uniqueSort=function(e){return(e=e.filter((function(e,t,n){return!n.includes(e,t+1)}))).sort((function(e,t){var n=i(e,t);return 2&n?-1:4&n?1:0})),e}},9432:function(e,t,n){"use strict";var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n),Object.defineProperty(e,r,{enumerable:!0,get:function(){return t[n]}})}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),i=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||r(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),t.hasChildren=t.isDocument=t.isComment=t.isText=t.isCDATA=t.isTag=void 0,i(n(3346),t),i(n(5010),t),i(n(6765),t),i(n(8043),t),i(n(3905),t),i(n(4975),t);var s=n(7915);Object.defineProperty(t,"isTag",{enumerable:!0,get:function(){return s.isTag}}),Object.defineProperty(t,"isCDATA",{enumerable:!0,get:function(){return s.isCDATA}}),Object.defineProperty(t,"isText",{enumerable:!0,get:function(){return s.isText}}),Object.defineProperty(t,"isComment",{enumerable:!0,get:function(){return s.isComment}}),Object.defineProperty(t,"isDocument",{enumerable:!0,get:function(){return s.isDocument}}),Object.defineProperty(t,"hasChildren",{enumerable:!0,get:function(){return s.hasChildren}})},3905:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getElementsByTagType=t.getElementsByTagName=t.getElementById=t.getElements=t.testElement=void 0;var r=n(7915),i=n(8043),s={tag_name:function(e){return"function"==typeof e?function(t){return r.isTag(t)&&e(t.name)}:"*"===e?r.isTag:function(t){return r.isTag(t)&&t.name===e}},tag_type:function(e){return"function"==typeof e?function(t){return e(t.type)}:function(t){return t.type===e}},tag_contains:function(e){return"function"==typeof e?function(t){return r.isText(t)&&e(t.data)}:function(t){return r.isText(t)&&t.data===e}}};function o(e,t){return"function"==typeof t?function(n){return r.isTag(n)&&t(n.attribs[e])}:function(n){return r.isTag(n)&&n.attribs[e]===t}}function a(e,t){return function(n){return e(n)||t(n)}}function c(e){var t=Object.keys(e).map((function(t){var n=e[t];return t in s?s[t](n):o(t,n)}));return 0===t.length?null:t.reduce(a)}t.testElement=function(e,t){var n=c(e);return!n||n(t)},t.getElements=function(e,t,n,r){void 0===r&&(r=1/0);var s=c(e);return s?i.filter(s,t,n,r):[]},t.getElementById=function(e,t,n){return void 0===n&&(n=!0),Array.isArray(t)||(t=[t]),i.findOne(o("id",e),t,n)},t.getElementsByTagName=function(e,t,n,r){return void 0===n&&(n=!0),void 0===r&&(r=1/0),i.filter(s.tag_name(e),t,n,r)},t.getElementsByTagType=function(e,t,n,r){return void 0===n&&(n=!0),void 0===r&&(r=1/0),i.filter(s.tag_type(e),t,n,r)}},6765:(e,t)=>{"use strict";function n(e){if(e.prev&&(e.prev.next=e.next),e.next&&(e.next.prev=e.prev),e.parent){var t=e.parent.children;t.splice(t.lastIndexOf(e),1)}}Object.defineProperty(t,"__esModule",{value:!0}),t.prepend=t.prependChild=t.append=t.appendChild=t.replaceElement=t.removeElement=void 0,t.removeElement=n,t.replaceElement=function(e,t){var n=t.prev=e.prev;n&&(n.next=t);var r=t.next=e.next;r&&(r.prev=t);var i=t.parent=e.parent;if(i){var s=i.children;s[s.lastIndexOf(e)]=t}},t.appendChild=function(e,t){if(n(t),t.next=null,t.parent=e,e.children.push(t)>1){var r=e.children[e.children.length-2];r.next=t,t.prev=r}else t.prev=null},t.append=function(e,t){n(t);var r=e.parent,i=e.next;if(t.next=i,t.prev=e,e.next=t,t.parent=r,i){if(i.prev=t,r){var s=r.children;s.splice(s.lastIndexOf(i),0,t)}}else r&&r.children.push(t)},t.prependChild=function(e,t){if(n(t),t.parent=e,t.prev=null,1!==e.children.unshift(t)){var r=e.children[1];r.prev=t,t.next=r}else t.next=null},t.prepend=function(e,t){n(t);var r=e.parent;if(r){var i=r.children;i.splice(i.indexOf(e),0,t)}e.prev&&(e.prev.next=t),t.parent=r,t.prev=e.prev,t.next=e,e.prev=t}},8043:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.findAll=t.existsOne=t.findOne=t.findOneChild=t.find=t.filter=void 0;var r=n(7915);function i(e,t,n,s){for(var o=[],a=0,c=t;a<c.length;a++){var l=c[a];if(e(l)&&(o.push(l),--s<=0))break;if(n&&r.hasChildren(l)&&l.children.length>0){var u=i(e,l.children,n,s);if(o.push.apply(o,u),(s-=u.length)<=0)break}}return o}t.filter=function(e,t,n,r){return void 0===n&&(n=!0),void 0===r&&(r=1/0),Array.isArray(t)||(t=[t]),i(e,t,n,r)},t.find=i,t.findOneChild=function(e,t){return t.find(e)},t.findOne=function e(t,n,i){void 0===i&&(i=!0);for(var s=null,o=0;o<n.length&&!s;o++){var a=n[o];r.isTag(a)&&(t(a)?s=a:i&&a.children.length>0&&(s=e(t,a.children)))}return s},t.existsOne=function e(t,n){return n.some((function(n){return r.isTag(n)&&(t(n)||n.children.length>0&&e(t,n.children))}))},t.findAll=function(e,t){for(var n,i,s=[],o=t.filter(r.isTag);i=o.shift();){var a=null===(n=i.children)||void 0===n?void 0:n.filter(r.isTag);a&&a.length>0&&o.unshift.apply(o,a),e(i)&&s.push(i)}return s}},3346:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.innerText=t.textContent=t.getText=t.getInnerHTML=t.getOuterHTML=void 0;var i=n(7915),s=r(n(7220)),o=n(9960);function a(e,t){return s.default(e,t)}t.getOuterHTML=a,t.getInnerHTML=function(e,t){return i.hasChildren(e)?e.children.map((function(e){return a(e,t)})).join(""):""},t.getText=function e(t){return Array.isArray(t)?t.map(e).join(""):i.isTag(t)?"br"===t.name?"\n":e(t.children):i.isCDATA(t)?e(t.children):i.isText(t)?t.data:""},t.textContent=function e(t){return Array.isArray(t)?t.map(e).join(""):i.isTag(t)||i.isCDATA(t)?e(t.children):i.isText(t)?t.data:""},t.innerText=function e(t){return Array.isArray(t)?t.map(e).join(""):i.hasChildren(t)&&t.type===o.ElementType.Tag||i.isCDATA(t)?e(t.children):i.isText(t)?t.data:""}},5010:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.prevElementSibling=t.nextElementSibling=t.getName=t.hasAttrib=t.getAttributeValue=t.getSiblings=t.getParent=t.getChildren=void 0;var r=n(7915),i=[];function s(e){var t;return null!==(t=e.children)&&void 0!==t?t:i}function o(e){return e.parent||null}t.getChildren=s,t.getParent=o,t.getSiblings=function(e){var t=o(e);if(null!=t)return s(t);for(var n=[e],r=e.prev,i=e.next;null!=r;)n.unshift(r),r=r.prev;for(;null!=i;)n.push(i),i=i.next;return n},t.getAttributeValue=function(e,t){var n;return null===(n=e.attribs)||void 0===n?void 0:n[t]},t.hasAttrib=function(e,t){return null!=e.attribs&&Object.prototype.hasOwnProperty.call(e.attribs,t)&&null!=e.attribs[t]},t.getName=function(e){return e.name},t.nextElementSibling=function(e){for(var t=e.next;null!==t&&!r.isTag(t);)t=t.next;return t},t.prevElementSibling=function(e){for(var t=e.prev;null!==t&&!r.isTag(t);)t=t.prev;return t}},4076:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.decodeHTML=t.decodeHTMLStrict=t.decodeXML=void 0;var i=r(n(4007)),s=r(n(7802)),o=r(n(2228)),a=r(n(26)),c=/&(?:[a-zA-Z0-9]+|#[xX][\da-fA-F]+|#\d+);/g;function l(e){var t=h(e);return function(e){return String(e).replace(c,t)}}t.decodeXML=l(o.default),t.decodeHTMLStrict=l(i.default);var u=function(e,t){return e<t?1:-1};function h(e){return function(t){if("#"===t.charAt(1)){var n=t.charAt(2);return"X"===n||"x"===n?a.default(parseInt(t.substr(3),16)):a.default(parseInt(t.substr(2),10))}return e[t.slice(1,-1)]||t}}t.decodeHTML=function(){for(var e=Object.keys(s.default).sort(u),t=Object.keys(i.default).sort(u),n=0,r=0;n<t.length;n++)e[r]===t[n]?(t[n]+=";?",r++):t[n]+=";";var o=new RegExp("&(?:"+t.join("|")+"|#[xX][\\da-fA-F]+;?|#\\d+;?)","g"),a=h(i.default);function c(e){return";"!==e.substr(-1)&&(e+=";"),a(e)}return function(e){return String(e).replace(o,c)}}()},26:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});var i=r(n(4589)),s=String.fromCodePoint||function(e){var t="";return e>65535&&(e-=65536,t+=String.fromCharCode(e>>>10&1023|55296),e=56320|1023&e),t+String.fromCharCode(e)};t.default=function(e){return e>=55296&&e<=57343||e>1114111?"�":(e in i.default&&(e=i.default[e]),s(e))}},7322:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.escapeUTF8=t.escape=t.encodeNonAsciiHTML=t.encodeHTML=t.encodeXML=void 0;var i=u(r(n(2228)).default),s=h(i);t.encodeXML=T(i);var o,a,c=u(r(n(4007)).default),l=h(c);function u(e){return Object.keys(e).sort().reduce((function(t,n){return t[e[n]]="&"+n+";",t}),{})}function h(e){for(var t=[],n=[],r=0,i=Object.keys(e);r<i.length;r++){var s=i[r];1===s.length?t.push("\\"+s):n.push(s)}t.sort();for(var o=0;o<t.length-1;o++){for(var a=o;a<t.length-1&&t[a].charCodeAt(1)+1===t[a+1].charCodeAt(1);)a+=1;var c=1+a-o;c<3||t.splice(o,c,t[o]+"-"+t[a])}return n.unshift("["+t.join("")+"]"),new RegExp(n.join("|"),"g")}t.encodeHTML=(o=c,a=l,function(e){return e.replace(a,(function(e){return o[e]})).replace(p,f)}),t.encodeNonAsciiHTML=T(c);var p=/(?:[\x80-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g,d=null!=String.prototype.codePointAt?function(e){return e.codePointAt(0)}:function(e){return 1024*(e.charCodeAt(0)-55296)+e.charCodeAt(1)-56320+65536};function f(e){return"&#x"+(e.length>1?d(e):e.charCodeAt(0)).toString(16).toUpperCase()+";"}var m=new RegExp(s.source+"|"+p.source,"g");function T(e){return function(t){return t.replace(m,(function(t){return e[t]||f(t)}))}}t.escape=function(e){return e.replace(m,f)},t.escapeUTF8=function(e){return e.replace(s,f)}},5863:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decodeXMLStrict=t.decodeHTML5Strict=t.decodeHTML4Strict=t.decodeHTML5=t.decodeHTML4=t.decodeHTMLStrict=t.decodeHTML=t.decodeXML=t.encodeHTML5=t.encodeHTML4=t.escapeUTF8=t.escape=t.encodeNonAsciiHTML=t.encodeHTML=t.encodeXML=t.encode=t.decodeStrict=t.decode=void 0;var r=n(4076),i=n(7322);t.decode=function(e,t){return(!t||t<=0?r.decodeXML:r.decodeHTML)(e)},t.decodeStrict=function(e,t){return(!t||t<=0?r.decodeXML:r.decodeHTMLStrict)(e)},t.encode=function(e,t){return(!t||t<=0?i.encodeXML:i.encodeHTML)(e)};var s=n(7322);Object.defineProperty(t,"encodeXML",{enumerable:!0,get:function(){return s.encodeXML}}),Object.defineProperty(t,"encodeHTML",{enumerable:!0,get:function(){return s.encodeHTML}}),Object.defineProperty(t,"encodeNonAsciiHTML",{enumerable:!0,get:function(){return s.encodeNonAsciiHTML}}),Object.defineProperty(t,"escape",{enumerable:!0,get:function(){return s.escape}}),Object.defineProperty(t,"escapeUTF8",{enumerable:!0,get:function(){return s.escapeUTF8}}),Object.defineProperty(t,"encodeHTML4",{enumerable:!0,get:function(){return s.encodeHTML}}),Object.defineProperty(t,"encodeHTML5",{enumerable:!0,get:function(){return s.encodeHTML}});var o=n(4076);Object.defineProperty(t,"decodeXML",{enumerable:!0,get:function(){return o.decodeXML}}),Object.defineProperty(t,"decodeHTML",{enumerable:!0,get:function(){return o.decodeHTML}}),Object.defineProperty(t,"decodeHTMLStrict",{enumerable:!0,get:function(){return o.decodeHTMLStrict}}),Object.defineProperty(t,"decodeHTML4",{enumerable:!0,get:function(){return o.decodeHTML}}),Object.defineProperty(t,"decodeHTML5",{enumerable:!0,get:function(){return o.decodeHTML}}),Object.defineProperty(t,"decodeHTML4Strict",{enumerable:!0,get:function(){return o.decodeHTMLStrict}}),Object.defineProperty(t,"decodeHTML5Strict",{enumerable:!0,get:function(){return o.decodeHTMLStrict}}),Object.defineProperty(t,"decodeXMLStrict",{enumerable:!0,get:function(){return o.decodeXML}})},4589:e=>{"use strict";e.exports=JSON.parse('{"0":65533,"128":8364,"130":8218,"131":402,"132":8222,"133":8230,"134":8224,"135":8225,"136":710,"137":8240,"138":352,"139":8249,"140":338,"142":381,"145":8216,"146":8217,"147":8220,"148":8221,"149":8226,"150":8211,"151":8212,"152":732,"153":8482,"154":353,"155":8250,"156":339,"158":382,"159":376}')},4007:e=>{"use strict";e.exports=JSON.parse('{"Aacute":"Á","aacute":"á","Abreve":"Ă","abreve":"ă","ac":"∾","acd":"∿","acE":"∾̳","Acirc":"Â","acirc":"â","acute":"´","Acy":"А","acy":"а","AElig":"Æ","aelig":"æ","af":"⁡","Afr":"𝔄","afr":"𝔞","Agrave":"À","agrave":"à","alefsym":"ℵ","aleph":"ℵ","Alpha":"Α","alpha":"α","Amacr":"Ā","amacr":"ā","amalg":"⨿","amp":"&","AMP":"&","andand":"⩕","And":"⩓","and":"∧","andd":"⩜","andslope":"⩘","andv":"⩚","ang":"∠","ange":"⦤","angle":"∠","angmsdaa":"⦨","angmsdab":"⦩","angmsdac":"⦪","angmsdad":"⦫","angmsdae":"⦬","angmsdaf":"⦭","angmsdag":"⦮","angmsdah":"⦯","angmsd":"∡","angrt":"∟","angrtvb":"⊾","angrtvbd":"⦝","angsph":"∢","angst":"Å","angzarr":"⍼","Aogon":"Ą","aogon":"ą","Aopf":"𝔸","aopf":"𝕒","apacir":"⩯","ap":"≈","apE":"⩰","ape":"≊","apid":"≋","apos":"\'","ApplyFunction":"⁡","approx":"≈","approxeq":"≊","Aring":"Å","aring":"å","Ascr":"𝒜","ascr":"𝒶","Assign":"≔","ast":"*","asymp":"≈","asympeq":"≍","Atilde":"Ã","atilde":"ã","Auml":"Ä","auml":"ä","awconint":"∳","awint":"⨑","backcong":"≌","backepsilon":"϶","backprime":"‵","backsim":"∽","backsimeq":"⋍","Backslash":"∖","Barv":"⫧","barvee":"⊽","barwed":"⌅","Barwed":"⌆","barwedge":"⌅","bbrk":"⎵","bbrktbrk":"⎶","bcong":"≌","Bcy":"Б","bcy":"б","bdquo":"„","becaus":"∵","because":"∵","Because":"∵","bemptyv":"⦰","bepsi":"϶","bernou":"ℬ","Bernoullis":"ℬ","Beta":"Β","beta":"β","beth":"ℶ","between":"≬","Bfr":"𝔅","bfr":"𝔟","bigcap":"⋂","bigcirc":"◯","bigcup":"⋃","bigodot":"⨀","bigoplus":"⨁","bigotimes":"⨂","bigsqcup":"⨆","bigstar":"★","bigtriangledown":"▽","bigtriangleup":"△","biguplus":"⨄","bigvee":"⋁","bigwedge":"⋀","bkarow":"⤍","blacklozenge":"⧫","blacksquare":"▪","blacktriangle":"▴","blacktriangledown":"▾","blacktriangleleft":"◂","blacktriangleright":"▸","blank":"␣","blk12":"▒","blk14":"░","blk34":"▓","block":"█","bne":"=⃥","bnequiv":"≡⃥","bNot":"⫭","bnot":"⌐","Bopf":"𝔹","bopf":"𝕓","bot":"⊥","bottom":"⊥","bowtie":"⋈","boxbox":"⧉","boxdl":"┐","boxdL":"╕","boxDl":"╖","boxDL":"╗","boxdr":"┌","boxdR":"╒","boxDr":"╓","boxDR":"╔","boxh":"─","boxH":"═","boxhd":"┬","boxHd":"╤","boxhD":"╥","boxHD":"╦","boxhu":"┴","boxHu":"╧","boxhU":"╨","boxHU":"╩","boxminus":"⊟","boxplus":"⊞","boxtimes":"⊠","boxul":"┘","boxuL":"╛","boxUl":"╜","boxUL":"╝","boxur":"└","boxuR":"╘","boxUr":"╙","boxUR":"╚","boxv":"│","boxV":"║","boxvh":"┼","boxvH":"╪","boxVh":"╫","boxVH":"╬","boxvl":"┤","boxvL":"╡","boxVl":"╢","boxVL":"╣","boxvr":"├","boxvR":"╞","boxVr":"╟","boxVR":"╠","bprime":"‵","breve":"˘","Breve":"˘","brvbar":"¦","bscr":"𝒷","Bscr":"ℬ","bsemi":"⁏","bsim":"∽","bsime":"⋍","bsolb":"⧅","bsol":"\\\\","bsolhsub":"⟈","bull":"•","bullet":"•","bump":"≎","bumpE":"⪮","bumpe":"≏","Bumpeq":"≎","bumpeq":"≏","Cacute":"Ć","cacute":"ć","capand":"⩄","capbrcup":"⩉","capcap":"⩋","cap":"∩","Cap":"⋒","capcup":"⩇","capdot":"⩀","CapitalDifferentialD":"ⅅ","caps":"∩︀","caret":"⁁","caron":"ˇ","Cayleys":"ℭ","ccaps":"⩍","Ccaron":"Č","ccaron":"č","Ccedil":"Ç","ccedil":"ç","Ccirc":"Ĉ","ccirc":"ĉ","Cconint":"∰","ccups":"⩌","ccupssm":"⩐","Cdot":"Ċ","cdot":"ċ","cedil":"¸","Cedilla":"¸","cemptyv":"⦲","cent":"¢","centerdot":"·","CenterDot":"·","cfr":"𝔠","Cfr":"ℭ","CHcy":"Ч","chcy":"ч","check":"✓","checkmark":"✓","Chi":"Χ","chi":"χ","circ":"ˆ","circeq":"≗","circlearrowleft":"↺","circlearrowright":"↻","circledast":"⊛","circledcirc":"⊚","circleddash":"⊝","CircleDot":"⊙","circledR":"®","circledS":"Ⓢ","CircleMinus":"⊖","CirclePlus":"⊕","CircleTimes":"⊗","cir":"○","cirE":"⧃","cire":"≗","cirfnint":"⨐","cirmid":"⫯","cirscir":"⧂","ClockwiseContourIntegral":"∲","CloseCurlyDoubleQuote":"”","CloseCurlyQuote":"’","clubs":"♣","clubsuit":"♣","colon":":","Colon":"∷","Colone":"⩴","colone":"≔","coloneq":"≔","comma":",","commat":"@","comp":"∁","compfn":"∘","complement":"∁","complexes":"ℂ","cong":"≅","congdot":"⩭","Congruent":"≡","conint":"∮","Conint":"∯","ContourIntegral":"∮","copf":"𝕔","Copf":"ℂ","coprod":"∐","Coproduct":"∐","copy":"©","COPY":"©","copysr":"℗","CounterClockwiseContourIntegral":"∳","crarr":"↵","cross":"✗","Cross":"⨯","Cscr":"𝒞","cscr":"𝒸","csub":"⫏","csube":"⫑","csup":"⫐","csupe":"⫒","ctdot":"⋯","cudarrl":"⤸","cudarrr":"⤵","cuepr":"⋞","cuesc":"⋟","cularr":"↶","cularrp":"⤽","cupbrcap":"⩈","cupcap":"⩆","CupCap":"≍","cup":"∪","Cup":"⋓","cupcup":"⩊","cupdot":"⊍","cupor":"⩅","cups":"∪︀","curarr":"↷","curarrm":"⤼","curlyeqprec":"⋞","curlyeqsucc":"⋟","curlyvee":"⋎","curlywedge":"⋏","curren":"¤","curvearrowleft":"↶","curvearrowright":"↷","cuvee":"⋎","cuwed":"⋏","cwconint":"∲","cwint":"∱","cylcty":"⌭","dagger":"†","Dagger":"‡","daleth":"ℸ","darr":"↓","Darr":"↡","dArr":"⇓","dash":"‐","Dashv":"⫤","dashv":"⊣","dbkarow":"⤏","dblac":"˝","Dcaron":"Ď","dcaron":"ď","Dcy":"Д","dcy":"д","ddagger":"‡","ddarr":"⇊","DD":"ⅅ","dd":"ⅆ","DDotrahd":"⤑","ddotseq":"⩷","deg":"°","Del":"∇","Delta":"Δ","delta":"δ","demptyv":"⦱","dfisht":"⥿","Dfr":"𝔇","dfr":"𝔡","dHar":"⥥","dharl":"⇃","dharr":"⇂","DiacriticalAcute":"´","DiacriticalDot":"˙","DiacriticalDoubleAcute":"˝","DiacriticalGrave":"`","DiacriticalTilde":"˜","diam":"⋄","diamond":"⋄","Diamond":"⋄","diamondsuit":"♦","diams":"♦","die":"¨","DifferentialD":"ⅆ","digamma":"ϝ","disin":"⋲","div":"÷","divide":"÷","divideontimes":"⋇","divonx":"⋇","DJcy":"Ђ","djcy":"ђ","dlcorn":"⌞","dlcrop":"⌍","dollar":"$","Dopf":"𝔻","dopf":"𝕕","Dot":"¨","dot":"˙","DotDot":"⃜","doteq":"≐","doteqdot":"≑","DotEqual":"≐","dotminus":"∸","dotplus":"∔","dotsquare":"⊡","doublebarwedge":"⌆","DoubleContourIntegral":"∯","DoubleDot":"¨","DoubleDownArrow":"⇓","DoubleLeftArrow":"⇐","DoubleLeftRightArrow":"⇔","DoubleLeftTee":"⫤","DoubleLongLeftArrow":"⟸","DoubleLongLeftRightArrow":"⟺","DoubleLongRightArrow":"⟹","DoubleRightArrow":"⇒","DoubleRightTee":"⊨","DoubleUpArrow":"⇑","DoubleUpDownArrow":"⇕","DoubleVerticalBar":"∥","DownArrowBar":"⤓","downarrow":"↓","DownArrow":"↓","Downarrow":"⇓","DownArrowUpArrow":"⇵","DownBreve":"̑","downdownarrows":"⇊","downharpoonleft":"⇃","downharpoonright":"⇂","DownLeftRightVector":"⥐","DownLeftTeeVector":"⥞","DownLeftVectorBar":"⥖","DownLeftVector":"↽","DownRightTeeVector":"⥟","DownRightVectorBar":"⥗","DownRightVector":"⇁","DownTeeArrow":"↧","DownTee":"⊤","drbkarow":"⤐","drcorn":"⌟","drcrop":"⌌","Dscr":"𝒟","dscr":"𝒹","DScy":"Ѕ","dscy":"ѕ","dsol":"⧶","Dstrok":"Đ","dstrok":"đ","dtdot":"⋱","dtri":"▿","dtrif":"▾","duarr":"⇵","duhar":"⥯","dwangle":"⦦","DZcy":"Џ","dzcy":"џ","dzigrarr":"⟿","Eacute":"É","eacute":"é","easter":"⩮","Ecaron":"Ě","ecaron":"ě","Ecirc":"Ê","ecirc":"ê","ecir":"≖","ecolon":"≕","Ecy":"Э","ecy":"э","eDDot":"⩷","Edot":"Ė","edot":"ė","eDot":"≑","ee":"ⅇ","efDot":"≒","Efr":"𝔈","efr":"𝔢","eg":"⪚","Egrave":"È","egrave":"è","egs":"⪖","egsdot":"⪘","el":"⪙","Element":"∈","elinters":"⏧","ell":"ℓ","els":"⪕","elsdot":"⪗","Emacr":"Ē","emacr":"ē","empty":"∅","emptyset":"∅","EmptySmallSquare":"◻","emptyv":"∅","EmptyVerySmallSquare":"▫","emsp13":" ","emsp14":" ","emsp":" ","ENG":"Ŋ","eng":"ŋ","ensp":" ","Eogon":"Ę","eogon":"ę","Eopf":"𝔼","eopf":"𝕖","epar":"⋕","eparsl":"⧣","eplus":"⩱","epsi":"ε","Epsilon":"Ε","epsilon":"ε","epsiv":"ϵ","eqcirc":"≖","eqcolon":"≕","eqsim":"≂","eqslantgtr":"⪖","eqslantless":"⪕","Equal":"⩵","equals":"=","EqualTilde":"≂","equest":"≟","Equilibrium":"⇌","equiv":"≡","equivDD":"⩸","eqvparsl":"⧥","erarr":"⥱","erDot":"≓","escr":"ℯ","Escr":"ℰ","esdot":"≐","Esim":"⩳","esim":"≂","Eta":"Η","eta":"η","ETH":"Ð","eth":"ð","Euml":"Ë","euml":"ë","euro":"€","excl":"!","exist":"∃","Exists":"∃","expectation":"ℰ","exponentiale":"ⅇ","ExponentialE":"ⅇ","fallingdotseq":"≒","Fcy":"Ф","fcy":"ф","female":"♀","ffilig":"ffi","fflig":"ff","ffllig":"ffl","Ffr":"𝔉","ffr":"𝔣","filig":"fi","FilledSmallSquare":"◼","FilledVerySmallSquare":"▪","fjlig":"fj","flat":"♭","fllig":"fl","fltns":"▱","fnof":"ƒ","Fopf":"𝔽","fopf":"𝕗","forall":"∀","ForAll":"∀","fork":"⋔","forkv":"⫙","Fouriertrf":"ℱ","fpartint":"⨍","frac12":"½","frac13":"⅓","frac14":"¼","frac15":"⅕","frac16":"⅙","frac18":"⅛","frac23":"⅔","frac25":"⅖","frac34":"¾","frac35":"⅗","frac38":"⅜","frac45":"⅘","frac56":"⅚","frac58":"⅝","frac78":"⅞","frasl":"⁄","frown":"⌢","fscr":"𝒻","Fscr":"ℱ","gacute":"ǵ","Gamma":"Γ","gamma":"γ","Gammad":"Ϝ","gammad":"ϝ","gap":"⪆","Gbreve":"Ğ","gbreve":"ğ","Gcedil":"Ģ","Gcirc":"Ĝ","gcirc":"ĝ","Gcy":"Г","gcy":"г","Gdot":"Ġ","gdot":"ġ","ge":"≥","gE":"≧","gEl":"⪌","gel":"⋛","geq":"≥","geqq":"≧","geqslant":"⩾","gescc":"⪩","ges":"⩾","gesdot":"⪀","gesdoto":"⪂","gesdotol":"⪄","gesl":"⋛︀","gesles":"⪔","Gfr":"𝔊","gfr":"𝔤","gg":"≫","Gg":"⋙","ggg":"⋙","gimel":"ℷ","GJcy":"Ѓ","gjcy":"ѓ","gla":"⪥","gl":"≷","glE":"⪒","glj":"⪤","gnap":"⪊","gnapprox":"⪊","gne":"⪈","gnE":"≩","gneq":"⪈","gneqq":"≩","gnsim":"⋧","Gopf":"𝔾","gopf":"𝕘","grave":"`","GreaterEqual":"≥","GreaterEqualLess":"⋛","GreaterFullEqual":"≧","GreaterGreater":"⪢","GreaterLess":"≷","GreaterSlantEqual":"⩾","GreaterTilde":"≳","Gscr":"𝒢","gscr":"ℊ","gsim":"≳","gsime":"⪎","gsiml":"⪐","gtcc":"⪧","gtcir":"⩺","gt":">","GT":">","Gt":"≫","gtdot":"⋗","gtlPar":"⦕","gtquest":"⩼","gtrapprox":"⪆","gtrarr":"⥸","gtrdot":"⋗","gtreqless":"⋛","gtreqqless":"⪌","gtrless":"≷","gtrsim":"≳","gvertneqq":"≩︀","gvnE":"≩︀","Hacek":"ˇ","hairsp":" ","half":"½","hamilt":"ℋ","HARDcy":"Ъ","hardcy":"ъ","harrcir":"⥈","harr":"↔","hArr":"⇔","harrw":"↭","Hat":"^","hbar":"ℏ","Hcirc":"Ĥ","hcirc":"ĥ","hearts":"♥","heartsuit":"♥","hellip":"…","hercon":"⊹","hfr":"𝔥","Hfr":"ℌ","HilbertSpace":"ℋ","hksearow":"⤥","hkswarow":"⤦","hoarr":"⇿","homtht":"∻","hookleftarrow":"↩","hookrightarrow":"↪","hopf":"𝕙","Hopf":"ℍ","horbar":"―","HorizontalLine":"─","hscr":"𝒽","Hscr":"ℋ","hslash":"ℏ","Hstrok":"Ħ","hstrok":"ħ","HumpDownHump":"≎","HumpEqual":"≏","hybull":"⁃","hyphen":"‐","Iacute":"Í","iacute":"í","ic":"⁣","Icirc":"Î","icirc":"î","Icy":"И","icy":"и","Idot":"İ","IEcy":"Е","iecy":"е","iexcl":"¡","iff":"⇔","ifr":"𝔦","Ifr":"ℑ","Igrave":"Ì","igrave":"ì","ii":"ⅈ","iiiint":"⨌","iiint":"∭","iinfin":"⧜","iiota":"℩","IJlig":"IJ","ijlig":"ij","Imacr":"Ī","imacr":"ī","image":"ℑ","ImaginaryI":"ⅈ","imagline":"ℐ","imagpart":"ℑ","imath":"ı","Im":"ℑ","imof":"⊷","imped":"Ƶ","Implies":"⇒","incare":"℅","in":"∈","infin":"∞","infintie":"⧝","inodot":"ı","intcal":"⊺","int":"∫","Int":"∬","integers":"ℤ","Integral":"∫","intercal":"⊺","Intersection":"⋂","intlarhk":"⨗","intprod":"⨼","InvisibleComma":"⁣","InvisibleTimes":"⁢","IOcy":"Ё","iocy":"ё","Iogon":"Į","iogon":"į","Iopf":"𝕀","iopf":"𝕚","Iota":"Ι","iota":"ι","iprod":"⨼","iquest":"¿","iscr":"𝒾","Iscr":"ℐ","isin":"∈","isindot":"⋵","isinE":"⋹","isins":"⋴","isinsv":"⋳","isinv":"∈","it":"⁢","Itilde":"Ĩ","itilde":"ĩ","Iukcy":"І","iukcy":"і","Iuml":"Ï","iuml":"ï","Jcirc":"Ĵ","jcirc":"ĵ","Jcy":"Й","jcy":"й","Jfr":"𝔍","jfr":"𝔧","jmath":"ȷ","Jopf":"𝕁","jopf":"𝕛","Jscr":"𝒥","jscr":"𝒿","Jsercy":"Ј","jsercy":"ј","Jukcy":"Є","jukcy":"є","Kappa":"Κ","kappa":"κ","kappav":"ϰ","Kcedil":"Ķ","kcedil":"ķ","Kcy":"К","kcy":"к","Kfr":"𝔎","kfr":"𝔨","kgreen":"ĸ","KHcy":"Х","khcy":"х","KJcy":"Ќ","kjcy":"ќ","Kopf":"𝕂","kopf":"𝕜","Kscr":"𝒦","kscr":"𝓀","lAarr":"⇚","Lacute":"Ĺ","lacute":"ĺ","laemptyv":"⦴","lagran":"ℒ","Lambda":"Λ","lambda":"λ","lang":"⟨","Lang":"⟪","langd":"⦑","langle":"⟨","lap":"⪅","Laplacetrf":"ℒ","laquo":"«","larrb":"⇤","larrbfs":"⤟","larr":"←","Larr":"↞","lArr":"⇐","larrfs":"⤝","larrhk":"↩","larrlp":"↫","larrpl":"⤹","larrsim":"⥳","larrtl":"↢","latail":"⤙","lAtail":"⤛","lat":"⪫","late":"⪭","lates":"⪭︀","lbarr":"⤌","lBarr":"⤎","lbbrk":"❲","lbrace":"{","lbrack":"[","lbrke":"⦋","lbrksld":"⦏","lbrkslu":"⦍","Lcaron":"Ľ","lcaron":"ľ","Lcedil":"Ļ","lcedil":"ļ","lceil":"⌈","lcub":"{","Lcy":"Л","lcy":"л","ldca":"⤶","ldquo":"“","ldquor":"„","ldrdhar":"⥧","ldrushar":"⥋","ldsh":"↲","le":"≤","lE":"≦","LeftAngleBracket":"⟨","LeftArrowBar":"⇤","leftarrow":"←","LeftArrow":"←","Leftarrow":"⇐","LeftArrowRightArrow":"⇆","leftarrowtail":"↢","LeftCeiling":"⌈","LeftDoubleBracket":"⟦","LeftDownTeeVector":"⥡","LeftDownVectorBar":"⥙","LeftDownVector":"⇃","LeftFloor":"⌊","leftharpoondown":"↽","leftharpoonup":"↼","leftleftarrows":"⇇","leftrightarrow":"↔","LeftRightArrow":"↔","Leftrightarrow":"⇔","leftrightarrows":"⇆","leftrightharpoons":"⇋","leftrightsquigarrow":"↭","LeftRightVector":"⥎","LeftTeeArrow":"↤","LeftTee":"⊣","LeftTeeVector":"⥚","leftthreetimes":"⋋","LeftTriangleBar":"⧏","LeftTriangle":"⊲","LeftTriangleEqual":"⊴","LeftUpDownVector":"⥑","LeftUpTeeVector":"⥠","LeftUpVectorBar":"⥘","LeftUpVector":"↿","LeftVectorBar":"⥒","LeftVector":"↼","lEg":"⪋","leg":"⋚","leq":"≤","leqq":"≦","leqslant":"⩽","lescc":"⪨","les":"⩽","lesdot":"⩿","lesdoto":"⪁","lesdotor":"⪃","lesg":"⋚︀","lesges":"⪓","lessapprox":"⪅","lessdot":"⋖","lesseqgtr":"⋚","lesseqqgtr":"⪋","LessEqualGreater":"⋚","LessFullEqual":"≦","LessGreater":"≶","lessgtr":"≶","LessLess":"⪡","lesssim":"≲","LessSlantEqual":"⩽","LessTilde":"≲","lfisht":"⥼","lfloor":"⌊","Lfr":"𝔏","lfr":"𝔩","lg":"≶","lgE":"⪑","lHar":"⥢","lhard":"↽","lharu":"↼","lharul":"⥪","lhblk":"▄","LJcy":"Љ","ljcy":"љ","llarr":"⇇","ll":"≪","Ll":"⋘","llcorner":"⌞","Lleftarrow":"⇚","llhard":"⥫","lltri":"◺","Lmidot":"Ŀ","lmidot":"ŀ","lmoustache":"⎰","lmoust":"⎰","lnap":"⪉","lnapprox":"⪉","lne":"⪇","lnE":"≨","lneq":"⪇","lneqq":"≨","lnsim":"⋦","loang":"⟬","loarr":"⇽","lobrk":"⟦","longleftarrow":"⟵","LongLeftArrow":"⟵","Longleftarrow":"⟸","longleftrightarrow":"⟷","LongLeftRightArrow":"⟷","Longleftrightarrow":"⟺","longmapsto":"⟼","longrightarrow":"⟶","LongRightArrow":"⟶","Longrightarrow":"⟹","looparrowleft":"↫","looparrowright":"↬","lopar":"⦅","Lopf":"𝕃","lopf":"𝕝","loplus":"⨭","lotimes":"⨴","lowast":"∗","lowbar":"_","LowerLeftArrow":"↙","LowerRightArrow":"↘","loz":"◊","lozenge":"◊","lozf":"⧫","lpar":"(","lparlt":"⦓","lrarr":"⇆","lrcorner":"⌟","lrhar":"⇋","lrhard":"⥭","lrm":"‎","lrtri":"⊿","lsaquo":"‹","lscr":"𝓁","Lscr":"ℒ","lsh":"↰","Lsh":"↰","lsim":"≲","lsime":"⪍","lsimg":"⪏","lsqb":"[","lsquo":"‘","lsquor":"‚","Lstrok":"Ł","lstrok":"ł","ltcc":"⪦","ltcir":"⩹","lt":"<","LT":"<","Lt":"≪","ltdot":"⋖","lthree":"⋋","ltimes":"⋉","ltlarr":"⥶","ltquest":"⩻","ltri":"◃","ltrie":"⊴","ltrif":"◂","ltrPar":"⦖","lurdshar":"⥊","luruhar":"⥦","lvertneqq":"≨︀","lvnE":"≨︀","macr":"¯","male":"♂","malt":"✠","maltese":"✠","Map":"⤅","map":"↦","mapsto":"↦","mapstodown":"↧","mapstoleft":"↤","mapstoup":"↥","marker":"▮","mcomma":"⨩","Mcy":"М","mcy":"м","mdash":"—","mDDot":"∺","measuredangle":"∡","MediumSpace":" ","Mellintrf":"ℳ","Mfr":"𝔐","mfr":"𝔪","mho":"℧","micro":"µ","midast":"*","midcir":"⫰","mid":"∣","middot":"·","minusb":"⊟","minus":"−","minusd":"∸","minusdu":"⨪","MinusPlus":"∓","mlcp":"⫛","mldr":"…","mnplus":"∓","models":"⊧","Mopf":"𝕄","mopf":"𝕞","mp":"∓","mscr":"𝓂","Mscr":"ℳ","mstpos":"∾","Mu":"Μ","mu":"μ","multimap":"⊸","mumap":"⊸","nabla":"∇","Nacute":"Ń","nacute":"ń","nang":"∠⃒","nap":"≉","napE":"⩰̸","napid":"≋̸","napos":"ʼn","napprox":"≉","natural":"♮","naturals":"ℕ","natur":"♮","nbsp":" ","nbump":"≎̸","nbumpe":"≏̸","ncap":"⩃","Ncaron":"Ň","ncaron":"ň","Ncedil":"Ņ","ncedil":"ņ","ncong":"≇","ncongdot":"⩭̸","ncup":"⩂","Ncy":"Н","ncy":"н","ndash":"–","nearhk":"⤤","nearr":"↗","neArr":"⇗","nearrow":"↗","ne":"≠","nedot":"≐̸","NegativeMediumSpace":"​","NegativeThickSpace":"​","NegativeThinSpace":"​","NegativeVeryThinSpace":"​","nequiv":"≢","nesear":"⤨","nesim":"≂̸","NestedGreaterGreater":"≫","NestedLessLess":"≪","NewLine":"\\n","nexist":"∄","nexists":"∄","Nfr":"𝔑","nfr":"𝔫","ngE":"≧̸","nge":"≱","ngeq":"≱","ngeqq":"≧̸","ngeqslant":"⩾̸","nges":"⩾̸","nGg":"⋙̸","ngsim":"≵","nGt":"≫⃒","ngt":"≯","ngtr":"≯","nGtv":"≫̸","nharr":"↮","nhArr":"⇎","nhpar":"⫲","ni":"∋","nis":"⋼","nisd":"⋺","niv":"∋","NJcy":"Њ","njcy":"њ","nlarr":"↚","nlArr":"⇍","nldr":"‥","nlE":"≦̸","nle":"≰","nleftarrow":"↚","nLeftarrow":"⇍","nleftrightarrow":"↮","nLeftrightarrow":"⇎","nleq":"≰","nleqq":"≦̸","nleqslant":"⩽̸","nles":"⩽̸","nless":"≮","nLl":"⋘̸","nlsim":"≴","nLt":"≪⃒","nlt":"≮","nltri":"⋪","nltrie":"⋬","nLtv":"≪̸","nmid":"∤","NoBreak":"⁠","NonBreakingSpace":" ","nopf":"𝕟","Nopf":"ℕ","Not":"⫬","not":"¬","NotCongruent":"≢","NotCupCap":"≭","NotDoubleVerticalBar":"∦","NotElement":"∉","NotEqual":"≠","NotEqualTilde":"≂̸","NotExists":"∄","NotGreater":"≯","NotGreaterEqual":"≱","NotGreaterFullEqual":"≧̸","NotGreaterGreater":"≫̸","NotGreaterLess":"≹","NotGreaterSlantEqual":"⩾̸","NotGreaterTilde":"≵","NotHumpDownHump":"≎̸","NotHumpEqual":"≏̸","notin":"∉","notindot":"⋵̸","notinE":"⋹̸","notinva":"∉","notinvb":"⋷","notinvc":"⋶","NotLeftTriangleBar":"⧏̸","NotLeftTriangle":"⋪","NotLeftTriangleEqual":"⋬","NotLess":"≮","NotLessEqual":"≰","NotLessGreater":"≸","NotLessLess":"≪̸","NotLessSlantEqual":"⩽̸","NotLessTilde":"≴","NotNestedGreaterGreater":"⪢̸","NotNestedLessLess":"⪡̸","notni":"∌","notniva":"∌","notnivb":"⋾","notnivc":"⋽","NotPrecedes":"⊀","NotPrecedesEqual":"⪯̸","NotPrecedesSlantEqual":"⋠","NotReverseElement":"∌","NotRightTriangleBar":"⧐̸","NotRightTriangle":"⋫","NotRightTriangleEqual":"⋭","NotSquareSubset":"⊏̸","NotSquareSubsetEqual":"⋢","NotSquareSuperset":"⊐̸","NotSquareSupersetEqual":"⋣","NotSubset":"⊂⃒","NotSubsetEqual":"⊈","NotSucceeds":"⊁","NotSucceedsEqual":"⪰̸","NotSucceedsSlantEqual":"⋡","NotSucceedsTilde":"≿̸","NotSuperset":"⊃⃒","NotSupersetEqual":"⊉","NotTilde":"≁","NotTildeEqual":"≄","NotTildeFullEqual":"≇","NotTildeTilde":"≉","NotVerticalBar":"∤","nparallel":"∦","npar":"∦","nparsl":"⫽⃥","npart":"∂̸","npolint":"⨔","npr":"⊀","nprcue":"⋠","nprec":"⊀","npreceq":"⪯̸","npre":"⪯̸","nrarrc":"⤳̸","nrarr":"↛","nrArr":"⇏","nrarrw":"↝̸","nrightarrow":"↛","nRightarrow":"⇏","nrtri":"⋫","nrtrie":"⋭","nsc":"⊁","nsccue":"⋡","nsce":"⪰̸","Nscr":"𝒩","nscr":"𝓃","nshortmid":"∤","nshortparallel":"∦","nsim":"≁","nsime":"≄","nsimeq":"≄","nsmid":"∤","nspar":"∦","nsqsube":"⋢","nsqsupe":"⋣","nsub":"⊄","nsubE":"⫅̸","nsube":"⊈","nsubset":"⊂⃒","nsubseteq":"⊈","nsubseteqq":"⫅̸","nsucc":"⊁","nsucceq":"⪰̸","nsup":"⊅","nsupE":"⫆̸","nsupe":"⊉","nsupset":"⊃⃒","nsupseteq":"⊉","nsupseteqq":"⫆̸","ntgl":"≹","Ntilde":"Ñ","ntilde":"ñ","ntlg":"≸","ntriangleleft":"⋪","ntrianglelefteq":"⋬","ntriangleright":"⋫","ntrianglerighteq":"⋭","Nu":"Ν","nu":"ν","num":"#","numero":"№","numsp":" ","nvap":"≍⃒","nvdash":"⊬","nvDash":"⊭","nVdash":"⊮","nVDash":"⊯","nvge":"≥⃒","nvgt":">⃒","nvHarr":"⤄","nvinfin":"⧞","nvlArr":"⤂","nvle":"≤⃒","nvlt":"<⃒","nvltrie":"⊴⃒","nvrArr":"⤃","nvrtrie":"⊵⃒","nvsim":"∼⃒","nwarhk":"⤣","nwarr":"↖","nwArr":"⇖","nwarrow":"↖","nwnear":"⤧","Oacute":"Ó","oacute":"ó","oast":"⊛","Ocirc":"Ô","ocirc":"ô","ocir":"⊚","Ocy":"О","ocy":"о","odash":"⊝","Odblac":"Ő","odblac":"ő","odiv":"⨸","odot":"⊙","odsold":"⦼","OElig":"Œ","oelig":"œ","ofcir":"⦿","Ofr":"𝔒","ofr":"𝔬","ogon":"˛","Ograve":"Ò","ograve":"ò","ogt":"⧁","ohbar":"⦵","ohm":"Ω","oint":"∮","olarr":"↺","olcir":"⦾","olcross":"⦻","oline":"‾","olt":"⧀","Omacr":"Ō","omacr":"ō","Omega":"Ω","omega":"ω","Omicron":"Ο","omicron":"ο","omid":"⦶","ominus":"⊖","Oopf":"𝕆","oopf":"𝕠","opar":"⦷","OpenCurlyDoubleQuote":"“","OpenCurlyQuote":"‘","operp":"⦹","oplus":"⊕","orarr":"↻","Or":"⩔","or":"∨","ord":"⩝","order":"ℴ","orderof":"ℴ","ordf":"ª","ordm":"º","origof":"⊶","oror":"⩖","orslope":"⩗","orv":"⩛","oS":"Ⓢ","Oscr":"𝒪","oscr":"ℴ","Oslash":"Ø","oslash":"ø","osol":"⊘","Otilde":"Õ","otilde":"õ","otimesas":"⨶","Otimes":"⨷","otimes":"⊗","Ouml":"Ö","ouml":"ö","ovbar":"⌽","OverBar":"‾","OverBrace":"⏞","OverBracket":"⎴","OverParenthesis":"⏜","para":"¶","parallel":"∥","par":"∥","parsim":"⫳","parsl":"⫽","part":"∂","PartialD":"∂","Pcy":"П","pcy":"п","percnt":"%","period":".","permil":"‰","perp":"⊥","pertenk":"‱","Pfr":"𝔓","pfr":"𝔭","Phi":"Φ","phi":"φ","phiv":"ϕ","phmmat":"ℳ","phone":"☎","Pi":"Π","pi":"π","pitchfork":"⋔","piv":"ϖ","planck":"ℏ","planckh":"ℎ","plankv":"ℏ","plusacir":"⨣","plusb":"⊞","pluscir":"⨢","plus":"+","plusdo":"∔","plusdu":"⨥","pluse":"⩲","PlusMinus":"±","plusmn":"±","plussim":"⨦","plustwo":"⨧","pm":"±","Poincareplane":"ℌ","pointint":"⨕","popf":"𝕡","Popf":"ℙ","pound":"£","prap":"⪷","Pr":"⪻","pr":"≺","prcue":"≼","precapprox":"⪷","prec":"≺","preccurlyeq":"≼","Precedes":"≺","PrecedesEqual":"⪯","PrecedesSlantEqual":"≼","PrecedesTilde":"≾","preceq":"⪯","precnapprox":"⪹","precneqq":"⪵","precnsim":"⋨","pre":"⪯","prE":"⪳","precsim":"≾","prime":"′","Prime":"″","primes":"ℙ","prnap":"⪹","prnE":"⪵","prnsim":"⋨","prod":"∏","Product":"∏","profalar":"⌮","profline":"⌒","profsurf":"⌓","prop":"∝","Proportional":"∝","Proportion":"∷","propto":"∝","prsim":"≾","prurel":"⊰","Pscr":"𝒫","pscr":"𝓅","Psi":"Ψ","psi":"ψ","puncsp":" ","Qfr":"𝔔","qfr":"𝔮","qint":"⨌","qopf":"𝕢","Qopf":"ℚ","qprime":"⁗","Qscr":"𝒬","qscr":"𝓆","quaternions":"ℍ","quatint":"⨖","quest":"?","questeq":"≟","quot":"\\"","QUOT":"\\"","rAarr":"⇛","race":"∽̱","Racute":"Ŕ","racute":"ŕ","radic":"√","raemptyv":"⦳","rang":"⟩","Rang":"⟫","rangd":"⦒","range":"⦥","rangle":"⟩","raquo":"»","rarrap":"⥵","rarrb":"⇥","rarrbfs":"⤠","rarrc":"⤳","rarr":"→","Rarr":"↠","rArr":"⇒","rarrfs":"⤞","rarrhk":"↪","rarrlp":"↬","rarrpl":"⥅","rarrsim":"⥴","Rarrtl":"⤖","rarrtl":"↣","rarrw":"↝","ratail":"⤚","rAtail":"⤜","ratio":"∶","rationals":"ℚ","rbarr":"⤍","rBarr":"⤏","RBarr":"⤐","rbbrk":"❳","rbrace":"}","rbrack":"]","rbrke":"⦌","rbrksld":"⦎","rbrkslu":"⦐","Rcaron":"Ř","rcaron":"ř","Rcedil":"Ŗ","rcedil":"ŗ","rceil":"⌉","rcub":"}","Rcy":"Р","rcy":"р","rdca":"⤷","rdldhar":"⥩","rdquo":"”","rdquor":"”","rdsh":"↳","real":"ℜ","realine":"ℛ","realpart":"ℜ","reals":"ℝ","Re":"ℜ","rect":"▭","reg":"®","REG":"®","ReverseElement":"∋","ReverseEquilibrium":"⇋","ReverseUpEquilibrium":"⥯","rfisht":"⥽","rfloor":"⌋","rfr":"𝔯","Rfr":"ℜ","rHar":"⥤","rhard":"⇁","rharu":"⇀","rharul":"⥬","Rho":"Ρ","rho":"ρ","rhov":"ϱ","RightAngleBracket":"⟩","RightArrowBar":"⇥","rightarrow":"→","RightArrow":"→","Rightarrow":"⇒","RightArrowLeftArrow":"⇄","rightarrowtail":"↣","RightCeiling":"⌉","RightDoubleBracket":"⟧","RightDownTeeVector":"⥝","RightDownVectorBar":"⥕","RightDownVector":"⇂","RightFloor":"⌋","rightharpoondown":"⇁","rightharpoonup":"⇀","rightleftarrows":"⇄","rightleftharpoons":"⇌","rightrightarrows":"⇉","rightsquigarrow":"↝","RightTeeArrow":"↦","RightTee":"⊢","RightTeeVector":"⥛","rightthreetimes":"⋌","RightTriangleBar":"⧐","RightTriangle":"⊳","RightTriangleEqual":"⊵","RightUpDownVector":"⥏","RightUpTeeVector":"⥜","RightUpVectorBar":"⥔","RightUpVector":"↾","RightVectorBar":"⥓","RightVector":"⇀","ring":"˚","risingdotseq":"≓","rlarr":"⇄","rlhar":"⇌","rlm":"‏","rmoustache":"⎱","rmoust":"⎱","rnmid":"⫮","roang":"⟭","roarr":"⇾","robrk":"⟧","ropar":"⦆","ropf":"𝕣","Ropf":"ℝ","roplus":"⨮","rotimes":"⨵","RoundImplies":"⥰","rpar":")","rpargt":"⦔","rppolint":"⨒","rrarr":"⇉","Rrightarrow":"⇛","rsaquo":"›","rscr":"𝓇","Rscr":"ℛ","rsh":"↱","Rsh":"↱","rsqb":"]","rsquo":"’","rsquor":"’","rthree":"⋌","rtimes":"⋊","rtri":"▹","rtrie":"⊵","rtrif":"▸","rtriltri":"⧎","RuleDelayed":"⧴","ruluhar":"⥨","rx":"℞","Sacute":"Ś","sacute":"ś","sbquo":"‚","scap":"⪸","Scaron":"Š","scaron":"š","Sc":"⪼","sc":"≻","sccue":"≽","sce":"⪰","scE":"⪴","Scedil":"Ş","scedil":"ş","Scirc":"Ŝ","scirc":"ŝ","scnap":"⪺","scnE":"⪶","scnsim":"⋩","scpolint":"⨓","scsim":"≿","Scy":"С","scy":"с","sdotb":"⊡","sdot":"⋅","sdote":"⩦","searhk":"⤥","searr":"↘","seArr":"⇘","searrow":"↘","sect":"§","semi":";","seswar":"⤩","setminus":"∖","setmn":"∖","sext":"✶","Sfr":"𝔖","sfr":"𝔰","sfrown":"⌢","sharp":"♯","SHCHcy":"Щ","shchcy":"щ","SHcy":"Ш","shcy":"ш","ShortDownArrow":"↓","ShortLeftArrow":"←","shortmid":"∣","shortparallel":"∥","ShortRightArrow":"→","ShortUpArrow":"↑","shy":"­","Sigma":"Σ","sigma":"σ","sigmaf":"ς","sigmav":"ς","sim":"∼","simdot":"⩪","sime":"≃","simeq":"≃","simg":"⪞","simgE":"⪠","siml":"⪝","simlE":"⪟","simne":"≆","simplus":"⨤","simrarr":"⥲","slarr":"←","SmallCircle":"∘","smallsetminus":"∖","smashp":"⨳","smeparsl":"⧤","smid":"∣","smile":"⌣","smt":"⪪","smte":"⪬","smtes":"⪬︀","SOFTcy":"Ь","softcy":"ь","solbar":"⌿","solb":"⧄","sol":"/","Sopf":"𝕊","sopf":"𝕤","spades":"♠","spadesuit":"♠","spar":"∥","sqcap":"⊓","sqcaps":"⊓︀","sqcup":"⊔","sqcups":"⊔︀","Sqrt":"√","sqsub":"⊏","sqsube":"⊑","sqsubset":"⊏","sqsubseteq":"⊑","sqsup":"⊐","sqsupe":"⊒","sqsupset":"⊐","sqsupseteq":"⊒","square":"□","Square":"□","SquareIntersection":"⊓","SquareSubset":"⊏","SquareSubsetEqual":"⊑","SquareSuperset":"⊐","SquareSupersetEqual":"⊒","SquareUnion":"⊔","squarf":"▪","squ":"□","squf":"▪","srarr":"→","Sscr":"𝒮","sscr":"𝓈","ssetmn":"∖","ssmile":"⌣","sstarf":"⋆","Star":"⋆","star":"☆","starf":"★","straightepsilon":"ϵ","straightphi":"ϕ","strns":"¯","sub":"⊂","Sub":"⋐","subdot":"⪽","subE":"⫅","sube":"⊆","subedot":"⫃","submult":"⫁","subnE":"⫋","subne":"⊊","subplus":"⪿","subrarr":"⥹","subset":"⊂","Subset":"⋐","subseteq":"⊆","subseteqq":"⫅","SubsetEqual":"⊆","subsetneq":"⊊","subsetneqq":"⫋","subsim":"⫇","subsub":"⫕","subsup":"⫓","succapprox":"⪸","succ":"≻","succcurlyeq":"≽","Succeeds":"≻","SucceedsEqual":"⪰","SucceedsSlantEqual":"≽","SucceedsTilde":"≿","succeq":"⪰","succnapprox":"⪺","succneqq":"⪶","succnsim":"⋩","succsim":"≿","SuchThat":"∋","sum":"∑","Sum":"∑","sung":"♪","sup1":"¹","sup2":"²","sup3":"³","sup":"⊃","Sup":"⋑","supdot":"⪾","supdsub":"⫘","supE":"⫆","supe":"⊇","supedot":"⫄","Superset":"⊃","SupersetEqual":"⊇","suphsol":"⟉","suphsub":"⫗","suplarr":"⥻","supmult":"⫂","supnE":"⫌","supne":"⊋","supplus":"⫀","supset":"⊃","Supset":"⋑","supseteq":"⊇","supseteqq":"⫆","supsetneq":"⊋","supsetneqq":"⫌","supsim":"⫈","supsub":"⫔","supsup":"⫖","swarhk":"⤦","swarr":"↙","swArr":"⇙","swarrow":"↙","swnwar":"⤪","szlig":"ß","Tab":"\\t","target":"⌖","Tau":"Τ","tau":"τ","tbrk":"⎴","Tcaron":"Ť","tcaron":"ť","Tcedil":"Ţ","tcedil":"ţ","Tcy":"Т","tcy":"т","tdot":"⃛","telrec":"⌕","Tfr":"𝔗","tfr":"𝔱","there4":"∴","therefore":"∴","Therefore":"∴","Theta":"Θ","theta":"θ","thetasym":"ϑ","thetav":"ϑ","thickapprox":"≈","thicksim":"∼","ThickSpace":"  ","ThinSpace":" ","thinsp":" ","thkap":"≈","thksim":"∼","THORN":"Þ","thorn":"þ","tilde":"˜","Tilde":"∼","TildeEqual":"≃","TildeFullEqual":"≅","TildeTilde":"≈","timesbar":"⨱","timesb":"⊠","times":"×","timesd":"⨰","tint":"∭","toea":"⤨","topbot":"⌶","topcir":"⫱","top":"⊤","Topf":"𝕋","topf":"𝕥","topfork":"⫚","tosa":"⤩","tprime":"‴","trade":"™","TRADE":"™","triangle":"▵","triangledown":"▿","triangleleft":"◃","trianglelefteq":"⊴","triangleq":"≜","triangleright":"▹","trianglerighteq":"⊵","tridot":"◬","trie":"≜","triminus":"⨺","TripleDot":"⃛","triplus":"⨹","trisb":"⧍","tritime":"⨻","trpezium":"⏢","Tscr":"𝒯","tscr":"𝓉","TScy":"Ц","tscy":"ц","TSHcy":"Ћ","tshcy":"ћ","Tstrok":"Ŧ","tstrok":"ŧ","twixt":"≬","twoheadleftarrow":"↞","twoheadrightarrow":"↠","Uacute":"Ú","uacute":"ú","uarr":"↑","Uarr":"↟","uArr":"⇑","Uarrocir":"⥉","Ubrcy":"Ў","ubrcy":"ў","Ubreve":"Ŭ","ubreve":"ŭ","Ucirc":"Û","ucirc":"û","Ucy":"У","ucy":"у","udarr":"⇅","Udblac":"Ű","udblac":"ű","udhar":"⥮","ufisht":"⥾","Ufr":"𝔘","ufr":"𝔲","Ugrave":"Ù","ugrave":"ù","uHar":"⥣","uharl":"↿","uharr":"↾","uhblk":"▀","ulcorn":"⌜","ulcorner":"⌜","ulcrop":"⌏","ultri":"◸","Umacr":"Ū","umacr":"ū","uml":"¨","UnderBar":"_","UnderBrace":"⏟","UnderBracket":"⎵","UnderParenthesis":"⏝","Union":"⋃","UnionPlus":"⊎","Uogon":"Ų","uogon":"ų","Uopf":"𝕌","uopf":"𝕦","UpArrowBar":"⤒","uparrow":"↑","UpArrow":"↑","Uparrow":"⇑","UpArrowDownArrow":"⇅","updownarrow":"↕","UpDownArrow":"↕","Updownarrow":"⇕","UpEquilibrium":"⥮","upharpoonleft":"↿","upharpoonright":"↾","uplus":"⊎","UpperLeftArrow":"↖","UpperRightArrow":"↗","upsi":"υ","Upsi":"ϒ","upsih":"ϒ","Upsilon":"Υ","upsilon":"υ","UpTeeArrow":"↥","UpTee":"⊥","upuparrows":"⇈","urcorn":"⌝","urcorner":"⌝","urcrop":"⌎","Uring":"Ů","uring":"ů","urtri":"◹","Uscr":"𝒰","uscr":"𝓊","utdot":"⋰","Utilde":"Ũ","utilde":"ũ","utri":"▵","utrif":"▴","uuarr":"⇈","Uuml":"Ü","uuml":"ü","uwangle":"⦧","vangrt":"⦜","varepsilon":"ϵ","varkappa":"ϰ","varnothing":"∅","varphi":"ϕ","varpi":"ϖ","varpropto":"∝","varr":"↕","vArr":"⇕","varrho":"ϱ","varsigma":"ς","varsubsetneq":"⊊︀","varsubsetneqq":"⫋︀","varsupsetneq":"⊋︀","varsupsetneqq":"⫌︀","vartheta":"ϑ","vartriangleleft":"⊲","vartriangleright":"⊳","vBar":"⫨","Vbar":"⫫","vBarv":"⫩","Vcy":"В","vcy":"в","vdash":"⊢","vDash":"⊨","Vdash":"⊩","VDash":"⊫","Vdashl":"⫦","veebar":"⊻","vee":"∨","Vee":"⋁","veeeq":"≚","vellip":"⋮","verbar":"|","Verbar":"‖","vert":"|","Vert":"‖","VerticalBar":"∣","VerticalLine":"|","VerticalSeparator":"❘","VerticalTilde":"≀","VeryThinSpace":" ","Vfr":"𝔙","vfr":"𝔳","vltri":"⊲","vnsub":"⊂⃒","vnsup":"⊃⃒","Vopf":"𝕍","vopf":"𝕧","vprop":"∝","vrtri":"⊳","Vscr":"𝒱","vscr":"𝓋","vsubnE":"⫋︀","vsubne":"⊊︀","vsupnE":"⫌︀","vsupne":"⊋︀","Vvdash":"⊪","vzigzag":"⦚","Wcirc":"Ŵ","wcirc":"ŵ","wedbar":"⩟","wedge":"∧","Wedge":"⋀","wedgeq":"≙","weierp":"℘","Wfr":"𝔚","wfr":"𝔴","Wopf":"𝕎","wopf":"𝕨","wp":"℘","wr":"≀","wreath":"≀","Wscr":"𝒲","wscr":"𝓌","xcap":"⋂","xcirc":"◯","xcup":"⋃","xdtri":"▽","Xfr":"𝔛","xfr":"𝔵","xharr":"⟷","xhArr":"⟺","Xi":"Ξ","xi":"ξ","xlarr":"⟵","xlArr":"⟸","xmap":"⟼","xnis":"⋻","xodot":"⨀","Xopf":"𝕏","xopf":"𝕩","xoplus":"⨁","xotime":"⨂","xrarr":"⟶","xrArr":"⟹","Xscr":"𝒳","xscr":"𝓍","xsqcup":"⨆","xuplus":"⨄","xutri":"△","xvee":"⋁","xwedge":"⋀","Yacute":"Ý","yacute":"ý","YAcy":"Я","yacy":"я","Ycirc":"Ŷ","ycirc":"ŷ","Ycy":"Ы","ycy":"ы","yen":"¥","Yfr":"𝔜","yfr":"𝔶","YIcy":"Ї","yicy":"ї","Yopf":"𝕐","yopf":"𝕪","Yscr":"𝒴","yscr":"𝓎","YUcy":"Ю","yucy":"ю","yuml":"ÿ","Yuml":"Ÿ","Zacute":"Ź","zacute":"ź","Zcaron":"Ž","zcaron":"ž","Zcy":"З","zcy":"з","Zdot":"Ż","zdot":"ż","zeetrf":"ℨ","ZeroWidthSpace":"​","Zeta":"Ζ","zeta":"ζ","zfr":"𝔷","Zfr":"ℨ","ZHcy":"Ж","zhcy":"ж","zigrarr":"⇝","zopf":"𝕫","Zopf":"ℤ","Zscr":"𝒵","zscr":"𝓏","zwj":"‍","zwnj":"‌"}')},7802:e=>{"use strict";e.exports=JSON.parse('{"Aacute":"Á","aacute":"á","Acirc":"Â","acirc":"â","acute":"´","AElig":"Æ","aelig":"æ","Agrave":"À","agrave":"à","amp":"&","AMP":"&","Aring":"Å","aring":"å","Atilde":"Ã","atilde":"ã","Auml":"Ä","auml":"ä","brvbar":"¦","Ccedil":"Ç","ccedil":"ç","cedil":"¸","cent":"¢","copy":"©","COPY":"©","curren":"¤","deg":"°","divide":"÷","Eacute":"É","eacute":"é","Ecirc":"Ê","ecirc":"ê","Egrave":"È","egrave":"è","ETH":"Ð","eth":"ð","Euml":"Ë","euml":"ë","frac12":"½","frac14":"¼","frac34":"¾","gt":">","GT":">","Iacute":"Í","iacute":"í","Icirc":"Î","icirc":"î","iexcl":"¡","Igrave":"Ì","igrave":"ì","iquest":"¿","Iuml":"Ï","iuml":"ï","laquo":"«","lt":"<","LT":"<","macr":"¯","micro":"µ","middot":"·","nbsp":" ","not":"¬","Ntilde":"Ñ","ntilde":"ñ","Oacute":"Ó","oacute":"ó","Ocirc":"Ô","ocirc":"ô","Ograve":"Ò","ograve":"ò","ordf":"ª","ordm":"º","Oslash":"Ø","oslash":"ø","Otilde":"Õ","otilde":"õ","Ouml":"Ö","ouml":"ö","para":"¶","plusmn":"±","pound":"£","quot":"\\"","QUOT":"\\"","raquo":"»","reg":"®","REG":"®","sect":"§","shy":"­","sup1":"¹","sup2":"²","sup3":"³","szlig":"ß","THORN":"Þ","thorn":"þ","times":"×","Uacute":"Ú","uacute":"ú","Ucirc":"Û","ucirc":"û","Ugrave":"Ù","ugrave":"ù","uml":"¨","Uuml":"Ü","uuml":"ü","Yacute":"Ý","yacute":"ý","yen":"¥","yuml":"ÿ"}')},2228:e=>{"use strict";e.exports=JSON.parse('{"amp":"&","apos":"\'","gt":">","lt":"<","quot":"\\""}')},3870:function(e,t,n){"use strict";var r,i=this&&this.__extends||(r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),s=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n),Object.defineProperty(e,r,{enumerable:!0,get:function(){return t[n]}})}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),o=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),a=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&s(t,e,n);return o(t,e),t},c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.parseFeed=t.FeedHandler=void 0;var l,u,h=c(n(7915)),p=a(n(9432)),d=n(763);!function(e){e[e.image=0]="image",e[e.audio=1]="audio",e[e.video=2]="video",e[e.document=3]="document",e[e.executable=4]="executable"}(l||(l={})),function(e){e[e.sample=0]="sample",e[e.full=1]="full",e[e.nonstop=2]="nonstop"}(u||(u={}));var f=function(e){function t(t,n){return"object"==typeof t&&(n=t=void 0),e.call(this,t,n)||this}return i(t,e),t.prototype.onend=function(){var e,t,n=E(C,this.dom);if(n){var r={};if("feed"===n.name){var i=n.children;r.type="atom",A(r,"id","id",i),A(r,"title","title",i);var s=g("href",E("link",i));s&&(r.link=s),A(r,"description","subtitle",i),(o=_("updated",i))&&(r.updated=new Date(o)),A(r,"author","email",i,!0),r.items=T("entry",i).map((function(e){var t={},n=e.children;A(t,"id","id",n),A(t,"title","title",n);var r=g("href",E("link",n));r&&(t.link=r);var i=_("summary",n)||_("content",n);i&&(t.description=i);var s=_("updated",n);return s&&(t.pubDate=new Date(s)),t.media=m(n),t}))}else{var o;i=null!==(t=null===(e=E("channel",n.children))||void 0===e?void 0:e.children)&&void 0!==t?t:[],r.type=n.name.substr(0,3),r.id="",A(r,"title","title",i),A(r,"link","link",i),A(r,"description","description",i),(o=_("lastBuildDate",i))&&(r.updated=new Date(o)),A(r,"author","managingEditor",i,!0),r.items=T("item",n.children).map((function(e){var t={},n=e.children;A(t,"id","guid",n),A(t,"title","title",n),A(t,"link","link",n),A(t,"description","description",n);var r=_("pubDate",n);return r&&(t.pubDate=new Date(r)),t.media=m(n),t}))}this.feed=r,this.handleCallback(null)}else this.handleCallback(new Error("couldn't find root of feed"))},t}(h.default);function m(e){return T("media:content",e).map((function(e){var t={medium:e.attribs.medium,isDefault:!!e.attribs.isDefault};return e.attribs.url&&(t.url=e.attribs.url),e.attribs.fileSize&&(t.fileSize=parseInt(e.attribs.fileSize,10)),e.attribs.type&&(t.type=e.attribs.type),e.attribs.expression&&(t.expression=e.attribs.expression),e.attribs.bitrate&&(t.bitrate=parseInt(e.attribs.bitrate,10)),e.attribs.framerate&&(t.framerate=parseInt(e.attribs.framerate,10)),e.attribs.samplingrate&&(t.samplingrate=parseInt(e.attribs.samplingrate,10)),e.attribs.channels&&(t.channels=parseInt(e.attribs.channels,10)),e.attribs.duration&&(t.duration=parseInt(e.attribs.duration,10)),e.attribs.height&&(t.height=parseInt(e.attribs.height,10)),e.attribs.width&&(t.width=parseInt(e.attribs.width,10)),e.attribs.lang&&(t.lang=e.attribs.lang),t}))}function T(e,t){return p.getElementsByTagName(e,t,!0)}function E(e,t){return p.getElementsByTagName(e,t,!0,1)[0]}function _(e,t,n){return void 0===n&&(n=!1),p.getText(p.getElementsByTagName(e,t,n,1)).trim()}function g(e,t){return t?t.attribs[e]:null}function A(e,t,n,r,i){void 0===i&&(i=!1);var s=_(n,r,i);s&&(e[t]=s)}function C(e){return"rss"===e||"feed"===e||"rdf:RDF"===e}t.FeedHandler=f,t.parseFeed=function(e,t){void 0===t&&(t={xmlMode:!0});var n=new f(t);return new d.Parser(n,t).end(e),n.feed}},763:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Parser=void 0;var i=r(n(9889)),s=new Set(["input","option","optgroup","select","button","datalist","textarea"]),o=new Set(["p"]),a={tr:new Set(["tr","th","td"]),th:new Set(["th"]),td:new Set(["thead","th","td"]),body:new Set(["head","link","script"]),li:new Set(["li"]),p:o,h1:o,h2:o,h3:o,h4:o,h5:o,h6:o,select:s,input:s,output:s,button:s,datalist:s,textarea:s,option:new Set(["option"]),optgroup:new Set(["optgroup","option"]),dd:new Set(["dt","dd"]),dt:new Set(["dt","dd"]),address:o,article:o,aside:o,blockquote:o,details:o,div:o,dl:o,fieldset:o,figcaption:o,figure:o,footer:o,form:o,header:o,hr:o,main:o,nav:o,ol:o,pre:o,section:o,table:o,ul:o,rt:new Set(["rt","rp"]),rp:new Set(["rt","rp"]),tbody:new Set(["thead","tbody"]),tfoot:new Set(["thead","tbody"])},c=new Set(["area","base","basefont","br","col","command","embed","frame","hr","img","input","isindex","keygen","link","meta","param","source","track","wbr"]),l=new Set(["math","svg"]),u=new Set(["mi","mo","mn","ms","mtext","annotation-xml","foreignObject","desc","title"]),h=/\s|\//,p=function(){function e(e,t){var n,r,s,o,a;void 0===t&&(t={}),this.startIndex=0,this.endIndex=null,this.tagname="",this.attribname="",this.attribvalue="",this.attribs=null,this.stack=[],this.foreignContext=[],this.options=t,this.cbs=null!=e?e:{},this.lowerCaseTagNames=null!==(n=t.lowerCaseTags)&&void 0!==n?n:!t.xmlMode,this.lowerCaseAttributeNames=null!==(r=t.lowerCaseAttributeNames)&&void 0!==r?r:!t.xmlMode,this.tokenizer=new(null!==(s=t.Tokenizer)&&void 0!==s?s:i.default)(this.options,this),null===(a=(o=this.cbs).onparserinit)||void 0===a||a.call(o,this)}return e.prototype.updatePosition=function(e){null===this.endIndex?this.tokenizer.sectionStart<=e?this.startIndex=0:this.startIndex=this.tokenizer.sectionStart-e:this.startIndex=this.endIndex+1,this.endIndex=this.tokenizer.getAbsoluteIndex()},e.prototype.ontext=function(e){var t,n;this.updatePosition(1),this.endIndex--,null===(n=(t=this.cbs).ontext)||void 0===n||n.call(t,e)},e.prototype.onopentagname=function(e){var t,n;if(this.lowerCaseTagNames&&(e=e.toLowerCase()),this.tagname=e,!this.options.xmlMode&&Object.prototype.hasOwnProperty.call(a,e))for(var r=void 0;this.stack.length>0&&a[e].has(r=this.stack[this.stack.length-1]);)this.onclosetag(r);!this.options.xmlMode&&c.has(e)||(this.stack.push(e),l.has(e)?this.foreignContext.push(!0):u.has(e)&&this.foreignContext.push(!1)),null===(n=(t=this.cbs).onopentagname)||void 0===n||n.call(t,e),this.cbs.onopentag&&(this.attribs={})},e.prototype.onopentagend=function(){var e,t;this.updatePosition(1),this.attribs&&(null===(t=(e=this.cbs).onopentag)||void 0===t||t.call(e,this.tagname,this.attribs),this.attribs=null),!this.options.xmlMode&&this.cbs.onclosetag&&c.has(this.tagname)&&this.cbs.onclosetag(this.tagname),this.tagname=""},e.prototype.onclosetag=function(e){if(this.updatePosition(1),this.lowerCaseTagNames&&(e=e.toLowerCase()),(l.has(e)||u.has(e))&&this.foreignContext.pop(),!this.stack.length||!this.options.xmlMode&&c.has(e))this.options.xmlMode||"br"!==e&&"p"!==e||(this.onopentagname(e),this.closeCurrentTag());else{var t=this.stack.lastIndexOf(e);if(-1!==t)if(this.cbs.onclosetag)for(t=this.stack.length-t;t--;)this.cbs.onclosetag(this.stack.pop());else this.stack.length=t;else"p"!==e||this.options.xmlMode||(this.onopentagname(e),this.closeCurrentTag())}},e.prototype.onselfclosingtag=function(){this.options.xmlMode||this.options.recognizeSelfClosing||this.foreignContext[this.foreignContext.length-1]?this.closeCurrentTag():this.onopentagend()},e.prototype.closeCurrentTag=function(){var e,t,n=this.tagname;this.onopentagend(),this.stack[this.stack.length-1]===n&&(null===(t=(e=this.cbs).onclosetag)||void 0===t||t.call(e,n),this.stack.pop())},e.prototype.onattribname=function(e){this.lowerCaseAttributeNames&&(e=e.toLowerCase()),this.attribname=e},e.prototype.onattribdata=function(e){this.attribvalue+=e},e.prototype.onattribend=function(e){var t,n;null===(n=(t=this.cbs).onattribute)||void 0===n||n.call(t,this.attribname,this.attribvalue,e),this.attribs&&!Object.prototype.hasOwnProperty.call(this.attribs,this.attribname)&&(this.attribs[this.attribname]=this.attribvalue),this.attribname="",this.attribvalue=""},e.prototype.getInstructionName=function(e){var t=e.search(h),n=t<0?e:e.substr(0,t);return this.lowerCaseTagNames&&(n=n.toLowerCase()),n},e.prototype.ondeclaration=function(e){if(this.cbs.onprocessinginstruction){var t=this.getInstructionName(e);this.cbs.onprocessinginstruction("!"+t,"!"+e)}},e.prototype.onprocessinginstruction=function(e){if(this.cbs.onprocessinginstruction){var t=this.getInstructionName(e);this.cbs.onprocessinginstruction("?"+t,"?"+e)}},e.prototype.oncomment=function(e){var t,n,r,i;this.updatePosition(4),null===(n=(t=this.cbs).oncomment)||void 0===n||n.call(t,e),null===(i=(r=this.cbs).oncommentend)||void 0===i||i.call(r)},e.prototype.oncdata=function(e){var t,n,r,i,s,o;this.updatePosition(1),this.options.xmlMode||this.options.recognizeCDATA?(null===(n=(t=this.cbs).oncdatastart)||void 0===n||n.call(t),null===(i=(r=this.cbs).ontext)||void 0===i||i.call(r,e),null===(o=(s=this.cbs).oncdataend)||void 0===o||o.call(s)):this.oncomment("[CDATA["+e+"]]")},e.prototype.onerror=function(e){var t,n;null===(n=(t=this.cbs).onerror)||void 0===n||n.call(t,e)},e.prototype.onend=function(){var e,t;if(this.cbs.onclosetag)for(var n=this.stack.length;n>0;this.cbs.onclosetag(this.stack[--n]));null===(t=(e=this.cbs).onend)||void 0===t||t.call(e)},e.prototype.reset=function(){var e,t,n,r;null===(t=(e=this.cbs).onreset)||void 0===t||t.call(e),this.tokenizer.reset(),this.tagname="",this.attribname="",this.attribs=null,this.stack=[],null===(r=(n=this.cbs).onparserinit)||void 0===r||r.call(n,this)},e.prototype.parseComplete=function(e){this.reset(),this.end(e)},e.prototype.write=function(e){this.tokenizer.write(e)},e.prototype.end=function(e){this.tokenizer.end(e)},e.prototype.pause=function(){this.tokenizer.pause()},e.prototype.resume=function(){this.tokenizer.resume()},e.prototype.parseChunk=function(e){this.write(e)},e.prototype.done=function(e){this.end(e)},e}();t.Parser=p},9889:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});var i=r(n(26)),s=r(n(4007)),o=r(n(7802)),a=r(n(2228));function c(e){return" "===e||"\n"===e||"\t"===e||"\f"===e||"\r"===e}function l(e){return e>="a"&&e<="z"||e>="A"&&e<="Z"}function u(e,t,n){var r=e.toLowerCase();return e===r?function(e,i){i===r?e._state=t:(e._state=n,e._index--)}:function(i,s){s===r||s===e?i._state=t:(i._state=n,i._index--)}}function h(e,t){var n=e.toLowerCase();return function(r,i){i===n||i===e?r._state=t:(r._state=3,r._index--)}}var p=u("C",24,16),d=u("D",25,16),f=u("A",26,16),m=u("T",27,16),T=u("A",28,16),E=h("R",35),_=h("I",36),g=h("P",37),A=h("T",38),C=u("R",40,1),N=u("I",41,1),v=u("P",42,1),O=u("T",43,1),b=h("Y",45),S=h("L",46),y=h("E",47),I=u("Y",49,1),R=u("L",50,1),k=u("E",51,1),L=h("I",54),M=h("T",55),x=h("L",56),P=h("E",57),D=u("I",58,1),w=u("T",59,1),H=u("L",60,1),F=u("E",61,1),U=u("#",63,64),B=u("X",66,65),G=function(){function e(e,t){var n;this._state=1,this.buffer="",this.sectionStart=0,this._index=0,this.bufferOffset=0,this.baseState=1,this.special=1,this.running=!0,this.ended=!1,this.cbs=t,this.xmlMode=!!(null==e?void 0:e.xmlMode),this.decodeEntities=null===(n=null==e?void 0:e.decodeEntities)||void 0===n||n}return e.prototype.reset=function(){this._state=1,this.buffer="",this.sectionStart=0,this._index=0,this.bufferOffset=0,this.baseState=1,this.special=1,this.running=!0,this.ended=!1},e.prototype.write=function(e){this.ended&&this.cbs.onerror(Error(".write() after done!")),this.buffer+=e,this.parse()},e.prototype.end=function(e){this.ended&&this.cbs.onerror(Error(".end() after done!")),e&&this.write(e),this.ended=!0,this.running&&this.finish()},e.prototype.pause=function(){this.running=!1},e.prototype.resume=function(){this.running=!0,this._index<this.buffer.length&&this.parse(),this.ended&&this.finish()},e.prototype.getAbsoluteIndex=function(){return this.bufferOffset+this._index},e.prototype.stateText=function(e){"<"===e?(this._index>this.sectionStart&&this.cbs.ontext(this.getSection()),this._state=2,this.sectionStart=this._index):!this.decodeEntities||"&"!==e||1!==this.special&&4!==this.special||(this._index>this.sectionStart&&this.cbs.ontext(this.getSection()),this.baseState=1,this._state=62,this.sectionStart=this._index)},e.prototype.isTagStartChar=function(e){return l(e)||this.xmlMode&&!c(e)&&"/"!==e&&">"!==e},e.prototype.stateBeforeTagName=function(e){"/"===e?this._state=5:"<"===e?(this.cbs.ontext(this.getSection()),this.sectionStart=this._index):">"===e||1!==this.special||c(e)?this._state=1:"!"===e?(this._state=15,this.sectionStart=this._index+1):"?"===e?(this._state=17,this.sectionStart=this._index+1):this.isTagStartChar(e)?(this._state=this.xmlMode||"s"!==e&&"S"!==e?this.xmlMode||"t"!==e&&"T"!==e?3:52:32,this.sectionStart=this._index):this._state=1},e.prototype.stateInTagName=function(e){("/"===e||">"===e||c(e))&&(this.emitToken("onopentagname"),this._state=8,this._index--)},e.prototype.stateBeforeClosingTagName=function(e){c(e)||(">"===e?this._state=1:1!==this.special?4===this.special||"s"!==e&&"S"!==e?4!==this.special||"t"!==e&&"T"!==e?(this._state=1,this._index--):this._state=53:this._state=33:this.isTagStartChar(e)?(this._state=6,this.sectionStart=this._index):(this._state=20,this.sectionStart=this._index))},e.prototype.stateInClosingTagName=function(e){(">"===e||c(e))&&(this.emitToken("onclosetag"),this._state=7,this._index--)},e.prototype.stateAfterClosingTagName=function(e){">"===e&&(this._state=1,this.sectionStart=this._index+1)},e.prototype.stateBeforeAttributeName=function(e){">"===e?(this.cbs.onopentagend(),this._state=1,this.sectionStart=this._index+1):"/"===e?this._state=4:c(e)||(this._state=9,this.sectionStart=this._index)},e.prototype.stateInSelfClosingTag=function(e){">"===e?(this.cbs.onselfclosingtag(),this._state=1,this.sectionStart=this._index+1,this.special=1):c(e)||(this._state=8,this._index--)},e.prototype.stateInAttributeName=function(e){("="===e||"/"===e||">"===e||c(e))&&(this.cbs.onattribname(this.getSection()),this.sectionStart=-1,this._state=10,this._index--)},e.prototype.stateAfterAttributeName=function(e){"="===e?this._state=11:"/"===e||">"===e?(this.cbs.onattribend(void 0),this._state=8,this._index--):c(e)||(this.cbs.onattribend(void 0),this._state=9,this.sectionStart=this._index)},e.prototype.stateBeforeAttributeValue=function(e){'"'===e?(this._state=12,this.sectionStart=this._index+1):"'"===e?(this._state=13,this.sectionStart=this._index+1):c(e)||(this._state=14,this.sectionStart=this._index,this._index--)},e.prototype.handleInAttributeValue=function(e,t){e===t?(this.emitToken("onattribdata"),this.cbs.onattribend(t),this._state=8):this.decodeEntities&&"&"===e&&(this.emitToken("onattribdata"),this.baseState=this._state,this._state=62,this.sectionStart=this._index)},e.prototype.stateInAttributeValueDoubleQuotes=function(e){this.handleInAttributeValue(e,'"')},e.prototype.stateInAttributeValueSingleQuotes=function(e){this.handleInAttributeValue(e,"'")},e.prototype.stateInAttributeValueNoQuotes=function(e){c(e)||">"===e?(this.emitToken("onattribdata"),this.cbs.onattribend(null),this._state=8,this._index--):this.decodeEntities&&"&"===e&&(this.emitToken("onattribdata"),this.baseState=this._state,this._state=62,this.sectionStart=this._index)},e.prototype.stateBeforeDeclaration=function(e){this._state="["===e?23:"-"===e?18:16},e.prototype.stateInDeclaration=function(e){">"===e&&(this.cbs.ondeclaration(this.getSection()),this._state=1,this.sectionStart=this._index+1)},e.prototype.stateInProcessingInstruction=function(e){">"===e&&(this.cbs.onprocessinginstruction(this.getSection()),this._state=1,this.sectionStart=this._index+1)},e.prototype.stateBeforeComment=function(e){"-"===e?(this._state=19,this.sectionStart=this._index+1):this._state=16},e.prototype.stateInComment=function(e){"-"===e&&(this._state=21)},e.prototype.stateInSpecialComment=function(e){">"===e&&(this.cbs.oncomment(this.buffer.substring(this.sectionStart,this._index)),this._state=1,this.sectionStart=this._index+1)},e.prototype.stateAfterComment1=function(e){this._state="-"===e?22:19},e.prototype.stateAfterComment2=function(e){">"===e?(this.cbs.oncomment(this.buffer.substring(this.sectionStart,this._index-2)),this._state=1,this.sectionStart=this._index+1):"-"!==e&&(this._state=19)},e.prototype.stateBeforeCdata6=function(e){"["===e?(this._state=29,this.sectionStart=this._index+1):(this._state=16,this._index--)},e.prototype.stateInCdata=function(e){"]"===e&&(this._state=30)},e.prototype.stateAfterCdata1=function(e){this._state="]"===e?31:29},e.prototype.stateAfterCdata2=function(e){">"===e?(this.cbs.oncdata(this.buffer.substring(this.sectionStart,this._index-2)),this._state=1,this.sectionStart=this._index+1):"]"!==e&&(this._state=29)},e.prototype.stateBeforeSpecialS=function(e){"c"===e||"C"===e?this._state=34:"t"===e||"T"===e?this._state=44:(this._state=3,this._index--)},e.prototype.stateBeforeSpecialSEnd=function(e){2!==this.special||"c"!==e&&"C"!==e?3!==this.special||"t"!==e&&"T"!==e?this._state=1:this._state=48:this._state=39},e.prototype.stateBeforeSpecialLast=function(e,t){("/"===e||">"===e||c(e))&&(this.special=t),this._state=3,this._index--},e.prototype.stateAfterSpecialLast=function(e,t){">"===e||c(e)?(this.special=1,this._state=6,this.sectionStart=this._index-t,this._index--):this._state=1},e.prototype.parseFixedEntity=function(e){if(void 0===e&&(e=this.xmlMode?a.default:s.default),this.sectionStart+1<this._index){var t=this.buffer.substring(this.sectionStart+1,this._index);Object.prototype.hasOwnProperty.call(e,t)&&(this.emitPartial(e[t]),this.sectionStart=this._index+1)}},e.prototype.parseLegacyEntity=function(){for(var e=this.sectionStart+1,t=Math.min(this._index-e,6);t>=2;){var n=this.buffer.substr(e,t);if(Object.prototype.hasOwnProperty.call(o.default,n))return this.emitPartial(o.default[n]),void(this.sectionStart+=t+1);t--}},e.prototype.stateInNamedEntity=function(e){";"===e?(this.parseFixedEntity(),1===this.baseState&&this.sectionStart+1<this._index&&!this.xmlMode&&this.parseLegacyEntity(),this._state=this.baseState):(e<"0"||e>"9")&&!l(e)&&(this.xmlMode||this.sectionStart+1===this._index||(1!==this.baseState?"="!==e&&this.parseFixedEntity(o.default):this.parseLegacyEntity()),this._state=this.baseState,this._index--)},e.prototype.decodeNumericEntity=function(e,t,n){var r=this.sectionStart+e;if(r!==this._index){var s=this.buffer.substring(r,this._index),o=parseInt(s,t);this.emitPartial(i.default(o)),this.sectionStart=n?this._index+1:this._index}this._state=this.baseState},e.prototype.stateInNumericEntity=function(e){";"===e?this.decodeNumericEntity(2,10,!0):(e<"0"||e>"9")&&(this.xmlMode?this._state=this.baseState:this.decodeNumericEntity(2,10,!1),this._index--)},e.prototype.stateInHexEntity=function(e){";"===e?this.decodeNumericEntity(3,16,!0):(e<"a"||e>"f")&&(e<"A"||e>"F")&&(e<"0"||e>"9")&&(this.xmlMode?this._state=this.baseState:this.decodeNumericEntity(3,16,!1),this._index--)},e.prototype.cleanup=function(){this.sectionStart<0?(this.buffer="",this.bufferOffset+=this._index,this._index=0):this.running&&(1===this._state?(this.sectionStart!==this._index&&this.cbs.ontext(this.buffer.substr(this.sectionStart)),this.buffer="",this.bufferOffset+=this._index,this._index=0):this.sectionStart===this._index?(this.buffer="",this.bufferOffset+=this._index,this._index=0):(this.buffer=this.buffer.substr(this.sectionStart),this._index-=this.sectionStart,this.bufferOffset+=this.sectionStart),this.sectionStart=0)},e.prototype.parse=function(){for(;this._index<this.buffer.length&&this.running;){var e=this.buffer.charAt(this._index);1===this._state?this.stateText(e):12===this._state?this.stateInAttributeValueDoubleQuotes(e):9===this._state?this.stateInAttributeName(e):19===this._state?this.stateInComment(e):20===this._state?this.stateInSpecialComment(e):8===this._state?this.stateBeforeAttributeName(e):3===this._state?this.stateInTagName(e):6===this._state?this.stateInClosingTagName(e):2===this._state?this.stateBeforeTagName(e):10===this._state?this.stateAfterAttributeName(e):13===this._state?this.stateInAttributeValueSingleQuotes(e):11===this._state?this.stateBeforeAttributeValue(e):5===this._state?this.stateBeforeClosingTagName(e):7===this._state?this.stateAfterClosingTagName(e):32===this._state?this.stateBeforeSpecialS(e):21===this._state?this.stateAfterComment1(e):14===this._state?this.stateInAttributeValueNoQuotes(e):4===this._state?this.stateInSelfClosingTag(e):16===this._state?this.stateInDeclaration(e):15===this._state?this.stateBeforeDeclaration(e):22===this._state?this.stateAfterComment2(e):18===this._state?this.stateBeforeComment(e):33===this._state?this.stateBeforeSpecialSEnd(e):53===this._state?D(this,e):39===this._state?C(this,e):40===this._state?N(this,e):41===this._state?v(this,e):34===this._state?E(this,e):35===this._state?_(this,e):36===this._state?g(this,e):37===this._state?A(this,e):38===this._state?this.stateBeforeSpecialLast(e,2):42===this._state?O(this,e):43===this._state?this.stateAfterSpecialLast(e,6):44===this._state?b(this,e):29===this._state?this.stateInCdata(e):45===this._state?S(this,e):46===this._state?y(this,e):47===this._state?this.stateBeforeSpecialLast(e,3):48===this._state?I(this,e):49===this._state?R(this,e):50===this._state?k(this,e):51===this._state?this.stateAfterSpecialLast(e,5):52===this._state?L(this,e):54===this._state?M(this,e):55===this._state?x(this,e):56===this._state?P(this,e):57===this._state?this.stateBeforeSpecialLast(e,4):58===this._state?w(this,e):59===this._state?H(this,e):60===this._state?F(this,e):61===this._state?this.stateAfterSpecialLast(e,5):17===this._state?this.stateInProcessingInstruction(e):64===this._state?this.stateInNamedEntity(e):23===this._state?p(this,e):62===this._state?U(this,e):24===this._state?d(this,e):25===this._state?f(this,e):30===this._state?this.stateAfterCdata1(e):31===this._state?this.stateAfterCdata2(e):26===this._state?m(this,e):27===this._state?T(this,e):28===this._state?this.stateBeforeCdata6(e):66===this._state?this.stateInHexEntity(e):65===this._state?this.stateInNumericEntity(e):63===this._state?B(this,e):this.cbs.onerror(Error("unknown _state"),this._state),this._index++}this.cleanup()},e.prototype.finish=function(){this.sectionStart<this._index&&this.handleTrailingData(),this.cbs.onend()},e.prototype.handleTrailingData=function(){var e=this.buffer.substr(this.sectionStart);29===this._state||30===this._state||31===this._state?this.cbs.oncdata(e):19===this._state||21===this._state||22===this._state?this.cbs.oncomment(e):64!==this._state||this.xmlMode?65!==this._state||this.xmlMode?66!==this._state||this.xmlMode?3!==this._state&&8!==this._state&&11!==this._state&&10!==this._state&&9!==this._state&&13!==this._state&&12!==this._state&&14!==this._state&&6!==this._state&&this.cbs.ontext(e):(this.decodeNumericEntity(3,16,!1),this.sectionStart<this._index&&(this._state=this.baseState,this.handleTrailingData())):(this.decodeNumericEntity(2,10,!1),this.sectionStart<this._index&&(this._state=this.baseState,this.handleTrailingData())):(this.parseLegacyEntity(),this.sectionStart<this._index&&(this._state=this.baseState,this.handleTrailingData()))},e.prototype.getSection=function(){return this.buffer.substring(this.sectionStart,this._index)},e.prototype.emitToken=function(e){this.cbs[e](this.getSection()),this.sectionStart=-1},e.prototype.emitPartial=function(e){1!==this.baseState?this.cbs.onattribdata(e):this.cbs.ontext(e)},e}();t.default=G},3719:function(e,t,n){"use strict";var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n),Object.defineProperty(e,r,{enumerable:!0,get:function(){return t[n]}})}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),s=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return i(t,e),t},o=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||r(t,e,n)},a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.RssHandler=t.DefaultHandler=t.DomUtils=t.ElementType=t.Tokenizer=t.createDomStream=t.parseDOM=t.parseDocument=t.DomHandler=t.Parser=void 0;var c=n(763);Object.defineProperty(t,"Parser",{enumerable:!0,get:function(){return c.Parser}});var l=n(7915);function u(e,t){var n=new l.DomHandler(void 0,t);return new c.Parser(n,t).end(e),n.root}Object.defineProperty(t,"DomHandler",{enumerable:!0,get:function(){return l.DomHandler}}),Object.defineProperty(t,"DefaultHandler",{enumerable:!0,get:function(){return l.DomHandler}}),t.parseDocument=u,t.parseDOM=function(e,t){return u(e,t).children},t.createDomStream=function(e,t,n){var r=new l.DomHandler(e,t,n);return new c.Parser(r,t)};var h=n(9889);Object.defineProperty(t,"Tokenizer",{enumerable:!0,get:function(){return a(h).default}});var p=s(n(9960));t.ElementType=p,o(n(3870),t),t.DomUtils=s(n(9432));var d=n(3870);Object.defineProperty(t,"RssHandler",{enumerable:!0,get:function(){return d.FeedHandler}})},9769:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.compile=void 0;var r=n(1073);t.compile=function(e){var t=e[0],n=e[1]-1;if(n<0&&t<=0)return r.falseFunc;if(-1===t)return function(e){return e<=n};if(0===t)return function(e){return e===n};if(1===t)return n<0?r.trueFunc:function(e){return e>=n};var i=Math.abs(t),s=(n%i+i)%i;return t>1?function(e){return e>=n&&e%i===s}:function(e){return e<=n&&e%i===s}}},7540:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.compile=t.parse=void 0;var r=n(7766);Object.defineProperty(t,"parse",{enumerable:!0,get:function(){return r.parse}});var i=n(9769);Object.defineProperty(t,"compile",{enumerable:!0,get:function(){return i.compile}}),t.default=function(e){return i.compile(r.parse(e))}},7766:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.parse=void 0;var n=/^([+-]?\d*n)?\s*(?:([+-]?)\s*(\d+))?$/;t.parse=function(e){if("even"===(e=e.trim().toLowerCase()))return[2,0];if("odd"===e)return[2,1];var t,r=e.match(n);if(!r)throw new Error("n-th rule couldn't be parsed ('"+e+"')");return r[1]?(t=parseInt(r[1],10),isNaN(t)&&(t=r[1].startsWith("-")?-1:1)):t=0,[t,("-"===r[2]?-1:1)*(r[3]?parseInt(r[3],10):0)]}},1906:(e,t,n)=>{"use strict";const r=n(1515),{DOCUMENT_MODE:i}=n(6152),s={element:1,text:3,cdata:4,comment:8},o={tagName:"name",childNodes:"children",parentNode:"parent",previousSibling:"prev",nextSibling:"next",nodeValue:"data"};class a{constructor(e){for(const t of Object.keys(e))this[t]=e[t]}get firstChild(){const e=this.children;return e&&e[0]||null}get lastChild(){const e=this.children;return e&&e[e.length-1]||null}get nodeType(){return s[this.type]||s.element}}Object.keys(o).forEach((e=>{const t=o[e];Object.defineProperty(a.prototype,e,{get:function(){return this[t]||null},set:function(e){return this[t]=e,e}})})),t.createDocument=function(){return new a({type:"root",name:"root",parent:null,prev:null,next:null,children:[],"x-mode":i.NO_QUIRKS})},t.createDocumentFragment=function(){return new a({type:"root",name:"root",parent:null,prev:null,next:null,children:[]})},t.createElement=function(e,t,n){const r=Object.create(null),i=Object.create(null),s=Object.create(null);for(let e=0;e<n.length;e++){const t=n[e].name;r[t]=n[e].value,i[t]=n[e].namespace,s[t]=n[e].prefix}return new a({type:"script"===e||"style"===e?e:"tag",name:e,namespace:t,attribs:r,"x-attribsNamespace":i,"x-attribsPrefix":s,children:[],parent:null,prev:null,next:null})},t.createCommentNode=function(e){return new a({type:"comment",data:e,parent:null,prev:null,next:null})};const c=function(e){return new a({type:"text",data:e,parent:null,prev:null,next:null})},l=t.appendChild=function(e,t){const n=e.children[e.children.length-1];n&&(n.next=t,t.prev=n),e.children.push(t),t.parent=e},u=t.insertBefore=function(e,t,n){const r=e.children.indexOf(n),i=n.prev;i&&(i.next=t,t.prev=i),n.prev=t,t.next=n,e.children.splice(r,0,t),t.parent=e};t.setTemplateContent=function(e,t){l(e,t)},t.getTemplateContent=function(e){return e.children[0]},t.setDocumentType=function(e,t,n,i){const s=r.serializeContent(t,n,i);let o=null;for(let t=0;t<e.children.length;t++)if("directive"===e.children[t].type&&"!doctype"===e.children[t].name){o=e.children[t];break}o?(o.data=s,o["x-name"]=t,o["x-publicId"]=n,o["x-systemId"]=i):l(e,new a({type:"directive",name:"!doctype",data:s,"x-name":t,"x-publicId":n,"x-systemId":i}))},t.setDocumentMode=function(e,t){e["x-mode"]=t},t.getDocumentMode=function(e){return e["x-mode"]},t.detachNode=function(e){if(e.parent){const t=e.parent.children.indexOf(e),n=e.prev,r=e.next;e.prev=null,e.next=null,n&&(n.next=r),r&&(r.prev=n),e.parent.children.splice(t,1),e.parent=null}},t.insertText=function(e,t){const n=e.children[e.children.length-1];n&&"text"===n.type?n.data+=t:l(e,c(t))},t.insertTextBefore=function(e,t,n){const r=e.children[e.children.indexOf(n)-1];r&&"text"===r.type?r.data+=t:u(e,c(t),n)},t.adoptAttributes=function(e,t){for(let n=0;n<t.length;n++){const r=t[n].name;void 0===e.attribs[r]&&(e.attribs[r]=t[n].value,e["x-attribsNamespace"][r]=t[n].namespace,e["x-attribsPrefix"][r]=t[n].prefix)}},t.getFirstChild=function(e){return e.children[0]},t.getChildNodes=function(e){return e.children},t.getParentNode=function(e){return e.parent},t.getAttrList=function(e){const t=[];for(const n in e.attribs)t.push({name:n,value:e.attribs[n],namespace:e["x-attribsNamespace"][n],prefix:e["x-attribsPrefix"][n]});return t},t.getTagName=function(e){return e.name},t.getNamespaceURI=function(e){return e.namespace},t.getTextNodeContent=function(e){return e.data},t.getCommentNodeContent=function(e){return e.data},t.getDocumentTypeNodeName=function(e){return e["x-name"]},t.getDocumentTypeNodePublicId=function(e){return e["x-publicId"]},t.getDocumentTypeNodeSystemId=function(e){return e["x-systemId"]},t.isTextNode=function(e){return"text"===e.type},t.isCommentNode=function(e){return"comment"===e.type},t.isDocumentTypeNode=function(e){return"directive"===e.type&&"!doctype"===e.name},t.isElementNode=function(e){return!!e.attribs},t.setNodeSourceCodeLocation=function(e,t){e.sourceCodeLocation=t},t.getNodeSourceCodeLocation=function(e){return e.sourceCodeLocation},t.updateNodeSourceCodeLocation=function(e,t){e.sourceCodeLocation=Object.assign(e.sourceCodeLocation,t)}},1515:(e,t,n)=>{"use strict";const{DOCUMENT_MODE:r}=n(6152),i="html",s=["+//silmaril//dtd html pro v0r11 19970101//","-//as//dtd html 3.0 aswedit + extensions//","-//advasoft ltd//dtd html 3.0 aswedit + extensions//","-//ietf//dtd html 2.0 level 1//","-//ietf//dtd html 2.0 level 2//","-//ietf//dtd html 2.0 strict level 1//","-//ietf//dtd html 2.0 strict level 2//","-//ietf//dtd html 2.0 strict//","-//ietf//dtd html 2.0//","-//ietf//dtd html 2.1e//","-//ietf//dtd html 3.0//","-//ietf//dtd html 3.2 final//","-//ietf//dtd html 3.2//","-//ietf//dtd html 3//","-//ietf//dtd html level 0//","-//ietf//dtd html level 1//","-//ietf//dtd html level 2//","-//ietf//dtd html level 3//","-//ietf//dtd html strict level 0//","-//ietf//dtd html strict level 1//","-//ietf//dtd html strict level 2//","-//ietf//dtd html strict level 3//","-//ietf//dtd html strict//","-//ietf//dtd html//","-//metrius//dtd metrius presentational//","-//microsoft//dtd internet explorer 2.0 html strict//","-//microsoft//dtd internet explorer 2.0 html//","-//microsoft//dtd internet explorer 2.0 tables//","-//microsoft//dtd internet explorer 3.0 html strict//","-//microsoft//dtd internet explorer 3.0 html//","-//microsoft//dtd internet explorer 3.0 tables//","-//netscape comm. corp.//dtd html//","-//netscape comm. corp.//dtd strict html//","-//o'reilly and associates//dtd html 2.0//","-//o'reilly and associates//dtd html extended 1.0//","-//o'reilly and associates//dtd html extended relaxed 1.0//","-//sq//dtd html 2.0 hotmetal + extensions//","-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//","-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//","-//spyglass//dtd html 2.0 extended//","-//sun microsystems corp.//dtd hotjava html//","-//sun microsystems corp.//dtd hotjava strict html//","-//w3c//dtd html 3 1995-03-24//","-//w3c//dtd html 3.2 draft//","-//w3c//dtd html 3.2 final//","-//w3c//dtd html 3.2//","-//w3c//dtd html 3.2s draft//","-//w3c//dtd html 4.0 frameset//","-//w3c//dtd html 4.0 transitional//","-//w3c//dtd html experimental 19960712//","-//w3c//dtd html experimental 970421//","-//w3c//dtd w3 html//","-//w3o//dtd w3 html 3.0//","-//webtechs//dtd mozilla html 2.0//","-//webtechs//dtd mozilla html//"],o=s.concat(["-//w3c//dtd html 4.01 frameset//","-//w3c//dtd html 4.01 transitional//"]),a=["-//w3o//dtd w3 html strict 3.0//en//","-/w3c/dtd html 4.0 transitional/en","html"],c=["-//w3c//dtd xhtml 1.0 frameset//","-//w3c//dtd xhtml 1.0 transitional//"],l=c.concat(["-//w3c//dtd html 4.01 frameset//","-//w3c//dtd html 4.01 transitional//"]);function u(e){const t=-1!==e.indexOf('"')?"'":'"';return t+e+t}function h(e,t){for(let n=0;n<t.length;n++)if(0===e.indexOf(t[n]))return!0;return!1}t.isConforming=function(e){return e.name===i&&null===e.publicId&&(null===e.systemId||"about:legacy-compat"===e.systemId)},t.getDocumentMode=function(e){if(e.name!==i)return r.QUIRKS;const t=e.systemId;if(t&&"http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd"===t.toLowerCase())return r.QUIRKS;let n=e.publicId;if(null!==n){if(n=n.toLowerCase(),a.indexOf(n)>-1)return r.QUIRKS;let e=null===t?o:s;if(h(n,e))return r.QUIRKS;if(e=null===t?c:l,h(n,e))return r.LIMITED_QUIRKS}return r.NO_QUIRKS},t.serializeContent=function(e,t,n){let r="!DOCTYPE ";return e&&(r+=e),t?r+=" PUBLIC "+u(t):n&&(r+=" SYSTEM"),null!==n&&(r+=" "+u(n)),r}},1734:e=>{"use strict";e.exports={controlCharacterInInputStream:"control-character-in-input-stream",noncharacterInInputStream:"noncharacter-in-input-stream",surrogateInInputStream:"surrogate-in-input-stream",nonVoidHtmlElementStartTagWithTrailingSolidus:"non-void-html-element-start-tag-with-trailing-solidus",endTagWithAttributes:"end-tag-with-attributes",endTagWithTrailingSolidus:"end-tag-with-trailing-solidus",unexpectedSolidusInTag:"unexpected-solidus-in-tag",unexpectedNullCharacter:"unexpected-null-character",unexpectedQuestionMarkInsteadOfTagName:"unexpected-question-mark-instead-of-tag-name",invalidFirstCharacterOfTagName:"invalid-first-character-of-tag-name",unexpectedEqualsSignBeforeAttributeName:"unexpected-equals-sign-before-attribute-name",missingEndTagName:"missing-end-tag-name",unexpectedCharacterInAttributeName:"unexpected-character-in-attribute-name",unknownNamedCharacterReference:"unknown-named-character-reference",missingSemicolonAfterCharacterReference:"missing-semicolon-after-character-reference",unexpectedCharacterAfterDoctypeSystemIdentifier:"unexpected-character-after-doctype-system-identifier",unexpectedCharacterInUnquotedAttributeValue:"unexpected-character-in-unquoted-attribute-value",eofBeforeTagName:"eof-before-tag-name",eofInTag:"eof-in-tag",missingAttributeValue:"missing-attribute-value",missingWhitespaceBetweenAttributes:"missing-whitespace-between-attributes",missingWhitespaceAfterDoctypePublicKeyword:"missing-whitespace-after-doctype-public-keyword",missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers:"missing-whitespace-between-doctype-public-and-system-identifiers",missingWhitespaceAfterDoctypeSystemKeyword:"missing-whitespace-after-doctype-system-keyword",missingQuoteBeforeDoctypePublicIdentifier:"missing-quote-before-doctype-public-identifier",missingQuoteBeforeDoctypeSystemIdentifier:"missing-quote-before-doctype-system-identifier",missingDoctypePublicIdentifier:"missing-doctype-public-identifier",missingDoctypeSystemIdentifier:"missing-doctype-system-identifier",abruptDoctypePublicIdentifier:"abrupt-doctype-public-identifier",abruptDoctypeSystemIdentifier:"abrupt-doctype-system-identifier",cdataInHtmlContent:"cdata-in-html-content",incorrectlyOpenedComment:"incorrectly-opened-comment",eofInScriptHtmlCommentLikeText:"eof-in-script-html-comment-like-text",eofInDoctype:"eof-in-doctype",nestedComment:"nested-comment",abruptClosingOfEmptyComment:"abrupt-closing-of-empty-comment",eofInComment:"eof-in-comment",incorrectlyClosedComment:"incorrectly-closed-comment",eofInCdata:"eof-in-cdata",absenceOfDigitsInNumericCharacterReference:"absence-of-digits-in-numeric-character-reference",nullCharacterReference:"null-character-reference",surrogateCharacterReference:"surrogate-character-reference",characterReferenceOutsideUnicodeRange:"character-reference-outside-unicode-range",controlCharacterReference:"control-character-reference",noncharacterCharacterReference:"noncharacter-character-reference",missingWhitespaceBeforeDoctypeName:"missing-whitespace-before-doctype-name",missingDoctypeName:"missing-doctype-name",invalidCharacterSequenceAfterDoctypeName:"invalid-character-sequence-after-doctype-name",duplicateAttribute:"duplicate-attribute",nonConformingDoctype:"non-conforming-doctype",missingDoctype:"missing-doctype",misplacedDoctype:"misplaced-doctype",endTagWithoutMatchingOpenElement:"end-tag-without-matching-open-element",closingOfElementWithOpenChildElements:"closing-of-element-with-open-child-elements",disallowedContentInNoscriptInHead:"disallowed-content-in-noscript-in-head",openElementsLeftAfterEof:"open-elements-left-after-eof",abandonedHeadElementChild:"abandoned-head-element-child",misplacedStartTagForHeadElement:"misplaced-start-tag-for-head-element",nestedNoscriptInHead:"nested-noscript-in-head",eofInElementThatCanContainOnlyText:"eof-in-element-that-can-contain-only-text"}},8779:(e,t,n)=>{"use strict";const r=n(5763),i=n(6152),s=i.TAG_NAMES,o=i.NAMESPACES,a=i.ATTRS,c={attributename:"attributeName",attributetype:"attributeType",basefrequency:"baseFrequency",baseprofile:"baseProfile",calcmode:"calcMode",clippathunits:"clipPathUnits",diffuseconstant:"diffuseConstant",edgemode:"edgeMode",filterunits:"filterUnits",glyphref:"glyphRef",gradienttransform:"gradientTransform",gradientunits:"gradientUnits",kernelmatrix:"kernelMatrix",kernelunitlength:"kernelUnitLength",keypoints:"keyPoints",keysplines:"keySplines",keytimes:"keyTimes",lengthadjust:"lengthAdjust",limitingconeangle:"limitingConeAngle",markerheight:"markerHeight",markerunits:"markerUnits",markerwidth:"markerWidth",maskcontentunits:"maskContentUnits",maskunits:"maskUnits",numoctaves:"numOctaves",pathlength:"pathLength",patterncontentunits:"patternContentUnits",patterntransform:"patternTransform",patternunits:"patternUnits",pointsatx:"pointsAtX",pointsaty:"pointsAtY",pointsatz:"pointsAtZ",preservealpha:"preserveAlpha",preserveaspectratio:"preserveAspectRatio",primitiveunits:"primitiveUnits",refx:"refX",refy:"refY",repeatcount:"repeatCount",repeatdur:"repeatDur",requiredextensions:"requiredExtensions",requiredfeatures:"requiredFeatures",specularconstant:"specularConstant",specularexponent:"specularExponent",spreadmethod:"spreadMethod",startoffset:"startOffset",stddeviation:"stdDeviation",stitchtiles:"stitchTiles",surfacescale:"surfaceScale",systemlanguage:"systemLanguage",tablevalues:"tableValues",targetx:"targetX",targety:"targetY",textlength:"textLength",viewbox:"viewBox",viewtarget:"viewTarget",xchannelselector:"xChannelSelector",ychannelselector:"yChannelSelector",zoomandpan:"zoomAndPan"},l={"xlink:actuate":{prefix:"xlink",name:"actuate",namespace:o.XLINK},"xlink:arcrole":{prefix:"xlink",name:"arcrole",namespace:o.XLINK},"xlink:href":{prefix:"xlink",name:"href",namespace:o.XLINK},"xlink:role":{prefix:"xlink",name:"role",namespace:o.XLINK},"xlink:show":{prefix:"xlink",name:"show",namespace:o.XLINK},"xlink:title":{prefix:"xlink",name:"title",namespace:o.XLINK},"xlink:type":{prefix:"xlink",name:"type",namespace:o.XLINK},"xml:base":{prefix:"xml",name:"base",namespace:o.XML},"xml:lang":{prefix:"xml",name:"lang",namespace:o.XML},"xml:space":{prefix:"xml",name:"space",namespace:o.XML},xmlns:{prefix:"",name:"xmlns",namespace:o.XMLNS},"xmlns:xlink":{prefix:"xmlns",name:"xlink",namespace:o.XMLNS}},u=t.SVG_TAG_NAMES_ADJUSTMENT_MAP={altglyph:"altGlyph",altglyphdef:"altGlyphDef",altglyphitem:"altGlyphItem",animatecolor:"animateColor",animatemotion:"animateMotion",animatetransform:"animateTransform",clippath:"clipPath",feblend:"feBlend",fecolormatrix:"feColorMatrix",fecomponenttransfer:"feComponentTransfer",fecomposite:"feComposite",feconvolvematrix:"feConvolveMatrix",fediffuselighting:"feDiffuseLighting",fedisplacementmap:"feDisplacementMap",fedistantlight:"feDistantLight",feflood:"feFlood",fefunca:"feFuncA",fefuncb:"feFuncB",fefuncg:"feFuncG",fefuncr:"feFuncR",fegaussianblur:"feGaussianBlur",feimage:"feImage",femerge:"feMerge",femergenode:"feMergeNode",femorphology:"feMorphology",feoffset:"feOffset",fepointlight:"fePointLight",fespecularlighting:"feSpecularLighting",fespotlight:"feSpotLight",fetile:"feTile",feturbulence:"feTurbulence",foreignobject:"foreignObject",glyphref:"glyphRef",lineargradient:"linearGradient",radialgradient:"radialGradient",textpath:"textPath"},h={[s.B]:!0,[s.BIG]:!0,[s.BLOCKQUOTE]:!0,[s.BODY]:!0,[s.BR]:!0,[s.CENTER]:!0,[s.CODE]:!0,[s.DD]:!0,[s.DIV]:!0,[s.DL]:!0,[s.DT]:!0,[s.EM]:!0,[s.EMBED]:!0,[s.H1]:!0,[s.H2]:!0,[s.H3]:!0,[s.H4]:!0,[s.H5]:!0,[s.H6]:!0,[s.HEAD]:!0,[s.HR]:!0,[s.I]:!0,[s.IMG]:!0,[s.LI]:!0,[s.LISTING]:!0,[s.MENU]:!0,[s.META]:!0,[s.NOBR]:!0,[s.OL]:!0,[s.P]:!0,[s.PRE]:!0,[s.RUBY]:!0,[s.S]:!0,[s.SMALL]:!0,[s.SPAN]:!0,[s.STRONG]:!0,[s.STRIKE]:!0,[s.SUB]:!0,[s.SUP]:!0,[s.TABLE]:!0,[s.TT]:!0,[s.U]:!0,[s.UL]:!0,[s.VAR]:!0};t.causesExit=function(e){const t=e.tagName;return!(t!==s.FONT||null===r.getTokenAttr(e,a.COLOR)&&null===r.getTokenAttr(e,a.SIZE)&&null===r.getTokenAttr(e,a.FACE))||h[t]},t.adjustTokenMathMLAttrs=function(e){for(let t=0;t<e.attrs.length;t++)if("definitionurl"===e.attrs[t].name){e.attrs[t].name="definitionURL";break}},t.adjustTokenSVGAttrs=function(e){for(let t=0;t<e.attrs.length;t++){const n=c[e.attrs[t].name];n&&(e.attrs[t].name=n)}},t.adjustTokenXMLAttrs=function(e){for(let t=0;t<e.attrs.length;t++){const n=l[e.attrs[t].name];n&&(e.attrs[t].prefix=n.prefix,e.attrs[t].name=n.name,e.attrs[t].namespace=n.namespace)}},t.adjustTokenSVGTagName=function(e){const t=u[e.tagName];t&&(e.tagName=t)},t.isIntegrationPoint=function(e,t,n,r){return!(r&&r!==o.HTML||!function(e,t,n){if(t===o.MATHML&&e===s.ANNOTATION_XML)for(let e=0;e<n.length;e++)if(n[e].name===a.ENCODING){const t=n[e].value.toLowerCase();return"text/html"===t||"application/xhtml+xml"===t}return t===o.SVG&&(e===s.FOREIGN_OBJECT||e===s.DESC||e===s.TITLE)}(e,t,n))||!(r&&r!==o.MATHML||!function(e,t){return t===o.MATHML&&(e===s.MI||e===s.MO||e===s.MN||e===s.MS||e===s.MTEXT)}(e,t))}},6152:(e,t)=>{"use strict";const n=t.NAMESPACES={HTML:"http://www.w3.org/1999/xhtml",MATHML:"http://www.w3.org/1998/Math/MathML",SVG:"http://www.w3.org/2000/svg",XLINK:"http://www.w3.org/1999/xlink",XML:"http://www.w3.org/XML/1998/namespace",XMLNS:"http://www.w3.org/2000/xmlns/"};t.ATTRS={TYPE:"type",ACTION:"action",ENCODING:"encoding",PROMPT:"prompt",NAME:"name",COLOR:"color",FACE:"face",SIZE:"size"},t.DOCUMENT_MODE={NO_QUIRKS:"no-quirks",QUIRKS:"quirks",LIMITED_QUIRKS:"limited-quirks"};const r=t.TAG_NAMES={A:"a",ADDRESS:"address",ANNOTATION_XML:"annotation-xml",APPLET:"applet",AREA:"area",ARTICLE:"article",ASIDE:"aside",B:"b",BASE:"base",BASEFONT:"basefont",BGSOUND:"bgsound",BIG:"big",BLOCKQUOTE:"blockquote",BODY:"body",BR:"br",BUTTON:"button",CAPTION:"caption",CENTER:"center",CODE:"code",COL:"col",COLGROUP:"colgroup",DD:"dd",DESC:"desc",DETAILS:"details",DIALOG:"dialog",DIR:"dir",DIV:"div",DL:"dl",DT:"dt",EM:"em",EMBED:"embed",FIELDSET:"fieldset",FIGCAPTION:"figcaption",FIGURE:"figure",FONT:"font",FOOTER:"footer",FOREIGN_OBJECT:"foreignObject",FORM:"form",FRAME:"frame",FRAMESET:"frameset",H1:"h1",H2:"h2",H3:"h3",H4:"h4",H5:"h5",H6:"h6",HEAD:"head",HEADER:"header",HGROUP:"hgroup",HR:"hr",HTML:"html",I:"i",IMG:"img",IMAGE:"image",INPUT:"input",IFRAME:"iframe",KEYGEN:"keygen",LABEL:"label",LI:"li",LINK:"link",LISTING:"listing",MAIN:"main",MALIGNMARK:"malignmark",MARQUEE:"marquee",MATH:"math",MENU:"menu",META:"meta",MGLYPH:"mglyph",MI:"mi",MO:"mo",MN:"mn",MS:"ms",MTEXT:"mtext",NAV:"nav",NOBR:"nobr",NOFRAMES:"noframes",NOEMBED:"noembed",NOSCRIPT:"noscript",OBJECT:"object",OL:"ol",OPTGROUP:"optgroup",OPTION:"option",P:"p",PARAM:"param",PLAINTEXT:"plaintext",PRE:"pre",RB:"rb",RP:"rp",RT:"rt",RTC:"rtc",RUBY:"ruby",S:"s",SCRIPT:"script",SECTION:"section",SELECT:"select",SOURCE:"source",SMALL:"small",SPAN:"span",STRIKE:"strike",STRONG:"strong",STYLE:"style",SUB:"sub",SUMMARY:"summary",SUP:"sup",TABLE:"table",TBODY:"tbody",TEMPLATE:"template",TEXTAREA:"textarea",TFOOT:"tfoot",TD:"td",TH:"th",THEAD:"thead",TITLE:"title",TR:"tr",TRACK:"track",TT:"tt",U:"u",UL:"ul",SVG:"svg",VAR:"var",WBR:"wbr",XMP:"xmp"};t.SPECIAL_ELEMENTS={[n.HTML]:{[r.ADDRESS]:!0,[r.APPLET]:!0,[r.AREA]:!0,[r.ARTICLE]:!0,[r.ASIDE]:!0,[r.BASE]:!0,[r.BASEFONT]:!0,[r.BGSOUND]:!0,[r.BLOCKQUOTE]:!0,[r.BODY]:!0,[r.BR]:!0,[r.BUTTON]:!0,[r.CAPTION]:!0,[r.CENTER]:!0,[r.COL]:!0,[r.COLGROUP]:!0,[r.DD]:!0,[r.DETAILS]:!0,[r.DIR]:!0,[r.DIV]:!0,[r.DL]:!0,[r.DT]:!0,[r.EMBED]:!0,[r.FIELDSET]:!0,[r.FIGCAPTION]:!0,[r.FIGURE]:!0,[r.FOOTER]:!0,[r.FORM]:!0,[r.FRAME]:!0,[r.FRAMESET]:!0,[r.H1]:!0,[r.H2]:!0,[r.H3]:!0,[r.H4]:!0,[r.H5]:!0,[r.H6]:!0,[r.HEAD]:!0,[r.HEADER]:!0,[r.HGROUP]:!0,[r.HR]:!0,[r.HTML]:!0,[r.IFRAME]:!0,[r.IMG]:!0,[r.INPUT]:!0,[r.LI]:!0,[r.LINK]:!0,[r.LISTING]:!0,[r.MAIN]:!0,[r.MARQUEE]:!0,[r.MENU]:!0,[r.META]:!0,[r.NAV]:!0,[r.NOEMBED]:!0,[r.NOFRAMES]:!0,[r.NOSCRIPT]:!0,[r.OBJECT]:!0,[r.OL]:!0,[r.P]:!0,[r.PARAM]:!0,[r.PLAINTEXT]:!0,[r.PRE]:!0,[r.SCRIPT]:!0,[r.SECTION]:!0,[r.SELECT]:!0,[r.SOURCE]:!0,[r.STYLE]:!0,[r.SUMMARY]:!0,[r.TABLE]:!0,[r.TBODY]:!0,[r.TD]:!0,[r.TEMPLATE]:!0,[r.TEXTAREA]:!0,[r.TFOOT]:!0,[r.TH]:!0,[r.THEAD]:!0,[r.TITLE]:!0,[r.TR]:!0,[r.TRACK]:!0,[r.UL]:!0,[r.WBR]:!0,[r.XMP]:!0},[n.MATHML]:{[r.MI]:!0,[r.MO]:!0,[r.MN]:!0,[r.MS]:!0,[r.MTEXT]:!0,[r.ANNOTATION_XML]:!0},[n.SVG]:{[r.TITLE]:!0,[r.FOREIGN_OBJECT]:!0,[r.DESC]:!0}}},4284:(e,t)=>{"use strict";const n=[65534,65535,131070,131071,196606,196607,262142,262143,327678,327679,393214,393215,458750,458751,524286,524287,589822,589823,655358,655359,720894,720895,786430,786431,851966,851967,917502,917503,983038,983039,1048574,1048575,1114110,1114111];t.REPLACEMENT_CHARACTER="�",t.CODE_POINTS={EOF:-1,NULL:0,TABULATION:9,CARRIAGE_RETURN:13,LINE_FEED:10,FORM_FEED:12,SPACE:32,EXCLAMATION_MARK:33,QUOTATION_MARK:34,NUMBER_SIGN:35,AMPERSAND:38,APOSTROPHE:39,HYPHEN_MINUS:45,SOLIDUS:47,DIGIT_0:48,DIGIT_9:57,SEMICOLON:59,LESS_THAN_SIGN:60,EQUALS_SIGN:61,GREATER_THAN_SIGN:62,QUESTION_MARK:63,LATIN_CAPITAL_A:65,LATIN_CAPITAL_F:70,LATIN_CAPITAL_X:88,LATIN_CAPITAL_Z:90,RIGHT_SQUARE_BRACKET:93,GRAVE_ACCENT:96,LATIN_SMALL_A:97,LATIN_SMALL_F:102,LATIN_SMALL_X:120,LATIN_SMALL_Z:122,REPLACEMENT_CHARACTER:65533},t.CODE_POINT_SEQUENCES={DASH_DASH_STRING:[45,45],DOCTYPE_STRING:[68,79,67,84,89,80,69],CDATA_START_STRING:[91,67,68,65,84,65,91],SCRIPT_STRING:[115,99,114,105,112,116],PUBLIC_STRING:[80,85,66,76,73,67],SYSTEM_STRING:[83,89,83,84,69,77]},t.isSurrogate=function(e){return e>=55296&&e<=57343},t.isSurrogatePair=function(e){return e>=56320&&e<=57343},t.getSurrogatePairCodePoint=function(e,t){return 1024*(e-55296)+9216+t},t.isControlCodePoint=function(e){return 32!==e&&10!==e&&13!==e&&9!==e&&12!==e&&e>=1&&e<=31||e>=127&&e<=159},t.isUndefinedCodePoint=function(e){return e>=64976&&e<=65007||n.indexOf(e)>-1}},3843:(e,t,n)=>{"use strict";const r=n(1704);e.exports=class extends r{constructor(e,t){super(e),this.posTracker=null,this.onParseError=t.onParseError}_setErrorLocation(e){e.startLine=e.endLine=this.posTracker.line,e.startCol=e.endCol=this.posTracker.col,e.startOffset=e.endOffset=this.posTracker.offset}_reportError(e){const t={code:e,startLine:-1,startCol:-1,startOffset:-1,endLine:-1,endCol:-1,endOffset:-1};this._setErrorLocation(t),this.onParseError(t)}_getOverriddenMethods(e){return{_err(t){e._reportError(t)}}}}},2232:(e,t,n)=>{"use strict";const r=n(3843),i=n(50),s=n(6110),o=n(1704);e.exports=class extends r{constructor(e,t){super(e,t),this.opts=t,this.ctLoc=null,this.locBeforeToken=!1}_setErrorLocation(e){this.ctLoc&&(e.startLine=this.ctLoc.startLine,e.startCol=this.ctLoc.startCol,e.startOffset=this.ctLoc.startOffset,e.endLine=this.locBeforeToken?this.ctLoc.startLine:this.ctLoc.endLine,e.endCol=this.locBeforeToken?this.ctLoc.startCol:this.ctLoc.endCol,e.endOffset=this.locBeforeToken?this.ctLoc.startOffset:this.ctLoc.endOffset)}_getOverriddenMethods(e,t){return{_bootstrap(n,r){t._bootstrap.call(this,n,r),o.install(this.tokenizer,i,e.opts),o.install(this.tokenizer,s)},_processInputToken(n){e.ctLoc=n.location,t._processInputToken.call(this,n)},_err(t,n){e.locBeforeToken=n&&n.beforeToken,e._reportError(t)}}}}},3288:(e,t,n)=>{"use strict";const r=n(3843),i=n(7930),s=n(1704);e.exports=class extends r{constructor(e,t){super(e,t),this.posTracker=s.install(e,i),this.lastErrOffset=-1}_reportError(e){this.lastErrOffset!==this.posTracker.offset&&(this.lastErrOffset=this.posTracker.offset,super._reportError(e))}}},50:(e,t,n)=>{"use strict";const r=n(3843),i=n(3288),s=n(1704);e.exports=class extends r{constructor(e,t){super(e,t);const n=s.install(e.preprocessor,i,t);this.posTracker=n.posTracker}}},1077:(e,t,n)=>{"use strict";const r=n(1704);e.exports=class extends r{constructor(e,t){super(e),this.onItemPop=t.onItemPop}_getOverriddenMethods(e,t){return{pop(){e.onItemPop(this.current),t.pop.call(this)},popAllUpToHtmlElement(){for(let t=this.stackTop;t>0;t--)e.onItemPop(this.items[t]);t.popAllUpToHtmlElement.call(this)},remove(n){e.onItemPop(this.current),t.remove.call(this,n)}}}}},452:(e,t,n)=>{"use strict";const r=n(1704),i=n(5763),s=n(6110),o=n(1077),a=n(6152).TAG_NAMES;e.exports=class extends r{constructor(e){super(e),this.parser=e,this.treeAdapter=this.parser.treeAdapter,this.posTracker=null,this.lastStartTagToken=null,this.lastFosterParentingLocation=null,this.currentToken=null}_setStartLocation(e){let t=null;this.lastStartTagToken&&(t=Object.assign({},this.lastStartTagToken.location),t.startTag=this.lastStartTagToken.location),this.treeAdapter.setNodeSourceCodeLocation(e,t)}_setEndLocation(e,t){if(this.treeAdapter.getNodeSourceCodeLocation(e)&&t.location){const n=t.location,r=this.treeAdapter.getTagName(e),s={};t.type===i.END_TAG_TOKEN&&r===t.tagName?(s.endTag=Object.assign({},n),s.endLine=n.endLine,s.endCol=n.endCol,s.endOffset=n.endOffset):(s.endLine=n.startLine,s.endCol=n.startCol,s.endOffset=n.startOffset),this.treeAdapter.updateNodeSourceCodeLocation(e,s)}}_getOverriddenMethods(e,t){return{_bootstrap(n,i){t._bootstrap.call(this,n,i),e.lastStartTagToken=null,e.lastFosterParentingLocation=null,e.currentToken=null;const a=r.install(this.tokenizer,s);e.posTracker=a.posTracker,r.install(this.openElements,o,{onItemPop:function(t){e._setEndLocation(t,e.currentToken)}})},_runParsingLoop(n){t._runParsingLoop.call(this,n);for(let t=this.openElements.stackTop;t>=0;t--)e._setEndLocation(this.openElements.items[t],e.currentToken)},_processTokenInForeignContent(n){e.currentToken=n,t._processTokenInForeignContent.call(this,n)},_processToken(n){if(e.currentToken=n,t._processToken.call(this,n),n.type===i.END_TAG_TOKEN&&(n.tagName===a.HTML||n.tagName===a.BODY&&this.openElements.hasInScope(a.BODY)))for(let t=this.openElements.stackTop;t>=0;t--){const r=this.openElements.items[t];if(this.treeAdapter.getTagName(r)===n.tagName){e._setEndLocation(r,n);break}}},_setDocumentType(e){t._setDocumentType.call(this,e);const n=this.treeAdapter.getChildNodes(this.document),r=n.length;for(let t=0;t<r;t++){const r=n[t];if(this.treeAdapter.isDocumentTypeNode(r)){this.treeAdapter.setNodeSourceCodeLocation(r,e.location);break}}},_attachElementToTree(n){e._setStartLocation(n),e.lastStartTagToken=null,t._attachElementToTree.call(this,n)},_appendElement(n,r){e.lastStartTagToken=n,t._appendElement.call(this,n,r)},_insertElement(n,r){e.lastStartTagToken=n,t._insertElement.call(this,n,r)},_insertTemplate(n){e.lastStartTagToken=n,t._insertTemplate.call(this,n);const r=this.treeAdapter.getTemplateContent(this.openElements.current);this.treeAdapter.setNodeSourceCodeLocation(r,null)},_insertFakeRootElement(){t._insertFakeRootElement.call(this),this.treeAdapter.setNodeSourceCodeLocation(this.openElements.current,null)},_appendCommentNode(e,n){t._appendCommentNode.call(this,e,n);const r=this.treeAdapter.getChildNodes(n),i=r[r.length-1];this.treeAdapter.setNodeSourceCodeLocation(i,e.location)},_findFosterParentingLocation(){return e.lastFosterParentingLocation=t._findFosterParentingLocation.call(this),e.lastFosterParentingLocation},_insertCharacters(n){t._insertCharacters.call(this,n);const r=this._shouldFosterParentOnInsertion(),i=r&&e.lastFosterParentingLocation.parent||this.openElements.currentTmplContent||this.openElements.current,s=this.treeAdapter.getChildNodes(i),o=r&&e.lastFosterParentingLocation.beforeElement?s.indexOf(e.lastFosterParentingLocation.beforeElement)-1:s.length-1,a=s[o];if(this.treeAdapter.getNodeSourceCodeLocation(a)){const{endLine:e,endCol:t,endOffset:r}=n.location;this.treeAdapter.updateNodeSourceCodeLocation(a,{endLine:e,endCol:t,endOffset:r})}else this.treeAdapter.setNodeSourceCodeLocation(a,n.location)}}}}},6110:(e,t,n)=>{"use strict";const r=n(1704),i=n(5763),s=n(7930);e.exports=class extends r{constructor(e){super(e),this.tokenizer=e,this.posTracker=r.install(e.preprocessor,s),this.currentAttrLocation=null,this.ctLoc=null}_getCurrentLocation(){return{startLine:this.posTracker.line,startCol:this.posTracker.col,startOffset:this.posTracker.offset,endLine:-1,endCol:-1,endOffset:-1}}_attachCurrentAttrLocationInfo(){this.currentAttrLocation.endLine=this.posTracker.line,this.currentAttrLocation.endCol=this.posTracker.col,this.currentAttrLocation.endOffset=this.posTracker.offset;const e=this.tokenizer.currentToken,t=this.tokenizer.currentAttr;e.location.attrs||(e.location.attrs=Object.create(null)),e.location.attrs[t.name]=this.currentAttrLocation}_getOverriddenMethods(e,t){const n={_createStartTagToken(){t._createStartTagToken.call(this),this.currentToken.location=e.ctLoc},_createEndTagToken(){t._createEndTagToken.call(this),this.currentToken.location=e.ctLoc},_createCommentToken(){t._createCommentToken.call(this),this.currentToken.location=e.ctLoc},_createDoctypeToken(n){t._createDoctypeToken.call(this,n),this.currentToken.location=e.ctLoc},_createCharacterToken(n,r){t._createCharacterToken.call(this,n,r),this.currentCharacterToken.location=e.ctLoc},_createEOFToken(){t._createEOFToken.call(this),this.currentToken.location=e._getCurrentLocation()},_createAttr(n){t._createAttr.call(this,n),e.currentAttrLocation=e._getCurrentLocation()},_leaveAttrName(n){t._leaveAttrName.call(this,n),e._attachCurrentAttrLocationInfo()},_leaveAttrValue(n){t._leaveAttrValue.call(this,n),e._attachCurrentAttrLocationInfo()},_emitCurrentToken(){const n=this.currentToken.location;this.currentCharacterToken&&(this.currentCharacterToken.location.endLine=n.startLine,this.currentCharacterToken.location.endCol=n.startCol,this.currentCharacterToken.location.endOffset=n.startOffset),this.currentToken.type===i.EOF_TOKEN?(n.endLine=n.startLine,n.endCol=n.startCol,n.endOffset=n.startOffset):(n.endLine=e.posTracker.line,n.endCol=e.posTracker.col+1,n.endOffset=e.posTracker.offset+1),t._emitCurrentToken.call(this)},_emitCurrentCharacterToken(){const n=this.currentCharacterToken&&this.currentCharacterToken.location;n&&-1===n.endOffset&&(n.endLine=e.posTracker.line,n.endCol=e.posTracker.col,n.endOffset=e.posTracker.offset),t._emitCurrentCharacterToken.call(this)}};return Object.keys(i.MODE).forEach((r=>{const s=i.MODE[r];n[s]=function(n){e.ctLoc=e._getCurrentLocation(),t[s].call(this,n)}})),n}}},7930:(e,t,n)=>{"use strict";const r=n(1704);e.exports=class extends r{constructor(e){super(e),this.preprocessor=e,this.isEol=!1,this.lineStartPos=0,this.droppedBufferSize=0,this.offset=0,this.col=0,this.line=1}_getOverriddenMethods(e,t){return{advance(){const n=this.pos+1,r=this.html[n];return e.isEol&&(e.isEol=!1,e.line++,e.lineStartPos=n),("\n"===r||"\r"===r&&"\n"!==this.html[n+1])&&(e.isEol=!0),e.col=n-e.lineStartPos+1,e.offset=e.droppedBufferSize+n,t.advance.call(this)},retreat(){t.retreat.call(this),e.isEol=!1,e.col=this.pos-e.lineStartPos+1},dropParsedChunk(){const n=this.pos;t.dropParsedChunk.call(this);const r=n-this.pos;e.lineStartPos-=r,e.droppedBufferSize+=r,e.offset=e.droppedBufferSize+this.pos}}}}},2394:(e,t,n)=>{"use strict";const r=n(7045),i=n(3988);t.parse=function(e,t){return new r(t).parse(e)},t.parseFragment=function(e,t,n){return"string"==typeof e&&(n=t,t=e,e=null),new r(n).parseFragment(t,e)},t.serialize=function(e,t){return new i(e,t).serialize()}},2484:e=>{"use strict";class t{constructor(e){this.length=0,this.entries=[],this.treeAdapter=e,this.bookmark=null}_getNoahArkConditionCandidates(e){const n=[];if(this.length>=3){const r=this.treeAdapter.getAttrList(e).length,i=this.treeAdapter.getTagName(e),s=this.treeAdapter.getNamespaceURI(e);for(let e=this.length-1;e>=0;e--){const o=this.entries[e];if(o.type===t.MARKER_ENTRY)break;const a=o.element,c=this.treeAdapter.getAttrList(a);this.treeAdapter.getTagName(a)===i&&this.treeAdapter.getNamespaceURI(a)===s&&c.length===r&&n.push({idx:e,attrs:c})}}return n.length<3?[]:n}_ensureNoahArkCondition(e){const t=this._getNoahArkConditionCandidates(e);let n=t.length;if(n){const r=this.treeAdapter.getAttrList(e),i=r.length,s=Object.create(null);for(let e=0;e<i;e++){const t=r[e];s[t.name]=t.value}for(let e=0;e<i;e++)for(let r=0;r<n;r++){const i=t[r].attrs[e];if(s[i.name]!==i.value&&(t.splice(r,1),n--),t.length<3)return}for(let e=n-1;e>=2;e--)this.entries.splice(t[e].idx,1),this.length--}}insertMarker(){this.entries.push({type:t.MARKER_ENTRY}),this.length++}pushElement(e,n){this._ensureNoahArkCondition(e),this.entries.push({type:t.ELEMENT_ENTRY,element:e,token:n}),this.length++}insertElementAfterBookmark(e,n){let r=this.length-1;for(;r>=0&&this.entries[r]!==this.bookmark;r--);this.entries.splice(r+1,0,{type:t.ELEMENT_ENTRY,element:e,token:n}),this.length++}removeEntry(e){for(let t=this.length-1;t>=0;t--)if(this.entries[t]===e){this.entries.splice(t,1),this.length--;break}}clearToLastMarker(){for(;this.length;){const e=this.entries.pop();if(this.length--,e.type===t.MARKER_ENTRY)break}}getElementEntryInScopeWithTagName(e){for(let n=this.length-1;n>=0;n--){const r=this.entries[n];if(r.type===t.MARKER_ENTRY)return null;if(this.treeAdapter.getTagName(r.element)===e)return r}return null}getElementEntry(e){for(let n=this.length-1;n>=0;n--){const r=this.entries[n];if(r.type===t.ELEMENT_ENTRY&&r.element===e)return r}return null}}t.MARKER_ENTRY="MARKER_ENTRY",t.ELEMENT_ENTRY="ELEMENT_ENTRY",e.exports=t},7045:(e,t,n)=>{"use strict";const r=n(5763),i=n(6519),s=n(2484),o=n(452),a=n(2232),c=n(1704),l=n(7296),u=n(8904),h=n(1515),p=n(8779),d=n(1734),f=n(4284),m=n(6152),T=m.TAG_NAMES,E=m.NAMESPACES,_=m.ATTRS,g={scriptingEnabled:!0,sourceCodeLocationInfo:!1,onParseError:null,treeAdapter:l},A="hidden",C="INITIAL_MODE",N="BEFORE_HTML_MODE",v="BEFORE_HEAD_MODE",O="IN_HEAD_MODE",b="IN_HEAD_NO_SCRIPT_MODE",S="AFTER_HEAD_MODE",y="IN_BODY_MODE",I="TEXT_MODE",R="IN_TABLE_MODE",k="IN_TABLE_TEXT_MODE",L="IN_CAPTION_MODE",M="IN_COLUMN_GROUP_MODE",x="IN_TABLE_BODY_MODE",P="IN_ROW_MODE",D="IN_CELL_MODE",w="IN_SELECT_MODE",H="IN_SELECT_IN_TABLE_MODE",F="IN_TEMPLATE_MODE",U="AFTER_BODY_MODE",B="IN_FRAMESET_MODE",G="AFTER_FRAMESET_MODE",j="AFTER_AFTER_BODY_MODE",K="AFTER_AFTER_FRAMESET_MODE",q={[T.TR]:P,[T.TBODY]:x,[T.THEAD]:x,[T.TFOOT]:x,[T.CAPTION]:L,[T.COLGROUP]:M,[T.TABLE]:R,[T.BODY]:y,[T.FRAMESET]:B},Y={[T.CAPTION]:R,[T.COLGROUP]:R,[T.TBODY]:R,[T.TFOOT]:R,[T.THEAD]:R,[T.COL]:M,[T.TR]:x,[T.TD]:P,[T.TH]:P},V={[C]:{[r.CHARACTER_TOKEN]:oe,[r.NULL_CHARACTER_TOKEN]:oe,[r.WHITESPACE_CHARACTER_TOKEN]:ee,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:function(e,t){e._setDocumentType(t);const n=t.forceQuirks?m.DOCUMENT_MODE.QUIRKS:h.getDocumentMode(t);h.isConforming(t)||e._err(d.nonConformingDoctype),e.treeAdapter.setDocumentMode(e.document,n),e.insertionMode=N},[r.START_TAG_TOKEN]:oe,[r.END_TAG_TOKEN]:oe,[r.EOF_TOKEN]:oe},[N]:{[r.CHARACTER_TOKEN]:ae,[r.NULL_CHARACTER_TOKEN]:ae,[r.WHITESPACE_CHARACTER_TOKEN]:ee,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:function(e,t){t.tagName===T.HTML?(e._insertElement(t,E.HTML),e.insertionMode=v):ae(e,t)},[r.END_TAG_TOKEN]:function(e,t){const n=t.tagName;n!==T.HTML&&n!==T.HEAD&&n!==T.BODY&&n!==T.BR||ae(e,t)},[r.EOF_TOKEN]:ae},[v]:{[r.CHARACTER_TOKEN]:ce,[r.NULL_CHARACTER_TOKEN]:ce,[r.WHITESPACE_CHARACTER_TOKEN]:ee,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:te,[r.START_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.HTML?Se(e,t):n===T.HEAD?(e._insertElement(t,E.HTML),e.headElement=e.openElements.current,e.insertionMode=O):ce(e,t)},[r.END_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.HEAD||n===T.BODY||n===T.HTML||n===T.BR?ce(e,t):e._err(d.endTagWithoutMatchingOpenElement)},[r.EOF_TOKEN]:ce},[O]:{[r.CHARACTER_TOKEN]:he,[r.NULL_CHARACTER_TOKEN]:he,[r.WHITESPACE_CHARACTER_TOKEN]:ie,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:te,[r.START_TAG_TOKEN]:le,[r.END_TAG_TOKEN]:ue,[r.EOF_TOKEN]:he},[b]:{[r.CHARACTER_TOKEN]:pe,[r.NULL_CHARACTER_TOKEN]:pe,[r.WHITESPACE_CHARACTER_TOKEN]:ie,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:te,[r.START_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.HTML?Se(e,t):n===T.BASEFONT||n===T.BGSOUND||n===T.HEAD||n===T.LINK||n===T.META||n===T.NOFRAMES||n===T.STYLE?le(e,t):n===T.NOSCRIPT?e._err(d.nestedNoscriptInHead):pe(e,t)},[r.END_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.NOSCRIPT?(e.openElements.pop(),e.insertionMode=O):n===T.BR?pe(e,t):e._err(d.endTagWithoutMatchingOpenElement)},[r.EOF_TOKEN]:pe},[S]:{[r.CHARACTER_TOKEN]:de,[r.NULL_CHARACTER_TOKEN]:de,[r.WHITESPACE_CHARACTER_TOKEN]:ie,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:te,[r.START_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.HTML?Se(e,t):n===T.BODY?(e._insertElement(t,E.HTML),e.framesetOk=!1,e.insertionMode=y):n===T.FRAMESET?(e._insertElement(t,E.HTML),e.insertionMode=B):n===T.BASE||n===T.BASEFONT||n===T.BGSOUND||n===T.LINK||n===T.META||n===T.NOFRAMES||n===T.SCRIPT||n===T.STYLE||n===T.TEMPLATE||n===T.TITLE?(e._err(d.abandonedHeadElementChild),e.openElements.push(e.headElement),le(e,t),e.openElements.remove(e.headElement)):n===T.HEAD?e._err(d.misplacedStartTagForHeadElement):de(e,t)},[r.END_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.BODY||n===T.HTML||n===T.BR?de(e,t):n===T.TEMPLATE?ue(e,t):e._err(d.endTagWithoutMatchingOpenElement)},[r.EOF_TOKEN]:de},[y]:{[r.CHARACTER_TOKEN]:me,[r.NULL_CHARACTER_TOKEN]:ee,[r.WHITESPACE_CHARACTER_TOKEN]:fe,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:Se,[r.END_TAG_TOKEN]:ke,[r.EOF_TOKEN]:Le},[I]:{[r.CHARACTER_TOKEN]:ie,[r.NULL_CHARACTER_TOKEN]:ie,[r.WHITESPACE_CHARACTER_TOKEN]:ie,[r.COMMENT_TOKEN]:ee,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:ee,[r.END_TAG_TOKEN]:function(e,t){t.tagName===T.SCRIPT&&(e.pendingScript=e.openElements.current),e.openElements.pop(),e.insertionMode=e.originalInsertionMode},[r.EOF_TOKEN]:function(e,t){e._err(d.eofInElementThatCanContainOnlyText),e.openElements.pop(),e.insertionMode=e.originalInsertionMode,e._processToken(t)}},[R]:{[r.CHARACTER_TOKEN]:Me,[r.NULL_CHARACTER_TOKEN]:Me,[r.WHITESPACE_CHARACTER_TOKEN]:Me,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:xe,[r.END_TAG_TOKEN]:Pe,[r.EOF_TOKEN]:Le},[k]:{[r.CHARACTER_TOKEN]:function(e,t){e.pendingCharacterTokens.push(t),e.hasNonWhitespacePendingCharacterToken=!0},[r.NULL_CHARACTER_TOKEN]:ee,[r.WHITESPACE_CHARACTER_TOKEN]:function(e,t){e.pendingCharacterTokens.push(t)},[r.COMMENT_TOKEN]:we,[r.DOCTYPE_TOKEN]:we,[r.START_TAG_TOKEN]:we,[r.END_TAG_TOKEN]:we,[r.EOF_TOKEN]:we},[L]:{[r.CHARACTER_TOKEN]:me,[r.NULL_CHARACTER_TOKEN]:ee,[r.WHITESPACE_CHARACTER_TOKEN]:fe,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.CAPTION||n===T.COL||n===T.COLGROUP||n===T.TBODY||n===T.TD||n===T.TFOOT||n===T.TH||n===T.THEAD||n===T.TR?e.openElements.hasInTableScope(T.CAPTION)&&(e.openElements.generateImpliedEndTags(),e.openElements.popUntilTagNamePopped(T.CAPTION),e.activeFormattingElements.clearToLastMarker(),e.insertionMode=R,e._processToken(t)):Se(e,t)},[r.END_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.CAPTION||n===T.TABLE?e.openElements.hasInTableScope(T.CAPTION)&&(e.openElements.generateImpliedEndTags(),e.openElements.popUntilTagNamePopped(T.CAPTION),e.activeFormattingElements.clearToLastMarker(),e.insertionMode=R,n===T.TABLE&&e._processToken(t)):n!==T.BODY&&n!==T.COL&&n!==T.COLGROUP&&n!==T.HTML&&n!==T.TBODY&&n!==T.TD&&n!==T.TFOOT&&n!==T.TH&&n!==T.THEAD&&n!==T.TR&&ke(e,t)},[r.EOF_TOKEN]:Le},[M]:{[r.CHARACTER_TOKEN]:He,[r.NULL_CHARACTER_TOKEN]:He,[r.WHITESPACE_CHARACTER_TOKEN]:ie,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.HTML?Se(e,t):n===T.COL?(e._appendElement(t,E.HTML),t.ackSelfClosing=!0):n===T.TEMPLATE?le(e,t):He(e,t)},[r.END_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.COLGROUP?e.openElements.currentTagName===T.COLGROUP&&(e.openElements.pop(),e.insertionMode=R):n===T.TEMPLATE?ue(e,t):n!==T.COL&&He(e,t)},[r.EOF_TOKEN]:Le},[x]:{[r.CHARACTER_TOKEN]:Me,[r.NULL_CHARACTER_TOKEN]:Me,[r.WHITESPACE_CHARACTER_TOKEN]:Me,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.TR?(e.openElements.clearBackToTableBodyContext(),e._insertElement(t,E.HTML),e.insertionMode=P):n===T.TH||n===T.TD?(e.openElements.clearBackToTableBodyContext(),e._insertFakeElement(T.TR),e.insertionMode=P,e._processToken(t)):n===T.CAPTION||n===T.COL||n===T.COLGROUP||n===T.TBODY||n===T.TFOOT||n===T.THEAD?e.openElements.hasTableBodyContextInTableScope()&&(e.openElements.clearBackToTableBodyContext(),e.openElements.pop(),e.insertionMode=R,e._processToken(t)):xe(e,t)},[r.END_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.TBODY||n===T.TFOOT||n===T.THEAD?e.openElements.hasInTableScope(n)&&(e.openElements.clearBackToTableBodyContext(),e.openElements.pop(),e.insertionMode=R):n===T.TABLE?e.openElements.hasTableBodyContextInTableScope()&&(e.openElements.clearBackToTableBodyContext(),e.openElements.pop(),e.insertionMode=R,e._processToken(t)):(n!==T.BODY&&n!==T.CAPTION&&n!==T.COL&&n!==T.COLGROUP||n!==T.HTML&&n!==T.TD&&n!==T.TH&&n!==T.TR)&&Pe(e,t)},[r.EOF_TOKEN]:Le},[P]:{[r.CHARACTER_TOKEN]:Me,[r.NULL_CHARACTER_TOKEN]:Me,[r.WHITESPACE_CHARACTER_TOKEN]:Me,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.TH||n===T.TD?(e.openElements.clearBackToTableRowContext(),e._insertElement(t,E.HTML),e.insertionMode=D,e.activeFormattingElements.insertMarker()):n===T.CAPTION||n===T.COL||n===T.COLGROUP||n===T.TBODY||n===T.TFOOT||n===T.THEAD||n===T.TR?e.openElements.hasInTableScope(T.TR)&&(e.openElements.clearBackToTableRowContext(),e.openElements.pop(),e.insertionMode=x,e._processToken(t)):xe(e,t)},[r.END_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.TR?e.openElements.hasInTableScope(T.TR)&&(e.openElements.clearBackToTableRowContext(),e.openElements.pop(),e.insertionMode=x):n===T.TABLE?e.openElements.hasInTableScope(T.TR)&&(e.openElements.clearBackToTableRowContext(),e.openElements.pop(),e.insertionMode=x,e._processToken(t)):n===T.TBODY||n===T.TFOOT||n===T.THEAD?(e.openElements.hasInTableScope(n)||e.openElements.hasInTableScope(T.TR))&&(e.openElements.clearBackToTableRowContext(),e.openElements.pop(),e.insertionMode=x,e._processToken(t)):(n!==T.BODY&&n!==T.CAPTION&&n!==T.COL&&n!==T.COLGROUP||n!==T.HTML&&n!==T.TD&&n!==T.TH)&&Pe(e,t)},[r.EOF_TOKEN]:Le},[D]:{[r.CHARACTER_TOKEN]:me,[r.NULL_CHARACTER_TOKEN]:ee,[r.WHITESPACE_CHARACTER_TOKEN]:fe,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.CAPTION||n===T.COL||n===T.COLGROUP||n===T.TBODY||n===T.TD||n===T.TFOOT||n===T.TH||n===T.THEAD||n===T.TR?(e.openElements.hasInTableScope(T.TD)||e.openElements.hasInTableScope(T.TH))&&(e._closeTableCell(),e._processToken(t)):Se(e,t)},[r.END_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.TD||n===T.TH?e.openElements.hasInTableScope(n)&&(e.openElements.generateImpliedEndTags(),e.openElements.popUntilTagNamePopped(n),e.activeFormattingElements.clearToLastMarker(),e.insertionMode=P):n===T.TABLE||n===T.TBODY||n===T.TFOOT||n===T.THEAD||n===T.TR?e.openElements.hasInTableScope(n)&&(e._closeTableCell(),e._processToken(t)):n!==T.BODY&&n!==T.CAPTION&&n!==T.COL&&n!==T.COLGROUP&&n!==T.HTML&&ke(e,t)},[r.EOF_TOKEN]:Le},[w]:{[r.CHARACTER_TOKEN]:ie,[r.NULL_CHARACTER_TOKEN]:ee,[r.WHITESPACE_CHARACTER_TOKEN]:ie,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:Fe,[r.END_TAG_TOKEN]:Ue,[r.EOF_TOKEN]:Le},[H]:{[r.CHARACTER_TOKEN]:ie,[r.NULL_CHARACTER_TOKEN]:ee,[r.WHITESPACE_CHARACTER_TOKEN]:ie,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.CAPTION||n===T.TABLE||n===T.TBODY||n===T.TFOOT||n===T.THEAD||n===T.TR||n===T.TD||n===T.TH?(e.openElements.popUntilTagNamePopped(T.SELECT),e._resetInsertionMode(),e._processToken(t)):Fe(e,t)},[r.END_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.CAPTION||n===T.TABLE||n===T.TBODY||n===T.TFOOT||n===T.THEAD||n===T.TR||n===T.TD||n===T.TH?e.openElements.hasInTableScope(n)&&(e.openElements.popUntilTagNamePopped(T.SELECT),e._resetInsertionMode(),e._processToken(t)):Ue(e,t)},[r.EOF_TOKEN]:Le},[F]:{[r.CHARACTER_TOKEN]:me,[r.NULL_CHARACTER_TOKEN]:ee,[r.WHITESPACE_CHARACTER_TOKEN]:fe,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:function(e,t){const n=t.tagName;if(n===T.BASE||n===T.BASEFONT||n===T.BGSOUND||n===T.LINK||n===T.META||n===T.NOFRAMES||n===T.SCRIPT||n===T.STYLE||n===T.TEMPLATE||n===T.TITLE)le(e,t);else{const r=Y[n]||y;e._popTmplInsertionMode(),e._pushTmplInsertionMode(r),e.insertionMode=r,e._processToken(t)}},[r.END_TAG_TOKEN]:function(e,t){t.tagName===T.TEMPLATE&&ue(e,t)},[r.EOF_TOKEN]:Be},[U]:{[r.CHARACTER_TOKEN]:Ge,[r.NULL_CHARACTER_TOKEN]:Ge,[r.WHITESPACE_CHARACTER_TOKEN]:fe,[r.COMMENT_TOKEN]:function(e,t){e._appendCommentNode(t,e.openElements.items[0])},[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:function(e,t){t.tagName===T.HTML?Se(e,t):Ge(e,t)},[r.END_TAG_TOKEN]:function(e,t){t.tagName===T.HTML?e.fragmentContext||(e.insertionMode=j):Ge(e,t)},[r.EOF_TOKEN]:se},[B]:{[r.CHARACTER_TOKEN]:ee,[r.NULL_CHARACTER_TOKEN]:ee,[r.WHITESPACE_CHARACTER_TOKEN]:ie,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.HTML?Se(e,t):n===T.FRAMESET?e._insertElement(t,E.HTML):n===T.FRAME?(e._appendElement(t,E.HTML),t.ackSelfClosing=!0):n===T.NOFRAMES&&le(e,t)},[r.END_TAG_TOKEN]:function(e,t){t.tagName!==T.FRAMESET||e.openElements.isRootHtmlElementCurrent()||(e.openElements.pop(),e.fragmentContext||e.openElements.currentTagName===T.FRAMESET||(e.insertionMode=G))},[r.EOF_TOKEN]:se},[G]:{[r.CHARACTER_TOKEN]:ee,[r.NULL_CHARACTER_TOKEN]:ee,[r.WHITESPACE_CHARACTER_TOKEN]:ie,[r.COMMENT_TOKEN]:ne,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.HTML?Se(e,t):n===T.NOFRAMES&&le(e,t)},[r.END_TAG_TOKEN]:function(e,t){t.tagName===T.HTML&&(e.insertionMode=K)},[r.EOF_TOKEN]:se},[j]:{[r.CHARACTER_TOKEN]:je,[r.NULL_CHARACTER_TOKEN]:je,[r.WHITESPACE_CHARACTER_TOKEN]:fe,[r.COMMENT_TOKEN]:re,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:function(e,t){t.tagName===T.HTML?Se(e,t):je(e,t)},[r.END_TAG_TOKEN]:je,[r.EOF_TOKEN]:se},[K]:{[r.CHARACTER_TOKEN]:ee,[r.NULL_CHARACTER_TOKEN]:ee,[r.WHITESPACE_CHARACTER_TOKEN]:fe,[r.COMMENT_TOKEN]:re,[r.DOCTYPE_TOKEN]:ee,[r.START_TAG_TOKEN]:function(e,t){const n=t.tagName;n===T.HTML?Se(e,t):n===T.NOFRAMES&&le(e,t)},[r.END_TAG_TOKEN]:ee,[r.EOF_TOKEN]:se}};function W(e,t){let n=e.activeFormattingElements.getElementEntryInScopeWithTagName(t.tagName);return n?e.openElements.contains(n.element)?e.openElements.hasInScope(t.tagName)||(n=null):(e.activeFormattingElements.removeEntry(n),n=null):Re(e,t),n}function Q(e,t){let n=null;for(let r=e.openElements.stackTop;r>=0;r--){const i=e.openElements.items[r];if(i===t.element)break;e._isSpecialElement(i)&&(n=i)}return n||(e.openElements.popUntilElementPopped(t.element),e.activeFormattingElements.removeEntry(t)),n}function z(e,t,n){let r=t,i=e.openElements.getCommonAncestor(t);for(let s=0,o=i;o!==n;s++,o=i){i=e.openElements.getCommonAncestor(o);const n=e.activeFormattingElements.getElementEntry(o),a=n&&s>=3;!n||a?(a&&e.activeFormattingElements.removeEntry(n),e.openElements.remove(o)):(o=X(e,n),r===t&&(e.activeFormattingElements.bookmark=n),e.treeAdapter.detachNode(r),e.treeAdapter.appendChild(o,r),r=o)}return r}function X(e,t){const n=e.treeAdapter.getNamespaceURI(t.element),r=e.treeAdapter.createElement(t.token.tagName,n,t.token.attrs);return e.openElements.replace(t.element,r),t.element=r,r}function $(e,t,n){if(e._isElementCausesFosterParenting(t))e._fosterParentElement(n);else{const r=e.treeAdapter.getTagName(t),i=e.treeAdapter.getNamespaceURI(t);r===T.TEMPLATE&&i===E.HTML&&(t=e.treeAdapter.getTemplateContent(t)),e.treeAdapter.appendChild(t,n)}}function J(e,t,n){const r=e.treeAdapter.getNamespaceURI(n.element),i=n.token,s=e.treeAdapter.createElement(i.tagName,r,i.attrs);e._adoptNodes(t,s),e.treeAdapter.appendChild(t,s),e.activeFormattingElements.insertElementAfterBookmark(s,n.token),e.activeFormattingElements.removeEntry(n),e.openElements.remove(n.element),e.openElements.insertAfter(t,s)}function Z(e,t){let n;for(let r=0;r<8&&(n=W(e,t),n);r++){const t=Q(e,n);if(!t)break;e.activeFormattingElements.bookmark=n;const r=z(e,t,n.element),i=e.openElements.getCommonAncestor(n.element);e.treeAdapter.detachNode(r),$(e,i,r),J(e,t,n)}}function ee(){}function te(e){e._err(d.misplacedDoctype)}function ne(e,t){e._appendCommentNode(t,e.openElements.currentTmplContent||e.openElements.current)}function re(e,t){e._appendCommentNode(t,e.document)}function ie(e,t){e._insertCharacters(t)}function se(e){e.stopped=!0}function oe(e,t){e._err(d.missingDoctype,{beforeToken:!0}),e.treeAdapter.setDocumentMode(e.document,m.DOCUMENT_MODE.QUIRKS),e.insertionMode=N,e._processToken(t)}function ae(e,t){e._insertFakeRootElement(),e.insertionMode=v,e._processToken(t)}function ce(e,t){e._insertFakeElement(T.HEAD),e.headElement=e.openElements.current,e.insertionMode=O,e._processToken(t)}function le(e,t){const n=t.tagName;n===T.HTML?Se(e,t):n===T.BASE||n===T.BASEFONT||n===T.BGSOUND||n===T.LINK||n===T.META?(e._appendElement(t,E.HTML),t.ackSelfClosing=!0):n===T.TITLE?e._switchToTextParsing(t,r.MODE.RCDATA):n===T.NOSCRIPT?e.options.scriptingEnabled?e._switchToTextParsing(t,r.MODE.RAWTEXT):(e._insertElement(t,E.HTML),e.insertionMode=b):n===T.NOFRAMES||n===T.STYLE?e._switchToTextParsing(t,r.MODE.RAWTEXT):n===T.SCRIPT?e._switchToTextParsing(t,r.MODE.SCRIPT_DATA):n===T.TEMPLATE?(e._insertTemplate(t,E.HTML),e.activeFormattingElements.insertMarker(),e.framesetOk=!1,e.insertionMode=F,e._pushTmplInsertionMode(F)):n===T.HEAD?e._err(d.misplacedStartTagForHeadElement):he(e,t)}function ue(e,t){const n=t.tagName;n===T.HEAD?(e.openElements.pop(),e.insertionMode=S):n===T.BODY||n===T.BR||n===T.HTML?he(e,t):n===T.TEMPLATE&&e.openElements.tmplCount>0?(e.openElements.generateImpliedEndTagsThoroughly(),e.openElements.currentTagName!==T.TEMPLATE&&e._err(d.closingOfElementWithOpenChildElements),e.openElements.popUntilTagNamePopped(T.TEMPLATE),e.activeFormattingElements.clearToLastMarker(),e._popTmplInsertionMode(),e._resetInsertionMode()):e._err(d.endTagWithoutMatchingOpenElement)}function he(e,t){e.openElements.pop(),e.insertionMode=S,e._processToken(t)}function pe(e,t){const n=t.type===r.EOF_TOKEN?d.openElementsLeftAfterEof:d.disallowedContentInNoscriptInHead;e._err(n),e.openElements.pop(),e.insertionMode=O,e._processToken(t)}function de(e,t){e._insertFakeElement(T.BODY),e.insertionMode=y,e._processToken(t)}function fe(e,t){e._reconstructActiveFormattingElements(),e._insertCharacters(t)}function me(e,t){e._reconstructActiveFormattingElements(),e._insertCharacters(t),e.framesetOk=!1}function Te(e,t){e.openElements.hasInButtonScope(T.P)&&e._closePElement(),e._insertElement(t,E.HTML)}function Ee(e,t){e.openElements.hasInButtonScope(T.P)&&e._closePElement(),e._insertElement(t,E.HTML),e.skipNextNewLine=!0,e.framesetOk=!1}function _e(e,t){e._reconstructActiveFormattingElements(),e._insertElement(t,E.HTML),e.activeFormattingElements.pushElement(e.openElements.current,t)}function ge(e,t){e._reconstructActiveFormattingElements(),e._insertElement(t,E.HTML),e.activeFormattingElements.insertMarker(),e.framesetOk=!1}function Ae(e,t){e._reconstructActiveFormattingElements(),e._appendElement(t,E.HTML),e.framesetOk=!1,t.ackSelfClosing=!0}function Ce(e,t){e._appendElement(t,E.HTML),t.ackSelfClosing=!0}function Ne(e,t){e._switchToTextParsing(t,r.MODE.RAWTEXT)}function ve(e,t){e.openElements.currentTagName===T.OPTION&&e.openElements.pop(),e._reconstructActiveFormattingElements(),e._insertElement(t,E.HTML)}function Oe(e,t){e.openElements.hasInScope(T.RUBY)&&e.openElements.generateImpliedEndTags(),e._insertElement(t,E.HTML)}function be(e,t){e._reconstructActiveFormattingElements(),e._insertElement(t,E.HTML)}function Se(e,t){const n=t.tagName;switch(n.length){case 1:n===T.I||n===T.S||n===T.B||n===T.U?_e(e,t):n===T.P?Te(e,t):n===T.A?function(e,t){const n=e.activeFormattingElements.getElementEntryInScopeWithTagName(T.A);n&&(Z(e,t),e.openElements.remove(n.element),e.activeFormattingElements.removeEntry(n)),e._reconstructActiveFormattingElements(),e._insertElement(t,E.HTML),e.activeFormattingElements.pushElement(e.openElements.current,t)}(e,t):be(e,t);break;case 2:n===T.DL||n===T.OL||n===T.UL?Te(e,t):n===T.H1||n===T.H2||n===T.H3||n===T.H4||n===T.H5||n===T.H6?function(e,t){e.openElements.hasInButtonScope(T.P)&&e._closePElement();const n=e.openElements.currentTagName;n!==T.H1&&n!==T.H2&&n!==T.H3&&n!==T.H4&&n!==T.H5&&n!==T.H6||e.openElements.pop(),e._insertElement(t,E.HTML)}(e,t):n===T.LI||n===T.DD||n===T.DT?function(e,t){e.framesetOk=!1;const n=t.tagName;for(let t=e.openElements.stackTop;t>=0;t--){const r=e.openElements.items[t],i=e.treeAdapter.getTagName(r);let s=null;if(n===T.LI&&i===T.LI?s=T.LI:n!==T.DD&&n!==T.DT||i!==T.DD&&i!==T.DT||(s=i),s){e.openElements.generateImpliedEndTagsWithExclusion(s),e.openElements.popUntilTagNamePopped(s);break}if(i!==T.ADDRESS&&i!==T.DIV&&i!==T.P&&e._isSpecialElement(r))break}e.openElements.hasInButtonScope(T.P)&&e._closePElement(),e._insertElement(t,E.HTML)}(e,t):n===T.EM||n===T.TT?_e(e,t):n===T.BR?Ae(e,t):n===T.HR?function(e,t){e.openElements.hasInButtonScope(T.P)&&e._closePElement(),e._appendElement(t,E.HTML),e.framesetOk=!1,t.ackSelfClosing=!0}(e,t):n===T.RB?Oe(e,t):n===T.RT||n===T.RP?function(e,t){e.openElements.hasInScope(T.RUBY)&&e.openElements.generateImpliedEndTagsWithExclusion(T.RTC),e._insertElement(t,E.HTML)}(e,t):n!==T.TH&&n!==T.TD&&n!==T.TR&&be(e,t);break;case 3:n===T.DIV||n===T.DIR||n===T.NAV?Te(e,t):n===T.PRE?Ee(e,t):n===T.BIG?_e(e,t):n===T.IMG||n===T.WBR?Ae(e,t):n===T.XMP?function(e,t){e.openElements.hasInButtonScope(T.P)&&e._closePElement(),e._reconstructActiveFormattingElements(),e.framesetOk=!1,e._switchToTextParsing(t,r.MODE.RAWTEXT)}(e,t):n===T.SVG?function(e,t){e._reconstructActiveFormattingElements(),p.adjustTokenSVGAttrs(t),p.adjustTokenXMLAttrs(t),t.selfClosing?e._appendElement(t,E.SVG):e._insertElement(t,E.SVG),t.ackSelfClosing=!0}(e,t):n===T.RTC?Oe(e,t):n!==T.COL&&be(e,t);break;case 4:n===T.HTML?function(e,t){0===e.openElements.tmplCount&&e.treeAdapter.adoptAttributes(e.openElements.items[0],t.attrs)}(e,t):n===T.BASE||n===T.LINK||n===T.META?le(e,t):n===T.BODY?function(e,t){const n=e.openElements.tryPeekProperlyNestedBodyElement();n&&0===e.openElements.tmplCount&&(e.framesetOk=!1,e.treeAdapter.adoptAttributes(n,t.attrs))}(e,t):n===T.MAIN||n===T.MENU?Te(e,t):n===T.FORM?function(e,t){const n=e.openElements.tmplCount>0;e.formElement&&!n||(e.openElements.hasInButtonScope(T.P)&&e._closePElement(),e._insertElement(t,E.HTML),n||(e.formElement=e.openElements.current))}(e,t):n===T.CODE||n===T.FONT?_e(e,t):n===T.NOBR?function(e,t){e._reconstructActiveFormattingElements(),e.openElements.hasInScope(T.NOBR)&&(Z(e,t),e._reconstructActiveFormattingElements()),e._insertElement(t,E.HTML),e.activeFormattingElements.pushElement(e.openElements.current,t)}(e,t):n===T.AREA?Ae(e,t):n===T.MATH?function(e,t){e._reconstructActiveFormattingElements(),p.adjustTokenMathMLAttrs(t),p.adjustTokenXMLAttrs(t),t.selfClosing?e._appendElement(t,E.MATHML):e._insertElement(t,E.MATHML),t.ackSelfClosing=!0}(e,t):n===T.MENU?function(e,t){e.openElements.hasInButtonScope(T.P)&&e._closePElement(),e._insertElement(t,E.HTML)}(e,t):n!==T.HEAD&&be(e,t);break;case 5:n===T.STYLE||n===T.TITLE?le(e,t):n===T.ASIDE?Te(e,t):n===T.SMALL?_e(e,t):n===T.TABLE?function(e,t){e.treeAdapter.getDocumentMode(e.document)!==m.DOCUMENT_MODE.QUIRKS&&e.openElements.hasInButtonScope(T.P)&&e._closePElement(),e._insertElement(t,E.HTML),e.framesetOk=!1,e.insertionMode=R}(e,t):n===T.EMBED?Ae(e,t):n===T.INPUT?function(e,t){e._reconstructActiveFormattingElements(),e._appendElement(t,E.HTML);const n=r.getTokenAttr(t,_.TYPE);n&&n.toLowerCase()===A||(e.framesetOk=!1),t.ackSelfClosing=!0}(e,t):n===T.PARAM||n===T.TRACK?Ce(e,t):n===T.IMAGE?function(e,t){t.tagName=T.IMG,Ae(e,t)}(e,t):n!==T.FRAME&&n!==T.TBODY&&n!==T.TFOOT&&n!==T.THEAD&&be(e,t);break;case 6:n===T.SCRIPT?le(e,t):n===T.CENTER||n===T.FIGURE||n===T.FOOTER||n===T.HEADER||n===T.HGROUP||n===T.DIALOG?Te(e,t):n===T.BUTTON?function(e,t){e.openElements.hasInScope(T.BUTTON)&&(e.openElements.generateImpliedEndTags(),e.openElements.popUntilTagNamePopped(T.BUTTON)),e._reconstructActiveFormattingElements(),e._insertElement(t,E.HTML),e.framesetOk=!1}(e,t):n===T.STRIKE||n===T.STRONG?_e(e,t):n===T.APPLET||n===T.OBJECT?ge(e,t):n===T.KEYGEN?Ae(e,t):n===T.SOURCE?Ce(e,t):n===T.IFRAME?function(e,t){e.framesetOk=!1,e._switchToTextParsing(t,r.MODE.RAWTEXT)}(e,t):n===T.SELECT?function(e,t){e._reconstructActiveFormattingElements(),e._insertElement(t,E.HTML),e.framesetOk=!1,e.insertionMode===R||e.insertionMode===L||e.insertionMode===x||e.insertionMode===P||e.insertionMode===D?e.insertionMode=H:e.insertionMode=w}(e,t):n===T.OPTION?ve(e,t):be(e,t);break;case 7:n===T.BGSOUND?le(e,t):n===T.DETAILS||n===T.ADDRESS||n===T.ARTICLE||n===T.SECTION||n===T.SUMMARY?Te(e,t):n===T.LISTING?Ee(e,t):n===T.MARQUEE?ge(e,t):n===T.NOEMBED?Ne(e,t):n!==T.CAPTION&&be(e,t);break;case 8:n===T.BASEFONT?le(e,t):n===T.FRAMESET?function(e,t){const n=e.openElements.tryPeekProperlyNestedBodyElement();e.framesetOk&&n&&(e.treeAdapter.detachNode(n),e.openElements.popAllUpToHtmlElement(),e._insertElement(t,E.HTML),e.insertionMode=B)}(e,t):n===T.FIELDSET?Te(e,t):n===T.TEXTAREA?function(e,t){e._insertElement(t,E.HTML),e.skipNextNewLine=!0,e.tokenizer.state=r.MODE.RCDATA,e.originalInsertionMode=e.insertionMode,e.framesetOk=!1,e.insertionMode=I}(e,t):n===T.TEMPLATE?le(e,t):n===T.NOSCRIPT?e.options.scriptingEnabled?Ne(e,t):be(e,t):n===T.OPTGROUP?ve(e,t):n!==T.COLGROUP&&be(e,t);break;case 9:n===T.PLAINTEXT?function(e,t){e.openElements.hasInButtonScope(T.P)&&e._closePElement(),e._insertElement(t,E.HTML),e.tokenizer.state=r.MODE.PLAINTEXT}(e,t):be(e,t);break;case 10:n===T.BLOCKQUOTE||n===T.FIGCAPTION?Te(e,t):be(e,t);break;default:be(e,t)}}function ye(e,t){const n=t.tagName;e.openElements.hasInScope(n)&&(e.openElements.generateImpliedEndTags(),e.openElements.popUntilTagNamePopped(n))}function Ie(e,t){const n=t.tagName;e.openElements.hasInScope(n)&&(e.openElements.generateImpliedEndTags(),e.openElements.popUntilTagNamePopped(n),e.activeFormattingElements.clearToLastMarker())}function Re(e,t){const n=t.tagName;for(let t=e.openElements.stackTop;t>0;t--){const r=e.openElements.items[t];if(e.treeAdapter.getTagName(r)===n){e.openElements.generateImpliedEndTagsWithExclusion(n),e.openElements.popUntilElementPopped(r);break}if(e._isSpecialElement(r))break}}function ke(e,t){const n=t.tagName;switch(n.length){case 1:n===T.A||n===T.B||n===T.I||n===T.S||n===T.U?Z(e,t):n===T.P?function(e){e.openElements.hasInButtonScope(T.P)||e._insertFakeElement(T.P),e._closePElement()}(e):Re(e,t);break;case 2:n===T.DL||n===T.UL||n===T.OL?ye(e,t):n===T.LI?function(e){e.openElements.hasInListItemScope(T.LI)&&(e.openElements.generateImpliedEndTagsWithExclusion(T.LI),e.openElements.popUntilTagNamePopped(T.LI))}(e):n===T.DD||n===T.DT?function(e,t){const n=t.tagName;e.openElements.hasInScope(n)&&(e.openElements.generateImpliedEndTagsWithExclusion(n),e.openElements.popUntilTagNamePopped(n))}(e,t):n===T.H1||n===T.H2||n===T.H3||n===T.H4||n===T.H5||n===T.H6?function(e){e.openElements.hasNumberedHeaderInScope()&&(e.openElements.generateImpliedEndTags(),e.openElements.popUntilNumberedHeaderPopped())}(e):n===T.BR?function(e){e._reconstructActiveFormattingElements(),e._insertFakeElement(T.BR),e.openElements.pop(),e.framesetOk=!1}(e):n===T.EM||n===T.TT?Z(e,t):Re(e,t);break;case 3:n===T.BIG?Z(e,t):n===T.DIR||n===T.DIV||n===T.NAV||n===T.PRE?ye(e,t):Re(e,t);break;case 4:n===T.BODY?function(e){e.openElements.hasInScope(T.BODY)&&(e.insertionMode=U)}(e):n===T.HTML?function(e,t){e.openElements.hasInScope(T.BODY)&&(e.insertionMode=U,e._processToken(t))}(e,t):n===T.FORM?function(e){const t=e.openElements.tmplCount>0,n=e.formElement;t||(e.formElement=null),(n||t)&&e.openElements.hasInScope(T.FORM)&&(e.openElements.generateImpliedEndTags(),t?e.openElements.popUntilTagNamePopped(T.FORM):e.openElements.remove(n))}(e):n===T.CODE||n===T.FONT||n===T.NOBR?Z(e,t):n===T.MAIN||n===T.MENU?ye(e,t):Re(e,t);break;case 5:n===T.ASIDE?ye(e,t):n===T.SMALL?Z(e,t):Re(e,t);break;case 6:n===T.CENTER||n===T.FIGURE||n===T.FOOTER||n===T.HEADER||n===T.HGROUP||n===T.DIALOG?ye(e,t):n===T.APPLET||n===T.OBJECT?Ie(e,t):n===T.STRIKE||n===T.STRONG?Z(e,t):Re(e,t);break;case 7:n===T.ADDRESS||n===T.ARTICLE||n===T.DETAILS||n===T.SECTION||n===T.SUMMARY||n===T.LISTING?ye(e,t):n===T.MARQUEE?Ie(e,t):Re(e,t);break;case 8:n===T.FIELDSET?ye(e,t):n===T.TEMPLATE?ue(e,t):Re(e,t);break;case 10:n===T.BLOCKQUOTE||n===T.FIGCAPTION?ye(e,t):Re(e,t);break;default:Re(e,t)}}function Le(e,t){e.tmplInsertionModeStackTop>-1?Be(e,t):e.stopped=!0}function Me(e,t){const n=e.openElements.currentTagName;n===T.TABLE||n===T.TBODY||n===T.TFOOT||n===T.THEAD||n===T.TR?(e.pendingCharacterTokens=[],e.hasNonWhitespacePendingCharacterToken=!1,e.originalInsertionMode=e.insertionMode,e.insertionMode=k,e._processToken(t)):De(e,t)}function xe(e,t){const n=t.tagName;switch(n.length){case 2:n===T.TD||n===T.TH||n===T.TR?function(e,t){e.openElements.clearBackToTableContext(),e._insertFakeElement(T.TBODY),e.insertionMode=x,e._processToken(t)}(e,t):De(e,t);break;case 3:n===T.COL?function(e,t){e.openElements.clearBackToTableContext(),e._insertFakeElement(T.COLGROUP),e.insertionMode=M,e._processToken(t)}(e,t):De(e,t);break;case 4:n===T.FORM?function(e,t){e.formElement||0!==e.openElements.tmplCount||(e._insertElement(t,E.HTML),e.formElement=e.openElements.current,e.openElements.pop())}(e,t):De(e,t);break;case 5:n===T.TABLE?function(e,t){e.openElements.hasInTableScope(T.TABLE)&&(e.openElements.popUntilTagNamePopped(T.TABLE),e._resetInsertionMode(),e._processToken(t))}(e,t):n===T.STYLE?le(e,t):n===T.TBODY||n===T.TFOOT||n===T.THEAD?function(e,t){e.openElements.clearBackToTableContext(),e._insertElement(t,E.HTML),e.insertionMode=x}(e,t):n===T.INPUT?function(e,t){const n=r.getTokenAttr(t,_.TYPE);n&&n.toLowerCase()===A?e._appendElement(t,E.HTML):De(e,t),t.ackSelfClosing=!0}(e,t):De(e,t);break;case 6:n===T.SCRIPT?le(e,t):De(e,t);break;case 7:n===T.CAPTION?function(e,t){e.openElements.clearBackToTableContext(),e.activeFormattingElements.insertMarker(),e._insertElement(t,E.HTML),e.insertionMode=L}(e,t):De(e,t);break;case 8:n===T.COLGROUP?function(e,t){e.openElements.clearBackToTableContext(),e._insertElement(t,E.HTML),e.insertionMode=M}(e,t):n===T.TEMPLATE?le(e,t):De(e,t);break;default:De(e,t)}}function Pe(e,t){const n=t.tagName;n===T.TABLE?e.openElements.hasInTableScope(T.TABLE)&&(e.openElements.popUntilTagNamePopped(T.TABLE),e._resetInsertionMode()):n===T.TEMPLATE?ue(e,t):n!==T.BODY&&n!==T.CAPTION&&n!==T.COL&&n!==T.COLGROUP&&n!==T.HTML&&n!==T.TBODY&&n!==T.TD&&n!==T.TFOOT&&n!==T.TH&&n!==T.THEAD&&n!==T.TR&&De(e,t)}function De(e,t){const n=e.fosterParentingEnabled;e.fosterParentingEnabled=!0,e._processTokenInBodyMode(t),e.fosterParentingEnabled=n}function we(e,t){let n=0;if(e.hasNonWhitespacePendingCharacterToken)for(;n<e.pendingCharacterTokens.length;n++)De(e,e.pendingCharacterTokens[n]);else for(;n<e.pendingCharacterTokens.length;n++)e._insertCharacters(e.pendingCharacterTokens[n]);e.insertionMode=e.originalInsertionMode,e._processToken(t)}function He(e,t){e.openElements.currentTagName===T.COLGROUP&&(e.openElements.pop(),e.insertionMode=R,e._processToken(t))}function Fe(e,t){const n=t.tagName;n===T.HTML?Se(e,t):n===T.OPTION?(e.openElements.currentTagName===T.OPTION&&e.openElements.pop(),e._insertElement(t,E.HTML)):n===T.OPTGROUP?(e.openElements.currentTagName===T.OPTION&&e.openElements.pop(),e.openElements.currentTagName===T.OPTGROUP&&e.openElements.pop(),e._insertElement(t,E.HTML)):n===T.INPUT||n===T.KEYGEN||n===T.TEXTAREA||n===T.SELECT?e.openElements.hasInSelectScope(T.SELECT)&&(e.openElements.popUntilTagNamePopped(T.SELECT),e._resetInsertionMode(),n!==T.SELECT&&e._processToken(t)):n!==T.SCRIPT&&n!==T.TEMPLATE||le(e,t)}function Ue(e,t){const n=t.tagName;if(n===T.OPTGROUP){const t=e.openElements.items[e.openElements.stackTop-1],n=t&&e.treeAdapter.getTagName(t);e.openElements.currentTagName===T.OPTION&&n===T.OPTGROUP&&e.openElements.pop(),e.openElements.currentTagName===T.OPTGROUP&&e.openElements.pop()}else n===T.OPTION?e.openElements.currentTagName===T.OPTION&&e.openElements.pop():n===T.SELECT&&e.openElements.hasInSelectScope(T.SELECT)?(e.openElements.popUntilTagNamePopped(T.SELECT),e._resetInsertionMode()):n===T.TEMPLATE&&ue(e,t)}function Be(e,t){e.openElements.tmplCount>0?(e.openElements.popUntilTagNamePopped(T.TEMPLATE),e.activeFormattingElements.clearToLastMarker(),e._popTmplInsertionMode(),e._resetInsertionMode(),e._processToken(t)):e.stopped=!0}function Ge(e,t){e.insertionMode=y,e._processToken(t)}function je(e,t){e.insertionMode=y,e._processToken(t)}e.exports=class{constructor(e){this.options=u(g,e),this.treeAdapter=this.options.treeAdapter,this.pendingScript=null,this.options.sourceCodeLocationInfo&&c.install(this,o),this.options.onParseError&&c.install(this,a,{onParseError:this.options.onParseError})}parse(e){const t=this.treeAdapter.createDocument();return this._bootstrap(t,null),this.tokenizer.write(e,!0),this._runParsingLoop(null),t}parseFragment(e,t){t||(t=this.treeAdapter.createElement(T.TEMPLATE,E.HTML,[]));const n=this.treeAdapter.createElement("documentmock",E.HTML,[]);this._bootstrap(n,t),this.treeAdapter.getTagName(t)===T.TEMPLATE&&this._pushTmplInsertionMode(F),this._initTokenizerForFragmentParsing(),this._insertFakeRootElement(),this._resetInsertionMode(),this._findFormInFragmentContext(),this.tokenizer.write(e,!0),this._runParsingLoop(null);const r=this.treeAdapter.getFirstChild(n),i=this.treeAdapter.createDocumentFragment();return this._adoptNodes(r,i),i}_bootstrap(e,t){this.tokenizer=new r(this.options),this.stopped=!1,this.insertionMode=C,this.originalInsertionMode="",this.document=e,this.fragmentContext=t,this.headElement=null,this.formElement=null,this.openElements=new i(this.document,this.treeAdapter),this.activeFormattingElements=new s(this.treeAdapter),this.tmplInsertionModeStack=[],this.tmplInsertionModeStackTop=-1,this.currentTmplInsertionMode=null,this.pendingCharacterTokens=[],this.hasNonWhitespacePendingCharacterToken=!1,this.framesetOk=!0,this.skipNextNewLine=!1,this.fosterParentingEnabled=!1}_err(){}_runParsingLoop(e){for(;!this.stopped;){this._setupTokenizerCDATAMode();const t=this.tokenizer.getNextToken();if(t.type===r.HIBERNATION_TOKEN)break;if(this.skipNextNewLine&&(this.skipNextNewLine=!1,t.type===r.WHITESPACE_CHARACTER_TOKEN&&"\n"===t.chars[0])){if(1===t.chars.length)continue;t.chars=t.chars.substr(1)}if(this._processInputToken(t),e&&this.pendingScript)break}}runParsingLoopForCurrentChunk(e,t){if(this._runParsingLoop(t),t&&this.pendingScript){const e=this.pendingScript;return this.pendingScript=null,void t(e)}e&&e()}_setupTokenizerCDATAMode(){const e=this._getAdjustedCurrentElement();this.tokenizer.allowCDATA=e&&e!==this.document&&this.treeAdapter.getNamespaceURI(e)!==E.HTML&&!this._isIntegrationPoint(e)}_switchToTextParsing(e,t){this._insertElement(e,E.HTML),this.tokenizer.state=t,this.originalInsertionMode=this.insertionMode,this.insertionMode=I}switchToPlaintextParsing(){this.insertionMode=I,this.originalInsertionMode=y,this.tokenizer.state=r.MODE.PLAINTEXT}_getAdjustedCurrentElement(){return 0===this.openElements.stackTop&&this.fragmentContext?this.fragmentContext:this.openElements.current}_findFormInFragmentContext(){let e=this.fragmentContext;do{if(this.treeAdapter.getTagName(e)===T.FORM){this.formElement=e;break}e=this.treeAdapter.getParentNode(e)}while(e)}_initTokenizerForFragmentParsing(){if(this.treeAdapter.getNamespaceURI(this.fragmentContext)===E.HTML){const e=this.treeAdapter.getTagName(this.fragmentContext);e===T.TITLE||e===T.TEXTAREA?this.tokenizer.state=r.MODE.RCDATA:e===T.STYLE||e===T.XMP||e===T.IFRAME||e===T.NOEMBED||e===T.NOFRAMES||e===T.NOSCRIPT?this.tokenizer.state=r.MODE.RAWTEXT:e===T.SCRIPT?this.tokenizer.state=r.MODE.SCRIPT_DATA:e===T.PLAINTEXT&&(this.tokenizer.state=r.MODE.PLAINTEXT)}}_setDocumentType(e){const t=e.name||"",n=e.publicId||"",r=e.systemId||"";this.treeAdapter.setDocumentType(this.document,t,n,r)}_attachElementToTree(e){if(this._shouldFosterParentOnInsertion())this._fosterParentElement(e);else{const t=this.openElements.currentTmplContent||this.openElements.current;this.treeAdapter.appendChild(t,e)}}_appendElement(e,t){const n=this.treeAdapter.createElement(e.tagName,t,e.attrs);this._attachElementToTree(n)}_insertElement(e,t){const n=this.treeAdapter.createElement(e.tagName,t,e.attrs);this._attachElementToTree(n),this.openElements.push(n)}_insertFakeElement(e){const t=this.treeAdapter.createElement(e,E.HTML,[]);this._attachElementToTree(t),this.openElements.push(t)}_insertTemplate(e){const t=this.treeAdapter.createElement(e.tagName,E.HTML,e.attrs),n=this.treeAdapter.createDocumentFragment();this.treeAdapter.setTemplateContent(t,n),this._attachElementToTree(t),this.openElements.push(t)}_insertFakeRootElement(){const e=this.treeAdapter.createElement(T.HTML,E.HTML,[]);this.treeAdapter.appendChild(this.openElements.current,e),this.openElements.push(e)}_appendCommentNode(e,t){const n=this.treeAdapter.createCommentNode(e.data);this.treeAdapter.appendChild(t,n)}_insertCharacters(e){if(this._shouldFosterParentOnInsertion())this._fosterParentText(e.chars);else{const t=this.openElements.currentTmplContent||this.openElements.current;this.treeAdapter.insertText(t,e.chars)}}_adoptNodes(e,t){for(let n=this.treeAdapter.getFirstChild(e);n;n=this.treeAdapter.getFirstChild(e))this.treeAdapter.detachNode(n),this.treeAdapter.appendChild(t,n)}_shouldProcessTokenInForeignContent(e){const t=this._getAdjustedCurrentElement();if(!t||t===this.document)return!1;const n=this.treeAdapter.getNamespaceURI(t);if(n===E.HTML)return!1;if(this.treeAdapter.getTagName(t)===T.ANNOTATION_XML&&n===E.MATHML&&e.type===r.START_TAG_TOKEN&&e.tagName===T.SVG)return!1;const i=e.type===r.CHARACTER_TOKEN||e.type===r.NULL_CHARACTER_TOKEN||e.type===r.WHITESPACE_CHARACTER_TOKEN;return!((e.type===r.START_TAG_TOKEN&&e.tagName!==T.MGLYPH&&e.tagName!==T.MALIGNMARK||i)&&this._isIntegrationPoint(t,E.MATHML)||(e.type===r.START_TAG_TOKEN||i)&&this._isIntegrationPoint(t,E.HTML)||e.type===r.EOF_TOKEN)}_processToken(e){V[this.insertionMode][e.type](this,e)}_processTokenInBodyMode(e){V.IN_BODY_MODE[e.type](this,e)}_processTokenInForeignContent(e){e.type===r.CHARACTER_TOKEN?function(e,t){e._insertCharacters(t),e.framesetOk=!1}(this,e):e.type===r.NULL_CHARACTER_TOKEN?function(e,t){t.chars=f.REPLACEMENT_CHARACTER,e._insertCharacters(t)}(this,e):e.type===r.WHITESPACE_CHARACTER_TOKEN?ie(this,e):e.type===r.COMMENT_TOKEN?ne(this,e):e.type===r.START_TAG_TOKEN?function(e,t){if(p.causesExit(t)&&!e.fragmentContext){for(;e.treeAdapter.getNamespaceURI(e.openElements.current)!==E.HTML&&!e._isIntegrationPoint(e.openElements.current);)e.openElements.pop();e._processToken(t)}else{const n=e._getAdjustedCurrentElement(),r=e.treeAdapter.getNamespaceURI(n);r===E.MATHML?p.adjustTokenMathMLAttrs(t):r===E.SVG&&(p.adjustTokenSVGTagName(t),p.adjustTokenSVGAttrs(t)),p.adjustTokenXMLAttrs(t),t.selfClosing?e._appendElement(t,r):e._insertElement(t,r),t.ackSelfClosing=!0}}(this,e):e.type===r.END_TAG_TOKEN&&function(e,t){for(let n=e.openElements.stackTop;n>0;n--){const r=e.openElements.items[n];if(e.treeAdapter.getNamespaceURI(r)===E.HTML){e._processToken(t);break}if(e.treeAdapter.getTagName(r).toLowerCase()===t.tagName){e.openElements.popUntilElementPopped(r);break}}}(this,e)}_processInputToken(e){this._shouldProcessTokenInForeignContent(e)?this._processTokenInForeignContent(e):this._processToken(e),e.type===r.START_TAG_TOKEN&&e.selfClosing&&!e.ackSelfClosing&&this._err(d.nonVoidHtmlElementStartTagWithTrailingSolidus)}_isIntegrationPoint(e,t){const n=this.treeAdapter.getTagName(e),r=this.treeAdapter.getNamespaceURI(e),i=this.treeAdapter.getAttrList(e);return p.isIntegrationPoint(n,r,i,t)}_reconstructActiveFormattingElements(){const e=this.activeFormattingElements.length;if(e){let t=e,n=null;do{if(t--,n=this.activeFormattingElements.entries[t],n.type===s.MARKER_ENTRY||this.openElements.contains(n.element)){t++;break}}while(t>0);for(let r=t;r<e;r++)n=this.activeFormattingElements.entries[r],this._insertElement(n.token,this.treeAdapter.getNamespaceURI(n.element)),n.element=this.openElements.current}}_closeTableCell(){this.openElements.generateImpliedEndTags(),this.openElements.popUntilTableCellPopped(),this.activeFormattingElements.clearToLastMarker(),this.insertionMode=P}_closePElement(){this.openElements.generateImpliedEndTagsWithExclusion(T.P),this.openElements.popUntilTagNamePopped(T.P)}_resetInsertionMode(){for(let e=this.openElements.stackTop,t=!1;e>=0;e--){let n=this.openElements.items[e];0===e&&(t=!0,this.fragmentContext&&(n=this.fragmentContext));const r=this.treeAdapter.getTagName(n),i=q[r];if(i){this.insertionMode=i;break}if(!(t||r!==T.TD&&r!==T.TH)){this.insertionMode=D;break}if(!t&&r===T.HEAD){this.insertionMode=O;break}if(r===T.SELECT){this._resetInsertionModeForSelect(e);break}if(r===T.TEMPLATE){this.insertionMode=this.currentTmplInsertionMode;break}if(r===T.HTML){this.insertionMode=this.headElement?S:v;break}if(t){this.insertionMode=y;break}}}_resetInsertionModeForSelect(e){if(e>0)for(let t=e-1;t>0;t--){const e=this.openElements.items[t],n=this.treeAdapter.getTagName(e);if(n===T.TEMPLATE)break;if(n===T.TABLE)return void(this.insertionMode=H)}this.insertionMode=w}_pushTmplInsertionMode(e){this.tmplInsertionModeStack.push(e),this.tmplInsertionModeStackTop++,this.currentTmplInsertionMode=e}_popTmplInsertionMode(){this.tmplInsertionModeStack.pop(),this.tmplInsertionModeStackTop--,this.currentTmplInsertionMode=this.tmplInsertionModeStack[this.tmplInsertionModeStackTop]}_isElementCausesFosterParenting(e){const t=this.treeAdapter.getTagName(e);return t===T.TABLE||t===T.TBODY||t===T.TFOOT||t===T.THEAD||t===T.TR}_shouldFosterParentOnInsertion(){return this.fosterParentingEnabled&&this._isElementCausesFosterParenting(this.openElements.current)}_findFosterParentingLocation(){const e={parent:null,beforeElement:null};for(let t=this.openElements.stackTop;t>=0;t--){const n=this.openElements.items[t],r=this.treeAdapter.getTagName(n),i=this.treeAdapter.getNamespaceURI(n);if(r===T.TEMPLATE&&i===E.HTML){e.parent=this.treeAdapter.getTemplateContent(n);break}if(r===T.TABLE){e.parent=this.treeAdapter.getParentNode(n),e.parent?e.beforeElement=n:e.parent=this.openElements.items[t-1];break}}return e.parent||(e.parent=this.openElements.items[0]),e}_fosterParentElement(e){const t=this._findFosterParentingLocation();t.beforeElement?this.treeAdapter.insertBefore(t.parent,e,t.beforeElement):this.treeAdapter.appendChild(t.parent,e)}_fosterParentText(e){const t=this._findFosterParentingLocation();t.beforeElement?this.treeAdapter.insertTextBefore(t.parent,e,t.beforeElement):this.treeAdapter.insertText(t.parent,e)}_isSpecialElement(e){const t=this.treeAdapter.getTagName(e),n=this.treeAdapter.getNamespaceURI(e);return m.SPECIAL_ELEMENTS[n][t]}}},6519:(e,t,n)=>{"use strict";const r=n(6152),i=r.TAG_NAMES,s=r.NAMESPACES;function o(e){switch(e.length){case 1:return e===i.P;case 2:return e===i.RB||e===i.RP||e===i.RT||e===i.DD||e===i.DT||e===i.LI;case 3:return e===i.RTC;case 6:return e===i.OPTION;case 8:return e===i.OPTGROUP}return!1}function a(e){switch(e.length){case 1:return e===i.P;case 2:return e===i.RB||e===i.RP||e===i.RT||e===i.DD||e===i.DT||e===i.LI||e===i.TD||e===i.TH||e===i.TR;case 3:return e===i.RTC;case 5:return e===i.TBODY||e===i.TFOOT||e===i.THEAD;case 6:return e===i.OPTION;case 7:return e===i.CAPTION;case 8:return e===i.OPTGROUP||e===i.COLGROUP}return!1}function c(e,t){switch(e.length){case 2:if(e===i.TD||e===i.TH)return t===s.HTML;if(e===i.MI||e===i.MO||e===i.MN||e===i.MS)return t===s.MATHML;break;case 4:if(e===i.HTML)return t===s.HTML;if(e===i.DESC)return t===s.SVG;break;case 5:if(e===i.TABLE)return t===s.HTML;if(e===i.MTEXT)return t===s.MATHML;if(e===i.TITLE)return t===s.SVG;break;case 6:return(e===i.APPLET||e===i.OBJECT)&&t===s.HTML;case 7:return(e===i.CAPTION||e===i.MARQUEE)&&t===s.HTML;case 8:return e===i.TEMPLATE&&t===s.HTML;case 13:return e===i.FOREIGN_OBJECT&&t===s.SVG;case 14:return e===i.ANNOTATION_XML&&t===s.MATHML}return!1}e.exports=class{constructor(e,t){this.stackTop=-1,this.items=[],this.current=e,this.currentTagName=null,this.currentTmplContent=null,this.tmplCount=0,this.treeAdapter=t}_indexOf(e){let t=-1;for(let n=this.stackTop;n>=0;n--)if(this.items[n]===e){t=n;break}return t}_isInTemplate(){return this.currentTagName===i.TEMPLATE&&this.treeAdapter.getNamespaceURI(this.current)===s.HTML}_updateCurrentElement(){this.current=this.items[this.stackTop],this.currentTagName=this.current&&this.treeAdapter.getTagName(this.current),this.currentTmplContent=this._isInTemplate()?this.treeAdapter.getTemplateContent(this.current):null}push(e){this.items[++this.stackTop]=e,this._updateCurrentElement(),this._isInTemplate()&&this.tmplCount++}pop(){this.stackTop--,this.tmplCount>0&&this._isInTemplate()&&this.tmplCount--,this._updateCurrentElement()}replace(e,t){const n=this._indexOf(e);this.items[n]=t,n===this.stackTop&&this._updateCurrentElement()}insertAfter(e,t){const n=this._indexOf(e)+1;this.items.splice(n,0,t),n===++this.stackTop&&this._updateCurrentElement()}popUntilTagNamePopped(e){for(;this.stackTop>-1;){const t=this.currentTagName,n=this.treeAdapter.getNamespaceURI(this.current);if(this.pop(),t===e&&n===s.HTML)break}}popUntilElementPopped(e){for(;this.stackTop>-1;){const t=this.current;if(this.pop(),t===e)break}}popUntilNumberedHeaderPopped(){for(;this.stackTop>-1;){const e=this.currentTagName,t=this.treeAdapter.getNamespaceURI(this.current);if(this.pop(),e===i.H1||e===i.H2||e===i.H3||e===i.H4||e===i.H5||e===i.H6&&t===s.HTML)break}}popUntilTableCellPopped(){for(;this.stackTop>-1;){const e=this.currentTagName,t=this.treeAdapter.getNamespaceURI(this.current);if(this.pop(),e===i.TD||e===i.TH&&t===s.HTML)break}}popAllUpToHtmlElement(){this.stackTop=0,this._updateCurrentElement()}clearBackToTableContext(){for(;this.currentTagName!==i.TABLE&&this.currentTagName!==i.TEMPLATE&&this.currentTagName!==i.HTML||this.treeAdapter.getNamespaceURI(this.current)!==s.HTML;)this.pop()}clearBackToTableBodyContext(){for(;this.currentTagName!==i.TBODY&&this.currentTagName!==i.TFOOT&&this.currentTagName!==i.THEAD&&this.currentTagName!==i.TEMPLATE&&this.currentTagName!==i.HTML||this.treeAdapter.getNamespaceURI(this.current)!==s.HTML;)this.pop()}clearBackToTableRowContext(){for(;this.currentTagName!==i.TR&&this.currentTagName!==i.TEMPLATE&&this.currentTagName!==i.HTML||this.treeAdapter.getNamespaceURI(this.current)!==s.HTML;)this.pop()}remove(e){for(let t=this.stackTop;t>=0;t--)if(this.items[t]===e){this.items.splice(t,1),this.stackTop--,this._updateCurrentElement();break}}tryPeekProperlyNestedBodyElement(){const e=this.items[1];return e&&this.treeAdapter.getTagName(e)===i.BODY?e:null}contains(e){return this._indexOf(e)>-1}getCommonAncestor(e){let t=this._indexOf(e);return--t>=0?this.items[t]:null}isRootHtmlElementCurrent(){return 0===this.stackTop&&this.currentTagName===i.HTML}hasInScope(e){for(let t=this.stackTop;t>=0;t--){const n=this.treeAdapter.getTagName(this.items[t]),r=this.treeAdapter.getNamespaceURI(this.items[t]);if(n===e&&r===s.HTML)return!0;if(c(n,r))return!1}return!0}hasNumberedHeaderInScope(){for(let e=this.stackTop;e>=0;e--){const t=this.treeAdapter.getTagName(this.items[e]),n=this.treeAdapter.getNamespaceURI(this.items[e]);if((t===i.H1||t===i.H2||t===i.H3||t===i.H4||t===i.H5||t===i.H6)&&n===s.HTML)return!0;if(c(t,n))return!1}return!0}hasInListItemScope(e){for(let t=this.stackTop;t>=0;t--){const n=this.treeAdapter.getTagName(this.items[t]),r=this.treeAdapter.getNamespaceURI(this.items[t]);if(n===e&&r===s.HTML)return!0;if((n===i.UL||n===i.OL)&&r===s.HTML||c(n,r))return!1}return!0}hasInButtonScope(e){for(let t=this.stackTop;t>=0;t--){const n=this.treeAdapter.getTagName(this.items[t]),r=this.treeAdapter.getNamespaceURI(this.items[t]);if(n===e&&r===s.HTML)return!0;if(n===i.BUTTON&&r===s.HTML||c(n,r))return!1}return!0}hasInTableScope(e){for(let t=this.stackTop;t>=0;t--){const n=this.treeAdapter.getTagName(this.items[t]);if(this.treeAdapter.getNamespaceURI(this.items[t])===s.HTML){if(n===e)return!0;if(n===i.TABLE||n===i.TEMPLATE||n===i.HTML)return!1}}return!0}hasTableBodyContextInTableScope(){for(let e=this.stackTop;e>=0;e--){const t=this.treeAdapter.getTagName(this.items[e]);if(this.treeAdapter.getNamespaceURI(this.items[e])===s.HTML){if(t===i.TBODY||t===i.THEAD||t===i.TFOOT)return!0;if(t===i.TABLE||t===i.HTML)return!1}}return!0}hasInSelectScope(e){for(let t=this.stackTop;t>=0;t--){const n=this.treeAdapter.getTagName(this.items[t]);if(this.treeAdapter.getNamespaceURI(this.items[t])===s.HTML){if(n===e)return!0;if(n!==i.OPTION&&n!==i.OPTGROUP)return!1}}return!0}generateImpliedEndTags(){for(;o(this.currentTagName);)this.pop()}generateImpliedEndTagsThoroughly(){for(;a(this.currentTagName);)this.pop()}generateImpliedEndTagsWithExclusion(e){for(;o(this.currentTagName)&&this.currentTagName!==e;)this.pop()}}},3988:(e,t,n)=>{"use strict";const r=n(7296),i=n(8904),s=n(1515),o=n(6152),a=o.TAG_NAMES,c=o.NAMESPACES,l={treeAdapter:r},u=/&/g,h=/\u00a0/g,p=/"/g,d=/</g,f=/>/g;class m{constructor(e,t){this.options=i(l,t),this.treeAdapter=this.options.treeAdapter,this.html="",this.startNode=e}serialize(){return this._serializeChildNodes(this.startNode),this.html}_serializeChildNodes(e){const t=this.treeAdapter.getChildNodes(e);if(t)for(let e=0,n=t.length;e<n;e++){const n=t[e];this.treeAdapter.isElementNode(n)?this._serializeElement(n):this.treeAdapter.isTextNode(n)?this._serializeTextNode(n):this.treeAdapter.isCommentNode(n)?this._serializeCommentNode(n):this.treeAdapter.isDocumentTypeNode(n)&&this._serializeDocumentTypeNode(n)}}_serializeElement(e){const t=this.treeAdapter.getTagName(e),n=this.treeAdapter.getNamespaceURI(e);if(this.html+="<"+t,this._serializeAttributes(e),this.html+=">",t!==a.AREA&&t!==a.BASE&&t!==a.BASEFONT&&t!==a.BGSOUND&&t!==a.BR&&t!==a.COL&&t!==a.EMBED&&t!==a.FRAME&&t!==a.HR&&t!==a.IMG&&t!==a.INPUT&&t!==a.KEYGEN&&t!==a.LINK&&t!==a.META&&t!==a.PARAM&&t!==a.SOURCE&&t!==a.TRACK&&t!==a.WBR){const r=t===a.TEMPLATE&&n===c.HTML?this.treeAdapter.getTemplateContent(e):e;this._serializeChildNodes(r),this.html+="</"+t+">"}}_serializeAttributes(e){const t=this.treeAdapter.getAttrList(e);for(let e=0,n=t.length;e<n;e++){const n=t[e],r=m.escapeString(n.value,!0);this.html+=" ",n.namespace?n.namespace===c.XML?this.html+="xml:"+n.name:n.namespace===c.XMLNS?("xmlns"!==n.name&&(this.html+="xmlns:"),this.html+=n.name):n.namespace===c.XLINK?this.html+="xlink:"+n.name:this.html+=n.prefix+":"+n.name:this.html+=n.name,this.html+='="'+r+'"'}}_serializeTextNode(e){const t=this.treeAdapter.getTextNodeContent(e),n=this.treeAdapter.getParentNode(e);let r;n&&this.treeAdapter.isElementNode(n)&&(r=this.treeAdapter.getTagName(n)),r===a.STYLE||r===a.SCRIPT||r===a.XMP||r===a.IFRAME||r===a.NOEMBED||r===a.NOFRAMES||r===a.PLAINTEXT||r===a.NOSCRIPT?this.html+=t:this.html+=m.escapeString(t,!1)}_serializeCommentNode(e){this.html+="\x3c!--"+this.treeAdapter.getCommentNodeContent(e)+"--\x3e"}_serializeDocumentTypeNode(e){const t=this.treeAdapter.getDocumentTypeNodeName(e);this.html+="<"+s.serializeContent(t,null,null)+">"}}m.escapeString=function(e,t){return e=e.replace(u,"&amp;").replace(h,"&nbsp;"),t?e.replace(p,"&quot;"):e.replace(d,"&lt;").replace(f,"&gt;")},e.exports=m},5763:(e,t,n)=>{"use strict";const r=n(7118),i=n(4284),s=n(5482),o=n(1734),a=i.CODE_POINTS,c=i.CODE_POINT_SEQUENCES,l={128:8364,130:8218,131:402,132:8222,133:8230,134:8224,135:8225,136:710,137:8240,138:352,139:8249,140:338,142:381,145:8216,146:8217,147:8220,148:8221,149:8226,150:8211,151:8212,152:732,153:8482,154:353,155:8250,156:339,158:382,159:376},u="DATA_STATE",h="RCDATA_STATE",p="RAWTEXT_STATE",d="SCRIPT_DATA_STATE",f="PLAINTEXT_STATE",m="TAG_OPEN_STATE",T="END_TAG_OPEN_STATE",E="TAG_NAME_STATE",_="RCDATA_LESS_THAN_SIGN_STATE",g="RCDATA_END_TAG_OPEN_STATE",A="RCDATA_END_TAG_NAME_STATE",C="RAWTEXT_LESS_THAN_SIGN_STATE",N="RAWTEXT_END_TAG_OPEN_STATE",v="RAWTEXT_END_TAG_NAME_STATE",O="SCRIPT_DATA_LESS_THAN_SIGN_STATE",b="SCRIPT_DATA_END_TAG_OPEN_STATE",S="SCRIPT_DATA_END_TAG_NAME_STATE",y="SCRIPT_DATA_ESCAPE_START_STATE",I="SCRIPT_DATA_ESCAPE_START_DASH_STATE",R="SCRIPT_DATA_ESCAPED_STATE",k="SCRIPT_DATA_ESCAPED_DASH_STATE",L="SCRIPT_DATA_ESCAPED_DASH_DASH_STATE",M="SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN_STATE",x="SCRIPT_DATA_ESCAPED_END_TAG_OPEN_STATE",P="SCRIPT_DATA_ESCAPED_END_TAG_NAME_STATE",D="SCRIPT_DATA_DOUBLE_ESCAPE_START_STATE",w="SCRIPT_DATA_DOUBLE_ESCAPED_STATE",H="SCRIPT_DATA_DOUBLE_ESCAPED_DASH_STATE",F="SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH_STATE",U="SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN_STATE",B="SCRIPT_DATA_DOUBLE_ESCAPE_END_STATE",G="BEFORE_ATTRIBUTE_NAME_STATE",j="ATTRIBUTE_NAME_STATE",K="AFTER_ATTRIBUTE_NAME_STATE",q="BEFORE_ATTRIBUTE_VALUE_STATE",Y="ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE",V="ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE",W="ATTRIBUTE_VALUE_UNQUOTED_STATE",Q="AFTER_ATTRIBUTE_VALUE_QUOTED_STATE",z="SELF_CLOSING_START_TAG_STATE",X="BOGUS_COMMENT_STATE",$="MARKUP_DECLARATION_OPEN_STATE",J="COMMENT_START_STATE",Z="COMMENT_START_DASH_STATE",ee="COMMENT_STATE",te="COMMENT_LESS_THAN_SIGN_STATE",ne="COMMENT_LESS_THAN_SIGN_BANG_STATE",re="COMMENT_LESS_THAN_SIGN_BANG_DASH_STATE",ie="COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH_STATE",se="COMMENT_END_DASH_STATE",oe="COMMENT_END_STATE",ae="COMMENT_END_BANG_STATE",ce="DOCTYPE_STATE",le="BEFORE_DOCTYPE_NAME_STATE",ue="DOCTYPE_NAME_STATE",he="AFTER_DOCTYPE_NAME_STATE",pe="AFTER_DOCTYPE_PUBLIC_KEYWORD_STATE",de="BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE",fe="DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE",me="DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE",Te="AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE",Ee="BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS_STATE",_e="AFTER_DOCTYPE_SYSTEM_KEYWORD_STATE",ge="BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE",Ae="DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE",Ce="DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE",Ne="AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE",ve="BOGUS_DOCTYPE_STATE",Oe="CDATA_SECTION_STATE",be="CDATA_SECTION_BRACKET_STATE",Se="CDATA_SECTION_END_STATE",ye="CHARACTER_REFERENCE_STATE",Ie="NAMED_CHARACTER_REFERENCE_STATE",Re="AMBIGUOS_AMPERSAND_STATE",ke="NUMERIC_CHARACTER_REFERENCE_STATE",Le="HEXADEMICAL_CHARACTER_REFERENCE_START_STATE",Me="DECIMAL_CHARACTER_REFERENCE_START_STATE",xe="HEXADEMICAL_CHARACTER_REFERENCE_STATE",Pe="DECIMAL_CHARACTER_REFERENCE_STATE",De="NUMERIC_CHARACTER_REFERENCE_END_STATE";function we(e){return e===a.SPACE||e===a.LINE_FEED||e===a.TABULATION||e===a.FORM_FEED}function He(e){return e>=a.DIGIT_0&&e<=a.DIGIT_9}function Fe(e){return e>=a.LATIN_CAPITAL_A&&e<=a.LATIN_CAPITAL_Z}function Ue(e){return e>=a.LATIN_SMALL_A&&e<=a.LATIN_SMALL_Z}function Be(e){return Ue(e)||Fe(e)}function Ge(e){return Be(e)||He(e)}function je(e){return e>=a.LATIN_CAPITAL_A&&e<=a.LATIN_CAPITAL_F}function Ke(e){return e>=a.LATIN_SMALL_A&&e<=a.LATIN_SMALL_F}function qe(e){return e+32}function Ye(e){return e<=65535?String.fromCharCode(e):(e-=65536,String.fromCharCode(e>>>10&1023|55296)+String.fromCharCode(56320|1023&e))}function Ve(e){return String.fromCharCode(qe(e))}function We(e,t){const n=s[++e];let r=++e,i=r+n-1;for(;r<=i;){const e=r+i>>>1,o=s[e];if(o<t)r=e+1;else{if(!(o>t))return s[e+n];i=e-1}}return-1}class Qe{constructor(){this.preprocessor=new r,this.tokenQueue=[],this.allowCDATA=!1,this.state=u,this.returnState="",this.charRefCode=-1,this.tempBuff=[],this.lastStartTagName="",this.consumedAfterSnapshot=-1,this.active=!1,this.currentCharacterToken=null,this.currentToken=null,this.currentAttr=null}_err(){}_errOnNextCodePoint(e){this._consume(),this._err(e),this._unconsume()}getNextToken(){for(;!this.tokenQueue.length&&this.active;){this.consumedAfterSnapshot=0;const e=this._consume();this._ensureHibernation()||this[this.state](e)}return this.tokenQueue.shift()}write(e,t){this.active=!0,this.preprocessor.write(e,t)}insertHtmlAtCurrentPos(e){this.active=!0,this.preprocessor.insertHtmlAtCurrentPos(e)}_ensureHibernation(){if(this.preprocessor.endOfChunkHit){for(;this.consumedAfterSnapshot>0;this.consumedAfterSnapshot--)this.preprocessor.retreat();return this.active=!1,this.tokenQueue.push({type:Qe.HIBERNATION_TOKEN}),!0}return!1}_consume(){return this.consumedAfterSnapshot++,this.preprocessor.advance()}_unconsume(){this.consumedAfterSnapshot--,this.preprocessor.retreat()}_reconsumeInState(e){this.state=e,this._unconsume()}_consumeSequenceIfMatch(e,t,n){let r=0,i=!0;const s=e.length;let o,c=0,l=t;for(;c<s;c++){if(c>0&&(l=this._consume(),r++),l===a.EOF){i=!1;break}if(o=e[c],l!==o&&(n||l!==qe(o))){i=!1;break}}if(!i)for(;r--;)this._unconsume();return i}_isTempBufferEqualToScriptString(){if(this.tempBuff.length!==c.SCRIPT_STRING.length)return!1;for(let e=0;e<this.tempBuff.length;e++)if(this.tempBuff[e]!==c.SCRIPT_STRING[e])return!1;return!0}_createStartTagToken(){this.currentToken={type:Qe.START_TAG_TOKEN,tagName:"",selfClosing:!1,ackSelfClosing:!1,attrs:[]}}_createEndTagToken(){this.currentToken={type:Qe.END_TAG_TOKEN,tagName:"",selfClosing:!1,attrs:[]}}_createCommentToken(){this.currentToken={type:Qe.COMMENT_TOKEN,data:""}}_createDoctypeToken(e){this.currentToken={type:Qe.DOCTYPE_TOKEN,name:e,forceQuirks:!1,publicId:null,systemId:null}}_createCharacterToken(e,t){this.currentCharacterToken={type:e,chars:t}}_createEOFToken(){this.currentToken={type:Qe.EOF_TOKEN}}_createAttr(e){this.currentAttr={name:e,value:""}}_leaveAttrName(e){null===Qe.getTokenAttr(this.currentToken,this.currentAttr.name)?this.currentToken.attrs.push(this.currentAttr):this._err(o.duplicateAttribute),this.state=e}_leaveAttrValue(e){this.state=e}_emitCurrentToken(){this._emitCurrentCharacterToken();const e=this.currentToken;this.currentToken=null,e.type===Qe.START_TAG_TOKEN?this.lastStartTagName=e.tagName:e.type===Qe.END_TAG_TOKEN&&(e.attrs.length>0&&this._err(o.endTagWithAttributes),e.selfClosing&&this._err(o.endTagWithTrailingSolidus)),this.tokenQueue.push(e)}_emitCurrentCharacterToken(){this.currentCharacterToken&&(this.tokenQueue.push(this.currentCharacterToken),this.currentCharacterToken=null)}_emitEOFToken(){this._createEOFToken(),this._emitCurrentToken()}_appendCharToCurrentCharacterToken(e,t){this.currentCharacterToken&&this.currentCharacterToken.type!==e&&this._emitCurrentCharacterToken(),this.currentCharacterToken?this.currentCharacterToken.chars+=t:this._createCharacterToken(e,t)}_emitCodePoint(e){let t=Qe.CHARACTER_TOKEN;we(e)?t=Qe.WHITESPACE_CHARACTER_TOKEN:e===a.NULL&&(t=Qe.NULL_CHARACTER_TOKEN),this._appendCharToCurrentCharacterToken(t,Ye(e))}_emitSeveralCodePoints(e){for(let t=0;t<e.length;t++)this._emitCodePoint(e[t])}_emitChars(e){this._appendCharToCurrentCharacterToken(Qe.CHARACTER_TOKEN,e)}_matchNamedCharacterReference(e){let t=null,n=1,r=We(0,e);for(this.tempBuff.push(e);r>-1;){const e=s[r],i=e<7;i&&1&e&&(t=2&e?[s[++r],s[++r]]:[s[++r]],n=0);const o=this._consume();if(this.tempBuff.push(o),n++,o===a.EOF)break;r=i?4&e?We(r,o):-1:o===e?++r:-1}for(;n--;)this.tempBuff.pop(),this._unconsume();return t}_isCharacterReferenceInAttribute(){return this.returnState===Y||this.returnState===V||this.returnState===W}_isCharacterReferenceAttributeQuirk(e){if(!e&&this._isCharacterReferenceInAttribute()){const e=this._consume();return this._unconsume(),e===a.EQUALS_SIGN||Ge(e)}return!1}_flushCodePointsConsumedAsCharacterReference(){if(this._isCharacterReferenceInAttribute())for(let e=0;e<this.tempBuff.length;e++)this.currentAttr.value+=Ye(this.tempBuff[e]);else this._emitSeveralCodePoints(this.tempBuff);this.tempBuff=[]}[u](e){this.preprocessor.dropParsedChunk(),e===a.LESS_THAN_SIGN?this.state=m:e===a.AMPERSAND?(this.returnState=u,this.state=ye):e===a.NULL?(this._err(o.unexpectedNullCharacter),this._emitCodePoint(e)):e===a.EOF?this._emitEOFToken():this._emitCodePoint(e)}[h](e){this.preprocessor.dropParsedChunk(),e===a.AMPERSAND?(this.returnState=h,this.state=ye):e===a.LESS_THAN_SIGN?this.state=_:e===a.NULL?(this._err(o.unexpectedNullCharacter),this._emitChars(i.REPLACEMENT_CHARACTER)):e===a.EOF?this._emitEOFToken():this._emitCodePoint(e)}[p](e){this.preprocessor.dropParsedChunk(),e===a.LESS_THAN_SIGN?this.state=C:e===a.NULL?(this._err(o.unexpectedNullCharacter),this._emitChars(i.REPLACEMENT_CHARACTER)):e===a.EOF?this._emitEOFToken():this._emitCodePoint(e)}[d](e){this.preprocessor.dropParsedChunk(),e===a.LESS_THAN_SIGN?this.state=O:e===a.NULL?(this._err(o.unexpectedNullCharacter),this._emitChars(i.REPLACEMENT_CHARACTER)):e===a.EOF?this._emitEOFToken():this._emitCodePoint(e)}[f](e){this.preprocessor.dropParsedChunk(),e===a.NULL?(this._err(o.unexpectedNullCharacter),this._emitChars(i.REPLACEMENT_CHARACTER)):e===a.EOF?this._emitEOFToken():this._emitCodePoint(e)}[m](e){e===a.EXCLAMATION_MARK?this.state=$:e===a.SOLIDUS?this.state=T:Be(e)?(this._createStartTagToken(),this._reconsumeInState(E)):e===a.QUESTION_MARK?(this._err(o.unexpectedQuestionMarkInsteadOfTagName),this._createCommentToken(),this._reconsumeInState(X)):e===a.EOF?(this._err(o.eofBeforeTagName),this._emitChars("<"),this._emitEOFToken()):(this._err(o.invalidFirstCharacterOfTagName),this._emitChars("<"),this._reconsumeInState(u))}[T](e){Be(e)?(this._createEndTagToken(),this._reconsumeInState(E)):e===a.GREATER_THAN_SIGN?(this._err(o.missingEndTagName),this.state=u):e===a.EOF?(this._err(o.eofBeforeTagName),this._emitChars("</"),this._emitEOFToken()):(this._err(o.invalidFirstCharacterOfTagName),this._createCommentToken(),this._reconsumeInState(X))}[E](e){we(e)?this.state=G:e===a.SOLIDUS?this.state=z:e===a.GREATER_THAN_SIGN?(this.state=u,this._emitCurrentToken()):Fe(e)?this.currentToken.tagName+=Ve(e):e===a.NULL?(this._err(o.unexpectedNullCharacter),this.currentToken.tagName+=i.REPLACEMENT_CHARACTER):e===a.EOF?(this._err(o.eofInTag),this._emitEOFToken()):this.currentToken.tagName+=Ye(e)}[_](e){e===a.SOLIDUS?(this.tempBuff=[],this.state=g):(this._emitChars("<"),this._reconsumeInState(h))}[g](e){Be(e)?(this._createEndTagToken(),this._reconsumeInState(A)):(this._emitChars("</"),this._reconsumeInState(h))}[A](e){if(Fe(e))this.currentToken.tagName+=Ve(e),this.tempBuff.push(e);else if(Ue(e))this.currentToken.tagName+=Ye(e),this.tempBuff.push(e);else{if(this.lastStartTagName===this.currentToken.tagName){if(we(e))return void(this.state=G);if(e===a.SOLIDUS)return void(this.state=z);if(e===a.GREATER_THAN_SIGN)return this.state=u,void this._emitCurrentToken()}this._emitChars("</"),this._emitSeveralCodePoints(this.tempBuff),this._reconsumeInState(h)}}[C](e){e===a.SOLIDUS?(this.tempBuff=[],this.state=N):(this._emitChars("<"),this._reconsumeInState(p))}[N](e){Be(e)?(this._createEndTagToken(),this._reconsumeInState(v)):(this._emitChars("</"),this._reconsumeInState(p))}[v](e){if(Fe(e))this.currentToken.tagName+=Ve(e),this.tempBuff.push(e);else if(Ue(e))this.currentToken.tagName+=Ye(e),this.tempBuff.push(e);else{if(this.lastStartTagName===this.currentToken.tagName){if(we(e))return void(this.state=G);if(e===a.SOLIDUS)return void(this.state=z);if(e===a.GREATER_THAN_SIGN)return this._emitCurrentToken(),void(this.state=u)}this._emitChars("</"),this._emitSeveralCodePoints(this.tempBuff),this._reconsumeInState(p)}}[O](e){e===a.SOLIDUS?(this.tempBuff=[],this.state=b):e===a.EXCLAMATION_MARK?(this.state=y,this._emitChars("<!")):(this._emitChars("<"),this._reconsumeInState(d))}[b](e){Be(e)?(this._createEndTagToken(),this._reconsumeInState(S)):(this._emitChars("</"),this._reconsumeInState(d))}[S](e){if(Fe(e))this.currentToken.tagName+=Ve(e),this.tempBuff.push(e);else if(Ue(e))this.currentToken.tagName+=Ye(e),this.tempBuff.push(e);else{if(this.lastStartTagName===this.currentToken.tagName){if(we(e))return void(this.state=G);if(e===a.SOLIDUS)return void(this.state=z);if(e===a.GREATER_THAN_SIGN)return this._emitCurrentToken(),void(this.state=u)}this._emitChars("</"),this._emitSeveralCodePoints(this.tempBuff),this._reconsumeInState(d)}}[y](e){e===a.HYPHEN_MINUS?(this.state=I,this._emitChars("-")):this._reconsumeInState(d)}[I](e){e===a.HYPHEN_MINUS?(this.state=L,this._emitChars("-")):this._reconsumeInState(d)}[R](e){e===a.HYPHEN_MINUS?(this.state=k,this._emitChars("-")):e===a.LESS_THAN_SIGN?this.state=M:e===a.NULL?(this._err(o.unexpectedNullCharacter),this._emitChars(i.REPLACEMENT_CHARACTER)):e===a.EOF?(this._err(o.eofInScriptHtmlCommentLikeText),this._emitEOFToken()):this._emitCodePoint(e)}[k](e){e===a.HYPHEN_MINUS?(this.state=L,this._emitChars("-")):e===a.LESS_THAN_SIGN?this.state=M:e===a.NULL?(this._err(o.unexpectedNullCharacter),this.state=R,this._emitChars(i.REPLACEMENT_CHARACTER)):e===a.EOF?(this._err(o.eofInScriptHtmlCommentLikeText),this._emitEOFToken()):(this.state=R,this._emitCodePoint(e))}[L](e){e===a.HYPHEN_MINUS?this._emitChars("-"):e===a.LESS_THAN_SIGN?this.state=M:e===a.GREATER_THAN_SIGN?(this.state=d,this._emitChars(">")):e===a.NULL?(this._err(o.unexpectedNullCharacter),this.state=R,this._emitChars(i.REPLACEMENT_CHARACTER)):e===a.EOF?(this._err(o.eofInScriptHtmlCommentLikeText),this._emitEOFToken()):(this.state=R,this._emitCodePoint(e))}[M](e){e===a.SOLIDUS?(this.tempBuff=[],this.state=x):Be(e)?(this.tempBuff=[],this._emitChars("<"),this._reconsumeInState(D)):(this._emitChars("<"),this._reconsumeInState(R))}[x](e){Be(e)?(this._createEndTagToken(),this._reconsumeInState(P)):(this._emitChars("</"),this._reconsumeInState(R))}[P](e){if(Fe(e))this.currentToken.tagName+=Ve(e),this.tempBuff.push(e);else if(Ue(e))this.currentToken.tagName+=Ye(e),this.tempBuff.push(e);else{if(this.lastStartTagName===this.currentToken.tagName){if(we(e))return void(this.state=G);if(e===a.SOLIDUS)return void(this.state=z);if(e===a.GREATER_THAN_SIGN)return this._emitCurrentToken(),void(this.state=u)}this._emitChars("</"),this._emitSeveralCodePoints(this.tempBuff),this._reconsumeInState(R)}}[D](e){we(e)||e===a.SOLIDUS||e===a.GREATER_THAN_SIGN?(this.state=this._isTempBufferEqualToScriptString()?w:R,this._emitCodePoint(e)):Fe(e)?(this.tempBuff.push(qe(e)),this._emitCodePoint(e)):Ue(e)?(this.tempBuff.push(e),this._emitCodePoint(e)):this._reconsumeInState(R)}[w](e){e===a.HYPHEN_MINUS?(this.state=H,this._emitChars("-")):e===a.LESS_THAN_SIGN?(this.state=U,this._emitChars("<")):e===a.NULL?(this._err(o.unexpectedNullCharacter),this._emitChars(i.REPLACEMENT_CHARACTER)):e===a.EOF?(this._err(o.eofInScriptHtmlCommentLikeText),this._emitEOFToken()):this._emitCodePoint(e)}[H](e){e===a.HYPHEN_MINUS?(this.state=F,this._emitChars("-")):e===a.LESS_THAN_SIGN?(this.state=U,this._emitChars("<")):e===a.NULL?(this._err(o.unexpectedNullCharacter),this.state=w,this._emitChars(i.REPLACEMENT_CHARACTER)):e===a.EOF?(this._err(o.eofInScriptHtmlCommentLikeText),this._emitEOFToken()):(this.state=w,this._emitCodePoint(e))}[F](e){e===a.HYPHEN_MINUS?this._emitChars("-"):e===a.LESS_THAN_SIGN?(this.state=U,this._emitChars("<")):e===a.GREATER_THAN_SIGN?(this.state=d,this._emitChars(">")):e===a.NULL?(this._err(o.unexpectedNullCharacter),this.state=w,this._emitChars(i.REPLACEMENT_CHARACTER)):e===a.EOF?(this._err(o.eofInScriptHtmlCommentLikeText),this._emitEOFToken()):(this.state=w,this._emitCodePoint(e))}[U](e){e===a.SOLIDUS?(this.tempBuff=[],this.state=B,this._emitChars("/")):this._reconsumeInState(w)}[B](e){we(e)||e===a.SOLIDUS||e===a.GREATER_THAN_SIGN?(this.state=this._isTempBufferEqualToScriptString()?R:w,this._emitCodePoint(e)):Fe(e)?(this.tempBuff.push(qe(e)),this._emitCodePoint(e)):Ue(e)?(this.tempBuff.push(e),this._emitCodePoint(e)):this._reconsumeInState(w)}[G](e){we(e)||(e===a.SOLIDUS||e===a.GREATER_THAN_SIGN||e===a.EOF?this._reconsumeInState(K):e===a.EQUALS_SIGN?(this._err(o.unexpectedEqualsSignBeforeAttributeName),this._createAttr("="),this.state=j):(this._createAttr(""),this._reconsumeInState(j)))}[j](e){we(e)||e===a.SOLIDUS||e===a.GREATER_THAN_SIGN||e===a.EOF?(this._leaveAttrName(K),this._unconsume()):e===a.EQUALS_SIGN?this._leaveAttrName(q):Fe(e)?this.currentAttr.name+=Ve(e):e===a.QUOTATION_MARK||e===a.APOSTROPHE||e===a.LESS_THAN_SIGN?(this._err(o.unexpectedCharacterInAttributeName),this.currentAttr.name+=Ye(e)):e===a.NULL?(this._err(o.unexpectedNullCharacter),this.currentAttr.name+=i.REPLACEMENT_CHARACTER):this.currentAttr.name+=Ye(e)}[K](e){we(e)||(e===a.SOLIDUS?this.state=z:e===a.EQUALS_SIGN?this.state=q:e===a.GREATER_THAN_SIGN?(this.state=u,this._emitCurrentToken()):e===a.EOF?(this._err(o.eofInTag),this._emitEOFToken()):(this._createAttr(""),this._reconsumeInState(j)))}[q](e){we(e)||(e===a.QUOTATION_MARK?this.state=Y:e===a.APOSTROPHE?this.state=V:e===a.GREATER_THAN_SIGN?(this._err(o.missingAttributeValue),this.state=u,this._emitCurrentToken()):this._reconsumeInState(W))}[Y](e){e===a.QUOTATION_MARK?this.state=Q:e===a.AMPERSAND?(this.returnState=Y,this.state=ye):e===a.NULL?(this._err(o.unexpectedNullCharacter),this.currentAttr.value+=i.REPLACEMENT_CHARACTER):e===a.EOF?(this._err(o.eofInTag),this._emitEOFToken()):this.currentAttr.value+=Ye(e)}[V](e){e===a.APOSTROPHE?this.state=Q:e===a.AMPERSAND?(this.returnState=V,this.state=ye):e===a.NULL?(this._err(o.unexpectedNullCharacter),this.currentAttr.value+=i.REPLACEMENT_CHARACTER):e===a.EOF?(this._err(o.eofInTag),this._emitEOFToken()):this.currentAttr.value+=Ye(e)}[W](e){we(e)?this._leaveAttrValue(G):e===a.AMPERSAND?(this.returnState=W,this.state=ye):e===a.GREATER_THAN_SIGN?(this._leaveAttrValue(u),this._emitCurrentToken()):e===a.NULL?(this._err(o.unexpectedNullCharacter),this.currentAttr.value+=i.REPLACEMENT_CHARACTER):e===a.QUOTATION_MARK||e===a.APOSTROPHE||e===a.LESS_THAN_SIGN||e===a.EQUALS_SIGN||e===a.GRAVE_ACCENT?(this._err(o.unexpectedCharacterInUnquotedAttributeValue),this.currentAttr.value+=Ye(e)):e===a.EOF?(this._err(o.eofInTag),this._emitEOFToken()):this.currentAttr.value+=Ye(e)}[Q](e){we(e)?this._leaveAttrValue(G):e===a.SOLIDUS?this._leaveAttrValue(z):e===a.GREATER_THAN_SIGN?(this._leaveAttrValue(u),this._emitCurrentToken()):e===a.EOF?(this._err(o.eofInTag),this._emitEOFToken()):(this._err(o.missingWhitespaceBetweenAttributes),this._reconsumeInState(G))}[z](e){e===a.GREATER_THAN_SIGN?(this.currentToken.selfClosing=!0,this.state=u,this._emitCurrentToken()):e===a.EOF?(this._err(o.eofInTag),this._emitEOFToken()):(this._err(o.unexpectedSolidusInTag),this._reconsumeInState(G))}[X](e){e===a.GREATER_THAN_SIGN?(this.state=u,this._emitCurrentToken()):e===a.EOF?(this._emitCurrentToken(),this._emitEOFToken()):e===a.NULL?(this._err(o.unexpectedNullCharacter),this.currentToken.data+=i.REPLACEMENT_CHARACTER):this.currentToken.data+=Ye(e)}[$](e){this._consumeSequenceIfMatch(c.DASH_DASH_STRING,e,!0)?(this._createCommentToken(),this.state=J):this._consumeSequenceIfMatch(c.DOCTYPE_STRING,e,!1)?this.state=ce:this._consumeSequenceIfMatch(c.CDATA_START_STRING,e,!0)?this.allowCDATA?this.state=Oe:(this._err(o.cdataInHtmlContent),this._createCommentToken(),this.currentToken.data="[CDATA[",this.state=X):this._ensureHibernation()||(this._err(o.incorrectlyOpenedComment),this._createCommentToken(),this._reconsumeInState(X))}[J](e){e===a.HYPHEN_MINUS?this.state=Z:e===a.GREATER_THAN_SIGN?(this._err(o.abruptClosingOfEmptyComment),this.state=u,this._emitCurrentToken()):this._reconsumeInState(ee)}[Z](e){e===a.HYPHEN_MINUS?this.state=oe:e===a.GREATER_THAN_SIGN?(this._err(o.abruptClosingOfEmptyComment),this.state=u,this._emitCurrentToken()):e===a.EOF?(this._err(o.eofInComment),this._emitCurrentToken(),this._emitEOFToken()):(this.currentToken.data+="-",this._reconsumeInState(ee))}[ee](e){e===a.HYPHEN_MINUS?this.state=se:e===a.LESS_THAN_SIGN?(this.currentToken.data+="<",this.state=te):e===a.NULL?(this._err(o.unexpectedNullCharacter),this.currentToken.data+=i.REPLACEMENT_CHARACTER):e===a.EOF?(this._err(o.eofInComment),this._emitCurrentToken(),this._emitEOFToken()):this.currentToken.data+=Ye(e)}[te](e){e===a.EXCLAMATION_MARK?(this.currentToken.data+="!",this.state=ne):e===a.LESS_THAN_SIGN?this.currentToken.data+="!":this._reconsumeInState(ee)}[ne](e){e===a.HYPHEN_MINUS?this.state=re:this._reconsumeInState(ee)}[re](e){e===a.HYPHEN_MINUS?this.state=ie:this._reconsumeInState(se)}[ie](e){e!==a.GREATER_THAN_SIGN&&e!==a.EOF&&this._err(o.nestedComment),this._reconsumeInState(oe)}[se](e){e===a.HYPHEN_MINUS?this.state=oe:e===a.EOF?(this._err(o.eofInComment),this._emitCurrentToken(),this._emitEOFToken()):(this.currentToken.data+="-",this._reconsumeInState(ee))}[oe](e){e===a.GREATER_THAN_SIGN?(this.state=u,this._emitCurrentToken()):e===a.EXCLAMATION_MARK?this.state=ae:e===a.HYPHEN_MINUS?this.currentToken.data+="-":e===a.EOF?(this._err(o.eofInComment),this._emitCurrentToken(),this._emitEOFToken()):(this.currentToken.data+="--",this._reconsumeInState(ee))}[ae](e){e===a.HYPHEN_MINUS?(this.currentToken.data+="--!",this.state=se):e===a.GREATER_THAN_SIGN?(this._err(o.incorrectlyClosedComment),this.state=u,this._emitCurrentToken()):e===a.EOF?(this._err(o.eofInComment),this._emitCurrentToken(),this._emitEOFToken()):(this.currentToken.data+="--!",this._reconsumeInState(ee))}[ce](e){we(e)?this.state=le:e===a.GREATER_THAN_SIGN?this._reconsumeInState(le):e===a.EOF?(this._err(o.eofInDoctype),this._createDoctypeToken(null),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this._emitEOFToken()):(this._err(o.missingWhitespaceBeforeDoctypeName),this._reconsumeInState(le))}[le](e){we(e)||(Fe(e)?(this._createDoctypeToken(Ve(e)),this.state=ue):e===a.NULL?(this._err(o.unexpectedNullCharacter),this._createDoctypeToken(i.REPLACEMENT_CHARACTER),this.state=ue):e===a.GREATER_THAN_SIGN?(this._err(o.missingDoctypeName),this._createDoctypeToken(null),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this.state=u):e===a.EOF?(this._err(o.eofInDoctype),this._createDoctypeToken(null),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this._emitEOFToken()):(this._createDoctypeToken(Ye(e)),this.state=ue))}[ue](e){we(e)?this.state=he:e===a.GREATER_THAN_SIGN?(this.state=u,this._emitCurrentToken()):Fe(e)?this.currentToken.name+=Ve(e):e===a.NULL?(this._err(o.unexpectedNullCharacter),this.currentToken.name+=i.REPLACEMENT_CHARACTER):e===a.EOF?(this._err(o.eofInDoctype),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this._emitEOFToken()):this.currentToken.name+=Ye(e)}[he](e){we(e)||(e===a.GREATER_THAN_SIGN?(this.state=u,this._emitCurrentToken()):e===a.EOF?(this._err(o.eofInDoctype),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this._emitEOFToken()):this._consumeSequenceIfMatch(c.PUBLIC_STRING,e,!1)?this.state=pe:this._consumeSequenceIfMatch(c.SYSTEM_STRING,e,!1)?this.state=_e:this._ensureHibernation()||(this._err(o.invalidCharacterSequenceAfterDoctypeName),this.currentToken.forceQuirks=!0,this._reconsumeInState(ve)))}[pe](e){we(e)?this.state=de:e===a.QUOTATION_MARK?(this._err(o.missingWhitespaceAfterDoctypePublicKeyword),this.currentToken.publicId="",this.state=fe):e===a.APOSTROPHE?(this._err(o.missingWhitespaceAfterDoctypePublicKeyword),this.currentToken.publicId="",this.state=me):e===a.GREATER_THAN_SIGN?(this._err(o.missingDoctypePublicIdentifier),this.currentToken.forceQuirks=!0,this.state=u,this._emitCurrentToken()):e===a.EOF?(this._err(o.eofInDoctype),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this._emitEOFToken()):(this._err(o.missingQuoteBeforeDoctypePublicIdentifier),this.currentToken.forceQuirks=!0,this._reconsumeInState(ve))}[de](e){we(e)||(e===a.QUOTATION_MARK?(this.currentToken.publicId="",this.state=fe):e===a.APOSTROPHE?(this.currentToken.publicId="",this.state=me):e===a.GREATER_THAN_SIGN?(this._err(o.missingDoctypePublicIdentifier),this.currentToken.forceQuirks=!0,this.state=u,this._emitCurrentToken()):e===a.EOF?(this._err(o.eofInDoctype),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this._emitEOFToken()):(this._err(o.missingQuoteBeforeDoctypePublicIdentifier),this.currentToken.forceQuirks=!0,this._reconsumeInState(ve)))}[fe](e){e===a.QUOTATION_MARK?this.state=Te:e===a.NULL?(this._err(o.unexpectedNullCharacter),this.currentToken.publicId+=i.REPLACEMENT_CHARACTER):e===a.GREATER_THAN_SIGN?(this._err(o.abruptDoctypePublicIdentifier),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this.state=u):e===a.EOF?(this._err(o.eofInDoctype),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this._emitEOFToken()):this.currentToken.publicId+=Ye(e)}[me](e){e===a.APOSTROPHE?this.state=Te:e===a.NULL?(this._err(o.unexpectedNullCharacter),this.currentToken.publicId+=i.REPLACEMENT_CHARACTER):e===a.GREATER_THAN_SIGN?(this._err(o.abruptDoctypePublicIdentifier),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this.state=u):e===a.EOF?(this._err(o.eofInDoctype),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this._emitEOFToken()):this.currentToken.publicId+=Ye(e)}[Te](e){we(e)?this.state=Ee:e===a.GREATER_THAN_SIGN?(this.state=u,this._emitCurrentToken()):e===a.QUOTATION_MARK?(this._err(o.missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers),this.currentToken.systemId="",this.state=Ae):e===a.APOSTROPHE?(this._err(o.missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers),this.currentToken.systemId="",this.state=Ce):e===a.EOF?(this._err(o.eofInDoctype),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this._emitEOFToken()):(this._err(o.missingQuoteBeforeDoctypeSystemIdentifier),this.currentToken.forceQuirks=!0,this._reconsumeInState(ve))}[Ee](e){we(e)||(e===a.GREATER_THAN_SIGN?(this._emitCurrentToken(),this.state=u):e===a.QUOTATION_MARK?(this.currentToken.systemId="",this.state=Ae):e===a.APOSTROPHE?(this.currentToken.systemId="",this.state=Ce):e===a.EOF?(this._err(o.eofInDoctype),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this._emitEOFToken()):(this._err(o.missingQuoteBeforeDoctypeSystemIdentifier),this.currentToken.forceQuirks=!0,this._reconsumeInState(ve)))}[_e](e){we(e)?this.state=ge:e===a.QUOTATION_MARK?(this._err(o.missingWhitespaceAfterDoctypeSystemKeyword),this.currentToken.systemId="",this.state=Ae):e===a.APOSTROPHE?(this._err(o.missingWhitespaceAfterDoctypeSystemKeyword),this.currentToken.systemId="",this.state=Ce):e===a.GREATER_THAN_SIGN?(this._err(o.missingDoctypeSystemIdentifier),this.currentToken.forceQuirks=!0,this.state=u,this._emitCurrentToken()):e===a.EOF?(this._err(o.eofInDoctype),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this._emitEOFToken()):(this._err(o.missingQuoteBeforeDoctypeSystemIdentifier),this.currentToken.forceQuirks=!0,this._reconsumeInState(ve))}[ge](e){we(e)||(e===a.QUOTATION_MARK?(this.currentToken.systemId="",this.state=Ae):e===a.APOSTROPHE?(this.currentToken.systemId="",this.state=Ce):e===a.GREATER_THAN_SIGN?(this._err(o.missingDoctypeSystemIdentifier),this.currentToken.forceQuirks=!0,this.state=u,this._emitCurrentToken()):e===a.EOF?(this._err(o.eofInDoctype),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this._emitEOFToken()):(this._err(o.missingQuoteBeforeDoctypeSystemIdentifier),this.currentToken.forceQuirks=!0,this._reconsumeInState(ve)))}[Ae](e){e===a.QUOTATION_MARK?this.state=Ne:e===a.NULL?(this._err(o.unexpectedNullCharacter),this.currentToken.systemId+=i.REPLACEMENT_CHARACTER):e===a.GREATER_THAN_SIGN?(this._err(o.abruptDoctypeSystemIdentifier),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this.state=u):e===a.EOF?(this._err(o.eofInDoctype),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this._emitEOFToken()):this.currentToken.systemId+=Ye(e)}[Ce](e){e===a.APOSTROPHE?this.state=Ne:e===a.NULL?(this._err(o.unexpectedNullCharacter),this.currentToken.systemId+=i.REPLACEMENT_CHARACTER):e===a.GREATER_THAN_SIGN?(this._err(o.abruptDoctypeSystemIdentifier),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this.state=u):e===a.EOF?(this._err(o.eofInDoctype),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this._emitEOFToken()):this.currentToken.systemId+=Ye(e)}[Ne](e){we(e)||(e===a.GREATER_THAN_SIGN?(this._emitCurrentToken(),this.state=u):e===a.EOF?(this._err(o.eofInDoctype),this.currentToken.forceQuirks=!0,this._emitCurrentToken(),this._emitEOFToken()):(this._err(o.unexpectedCharacterAfterDoctypeSystemIdentifier),this._reconsumeInState(ve)))}[ve](e){e===a.GREATER_THAN_SIGN?(this._emitCurrentToken(),this.state=u):e===a.NULL?this._err(o.unexpectedNullCharacter):e===a.EOF&&(this._emitCurrentToken(),this._emitEOFToken())}[Oe](e){e===a.RIGHT_SQUARE_BRACKET?this.state=be:e===a.EOF?(this._err(o.eofInCdata),this._emitEOFToken()):this._emitCodePoint(e)}[be](e){e===a.RIGHT_SQUARE_BRACKET?this.state=Se:(this._emitChars("]"),this._reconsumeInState(Oe))}[Se](e){e===a.GREATER_THAN_SIGN?this.state=u:e===a.RIGHT_SQUARE_BRACKET?this._emitChars("]"):(this._emitChars("]]"),this._reconsumeInState(Oe))}[ye](e){this.tempBuff=[a.AMPERSAND],e===a.NUMBER_SIGN?(this.tempBuff.push(e),this.state=ke):Ge(e)?this._reconsumeInState(Ie):(this._flushCodePointsConsumedAsCharacterReference(),this._reconsumeInState(this.returnState))}[Ie](e){const t=this._matchNamedCharacterReference(e);if(this._ensureHibernation())this.tempBuff=[a.AMPERSAND];else if(t){const e=this.tempBuff[this.tempBuff.length-1]===a.SEMICOLON;this._isCharacterReferenceAttributeQuirk(e)||(e||this._errOnNextCodePoint(o.missingSemicolonAfterCharacterReference),this.tempBuff=t),this._flushCodePointsConsumedAsCharacterReference(),this.state=this.returnState}else this._flushCodePointsConsumedAsCharacterReference(),this.state=Re}[Re](e){Ge(e)?this._isCharacterReferenceInAttribute()?this.currentAttr.value+=Ye(e):this._emitCodePoint(e):(e===a.SEMICOLON&&this._err(o.unknownNamedCharacterReference),this._reconsumeInState(this.returnState))}[ke](e){this.charRefCode=0,e===a.LATIN_SMALL_X||e===a.LATIN_CAPITAL_X?(this.tempBuff.push(e),this.state=Le):this._reconsumeInState(Me)}[Le](e){!function(e){return He(e)||je(e)||Ke(e)}(e)?(this._err(o.absenceOfDigitsInNumericCharacterReference),this._flushCodePointsConsumedAsCharacterReference(),this._reconsumeInState(this.returnState)):this._reconsumeInState(xe)}[Me](e){He(e)?this._reconsumeInState(Pe):(this._err(o.absenceOfDigitsInNumericCharacterReference),this._flushCodePointsConsumedAsCharacterReference(),this._reconsumeInState(this.returnState))}[xe](e){je(e)?this.charRefCode=16*this.charRefCode+e-55:Ke(e)?this.charRefCode=16*this.charRefCode+e-87:He(e)?this.charRefCode=16*this.charRefCode+e-48:e===a.SEMICOLON?this.state=De:(this._err(o.missingSemicolonAfterCharacterReference),this._reconsumeInState(De))}[Pe](e){He(e)?this.charRefCode=10*this.charRefCode+e-48:e===a.SEMICOLON?this.state=De:(this._err(o.missingSemicolonAfterCharacterReference),this._reconsumeInState(De))}[De](){if(this.charRefCode===a.NULL)this._err(o.nullCharacterReference),this.charRefCode=a.REPLACEMENT_CHARACTER;else if(this.charRefCode>1114111)this._err(o.characterReferenceOutsideUnicodeRange),this.charRefCode=a.REPLACEMENT_CHARACTER;else if(i.isSurrogate(this.charRefCode))this._err(o.surrogateCharacterReference),this.charRefCode=a.REPLACEMENT_CHARACTER;else if(i.isUndefinedCodePoint(this.charRefCode))this._err(o.noncharacterCharacterReference);else if(i.isControlCodePoint(this.charRefCode)||this.charRefCode===a.CARRIAGE_RETURN){this._err(o.controlCharacterReference);const e=l[this.charRefCode];e&&(this.charRefCode=e)}this.tempBuff=[this.charRefCode],this._flushCodePointsConsumedAsCharacterReference(),this._reconsumeInState(this.returnState)}}Qe.CHARACTER_TOKEN="CHARACTER_TOKEN",Qe.NULL_CHARACTER_TOKEN="NULL_CHARACTER_TOKEN",Qe.WHITESPACE_CHARACTER_TOKEN="WHITESPACE_CHARACTER_TOKEN",Qe.START_TAG_TOKEN="START_TAG_TOKEN",Qe.END_TAG_TOKEN="END_TAG_TOKEN",Qe.COMMENT_TOKEN="COMMENT_TOKEN",Qe.DOCTYPE_TOKEN="DOCTYPE_TOKEN",Qe.EOF_TOKEN="EOF_TOKEN",Qe.HIBERNATION_TOKEN="HIBERNATION_TOKEN",Qe.MODE={DATA:u,RCDATA:h,RAWTEXT:p,SCRIPT_DATA:d,PLAINTEXT:f},Qe.getTokenAttr=function(e,t){for(let n=e.attrs.length-1;n>=0;n--)if(e.attrs[n].name===t)return e.attrs[n].value;return null},e.exports=Qe},5482:e=>{"use strict";e.exports=new Uint16Array([4,52,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,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,106,303,412,810,1432,1701,1796,1987,2114,2360,2420,2484,3170,3251,4140,4393,4575,4610,5106,5512,5728,6117,6274,6315,6345,6427,6516,7002,7910,8733,9323,9870,10170,10631,10893,11318,11386,11467,12773,13092,14474,14922,15448,15542,16419,17666,18166,18611,19004,19095,19298,19397,4,16,69,77,97,98,99,102,103,108,109,110,111,112,114,115,116,117,140,150,158,169,176,194,199,210,216,222,226,242,256,266,283,294,108,105,103,5,198,1,59,148,1,198,80,5,38,1,59,156,1,38,99,117,116,101,5,193,1,59,167,1,193,114,101,118,101,59,1,258,4,2,105,121,182,191,114,99,5,194,1,59,189,1,194,59,1,1040,114,59,3,55349,56580,114,97,118,101,5,192,1,59,208,1,192,112,104,97,59,1,913,97,99,114,59,1,256,100,59,1,10835,4,2,103,112,232,237,111,110,59,1,260,102,59,3,55349,56632,112,108,121,70,117,110,99,116,105,111,110,59,1,8289,105,110,103,5,197,1,59,264,1,197,4,2,99,115,272,277,114,59,3,55349,56476,105,103,110,59,1,8788,105,108,100,101,5,195,1,59,292,1,195,109,108,5,196,1,59,301,1,196,4,8,97,99,101,102,111,114,115,117,321,350,354,383,388,394,400,405,4,2,99,114,327,336,107,115,108,97,115,104,59,1,8726,4,2,118,119,342,345,59,1,10983,101,100,59,1,8966,121,59,1,1041,4,3,99,114,116,362,369,379,97,117,115,101,59,1,8757,110,111,117,108,108,105,115,59,1,8492,97,59,1,914,114,59,3,55349,56581,112,102,59,3,55349,56633,101,118,101,59,1,728,99,114,59,1,8492,109,112,101,113,59,1,8782,4,14,72,79,97,99,100,101,102,104,105,108,111,114,115,117,442,447,456,504,542,547,569,573,577,616,678,784,790,796,99,121,59,1,1063,80,89,5,169,1,59,454,1,169,4,3,99,112,121,464,470,497,117,116,101,59,1,262,4,2,59,105,476,478,1,8914,116,97,108,68,105,102,102,101,114,101,110,116,105,97,108,68,59,1,8517,108,101,121,115,59,1,8493,4,4,97,101,105,111,514,520,530,535,114,111,110,59,1,268,100,105,108,5,199,1,59,528,1,199,114,99,59,1,264,110,105,110,116,59,1,8752,111,116,59,1,266,4,2,100,110,553,560,105,108,108,97,59,1,184,116,101,114,68,111,116,59,1,183,114,59,1,8493,105,59,1,935,114,99,108,101,4,4,68,77,80,84,591,596,603,609,111,116,59,1,8857,105,110,117,115,59,1,8854,108,117,115,59,1,8853,105,109,101,115,59,1,8855,111,4,2,99,115,623,646,107,119,105,115,101,67,111,110,116,111,117,114,73,110,116,101,103,114,97,108,59,1,8754,101,67,117,114,108,121,4,2,68,81,658,671,111,117,98,108,101,81,117,111,116,101,59,1,8221,117,111,116,101,59,1,8217,4,4,108,110,112,117,688,701,736,753,111,110,4,2,59,101,696,698,1,8759,59,1,10868,4,3,103,105,116,709,717,722,114,117,101,110,116,59,1,8801,110,116,59,1,8751,111,117,114,73,110,116,101,103,114,97,108,59,1,8750,4,2,102,114,742,745,59,1,8450,111,100,117,99,116,59,1,8720,110,116,101,114,67,108,111,99,107,119,105,115,101,67,111,110,116,111,117,114,73,110,116,101,103,114,97,108,59,1,8755,111,115,115,59,1,10799,99,114,59,3,55349,56478,112,4,2,59,67,803,805,1,8915,97,112,59,1,8781,4,11,68,74,83,90,97,99,101,102,105,111,115,834,850,855,860,865,888,903,916,921,1011,1415,4,2,59,111,840,842,1,8517,116,114,97,104,100,59,1,10513,99,121,59,1,1026,99,121,59,1,1029,99,121,59,1,1039,4,3,103,114,115,873,879,883,103,101,114,59,1,8225,114,59,1,8609,104,118,59,1,10980,4,2,97,121,894,900,114,111,110,59,1,270,59,1,1044,108,4,2,59,116,910,912,1,8711,97,59,1,916,114,59,3,55349,56583,4,2,97,102,927,998,4,2,99,109,933,992,114,105,116,105,99,97,108,4,4,65,68,71,84,950,957,978,985,99,117,116,101,59,1,180,111,4,2,116,117,964,967,59,1,729,98,108,101,65,99,117,116,101,59,1,733,114,97,118,101,59,1,96,105,108,100,101,59,1,732,111,110,100,59,1,8900,102,101,114,101,110,116,105,97,108,68,59,1,8518,4,4,112,116,117,119,1021,1026,1048,1249,102,59,3,55349,56635,4,3,59,68,69,1034,1036,1041,1,168,111,116,59,1,8412,113,117,97,108,59,1,8784,98,108,101,4,6,67,68,76,82,85,86,1065,1082,1101,1189,1211,1236,111,110,116,111,117,114,73,110,116,101,103,114,97,108,59,1,8751,111,4,2,116,119,1089,1092,59,1,168,110,65,114,114,111,119,59,1,8659,4,2,101,111,1107,1141,102,116,4,3,65,82,84,1117,1124,1136,114,114,111,119,59,1,8656,105,103,104,116,65,114,114,111,119,59,1,8660,101,101,59,1,10980,110,103,4,2,76,82,1149,1177,101,102,116,4,2,65,82,1158,1165,114,114,111,119,59,1,10232,105,103,104,116,65,114,114,111,119,59,1,10234,105,103,104,116,65,114,114,111,119,59,1,10233,105,103,104,116,4,2,65,84,1199,1206,114,114,111,119,59,1,8658,101,101,59,1,8872,112,4,2,65,68,1218,1225,114,114,111,119,59,1,8657,111,119,110,65,114,114,111,119,59,1,8661,101,114,116,105,99,97,108,66,97,114,59,1,8741,110,4,6,65,66,76,82,84,97,1264,1292,1299,1352,1391,1408,114,114,111,119,4,3,59,66,85,1276,1278,1283,1,8595,97,114,59,1,10515,112,65,114,114,111,119,59,1,8693,114,101,118,101,59,1,785,101,102,116,4,3,82,84,86,1310,1323,1334,105,103,104,116,86,101,99,116,111,114,59,1,10576,101,101,86,101,99,116,111,114,59,1,10590,101,99,116,111,114,4,2,59,66,1345,1347,1,8637,97,114,59,1,10582,105,103,104,116,4,2,84,86,1362,1373,101,101,86,101,99,116,111,114,59,1,10591,101,99,116,111,114,4,2,59,66,1384,1386,1,8641,97,114,59,1,10583,101,101,4,2,59,65,1399,1401,1,8868,114,114,111,119,59,1,8615,114,114,111,119,59,1,8659,4,2,99,116,1421,1426,114,59,3,55349,56479,114,111,107,59,1,272,4,16,78,84,97,99,100,102,103,108,109,111,112,113,115,116,117,120,1466,1470,1478,1489,1515,1520,1525,1536,1544,1593,1609,1617,1650,1664,1668,1677,71,59,1,330,72,5,208,1,59,1476,1,208,99,117,116,101,5,201,1,59,1487,1,201,4,3,97,105,121,1497,1503,1512,114,111,110,59,1,282,114,99,5,202,1,59,1510,1,202,59,1,1069,111,116,59,1,278,114,59,3,55349,56584,114,97,118,101,5,200,1,59,1534,1,200,101,109,101,110,116,59,1,8712,4,2,97,112,1550,1555,99,114,59,1,274,116,121,4,2,83,86,1563,1576,109,97,108,108,83,113,117,97,114,101,59,1,9723,101,114,121,83,109,97,108,108,83,113,117,97,114,101,59,1,9643,4,2,103,112,1599,1604,111,110,59,1,280,102,59,3,55349,56636,115,105,108,111,110,59,1,917,117,4,2,97,105,1624,1640,108,4,2,59,84,1631,1633,1,10869,105,108,100,101,59,1,8770,108,105,98,114,105,117,109,59,1,8652,4,2,99,105,1656,1660,114,59,1,8496,109,59,1,10867,97,59,1,919,109,108,5,203,1,59,1675,1,203,4,2,105,112,1683,1689,115,116,115,59,1,8707,111,110,101,110,116,105,97,108,69,59,1,8519,4,5,99,102,105,111,115,1713,1717,1722,1762,1791,121,59,1,1060,114,59,3,55349,56585,108,108,101,100,4,2,83,86,1732,1745,109,97,108,108,83,113,117,97,114,101,59,1,9724,101,114,121,83,109,97,108,108,83,113,117,97,114,101,59,1,9642,4,3,112,114,117,1770,1775,1781,102,59,3,55349,56637,65,108,108,59,1,8704,114,105,101,114,116,114,102,59,1,8497,99,114,59,1,8497,4,12,74,84,97,98,99,100,102,103,111,114,115,116,1822,1827,1834,1848,1855,1877,1882,1887,1890,1896,1978,1984,99,121,59,1,1027,5,62,1,59,1832,1,62,109,109,97,4,2,59,100,1843,1845,1,915,59,1,988,114,101,118,101,59,1,286,4,3,101,105,121,1863,1869,1874,100,105,108,59,1,290,114,99,59,1,284,59,1,1043,111,116,59,1,288,114,59,3,55349,56586,59,1,8921,112,102,59,3,55349,56638,101,97,116,101,114,4,6,69,70,71,76,83,84,1915,1933,1944,1953,1959,1971,113,117,97,108,4,2,59,76,1925,1927,1,8805,101,115,115,59,1,8923,117,108,108,69,113,117,97,108,59,1,8807,114,101,97,116,101,114,59,1,10914,101,115,115,59,1,8823,108,97,110,116,69,113,117,97,108,59,1,10878,105,108,100,101,59,1,8819,99,114,59,3,55349,56482,59,1,8811,4,8,65,97,99,102,105,111,115,117,2005,2012,2026,2032,2036,2049,2073,2089,82,68,99,121,59,1,1066,4,2,99,116,2018,2023,101,107,59,1,711,59,1,94,105,114,99,59,1,292,114,59,1,8460,108,98,101,114,116,83,112,97,99,101,59,1,8459,4,2,112,114,2055,2059,102,59,1,8461,105,122,111,110,116,97,108,76,105,110,101,59,1,9472,4,2,99,116,2079,2083,114,59,1,8459,114,111,107,59,1,294,109,112,4,2,68,69,2097,2107,111,119,110,72,117,109,112,59,1,8782,113,117,97,108,59,1,8783,4,14,69,74,79,97,99,100,102,103,109,110,111,115,116,117,2144,2149,2155,2160,2171,2189,2194,2198,2209,2245,2307,2329,2334,2341,99,121,59,1,1045,108,105,103,59,1,306,99,121,59,1,1025,99,117,116,101,5,205,1,59,2169,1,205,4,2,105,121,2177,2186,114,99,5,206,1,59,2184,1,206,59,1,1048,111,116,59,1,304,114,59,1,8465,114,97,118,101,5,204,1,59,2207,1,204,4,3,59,97,112,2217,2219,2238,1,8465,4,2,99,103,2225,2229,114,59,1,298,105,110,97,114,121,73,59,1,8520,108,105,101,115,59,1,8658,4,2,116,118,2251,2281,4,2,59,101,2257,2259,1,8748,4,2,103,114,2265,2271,114,97,108,59,1,8747,115,101,99,116,105,111,110,59,1,8898,105,115,105,98,108,101,4,2,67,84,2293,2300,111,109,109,97,59,1,8291,105,109,101,115,59,1,8290,4,3,103,112,116,2315,2320,2325,111,110,59,1,302,102,59,3,55349,56640,97,59,1,921,99,114,59,1,8464,105,108,100,101,59,1,296,4,2,107,109,2347,2352,99,121,59,1,1030,108,5,207,1,59,2358,1,207,4,5,99,102,111,115,117,2372,2386,2391,2397,2414,4,2,105,121,2378,2383,114,99,59,1,308,59,1,1049,114,59,3,55349,56589,112,102,59,3,55349,56641,4,2,99,101,2403,2408,114,59,3,55349,56485,114,99,121,59,1,1032,107,99,121,59,1,1028,4,7,72,74,97,99,102,111,115,2436,2441,2446,2452,2467,2472,2478,99,121,59,1,1061,99,121,59,1,1036,112,112,97,59,1,922,4,2,101,121,2458,2464,100,105,108,59,1,310,59,1,1050,114,59,3,55349,56590,112,102,59,3,55349,56642,99,114,59,3,55349,56486,4,11,74,84,97,99,101,102,108,109,111,115,116,2508,2513,2520,2562,2585,2981,2986,3004,3011,3146,3167,99,121,59,1,1033,5,60,1,59,2518,1,60,4,5,99,109,110,112,114,2532,2538,2544,2548,2558,117,116,101,59,1,313,98,100,97,59,1,923,103,59,1,10218,108,97,99,101,116,114,102,59,1,8466,114,59,1,8606,4,3,97,101,121,2570,2576,2582,114,111,110,59,1,317,100,105,108,59,1,315,59,1,1051,4,2,102,115,2591,2907,116,4,10,65,67,68,70,82,84,85,86,97,114,2614,2663,2672,2728,2735,2760,2820,2870,2888,2895,4,2,110,114,2620,2633,103,108,101,66,114,97,99,107,101,116,59,1,10216,114,111,119,4,3,59,66,82,2644,2646,2651,1,8592,97,114,59,1,8676,105,103,104,116,65,114,114,111,119,59,1,8646,101,105,108,105,110,103,59,1,8968,111,4,2,117,119,2679,2692,98,108,101,66,114,97,99,107,101,116,59,1,10214,110,4,2,84,86,2699,2710,101,101,86,101,99,116,111,114,59,1,10593,101,99,116,111,114,4,2,59,66,2721,2723,1,8643,97,114,59,1,10585,108,111,111,114,59,1,8970,105,103,104,116,4,2,65,86,2745,2752,114,114,111,119,59,1,8596,101,99,116,111,114,59,1,10574,4,2,101,114,2766,2792,101,4,3,59,65,86,2775,2777,2784,1,8867,114,114,111,119,59,1,8612,101,99,116,111,114,59,1,10586,105,97,110,103,108,101,4,3,59,66,69,2806,2808,2813,1,8882,97,114,59,1,10703,113,117,97,108,59,1,8884,112,4,3,68,84,86,2829,2841,2852,111,119,110,86,101,99,116,111,114,59,1,10577,101,101,86,101,99,116,111,114,59,1,10592,101,99,116,111,114,4,2,59,66,2863,2865,1,8639,97,114,59,1,10584,101,99,116,111,114,4,2,59,66,2881,2883,1,8636,97,114,59,1,10578,114,114,111,119,59,1,8656,105,103,104,116,97,114,114,111,119,59,1,8660,115,4,6,69,70,71,76,83,84,2922,2936,2947,2956,2962,2974,113,117,97,108,71,114,101,97,116,101,114,59,1,8922,117,108,108,69,113,117,97,108,59,1,8806,114,101,97,116,101,114,59,1,8822,101,115,115,59,1,10913,108,97,110,116,69,113,117,97,108,59,1,10877,105,108,100,101,59,1,8818,114,59,3,55349,56591,4,2,59,101,2992,2994,1,8920,102,116,97,114,114,111,119,59,1,8666,105,100,111,116,59,1,319,4,3,110,112,119,3019,3110,3115,103,4,4,76,82,108,114,3030,3058,3070,3098,101,102,116,4,2,65,82,3039,3046,114,114,111,119,59,1,10229,105,103,104,116,65,114,114,111,119,59,1,10231,105,103,104,116,65,114,114,111,119,59,1,10230,101,102,116,4,2,97,114,3079,3086,114,114,111,119,59,1,10232,105,103,104,116,97,114,114,111,119,59,1,10234,105,103,104,116,97,114,114,111,119,59,1,10233,102,59,3,55349,56643,101,114,4,2,76,82,3123,3134,101,102,116,65,114,114,111,119,59,1,8601,105,103,104,116,65,114,114,111,119,59,1,8600,4,3,99,104,116,3154,3158,3161,114,59,1,8466,59,1,8624,114,111,107,59,1,321,59,1,8810,4,8,97,99,101,102,105,111,115,117,3188,3192,3196,3222,3227,3237,3243,3248,112,59,1,10501,121,59,1,1052,4,2,100,108,3202,3213,105,117,109,83,112,97,99,101,59,1,8287,108,105,110,116,114,102,59,1,8499,114,59,3,55349,56592,110,117,115,80,108,117,115,59,1,8723,112,102,59,3,55349,56644,99,114,59,1,8499,59,1,924,4,9,74,97,99,101,102,111,115,116,117,3271,3276,3283,3306,3422,3427,4120,4126,4137,99,121,59,1,1034,99,117,116,101,59,1,323,4,3,97,101,121,3291,3297,3303,114,111,110,59,1,327,100,105,108,59,1,325,59,1,1053,4,3,103,115,119,3314,3380,3415,97,116,105,118,101,4,3,77,84,86,3327,3340,3365,101,100,105,117,109,83,112,97,99,101,59,1,8203,104,105,4,2,99,110,3348,3357,107,83,112,97,99,101,59,1,8203,83,112,97,99,101,59,1,8203,101,114,121,84,104,105,110,83,112,97,99,101,59,1,8203,116,101,100,4,2,71,76,3389,3405,114,101,97,116,101,114,71,114,101,97,116,101,114,59,1,8811,101,115,115,76,101,115,115,59,1,8810,76,105,110,101,59,1,10,114,59,3,55349,56593,4,4,66,110,112,116,3437,3444,3460,3464,114,101,97,107,59,1,8288,66,114,101,97,107,105,110,103,83,112,97,99,101,59,1,160,102,59,1,8469,4,13,59,67,68,69,71,72,76,78,80,82,83,84,86,3492,3494,3517,3536,3578,3657,3685,3784,3823,3860,3915,4066,4107,1,10988,4,2,111,117,3500,3510,110,103,114,117,101,110,116,59,1,8802,112,67,97,112,59,1,8813,111,117,98,108,101,86,101,114,116,105,99,97,108,66,97,114,59,1,8742,4,3,108,113,120,3544,3552,3571,101,109,101,110,116,59,1,8713,117,97,108,4,2,59,84,3561,3563,1,8800,105,108,100,101,59,3,8770,824,105,115,116,115,59,1,8708,114,101,97,116,101,114,4,7,59,69,70,71,76,83,84,3600,3602,3609,3621,3631,3637,3650,1,8815,113,117,97,108,59,1,8817,117,108,108,69,113,117,97,108,59,3,8807,824,114,101,97,116,101,114,59,3,8811,824,101,115,115,59,1,8825,108,97,110,116,69,113,117,97,108,59,3,10878,824,105,108,100,101,59,1,8821,117,109,112,4,2,68,69,3666,3677,111,119,110,72,117,109,112,59,3,8782,824,113,117,97,108,59,3,8783,824,101,4,2,102,115,3692,3724,116,84,114,105,97,110,103,108,101,4,3,59,66,69,3709,3711,3717,1,8938,97,114,59,3,10703,824,113,117,97,108,59,1,8940,115,4,6,59,69,71,76,83,84,3739,3741,3748,3757,3764,3777,1,8814,113,117,97,108,59,1,8816,114,101,97,116,101,114,59,1,8824,101,115,115,59,3,8810,824,108,97,110,116,69,113,117,97,108,59,3,10877,824,105,108,100,101,59,1,8820,101,115,116,101,100,4,2,71,76,3795,3812,114,101,97,116,101,114,71,114,101,97,116,101,114,59,3,10914,824,101,115,115,76,101,115,115,59,3,10913,824,114,101,99,101,100,101,115,4,3,59,69,83,3838,3840,3848,1,8832,113,117,97,108,59,3,10927,824,108,97,110,116,69,113,117,97,108,59,1,8928,4,2,101,105,3866,3881,118,101,114,115,101,69,108,101,109,101,110,116,59,1,8716,103,104,116,84,114,105,97,110,103,108,101,4,3,59,66,69,3900,3902,3908,1,8939,97,114,59,3,10704,824,113,117,97,108,59,1,8941,4,2,113,117,3921,3973,117,97,114,101,83,117,4,2,98,112,3933,3952,115,101,116,4,2,59,69,3942,3945,3,8847,824,113,117,97,108,59,1,8930,101,114,115,101,116,4,2,59,69,3963,3966,3,8848,824,113,117,97,108,59,1,8931,4,3,98,99,112,3981,4e3,4045,115,101,116,4,2,59,69,3990,3993,3,8834,8402,113,117,97,108,59,1,8840,99,101,101,100,115,4,4,59,69,83,84,4015,4017,4025,4037,1,8833,113,117,97,108,59,3,10928,824,108,97,110,116,69,113,117,97,108,59,1,8929,105,108,100,101,59,3,8831,824,101,114,115,101,116,4,2,59,69,4056,4059,3,8835,8402,113,117,97,108,59,1,8841,105,108,100,101,4,4,59,69,70,84,4080,4082,4089,4100,1,8769,113,117,97,108,59,1,8772,117,108,108,69,113,117,97,108,59,1,8775,105,108,100,101,59,1,8777,101,114,116,105,99,97,108,66,97,114,59,1,8740,99,114,59,3,55349,56489,105,108,100,101,5,209,1,59,4135,1,209,59,1,925,4,14,69,97,99,100,102,103,109,111,112,114,115,116,117,118,4170,4176,4187,4205,4212,4217,4228,4253,4259,4292,4295,4316,4337,4346,108,105,103,59,1,338,99,117,116,101,5,211,1,59,4185,1,211,4,2,105,121,4193,4202,114,99,5,212,1,59,4200,1,212,59,1,1054,98,108,97,99,59,1,336,114,59,3,55349,56594,114,97,118,101,5,210,1,59,4226,1,210,4,3,97,101,105,4236,4241,4246,99,114,59,1,332,103,97,59,1,937,99,114,111,110,59,1,927,112,102,59,3,55349,56646,101,110,67,117,114,108,121,4,2,68,81,4272,4285,111,117,98,108,101,81,117,111,116,101,59,1,8220,117,111,116,101,59,1,8216,59,1,10836,4,2,99,108,4301,4306,114,59,3,55349,56490,97,115,104,5,216,1,59,4314,1,216,105,4,2,108,109,4323,4332,100,101,5,213,1,59,4330,1,213,101,115,59,1,10807,109,108,5,214,1,59,4344,1,214,101,114,4,2,66,80,4354,4380,4,2,97,114,4360,4364,114,59,1,8254,97,99,4,2,101,107,4372,4375,59,1,9182,101,116,59,1,9140,97,114,101,110,116,104,101,115,105,115,59,1,9180,4,9,97,99,102,104,105,108,111,114,115,4413,4422,4426,4431,4435,4438,4448,4471,4561,114,116,105,97,108,68,59,1,8706,121,59,1,1055,114,59,3,55349,56595,105,59,1,934,59,1,928,117,115,77,105,110,117,115,59,1,177,4,2,105,112,4454,4467,110,99,97,114,101,112,108,97,110,101,59,1,8460,102,59,1,8473,4,4,59,101,105,111,4481,4483,4526,4531,1,10939,99,101,100,101,115,4,4,59,69,83,84,4498,4500,4507,4519,1,8826,113,117,97,108,59,1,10927,108,97,110,116,69,113,117,97,108,59,1,8828,105,108,100,101,59,1,8830,109,101,59,1,8243,4,2,100,112,4537,4543,117,99,116,59,1,8719,111,114,116,105,111,110,4,2,59,97,4555,4557,1,8759,108,59,1,8733,4,2,99,105,4567,4572,114,59,3,55349,56491,59,1,936,4,4,85,102,111,115,4585,4594,4599,4604,79,84,5,34,1,59,4592,1,34,114,59,3,55349,56596,112,102,59,1,8474,99,114,59,3,55349,56492,4,12,66,69,97,99,101,102,104,105,111,114,115,117,4636,4642,4650,4681,4704,4763,4767,4771,5047,5069,5081,5094,97,114,114,59,1,10512,71,5,174,1,59,4648,1,174,4,3,99,110,114,4658,4664,4668,117,116,101,59,1,340,103,59,1,10219,114,4,2,59,116,4675,4677,1,8608,108,59,1,10518,4,3,97,101,121,4689,4695,4701,114,111,110,59,1,344,100,105,108,59,1,342,59,1,1056,4,2,59,118,4710,4712,1,8476,101,114,115,101,4,2,69,85,4722,4748,4,2,108,113,4728,4736,101,109,101,110,116,59,1,8715,117,105,108,105,98,114,105,117,109,59,1,8651,112,69,113,117,105,108,105,98,114,105,117,109,59,1,10607,114,59,1,8476,111,59,1,929,103,104,116,4,8,65,67,68,70,84,85,86,97,4792,4840,4849,4905,4912,4972,5022,5040,4,2,110,114,4798,4811,103,108,101,66,114,97,99,107,101,116,59,1,10217,114,111,119,4,3,59,66,76,4822,4824,4829,1,8594,97,114,59,1,8677,101,102,116,65,114,114,111,119,59,1,8644,101,105,108,105,110,103,59,1,8969,111,4,2,117,119,4856,4869,98,108,101,66,114,97,99,107,101,116,59,1,10215,110,4,2,84,86,4876,4887,101,101,86,101,99,116,111,114,59,1,10589,101,99,116,111,114,4,2,59,66,4898,4900,1,8642,97,114,59,1,10581,108,111,111,114,59,1,8971,4,2,101,114,4918,4944,101,4,3,59,65,86,4927,4929,4936,1,8866,114,114,111,119,59,1,8614,101,99,116,111,114,59,1,10587,105,97,110,103,108,101,4,3,59,66,69,4958,4960,4965,1,8883,97,114,59,1,10704,113,117,97,108,59,1,8885,112,4,3,68,84,86,4981,4993,5004,111,119,110,86,101,99,116,111,114,59,1,10575,101,101,86,101,99,116,111,114,59,1,10588,101,99,116,111,114,4,2,59,66,5015,5017,1,8638,97,114,59,1,10580,101,99,116,111,114,4,2,59,66,5033,5035,1,8640,97,114,59,1,10579,114,114,111,119,59,1,8658,4,2,112,117,5053,5057,102,59,1,8477,110,100,73,109,112,108,105,101,115,59,1,10608,105,103,104,116,97,114,114,111,119,59,1,8667,4,2,99,104,5087,5091,114,59,1,8475,59,1,8625,108,101,68,101,108,97,121,101,100,59,1,10740,4,13,72,79,97,99,102,104,105,109,111,113,115,116,117,5134,5150,5157,5164,5198,5203,5259,5265,5277,5283,5374,5380,5385,4,2,67,99,5140,5146,72,99,121,59,1,1065,121,59,1,1064,70,84,99,121,59,1,1068,99,117,116,101,59,1,346,4,5,59,97,101,105,121,5176,5178,5184,5190,5195,1,10940,114,111,110,59,1,352,100,105,108,59,1,350,114,99,59,1,348,59,1,1057,114,59,3,55349,56598,111,114,116,4,4,68,76,82,85,5216,5227,5238,5250,111,119,110,65,114,114,111,119,59,1,8595,101,102,116,65,114,114,111,119,59,1,8592,105,103,104,116,65,114,114,111,119,59,1,8594,112,65,114,114,111,119,59,1,8593,103,109,97,59,1,931,97,108,108,67,105,114,99,108,101,59,1,8728,112,102,59,3,55349,56650,4,2,114,117,5289,5293,116,59,1,8730,97,114,101,4,4,59,73,83,85,5306,5308,5322,5367,1,9633,110,116,101,114,115,101,99,116,105,111,110,59,1,8851,117,4,2,98,112,5329,5347,115,101,116,4,2,59,69,5338,5340,1,8847,113,117,97,108,59,1,8849,101,114,115,101,116,4,2,59,69,5358,5360,1,8848,113,117,97,108,59,1,8850,110,105,111,110,59,1,8852,99,114,59,3,55349,56494,97,114,59,1,8902,4,4,98,99,109,112,5395,5420,5475,5478,4,2,59,115,5401,5403,1,8912,101,116,4,2,59,69,5411,5413,1,8912,113,117,97,108,59,1,8838,4,2,99,104,5426,5468,101,101,100,115,4,4,59,69,83,84,5440,5442,5449,5461,1,8827,113,117,97,108,59,1,10928,108,97,110,116,69,113,117,97,108,59,1,8829,105,108,100,101,59,1,8831,84,104,97,116,59,1,8715,59,1,8721,4,3,59,101,115,5486,5488,5507,1,8913,114,115,101,116,4,2,59,69,5498,5500,1,8835,113,117,97,108,59,1,8839,101,116,59,1,8913,4,11,72,82,83,97,99,102,104,105,111,114,115,5536,5546,5552,5567,5579,5602,5607,5655,5695,5701,5711,79,82,78,5,222,1,59,5544,1,222,65,68,69,59,1,8482,4,2,72,99,5558,5563,99,121,59,1,1035,121,59,1,1062,4,2,98,117,5573,5576,59,1,9,59,1,932,4,3,97,101,121,5587,5593,5599,114,111,110,59,1,356,100,105,108,59,1,354,59,1,1058,114,59,3,55349,56599,4,2,101,105,5613,5631,4,2,114,116,5619,5627,101,102,111,114,101,59,1,8756,97,59,1,920,4,2,99,110,5637,5647,107,83,112,97,99,101,59,3,8287,8202,83,112,97,99,101,59,1,8201,108,100,101,4,4,59,69,70,84,5668,5670,5677,5688,1,8764,113,117,97,108,59,1,8771,117,108,108,69,113,117,97,108,59,1,8773,105,108,100,101,59,1,8776,112,102,59,3,55349,56651,105,112,108,101,68,111,116,59,1,8411,4,2,99,116,5717,5722,114,59,3,55349,56495,114,111,107,59,1,358,4,14,97,98,99,100,102,103,109,110,111,112,114,115,116,117,5758,5789,5805,5823,5830,5835,5846,5852,5921,5937,6089,6095,6101,6108,4,2,99,114,5764,5774,117,116,101,5,218,1,59,5772,1,218,114,4,2,59,111,5781,5783,1,8607,99,105,114,59,1,10569,114,4,2,99,101,5796,5800,121,59,1,1038,118,101,59,1,364,4,2,105,121,5811,5820,114,99,5,219,1,59,5818,1,219,59,1,1059,98,108,97,99,59,1,368,114,59,3,55349,56600,114,97,118,101,5,217,1,59,5844,1,217,97,99,114,59,1,362,4,2,100,105,5858,5905,101,114,4,2,66,80,5866,5892,4,2,97,114,5872,5876,114,59,1,95,97,99,4,2,101,107,5884,5887,59,1,9183,101,116,59,1,9141,97,114,101,110,116,104,101,115,105,115,59,1,9181,111,110,4,2,59,80,5913,5915,1,8899,108,117,115,59,1,8846,4,2,103,112,5927,5932,111,110,59,1,370,102,59,3,55349,56652,4,8,65,68,69,84,97,100,112,115,5955,5985,5996,6009,6026,6033,6044,6075,114,114,111,119,4,3,59,66,68,5967,5969,5974,1,8593,97,114,59,1,10514,111,119,110,65,114,114,111,119,59,1,8645,111,119,110,65,114,114,111,119,59,1,8597,113,117,105,108,105,98,114,105,117,109,59,1,10606,101,101,4,2,59,65,6017,6019,1,8869,114,114,111,119,59,1,8613,114,114,111,119,59,1,8657,111,119,110,97,114,114,111,119,59,1,8661,101,114,4,2,76,82,6052,6063,101,102,116,65,114,114,111,119,59,1,8598,105,103,104,116,65,114,114,111,119,59,1,8599,105,4,2,59,108,6082,6084,1,978,111,110,59,1,933,105,110,103,59,1,366,99,114,59,3,55349,56496,105,108,100,101,59,1,360,109,108,5,220,1,59,6115,1,220,4,9,68,98,99,100,101,102,111,115,118,6137,6143,6148,6152,6166,6250,6255,6261,6267,97,115,104,59,1,8875,97,114,59,1,10987,121,59,1,1042,97,115,104,4,2,59,108,6161,6163,1,8873,59,1,10982,4,2,101,114,6172,6175,59,1,8897,4,3,98,116,121,6183,6188,6238,97,114,59,1,8214,4,2,59,105,6194,6196,1,8214,99,97,108,4,4,66,76,83,84,6209,6214,6220,6231,97,114,59,1,8739,105,110,101,59,1,124,101,112,97,114,97,116,111,114,59,1,10072,105,108,100,101,59,1,8768,84,104,105,110,83,112,97,99,101,59,1,8202,114,59,3,55349,56601,112,102,59,3,55349,56653,99,114,59,3,55349,56497,100,97,115,104,59,1,8874,4,5,99,101,102,111,115,6286,6292,6298,6303,6309,105,114,99,59,1,372,100,103,101,59,1,8896,114,59,3,55349,56602,112,102,59,3,55349,56654,99,114,59,3,55349,56498,4,4,102,105,111,115,6325,6330,6333,6339,114,59,3,55349,56603,59,1,926,112,102,59,3,55349,56655,99,114,59,3,55349,56499,4,9,65,73,85,97,99,102,111,115,117,6365,6370,6375,6380,6391,6405,6410,6416,6422,99,121,59,1,1071,99,121,59,1,1031,99,121,59,1,1070,99,117,116,101,5,221,1,59,6389,1,221,4,2,105,121,6397,6402,114,99,59,1,374,59,1,1067,114,59,3,55349,56604,112,102,59,3,55349,56656,99,114,59,3,55349,56500,109,108,59,1,376,4,8,72,97,99,100,101,102,111,115,6445,6450,6457,6472,6477,6501,6505,6510,99,121,59,1,1046,99,117,116,101,59,1,377,4,2,97,121,6463,6469,114,111,110,59,1,381,59,1,1047,111,116,59,1,379,4,2,114,116,6483,6497,111,87,105,100,116,104,83,112,97,99,101,59,1,8203,97,59,1,918,114,59,1,8488,112,102,59,1,8484,99,114,59,3,55349,56501,4,16,97,98,99,101,102,103,108,109,110,111,112,114,115,116,117,119,6550,6561,6568,6612,6622,6634,6645,6672,6699,6854,6870,6923,6933,6963,6974,6983,99,117,116,101,5,225,1,59,6559,1,225,114,101,118,101,59,1,259,4,6,59,69,100,105,117,121,6582,6584,6588,6591,6600,6609,1,8766,59,3,8766,819,59,1,8767,114,99,5,226,1,59,6598,1,226,116,101,5,180,1,59,6607,1,180,59,1,1072,108,105,103,5,230,1,59,6620,1,230,4,2,59,114,6628,6630,1,8289,59,3,55349,56606,114,97,118,101,5,224,1,59,6643,1,224,4,2,101,112,6651,6667,4,2,102,112,6657,6663,115,121,109,59,1,8501,104,59,1,8501,104,97,59,1,945,4,2,97,112,6678,6692,4,2,99,108,6684,6688,114,59,1,257,103,59,1,10815,5,38,1,59,6697,1,38,4,2,100,103,6705,6737,4,5,59,97,100,115,118,6717,6719,6724,6727,6734,1,8743,110,100,59,1,10837,59,1,10844,108,111,112,101,59,1,10840,59,1,10842,4,7,59,101,108,109,114,115,122,6753,6755,6758,6762,6814,6835,6848,1,8736,59,1,10660,101,59,1,8736,115,100,4,2,59,97,6770,6772,1,8737,4,8,97,98,99,100,101,102,103,104,6790,6793,6796,6799,6802,6805,6808,6811,59,1,10664,59,1,10665,59,1,10666,59,1,10667,59,1,10668,59,1,10669,59,1,10670,59,1,10671,116,4,2,59,118,6821,6823,1,8735,98,4,2,59,100,6830,6832,1,8894,59,1,10653,4,2,112,116,6841,6845,104,59,1,8738,59,1,197,97,114,114,59,1,9084,4,2,103,112,6860,6865,111,110,59,1,261,102,59,3,55349,56658,4,7,59,69,97,101,105,111,112,6886,6888,6891,6897,6900,6904,6908,1,8776,59,1,10864,99,105,114,59,1,10863,59,1,8778,100,59,1,8779,115,59,1,39,114,111,120,4,2,59,101,6917,6919,1,8776,113,59,1,8778,105,110,103,5,229,1,59,6931,1,229,4,3,99,116,121,6941,6946,6949,114,59,3,55349,56502,59,1,42,109,112,4,2,59,101,6957,6959,1,8776,113,59,1,8781,105,108,100,101,5,227,1,59,6972,1,227,109,108,5,228,1,59,6981,1,228,4,2,99,105,6989,6997,111,110,105,110,116,59,1,8755,110,116,59,1,10769,4,16,78,97,98,99,100,101,102,105,107,108,110,111,112,114,115,117,7036,7041,7119,7135,7149,7155,7219,7224,7347,7354,7463,7489,7786,7793,7814,7866,111,116,59,1,10989,4,2,99,114,7047,7094,107,4,4,99,101,112,115,7058,7064,7073,7080,111,110,103,59,1,8780,112,115,105,108,111,110,59,1,1014,114,105,109,101,59,1,8245,105,109,4,2,59,101,7088,7090,1,8765,113,59,1,8909,4,2,118,119,7100,7105,101,101,59,1,8893,101,100,4,2,59,103,7113,7115,1,8965,101,59,1,8965,114,107,4,2,59,116,7127,7129,1,9141,98,114,107,59,1,9142,4,2,111,121,7141,7146,110,103,59,1,8780,59,1,1073,113,117,111,59,1,8222,4,5,99,109,112,114,116,7167,7181,7188,7193,7199,97,117,115,4,2,59,101,7176,7178,1,8757,59,1,8757,112,116,121,118,59,1,10672,115,105,59,1,1014,110,111,117,59,1,8492,4,3,97,104,119,7207,7210,7213,59,1,946,59,1,8502,101,101,110,59,1,8812,114,59,3,55349,56607,103,4,7,99,111,115,116,117,118,119,7241,7262,7288,7305,7328,7335,7340,4,3,97,105,117,7249,7253,7258,112,59,1,8898,114,99,59,1,9711,112,59,1,8899,4,3,100,112,116,7270,7275,7281,111,116,59,1,10752,108,117,115,59,1,10753,105,109,101,115,59,1,10754,4,2,113,116,7294,7300,99,117,112,59,1,10758,97,114,59,1,9733,114,105,97,110,103,108,101,4,2,100,117,7318,7324,111,119,110,59,1,9661,112,59,1,9651,112,108,117,115,59,1,10756,101,101,59,1,8897,101,100,103,101,59,1,8896,97,114,111,119,59,1,10509,4,3,97,107,111,7362,7436,7458,4,2,99,110,7368,7432,107,4,3,108,115,116,7377,7386,7394,111,122,101,110,103,101,59,1,10731,113,117,97,114,101,59,1,9642,114,105,97,110,103,108,101,4,4,59,100,108,114,7411,7413,7419,7425,1,9652,111,119,110,59,1,9662,101,102,116,59,1,9666,105,103,104,116,59,1,9656,107,59,1,9251,4,2,49,51,7442,7454,4,2,50,52,7448,7451,59,1,9618,59,1,9617,52,59,1,9619,99,107,59,1,9608,4,2,101,111,7469,7485,4,2,59,113,7475,7478,3,61,8421,117,105,118,59,3,8801,8421,116,59,1,8976,4,4,112,116,119,120,7499,7504,7517,7523,102,59,3,55349,56659,4,2,59,116,7510,7512,1,8869,111,109,59,1,8869,116,105,101,59,1,8904,4,12,68,72,85,86,98,100,104,109,112,116,117,118,7549,7571,7597,7619,7655,7660,7682,7708,7715,7721,7728,7750,4,4,76,82,108,114,7559,7562,7565,7568,59,1,9559,59,1,9556,59,1,9558,59,1,9555,4,5,59,68,85,100,117,7583,7585,7588,7591,7594,1,9552,59,1,9574,59,1,9577,59,1,9572,59,1,9575,4,4,76,82,108,114,7607,7610,7613,7616,59,1,9565,59,1,9562,59,1,9564,59,1,9561,4,7,59,72,76,82,104,108,114,7635,7637,7640,7643,7646,7649,7652,1,9553,59,1,9580,59,1,9571,59,1,9568,59,1,9579,59,1,9570,59,1,9567,111,120,59,1,10697,4,4,76,82,108,114,7670,7673,7676,7679,59,1,9557,59,1,9554,59,1,9488,59,1,9484,4,5,59,68,85,100,117,7694,7696,7699,7702,7705,1,9472,59,1,9573,59,1,9576,59,1,9516,59,1,9524,105,110,117,115,59,1,8863,108,117,115,59,1,8862,105,109,101,115,59,1,8864,4,4,76,82,108,114,7738,7741,7744,7747,59,1,9563,59,1,9560,59,1,9496,59,1,9492,4,7,59,72,76,82,104,108,114,7766,7768,7771,7774,7777,7780,7783,1,9474,59,1,9578,59,1,9569,59,1,9566,59,1,9532,59,1,9508,59,1,9500,114,105,109,101,59,1,8245,4,2,101,118,7799,7804,118,101,59,1,728,98,97,114,5,166,1,59,7812,1,166,4,4,99,101,105,111,7824,7829,7834,7846,114,59,3,55349,56503,109,105,59,1,8271,109,4,2,59,101,7841,7843,1,8765,59,1,8909,108,4,3,59,98,104,7855,7857,7860,1,92,59,1,10693,115,117,98,59,1,10184,4,2,108,109,7872,7885,108,4,2,59,101,7879,7881,1,8226,116,59,1,8226,112,4,3,59,69,101,7894,7896,7899,1,8782,59,1,10926,4,2,59,113,7905,7907,1,8783,59,1,8783,4,15,97,99,100,101,102,104,105,108,111,114,115,116,117,119,121,7942,8021,8075,8080,8121,8126,8157,8279,8295,8430,8446,8485,8491,8707,8726,4,3,99,112,114,7950,7956,8007,117,116,101,59,1,263,4,6,59,97,98,99,100,115,7970,7972,7977,7984,7998,8003,1,8745,110,100,59,1,10820,114,99,117,112,59,1,10825,4,2,97,117,7990,7994,112,59,1,10827,112,59,1,10823,111,116,59,1,10816,59,3,8745,65024,4,2,101,111,8013,8017,116,59,1,8257,110,59,1,711,4,4,97,101,105,117,8031,8046,8056,8061,4,2,112,114,8037,8041,115,59,1,10829,111,110,59,1,269,100,105,108,5,231,1,59,8054,1,231,114,99,59,1,265,112,115,4,2,59,115,8069,8071,1,10828,109,59,1,10832,111,116,59,1,267,4,3,100,109,110,8088,8097,8104,105,108,5,184,1,59,8095,1,184,112,116,121,118,59,1,10674,116,5,162,2,59,101,8112,8114,1,162,114,100,111,116,59,1,183,114,59,3,55349,56608,4,3,99,101,105,8134,8138,8154,121,59,1,1095,99,107,4,2,59,109,8146,8148,1,10003,97,114,107,59,1,10003,59,1,967,114,4,7,59,69,99,101,102,109,115,8174,8176,8179,8258,8261,8268,8273,1,9675,59,1,10691,4,3,59,101,108,8187,8189,8193,1,710,113,59,1,8791,101,4,2,97,100,8200,8223,114,114,111,119,4,2,108,114,8210,8216,101,102,116,59,1,8634,105,103,104,116,59,1,8635,4,5,82,83,97,99,100,8235,8238,8241,8246,8252,59,1,174,59,1,9416,115,116,59,1,8859,105,114,99,59,1,8858,97,115,104,59,1,8861,59,1,8791,110,105,110,116,59,1,10768,105,100,59,1,10991,99,105,114,59,1,10690,117,98,115,4,2,59,117,8288,8290,1,9827,105,116,59,1,9827,4,4,108,109,110,112,8305,8326,8376,8400,111,110,4,2,59,101,8313,8315,1,58,4,2,59,113,8321,8323,1,8788,59,1,8788,4,2,109,112,8332,8344,97,4,2,59,116,8339,8341,1,44,59,1,64,4,3,59,102,108,8352,8354,8358,1,8705,110,59,1,8728,101,4,2,109,120,8365,8371,101,110,116,59,1,8705,101,115,59,1,8450,4,2,103,105,8382,8395,4,2,59,100,8388,8390,1,8773,111,116,59,1,10861,110,116,59,1,8750,4,3,102,114,121,8408,8412,8417,59,3,55349,56660,111,100,59,1,8720,5,169,2,59,115,8424,8426,1,169,114,59,1,8471,4,2,97,111,8436,8441,114,114,59,1,8629,115,115,59,1,10007,4,2,99,117,8452,8457,114,59,3,55349,56504,4,2,98,112,8463,8474,4,2,59,101,8469,8471,1,10959,59,1,10961,4,2,59,101,8480,8482,1,10960,59,1,10962,100,111,116,59,1,8943,4,7,100,101,108,112,114,118,119,8507,8522,8536,8550,8600,8697,8702,97,114,114,4,2,108,114,8516,8519,59,1,10552,59,1,10549,4,2,112,115,8528,8532,114,59,1,8926,99,59,1,8927,97,114,114,4,2,59,112,8545,8547,1,8630,59,1,10557,4,6,59,98,99,100,111,115,8564,8566,8573,8587,8592,8596,1,8746,114,99,97,112,59,1,10824,4,2,97,117,8579,8583,112,59,1,10822,112,59,1,10826,111,116,59,1,8845,114,59,1,10821,59,3,8746,65024,4,4,97,108,114,118,8610,8623,8663,8672,114,114,4,2,59,109,8618,8620,1,8631,59,1,10556,121,4,3,101,118,119,8632,8651,8656,113,4,2,112,115,8639,8645,114,101,99,59,1,8926,117,99,99,59,1,8927,101,101,59,1,8910,101,100,103,101,59,1,8911,101,110,5,164,1,59,8670,1,164,101,97,114,114,111,119,4,2,108,114,8684,8690,101,102,116,59,1,8630,105,103,104,116,59,1,8631,101,101,59,1,8910,101,100,59,1,8911,4,2,99,105,8713,8721,111,110,105,110,116,59,1,8754,110,116,59,1,8753,108,99,116,121,59,1,9005,4,19,65,72,97,98,99,100,101,102,104,105,106,108,111,114,115,116,117,119,122,8773,8778,8783,8821,8839,8854,8887,8914,8930,8944,9036,9041,9058,9197,9227,9258,9281,9297,9305,114,114,59,1,8659,97,114,59,1,10597,4,4,103,108,114,115,8793,8799,8805,8809,103,101,114,59,1,8224,101,116,104,59,1,8504,114,59,1,8595,104,4,2,59,118,8816,8818,1,8208,59,1,8867,4,2,107,108,8827,8834,97,114,111,119,59,1,10511,97,99,59,1,733,4,2,97,121,8845,8851,114,111,110,59,1,271,59,1,1076,4,3,59,97,111,8862,8864,8880,1,8518,4,2,103,114,8870,8876,103,101,114,59,1,8225,114,59,1,8650,116,115,101,113,59,1,10871,4,3,103,108,109,8895,8902,8907,5,176,1,59,8900,1,176,116,97,59,1,948,112,116,121,118,59,1,10673,4,2,105,114,8920,8926,115,104,116,59,1,10623,59,3,55349,56609,97,114,4,2,108,114,8938,8941,59,1,8643,59,1,8642,4,5,97,101,103,115,118,8956,8986,8989,8996,9001,109,4,3,59,111,115,8965,8967,8983,1,8900,110,100,4,2,59,115,8975,8977,1,8900,117,105,116,59,1,9830,59,1,9830,59,1,168,97,109,109,97,59,1,989,105,110,59,1,8946,4,3,59,105,111,9009,9011,9031,1,247,100,101,5,247,2,59,111,9020,9022,1,247,110,116,105,109,101,115,59,1,8903,110,120,59,1,8903,99,121,59,1,1106,99,4,2,111,114,9048,9053,114,110,59,1,8990,111,112,59,1,8973,4,5,108,112,116,117,119,9070,9076,9081,9130,9144,108,97,114,59,1,36,102,59,3,55349,56661,4,5,59,101,109,112,115,9093,9095,9109,9116,9122,1,729,113,4,2,59,100,9102,9104,1,8784,111,116,59,1,8785,105,110,117,115,59,1,8760,108,117,115,59,1,8724,113,117,97,114,101,59,1,8865,98,108,101,98,97,114,119,101,100,103,101,59,1,8966,110,4,3,97,100,104,9153,9160,9172,114,114,111,119,59,1,8595,111,119,110,97,114,114,111,119,115,59,1,8650,97,114,112,111,111,110,4,2,108,114,9184,9190,101,102,116,59,1,8643,105,103,104,116,59,1,8642,4,2,98,99,9203,9211,107,97,114,111,119,59,1,10512,4,2,111,114,9217,9222,114,110,59,1,8991,111,112,59,1,8972,4,3,99,111,116,9235,9248,9252,4,2,114,121,9241,9245,59,3,55349,56505,59,1,1109,108,59,1,10742,114,111,107,59,1,273,4,2,100,114,9264,9269,111,116,59,1,8945,105,4,2,59,102,9276,9278,1,9663,59,1,9662,4,2,97,104,9287,9292,114,114,59,1,8693,97,114,59,1,10607,97,110,103,108,101,59,1,10662,4,2,99,105,9311,9315,121,59,1,1119,103,114,97,114,114,59,1,10239,4,18,68,97,99,100,101,102,103,108,109,110,111,112,113,114,115,116,117,120,9361,9376,9398,9439,9444,9447,9462,9495,9531,9585,9598,9614,9659,9755,9771,9792,9808,9826,4,2,68,111,9367,9372,111,116,59,1,10871,116,59,1,8785,4,2,99,115,9382,9392,117,116,101,5,233,1,59,9390,1,233,116,101,114,59,1,10862,4,4,97,105,111,121,9408,9414,9430,9436,114,111,110,59,1,283,114,4,2,59,99,9421,9423,1,8790,5,234,1,59,9428,1,234,108,111,110,59,1,8789,59,1,1101,111,116,59,1,279,59,1,8519,4,2,68,114,9453,9458,111,116,59,1,8786,59,3,55349,56610,4,3,59,114,115,9470,9472,9482,1,10906,97,118,101,5,232,1,59,9480,1,232,4,2,59,100,9488,9490,1,10902,111,116,59,1,10904,4,4,59,105,108,115,9505,9507,9515,9518,1,10905,110,116,101,114,115,59,1,9191,59,1,8467,4,2,59,100,9524,9526,1,10901,111,116,59,1,10903,4,3,97,112,115,9539,9544,9564,99,114,59,1,275,116,121,4,3,59,115,118,9554,9556,9561,1,8709,101,116,59,1,8709,59,1,8709,112,4,2,49,59,9571,9583,4,2,51,52,9577,9580,59,1,8196,59,1,8197,1,8195,4,2,103,115,9591,9594,59,1,331,112,59,1,8194,4,2,103,112,9604,9609,111,110,59,1,281,102,59,3,55349,56662,4,3,97,108,115,9622,9635,9640,114,4,2,59,115,9629,9631,1,8917,108,59,1,10723,117,115,59,1,10865,105,4,3,59,108,118,9649,9651,9656,1,949,111,110,59,1,949,59,1,1013,4,4,99,115,117,118,9669,9686,9716,9747,4,2,105,111,9675,9680,114,99,59,1,8790,108,111,110,59,1,8789,4,2,105,108,9692,9696,109,59,1,8770,97,110,116,4,2,103,108,9705,9710,116,114,59,1,10902,101,115,115,59,1,10901,4,3,97,101,105,9724,9729,9734,108,115,59,1,61,115,116,59,1,8799,118,4,2,59,68,9741,9743,1,8801,68,59,1,10872,112,97,114,115,108,59,1,10725,4,2,68,97,9761,9766,111,116,59,1,8787,114,114,59,1,10609,4,3,99,100,105,9779,9783,9788,114,59,1,8495,111,116,59,1,8784,109,59,1,8770,4,2,97,104,9798,9801,59,1,951,5,240,1,59,9806,1,240,4,2,109,114,9814,9822,108,5,235,1,59,9820,1,235,111,59,1,8364,4,3,99,105,112,9834,9838,9843,108,59,1,33,115,116,59,1,8707,4,2,101,111,9849,9859,99,116,97,116,105,111,110,59,1,8496,110,101,110,116,105,97,108,101,59,1,8519,4,12,97,99,101,102,105,106,108,110,111,112,114,115,9896,9910,9914,9921,9954,9960,9967,9989,9994,10027,10036,10164,108,108,105,110,103,100,111,116,115,101,113,59,1,8786,121,59,1,1092,109,97,108,101,59,1,9792,4,3,105,108,114,9929,9935,9950,108,105,103,59,1,64259,4,2,105,108,9941,9945,103,59,1,64256,105,103,59,1,64260,59,3,55349,56611,108,105,103,59,1,64257,108,105,103,59,3,102,106,4,3,97,108,116,9975,9979,9984,116,59,1,9837,105,103,59,1,64258,110,115,59,1,9649,111,102,59,1,402,4,2,112,114,1e4,10005,102,59,3,55349,56663,4,2,97,107,10011,10016,108,108,59,1,8704,4,2,59,118,10022,10024,1,8916,59,1,10969,97,114,116,105,110,116,59,1,10765,4,2,97,111,10042,10159,4,2,99,115,10048,10155,4,6,49,50,51,52,53,55,10062,10102,10114,10135,10139,10151,4,6,50,51,52,53,54,56,10076,10083,10086,10093,10096,10099,5,189,1,59,10081,1,189,59,1,8531,5,188,1,59,10091,1,188,59,1,8533,59,1,8537,59,1,8539,4,2,51,53,10108,10111,59,1,8532,59,1,8534,4,3,52,53,56,10122,10129,10132,5,190,1,59,10127,1,190,59,1,8535,59,1,8540,53,59,1,8536,4,2,54,56,10145,10148,59,1,8538,59,1,8541,56,59,1,8542,108,59,1,8260,119,110,59,1,8994,99,114,59,3,55349,56507,4,17,69,97,98,99,100,101,102,103,105,106,108,110,111,114,115,116,118,10206,10217,10247,10254,10268,10273,10358,10363,10374,10380,10385,10406,10458,10464,10470,10497,10610,4,2,59,108,10212,10214,1,8807,59,1,10892,4,3,99,109,112,10225,10231,10244,117,116,101,59,1,501,109,97,4,2,59,100,10239,10241,1,947,59,1,989,59,1,10886,114,101,118,101,59,1,287,4,2,105,121,10260,10265,114,99,59,1,285,59,1,1075,111,116,59,1,289,4,4,59,108,113,115,10283,10285,10288,10308,1,8805,59,1,8923,4,3,59,113,115,10296,10298,10301,1,8805,59,1,8807,108,97,110,116,59,1,10878,4,4,59,99,100,108,10318,10320,10324,10345,1,10878,99,59,1,10921,111,116,4,2,59,111,10332,10334,1,10880,4,2,59,108,10340,10342,1,10882,59,1,10884,4,2,59,101,10351,10354,3,8923,65024,115,59,1,10900,114,59,3,55349,56612,4,2,59,103,10369,10371,1,8811,59,1,8921,109,101,108,59,1,8503,99,121,59,1,1107,4,4,59,69,97,106,10395,10397,10400,10403,1,8823,59,1,10898,59,1,10917,59,1,10916,4,4,69,97,101,115,10416,10419,10434,10453,59,1,8809,112,4,2,59,112,10426,10428,1,10890,114,111,120,59,1,10890,4,2,59,113,10440,10442,1,10888,4,2,59,113,10448,10450,1,10888,59,1,8809,105,109,59,1,8935,112,102,59,3,55349,56664,97,118,101,59,1,96,4,2,99,105,10476,10480,114,59,1,8458,109,4,3,59,101,108,10489,10491,10494,1,8819,59,1,10894,59,1,10896,5,62,6,59,99,100,108,113,114,10512,10514,10527,10532,10538,10545,1,62,4,2,99,105,10520,10523,59,1,10919,114,59,1,10874,111,116,59,1,8919,80,97,114,59,1,10645,117,101,115,116,59,1,10876,4,5,97,100,101,108,115,10557,10574,10579,10599,10605,4,2,112,114,10563,10570,112,114,111,120,59,1,10886,114,59,1,10616,111,116,59,1,8919,113,4,2,108,113,10586,10592,101,115,115,59,1,8923,108,101,115,115,59,1,10892,101,115,115,59,1,8823,105,109,59,1,8819,4,2,101,110,10616,10626,114,116,110,101,113,113,59,3,8809,65024,69,59,3,8809,65024,4,10,65,97,98,99,101,102,107,111,115,121,10653,10658,10713,10718,10724,10760,10765,10786,10850,10875,114,114,59,1,8660,4,4,105,108,109,114,10668,10674,10678,10684,114,115,112,59,1,8202,102,59,1,189,105,108,116,59,1,8459,4,2,100,114,10690,10695,99,121,59,1,1098,4,3,59,99,119,10703,10705,10710,1,8596,105,114,59,1,10568,59,1,8621,97,114,59,1,8463,105,114,99,59,1,293,4,3,97,108,114,10732,10748,10754,114,116,115,4,2,59,117,10741,10743,1,9829,105,116,59,1,9829,108,105,112,59,1,8230,99,111,110,59,1,8889,114,59,3,55349,56613,115,4,2,101,119,10772,10779,97,114,111,119,59,1,10533,97,114,111,119,59,1,10534,4,5,97,109,111,112,114,10798,10803,10809,10839,10844,114,114,59,1,8703,116,104,116,59,1,8763,107,4,2,108,114,10816,10827,101,102,116,97,114,114,111,119,59,1,8617,105,103,104,116,97,114,114,111,119,59,1,8618,102,59,3,55349,56665,98,97,114,59,1,8213,4,3,99,108,116,10858,10863,10869,114,59,3,55349,56509,97,115,104,59,1,8463,114,111,107,59,1,295,4,2,98,112,10881,10887,117,108,108,59,1,8259,104,101,110,59,1,8208,4,15,97,99,101,102,103,105,106,109,110,111,112,113,115,116,117,10925,10936,10958,10977,10990,11001,11039,11045,11101,11192,11220,11226,11237,11285,11299,99,117,116,101,5,237,1,59,10934,1,237,4,3,59,105,121,10944,10946,10955,1,8291,114,99,5,238,1,59,10953,1,238,59,1,1080,4,2,99,120,10964,10968,121,59,1,1077,99,108,5,161,1,59,10975,1,161,4,2,102,114,10983,10986,59,1,8660,59,3,55349,56614,114,97,118,101,5,236,1,59,10999,1,236,4,4,59,105,110,111,11011,11013,11028,11034,1,8520,4,2,105,110,11019,11024,110,116,59,1,10764,116,59,1,8749,102,105,110,59,1,10716,116,97,59,1,8489,108,105,103,59,1,307,4,3,97,111,112,11053,11092,11096,4,3,99,103,116,11061,11065,11088,114,59,1,299,4,3,101,108,112,11073,11076,11082,59,1,8465,105,110,101,59,1,8464,97,114,116,59,1,8465,104,59,1,305,102,59,1,8887,101,100,59,1,437,4,5,59,99,102,111,116,11113,11115,11121,11136,11142,1,8712,97,114,101,59,1,8453,105,110,4,2,59,116,11129,11131,1,8734,105,101,59,1,10717,100,111,116,59,1,305,4,5,59,99,101,108,112,11154,11156,11161,11179,11186,1,8747,97,108,59,1,8890,4,2,103,114,11167,11173,101,114,115,59,1,8484,99,97,108,59,1,8890,97,114,104,107,59,1,10775,114,111,100,59,1,10812,4,4,99,103,112,116,11202,11206,11211,11216,121,59,1,1105,111,110,59,1,303,102,59,3,55349,56666,97,59,1,953,114,111,100,59,1,10812,117,101,115,116,5,191,1,59,11235,1,191,4,2,99,105,11243,11248,114,59,3,55349,56510,110,4,5,59,69,100,115,118,11261,11263,11266,11271,11282,1,8712,59,1,8953,111,116,59,1,8949,4,2,59,118,11277,11279,1,8948,59,1,8947,59,1,8712,4,2,59,105,11291,11293,1,8290,108,100,101,59,1,297,4,2,107,109,11305,11310,99,121,59,1,1110,108,5,239,1,59,11316,1,239,4,6,99,102,109,111,115,117,11332,11346,11351,11357,11363,11380,4,2,105,121,11338,11343,114,99,59,1,309,59,1,1081,114,59,3,55349,56615,97,116,104,59,1,567,112,102,59,3,55349,56667,4,2,99,101,11369,11374,114,59,3,55349,56511,114,99,121,59,1,1112,107,99,121,59,1,1108,4,8,97,99,102,103,104,106,111,115,11404,11418,11433,11438,11445,11450,11455,11461,112,112,97,4,2,59,118,11413,11415,1,954,59,1,1008,4,2,101,121,11424,11430,100,105,108,59,1,311,59,1,1082,114,59,3,55349,56616,114,101,101,110,59,1,312,99,121,59,1,1093,99,121,59,1,1116,112,102,59,3,55349,56668,99,114,59,3,55349,56512,4,23,65,66,69,72,97,98,99,100,101,102,103,104,106,108,109,110,111,112,114,115,116,117,118,11515,11538,11544,11555,11560,11721,11780,11818,11868,12136,12160,12171,12203,12208,12246,12275,12327,12509,12523,12569,12641,12732,12752,4,3,97,114,116,11523,11528,11532,114,114,59,1,8666,114,59,1,8656,97,105,108,59,1,10523,97,114,114,59,1,10510,4,2,59,103,11550,11552,1,8806,59,1,10891,97,114,59,1,10594,4,9,99,101,103,109,110,112,113,114,116,11580,11586,11594,11600,11606,11624,11627,11636,11694,117,116,101,59,1,314,109,112,116,121,118,59,1,10676,114,97,110,59,1,8466,98,100,97,59,1,955,103,4,3,59,100,108,11615,11617,11620,1,10216,59,1,10641,101,59,1,10216,59,1,10885,117,111,5,171,1,59,11634,1,171,114,4,8,59,98,102,104,108,112,115,116,11655,11657,11669,11673,11677,11681,11685,11690,1,8592,4,2,59,102,11663,11665,1,8676,115,59,1,10527,115,59,1,10525,107,59,1,8617,112,59,1,8619,108,59,1,10553,105,109,59,1,10611,108,59,1,8610,4,3,59,97,101,11702,11704,11709,1,10923,105,108,59,1,10521,4,2,59,115,11715,11717,1,10925,59,3,10925,65024,4,3,97,98,114,11729,11734,11739,114,114,59,1,10508,114,107,59,1,10098,4,2,97,107,11745,11758,99,4,2,101,107,11752,11755,59,1,123,59,1,91,4,2,101,115,11764,11767,59,1,10635,108,4,2,100,117,11774,11777,59,1,10639,59,1,10637,4,4,97,101,117,121,11790,11796,11811,11815,114,111,110,59,1,318,4,2,100,105,11802,11807,105,108,59,1,316,108,59,1,8968,98,59,1,123,59,1,1083,4,4,99,113,114,115,11828,11832,11845,11864,97,59,1,10550,117,111,4,2,59,114,11840,11842,1,8220,59,1,8222,4,2,100,117,11851,11857,104,97,114,59,1,10599,115,104,97,114,59,1,10571,104,59,1,8626,4,5,59,102,103,113,115,11880,11882,12008,12011,12031,1,8804,116,4,5,97,104,108,114,116,11895,11913,11935,11947,11996,114,114,111,119,4,2,59,116,11905,11907,1,8592,97,105,108,59,1,8610,97,114,112,111,111,110,4,2,100,117,11925,11931,111,119,110,59,1,8637,112,59,1,8636,101,102,116,97,114,114,111,119,115,59,1,8647,105,103,104,116,4,3,97,104,115,11959,11974,11984,114,114,111,119,4,2,59,115,11969,11971,1,8596,59,1,8646,97,114,112,111,111,110,115,59,1,8651,113,117,105,103,97,114,114,111,119,59,1,8621,104,114,101,101,116,105,109,101,115,59,1,8907,59,1,8922,4,3,59,113,115,12019,12021,12024,1,8804,59,1,8806,108,97,110,116,59,1,10877,4,5,59,99,100,103,115,12043,12045,12049,12070,12083,1,10877,99,59,1,10920,111,116,4,2,59,111,12057,12059,1,10879,4,2,59,114,12065,12067,1,10881,59,1,10883,4,2,59,101,12076,12079,3,8922,65024,115,59,1,10899,4,5,97,100,101,103,115,12095,12103,12108,12126,12131,112,112,114,111,120,59,1,10885,111,116,59,1,8918,113,4,2,103,113,12115,12120,116,114,59,1,8922,103,116,114,59,1,10891,116,114,59,1,8822,105,109,59,1,8818,4,3,105,108,114,12144,12150,12156,115,104,116,59,1,10620,111,111,114,59,1,8970,59,3,55349,56617,4,2,59,69,12166,12168,1,8822,59,1,10897,4,2,97,98,12177,12198,114,4,2,100,117,12184,12187,59,1,8637,4,2,59,108,12193,12195,1,8636,59,1,10602,108,107,59,1,9604,99,121,59,1,1113,4,5,59,97,99,104,116,12220,12222,12227,12235,12241,1,8810,114,114,59,1,8647,111,114,110,101,114,59,1,8990,97,114,100,59,1,10603,114,105,59,1,9722,4,2,105,111,12252,12258,100,111,116,59,1,320,117,115,116,4,2,59,97,12267,12269,1,9136,99,104,101,59,1,9136,4,4,69,97,101,115,12285,12288,12303,12322,59,1,8808,112,4,2,59,112,12295,12297,1,10889,114,111,120,59,1,10889,4,2,59,113,12309,12311,1,10887,4,2,59,113,12317,12319,1,10887,59,1,8808,105,109,59,1,8934,4,8,97,98,110,111,112,116,119,122,12345,12359,12364,12421,12446,12467,12474,12490,4,2,110,114,12351,12355,103,59,1,10220,114,59,1,8701,114,107,59,1,10214,103,4,3,108,109,114,12373,12401,12409,101,102,116,4,2,97,114,12382,12389,114,114,111,119,59,1,10229,105,103,104,116,97,114,114,111,119,59,1,10231,97,112,115,116,111,59,1,10236,105,103,104,116,97,114,114,111,119,59,1,10230,112,97,114,114,111,119,4,2,108,114,12433,12439,101,102,116,59,1,8619,105,103,104,116,59,1,8620,4,3,97,102,108,12454,12458,12462,114,59,1,10629,59,3,55349,56669,117,115,59,1,10797,105,109,101,115,59,1,10804,4,2,97,98,12480,12485,115,116,59,1,8727,97,114,59,1,95,4,3,59,101,102,12498,12500,12506,1,9674,110,103,101,59,1,9674,59,1,10731,97,114,4,2,59,108,12517,12519,1,40,116,59,1,10643,4,5,97,99,104,109,116,12535,12540,12548,12561,12564,114,114,59,1,8646,111,114,110,101,114,59,1,8991,97,114,4,2,59,100,12556,12558,1,8651,59,1,10605,59,1,8206,114,105,59,1,8895,4,6,97,99,104,105,113,116,12583,12589,12594,12597,12614,12635,113,117,111,59,1,8249,114,59,3,55349,56513,59,1,8624,109,4,3,59,101,103,12606,12608,12611,1,8818,59,1,10893,59,1,10895,4,2,98,117,12620,12623,59,1,91,111,4,2,59,114,12630,12632,1,8216,59,1,8218,114,111,107,59,1,322,5,60,8,59,99,100,104,105,108,113,114,12660,12662,12675,12680,12686,12692,12698,12705,1,60,4,2,99,105,12668,12671,59,1,10918,114,59,1,10873,111,116,59,1,8918,114,101,101,59,1,8907,109,101,115,59,1,8905,97,114,114,59,1,10614,117,101,115,116,59,1,10875,4,2,80,105,12711,12716,97,114,59,1,10646,4,3,59,101,102,12724,12726,12729,1,9667,59,1,8884,59,1,9666,114,4,2,100,117,12739,12746,115,104,97,114,59,1,10570,104,97,114,59,1,10598,4,2,101,110,12758,12768,114,116,110,101,113,113,59,3,8808,65024,69,59,3,8808,65024,4,14,68,97,99,100,101,102,104,105,108,110,111,112,115,117,12803,12809,12893,12908,12914,12928,12933,12937,13011,13025,13032,13049,13052,13069,68,111,116,59,1,8762,4,4,99,108,112,114,12819,12827,12849,12887,114,5,175,1,59,12825,1,175,4,2,101,116,12833,12836,59,1,9794,4,2,59,101,12842,12844,1,10016,115,101,59,1,10016,4,2,59,115,12855,12857,1,8614,116,111,4,4,59,100,108,117,12869,12871,12877,12883,1,8614,111,119,110,59,1,8615,101,102,116,59,1,8612,112,59,1,8613,107,101,114,59,1,9646,4,2,111,121,12899,12905,109,109,97,59,1,10793,59,1,1084,97,115,104,59,1,8212,97,115,117,114,101,100,97,110,103,108,101,59,1,8737,114,59,3,55349,56618,111,59,1,8487,4,3,99,100,110,12945,12954,12985,114,111,5,181,1,59,12952,1,181,4,4,59,97,99,100,12964,12966,12971,12976,1,8739,115,116,59,1,42,105,114,59,1,10992,111,116,5,183,1,59,12983,1,183,117,115,4,3,59,98,100,12995,12997,13e3,1,8722,59,1,8863,4,2,59,117,13006,13008,1,8760,59,1,10794,4,2,99,100,13017,13021,112,59,1,10971,114,59,1,8230,112,108,117,115,59,1,8723,4,2,100,112,13038,13044,101,108,115,59,1,8871,102,59,3,55349,56670,59,1,8723,4,2,99,116,13058,13063,114,59,3,55349,56514,112,111,115,59,1,8766,4,3,59,108,109,13077,13079,13087,1,956,116,105,109,97,112,59,1,8888,97,112,59,1,8888,4,24,71,76,82,86,97,98,99,100,101,102,103,104,105,106,108,109,111,112,114,115,116,117,118,119,13142,13165,13217,13229,13247,13330,13359,13414,13420,13508,13513,13579,13602,13626,13631,13762,13767,13855,13936,13995,14214,14285,14312,14432,4,2,103,116,13148,13152,59,3,8921,824,4,2,59,118,13158,13161,3,8811,8402,59,3,8811,824,4,3,101,108,116,13173,13200,13204,102,116,4,2,97,114,13181,13188,114,114,111,119,59,1,8653,105,103,104,116,97,114,114,111,119,59,1,8654,59,3,8920,824,4,2,59,118,13210,13213,3,8810,8402,59,3,8810,824,105,103,104,116,97,114,114,111,119,59,1,8655,4,2,68,100,13235,13241,97,115,104,59,1,8879,97,115,104,59,1,8878,4,5,98,99,110,112,116,13259,13264,13270,13275,13308,108,97,59,1,8711,117,116,101,59,1,324,103,59,3,8736,8402,4,5,59,69,105,111,112,13287,13289,13293,13298,13302,1,8777,59,3,10864,824,100,59,3,8779,824,115,59,1,329,114,111,120,59,1,8777,117,114,4,2,59,97,13316,13318,1,9838,108,4,2,59,115,13325,13327,1,9838,59,1,8469,4,2,115,117,13336,13344,112,5,160,1,59,13342,1,160,109,112,4,2,59,101,13352,13355,3,8782,824,59,3,8783,824,4,5,97,101,111,117,121,13371,13385,13391,13407,13411,4,2,112,114,13377,13380,59,1,10819,111,110,59,1,328,100,105,108,59,1,326,110,103,4,2,59,100,13399,13401,1,8775,111,116,59,3,10861,824,112,59,1,10818,59,1,1085,97,115,104,59,1,8211,4,7,59,65,97,100,113,115,120,13436,13438,13443,13466,13472,13478,13494,1,8800,114,114,59,1,8663,114,4,2,104,114,13450,13454,107,59,1,10532,4,2,59,111,13460,13462,1,8599,119,59,1,8599,111,116,59,3,8784,824,117,105,118,59,1,8802,4,2,101,105,13484,13489,97,114,59,1,10536,109,59,3,8770,824,105,115,116,4,2,59,115,13503,13505,1,8708,59,1,8708,114,59,3,55349,56619,4,4,69,101,115,116,13523,13527,13563,13568,59,3,8807,824,4,3,59,113,115,13535,13537,13559,1,8817,4,3,59,113,115,13545,13547,13551,1,8817,59,3,8807,824,108,97,110,116,59,3,10878,824,59,3,10878,824,105,109,59,1,8821,4,2,59,114,13574,13576,1,8815,59,1,8815,4,3,65,97,112,13587,13592,13597,114,114,59,1,8654,114,114,59,1,8622,97,114,59,1,10994,4,3,59,115,118,13610,13612,13623,1,8715,4,2,59,100,13618,13620,1,8956,59,1,8954,59,1,8715,99,121,59,1,1114,4,7,65,69,97,100,101,115,116,13647,13652,13656,13661,13665,13737,13742,114,114,59,1,8653,59,3,8806,824,114,114,59,1,8602,114,59,1,8229,4,4,59,102,113,115,13675,13677,13703,13725,1,8816,116,4,2,97,114,13684,13691,114,114,111,119,59,1,8602,105,103,104,116,97,114,114,111,119,59,1,8622,4,3,59,113,115,13711,13713,13717,1,8816,59,3,8806,824,108,97,110,116,59,3,10877,824,4,2,59,115,13731,13734,3,10877,824,59,1,8814,105,109,59,1,8820,4,2,59,114,13748,13750,1,8814,105,4,2,59,101,13757,13759,1,8938,59,1,8940,105,100,59,1,8740,4,2,112,116,13773,13778,102,59,3,55349,56671,5,172,3,59,105,110,13787,13789,13829,1,172,110,4,4,59,69,100,118,13800,13802,13806,13812,1,8713,59,3,8953,824,111,116,59,3,8949,824,4,3,97,98,99,13820,13823,13826,59,1,8713,59,1,8951,59,1,8950,105,4,2,59,118,13836,13838,1,8716,4,3,97,98,99,13846,13849,13852,59,1,8716,59,1,8958,59,1,8957,4,3,97,111,114,13863,13892,13899,114,4,4,59,97,115,116,13874,13876,13883,13888,1,8742,108,108,101,108,59,1,8742,108,59,3,11005,8421,59,3,8706,824,108,105,110,116,59,1,10772,4,3,59,99,101,13907,13909,13914,1,8832,117,101,59,1,8928,4,2,59,99,13920,13923,3,10927,824,4,2,59,101,13929,13931,1,8832,113,59,3,10927,824,4,4,65,97,105,116,13946,13951,13971,13982,114,114,59,1,8655,114,114,4,3,59,99,119,13961,13963,13967,1,8603,59,3,10547,824,59,3,8605,824,103,104,116,97,114,114,111,119,59,1,8603,114,105,4,2,59,101,13990,13992,1,8939,59,1,8941,4,7,99,104,105,109,112,113,117,14011,14036,14060,14080,14085,14090,14106,4,4,59,99,101,114,14021,14023,14028,14032,1,8833,117,101,59,1,8929,59,3,10928,824,59,3,55349,56515,111,114,116,4,2,109,112,14045,14050,105,100,59,1,8740,97,114,97,108,108,101,108,59,1,8742,109,4,2,59,101,14067,14069,1,8769,4,2,59,113,14075,14077,1,8772,59,1,8772,105,100,59,1,8740,97,114,59,1,8742,115,117,4,2,98,112,14098,14102,101,59,1,8930,101,59,1,8931,4,3,98,99,112,14114,14157,14171,4,4,59,69,101,115,14124,14126,14130,14133,1,8836,59,3,10949,824,59,1,8840,101,116,4,2,59,101,14141,14144,3,8834,8402,113,4,2,59,113,14151,14153,1,8840,59,3,10949,824,99,4,2,59,101,14164,14166,1,8833,113,59,3,10928,824,4,4,59,69,101,115,14181,14183,14187,14190,1,8837,59,3,10950,824,59,1,8841,101,116,4,2,59,101,14198,14201,3,8835,8402,113,4,2,59,113,14208,14210,1,8841,59,3,10950,824,4,4,103,105,108,114,14224,14228,14238,14242,108,59,1,8825,108,100,101,5,241,1,59,14236,1,241,103,59,1,8824,105,97,110,103,108,101,4,2,108,114,14254,14269,101,102,116,4,2,59,101,14263,14265,1,8938,113,59,1,8940,105,103,104,116,4,2,59,101,14279,14281,1,8939,113,59,1,8941,4,2,59,109,14291,14293,1,957,4,3,59,101,115,14301,14303,14308,1,35,114,111,59,1,8470,112,59,1,8199,4,9,68,72,97,100,103,105,108,114,115,14332,14338,14344,14349,14355,14369,14376,14408,14426,97,115,104,59,1,8877,97,114,114,59,1,10500,112,59,3,8781,8402,97,115,104,59,1,8876,4,2,101,116,14361,14365,59,3,8805,8402,59,3,62,8402,110,102,105,110,59,1,10718,4,3,65,101,116,14384,14389,14393,114,114,59,1,10498,59,3,8804,8402,4,2,59,114,14399,14402,3,60,8402,105,101,59,3,8884,8402,4,2,65,116,14414,14419,114,114,59,1,10499,114,105,101,59,3,8885,8402,105,109,59,3,8764,8402,4,3,65,97,110,14440,14445,14468,114,114,59,1,8662,114,4,2,104,114,14452,14456,107,59,1,10531,4,2,59,111,14462,14464,1,8598,119,59,1,8598,101,97,114,59,1,10535,4,18,83,97,99,100,101,102,103,104,105,108,109,111,112,114,115,116,117,118,14512,14515,14535,14560,14597,14603,14618,14643,14657,14662,14701,14741,14747,14769,14851,14877,14907,14916,59,1,9416,4,2,99,115,14521,14531,117,116,101,5,243,1,59,14529,1,243,116,59,1,8859,4,2,105,121,14541,14557,114,4,2,59,99,14548,14550,1,8858,5,244,1,59,14555,1,244,59,1,1086,4,5,97,98,105,111,115,14572,14577,14583,14587,14591,115,104,59,1,8861,108,97,99,59,1,337,118,59,1,10808,116,59,1,8857,111,108,100,59,1,10684,108,105,103,59,1,339,4,2,99,114,14609,14614,105,114,59,1,10687,59,3,55349,56620,4,3,111,114,116,14626,14630,14640,110,59,1,731,97,118,101,5,242,1,59,14638,1,242,59,1,10689,4,2,98,109,14649,14654,97,114,59,1,10677,59,1,937,110,116,59,1,8750,4,4,97,99,105,116,14672,14677,14693,14698,114,114,59,1,8634,4,2,105,114,14683,14687,114,59,1,10686,111,115,115,59,1,10683,110,101,59,1,8254,59,1,10688,4,3,97,101,105,14709,14714,14719,99,114,59,1,333,103,97,59,1,969,4,3,99,100,110,14727,14733,14736,114,111,110,59,1,959,59,1,10678,117,115,59,1,8854,112,102,59,3,55349,56672,4,3,97,101,108,14755,14759,14764,114,59,1,10679,114,112,59,1,10681,117,115,59,1,8853,4,7,59,97,100,105,111,115,118,14785,14787,14792,14831,14837,14841,14848,1,8744,114,114,59,1,8635,4,4,59,101,102,109,14802,14804,14817,14824,1,10845,114,4,2,59,111,14811,14813,1,8500,102,59,1,8500,5,170,1,59,14822,1,170,5,186,1,59,14829,1,186,103,111,102,59,1,8886,114,59,1,10838,108,111,112,101,59,1,10839,59,1,10843,4,3,99,108,111,14859,14863,14873,114,59,1,8500,97,115,104,5,248,1,59,14871,1,248,108,59,1,8856,105,4,2,108,109,14884,14893,100,101,5,245,1,59,14891,1,245,101,115,4,2,59,97,14901,14903,1,8855,115,59,1,10806,109,108,5,246,1,59,14914,1,246,98,97,114,59,1,9021,4,12,97,99,101,102,104,105,108,109,111,114,115,117,14948,14992,14996,15033,15038,15068,15090,15189,15192,15222,15427,15441,114,4,4,59,97,115,116,14959,14961,14976,14989,1,8741,5,182,2,59,108,14968,14970,1,182,108,101,108,59,1,8741,4,2,105,108,14982,14986,109,59,1,10995,59,1,11005,59,1,8706,121,59,1,1087,114,4,5,99,105,109,112,116,15009,15014,15019,15024,15027,110,116,59,1,37,111,100,59,1,46,105,108,59,1,8240,59,1,8869,101,110,107,59,1,8241,114,59,3,55349,56621,4,3,105,109,111,15046,15057,15063,4,2,59,118,15052,15054,1,966,59,1,981,109,97,116,59,1,8499,110,101,59,1,9742,4,3,59,116,118,15076,15078,15087,1,960,99,104,102,111,114,107,59,1,8916,59,1,982,4,2,97,117,15096,15119,110,4,2,99,107,15103,15115,107,4,2,59,104,15110,15112,1,8463,59,1,8462,118,59,1,8463,115,4,9,59,97,98,99,100,101,109,115,116,15140,15142,15148,15151,15156,15168,15171,15179,15184,1,43,99,105,114,59,1,10787,59,1,8862,105,114,59,1,10786,4,2,111,117,15162,15165,59,1,8724,59,1,10789,59,1,10866,110,5,177,1,59,15177,1,177,105,109,59,1,10790,119,111,59,1,10791,59,1,177,4,3,105,112,117,15200,15208,15213,110,116,105,110,116,59,1,10773,102,59,3,55349,56673,110,100,5,163,1,59,15220,1,163,4,10,59,69,97,99,101,105,110,111,115,117,15244,15246,15249,15253,15258,15334,15347,15367,15416,15421,1,8826,59,1,10931,112,59,1,10935,117,101,59,1,8828,4,2,59,99,15264,15266,1,10927,4,6,59,97,99,101,110,115,15280,15282,15290,15299,15303,15329,1,8826,112,112,114,111,120,59,1,10935,117,114,108,121,101,113,59,1,8828,113,59,1,10927,4,3,97,101,115,15311,15319,15324,112,112,114,111,120,59,1,10937,113,113,59,1,10933,105,109,59,1,8936,105,109,59,1,8830,109,101,4,2,59,115,15342,15344,1,8242,59,1,8473,4,3,69,97,115,15355,15358,15362,59,1,10933,112,59,1,10937,105,109,59,1,8936,4,3,100,102,112,15375,15378,15404,59,1,8719,4,3,97,108,115,15386,15392,15398,108,97,114,59,1,9006,105,110,101,59,1,8978,117,114,102,59,1,8979,4,2,59,116,15410,15412,1,8733,111,59,1,8733,105,109,59,1,8830,114,101,108,59,1,8880,4,2,99,105,15433,15438,114,59,3,55349,56517,59,1,968,110,99,115,112,59,1,8200,4,6,102,105,111,112,115,117,15462,15467,15472,15478,15485,15491,114,59,3,55349,56622,110,116,59,1,10764,112,102,59,3,55349,56674,114,105,109,101,59,1,8279,99,114,59,3,55349,56518,4,3,97,101,111,15499,15520,15534,116,4,2,101,105,15506,15515,114,110,105,111,110,115,59,1,8461,110,116,59,1,10774,115,116,4,2,59,101,15528,15530,1,63,113,59,1,8799,116,5,34,1,59,15540,1,34,4,21,65,66,72,97,98,99,100,101,102,104,105,108,109,110,111,112,114,115,116,117,120,15586,15609,15615,15620,15796,15855,15893,15931,15977,16001,16039,16183,16204,16222,16228,16285,16312,16318,16363,16408,16416,4,3,97,114,116,15594,15599,15603,114,114,59,1,8667,114,59,1,8658,97,105,108,59,1,10524,97,114,114,59,1,10511,97,114,59,1,10596,4,7,99,100,101,110,113,114,116,15636,15651,15656,15664,15687,15696,15770,4,2,101,117,15642,15646,59,3,8765,817,116,101,59,1,341,105,99,59,1,8730,109,112,116,121,118,59,1,10675,103,4,4,59,100,101,108,15675,15677,15680,15683,1,10217,59,1,10642,59,1,10661,101,59,1,10217,117,111,5,187,1,59,15694,1,187,114,4,11,59,97,98,99,102,104,108,112,115,116,119,15721,15723,15727,15739,15742,15746,15750,15754,15758,15763,15767,1,8594,112,59,1,10613,4,2,59,102,15733,15735,1,8677,115,59,1,10528,59,1,10547,115,59,1,10526,107,59,1,8618,112,59,1,8620,108,59,1,10565,105,109,59,1,10612,108,59,1,8611,59,1,8605,4,2,97,105,15776,15781,105,108,59,1,10522,111,4,2,59,110,15788,15790,1,8758,97,108,115,59,1,8474,4,3,97,98,114,15804,15809,15814,114,114,59,1,10509,114,107,59,1,10099,4,2,97,107,15820,15833,99,4,2,101,107,15827,15830,59,1,125,59,1,93,4,2,101,115,15839,15842,59,1,10636,108,4,2,100,117,15849,15852,59,1,10638,59,1,10640,4,4,97,101,117,121,15865,15871,15886,15890,114,111,110,59,1,345,4,2,100,105,15877,15882,105,108,59,1,343,108,59,1,8969,98,59,1,125,59,1,1088,4,4,99,108,113,115,15903,15907,15914,15927,97,59,1,10551,100,104,97,114,59,1,10601,117,111,4,2,59,114,15922,15924,1,8221,59,1,8221,104,59,1,8627,4,3,97,99,103,15939,15966,15970,108,4,4,59,105,112,115,15950,15952,15957,15963,1,8476,110,101,59,1,8475,97,114,116,59,1,8476,59,1,8477,116,59,1,9645,5,174,1,59,15975,1,174,4,3,105,108,114,15985,15991,15997,115,104,116,59,1,10621,111,111,114,59,1,8971,59,3,55349,56623,4,2,97,111,16007,16028,114,4,2,100,117,16014,16017,59,1,8641,4,2,59,108,16023,16025,1,8640,59,1,10604,4,2,59,118,16034,16036,1,961,59,1,1009,4,3,103,110,115,16047,16167,16171,104,116,4,6,97,104,108,114,115,116,16063,16081,16103,16130,16143,16155,114,114,111,119,4,2,59,116,16073,16075,1,8594,97,105,108,59,1,8611,97,114,112,111,111,110,4,2,100,117,16093,16099,111,119,110,59,1,8641,112,59,1,8640,101,102,116,4,2,97,104,16112,16120,114,114,111,119,115,59,1,8644,97,114,112,111,111,110,115,59,1,8652,105,103,104,116,97,114,114,111,119,115,59,1,8649,113,117,105,103,97,114,114,111,119,59,1,8605,104,114,101,101,116,105,109,101,115,59,1,8908,103,59,1,730,105,110,103,100,111,116,115,101,113,59,1,8787,4,3,97,104,109,16191,16196,16201,114,114,59,1,8644,97,114,59,1,8652,59,1,8207,111,117,115,116,4,2,59,97,16214,16216,1,9137,99,104,101,59,1,9137,109,105,100,59,1,10990,4,4,97,98,112,116,16238,16252,16257,16278,4,2,110,114,16244,16248,103,59,1,10221,114,59,1,8702,114,107,59,1,10215,4,3,97,102,108,16265,16269,16273,114,59,1,10630,59,3,55349,56675,117,115,59,1,10798,105,109,101,115,59,1,10805,4,2,97,112,16291,16304,114,4,2,59,103,16298,16300,1,41,116,59,1,10644,111,108,105,110,116,59,1,10770,97,114,114,59,1,8649,4,4,97,99,104,113,16328,16334,16339,16342,113,117,111,59,1,8250,114,59,3,55349,56519,59,1,8625,4,2,98,117,16348,16351,59,1,93,111,4,2,59,114,16358,16360,1,8217,59,1,8217,4,3,104,105,114,16371,16377,16383,114,101,101,59,1,8908,109,101,115,59,1,8906,105,4,4,59,101,102,108,16394,16396,16399,16402,1,9657,59,1,8885,59,1,9656,116,114,105,59,1,10702,108,117,104,97,114,59,1,10600,59,1,8478,4,19,97,98,99,100,101,102,104,105,108,109,111,112,113,114,115,116,117,119,122,16459,16466,16472,16572,16590,16672,16687,16746,16844,16850,16924,16963,16988,17115,17121,17154,17206,17614,17656,99,117,116,101,59,1,347,113,117,111,59,1,8218,4,10,59,69,97,99,101,105,110,112,115,121,16494,16496,16499,16513,16518,16531,16536,16556,16564,16569,1,8827,59,1,10932,4,2,112,114,16505,16508,59,1,10936,111,110,59,1,353,117,101,59,1,8829,4,2,59,100,16524,16526,1,10928,105,108,59,1,351,114,99,59,1,349,4,3,69,97,115,16544,16547,16551,59,1,10934,112,59,1,10938,105,109,59,1,8937,111,108,105,110,116,59,1,10771,105,109,59,1,8831,59,1,1089,111,116,4,3,59,98,101,16582,16584,16587,1,8901,59,1,8865,59,1,10854,4,7,65,97,99,109,115,116,120,16606,16611,16634,16642,16646,16652,16668,114,114,59,1,8664,114,4,2,104,114,16618,16622,107,59,1,10533,4,2,59,111,16628,16630,1,8600,119,59,1,8600,116,5,167,1,59,16640,1,167,105,59,1,59,119,97,114,59,1,10537,109,4,2,105,110,16659,16665,110,117,115,59,1,8726,59,1,8726,116,59,1,10038,114,4,2,59,111,16679,16682,3,55349,56624,119,110,59,1,8994,4,4,97,99,111,121,16697,16702,16716,16739,114,112,59,1,9839,4,2,104,121,16708,16713,99,121,59,1,1097,59,1,1096,114,116,4,2,109,112,16724,16729,105,100,59,1,8739,97,114,97,108,108,101,108,59,1,8741,5,173,1,59,16744,1,173,4,2,103,109,16752,16770,109,97,4,3,59,102,118,16762,16764,16767,1,963,59,1,962,59,1,962,4,8,59,100,101,103,108,110,112,114,16788,16790,16795,16806,16817,16828,16832,16838,1,8764,111,116,59,1,10858,4,2,59,113,16801,16803,1,8771,59,1,8771,4,2,59,69,16812,16814,1,10910,59,1,10912,4,2,59,69,16823,16825,1,10909,59,1,10911,101,59,1,8774,108,117,115,59,1,10788,97,114,114,59,1,10610,97,114,114,59,1,8592,4,4,97,101,105,116,16860,16883,16891,16904,4,2,108,115,16866,16878,108,115,101,116,109,105,110,117,115,59,1,8726,104,112,59,1,10803,112,97,114,115,108,59,1,10724,4,2,100,108,16897,16900,59,1,8739,101,59,1,8995,4,2,59,101,16910,16912,1,10922,4,2,59,115,16918,16920,1,10924,59,3,10924,65024,4,3,102,108,112,16932,16938,16958,116,99,121,59,1,1100,4,2,59,98,16944,16946,1,47,4,2,59,97,16952,16954,1,10692,114,59,1,9023,102,59,3,55349,56676,97,4,2,100,114,16970,16985,101,115,4,2,59,117,16978,16980,1,9824,105,116,59,1,9824,59,1,8741,4,3,99,115,117,16996,17028,17089,4,2,97,117,17002,17015,112,4,2,59,115,17009,17011,1,8851,59,3,8851,65024,112,4,2,59,115,17022,17024,1,8852,59,3,8852,65024,117,4,2,98,112,17035,17062,4,3,59,101,115,17043,17045,17048,1,8847,59,1,8849,101,116,4,2,59,101,17056,17058,1,8847,113,59,1,8849,4,3,59,101,115,17070,17072,17075,1,8848,59,1,8850,101,116,4,2,59,101,17083,17085,1,8848,113,59,1,8850,4,3,59,97,102,17097,17099,17112,1,9633,114,4,2,101,102,17106,17109,59,1,9633,59,1,9642,59,1,9642,97,114,114,59,1,8594,4,4,99,101,109,116,17131,17136,17142,17148,114,59,3,55349,56520,116,109,110,59,1,8726,105,108,101,59,1,8995,97,114,102,59,1,8902,4,2,97,114,17160,17172,114,4,2,59,102,17167,17169,1,9734,59,1,9733,4,2,97,110,17178,17202,105,103,104,116,4,2,101,112,17188,17197,112,115,105,108,111,110,59,1,1013,104,105,59,1,981,115,59,1,175,4,5,98,99,109,110,112,17218,17351,17420,17423,17427,4,9,59,69,100,101,109,110,112,114,115,17238,17240,17243,17248,17261,17267,17279,17285,17291,1,8834,59,1,10949,111,116,59,1,10941,4,2,59,100,17254,17256,1,8838,111,116,59,1,10947,117,108,116,59,1,10945,4,2,69,101,17273,17276,59,1,10955,59,1,8842,108,117,115,59,1,10943,97,114,114,59,1,10617,4,3,101,105,117,17299,17335,17339,116,4,3,59,101,110,17308,17310,17322,1,8834,113,4,2,59,113,17317,17319,1,8838,59,1,10949,101,113,4,2,59,113,17330,17332,1,8842,59,1,10955,109,59,1,10951,4,2,98,112,17345,17348,59,1,10965,59,1,10963,99,4,6,59,97,99,101,110,115,17366,17368,17376,17385,17389,17415,1,8827,112,112,114,111,120,59,1,10936,117,114,108,121,101,113,59,1,8829,113,59,1,10928,4,3,97,101,115,17397,17405,17410,112,112,114,111,120,59,1,10938,113,113,59,1,10934,105,109,59,1,8937,105,109,59,1,8831,59,1,8721,103,59,1,9834,4,13,49,50,51,59,69,100,101,104,108,109,110,112,115,17455,17462,17469,17476,17478,17481,17496,17509,17524,17530,17536,17548,17554,5,185,1,59,17460,1,185,5,178,1,59,17467,1,178,5,179,1,59,17474,1,179,1,8835,59,1,10950,4,2,111,115,17487,17491,116,59,1,10942,117,98,59,1,10968,4,2,59,100,17502,17504,1,8839,111,116,59,1,10948,115,4,2,111,117,17516,17520,108,59,1,10185,98,59,1,10967,97,114,114,59,1,10619,117,108,116,59,1,10946,4,2,69,101,17542,17545,59,1,10956,59,1,8843,108,117,115,59,1,10944,4,3,101,105,117,17562,17598,17602,116,4,3,59,101,110,17571,17573,17585,1,8835,113,4,2,59,113,17580,17582,1,8839,59,1,10950,101,113,4,2,59,113,17593,17595,1,8843,59,1,10956,109,59,1,10952,4,2,98,112,17608,17611,59,1,10964,59,1,10966,4,3,65,97,110,17622,17627,17650,114,114,59,1,8665,114,4,2,104,114,17634,17638,107,59,1,10534,4,2,59,111,17644,17646,1,8601,119,59,1,8601,119,97,114,59,1,10538,108,105,103,5,223,1,59,17664,1,223,4,13,97,98,99,100,101,102,104,105,111,112,114,115,119,17694,17709,17714,17737,17742,17749,17754,17860,17905,17957,17964,18090,18122,4,2,114,117,17700,17706,103,101,116,59,1,8982,59,1,964,114,107,59,1,9140,4,3,97,101,121,17722,17728,17734,114,111,110,59,1,357,100,105,108,59,1,355,59,1,1090,111,116,59,1,8411,108,114,101,99,59,1,8981,114,59,3,55349,56625,4,4,101,105,107,111,17764,17805,17836,17851,4,2,114,116,17770,17786,101,4,2,52,102,17777,17780,59,1,8756,111,114,101,59,1,8756,97,4,3,59,115,118,17795,17797,17802,1,952,121,109,59,1,977,59,1,977,4,2,99,110,17811,17831,107,4,2,97,115,17818,17826,112,112,114,111,120,59,1,8776,105,109,59,1,8764,115,112,59,1,8201,4,2,97,115,17842,17846,112,59,1,8776,105,109,59,1,8764,114,110,5,254,1,59,17858,1,254,4,3,108,109,110,17868,17873,17901,100,101,59,1,732,101,115,5,215,3,59,98,100,17884,17886,17898,1,215,4,2,59,97,17892,17894,1,8864,114,59,1,10801,59,1,10800,116,59,1,8749,4,3,101,112,115,17913,17917,17953,97,59,1,10536,4,4,59,98,99,102,17927,17929,17934,17939,1,8868,111,116,59,1,9014,105,114,59,1,10993,4,2,59,111,17945,17948,3,55349,56677,114,107,59,1,10970,97,59,1,10537,114,105,109,101,59,1,8244,4,3,97,105,112,17972,17977,18082,100,101,59,1,8482,4,7,97,100,101,109,112,115,116,17993,18051,18056,18059,18066,18072,18076,110,103,108,101,4,5,59,100,108,113,114,18009,18011,18017,18032,18035,1,9653,111,119,110,59,1,9663,101,102,116,4,2,59,101,18026,18028,1,9667,113,59,1,8884,59,1,8796,105,103,104,116,4,2,59,101,18045,18047,1,9657,113,59,1,8885,111,116,59,1,9708,59,1,8796,105,110,117,115,59,1,10810,108,117,115,59,1,10809,98,59,1,10701,105,109,101,59,1,10811,101,122,105,117,109,59,1,9186,4,3,99,104,116,18098,18111,18116,4,2,114,121,18104,18108,59,3,55349,56521,59,1,1094,99,121,59,1,1115,114,111,107,59,1,359,4,2,105,111,18128,18133,120,116,59,1,8812,104,101,97,100,4,2,108,114,18143,18154,101,102,116,97,114,114,111,119,59,1,8606,105,103,104,116,97,114,114,111,119,59,1,8608,4,18,65,72,97,98,99,100,102,103,104,108,109,111,112,114,115,116,117,119,18204,18209,18214,18234,18250,18268,18292,18308,18319,18343,18379,18397,18413,18504,18547,18553,18584,18603,114,114,59,1,8657,97,114,59,1,10595,4,2,99,114,18220,18230,117,116,101,5,250,1,59,18228,1,250,114,59,1,8593,114,4,2,99,101,18241,18245,121,59,1,1118,118,101,59,1,365,4,2,105,121,18256,18265,114,99,5,251,1,59,18263,1,251,59,1,1091,4,3,97,98,104,18276,18281,18287,114,114,59,1,8645,108,97,99,59,1,369,97,114,59,1,10606,4,2,105,114,18298,18304,115,104,116,59,1,10622,59,3,55349,56626,114,97,118,101,5,249,1,59,18317,1,249,4,2,97,98,18325,18338,114,4,2,108,114,18332,18335,59,1,8639,59,1,8638,108,107,59,1,9600,4,2,99,116,18349,18374,4,2,111,114,18355,18369,114,110,4,2,59,101,18363,18365,1,8988,114,59,1,8988,111,112,59,1,8975,114,105,59,1,9720,4,2,97,108,18385,18390,99,114,59,1,363,5,168,1,59,18395,1,168,4,2,103,112,18403,18408,111,110,59,1,371,102,59,3,55349,56678,4,6,97,100,104,108,115,117,18427,18434,18445,18470,18475,18494,114,114,111,119,59,1,8593,111,119,110,97,114,114,111,119,59,1,8597,97,114,112,111,111,110,4,2,108,114,18457,18463,101,102,116,59,1,8639,105,103,104,116,59,1,8638,117,115,59,1,8846,105,4,3,59,104,108,18484,18486,18489,1,965,59,1,978,111,110,59,1,965,112,97,114,114,111,119,115,59,1,8648,4,3,99,105,116,18512,18537,18542,4,2,111,114,18518,18532,114,110,4,2,59,101,18526,18528,1,8989,114,59,1,8989,111,112,59,1,8974,110,103,59,1,367,114,105,59,1,9721,99,114,59,3,55349,56522,4,3,100,105,114,18561,18566,18572,111,116,59,1,8944,108,100,101,59,1,361,105,4,2,59,102,18579,18581,1,9653,59,1,9652,4,2,97,109,18590,18595,114,114,59,1,8648,108,5,252,1,59,18601,1,252,97,110,103,108,101,59,1,10663,4,15,65,66,68,97,99,100,101,102,108,110,111,112,114,115,122,18643,18648,18661,18667,18847,18851,18857,18904,18909,18915,18931,18937,18943,18949,18996,114,114,59,1,8661,97,114,4,2,59,118,18656,18658,1,10984,59,1,10985,97,115,104,59,1,8872,4,2,110,114,18673,18679,103,114,116,59,1,10652,4,7,101,107,110,112,114,115,116,18695,18704,18711,18720,18742,18754,18810,112,115,105,108,111,110,59,1,1013,97,112,112,97,59,1,1008,111,116,104,105,110,103,59,1,8709,4,3,104,105,114,18728,18732,18735,105,59,1,981,59,1,982,111,112,116,111,59,1,8733,4,2,59,104,18748,18750,1,8597,111,59,1,1009,4,2,105,117,18760,18766,103,109,97,59,1,962,4,2,98,112,18772,18791,115,101,116,110,101,113,4,2,59,113,18784,18787,3,8842,65024,59,3,10955,65024,115,101,116,110,101,113,4,2,59,113,18803,18806,3,8843,65024,59,3,10956,65024,4,2,104,114,18816,18822,101,116,97,59,1,977,105,97,110,103,108,101,4,2,108,114,18834,18840,101,102,116,59,1,8882,105,103,104,116,59,1,8883,121,59,1,1074,97,115,104,59,1,8866,4,3,101,108,114,18865,18884,18890,4,3,59,98,101,18873,18875,18880,1,8744,97,114,59,1,8891,113,59,1,8794,108,105,112,59,1,8942,4,2,98,116,18896,18901,97,114,59,1,124,59,1,124,114,59,3,55349,56627,116,114,105,59,1,8882,115,117,4,2,98,112,18923,18927,59,3,8834,8402,59,3,8835,8402,112,102,59,3,55349,56679,114,111,112,59,1,8733,116,114,105,59,1,8883,4,2,99,117,18955,18960,114,59,3,55349,56523,4,2,98,112,18966,18981,110,4,2,69,101,18973,18977,59,3,10955,65024,59,3,8842,65024,110,4,2,69,101,18988,18992,59,3,10956,65024,59,3,8843,65024,105,103,122,97,103,59,1,10650,4,7,99,101,102,111,112,114,115,19020,19026,19061,19066,19072,19075,19089,105,114,99,59,1,373,4,2,100,105,19032,19055,4,2,98,103,19038,19043,97,114,59,1,10847,101,4,2,59,113,19050,19052,1,8743,59,1,8793,101,114,112,59,1,8472,114,59,3,55349,56628,112,102,59,3,55349,56680,59,1,8472,4,2,59,101,19081,19083,1,8768,97,116,104,59,1,8768,99,114,59,3,55349,56524,4,14,99,100,102,104,105,108,109,110,111,114,115,117,118,119,19125,19146,19152,19157,19173,19176,19192,19197,19202,19236,19252,19269,19286,19291,4,3,97,105,117,19133,19137,19142,112,59,1,8898,114,99,59,1,9711,112,59,1,8899,116,114,105,59,1,9661,114,59,3,55349,56629,4,2,65,97,19163,19168,114,114,59,1,10234,114,114,59,1,10231,59,1,958,4,2,65,97,19182,19187,114,114,59,1,10232,114,114,59,1,10229,97,112,59,1,10236,105,115,59,1,8955,4,3,100,112,116,19210,19215,19230,111,116,59,1,10752,4,2,102,108,19221,19225,59,3,55349,56681,117,115,59,1,10753,105,109,101,59,1,10754,4,2,65,97,19242,19247,114,114,59,1,10233,114,114,59,1,10230,4,2,99,113,19258,19263,114,59,3,55349,56525,99,117,112,59,1,10758,4,2,112,116,19275,19281,108,117,115,59,1,10756,114,105,59,1,9651,101,101,59,1,8897,101,100,103,101,59,1,8896,4,8,97,99,101,102,105,111,115,117,19316,19335,19349,19357,19362,19367,19373,19379,99,4,2,117,121,19323,19332,116,101,5,253,1,59,19330,1,253,59,1,1103,4,2,105,121,19341,19346,114,99,59,1,375,59,1,1099,110,5,165,1,59,19355,1,165,114,59,3,55349,56630,99,121,59,1,1111,112,102,59,3,55349,56682,99,114,59,3,55349,56526,4,2,99,109,19385,19389,121,59,1,1102,108,5,255,1,59,19395,1,255,4,10,97,99,100,101,102,104,105,111,115,119,19419,19426,19441,19446,19462,19467,19472,19480,19486,19492,99,117,116,101,59,1,378,4,2,97,121,19432,19438,114,111,110,59,1,382,59,1,1079,111,116,59,1,380,4,2,101,116,19452,19458,116,114,102,59,1,8488,97,59,1,950,114,59,3,55349,56631,99,121,59,1,1078,103,114,97,114,114,59,1,8669,112,102,59,3,55349,56683,99,114,59,3,55349,56527,4,2,106,110,19498,19501,59,1,8205,106,59,1,8204])},7118:(e,t,n)=>{"use strict";const r=n(4284),i=n(1734),s=r.CODE_POINTS;e.exports=class{constructor(){this.html=null,this.pos=-1,this.lastGapPos=-1,this.lastCharPos=-1,this.gapStack=[],this.skipNextNewLine=!1,this.lastChunkWritten=!1,this.endOfChunkHit=!1,this.bufferWaterline=65536}_err(){}_addGap(){this.gapStack.push(this.lastGapPos),this.lastGapPos=this.pos}_processSurrogate(e){if(this.pos!==this.lastCharPos){const t=this.html.charCodeAt(this.pos+1);if(r.isSurrogatePair(t))return this.pos++,this._addGap(),r.getSurrogatePairCodePoint(e,t)}else if(!this.lastChunkWritten)return this.endOfChunkHit=!0,s.EOF;return this._err(i.surrogateInInputStream),e}dropParsedChunk(){this.pos>this.bufferWaterline&&(this.lastCharPos-=this.pos,this.html=this.html.substring(this.pos),this.pos=0,this.lastGapPos=-1,this.gapStack=[])}write(e,t){this.html?this.html+=e:this.html=e,this.lastCharPos=this.html.length-1,this.endOfChunkHit=!1,this.lastChunkWritten=t}insertHtmlAtCurrentPos(e){this.html=this.html.substring(0,this.pos+1)+e+this.html.substring(this.pos+1,this.html.length),this.lastCharPos=this.html.length-1,this.endOfChunkHit=!1}advance(){if(this.pos++,this.pos>this.lastCharPos)return this.endOfChunkHit=!this.lastChunkWritten,s.EOF;let e=this.html.charCodeAt(this.pos);return this.skipNextNewLine&&e===s.LINE_FEED?(this.skipNextNewLine=!1,this._addGap(),this.advance()):e===s.CARRIAGE_RETURN?(this.skipNextNewLine=!0,s.LINE_FEED):(this.skipNextNewLine=!1,r.isSurrogate(e)&&(e=this._processSurrogate(e)),e>31&&e<127||e===s.LINE_FEED||e===s.CARRIAGE_RETURN||e>159&&e<64976||this._checkForProblematicCharacters(e),e)}_checkForProblematicCharacters(e){r.isControlCodePoint(e)?this._err(i.controlCharacterInInputStream):r.isUndefinedCodePoint(e)&&this._err(i.noncharacterInInputStream)}retreat(){this.pos===this.lastGapPos&&(this.lastGapPos=this.gapStack.pop(),this.pos--),this.pos--}}},7296:(e,t,n)=>{"use strict";const{DOCUMENT_MODE:r}=n(6152);t.createDocument=function(){return{nodeName:"#document",mode:r.NO_QUIRKS,childNodes:[]}},t.createDocumentFragment=function(){return{nodeName:"#document-fragment",childNodes:[]}},t.createElement=function(e,t,n){return{nodeName:e,tagName:e,attrs:n,namespaceURI:t,childNodes:[],parentNode:null}},t.createCommentNode=function(e){return{nodeName:"#comment",data:e,parentNode:null}};const i=function(e){return{nodeName:"#text",value:e,parentNode:null}},s=t.appendChild=function(e,t){e.childNodes.push(t),t.parentNode=e},o=t.insertBefore=function(e,t,n){const r=e.childNodes.indexOf(n);e.childNodes.splice(r,0,t),t.parentNode=e};t.setTemplateContent=function(e,t){e.content=t},t.getTemplateContent=function(e){return e.content},t.setDocumentType=function(e,t,n,r){let i=null;for(let t=0;t<e.childNodes.length;t++)if("#documentType"===e.childNodes[t].nodeName){i=e.childNodes[t];break}i?(i.name=t,i.publicId=n,i.systemId=r):s(e,{nodeName:"#documentType",name:t,publicId:n,systemId:r})},t.setDocumentMode=function(e,t){e.mode=t},t.getDocumentMode=function(e){return e.mode},t.detachNode=function(e){if(e.parentNode){const t=e.parentNode.childNodes.indexOf(e);e.parentNode.childNodes.splice(t,1),e.parentNode=null}},t.insertText=function(e,t){if(e.childNodes.length){const n=e.childNodes[e.childNodes.length-1];if("#text"===n.nodeName)return void(n.value+=t)}s(e,i(t))},t.insertTextBefore=function(e,t,n){const r=e.childNodes[e.childNodes.indexOf(n)-1];r&&"#text"===r.nodeName?r.value+=t:o(e,i(t),n)},t.adoptAttributes=function(e,t){const n=[];for(let t=0;t<e.attrs.length;t++)n.push(e.attrs[t].name);for(let r=0;r<t.length;r++)-1===n.indexOf(t[r].name)&&e.attrs.push(t[r])},t.getFirstChild=function(e){return e.childNodes[0]},t.getChildNodes=function(e){return e.childNodes},t.getParentNode=function(e){return e.parentNode},t.getAttrList=function(e){return e.attrs},t.getTagName=function(e){return e.tagName},t.getNamespaceURI=function(e){return e.namespaceURI},t.getTextNodeContent=function(e){return e.value},t.getCommentNodeContent=function(e){return e.data},t.getDocumentTypeNodeName=function(e){return e.name},t.getDocumentTypeNodePublicId=function(e){return e.publicId},t.getDocumentTypeNodeSystemId=function(e){return e.systemId},t.isTextNode=function(e){return"#text"===e.nodeName},t.isCommentNode=function(e){return"#comment"===e.nodeName},t.isDocumentTypeNode=function(e){return"#documentType"===e.nodeName},t.isElementNode=function(e){return!!e.tagName},t.setNodeSourceCodeLocation=function(e,t){e.sourceCodeLocation=t},t.getNodeSourceCodeLocation=function(e){return e.sourceCodeLocation},t.updateNodeSourceCodeLocation=function(e,t){e.sourceCodeLocation=Object.assign(e.sourceCodeLocation,t)}},8904:e=>{"use strict";e.exports=function(e,t){return[e,t=t||Object.create(null)].reduce(((e,t)=>(Object.keys(t).forEach((n=>{e[n]=t[n]})),e)),Object.create(null))}},1704:e=>{"use strict";class t{constructor(e){const t={},n=this._getOverriddenMethods(this,t);for(const r of Object.keys(n))"function"==typeof n[r]&&(t[r]=e[r],e[r]=n[r])}_getOverriddenMethods(){throw new Error("Not implemented")}}t.install=function(e,t,n){e.__mixins||(e.__mixins=[]);for(let n=0;n<e.__mixins.length;n++)if(e.__mixins[n].constructor===t)return e.__mixins[n];const r=new t(e,n);return e.__mixins.push(r),r},e.exports=t},184:e=>{"use strict";e.exports=".nav {\n margin: 0;\n max-width: 150px;\n min-width: 90px;\n justify-content: center;\n align-content: center;\n font-size: 40px;\n color: #ccc;\n text-align: center;\n text-decoration: none;\n text-rendering: auto;\n -webkit-transition: all 350ms ease;\n -moz-transition: all 350ms ease;\n -o-transition: all 350ms ease;\n transition: all 350ms ease\n}\n\n.nav:hover {\n text-decoration: none;\n color: #444\n}\n\n.nav-next {\n float: right;\n display: block;\n}\n\n.nav-prev {\n float: left;\n display: block;\n}\n\n#toc li {\n padding: 0.07rem;\n}\n\nli.current {\n border-radius: 0.5rem;\n background-color: rgb(226, 231, 235);\n /* rgb(226, 231, 235); */\n /* rgb(255, 247, 229); */\n}\n"},3129:e=>{"use strict";e.exports=require("child_process")},8614:e=>{"use strict";e.exports=require("events")},5747:e=>{"use strict";e.exports=require("fs")},5622:e=>{"use strict";e.exports=require("path")},1669:e=>{"use strict";e.exports=require("util")}},r={};function i(e){if(r[e])return r[e].exports;var t=r[e]={exports:{}};return n[e].call(t.exports,t,t.exports,i),t.exports}t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,i.t=function(n,r){if(1&r&&(n=this(n)),8&r)return n;if("object"==typeof n&&n){if(4&r&&n.__esModule)return n;if(16&r&&"function"==typeof n.then)return n}var s=Object.create(null);i.r(s);var o={};e=e||[null,t({}),t([]),t(t)];for(var a=2&r&&n;"object"==typeof a&&!~e.indexOf(a);a=t(a))Object.getOwnPropertyNames(a).forEach((e=>o[e]=()=>n[e]));return o.default=()=>n,i.d(s,o),s},i.d=(e,t)=>{for(var n in t)i.o(t,n)&&!i.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),i.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{"use strict";var e=i(5747),t=i(5622),n=i(7503),r=i(7911);const s=(...e)=>(...t)=>{let n=t;for(let t=0;t<e.length;t++)n=[e[t].apply(void 0,n)];return n[0]},o=e.promises,a=e=>o.mkdir(e,{recursive:!0}).then((t=>e),(e=>e)),c=e=>async n=>{if(await(e=>t=>Promise.allSettled([o.stat(e),o.stat(t)]).then((([e,t])=>"rejected"===t.status||e.value.atimeMs>t.value.atimeMs)))(e)(n)){const r=t.dirname(n);return await l(r)||await a(r),o.copyFile(e,n).then((e=>n))}return!1},l=t=>o.access(t,e.constants.F_OK).then((e=>!0),(e=>!1)),u=require("url"),h=e.promises,p=e=>("#content",e=>e.find("#content"))(e),d=(e,t)=>(n,r,i,...o)=>{const a=_(t),c=o.map(a),l=i.clone();return s(p,((...e)=>t=>(e.forEach((e=>t.append(e.clone()))),t.end()))(...c),O(e(l.find("#footnotes"))),I(r,t.get("navigation")),b(r),D)(l)},f=e=>{const t=(n,i,s,o,a,c,l)=>{const u=n.depth[c]||n.depth.default,h=l?"index":((e,t,n)=>1===t?`${e}${n}`:2===t?`${e}_sec${n}`:`${e}-${n}`)(a,o,c);if(u===o)return void e(n,h,i,s,l);const p=`div.sect${o+1}`;var d;e(n,h,i,(d=p,e=>e.clone().find(d).remove().end())(s),l);const f=s.find(p);return 0!==f.length?f.each(((e,s)=>t(n,i,new r.Cheerio(s),o+1,h,e+1,!1))):void 0};return t},m=(e,t,n,i,s)=>{const o=i.clone();let a=0,c=0,l=!1,u=!1;o.find("#content").children().each(((i,h)=>{const p=new r.Cheerio(h);if(!p.hasClass("partintro"))return p.hasClass("sect1")?(l||u?u=!1:(u=!0,l=!0),n(s,o,p,1,"chap",++a,u)):p.hasClass("sect0")?(l||u?u=!1:(u=!0,l=!0),t(s,o,p,++c,u)):"preamble"===p.attr("id")?(u=!0,l=!0,e(s,o,p,u)):void 0}))},T=(e,t,n)=>{const i=((e,t)=>{const n=new Map,i={},s=[];let o=0;const a=(e,t)=>{i[t]=o,s[o]=t,o++,e.find("*[id]").each(((e,i)=>{const s=new r.Cheerio(i).attr("id");s.startsWith("_footnotedef_")||n.set(s,`${t}#${s}`)})),e.attr("id")?n.set(e.attr("id"),t):n.set(e.children().first().attr("id"),t)},c=f(((e,t,n,r,i)=>{a(r,i?"index.html":`${t}.html`)}));return m(((e,t,n,r)=>{a(n,r?"index.html":"preamble.html")}),((e,t,n,r,i)=>{a(n,i?"index.html":`part${r}.html`)}),c,e,t),n.set("navigation",{filename2pageNum:i,filenameList:s}),n})(t.root(),n),o=_(i),a=s((e=>t=>{const{strictMode:n}=e,r=t.root().clone().find("#content > #preamble, #content > .partintro, #content > .sect1, #content > .sect0").remove().end(),i=r.find("#content");return n?(i.children().length>0&&(s=i,console.log("INFO: Non-Asciidoc contents encountered under <div id='#content'>.\nINFO: They are ignored and not included in chunked html by default.\nINFO: If you want them to be included, use the '--no-strictMode' command option."),s.html().trim().split(/\n+/).forEach((e=>console.log(`INFO: Found content => ${e}`))),console.log()),i.empty().end()):r;var s})(n),E,o,M(n.outdir),x(n),(e=>t=>(new r.Cheerio(`<li><a href="index.html">${e.titlePage}</a></li>`).insertBefore(t.find("div#toc > ul > li:first-child")),t))(n))(t),c=C(g(t("#footnotes")));m(((e,t,n)=>(r,i,s,o)=>{const a=o?"index":"preamble";e(a,n(r,a,t,s))})(e,a,d(c,i)),((e,t,n)=>(r,i,s,o,a)=>{const c=a?"index":`part${o}`;e(c,((e,t,n,r,i)=>i(e,t,n,...r.next().hasClass("partintro")?[r,r.next()]:[r]))(r,c,t,s,n))})(e,a,d(c,i)),((e,t,n)=>f(((r,i,s,o,a)=>{e(i,n(r,i,t,o))})))(e,a,d(c,i)),t.root(),n)},E=e=>(0===e.find("#toc a[href^=#]").length&&console.log("INFO: Your TOC has no in-document links.\n"),e),_=e=>t=>(t.find("a[href^=#]").each(((t,n)=>{const i=new r.Cheerio(n),s=i.attr("href");if(!s.startsWith("#_footnotedef_")&&!s.startsWith("#_footnoteref_")){const t=s.substring(1);i.attr("href",`${e.get(t)}`)}})),t),g=e=>{const t=new Set;return e.find("div.footnote").each(((e,n)=>{t.add(new r.Cheerio(n).attr("id"))})),t},A=e=>e.find("a.footnote"),C=e=>t=>n=>{if(0===n.length)return t.empty().end(),n;const i=new Set([...e]);return n.each(((e,t)=>{i.delete(new r.Cheerio(t).attr("href").substring(1))})),i.forEach((e=>{t.find(`#${e}`).remove().end()})),n},N=e=>{if(0===e.length)return e;const t=new Set;return e.each(((e,n)=>{const i=new r.Cheerio(n);if(i.attr("id"))return;const s=i.attr("href");if(t.has(s))return;t.add(s);const o=v(s);i.attr("id",o)})),e},v=e=>`_footnoteref${e.substring(e.lastIndexOf("_"))}`,O=e=>t=>(s(p,A,e,N)(t),t),b=e=>t=>(s(S(e),y)(t),t),S=e=>t=>t.find(`#toc a[href^="${e}.html"]`).parent(),y=e=>e.addClass("current"),I=(e,{filename2pageNum:t,filenameList:n})=>i=>{const s=t[`${e}.html`],o=s>0?n[s-1]:null,a=s<n.length-1?n[s+1]:null,c=R(o,a),l=i.find("body > div:last-of-type");return"footer"===l.attr("id")?new r.Cheerio(c).insertBefore(l):new r.Cheerio(c).insertAfter(l),i},R=(e,t)=>`\n<nav>\n ${e?`<a rel="prev" href="${e}" class="nav nav-prev"\n title="Previous page"\n aria-label="Previous page"\n aria-keyshortcuts="Left">\n <i class="fa fa-angle-left"></i>\n </a>`:""}\n ${t?`<a rel="next" href="${t}" class="nav nav-next"\n title="Next page"\n aria-label="Next page"\n aria-keyshortcuts="Right">\n <i class="fa fa-angle-right"></i>\n </a>`:""}\n <div style="clear: both"></div>\n</nav>\n`,k=/^#|https:|http:|file:/,L=(e,n)=>i=>{const s=(e=>n=>{const r=t.dirname(e);return t.join(r,n)})(e);(e=>{const n=[];return e.find("link[href], script[src], img[src]").each(((e,i)=>{const s=new r.Cheerio(i),o=s.attr("href")||s.attr("src");o.match(k)||t.isAbsolute(o)||n.push((e=>{const n=t.basename(e),r=n.indexOf("?");return-1===r?e:t.join(t.dirname(e),n.substring(0,r))})(o))})),n})(i).forEach((e=>{return c(s(e))((r=e,t.join(n,r))).catch((t=>console.log(` Local file linked from the document is missing: ${s(e)}`)));var r}))},M=e=>n=>(n.find("style").each(((n,i)=>{const s=`style${n}.css`,o=new r.Cheerio(i);h.writeFile(t.join(e,s),new r.Cheerio(i).contents().text()),o.replaceWith(new r.Cheerio(`<link rel='stylesheet' href='${s}' type='text/css' />`))})),n),x=e=>t=>{const{css:n,outdir:r}=e;if(!n||0==n.length)return t;const i=t.find("head");return n.forEach((e=>i.append(P(r,e)))),t},P=(e,n)=>{const r=t.basename(n),s=t.join(e,r);return"asciidoctor-chunker.css"===n?Promise.resolve().then(i.t.bind(i,184,17)).then((e=>h.writeFile(s,e.default))).catch((e=>{const n=t.dirname((0,u.fileURLToPath)("file:///Users/shito/Documents/git-repositories/javascript/asciidoctor-chunker/src/DOM.mjs")),r=t.resolve(n,"css","asciidoctor-chunker.css");c(r)(s)})):c(n)(s),`<link rel="stylesheet" href="${r}" type="text/css" />`},D=e=>(e.find("html").append("\n <script>\n function isInViewport(ele) {\n const rect = ele.getBoundingClientRect();\n return (\n rect.top >= 0 &&\n rect.bottom <= (window.innerHeight || document.documentElement.clientHeight)\n );\n }\n function yPosition (ele) {\n const rect = ele.getBoundingClientRect();\n return (rect.top - 20); // 20px above\n }\n let curr = document.getElementsByClassName('current');\n if (!isInViewport(curr[curr.length - 1])) {\n document.getElementById('toc').scrollTo({\n top: yPosition(curr[0]),\n left: 0,\n behavior: 'smooth'\n });\n }\n\n /* For page navigation */\n function gotoPage(selector) {\n const button = document.querySelector(selector);\n if (button)\n window.location.href = button.href;\n }\n document.addEventListener('keydown', e => {\n switch (e.key) {\n case 'ArrowRight':\n e.preventDefault();\n gotoPage('.nav-next');\n break;\n case 'ArrowLeft':\n e.preventDefault();\n gotoPage('.nav-prev');\n break;\n }\n });\n <\/script>\n "),e);var w=i(8783);const H=(e,t)=>e.split(","),F=(e,t)=>{const[n,r]=e.split("-").map((e=>parseInt(e)));return r?new Array(r-n+1).fill(0).reduce(((e,r,i)=>({...e,[i+n]:+t})),{}):{[n]:+t}},U={depth:1,outdir:"html_chunks",css:["asciidoctor-chunker.css"],strictMode:!0,titlePage:"Titlepage"};console.log();const{singleHTML:B,config:G}=(e=>{const t=w.version("1.0.4").name("node asciidoctor-chunker.js").usage("<single.html> [options]").option("-o, --outdir <directory>","The output directory where the chunked html will be written out to.","html_chunks").option("--depth <depth specifier>","See the description above.","1").option("--css <paths>","The comma seprated list of css file paths to include. The paths must be accesible from the current directory.",H).option("--no-strictMode","Turns off the strict mode.").option("--titlePage <title string>","Sets title page toc string.","Titlepage").description("Description:\n Splits an html file generated by Asciidoctor to chunked htmls.\n The default output directory is 'html_chunks'. You can override\n it with the '-o' option.\n\n The default splits are made by preamble, parts, and chapters.\n You can specify the extraction level with the '--depth' option.\n\n If you have any custom elements inserted under <div d=#content>\n in the source single html, asciidoctor-chunker ignores it by\n default. If you want them to be included into the chunked html,\n set the option --no-strictMode. The element will be copied to\n every chunked page.\n\n By default asciidoctor-chunker.css is included in the\n output directory. It provides the non-opinionated page\n navigation at the bottom of every chunked page. You can\n override this by giving a comma separated list of paths\n to your custom css files. They are copied into the output\n directory so the paths must be accessible by\n asciidoctor-chunker.\n\nThe Depth Specifier:\n You can list the multiple settings by connecting each\n specifier with a comma. Each specifier is consisted of\n either a single number or a collon separated with two\n numbers.\n\n The single number sets the default level of extraction.\n Number 1 is the application's default and it extracts the\n chapter level. Number 2 for section extraction, 3 for\n subsection, and so on to 6 which is the maximum section\n level of Asciidoctor.\n\n The list of collon separated numbers, chap:level, can\n change the extraction depth for specific chapters,\n so 3:2 means chapter 3 is extracted down to 2 levels (i.e.\n section level). You can use a hyphen to specify the range\n of chapters to set as chapFrom-chapTo:level, so 1-3:5 means\n chapter 1 through 5 should be extracted with the depth\n level 5.\n\nExample:\n --depth 2 The default level 2, all the chapters and\n sections will be extracted.\n --depth 3,1:2,8:5 The default level 3, level 2 for Chap 1,\n level 5 for Chap 8.\n --depth 1,3-8:2 The default level 1, level 2 for Chap 3 to 8.\n --depth 3-8:3 No default is set so default level is 1, and\n level 3 for chap3 to 8.").parse(e),{args:n,depth:r,outdir:i,strictMode:s,titlePage:o,css:a=["asciidoctor-chunker.css"]}=t;1!==n.length&&t.help();const c=(e=>e.split(",").map((e=>{const[t,n]=e.split(":");return n?F(t,n):{default:+t}})).reduce(((e,t)=>({...e,...t})),{default:1}))(r);return{singleHTML:n[0],config:{depth:c,outdir:i,css:a,strictMode:s,titlePage:o}}})(process.argv);(async(r,i=U)=>{const{outdir:s}=i;await l(s)||await a(s);const o=(c=s,(e,n)=>{const r=t.format({dir:c,base:`${e}.html`});h.writeFile(r,n.html()).catch((e=>console.log("File write error:",r)))});var c;const u=(p=r,n.load(e.readFileSync(p)));var p;L(r,s)(u.root()),T(o,u,i),console.log(`Successfully chunked! => ${t.join(s,"index.html")}\n`)})(B,G)})()})(); \ No newline at end of file
diff --git a/codegen/vulkan/scripts/cereal/__init__.py b/codegen/vulkan/scripts/cereal/__init__.py
deleted file mode 100644
index 1966572f..00000000
--- a/codegen/vulkan/scripts/cereal/__init__.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from .common import *
-from .decoder import *
-from .encoder import *
-from .extensionstructs import *
-from .frontend import *
-from .functable import *
-from .marshaling import *
-from .reservedmarshaling import *
-from .counting import *
-from .testing import *
-from .transform import *
-from .deepcopy import *
-from .handlemap import *
-from .dispatch import *
-from .unbox import *
-from .decodersnapshot import *
-from .subdecode import *
-from .api_log_decoder import *
-from .vkextensionstructuretype import VulkanGfxstreamStructureType, \
- VulkanAndroidNativeBufferStructureType
diff --git a/codegen/vulkan/scripts/cereal/api_log_decoder.py b/codegen/vulkan/scripts/cereal/api_log_decoder.py
deleted file mode 100644
index 97930f5f..00000000
--- a/codegen/vulkan/scripts/cereal/api_log_decoder.py
+++ /dev/null
@@ -1,338 +0,0 @@
-import os
-from typing import List, Set, Dict, Optional
-
-from . import VulkanType, VulkanCompoundType
-from .wrapperdefs import VulkanWrapperGenerator
-
-
-class ApiLogDecoder(VulkanWrapperGenerator):
- """
- This class generates decoding logic for the graphics API logs captured by
- [GfxApiLogger](http://source/play-internal/battlestar/aosp/device/generic/vulkan-cereal/base/GfxApiLogger.h)
-
- This allows developers to see a pretty-printed version of the API log data when using
- print_gfx_logs.py
- """
-
- # List of Vulkan APIs that we will generate decoding logic for
- generated_apis = [
- "vkAcquireImageANDROID",
- "vkAllocateMemory",
- "vkBeginCommandBufferAsyncGOOGLE",
- "vkBindBufferMemory",
- "vkBindImageMemory",
- "vkCmdBeginRenderPass",
- "vkCmdBindDescriptorSets",
- "vkCmdBindIndexBuffer",
- "vkCmdBindPipeline",
- "vkCmdBindVertexBuffers",
- "vkCmdClearAttachments",
- "vkCmdClearColorImage",
- "vkCmdCopyBufferToImage",
- "vkCmdCopyImageToBuffer",
- "vkCmdDraw",
- "vkCmdDrawIndexed",
- "vkCmdEndRenderPass",
- "vkCmdPipelineBarrier",
- "vkCmdSetScissor",
- "vkCmdSetViewport",
- "vkCollectDescriptorPoolIdsGOOGLE",
- "vkCreateBufferWithRequirementsGOOGLE",
- "vkCreateDescriptorPool",
- "vkCreateDescriptorSetLayout",
- "vkCreateFence",
- "vkCreateFramebuffer",
- "vkCreateGraphicsPipelines",
- "vkCreateImageView",
- "vkCreateImageWithRequirementsGOOGLE",
- "vkCreatePipelineCache",
- "vkCreateRenderPass",
- "vkCreateSampler",
- "vkCreateSemaphore",
- "vkCreateShaderModule",
- "vkDestroyBuffer",
- "vkDestroyCommandPool",
- "vkDestroyDescriptorPool",
- "vkDestroyDescriptorSetLayout",
- "vkDestroyDevice",
- "vkDestroyFence",
- "vkDestroyFramebuffer",
- "vkDestroyImage",
- "vkDestroyImageView",
- "vkDestroyInstance",
- "vkDestroyPipeline",
- "vkDestroyPipelineCache",
- "vkDestroyPipelineLayout",
- "vkDestroyRenderPass",
- "vkDestroySemaphore",
- "vkDestroyShaderModule",
- "vkEndCommandBufferAsyncGOOGLE",
- "vkFreeCommandBuffers",
- "vkFreeMemory",
- "vkFreeMemorySyncGOOGLE",
- "vkGetFenceStatus",
- "vkGetMemoryHostAddressInfoGOOGLE",
- "vkGetBlobGOOGLE",
- "vkGetPhysicalDeviceFormatProperties",
- "vkGetPhysicalDeviceProperties2KHR",
- "vkGetPipelineCacheData",
- "vkGetSwapchainGrallocUsageANDROID",
- "vkQueueCommitDescriptorSetUpdatesGOOGLE",
- "vkQueueFlushCommandsGOOGLE",
- "vkQueueSignalReleaseImageANDROIDAsyncGOOGLE",
- "vkQueueSubmitAsyncGOOGLE",
- "vkQueueWaitIdle",
- "vkResetFences",
- "vkWaitForFences",
- ]
-
- def __init__(self, module, typeInfo):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
- self.typeInfo = typeInfo
-
- # Set of Vulkan structs that we need to write decoding logic for
- self.structs: Set[str] = set()
-
- # Maps enum group names to the list of enums in the group, for all enum groups in the spec
- # E.g.: "VkResult": ["VK_SUCCESS", "VK_NOT_READY", "VK_TIMEOUT", etc...]
- self.all_enums: Dict[str, List[str]] = {}
-
- # Set of Vulkan enums that we need to write decoding logic for
- self.needed_enums: Set[str] = {"VkStructureType"}
-
- def onBegin(self):
- self.module.append("""
-#####################################################################################################
-# Pretty-printer functions for Vulkan data structures
-# THIS FILE IS AUTO-GENERATED - DO NOT EDIT
-#
-# To re-generate this file, run generate-vulkan-sources.sh
-#####################################################################################################
-
-""".lstrip())
-
- def onGenGroup(self, groupinfo, groupName, alias=None):
- """Called for each enum group in the spec"""
- for enum in groupinfo.elem.findall("enum"):
- self.all_enums[groupName] = self.all_enums.get(groupName, []) + [enum.get('name')]
-
- def onEnd(self):
- for api_name in sorted(self.generated_apis):
- self.process_api(api_name)
- self.process_structs()
- self.process_enums()
-
- def process_api(self, api_name):
- """Main entry point to generate decoding logic for each Vulkan API"""
- api = self.typeInfo.apis[api_name]
- self.module.append('def OP_{}(printer, indent: int):\n'.format(api_name))
-
- # Decode the sequence number. All commands have sequence numbers, except those handled
- # by VkSubdecoder.cpp. The logic here is a bit of a hack since it's based on the command
- # name. Ideally, we would detect whether a particular command is part of a subdecode block
- # in the decoding script.
- if not api_name.startswith("vkCmd") and api_name != "vkBeginCommandBufferAsyncGOOGLE":
- self.module.append(' printer.write_int("seqno: ", 4, indent)\n')
-
- for param in api.parameters:
- # Add any structs that this API uses to the list of structs to write decoding logic for
- if self.typeInfo.isCompoundType(param.typeName):
- self.structs.add(param.typeName)
-
- # Don't try to print the pData field of vkQueueFlushCommandsGOOGLE, those are the
- # commands processed as part of the subdecode pass
- if api.name == "vkQueueFlushCommandsGOOGLE" and param.paramName == "pData":
- continue
-
- # Write out decoding logic for that parameter
- self.process_type(param)
-
- # Finally, add a return statement. This is needed in case the API has no parameters.
- self.module.append(' return\n\n')
-
- def process_structs(self):
- """Writes decoding logic for all the structs that we use"""
-
- # self.structs now contains all the structs used directly by the Vulkan APIs we use.
- # Recursively expand this set to add all the structs used by these structs.
- copy = self.structs.copy()
- self.structs.clear()
- for struct_name in copy:
- self.expand_needed_structs(struct_name)
-
- # Now we have the full list of structs that we need to write decoding logic for.
- # Write a decoder for each of them
- for struct_name in sorted(self.structs):
- struct = self.typeInfo.structs[struct_name]
- self.module.append('def struct_{}(printer, indent: int):\n'.format(struct_name))
- for member in self.get_members(struct):
- self.process_type(member)
- self.module.append('\n')
-
- def expand_needed_structs(self, struct_name: str):
- """
- Recursively adds all the structs used by a given struct to the list of structs to process
- """
- if struct_name in self.structs:
- return
- self.structs.add(struct_name)
- struct = self.typeInfo.structs[struct_name]
- for member in self.get_members(struct):
- if self.typeInfo.isCompoundType(member.typeName):
- self.expand_needed_structs(member.typeName)
-
- def get_members(self, struct: VulkanCompoundType):
- """
- Returns the members of a struct/union that we need to process.
- For structs, returns the list of all members
- For unions, returns a list with just the first member.
- """
- return struct.members[0:1] if struct.isUnion else struct.members
-
- def process_type(self, type: VulkanType):
- """
- Writes decoding logic for a single Vulkan type. This could be the parameter in a Vulkan API,
- or a struct member.
- """
- if type.typeName == "VkStructureType":
- self.module.append(
- ' printer.write_stype_and_pnext("{}", indent)\n'.format(
- type.parent.structEnumExpr))
- return
-
- if type.isNextPointer():
- return
-
- if type.paramName == "commandBuffer":
- if type.parent.name != "vkQueueFlushCommandsGOOGLE":
- return
-
- # Enums
- if type.isEnum(self.typeInfo):
- self.needed_enums.add(type.typeName)
- self.module.append(
- ' printer.write_enum("{}", {}, indent)\n'.format(
- type.paramName, type.typeName))
- return
-
- # Bitmasks
- if type.isBitmask(self.typeInfo):
- enum_type = self.typeInfo.bitmasks.get(type.typeName)
- if enum_type:
- self.needed_enums.add(enum_type)
- self.module.append(
- ' printer.write_flags("{}", {}, indent)\n'.format(
- type.paramName, enum_type))
- return
- # else, fall through and let the primitive type logic handle it
-
- # Structs or unions
- if self.typeInfo.isCompoundType(type.typeName):
- self.module.append(
- ' printer.write_struct("{name}", struct_{type}, {optional}, {count}, indent)\n'
- .format(name=type.paramName,
- type=type.typeName,
- optional=type.isOptionalPointer(),
- count=self.get_length_expression(type)))
- return
-
- # Null-terminated strings
- if type.isString():
- self.module.append(' printer.write_string("{}", None, indent)\n'.format(
- type.paramName))
- return
-
- # Arrays of primitive types
- if type.staticArrExpr and type.primitiveEncodingSize and type.primitiveEncodingSize <= 8:
- # Array sizes are specified either as a number, or as an enum value
- array_size = int(type.staticArrExpr) if type.staticArrExpr.isdigit() \
- else self.typeInfo.enumValues.get(type.staticArrExpr)
- assert array_size is not None, type.staticArrExpr
-
- if type.typeName == "char":
- self.module.append(
- ' printer.write_string("{}", {}, indent)\n'.format(
- type.paramName, array_size))
- elif type.typeName == "float":
- self.module.append(
- ' printer.write_float("{}", indent, count={})\n'
- .format(type.paramName, array_size))
- else:
- self.module.append(
- ' printer.write_int("{name}", {int_size}, indent, signed={signed}, count={array_size})\n'
- .format(name=type.paramName,
- array_size=array_size,
- int_size=type.primitiveEncodingSize,
- signed=type.isSigned()))
- return
-
- # Pointers
- if type.pointerIndirectionLevels > 0:
- # Assume that all uint32* are always serialized directly rather than passed by pointers.
- # This is probably not always true (e.g. out params) - fix this as needed.
- size = 4 if type.primitiveEncodingSize == 4 else 8
- self.module.append(
- ' {name} = printer.write_int("{name}", {size}, indent, optional={opt}, count={count}, big_endian={big_endian})\n'
- .format(name=type.paramName,
- size=size,
- opt=type.isOptionalPointer(),
- count=self.get_length_expression(type),
- big_endian=self.using_big_endian(type)))
- return
-
- # Primitive types (ints, floats)
- if type.isSimpleValueType(self.typeInfo) and type.primitiveEncodingSize:
- if type.typeName == "float":
- self.module.append(
- ' printer.write_float("{name}", indent)\n'.format(name=type.paramName))
- else:
- self.module.append(
- ' {name} = printer.write_int("{name}", {size}, indent, signed={signed}, big_endian={big_endian})\n'.format(
- name=type.paramName,
- size=type.primitiveEncodingSize,
- signed=type.isSigned(),
- big_endian=self.using_big_endian(type))
- )
- return
-
- raise NotImplementedError(
- "No decoding logic for {} {}".format(type.typeName, type.paramName))
-
- def using_big_endian(self, type: VulkanType):
- """For some reason gfxstream serializes some types as big endian"""
- return type.typeName == "size_t"
-
- def get_length_expression(self, type: VulkanType) -> Optional[str]:
- """Returns the length expression for a given type"""
- if type.lenExpr is None:
- return None
-
- if type.lenExpr.isalpha():
- return type.lenExpr
-
- # There are a couple of instances in the spec where we use a math expression to express the
- # length (e.g. VkPipelineMultisampleStateCreateInfo). CodeGen().generalLengthAccess() has
- # logic o parse these expressions correctly, but for now,we just use a simple lookup table.
- known_expressions = {
- r"latexmath:[\lceil{\mathit{rasterizationSamples} \over 32}\rceil]":
- "int(rasterizationSamples / 32)",
- r"latexmath:[\textrm{codeSize} \over 4]": "int(codeSize / 4)",
- r"null-terminated": None
- }
- if type.lenExpr in known_expressions:
- return known_expressions[type.lenExpr]
-
- raise NotImplementedError("Unknown length expression: " + type.lenExpr)
-
- def process_enums(self):
- """
- For each Vulkan enum that we use, write out a python dictionary mapping the enum values back
- to the enum name as a string
- """
- for enum_name in sorted(self.needed_enums):
- self.module.append('{} = {{\n'.format(enum_name))
- for identifier in self.all_enums[enum_name]:
- value = self.typeInfo.enumValues.get(identifier)
- if value is not None and isinstance(value, int):
- self.module.append(' {}: "{}",\n'.format(value, identifier))
- self.module.append('}\n\n')
diff --git a/codegen/vulkan/scripts/cereal/common/__init__.py b/codegen/vulkan/scripts/cereal/common/__init__.py
deleted file mode 100644
index dd6cdc99..00000000
--- a/codegen/vulkan/scripts/cereal/common/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from .vulkantypes import *
-from .codegen import *
diff --git a/codegen/vulkan/scripts/cereal/common/codegen.py b/codegen/vulkan/scripts/cereal/common/codegen.py
deleted file mode 100644
index b6b8a6b3..00000000
--- a/codegen/vulkan/scripts/cereal/common/codegen.py
+++ /dev/null
@@ -1,1061 +0,0 @@
-# Copyright (c) 2018 The Android Open Source Project
-# Copyright (c) 2018 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from .vulkantypes import VulkanType, VulkanTypeInfo, VulkanCompoundType, VulkanAPI
-from collections import OrderedDict
-from copy import copy
-from pathlib import Path, PurePosixPath
-
-import os
-import sys
-import shutil
-import subprocess
-
-# Class capturing a single file
-
-
-class SingleFileModule(object):
- def __init__(self, suffix, directory, basename, customAbsDir=None, suppress=False):
- self.directory = directory
- self.basename = basename
- self.customAbsDir = customAbsDir
- self.suffix = suffix
- self.file = None
-
- self.preamble = ""
- self.postamble = ""
-
- self.suppress = suppress
-
- def begin(self, globalDir):
- if self.suppress:
- return
-
- # Create subdirectory, if needed
- if self.customAbsDir:
- absDir = self.customAbsDir
- else:
- absDir = os.path.join(globalDir, self.directory)
-
- filename = os.path.join(absDir, self.basename)
-
- self.file = open(filename + self.suffix, "w", encoding="utf-8")
- self.file.write(self.preamble)
-
- def append(self, toAppend):
- if self.suppress:
- return
-
- self.file.write(toAppend)
-
- def end(self):
- if self.suppress:
- return
-
- self.file.write(self.postamble)
- self.file.close()
-
- def getMakefileSrcEntry(self):
- return ""
-
- def getCMakeSrcEntry(self):
- return ""
-
-# Class capturing a .cpp file and a .h file (a "C++ module")
-
-
-class Module(object):
-
- def __init__(
- self, directory, basename, customAbsDir=None, suppress=False, implOnly=False,
- headerOnly=False, suppressFeatureGuards=False):
- self._headerFileModule = SingleFileModule(
- ".h", directory, basename, customAbsDir, suppress or implOnly)
- self._implFileModule = SingleFileModule(
- ".cpp", directory, basename, customAbsDir, suppress or headerOnly)
-
- self._headerOnly = headerOnly
- self._implOnly = implOnly
-
- self.directory = directory
- self.basename = basename
- self._customAbsDir = customAbsDir
-
- self.suppressFeatureGuards = suppressFeatureGuards
-
- @property
- def suppress(self):
- raise AttributeError("suppress is write only")
-
- @suppress.setter
- def suppress(self, value: bool):
- self._headerFileModule.suppress = self._implOnly or value
- self._implFileModule.suppress = self._headerOnly or value
-
- @property
- def headerPreamble(self) -> str:
- return self._headerFileModule.preamble
-
- @headerPreamble.setter
- def headerPreamble(self, value: str):
- self._headerFileModule.preamble = value
-
- @property
- def headerPostamble(self) -> str:
- return self._headerFileModule.postamble
-
- @headerPostamble.setter
- def headerPostamble(self, value: str):
- self._headerFileModule.postamble = value
-
- @property
- def implPreamble(self) -> str:
- return self._implFileModule.preamble
-
- @implPreamble.setter
- def implPreamble(self, value: str):
- self._implFileModule.preamble = value
-
- @property
- def implPostamble(self) -> str:
- return self._implFileModule.postamble
-
- @implPostamble.setter
- def implPostamble(self, value: str):
- self._implFileModule.postamble = value
-
- def getMakefileSrcEntry(self):
- if self._customAbsDir:
- return self.basename + ".cpp \\\n"
- dirName = self.directory
- baseName = self.basename
- joined = os.path.join(dirName, baseName)
- return " " + joined + ".cpp \\\n"
-
- def getCMakeSrcEntry(self):
- if self._customAbsDir:
- return "\n" + self.basename + ".cpp "
- dirName = Path(self.directory)
- baseName = Path(self.basename)
- joined = PurePosixPath(dirName / baseName)
- return "\n " + str(joined) + ".cpp "
-
- def begin(self, globalDir):
- self._headerFileModule.begin(globalDir)
- self._implFileModule.begin(globalDir)
-
- def appendHeader(self, toAppend):
- self._headerFileModule.append(toAppend)
-
- def appendImpl(self, toAppend):
- self._implFileModule.append(toAppend)
-
- def end(self):
- self._headerFileModule.end()
- self._implFileModule.end()
-
- clang_format_command = shutil.which('clang-format')
- assert (clang_format_command is not None)
-
- def formatFile(filename: Path):
- assert (subprocess.call([clang_format_command, "-i",
- "--style=file", str(filename.resolve())]) == 0)
-
- if not self._headerFileModule.suppress:
- formatFile(Path(self._headerFileModule.file.name))
-
- if not self._implFileModule.suppress:
- formatFile(Path(self._implFileModule.file.name))
-
-
-class PyScript(SingleFileModule):
- def __init__(self, directory, basename, customAbsDir=None, suppress=False):
- super().__init__(".py", directory, basename, customAbsDir, suppress)
-
-
-# Class capturing a .proto protobuf definition file
-class Proto(SingleFileModule):
-
- def __init__(self, directory, basename, customAbsDir=None, suppress=False):
- super().__init__(".proto", directory, basename, customAbsDir, suppress)
-
- def getMakefileSrcEntry(self):
- super().getMakefileSrcEntry()
- if self.customAbsDir:
- return self.basename + ".proto \\\n"
- dirName = self.directory
- baseName = self.basename
- joined = os.path.join(dirName, baseName)
- return " " + joined + ".proto \\\n"
-
- def getCMakeSrcEntry(self):
- super().getCMakeSrcEntry()
- if self.customAbsDir:
- return "\n" + self.basename + ".proto "
-
- dirName = self.directory
- baseName = self.basename
- joined = os.path.join(dirName, baseName)
- return "\n " + joined + ".proto "
-
-class CodeGen(object):
-
- def __init__(self,):
- self.code = ""
- self.indentLevel = 0
- self.gensymCounter = [-1]
-
- def var(self, prefix="cgen_var"):
- self.gensymCounter[-1] += 1
- res = "%s_%s" % (prefix, '_'.join(str(i) for i in self.gensymCounter if i >= 0))
- return res
-
- def swapCode(self,):
- res = "%s" % self.code
- self.code = ""
- return res
-
- def indent(self,extra=0):
- return "".join(" " * (self.indentLevel + extra))
-
- def incrIndent(self,):
- self.indentLevel += 1
-
- def decrIndent(self,):
- if self.indentLevel > 0:
- self.indentLevel -= 1
-
- def beginBlock(self, bracketPrint=True):
- if bracketPrint:
- self.code += self.indent() + "{\n"
- self.indentLevel += 1
- self.gensymCounter.append(-1)
-
- def endBlock(self,bracketPrint=True):
- self.indentLevel -= 1
- if bracketPrint:
- self.code += self.indent() + "}\n"
- del self.gensymCounter[-1]
-
- def beginIf(self, cond):
- self.code += self.indent() + "if (" + cond + ")\n"
- self.beginBlock()
-
- def beginElse(self, cond = None):
- if cond is not None:
- self.code += \
- self.indent() + \
- "else if (" + cond + ")\n"
- else:
- self.code += self.indent() + "else\n"
- self.beginBlock()
-
- def endElse(self):
- self.endBlock()
-
- def endIf(self):
- self.endBlock()
-
- def beginSwitch(self, switchvar):
- self.code += self.indent() + "switch (" + switchvar + ")\n"
- self.beginBlock()
-
- def switchCase(self, switchval, blocked = False):
- self.code += self.indent() + "case %s:" % switchval
- self.beginBlock(bracketPrint = blocked)
-
- def switchCaseBreak(self, switchval, blocked = False):
- self.code += self.indent() + "case %s:" % switchval
- self.endBlock(bracketPrint = blocked)
-
- def switchCaseDefault(self, blocked = False):
- self.code += self.indent() + "default:" % switchval
- self.beginBlock(bracketPrint = blocked)
-
- def endSwitch(self):
- self.endBlock()
-
- def beginWhile(self, cond):
- self.code += self.indent() + "while (" + cond + ")\n"
- self.beginBlock()
-
- def endWhile(self):
- self.endBlock()
-
- def beginFor(self, initial, condition, increment):
- self.code += \
- self.indent() + "for (" + \
- "; ".join([initial, condition, increment]) + \
- ")\n"
- self.beginBlock()
-
- def endFor(self):
- self.endBlock()
-
- def beginLoop(self, loopVarType, loopVar, loopInit, loopBound):
- self.beginFor(
- "%s %s = %s" % (loopVarType, loopVar, loopInit),
- "%s < %s" % (loopVar, loopBound),
- "++%s" % (loopVar))
-
- def endLoop(self):
- self.endBlock()
-
- def stmt(self, code):
- self.code += self.indent() + code + ";\n"
-
- def line(self, code):
- self.code += self.indent() + code + "\n"
-
- def leftline(self, code):
- self.code += code + "\n"
-
- def makeCallExpr(self, funcName, parameters):
- return funcName + "(%s)" % (", ".join(parameters))
-
- def funcCall(self, lhs, funcName, parameters):
- res = self.indent()
-
- if lhs is not None:
- res += lhs + " = "
-
- res += self.makeCallExpr(funcName, parameters) + ";\n"
- self.code += res
-
- def funcCallRet(self, _lhs, funcName, parameters):
- res = self.indent()
- res += "return " + self.makeCallExpr(funcName, parameters) + ";\n"
- self.code += res
-
- # Given a VulkanType object, generate a C type declaration
- # with optional parameter name:
- # [const] [typename][*][const*] [paramName]
- def makeCTypeDecl(self, vulkanType, useParamName=True):
- constness = "const " if vulkanType.isConst else ""
- typeName = vulkanType.typeName
-
- if vulkanType.pointerIndirectionLevels == 0:
- ptrSpec = ""
- elif vulkanType.isPointerToConstPointer:
- ptrSpec = "* const*" if vulkanType.isConst else "**"
- if vulkanType.pointerIndirectionLevels > 2:
- ptrSpec += "*" * (vulkanType.pointerIndirectionLevels - 2)
- else:
- ptrSpec = "*" * vulkanType.pointerIndirectionLevels
-
- if useParamName and (vulkanType.paramName is not None):
- paramStr = (" " + vulkanType.paramName)
- else:
- paramStr = ""
-
- return "%s%s%s%s" % (constness, typeName, ptrSpec, paramStr)
-
- def makeRichCTypeDecl(self, vulkanType, useParamName=True):
- constness = "const " if vulkanType.isConst else ""
- typeName = vulkanType.typeName
-
- if vulkanType.pointerIndirectionLevels == 0:
- ptrSpec = ""
- elif vulkanType.isPointerToConstPointer:
- ptrSpec = "* const*" if vulkanType.isConst else "**"
- if vulkanType.pointerIndirectionLevels > 2:
- ptrSpec += "*" * (vulkanType.pointerIndirectionLevels - 2)
- else:
- ptrSpec = "*" * vulkanType.pointerIndirectionLevels
-
- if useParamName and (vulkanType.paramName is not None):
- paramStr = (" " + vulkanType.paramName)
- else:
- paramStr = ""
-
- if vulkanType.staticArrExpr:
- staticArrInfo = "[%s]" % vulkanType.staticArrExpr
- else:
- staticArrInfo = ""
-
- return "%s%s%s%s%s" % (constness, typeName, ptrSpec, paramStr, staticArrInfo)
-
- # Given a VulkanAPI object, generate the C function protype:
- # <returntype> <funcname>(<parameters>)
- def makeFuncProto(self, vulkanApi, useParamName=True):
-
- protoBegin = "%s %s" % (self.makeCTypeDecl(
- vulkanApi.retType, useParamName=False), vulkanApi.name)
-
- def getFuncArgDecl(param):
- if param.staticArrExpr:
- return self.makeCTypeDecl(param, useParamName=useParamName) + ("[%s]" % param.staticArrExpr)
- else:
- return self.makeCTypeDecl(param, useParamName=useParamName)
-
- protoParams = "(\n %s)" % ((",\n%s" % self.indent(1)).join(
- list(map(
- getFuncArgDecl,
- vulkanApi.parameters))))
-
- return protoBegin + protoParams
-
- def makeFuncAlias(self, nameDst, nameSrc):
- return "DEFINE_ALIAS_FUNCTION({}, {})\n\n".format(nameSrc, nameDst)
-
- def makeFuncDecl(self, vulkanApi):
- return self.makeFuncProto(vulkanApi) + ";\n\n"
-
- def makeFuncImpl(self, vulkanApi, codegenFunc):
- self.swapCode()
-
- self.line(self.makeFuncProto(vulkanApi))
- self.beginBlock()
- codegenFunc(self)
- self.endBlock()
-
- return self.swapCode() + "\n"
-
- def emitFuncImpl(self, vulkanApi, codegenFunc):
- self.line(self.makeFuncProto(vulkanApi))
- self.beginBlock()
- codegenFunc(self)
- self.endBlock()
-
- def makeStructAccess(self,
- vulkanType,
- structVarName,
- asPtr=True,
- structAsPtr=True,
- accessIndex=None):
-
- deref = "->" if structAsPtr else "."
-
- indexExpr = (" + %s" % accessIndex) if accessIndex else ""
-
- addrOfExpr = "" if vulkanType.accessibleAsPointer() or (
- not asPtr) else "&"
-
- return "%s%s%s%s%s" % (addrOfExpr, structVarName, deref,
- vulkanType.paramName, indexExpr)
-
- def makeRawLengthAccess(self, vulkanType):
- lenExpr = vulkanType.getLengthExpression()
-
- if not lenExpr:
- return None, None
-
- if lenExpr == "null-terminated":
- return "strlen(%s)" % vulkanType.paramName, None
-
- return lenExpr, None
-
- def makeLengthAccessFromStruct(self,
- structInfo,
- vulkanType,
- structVarName,
- asPtr=True):
- # Handle special cases first
- # Mostly when latexmath is involved
- def handleSpecialCases(structInfo, vulkanType, structVarName, asPtr):
- cases = [
- {
- "structName": "VkShaderModuleCreateInfo",
- "field": "pCode",
- "lenExprMember": "codeSize",
- "postprocess": lambda expr: "(%s / 4)" % expr
- },
- {
- "structName": "VkPipelineMultisampleStateCreateInfo",
- "field": "pSampleMask",
- "lenExprMember": "rasterizationSamples",
- "postprocess": lambda expr: "(((%s) + 31) / 32)" % expr
- },
- {
- "structName": "VkAccelerationStructureVersionInfoKHR",
- "field": "pVersionData",
- "lenExprMember": "",
- "postprocess": lambda _: "2*VK_UUID_SIZE"
- },
- ]
-
- for c in cases:
- if (structInfo.name, vulkanType.paramName) == (c["structName"],
- c["field"]):
- deref = "->" if asPtr else "."
- expr = "%s%s%s" % (structVarName, deref,
- c["lenExprMember"])
- lenAccessGuardExpr = "%s" % structVarName
- return c["postprocess"](expr), lenAccessGuardExpr
-
- return None, None
-
- specialCaseAccess = \
- handleSpecialCases(
- structInfo, vulkanType, structVarName, asPtr)
-
- if specialCaseAccess != (None, None):
- return specialCaseAccess
-
- lenExpr = vulkanType.getLengthExpression()
-
- if not lenExpr:
- return None, None
-
- deref = "->" if asPtr else "."
- lenAccessGuardExpr = "%s" % (
-
- structVarName) if deref else None
- if lenExpr == "null-terminated":
- return "strlen(%s%s%s)" % (structVarName, deref,
- vulkanType.paramName), lenAccessGuardExpr
-
- if not structInfo.getMember(lenExpr):
- return self.makeRawLengthAccess(vulkanType)
-
- return "%s%s%s" % (structVarName, deref, lenExpr), lenAccessGuardExpr
-
- def makeLengthAccessFromApi(self, api, vulkanType):
- # Handle special cases first
- # Mostly when :: is involved
- def handleSpecialCases(vulkanType):
- lenExpr = vulkanType.getLengthExpression()
-
- if lenExpr is None:
- return None, None
-
- if "::" in lenExpr:
- structVarName, memberVarName = lenExpr.split("::")
- lenAccessGuardExpr = "%s" % (structVarName)
- return "%s->%s" % (structVarName, memberVarName), lenAccessGuardExpr
- return None, None
-
- specialCaseAccess = handleSpecialCases(vulkanType)
-
- if specialCaseAccess != (None, None):
- return specialCaseAccess
-
- lenExpr = vulkanType.getLengthExpression()
-
- if not lenExpr:
- return None, None
-
- lenExprInfo = api.getParameter(lenExpr)
-
- if not lenExprInfo:
- return self.makeRawLengthAccess(vulkanType)
-
- if lenExpr == "null-terminated":
- return "strlen(%s)" % vulkanType.paramName(), None
- else:
- deref = "*" if lenExprInfo.pointerIndirectionLevels > 0 else ""
- lenAccessGuardExpr = "%s" % lenExpr if deref else None
- return "(%s(%s))" % (deref, lenExpr), lenAccessGuardExpr
-
- def accessParameter(self, param, asPtr=True):
- if asPtr:
- if param.pointerIndirectionLevels > 0:
- return param.paramName
- else:
- return "&%s" % param.paramName
- else:
- return param.paramName
-
- def sizeofExpr(self, vulkanType):
- return "sizeof(%s)" % (
- self.makeCTypeDecl(vulkanType, useParamName=False))
-
- def generalAccess(self,
- vulkanType,
- parentVarName=None,
- asPtr=True,
- structAsPtr=True):
- if vulkanType.parent is None:
- if parentVarName is None:
- return self.accessParameter(vulkanType, asPtr=asPtr)
- else:
- return self.accessParameter(vulkanType.withModifiedName(parentVarName), asPtr=asPtr)
-
- if isinstance(vulkanType.parent, VulkanCompoundType):
- return self.makeStructAccess(
- vulkanType, parentVarName, asPtr=asPtr, structAsPtr=structAsPtr)
-
- if isinstance(vulkanType.parent, VulkanAPI):
- if parentVarName is None:
- return self.accessParameter(vulkanType, asPtr=asPtr)
- else:
- return self.accessParameter(vulkanType.withModifiedName(parentVarName), asPtr=asPtr)
-
- os.abort("Could not find a way to access Vulkan type %s" %
- vulkanType.name)
-
- def makeLengthAccess(self, vulkanType, parentVarName="parent"):
- if vulkanType.parent is None:
- return self.makeRawLengthAccess(vulkanType)
-
- if isinstance(vulkanType.parent, VulkanCompoundType):
- return self.makeLengthAccessFromStruct(
- vulkanType.parent, vulkanType, parentVarName, asPtr=True)
-
- if isinstance(vulkanType.parent, VulkanAPI):
- return self.makeLengthAccessFromApi(vulkanType.parent, vulkanType)
-
- os.abort("Could not find a way to access length of Vulkan type %s" %
- vulkanType.name)
-
- def generalLengthAccess(self, vulkanType, parentVarName="parent"):
- return self.makeLengthAccess(vulkanType, parentVarName)[0]
-
- def generalLengthAccessGuard(self, vulkanType, parentVarName="parent"):
- return self.makeLengthAccess(vulkanType, parentVarName)[1]
-
- def vkApiCall(self, api, customPrefix="", globalStatePrefix="", customParameters=None, checkForDeviceLost=False, checkForOutOfMemory=False):
- callLhs = None
-
- retTypeName = api.getRetTypeExpr()
- retVar = None
-
- if retTypeName != "void":
- retVar = api.getRetVarExpr()
- self.stmt("%s %s = (%s)0" % (retTypeName, retVar, retTypeName))
- callLhs = retVar
-
- if customParameters is None:
- self.funcCall(
- callLhs, customPrefix + api.name, [p.paramName for p in api.parameters])
- else:
- self.funcCall(
- callLhs, customPrefix + api.name, customParameters)
-
- if retTypeName == "VkResult" and checkForDeviceLost:
- self.stmt("if ((%s) == VK_ERROR_DEVICE_LOST) %sDeviceLost()" % (callLhs, globalStatePrefix))
-
- if retTypeName == "VkResult" and checkForOutOfMemory:
- if api.name == "vkAllocateMemory":
- self.stmt(
- "%sCheckOutOfMemory(%s, opcode, context, std::make_optional<uint64_t>(pAllocateInfo->allocationSize))"
- % (globalStatePrefix, callLhs))
- else:
- self.stmt(
- "%sCheckOutOfMemory(%s, opcode, context)"
- % (globalStatePrefix, callLhs))
-
- return (retTypeName, retVar)
-
- def makeCheckVkSuccess(self, expr):
- return "((%s) == VK_SUCCESS)" % expr
-
- def makeReinterpretCast(self, varName, typeName, const=True):
- return "reinterpret_cast<%s%s*>(%s)" % \
- ("const " if const else "", typeName, varName)
-
- def validPrimitive(self, typeInfo, typeName):
- size = typeInfo.getPrimitiveEncodingSize(typeName)
- return size != None
-
- def makePrimitiveStreamMethod(self, typeInfo, typeName, direction="write"):
- if not self.validPrimitive(typeInfo, typeName):
- return None
-
- size = typeInfo.getPrimitiveEncodingSize(typeName)
- prefix = "put" if direction == "write" else "get"
- suffix = None
- if size == 1:
- suffix = "Byte"
- elif size == 2:
- suffix = "Be16"
- elif size == 4:
- suffix = "Be32"
- elif size == 8:
- suffix = "Be64"
-
- if suffix:
- return prefix + suffix
-
- return None
-
- def makePrimitiveStreamMethodInPlace(self, typeInfo, typeName, direction="write"):
- if not self.validPrimitive(typeInfo, typeName):
- return None
-
- size = typeInfo.getPrimitiveEncodingSize(typeName)
- prefix = "to" if direction == "write" else "from"
- suffix = None
- if size == 1:
- suffix = "Byte"
- elif size == 2:
- suffix = "Be16"
- elif size == 4:
- suffix = "Be32"
- elif size == 8:
- suffix = "Be64"
-
- if suffix:
- return prefix + suffix
-
- return None
-
- def streamPrimitive(self, typeInfo, streamVar, accessExpr, accessType, direction="write"):
- accessTypeName = accessType.typeName
-
- if accessType.pointerIndirectionLevels == 0 and not self.validPrimitive(typeInfo, accessTypeName):
- print("Tried to stream a non-primitive type: %s" % accessTypeName)
- os.abort()
-
- needPtrCast = False
-
- if accessType.pointerIndirectionLevels > 0:
- streamSize = 8
- streamStorageVarType = "uint64_t"
- needPtrCast = True
- streamMethod = "putBe64" if direction == "write" else "getBe64"
- else:
- streamSize = typeInfo.getPrimitiveEncodingSize(accessTypeName)
- if streamSize == 1:
- streamStorageVarType = "uint8_t"
- elif streamSize == 2:
- streamStorageVarType = "uint16_t"
- elif streamSize == 4:
- streamStorageVarType = "uint32_t"
- elif streamSize == 8:
- streamStorageVarType = "uint64_t"
- streamMethod = self.makePrimitiveStreamMethod(
- typeInfo, accessTypeName, direction=direction)
-
- streamStorageVar = self.var()
-
- accessCast = self.makeRichCTypeDecl(accessType, useParamName=False)
-
- ptrCast = "(uintptr_t)" if needPtrCast else ""
-
- if direction == "read":
- self.stmt("%s = (%s)%s%s->%s()" %
- (accessExpr,
- accessCast,
- ptrCast,
- streamVar,
- streamMethod))
- else:
- self.stmt("%s %s = (%s)%s%s" %
- (streamStorageVarType, streamStorageVar,
- streamStorageVarType, ptrCast, accessExpr))
- self.stmt("%s->%s(%s)" %
- (streamVar, streamMethod, streamStorageVar))
-
- def memcpyPrimitive(self, typeInfo, streamVar, accessExpr, accessType, direction="write"):
- accessTypeName = accessType.typeName
-
- if accessType.pointerIndirectionLevels == 0 and not self.validPrimitive(typeInfo, accessTypeName):
- print("Tried to stream a non-primitive type: %s" % accessTypeName)
- os.abort()
-
- needPtrCast = False
-
- streamSize = 8
-
- if accessType.pointerIndirectionLevels > 0:
- streamSize = 8
- streamStorageVarType = "uint64_t"
- needPtrCast = True
- streamMethod = "toBe64" if direction == "write" else "fromBe64"
- else:
- streamSize = typeInfo.getPrimitiveEncodingSize(accessTypeName)
- if streamSize == 1:
- streamStorageVarType = "uint8_t"
- elif streamSize == 2:
- streamStorageVarType = "uint16_t"
- elif streamSize == 4:
- streamStorageVarType = "uint32_t"
- elif streamSize == 8:
- streamStorageVarType = "uint64_t"
- streamMethod = self.makePrimitiveStreamMethodInPlace(
- typeInfo, accessTypeName, direction=direction)
-
- streamStorageVar = self.var()
-
- accessCast = self.makeRichCTypeDecl(accessType, useParamName=False)
-
- if direction == "read":
- accessCast = self.makeRichCTypeDecl(
- accessType.getForNonConstAccess(), useParamName=False)
-
- ptrCast = "(uintptr_t)" if needPtrCast else ""
-
- if direction == "read":
- self.stmt("memcpy((%s*)&%s, %s, %s)" %
- (accessCast,
- accessExpr,
- streamVar,
- str(streamSize)))
- self.stmt("android::base::Stream::%s((uint8_t*)&%s)" % (
- streamMethod,
- accessExpr))
- else:
- self.stmt("%s %s = (%s)%s%s" %
- (streamStorageVarType, streamStorageVar,
- streamStorageVarType, ptrCast, accessExpr))
- self.stmt("memcpy(%s, &%s, %s)" %
- (streamVar, streamStorageVar, str(streamSize)))
- self.stmt("android::base::Stream::%s((uint8_t*)%s)" % (
- streamMethod,
- streamVar))
-
- def countPrimitive(self, typeInfo, accessType):
- accessTypeName = accessType.typeName
-
- if accessType.pointerIndirectionLevels == 0 and not self.validPrimitive(typeInfo, accessTypeName):
- print("Tried to count a non-primitive type: %s" % accessTypeName)
- os.abort()
-
- needPtrCast = False
-
- if accessType.pointerIndirectionLevels > 0:
- streamSize = 8
- else:
- streamSize = typeInfo.getPrimitiveEncodingSize(accessTypeName)
-
- return streamSize
-
-# Class to wrap a Vulkan API call.
-#
-# The user gives a generic callback, |codegenDef|,
-# that takes a CodeGen object and a VulkanAPI object as arguments.
-# codegenDef uses CodeGen along with the VulkanAPI object
-# to generate the function body.
-class VulkanAPIWrapper(object):
-
- def __init__(self,
- customApiPrefix,
- extraParameters=None,
- returnTypeOverride=None,
- codegenDef=None):
- self.customApiPrefix = customApiPrefix
- self.extraParameters = extraParameters
- self.returnTypeOverride = returnTypeOverride
-
- self.codegen = CodeGen()
-
- self.definitionFunc = codegenDef
-
- # Private function
-
- def makeApiFunc(self, typeInfo, apiName):
- customApi = copy(typeInfo.apis[apiName])
- customApi.name = self.customApiPrefix + customApi.name
- if self.extraParameters is not None:
- if isinstance(self.extraParameters, list):
- customApi.parameters = \
- self.extraParameters + customApi.parameters
- else:
- os.abort(
- "Type of extra parameters to custom API not valid. Expected list, got %s" % type(
- self.extraParameters))
-
- if self.returnTypeOverride is not None:
- customApi.retType = self.returnTypeOverride
- return customApi
-
- self.makeApi = makeApiFunc
-
- def setCodegenDef(self, codegenDefFunc):
- self.definitionFunc = codegenDefFunc
-
- def makeDecl(self, typeInfo, apiName):
- return self.codegen.makeFuncProto(
- self.makeApi(self, typeInfo, apiName)) + ";\n\n"
-
- def makeDefinition(self, typeInfo, apiName, isStatic=False):
- vulkanApi = self.makeApi(self, typeInfo, apiName)
-
- self.codegen.swapCode()
- self.codegen.beginBlock()
-
- if self.definitionFunc is None:
- print("ERROR: No definition found for (%s, %s)" %
- (vulkanApi.name, self.customApiPrefix))
- sys.exit(1)
-
- self.definitionFunc(self.codegen, vulkanApi)
-
- self.codegen.endBlock()
-
- return ("static " if isStatic else "") + self.codegen.makeFuncProto(
- vulkanApi) + "\n" + self.codegen.swapCode() + "\n"
-
-# Base class for wrapping all Vulkan API objects. These work with Vulkan
-# Registry generators and have gen* triggers. They tend to contain
-# VulkanAPIWrapper objects to make it easier to generate the code.
-class VulkanWrapperGenerator(object):
-
- def __init__(self, module: Module, typeInfo: VulkanTypeInfo):
- self.module: Module = module
- self.typeInfo: VulkanTypeInfo = typeInfo
- self.extensionStructTypes = OrderedDict()
-
- def onBegin(self):
- pass
-
- def onEnd(self):
- pass
-
- def onBeginFeature(self, featureName, featureType):
- pass
-
- def onFeatureNewCmd(self, cmdName):
- pass
-
- def onEndFeature(self):
- pass
-
- def onGenType(self, typeInfo, name, alias):
- category = self.typeInfo.categoryOf(name)
- if category in ["struct", "union"] and not alias:
- structInfo = self.typeInfo.structs[name]
- if structInfo.structExtendsExpr:
- self.extensionStructTypes[name] = structInfo
- pass
-
- def onGenStruct(self, typeInfo, name, alias):
- pass
-
- def onGenGroup(self, groupinfo, groupName, alias=None):
- pass
-
- def onGenEnum(self, enuminfo, name, alias):
- pass
-
- def onGenCmd(self, cmdinfo, name, alias):
- pass
-
- # Below Vulkan structure types may correspond to multiple Vulkan structs
- # due to a conflict between different Vulkan registries. In order to get
- # the correct Vulkan struct type, we need to check the type of its "root"
- # struct as well.
- ROOT_TYPE_MAPPING = {
- "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT": {
- "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2": "VkPhysicalDeviceFragmentDensityMapFeaturesEXT",
- "VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO": "VkPhysicalDeviceFragmentDensityMapFeaturesEXT",
- "VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO": "VkImportColorBufferGOOGLE",
- "default": "VkPhysicalDeviceFragmentDensityMapFeaturesEXT",
- },
- "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT": {
- "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2": "VkPhysicalDeviceFragmentDensityMapPropertiesEXT",
- "VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO": "VkCreateBlobGOOGLE",
- "default": "VkPhysicalDeviceFragmentDensityMapPropertiesEXT",
- },
- "VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT": {
- "VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO": "VkRenderPassFragmentDensityMapCreateInfoEXT",
- "VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2": "VkRenderPassFragmentDensityMapCreateInfoEXT",
- "VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO": "VkImportBufferGOOGLE",
- "default": "VkRenderPassFragmentDensityMapCreateInfoEXT",
- },
- }
-
- def emitForEachStructExtension(self, cgen, retType, triggerVar, forEachFunc, autoBreak=True, defaultEmit=None, nullEmit=None, rootTypeVar=None):
- def readStructType(structTypeName, structVarName, cgen):
- cgen.stmt("uint32_t %s = (uint32_t)%s(%s)" % \
- (structTypeName, "goldfish_vk_struct_type", structVarName))
-
- def castAsStruct(varName, typeName, const=True):
- return "reinterpret_cast<%s%s*>(%s)" % \
- ("const " if const else "", typeName, varName)
-
- def doDefaultReturn(cgen):
- if retType.typeName == "void":
- cgen.stmt("return")
- else:
- cgen.stmt("return (%s)0" % retType.typeName)
-
- cgen.beginIf("!%s" % triggerVar.paramName)
- if nullEmit is None:
- doDefaultReturn(cgen)
- else:
- nullEmit(cgen)
- cgen.endIf()
-
- readStructType("structType", triggerVar.paramName, cgen)
-
- cgen.line("switch(structType)")
- cgen.beginBlock()
-
- currFeature = None
-
- for ext in self.extensionStructTypes.values():
- if not currFeature:
- cgen.leftline("#ifdef %s" % ext.feature)
- currFeature = ext.feature
-
- if currFeature and ext.feature != currFeature:
- cgen.leftline("#endif")
- cgen.leftline("#ifdef %s" % ext.feature)
- currFeature = ext.feature
-
- enum = ext.structEnumExpr
- cgen.line("case %s:" % enum)
- cgen.beginBlock()
-
- if rootTypeVar is not None and enum in VulkanWrapperGenerator.ROOT_TYPE_MAPPING:
- cgen.line("switch(%s)" % rootTypeVar.paramName)
- cgen.beginBlock()
- kv = VulkanWrapperGenerator.ROOT_TYPE_MAPPING[enum]
- for k in kv:
- v = self.extensionStructTypes[kv[k]]
- if k == "default":
- cgen.line("%s:" % k)
- else:
- cgen.line("case %s:" % k)
- cgen.beginBlock()
- castedAccess = castAsStruct(
- triggerVar.paramName, v.name, const=triggerVar.isConst)
- forEachFunc(v, castedAccess, cgen)
- cgen.line("break;")
- cgen.endBlock()
- cgen.endBlock()
- else:
- castedAccess = castAsStruct(
- triggerVar.paramName, ext.name, const=triggerVar.isConst)
- forEachFunc(ext, castedAccess, cgen)
-
- if autoBreak:
- cgen.stmt("break")
- cgen.endBlock()
-
- if currFeature:
- cgen.leftline("#endif")
-
- cgen.line("default:")
- cgen.beginBlock()
- if defaultEmit is None:
- doDefaultReturn(cgen)
- else:
- defaultEmit(cgen)
- cgen.endBlock()
-
- cgen.endBlock()
-
- def emitForEachStructExtensionGeneral(self, cgen, forEachFunc, doFeatureIfdefs=False):
- currFeature = None
-
- for (i, ext) in enumerate(self.extensionStructTypes.values()):
- if doFeatureIfdefs:
- if not currFeature:
- cgen.leftline("#ifdef %s" % ext.feature)
- currFeature = ext.feature
-
- if currFeature and ext.feature != currFeature:
- cgen.leftline("#endif")
- cgen.leftline("#ifdef %s" % ext.feature)
- currFeature = ext.feature
-
- forEachFunc(i, ext, cgen)
-
- if doFeatureIfdefs:
- if currFeature:
- cgen.leftline("#endif")
diff --git a/codegen/vulkan/scripts/cereal/common/vulkantypes.py b/codegen/vulkan/scripts/cereal/common/vulkantypes.py
deleted file mode 100644
index dc3a9072..00000000
--- a/codegen/vulkan/scripts/cereal/common/vulkantypes.py
+++ /dev/null
@@ -1,1216 +0,0 @@
-# Copyright (c) 2018 The Android Open Source Project
-# Copyright (c) 2018 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-from typing import Dict, Optional, List, Set, Union
-from xml.etree.ElementTree import Element
-
-from generator import noneStr
-
-from copy import copy
-from string import whitespace
-
-# Holds information about core Vulkan objects
-# and the API calls that are used to create/destroy each one.
-class HandleInfo(object):
- def __init__(self, name, createApis, destroyApis):
- self.name = name
- self.createApis = createApis
- self.destroyApis = destroyApis
-
- def isCreateApi(self, apiName):
- return apiName == self.createApis or (apiName in self.createApis)
-
- def isDestroyApi(self, apiName):
- if self.destroyApis is None:
- return False
- return apiName == self.destroyApis or (apiName in self.destroyApis)
-
-DISPATCHABLE_HANDLE_TYPES = [
- "VkInstance",
- "VkPhysicalDevice",
- "VkDevice",
- "VkQueue",
- "VkCommandBuffer",
-]
-
-NON_DISPATCHABLE_HANDLE_TYPES = [
- "VkDeviceMemory",
- "VkBuffer",
- "VkBufferView",
- "VkImage",
- "VkImageView",
- "VkShaderModule",
- "VkDescriptorPool",
- "VkDescriptorSetLayout",
- "VkDescriptorSet",
- "VkSampler",
- "VkPipeline",
- "VkPipelineLayout",
- "VkRenderPass",
- "VkFramebuffer",
- "VkPipelineCache",
- "VkCommandPool",
- "VkFence",
- "VkSemaphore",
- "VkEvent",
- "VkQueryPool",
- "VkSamplerYcbcrConversion",
- "VkSamplerYcbcrConversionKHR",
- "VkDescriptorUpdateTemplate",
- "VkSurfaceKHR",
- "VkSwapchainKHR",
- "VkDisplayKHR",
- "VkDisplayModeKHR",
- "VkObjectTableNVX",
- "VkIndirectCommandsLayoutNVX",
- "VkValidationCacheEXT",
- "VkDebugReportCallbackEXT",
- "VkDebugUtilsMessengerEXT",
- "VkAccelerationStructureNV",
- "VkIndirectCommandsLayoutNV",
- "VkAccelerationStructureKHR",
-]
-
-CUSTOM_HANDLE_CREATE_TYPES = [
- "VkPhysicalDevice",
- "VkQueue",
- "VkPipeline",
- "VkDeviceMemory",
- "VkDescriptorSet",
- "VkCommandBuffer",
- "VkRenderPass",
-]
-
-HANDLE_TYPES = list(sorted(list(set(DISPATCHABLE_HANDLE_TYPES +
- NON_DISPATCHABLE_HANDLE_TYPES + CUSTOM_HANDLE_CREATE_TYPES))))
-
-HANDLE_INFO = {}
-
-for h in HANDLE_TYPES:
- if h in CUSTOM_HANDLE_CREATE_TYPES:
- if h == "VkPhysicalDevice":
- HANDLE_INFO[h] = \
- HandleInfo(
- "VkPhysicalDevice",
- "vkEnumeratePhysicalDevices", None)
- if h == "VkQueue":
- HANDLE_INFO[h] = \
- HandleInfo(
- "VkQueue",
- ["vkGetDeviceQueue", "vkGetDeviceQueue2"],
- None)
- if h == "VkPipeline":
- HANDLE_INFO[h] = \
- HandleInfo(
- "VkPipeline",
- ["vkCreateGraphicsPipelines", "vkCreateComputePipelines"],
- "vkDestroyPipeline")
- if h == "VkDeviceMemory":
- HANDLE_INFO[h] = \
- HandleInfo("VkDeviceMemory",
- "vkAllocateMemory", ["vkFreeMemory", "vkFreeMemorySyncGOOGLE"])
- if h == "VkDescriptorSet":
- HANDLE_INFO[h] = \
- HandleInfo("VkDescriptorSet", "vkAllocateDescriptorSets",
- "vkFreeDescriptorSets")
- if h == "VkCommandBuffer":
- HANDLE_INFO[h] = \
- HandleInfo("VkCommandBuffer", "vkAllocateCommandBuffers",
- "vkFreeCommandBuffers")
- if h == "VkRenderPass":
- HANDLE_INFO[h] = \
- HandleInfo(
- "VkRenderPass",
- ["vkCreateRenderPass", "vkCreateRenderPass2", "vkCreateRenderPass2KHR"],
- "vkDestroyRenderPass")
- else:
- HANDLE_INFO[h] = \
- HandleInfo(h, "vkCreate" + h[2:], "vkDestroy" + h[2:])
-
-EXCLUDED_APIS = [
- "vkEnumeratePhysicalDeviceGroups",
-]
-
-EXPLICITLY_ABI_PORTABLE_TYPES = [
- "VkResult",
- "VkBool32",
- "VkSampleMask",
- "VkFlags",
- "VkDeviceSize",
-]
-
-EXPLICITLY_ABI_NON_PORTABLE_TYPES = [
- "size_t"
-]
-
-NON_ABI_PORTABLE_TYPE_CATEGORIES = [
- "handle",
- "funcpointer",
-]
-
-DEVICE_MEMORY_INFO_KEYS = [
- "devicememoryhandle",
- "devicememoryoffset",
- "devicememorysize",
- "devicememorytypeindex",
- "devicememorytypebits",
-]
-
-TRIVIAL_TRANSFORMED_TYPES = [
- "VkPhysicalDeviceExternalImageFormatInfo",
- "VkPhysicalDeviceExternalBufferInfo",
- "VkExternalMemoryImageCreateInfo",
- "VkExternalMemoryBufferCreateInfo",
- "VkExportMemoryAllocateInfo",
- "VkExternalImageFormatProperties",
- "VkExternalBufferProperties",
-]
-
-NON_TRIVIAL_TRANSFORMED_TYPES = [
- "VkExternalMemoryProperties",
- "VkImageCreateInfo",
-]
-
-TRANSFORMED_TYPES = TRIVIAL_TRANSFORMED_TYPES + NON_TRIVIAL_TRANSFORMED_TYPES
-
-# Holds information about a Vulkan type instance (i.e., not a type definition).
-# Type instances are used as struct field definitions or function parameters,
-# to be later fed to code generation.
-# VulkanType instances can be constructed in two ways:
-# 1. From an XML tag with <type> / <param> tags in vk.xml,
-# using makeVulkanTypeFromXMLTag
-# 2. User-defined instances with makeVulkanTypeSimple.
-class VulkanType(object):
-
- def __init__(self):
- self.parent: Optional[VulkanType] = None
- self.typeName: str = ""
-
- self.isTransformed = False
-
- self.paramName: Optional[str] = None
-
- self.lenExpr: Optional[str] = None # Value of the `len` attribute in the spec
- self.isOptional: bool = False
- self.optionalStr: Optional[str] = None # Value of the `optional` attribute in the spec
-
- self.isConst = False
-
- # "" means it's not a static array, otherwise this is the total size of
- # all elements. e.g. staticArrExpr of "x[3][2][8]" will be "((3)*(2)*(8))".
- self.staticArrExpr = ""
- # "" means it's not a static array, otherwise it's the raw expression
- # of static array size, which can be one-dimensional or multi-dimensional.
- self.rawStaticArrExpr = ""
-
- self.pointerIndirectionLevels = 0 # 0 means not pointer
- self.isPointerToConstPointer = False
-
- self.primitiveEncodingSize = None
-
- self.deviceMemoryInfoParameterIndices = None
-
- # Annotations
- # Environment annotation for binding current
- # variables to sub-structures
- self.binds = {}
-
- # Device memory annotations
-
- # self.deviceMemoryAttrib/Val stores
- # device memory info attributes from the XML.
- # devicememoryhandle
- # devicememoryoffset
- # devicememorysize
- # devicememorytypeindex
- # devicememorytypebits
- self.deviceMemoryAttrib = None
- self.deviceMemoryVal = None
-
- # Filter annotations
- self.filterVar = None
- self.filterVals = None
- self.filterFunc = None
- self.filterOtherwise = None
-
- # Stream feature
- self.streamFeature = None
-
- # All other annotations
- self.attribs = {}
-
- self.nonDispatchableHandleCreate = False
- self.nonDispatchableHandleDestroy = False
- self.dispatchHandle = False
- self.dispatchableHandleCreate = False
- self.dispatchableHandleDestroy = False
-
-
- def __str__(self,):
- return ("(vulkantype %s %s paramName %s len %s optional? %s "
- "staticArrExpr %s)") % (
- self.typeName + ("*" * self.pointerIndirectionLevels) +
- ("ptr2constptr" if self.isPointerToConstPointer else ""), "const"
- if self.isConst else "nonconst", self.paramName, self.lenExpr,
- self.isOptional, self.staticArrExpr)
-
- def isString(self):
- return self.pointerIndirectionLevels == 1 and (self.typeName == "char")
-
- def isArrayOfStrings(self):
- return self.isPointerToConstPointer and (self.typeName == "char")
-
- def primEncodingSize(self):
- return self.primitiveEncodingSize
-
- # Utility functions to make codegen life easier.
- # This method derives the correct "count" expression if possible.
- # Otherwise, returns None or "null-terminated" if a string.
- def getLengthExpression(self):
- if self.staticArrExpr != "":
- return self.staticArrExpr
- if self.lenExpr:
- return self.lenExpr
- return None
-
- # Can we just pass this to functions expecting T*
- def accessibleAsPointer(self):
- if self.staticArrExpr != "":
- return True
- if self.pointerIndirectionLevels > 0:
- return True
- return False
-
- # Rough attempt to infer where a type could be an output.
- # Good for inferring which things need to be marshaled in
- # versus marshaled out for Vulkan API calls
- def possiblyOutput(self,):
- return self.pointerIndirectionLevels > 0 and (not self.isConst)
-
- def isVoidWithNoSize(self,):
- return self.typeName == "void" and self.pointerIndirectionLevels == 0
-
- def getCopy(self,):
- return copy(self)
-
- def getTransformed(self, isConstChoice=None, ptrIndirectionChoice=None):
- res = self.getCopy()
-
- if isConstChoice is not None:
- res.isConst = isConstChoice
- if ptrIndirectionChoice is not None:
- res.pointerIndirectionLevels = ptrIndirectionChoice
-
- return res
-
- def getWithCustomName(self):
- return self.getTransformed(
- ptrIndirectionChoice=self.pointerIndirectionLevels + 1)
-
- def getForAddressAccess(self):
- return self.getTransformed(
- ptrIndirectionChoice=self.pointerIndirectionLevels + 1)
-
- def getForValueAccess(self):
- if self.typeName == "void" and self.pointerIndirectionLevels == 1:
- asUint8Type = self.getCopy()
- asUint8Type.typeName = "uint8_t"
- return asUint8Type.getForValueAccess()
- return self.getTransformed(
- ptrIndirectionChoice=self.pointerIndirectionLevels - 1)
-
- def getForNonConstAccess(self):
- return self.getTransformed(isConstChoice=False)
-
- def withModifiedName(self, newName):
- res = self.getCopy()
- res.paramName = newName
- return res
-
- def isNextPointer(self):
- return self.paramName == "pNext"
-
- def isSigned(self):
- return self.typeName in ["int", "int8_t", "int16_t", "int32_t", "int64_t"]
-
- def isEnum(self, typeInfo):
- return typeInfo.categoryOf(self.typeName) == "enum"
-
- def isBitmask(self, typeInfo):
- return typeInfo.categoryOf(self.typeName) == "enum"
-
- # Only deals with 'core' handle types here.
- def isDispatchableHandleType(self):
- return self.typeName in DISPATCHABLE_HANDLE_TYPES
-
- def isNonDispatchableHandleType(self):
- return self.typeName in NON_DISPATCHABLE_HANDLE_TYPES
-
- def isHandleType(self):
- return self.isDispatchableHandleType() or \
- self.isNonDispatchableHandleType()
-
- def isCreatedBy(self, api):
- if self.typeName in HANDLE_INFO.keys():
- nonKhrRes = HANDLE_INFO[self.typeName].isCreateApi(api.name)
- if nonKhrRes:
- return True
- if len(api.name) > 3 and "KHR" == api.name[-3:]:
- return HANDLE_INFO[self.typeName].isCreateApi(api.name[:-3])
-
- if self.typeName == "VkImage" and api.name == "vkCreateImageWithRequirementsGOOGLE":
- return True
-
- if self.typeName == "VkBuffer" and api.name == "vkCreateBufferWithRequirementsGOOGLE":
- return True
-
- return False
-
- def isDestroyedBy(self, api):
- if self.typeName in HANDLE_INFO.keys():
- nonKhrRes = HANDLE_INFO[self.typeName].isDestroyApi(api.name)
- if nonKhrRes:
- return True
- if len(api.name) > 3 and "KHR" == api.name[-3:]:
- return HANDLE_INFO[self.typeName].isDestroyApi(api.name[:-3])
-
- return False
-
- def isSimpleValueType(self, typeInfo):
- if typeInfo.isCompoundType(self.typeName):
- return False
- if self.isString() or self.isArrayOfStrings():
- return False
- if self.staticArrExpr or self.pointerIndirectionLevels > 0:
- return False
- return True
-
- def getStructEnumExpr(self,):
- return None
-
- def getPrintFormatSpecifier(self):
- kKnownTypePrintFormatSpecifiers = {
- 'float': '%f',
- 'int': '%d',
- 'int32_t': '%d',
- 'size_t': '%ld',
- 'uint16_t': '%d',
- 'uint32_t': '%d',
- 'uint64_t': '%ld',
- 'VkBool32': '%d',
- 'VkDeviceSize': '%ld',
- 'VkFormat': '%d',
- 'VkImageLayout': '%d',
- }
-
- if self.pointerIndirectionLevels > 0 or self.isHandleType():
- return '%p'
-
- if self.typeName in kKnownTypePrintFormatSpecifiers:
- return kKnownTypePrintFormatSpecifiers[self.typeName]
-
- if self.typeName.endswith('Flags'):
- # Based on `typedef uint32_t VkFlags;`
- return '%d'
-
- return None
- def isOptionalPointer(self) -> bool:
- return self.isOptional and \
- self.pointerIndirectionLevels > 0 and \
- (not self.isNextPointer())
-
-
-# Is an S-expression w/ the following spec:
-# From https://gist.github.com/pib/240957
-class Atom(object):
- def __init__(self, name):
- self.name = name
- def __repr__(self,):
- return self.name
-
-def parse_sexp(sexp):
- atom_end = set('()"\'') | set(whitespace)
- stack, i, length = [[]], 0, len(sexp)
- while i < length:
- c = sexp[i]
-
- reading = type(stack[-1])
- if reading == list:
- if c == '(': stack.append([])
- elif c == ')':
- stack[-2].append(stack.pop())
- if stack[-1][0] == ('quote',): stack[-2].append(stack.pop())
- elif c == '"': stack.append('')
- elif c == "'": stack.append([('quote',)])
- elif c in whitespace: pass
- else: stack.append(Atom(c))
- elif reading == str:
- if c == '"':
- stack[-2].append(stack.pop())
- if stack[-1][0] == ('quote',): stack[-2].append(stack.pop())
- elif c == '\\':
- i += 1
- stack[-1] += sexp[i]
- else: stack[-1] += c
- elif reading == Atom:
- if c in atom_end:
- atom = stack.pop()
- if atom.name[0].isdigit(): stack[-1].append(eval(atom.name))
- else: stack[-1].append(atom)
- if stack[-1][0] == ('quote',): stack[-2].append(stack.pop())
- continue
- else: stack[-1] = Atom(stack[-1].name + c)
- i += 1
-
- return stack.pop()
-
-class FuncExprVal(object):
- def __init__(self, val):
- self.val = val
- def __repr__(self,):
- return self.val.__repr__()
-
-class FuncExpr(object):
- def __init__(self, name, args):
- self.name = name
- self.args = args
- def __repr__(self,):
- if len(self.args) == 0:
- return "(%s)" % (self.name.__repr__())
- else:
- return "(%s %s)" % (self.name.__repr__(), " ".join(map(lambda x: x.__repr__(), self.args)))
-
-class FuncLambda(object):
- def __init__(self, vs, body):
- self.vs = vs
- self.body = body
- def __repr__(self,):
- return "(L (%s) %s)" % (" ".join(map(lambda x: x.__repr__(), self.vs)), self.body.__repr__())
-
-class FuncLambdaParam(object):
- def __init__(self, name, typ):
- self.name = name
- self.typ = typ
- def __repr__(self,):
- return "%s : %s" % (self.name, self.typ)
-
-def parse_func_expr(parsed_sexp):
- if len(parsed_sexp) != 1:
- print("Error: parsed # expressions != 1: %d" % (len(parsed_sexp)))
- raise
-
- e = parsed_sexp[0]
-
- def parse_lambda_param(e):
- return FuncLambdaParam(e[0].name, e[1].name)
-
- def parse_one(exp):
- if list == type(exp):
- if "lambda" == exp[0].__repr__():
- return FuncLambda(list(map(parse_lambda_param, exp[1])), parse_one(exp[2]))
- else:
- return FuncExpr(exp[0], list(map(parse_one, exp[1:])))
- else:
- return FuncExprVal(exp)
-
- return parse_one(e)
-
-def parseFilterFuncExpr(expr):
- res = parse_func_expr(parse_sexp(expr))
- print("parseFilterFuncExpr: parsed %s" % res)
- return res
-
-def parseLetBodyExpr(expr):
- res = parse_func_expr(parse_sexp(expr))
- print("parseLetBodyExpr: parsed %s" % res)
- return res
-
-
-def makeVulkanTypeFromXMLTag(typeInfo, tag: Element) -> VulkanType:
- res = VulkanType()
-
- # Process the length expression
-
- if tag.attrib.get("len") is not None:
- lengths = tag.attrib.get("len").split(",")
- res.lenExpr = lengths[0]
-
- # Calculate static array expression
-
- nametag = tag.find("name")
- enumtag = tag.find("enum")
-
- if enumtag is not None:
- res.staticArrExpr = enumtag.text
- elif nametag is not None:
- res.rawStaticArrExpr = noneStr(nametag.tail)
-
- dimensions = res.rawStaticArrExpr.count('[')
- if dimensions == 1:
- res.staticArrExpr = res.rawStaticArrExpr[1:-1]
- elif dimensions > 1:
- arraySizes = res.rawStaticArrExpr[1:-1].split('][')
- res.staticArrExpr = '(' + \
- '*'.join(f'({size})' for size in arraySizes) + ')'
-
- # Determine const
-
- beforeTypePart = noneStr(tag.text)
-
- if "const" in beforeTypePart:
- res.isConst = True
-
- # Calculate type and pointer info
- for elem in tag:
- if elem.tag == "name":
- res.paramName = elem.text
- if elem.tag == "type":
- duringTypePart = noneStr(elem.text)
- afterTypePart = noneStr(elem.tail)
- # Now we know enough to fill some stuff in
- res.typeName = duringTypePart
-
- if res.typeName in TRANSFORMED_TYPES:
- res.isTransformed = True
-
- # This only handles pointerIndirectionLevels == 2
- # along with optional constant pointer for the inner part.
- for c in afterTypePart:
- if c == "*":
- res.pointerIndirectionLevels += 1
- if "const" in afterTypePart and res.pointerIndirectionLevels == 2:
- res.isPointerToConstPointer = True
-
- # If void*, treat like it's not a pointer
- # if duringTypePart == "void":
- # res.pointerIndirectionLevels -= 1
-
- # Calculate optionality (based on validitygenerator.py)
- if tag.attrib.get("optional") is not None:
- res.isOptional = True
- res.optionalStr = tag.attrib.get("optional")
-
- # If no validity is being generated, it usually means that
- # validity is complex and not absolute, so let's say yes.
- if tag.attrib.get("noautovalidity") is not None:
- res.isOptional = True
-
- # If this is a structure extension, it is optional.
- if tag.attrib.get("structextends") is not None:
- res.isOptional = True
-
- # If this is a pNext pointer, it is optional.
- if res.paramName == "pNext":
- res.isOptional = True
-
- res.primitiveEncodingSize = typeInfo.getPrimitiveEncodingSize(res.typeName)
-
- # Annotations: Environment binds
- if tag.attrib.get("binds") is not None:
- bindPairs = map(lambda x: x.strip(), tag.attrib.get("binds").split(","))
- bindPairsSplit = map(lambda p: p.split(":"), bindPairs)
- res.binds = dict(map(lambda sp: (sp[0].strip(), sp[1].strip()), bindPairsSplit))
-
- # Annotations: Device memory
- for k in DEVICE_MEMORY_INFO_KEYS:
- if tag.attrib.get(k) is not None:
- res.deviceMemoryAttrib = k
- res.deviceMemoryVal = tag.attrib.get(k)
- break
-
- # Annotations: Filters
- if tag.attrib.get("filterVar") is not None:
- res.filterVar = tag.attrib.get("filterVar").strip()
-
- if tag.attrib.get("filterVals") is not None:
- res.filterVals = \
- list(map(lambda v: v.strip(),
- tag.attrib.get("filterVals").strip().split(",")))
- print("Filtervals: %s" % res.filterVals)
-
- if tag.attrib.get("filterFunc") is not None:
- res.filterFunc = parseFilterFuncExpr(tag.attrib.get("filterFunc"))
-
- if tag.attrib.get("filterOtherwise") is not None:
- res.Otherwise = tag.attrib.get("filterOtherwise")
-
- # store all other attribs here
- res.attribs = dict(tag.attrib)
-
- return res
-
-
-def makeVulkanTypeSimple(isConst,
- typeName,
- ptrIndirectionLevels,
- paramName=None):
- res = VulkanType()
-
- res.typeName = typeName
- res.isConst = isConst
- res.pointerIndirectionLevels = ptrIndirectionLevels
- res.isPointerToConstPointer = False
- res.paramName = paramName
- res.primitiveEncodingSize = None
-
- return res
-
-# A class for holding the parameter indices corresponding to various
-# attributes about a VkDeviceMemory, such as the handle, size, offset, etc.
-class DeviceMemoryInfoParameterIndices(object):
- def __init__(self, handle, offset, size, typeIndex, typeBits):
- self.handle = handle
- self.offset = offset
- self.size = size
- self.typeIndex = typeIndex
- self.typeBits = typeBits
-
-# initializes DeviceMemoryInfoParameterIndices for each
-# abstract VkDeviceMemory encountered over |parameters|
-def initDeviceMemoryInfoParameterIndices(parameters):
-
- use = False
- deviceMemoryInfoById = {}
-
- for (i, p) in enumerate(parameters):
- a = p.deviceMemoryAttrib
- if not a:
- continue
-
- if a in DEVICE_MEMORY_INFO_KEYS:
- use = True
- deviceMemoryInfoById[p.deviceMemoryVal] = DeviceMemoryInfoParameterIndices(
- None, None, None, None, None)
-
- for (i, p) in enumerate(parameters):
- a = p.deviceMemoryAttrib
- if not a:
- continue
-
- info = deviceMemoryInfoById[p.deviceMemoryVal]
-
- if a == "devicememoryhandle":
- info.handle = i
- if a == "devicememoryoffset":
- info.offset = i
- if a == "devicememorysize":
- info.size = i
- if a == "devicememorytypeindex":
- info.typeIndex = i
- if a == "devicememorytypebits":
- info.typeBits = i
-
- if not use:
- return None
-
- return deviceMemoryInfoById
-
-# Classes for describing aggregate types (unions, structs) and API calls.
-class VulkanCompoundType(object):
-
- def __init__(self, name: str, members: List[VulkanType], isUnion=False, structEnumExpr=None, structExtendsExpr=None, feature=None, initialEnv={}, optional=None):
- self.name: str = name
- self.typeName: str = name
- self.members: List[VulkanType] = members
- self.environment = initialEnv
- self.isUnion = isUnion
- self.structEnumExpr = structEnumExpr
- self.structExtendsExpr = structExtendsExpr
- self.feature = feature
- self.deviceMemoryInfoParameterIndices = initDeviceMemoryInfoParameterIndices(self.members)
- self.isTransformed = name in TRANSFORMED_TYPES
- self.copy = None
- self.optionalStr = optional
-
- def initCopies(self):
- self.copy = self
-
- for m in self.members:
- m.parent = self.copy
-
- def getMember(self, memberName) -> Optional[VulkanType]:
- for m in self.members:
- if m.paramName == memberName:
- return m
- return None
-
- def getStructEnumExpr(self,):
- return self.structEnumExpr
-
-class VulkanAPI(object):
-
- def __init__(self, name: str, retType: VulkanType, parameters, origName=None):
- self.name: str = name
- self.origName = name
- self.retType: VulkanType = retType
- self.parameters: List[VulkanType] = parameters
-
- self.deviceMemoryInfoParameterIndices = initDeviceMemoryInfoParameterIndices(self.parameters)
-
- self.copy = None
-
- self.isTransformed = name in TRANSFORMED_TYPES
-
- if origName:
- self.origName = origName
-
- def initCopies(self):
- self.copy = self
-
- for m in self.parameters:
- m.parent = self.copy
-
- def getCopy(self,):
- return copy(self)
-
- def getParameter(self, parameterName):
- for p in self.parameters:
- if p.paramName == parameterName:
- return p
- return None
-
- def withModifiedName(self, newName):
- res = VulkanAPI(newName, self.retType, self.parameters)
- return res
-
- def getRetVarExpr(self):
- if self.retType.typeName == "void":
- return None
- return "%s_%s_return" % (self.name, self.retType.typeName)
-
- def getRetTypeExpr(self):
- return self.retType.typeName
-
- def withCustomParameters(self, customParams):
- res = self.getCopy()
- res.parameters = customParams
- return res
-
- def withCustomReturnType(self, retType):
- res = self.getCopy()
- res.retType = retType
- return res
-
-# Whether or not special handling of virtual elements
-# such as VkDeviceMemory is needed.
-def vulkanTypeNeedsTransform(structOrApi):
- return structOrApi.deviceMemoryInfoParameterIndices != None
-
-def vulkanTypeGetNeededTransformTypes(structOrApi):
- res = []
- if structOrApi.deviceMemoryInfoParameterIndices != None:
- res.append("devicememory")
- return res
-
-def vulkanTypeforEachSubType(structOrApi, f):
- toLoop = None
- if type(structOrApi) == VulkanCompoundType:
- toLoop = structOrApi.members
- if type(structOrApi) == VulkanAPI:
- toLoop = structOrApi.parameters
-
- for (i, x) in enumerate(toLoop):
- f(i, x)
-
-# Parses everything about Vulkan types into a Python readable format.
-class VulkanTypeInfo(object):
-
- def __init__(self, generator):
- self.generator = generator
- self.categories: Set[str] = set([])
-
- # Tracks what Vulkan type is part of what category.
- self.typeCategories: Dict[str, str] = {}
-
- # Tracks the primitive encoding size for each type, if applicable.
- self.encodingSizes: Dict[str, Optional[int]] = {}
-
- self.structs: Dict[str, VulkanCompoundType] = {}
- self.apis: Dict[str, VulkanAPI] = {}
-
- # Maps bitmask types to the enum type used for the flags
- # E.g. "VkImageAspectFlags" -> "VkImageAspectFlagBits"
- self.bitmasks: Dict[str, str] = {}
-
- # Maps all enum names to their values.
- # For aliases, the value is the name of the canonical enum
- self.enumValues: Dict[str, Union[int, str]] = {}
-
- self.feature = None
-
- def initType(self, name: str, category: str):
- self.categories.add(category)
- self.typeCategories[name] = category
- self.encodingSizes[name] = self.setPrimitiveEncodingSize(name)
-
- def categoryOf(self, name):
- return self.typeCategories[name]
-
- def getPrimitiveEncodingSize(self, name):
- return self.encodingSizes[name]
-
- # Queries relating to categories of Vulkan types.
- def isHandleType(self, name):
- return self.typeCategories.get(name) == "handle"
-
- def isCompoundType(self, name: str):
- return self.typeCategories.get(name) in ["struct", "union"]
-
- # Gets the best size in bytes
- # for encoding/decoding a particular Vulkan type.
- # If not applicable, returns None.
- def setPrimitiveEncodingSize(self, name: str) -> Optional[int]:
- baseEncodingSizes = {
- "void": 8,
- "char": 1,
- "float": 4,
- "uint8_t": 1,
- "uint16_t": 2,
- "uint32_t": 4,
- "uint64_t": 8,
- "int": 4,
- "int8_t": 1,
- "int16_t": 2,
- "int32_t": 4,
- "int64_t": 8,
- "size_t": 8,
- "ssize_t": 8,
- "VkBool32": 4,
- }
-
- if name in baseEncodingSizes:
- return baseEncodingSizes[name]
-
- category = self.typeCategories[name]
-
- if category in [None, "api", "include", "define", "struct", "union"]:
- return None
-
- # Handles are pointers so they must be 8 bytes. Basetype includes VkDeviceSize which is 8 bytes.
- if category in ["handle", "basetype", "funcpointer"]:
- return 8
-
- if category in ["enum", "bitmask"]:
- return 4
-
- def isNonAbiPortableType(self, typeName):
- if typeName in EXPLICITLY_ABI_PORTABLE_TYPES:
- return False
-
- if typeName in EXPLICITLY_ABI_NON_PORTABLE_TYPES:
- return True
-
- category = self.typeCategories[typeName]
- return category in NON_ABI_PORTABLE_TYPE_CATEGORIES
-
- def onBeginFeature(self, featureName, featureType):
- self.feature = featureName
-
- def onEndFeature(self):
- self.feature = None
-
- def onGenType(self, typeinfo, name, alias):
- category = typeinfo.elem.get("category")
- self.initType(name, category)
-
- if category in ["struct", "union"]:
- self.onGenStruct(typeinfo, name, alias)
-
- if category == "bitmask":
- self.bitmasks[name] = typeinfo.elem.get("requires")
-
- def onGenStruct(self, typeinfo, typeName, alias):
- if not alias:
- members: List[VulkanType] = []
-
- structExtendsExpr = typeinfo.elem.get("structextends")
-
- structEnumExpr = None
-
- initialEnv = {}
- envStr = typeinfo.elem.get("exists")
- if envStr != None:
- comma_separated = envStr.split(",")
- name_type_pairs = map(lambda cs: tuple(map(lambda t: t.strip(), cs.split(":"))), comma_separated)
- for (name, typ) in name_type_pairs:
- initialEnv[name] = {
- "type" : typ,
- "binding" : None,
- "structmember" : False,
- "body" : None,
- }
-
- letenvStr = typeinfo.elem.get("let")
- if letenvStr != None:
- comma_separated = letenvStr.split(",")
- name_body_pairs = map(lambda cs: tuple(map(lambda t: t.strip(), cs.split(":"))), comma_separated)
- for (name, body) in name_body_pairs:
- initialEnv[name] = {
- "type" : "uint32_t",
- "binding" : name,
- "structmember" : False,
- "body" : parseLetBodyExpr(body)
- }
-
- for member in typeinfo.elem.findall(".//member"):
- vulkanType = makeVulkanTypeFromXMLTag(self, member)
- initialEnv[vulkanType.paramName] = {
- "type": vulkanType.typeName,
- "binding": vulkanType.paramName,
- "structmember": True,
- "body": None,
- }
- members.append(vulkanType)
- if vulkanType.typeName == "VkStructureType" and \
- member.get("values"):
- structEnumExpr = member.get("values")
-
- self.structs[typeName] = \
- VulkanCompoundType(
- typeName,
- members,
- isUnion = self.categoryOf(typeName) == "union",
- structEnumExpr = structEnumExpr,
- structExtendsExpr = structExtendsExpr,
- feature = self.feature,
- initialEnv = initialEnv,
- optional = typeinfo.elem.get("optional", None))
- self.structs[typeName].initCopies()
-
- def onGenGroup(self, groupinfo, groupName, _alias=None):
- self.initType(groupName, "enum")
- enums = groupinfo.elem.findall("enum")
- for enum in enums:
- intVal, strVal = self.generator.enumToValue(enum, True)
- self.enumValues[enum.get('name')] = intVal if intVal is not None else strVal
-
-
- def onGenEnum(self, enuminfo, name: str, alias):
- self.initType(name, "enum")
- value: str = enuminfo.elem.get("value")
- if value and value.isdigit():
- self.enumValues[name] = int(value)
- elif value and value[0] == '"' and value[-1] == '"':
- self.enumValues[name] = value[1:-1]
- elif alias is not None:
- self.enumValues[name] = alias
- else:
- # There's about a dozen cases of using the bitwise NOT operator (e.g.: `(~0U)`, `(~0ULL)`)
- # to concisely represent large values. Just ignore them for now.
- # In the future, we can add a lookup table to convert these to int
- return
-
- def onGenCmd(self, cmdinfo, name, _alias):
- self.initType(name, "api")
-
- proto = cmdinfo.elem.find("proto")
- params = cmdinfo.elem.findall("param")
-
- self.apis[name] = \
- VulkanAPI(
- name,
- makeVulkanTypeFromXMLTag(self, proto),
- list(map(lambda p: makeVulkanTypeFromXMLTag(self, p),
- params)))
- self.apis[name].initCopies()
-
- def onEnd(self):
- pass
-
-def hasNullOptionalStringFeature(forEachType):
- return (hasattr(forEachType, "onCheckWithNullOptionalStringFeature")) and \
- (hasattr(forEachType, "endCheckWithNullOptionalStringFeature")) and \
- (hasattr(forEachType, "finalCheckWithNullOptionalStringFeature"))
-
-
-# General function to iterate over a vulkan type and call code that processes
-# each of its sub-components, if any.
-def iterateVulkanType(typeInfo: VulkanTypeInfo, vulkanType: VulkanType, forEachType):
- if not vulkanType.isArrayOfStrings():
- if vulkanType.isPointerToConstPointer:
- return False
-
- forEachType.registerTypeInfo(typeInfo)
-
- needCheck = vulkanType.isOptionalPointer()
-
- if typeInfo.isCompoundType(vulkanType.typeName) and not vulkanType.isNextPointer():
-
- if needCheck:
- forEachType.onCheck(vulkanType)
-
- forEachType.onCompoundType(vulkanType)
-
- if needCheck:
- forEachType.endCheck(vulkanType)
-
- else:
- if vulkanType.isString():
- if needCheck and hasNullOptionalStringFeature(forEachType):
- forEachType.onCheckWithNullOptionalStringFeature(vulkanType)
- forEachType.onString(vulkanType)
- forEachType.endCheckWithNullOptionalStringFeature(vulkanType)
- forEachType.onString(vulkanType)
- forEachType.finalCheckWithNullOptionalStringFeature(vulkanType)
- elif needCheck:
- forEachType.onCheck(vulkanType)
- forEachType.onString(vulkanType)
- forEachType.endCheck(vulkanType)
- else:
- forEachType.onString(vulkanType)
-
- elif vulkanType.isArrayOfStrings():
- forEachType.onStringArray(vulkanType)
-
- elif vulkanType.staticArrExpr:
- forEachType.onStaticArr(vulkanType)
-
- elif vulkanType.isNextPointer():
- if needCheck:
- forEachType.onCheck(vulkanType)
- forEachType.onStructExtension(vulkanType)
- if needCheck:
- forEachType.endCheck(vulkanType)
-
- elif vulkanType.pointerIndirectionLevels > 0:
- if needCheck:
- forEachType.onCheck(vulkanType)
- forEachType.onPointer(vulkanType)
- if needCheck:
- forEachType.endCheck(vulkanType)
-
- else:
- forEachType.onValue(vulkanType)
-
- return True
-
-class VulkanTypeIterator(object):
- def __init__(self,):
- self.typeInfo = None
-
- def registerTypeInfo(self, typeInfo):
- self.typeInfo = typeInfo
-
-def vulkanTypeGetStructFieldLengthInfo(structInfo, vulkanType):
- def getSpecialCaseVulkanStructFieldLength(structInfo, vulkanType):
- cases = [
- {
- "structName": "VkShaderModuleCreateInfo",
- "field": "pCode",
- "lenExpr": "codeSize",
- "postprocess": lambda expr: "(%s / 4)" % expr
- },
- {
- "structName": "VkPipelineMultisampleStateCreateInfo",
- "field": "pSampleMask",
- "lenExpr": "rasterizationSamples",
- "postprocess": lambda expr: "(((%s) + 31) / 32)" % expr
- },
- ]
-
- for c in cases:
- if (structInfo.name, vulkanType.paramName) == (c["structName"], c["field"]):
- return c
-
- return None
-
- specialCaseAccess = getSpecialCaseVulkanStructFieldLength(structInfo, vulkanType)
-
- if specialCaseAccess is not None:
- return specialCaseAccess
-
- lenExpr = vulkanType.getLengthExpression()
-
- if lenExpr is None:
- return None
-
- return {
- "structName": structInfo.name,
- "field": vulkanType.typeName,
- "lenExpr": lenExpr,
- "postprocess": lambda expr: expr}
-
-
-class VulkanTypeProtobufInfo(object):
- def __init__(self, typeInfo, structInfo, vulkanType):
- self.needsMessage = typeInfo.isCompoundType(vulkanType.typeName)
- self.isRepeatedString = vulkanType.isArrayOfStrings()
- self.isString = vulkanType.isString() or (
- vulkanType.typeName == "char" and (vulkanType.staticArrExpr != ""))
-
- if structInfo is not None:
- self.lengthInfo = vulkanTypeGetStructFieldLengthInfo(
- structInfo, vulkanType)
- else:
- self.lengthInfo = vulkanType.getLengthExpression()
-
- self.protobufType = None
- self.origTypeCategory = typeInfo.categoryOf(vulkanType.typeName)
-
- self.isExtensionStruct = \
- vulkanType.typeName == "void" and \
- vulkanType.pointerIndirectionLevels > 0 and \
- vulkanType.paramName == "pNext"
-
- if self.needsMessage:
- return
-
- if typeInfo.categoryOf(vulkanType.typeName) in ["enum", "bitmask"]:
- self.protobufType = "uint32"
-
- if typeInfo.categoryOf(vulkanType.typeName) in ["funcpointer", "handle", "define"]:
- self.protobufType = "uint64"
-
- if typeInfo.categoryOf(vulkanType.typeName) in ["basetype"]:
- baseTypeMapping = {
- "VkFlags" : "uint32",
- "VkBool32" : "uint32",
- "VkDeviceSize" : "uint64",
- "VkSampleMask" : "uint32",
- }
- self.protobufType = baseTypeMapping[vulkanType.typeName]
-
- if typeInfo.categoryOf(vulkanType.typeName) == None:
-
- otherTypeMapping = {
- "void" : "uint64",
- "char" : "uint8",
- "size_t" : "uint64",
- "float" : "float",
- "uint8_t" : "uint32",
- "uint16_t" : "uint32",
- "int32_t" : "int32",
- "uint32_t" : "uint32",
- "uint64_t" : "uint64",
- "VkDeviceSize" : "uint64",
- "VkSampleMask" : "uint32",
- }
-
- if vulkanType.typeName in otherTypeMapping:
- self.protobufType = otherTypeMapping[vulkanType.typeName]
- else:
- self.protobufType = "uint64"
-
-
- protobufCTypeMapping = {
- "uint8" : "uint8_t",
- "uint32" : "uint32_t",
- "int32" : "int32_t",
- "uint64" : "uint64_t",
- "float" : "float",
- "string" : "const char*",
- }
-
- self.protobufCType = protobufCTypeMapping[self.protobufType]
-
diff --git a/codegen/vulkan/scripts/cereal/counting.py b/codegen/vulkan/scripts/cereal/counting.py
deleted file mode 100644
index 0557d328..00000000
--- a/codegen/vulkan/scripts/cereal/counting.py
+++ /dev/null
@@ -1,698 +0,0 @@
-# Copyright (c) 2018 The Android Open Source Project
-# Copyright (c) 2018 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from copy import copy
-
-from .common.codegen import CodeGen
-from .common.vulkantypes import \
- VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, VulkanTypeIterator, Atom, FuncExpr, FuncExprVal, FuncLambda
-
-from .wrapperdefs import VulkanWrapperGenerator
-from .wrapperdefs import ROOT_TYPE_VAR_NAME, ROOT_TYPE_PARAM
-from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM_FOR_WRITE, EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME
-
-class VulkanCountingCodegen(VulkanTypeIterator):
- def __init__(self, cgen, featureBitsVar, toCountVar, countVar, rootTypeVar, prefix, forApiOutput=False, mapHandles=True, handleMapOverwrites=False, doFiltering=True):
- self.cgen = cgen
- self.featureBitsVar = featureBitsVar
- self.toCountVar = toCountVar
- self.rootTypeVar = rootTypeVar
- self.countVar = countVar
- self.prefix = prefix
- self.forApiOutput = forApiOutput
-
- self.exprAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.toCountVar, asPtr = True)
- self.exprValueAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.toCountVar, asPtr = False)
- self.exprPrimitiveValueAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.toCountVar, asPtr = False)
-
- self.lenAccessor = lambda t: self.cgen.generalLengthAccess(t, parentVarName = self.toCountVar)
- self.lenAccessorGuard = lambda t: self.cgen.generalLengthAccessGuard(t, parentVarName = self.toCountVar)
- self.filterVarAccessor = lambda t: self.cgen.filterVarAccess(t, parentVarName = self.toCountVar)
-
- self.checked = False
-
- self.mapHandles = mapHandles
- self.handleMapOverwrites = handleMapOverwrites
- self.doFiltering = doFiltering
-
- def getTypeForStreaming(self, vulkanType):
- res = copy(vulkanType)
-
- if not vulkanType.accessibleAsPointer():
- res = res.getForAddressAccess()
-
- if vulkanType.staticArrExpr:
- res = res.getForAddressAccess()
-
- return res
-
- def makeCastExpr(self, vulkanType):
- return "(%s)" % (
- self.cgen.makeCTypeDecl(vulkanType, useParamName=False))
-
- def genCount(self, sizeExpr):
- self.cgen.stmt("*%s += %s" % (self.countVar, sizeExpr))
-
- def genPrimitiveStreamCall(self, vulkanType):
- self.genCount(str(self.cgen.countPrimitive(
- self.typeInfo,
- vulkanType)))
-
- def genHandleMappingCall(self, vulkanType, access, lenAccess):
-
- if lenAccess is None:
- lenAccess = "1"
- handle64Bytes = "8"
- else:
- handle64Bytes = "%s * 8" % lenAccess
-
- handle64Var = self.cgen.var()
- if lenAccess != "1":
- self.cgen.beginIf(lenAccess)
- # self.cgen.stmt("uint64_t* %s" % handle64Var)
- # self.cgen.stmt(
- # "%s->alloc((void**)&%s, %s * 8)" % \
- # (self.streamVarName, handle64Var, lenAccess))
- handle64VarAccess = handle64Var
- handle64VarType = \
- makeVulkanTypeSimple(False, "uint64_t", 1, paramName=handle64Var)
- else:
- self.cgen.stmt("uint64_t %s" % handle64Var)
- handle64VarAccess = "&%s" % handle64Var
- handle64VarType = \
- makeVulkanTypeSimple(False, "uint64_t", 0, paramName=handle64Var)
-
- if self.handleMapOverwrites:
- # self.cgen.stmt(
- # "static_assert(8 == sizeof(%s), \"handle map overwrite requres %s to be 8 bytes long\")" % \
- # (vulkanType.typeName, vulkanType.typeName))
- # self.cgen.stmt(
- # "%s->handleMapping()->mapHandles_%s((%s*)%s, %s)" %
- # (self.streamVarName, vulkanType.typeName, vulkanType.typeName,
- # access, lenAccess))
- self.genCount("8 * %s" % lenAccess)
- else:
- # self.cgen.stmt(
- # "%s->handleMapping()->mapHandles_%s_u64(%s, %s, %s)" %
- # (self.streamVarName, vulkanType.typeName,
- # access,
- # handle64VarAccess, lenAccess))
- self.genCount(handle64Bytes)
-
- if lenAccess != "1":
- self.cgen.endIf()
-
- def doAllocSpace(self, vulkanType):
- pass
-
- def getOptionalStringFeatureExpr(self, vulkanType):
- if vulkanType.optionalStr is not None:
- if vulkanType.optionalStr.startswith("streamFeature:"):
- splitted = vulkanType.optionalStr.split(":")
- featureExpr = "%s & %s" % (self.featureBitsVar, splitted[1])
- return featureExpr
- return None
-
- def onCheck(self, vulkanType):
-
- if self.forApiOutput:
- return
-
- featureExpr = self.getOptionalStringFeatureExpr(vulkanType);
-
- self.checked = True
-
- access = self.exprAccessor(vulkanType)
-
- needConsistencyCheck = False
-
- self.cgen.line("// WARNING PTR CHECK")
- checkAccess = self.exprAccessor(vulkanType)
- addrExpr = "&" + checkAccess
- sizeExpr = self.cgen.sizeofExpr(vulkanType)
-
- if featureExpr is not None:
- self.cgen.beginIf(featureExpr)
-
- self.genPrimitiveStreamCall(
- vulkanType)
-
- if featureExpr is not None:
- self.cgen.endIf()
-
- if featureExpr is not None:
- self.cgen.beginIf("(!(%s) || %s)" % (featureExpr, access))
- else:
- self.cgen.beginIf(access)
-
- if needConsistencyCheck and featureExpr is None:
- self.cgen.beginIf("!(%s)" % checkName)
- self.cgen.stmt(
- "fprintf(stderr, \"fatal: %s inconsistent between guest and host\\n\")" % (access))
- self.cgen.endIf()
-
-
- def onCheckWithNullOptionalStringFeature(self, vulkanType):
- self.cgen.beginIf("%s & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT" % self.featureBitsVar)
- self.onCheck(vulkanType)
-
- def endCheckWithNullOptionalStringFeature(self, vulkanType):
- self.endCheck(vulkanType)
- self.cgen.endIf()
- self.cgen.beginElse()
-
- def finalCheckWithNullOptionalStringFeature(self, vulkanType):
- self.cgen.endElse()
-
- def endCheck(self, vulkanType):
-
- if self.checked:
- self.cgen.endIf()
- self.checked = False
-
- def genFilterFunc(self, filterfunc, env):
-
- def loop(expr, lambdaEnv={}):
- def do_func(expr):
- fnamestr = expr.name.name
- if "not" == fnamestr:
- return "!(%s)" % (loop(expr.args[0], lambdaEnv))
- if "eq" == fnamestr:
- return "(%s == %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv))
- if "and" == fnamestr:
- return "(%s && %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv))
- if "or" == fnamestr:
- return "(%s || %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv))
- if "bitwise_and" == fnamestr:
- return "(%s & %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv))
- if "getfield" == fnamestr:
- ptrlevels = get_ptrlevels(expr.args[0].val.name)
- if ptrlevels == 0:
- return "%s.%s" % (loop(expr.args[0], lambdaEnv), expr.args[1].val)
- else:
- return "(%s(%s)).%s" % ("*" * ptrlevels, loop(expr.args[0], lambdaEnv), expr.args[1].val)
-
- if "if" == fnamestr:
- return "((%s) ? (%s) : (%s))" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv), loop(expr.args[2], lambdaEnv))
-
- return "%s(%s)" % (fnamestr, ", ".join(map(lambda e: loop(e, lambdaEnv), expr.args)))
-
- def do_expratom(atomname, lambdaEnv= {}):
- if lambdaEnv.get(atomname, None) is not None:
- return atomname
-
- enventry = env.get(atomname, None)
- if None != enventry:
- return self.getEnvAccessExpr(atomname)
- return atomname
-
- def get_ptrlevels(atomname, lambdaEnv= {}):
- if lambdaEnv.get(atomname, None) is not None:
- return 0
-
- enventry = env.get(atomname, None)
- if None != enventry:
- return self.getPointerIndirectionLevels(atomname)
-
- return 0
-
- def do_exprval(expr, lambdaEnv= {}):
- expratom = expr.val
-
- if Atom == type(expratom):
- return do_expratom(expratom.name, lambdaEnv)
-
- return "%s" % expratom
-
- def do_lambda(expr, lambdaEnv= {}):
- params = expr.vs
- body = expr.body
- newEnv = {}
-
- for (k, v) in lambdaEnv.items():
- newEnv[k] = v
-
- for p in params:
- newEnv[p.name] = p.typ
-
- return "[](%s) { return %s; }" % (", ".join(list(map(lambda p: "%s %s" % (p.typ, p.name), params))), loop(body, lambdaEnv=newEnv))
-
- if FuncExpr == type(expr):
- return do_func(expr)
- if FuncLambda == type(expr):
- return do_lambda(expr)
- elif FuncExprVal == type(expr):
- return do_exprval(expr)
-
- return loop(filterfunc)
-
- def beginFilterGuard(self, vulkanType):
- if vulkanType.filterVar == None:
- return
-
- if self.doFiltering == False:
- return
-
- filterVarAccess = self.getEnvAccessExpr(vulkanType.filterVar)
-
- filterValsExpr = None
- filterFuncExpr = None
- filterExpr = None
-
- filterFeature = "%s & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT" % self.featureBitsVar
-
- if None != vulkanType.filterVals:
- filterValsExpr = " || ".join(map(lambda filterval: "(%s == %s)" % (filterval, filterVarAccess), vulkanType.filterVals))
-
- if None != vulkanType.filterFunc:
- filterFuncExpr = self.genFilterFunc(vulkanType.filterFunc, self.currentStructInfo.environment)
-
- if None != filterValsExpr and None != filterFuncExpr:
- filterExpr = "%s || %s" % (filterValsExpr, filterFuncExpr)
- elif None == filterValsExpr and None == filterFuncExpr:
- # Assume is bool
- self.cgen.beginIf(filterVarAccess)
- elif None != filterValsExpr:
- self.cgen.beginIf("(!(%s) || (%s))" % (filterFeature, filterValsExpr))
- elif None != filterFuncExpr:
- self.cgen.beginIf("(!(%s) || (%s))" % (filterFeature, filterFuncExpr))
-
- def endFilterGuard(self, vulkanType, cleanupExpr=None):
- if vulkanType.filterVar == None:
- return
-
- if self.doFiltering == False:
- return
-
- if cleanupExpr == None:
- self.cgen.endIf()
- else:
- self.cgen.endIf()
- self.cgen.beginElse()
- self.cgen.stmt(cleanupExpr)
- self.cgen.endElse()
-
- def getEnvAccessExpr(self, varName):
- parentEnvEntry = self.currentStructInfo.environment.get(varName, None)
-
- if parentEnvEntry != None:
- isParentMember = parentEnvEntry["structmember"]
-
- if isParentMember:
- envAccess = self.exprValueAccessor(list(filter(lambda member: member.paramName == varName, self.currentStructInfo.members))[0])
- else:
- envAccess = varName
- return envAccess
-
- return None
-
- def getPointerIndirectionLevels(self, varName):
- parentEnvEntry = self.currentStructInfo.environment.get(varName, None)
-
- if parentEnvEntry != None:
- isParentMember = parentEnvEntry["structmember"]
-
- if isParentMember:
- return list(filter(lambda member: member.paramName == varName, self.currentStructInfo.members))[0].pointerIndirectionLevels
- else:
- return 0
- return 0
-
- return 0
-
-
- def onCompoundType(self, vulkanType):
-
- access = self.exprAccessor(vulkanType)
- lenAccess = self.lenAccessor(vulkanType)
- lenAccessGuard = self.lenAccessorGuard(vulkanType)
-
- self.beginFilterGuard(vulkanType)
-
- if vulkanType.pointerIndirectionLevels > 0:
- self.doAllocSpace(vulkanType)
-
- if lenAccess is not None:
- if lenAccessGuard is not None:
- self.cgen.beginIf(lenAccessGuard)
- loopVar = "i"
- access = "%s + %s" % (access, loopVar)
- forInit = "uint32_t %s = 0" % loopVar
- forCond = "%s < (uint32_t)%s" % (loopVar, lenAccess)
- forIncr = "++%s" % loopVar
- self.cgen.beginFor(forInit, forCond, forIncr)
-
- accessWithCast = "%s(%s)" % (self.makeCastExpr(
- self.getTypeForStreaming(vulkanType)), access)
-
- callParams = [self.featureBitsVar,
- self.rootTypeVar, accessWithCast, self.countVar]
-
- for (bindName, localName) in vulkanType.binds.items():
- callParams.append(self.getEnvAccessExpr(localName))
-
- self.cgen.funcCall(None, self.prefix + vulkanType.typeName,
- callParams)
-
- if lenAccess is not None:
- self.cgen.endFor()
- if lenAccessGuard is not None:
- self.cgen.endIf()
-
- self.endFilterGuard(vulkanType)
-
- def onString(self, vulkanType):
- access = self.exprAccessor(vulkanType)
- self.genCount("sizeof(uint32_t) + (%s ? strlen(%s) : 0)" % (access, access))
-
- def onStringArray(self, vulkanType):
- access = self.exprAccessor(vulkanType)
- lenAccess = self.lenAccessor(vulkanType)
- lenAccessGuard = self.lenAccessorGuard(vulkanType)
-
- self.genCount("sizeof(uint32_t)")
- if lenAccessGuard is not None:
- self.cgen.beginIf(lenAccessGuard)
- self.cgen.beginFor("uint32_t i = 0", "i < %s" % lenAccess, "++i")
- self.cgen.stmt("size_t l = %s[i] ? strlen(%s[i]) : 0" % (access, access))
- self.genCount("sizeof(uint32_t) + (%s[i] ? strlen(%s[i]) : 0)" % (access, access))
- self.cgen.endFor()
- if lenAccessGuard is not None:
- self.cgen.endIf()
-
- def onStaticArr(self, vulkanType):
- access = self.exprValueAccessor(vulkanType)
- lenAccess = self.lenAccessor(vulkanType)
- lenAccessGuard = self.lenAccessorGuard(vulkanType)
-
- if lenAccessGuard is not None:
- self.cgen.beginIf(lenAccessGuard)
- finalLenExpr = "%s * %s" % (lenAccess, self.cgen.sizeofExpr(vulkanType))
- if lenAccessGuard is not None:
- self.cgen.endIf()
- self.genCount(finalLenExpr)
-
- def onStructExtension(self, vulkanType):
- sTypeParam = copy(vulkanType)
- sTypeParam.paramName = "sType"
-
- access = self.exprAccessor(vulkanType)
- sizeVar = "%s_size" % vulkanType.paramName
-
- castedAccessExpr = access
-
- sTypeAccess = self.exprAccessor(sTypeParam)
- self.cgen.beginIf("%s == VK_STRUCTURE_TYPE_MAX_ENUM" %
- self.rootTypeVar)
- self.cgen.stmt("%s = %s" % (self.rootTypeVar, sTypeAccess))
- self.cgen.endIf()
-
- self.cgen.funcCall(None, self.prefix + "extension_struct",
- [self.featureBitsVar, self.rootTypeVar, castedAccessExpr, self.countVar])
-
-
- def onPointer(self, vulkanType):
- access = self.exprAccessor(vulkanType)
-
- lenAccess = self.lenAccessor(vulkanType)
- lenAccessGuard = self.lenAccessorGuard(vulkanType)
-
- self.beginFilterGuard(vulkanType)
- self.doAllocSpace(vulkanType)
-
- if vulkanType.filterVar != None:
- print("onPointer Needs filter: %s filterVar %s" % (access, vulkanType.filterVar))
-
- if vulkanType.isHandleType() and self.mapHandles:
- self.genHandleMappingCall(vulkanType, access, lenAccess)
- else:
- if self.typeInfo.isNonAbiPortableType(vulkanType.typeName):
- if lenAccess is not None:
- if lenAccessGuard is not None:
- self.cgen.beginIf(lenAccessGuard)
- self.cgen.beginFor("uint32_t i = 0", "i < (uint32_t)%s" % lenAccess, "++i")
- self.genPrimitiveStreamCall(vulkanType.getForValueAccess())
- self.cgen.endFor()
- if lenAccessGuard is not None:
- self.cgen.endIf()
- else:
- self.genPrimitiveStreamCall(vulkanType.getForValueAccess())
- else:
- if lenAccess is not None:
- needLenAccessGuard = True
- finalLenExpr = "%s * %s" % (
- lenAccess, self.cgen.sizeofExpr(vulkanType.getForValueAccess()))
- else:
- needLenAccessGuard = False
- finalLenExpr = "%s" % (
- self.cgen.sizeofExpr(vulkanType.getForValueAccess()))
- if needLenAccessGuard and lenAccessGuard is not None:
- self.cgen.beginIf(lenAccessGuard)
- self.genCount(finalLenExpr)
- if needLenAccessGuard and lenAccessGuard is not None:
- self.cgen.endIf()
-
- self.endFilterGuard(vulkanType)
-
- def onValue(self, vulkanType):
- self.beginFilterGuard(vulkanType)
-
- if vulkanType.isHandleType() and self.mapHandles:
- access = self.exprAccessor(vulkanType)
- if vulkanType.filterVar != None:
- print("onValue Needs filter: %s filterVar %s" % (access, vulkanType.filterVar))
- self.genHandleMappingCall(
- vulkanType.getForAddressAccess(), access, "1")
- elif self.typeInfo.isNonAbiPortableType(vulkanType.typeName):
- access = self.exprPrimitiveValueAccessor(vulkanType)
- self.genPrimitiveStreamCall(vulkanType)
- else:
- access = self.exprAccessor(vulkanType)
- self.genCount(self.cgen.sizeofExpr(vulkanType))
-
- self.endFilterGuard(vulkanType)
-
- def streamLetParameter(self, structInfo, letParamInfo):
- filterFeature = "%s & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT" % (self.featureBitsVar)
- self.cgen.stmt("%s %s = 1" % (letParamInfo.typeName, letParamInfo.paramName))
-
- self.cgen.beginIf(filterFeature)
-
- bodyExpr = self.currentStructInfo.environment[letParamInfo.paramName]["body"]
- self.cgen.stmt("%s = %s" % (letParamInfo.paramName, self.genFilterFunc(bodyExpr, self.currentStructInfo.environment)))
-
- self.genPrimitiveStreamCall(letParamInfo)
-
- self.cgen.endIf()
-
-class VulkanCounting(VulkanWrapperGenerator):
-
- def __init__(self, module, typeInfo):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
-
- self.codegen = CodeGen()
-
- self.featureBitsVar = "featureBits"
- self.featureBitsVarType = makeVulkanTypeSimple(False, "uint32_t", 0, self.featureBitsVar)
- self.countingPrefix = "count_"
- self.countVars = ["toCount", "count"]
- self.countVarType = makeVulkanTypeSimple(False, "size_t", 1, self.countVars[1])
- self.voidType = makeVulkanTypeSimple(False, "void", 0)
- self.rootTypeVar = ROOT_TYPE_VAR_NAME
-
- self.countingCodegen = \
- VulkanCountingCodegen(
- self.codegen,
- self.featureBitsVar,
- self.countVars[0],
- self.countVars[1],
- self.rootTypeVar,
- self.countingPrefix)
-
- self.knownDefs = {}
-
- self.extensionCountingPrototype = \
- VulkanAPI(self.countingPrefix + "extension_struct",
- self.voidType,
- [self.featureBitsVarType,
- ROOT_TYPE_PARAM,
- STRUCT_EXTENSION_PARAM,
- self.countVarType])
-
- def onBegin(self,):
- VulkanWrapperGenerator.onBegin(self)
- self.module.appendImpl(self.codegen.makeFuncDecl(
- self.extensionCountingPrototype))
-
- def onGenType(self, typeXml, name, alias):
- VulkanWrapperGenerator.onGenType(self, typeXml, name, alias)
-
- if name in self.knownDefs:
- return
-
- category = self.typeInfo.categoryOf(name)
-
- if category in ["struct", "union"] and alias:
- # TODO(liyl): might not work if freeParams != []
- self.module.appendHeader(
- self.codegen.makeFuncAlias(self.countingPrefix + name,
- self.countingPrefix + alias))
-
- if category in ["struct", "union"] and not alias:
-
- structInfo = self.typeInfo.structs[name]
-
- freeParams = []
- letParams = []
-
- for (envname, bindingInfo) in list(sorted(structInfo.environment.items(), key = lambda kv: kv[0])):
- if None == bindingInfo["binding"]:
- freeParams.append(makeVulkanTypeSimple(True, bindingInfo["type"], 0, envname))
- else:
- if not bindingInfo["structmember"]:
- letParams.append(makeVulkanTypeSimple(True, bindingInfo["type"], 0, envname))
-
- typeFromName = \
- lambda varname: \
- makeVulkanTypeSimple(True, name, 1, varname)
-
- countingParams = \
- [makeVulkanTypeSimple(False, "uint32_t", 0, self.featureBitsVar),
- ROOT_TYPE_PARAM,
- typeFromName(self.countVars[0]),
- makeVulkanTypeSimple(False, "size_t", 1, self.countVars[1])]
-
- countingPrototype = \
- VulkanAPI(self.countingPrefix + name,
- self.voidType,
- countingParams + freeParams)
-
- countingPrototypeNoFilter = \
- VulkanAPI(self.countingPrefix + name,
- self.voidType,
- countingParams)
-
- def structCountingDef(cgen):
- self.countingCodegen.cgen = cgen
- self.countingCodegen.currentStructInfo = structInfo
- cgen.stmt("(void)%s" % self.featureBitsVar);
- cgen.stmt("(void)%s" % self.rootTypeVar);
- cgen.stmt("(void)%s" % self.countVars[0]);
- cgen.stmt("(void)%s" % self.countVars[1]);
-
- if category == "struct":
- # marshal 'let' parameters first
- for letp in letParams:
- self.countingCodegen.streamLetParameter(self.typeInfo, letp)
-
- for member in structInfo.members:
- iterateVulkanType(self.typeInfo, member, self.countingCodegen)
- if category == "union":
- iterateVulkanType(self.typeInfo, structInfo.members[0], self.countingCodegen)
-
- def structCountingDefNoFilter(cgen):
- self.countingCodegen.cgen = cgen
- self.countingCodegen.currentStructInfo = structInfo
- self.countingCodegen.doFiltering = False
- cgen.stmt("(void)%s" % self.featureBitsVar);
- cgen.stmt("(void)%s" % self.rootTypeVar);
- cgen.stmt("(void)%s" % self.countVars[0]);
- cgen.stmt("(void)%s" % self.countVars[1]);
-
- if category == "struct":
- # marshal 'let' parameters first
- for letp in letParams:
- self.countingCodegen.streamLetParameter(self.typeInfo, letp)
-
- for member in structInfo.members:
- iterateVulkanType(self.typeInfo, member, self.countingCodegen)
- if category == "union":
- iterateVulkanType(self.typeInfo, structInfo.members[0], self.countingCodegen)
-
- self.countingCodegen.doFiltering = True
-
- self.module.appendHeader(
- self.codegen.makeFuncDecl(countingPrototype))
- self.module.appendImpl(
- self.codegen.makeFuncImpl(countingPrototype, structCountingDef))
-
- if freeParams != []:
- self.module.appendHeader(
- self.cgenHeader.makeFuncDecl(countingPrototypeNoFilter))
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- countingPrototypeNoFilter, structCountingDefNoFilter))
-
- def onGenCmd(self, cmdinfo, name, alias):
- VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
-
- def doExtensionStructCountCodegen(self, cgen, extParam, forEach, funcproto):
- accessVar = "structAccess"
- sizeVar = "currExtSize"
- cgen.stmt("VkInstanceCreateInfo* %s = (VkInstanceCreateInfo*)(%s)" % (accessVar, extParam.paramName))
- cgen.stmt("size_t %s = %s(%s, %s, %s)" % (sizeVar, EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME,
- self.featureBitsVar, ROOT_TYPE_VAR_NAME, extParam.paramName))
-
- cgen.beginIf("!%s && %s" % (sizeVar, extParam.paramName))
-
- cgen.line("// unknown struct extension; skip and call on its pNext field");
- cgen.funcCall(None, funcproto.name, [
- self.featureBitsVar, ROOT_TYPE_VAR_NAME, "(void*)%s->pNext" % accessVar, self.countVars[1]])
- cgen.stmt("return")
-
- cgen.endIf()
- cgen.beginElse()
-
- cgen.line("// known or null extension struct")
-
- cgen.stmt("*%s += sizeof(uint32_t)" % self.countVars[1])
-
- cgen.beginIf("!%s" % (sizeVar))
- cgen.line("// exit if this was a null extension struct (size == 0 in this branch)")
- cgen.stmt("return")
- cgen.endIf()
-
- cgen.endIf()
-
- cgen.stmt("*%s += sizeof(VkStructureType)" % self.countVars[1])
-
- def fatalDefault(cgen):
- cgen.line("// fatal; the switch is only taken if the extension struct is known");
- cgen.stmt("abort()")
- pass
-
- self.emitForEachStructExtension(
- cgen,
- makeVulkanTypeSimple(False, "void", 0, "void"),
- extParam,
- forEach,
- defaultEmit=fatalDefault,
- rootTypeVar=ROOT_TYPE_PARAM)
-
- def onEnd(self,):
- VulkanWrapperGenerator.onEnd(self)
-
- def forEachExtensionCounting(ext, castedAccess, cgen):
- cgen.funcCall(None, self.countingPrefix + ext.name,
- [self.featureBitsVar, self.rootTypeVar, castedAccess, self.countVars[1]])
-
- self.module.appendImpl(
- self.codegen.makeFuncImpl(
- self.extensionCountingPrototype,
- lambda cgen: self.doExtensionStructCountCodegen(
- cgen,
- STRUCT_EXTENSION_PARAM,
- forEachExtensionCounting,
- self.extensionCountingPrototype)))
diff --git a/codegen/vulkan/scripts/cereal/decoder.py b/codegen/vulkan/scripts/cereal/decoder.py
deleted file mode 100644
index e082db0c..00000000
--- a/codegen/vulkan/scripts/cereal/decoder.py
+++ /dev/null
@@ -1,912 +0,0 @@
-from .common.codegen import CodeGen, VulkanWrapperGenerator
-from .common.vulkantypes import VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, VulkanTypeInfo,\
- VulkanType
-
-from .marshaling import VulkanMarshalingCodegen
-from .reservedmarshaling import VulkanReservedMarshalingCodegen
-from .transform import TransformCodegen
-
-from .wrapperdefs import API_PREFIX_MARSHAL
-from .wrapperdefs import API_PREFIX_RESERVEDUNMARSHAL
-from .wrapperdefs import MAX_PACKET_LENGTH
-from .wrapperdefs import VULKAN_STREAM_TYPE
-from .wrapperdefs import ROOT_TYPE_DEFAULT_VALUE
-from .wrapperdefs import RELAXED_APIS
-
-
-SKIPPED_DECODER_DELETES = [
- "vkFreeDescriptorSets",
-]
-
-DELAYED_DECODER_DELETES = [
- "vkDestroyPipelineLayout",
-]
-
-global_state_prefix = "m_state->on_"
-
-decoder_decl_preamble = """
-
-namespace gfxstream {
-class IOStream;
-class ProcessResources;
-} // namespace gfxstream
-
-namespace gfxstream {
-namespace vk {
-
-class VkDecoder {
-public:
- VkDecoder();
- ~VkDecoder();
- void setForSnapshotLoad(bool forSnapshotLoad);
- size_t decode(void* buf, size_t bufsize, IOStream* stream,
- const ProcessResources* processResources, const VkDecoderContext&);
-private:
- class Impl;
- std::unique_ptr<Impl> mImpl;
-};
-
-} // namespace vk
-} // namespace gfxstream
-
-"""
-
-decoder_impl_preamble ="""
-namespace gfxstream {
-namespace vk {
-
-using android::base::MetricEventBadPacketLength;
-using android::base::MetricEventDuplicateSequenceNum;
-
-class VkDecoder::Impl {
-public:
- Impl() : m_logCalls(android::base::getEnvironmentVariable("ANDROID_EMU_VK_LOG_CALLS") == "1"),
- m_vk(vkDispatch()),
- m_state(VkDecoderGlobalState::get()),
- m_boxedHandleUnwrapMapping(m_state),
- m_boxedHandleCreateMapping(m_state),
- m_boxedHandleDestroyMapping(m_state),
- m_boxedHandleUnwrapAndDeleteMapping(m_state),
- m_boxedHandleUnwrapAndDeletePreserveBoxedMapping(m_state),
- m_prevSeqno(std::nullopt) {}
- %s* stream() { return &m_vkStream; }
- VulkanMemReadingStream* readStream() { return &m_vkMemReadingStream; }
-
- void setForSnapshotLoad(bool forSnapshotLoad) {
- m_forSnapshotLoad = forSnapshotLoad;
- }
-
- size_t decode(void* buf, size_t bufsize, IOStream* stream,
- const ProcessResources* processResources, const VkDecoderContext&);
-
-private:
- bool m_logCalls;
- bool m_forSnapshotLoad = false;
- VulkanDispatch* m_vk;
- VkDecoderGlobalState* m_state;
- %s m_vkStream { nullptr };
- VulkanMemReadingStream m_vkMemReadingStream { nullptr };
- BoxedHandleUnwrapMapping m_boxedHandleUnwrapMapping;
- BoxedHandleCreateMapping m_boxedHandleCreateMapping;
- BoxedHandleDestroyMapping m_boxedHandleDestroyMapping;
- BoxedHandleUnwrapAndDeleteMapping m_boxedHandleUnwrapAndDeleteMapping;
- android::base::BumpPool m_pool;
- BoxedHandleUnwrapAndDeletePreserveBoxedMapping m_boxedHandleUnwrapAndDeletePreserveBoxedMapping;
- std::optional<uint32_t> m_prevSeqno;
-};
-
-VkDecoder::VkDecoder() :
- mImpl(new VkDecoder::Impl()) { }
-
-VkDecoder::~VkDecoder() = default;
-
-void VkDecoder::setForSnapshotLoad(bool forSnapshotLoad) {
- mImpl->setForSnapshotLoad(forSnapshotLoad);
-}
-
-size_t VkDecoder::decode(void* buf, size_t bufsize, IOStream* stream,
- const ProcessResources* processResources,
- const VkDecoderContext& context) {
- return mImpl->decode(buf, bufsize, stream, processResources, context);
-}
-
-// VkDecoder::Impl::decode to follow
-""" % (VULKAN_STREAM_TYPE, VULKAN_STREAM_TYPE)
-
-decoder_impl_postamble = """
-
-} // namespace vk
-} // namespace gfxstream
-
-"""
-
-READ_STREAM = "vkReadStream"
-WRITE_STREAM = "vkStream"
-
-# Driver workarounds for APIs that don't work well multithreaded
-driver_workarounds_global_lock_apis = [ \
- "vkCreatePipelineLayout",
- "vkDestroyPipelineLayout",
-]
-
-def emit_param_decl_for_reading(param, cgen):
- if param.staticArrExpr:
- cgen.stmt(
- cgen.makeRichCTypeDecl(param.getForNonConstAccess()))
- else:
- cgen.stmt(
- cgen.makeRichCTypeDecl(param))
-
-def emit_unmarshal(typeInfo, param, cgen, output = False, destroy = False, noUnbox = False):
- if destroy:
- iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
- cgen,
- READ_STREAM,
- ROOT_TYPE_DEFAULT_VALUE,
- param.paramName,
- "readStreamPtrPtr",
- API_PREFIX_RESERVEDUNMARSHAL,
- "",
- direction="read",
- dynAlloc=True))
- lenAccess = cgen.generalLengthAccess(param)
- lenAccessGuard = cgen.generalLengthAccessGuard(param)
- if None == lenAccess or "1" == lenAccess:
- cgen.stmt("boxed_%s_preserve = %s" % (param.paramName, param.paramName))
- cgen.stmt("%s = unbox_%s(%s)" % (param.paramName, param.typeName, param.paramName))
- else:
- if lenAccessGuard is not None:
- cgen.beginIf(lenAccessGuard)
- cgen.beginFor("uint32_t i = 0", "i < %s" % lenAccess, "++i")
- cgen.stmt("boxed_%s_preserve[i] = %s[i]" % (param.paramName, param.paramName))
- cgen.stmt("((%s*)(%s))[i] = unbox_%s(%s[i])" % (param.typeName, param.paramName, param.typeName, param.paramName))
- cgen.endFor()
- if lenAccessGuard is not None:
- cgen.endIf()
- else:
- if noUnbox:
- cgen.line("// No unbox for %s" % (param.paramName))
- iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
- cgen,
- READ_STREAM,
- ROOT_TYPE_DEFAULT_VALUE,
- param.paramName,
- "readStreamPtrPtr",
- API_PREFIX_RESERVEDUNMARSHAL,
- "" if (output or noUnbox) else "unbox_",
- direction="read",
- dynAlloc=True))
-
-
-def emit_dispatch_unmarshal(typeInfo: VulkanTypeInfo, param: VulkanType, cgen, globalWrapped):
- cgen.stmt("// Begin {} wrapped dispatchable handle unboxing for {}".format(
- "global" if globalWrapped else "non",
- param.paramName))
-
- iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
- cgen,
- READ_STREAM,
- ROOT_TYPE_DEFAULT_VALUE,
- param.paramName,
- "readStreamPtrPtr",
- API_PREFIX_RESERVEDUNMARSHAL,
- "",
- direction="read",
- dynAlloc=True))
-
- if not globalWrapped:
- cgen.stmt("auto unboxed_%s = unbox_%s(%s)" %
- (param.paramName, param.typeName, param.paramName))
- cgen.stmt("auto vk = dispatch_%s(%s)" %
- (param.typeName, param.paramName))
- cgen.stmt("// End manual dispatchable handle unboxing for %s" % param.paramName)
-
-
-def emit_transform(typeInfo, param, cgen, variant="tohost"):
- res = iterateVulkanType(typeInfo, param, TransformCodegen(
- cgen, param.paramName, "m_state", "transform_%s_" % variant, variant))
- if not res:
- cgen.stmt("(void)%s" % param.paramName)
-
-
-def emit_marshal(typeInfo, param, cgen, handleMapOverwrites=False):
- iterateVulkanType(typeInfo, param, VulkanMarshalingCodegen(
- cgen,
- WRITE_STREAM,
- ROOT_TYPE_DEFAULT_VALUE,
- param.paramName,
- API_PREFIX_MARSHAL,
- direction="write",
- handleMapOverwrites=handleMapOverwrites))
-
-
-class DecodingParameters(object):
- def __init__(self, api: VulkanAPI):
- self.params: list[VulkanType] = []
- self.toRead: list[VulkanType] = []
- self.toWrite: list[VulkanType] = []
-
- for i, param in enumerate(api.parameters):
- if i == 0 and param.isDispatchableHandleType():
- param.dispatchHandle = True
-
- if param.isNonDispatchableHandleType() and param.isCreatedBy(api):
- param.nonDispatchableHandleCreate = True
-
- if param.isNonDispatchableHandleType() and param.isDestroyedBy(api):
- param.nonDispatchableHandleDestroy = True
-
- if param.isDispatchableHandleType() and param.isCreatedBy(api):
- param.dispatchableHandleCreate = True
-
- if param.isDispatchableHandleType() and param.isDestroyedBy(api):
- param.dispatchableHandleDestroy = True
-
- self.toRead.append(param)
-
- if param.possiblyOutput():
- self.toWrite.append(param)
-
- self.params.append(param)
-
-
-def emit_call_log(api, cgen):
- decodingParams = DecodingParameters(api)
- paramsToRead = decodingParams.toRead
-
- cgen.beginIf("m_logCalls")
- paramLogFormat = ""
- paramLogArgs = []
- for p in paramsToRead:
- paramLogFormat += "0x%llx "
- for p in paramsToRead:
- paramLogArgs.append("(unsigned long long)%s" % (p.paramName))
- cgen.stmt("fprintf(stderr, \"stream %%p: call %s %s\\n\", ioStream, %s)" % (api.name, paramLogFormat, ", ".join(paramLogArgs)))
- cgen.endIf()
-
-def emit_decode_parameters(typeInfo: VulkanTypeInfo, api: VulkanAPI, cgen, globalWrapped=False):
- decodingParams = DecodingParameters(api)
-
- paramsToRead = decodingParams.toRead
-
- for p in paramsToRead:
- emit_param_decl_for_reading(p, cgen)
-
- for i, p in enumerate(paramsToRead):
- lenAccess = cgen.generalLengthAccess(p)
-
- if p.dispatchHandle:
- emit_dispatch_unmarshal(typeInfo, p, cgen, globalWrapped)
- else:
- destroy = p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy
- noUnbox = api.name in ["vkQueueFlushCommandsGOOGLE", "vkQueueFlushCommandsFromAuxMemoryGOOGLE"] and p.paramName == "commandBuffer"
-
- if p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy:
- destroy = True
- cgen.stmt("// Begin manual non dispatchable handle destroy unboxing for %s" % p.paramName)
- if None == lenAccess or "1" == lenAccess:
- cgen.stmt("%s boxed_%s_preserve" % (p.typeName, p.paramName))
- else:
- cgen.stmt("%s* boxed_%s_preserve; %s->alloc((void**)&boxed_%s_preserve, %s * sizeof(%s))" % (p.typeName, p.paramName, READ_STREAM, p.paramName, lenAccess, p.typeName))
-
- if p.possiblyOutput():
- cgen.stmt("// Begin manual dispatchable handle unboxing for %s" % p.paramName)
- cgen.stmt("%s->unsetHandleMapping()" % READ_STREAM)
-
- emit_unmarshal(typeInfo, p, cgen, output = p.possiblyOutput(), destroy = destroy, noUnbox = noUnbox)
-
- for p in paramsToRead:
- emit_transform(typeInfo, p, cgen, variant="tohost")
-
- emit_call_log(api, cgen)
-
-def emit_dispatch_call(api, cgen):
-
- decodingParams = DecodingParameters(api)
-
- customParams = []
-
- delay = api.name in DELAYED_DECODER_DELETES
-
- for i, p in enumerate(api.parameters):
- customParam = p.paramName
- if decodingParams.params[i].dispatchHandle:
- customParam = "unboxed_%s" % p.paramName
- customParams.append(customParam)
-
- if delay:
- cgen.line("std::function<void()> delayed_remove_callback = [vk, %s]() {" % ", ".join(customParams))
-
- if api.name in driver_workarounds_global_lock_apis:
- if delay:
- cgen.stmt("auto state = VkDecoderGlobalState::get()")
- cgen.stmt("// state already locked")
- else:
- cgen.stmt("m_state->lock()")
-
- cgen.vkApiCall(api, customPrefix="vk->", customParameters=customParams, \
- globalStatePrefix=global_state_prefix, checkForDeviceLost=True,
- checkForOutOfMemory=True)
-
- if api.name in driver_workarounds_global_lock_apis:
- if not delay:
- cgen.stmt("m_state->unlock()")
- # for delayed remove, state is already locked, so we do not need to
- # unlock
-
- if delay:
- cgen.line("};")
-
-def emit_global_state_wrapped_call(api, cgen, context):
- if api.name in DELAYED_DECODER_DELETES:
- print("Error: Cannot generate a global state wrapped call that is also a delayed delete (yet)");
- raise
-
- customParams = ["&m_pool"] + list(map(lambda p: p.paramName, api.parameters))
- if context:
- customParams += ["context"]
- cgen.vkApiCall(api, customPrefix=global_state_prefix, \
- customParameters=customParams, globalStatePrefix=global_state_prefix, \
- checkForDeviceLost=True, checkForOutOfMemory=True)
-
-def emit_decode_parameters_writeback(typeInfo, api, cgen, autobox=True):
- decodingParams = DecodingParameters(api)
-
- paramsToWrite = decodingParams.toWrite
-
- cgen.stmt("%s->unsetHandleMapping()" % WRITE_STREAM)
-
- handleMapOverwrites = False
-
- for p in paramsToWrite:
- emit_transform(typeInfo, p, cgen, variant="fromhost")
-
- handleMapOverwrites = False
-
- if p.nonDispatchableHandleCreate or p.dispatchableHandleCreate:
- handleMapOverwrites = True
-
- if autobox and p.nonDispatchableHandleCreate:
- cgen.stmt("// Begin auto non dispatchable handle create for %s" % p.paramName)
- cgen.stmt("if (%s == VK_SUCCESS) %s->setHandleMapping(&m_boxedHandleCreateMapping)" % \
- (api.getRetVarExpr(), WRITE_STREAM))
-
- if (not autobox) and p.nonDispatchableHandleCreate:
- cgen.stmt("// Begin manual non dispatchable handle create for %s" % p.paramName)
- cgen.stmt("%s->unsetHandleMapping()" % WRITE_STREAM)
-
- emit_marshal(typeInfo, p, cgen, handleMapOverwrites=handleMapOverwrites)
-
- if autobox and p.nonDispatchableHandleCreate:
- cgen.stmt("// Begin auto non dispatchable handle create for %s" % p.paramName)
- cgen.stmt("%s->setHandleMapping(&m_boxedHandleUnwrapMapping)" % WRITE_STREAM)
-
- if (not autobox) and p.nonDispatchableHandleCreate:
- cgen.stmt("// Begin manual non dispatchable handle create for %s" % p.paramName)
- cgen.stmt("%s->setHandleMapping(&m_boxedHandleUnwrapMapping)" % WRITE_STREAM)
-
-def emit_decode_return_writeback(api, cgen):
- retTypeName = api.getRetTypeExpr()
- if retTypeName != "void":
- retVar = api.getRetVarExpr()
- cgen.stmt("%s->write(&%s, %s)" %
- (WRITE_STREAM, retVar, cgen.sizeofExpr(api.retType)))
-
-def emit_decode_finish(api, cgen):
- decodingParams = DecodingParameters(api)
- retTypeName = api.getRetTypeExpr()
- paramsToWrite = decodingParams.toWrite
-
- if retTypeName != "void" or len(paramsToWrite) != 0:
- cgen.stmt("%s->commitWrite()" % WRITE_STREAM)
-
-def emit_destroyed_handle_cleanup(api, cgen):
- decodingParams = DecodingParameters(api)
- paramsToRead = decodingParams.toRead
-
- skipDelete = api.name in SKIPPED_DECODER_DELETES
-
- if skipDelete:
- cgen.line("// Skipping handle cleanup for %s" % api.name)
- return
-
- for p in paramsToRead:
- if p.dispatchHandle:
- pass
- else:
- lenAccess = cgen.generalLengthAccess(p)
- lenAccessGuard = cgen.generalLengthAccess(p)
- destroy = p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy
- if destroy:
- if None == lenAccess or "1" == lenAccess:
- if api.name in DELAYED_DECODER_DELETES:
- cgen.stmt("delayed_delete_%s(boxed_%s_preserve, unboxed_device, delayed_remove_callback)" % (p.typeName, p.paramName))
- else:
- cgen.stmt("delete_%s(boxed_%s_preserve)" % (p.typeName, p.paramName))
- else:
- if lenAccessGuard is not None:
- cgen.beginIf(lenAccessGuard)
- cgen.beginFor("uint32_t i = 0", "i < %s" % lenAccess, "++i")
- if api.name in DELAYED_DECODER_DELETES:
- cgen.stmt("delayed_delete_%s(boxed_%s_preserve[i], unboxed_device, delayed_remove_callback)" % (p.typeName, p.paramName))
- else:
- cgen.stmt("delete_%s(boxed_%s_preserve[i])" % (p.typeName, p.paramName))
- cgen.endFor()
- if lenAccessGuard is not None:
- cgen.endIf()
-
-def emit_pool_free(cgen):
- cgen.stmt("%s->clearPool()" % READ_STREAM)
-
-def emit_seqno_incr(api, cgen):
- cgen.stmt("if (queueSubmitWithCommandsEnabled) seqnoPtr->fetch_add(1, std::memory_order_seq_cst)")
-
-def emit_snapshot(typeInfo, api, cgen):
-
- cgen.stmt("%s->setReadPos((uintptr_t)(*readStreamPtrPtr) - (uintptr_t)snapshotTraceBegin)" % READ_STREAM)
- cgen.stmt("size_t snapshotTraceBytes = %s->endTrace()" % READ_STREAM)
-
- additionalParams = [ \
- makeVulkanTypeSimple(True, "uint8_t", 1, "snapshotTraceBegin"),
- makeVulkanTypeSimple(False, "size_t", 0, "snapshotTraceBytes"),
- makeVulkanTypeSimple(False, "android::base::BumpPool", 1, "&m_pool"),
- ]
-
- retTypeName = api.getRetTypeExpr()
- if retTypeName != "void":
- retVar = api.getRetVarExpr()
- additionalParams.append(makeVulkanTypeSimple(False, retTypeName, 0, retVar))
-
- paramsForSnapshot = []
-
- decodingParams = DecodingParameters(api)
-
- for p in decodingParams.toRead:
- if p.nonDispatchableHandleDestroy or (not p.dispatchHandle and p.dispatchableHandleDestroy):
- paramsForSnapshot.append(p.withModifiedName("boxed_%s_preserve" % p.paramName))
- else:
- paramsForSnapshot.append(p)
-
- customParams = additionalParams + paramsForSnapshot
-
- apiForSnapshot = \
- api.withCustomReturnType(makeVulkanTypeSimple(False, "void", 0, "void")). \
- withCustomParameters(customParams)
-
- cgen.beginIf("m_state->snapshotsEnabled()")
- cgen.vkApiCall(apiForSnapshot, customPrefix="m_state->snapshot()->")
- cgen.endIf()
-
-def emit_decoding(typeInfo, api, cgen, globalWrapped=False, context=False):
- isAcquire = api.name in RELAXED_APIS
- emit_decode_parameters(typeInfo, api, cgen, globalWrapped)
-
- if isAcquire:
- emit_seqno_incr(api, cgen)
-
- if globalWrapped:
- emit_global_state_wrapped_call(api, cgen, context)
- else:
- emit_dispatch_call(api, cgen)
-
- emit_decode_parameters_writeback(typeInfo, api, cgen, autobox=not globalWrapped)
- emit_decode_return_writeback(api, cgen)
- emit_decode_finish(api, cgen)
- emit_snapshot(typeInfo, api, cgen)
- emit_destroyed_handle_cleanup(api, cgen)
- emit_pool_free(cgen)
-
- if not isAcquire:
- emit_seqno_incr(api, cgen)
-
-def emit_default_decoding(typeInfo, api, cgen):
- emit_decoding(typeInfo, api, cgen)
-
-def emit_global_state_wrapped_decoding(typeInfo, api, cgen):
- emit_decoding(typeInfo, api, cgen, globalWrapped=True)
-
-def emit_global_state_wrapped_decoding_with_context(typeInfo, api, cgen):
- emit_decoding(typeInfo, api, cgen, globalWrapped=True, context=True)
-
-## Custom decoding definitions##################################################
-def decode_vkFlushMappedMemoryRanges(typeInfo: VulkanTypeInfo, api, cgen):
- emit_decode_parameters(typeInfo, api, cgen)
-
- cgen.beginIf("!m_state->usingDirectMapping()")
- cgen.beginFor("uint32_t i = 0", "i < memoryRangeCount", "++i")
- cgen.stmt("auto range = pMemoryRanges[i]")
- cgen.stmt("auto memory = pMemoryRanges[i].memory")
- cgen.stmt("auto size = pMemoryRanges[i].size")
- cgen.stmt("auto offset = pMemoryRanges[i].offset")
- cgen.stmt("uint64_t readStream = 0")
- cgen.stmt("memcpy(&readStream, *readStreamPtrPtr, sizeof(uint64_t)); *readStreamPtrPtr += sizeof(uint64_t)")
- cgen.stmt("auto hostPtr = m_state->getMappedHostPointer(memory)")
- cgen.stmt("if (!hostPtr && readStream > 0) GFXSTREAM_ABORT(::emugl::FatalError(::emugl::ABORT_REASON_OTHER))")
- cgen.stmt("if (!hostPtr) continue")
- cgen.stmt("uint8_t* targetRange = hostPtr + offset")
- cgen.stmt("memcpy(targetRange, *readStreamPtrPtr, readStream); *readStreamPtrPtr += readStream")
- cgen.endFor()
- cgen.endIf()
-
- emit_dispatch_call(api, cgen)
- emit_decode_parameters_writeback(typeInfo, api, cgen)
- emit_decode_return_writeback(api, cgen)
- emit_decode_finish(api, cgen)
- emit_snapshot(typeInfo, api, cgen);
- emit_pool_free(cgen)
- emit_seqno_incr(api, cgen)
-
-def decode_vkInvalidateMappedMemoryRanges(typeInfo, api, cgen):
- emit_decode_parameters(typeInfo, api, cgen)
- emit_dispatch_call(api, cgen)
- emit_decode_parameters_writeback(typeInfo, api, cgen)
- emit_decode_return_writeback(api, cgen)
-
- cgen.beginIf("!m_state->usingDirectMapping()")
- cgen.beginFor("uint32_t i = 0", "i < memoryRangeCount", "++i")
- cgen.stmt("auto range = pMemoryRanges[i]")
- cgen.stmt("auto memory = range.memory")
- cgen.stmt("auto size = range.size")
- cgen.stmt("auto offset = range.offset")
- cgen.stmt("auto hostPtr = m_state->getMappedHostPointer(memory)")
- cgen.stmt("auto actualSize = size == VK_WHOLE_SIZE ? m_state->getDeviceMemorySize(memory) : size")
- cgen.stmt("uint64_t writeStream = 0")
- cgen.stmt("if (!hostPtr) { %s->write(&writeStream, sizeof(uint64_t)); continue; }" % WRITE_STREAM)
- cgen.stmt("uint8_t* targetRange = hostPtr + offset")
- cgen.stmt("writeStream = actualSize")
- cgen.stmt("%s->write(&writeStream, sizeof(uint64_t))" % WRITE_STREAM)
- cgen.stmt("%s->write(targetRange, actualSize)" % WRITE_STREAM)
- cgen.endFor()
- cgen.endIf()
-
- emit_decode_finish(api, cgen)
- emit_snapshot(typeInfo, api, cgen);
- emit_pool_free(cgen)
- emit_seqno_incr(api, cgen)
-
-def decode_unsupported_api(typeInfo, api, cgen):
- cgen.line(f"// Decoding {api.name} is not supported. This should not run.")
- cgen.stmt(f"fprintf(stderr, \"stream %p: fatal: decoding unsupported API {api.name}\\n\", ioStream)");
- cgen.stmt("__builtin_trap()")
-
-custom_decodes = {
- "vkEnumerateInstanceVersion" : emit_global_state_wrapped_decoding,
- "vkCreateInstance" : emit_global_state_wrapped_decoding,
- "vkDestroyInstance" : emit_global_state_wrapped_decoding,
- "vkEnumeratePhysicalDevices" : emit_global_state_wrapped_decoding,
-
- "vkGetPhysicalDeviceFeatures" : emit_global_state_wrapped_decoding,
- "vkGetPhysicalDeviceFeatures2" : emit_global_state_wrapped_decoding,
- "vkGetPhysicalDeviceFeatures2KHR" : emit_global_state_wrapped_decoding,
- "vkGetPhysicalDeviceFormatProperties" : emit_global_state_wrapped_decoding,
- "vkGetPhysicalDeviceFormatProperties2" : emit_global_state_wrapped_decoding,
- "vkGetPhysicalDeviceFormatProperties2KHR" : emit_global_state_wrapped_decoding,
- "vkGetPhysicalDeviceImageFormatProperties" : emit_global_state_wrapped_decoding,
- "vkGetPhysicalDeviceImageFormatProperties2" : emit_global_state_wrapped_decoding,
- "vkGetPhysicalDeviceImageFormatProperties2KHR" : emit_global_state_wrapped_decoding,
- "vkGetPhysicalDeviceProperties" : emit_global_state_wrapped_decoding,
- "vkGetPhysicalDeviceProperties2" : emit_global_state_wrapped_decoding,
- "vkGetPhysicalDeviceProperties2KHR" : emit_global_state_wrapped_decoding,
-
- "vkGetPhysicalDeviceMemoryProperties" : emit_global_state_wrapped_decoding,
- "vkGetPhysicalDeviceMemoryProperties2" : emit_global_state_wrapped_decoding,
- "vkGetPhysicalDeviceMemoryProperties2KHR" : emit_global_state_wrapped_decoding,
-
- "vkGetPhysicalDeviceExternalSemaphoreProperties" : emit_global_state_wrapped_decoding,
- "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" : emit_global_state_wrapped_decoding,
-
- "vkEnumerateDeviceExtensionProperties" : emit_global_state_wrapped_decoding,
-
- "vkCreateBuffer" : emit_global_state_wrapped_decoding,
- "vkDestroyBuffer" : emit_global_state_wrapped_decoding,
-
- "vkBindBufferMemory" : emit_global_state_wrapped_decoding,
- "vkBindBufferMemory2" : emit_global_state_wrapped_decoding,
- "vkBindBufferMemory2KHR" : emit_global_state_wrapped_decoding,
-
- "vkCreateDevice" : emit_global_state_wrapped_decoding,
- "vkGetDeviceQueue" : emit_global_state_wrapped_decoding,
- "vkDestroyDevice" : emit_global_state_wrapped_decoding,
-
- "vkGetDeviceQueue2" : emit_global_state_wrapped_decoding,
-
- "vkBindImageMemory" : emit_global_state_wrapped_decoding,
- "vkBindImageMemory2" : emit_global_state_wrapped_decoding,
- "vkBindImageMemory2KHR" : emit_global_state_wrapped_decoding,
-
- "vkCreateImage" : emit_global_state_wrapped_decoding,
- "vkCreateImageView" : emit_global_state_wrapped_decoding,
- "vkCreateSampler" : emit_global_state_wrapped_decoding,
- "vkDestroyImage" : emit_global_state_wrapped_decoding,
- "vkDestroyImageView" : emit_global_state_wrapped_decoding,
- "vkDestroySampler" : emit_global_state_wrapped_decoding,
- "vkCmdCopyBufferToImage" : emit_global_state_wrapped_decoding_with_context,
- "vkCmdCopyImage" : emit_global_state_wrapped_decoding,
- "vkCmdCopyImageToBuffer" : emit_global_state_wrapped_decoding,
- "vkGetImageMemoryRequirements" : emit_global_state_wrapped_decoding,
- "vkGetImageMemoryRequirements2" : emit_global_state_wrapped_decoding,
- "vkGetImageMemoryRequirements2KHR" : emit_global_state_wrapped_decoding,
- "vkGetBufferMemoryRequirements" : emit_global_state_wrapped_decoding,
- "vkGetBufferMemoryRequirements2": emit_global_state_wrapped_decoding,
- "vkGetBufferMemoryRequirements2KHR": emit_global_state_wrapped_decoding,
-
- "vkCreateDescriptorSetLayout" : emit_global_state_wrapped_decoding,
- "vkDestroyDescriptorSetLayout" : emit_global_state_wrapped_decoding,
- "vkCreateDescriptorPool" : emit_global_state_wrapped_decoding,
- "vkDestroyDescriptorPool" : emit_global_state_wrapped_decoding,
- "vkResetDescriptorPool" : emit_global_state_wrapped_decoding,
- "vkAllocateDescriptorSets" : emit_global_state_wrapped_decoding,
- "vkFreeDescriptorSets" : emit_global_state_wrapped_decoding,
-
- "vkUpdateDescriptorSets" : emit_global_state_wrapped_decoding,
-
- "vkCreateShaderModule": emit_global_state_wrapped_decoding,
- "vkDestroyShaderModule": emit_global_state_wrapped_decoding,
- "vkCreatePipelineCache": emit_global_state_wrapped_decoding,
- "vkDestroyPipelineCache": emit_global_state_wrapped_decoding,
- "vkCreateGraphicsPipelines": emit_global_state_wrapped_decoding,
- "vkDestroyPipeline": emit_global_state_wrapped_decoding,
-
- "vkAllocateMemory" : emit_global_state_wrapped_decoding,
- "vkFreeMemory" : emit_global_state_wrapped_decoding,
- "vkMapMemory" : emit_global_state_wrapped_decoding,
- "vkUnmapMemory" : emit_global_state_wrapped_decoding,
- "vkFlushMappedMemoryRanges" : decode_vkFlushMappedMemoryRanges,
- "vkInvalidateMappedMemoryRanges" : decode_vkInvalidateMappedMemoryRanges,
-
- "vkAllocateCommandBuffers" : emit_global_state_wrapped_decoding,
- "vkCmdExecuteCommands" : emit_global_state_wrapped_decoding,
- "vkQueueSubmit" : emit_global_state_wrapped_decoding,
- "vkQueueWaitIdle" : emit_global_state_wrapped_decoding,
- "vkBeginCommandBuffer" : emit_global_state_wrapped_decoding_with_context,
- "vkEndCommandBuffer" : emit_global_state_wrapped_decoding_with_context,
- "vkResetCommandBuffer" : emit_global_state_wrapped_decoding,
- "vkFreeCommandBuffers" : emit_global_state_wrapped_decoding,
- "vkCreateCommandPool" : emit_global_state_wrapped_decoding,
- "vkDestroyCommandPool" : emit_global_state_wrapped_decoding,
- "vkResetCommandPool" : emit_global_state_wrapped_decoding,
- "vkCmdPipelineBarrier" : emit_global_state_wrapped_decoding,
- "vkCmdBindPipeline" : emit_global_state_wrapped_decoding,
- "vkCmdBindDescriptorSets" : emit_global_state_wrapped_decoding,
-
- "vkCreateRenderPass" : emit_global_state_wrapped_decoding,
- "vkCreateRenderPass2" : emit_global_state_wrapped_decoding,
- "vkCreateRenderPass2KHR" : emit_global_state_wrapped_decoding,
- "vkDestroyRenderPass" : emit_global_state_wrapped_decoding,
- "vkCreateFramebuffer" : emit_global_state_wrapped_decoding,
- "vkDestroyFramebuffer" : emit_global_state_wrapped_decoding,
-
- "vkCreateSamplerYcbcrConversion": emit_global_state_wrapped_decoding,
- "vkDestroySamplerYcbcrConversion": emit_global_state_wrapped_decoding,
-
- # VK_ANDROID_native_buffer
- "vkGetSwapchainGrallocUsageANDROID" : emit_global_state_wrapped_decoding,
- "vkGetSwapchainGrallocUsage2ANDROID" : emit_global_state_wrapped_decoding,
- "vkAcquireImageANDROID" : emit_global_state_wrapped_decoding,
- "vkQueueSignalReleaseImageANDROID" : emit_global_state_wrapped_decoding,
-
- "vkCreateSemaphore" : emit_global_state_wrapped_decoding,
- "vkGetSemaphoreFdKHR" : emit_global_state_wrapped_decoding,
- "vkImportSemaphoreFdKHR" : emit_global_state_wrapped_decoding,
- "vkDestroySemaphore" : emit_global_state_wrapped_decoding,
-
- "vkCreateFence" : emit_global_state_wrapped_decoding,
- "vkResetFences" : emit_global_state_wrapped_decoding,
- "vkDestroyFence" : emit_global_state_wrapped_decoding,
-
- # VK_GOOGLE_gfxstream
- "vkFreeMemorySyncGOOGLE" : emit_global_state_wrapped_decoding,
- "vkMapMemoryIntoAddressSpaceGOOGLE" : emit_global_state_wrapped_decoding,
- "vkGetMemoryHostAddressInfoGOOGLE" : emit_global_state_wrapped_decoding,
- "vkGetBlobGOOGLE" : emit_global_state_wrapped_decoding,
-
- # Descriptor update templates
- "vkCreateDescriptorUpdateTemplate" : emit_global_state_wrapped_decoding,
- "vkCreateDescriptorUpdateTemplateKHR" : emit_global_state_wrapped_decoding,
- "vkDestroyDescriptorUpdateTemplate" : emit_global_state_wrapped_decoding,
- "vkDestroyDescriptorUpdateTemplateKHR" : emit_global_state_wrapped_decoding,
- "vkUpdateDescriptorSetWithTemplateSizedGOOGLE" : emit_global_state_wrapped_decoding,
-
- # VK_GOOGLE_gfxstream
- "vkBeginCommandBufferAsyncGOOGLE" : emit_global_state_wrapped_decoding_with_context,
- "vkEndCommandBufferAsyncGOOGLE" : emit_global_state_wrapped_decoding_with_context,
- "vkResetCommandBufferAsyncGOOGLE" : emit_global_state_wrapped_decoding,
- "vkCommandBufferHostSyncGOOGLE" : emit_global_state_wrapped_decoding,
- "vkCreateImageWithRequirementsGOOGLE" : emit_global_state_wrapped_decoding,
- "vkCreateBufferWithRequirementsGOOGLE" : emit_global_state_wrapped_decoding,
- "vkQueueHostSyncGOOGLE" : emit_global_state_wrapped_decoding,
- "vkQueueSubmitAsyncGOOGLE" : emit_global_state_wrapped_decoding,
- "vkQueueWaitIdleAsyncGOOGLE" : emit_global_state_wrapped_decoding,
- "vkQueueBindSparseAsyncGOOGLE" : emit_global_state_wrapped_decoding,
- "vkGetLinearImageLayoutGOOGLE" : emit_global_state_wrapped_decoding,
- "vkGetLinearImageLayout2GOOGLE" : emit_global_state_wrapped_decoding,
- "vkQueueFlushCommandsGOOGLE" : emit_global_state_wrapped_decoding_with_context,
- "vkQueueFlushCommandsFromAuxMemoryGOOGLE" : emit_global_state_wrapped_decoding_with_context,
- "vkQueueCommitDescriptorSetUpdatesGOOGLE" : emit_global_state_wrapped_decoding,
- "vkCollectDescriptorPoolIdsGOOGLE" : emit_global_state_wrapped_decoding,
- "vkQueueSignalReleaseImageANDROIDAsyncGOOGLE" : emit_global_state_wrapped_decoding,
-
- "vkQueueBindSparse" : emit_global_state_wrapped_decoding,
-
- # VK_KHR_xcb_surface
- "vkCreateXcbSurfaceKHR": decode_unsupported_api,
- "vkGetPhysicalDeviceXcbPresentationSupportKHR": decode_unsupported_api,
-
- # VK_EXT_metal_surface
- "vkCreateMetalSurfaceEXT": decode_unsupported_api,
-
- # VK_KHR_sampler_ycbcr_conversion
- "vkCreateSamplerYcbcrConversionKHR": emit_global_state_wrapped_decoding,
- "vkDestroySamplerYcbcrConversionKHR": emit_global_state_wrapped_decoding,
-}
-
-class VulkanDecoder(VulkanWrapperGenerator):
- def __init__(self, module, typeInfo):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
- self.typeInfo: VulkanTypeInfo = typeInfo
- self.cgen = CodeGen()
-
- def onBegin(self,):
- self.module.appendImpl(
- "#define MAX_PACKET_LENGTH %s\n" % MAX_PACKET_LENGTH)
- self.module.appendHeader(decoder_decl_preamble)
- self.module.appendImpl(decoder_impl_preamble)
-
- self.module.appendImpl(
- """
-size_t VkDecoder::Impl::decode(void* buf, size_t len, IOStream* ioStream,
- const ProcessResources* processResources,
- const VkDecoderContext& context)
-""")
-
- self.cgen.beginBlock() # function body
-
- self.cgen.stmt("const char* processName = context.processName")
- self.cgen.stmt("auto& gfx_logger = *context.gfxApiLogger")
- self.cgen.stmt("auto* healthMonitor = context.healthMonitor")
- self.cgen.stmt("auto& metricsLogger = *context.metricsLogger")
- self.cgen.stmt("if (len < 8) return 0")
- self.cgen.stmt("bool queueSubmitWithCommandsEnabled = feature_is_enabled(kFeature_VulkanQueueSubmitWithCommands)")
- self.cgen.stmt("unsigned char *ptr = (unsigned char *)buf")
- self.cgen.stmt("const unsigned char* const end = (const unsigned char*)buf + len")
-
- self.cgen.beginIf("m_forSnapshotLoad")
- self.cgen.stmt("ptr += m_state->setCreatedHandlesForSnapshotLoad(ptr)");
- self.cgen.endIf()
- self.cgen.line("while (end - ptr >= 8)")
- self.cgen.beginBlock() # while loop
-
- self.cgen.stmt("uint32_t opcode = *(uint32_t *)ptr")
- self.cgen.stmt("uint32_t packetLen = *(uint32_t *)(ptr + 4)")
- self.cgen.line("""
- // packetLen should be at least 8 (op code and packet length) and should not be excessively large
- if (packetLen < 8 || packetLen > MAX_PACKET_LENGTH) {
- WARN("Bad packet length %d detected, decode may fail", packetLen);
- metricsLogger.logMetricEvent(MetricEventBadPacketLength{ .len = packetLen });
- }
- """)
- self.cgen.stmt("if (end - ptr < packetLen) return ptr - (unsigned char*)buf")
- self.cgen.stmt("gfx_logger.record(ptr, std::min(size_t(packetLen + 8), size_t(end - ptr)))")
-
- self.cgen.stmt("stream()->setStream(ioStream)")
- self.cgen.stmt("VulkanStream* %s = stream()" % WRITE_STREAM)
- self.cgen.stmt("VulkanMemReadingStream* %s = readStream()" % READ_STREAM)
- self.cgen.stmt("%s->setBuf((uint8_t*)(ptr + 8))" % READ_STREAM)
- self.cgen.stmt("uint8_t* readStreamPtr = %s->getBuf(); uint8_t** readStreamPtrPtr = &readStreamPtr" % READ_STREAM)
- self.cgen.stmt("uint8_t* snapshotTraceBegin = %s->beginTrace()" % READ_STREAM)
- self.cgen.stmt("%s->setHandleMapping(&m_boxedHandleUnwrapMapping)" % READ_STREAM)
- self.cgen.line("""
- std::unique_ptr<EventHangMetadata::HangAnnotations> executionData =
- std::make_unique<EventHangMetadata::HangAnnotations>();
- if (healthMonitor) {
- executionData->insert(
- {{"packet_length", std::to_string(packetLen)},
- {"opcode", std::to_string(opcode)}});
- if (processName) {
- executionData->insert(
- {{"renderthread_guest_process", std::string(processName)}});
- }
- if (m_prevSeqno) {
- executionData->insert({{"previous_seqno", std::to_string(m_prevSeqno.value())}});
- }
- }
-
- std::atomic<uint32_t>* seqnoPtr = processResources->getSequenceNumberPtr();
-
- if (queueSubmitWithCommandsEnabled && ((opcode >= OP_vkFirst && opcode < OP_vkLast) || (opcode >= OP_vkFirst_old && opcode < OP_vkLast_old))) {
- uint32_t seqno;
- memcpy(&seqno, *readStreamPtrPtr, sizeof(uint32_t)); *readStreamPtrPtr += sizeof(uint32_t);
- if (healthMonitor) executionData->insert({{"seqno", std::to_string(seqno)}});
- if (m_prevSeqno && seqno == m_prevSeqno.value()) {
- WARN(
- "Seqno %d is the same as previously processed on thread %d. It might be a "
- "duplicate command.",
- seqno, getCurrentThreadId());
- metricsLogger.logMetricEvent(MetricEventDuplicateSequenceNum{ .opcode = opcode });
- }
- if (seqnoPtr && !m_forSnapshotLoad) {
- {
- auto seqnoWatchdog =
- WATCHDOG_BUILDER(healthMonitor,
- "RenderThread seqno loop")
- .setHangType(EventHangMetadata::HangType::kRenderThread)
- .setAnnotations(std::make_unique<EventHangMetadata::HangAnnotations>(*executionData))
- /* Data gathered if this hangs*/
- .setOnHangCallback([=]() {
- auto annotations = std::make_unique<EventHangMetadata::HangAnnotations>();
- annotations->insert({{"seqnoPtr", std::to_string(seqnoPtr->load(std::memory_order_seq_cst))}});
- return annotations;
- })
- .build();
- while ((seqno - seqnoPtr->load(std::memory_order_seq_cst) != 1)) {
- #if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)))
- _mm_pause();
- #elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
- __asm__ __volatile__("pause;");
- #endif
- }
- m_prevSeqno = seqno;
- }
- }
- }
- """)
-
- self.cgen.line("""
- gfx_logger.recordCommandExecution();
- """)
-
- self.cgen.line("""
- auto executionWatchdog =
- WATCHDOG_BUILDER(healthMonitor, "RenderThread VkDecoder command execution")
- .setHangType(EventHangMetadata::HangType::kRenderThread)
- .setAnnotations(std::move(executionData))
- .build();
- """)
-
- self.cgen.stmt("auto vk = m_vk")
-
- self.cgen.line("switch (opcode)")
- self.cgen.beginBlock() # switch stmt
-
- self.module.appendImpl(self.cgen.swapCode())
-
- def onGenCmd(self, cmdinfo, name, alias):
- typeInfo = self.typeInfo
- cgen = self.cgen
- api: VulkanAPI = typeInfo.apis[name]
-
- cgen.line("case OP_%s:" % name)
- cgen.beginBlock()
- cgen.stmt("android::base::beginTrace(\"%s decode\")" % name)
-
- if api.name in custom_decodes.keys():
- custom_decodes[api.name](typeInfo, api, cgen)
- else:
- emit_default_decoding(typeInfo, api, cgen)
-
- cgen.stmt("android::base::endTrace()")
- cgen.stmt("break")
- cgen.endBlock()
- self.module.appendImpl(self.cgen.swapCode())
-
- def onEnd(self,):
- self.cgen.line("default:")
- self.cgen.beginBlock()
- self.cgen.stmt("m_pool.freeAll()")
- self.cgen.stmt("return ptr - (unsigned char *)buf")
- self.cgen.endBlock()
-
- self.cgen.endBlock() # switch stmt
-
- self.cgen.stmt("ptr += packetLen")
- self.cgen.endBlock() # while loop
-
- self.cgen.beginIf("m_forSnapshotLoad")
- self.cgen.stmt("m_state->clearCreatedHandlesForSnapshotLoad()");
- self.cgen.endIf()
-
- self.cgen.stmt("m_pool.freeAll()")
- self.cgen.stmt("return ptr - (unsigned char*)buf;")
- self.cgen.endBlock() # function body
- self.module.appendImpl(self.cgen.swapCode())
- self.module.appendImpl(decoder_impl_postamble)
diff --git a/codegen/vulkan/scripts/cereal/decodersnapshot.py b/codegen/vulkan/scripts/cereal/decodersnapshot.py
deleted file mode 100644
index 4ff97a1d..00000000
--- a/codegen/vulkan/scripts/cereal/decodersnapshot.py
+++ /dev/null
@@ -1,267 +0,0 @@
-from .common.codegen import CodeGen, VulkanWrapperGenerator, VulkanAPIWrapper
-from .common.vulkantypes import \
- VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, DISPATCHABLE_HANDLE_TYPES, NON_DISPATCHABLE_HANDLE_TYPES
-
-from .transform import TransformCodegen, genTransformsForVulkanType
-
-from .wrapperdefs import API_PREFIX_MARSHAL
-from .wrapperdefs import API_PREFIX_UNMARSHAL
-from .wrapperdefs import VULKAN_STREAM_TYPE
-
-from copy import copy
-
-decoder_snapshot_decl_preamble = """
-
-namespace android {
-namespace base {
-class BumpPool;
-class Stream;
-} // namespace base {
-} // namespace android {
-
-class VkDecoderSnapshot {
-public:
- VkDecoderSnapshot();
- ~VkDecoderSnapshot();
-
- void save(android::base::Stream* stream);
- void load(android::base::Stream* stream, emugl::GfxApiLogger& gfx_logger,
- emugl::HealthMonitor<>* healthMonitor);
-"""
-
-decoder_snapshot_decl_postamble = """
-private:
- class Impl;
- std::unique_ptr<Impl> mImpl;
-
-};
-"""
-
-decoder_snapshot_impl_preamble ="""
-
-using namespace gfxstream::vk;
-using emugl::GfxApiLogger;
-using emugl::HealthMonitor;
-
-class VkDecoderSnapshot::Impl {
-public:
- Impl() { }
-
- void save(android::base::Stream* stream) {
- mReconstruction.save(stream);
- }
-
- void load(android::base::Stream* stream, GfxApiLogger& gfx_logger,
- HealthMonitor<>* healthMonitor) {
- mReconstruction.load(stream, gfx_logger, healthMonitor);
- }
-
-"""
-
-decoder_snapshot_impl_postamble = """
-private:
- android::base::Lock mLock;
- VkReconstruction mReconstruction;
-};
-
-VkDecoderSnapshot::VkDecoderSnapshot() :
- mImpl(new VkDecoderSnapshot::Impl()) { }
-
-void VkDecoderSnapshot::save(android::base::Stream* stream) {
- mImpl->save(stream);
-}
-
-void VkDecoderSnapshot::load(android::base::Stream* stream, GfxApiLogger& gfx_logger,
- HealthMonitor<>* healthMonitor) {
- mImpl->load(stream, gfx_logger, healthMonitor);
-}
-
-VkDecoderSnapshot::~VkDecoderSnapshot() = default;
-"""
-
-AUXILIARY_SNAPSHOT_API_BASE_PARAM_COUNT = 3
-
-AUXILIARY_SNAPSHOT_API_PARAM_NAMES = [
- "input_result",
-]
-
-# Vulkan handle dependencies.
-# (a, b): a depends on b
-SNAPSHOT_HANDLE_DEPENDENCIES = [
- # Dispatchable handle types
- ("VkCommandBuffer", "VkCommandPool"),
- ("VkCommandPool", "VkDevice"),
- ("VkQueue", "VkDevice"),
- ("VkDevice", "VkPhysicalDevice"),
- ("VkPhysicalDevice", "VkInstance")] + \
- list(map(lambda handleType : (handleType, "VkDevice"), NON_DISPATCHABLE_HANDLE_TYPES))
-
-handleDependenciesDict = dict(SNAPSHOT_HANDLE_DEPENDENCIES)
-
-def extract_deps_vkAllocateCommandBuffers(param, access, lenExpr, api, cgen):
- cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)%s)" % \
- (access, lenExpr, "unboxed_to_boxed_non_dispatchable_VkCommandPool(pAllocateInfo->commandPool)"))
-
-specialCaseDependencyExtractors = {
- "vkAllocateCommandBuffers" : extract_deps_vkAllocateCommandBuffers,
-}
-
-apiSequences = {
- "vkAllocateMemory" : ["vkAllocateMemory", "vkMapMemoryIntoAddressSpaceGOOGLE"]
-}
-
-apiModifies = {
- "vkMapMemoryIntoAddressSpaceGOOGLE" : ["memory"],
-}
-
-def is_modify_operation(api, param):
- if api.name in apiModifies:
- if param.paramName in apiModifies[api.name]:
- return True
- return False
-
-def emit_impl(typeInfo, api, cgen):
-
- cgen.line("// TODO: Implement")
-
- for p in api.parameters:
- if not (p.isHandleType):
- continue
-
- lenExpr = cgen.generalLengthAccess(p)
- lenAccessGuard = cgen.generalLengthAccessGuard(p)
-
- if lenExpr is None:
- lenExpr = "1"
-
- if p.pointerIndirectionLevels > 0:
- access = p.paramName
- else:
- access = "(&%s)" % p.paramName
-
- if p.isCreatedBy(api):
- cgen.stmt("android::base::AutoLock lock(mLock)")
- cgen.line("// %s create" % p.paramName)
- cgen.stmt("mReconstruction.addHandles((const uint64_t*)%s, %s)" % (access, lenExpr));
-
- if p.typeName in handleDependenciesDict:
- dependsOnType = handleDependenciesDict[p.typeName];
- for p2 in api.parameters:
- if p2.typeName == dependsOnType:
- cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)%s)" % (access, lenExpr, p2.paramName))
- if api.name in specialCaseDependencyExtractors:
- specialCaseDependencyExtractors[api.name](p, access, lenExpr, api, cgen)
-
- cgen.stmt("if (!%s) return" % access)
- cgen.stmt("auto apiHandle = mReconstruction.createApiInfo()")
- cgen.stmt("auto apiInfo = mReconstruction.getApiInfo(apiHandle)")
- cgen.stmt("mReconstruction.setApiTrace(apiInfo, OP_%s, snapshotTraceBegin, snapshotTraceBytes)" % api.name)
- if lenAccessGuard is not None:
- cgen.beginIf(lenAccessGuard)
- cgen.stmt("mReconstruction.forEachHandleAddApi((const uint64_t*)%s, %s, apiHandle)" % (access, lenExpr))
- cgen.stmt("mReconstruction.setCreatedHandlesForApi(apiHandle, (const uint64_t*)%s, %s)" % (access, lenExpr))
- if lenAccessGuard is not None:
- cgen.endIf()
-
- if p.isDestroyedBy(api):
- cgen.stmt("android::base::AutoLock lock(mLock)")
- cgen.line("// %s destroy" % p.paramName)
- if lenAccessGuard is not None:
- cgen.beginIf(lenAccessGuard)
- cgen.stmt("mReconstruction.removeHandles((const uint64_t*)%s, %s)" % (access, lenExpr));
- if lenAccessGuard is not None:
- cgen.endIf()
-
- if is_modify_operation(api, p):
- cgen.stmt("android::base::AutoLock lock(mLock)")
- cgen.line("// %s modify" % p.paramName)
- cgen.stmt("auto apiHandle = mReconstruction.createApiInfo()")
- cgen.stmt("auto apiInfo = mReconstruction.getApiInfo(apiHandle)")
- cgen.stmt("mReconstruction.setApiTrace(apiInfo, OP_%s, snapshotTraceBegin, snapshotTraceBytes)" % api.name)
- if lenAccessGuard is not None:
- cgen.beginIf(lenAccessGuard)
- cgen.beginFor("uint32_t i = 0", "i < %s" % lenExpr, "++i")
- if p.isNonDispatchableHandleType():
- cgen.stmt("%s boxed = unboxed_to_boxed_non_dispatchable_%s(%s[i])" % (p.typeName, p.typeName, access))
- else:
- cgen.stmt("%s boxed = unboxed_to_boxed_%s(%s[i])" % (p.typeName, p.typeName, access))
- cgen.stmt("mReconstruction.forEachHandleAddModifyApi((const uint64_t*)(&boxed), 1, apiHandle)")
- cgen.endFor()
- if lenAccessGuard is not None:
- cgen.endIf()
-
-def emit_passthrough_to_impl(typeInfo, api, cgen):
- cgen.vkApiCall(api, customPrefix = "mImpl->")
-
-class VulkanDecoderSnapshot(VulkanWrapperGenerator):
- def __init__(self, module, typeInfo):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
-
- self.typeInfo = typeInfo
-
- self.cgenHeader = CodeGen()
- self.cgenHeader.incrIndent()
-
- self.cgenImpl = CodeGen()
-
- self.currentFeature = None
-
- self.feature_apis = []
-
- def onBegin(self,):
- self.module.appendHeader(decoder_snapshot_decl_preamble)
- self.module.appendImpl(decoder_snapshot_impl_preamble)
-
- def onBeginFeature(self, featureName, featureType):
- VulkanWrapperGenerator.onBeginFeature(self, featureName, featureType)
- self.currentFeature = featureName
-
- def onGenCmd(self, cmdinfo, name, alias):
- VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
-
- api = self.typeInfo.apis[name]
-
- additionalParams = [ \
- makeVulkanTypeSimple(True, "uint8_t", 1, "snapshotTraceBegin"),
- makeVulkanTypeSimple(False, "size_t", 0, "snapshotTraceBytes"),
- makeVulkanTypeSimple(False, "android::base::BumpPool", 1, "pool"),]
-
- if api.retType.typeName != "void":
- additionalParams.append( \
- makeVulkanTypeSimple(False, api.retType.typeName, 0, "input_result"))
-
- apiForSnapshot = \
- api.withCustomParameters( \
- additionalParams + \
- api.parameters).withCustomReturnType( \
- makeVulkanTypeSimple(False, "void", 0, "void"))
-
- self.feature_apis.append((self.currentFeature, apiForSnapshot))
-
- self.cgenHeader.stmt(self.cgenHeader.makeFuncProto(apiForSnapshot))
- self.module.appendHeader(self.cgenHeader.swapCode())
-
- self.cgenImpl.emitFuncImpl( \
- apiForSnapshot, lambda cgen: emit_impl(self.typeInfo, apiForSnapshot, cgen))
- self.module.appendImpl(self.cgenImpl.swapCode())
-
- def onEnd(self,):
- self.module.appendHeader(decoder_snapshot_decl_postamble)
- self.module.appendImpl(decoder_snapshot_impl_postamble)
- self.cgenHeader.decrIndent()
-
- for feature, api in self.feature_apis:
- if feature is not None:
- self.cgenImpl.line("#ifdef %s" % feature)
-
- apiImplShell = \
- api.withModifiedName("VkDecoderSnapshot::" + api.name)
-
- self.cgenImpl.emitFuncImpl( \
- apiImplShell, lambda cgen: emit_passthrough_to_impl(self.typeInfo, api, cgen))
-
- if feature is not None:
- self.cgenImpl.line("#endif")
-
- self.module.appendImpl(self.cgenImpl.swapCode())
-
diff --git a/codegen/vulkan/scripts/cereal/deepcopy.py b/codegen/vulkan/scripts/cereal/deepcopy.py
deleted file mode 100644
index 52842e99..00000000
--- a/codegen/vulkan/scripts/cereal/deepcopy.py
+++ /dev/null
@@ -1,383 +0,0 @@
-# Copyright (c) 2018 The Android Open Source Project
-# Copyright (c) 2018 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from .common.codegen import CodeGen
-from .common.vulkantypes import \
- VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, VulkanTypeIterator
-
-from .wrapperdefs import VulkanWrapperGenerator
-from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM_FOR_WRITE, EXTENSION_SIZE_API_NAME
-
-class DeepcopyCodegen(VulkanTypeIterator):
- def __init__(self, cgen, inputVars, poolVarName, rootVarName, prefix, skipValues=False):
- self.cgen = cgen
- self.inputVars = inputVars
- self.prefix = prefix
- self.poolVarName = poolVarName
- self.rootVarName = rootVarName
- self.skipValues = skipValues
-
- def makeAccess(varName, asPtr = True):
- return lambda t: self.cgen.generalAccess(t, parentVarName = varName, asPtr = asPtr)
-
- def makeLengthAccess(varName):
- return lambda t: self.cgen.generalLengthAccess(t, parentVarName = varName)
-
- def makeLengthAccessGuard(varName):
- return lambda t: self.cgen.generalLengthAccessGuard(t, parentVarName=varName)
-
- self.exprAccessorLhs = makeAccess(self.inputVars[0])
- self.exprAccessorRhs = makeAccess(self.inputVars[1])
-
- self.exprAccessorValueLhs = makeAccess(self.inputVars[0], asPtr = False)
- self.exprAccessorValueRhs = makeAccess(self.inputVars[1], asPtr = False)
-
- self.lenAccessorLhs = makeLengthAccess(self.inputVars[0])
- self.lenAccessorRhs = makeLengthAccess(self.inputVars[1])
-
- self.lenAccessorGuardLhs = makeLengthAccessGuard(self.inputVars[0])
- self.lenAccessorGuardRhs = makeLengthAccessGuard(self.inputVars[1])
-
- self.checked = False
-
- def needSkip(self, vulkanType):
- return False
-
- def makeCastExpr(self, vulkanType):
- return "(%s)" % (
- self.cgen.makeCTypeDecl(vulkanType, useParamName=False))
-
- def makeNonConstCastForCopy(self, access, vulkanType):
- if vulkanType.staticArrExpr:
- casted = "%s(%s)" % (self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()), access)
- elif vulkanType.accessibleAsPointer():
- casted = "%s(%s)" % (self.makeCastExpr(vulkanType.getForNonConstAccess()), access)
- else:
- casted = "%s(%s)" % (self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()), access)
- return casted
-
- def makeAllocBytesExpr(self, lenAccess, vulkanType):
- sizeof = self.cgen.sizeofExpr( \
- vulkanType.getForValueAccess())
- if lenAccess:
- bytesExpr = "%s * %s" % (lenAccess, sizeof)
- else:
- bytesExpr = sizeof
-
- return bytesExpr
-
- def onCheck(self, vulkanType):
- pass
-
- def endCheck(self, vulkanType):
- pass
-
- def onCompoundType(self, vulkanType):
-
- if self.needSkip(vulkanType):
- self.cgen.line("// TODO: Unsupported : %s" %
- self.cgen.makeCTypeDecl(vulkanType))
- return
-
- accessLhs = self.exprAccessorLhs(vulkanType)
- accessRhs = self.exprAccessorRhs(vulkanType)
-
- lenAccessLhs = self.lenAccessorLhs(vulkanType)
- lenAccessRhs = self.lenAccessorRhs(vulkanType)
-
- lenAccessorGuardLhs = self.lenAccessorGuardLhs(vulkanType)
- lenAccessorGuardRhs = self.lenAccessorGuardRhs(vulkanType)
-
- isPtr = vulkanType.pointerIndirectionLevels > 0
-
- if lenAccessorGuardLhs is not None:
- self.cgen.beginIf(lenAccessorGuardLhs)
-
- if isPtr:
- self.cgen.stmt("%s = nullptr" % accessRhs)
- self.cgen.beginIf(accessLhs)
-
- self.cgen.stmt( \
- "%s = %s%s->alloc(%s)" % \
- (accessRhs, self.makeCastExpr(vulkanType.getForNonConstAccess()),
- self.poolVarName, self.makeAllocBytesExpr(lenAccessLhs, vulkanType)))
-
- if lenAccessLhs is not None:
-
- loopVar = "i"
- accessLhs = "%s + %s" % (accessLhs, loopVar)
- forInit = "uint32_t %s = 0" % loopVar
- forCond = "%s < (uint32_t)%s" % (loopVar, lenAccessLhs)
- forIncr = "++%s" % loopVar
-
- if isPtr:
- # Avoid generating a self-assign.
- if lenAccessRhs != lenAccessLhs:
- self.cgen.stmt("%s = %s" % (lenAccessRhs, lenAccessLhs))
-
- accessRhs = "%s + %s" % (accessRhs, loopVar)
- self.cgen.beginFor(forInit, forCond, forIncr)
-
-
- accessRhsCasted = self.makeNonConstCastForCopy(accessRhs, vulkanType)
-
- self.cgen.funcCall(None, self.prefix + vulkanType.typeName,
- [self.poolVarName, self.rootVarName, accessLhs, accessRhsCasted])
-
- if lenAccessLhs is not None:
- self.cgen.endFor()
-
- if isPtr:
- self.cgen.endIf()
-
- if lenAccessorGuardLhs is not None:
- self.cgen.endIf()
-
- def onString(self, vulkanType):
- accessLhs = self.exprAccessorLhs(vulkanType)
- accessRhs = self.exprAccessorRhs(vulkanType)
-
- self.cgen.stmt("%s = nullptr" % accessRhs)
- self.cgen.beginIf(accessLhs)
-
- self.cgen.stmt( \
- "%s = %s->strDup(%s)" % \
- (accessRhs,
- self.poolVarName,
- accessLhs))
-
- self.cgen.endIf()
-
- def onStringArray(self, vulkanType):
- accessLhs = self.exprAccessorLhs(vulkanType)
- accessRhs = self.exprAccessorRhs(vulkanType)
-
- lenAccessLhs = self.lenAccessorLhs(vulkanType)
-
- self.cgen.stmt("%s = nullptr" % accessRhs)
- self.cgen.beginIf("%s && %s" % (accessLhs, lenAccessLhs))
-
- self.cgen.stmt( \
- "%s = %s->strDupArray(%s, %s)" % \
- (accessRhs,
- self.poolVarName,
- accessLhs,
- lenAccessLhs))
-
- self.cgen.endIf()
-
- def onStaticArr(self, vulkanType):
- accessLhs = self.exprAccessorValueLhs(vulkanType)
- accessRhs = self.exprAccessorValueRhs(vulkanType)
-
- lenAccessLhs = self.lenAccessorLhs(vulkanType)
-
- bytesExpr = self.makeAllocBytesExpr(lenAccessLhs, vulkanType)
- self.cgen.stmt("memcpy(%s, %s, %s)" % (accessRhs, accessLhs, bytesExpr))
-
- def onStructExtension(self, vulkanType):
-
- lhs = self.exprAccessorLhs(vulkanType)
- rhs = self.exprAccessorRhs(vulkanType)
-
- rhsExpr = "(%s)(%s)" % ("void*", rhs)
-
- nextVar = "from_%s" % vulkanType.paramName
- sizeVar = "%s_size" % vulkanType.paramName
-
- self.cgen.beginIf("%s == VK_STRUCTURE_TYPE_MAX_ENUM" %
- self.rootVarName)
- self.cgen.stmt("%s = from->sType" % self.rootVarName)
- self.cgen.endIf()
-
- self.cgen.stmt("const void* %s = %s" % (nextVar, self.inputVars[0]))
- self.cgen.stmt("size_t %s = 0u" % sizeVar)
- self.cgen.beginWhile("!%s && %s" % (sizeVar, nextVar))
- self.cgen.stmt("%s = static_cast<const vk_struct_common*>(%s)->%s" % (
- nextVar, nextVar, vulkanType.paramName
- ))
- self.cgen.stmt("%s = %s(%s, %s)" % (
- sizeVar, EXTENSION_SIZE_API_NAME, self.rootVarName, nextVar))
- self.cgen.endWhile()
-
- self.cgen.stmt("%s = nullptr" % rhs)
-
- self.cgen.beginIf(sizeVar)
-
- self.cgen.stmt( \
- "%s = %s%s->alloc(%s)" % \
- (rhs, self.makeCastExpr(vulkanType.getForNonConstAccess()), self.poolVarName, sizeVar))
-
- self.cgen.funcCall(None, self.prefix + "extension_struct",
- [self.poolVarName, self.rootVarName, nextVar, rhsExpr])
-
- self.cgen.endIf()
-
- def onPointer(self, vulkanType):
-
- accessLhs = self.exprAccessorLhs(vulkanType)
- accessRhs = self.exprAccessorRhs(vulkanType)
-
- if self.needSkip(vulkanType):
- self.cgen.stmt("%s = nullptr" % accessRhs)
- return
-
- lenAccessLhs = self.lenAccessorLhs(vulkanType)
-
- self.cgen.stmt("%s = nullptr" % accessRhs)
- self.cgen.beginIf(accessLhs)
-
- bytesExpr = self.makeAllocBytesExpr(lenAccessLhs, vulkanType)
-
- self.cgen.stmt( \
- "%s = %s%s->dupArray(%s, %s)" % \
- (accessRhs,
- self.makeCastExpr(vulkanType.getForNonConstAccess()),
- self.poolVarName,
- accessLhs,
- bytesExpr))
-
- self.cgen.endIf()
-
- def onValue(self, vulkanType):
- if self.skipValues:
- return
-
- accessLhs = self.exprAccessorValueLhs(vulkanType)
- accessRhs = self.exprAccessorValueRhs(vulkanType)
-
- self.cgen.stmt("%s = %s" % (accessRhs, accessLhs))
-
-class VulkanDeepcopy(VulkanWrapperGenerator):
-
- def __init__(self, module, typeInfo):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
-
- self.codegen = CodeGen()
-
- self.deepcopyPrefix = "deepcopy_"
- self.deepcopyVars = ["from", "to"]
- self.deepcopyAllocatorVarName = "alloc"
- self.deepcopyAllocatorParam = \
- makeVulkanTypeSimple(False, "Allocator", 1,
- self.deepcopyAllocatorVarName)
- self.deepcopyRootVarName = "rootType"
- self.deepcopyRootParam = \
- makeVulkanTypeSimple(False, "VkStructureType",
- 0, self.deepcopyRootVarName)
- self.voidType = makeVulkanTypeSimple(False, "void", 0)
-
- self.deepcopyCodegen = \
- DeepcopyCodegen(
- None,
- self.deepcopyVars,
- self.deepcopyAllocatorVarName,
- self.deepcopyRootVarName,
- self.deepcopyPrefix,
- skipValues=True)
-
- self.knownDefs = {}
-
- self.extensionDeepcopyPrototype = \
- VulkanAPI(self.deepcopyPrefix + "extension_struct",
- self.voidType,
- [self.deepcopyAllocatorParam,
- self.deepcopyRootParam,
- STRUCT_EXTENSION_PARAM,
- STRUCT_EXTENSION_PARAM_FOR_WRITE])
-
- def onBegin(self,):
- VulkanWrapperGenerator.onBegin(self)
- self.module.appendImpl(self.codegen.makeFuncDecl(
- self.extensionDeepcopyPrototype))
-
- def onGenType(self, typeXml, name, alias):
- VulkanWrapperGenerator.onGenType(self, typeXml, name, alias)
-
- if name in self.knownDefs:
- return
-
- category = self.typeInfo.categoryOf(name)
-
- if category in ["struct", "union"] and alias:
- self.module.appendHeader(
- self.codegen.makeFuncAlias(self.deepcopyPrefix + name,
- self.deepcopyPrefix + alias))
-
- if category in ["struct", "union"] and not alias:
-
- structInfo = self.typeInfo.structs[name]
-
- typeFromName = \
- lambda varname: \
- makeVulkanTypeSimple(varname == "from", name, 1, varname)
-
- deepcopyParams = \
- [self.deepcopyAllocatorParam, self.deepcopyRootParam] + \
- list(map(typeFromName, self.deepcopyVars))
-
- deepcopyPrototype = \
- VulkanAPI(self.deepcopyPrefix + name,
- self.voidType,
- deepcopyParams)
-
- def structDeepcopyDef(cgen):
- self.deepcopyCodegen.cgen = cgen
- canSimplyAssign = True
- for member in structInfo.members:
- if not member.isSimpleValueType(self.typeInfo):
- canSimplyAssign = False
-
- cgen.stmt("(void)%s" % self.deepcopyAllocatorVarName)
- cgen.stmt("(void)%s" % self.deepcopyRootVarName)
- cgen.stmt("*to = *from")
- if canSimplyAssign:
- pass
- else:
- for member in structInfo.members:
- iterateVulkanType(self.typeInfo, member,
- self.deepcopyCodegen)
-
- self.module.appendHeader(
- self.codegen.makeFuncDecl(deepcopyPrototype))
- self.module.appendImpl(
- self.codegen.makeFuncImpl(deepcopyPrototype, structDeepcopyDef))
-
- def onGenCmd(self, cmdinfo, name, alias):
- VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
-
- def onEnd(self,):
- VulkanWrapperGenerator.onEnd(self)
-
- def deepcopyDstExpr(cgen, typeName):
- return cgen.makeReinterpretCast( \
- STRUCT_EXTENSION_PARAM_FOR_WRITE.paramName,
- typeName, const=False)
-
- def forEachExtensionDeepcopy(ext, castedAccess, cgen):
- cgen.funcCall(None, self.deepcopyPrefix + ext.name,
- [self.deepcopyAllocatorVarName,
- self.deepcopyRootVarName,
- castedAccess, deepcopyDstExpr(cgen, ext.name)])
-
- self.module.appendImpl(
- self.codegen.makeFuncImpl(
- self.extensionDeepcopyPrototype,
- lambda cgen: self.emitForEachStructExtension(
- cgen,
- self.voidType,
- STRUCT_EXTENSION_PARAM,
- forEachExtensionDeepcopy,
- rootTypeVar=self.deepcopyRootParam)))
diff --git a/codegen/vulkan/scripts/cereal/dispatch.py b/codegen/vulkan/scripts/cereal/dispatch.py
deleted file mode 100644
index 42cba8ca..00000000
--- a/codegen/vulkan/scripts/cereal/dispatch.py
+++ /dev/null
@@ -1,499 +0,0 @@
-# Copyright (c) 2018 The Android Open Source Project
-# Copyright (c) 2018 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from .common.codegen import CodeGen
-from .common.vulkantypes import \
- VulkanAPI, makeVulkanTypeSimple, iterateVulkanType
-
-from .wrapperdefs import VulkanWrapperGenerator
-
-# No real good way to automatically infer the most important Vulkan API
-# functions as it relates to which getProcAddress function to use, plus
-# we might want to control which function to use depending on our
-# performance needs.
-
-# This is based on the minimum set of functions needed to be directly
-# queried with dlsym and not returning null.
-getProcAddrFuncs = [
- "vkGetInstanceProcAddr",
- "vkDestroyInstance",
- "vkEnumeratePhysicalDevices",
- "vkGetPhysicalDeviceFeatures",
- "vkGetPhysicalDeviceFormatProperties",
- "vkGetPhysicalDeviceImageFormatProperties",
- "vkGetPhysicalDeviceProperties",
- "vkGetPhysicalDeviceQueueFamilyProperties",
- "vkGetPhysicalDeviceMemoryProperties",
- "vkCreateDevice",
- "vkDestroyDevice",
- "vkEnumerateDeviceExtensionProperties",
- "vkEnumerateDeviceLayerProperties",
-]
-
-# Some methods can only be found using dlsym() while we cannot get the function
-# address using vkGetInstProcAddr() or vkGetDeviceProcAddr(). These function
-# pointers should only be initialized when setting up the dispatch from system
-# loader.
-getProcAddrOnlyFuncs = [
- "vkGetMTLDeviceMVK",
- "vkSetMTLTextureMVK",
- "vkGetMTLTextureMVK",
- "vkGetMTLBufferMVK",
- "vkUseIOSurfaceMVK",
- "vkGetIOSurfaceMVK",
-]
-
-getInstanceProcAddrNoInstanceFuncs = [
- "vkCreateInstance",
- "vkEnumerateInstanceExtensionProperties",
- "vkEnumerateInstanceLayerProperties",
-]
-
-getInstanceProcAddrFuncs = [
- "vkGetDeviceProcAddr",
- "vkCreateSwapchainKHR",
- "vkDestroySwapchainKHR",
- "vkGetSwapchainImagesKHR",
- "vkAcquireNextImageKHR",
- "vkQueuePresentKHR",
- "vkCreateMacOSSurfaceMVK",
- "vkCreateWin32SurfaceKHR",
- "vkGetPhysicalDeviceWin32PresentationSupportKHR",
- "vkCreateXlibSurfaceKHR",
- "vkGetPhysicalDeviceXlibPresentationSupportKHR",
- "vkCreateXcbSurfaceKHR",
- "vkGetPhysicalDeviceXcbPresentationSupportKHR",
- "vkGetPhysicalDeviceSparseImageFormatProperties",
- "vkEnumerateInstanceVersion",
- "vkEnumeratePhysicalDeviceGroups",
- "vkGetPhysicalDeviceFeatures2",
- "vkGetPhysicalDeviceProperties2",
- "vkGetPhysicalDeviceFormatProperties2",
- "vkGetPhysicalDeviceImageFormatProperties2",
- "vkGetPhysicalDeviceQueueFamilyProperties2",
- "vkGetPhysicalDeviceMemoryProperties2",
- "vkGetPhysicalDeviceSparseImageFormatProperties2",
- "vkGetPhysicalDeviceExternalBufferProperties",
- "vkGetPhysicalDeviceExternalFenceProperties",
- "vkGetPhysicalDeviceExternalSemaphoreProperties",
-]
-
-# Implicitly, everything else is going to be obtained
-# with vkGetDeviceProcAddr,
-# unless it has instance in the arg.
-
-def isGetProcAddressAPI(vulkanApi):
- return vulkanApi.name in getProcAddrFuncs
-
-def isGetProcAddressOnlyAPI(vulkanApi):
- return vulkanApi.name in getProcAddrOnlyFuncs
-
-def isGetInstanceProcAddressNoInstanceAPI(vulkanApi):
- return vulkanApi.name in getInstanceProcAddrNoInstanceFuncs
-
-def isGetInstanceProcAddressAPI(vulkanApi):
- if vulkanApi.name in getInstanceProcAddrFuncs:
- return True
-
- if vulkanApi.parameters[0].typeName == "VkInstance":
- return True
-
- return False
-
-def isGetDeviceProcAddressAPI(vulkanApi):
- if isGetProcAddressAPI(vulkanApi):
- return False
-
- if isGetProcAddressOnlyAPI(vulkanApi):
- return False
-
- if isGetInstanceProcAddressAPI(vulkanApi):
- return False
-
- return True
-
-def inferProcAddressFuncType(vulkanApi):
- if isGetProcAddressAPI(vulkanApi):
- return "global"
- if isGetProcAddressOnlyAPI(vulkanApi):
- return "global-only"
- if isGetInstanceProcAddressNoInstanceAPI(vulkanApi):
- return "global-instance"
- if isGetInstanceProcAddressAPI(vulkanApi):
- return "instance"
- return "device"
-
-# VulkanDispatch defines a struct, VulkanDispatch,
-# that is populated by function pointers from the Vulkan
-# loader. No attempt is made to do something different
-# for instance vs device functions.
-class VulkanDispatch(VulkanWrapperGenerator):
- def __init__(self, module, typeInfo):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
-
- self.apisToGet = {}
-
- self.cgenHeader = CodeGen()
- self.cgenImpl = CodeGen()
- self.typeInfo = typeInfo
-
- self.currentFeature = ""
- self.featureForCodegen = ""
-
- def onBegin(self):
-
- # The first way is to use just the loader to get symbols. This doesn't
- # necessarily work with extensions because at that point the dispatch
- # table needs to be specific to a particular Vulkan instance or device.
-
- self.cgenHeader.line("""
-void init_vulkan_dispatch_from_system_loader(
- DlOpenFunc dlOpenFunc,
- DlSymFunc dlSymFunc,
- VulkanDispatch* dispatch_out);
-""")
-
- # The second way is to initialize the table from a given Vulkan
- # instance or device. Provided the instance or device was created with
- # the right extensions, we can obtain function pointers to extension
- # functions this way.
-
- self.cgenHeader.line("""
-void init_vulkan_dispatch_from_instance(
- VulkanDispatch* vk,
- VkInstance instance,
- VulkanDispatch* dispatch_out);
-""")
- self.cgenHeader.line("""
-void init_vulkan_dispatch_from_device(
- VulkanDispatch* vk,
- VkDevice device,
- VulkanDispatch* dispatch_out);
-""")
-
- # After populating a VulkanDispatch with the above methods,
- # it can be useful to check whether the Vulkan 1.0 or 1.1 methods
- # are all there.
- def emit_feature_check_decl(cgen, tag, featureToCheck):
- cgen.line("""
-bool vulkan_dispatch_check_%s_%s(
- const VulkanDispatch* vk);
-""" % (tag, featureToCheck))
-
- emit_feature_check_decl(self.cgenHeader, "instance", "VK_VERSION_1_0")
- emit_feature_check_decl(self.cgenHeader, "instance", "VK_VERSION_1_1")
- emit_feature_check_decl(self.cgenHeader, "device", "VK_VERSION_1_0")
- emit_feature_check_decl(self.cgenHeader, "device", "VK_VERSION_1_1")
-
- self.cgenHeader.line("struct VulkanDispatch {")
- self.module.appendHeader(self.cgenHeader.swapCode())
-
- def syncFeatureQuiet(self, cgen, feature):
- if self.featureForCodegen != feature:
- if feature == "":
- self.featureForCodegen = feature
- return
-
- self.featureForCodegen = feature
-
- def syncFeature(self, cgen, feature):
- if self.featureForCodegen != feature:
- if feature == "":
- cgen.leftline("#endif")
- self.featureForCodegen = feature
- return
-
- if self.featureForCodegen != "":
- cgen.leftline("#endif")
-
- cgen.leftline("#ifdef %s" % feature)
- self.featureForCodegen = feature
-
- def makeDlsymCall(self, cgen, apiname, typedecl):
- cgen.stmt( \
- "out->%s = (%s)dlSymFunc(lib, \"%s\")" % \
- (apiname, typedecl, apiname))
-
- def makeGetInstanceProcAddrCall(self, cgen, dispatch, instance, apiname, typedecl):
- cgen.stmt( \
- "out->%s = (%s)%s->vkGetInstanceProcAddr(%s, \"%s\")" % \
- (apiname, typedecl, dispatch, instance, apiname))
-
- def makeGetDeviceProcAddrCall(self, cgen, dispatch, device, apiname, typedecl):
- cgen.stmt( \
- "out->%s = (%s)%s->vkGetDeviceProcAddr(%s, \"%s\")" % \
- (apiname, typedecl, dispatch, device, apiname))
-
- def onEnd(self):
- self.cgenHeader.line("};")
- self.module.appendHeader(self.cgenHeader.swapCode())
-
- # Getting dispatch tables from the loader
- self.cgenImpl.line("""
-void init_vulkan_dispatch_from_system_loader(
- DlOpenFunc dlOpenFunc,
- DlSymFunc dlSymFunc,
- VulkanDispatch* out)""")
-
- self.cgenImpl.beginBlock()
-
- self.cgenImpl.stmt("memset(out, 0x0, sizeof(VulkanDispatch))")
-
- self.cgenImpl.stmt("void* lib = dlOpenFunc()")
- self.cgenImpl.stmt("if (!lib) return")
-
- apis = \
- self.apisToGet["global"] + \
- self.apisToGet["global-instance"] + \
- self.apisToGet["instance"] + \
- self.apisToGet["device"] + \
- self.apisToGet["global-only"]
-
- for vulkanApi, typeDecl, feature in apis:
- self.syncFeature(self.cgenImpl, feature)
- self.makeDlsymCall(self.cgenImpl, vulkanApi.name, typeDecl)
-
- self.syncFeature(self.cgenImpl, "")
- self.cgenImpl.endBlock()
-
- # Getting instance dispatch tables
- self.cgenImpl.line("""
-void init_vulkan_dispatch_from_instance(
- VulkanDispatch* vk,
- VkInstance instance,
- VulkanDispatch* out)""")
-
- self.cgenImpl.beginBlock()
-
- self.cgenImpl.stmt("memset(out, 0x0, sizeof(VulkanDispatch))")
-
- apis = \
- self.apisToGet["global"] + \
- self.apisToGet["global-instance"] + \
- self.apisToGet["instance"] + \
- self.apisToGet["device"]
-
- for vulkanApi, typeDecl, feature in apis:
- self.syncFeature(self.cgenImpl, feature)
- self.makeGetInstanceProcAddrCall(
- self.cgenImpl, "vk", "instance", vulkanApi.name, typeDecl)
-
- self.syncFeature(self.cgenImpl, "")
- self.cgenImpl.endBlock()
-
- # Getting device dispatch tables
- self.cgenImpl.line("""
-void init_vulkan_dispatch_from_device(
- VulkanDispatch* vk,
- VkDevice device,
- VulkanDispatch* out)""")
-
- self.cgenImpl.beginBlock()
-
- self.cgenImpl.stmt("memset(out, 0x0, sizeof(VulkanDispatch))")
-
- apis = \
- self.apisToGet["global"] + \
- self.apisToGet["global-instance"] + \
- self.apisToGet["instance"] + \
- self.apisToGet["device"]
-
- for vulkanApi, typeDecl, feature in apis:
- self.syncFeature(self.cgenImpl, feature)
- self.makeGetDeviceProcAddrCall(
- self.cgenImpl, "vk", "device", vulkanApi.name, typeDecl)
-
- self.syncFeature(self.cgenImpl, "")
- self.cgenImpl.endBlock()
-
- # Check Vulkan 1.0 / 1.1 functions
-
- def emit_check_impl(cgen, dispatchVar, feature, featureToCheck, apiName):
- if feature == featureToCheck:
- cgen.beginIf("!%s->%s" % (dispatchVar, apiName))
- cgen.stmt("fprintf(stderr, \"%s check failed: %s not found\\n\")" % (featureToCheck, apiName))
- cgen.stmt("good = false")
- cgen.endIf()
-
- def emit_feature_check_impl(context, cgen, tag, featureToCheck, apis):
- cgen.line("""
-bool vulkan_dispatch_check_%s_%s(
- const VulkanDispatch* vk)
-""" % (tag, featureToCheck))
-
- cgen.beginBlock()
-
- cgen.stmt("bool good = true")
-
- for vulkanApi, typeDecl, feature in apis:
- context.syncFeatureQuiet(self.cgenImpl, feature)
- emit_check_impl(cgen, "vk", feature, featureToCheck, vulkanApi.name)
-
- context.syncFeatureQuiet(self.cgenImpl, "")
-
- cgen.stmt("return good")
- cgen.endBlock()
-
- instanceApis = self.apisToGet["global-instance"] + self.apisToGet["instance"]
-
- emit_feature_check_impl(self, self.cgenImpl, "instance", "VK_VERSION_1_0", instanceApis)
- emit_feature_check_impl(self, self.cgenImpl, "instance", "VK_VERSION_1_1", instanceApis)
- emit_feature_check_impl(self, self.cgenImpl, "device", "VK_VERSION_1_0", self.apisToGet["device"])
- emit_feature_check_impl(self, self.cgenImpl, "device", "VK_VERSION_1_1", self.apisToGet["device"])
-
- self.module.appendImpl(self.cgenImpl.swapCode())
-
- def onBeginFeature(self, featureName, featureType):
- self.currentFeature = featureName
-
- def onGenType(self, typeXml, name, alias):
- VulkanWrapperGenerator.onGenType(self, typeXml, name, alias)
-
- def onGenCmd(self, cmdinfo, name, alias):
- VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
-
- vulkanApi = self.typeInfo.apis[name]
-
- typeDecl = "PFN_%s" % name
-
- procAddressType = inferProcAddressFuncType(vulkanApi)
-
- self.cgenHeader.stmt("%s %s" % (typeDecl, name));
- self.module.appendHeader(self.cgenHeader.swapCode())
-
- current = self.apisToGet.get(procAddressType, [])
- if current == []:
- self.apisToGet[procAddressType] = current
- current.append((vulkanApi, typeDecl, self.currentFeature))
-
-# VulkanDispatchFast allows one to get the optimal function pointers
-# for a given Vulkan API call, in order to improve performance.
-#
-# We can optionally query VkDevices to get function pointers that are
-# closer to the ICD and have fewer levels of indirection from the loader
-# to get there.
-# See
-# https://github.com/KhronosGroup/Vulkan-Loader/blob/master/loader/LoaderAndLayerInterface.md
-# for more info.
-#
-# This requires the calling C++ code to provide functions to
-# generate the desired instances and devices, otherwise we won't know
-# which instance or device to pass to vkGet(Instance|Device)ProcAddr,
-# so it does push more complexity to the user.
-class VulkanDispatchFast(VulkanDispatch):
-
- def __init__(self, module, typeInfo):
- VulkanDispatch.__init__(self, module, typeInfo)
-
- def onBegin(self):
- self.cgenHeader.line("""
-void init_vulkan_dispatch_from_system_loader(
- DlOpenFunc dlOpenFunc,
- DlSymFunc dlSymFunc,
- InstanceGetter instanceGetter,
- DeviceGetter deviceGetter,
- VulkanDispatch* dispatch_out);
-""")
-
- self.cgenHeader.line("struct VulkanDispatch {")
- self.cgenHeader.line("VkInstance instance;")
- self.cgenHeader.line("VkPhysicalDevice physicalDevice;")
- self.cgenHeader.line("uint32_t physicalDeviceQueueFamilyInfoCount;")
- self.cgenHeader.line("VkQueueFamilyProperties* physicalDeviceQueueFamilyInfos;")
- self.cgenHeader.line("VkDevice device;")
- self.cgenHeader.line("bool presentCapable;")
- self.module.appendHeader(self.cgenHeader.swapCode())
-
- def makeGetProcAddr(self, cgen, dispatchLevel, dispatch, apiname, typedecl):
- if dispatchLevel == "instance":
- funcname = "vkGetInstanceProcAddr"
- elif dispatchLevel == "device":
- funcname = "vkGetDeviceProcAddr"
- else:
- raise
-
- cgen.stmt( \
- "out->%s = (%s)out->%s(%s, \"%s\")" % \
- (apiname, typedecl, funcname, dispatch, apiname))
-
- def onEnd(self):
- self.cgenHeader.line("};")
- self.module.appendHeader(self.cgenHeader.swapCode())
-
- self.cgenImpl.line("""
-void init_vulkan_dispatch_from_system_loader(
- DlOpenFunc dlOpenFunc,
- DlSymFunc dlSymFunc,
- InstanceGetter instanceGetter,
- DeviceGetter deviceGetter,
- VulkanDispatch* out)""")
-
- self.cgenImpl.beginBlock()
-
- self.cgenImpl.stmt("out->instance = nullptr")
- self.cgenImpl.stmt("out->physicalDevice = nullptr")
- self.cgenImpl.stmt("out->physicalDeviceQueueFamilyInfoCount = 0")
- self.cgenImpl.stmt("out->physicalDeviceQueueFamilyInfos = nullptr")
- self.cgenImpl.stmt("out->device = nullptr")
- self.cgenImpl.stmt("out->presentCapable = false")
-
- self.cgenImpl.stmt("void* lib = dlOpenFunc()")
- self.cgenImpl.stmt("if (!lib) return")
-
- for vulkanApi, typeDecl, feature in self.apisToGet["global"]:
- self.syncFeature(self.cgenImpl, feature)
- self.makeDlsymCall(self.cgenImpl, vulkanApi.name, typeDecl)
-
- self.syncFeature(self.cgenImpl, "")
- self.cgenImpl.stmt("if (!out->vkGetInstanceProcAddr) return")
-
- for vulkanApi, typeDecl, feature in self.apisToGet["global-instance"]:
- self.syncFeature(self.cgenImpl, feature)
- self.makeGetProcAddr( \
- self.cgenImpl, "instance", "nullptr", vulkanApi.name, typeDecl);
-
- self.syncFeature(self.cgenImpl, "")
- self.cgenImpl.stmt("if (!instanceGetter(out, &out->instance)) return")
-
- for vulkanApi, typeDecl, feature in self.apisToGet["instance"]:
- self.syncFeature(self.cgenImpl, feature)
- self.makeGetProcAddr( \
- self.cgenImpl, "instance", "out->instance", vulkanApi.name, typeDecl);
-
- self.syncFeature(self.cgenImpl, "")
-
- self.cgenImpl.stmt("if (!deviceGetter(out, out->instance, &out->physicalDevice, &out->physicalDeviceQueueFamilyInfoCount, nullptr, &out->device, &out->presentCapable)) return")
- self.cgenImpl.stmt("out->physicalDeviceQueueFamilyInfos = (VkQueueFamilyProperties*)malloc(out->physicalDeviceQueueFamilyInfoCount * sizeof(VkQueueFamilyProperties))");
- self.cgenImpl.stmt("if (!deviceGetter(out, out->instance, &out->physicalDevice, &out->physicalDeviceQueueFamilyInfoCount, out->physicalDeviceQueueFamilyInfos, &out->device, &out->presentCapable)) return")
-
- for vulkanApi, typeDecl, feature in self.apisToGet["device"]:
- self.syncFeature(self.cgenImpl, feature)
- self.makeGetProcAddr( \
- self.cgenImpl, "device", "out->device", vulkanApi.name, typeDecl);
-
- self.syncFeature(self.cgenImpl, "")
-
- self.cgenImpl.endBlock()
-
- self.module.appendImpl(self.cgenImpl.swapCode())
-
- def onBeginFeature(self, featureName, featureType):
- VulkanDispatch.onBeginFeature(self, featureName, featureType);
-
- def onGenType(self, typeXml, name, alias):
- VulkanDispatch.onGenType(self, typeXml, name, alias);
-
- def onGenCmd(self, cmdinfo, name, alias):
- VulkanDispatch.onGenCmd(self, cmdinfo, name, alias);
diff --git a/codegen/vulkan/scripts/cereal/encoder.py b/codegen/vulkan/scripts/cereal/encoder.py
deleted file mode 100644
index d3e39745..00000000
--- a/codegen/vulkan/scripts/cereal/encoder.py
+++ /dev/null
@@ -1,717 +0,0 @@
-import copy
-
-from .common.codegen import CodeGen, VulkanWrapperGenerator
-from .common.vulkantypes import \
- VulkanAPI, makeVulkanTypeSimple, iterateVulkanType
-
-from .marshaling import VulkanMarshalingCodegen
-from .reservedmarshaling import VulkanReservedMarshalingCodegen
-from .counting import VulkanCountingCodegen
-from .handlemap import HandleMapCodegen
-from .deepcopy import DeepcopyCodegen
-from .transform import TransformCodegen, genTransformsForVulkanType
-
-from .wrapperdefs import API_PREFIX_RESERVEDMARSHAL
-from .wrapperdefs import API_PREFIX_MARSHAL
-from .wrapperdefs import API_PREFIX_UNMARSHAL
-from .wrapperdefs import ROOT_TYPE_DEFAULT_VALUE
-from .wrapperdefs import VULKAN_STREAM_TYPE_GUEST
-
-encoder_decl_preamble = """
-using android::base::guest::HealthMonitor;
-
-class VkEncoder {
-public:
- VkEncoder(IOStream* stream, HealthMonitor<>* healthMonitor = nullptr);
- ~VkEncoder();
-
-#include "VkEncoder.h.inl"
-"""
-
-encoder_decl_postamble = """
-private:
- class Impl;
- std::unique_ptr<Impl> mImpl;
- HealthMonitor<>* mHealthMonitor;
-};
-"""
-
-encoder_impl_preamble ="""
-
-using namespace gfxstream::vk;
-
-using android::base::guest::AutoLock;
-using android::base::guest::Lock;
-using android::base::BumpPool;
-
-#include "VkEncoder.cpp.inl"
-
-#define VALIDATE_RET(retType, success, validate) \\
- retType goldfish_vk_validateResult = validate; \\
- if (goldfish_vk_validateResult != success) return goldfish_vk_validateResult; \\
-
-#define VALIDATE_VOID(validate) \\
- VkResult goldfish_vk_validateResult = validate; \\
- if (goldfish_vk_validateResult != VK_SUCCESS) return; \\
-
-"""
-
-STREAM = "stream"
-RESOURCES = "sResourceTracker"
-POOL = "pool"
-
-ENCODER_PREVALIDATED_APIS = [
- "vkFlushMappedMemoryRanges",
- "vkInvalidateMappedMemoryRanges",
-]
-
-ENCODER_CUSTOM_RESOURCE_PREPROCESS = [
- "vkMapMemoryIntoAddressSpaceGOOGLE",
- "vkDestroyDevice",
-]
-
-ENCODER_CUSTOM_RESOURCE_POSTPROCESS = [
- "vkCreateInstance",
- "vkCreateDevice",
- "vkMapMemoryIntoAddressSpaceGOOGLE",
- "vkGetPhysicalDeviceFeatures2",
- "vkGetPhysicalDeviceFeatures2KHR",
- "vkGetPhysicalDeviceProperties",
- "vkGetPhysicalDeviceProperties2",
- "vkGetPhysicalDeviceProperties2KHR",
- "vkCreateDescriptorUpdateTemplate",
- "vkCreateDescriptorUpdateTemplateKHR",
- "vkGetPhysicalDeviceExternalSemaphoreProperties",
- "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR",
- "vkGetDeviceQueue",
- "vkGetDeviceQueue2",
-]
-
-ENCODER_EXPLICIT_FLUSHED_APIS = [
- "vkEndCommandBufferAsyncGOOGLE",
- "vkQueueSubmitAsyncGOOGLE",
- "vkQueueBindSparseAsyncGOOGLE",
- "vkQueueWaitIdleAsyncGOOGLE",
- "vkQueueSignalReleaseImageANDROID",
- "vkDestroyDevice",
-]
-
-SUCCESS_RET_TYPES = {
- "VkResult" : "VK_SUCCESS",
- "void" : None,
- # TODO: Put up success results for other return types here.
-}
-
-ENCODER_THIS_PARAM = makeVulkanTypeSimple(False, "VkEncoder", 1, "this")
-
-# Common components of encoding a Vulkan API call
-def make_event_handler_call(
- handler_access,
- api,
- context_param,
- input_result_param,
- cgen,
- suffix=""):
- extraParams = [context_param.paramName]
- if input_result_param:
- extraParams.append(input_result_param)
- return cgen.makeCallExpr( \
- "%s->on_%s%s" % (handler_access, api.name, suffix),
- extraParams + \
- [p.paramName for p in api.parameters[:-1]])
-
-def emit_custom_pre_validate(typeInfo, api, cgen):
- if api.name in ENCODER_PREVALIDATED_APIS:
- callExpr = \
- make_event_handler_call( \
- "mImpl->validation()", api,
- ENCODER_THIS_PARAM,
- SUCCESS_RET_TYPES[api.getRetTypeExpr()],
- cgen)
-
- if api.getRetTypeExpr() == "void":
- cgen.stmt("VALIDATE_VOID(%s)" % callExpr)
- else:
- cgen.stmt("VALIDATE_RET(%s, %s, %s)" % \
- (api.getRetTypeExpr(),
- SUCCESS_RET_TYPES[api.getRetTypeExpr()],
- callExpr))
-
-def emit_custom_resource_preprocess(typeInfo, api, cgen):
- if api.name in ENCODER_CUSTOM_RESOURCE_PREPROCESS:
- cgen.stmt( \
- make_event_handler_call( \
- "sResourceTracker", api,
- ENCODER_THIS_PARAM,
- SUCCESS_RET_TYPES[api.getRetTypeExpr()],
- cgen, suffix="_pre"))
-
-def emit_custom_resource_postprocess(typeInfo, api, cgen):
- if api.name in ENCODER_CUSTOM_RESOURCE_POSTPROCESS:
- cgen.stmt(make_event_handler_call( \
- "sResourceTracker",
- api,
- ENCODER_THIS_PARAM,
- api.getRetVarExpr(),
- cgen))
-
-def emit_count_marshal(typeInfo, param, cgen):
- res = \
- iterateVulkanType(
- typeInfo, param,
- VulkanCountingCodegen( \
- cgen, "sFeatureBits", param.paramName, "countPtr", ROOT_TYPE_DEFAULT_VALUE,
- "count_"))
- if not res:
- cgen.stmt("(void)%s" % param.paramName)
-
-def emit_marshal(typeInfo, param, cgen):
- forOutput = param.isHandleType() and ("out" in param.inout)
- if forOutput:
- cgen.stmt("/* is handle, possibly out */")
-
- res = \
- iterateVulkanType(
- typeInfo, param,
- VulkanReservedMarshalingCodegen( \
- cgen, STREAM, ROOT_TYPE_DEFAULT_VALUE, param.paramName, "streamPtrPtr",
- API_PREFIX_RESERVEDMARSHAL,
- "" if forOutput else "get_host_u64_",
- direction="write"))
- if not res:
- cgen.stmt("(void)%s" % param.paramName)
-
- if forOutput:
- cgen.stmt("/* is handle, possibly out */")
-
-def emit_unmarshal(typeInfo, param, cgen):
- iterateVulkanType(
- typeInfo, param,
- VulkanMarshalingCodegen( \
- cgen, STREAM, ROOT_TYPE_DEFAULT_VALUE, param.paramName,
- API_PREFIX_UNMARSHAL, direction="read"))
-
-def emit_deepcopy(typeInfo, param, cgen):
- res = \
- iterateVulkanType(typeInfo, param, DeepcopyCodegen(
- cgen, [param.paramName, "local_" + param.paramName], "pool", ROOT_TYPE_DEFAULT_VALUE, "deepcopy_"))
- if not res:
- cgen.stmt("(void)%s" % param.paramName)
-
-def emit_transform(typeInfo, param, cgen, variant="tohost"):
- res = \
- iterateVulkanType(typeInfo, param, TransformCodegen( \
- cgen, param.paramName, "sResourceTracker", "transform_%s_" % variant, variant))
- if not res:
- cgen.stmt("(void)%s" % param.paramName)
-
-def emit_handlemap_create(typeInfo, param, cgen):
- iterateVulkanType(typeInfo, param, HandleMapCodegen(
- cgen, None, "sResourceTracker", "handlemap_",
- lambda vtype: typeInfo.isHandleType(vtype.typeName)
- ))
-
-def custom_encoder_args(api):
- params = ["this"]
- if api.getRetVarExpr() is not None:
- params.append(api.getRetVarExpr())
- return params
-
-def emit_handlemap_destroy(typeInfo, param, cgen):
- iterateVulkanType(typeInfo, param, HandleMapCodegen(
- cgen, None, "sResourceTracker->destroyMapping()", "handlemap_",
- lambda vtype: typeInfo.isHandleType(vtype.typeName)
- ))
-
-class EncodingParameters(object):
- def __init__(self, api):
- self.localCopied = []
- self.toWrite = []
- self.toRead = []
- self.toCreate = []
- self.toDestroy = []
-
- for param in api.parameters:
- param.action = None
- param.inout = "in"
-
- if param.paramName == "doLock":
- continue
-
- if param.possiblyOutput():
- param.inout += "out"
- self.toWrite.append(param)
- self.toRead.append(param)
- if param.isCreatedBy(api):
- self.toCreate.append(param)
- param.action = "create"
- else:
-
- if param.paramName == "doLock":
- continue
-
- if param.isDestroyedBy(api):
- self.toDestroy.append(param)
- param.action = "destroy"
- localCopyParam = \
- param.getForNonConstAccess().withModifiedName( \
- "local_" + param.paramName)
- self.localCopied.append((param, localCopyParam))
- self.toWrite.append(localCopyParam)
-
-def emit_parameter_encode_preamble_write(typeInfo, api, cgen):
- emit_custom_pre_validate(typeInfo, api, cgen);
- emit_custom_resource_preprocess(typeInfo, api, cgen);
-
- cgen.stmt("auto %s = mImpl->stream()" % STREAM)
- cgen.stmt("auto %s = mImpl->pool()" % POOL)
- # cgen.stmt("%s->setHandleMapping(%s->unwrapMapping())" % (STREAM, RESOURCES))
-
- encodingParams = EncodingParameters(api)
- for (_, localCopyParam) in encodingParams.localCopied:
- cgen.stmt(cgen.makeRichCTypeDecl(localCopyParam))
-
-def emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen, customUnwrap=None):
- encodingParams = EncodingParameters(api)
-
- for (origParam, localCopyParam) in encodingParams.localCopied:
- shouldCustomCopy = \
- customUnwrap and \
- origParam.paramName in customUnwrap and \
- "copyOp" in customUnwrap[origParam.paramName]
-
- shouldCustomMap = \
- customUnwrap and \
- origParam.paramName in customUnwrap and \
- "mapOp" in customUnwrap[origParam.paramName]
-
- if shouldCustomCopy:
- customUnwrap[origParam.paramName]["copyOp"](cgen, origParam, localCopyParam)
- else:
- # if this is a pointer type and we don't do custom copy nor unwrap,
- # and the transform doesn't end up doing anything,
- # don't deepcopy, just cast it.
-
- avoidDeepcopy = False
-
- if origParam.pointerIndirectionLevels > 0:
- testCgen = CodeGen()
- genTransformsForVulkanType("sResourceTracker", origParam, lambda p: testCgen.generalAccess(p, parentVarName = None, asPtr = True), lambda p: testCgen.generalLengthAccess(p, parentVarName = None), testCgen)
- emit_transform(typeInfo, origParam, testCgen, variant="tohost")
- if "" == testCgen.swapCode():
- avoidDeepcopy = True
- if avoidDeepcopy:
- cgen.line("// Avoiding deepcopy for %s" % origParam.paramName)
- cgen.stmt("%s = (%s%s)%s" % (localCopyParam.paramName, localCopyParam.typeName, "*" * origParam.pointerIndirectionLevels, origParam.paramName))
- else:
- emit_deepcopy(typeInfo, origParam, cgen)
-
- for (origParam, localCopyParam) in encodingParams.localCopied:
- shouldCustomMap = \
- customUnwrap and \
- origParam.paramName in customUnwrap and \
- "mapOp" in customUnwrap[origParam.paramName]
-
- if shouldCustomMap:
- customUnwrap[origParam.paramName]["mapOp"](cgen, origParam, localCopyParam)
- else:
- if localCopyParam.typeName == "VkAllocationCallbacks":
- cgen.stmt("%s = nullptr" % localCopyParam.paramName)
-
- apiForTransform = \
- api.withCustomParameters( \
- map(lambda p: p[1], \
- encodingParams.localCopied))
-
- # Apply transforms if applicable.
- # Apply transform to API itself:
- genTransformsForVulkanType(
- "sResourceTracker",
- apiForTransform,
- lambda p: cgen.generalAccess(p, parentVarName = None, asPtr = True),
- lambda p: cgen.generalLengthAccess(p, parentVarName = None),
- cgen)
-
- # For all local copied parameters, run the transforms
- for localParam in apiForTransform.parameters:
- if "doLock" in localParam.paramName:
- continue
- emit_transform(typeInfo, localParam, cgen, variant="tohost")
-
- cgen.stmt("size_t count = 0")
- cgen.stmt("size_t* countPtr = &count")
- cgen.beginBlock()
-
- # Use counting stream to calculate the packet size.
- for p in encodingParams.toWrite:
- emit_count_marshal(typeInfo, p, cgen)
-
- cgen.endBlock()
-
-def is_cmdbuf_dispatch(api):
- return "VkCommandBuffer" == api.parameters[0].typeName
-
-def emit_parameter_encode_write_packet_info(typeInfo, api, cgen):
- # Seqno and skipping dispatch serialize are for use with VULKAN_STREAM_FEATURE_QUEUE_SUBMIT_WITH_COMMANDS_BIT
- doSeqno = True
- doDispatchSerialize = True
-
- if is_cmdbuf_dispatch(api):
- doSeqno = False
- doDispatchSerialize = False
-
- if doSeqno:
- cgen.stmt("uint32_t packetSize_%s = 4 + 4 + (queueSubmitWithCommandsEnabled ? 4 : 0) + count" % (api.name))
- else:
- cgen.stmt("uint32_t packetSize_%s = 4 + 4 + count" % (api.name))
- cgen.stmt("healthMonitorAnnotation_packetSize = std::make_optional(packetSize_%s)" % (api.name))
-
- if not doDispatchSerialize:
- cgen.stmt("if (queueSubmitWithCommandsEnabled) packetSize_%s -= 8" % api.name)
-
- cgen.stmt("uint8_t* streamPtr = %s->reserve(packetSize_%s)" % (STREAM, api.name))
- cgen.stmt("uint8_t* packetBeginPtr = streamPtr")
- cgen.stmt("uint8_t** streamPtrPtr = &streamPtr")
- cgen.stmt("uint32_t opcode_%s = OP_%s" % (api.name, api.name))
-
- if doSeqno:
- cgen.stmt("uint32_t seqno; if (queueSubmitWithCommandsEnabled) seqno = ResourceTracker::nextSeqno()")
- cgen.stmt("healthMonitorAnnotation_seqno = std::make_optional(seqno)")
-
- cgen.stmt("memcpy(streamPtr, &opcode_%s, sizeof(uint32_t)); streamPtr += sizeof(uint32_t)" % api.name)
- cgen.stmt("memcpy(streamPtr, &packetSize_%s, sizeof(uint32_t)); streamPtr += sizeof(uint32_t)" % api.name)
-
- if doSeqno:
- cgen.line("if (queueSubmitWithCommandsEnabled) { memcpy(streamPtr, &seqno, sizeof(uint32_t)); streamPtr += sizeof(uint32_t); }")
-
-def emit_parameter_encode_do_parameter_write(typeInfo, api, cgen):
- encodingParams = EncodingParameters(api)
-
- dispatchDone = False
-
- for p in encodingParams.toWrite:
- if is_cmdbuf_dispatch(api) and not dispatchDone:
- cgen.beginIf("!queueSubmitWithCommandsEnabled")
- emit_marshal(typeInfo, p, cgen)
- cgen.endIf()
- else:
- emit_marshal(typeInfo, p, cgen)
-
- dispatchDone = True
-
- cgen.beginIf("watchdog")
- cgen.stmt("size_t watchdogBufSize = std::min<size_t>(static_cast<size_t>(packetSize_%s), kWatchdogBufferMax)" % (api.name))
- cgen.stmt("healthMonitorAnnotation_packetContents.resize(watchdogBufSize)")
- cgen.stmt("memcpy(&healthMonitorAnnotation_packetContents[0], packetBeginPtr, watchdogBufSize)")
- cgen.endIf()
-
-def emit_parameter_encode_read(typeInfo, api, cgen):
- encodingParams = EncodingParameters(api)
-
- for p in encodingParams.toRead:
- if p.action == "create":
- cgen.stmt(
- "%s->setHandleMapping(%s->createMapping())" % \
- (STREAM, RESOURCES))
- emit_unmarshal(typeInfo, p, cgen)
- if p.action == "create":
- cgen.stmt(
- "%s->unsetHandleMapping()" % STREAM)
- emit_transform(typeInfo, p, cgen, variant="fromhost")
-
-def emit_post(typeInfo, api, cgen):
- encodingParams = EncodingParameters(api)
-
- emit_custom_resource_postprocess(typeInfo, api, cgen)
-
- for p in encodingParams.toDestroy:
- emit_handlemap_destroy(typeInfo, p, cgen)
-
- doSeqno = True
- if is_cmdbuf_dispatch(api):
- doSeqno = False
-
- retType = api.getRetTypeExpr()
-
- if api.name in ENCODER_EXPLICIT_FLUSHED_APIS:
- cgen.stmt("stream->flush()");
- return
-
- if doSeqno:
- if retType == "void":
- encodingParams = EncodingParameters(api)
- if 0 == len(encodingParams.toRead):
- cgen.stmt("stream->flush()");
-
-def emit_pool_free(cgen):
- cgen.stmt("++encodeCount;")
- cgen.beginIf("0 == encodeCount % POOL_CLEAR_INTERVAL")
- cgen.stmt("pool->freeAll()")
- cgen.stmt("%s->clearPool()" % STREAM)
- cgen.endIf()
-
-def emit_return_unmarshal(typeInfo, api, cgen):
-
- retType = api.getRetTypeExpr()
-
- if retType == "void":
- return
-
- retVar = api.getRetVarExpr()
- cgen.stmt("%s %s = (%s)0" % (retType, retVar, retType))
- cgen.stmt("%s->read(&%s, %s)" % \
- (STREAM, retVar, cgen.sizeofExpr(api.retType)))
-
-def emit_return(typeInfo, api, cgen):
- if api.getRetTypeExpr() == "void":
- return
-
- retVar = api.getRetVarExpr()
- cgen.stmt("return %s" % retVar)
-
-def emit_lock(cgen):
- cgen.stmt("(void)doLock");
- cgen.stmt("bool queueSubmitWithCommandsEnabled = sFeatureBits & VULKAN_STREAM_FEATURE_QUEUE_SUBMIT_WITH_COMMANDS_BIT")
- cgen.stmt("if (!queueSubmitWithCommandsEnabled && doLock) this->lock()")
-
-def emit_unlock(cgen):
- cgen.stmt("if (!queueSubmitWithCommandsEnabled && doLock) this->unlock()")
-
-def emit_debug_log(typeInfo, api, cgen):
- logFormat = []
- logVargs = []
- for param in api.parameters:
- if param.paramName == "doLock":
- continue
-
- paramFormatSpecifier = param.getPrintFormatSpecifier()
- if not paramFormatSpecifier:
- continue
-
- logFormat.append(param.paramName + ":" + paramFormatSpecifier)
- logVargs.append(param.paramName)
-
- logFormatStr = ", ".join(logFormat)
- logVargsStr = ", ".join(logVargs)
-
- cgen.stmt("ENCODER_DEBUG_LOG(\"%s(%s)\", %s)" % (api.name, logFormatStr, logVargsStr))
-
-def emit_health_watchdog(api, cgen):
- cgen.stmt("std::optional<uint32_t> healthMonitorAnnotation_seqno = std::nullopt")
- cgen.stmt("std::optional<uint32_t> healthMonitorAnnotation_packetSize = std::nullopt")
- cgen.stmt("std::vector<uint8_t> healthMonitorAnnotation_packetContents")
- cgen.line("""
- auto watchdog = WATCHDOG_BUILDER(mHealthMonitor, \"%s in VkEncoder\")
- .setOnHangCallback([&]() {
- auto annotations = std::make_unique<EventHangMetadata::HangAnnotations>();
- if (healthMonitorAnnotation_seqno) {
- annotations->insert({{"seqno", std::to_string(healthMonitorAnnotation_seqno.value())}});
- }
- if (healthMonitorAnnotation_packetSize) {
- annotations->insert({{"packetSize", std::to_string(healthMonitorAnnotation_packetSize.value())}});
- }
- if (!healthMonitorAnnotation_packetContents.empty()) {
- annotations->insert(
- {{"packetContents", getPacketContents(
- &healthMonitorAnnotation_packetContents[0], healthMonitorAnnotation_packetContents.size())}});
- }
- return std::move(annotations);
- })
- .build();
- """% (api.name)
- )
-
-def emit_default_encoding(typeInfo, api, cgen):
- emit_debug_log(typeInfo, api, cgen)
- emit_lock(cgen)
- emit_parameter_encode_preamble_write(typeInfo, api, cgen)
- emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen)
- emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
- emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
- emit_parameter_encode_read(typeInfo, api, cgen)
- emit_return_unmarshal(typeInfo, api, cgen)
- emit_post(typeInfo, api, cgen)
- emit_pool_free(cgen)
- emit_unlock(cgen)
- emit_return(typeInfo, api, cgen)
-
-## Custom encoding definitions##################################################
-
-def emit_only_goldfish_custom(typeInfo, api, cgen):
- emit_lock(cgen)
- cgen.vkApiCall( \
- api,
- customPrefix="sResourceTracker->on_",
- customParameters=custom_encoder_args(api) + \
- [p.paramName for p in api.parameters[:-1]])
- emit_unlock(cgen)
- emit_return(typeInfo, api, cgen)
-
-def emit_only_resource_event(typeInfo, api, cgen):
- cgen.stmt("(void)doLock");
- input_result = None
- retExpr = api.getRetVarExpr()
-
- if retExpr:
- retType = api.getRetTypeExpr()
- input_result = SUCCESS_RET_TYPES[retType]
- cgen.stmt("%s %s = (%s)0" % (retType, retExpr, retType))
-
- cgen.stmt(
- (("%s = " % retExpr) if retExpr else "") +
- make_event_handler_call(
- "sResourceTracker",
- api,
- ENCODER_THIS_PARAM,
- input_result, cgen))
-
- if retExpr:
- emit_return(typeInfo, api, cgen)
-
-def emit_with_custom_unwrap(custom):
- def call(typeInfo, api, cgen):
- emit_lock(cgen)
- emit_parameter_encode_preamble_write(typeInfo, api, cgen)
- emit_parameter_encode_copy_unwrap_count(
- typeInfo, api, cgen, customUnwrap=custom)
- emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
- emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
- emit_parameter_encode_read(typeInfo, api, cgen)
- emit_return_unmarshal(typeInfo, api, cgen)
- emit_pool_free(cgen)
- emit_unlock(cgen)
- emit_return(typeInfo, api, cgen)
- return call
-
-def encode_vkFlushMappedMemoryRanges(typeInfo, api, cgen):
- emit_lock(cgen)
- emit_parameter_encode_preamble_write(typeInfo, api, cgen)
- emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen)
-
- def emit_flush_ranges(streamVar):
- cgen.beginIf("!sResourceTracker->usingDirectMapping()")
- cgen.beginFor("uint32_t i = 0", "i < memoryRangeCount", "++i")
- cgen.stmt("auto range = pMemoryRanges[i]")
- cgen.stmt("auto memory = pMemoryRanges[i].memory")
- cgen.stmt("auto size = pMemoryRanges[i].size")
- cgen.stmt("auto offset = pMemoryRanges[i].offset")
- cgen.stmt("uint64_t streamSize = 0")
- cgen.stmt("if (!memory) { %s->write(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
- cgen.stmt("auto hostPtr = sResourceTracker->getMappedPointer(memory)")
- cgen.stmt("auto actualSize = size == VK_WHOLE_SIZE ? sResourceTracker->getMappedSize(memory) : size")
- cgen.stmt("if (!hostPtr) { %s->write(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
- cgen.stmt("streamSize = actualSize")
- cgen.stmt("%s->write(&streamSize, sizeof(uint64_t))" % streamVar)
- cgen.stmt("uint8_t* targetRange = hostPtr + offset")
- cgen.stmt("%s->write(targetRange, actualSize)" % streamVar)
- cgen.endFor()
- cgen.endIf()
-
- emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
- emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
-
- emit_flush_ranges(STREAM)
-
- emit_parameter_encode_read(typeInfo, api, cgen)
- emit_return_unmarshal(typeInfo, api, cgen)
- emit_pool_free(cgen)
- emit_unlock(cgen)
- emit_return(typeInfo, api, cgen)
-
-def encode_vkInvalidateMappedMemoryRanges(typeInfo, api, cgen):
- emit_lock(cgen)
- emit_parameter_encode_preamble_write(typeInfo, api, cgen)
- emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen)
- emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
- emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
- emit_parameter_encode_read(typeInfo, api, cgen)
- emit_return_unmarshal(typeInfo, api, cgen)
-
- def emit_invalidate_ranges(streamVar):
- cgen.beginIf("!sResourceTracker->usingDirectMapping()")
- cgen.beginFor("uint32_t i = 0", "i < memoryRangeCount", "++i")
- cgen.stmt("auto range = pMemoryRanges[i]")
- cgen.stmt("auto memory = pMemoryRanges[i].memory")
- cgen.stmt("auto size = pMemoryRanges[i].size")
- cgen.stmt("auto offset = pMemoryRanges[i].offset")
- cgen.stmt("uint64_t streamSize = 0")
- cgen.stmt("if (!memory) { %s->read(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
- cgen.stmt("auto hostPtr = sResourceTracker->getMappedPointer(memory)")
- cgen.stmt("auto actualSize = size == VK_WHOLE_SIZE ? sResourceTracker->getMappedSize(memory) : size")
- cgen.stmt("if (!hostPtr) { %s->read(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
- cgen.stmt("streamSize = actualSize")
- cgen.stmt("%s->read(&streamSize, sizeof(uint64_t))" % streamVar)
- cgen.stmt("uint8_t* targetRange = hostPtr + offset")
- cgen.stmt("%s->read(targetRange, actualSize)" % streamVar)
- cgen.endFor()
- cgen.endIf()
-
- emit_invalidate_ranges(STREAM)
- emit_pool_free(cgen)
- emit_unlock(cgen)
- emit_return(typeInfo, api, cgen)
-
-def emit_manual_inline(typeInfo, api, cgen):
- cgen.line("#include \"%s_encode_impl.cpp.inl\"" % api.name)
-
-def unwrap_VkNativeBufferANDROID():
- def mapOp(cgen, orig, local):
- cgen.stmt("sResourceTracker->unwrap_VkNativeBufferANDROID(%s, %s)" %
- (orig.paramName, local.paramName))
- return { "pCreateInfo" : { "mapOp" : mapOp } }
-
-def unwrap_vkAcquireImageANDROID_nativeFenceFd():
- def mapOp(cgen, orig, local):
- cgen.stmt("sResourceTracker->unwrap_vkAcquireImageANDROID_nativeFenceFd(%s, &%s)" %
- (orig.paramName, local.paramName))
- return { "nativeFenceFd" : { "mapOp" : mapOp } }
-
-custom_encodes = {
- "vkMapMemory" : emit_only_resource_event,
- "vkUnmapMemory" : emit_only_resource_event,
- "vkFlushMappedMemoryRanges" : encode_vkFlushMappedMemoryRanges,
- "vkInvalidateMappedMemoryRanges" : encode_vkInvalidateMappedMemoryRanges,
- "vkCreateImage" : emit_with_custom_unwrap(unwrap_VkNativeBufferANDROID()),
- "vkCreateImageWithRequirementsGOOGLE" : emit_with_custom_unwrap(unwrap_VkNativeBufferANDROID()),
- "vkAcquireImageANDROID" : emit_with_custom_unwrap(unwrap_vkAcquireImageANDROID_nativeFenceFd()),
- "vkQueueFlushCommandsGOOGLE" : emit_manual_inline,
-}
-
-class VulkanEncoder(VulkanWrapperGenerator):
- def __init__(self, module, typeInfo):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
-
- self.typeInfo = typeInfo
-
- self.cgenHeader = CodeGen()
- self.cgenHeader.incrIndent()
-
- self.cgenImpl = CodeGen()
-
- def onBegin(self,):
- self.module.appendHeader(encoder_decl_preamble)
- self.module.appendImpl(encoder_impl_preamble)
-
- def onGenCmd(self, cmdinfo, name, alias):
- VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
-
- api = copy.deepcopy(self.typeInfo.apis[name])
- api.parameters.append(makeVulkanTypeSimple(False, "uint32_t", 0, "doLock"))
-
- self.cgenHeader.stmt(self.cgenHeader.makeFuncProto(api))
- apiImpl = api.withModifiedName("VkEncoder::" + api.name)
-
- self.module.appendHeader(self.cgenHeader.swapCode())
-
- def emit_function_impl(cgen):
- emit_health_watchdog(api, cgen)
- if api.name in custom_encodes.keys():
- custom_encodes[api.name](self.typeInfo, api, cgen)
- else:
- emit_default_encoding(self.typeInfo, api, cgen)
-
- self.module.appendImpl(self.cgenImpl.makeFuncImpl(apiImpl, emit_function_impl))
-
- def onEnd(self,):
- self.module.appendHeader(encoder_decl_postamble)
- self.cgenHeader.decrIndent()
diff --git a/codegen/vulkan/scripts/cereal/extensionstructs.py b/codegen/vulkan/scripts/cereal/extensionstructs.py
deleted file mode 100644
index 95c95237..00000000
--- a/codegen/vulkan/scripts/cereal/extensionstructs.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# Copyright (c) 2018 The Android Open Source Project
-# Copyright (c) 2018 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from .common.codegen import CodeGen
-from .common.vulkantypes import \
- VulkanAPI, makeVulkanTypeSimple, iterateVulkanType
-
-from .wrapperdefs import VulkanWrapperGenerator
-from .wrapperdefs import STRUCT_EXTENSION_PARAM
-from .wrapperdefs import STRUCT_EXTENSION_PARAM_FOR_WRITE
-from .wrapperdefs import EXTENSION_SIZE_API_NAME
-from .wrapperdefs import EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME
-from .wrapperdefs import STRUCT_TYPE_API_NAME
-
-class VulkanExtensionStructs(VulkanWrapperGenerator):
-
- def __init__(self, module, typeInfo):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
-
- self.codegen = CodeGen()
-
- self.structTypeRetType = \
- makeVulkanTypeSimple(False, "uint32_t", 0)
-
- self.rootTypeVarName = "rootType"
- self.rootTypeParam = \
- makeVulkanTypeSimple(False, "VkStructureType",
- 0, self.rootTypeVarName)
- self.structTypePrototype = \
- VulkanAPI(STRUCT_TYPE_API_NAME,
- self.structTypeRetType,
- [STRUCT_EXTENSION_PARAM])
-
- self.extensionStructSizeRetType = \
- makeVulkanTypeSimple(False, "size_t", 0)
- self.extensionStructSizePrototype = \
- VulkanAPI(EXTENSION_SIZE_API_NAME,
- self.extensionStructSizeRetType,
- [self.rootTypeParam, STRUCT_EXTENSION_PARAM])
-
- self.streamFeaturesType = makeVulkanTypeSimple(False, "uint32_t", 0, "streamFeatures")
-
- self.extensionStructSizeWithStreamFeaturesPrototype = \
- VulkanAPI(EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME,
- self.extensionStructSizeRetType,
- [self.streamFeaturesType, self.rootTypeParam, STRUCT_EXTENSION_PARAM])
- def onBegin(self,):
- VulkanWrapperGenerator.onBegin(self)
- self.module.appendHeader(self.codegen.makeFuncDecl(
- self.structTypePrototype))
- self.module.appendHeader(self.codegen.makeFuncDecl(
- self.extensionStructSizePrototype))
- self.module.appendHeader(self.codegen.makeFuncDecl(
- self.extensionStructSizeWithStreamFeaturesPrototype))
-
- def onGenType(self, typeXml, name, alias):
- VulkanWrapperGenerator.onGenType(self, typeXml, name, alias)
-
- def onGenCmd(self, cmdinfo, name, alias):
- VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
-
- def onEnd(self,):
- VulkanWrapperGenerator.onEnd(self)
-
- def castAsStruct(varName, typeName, const=True):
- return "reinterpret_cast<%s%s*>(%s)" % \
- ("const " if const else "", typeName, varName)
-
- def structTypeImpl(cgen):
- cgen.stmt(
- "const uint32_t asStructType = *(%s)" %
- (castAsStruct(STRUCT_EXTENSION_PARAM.paramName, "uint32_t")))
- cgen.stmt("return asStructType")
-
- self.module.appendImpl(
- self.codegen.makeFuncImpl(
- self.structTypePrototype, structTypeImpl))
-
- def forEachExtensionReturnSize(ext, _, cgen):
- cgen.stmt("return sizeof(%s)" % ext.name)
-
- def forEachExtensionReturnSizeProtectedByFeature(ext, _, cgen):
- featureProtected = (ext.optionalStr is not None) and (ext.optionalStr.startswith("streamFeature:"))
- if featureProtected:
- splitted = ext.optionalStr.split(":")
- cgen.beginIf("%s & %s" % ("streamFeatures", splitted[1]))
- cgen.stmt("return sizeof(%s)" % ext.name)
- cgen.endIf()
- cgen.beginElse()
- cgen.stmt("return 0")
- cgen.endIf()
- else:
- cgen.stmt("return sizeof(%s)" % ext.name)
-
- self.module.appendImpl(
- self.codegen.makeFuncImpl(
- self.extensionStructSizePrototype,
- lambda cgen: self.emitForEachStructExtension(
- cgen,
- self.extensionStructSizeRetType,
- STRUCT_EXTENSION_PARAM,
- forEachExtensionReturnSize, autoBreak=False,
- rootTypeVar=self.rootTypeParam)))
-
- self.module.appendImpl(
- self.codegen.makeFuncImpl(
- self.extensionStructSizeWithStreamFeaturesPrototype,
- lambda cgen: self.emitForEachStructExtension(
- cgen,
- self.extensionStructSizeRetType,
- STRUCT_EXTENSION_PARAM,
- forEachExtensionReturnSizeProtectedByFeature, autoBreak=False,
- rootTypeVar=self.rootTypeParam)))
diff --git a/codegen/vulkan/scripts/cereal/frontend.py b/codegen/vulkan/scripts/cereal/frontend.py
deleted file mode 100644
index b182c0e7..00000000
--- a/codegen/vulkan/scripts/cereal/frontend.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# Copyright (c) 2018 The Android Open Source Project
-# Copyright (c) 2018 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from .common.codegen import CodeGen, VulkanAPIWrapper
-from .common.vulkantypes import \
- VulkanAPI, makeVulkanTypeSimple, iterateVulkanType
-
-from .wrapperdefs import VulkanWrapperGenerator
-
-from .wrapperdefs import API_PREFIX_VALIDATE
-from .wrapperdefs import PARAMETERS_VALIDATE
-from .wrapperdefs import VOID_TYPE
-from .wrapperdefs import VALIDATE_RESULT_TYPE
-from .wrapperdefs import VALIDATE_VAR_NAME
-from .wrapperdefs import VALIDATE_GOOD_RESULT
-
-from .wrapperdefs import VULKAN_STREAM_TYPE
-from .wrapperdefs import VULKAN_STREAM_VAR_NAME
-
-from .wrapperdefs import API_PREFIX_MARSHAL
-from .wrapperdefs import API_PREFIX_FRONTEND
-
-# Frontend
-class VulkanFrontend(VulkanWrapperGenerator):
-
- def __init__(self, module, typeInfo):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
-
- def validateDefFunc(_codegen, _api):
- # TODO
- pass
-
- self.validateWrapper = \
- VulkanAPIWrapper(
- API_PREFIX_VALIDATE,
- PARAMETERS_VALIDATE,
- VOID_TYPE,
- validateDefFunc)
-
- def frontendDefFunc(codegen, api):
- retTypeName = api.retType.typeName
-
- codegen.stmt(
- "%s %s = %s" % (VALIDATE_RESULT_TYPE, VALIDATE_VAR_NAME,
- VALIDATE_GOOD_RESULT))
- codegen.funcCall(None, API_PREFIX_VALIDATE + api.origName,
- ["&%s" % VALIDATE_VAR_NAME] + list(
- map(lambda p: p.paramName, api.parameters)))
-
- codegen.beginIf(
- "%s != %s" % (VALIDATE_VAR_NAME, VALIDATE_GOOD_RESULT))
- if retTypeName == VALIDATE_RESULT_TYPE:
- codegen.stmt("return %s" % VALIDATE_VAR_NAME)
- elif retTypeName != "void":
- codegen.stmt("return (%s)0" % retTypeName)
- else:
- codegen.stmt("return")
- codegen.endIf()
-
- codegen.stmt("// VULKAN_STREAM_GET()")
- codegen.stmt("%s* %s = nullptr" % (VULKAN_STREAM_TYPE,
- VULKAN_STREAM_VAR_NAME))
-
- retLhs = None
- if retTypeName != "void":
- retLhs = retTypeName + " res"
-
- codegen.funcCall(retLhs, API_PREFIX_MARSHAL + api.origName,
- [VULKAN_STREAM_VAR_NAME] + list(
- map(lambda p: p.paramName, api.parameters)))
-
- if retTypeName != "void":
- codegen.stmt("return res")
-
- self.frontendWrapper = \
- VulkanAPIWrapper(
- API_PREFIX_FRONTEND,
- [],
- None,
- frontendDefFunc)
-
- def onGenCmd(self, cmdinfo, name, alias):
- VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
- self.module.appendHeader(
- self.frontendWrapper.makeDecl(self.typeInfo, name))
- self.module.appendImpl(
- self.validateWrapper.makeDefinition(
- self.typeInfo, name, isStatic=True))
- self.module.appendImpl(
- self.frontendWrapper.makeDefinition(self.typeInfo, name))
diff --git a/codegen/vulkan/scripts/cereal/functable.py b/codegen/vulkan/scripts/cereal/functable.py
deleted file mode 100644
index f16735a3..00000000
--- a/codegen/vulkan/scripts/cereal/functable.py
+++ /dev/null
@@ -1,360 +0,0 @@
-from .common.codegen import CodeGen, VulkanWrapperGenerator
-from .common.vulkantypes import \
- VulkanAPI, makeVulkanTypeSimple, iterateVulkanType
-from .common.vulkantypes import EXCLUDED_APIS
-
-RESOURCE_TRACKER_ENTRIES = [
- "vkEnumerateInstanceExtensionProperties",
- "vkEnumerateDeviceExtensionProperties",
- "vkEnumeratePhysicalDevices",
- "vkAllocateMemory",
- "vkFreeMemory",
- "vkCreateImage",
- "vkDestroyImage",
- "vkGetImageMemoryRequirements",
- "vkGetImageMemoryRequirements2",
- "vkGetImageMemoryRequirements2KHR",
- "vkBindImageMemory",
- "vkBindImageMemory2",
- "vkBindImageMemory2KHR",
- "vkCreateBuffer",
- "vkDestroyBuffer",
- "vkGetBufferMemoryRequirements",
- "vkGetBufferMemoryRequirements2",
- "vkGetBufferMemoryRequirements2KHR",
- "vkBindBufferMemory",
- "vkBindBufferMemory2",
- "vkBindBufferMemory2KHR",
- "vkCreateSemaphore",
- "vkDestroySemaphore",
- "vkQueueSubmit",
- "vkQueueWaitIdle",
- "vkImportSemaphoreFdKHR",
- "vkGetSemaphoreFdKHR",
- # Warning: These need to be defined in vk.xml (currently no-op) {
- "vkGetMemoryFuchsiaHandleKHR",
- "vkGetMemoryFuchsiaHandlePropertiesKHR",
- "vkGetSemaphoreFuchsiaHandleKHR",
- "vkImportSemaphoreFuchsiaHandleKHR",
- # } end Warning: These need to be defined in vk.xml (currently no-op)
- "vkGetAndroidHardwareBufferPropertiesANDROID",
- "vkGetMemoryAndroidHardwareBufferANDROID",
- "vkCreateSamplerYcbcrConversion",
- "vkDestroySamplerYcbcrConversion",
- "vkCreateSamplerYcbcrConversionKHR",
- "vkDestroySamplerYcbcrConversionKHR",
- "vkUpdateDescriptorSetWithTemplate",
- "vkGetPhysicalDeviceImageFormatProperties2",
- "vkGetPhysicalDeviceImageFormatProperties2KHR",
- "vkBeginCommandBuffer",
- "vkEndCommandBuffer",
- "vkResetCommandBuffer",
- "vkCreateImageView",
- "vkCreateSampler",
- "vkGetPhysicalDeviceExternalFenceProperties",
- "vkGetPhysicalDeviceExternalFencePropertiesKHR",
- "vkCreateFence",
- "vkResetFences",
- "vkImportFenceFdKHR",
- "vkGetFenceFdKHR",
- "vkWaitForFences",
- "vkCreateDescriptorPool",
- "vkDestroyDescriptorPool",
- "vkResetDescriptorPool",
- "vkAllocateDescriptorSets",
- "vkFreeDescriptorSets",
- "vkCreateDescriptorSetLayout",
- "vkUpdateDescriptorSets",
- "vkCmdExecuteCommands",
- "vkCmdBindDescriptorSets",
- "vkDestroyDescriptorSetLayout",
- "vkAllocateCommandBuffers",
- "vkQueueSignalReleaseImageANDROID",
- "vkCmdPipelineBarrier",
- "vkCreateGraphicsPipelines",
-]
-
-SUCCESS_VAL = {
- "VkResult" : ["VK_SUCCESS"],
-}
-
-POSTPROCESSES = {
- "vkResetCommandPool" : """if (vkResetCommandPool_VkResult_return == VK_SUCCESS) {
- ResourceTracker::get()->resetCommandPoolStagingInfo(commandPool);
- }""",
- "vkAllocateCommandBuffers" : """if (vkAllocateCommandBuffers_VkResult_return == VK_SUCCESS) {
- ResourceTracker::get()->addToCommandPool(pAllocateInfo->commandPool, pAllocateInfo->commandBufferCount, pCommandBuffers);
- }""",
-}
-
-def is_cmdbuf_dispatch(api):
- return "VkCommandBuffer" == api.parameters[0].typeName
-
-def is_queue_dispatch(api):
- return "VkQueue" == api.parameters[0].typeName
-
-class VulkanFuncTable(VulkanWrapperGenerator):
- def __init__(self, module, typeInfo):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
- self.typeInfo = typeInfo
- self.cgen = CodeGen()
- self.entries = []
- self.entryFeatures = []
- self.cmdToFeatureType = {}
- self.feature = None
- self.featureType = None
-
- def onBegin(self,):
- cgen = self.cgen
- cgen.line("static void sOnInvalidDynamicallyCheckedCall(const char* apiname, const char* neededFeature)")
- cgen.beginBlock()
- cgen.stmt("ALOGE(\"invalid call to %s: %s not supported\", apiname, neededFeature)")
- cgen.stmt("abort()")
- cgen.endBlock()
- self.module.appendImpl(cgen.swapCode())
- pass
-
- def onBeginFeature(self, featureName, featureType):
- self.feature = featureName
- self.featureType = featureType
-
- def onEndFeature(self):
- self.feature = None
- self.featureType = None
-
- def onFeatureNewCmd(self, name):
- self.cmdToFeatureType[name] = self.featureType
-
- def onGenCmd(self, cmdinfo, name, alias):
- typeInfo = self.typeInfo
- cgen = self.cgen
- api = typeInfo.apis[name]
- self.entries.append(api)
- self.entryFeatures.append(self.feature)
-
- def genEncoderOrResourceTrackerCall(cgen, api, declareResources=True):
- cgen.stmt("AEMU_SCOPED_TRACE(\"%s\")" % api.name)
-
- if is_cmdbuf_dispatch(api):
- cgen.stmt("auto vkEnc = ResourceTracker::getCommandBufferEncoder(commandBuffer)")
- elif is_queue_dispatch(api):
- cgen.stmt("auto vkEnc = ResourceTracker::getQueueEncoder(queue)")
- else:
- cgen.stmt("auto vkEnc = ResourceTracker::getThreadLocalEncoder()")
- callLhs = None
- retTypeName = api.getRetTypeExpr()
- if retTypeName != "void":
- retVar = api.getRetVarExpr()
- cgen.stmt("%s %s = (%s)0" % (retTypeName, retVar, retTypeName))
- callLhs = retVar
-
- if name in RESOURCE_TRACKER_ENTRIES:
- if declareResources:
- cgen.stmt("auto resources = ResourceTracker::get()")
- cgen.funcCall(
- callLhs, "resources->" + "on_" + api.name,
- ["vkEnc"] + SUCCESS_VAL.get(retTypeName, []) + \
- [p.paramName for p in api.parameters])
- else:
- cgen.funcCall(
- callLhs, "vkEnc->" + api.name, [p.paramName for p in api.parameters] + ["true /* do lock */"])
-
- if name in POSTPROCESSES:
- cgen.line(POSTPROCESSES[name])
-
- if retTypeName != "void":
- cgen.stmt("return %s" % retVar)
-
-
- api_entry = api.withModifiedName("entry_" + api.name)
-
- cgen.line("static " + self.cgen.makeFuncProto(api_entry))
- cgen.beginBlock()
- genEncoderOrResourceTrackerCall(cgen, api)
- cgen.endBlock()
-
- if self.isDeviceDispatch(api) and self.feature != "VK_VERSION_1_0":
- api_entry_dyn_check = api.withModifiedName("dynCheck_entry_" + api.name)
- cgen.line("static " + self.cgen.makeFuncProto(api_entry_dyn_check))
- cgen.beginBlock()
- if self.feature == "VK_VERSION_1_1":
- cgen.stmt("auto resources = ResourceTracker::get()")
- if "VkCommandBuffer" == api.parameters[0].typeName:
- cgen.stmt("VkDevice device = resources->getDevice(commandBuffer)")
- cgen.beginIf("resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1")
- cgen.stmt("sOnInvalidDynamicallyCheckedCall(\"%s\", \"%s\")" % (api.name, self.feature))
- cgen.endIf()
- elif self.feature != "VK_VERSION_1_0":
- cgen.stmt("auto resources = ResourceTracker::get()")
- if "VkCommandBuffer" == api.parameters[0].typeName:
- cgen.stmt("VkDevice device = resources->getDevice(commandBuffer);")
- cgen.beginIf("!resources->hasDeviceExtension(device, \"%s\")" % self.feature)
- cgen.stmt("sOnInvalidDynamicallyCheckedCall(\"%s\", \"%s\")" % (api.name, self.feature))
- cgen.endIf()
- else:
- print("About to generate a frivolous api!: dynCheck entry: %s" % api.name)
- raise
- genEncoderOrResourceTrackerCall(cgen, api, declareResources = False)
- cgen.endBlock()
-
- self.module.appendImpl(cgen.swapCode())
-
- def onEnd(self,):
- getProcAddressDecl = "void* goldfish_vulkan_get_proc_address(const char* name)"
- self.module.appendHeader(getProcAddressDecl + ";\n")
- self.module.appendImpl(getProcAddressDecl)
- self.cgen.beginBlock()
-
- prevFeature = None
- for e, f in zip(self.entries, self.entryFeatures):
- featureEndif = prevFeature is not None and (f != prevFeature)
- featureif = not featureEndif and (f != prevFeature)
-
- if featureEndif:
- self.cgen.leftline("#endif")
- self.cgen.leftline("#ifdef %s" % f)
-
- if featureif:
- self.cgen.leftline("#ifdef %s" % f)
-
- self.cgen.beginIf("!strcmp(name, \"%s\")" % e.name)
- if e.name in EXCLUDED_APIS:
- self.cgen.stmt("return nullptr")
- elif f == "VK_VERSION_1_1":
- self.cgen.stmt("return nullptr")
- elif f != "VK_VERSION_1_0":
- self.cgen.stmt("return nullptr")
- else:
- self.cgen.stmt("return (void*)%s" % ("entry_" + e.name))
- self.cgen.endIf()
- prevFeature = f
-
- self.cgen.leftline("#endif")
-
- self.cgen.stmt("return nullptr")
- self.cgen.endBlock()
- self.module.appendImpl(self.cgen.swapCode())
-
- getInstanceProcAddressDecl = "void* goldfish_vulkan_get_instance_proc_address(VkInstance instance, const char* name)"
- self.module.appendHeader(getInstanceProcAddressDecl + ";\n")
- self.module.appendImpl(getInstanceProcAddressDecl)
- self.cgen.beginBlock()
-
- self.cgen.stmt(
- "auto resources = ResourceTracker::get()")
- self.cgen.stmt(
- "bool has1_1OrHigher = resources->getApiVersionFromInstance(instance) >= VK_API_VERSION_1_1")
- self.cgen.stmt(
- "bool has1_2OrHigher = resources->getApiVersionFromInstance(instance) >= VK_API_VERSION_1_2")
-
- prevFeature = None
- for e, f in zip(self.entries, self.entryFeatures):
- featureEndif = prevFeature is not None and (f != prevFeature)
- featureif = not featureEndif and (f != prevFeature)
-
- if featureEndif:
- self.cgen.leftline("#endif")
- self.cgen.leftline("#ifdef %s" % f)
-
- if featureif:
- self.cgen.leftline("#ifdef %s" % f)
-
- self.cgen.beginIf("!strcmp(name, \"%s\")" % e.name)
-
- entryPointExpr = "(void*)%s" % ("entry_" + e.name)
-
- if e.name in EXCLUDED_APIS:
- self.cgen.stmt("return nullptr")
- elif f == "VK_VERSION_1_2":
- if self.isDeviceDispatch(e):
- self.cgen.stmt("return (void*)dynCheck_entry_%s" % e.name)
- else:
- self.cgen.stmt( \
- "return has1_2OrHigher ? %s : nullptr" % \
- entryPointExpr)
- elif f == "VK_VERSION_1_1":
- if self.isDeviceDispatch(e):
- self.cgen.stmt("return (void*)dynCheck_entry_%s" % e.name)
- else:
- self.cgen.stmt( \
- "return has1_1OrHigher ? %s : nullptr" % \
- entryPointExpr)
- elif f != "VK_VERSION_1_0":
- entryNeedsInstanceExtensionCheck = self.cmdToFeatureType[e.name] == "instance"
-
- entryPrefix = "dynCheck_" if self.isDeviceDispatch(e) else ""
- entryPointExpr = "(void*)%sentry_%s" % (entryPrefix, e.name)
-
- if entryNeedsInstanceExtensionCheck:
- self.cgen.stmt("bool hasExt = resources->hasInstanceExtension(instance, \"%s\")" % f)
- self.cgen.stmt("return hasExt ? %s : nullptr" % entryPointExpr)
- else:
- # TODO(b/236246382): We need to check the device extension support here.
- self.cgen.stmt("// TODO(b/236246382): Check support for device extension");
- self.cgen.stmt("return %s" % entryPointExpr)
-
- else:
- self.cgen.stmt("return %s" % entryPointExpr)
- self.cgen.endIf()
- prevFeature = f
-
- self.cgen.leftline("#endif")
-
- self.cgen.stmt("return nullptr")
- self.cgen.endBlock()
- self.module.appendImpl(self.cgen.swapCode())
-
- getDeviceProcAddressDecl = "void* goldfish_vulkan_get_device_proc_address(VkDevice device, const char* name)"
- self.module.appendHeader(getDeviceProcAddressDecl + ";\n")
- self.module.appendImpl(getDeviceProcAddressDecl)
- self.cgen.beginBlock()
-
- self.cgen.stmt(
- "auto resources = ResourceTracker::get()")
- self.cgen.stmt(
- "bool has1_1OrHigher = resources->getApiVersionFromDevice(device) >= VK_API_VERSION_1_1")
-
- prevFeature = None
- for e, f in zip(self.entries, self.entryFeatures):
- featureEndif = prevFeature is not None and (f != prevFeature)
- featureif = not featureEndif and (f != prevFeature)
-
- if featureEndif:
- self.cgen.leftline("#endif")
- self.cgen.leftline("#ifdef %s" % f)
-
- if featureif:
- self.cgen.leftline("#ifdef %s" % f)
-
- self.cgen.beginIf("!strcmp(name, \"%s\")" % e.name)
-
- entryPointExpr = "(void*)%s" % ("entry_" + e.name)
-
- if e.name in EXCLUDED_APIS:
- self.cgen.stmt("return nullptr")
- elif f == "VK_VERSION_1_1":
- self.cgen.stmt( \
- "return has1_1OrHigher ? %s : nullptr" % \
- entryPointExpr)
- elif f != "VK_VERSION_1_0":
- self.cgen.stmt( \
- "bool hasExt = resources->hasDeviceExtension(device, \"%s\")" % f)
- self.cgen.stmt("return hasExt ? %s : nullptr" % entryPointExpr)
- else:
- self.cgen.stmt("return %s" % entryPointExpr)
- self.cgen.endIf()
- prevFeature = f
-
- self.cgen.leftline("#endif")
-
- self.cgen.stmt("return nullptr")
- self.cgen.endBlock()
-
- self.module.appendImpl(self.cgen.swapCode())
-
- def isDeviceDispatch(self, api):
- # TODO(230793667): improve the heuristic and just use "cmdToFeatureType"
- return (len(api.parameters) > 0 and
- "VkDevice" == api.parameters[0].typeName) or (
- "VkCommandBuffer" == api.parameters[0].typeName and
- self.cmdToFeatureType.get(api.name, "") == "device")
diff --git a/codegen/vulkan/scripts/cereal/handlemap.py b/codegen/vulkan/scripts/cereal/handlemap.py
deleted file mode 100644
index 6360e37e..00000000
--- a/codegen/vulkan/scripts/cereal/handlemap.py
+++ /dev/null
@@ -1,264 +0,0 @@
-# Copyright (c) 2018 The Android Open Source Project
-# Copyright (c) 2018 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from .common.codegen import CodeGen
-from .common.vulkantypes import \
- VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, VulkanTypeIterator
-
-from .wrapperdefs import VulkanWrapperGenerator
-from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM_FOR_WRITE
-
-class HandleMapCodegen(VulkanTypeIterator):
- def __init__(self, cgen, inputVar, handlemapVarName, prefix, isHandleFunc):
- self.cgen = cgen
- self.inputVar = inputVar
- self.prefix = prefix
- self.handlemapVarName = handlemapVarName
-
- def makeAccess(varName, asPtr = True):
- return lambda t: self.cgen.generalAccess(t, parentVarName = varName, asPtr = asPtr)
-
- def makeLengthAccess(varName):
- return lambda t: self.cgen.generalLengthAccess(t, parentVarName = varName)
-
- def makeLengthAccessGuard(varName):
- return lambda t: self.cgen.generalLengthAccessGuard(t, parentVarName=varName)
-
- self.exprAccessor = makeAccess(self.inputVar)
- self.exprAccessorValue = makeAccess(self.inputVar, asPtr = False)
- self.lenAccessor = makeLengthAccess(self.inputVar)
- self.lenAccessorGuard = makeLengthAccessGuard(self.inputVar)
-
- self.checked = False
- self.isHandleFunc = isHandleFunc
-
- def needSkip(self, vulkanType):
- return False
-
- def makeCastExpr(self, vulkanType):
- return "(%s)" % (
- self.cgen.makeCTypeDecl(vulkanType, useParamName=False))
-
- def asNonConstCast(self, access, vulkanType):
- if vulkanType.staticArrExpr:
- casted = "%s(%s)" % (self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()), access)
- elif vulkanType.accessibleAsPointer():
- casted = "%s(%s)" % (self.makeCastExpr(vulkanType.getForNonConstAccess()), access)
- else:
- casted = "%s(%s)" % (self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()), access)
- return casted
-
- def onCheck(self, vulkanType):
- pass
-
- def endCheck(self, vulkanType):
- pass
-
- def onCompoundType(self, vulkanType):
-
- if self.needSkip(vulkanType):
- self.cgen.line("// TODO: Unsupported : %s" %
- self.cgen.makeCTypeDecl(vulkanType))
- return
- access = self.exprAccessor(vulkanType)
- lenAccess = self.lenAccessor(vulkanType)
- lenAccessGuard = self.lenAccessorGuard(vulkanType)
-
- isPtr = vulkanType.pointerIndirectionLevels > 0
-
- if lenAccessGuard is not None:
- self.cgen.beginIf(lenAccessGuard)
-
- if isPtr:
- self.cgen.beginIf(access)
-
- if lenAccess is not None:
-
- loopVar = "i"
- access = "%s + %s" % (access, loopVar)
- forInit = "uint32_t %s = 0" % loopVar
- forCond = "%s < (uint32_t)%s" % (loopVar, lenAccess)
- forIncr = "++%s" % loopVar
-
- self.cgen.beginFor(forInit, forCond, forIncr)
-
- accessCasted = self.asNonConstCast(access, vulkanType)
- self.cgen.funcCall(None, self.prefix + vulkanType.typeName,
- [self.handlemapVarName, accessCasted])
-
- if lenAccess is not None:
- self.cgen.endFor()
-
- if isPtr:
- self.cgen.endIf()
-
- if lenAccessGuard is not None:
- self.cgen.endIf()
-
- def onString(self, vulkanType):
- pass
-
- def onStringArray(self, vulkanType):
- pass
-
- def onStaticArr(self, vulkanType):
- if not self.isHandleFunc(vulkanType):
- return
-
- accessLhs = self.exprAccessor(vulkanType)
- lenAccess = self.lenAccessor(vulkanType)
-
- self.cgen.stmt("%s->mapHandles_%s(%s%s, %s)" % \
- (self.handlemapVarName, vulkanType.typeName,
- self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()),
- accessLhs, lenAccess))
-
- def onStructExtension(self, vulkanType):
- access = self.exprAccessor(vulkanType)
-
- castedAccessExpr = "(%s)(%s)" % ("void*", access)
- self.cgen.beginIf(access)
- self.cgen.funcCall(None, self.prefix + "extension_struct",
- [self.handlemapVarName, castedAccessExpr])
- self.cgen.endIf()
-
- def onPointer(self, vulkanType):
- if self.needSkip(vulkanType):
- return
-
- if not self.isHandleFunc(vulkanType):
- return
-
- access = self.exprAccessor(vulkanType)
- lenAccess = self.lenAccessor(vulkanType)
- lenAccess = "1" if lenAccess is None else lenAccess
-
- self.cgen.beginIf(access)
-
- self.cgen.stmt( \
- "%s->mapHandles_%s(%s%s, %s)" % \
- (self.handlemapVarName,
- vulkanType.typeName,
- self.makeCastExpr(vulkanType.getForNonConstAccess()),
- access,
- lenAccess))
-
- self.cgen.endIf()
-
- def onValue(self, vulkanType):
- if not self.isHandleFunc(vulkanType):
- return
- access = self.exprAccessor(vulkanType)
- self.cgen.stmt(
- "%s->mapHandles_%s(%s%s)" % \
- (self.handlemapVarName, vulkanType.typeName,
- self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()),
- access))
-
-class VulkanHandleMap(VulkanWrapperGenerator):
- def __init__(self, module, typeInfo):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
-
- self.codegen = CodeGen()
-
- self.handlemapPrefix = "handlemap_"
- self.toMapVar = "toMap"
- self.handlemapVarName = "handlemap"
- self.handlemapParam = \
- makeVulkanTypeSimple(False, "VulkanHandleMapping", 1,
- self.handlemapVarName)
- self.voidType = makeVulkanTypeSimple(False, "void", 0)
-
- self.handlemapCodegen = \
- HandleMapCodegen(
- None,
- self.toMapVar,
- self.handlemapVarName,
- self.handlemapPrefix,
- lambda vtype : typeInfo.isHandleType(vtype.typeName))
-
- self.knownDefs = {}
-
- self.extensionHandlemapPrototype = \
- VulkanAPI(self.handlemapPrefix + "extension_struct",
- self.voidType,
- [self.handlemapParam, STRUCT_EXTENSION_PARAM_FOR_WRITE])
-
- def onBegin(self,):
- VulkanWrapperGenerator.onBegin(self)
- self.module.appendImpl(self.codegen.makeFuncDecl(
- self.extensionHandlemapPrototype))
-
- def onGenType(self, typeXml, name, alias):
- VulkanWrapperGenerator.onGenType(self, typeXml, name, alias)
-
- if name in self.knownDefs:
- return
-
- category = self.typeInfo.categoryOf(name)
-
- if category in ["struct", "union"] and alias:
- self.module.appendHeader(
- self.codegen.makeFuncAlias(self.handlemapPrefix + name,
- self.handlemapPrefix + alias))
-
- if category in ["struct", "union"] and not alias:
-
- structInfo = self.typeInfo.structs[name]
-
- typeFromName = \
- lambda varname: \
- makeVulkanTypeSimple(varname == "from", name, 1, varname)
-
- handlemapParams = \
- [self.handlemapParam] + \
- list(map(typeFromName, [self.toMapVar]))
-
- handlemapPrototype = \
- VulkanAPI(self.handlemapPrefix + name,
- self.voidType,
- handlemapParams)
-
- def funcDefGenerator(cgen):
- self.handlemapCodegen.cgen = cgen
- for p in handlemapParams:
- cgen.stmt("(void)%s" % p.paramName)
- for member in structInfo.members:
- iterateVulkanType(self.typeInfo, member,
- self.handlemapCodegen)
-
- self.module.appendHeader(
- self.codegen.makeFuncDecl(handlemapPrototype))
- self.module.appendImpl(
- self.codegen.makeFuncImpl(handlemapPrototype, funcDefGenerator))
-
- def onGenCmd(self, cmdinfo, name, alias):
- VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
-
- def onEnd(self,):
- VulkanWrapperGenerator.onEnd(self)
-
- def forEachExtensionHandlemap(ext, castedAccess, cgen):
- cgen.funcCall(None, self.handlemapPrefix + ext.name,
- [self.handlemapVarName, castedAccess])
-
- self.module.appendImpl(
- self.codegen.makeFuncImpl(
- self.extensionHandlemapPrototype,
- lambda cgen: self.emitForEachStructExtension(
- cgen,
- self.voidType,
- STRUCT_EXTENSION_PARAM_FOR_WRITE,
- forEachExtensionHandlemap)))
diff --git a/codegen/vulkan/scripts/cereal/marshaling.py b/codegen/vulkan/scripts/cereal/marshaling.py
deleted file mode 100644
index 3427fed7..00000000
--- a/codegen/vulkan/scripts/cereal/marshaling.py
+++ /dev/null
@@ -1,1037 +0,0 @@
-# Copyright (c) 2018 The Android Open Source Project
-# Copyright (c) 2018 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from copy import copy
-import hashlib, sys
-
-from .common.codegen import CodeGen, VulkanAPIWrapper
-from .common.vulkantypes import \
- VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, VulkanTypeIterator, Atom, FuncExpr, FuncExprVal, FuncLambda
-
-from .wrapperdefs import VulkanWrapperGenerator
-from .wrapperdefs import VULKAN_STREAM_VAR_NAME
-from .wrapperdefs import ROOT_TYPE_VAR_NAME, ROOT_TYPE_PARAM
-from .wrapperdefs import STREAM_RET_TYPE
-from .wrapperdefs import MARSHAL_INPUT_VAR_NAME
-from .wrapperdefs import UNMARSHAL_INPUT_VAR_NAME
-from .wrapperdefs import PARAMETERS_MARSHALING
-from .wrapperdefs import PARAMETERS_MARSHALING_GUEST
-from .wrapperdefs import STYPE_OVERRIDE
-from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM_FOR_WRITE, EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME
-from .wrapperdefs import API_PREFIX_MARSHAL
-from .wrapperdefs import API_PREFIX_UNMARSHAL
-
-from .marshalingdefs import KNOWN_FUNCTION_OPCODES, CUSTOM_MARSHAL_TYPES
-
-class VulkanMarshalingCodegen(VulkanTypeIterator):
-
- def __init__(self,
- cgen,
- streamVarName,
- rootTypeVarName,
- inputVarName,
- marshalPrefix,
- direction = "write",
- forApiOutput = False,
- dynAlloc = False,
- mapHandles = True,
- handleMapOverwrites = False,
- doFiltering = True):
- self.cgen = cgen
- self.direction = direction
- self.processSimple = "write" if self.direction == "write" else "read"
- self.forApiOutput = forApiOutput
-
- self.checked = False
-
- self.streamVarName = streamVarName
- self.rootTypeVarName = rootTypeVarName
- self.inputVarName = inputVarName
- self.marshalPrefix = marshalPrefix
-
- self.exprAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.inputVarName, asPtr = True)
- self.exprValueAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.inputVarName, asPtr = False)
- self.exprPrimitiveValueAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.inputVarName, asPtr = False)
- self.lenAccessor = lambda t: self.cgen.generalLengthAccess(t, parentVarName = self.inputVarName)
- self.lenAccessorGuard = lambda t: self.cgen.generalLengthAccessGuard(
- t, parentVarName=self.inputVarName)
- self.filterVarAccessor = lambda t: self.cgen.filterVarAccess(t, parentVarName = self.inputVarName)
-
- self.dynAlloc = dynAlloc
- self.mapHandles = mapHandles
- self.handleMapOverwrites = handleMapOverwrites
- self.doFiltering = doFiltering
-
- def getTypeForStreaming(self, vulkanType):
- res = copy(vulkanType)
-
- if not vulkanType.accessibleAsPointer():
- res = res.getForAddressAccess()
-
- if vulkanType.staticArrExpr:
- res = res.getForAddressAccess()
-
- if self.direction == "write":
- return res
- else:
- return res.getForNonConstAccess()
-
- def makeCastExpr(self, vulkanType):
- return "(%s)" % (
- self.cgen.makeCTypeDecl(vulkanType, useParamName=False))
-
- def genStreamCall(self, vulkanType, toStreamExpr, sizeExpr):
- varname = self.streamVarName
- func = self.processSimple
- cast = self.makeCastExpr(self.getTypeForStreaming(vulkanType))
-
- self.cgen.stmt(
- "%s->%s(%s%s, %s)" % (varname, func, cast, toStreamExpr, sizeExpr))
-
- def genPrimitiveStreamCall(self, vulkanType, access):
- varname = self.streamVarName
-
- self.cgen.streamPrimitive(
- self.typeInfo,
- varname,
- access,
- vulkanType,
- direction=self.direction)
-
- def genHandleMappingCall(self, vulkanType, access, lenAccess):
-
- if lenAccess is None:
- lenAccess = "1"
- handle64Bytes = "8"
- else:
- handle64Bytes = "%s * 8" % lenAccess
-
- handle64Var = self.cgen.var()
- if lenAccess != "1":
- self.cgen.beginIf(lenAccess)
- self.cgen.stmt("uint64_t* %s" % handle64Var)
- self.cgen.stmt(
- "%s->alloc((void**)&%s, %s * 8)" % \
- (self.streamVarName, handle64Var, lenAccess))
- handle64VarAccess = handle64Var
- handle64VarType = \
- makeVulkanTypeSimple(False, "uint64_t", 1, paramName=handle64Var)
- else:
- self.cgen.stmt("uint64_t %s" % handle64Var)
- handle64VarAccess = "&%s" % handle64Var
- handle64VarType = \
- makeVulkanTypeSimple(False, "uint64_t", 0, paramName=handle64Var)
-
- if self.direction == "write":
- if self.handleMapOverwrites:
- self.cgen.stmt(
- "static_assert(8 == sizeof(%s), \"handle map overwrite requires %s to be 8 bytes long\")" % \
- (vulkanType.typeName, vulkanType.typeName))
- self.cgen.stmt(
- "%s->handleMapping()->mapHandles_%s((%s*)%s, %s)" %
- (self.streamVarName, vulkanType.typeName, vulkanType.typeName,
- access, lenAccess))
- self.genStreamCall(vulkanType, access, "8 * %s" % lenAccess)
- else:
- self.cgen.stmt(
- "%s->handleMapping()->mapHandles_%s_u64(%s, %s, %s)" %
- (self.streamVarName, vulkanType.typeName,
- access,
- handle64VarAccess, lenAccess))
- self.genStreamCall(handle64VarType, handle64VarAccess, handle64Bytes)
- else:
- self.genStreamCall(handle64VarType, handle64VarAccess, handle64Bytes)
- self.cgen.stmt(
- "%s->handleMapping()->mapHandles_u64_%s(%s, %s%s, %s)" %
- (self.streamVarName, vulkanType.typeName,
- handle64VarAccess,
- self.makeCastExpr(vulkanType.getForNonConstAccess()), access,
- lenAccess))
-
- if lenAccess != "1":
- self.cgen.endIf()
-
- def doAllocSpace(self, vulkanType):
- if self.dynAlloc and self.direction == "read":
- access = self.exprAccessor(vulkanType)
- lenAccess = self.lenAccessor(vulkanType)
- sizeof = self.cgen.sizeofExpr( \
- vulkanType.getForValueAccess())
- if lenAccess:
- bytesExpr = "%s * %s" % (lenAccess, sizeof)
- else:
- bytesExpr = sizeof
-
- self.cgen.stmt( \
- "%s->alloc((void**)&%s, %s)" %
- (self.streamVarName,
- access, bytesExpr))
-
- def getOptionalStringFeatureExpr(self, vulkanType):
- if vulkanType.optionalStr is not None:
- if vulkanType.optionalStr.startswith("streamFeature:"):
- splitted = vulkanType.optionalStr.split(":")
- featureExpr = "%s->getFeatureBits() & %s" % (self.streamVarName, splitted[1])
- return featureExpr
- return None
-
- def onCheck(self, vulkanType):
-
- if self.forApiOutput:
- return
-
- featureExpr = self.getOptionalStringFeatureExpr(vulkanType);
-
- self.checked = True
-
- access = self.exprAccessor(vulkanType)
-
- needConsistencyCheck = False
-
- self.cgen.line("// WARNING PTR CHECK")
- if (self.dynAlloc and self.direction == "read") or self.direction == "write":
- checkAccess = self.exprAccessor(vulkanType)
- addrExpr = "&" + checkAccess
- sizeExpr = self.cgen.sizeofExpr(vulkanType)
- else:
- checkName = "check_%s" % vulkanType.paramName
- self.cgen.stmt("%s %s" % (
- self.cgen.makeCTypeDecl(vulkanType, useParamName = False), checkName))
- checkAccess = checkName
- addrExpr = "&" + checkAccess
- sizeExpr = self.cgen.sizeofExpr(vulkanType)
- needConsistencyCheck = True
-
- if featureExpr is not None:
- self.cgen.beginIf(featureExpr)
-
- self.genPrimitiveStreamCall(
- vulkanType,
- checkAccess)
-
- if featureExpr is not None:
- self.cgen.endIf()
-
- if featureExpr is not None:
- self.cgen.beginIf("(!(%s) || %s)" % (featureExpr, access))
- else:
- self.cgen.beginIf(access)
-
- if needConsistencyCheck and featureExpr is None:
- self.cgen.beginIf("!(%s)" % checkName)
- self.cgen.stmt(
- "fprintf(stderr, \"fatal: %s inconsistent between guest and host\\n\")" % (access))
- self.cgen.endIf()
-
-
- def onCheckWithNullOptionalStringFeature(self, vulkanType):
- self.cgen.beginIf("%s->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT" % self.streamVarName)
- self.onCheck(vulkanType)
-
- def endCheckWithNullOptionalStringFeature(self, vulkanType):
- self.endCheck(vulkanType)
- self.cgen.endIf()
- self.cgen.beginElse()
-
- def finalCheckWithNullOptionalStringFeature(self, vulkanType):
- self.cgen.endElse()
-
- def endCheck(self, vulkanType):
-
- if self.checked:
- self.cgen.endIf()
- self.checked = False
-
- def genFilterFunc(self, filterfunc, env):
-
- def loop(expr, lambdaEnv={}):
- def do_func(expr):
- fnamestr = expr.name.name
- if "not" == fnamestr:
- return "!(%s)" % (loop(expr.args[0], lambdaEnv))
- if "eq" == fnamestr:
- return "(%s == %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv))
- if "and" == fnamestr:
- return "(%s && %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv))
- if "or" == fnamestr:
- return "(%s || %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv))
- if "bitwise_and" == fnamestr:
- return "(%s & %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv))
- if "getfield" == fnamestr:
- ptrlevels = get_ptrlevels(expr.args[0].val.name)
- if ptrlevels == 0:
- return "%s.%s" % (loop(expr.args[0], lambdaEnv), expr.args[1].val)
- else:
- return "(%s(%s)).%s" % ("*" * ptrlevels, loop(expr.args[0], lambdaEnv), expr.args[1].val)
-
- if "if" == fnamestr:
- return "((%s) ? (%s) : (%s))" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv), loop(expr.args[2], lambdaEnv))
-
- return "%s(%s)" % (fnamestr, ", ".join(map(lambda e: loop(e, lambdaEnv), expr.args)))
-
- def do_expratom(atomname, lambdaEnv= {}):
- if lambdaEnv.get(atomname, None) is not None:
- return atomname
-
- enventry = env.get(atomname, None)
- if None != enventry:
- return self.getEnvAccessExpr(atomname)
- return atomname
-
- def get_ptrlevels(atomname, lambdaEnv= {}):
- if lambdaEnv.get(atomname, None) is not None:
- return 0
-
- enventry = env.get(atomname, None)
- if None != enventry:
- return self.getPointerIndirectionLevels(atomname)
-
- return 0
-
- def do_exprval(expr, lambdaEnv= {}):
- expratom = expr.val
-
- if Atom == type(expratom):
- return do_expratom(expratom.name, lambdaEnv)
-
- return "%s" % expratom
-
- def do_lambda(expr, lambdaEnv= {}):
- params = expr.vs
- body = expr.body
- newEnv = {}
-
- for (k, v) in lambdaEnv.items():
- newEnv[k] = v
-
- for p in params:
- newEnv[p.name] = p.typ
-
- return "[](%s) { return %s; }" % (", ".join(list(map(lambda p: "%s %s" % (p.typ, p.name), params))), loop(body, lambdaEnv=newEnv))
-
- if FuncExpr == type(expr):
- return do_func(expr)
- if FuncLambda == type(expr):
- return do_lambda(expr)
- elif FuncExprVal == type(expr):
- return do_exprval(expr)
-
- return loop(filterfunc)
-
- def beginFilterGuard(self, vulkanType):
- if vulkanType.filterVar == None:
- return
-
- if self.doFiltering == False:
- return
-
- filterVarAccess = self.getEnvAccessExpr(vulkanType.filterVar)
-
- filterValsExpr = None
- filterFuncExpr = None
- filterExpr = None
-
- filterFeature = "%s->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT" % self.streamVarName
-
- if None != vulkanType.filterVals:
- filterValsExpr = " || ".join(map(lambda filterval: "(%s == %s)" % (filterval, filterVarAccess), vulkanType.filterVals))
-
- if None != vulkanType.filterFunc:
- filterFuncExpr = self.genFilterFunc(vulkanType.filterFunc, self.currentStructInfo.environment)
-
- if None != filterValsExpr and None != filterFuncExpr:
- filterExpr = "%s || %s" % (filterValsExpr, filterFuncExpr)
- elif None == filterValsExpr and None == filterFuncExpr:
- # Assume is bool
- self.cgen.beginIf(filterVarAccess)
- elif None != filterValsExpr:
- self.cgen.beginIf("(!(%s) || (%s))" % (filterFeature, filterValsExpr))
- elif None != filterFuncExpr:
- self.cgen.beginIf("(!(%s) || (%s))" % (filterFeature, filterFuncExpr))
-
- def endFilterGuard(self, vulkanType, cleanupExpr=None):
- if vulkanType.filterVar == None:
- return
-
- if self.doFiltering == False:
- return
-
- if cleanupExpr == None:
- self.cgen.endIf()
- else:
- self.cgen.endIf()
- self.cgen.beginElse()
- self.cgen.stmt(cleanupExpr)
- self.cgen.endElse()
-
- def getEnvAccessExpr(self, varName):
- parentEnvEntry = self.currentStructInfo.environment.get(varName, None)
-
- if parentEnvEntry != None:
- isParentMember = parentEnvEntry["structmember"]
-
- if isParentMember:
- envAccess = self.exprValueAccessor(list(filter(lambda member: member.paramName == varName, self.currentStructInfo.members))[0])
- else:
- envAccess = varName
- return envAccess
-
- return None
-
- def getPointerIndirectionLevels(self, varName):
- parentEnvEntry = self.currentStructInfo.environment.get(varName, None)
-
- if parentEnvEntry != None:
- isParentMember = parentEnvEntry["structmember"]
-
- if isParentMember:
- return list(filter(lambda member: member.paramName == varName, self.currentStructInfo.members))[0].pointerIndirectionLevels
- else:
- return 0
- return 0
-
- return 0
-
-
- def onCompoundType(self, vulkanType):
-
- access = self.exprAccessor(vulkanType)
- lenAccess = self.lenAccessor(vulkanType)
- lenAccessGuard = self.lenAccessorGuard(vulkanType)
-
- self.beginFilterGuard(vulkanType)
-
- if vulkanType.pointerIndirectionLevels > 0:
- self.doAllocSpace(vulkanType)
-
- if lenAccess is not None:
- if lenAccessGuard is not None:
- self.cgen.beginIf(lenAccessGuard)
- loopVar = "i"
- access = "%s + %s" % (access, loopVar)
- forInit = "uint32_t %s = 0" % loopVar
- forCond = "%s < (uint32_t)%s" % (loopVar, lenAccess)
- forIncr = "++%s" % loopVar
- self.cgen.beginFor(forInit, forCond, forIncr)
-
- accessWithCast = "%s(%s)" % (self.makeCastExpr(
- self.getTypeForStreaming(vulkanType)), access)
-
- callParams = [self.streamVarName, self.rootTypeVarName, accessWithCast]
-
- for (bindName, localName) in vulkanType.binds.items():
- callParams.append(self.getEnvAccessExpr(localName))
-
- self.cgen.funcCall(None, self.marshalPrefix + vulkanType.typeName,
- callParams)
-
- if lenAccess is not None:
- self.cgen.endFor()
- if lenAccessGuard is not None:
- self.cgen.endIf()
-
- if self.direction == "read":
- self.endFilterGuard(vulkanType, "%s = 0" % self.exprAccessor(vulkanType))
- else:
- self.endFilterGuard(vulkanType)
-
- def onString(self, vulkanType):
-
- access = self.exprAccessor(vulkanType)
-
- if self.direction == "write":
- self.cgen.stmt("%s->putString(%s)" % (self.streamVarName, access))
- else:
- castExpr = \
- self.makeCastExpr( \
- self.getTypeForStreaming( \
- vulkanType.getForAddressAccess()))
-
- self.cgen.stmt( \
- "%s->loadStringInPlace(%s&%s)" % (self.streamVarName, castExpr, access))
-
- def onStringArray(self, vulkanType):
-
- access = self.exprAccessor(vulkanType)
- lenAccess = self.lenAccessor(vulkanType)
-
- if self.direction == "write":
- self.cgen.stmt("saveStringArray(%s, %s, %s)" % (self.streamVarName,
- access, lenAccess))
- else:
- castExpr = \
- self.makeCastExpr( \
- self.getTypeForStreaming( \
- vulkanType.getForAddressAccess()))
-
- self.cgen.stmt("%s->loadStringArrayInPlace(%s&%s)" % (self.streamVarName, castExpr, access))
-
- def onStaticArr(self, vulkanType):
- access = self.exprValueAccessor(vulkanType)
- lenAccess = self.lenAccessor(vulkanType)
- finalLenExpr = "%s * %s" % (lenAccess, self.cgen.sizeofExpr(vulkanType))
- self.genStreamCall(vulkanType, access, finalLenExpr)
-
- # Old version VkEncoder may have some sType values conflict with VkDecoder
- # of new versions. For host decoder, it should not carry the incorrect old
- # sType values to the |forUnmarshaling| struct. Instead it should overwrite
- # the sType value.
- def overwriteSType(self, vulkanType):
- if self.direction == "read":
- sTypeParam = copy(vulkanType)
- sTypeParam.paramName = "sType"
- sTypeAccess = self.exprAccessor(sTypeParam)
-
- typeName = vulkanType.parent.typeName
- if typeName in STYPE_OVERRIDE:
- self.cgen.stmt("%s = %s" %
- (sTypeAccess, STYPE_OVERRIDE[typeName]))
-
- def onStructExtension(self, vulkanType):
- self.overwriteSType(vulkanType)
-
- sTypeParam = copy(vulkanType)
- sTypeParam.paramName = "sType"
-
- access = self.exprAccessor(vulkanType)
- sizeVar = "%s_size" % vulkanType.paramName
-
- if self.direction == "read":
- castedAccessExpr = "(%s)(%s)" % ("void*", access)
- else:
- castedAccessExpr = access
-
- sTypeAccess = self.exprAccessor(sTypeParam)
- self.cgen.beginIf("%s == VK_STRUCTURE_TYPE_MAX_ENUM" %
- self.rootTypeVarName)
- self.cgen.stmt("%s = %s" % (self.rootTypeVarName, sTypeAccess))
- self.cgen.endIf()
-
- if self.direction == "read" and self.dynAlloc:
- self.cgen.stmt("size_t %s" % sizeVar)
- self.cgen.stmt("%s = %s->getBe32()" % \
- (sizeVar, self.streamVarName))
- self.cgen.stmt("%s = nullptr" % access)
- self.cgen.beginIf(sizeVar)
- self.cgen.stmt( \
- "%s->alloc((void**)&%s, sizeof(VkStructureType))" %
- (self.streamVarName, access))
-
- self.genStreamCall(vulkanType, access, "sizeof(VkStructureType)")
- self.cgen.stmt("VkStructureType extType = *(VkStructureType*)(%s)" % access)
- self.cgen.stmt( \
- "%s->alloc((void**)&%s, %s(%s->getFeatureBits(), %s, %s))" %
- (self.streamVarName, access, EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME, self.streamVarName, self.rootTypeVarName, access))
- self.cgen.stmt("*(VkStructureType*)%s = extType" % access)
-
- self.cgen.funcCall(None, self.marshalPrefix + "extension_struct",
- [self.streamVarName, self.rootTypeVarName, castedAccessExpr])
- self.cgen.endIf()
- else:
-
- self.cgen.funcCall(None, self.marshalPrefix + "extension_struct",
- [self.streamVarName, self.rootTypeVarName, castedAccessExpr])
-
-
- def onPointer(self, vulkanType):
- access = self.exprAccessor(vulkanType)
-
- lenAccess = self.lenAccessor(vulkanType)
- lenAccessGuard = self.lenAccessorGuard(vulkanType)
-
- self.beginFilterGuard(vulkanType)
- self.doAllocSpace(vulkanType)
-
- if vulkanType.filterVar != None:
- print("onPointer Needs filter: %s filterVar %s" % (access, vulkanType.filterVar))
-
- if vulkanType.isHandleType() and self.mapHandles:
- self.genHandleMappingCall(vulkanType, access, lenAccess)
- else:
- if self.typeInfo.isNonAbiPortableType(vulkanType.typeName):
- if lenAccess is not None:
- if lenAccessGuard is not None:
- self.cgen.beginIf(lenAccessGuard)
- self.cgen.beginFor("uint32_t i = 0", "i < (uint32_t)%s" % lenAccess, "++i")
- self.genPrimitiveStreamCall(vulkanType.getForValueAccess(), "%s[i]" % access)
- self.cgen.endFor()
- if lenAccessGuard is not None:
- self.cgen.endIf()
- else:
- self.genPrimitiveStreamCall(vulkanType.getForValueAccess(), "(*%s)" % access)
- else:
- if lenAccess is not None:
- finalLenExpr = "%s * %s" % (
- lenAccess, self.cgen.sizeofExpr(vulkanType.getForValueAccess()))
- else:
- finalLenExpr = "%s" % (
- self.cgen.sizeofExpr(vulkanType.getForValueAccess()))
- self.genStreamCall(vulkanType, access, finalLenExpr)
-
- if self.direction == "read":
- self.endFilterGuard(vulkanType, "%s = 0" % access)
- else:
- self.endFilterGuard(vulkanType)
-
- def onValue(self, vulkanType):
- self.beginFilterGuard(vulkanType)
-
- if vulkanType.isHandleType() and self.mapHandles:
- access = self.exprAccessor(vulkanType)
- if vulkanType.filterVar != None:
- print("onValue Needs filter: %s filterVar %s" % (access, vulkanType.filterVar))
- self.genHandleMappingCall(
- vulkanType.getForAddressAccess(), access, "1")
- elif self.typeInfo.isNonAbiPortableType(vulkanType.typeName):
- access = self.exprPrimitiveValueAccessor(vulkanType)
- self.genPrimitiveStreamCall(vulkanType, access)
- else:
- access = self.exprAccessor(vulkanType)
- self.genStreamCall(vulkanType, access, self.cgen.sizeofExpr(vulkanType))
-
- self.endFilterGuard(vulkanType)
-
- def streamLetParameter(self, structInfo, letParamInfo):
- filterFeature = "%s->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT" % self.streamVarName
- self.cgen.stmt("%s %s = 1" % (letParamInfo.typeName, letParamInfo.paramName))
-
- self.cgen.beginIf(filterFeature)
-
- if self.direction == "write":
- bodyExpr = self.currentStructInfo.environment[letParamInfo.paramName]["body"]
- self.cgen.stmt("%s = %s" % (letParamInfo.paramName, self.genFilterFunc(bodyExpr, self.currentStructInfo.environment)))
-
- self.genPrimitiveStreamCall(letParamInfo, letParamInfo.paramName)
-
- self.cgen.endIf()
-
-
-class VulkanMarshaling(VulkanWrapperGenerator):
-
- def __init__(self, module, typeInfo, variant="host"):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
-
- self.cgenHeader = CodeGen()
- self.cgenImpl = CodeGen()
-
- self.variant = variant
-
- self.currentFeature = None
- self.apiOpcodes = {}
- self.dynAlloc = self.variant != "guest"
-
- if self.variant == "guest":
- self.marshalingParams = PARAMETERS_MARSHALING_GUEST
- else:
- self.marshalingParams = PARAMETERS_MARSHALING
-
- self.writeCodegen = \
- VulkanMarshalingCodegen(
- None,
- VULKAN_STREAM_VAR_NAME,
- ROOT_TYPE_VAR_NAME,
- MARSHAL_INPUT_VAR_NAME,
- API_PREFIX_MARSHAL,
- direction = "write")
-
- self.readCodegen = \
- VulkanMarshalingCodegen(
- None,
- VULKAN_STREAM_VAR_NAME,
- ROOT_TYPE_VAR_NAME,
- UNMARSHAL_INPUT_VAR_NAME,
- API_PREFIX_UNMARSHAL,
- direction = "read",
- dynAlloc=self.dynAlloc)
-
- self.knownDefs = {}
-
- # Begin Vulkan API opcodes from something high
- # that is not going to interfere with renderControl
- # opcodes
- self.beginOpcodeOld = 20000
- self.endOpcodeOld = 30000
-
- self.beginOpcode = 200000000
- self.endOpcode = 300000000
- self.knownOpcodes = set()
-
- self.extensionMarshalPrototype = \
- VulkanAPI(API_PREFIX_MARSHAL + "extension_struct",
- STREAM_RET_TYPE,
- self.marshalingParams +
- [STRUCT_EXTENSION_PARAM])
-
- self.extensionUnmarshalPrototype = \
- VulkanAPI(API_PREFIX_UNMARSHAL + "extension_struct",
- STREAM_RET_TYPE,
- self.marshalingParams +
- [STRUCT_EXTENSION_PARAM_FOR_WRITE])
-
- def onBegin(self,):
- VulkanWrapperGenerator.onBegin(self)
- self.module.appendImpl(self.cgenImpl.makeFuncDecl(self.extensionMarshalPrototype))
- self.module.appendImpl(self.cgenImpl.makeFuncDecl(self.extensionUnmarshalPrototype))
-
- def onBeginFeature(self, featureName, featureType):
- VulkanWrapperGenerator.onBeginFeature(self, featureName, featureType)
- self.currentFeature = featureName
-
- def onGenType(self, typeXml, name, alias):
- VulkanWrapperGenerator.onGenType(self, typeXml, name, alias)
-
- if name in self.knownDefs:
- return
-
- category = self.typeInfo.categoryOf(name)
-
- if category in ["struct", "union"] and alias:
- self.module.appendHeader(
- self.cgenHeader.makeFuncAlias(API_PREFIX_MARSHAL + name,
- API_PREFIX_MARSHAL + alias))
- self.module.appendHeader(
- self.cgenHeader.makeFuncAlias(API_PREFIX_UNMARSHAL + name,
- API_PREFIX_UNMARSHAL + alias))
-
- if category in ["struct", "union"] and not alias:
-
- structInfo = self.typeInfo.structs[name]
-
- marshalParams = self.marshalingParams + \
- [makeVulkanTypeSimple(True, name, 1, MARSHAL_INPUT_VAR_NAME)]
-
- freeParams = []
- letParams = []
-
- for (envname, bindingInfo) in list(sorted(structInfo.environment.items(), key = lambda kv: kv[0])):
- if None == bindingInfo["binding"]:
- freeParams.append(makeVulkanTypeSimple(True, bindingInfo["type"], 0, envname))
- else:
- if not bindingInfo["structmember"]:
- letParams.append(makeVulkanTypeSimple(True, bindingInfo["type"], 0, envname))
-
- marshalPrototype = \
- VulkanAPI(API_PREFIX_MARSHAL + name,
- STREAM_RET_TYPE,
- marshalParams + freeParams)
-
- marshalPrototypeNoFilter = \
- VulkanAPI(API_PREFIX_MARSHAL + name,
- STREAM_RET_TYPE,
- marshalParams)
-
- def structMarshalingCustom(cgen):
- self.writeCodegen.cgen = cgen
- self.writeCodegen.currentStructInfo = structInfo
- self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME)
-
- marshalingCode = \
- CUSTOM_MARSHAL_TYPES[name]["common"] + \
- CUSTOM_MARSHAL_TYPES[name]["marshaling"].format(
- streamVarName=self.writeCodegen.streamVarName,
- rootTypeVarName=self.writeCodegen.rootTypeVarName,
- inputVarName=self.writeCodegen.inputVarName,
- newInputVarName=self.writeCodegen.inputVarName + "_new")
- for line in marshalingCode.split('\n'):
- cgen.line(line)
-
- def structMarshalingDef(cgen):
- self.writeCodegen.cgen = cgen
- self.writeCodegen.currentStructInfo = structInfo
- self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME)
-
- if category == "struct":
- # marshal 'let' parameters first
- for letp in letParams:
- self.writeCodegen.streamLetParameter(self.typeInfo, letp)
-
- for member in structInfo.members:
- iterateVulkanType(self.typeInfo, member, self.writeCodegen)
- if category == "union":
- iterateVulkanType(self.typeInfo, structInfo.members[0], self.writeCodegen)
-
- def structMarshalingDefNoFilter(cgen):
- self.writeCodegen.cgen = cgen
- self.writeCodegen.currentStructInfo = structInfo
- self.writeCodegen.doFiltering = False
- self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME)
-
- if category == "struct":
- # marshal 'let' parameters first
- for letp in letParams:
- self.writeCodegen.streamLetParameter(self.typeInfo, letp)
-
- for member in structInfo.members:
- iterateVulkanType(self.typeInfo, member, self.writeCodegen)
- if category == "union":
- iterateVulkanType(self.typeInfo, structInfo.members[0], self.writeCodegen)
- self.writeCodegen.doFiltering = True
-
- self.module.appendHeader(
- self.cgenHeader.makeFuncDecl(marshalPrototype))
-
- if name in CUSTOM_MARSHAL_TYPES:
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- marshalPrototype, structMarshalingCustom))
- else:
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- marshalPrototype, structMarshalingDef))
-
- if freeParams != []:
- self.module.appendHeader(
- self.cgenHeader.makeFuncDecl(marshalPrototypeNoFilter))
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- marshalPrototypeNoFilter, structMarshalingDefNoFilter))
-
- unmarshalPrototype = \
- VulkanAPI(API_PREFIX_UNMARSHAL + name,
- STREAM_RET_TYPE,
- self.marshalingParams + [makeVulkanTypeSimple(False, name, 1, UNMARSHAL_INPUT_VAR_NAME)] + freeParams)
-
- unmarshalPrototypeNoFilter = \
- VulkanAPI(API_PREFIX_UNMARSHAL + name,
- STREAM_RET_TYPE,
- self.marshalingParams + [makeVulkanTypeSimple(False, name, 1, UNMARSHAL_INPUT_VAR_NAME)])
-
- def structUnmarshalingCustom(cgen):
- self.readCodegen.cgen = cgen
- self.readCodegen.currentStructInfo = structInfo
- self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME)
-
- unmarshalingCode = \
- CUSTOM_MARSHAL_TYPES[name]["common"] + \
- CUSTOM_MARSHAL_TYPES[name]["unmarshaling"].format(
- streamVarName=self.readCodegen.streamVarName,
- rootTypeVarName=self.readCodegen.rootTypeVarName,
- inputVarName=self.readCodegen.inputVarName,
- newInputVarName=self.readCodegen.inputVarName + "_new")
- for line in unmarshalingCode.split('\n'):
- cgen.line(line)
-
- def structUnmarshalingDef(cgen):
- self.readCodegen.cgen = cgen
- self.readCodegen.currentStructInfo = structInfo
- self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME)
-
- if category == "struct":
- # unmarshal 'let' parameters first
- for letp in letParams:
- self.readCodegen.streamLetParameter(self.typeInfo, letp)
-
- for member in structInfo.members:
- iterateVulkanType(self.typeInfo, member, self.readCodegen)
- if category == "union":
- iterateVulkanType(self.typeInfo, structInfo.members[0], self.readCodegen)
-
- def structUnmarshalingDefNoFilter(cgen):
- self.readCodegen.cgen = cgen
- self.readCodegen.currentStructInfo = structInfo
- self.readCodegen.doFiltering = False
- self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME)
-
- if category == "struct":
- # unmarshal 'let' parameters first
- for letp in letParams:
- iterateVulkanType(self.typeInfo, letp, self.readCodegen)
- for member in structInfo.members:
- iterateVulkanType(self.typeInfo, member, self.readCodegen)
- if category == "union":
- iterateVulkanType(self.typeInfo, structInfo.members[0], self.readCodegen)
- self.readCodegen.doFiltering = True
-
- self.module.appendHeader(
- self.cgenHeader.makeFuncDecl(unmarshalPrototype))
-
- if name in CUSTOM_MARSHAL_TYPES:
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- unmarshalPrototype, structUnmarshalingCustom))
- else:
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- unmarshalPrototype, structUnmarshalingDef))
-
- if freeParams != []:
- self.module.appendHeader(
- self.cgenHeader.makeFuncDecl(unmarshalPrototypeNoFilter))
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- unmarshalPrototypeNoFilter, structUnmarshalingDefNoFilter))
-
- def onGenCmd(self, cmdinfo, name, alias):
- VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
- if name in KNOWN_FUNCTION_OPCODES:
- opcode = KNOWN_FUNCTION_OPCODES[name]
- else:
- hashCode = hashlib.sha256(name.encode()).hexdigest()[:8]
- hashInt = int(hashCode, 16)
- opcode = self.beginOpcode + hashInt % (self.endOpcode - self.beginOpcode)
- hasHashCollision = False
- while opcode in self.knownOpcodes:
- hasHashCollision = True
- opcode += 1
- if hasHashCollision:
- print("Hash collision occurred on function '{}'. "
- "Please add the following line to marshalingdefs.py:".format(name), file=sys.stderr)
- print("----------------------", file=sys.stderr)
- print(" \"{}\": {},".format(name, opcode), file=sys.stderr)
- print("----------------------", file=sys.stderr)
-
- self.module.appendHeader(
- "#define OP_%s %d\n" % (name, opcode))
- self.apiOpcodes[name] = (opcode, self.currentFeature)
- self.knownOpcodes.add(opcode)
-
- def doExtensionStructMarshalingCodegen(self, cgen, retType, extParam, forEach, funcproto, direction):
- accessVar = "structAccess"
- sizeVar = "currExtSize"
- cgen.stmt("VkInstanceCreateInfo* %s = (VkInstanceCreateInfo*)(%s)" % (accessVar, extParam.paramName))
- cgen.stmt("size_t %s = %s(%s->getFeatureBits(), %s, %s)" % (sizeVar,
- EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME, VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, extParam.paramName))
-
- cgen.beginIf("!%s && %s" % (sizeVar, extParam.paramName))
-
- cgen.line("// unknown struct extension; skip and call on its pNext field");
- cgen.funcCall(None, funcproto.name, [
- "vkStream", ROOT_TYPE_VAR_NAME, "(void*)%s->pNext" % accessVar])
- cgen.stmt("return")
-
- cgen.endIf()
- cgen.beginElse()
-
- cgen.line("// known or null extension struct")
-
- if direction == "write":
- cgen.stmt("vkStream->putBe32(%s)" % sizeVar)
- elif not self.dynAlloc:
- cgen.stmt("vkStream->getBe32()");
-
- cgen.beginIf("!%s" % (sizeVar))
- cgen.line("// exit if this was a null extension struct (size == 0 in this branch)")
- cgen.stmt("return")
- cgen.endIf()
-
- cgen.endIf()
-
- # Now we can do stream stuff
- if direction == "write":
- cgen.stmt("vkStream->write(%s, sizeof(VkStructureType))" % extParam.paramName)
- elif not self.dynAlloc:
- cgen.stmt("uint64_t pNext_placeholder")
- placeholderAccess = "(&pNext_placeholder)"
- cgen.stmt("vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType))")
- cgen.stmt("(void)pNext_placeholder")
-
- def fatalDefault(cgen):
- cgen.line("// fatal; the switch is only taken if the extension struct is known");
- cgen.stmt("abort()")
- pass
-
- self.emitForEachStructExtension(
- cgen,
- retType,
- extParam,
- forEach,
- defaultEmit=fatalDefault,
- rootTypeVar=ROOT_TYPE_PARAM)
-
- def onEnd(self,):
- VulkanWrapperGenerator.onEnd(self)
-
- def forEachExtensionMarshal(ext, castedAccess, cgen):
- cgen.funcCall(None, API_PREFIX_MARSHAL + ext.name,
- [VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, castedAccess])
-
- def forEachExtensionUnmarshal(ext, castedAccess, cgen):
- cgen.funcCall(None, API_PREFIX_UNMARSHAL + ext.name,
- [VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, castedAccess])
-
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- self.extensionMarshalPrototype,
- lambda cgen: self.doExtensionStructMarshalingCodegen(
- cgen,
- STREAM_RET_TYPE,
- STRUCT_EXTENSION_PARAM,
- forEachExtensionMarshal,
- self.extensionMarshalPrototype,
- "write")))
-
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- self.extensionUnmarshalPrototype,
- lambda cgen: self.doExtensionStructMarshalingCodegen(
- cgen,
- STREAM_RET_TYPE,
- STRUCT_EXTENSION_PARAM_FOR_WRITE,
- forEachExtensionUnmarshal,
- self.extensionUnmarshalPrototype,
- "read")))
-
- opcode2stringPrototype = \
- VulkanAPI("api_opcode_to_string",
- makeVulkanTypeSimple(True, "char", 1, "none"),
- [ makeVulkanTypeSimple(True, "uint32_t", 0, "opcode") ])
-
- self.module.appendHeader(
- self.cgenHeader.makeFuncDecl(opcode2stringPrototype))
-
- def emitOpcode2StringImpl(apiOpcodes, cgen):
- cgen.line("switch(opcode)")
- cgen.beginBlock()
-
- currFeature = None
-
- for (name, (opcodeNum, feature)) in sorted(apiOpcodes.items(), key = lambda x : x[1][0]):
- if not currFeature:
- cgen.leftline("#ifdef %s" % feature)
- currFeature = feature
-
- if currFeature and feature != currFeature:
- cgen.leftline("#endif")
- cgen.leftline("#ifdef %s" % feature)
- currFeature = feature
-
- cgen.line("case OP_%s:" % name)
- cgen.beginBlock()
- cgen.stmt("return \"OP_%s\"" % name)
- cgen.endBlock()
-
- if currFeature:
- cgen.leftline("#endif")
-
- cgen.line("default:")
- cgen.beginBlock()
- cgen.stmt("return \"OP_UNKNOWN_API_CALL\"")
- cgen.endBlock()
-
- cgen.endBlock()
-
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- opcode2stringPrototype,
- lambda cgen: emitOpcode2StringImpl(self.apiOpcodes, cgen)))
-
- self.module.appendHeader(
- "#define OP_vkFirst_old %d\n" % (self.beginOpcodeOld))
- self.module.appendHeader(
- "#define OP_vkLast_old %d\n" % (self.endOpcodeOld))
- self.module.appendHeader(
- "#define OP_vkFirst %d\n" % (self.beginOpcode))
- self.module.appendHeader(
- "#define OP_vkLast %d\n" % (self.endOpcode))
diff --git a/codegen/vulkan/scripts/cereal/marshalingdefs.py b/codegen/vulkan/scripts/cereal/marshalingdefs.py
deleted file mode 100644
index 88791f68..00000000
--- a/codegen/vulkan/scripts/cereal/marshalingdefs.py
+++ /dev/null
@@ -1,528 +0,0 @@
-# Copyright (c) 2021 The Android Open Source Project
-# Copyright (c) 2021 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-KNOWN_FUNCTION_OPCODES = {
- "vkCreateInstance": 20000,
- "vkDestroyInstance": 20001,
- "vkEnumeratePhysicalDevices": 20002,
- "vkGetPhysicalDeviceFeatures": 20003,
- "vkGetPhysicalDeviceFormatProperties": 20004,
- "vkGetPhysicalDeviceImageFormatProperties": 20005,
- "vkGetPhysicalDeviceProperties": 20006,
- "vkGetPhysicalDeviceQueueFamilyProperties": 20007,
- "vkGetPhysicalDeviceMemoryProperties": 20008,
- "vkGetInstanceProcAddr": 20009,
- "vkGetDeviceProcAddr": 20010,
- "vkCreateDevice": 20011,
- "vkDestroyDevice": 20012,
- "vkEnumerateInstanceExtensionProperties": 20013,
- "vkEnumerateDeviceExtensionProperties": 20014,
- "vkEnumerateInstanceLayerProperties": 20015,
- "vkEnumerateDeviceLayerProperties": 20016,
- "vkGetDeviceQueue": 20017,
- "vkQueueSubmit": 20018,
- "vkQueueWaitIdle": 20019,
- "vkDeviceWaitIdle": 20020,
- "vkAllocateMemory": 20021,
- "vkFreeMemory": 20022,
- "vkMapMemory": 20023,
- "vkUnmapMemory": 20024,
- "vkFlushMappedMemoryRanges": 20025,
- "vkInvalidateMappedMemoryRanges": 20026,
- "vkGetDeviceMemoryCommitment": 20027,
- "vkBindBufferMemory": 20028,
- "vkBindImageMemory": 20029,
- "vkGetBufferMemoryRequirements": 20030,
- "vkGetImageMemoryRequirements": 20031,
- "vkGetImageSparseMemoryRequirements": 20032,
- "vkGetPhysicalDeviceSparseImageFormatProperties": 20033,
- "vkQueueBindSparse": 20034,
- "vkCreateFence": 20035,
- "vkDestroyFence": 20036,
- "vkResetFences": 20037,
- "vkGetFenceStatus": 20038,
- "vkWaitForFences": 20039,
- "vkCreateSemaphore": 20040,
- "vkDestroySemaphore": 20041,
- "vkCreateEvent": 20042,
- "vkDestroyEvent": 20043,
- "vkGetEventStatus": 20044,
- "vkSetEvent": 20045,
- "vkResetEvent": 20046,
- "vkCreateQueryPool": 20047,
- "vkDestroyQueryPool": 20048,
- "vkGetQueryPoolResults": 20049,
- "vkCreateBuffer": 20050,
- "vkDestroyBuffer": 20051,
- "vkCreateBufferView": 20052,
- "vkDestroyBufferView": 20053,
- "vkCreateImage": 20054,
- "vkDestroyImage": 20055,
- "vkGetImageSubresourceLayout": 20056,
- "vkCreateImageView": 20057,
- "vkDestroyImageView": 20058,
- "vkCreateShaderModule": 20059,
- "vkDestroyShaderModule": 20060,
- "vkCreatePipelineCache": 20061,
- "vkDestroyPipelineCache": 20062,
- "vkGetPipelineCacheData": 20063,
- "vkMergePipelineCaches": 20064,
- "vkCreateGraphicsPipelines": 20065,
- "vkCreateComputePipelines": 20066,
- "vkDestroyPipeline": 20067,
- "vkCreatePipelineLayout": 20068,
- "vkDestroyPipelineLayout": 20069,
- "vkCreateSampler": 20070,
- "vkDestroySampler": 20071,
- "vkCreateDescriptorSetLayout": 20072,
- "vkDestroyDescriptorSetLayout": 20073,
- "vkCreateDescriptorPool": 20074,
- "vkDestroyDescriptorPool": 20075,
- "vkResetDescriptorPool": 20076,
- "vkAllocateDescriptorSets": 20077,
- "vkFreeDescriptorSets": 20078,
- "vkUpdateDescriptorSets": 20079,
- "vkCreateFramebuffer": 20080,
- "vkDestroyFramebuffer": 20081,
- "vkCreateRenderPass": 20082,
- "vkDestroyRenderPass": 20083,
- "vkGetRenderAreaGranularity": 20084,
- "vkCreateCommandPool": 20085,
- "vkDestroyCommandPool": 20086,
- "vkResetCommandPool": 20087,
- "vkAllocateCommandBuffers": 20088,
- "vkFreeCommandBuffers": 20089,
- "vkBeginCommandBuffer": 20090,
- "vkEndCommandBuffer": 20091,
- "vkResetCommandBuffer": 20092,
- "vkCmdBindPipeline": 20093,
- "vkCmdSetViewport": 20094,
- "vkCmdSetScissor": 20095,
- "vkCmdSetLineWidth": 20096,
- "vkCmdSetDepthBias": 20097,
- "vkCmdSetBlendConstants": 20098,
- "vkCmdSetDepthBounds": 20099,
- "vkCmdSetStencilCompareMask": 20100,
- "vkCmdSetStencilWriteMask": 20101,
- "vkCmdSetStencilReference": 20102,
- "vkCmdBindDescriptorSets": 20103,
- "vkCmdBindIndexBuffer": 20104,
- "vkCmdBindVertexBuffers": 20105,
- "vkCmdDraw": 20106,
- "vkCmdDrawIndexed": 20107,
- "vkCmdDrawIndirect": 20108,
- "vkCmdDrawIndexedIndirect": 20109,
- "vkCmdDispatch": 20110,
- "vkCmdDispatchIndirect": 20111,
- "vkCmdCopyBuffer": 20112,
- "vkCmdCopyImage": 20113,
- "vkCmdBlitImage": 20114,
- "vkCmdCopyBufferToImage": 20115,
- "vkCmdCopyImageToBuffer": 20116,
- "vkCmdUpdateBuffer": 20117,
- "vkCmdFillBuffer": 20118,
- "vkCmdClearColorImage": 20119,
- "vkCmdClearDepthStencilImage": 20120,
- "vkCmdClearAttachments": 20121,
- "vkCmdResolveImage": 20122,
- "vkCmdSetEvent": 20123,
- "vkCmdResetEvent": 20124,
- "vkCmdWaitEvents": 20125,
- "vkCmdPipelineBarrier": 20126,
- "vkCmdBeginQuery": 20127,
- "vkCmdEndQuery": 20128,
- "vkCmdResetQueryPool": 20129,
- "vkCmdWriteTimestamp": 20130,
- "vkCmdCopyQueryPoolResults": 20131,
- "vkCmdPushConstants": 20132,
- "vkCmdBeginRenderPass": 20133,
- "vkCmdNextSubpass": 20134,
- "vkCmdEndRenderPass": 20135,
- "vkCmdExecuteCommands": 20136,
- "vkEnumerateInstanceVersion": 20137,
- "vkBindBufferMemory2": 20138,
- "vkBindImageMemory2": 20139,
- "vkGetDeviceGroupPeerMemoryFeatures": 20140,
- "vkCmdSetDeviceMask": 20141,
- "vkCmdDispatchBase": 20142,
- "vkEnumeratePhysicalDeviceGroups": 20143,
- "vkGetImageMemoryRequirements2": 20144,
- "vkGetBufferMemoryRequirements2": 20145,
- "vkGetImageSparseMemoryRequirements2": 20146,
- "vkGetPhysicalDeviceFeatures2": 20147,
- "vkGetPhysicalDeviceProperties2": 20148,
- "vkGetPhysicalDeviceFormatProperties2": 20149,
- "vkGetPhysicalDeviceImageFormatProperties2": 20150,
- "vkGetPhysicalDeviceQueueFamilyProperties2": 20151,
- "vkGetPhysicalDeviceMemoryProperties2": 20152,
- "vkGetPhysicalDeviceSparseImageFormatProperties2": 20153,
- "vkTrimCommandPool": 20154,
- "vkGetDeviceQueue2": 20155,
- "vkCreateSamplerYcbcrConversion": 20156,
- "vkDestroySamplerYcbcrConversion": 20157,
- "vkCreateDescriptorUpdateTemplate": 20158,
- "vkDestroyDescriptorUpdateTemplate": 20159,
- "vkUpdateDescriptorSetWithTemplate": 20160,
- "vkGetPhysicalDeviceExternalBufferProperties": 20161,
- "vkGetPhysicalDeviceExternalFenceProperties": 20162,
- "vkGetPhysicalDeviceExternalSemaphoreProperties": 20163,
- "vkGetDescriptorSetLayoutSupport": 20164,
- "vkDestroySurfaceKHR": 20165,
- "vkGetPhysicalDeviceSurfaceSupportKHR": 20166,
- "vkGetPhysicalDeviceSurfaceCapabilitiesKHR": 20167,
- "vkGetPhysicalDeviceSurfaceFormatsKHR": 20168,
- "vkGetPhysicalDeviceSurfacePresentModesKHR": 20169,
- "vkCreateSwapchainKHR": 20170,
- "vkDestroySwapchainKHR": 20171,
- "vkGetSwapchainImagesKHR": 20172,
- "vkAcquireNextImageKHR": 20173,
- "vkQueuePresentKHR": 20174,
- "vkGetDeviceGroupPresentCapabilitiesKHR": 20175,
- "vkGetDeviceGroupSurfacePresentModesKHR": 20176,
- "vkGetPhysicalDevicePresentRectanglesKHR": 20177,
- "vkAcquireNextImage2KHR": 20178,
- "vkGetPhysicalDeviceDisplayPropertiesKHR": 20179,
- "vkGetPhysicalDeviceDisplayPlanePropertiesKHR": 20180,
- "vkGetDisplayPlaneSupportedDisplaysKHR": 20181,
- "vkGetDisplayModePropertiesKHR": 20182,
- "vkCreateDisplayModeKHR": 20183,
- "vkGetDisplayPlaneCapabilitiesKHR": 20184,
- "vkCreateDisplayPlaneSurfaceKHR": 20185,
- "vkCreateSharedSwapchainsKHR": 20186,
- "vkCreateXlibSurfaceKHR": 20187,
- "vkGetPhysicalDeviceXlibPresentationSupportKHR": 20188,
- "vkCreateXcbSurfaceKHR": 20189,
- "vkGetPhysicalDeviceXcbPresentationSupportKHR": 20190,
- "vkCreateWaylandSurfaceKHR": 20191,
- "vkGetPhysicalDeviceWaylandPresentationSupportKHR": 20192,
- "vkCreateMirSurfaceKHR": 20193,
- "vkGetPhysicalDeviceMirPresentationSupportKHR": 20194,
- "vkCreateAndroidSurfaceKHR": 20195,
- "vkCreateWin32SurfaceKHR": 20196,
- "vkGetPhysicalDeviceWin32PresentationSupportKHR": 20197,
- "vkGetPhysicalDeviceFeatures2KHR": 20198,
- "vkGetPhysicalDeviceProperties2KHR": 20199,
- "vkGetPhysicalDeviceFormatProperties2KHR": 20200,
- "vkGetPhysicalDeviceImageFormatProperties2KHR": 20201,
- "vkGetPhysicalDeviceQueueFamilyProperties2KHR": 20202,
- "vkGetPhysicalDeviceMemoryProperties2KHR": 20203,
- "vkGetPhysicalDeviceSparseImageFormatProperties2KHR": 20204,
- "vkGetDeviceGroupPeerMemoryFeaturesKHR": 20205,
- "vkCmdSetDeviceMaskKHR": 20206,
- "vkCmdDispatchBaseKHR": 20207,
- "vkTrimCommandPoolKHR": 20208,
- "vkEnumeratePhysicalDeviceGroupsKHR": 20209,
- "vkGetPhysicalDeviceExternalBufferPropertiesKHR": 20210,
- "vkGetMemoryWin32HandleKHR": 20211,
- "vkGetMemoryWin32HandlePropertiesKHR": 20212,
- "vkGetMemoryFdKHR": 20213,
- "vkGetMemoryFdPropertiesKHR": 20214,
- "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR": 20215,
- "vkImportSemaphoreWin32HandleKHR": 20216,
- "vkGetSemaphoreWin32HandleKHR": 20217,
- "vkImportSemaphoreFdKHR": 20218,
- "vkGetSemaphoreFdKHR": 20219,
- "vkCmdPushDescriptorSetKHR": 20220,
- "vkCmdPushDescriptorSetWithTemplateKHR": 20221,
- "vkCreateDescriptorUpdateTemplateKHR": 20222,
- "vkDestroyDescriptorUpdateTemplateKHR": 20223,
- "vkUpdateDescriptorSetWithTemplateKHR": 20224,
- "vkCreateRenderPass2KHR": 20225,
- "vkCmdBeginRenderPass2KHR": 20226,
- "vkCmdNextSubpass2KHR": 20227,
- "vkCmdEndRenderPass2KHR": 20228,
- "vkGetSwapchainStatusKHR": 20229,
- "vkGetPhysicalDeviceExternalFencePropertiesKHR": 20230,
- "vkImportFenceWin32HandleKHR": 20231,
- "vkGetFenceWin32HandleKHR": 20232,
- "vkImportFenceFdKHR": 20233,
- "vkGetFenceFdKHR": 20234,
- "vkGetPhysicalDeviceSurfaceCapabilities2KHR": 20235,
- "vkGetPhysicalDeviceSurfaceFormats2KHR": 20236,
- "vkGetPhysicalDeviceDisplayProperties2KHR": 20237,
- "vkGetPhysicalDeviceDisplayPlaneProperties2KHR": 20238,
- "vkGetDisplayModeProperties2KHR": 20239,
- "vkGetDisplayPlaneCapabilities2KHR": 20240,
- "vkGetImageMemoryRequirements2KHR": 20241,
- "vkGetBufferMemoryRequirements2KHR": 20242,
- "vkGetImageSparseMemoryRequirements2KHR": 20243,
- "vkCreateSamplerYcbcrConversionKHR": 20244,
- "vkDestroySamplerYcbcrConversionKHR": 20245,
- "vkBindBufferMemory2KHR": 20246,
- "vkBindImageMemory2KHR": 20247,
- "vkGetDescriptorSetLayoutSupportKHR": 20248,
- "vkCmdDrawIndirectCountKHR": 20249,
- "vkCmdDrawIndexedIndirectCountKHR": 20250,
- "vkGetSwapchainGrallocUsageANDROID": 20251,
- "vkAcquireImageANDROID": 20252,
- "vkQueueSignalReleaseImageANDROID": 20253,
- "vkCreateDebugReportCallbackEXT": 20254,
- "vkDestroyDebugReportCallbackEXT": 20255,
- "vkDebugReportMessageEXT": 20256,
- "vkDebugMarkerSetObjectTagEXT": 20257,
- "vkDebugMarkerSetObjectNameEXT": 20258,
- "vkCmdDebugMarkerBeginEXT": 20259,
- "vkCmdDebugMarkerEndEXT": 20260,
- "vkCmdDebugMarkerInsertEXT": 20261,
- "vkCmdDrawIndirectCountAMD": 20262,
- "vkCmdDrawIndexedIndirectCountAMD": 20263,
- "vkGetShaderInfoAMD": 20264,
- "vkGetPhysicalDeviceExternalImageFormatPropertiesNV": 20265,
- "vkGetMemoryWin32HandleNV": 20266,
- "vkCreateViSurfaceNN": 20267,
- "vkCmdBeginConditionalRenderingEXT": 20268,
- "vkCmdEndConditionalRenderingEXT": 20269,
- "vkCmdProcessCommandsNVX": 20270,
- "vkCmdReserveSpaceForCommandsNVX": 20271,
- "vkCreateIndirectCommandsLayoutNVX": 20272,
- "vkDestroyIndirectCommandsLayoutNVX": 20273,
- "vkCreateObjectTableNVX": 20274,
- "vkDestroyObjectTableNVX": 20275,
- "vkRegisterObjectsNVX": 20276,
- "vkUnregisterObjectsNVX": 20277,
- "vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX": 20278,
- "vkCmdSetViewportWScalingNV": 20279,
- "vkReleaseDisplayEXT": 20280,
- "vkAcquireXlibDisplayEXT": 20281,
- "vkGetRandROutputDisplayEXT": 20282,
- "vkGetPhysicalDeviceSurfaceCapabilities2EXT": 20283,
- "vkDisplayPowerControlEXT": 20284,
- "vkRegisterDeviceEventEXT": 20285,
- "vkRegisterDisplayEventEXT": 20286,
- "vkGetSwapchainCounterEXT": 20287,
- "vkGetRefreshCycleDurationGOOGLE": 20288,
- "vkGetPastPresentationTimingGOOGLE": 20289,
- "vkCmdSetDiscardRectangleEXT": 20290,
- "vkSetHdrMetadataEXT": 20291,
- "vkCreateIOSSurfaceMVK": 20292,
- "vkCreateMacOSSurfaceMVK": 20293,
- "vkSetDebugUtilsObjectNameEXT": 20294,
- "vkSetDebugUtilsObjectTagEXT": 20295,
- "vkQueueBeginDebugUtilsLabelEXT": 20296,
- "vkQueueEndDebugUtilsLabelEXT": 20297,
- "vkQueueInsertDebugUtilsLabelEXT": 20298,
- "vkCmdBeginDebugUtilsLabelEXT": 20299,
- "vkCmdEndDebugUtilsLabelEXT": 20300,
- "vkCmdInsertDebugUtilsLabelEXT": 20301,
- "vkCreateDebugUtilsMessengerEXT": 20302,
- "vkDestroyDebugUtilsMessengerEXT": 20303,
- "vkSubmitDebugUtilsMessageEXT": 20304,
- "vkGetAndroidHardwareBufferPropertiesANDROID": 20305,
- "vkGetMemoryAndroidHardwareBufferANDROID": 20306,
- "vkCmdSetSampleLocationsEXT": 20307,
- "vkGetPhysicalDeviceMultisamplePropertiesEXT": 20308,
- "vkCreateValidationCacheEXT": 20309,
- "vkDestroyValidationCacheEXT": 20310,
- "vkMergeValidationCachesEXT": 20311,
- "vkGetValidationCacheDataEXT": 20312,
- "vkGetMemoryHostPointerPropertiesEXT": 20313,
- "vkCmdWriteBufferMarkerAMD": 20314,
- "vkCmdSetCheckpointNV": 20315,
- "vkGetQueueCheckpointDataNV": 20316,
- "vkMapMemoryIntoAddressSpaceGOOGLE": 20317,
- "vkUpdateDescriptorSetWithTemplateSizedGOOGLE": 20320,
- "vkBeginCommandBufferAsyncGOOGLE": 20321,
- "vkEndCommandBufferAsyncGOOGLE": 20322,
- "vkResetCommandBufferAsyncGOOGLE": 20323,
- "vkCommandBufferHostSyncGOOGLE": 20324,
- "vkCreateImageWithRequirementsGOOGLE": 20325,
- "vkCreateBufferWithRequirementsGOOGLE": 20326,
- "vkGetMemoryHostAddressInfoGOOGLE": 20327,
- "vkFreeMemorySyncGOOGLE": 20328,
- "vkQueueHostSyncGOOGLE": 20329,
- "vkQueueSubmitAsyncGOOGLE": 20330,
- "vkQueueWaitIdleAsyncGOOGLE": 20331,
- "vkQueueBindSparseAsyncGOOGLE": 20332,
- "vkGetLinearImageLayoutGOOGLE": 20333,
- "vkGetMTLDeviceMVK": 20334,
- "vkSetMTLTextureMVK": 20335,
- "vkGetMTLTextureMVK": 20336,
- "vkGetMTLBufferMVK": 20337,
- "vkUseIOSurfaceMVK": 20338,
- "vkGetIOSurfaceMVK": 20339,
- "vkQueueFlushCommandsGOOGLE": 20340,
- "vkGetBlobGOOGLE": 20341,
-}
-
-CUSTOM_MARSHAL_TYPES = {
- "VkAccelerationStructureInstanceKHR": {
- "common": """
-typedef struct VkAccelerationStructureInstanceKHRWithoutBitFields {
- VkTransformMatrixKHR transform;
- uint32_t dwords[2];
- uint64_t accelerationStructureReference;
-} VkAccelerationStructureInstanceKHRWithoutBitFields;
-""",
- "marshaling": """
-const VkAccelerationStructureInstanceKHRWithoutBitFields* {newInputVarName} = (const VkAccelerationStructureInstanceKHRWithoutBitFields*)({inputVarName});
-marshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transform));
-for (uint32_t i = 0; i < 2; i++) {{
- {streamVarName}->write((uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
-}}
-{streamVarName}->write((uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
-""",
- "unmarshaling": """
-VkAccelerationStructureInstanceKHRWithoutBitFields* {newInputVarName} = (VkAccelerationStructureInstanceKHRWithoutBitFields*)({inputVarName});
-unmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transform));
-for (uint32_t i = 0; i < 2; i++) {{
- {streamVarName}->read((uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
-}}
-{streamVarName}->read((uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
-""",
- "reservedmarshaling": """
-(void)vkStream;
-const VkAccelerationStructureInstanceKHRWithoutBitFields* {newInputVarName} = (const VkAccelerationStructureInstanceKHRWithoutBitFields*)({inputVarName});
-reservedmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transform), ptr);
-for (uint32_t i = 0; i < 2; i++) {{
- memcpy(*ptr, (uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
- *ptr += sizeof(uint32_t);
-}}
-memcpy(*ptr, (uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
-*ptr += sizeof(uint64_t);
-""",
- "reservedunmarshaling": """
-VkAccelerationStructureInstanceKHRWithoutBitFields* {newInputVarName} = (VkAccelerationStructureInstanceKHRWithoutBitFields*)({inputVarName});
-reservedunmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transform), ptr);
-for (uint32_t i = 0; i < 2; i++) {{
- memcpy((uint32_t*)&({newInputVarName}->dwords[i]), *ptr, sizeof(uint32_t));
- *ptr += sizeof(uint32_t);
-}}
-memcpy((uint64_t*)&{newInputVarName}->accelerationStructureReference, *ptr, sizeof(uint64_t));
-*ptr += sizeof(uint64_t);
-""",
- },
- "VkAccelerationStructureMatrixMotionInstanceNV": {
- "common": """
-typedef struct VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields {
- VkTransformMatrixKHR transformT0;
- VkTransformMatrixKHR transformT1;
- uint32_t dwords[2];
- uint64_t accelerationStructureReference;
-} VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields;
-""",
- "marshaling": """
-const VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields* {newInputVarName} = (const VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields*)({inputVarName});
-marshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT0));
-marshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT1));
-for (uint32_t i = 0; i < 2; i++) {{
- {streamVarName}->write((uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
-}}
-{streamVarName}->write((uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
-""",
- "unmarshaling": """
-VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields* {newInputVarName} = (VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields*)({inputVarName});
-unmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT0));
-unmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT1));
-for (uint32_t i = 0; i < 2; i++) {{
- {streamVarName}->read((uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
-}}
-{streamVarName}->read((uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
-""",
- "reservedmarshaling": """
-(void)vkStream;
-const VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields* {newInputVarName} = (const VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields*)({inputVarName});
-reservedmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT0), ptr);
-reservedmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT1), ptr);
-for (uint32_t i = 0; i < 2; i++) {{
- memcpy(*ptr, (uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
- *ptr += sizeof(uint32_t);
-}}
-memcpy(*ptr, (uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
-*ptr += sizeof(uint64_t);
-""",
- "reservedunmarshaling": """
-VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields* {newInputVarName} = (VkAccelerationStructureMatrixMotionInstanceNVWithoutBitFields*)({inputVarName});
-reservedunmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT0), ptr);
-reservedunmarshal_VkTransformMatrixKHR({streamVarName}, {rootTypeVarName}, (VkTransformMatrixKHR*)(&{newInputVarName}->transformT1), ptr);
-for (uint32_t i = 0; i < 2; i++) {{
- memcpy((uint32_t*)&({newInputVarName}->dwords[i]), *ptr, sizeof(uint32_t));
- *ptr += sizeof(uint32_t);
-}}
-memcpy((uint64_t*)&{newInputVarName}->accelerationStructureReference, *ptr, sizeof(uint64_t));
-*ptr += sizeof(uint64_t);
-""",
- },
- "VkAccelerationStructureSRTMotionInstanceNV": {
- "common": """
-typedef struct VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields {
- VkSRTDataNV transformT0;
- VkSRTDataNV transformT1;
- uint32_t dwords[2];
- uint64_t accelerationStructureReference;
-} VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields;
-""",
- "marshaling": """
-const VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields* {newInputVarName} = (const VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields*)({inputVarName});
-marshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT0));
-marshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT1));
-for (uint32_t i = 0; i < 2; i++) {{
- {streamVarName}->write((uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
-}}
-{streamVarName}->write((uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
-""",
- "unmarshaling": """
-VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields* {newInputVarName} = (VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields*)({inputVarName});
-unmarshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT0));
-unmarshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT1));
-for (uint32_t i = 0; i < 2; i++) {{
- {streamVarName}->read((uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
-}}
-{streamVarName}->read((uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
-""",
- "reservedmarshaling": """
-(void)vkStream;
-const VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields* {newInputVarName} = (const VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields*)({inputVarName});
-reservedmarshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT0), ptr);
-reservedmarshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT1), ptr);
-for (uint32_t i = 0; i < 2; i++) {{
- memcpy(*ptr, (uint32_t*)&({newInputVarName}->dwords[i]), sizeof(uint32_t));
- *ptr += sizeof(uint32_t);
-}}
-memcpy(*ptr, (uint64_t*)&{newInputVarName}->accelerationStructureReference, sizeof(uint64_t));
-*ptr += sizeof(uint64_t);
-""",
- "reservedunmarshaling": """
-VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields* {newInputVarName} = (VkAccelerationStructureSRTMotionInstanceNVWithoutBitFields*)({inputVarName});
-reservedunmarshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT0), ptr);
-reservedunmarshal_VkSRTDataNV({streamVarName}, {rootTypeVarName}, (VkSRTDataNV*)(&{newInputVarName}->transformT1), ptr);
-for (uint32_t i = 0; i < 2; i++) {{
- memcpy((uint32_t*)&({newInputVarName}->dwords[i]), *ptr, sizeof(uint32_t));
- *ptr += sizeof(uint32_t);
-}}
-memcpy((uint64_t*)&{newInputVarName}->accelerationStructureReference, *ptr, sizeof(uint64_t));
-*ptr += sizeof(uint64_t);
-""",
- },
- "VkXcbSurfaceCreateInfoKHR": {
- "common": """
-// This struct should never be marshaled / unmarshaled.
-__builtin_trap();
-""",
- "marshaling": "",
- "unmarshaling": "",
- "reservedmarshaling": "",
- "reservedunmarshaling": "",
- },
- "VkMetalSurfaceCreateInfoEXT": {
- "common": """
-// This struct should never be marshaled / unmarshaled.
-__builtin_trap();
-""",
- "marshaling": "",
- "unmarshaling": "",
- "reservedmarshaling": "",
- "reservedunmarshaling": "",
- },
-}
diff --git a/codegen/vulkan/scripts/cereal/reservedmarshaling.py b/codegen/vulkan/scripts/cereal/reservedmarshaling.py
deleted file mode 100644
index 23ace9d3..00000000
--- a/codegen/vulkan/scripts/cereal/reservedmarshaling.py
+++ /dev/null
@@ -1,1055 +0,0 @@
-# Copyright (c) 2018 The Android Open Source Project
-# Copyright (c) 2018 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-from copy import copy
-
-from .common.codegen import CodeGen, VulkanAPIWrapper
-from .common.vulkantypes import \
- VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, VulkanTypeIterator, Atom, FuncExpr, FuncExprVal, FuncLambda
-
-from .wrapperdefs import VulkanWrapperGenerator
-from .wrapperdefs import VULKAN_STREAM_VAR_NAME
-from .wrapperdefs import ROOT_TYPE_VAR_NAME, ROOT_TYPE_PARAM
-from .wrapperdefs import STREAM_RET_TYPE
-from .wrapperdefs import MARSHAL_INPUT_VAR_NAME
-from .wrapperdefs import UNMARSHAL_INPUT_VAR_NAME
-from .wrapperdefs import PARAMETERS_MARSHALING
-from .wrapperdefs import PARAMETERS_MARSHALING_GUEST
-from .wrapperdefs import STYPE_OVERRIDE
-from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM_FOR_WRITE, EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME
-from .wrapperdefs import API_PREFIX_RESERVEDMARSHAL
-from .wrapperdefs import API_PREFIX_RESERVEDUNMARSHAL
-
-from .marshalingdefs import CUSTOM_MARSHAL_TYPES
-class VulkanReservedMarshalingCodegen(VulkanTypeIterator):
- def __init__(self,
- cgen,
- streamVarName,
- rootTypeVarName,
- inputVarName,
- ptrVarName,
- marshalPrefix,
- handlemapPrefix,
- direction = "write",
- forApiOutput = False,
- dynAlloc = False,
- mapHandles = True,
- handleMapOverwrites = False,
- doFiltering = True,
- stackVar=None,
- stackArrSize=None):
- self.cgen = cgen
- self.direction = direction
- self.processSimple = "write" if self.direction == "write" else "read"
- self.forApiOutput = forApiOutput
-
- self.checked = False
-
- self.streamVarName = streamVarName
- self.rootTypeVarName = rootTypeVarName
- self.inputVarName = inputVarName
- self.ptrVar = ptrVarName
- self.marshalPrefix = marshalPrefix
- self.handlemapPrefix = handlemapPrefix
-
- self.exprAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.inputVarName, asPtr = True)
- self.exprValueAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.inputVarName, asPtr = False)
- self.exprPrimitiveValueAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.inputVarName, asPtr = False)
- self.lenAccessor = lambda t: self.cgen.generalLengthAccess(t, parentVarName = self.inputVarName)
- self.lenAccessorGuard = lambda t: self.cgen.generalLengthAccessGuard(
- t, parentVarName=self.inputVarName)
- self.filterVarAccessor = lambda t: self.cgen.filterVarAccess(t, parentVarName = self.inputVarName)
-
- self.dynAlloc = dynAlloc
- self.mapHandles = mapHandles
- self.handleMapOverwrites = handleMapOverwrites
- self.doFiltering = doFiltering
-
- self.stackVar = stackVar
- self.stackArrSize = stackArrSize
-
- def getTypeForStreaming(self, vulkanType):
- res = copy(vulkanType)
-
- if not vulkanType.accessibleAsPointer():
- res = res.getForAddressAccess()
-
- if vulkanType.staticArrExpr:
- res = res.getForAddressAccess()
-
- if self.direction == "write":
- return res
- else:
- return res.getForNonConstAccess()
-
- def makeCastExpr(self, vulkanType):
- return "(%s)" % (
- self.cgen.makeCTypeDecl(vulkanType, useParamName=False))
-
- def genPtrIncr(self, sizeExpr):
- self.cgen.stmt("*%s += %s" % (self.ptrVar, sizeExpr))
-
- def genMemcpyAndIncr(self, varname, cast, toStreamExpr, sizeExpr, toBe = False, actualSize = 4):
- if self.direction == "write":
- self.cgen.stmt("memcpy(*%s, %s%s, %s)" % (varname, cast, toStreamExpr, sizeExpr))
- else:
- self.cgen.stmt("memcpy(%s%s, *%s, %s)" % (cast, toStreamExpr, varname, sizeExpr))
-
- if toBe:
- streamPrefix = "to"
- if "read" == self.direction:
- streamPrefix = "from"
-
- streamMethod = streamPrefix
-
- if 1 == actualSize:
- streamMethod += "Byte"
- elif 2 == actualSize:
- streamMethod += "Be16"
- elif 4 == actualSize:
- streamMethod += "Be32"
- elif 8 == actualSize:
- streamMethod += "Be64"
- else:
- pass
-
- if self.direction == "write":
- self.cgen.stmt("android::base::Stream::%s((uint8_t*)*%s)" % (streamMethod, varname))
- else:
- self.cgen.stmt("android::base::Stream::%s((uint8_t*)%s)" % (streamMethod, toStreamExpr))
-
- self.genPtrIncr(sizeExpr)
-
- def genStreamCall(self, vulkanType, toStreamExpr, sizeExpr):
- varname = self.ptrVar
- cast = self.makeCastExpr(self.getTypeForStreaming(vulkanType))
- self.genMemcpyAndIncr(varname, cast, toStreamExpr, sizeExpr)
-
- def genPrimitiveStreamCall(self, vulkanType, access):
- varname = self.ptrVar
- self.cgen.memcpyPrimitive(
- self.typeInfo,
- "(*" + varname + ")",
- access,
- vulkanType,
- direction=self.direction)
- self.genPtrIncr(str(self.cgen.countPrimitive(
- self.typeInfo,
- vulkanType)))
-
- def genHandleMappingCall(self, vulkanType, access, lenAccess, lenAccessGuard):
-
- if lenAccess is None:
- lenAccess = "1"
- handle64Bytes = "8"
- else:
- handle64Bytes = "%s * 8" % lenAccess
-
- handle64Var = self.cgen.var()
- if lenAccess != "1":
- self.cgen.beginIf(lenAccess)
- self.cgen.stmt("uint8_t* %s_ptr = (uint8_t*)(*%s)" % (handle64Var, self.ptrVar))
- handle64VarAccess = handle64Var
- handle64VarType = \
- makeVulkanTypeSimple(False, "uint64_t", 1, paramName=handle64Var)
- else:
- self.cgen.stmt("uint64_t %s" % handle64Var)
- handle64VarAccess = "&%s" % handle64Var
- handle64VarType = \
- makeVulkanTypeSimple(False, "uint64_t", 0, paramName=handle64Var)
-
- if "" == self.handlemapPrefix:
- mapFunc = ("(%s)" % vulkanType.typeName)
- mapFunc64 = ("(%s)" % "uint64_t")
- else:
- mapFunc = self.handlemapPrefix + vulkanType.typeName
- mapFunc64 = mapFunc
-
- if self.direction == "write":
- if self.handleMapOverwrites:
- self.cgen.stmt(
- "static_assert(8 == sizeof(%s), \"handle map overwrite requres %s to be 8 bytes long\")" % \
- (vulkanType.typeName, vulkanType.typeName))
- if "1" == lenAccess:
- self.cgen.stmt("*%s = (%s)%s(*%s)" % (access, vulkanType.typeName, mapFunc, access))
- self.genStreamCall(vulkanType, access, "8 * %s" % lenAccess)
- else:
- if lenAccessGuard is not None:
- self.cgen.beginIf(lenAccessGuard)
- self.cgen.beginFor("uint32_t k = 0", "k < %s" % lenAccess, "++k")
- self.cgen.stmt("%s[k] = (%s)%s(%s[k])" % (access, vulkanType.typeName, mapFunc, access))
- self.cgen.endFor()
- if lenAccessGuard is not None:
- self.cgen.endIf()
- self.genPtrIncr("8 * %s" % lenAccess)
- else:
- if "1" == lenAccess:
- self.cgen.stmt("*%s = %s((*%s))" % (handle64VarAccess, mapFunc64, access))
- self.genStreamCall(handle64VarType, handle64VarAccess, handle64Bytes)
- else:
- if lenAccessGuard is not None:
- self.cgen.beginIf(lenAccessGuard)
- self.cgen.beginFor("uint32_t k = 0", "k < %s" % lenAccess, "++k")
- self.cgen.stmt("uint64_t tmpval = %s(%s[k])" % (mapFunc64, access))
- self.cgen.stmt("memcpy(%s_ptr + k * 8, &tmpval, sizeof(uint64_t))" % (handle64Var))
- self.cgen.endFor()
- if lenAccessGuard is not None:
- self.cgen.endIf()
- self.genPtrIncr("8 * %s" % lenAccess)
- else:
- if "1" == lenAccess:
- self.genStreamCall(handle64VarType, handle64VarAccess, handle64Bytes)
- self.cgen.stmt("*%s%s = (%s)%s((%s)(*%s))" % (
- self.makeCastExpr(vulkanType.getForNonConstAccess()), access,
- vulkanType.typeName, mapFunc, vulkanType.typeName, handle64VarAccess))
- else:
- self.genPtrIncr("8 * %s" % lenAccess)
- if lenAccessGuard is not None:
- self.cgen.beginIf(lenAccessGuard)
- self.cgen.beginFor("uint32_t k = 0", "k < %s" % lenAccess, "++k")
- self.cgen.stmt("uint64_t tmpval; memcpy(&tmpval, %s_ptr + k * 8, sizeof(uint64_t))" % handle64Var)
- self.cgen.stmt("*((%s%s) + k) = (%s)%s((%s)tmpval)" % (
- self.makeCastExpr(vulkanType.getForNonConstAccess()), access,
- vulkanType.typeName, mapFunc, vulkanType.typeName))
- if lenAccessGuard is not None:
- self.cgen.endIf()
- self.cgen.endFor()
-
- if lenAccess != "1":
- self.cgen.endIf()
-
- def doAllocSpace(self, vulkanType):
- if self.dynAlloc and self.direction == "read":
- access = self.exprAccessor(vulkanType)
- lenAccess = self.lenAccessor(vulkanType)
- sizeof = self.cgen.sizeofExpr(vulkanType.getForValueAccess())
- if lenAccess:
- bytesExpr = "%s * %s" % (lenAccess, sizeof)
- else:
- bytesExpr = sizeof
- lenAccess = "1"
-
- if self.stackVar:
- if self.stackArrSize != lenAccess:
- self.cgen.beginIf("%s <= %s" % (lenAccess, self.stackArrSize))
-
- self.cgen.stmt(
- "%s = %s%s" % (access, self.makeCastExpr(vulkanType.getForNonConstAccess()), self.stackVar))
-
- if self.stackArrSize != lenAccess:
- self.cgen.endIf()
- self.cgen.beginElse()
-
- if self.stackArrSize != lenAccess:
- self.cgen.stmt(
- "%s->alloc((void**)&%s, %s)" %
- (self.streamVarName,
- access, bytesExpr))
-
- if self.stackArrSize != lenAccess:
- self.cgen.endIf()
- else:
- self.cgen.stmt(
- "%s->alloc((void**)&%s, %s)" %
- (self.streamVarName,
- access, bytesExpr))
-
- def getOptionalStringFeatureExpr(self, vulkanType):
- if vulkanType.optionalStr is not None:
- if vulkanType.optionalStr.startswith("streamFeature:"):
- splitted = vulkanType.optionalStr.split(":")
- featureExpr = "%s->getFeatureBits() & %s" % (self.streamVarName, splitted[1])
- return featureExpr
- return None
-
- def onCheck(self, vulkanType):
- if self.forApiOutput:
- return
-
- featureExpr = self.getOptionalStringFeatureExpr(vulkanType)
- self.checked = True
- access = self.exprAccessor(vulkanType)
- needConsistencyCheck = False
-
- self.cgen.line("// WARNING PTR CHECK")
- if (self.dynAlloc and self.direction == "read") or self.direction == "write":
- checkAccess = self.exprAccessor(vulkanType)
- addrExpr = "&" + checkAccess
- sizeExpr = self.cgen.sizeofExpr(vulkanType)
- else:
- checkName = "check_%s" % vulkanType.paramName
- self.cgen.stmt("%s %s" % (
- self.cgen.makeCTypeDecl(vulkanType, useParamName = False), checkName))
- checkAccess = checkName
- addrExpr = "&" + checkAccess
- sizeExpr = self.cgen.sizeofExpr(vulkanType)
- needConsistencyCheck = True
-
- if featureExpr is not None:
- self.cgen.beginIf(featureExpr)
-
- self.genPrimitiveStreamCall(
- vulkanType,
- checkAccess)
-
- if featureExpr is not None:
- self.cgen.endIf()
-
- if featureExpr is not None:
- self.cgen.beginIf("(!(%s) || %s)" % (featureExpr, access))
- else:
- self.cgen.beginIf(access)
-
- if needConsistencyCheck and featureExpr is None:
- self.cgen.beginIf("!(%s)" % checkName)
- self.cgen.stmt(
- "fprintf(stderr, \"fatal: %s inconsistent between guest and host\\n\")" % (access))
- self.cgen.endIf()
-
- def onCheckWithNullOptionalStringFeature(self, vulkanType):
- self.cgen.beginIf("%s->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT" % self.streamVarName)
- self.onCheck(vulkanType)
-
- def endCheckWithNullOptionalStringFeature(self, vulkanType):
- self.endCheck(vulkanType)
- self.cgen.endIf()
- self.cgen.beginElse()
-
- def finalCheckWithNullOptionalStringFeature(self, vulkanType):
- self.cgen.endElse()
-
- def endCheck(self, vulkanType):
-
- if self.checked:
- self.cgen.endIf()
- self.checked = False
-
- def genFilterFunc(self, filterfunc, env):
-
- def loop(expr, lambdaEnv={}):
- def do_func(expr):
- fnamestr = expr.name.name
- if "not" == fnamestr:
- return "!(%s)" % (loop(expr.args[0], lambdaEnv))
- if "eq" == fnamestr:
- return "(%s == %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv))
- if "and" == fnamestr:
- return "(%s && %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv))
- if "or" == fnamestr:
- return "(%s || %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv))
- if "bitwise_and" == fnamestr:
- return "(%s & %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv))
- if "getfield" == fnamestr:
- ptrlevels = get_ptrlevels(expr.args[0].val.name)
- if ptrlevels == 0:
- return "%s.%s" % (loop(expr.args[0], lambdaEnv), expr.args[1].val)
- else:
- return "(%s(%s)).%s" % ("*" * ptrlevels, loop(expr.args[0], lambdaEnv), expr.args[1].val)
-
- if "if" == fnamestr:
- return "((%s) ? (%s) : (%s))" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv), loop(expr.args[2], lambdaEnv))
-
- return "%s(%s)" % (fnamestr, ", ".join(map(lambda e: loop(e, lambdaEnv), expr.args)))
-
- def do_expratom(atomname, lambdaEnv= {}):
- if lambdaEnv.get(atomname, None) is not None:
- return atomname
-
- enventry = env.get(atomname, None)
- if None != enventry:
- return self.getEnvAccessExpr(atomname)
- return atomname
-
- def get_ptrlevels(atomname, lambdaEnv= {}):
- if lambdaEnv.get(atomname, None) is not None:
- return 0
-
- enventry = env.get(atomname, None)
- if None != enventry:
- return self.getPointerIndirectionLevels(atomname)
-
- return 0
-
- def do_exprval(expr, lambdaEnv= {}):
- expratom = expr.val
-
- if Atom == type(expratom):
- return do_expratom(expratom.name, lambdaEnv)
-
- return "%s" % expratom
-
- def do_lambda(expr, lambdaEnv= {}):
- params = expr.vs
- body = expr.body
- newEnv = {}
-
- for (k, v) in lambdaEnv.items():
- newEnv[k] = v
-
- for p in params:
- newEnv[p.name] = p.typ
-
- return "[](%s) { return %s; }" % (", ".join(list(map(lambda p: "%s %s" % (p.typ, p.name), params))), loop(body, lambdaEnv=newEnv))
-
- if FuncExpr == type(expr):
- return do_func(expr)
- if FuncLambda == type(expr):
- return do_lambda(expr)
- elif FuncExprVal == type(expr):
- return do_exprval(expr)
-
- return loop(filterfunc)
-
- def beginFilterGuard(self, vulkanType):
- if vulkanType.filterVar == None:
- return
-
- if self.doFiltering == False:
- return
-
- filterVarAccess = self.getEnvAccessExpr(vulkanType.filterVar)
-
- filterValsExpr = None
- filterFuncExpr = None
- filterExpr = None
-
- filterFeature = "%s->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT" % self.streamVarName
-
- if None != vulkanType.filterVals:
- filterValsExpr = " || ".join(map(lambda filterval: "(%s == %s)" % (filterval, filterVarAccess), vulkanType.filterVals))
-
- if None != vulkanType.filterFunc:
- filterFuncExpr = self.genFilterFunc(vulkanType.filterFunc, self.currentStructInfo.environment)
-
- if None != filterValsExpr and None != filterFuncExpr:
- filterExpr = "%s || %s" % (filterValsExpr, filterFuncExpr)
- elif None == filterValsExpr and None == filterFuncExpr:
- # Assume is bool
- self.cgen.beginIf(filterVarAccess)
- elif None != filterValsExpr:
- self.cgen.beginIf("(!(%s) || (%s))" % (filterFeature, filterValsExpr))
- elif None != filterFuncExpr:
- self.cgen.beginIf("(!(%s) || (%s))" % (filterFeature, filterFuncExpr))
-
- def endFilterGuard(self, vulkanType, cleanupExpr=None):
- if vulkanType.filterVar == None:
- return
-
- if self.doFiltering == False:
- return
-
- if cleanupExpr == None:
- self.cgen.endIf()
- else:
- self.cgen.endIf()
- self.cgen.beginElse()
- self.cgen.stmt(cleanupExpr)
- self.cgen.endElse()
-
- def getEnvAccessExpr(self, varName):
- parentEnvEntry = self.currentStructInfo.environment.get(varName, None)
-
- if parentEnvEntry != None:
- isParentMember = parentEnvEntry["structmember"]
-
- if isParentMember:
- envAccess = self.exprValueAccessor(list(filter(lambda member: member.paramName == varName, self.currentStructInfo.members))[0])
- else:
- envAccess = varName
- return envAccess
-
- return None
-
- def getPointerIndirectionLevels(self, varName):
- parentEnvEntry = self.currentStructInfo.environment.get(varName, None)
-
- if parentEnvEntry != None:
- isParentMember = parentEnvEntry["structmember"]
-
- if isParentMember:
- return list(filter(lambda member: member.paramName == varName, self.currentStructInfo.members))[0].pointerIndirectionLevels
- else:
- return 0
- return 0
-
- return 0
-
-
- def onCompoundType(self, vulkanType):
-
- access = self.exprAccessor(vulkanType)
- lenAccess = self.lenAccessor(vulkanType)
-
- self.beginFilterGuard(vulkanType)
-
- if vulkanType.pointerIndirectionLevels > 0:
- self.doAllocSpace(vulkanType)
-
- if lenAccess is not None:
- loopVar = "i"
- access = "%s + %s" % (access, loopVar)
- forInit = "uint32_t %s = 0" % loopVar
- forCond = "%s < (uint32_t)%s" % (loopVar, lenAccess)
- forIncr = "++%s" % loopVar
- self.cgen.beginFor(forInit, forCond, forIncr)
-
- accessWithCast = "%s(%s)" % (self.makeCastExpr(
- self.getTypeForStreaming(vulkanType)), access)
-
- callParams = [self.streamVarName, self.rootTypeVarName, accessWithCast, self.ptrVar]
-
- for (bindName, localName) in vulkanType.binds.items():
- callParams.append(self.getEnvAccessExpr(localName))
-
- self.cgen.funcCall(None, self.marshalPrefix + vulkanType.typeName,
- callParams)
-
- if lenAccess is not None:
- self.cgen.endFor()
-
- if self.direction == "read":
- self.endFilterGuard(vulkanType, "%s = 0" % self.exprAccessor(vulkanType))
- else:
- self.endFilterGuard(vulkanType)
-
- def onString(self, vulkanType):
- access = self.exprAccessor(vulkanType)
-
- if self.direction == "write":
- self.cgen.beginBlock()
- self.cgen.stmt("uint32_t l = %s ? strlen(%s): 0" % (access, access))
- self.genMemcpyAndIncr(self.ptrVar, "(uint32_t*)" ,"&l", "sizeof(uint32_t)", toBe = True, actualSize = 4)
- self.genMemcpyAndIncr(self.ptrVar, "(char*)", access, "l")
- self.cgen.endBlock()
- else:
- castExpr = \
- self.makeCastExpr( \
- self.getTypeForStreaming( \
- vulkanType.getForAddressAccess()))
- self.cgen.stmt( \
- "%s->loadStringInPlaceWithStreamPtr(%s&%s, %s)" % (self.streamVarName, castExpr, access, self.ptrVar))
-
- def onStringArray(self, vulkanType):
- access = self.exprAccessor(vulkanType)
- lenAccess = self.lenAccessor(vulkanType)
- lenAccessGuard = self.lenAccessorGuard(vulkanType)
-
- if self.direction == "write":
- self.cgen.beginBlock()
-
- self.cgen.stmt("uint32_t c = 0")
- if lenAccessGuard is not None:
- self.cgen.beginIf(lenAccessGuard)
- self.cgen.stmt("c = %s" % (lenAccess))
- if lenAccessGuard is not None:
- self.cgen.endIf()
- self.genMemcpyAndIncr(self.ptrVar, "(uint32_t*)" ,"&c", "sizeof(uint32_t)", toBe = True, actualSize = 4)
-
- self.cgen.beginFor("uint32_t i = 0", "i < c", "++i")
- self.cgen.stmt("uint32_t l = %s ? strlen(%s[i]): 0" % (access, access))
- self.genMemcpyAndIncr(self.ptrVar, "(uint32_t*)" ,"&l", "sizeof(uint32_t)", toBe = True, actualSize = 4)
- self.cgen.beginIf("l")
- self.genMemcpyAndIncr(self.ptrVar, "(char*)", "(%s[i])" % access, "l")
- self.cgen.endIf()
- self.cgen.endFor()
-
- self.cgen.endBlock()
- else:
- castExpr = \
- self.makeCastExpr( \
- self.getTypeForStreaming( \
- vulkanType.getForAddressAccess()))
-
- self.cgen.stmt("%s->loadStringArrayInPlaceWithStreamPtr(%s&%s, %s)" % (self.streamVarName, castExpr, access, self.ptrVar))
-
- def onStaticArr(self, vulkanType):
- access = self.exprValueAccessor(vulkanType)
- lenAccess = self.lenAccessor(vulkanType)
- finalLenExpr = "%s * %s" % (lenAccess, self.cgen.sizeofExpr(vulkanType))
- self.genStreamCall(vulkanType, access, finalLenExpr)
-
- # Old version VkEncoder may have some sType values conflict with VkDecoder
- # of new versions. For host decoder, it should not carry the incorrect old
- # sType values to the |forUnmarshaling| struct. Instead it should overwrite
- # the sType value.
- def overwriteSType(self, vulkanType):
- if self.direction == "read":
- sTypeParam = copy(vulkanType)
- sTypeParam.paramName = "sType"
- sTypeAccess = self.exprAccessor(sTypeParam)
-
- typeName = vulkanType.parent.typeName
- if typeName in STYPE_OVERRIDE:
- self.cgen.stmt("%s = %s" %
- (sTypeAccess, STYPE_OVERRIDE[typeName]))
-
- def onStructExtension(self, vulkanType):
- self.overwriteSType(vulkanType)
-
- sTypeParam = copy(vulkanType)
- sTypeParam.paramName = "sType"
-
- access = self.exprAccessor(vulkanType)
- sizeVar = "%s_size" % vulkanType.paramName
-
- if self.direction == "read":
- castedAccessExpr = "(%s)(%s)" % ("void*", access)
- else:
- castedAccessExpr = access
-
- sTypeAccess = self.exprAccessor(sTypeParam)
- self.cgen.beginIf("%s == VK_STRUCTURE_TYPE_MAX_ENUM" % self.rootTypeVarName)
- self.cgen.stmt("%s = %s" % (self.rootTypeVarName, sTypeAccess))
- self.cgen.endIf()
-
- if self.direction == "read" and self.dynAlloc:
- self.cgen.stmt("uint32_t %s" % sizeVar)
-
- self.genMemcpyAndIncr(self.ptrVar, "(uint32_t*)", "&" + sizeVar, "sizeof(uint32_t)", toBe = True, actualSize = 4)
-
- self.cgen.stmt("%s = nullptr" % access)
- self.cgen.beginIf(sizeVar)
- self.cgen.stmt( \
- "%s->alloc((void**)&%s, sizeof(VkStructureType))" %
- (self.streamVarName, access))
-
- self.genStreamCall(vulkanType, access, "sizeof(VkStructureType)")
- self.cgen.stmt("VkStructureType extType = *(VkStructureType*)(%s)" % access)
- self.cgen.stmt( \
- "%s->alloc((void**)&%s, %s(%s->getFeatureBits(), %s, %s))" %
- (self.streamVarName, access, EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME, self.streamVarName, self.rootTypeVarName, access))
- self.cgen.stmt("*(VkStructureType*)%s = extType" % access)
-
- self.cgen.funcCall(None, self.marshalPrefix + "extension_struct",
- [self.streamVarName, self.rootTypeVarName, castedAccessExpr, self.ptrVar])
- self.cgen.endIf()
- else:
-
- self.cgen.funcCall(None, self.marshalPrefix + "extension_struct",
- [self.streamVarName, self.rootTypeVarName, castedAccessExpr, self.ptrVar])
-
- def onPointer(self, vulkanType):
- access = self.exprAccessor(vulkanType)
-
- lenAccess = self.lenAccessor(vulkanType)
- lenAccessGuard = self.lenAccessorGuard(vulkanType)
-
- self.beginFilterGuard(vulkanType)
- self.doAllocSpace(vulkanType)
-
- if vulkanType.filterVar != None:
- print("onPointer Needs filter: %s filterVar %s" % (access, vulkanType.filterVar))
-
- if vulkanType.isHandleType() and self.mapHandles:
- self.genHandleMappingCall(
- vulkanType, access, lenAccess, lenAccessGuard)
- else:
- if self.typeInfo.isNonAbiPortableType(vulkanType.typeName):
- if lenAccess is not None:
- if lenAccessGuard is not None:
- self.cgen.beginIf(lenAccessGuard)
- self.cgen.beginFor("uint32_t i = 0", "i < (uint32_t)%s" % lenAccess, "++i")
- self.genPrimitiveStreamCall(vulkanType.getForValueAccess(), "%s[i]" % access)
- self.cgen.endFor()
- if lenAccessGuard is not None:
- self.cgen.endIf()
- else:
- self.genPrimitiveStreamCall(vulkanType.getForValueAccess(), "(*%s)" % access)
- else:
- if lenAccess is not None:
- finalLenExpr = "%s * %s" % (
- lenAccess, self.cgen.sizeofExpr(vulkanType.getForValueAccess()))
- else:
- finalLenExpr = "%s" % (
- self.cgen.sizeofExpr(vulkanType.getForValueAccess()))
- self.genStreamCall(vulkanType, access, finalLenExpr)
-
- if self.direction == "read":
- self.endFilterGuard(vulkanType, "%s = 0" % access)
- else:
- self.endFilterGuard(vulkanType)
-
- def onValue(self, vulkanType):
- self.beginFilterGuard(vulkanType)
-
- if vulkanType.isHandleType() and self.mapHandles:
- access = self.exprAccessor(vulkanType)
- if vulkanType.filterVar != None:
- print("onValue Needs filter: %s filterVar %s" % (access, vulkanType.filterVar))
- self.genHandleMappingCall(
- vulkanType.getForAddressAccess(), access, "1", None)
- elif self.typeInfo.isNonAbiPortableType(vulkanType.typeName):
- access = self.exprPrimitiveValueAccessor(vulkanType)
- self.genPrimitiveStreamCall(vulkanType, access)
- else:
- access = self.exprAccessor(vulkanType)
- self.genStreamCall(vulkanType, access, self.cgen.sizeofExpr(vulkanType))
-
- self.endFilterGuard(vulkanType)
-
- def streamLetParameter(self, structInfo, letParamInfo):
- filterFeature = "%s->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT" % self.streamVarName
- self.cgen.stmt("%s %s = 1" % (letParamInfo.typeName, letParamInfo.paramName))
-
- self.cgen.beginIf(filterFeature)
-
- if self.direction == "write":
- bodyExpr = self.currentStructInfo.environment[letParamInfo.paramName]["body"]
- self.cgen.stmt("%s = %s" % (letParamInfo.paramName, self.genFilterFunc(bodyExpr, self.currentStructInfo.environment)))
-
- self.genPrimitiveStreamCall(letParamInfo, letParamInfo.paramName)
-
- self.cgen.endIf()
-
-class VulkanReservedMarshaling(VulkanWrapperGenerator):
-
- def __init__(self, module, typeInfo, variant="host"):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
-
- self.cgenHeader = CodeGen()
- self.cgenImpl = CodeGen()
-
- self.variant = variant
-
- self.currentFeature = None
- self.apiOpcodes = {}
- self.dynAlloc = self.variant != "guest"
- self.ptrVarName = "ptr"
- self.ptrVarType = makeVulkanTypeSimple(False, "uint8_t", 2, self.ptrVarName)
- self.ptrVarTypeUnmarshal = makeVulkanTypeSimple(False, "uint8_t", 2, self.ptrVarName)
-
- if self.variant == "guest":
- self.marshalingParams = PARAMETERS_MARSHALING_GUEST
- else:
- self.marshalingParams = PARAMETERS_MARSHALING
-
- self.writeCodegen = \
- VulkanReservedMarshalingCodegen(
- None,
- VULKAN_STREAM_VAR_NAME,
- ROOT_TYPE_VAR_NAME,
- MARSHAL_INPUT_VAR_NAME,
- self.ptrVarName,
- API_PREFIX_RESERVEDMARSHAL,
- "get_host_u64_" if "guest" == self.variant else "",
- direction = "write")
-
- self.readCodegen = \
- VulkanReservedMarshalingCodegen(
- None,
- VULKAN_STREAM_VAR_NAME,
- ROOT_TYPE_VAR_NAME,
- UNMARSHAL_INPUT_VAR_NAME,
- self.ptrVarName,
- API_PREFIX_RESERVEDUNMARSHAL,
- "unbox_" if "host" == self.variant else "",
- direction = "read",
- dynAlloc=self.dynAlloc)
-
- self.knownDefs = {}
-
- self.extensionMarshalPrototype = \
- VulkanAPI(API_PREFIX_RESERVEDMARSHAL + "extension_struct",
- STREAM_RET_TYPE,
- self.marshalingParams +
- [STRUCT_EXTENSION_PARAM, self.ptrVarType])
-
- self.extensionUnmarshalPrototype = \
- VulkanAPI(API_PREFIX_RESERVEDUNMARSHAL + "extension_struct",
- STREAM_RET_TYPE,
- self.marshalingParams +
- [STRUCT_EXTENSION_PARAM_FOR_WRITE, self.ptrVarTypeUnmarshal])
-
- def onBegin(self,):
- VulkanWrapperGenerator.onBegin(self)
- self.module.appendImpl(self.cgenImpl.makeFuncDecl(self.extensionMarshalPrototype))
- self.module.appendImpl(self.cgenImpl.makeFuncDecl(self.extensionUnmarshalPrototype))
-
- def onBeginFeature(self, featureName, featureType):
- VulkanWrapperGenerator.onBeginFeature(self, featureName, featureType)
- self.currentFeature = featureName
-
- def onGenType(self, typeXml, name, alias):
- VulkanWrapperGenerator.onGenType(self, typeXml, name, alias)
-
- if name in self.knownDefs:
- return
-
- category = self.typeInfo.categoryOf(name)
-
- if category in ["struct", "union"] and alias:
- if self.variant != "host":
- self.module.appendHeader(
- self.cgenHeader.makeFuncAlias(API_PREFIX_RESERVEDMARSHAL + name,
- API_PREFIX_RESERVEDMARSHAL + alias))
- if self.variant != "guest":
- self.module.appendHeader(
- self.cgenHeader.makeFuncAlias(API_PREFIX_RESERVEDUNMARSHAL + name,
- API_PREFIX_RESERVEDUNMARSHAL + alias))
-
- if category in ["struct", "union"] and not alias:
-
- structInfo = self.typeInfo.structs[name]
-
- marshalParams = self.marshalingParams + \
- [makeVulkanTypeSimple(True, name, 1, MARSHAL_INPUT_VAR_NAME),
- self.ptrVarType]
-
- freeParams = []
- letParams = []
-
- for (envname, bindingInfo) in list(sorted(structInfo.environment.items(), key = lambda kv: kv[0])):
- if None == bindingInfo["binding"]:
- freeParams.append(makeVulkanTypeSimple(True, bindingInfo["type"], 0, envname))
- else:
- if not bindingInfo["structmember"]:
- letParams.append(makeVulkanTypeSimple(True, bindingInfo["type"], 0, envname))
-
- marshalPrototype = \
- VulkanAPI(API_PREFIX_RESERVEDMARSHAL + name,
- STREAM_RET_TYPE,
- marshalParams + freeParams)
-
- marshalPrototypeNoFilter = \
- VulkanAPI(API_PREFIX_RESERVEDMARSHAL + name,
- STREAM_RET_TYPE,
- marshalParams)
-
- def structMarshalingCustom(cgen):
- self.writeCodegen.cgen = cgen
- self.writeCodegen.currentStructInfo = structInfo
- marshalingCode = \
- CUSTOM_MARSHAL_TYPES[name]["common"] + \
- CUSTOM_MARSHAL_TYPES[name]["reservedmarshaling"].format(
- streamVarName=self.writeCodegen.streamVarName,
- rootTypeVarName=self.writeCodegen.rootTypeVarName,
- inputVarName=self.writeCodegen.inputVarName,
- newInputVarName=self.writeCodegen.inputVarName + "_new")
- for line in marshalingCode.split('\n'):
- cgen.line(line)
-
- def structMarshalingDef(cgen):
- self.writeCodegen.cgen = cgen
- self.writeCodegen.currentStructInfo = structInfo
- self.writeCodegen.cgen.stmt("(void)%s" % VULKAN_STREAM_VAR_NAME)
- self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME)
-
- if category == "struct":
- # marshal 'let' parameters first
- for letp in letParams:
- self.writeCodegen.streamLetParameter(self.typeInfo, letp)
-
- for member in structInfo.members:
- iterateVulkanType(self.typeInfo, member, self.writeCodegen)
- if category == "union":
- iterateVulkanType(self.typeInfo, structInfo.members[0], self.writeCodegen)
-
- def structMarshalingDefNoFilter(cgen):
- self.writeCodegen.cgen = cgen
- self.writeCodegen.currentStructInfo = structInfo
- self.writeCodegen.doFiltering = False
- self.writeCodegen.cgen.stmt("(void)%s" % VULKAN_STREAM_VAR_NAME)
- self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME)
-
- if category == "struct":
- # marshal 'let' parameters first
- for letp in letParams:
- self.writeCodegen.streamLetParameter(self.typeInfo, letp)
-
- for member in structInfo.members:
- iterateVulkanType(self.typeInfo, member, self.writeCodegen)
- if category == "union":
- iterateVulkanType(self.typeInfo, structInfo.members[0], self.writeCodegen)
- self.writeCodegen.doFiltering = True
-
- if self.variant != "host":
- self.module.appendHeader(
- self.cgenHeader.makeFuncDecl(marshalPrototype))
-
- if name in CUSTOM_MARSHAL_TYPES:
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- marshalPrototype, structMarshalingCustom))
- else:
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- marshalPrototype, structMarshalingDef))
-
- if freeParams != []:
- self.module.appendHeader(
- self.cgenHeader.makeFuncDecl(marshalPrototypeNoFilter))
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- marshalPrototypeNoFilter, structMarshalingDefNoFilter))
-
- unmarshalPrototype = \
- VulkanAPI(API_PREFIX_RESERVEDUNMARSHAL + name,
- STREAM_RET_TYPE,
- self.marshalingParams + [makeVulkanTypeSimple(False, name, 1, UNMARSHAL_INPUT_VAR_NAME), self.ptrVarTypeUnmarshal] + freeParams)
-
- unmarshalPrototypeNoFilter = \
- VulkanAPI(API_PREFIX_RESERVEDUNMARSHAL + name,
- STREAM_RET_TYPE,
- self.marshalingParams + [makeVulkanTypeSimple(False, name, 1, UNMARSHAL_INPUT_VAR_NAME), self.ptrVarTypeUnmarshal])
-
- def structUnmarshalingCustom(cgen):
- self.readCodegen.cgen = cgen
- self.readCodegen.currentStructInfo = structInfo
- unmarshalingCode = \
- CUSTOM_MARSHAL_TYPES[name]["common"] + \
- CUSTOM_MARSHAL_TYPES[name]["reservedunmarshaling"].format(
- streamVarName=self.readCodegen.streamVarName,
- rootTypeVarName=self.readCodegen.rootTypeVarName,
- inputVarName=self.readCodegen.inputVarName,
- newInputVarName=self.readCodegen.inputVarName + "_new")
- for line in unmarshalingCode.split('\n'):
- cgen.line(line)
-
- def structUnmarshalingDef(cgen):
- self.readCodegen.cgen = cgen
- self.readCodegen.currentStructInfo = structInfo
- if category == "struct":
- # unmarshal 'let' parameters first
- for letp in letParams:
- self.readCodegen.streamLetParameter(self.typeInfo, letp)
-
- for member in structInfo.members:
- iterateVulkanType(self.typeInfo, member, self.readCodegen)
- if category == "union":
- iterateVulkanType(self.typeInfo, structInfo.members[0], self.readCodegen)
-
- def structUnmarshalingDefNoFilter(cgen):
- self.readCodegen.cgen = cgen
- self.readCodegen.currentStructInfo = structInfo
- self.readCodegen.doFiltering = False
- if category == "struct":
- # unmarshal 'let' parameters first
- for letp in letParams:
- iterateVulkanType(self.typeInfo, letp, self.readCodegen)
- for member in structInfo.members:
- iterateVulkanType(self.typeInfo, member, self.readCodegen)
- if category == "union":
- iterateVulkanType(self.typeInfo, structInfo.members[0], self.readCodegen)
- self.readCodegen.doFiltering = True
-
- if self.variant != "guest":
- self.module.appendHeader(
- self.cgenHeader.makeFuncDecl(unmarshalPrototype))
-
- if name in CUSTOM_MARSHAL_TYPES:
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- unmarshalPrototype, structUnmarshalingCustom))
- else:
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- unmarshalPrototype, structUnmarshalingDef))
-
- if freeParams != []:
- self.module.appendHeader(
- self.cgenHeader.makeFuncDecl(unmarshalPrototypeNoFilter))
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- unmarshalPrototypeNoFilter, structUnmarshalingDefNoFilter))
-
- def onGenCmd(self, cmdinfo, name, alias):
- VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
-
- def doExtensionStructMarshalingCodegen(self, cgen, retType, extParam, forEach, funcproto, direction):
- accessVar = "structAccess"
- sizeVar = "currExtSize"
- cgen.stmt("VkInstanceCreateInfo* %s = (VkInstanceCreateInfo*)(%s)" % (accessVar, extParam.paramName))
- cgen.stmt("uint32_t %s = %s(%s->getFeatureBits(), %s, %s)" % (sizeVar, EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME, VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, extParam.paramName))
-
- cgen.beginIf("!%s && %s" % (sizeVar, extParam.paramName))
-
- cgen.line("// unknown struct extension; skip and call on its pNext field");
- cgen.funcCall(None, funcproto.name, ["vkStream", ROOT_TYPE_VAR_NAME, "(void*)%s->pNext" % accessVar, self.ptrVarName])
- cgen.stmt("return")
-
- cgen.endIf()
- cgen.beginElse()
-
- cgen.line("// known or null extension struct")
-
- if direction == "write":
- cgen.stmt("memcpy(*%s, &%s, sizeof(uint32_t));" % (self.ptrVarName, sizeVar))
- cgen.stmt("android::base::Stream::toBe32((uint8_t*)*%s); *%s += sizeof(uint32_t)" % (self.ptrVarName, self.ptrVarName))
- elif not self.dynAlloc:
- cgen.stmt("memcpy(&%s, *%s, sizeof(uint32_t));" % (sizeVar, self.ptrVarName))
- cgen.stmt("android::base::Stream::fromBe32((uint8_t*)&%s); *%s += sizeof(uint32_t)" % (sizeVar, self.ptrVarName))
-
- cgen.beginIf("!%s" % (sizeVar))
- cgen.line("// exit if this was a null extension struct (size == 0 in this branch)")
- cgen.stmt("return")
- cgen.endIf()
-
- cgen.endIf()
-
- # Now we can do stream stuff
- if direction == "write":
- cgen.stmt("memcpy(*%s, %s, sizeof(VkStructureType)); *%s += sizeof(VkStructureType)" % (self.ptrVarName, extParam.paramName, self.ptrVarName))
- elif not self.dynAlloc:
- cgen.stmt("uint64_t pNext_placeholder")
- placeholderAccess = "(&pNext_placeholder)"
- cgen.stmt("memcpy(%s, *%s, sizeof(VkStructureType)); *%s += sizeof(VkStructureType)" % (placeholderAccess, self.ptrVarName, self.ptrVarName))
- cgen.stmt("(void)pNext_placeholder")
-
- def fatalDefault(cgen):
- cgen.line("// fatal; the switch is only taken if the extension struct is known");
- cgen.stmt("abort()")
- pass
-
- self.emitForEachStructExtension(
- cgen,
- retType,
- extParam,
- forEach,
- defaultEmit=fatalDefault,
- rootTypeVar=ROOT_TYPE_PARAM)
-
- def onEnd(self,):
- VulkanWrapperGenerator.onEnd(self)
-
- def forEachExtensionMarshal(ext, castedAccess, cgen):
- cgen.funcCall(None, API_PREFIX_RESERVEDMARSHAL + ext.name,
- [VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, castedAccess, self.ptrVarName])
-
- def forEachExtensionUnmarshal(ext, castedAccess, cgen):
- cgen.funcCall(None, API_PREFIX_RESERVEDUNMARSHAL + ext.name,
- [VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, castedAccess, self.ptrVarName])
-
- if self.variant != "host":
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- self.extensionMarshalPrototype,
- lambda cgen: self.doExtensionStructMarshalingCodegen(
- cgen,
- STREAM_RET_TYPE,
- STRUCT_EXTENSION_PARAM,
- forEachExtensionMarshal,
- self.extensionMarshalPrototype,
- "write")))
-
- if self.variant != "guest":
- self.module.appendImpl(
- self.cgenImpl.makeFuncImpl(
- self.extensionUnmarshalPrototype,
- lambda cgen: self.doExtensionStructMarshalingCodegen(
- cgen,
- STREAM_RET_TYPE,
- STRUCT_EXTENSION_PARAM_FOR_WRITE,
- forEachExtensionUnmarshal,
- self.extensionUnmarshalPrototype,
- "read")))
diff --git a/codegen/vulkan/scripts/cereal/subdecode.py b/codegen/vulkan/scripts/cereal/subdecode.py
deleted file mode 100644
index b77cad77..00000000
--- a/codegen/vulkan/scripts/cereal/subdecode.py
+++ /dev/null
@@ -1,395 +0,0 @@
-from .common.codegen import CodeGen, VulkanWrapperGenerator
-from .common.vulkantypes import VulkanAPI, iterateVulkanType, VulkanType
-
-from .reservedmarshaling import VulkanReservedMarshalingCodegen
-from .transform import TransformCodegen
-
-from .wrapperdefs import API_PREFIX_RESERVEDUNMARSHAL
-from .wrapperdefs import MAX_PACKET_LENGTH
-from .wrapperdefs import ROOT_TYPE_DEFAULT_VALUE
-
-
-decoder_decl_preamble = """
-"""
-
-decoder_impl_preamble = """
-"""
-
-global_state_prefix = "this->on_"
-
-READ_STREAM = "readStream"
-WRITE_STREAM = "vkStream"
-
-# Driver workarounds for APIs that don't work well multithreaded
-driver_workarounds_global_lock_apis = [
- "vkCreatePipelineLayout",
- "vkDestroyPipelineLayout",
-]
-
-MAX_STACK_ITEMS = "16"
-
-
-def emit_param_decl_for_reading(param, cgen):
- if param.staticArrExpr:
- cgen.stmt(
- cgen.makeRichCTypeDecl(param.getForNonConstAccess()))
- else:
- cgen.stmt(
- cgen.makeRichCTypeDecl(param))
-
- if param.pointerIndirectionLevels > 0:
- lenAccess = cgen.generalLengthAccess(param)
- if not lenAccess:
- lenAccess = "1"
- arrSize = "1" if "1" == lenAccess else "MAX_STACK_ITEMS"
-
- typeHere = "uint8_t*" if "void" == param.typeName else param.typeName
- cgen.stmt("%s%s stack_%s[%s]" % (
- typeHere, "*" * (param.pointerIndirectionLevels - 1), param.paramName, arrSize))
-
-
-def emit_unmarshal(typeInfo, param, cgen, output=False, destroy=False, noUnbox=False):
- if destroy:
- iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
- cgen,
- READ_STREAM,
- ROOT_TYPE_DEFAULT_VALUE,
- param.paramName,
- "readStreamPtrPtr",
- API_PREFIX_RESERVEDUNMARSHAL,
- "",
- direction="read",
- dynAlloc=True))
- lenAccess = cgen.generalLengthAccess(param)
- lenAccessGuard = cgen.generalLengthAccessGuard(param)
- if None == lenAccess or "1" == lenAccess:
- cgen.stmt("boxed_%s_preserve = %s" %
- (param.paramName, param.paramName))
- cgen.stmt("%s = unbox_%s(%s)" %
- (param.paramName, param.typeName, param.paramName))
- else:
- if lenAccessGuard is not None:
- self.cgen.beginIf(lenAccessGuard)
- cgen.beginFor("uint32_t i = 0", "i < %s" % lenAccess, "++i")
- cgen.stmt("boxed_%s_preserve[i] = %s[i]" %
- (param.paramName, param.paramName))
- cgen.stmt("((%s*)(%s))[i] = unbox_%s(%s[i])" % (param.typeName,
- param.paramName, param.typeName, param.paramName))
- cgen.endFor()
- if lenAccessGuard is not None:
- self.cgen.endIf()
- else:
- if noUnbox:
- cgen.line("// No unbox for %s" % (param.paramName))
-
- lenAccess = cgen.generalLengthAccess(param)
- if not lenAccess:
- lenAccess = "1"
- arrSize = "1" if "1" == lenAccess else "MAX_STACK_ITEMS"
-
- iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
- cgen,
- READ_STREAM,
- ROOT_TYPE_DEFAULT_VALUE,
- param.paramName,
- "readStreamPtrPtr",
- API_PREFIX_RESERVEDUNMARSHAL,
- "" if (output or noUnbox) else "unbox_",
- direction="read",
- dynAlloc=True,
- stackVar="stack_%s" % param.paramName,
- stackArrSize=arrSize))
-
-
-def emit_dispatch_unmarshal(typeInfo, param, cgen, globalWrapped):
- if globalWrapped:
- cgen.stmt(
- "// Begin global wrapped dispatchable handle unboxing for %s" % param.paramName)
- iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
- cgen,
- READ_STREAM,
- ROOT_TYPE_DEFAULT_VALUE,
- param.paramName,
- "readStreamPtrPtr",
- API_PREFIX_RESERVEDUNMARSHAL,
- "",
- direction="read",
- dynAlloc=True))
- else:
- cgen.stmt(
- "// Begin non wrapped dispatchable handle unboxing for %s" % param.paramName)
- # cgen.stmt("%s->unsetHandleMapping()" % READ_STREAM)
- iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
- cgen,
- READ_STREAM,
- ROOT_TYPE_DEFAULT_VALUE,
- param.paramName,
- "readStreamPtrPtr",
- API_PREFIX_RESERVEDUNMARSHAL,
- "",
- direction="read",
- dynAlloc=True))
- cgen.stmt("auto unboxed_%s = unbox_%s(%s)" %
- (param.paramName, param.typeName, param.paramName))
- cgen.stmt("auto vk = dispatch_%s(%s)" %
- (param.typeName, param.paramName))
- cgen.stmt("// End manual dispatchable handle unboxing for %s" %
- param.paramName)
-
-
-def emit_transform(typeInfo, param, cgen, variant="tohost"):
- res = \
- iterateVulkanType(typeInfo, param, TransformCodegen(
- cgen, param.paramName, "globalstate", "transform_%s_" % variant, variant))
- if not res:
- cgen.stmt("(void)%s" % param.paramName)
-
-# Everything here elides the initial arg
-
-
-class DecodingParameters(object):
- def __init__(self, api: VulkanAPI):
- self.params: list[VulkanType] = []
- self.toRead: list[VulkanType] = []
- self.toWrite: list[VulkanType] = []
-
- for i, param in enumerate(api.parameters[1:]):
- if i == 0 and param.isDispatchableHandleType():
- param.dispatchHandle = True
-
- if param.isNonDispatchableHandleType() and param.isCreatedBy(api):
- param.nonDispatchableHandleCreate = True
-
- if param.isNonDispatchableHandleType() and param.isDestroyedBy(api):
- param.nonDispatchableHandleDestroy = True
-
- if param.isDispatchableHandleType() and param.isCreatedBy(api):
- param.dispatchableHandleCreate = True
-
- if param.isDispatchableHandleType() and param.isDestroyedBy(api):
- param.dispatchableHandleDestroy = True
-
- self.toRead.append(param)
-
- if param.possiblyOutput():
- self.toWrite.append(param)
-
- self.params.append(param)
-
-
-def emit_call_log(api, cgen):
- decodingParams = DecodingParameters(api)
- paramsToRead = decodingParams.toRead
-
- # cgen.beginIf("m_logCalls")
- paramLogFormat = "%p"
- paramLogArgs = ["(void*)boxed_dispatchHandle"]
-
- for p in paramsToRead:
- paramLogFormat += "0x%llx "
- for p in paramsToRead:
- paramLogArgs.append("(unsigned long long)%s" % (p.paramName))
- # cgen.stmt("fprintf(stderr, \"substream %%p: call %s %s\\n\", readStream, %s)" % (api.name, paramLogFormat, ", ".join(paramLogArgs)))
- # cgen.endIf()
-
-
-def emit_decode_parameters(typeInfo, api, cgen, globalWrapped=False):
-
- decodingParams = DecodingParameters(api)
-
- paramsToRead = decodingParams.toRead
-
- for p in paramsToRead:
- emit_param_decl_for_reading(p, cgen)
-
- i = 0
- for p in paramsToRead:
- lenAccess = cgen.generalLengthAccess(p)
-
- if p.dispatchHandle:
- emit_dispatch_unmarshal(typeInfo, p, cgen, globalWrapped)
- else:
- destroy = p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy
- noUnbox = False
-
- if p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy:
- destroy = True
- cgen.stmt(
- "// Begin manual non dispatchable handle destroy unboxing for %s" % p.paramName)
- if None == lenAccess or "1" == lenAccess:
- cgen.stmt("%s boxed_%s_preserve" %
- (p.typeName, p.paramName))
- else:
- cgen.stmt("%s* boxed_%s_preserve; %s->alloc((void**)&boxed_%s_preserve, %s * sizeof(%s))" %
- (p.typeName, p.paramName, READ_STREAM, p.paramName, lenAccess, p.typeName))
-
- if p.possiblyOutput():
- cgen.stmt(
- "// Begin manual dispatchable handle unboxing for %s" % p.paramName)
- cgen.stmt("%s->unsetHandleMapping()" % READ_STREAM)
-
- emit_unmarshal(typeInfo, p, cgen, output=p.possiblyOutput(
- ), destroy=destroy, noUnbox=noUnbox)
- i += 1
-
- for p in paramsToRead:
- emit_transform(typeInfo, p, cgen, variant="tohost")
-
- emit_call_log(api, cgen)
-
-
-def emit_dispatch_call(api, cgen):
-
- decodingParams = DecodingParameters(api)
-
- customParams = ["(VkCommandBuffer)dispatchHandle"]
-
- for (i, p) in enumerate(api.parameters[1:]):
- customParam = p.paramName
- if decodingParams.params[i].dispatchHandle:
- customParam = "unboxed_%s" % p.paramName
- customParams.append(customParam)
-
- if api.name in driver_workarounds_global_lock_apis:
- cgen.stmt("lock()")
-
- cgen.vkApiCall(api, customPrefix="vk->", customParameters=customParams,
- checkForDeviceLost=True, globalStatePrefix=global_state_prefix,
- checkForOutOfMemory=True)
-
- if api.name in driver_workarounds_global_lock_apis:
- cgen.stmt("unlock()")
-
-
-def emit_global_state_wrapped_call(api, cgen, context=False):
- customParams = ["pool", "(VkCommandBuffer)(boxed_dispatchHandle)"] + \
- list(map(lambda p: p.paramName, api.parameters[1:]))
- if context:
- customParams += ["context"];
- cgen.vkApiCall(api, customPrefix=global_state_prefix,
- customParameters=customParams, checkForDeviceLost=True,
- checkForOutOfMemory=True, globalStatePrefix=global_state_prefix)
-
-
-def emit_default_decoding(typeInfo, api, cgen):
- emit_decode_parameters(typeInfo, api, cgen)
- emit_dispatch_call(api, cgen)
-
-
-def emit_global_state_wrapped_decoding(typeInfo, api, cgen):
- emit_decode_parameters(typeInfo, api, cgen, globalWrapped=True)
- emit_global_state_wrapped_call(api, cgen)
-
-def emit_global_state_wrapped_decoding_with_context(typeInfo, api, cgen):
- emit_decode_parameters(typeInfo, api, cgen, globalWrapped=True)
- emit_global_state_wrapped_call(api, cgen, context=True)
-
-custom_decodes = {
- "vkCmdCopyBufferToImage": emit_global_state_wrapped_decoding_with_context,
- "vkCmdCopyImage": emit_global_state_wrapped_decoding,
- "vkCmdCopyImageToBuffer": emit_global_state_wrapped_decoding,
- "vkCmdExecuteCommands": emit_global_state_wrapped_decoding,
- "vkBeginCommandBuffer": emit_global_state_wrapped_decoding_with_context,
- "vkEndCommandBuffer": emit_global_state_wrapped_decoding_with_context,
- "vkResetCommandBuffer": emit_global_state_wrapped_decoding,
- "vkCmdPipelineBarrier": emit_global_state_wrapped_decoding,
- "vkCmdBindPipeline": emit_global_state_wrapped_decoding,
- "vkCmdBindDescriptorSets": emit_global_state_wrapped_decoding,
- "vkCmdCopyQueryPoolResults": emit_global_state_wrapped_decoding,
- "vkBeginCommandBufferAsyncGOOGLE": emit_global_state_wrapped_decoding_with_context,
- "vkEndCommandBufferAsyncGOOGLE": emit_global_state_wrapped_decoding_with_context,
- "vkResetCommandBufferAsyncGOOGLE": emit_global_state_wrapped_decoding,
- "vkCommandBufferHostSyncGOOGLE": emit_global_state_wrapped_decoding,
-}
-
-
-class VulkanSubDecoder(VulkanWrapperGenerator):
- def __init__(self, module, typeInfo):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
- self.typeInfo = typeInfo
- self.cgen = CodeGen()
-
- def onBegin(self,):
- self.module.appendImpl(
- "#define MAX_STACK_ITEMS %s\n" % MAX_STACK_ITEMS)
-
- self.module.appendImpl(
- "#define MAX_PACKET_LENGTH %s\n" % MAX_PACKET_LENGTH)
-
- self.module.appendImpl(
- "size_t subDecode(VulkanMemReadingStream* readStream, VulkanDispatch* vk, void* boxed_dispatchHandle, void* dispatchHandle, VkDeviceSize dataSize, const void* pData, const VkDecoderContext& context)\n")
-
- self.cgen.beginBlock() # function body
-
- self.cgen.stmt("auto& metricsLogger = *context.metricsLogger")
- self.cgen.stmt("uint32_t count = 0")
- self.cgen.stmt("unsigned char *buf = (unsigned char *)pData")
- self.cgen.stmt("android::base::BumpPool* pool = readStream->pool()")
- self.cgen.stmt("unsigned char *ptr = (unsigned char *)pData")
- self.cgen.stmt(
- "const unsigned char* const end = (const unsigned char*)buf + dataSize")
- self.cgen.stmt(
- "VkDecoderGlobalState* globalstate = VkDecoderGlobalState::get()")
-
- self.cgen.line("while (end - ptr >= 8)")
- self.cgen.beginBlock() # while loop
-
- self.cgen.stmt("uint32_t opcode = *(uint32_t *)ptr")
- self.cgen.stmt("uint32_t packetLen = *(uint32_t *)(ptr + 4)")
- self.cgen.line("""
- // packetLen should be at least 8 (op code and packet length) and should not be excessively large
- if (packetLen < 8 || packetLen > MAX_PACKET_LENGTH) {
- WARN("Bad packet length %d detected, subdecode may fail", packetLen);
- metricsLogger.logMetricEvent(MetricEventBadPacketLength{ .len = packetLen });
- }
- """)
- self.cgen.stmt("if (end - ptr < packetLen) return ptr - (unsigned char*)buf")
-
-
- self.cgen.stmt("%s->setBuf((uint8_t*)(ptr + 8))" % READ_STREAM)
- self.cgen.stmt(
- "uint8_t* readStreamPtr = %s->getBuf(); uint8_t** readStreamPtrPtr = &readStreamPtr" % READ_STREAM)
- self.cgen.line("switch (opcode)")
- self.cgen.beginBlock() # switch stmt
-
- self.module.appendImpl(self.cgen.swapCode())
-
- def onGenCmd(self, cmdinfo, name, alias):
- typeInfo = self.typeInfo
- cgen = self.cgen
- api = typeInfo.apis[name]
-
- if "commandBuffer" != api.parameters[0].paramName:
- return
-
- cgen.line("case OP_%s:" % name)
- cgen.beginBlock()
- cgen.stmt("android::base::beginTrace(\"%s subdecode\")" % name)
-
- if api.name in custom_decodes.keys():
- custom_decodes[api.name](typeInfo, api, cgen)
- else:
- emit_default_decoding(typeInfo, api, cgen)
-
- cgen.stmt("android::base::endTrace()")
- cgen.stmt("break")
- cgen.endBlock()
- self.module.appendImpl(self.cgen.swapCode())
-
- def onEnd(self,):
- self.cgen.line("default:")
- self.cgen.beginBlock()
- self.cgen.stmt(
- "GFXSTREAM_ABORT(::emugl::FatalError(::emugl::ABORT_REASON_OTHER)) << \"Unrecognized opcode \" << opcode")
- self.cgen.endBlock()
-
- self.cgen.endBlock() # switch stmt
-
- self.cgen.stmt("++count; if (count % 1000 == 0) { pool->freeAll(); }")
- self.cgen.stmt("ptr += packetLen")
- self.cgen.endBlock() # while loop
-
- self.cgen.stmt("pool->freeAll()")
- self.cgen.stmt("return ptr - (unsigned char*)buf;")
- self.cgen.endBlock() # function body
- self.module.appendImpl(self.cgen.swapCode())
diff --git a/codegen/vulkan/scripts/cereal/testing.py b/codegen/vulkan/scripts/cereal/testing.py
deleted file mode 100644
index 898532fc..00000000
--- a/codegen/vulkan/scripts/cereal/testing.py
+++ /dev/null
@@ -1,399 +0,0 @@
-# Copyright (c) 2018 The Android Open Source Project
-# Copyright (c) 2018 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from copy import copy
-
-from .common.codegen import CodeGen
-from .common.vulkantypes import \
- VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, VulkanTypeIterator
-
-from .wrapperdefs import VulkanWrapperGenerator
-from .wrapperdefs import EQUALITY_VAR_NAMES
-from .wrapperdefs import EQUALITY_ON_FAIL_VAR
-from .wrapperdefs import EQUALITY_ON_FAIL_VAR_TYPE
-from .wrapperdefs import EQUALITY_RET_TYPE
-from .wrapperdefs import API_PREFIX_EQUALITY
-from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM2
-
-class VulkanEqualityCodegen(VulkanTypeIterator):
-
- def __init__(self, cgen, inputVars, onFailCompareVar, prefix):
- self.cgen = cgen
- self.inputVars = inputVars
- self.onFailCompareVar = onFailCompareVar
- self.prefix = prefix
-
- def makeAccess(varName, asPtr = True):
- return lambda t: self.cgen.generalAccess(t, parentVarName = varName, asPtr = asPtr)
-
- def makeLengthAccess(varName):
- return lambda t: self.cgen.generalLengthAccess(t, parentVarName = varName)
-
- def makeLengthAccessGuard(varName):
- return lambda t: self.cgen.generalLengthAccessGuard(t, parentVarName=varName)
-
- self.exprAccessorLhs = makeAccess(self.inputVars[0])
- self.exprAccessorRhs = makeAccess(self.inputVars[1])
-
- self.exprAccessorValueLhs = makeAccess(self.inputVars[0], asPtr = False)
- self.exprAccessorValueRhs = makeAccess(self.inputVars[1], asPtr = False)
-
- self.lenAccessorLhs = makeLengthAccess(self.inputVars[0])
- self.lenAccessorRhs = makeLengthAccess(self.inputVars[1])
-
- self.lenAccessGuardLhs = makeLengthAccessGuard(self.inputVars[0])
- self.lenAccessGuardRhs = makeLengthAccessGuard(self.inputVars[1])
-
- self.checked = False
-
- def getTypeForCompare(self, vulkanType):
- res = copy(vulkanType)
-
- if not vulkanType.accessibleAsPointer():
- res = res.getForAddressAccess()
-
- if vulkanType.staticArrExpr:
- res = res.getForAddressAccess()
-
- return res
-
- def makeCastExpr(self, vulkanType):
- return "(%s)" % (
- self.cgen.makeCTypeDecl(vulkanType, useParamName=False))
-
- def makeEqualExpr(self, lhs, rhs):
- return "(%s) == (%s)" % (lhs, rhs)
-
- def makeEqualBufExpr(self, lhs, rhs, size):
- return "(memcmp(%s, %s, %s) == 0)" % (lhs, rhs, size)
-
- def makeEqualStringExpr(self, lhs, rhs):
- return "(strcmp(%s, %s) == 0)" % (lhs, rhs)
-
- def makeBothNotNullExpr(self, lhs, rhs):
- return "(%s) && (%s)" % (lhs, rhs)
-
- def makeBothNullExpr(self, lhs, rhs):
- return "!(%s) && !(%s)" % (lhs, rhs)
-
- def compareWithConsequence(self, compareExpr, vulkanType, errMsg=""):
- self.cgen.stmt("if (!(%s)) { %s(\"%s (Error: %s)\"); }" %
- (compareExpr, self.onFailCompareVar,
- self.exprAccessorValueLhs(vulkanType), errMsg))
-
- def onCheck(self, vulkanType):
-
- self.checked = True
-
- accessLhs = self.exprAccessorLhs(vulkanType)
- accessRhs = self.exprAccessorRhs(vulkanType)
-
- bothNull = self.makeBothNullExpr(accessLhs, accessRhs)
- bothNotNull = self.makeBothNotNullExpr(accessLhs, accessRhs)
- nullMatchExpr = "(%s) || (%s)" % (bothNull, bothNotNull)
-
- self.compareWithConsequence( \
- nullMatchExpr,
- vulkanType,
- "Mismatch in optional field")
-
- skipStreamInternal = vulkanType.typeName == "void"
-
- if skipStreamInternal:
- return
-
- self.cgen.beginIf("%s && %s" % (accessLhs, accessRhs))
-
- def endCheck(self, vulkanType):
-
- skipStreamInternal = vulkanType.typeName == "void"
- if skipStreamInternal:
- return
-
- if self.checked:
- self.cgen.endIf()
- self.checked = False
-
- def onCompoundType(self, vulkanType):
- accessLhs = self.exprAccessorLhs(vulkanType)
- accessRhs = self.exprAccessorRhs(vulkanType)
-
- lenAccessLhs = self.lenAccessorLhs(vulkanType)
- lenAccessRhs = self.lenAccessorRhs(vulkanType)
-
- lenAccessGuardLhs = self.lenAccessGuardLhs(vulkanType)
- lenAccessGuardRhs = self.lenAccessGuardRhs(vulkanType)
-
- needNullCheck = vulkanType.pointerIndirectionLevels > 0
-
- if needNullCheck:
- bothNotNullExpr = self.makeBothNotNullExpr(accessLhs, accessRhs)
- self.cgen.beginIf(bothNotNullExpr)
-
- if lenAccessLhs is not None:
- equalLenExpr = self.makeEqualExpr(lenAccessLhs, lenAccessRhs)
-
- self.compareWithConsequence( \
- equalLenExpr,
- vulkanType, "Lengths not equal")
-
- loopVar = "i"
- accessLhs = "%s + %s" % (accessLhs, loopVar)
- accessRhs = "%s + %s" % (accessRhs, loopVar)
- forInit = "uint32_t %s = 0" % loopVar
- forCond = "%s < (uint32_t)%s" % (loopVar, lenAccessLhs)
- forIncr = "++%s" % loopVar
-
- if needNullCheck:
- self.cgen.beginIf(equalLenExpr)
-
- if lenAccessGuardLhs is not None:
- self.cgen.beginIf(lenAccessGuardLhs)
-
- self.cgen.beginFor(forInit, forCond, forIncr)
-
- self.cgen.funcCall(None, self.prefix + vulkanType.typeName,
- [accessLhs, accessRhs, self.onFailCompareVar])
-
- if lenAccessLhs is not None:
- self.cgen.endFor()
- if lenAccessGuardLhs is not None:
- self.cgen.endIf()
- if needNullCheck:
- self.cgen.endIf()
-
- if needNullCheck:
- self.cgen.endIf()
-
- def onString(self, vulkanType):
- accessLhs = self.exprAccessorLhs(vulkanType)
- accessRhs = self.exprAccessorRhs(vulkanType)
-
- bothNullExpr = self.makeBothNullExpr(accessLhs, accessRhs)
- bothNotNullExpr = self.makeBothNotNullExpr(accessLhs, accessRhs)
- nullMatchExpr = "(%s) || (%s)" % (bothNullExpr, bothNotNullExpr)
-
- self.compareWithConsequence( \
- nullMatchExpr,
- vulkanType,
- "Mismatch in string pointer nullness")
-
- self.cgen.beginIf(bothNotNullExpr)
-
- self.compareWithConsequence(
- self.makeEqualStringExpr(accessLhs, accessRhs),
- vulkanType, "Unequal strings")
-
- self.cgen.endIf()
-
- def onStringArray(self, vulkanType):
- accessLhs = self.exprAccessorLhs(vulkanType)
- accessRhs = self.exprAccessorRhs(vulkanType)
-
- lenAccessLhs = self.lenAccessorLhs(vulkanType)
- lenAccessRhs = self.lenAccessorRhs(vulkanType)
-
- lenAccessGuardLhs = self.lenAccessGuardLhs(vulkanType)
- lenAccessGuardRhs = self.lenAccessGuardRhs(vulkanType)
-
- bothNullExpr = self.makeBothNullExpr(accessLhs, accessRhs)
- bothNotNullExpr = self.makeBothNotNullExpr(accessLhs, accessRhs)
- nullMatchExpr = "(%s) || (%s)" % (bothNullExpr, bothNotNullExpr)
-
- self.compareWithConsequence( \
- nullMatchExpr,
- vulkanType,
- "Mismatch in string array pointer nullness")
-
- equalLenExpr = self.makeEqualExpr(lenAccessLhs, lenAccessRhs)
-
- self.compareWithConsequence( \
- equalLenExpr,
- vulkanType, "Lengths not equal in string array")
-
- self.compareWithConsequence( \
- equalLenExpr,
- vulkanType, "Lengths not equal in string array")
-
- self.cgen.beginIf("%s && %s" % (equalLenExpr, bothNotNullExpr))
-
- loopVar = "i"
- accessLhs = "*(%s + %s)" % (accessLhs, loopVar)
- accessRhs = "*(%s + %s)" % (accessRhs, loopVar)
- forInit = "uint32_t %s = 0" % loopVar
- forCond = "%s < (uint32_t)%s" % (loopVar, lenAccessLhs)
- forIncr = "++%s" % loopVar
-
- if lenAccessGuardLhs is not None:
- self.cgen.beginIf(lenAccessGuardLhs)
-
- self.cgen.beginFor(forInit, forCond, forIncr)
-
- self.compareWithConsequence(
- self.makeEqualStringExpr(accessLhs, accessRhs),
- vulkanType, "Unequal string in string array")
-
- self.cgen.endFor()
-
- if lenAccessGuardLhs is not None:
- self.cgen.endIf()
-
- self.cgen.endIf()
-
- def onStaticArr(self, vulkanType):
- accessLhs = self.exprAccessorLhs(vulkanType)
- accessRhs = self.exprAccessorRhs(vulkanType)
-
- lenAccessLhs = self.lenAccessorLhs(vulkanType)
-
- finalLenExpr = "%s * %s" % (lenAccessLhs,
- self.cgen.sizeofExpr(vulkanType))
-
- self.compareWithConsequence(
- self.makeEqualBufExpr(accessLhs, accessRhs, finalLenExpr),
- vulkanType, "Unequal static array")
-
- def onStructExtension(self, vulkanType):
- lhs = self.exprAccessorLhs(vulkanType)
- rhs = self.exprAccessorRhs(vulkanType)
-
- self.cgen.beginIf(lhs)
- self.cgen.funcCall(None, self.prefix + "extension_struct",
- [lhs, rhs, self.onFailCompareVar])
- self.cgen.endIf()
-
- def onPointer(self, vulkanType):
- accessLhs = self.exprAccessorLhs(vulkanType)
- accessRhs = self.exprAccessorRhs(vulkanType)
-
- skipStreamInternal = vulkanType.typeName == "void"
- if skipStreamInternal:
- return
-
- lenAccessLhs = self.lenAccessorLhs(vulkanType)
- lenAccessRhs = self.lenAccessorRhs(vulkanType)
-
- if lenAccessLhs is not None:
- self.compareWithConsequence( \
- self.makeEqualExpr(lenAccessLhs, lenAccessRhs),
- vulkanType, "Lengths not equal")
-
- finalLenExpr = "%s * %s" % (lenAccessLhs,
- self.cgen.sizeofExpr(
- vulkanType.getForValueAccess()))
- else:
- finalLenExpr = self.cgen.sizeofExpr(vulkanType.getForValueAccess())
-
- self.compareWithConsequence(
- self.makeEqualBufExpr(accessLhs, accessRhs, finalLenExpr),
- vulkanType, "Unequal dyn array")
-
- def onValue(self, vulkanType):
- accessLhs = self.exprAccessorValueLhs(vulkanType)
- accessRhs = self.exprAccessorValueRhs(vulkanType)
- self.compareWithConsequence(
- self.makeEqualExpr(accessLhs, accessRhs), vulkanType,
- "Value not equal")
-
-
-class VulkanTesting(VulkanWrapperGenerator):
-
- def __init__(self, module, typeInfo):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
-
- self.codegen = CodeGen()
-
- self.equalityCodegen = \
- VulkanEqualityCodegen(
- None,
- EQUALITY_VAR_NAMES,
- EQUALITY_ON_FAIL_VAR,
- API_PREFIX_EQUALITY)
-
- self.knownDefs = {}
-
- self.extensionTestingPrototype = \
- VulkanAPI(API_PREFIX_EQUALITY + "extension_struct",
- EQUALITY_RET_TYPE,
- [STRUCT_EXTENSION_PARAM,
- STRUCT_EXTENSION_PARAM2,
- EQUALITY_ON_FAIL_VAR_TYPE])
-
- def onBegin(self,):
- VulkanWrapperGenerator.onBegin(self)
- self.module.appendImpl(self.codegen.makeFuncDecl(
- self.extensionTestingPrototype))
-
- def onGenType(self, typeXml, name, alias):
- VulkanWrapperGenerator.onGenType(self, typeXml, name, alias)
-
- if name in self.knownDefs:
- return
-
- category = self.typeInfo.categoryOf(name)
-
- if category in ["struct", "union"] and alias:
- self.module.appendHeader(
- self.codegen.makeFuncAlias(API_PREFIX_EQUALITY + name,
- API_PREFIX_EQUALITY + alias))
-
- if category in ["struct", "union"] and not alias:
-
- structInfo = self.typeInfo.structs[name]
-
- typeFromName = \
- lambda varname: makeVulkanTypeSimple(True, name, 1, varname)
-
- compareParams = \
- list(map(typeFromName, EQUALITY_VAR_NAMES)) + \
- [EQUALITY_ON_FAIL_VAR_TYPE]
-
- comparePrototype = \
- VulkanAPI(API_PREFIX_EQUALITY + name,
- EQUALITY_RET_TYPE,
- compareParams)
-
- def structCompareDef(cgen):
- self.equalityCodegen.cgen = cgen
- for member in structInfo.members:
- iterateVulkanType(self.typeInfo, member,
- self.equalityCodegen)
-
- self.module.appendHeader(
- self.codegen.makeFuncDecl(comparePrototype))
- self.module.appendImpl(
- self.codegen.makeFuncImpl(comparePrototype, structCompareDef))
-
- def onGenCmd(self, cmdinfo, name, alias):
- VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
-
- def onEnd(self,):
- VulkanWrapperGenerator.onEnd(self)
-
- def forEachExtensionCompare(ext, castedAccess, cgen):
- cgen.funcCall(None, API_PREFIX_EQUALITY + ext.name,
- [castedAccess,
- cgen.makeReinterpretCast(
- STRUCT_EXTENSION_PARAM2.paramName, ext.name),
- EQUALITY_ON_FAIL_VAR])
-
- self.module.appendImpl(
- self.codegen.makeFuncImpl(
- self.extensionTestingPrototype,
- lambda cgen: self.emitForEachStructExtension(
- cgen,
- EQUALITY_RET_TYPE,
- STRUCT_EXTENSION_PARAM,
- forEachExtensionCompare)))
diff --git a/codegen/vulkan/scripts/cereal/transform.py b/codegen/vulkan/scripts/cereal/transform.py
deleted file mode 100644
index 79aff0e3..00000000
--- a/codegen/vulkan/scripts/cereal/transform.py
+++ /dev/null
@@ -1,348 +0,0 @@
-# Copyright (c) 2018 The Android Open Source Project
-# Copyright (c) 2018 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from .common.codegen import CodeGen
-from .common.vulkantypes import \
- VulkanCompoundType, VulkanAPI, makeVulkanTypeSimple, vulkanTypeNeedsTransform, vulkanTypeGetNeededTransformTypes, VulkanTypeIterator, iterateVulkanType, vulkanTypeforEachSubType, TRIVIAL_TRANSFORMED_TYPES, NON_TRIVIAL_TRANSFORMED_TYPES, TRANSFORMED_TYPES
-
-from .wrapperdefs import VulkanWrapperGenerator
-from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM_FOR_WRITE
-
-def deviceMemoryTransform(resourceTrackerVarName, structOrApiInfo, getExpr, getLen, cgen, variant="tohost"):
- paramIndices = \
- structOrApiInfo.deviceMemoryInfoParameterIndices
-
- for _, info in paramIndices.items():
- orderedKeys = [
- "handle",
- "offset",
- "size",
- "typeIndex",
- "typeBits",]
-
- casts = {
- "handle" : "VkDeviceMemory*",
- "offset" : "VkDeviceSize*",
- "size" : "VkDeviceSize*",
- "typeIndex" : "uint32_t*",
- "typeBits" : "uint32_t*",
- }
-
- accesses = {
- "handle" : "nullptr",
- "offset" : "nullptr",
- "size" : "nullptr",
- "typeIndex" : "nullptr",
- "typeBits" : "nullptr",
- }
-
- lenAccesses = {
- "handle" : "0",
- "offset" : "0",
- "size" : "0",
- "typeIndex" : "0",
- "typeBits" : "0",
- }
-
- def doParam(i, vulkanType):
- access = getExpr(vulkanType)
- lenAccess = getLen(vulkanType)
-
- for k in orderedKeys:
- if i == info.__dict__[k]:
- accesses[k] = access
- if lenAccess is not None:
- lenAccesses[k] = lenAccess
- else:
- lenAccesses[k] = "1"
-
- vulkanTypeforEachSubType(structOrApiInfo, doParam)
-
- callParams = ", ".join( \
- ["(%s)%s, %s" % (casts[k], accesses[k], lenAccesses[k]) \
- for k in orderedKeys])
-
- if variant == "tohost":
- cgen.stmt("%s->deviceMemoryTransform_tohost(%s)" % \
- (resourceTrackerVarName, callParams))
- else:
- cgen.stmt("%s->deviceMemoryTransform_fromhost(%s)" % \
- (resourceTrackerVarName, callParams))
-
-def directTransform(resourceTrackerVarName, vulkanType, getExpr, getLen, cgen, variant="tohost"):
- access = getExpr(vulkanType)
- lenAccess = getLen(vulkanType)
-
- if lenAccess:
- finalLenAccess = lenAccess
- else:
- finalLenAccess = "1"
-
- cgen.stmt("%s->transformImpl_%s_%s(%s, %s)" % (resourceTrackerVarName,
- vulkanType.typeName, variant, access, finalLenAccess))
-
-def genTransformsForVulkanType(resourceTrackerVarName, structOrApiInfo, getExpr, getLen, cgen, variant="tohost"):
- for transform in vulkanTypeGetNeededTransformTypes(structOrApiInfo):
- if transform == "devicememory":
- deviceMemoryTransform( \
- resourceTrackerVarName,
- structOrApiInfo,
- getExpr, getLen, cgen, variant=variant)
-
-class TransformCodegen(VulkanTypeIterator):
- def __init__(self, cgen, inputVar, resourceTrackerVarName, prefix, variant):
- self.cgen = cgen
- self.inputVar = inputVar
- self.prefix = prefix
- self.resourceTrackerVarName = resourceTrackerVarName
-
- def makeAccess(varName, asPtr = True):
- return lambda t: self.cgen.generalAccess(t, parentVarName = varName, asPtr = asPtr)
-
- def makeLengthAccess(varName):
- return lambda t: self.cgen.generalLengthAccess(t, parentVarName = varName)
-
- def makeLengthAccessGuard(varName):
- return lambda t: self.cgen.generalLengthAccessGuard(t, parentVarName=varName)
-
- self.exprAccessor = makeAccess(self.inputVar)
- self.exprAccessorValue = makeAccess(self.inputVar, asPtr = False)
- self.lenAccessor = makeLengthAccess(self.inputVar)
- self.lenAccessorGuard = makeLengthAccessGuard(self.inputVar)
-
- self.checked = False
-
- self.variant = variant
-
- def makeCastExpr(self, vulkanType):
- return "(%s)" % (
- self.cgen.makeCTypeDecl(vulkanType, useParamName=False))
-
- def asNonConstCast(self, access, vulkanType):
- if vulkanType.staticArrExpr:
- casted = "%s(%s)" % (self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()), access)
- elif vulkanType.accessibleAsPointer():
- casted = "%s(%s)" % (self.makeCastExpr(vulkanType.getForNonConstAccess()), access)
- else:
- casted = "%s(%s)" % (self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()), access)
- return casted
-
- def onCheck(self, vulkanType):
- pass
-
- def endCheck(self, vulkanType):
- pass
-
- def onCompoundType(self, vulkanType):
-
- access = self.exprAccessor(vulkanType)
- lenAccess = self.lenAccessor(vulkanType)
- lenAccessGuard = self.lenAccessorGuard(vulkanType)
-
- isPtr = vulkanType.pointerIndirectionLevels > 0
-
- if lenAccessGuard is not None:
- self.cgen.beginIf(lenAccessGuard)
-
- if isPtr:
- self.cgen.beginIf(access)
-
- if lenAccess is not None:
-
- loopVar = "i"
- access = "%s + %s" % (access, loopVar)
- forInit = "uint32_t %s = 0" % loopVar
- forCond = "%s < (uint32_t)%s" % (loopVar, lenAccess)
- forIncr = "++%s" % loopVar
-
- self.cgen.beginFor(forInit, forCond, forIncr)
-
- accessCasted = self.asNonConstCast(access, vulkanType)
-
- if vulkanType.isTransformed:
- directTransform(self.resourceTrackerVarName, vulkanType, self.exprAccessor, self.lenAccessor, self.cgen, variant=self.variant)
-
- self.cgen.funcCall(None, self.prefix + vulkanType.typeName,
- [self.resourceTrackerVarName, accessCasted])
-
- if lenAccess is not None:
- self.cgen.endFor()
-
- if isPtr:
- self.cgen.endIf()
-
- if lenAccessGuard is not None:
- self.cgen.endIf()
-
- def onString(self, vulkanType):
- pass
-
- def onStringArray(self, vulkanType):
- pass
-
- def onStaticArr(self, vulkanType):
- pass
-
- def onStructExtension(self, vulkanType):
- access = self.exprAccessor(vulkanType)
-
- castedAccessExpr = "(%s)(%s)" % ("void*", access)
- self.cgen.beginIf(access)
- self.cgen.funcCall(None, self.prefix + "extension_struct",
- [self.resourceTrackerVarName, castedAccessExpr])
- self.cgen.endIf()
-
- def onPointer(self, vulkanType):
- pass
-
- def onValue(self, vulkanType):
- pass
-
-
-class VulkanTransform(VulkanWrapperGenerator):
- def __init__(self, module, typeInfo, resourceTrackerTypeName="ResourceTracker", resourceTrackerVarName="resourceTracker"):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
-
- self.codegen = CodeGen()
-
- self.transformPrefix = "transform_"
-
- self.tohostpart = "tohost"
- self.fromhostpart = "fromhost"
- self.variants = [self.tohostpart, self.fromhostpart]
-
- self.toTransformVar = "toTransform"
- self.resourceTrackerTypeName = resourceTrackerTypeName
- self.resourceTrackerVarName = resourceTrackerVarName
- self.transformParam = \
- makeVulkanTypeSimple(False, self.resourceTrackerTypeName, 1,
- self.resourceTrackerVarName)
- self.voidType = makeVulkanTypeSimple(False, "void", 0)
-
- self.extensionTransformPrototypes = []
-
- for variant in self.variants:
- self.extensionTransformPrototypes.append( \
- VulkanAPI(self.transformPrefix + variant + "_extension_struct",
- self.voidType,
- [self.transformParam, STRUCT_EXTENSION_PARAM_FOR_WRITE]))
-
- self.knownStructs = {}
- self.needsTransform = set([])
-
- def onBegin(self,):
- VulkanWrapperGenerator.onBegin(self)
- # Set up a convenience macro fro the transformed structs
- # and forward-declare the resource tracker class
- self.codegen.stmt("class %s" % self.resourceTrackerTypeName)
- self.codegen.line("#define LIST_TRIVIAL_TRANSFORMED_TYPES(f) \\")
- for name in TRIVIAL_TRANSFORMED_TYPES:
- self.codegen.line("f(%s) \\" % name)
- self.codegen.line("")
-
- self.codegen.line("#define LIST_NON_TRIVIAL_TRANSFORMED_TYPES(f) \\")
- for name in NON_TRIVIAL_TRANSFORMED_TYPES:
- self.codegen.line("f(%s) \\" % name)
- self.codegen.line("")
-
- self.codegen.line("#define LIST_TRANSFORMED_TYPES(f) \\")
- self.codegen.line("LIST_TRIVIAL_TRANSFORMED_TYPES(f) \\")
- self.codegen.line("LIST_NON_TRIVIAL_TRANSFORMED_TYPES(f) \\")
- self.codegen.line("")
-
- self.module.appendHeader(self.codegen.swapCode())
-
- for prototype in self.extensionTransformPrototypes:
- self.module.appendImpl(self.codegen.makeFuncDecl(
- prototype))
-
- def onGenType(self, typeXml, name, alias):
- VulkanWrapperGenerator.onGenType(self, typeXml, name, alias)
-
- if name in self.knownStructs:
- return
-
- category = self.typeInfo.categoryOf(name)
-
- if category in ["struct", "union"] and alias:
- for variant in self.variants:
- self.module.appendHeader(
- self.codegen.makeFuncAlias(self.transformPrefix + variant + "_" + name,
- self.transformPrefix + variant + "_" + alias))
-
- if category in ["struct", "union"] and not alias:
- structInfo = self.typeInfo.structs[name]
- self.knownStructs[name] = structInfo
-
- for variant in self.variants:
- api = VulkanAPI( \
- self.transformPrefix + variant + "_" + name,
- self.voidType,
- [self.transformParam] + \
- [makeVulkanTypeSimple( \
- False, name, 1, self.toTransformVar)])
-
- transformer = TransformCodegen(
- None,
- self.toTransformVar,
- self.resourceTrackerVarName,
- self.transformPrefix + variant + "_",
- variant)
-
- def funcDefGenerator(cgen):
- transformer.cgen = cgen
- for p in api.parameters:
- cgen.stmt("(void)%s" % p.paramName)
-
- genTransformsForVulkanType(
- self.resourceTrackerVarName,
- structInfo,
- transformer.exprAccessor,
- transformer.lenAccessor,
- cgen,
- variant=variant)
-
- for member in structInfo.members:
- iterateVulkanType(
- self.typeInfo, member,
- transformer)
-
- self.module.appendHeader(
- self.codegen.makeFuncDecl(api))
- self.module.appendImpl(
- self.codegen.makeFuncImpl(api, funcDefGenerator))
-
-
- def onGenCmd(self, cmdinfo, name, alias):
- VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
-
- def onEnd(self,):
- VulkanWrapperGenerator.onEnd(self)
-
- for (variant, prototype) in zip(self.variants, self.extensionTransformPrototypes):
- def forEachExtensionTransform(ext, castedAccess, cgen):
- if ext.isTransformed:
- directTransform(self.resourceTrackerVarName, ext, lambda _ : castedAccess, lambda _ : "1", cgen, variant);
- cgen.funcCall(None, self.transformPrefix + variant + "_" + ext.name,
- [self.resourceTrackerVarName, castedAccess])
-
- self.module.appendImpl(
- self.codegen.makeFuncImpl(
- prototype,
- lambda cgen: self.emitForEachStructExtension(
- cgen,
- self.voidType,
- STRUCT_EXTENSION_PARAM_FOR_WRITE,
- forEachExtensionTransform)))
diff --git a/codegen/vulkan/scripts/cereal/unbox.py b/codegen/vulkan/scripts/cereal/unbox.py
deleted file mode 100644
index f18fa271..00000000
--- a/codegen/vulkan/scripts/cereal/unbox.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# Copyright (c) 2018 The Android Open Source Project
-# Copyright (c) 2018 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from .common.codegen import CodeGen
-from .common.vulkantypes import \
- VulkanCompoundType, VulkanAPI, makeVulkanTypeSimple, vulkanTypeNeedsTransform, vulkanTypeGetNeededTransformTypes, VulkanTypeIterator, iterateVulkanType, vulkanTypeforEachSubType, TRANSFORMED_TYPES
-
-from .wrapperdefs import VulkanWrapperGenerator
-from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM_FOR_WRITE
-
-# This is different from others; it operations solely in terms of deepcopy and handlemap
-class VulkanUnbox(VulkanWrapperGenerator):
- def __init__(self, module, typeInfo):
- VulkanWrapperGenerator.__init__(self, module, typeInfo)
-
- self.codegen = CodeGen()
-
- self.unboxPrefix = "unbox"
- self.toUnboxVar = "toUnbox"
- self.poolParam = \
- makeVulkanTypeSimple(False, "BumpPool", 1, "pool")
-
- self.knownStructs = {}
- self.needsTransform = set([])
-
- def onBegin(self,):
- VulkanWrapperGenerator.onBegin(self)
-
- def onGenType(self, typeXml, name, alias):
- VulkanWrapperGenerator.onGenType(self, typeXml, name, alias)
-
- if name in self.knownStructs:
- return
-
- category = self.typeInfo.categoryOf(name)
-
- if category in ["struct", "union"] and alias:
- self.module.appendHeader(
- self.codegen.makeFuncAlias(self.unboxPrefix + "_" + name,
- self.unboxPrefix + "_" + alias))
-
- if category in ["struct", "union"] and not alias:
- structInfo = self.typeInfo.structs[name]
- self.knownStructs[name] = structInfo
-
- api = VulkanAPI( \
- self.unboxPrefix + "_" + name,
- makeVulkanTypeSimple(False, name, 1),
- [self.poolParam] + \
- [makeVulkanTypeSimple( \
- True, name, 1, self.toUnboxVar)])
-
- def funcDefGenerator(cgen):
- cgen.stmt("BoxedHandleUnwrapMapping unboxMapping")
- cgen.stmt("%s* res = (%s*)pool->alloc(sizeof(const %s))" % (name, name, name))
- cgen.stmt("deepcopy_%s(pool, %s, %s)" % (name, self.toUnboxVar, "res"))
- cgen.stmt("handlemap_%s(%s, %s)" % (name, "&unboxMapping", "res"))
- cgen.stmt("return res")
-
- self.module.appendHeader(
- self.codegen.makeFuncDecl(api))
- self.module.appendImpl(
- self.codegen.makeFuncImpl(api, funcDefGenerator))
-
- def onGenCmd(self, cmdinfo, name, alias):
- VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
-
- def onEnd(self,):
- VulkanWrapperGenerator.onEnd(self)
diff --git a/codegen/vulkan/scripts/cereal/vkextensionstructuretype.py b/codegen/vulkan/scripts/cereal/vkextensionstructuretype.py
deleted file mode 100644
index 8db988ae..00000000
--- a/codegen/vulkan/scripts/cereal/vkextensionstructuretype.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (c) 2022 The Android Open Source Project
-# Copyright (c) 2022 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from .wrapperdefs import VulkanWrapperGenerator
-
-
-class VulkanExtensionStructureType(VulkanWrapperGenerator):
- def __init__(self, extensionName: str, module, typeInfo):
- super().__init__(module, typeInfo)
- self._extensionName = extensionName
-
- def onGenGroup(self, groupinfo, groupName, alias=None):
- super().onGenGroup(groupinfo, groupName, alias)
- elem = groupinfo.elem
- if (not elem.get('type') == 'enum'):
- return
- if (not elem.get('name') == 'VkStructureType'):
- return
- extensionEnumFactoryMacro = f'{self._extensionName.upper()}_ENUM'
- for enum in elem.findall(f"enum[@extname='{self._extensionName}']"):
- name = enum.get('name')
- offset = enum.get('offset')
- self.module.appendHeader(
- f"#define {name} {extensionEnumFactoryMacro}(VkStructureType, {offset})\n")
-
-
-class VulkanGfxstreamStructureType(VulkanExtensionStructureType):
- def __init__(self, module, typeInfo):
- super().__init__('VK_GOOGLE_gfxstream', module, typeInfo)
-
-
-class VulkanAndroidNativeBufferStructureType(VulkanExtensionStructureType):
- def __init__(self, module, typeInfo):
- super().__init__('VK_ANDROID_native_buffer', module, typeInfo)
diff --git a/codegen/vulkan/scripts/cereal/wrapperdefs.py b/codegen/vulkan/scripts/cereal/wrapperdefs.py
deleted file mode 100644
index 9b969875..00000000
--- a/codegen/vulkan/scripts/cereal/wrapperdefs.py
+++ /dev/null
@@ -1,108 +0,0 @@
-# Copyright (c) 2018 The Android Open Source Project
-# Copyright (c) 2018 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from .common.codegen import VulkanWrapperGenerator
-from .common.vulkantypes import makeVulkanTypeSimple
-
-# Contains definitions for various Vulkan API wrappers. This information is
-# shared to make it easier for one kind of wrapper to know how to call
-# another one.
-
-API_PREFIX_MARSHAL = "marshal_"
-API_PREFIX_UNMARSHAL = "unmarshal_"
-API_PREFIX_RESERVEDMARSHAL = "reservedmarshal_"
-API_PREFIX_RESERVEDUNMARSHAL = "reservedunmarshal_"
-
-MARSHAL_INPUT_VAR_NAME = "forMarshaling"
-UNMARSHAL_INPUT_VAR_NAME = "forUnmarshaling"
-
-API_PREFIX_VALIDATE = "validate_"
-API_PREFIX_FRONTEND = "goldfish_frontend_"
-
-VULKAN_STREAM_TYPE = "VulkanStream"
-VULKAN_STREAM_TYPE_GUEST = "VulkanStreamGuest"
-VULKAN_STREAM_VAR_NAME = "vkStream"
-
-VALIDATE_RESULT_TYPE = "VkResult"
-VALIDATE_VAR_NAME = "validateResult"
-VALIDATE_GOOD_RESULT = "VK_SUCCESS"
-
-ROOT_TYPE_VAR_NAME = "rootType"
-ROOT_TYPE_DEFAULT_VALUE = "VK_STRUCTURE_TYPE_MAX_ENUM"
-ROOT_TYPE_TYPE = "VkStructureType"
-ROOT_TYPE_PARAM = makeVulkanTypeSimple(
- False, ROOT_TYPE_TYPE, 0, ROOT_TYPE_VAR_NAME)
-
-PARAMETERS_MARSHALING = [
- makeVulkanTypeSimple(False, VULKAN_STREAM_TYPE, 1, VULKAN_STREAM_VAR_NAME),
- ROOT_TYPE_PARAM,
-]
-PARAMETERS_MARSHALING_GUEST = [
- makeVulkanTypeSimple(False, VULKAN_STREAM_TYPE_GUEST,
- 1, VULKAN_STREAM_VAR_NAME),
- ROOT_TYPE_PARAM,
-]
-PARAMETERS_VALIDATE = [
- makeVulkanTypeSimple(False, VALIDATE_RESULT_TYPE, 1, VALIDATE_VAR_NAME)
-]
-PARAMETERS_COUNTING = [
- makeVulkanTypeSimple(False, "size_t", 1, VULKAN_STREAM_VAR_NAME)
-]
-
-STRUCT_EXTENSION_PARAM = \
- makeVulkanTypeSimple(True, "void", 1, "structExtension")
-
-STRUCT_EXTENSION_PARAM2 = \
- makeVulkanTypeSimple(True, "void", 1, "structExtension2")
-
-STRUCT_EXTENSION_PARAM_FOR_WRITE = \
- makeVulkanTypeSimple(False, "void", 1, "structExtension_out")
-
-STRUCT_TYPE_API_NAME = "goldfish_vk_struct_type"
-EXTENSION_SIZE_API_NAME = "goldfish_vk_extension_struct_size"
-EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME = "goldfish_vk_extension_struct_size_with_stream_features"
-
-VOID_TYPE = makeVulkanTypeSimple(False, "void", 0)
-STREAM_RET_TYPE = makeVulkanTypeSimple(False, "void", 0)
-
-API_PREFIX_EQUALITY = "checkEqual_"
-EQUALITY_VAR_NAMES = ["a", "b"]
-EQUALITY_ON_FAIL_VAR = "onFail"
-EQUALITY_ON_FAIL_VAR_TYPE = makeVulkanTypeSimple(False, "OnFailCompareFunc", 0,
- EQUALITY_ON_FAIL_VAR)
-EQUALITY_RET_TYPE = makeVulkanTypeSimple(False, "void", 0)
-
-RELAXED_APIS = [
- "vkWaitForFences",
- "vkWaitSemaphores",
- "vkWaitSemaphoresKHR",
- "vkQueueWaitIdle",
- "vkDeviceWaitIdle",
- "vkQueueFlushCommandsGOOGLE",
-]
-
-STYPE_OVERRIDE = {
- "VkPhysicalDeviceFragmentDensityMapFeaturesEXT": "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT",
- "VkPhysicalDeviceFragmentDensityMapPropertiesEXT": "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT",
- "VkRenderPassFragmentDensityMapCreateInfoEXT": "VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT",
- "VkImportColorBufferGOOGLE": "VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE",
- "VkImportBufferGOOGLE": "VK_STRUCTURE_TYPE_IMPORT_BUFFER_GOOGLE",
- "VkCreateBlobGOOGLE": "VK_STRUCTURE_TYPE_CREATE_BLOB_GOOGLE",
-}
-
-MAX_PACKET_LENGTH = "(400 * 1024 * 1024) // 400MB"
-
-
-
diff --git a/codegen/vulkan/scripts/cerealgenerator.py b/codegen/vulkan/scripts/cerealgenerator.py
deleted file mode 100644
index 02d7f220..00000000
--- a/codegen/vulkan/scripts/cerealgenerator.py
+++ /dev/null
@@ -1,802 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright (c) 2013-2018 The Khronos Group Inc.
-# Copyright (c) 2013-2018 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os, re, sys
-from generator import *
-from pathlib import Path, PurePosixPath
-
-import cereal
-from cereal.wrapperdefs import VULKAN_STREAM_TYPE
-from cereal.wrapperdefs import VULKAN_STREAM_TYPE_GUEST
-
-# CerealGenerator - generates set of driver sources
-# while being agnostic to the stream implementation
-from reg import GroupInfo, TypeInfo, EnumInfo
-
-copyrightHeader = """// Copyright (C) 2018 The Android Open Source Project
-// Copyright (C) 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-"""
-
-# We put the long generated commands in a separate paragraph, so that the formatter won't mess up
-# with other texts.
-autogeneratedHeaderTemplate = """
-// Autogenerated module %s
-//
-// %s
-//
-// Please do not modify directly;
-// re-run gfxstream-protocols/scripts/generate-vulkan-sources.sh,
-// or directly from Python by defining:
-// VULKAN_REGISTRY_XML_DIR : Directory containing vk.xml
-// VULKAN_REGISTRY_SCRIPTS_DIR : Directory containing genvk.py
-// CEREAL_OUTPUT_DIR: Where to put the generated sources.
-//
-// python3 $VULKAN_REGISTRY_SCRIPTS_DIR/genvk.py -registry $VULKAN_REGISTRY_XML_DIR/vk.xml cereal -o $CEREAL_OUTPUT_DIR
-//
-"""
-
-autogeneratedMkTemplate = """
-# Autogenerated makefile
-# %s
-# Please do not modify directly;
-# re-run gfxstream-protocols/scripts/generate-vulkan-sources.sh,
-# or directly from Python by defining:
-# VULKAN_REGISTRY_XML_DIR : Directory containing vk.xml
-# VULKAN_REGISTRY_SCRIPTS_DIR : Directory containing genvk.py
-# CEREAL_OUTPUT_DIR: Where to put the generated sources.
-# python3 $VULKAN_REGISTRY_SCRIPTS_DIR/genvk.py -registry $VULKAN_REGISTRY_XML_DIR/vk.xml cereal -o $CEREAL_OUTPUT_DIR
-"""
-
-def banner_command(argv):
- """Return sanitized command-line description.
- |argv| must be a list of command-line parameters, e.g. sys.argv.
- Return a string corresponding to the command, with platform-specific
- paths removed."""
-
- def makePosixRelative(someArg):
- if os.path.exists(someArg):
- return str(PurePosixPath(Path(os.path.relpath(someArg))))
- return someArg
-
- return ' '.join(map(makePosixRelative, argv))
-
-suppressEnabled = False
-suppressExceptModule = None
-
-def envGetOrDefault(key, default=None):
- if key in os.environ:
- return os.environ[key]
- print("envGetOrDefault: notfound: %s" % key)
- return default
-
-def init_suppress_option():
- global suppressEnabled
- global suppressExceptModule
-
- if "ANDROID_EMU_VK_CEREAL_SUPPRESS" in os.environ:
- option = os.environ["ANDROID_EMU_VK_CEREAL_SUPPRESS"]
-
- if option != "":
- suppressExceptModule = option
- suppressEnabled = True
- print("suppressEnabled: %s" % suppressExceptModule)
-
-# ---- methods overriding base class ----
-# beginFile(genOpts)
-# endFile()
-# beginFeature(interface, emit)
-# endFeature()
-# genType(typeinfo,name)
-# genStruct(typeinfo,name)
-# genGroup(groupinfo,name)
-# genEnum(enuminfo, name)
-# genCmd(cmdinfo)
-class CerealGenerator(OutputGenerator):
-
- """Generate serialization code"""
- def __init__(self, errFile = sys.stderr,
- warnFile = sys.stderr,
- diagFile = sys.stdout):
- OutputGenerator.__init__(self, errFile, warnFile, diagFile)
-
- init_suppress_option()
-
- self.typeInfo = cereal.VulkanTypeInfo(self)
-
- self.modules = {}
- self.protos = {}
- self.moduleList = []
- self.protoList = []
-
- self.wrappers = []
-
- self.codegen = cereal.CodeGen()
-
- self.guestBaseLibDirPrefix = \
- envGetOrDefault("VK_CEREAL_GUEST_BASELIB_PREFIX", "aemu/base")
- self.baseLibDirPrefix = \
- envGetOrDefault("VK_CEREAL_BASELIB_PREFIX", "aemu/base")
- self.baseLibLinkName = \
- envGetOrDefault("VK_CEREAL_BASELIB_LINKNAME", "android-emu-base")
- self.vulkanHeaderTargetName = envGetOrDefault("VK_CEREAL_VK_HEADER_TARGET", "")
- self.utilsHeader = envGetOrDefault("VK_CEREAL_UTILS_LINKNAME", "")
- self.utilsHeaderDirPrefix = envGetOrDefault("VK_CEREAL_UTILS_PREFIX", "utils")
-
- # THe host always needs all possible guest struct definitions, while the guest only needs
- # platform sepcific headers.
- self.hostCommonExtraVulkanHeaders = '#include "vk_android_native_buffer.h"'
- self.host_cmake_generator = lambda cppFiles: f"""{autogeneratedMkTemplate % banner_command(sys.argv)}
-add_library(OpenglRender_vulkan_cereal {cppFiles})
-target_compile_definitions(OpenglRender_vulkan_cereal PRIVATE -DVK_GOOGLE_gfxstream)
-if (WIN32)
- target_compile_definitions(OpenglRender_vulkan_cereal PRIVATE -DVK_USE_PLATFORM_WIN32_KHR)
-endif()
-target_link_libraries(
- OpenglRender_vulkan_cereal
- PUBLIC
- {self.baseLibLinkName}
- {self.vulkanHeaderTargetName}
- PRIVATE
- {self.utilsHeader})
-
-target_include_directories(OpenglRender_vulkan_cereal
- PUBLIC
- .
- PRIVATE
- ..
- ../..
- ../../../include)
-"""
-
- encoderInclude = f"""
-#include "{self.guestBaseLibDirPrefix}/AndroidHealthMonitor.h"
-#include "goldfish_vk_private_defs.h"
-#include <memory>
-
-namespace gfxstream {{
-class IOStream;
-}}
-"""
- encoderImplInclude = f"""
-#include "EncoderDebug.h"
-#include "IOStream.h"
-#include "Resources.h"
-#include "ResourceTracker.h"
-#include "Validation.h"
-#include "%s.h"
-
-#include "{self.guestBaseLibDirPrefix}/AlignedBuf.h"
-#include "{self.guestBaseLibDirPrefix}/BumpPool.h"
-#include "{self.guestBaseLibDirPrefix}/synchronization/AndroidLock.h"
-
-#include <cutils/properties.h>
-
-#include "goldfish_vk_marshaling_guest.h"
-#include "goldfish_vk_reserved_marshaling_guest.h"
-#include "goldfish_vk_deepcopy_guest.h"
-#include "goldfish_vk_counting_guest.h"
-#include "goldfish_vk_handlemap_guest.h"
-#include "goldfish_vk_private_defs.h"
-#include "goldfish_vk_transform_guest.h"
-
-#include <memory>
-#include <optional>
-#include <unordered_map>
-#include <string>
-#include <vector>
-
-""" % VULKAN_STREAM_TYPE_GUEST
-
- functableImplInclude = """
-#include "VkEncoder.h"
-#include "../OpenglSystemCommon/HostConnection.h"
-#include "ResourceTracker.h"
-
-#include "goldfish_vk_private_defs.h"
-
-#include <log/log.h>
-#include <cstring>
-
-// Stuff we are not going to use but if included,
-// will cause compile errors. These are Android Vulkan
-// required extensions, but the approach will be to
-// implement them completely on the guest side.
-#undef VK_KHR_android_surface
-"""
- marshalIncludeGuest = """
-#include "goldfish_vk_marshaling_guest.h"
-#include "goldfish_vk_private_defs.h"
-#include "%s.h"
-
-// Stuff we are not going to use but if included,
-// will cause compile errors. These are Android Vulkan
-// required extensions, but the approach will be to
-// implement them completely on the guest side.
-#undef VK_KHR_android_surface
-#undef VK_ANDROID_external_memory_android_hardware_buffer
-""" % VULKAN_STREAM_TYPE_GUEST
-
- reservedmarshalIncludeGuest = """
-#include "goldfish_vk_marshaling_guest.h"
-#include "goldfish_vk_private_defs.h"
-#include "%s.h"
-
-// Stuff we are not going to use but if included,
-// will cause compile errors. These are Android Vulkan
-// required extensions, but the approach will be to
-// implement them completely on the guest side.
-#undef VK_KHR_android_surface
-#undef VK_ANDROID_external_memory_android_hardware_buffer
-""" % VULKAN_STREAM_TYPE_GUEST
-
- reservedmarshalImplIncludeGuest = """
-#include "Resources.h"
-"""
-
- vulkanStreamIncludeHost = f"""
-{self.hostCommonExtraVulkanHeaders}
-#include "goldfish_vk_private_defs.h"
-
-#include "%s.h"
-#include "{self.baseLibDirPrefix}/files/StreamSerializing.h"
-""" % VULKAN_STREAM_TYPE
-
- testingInclude = f"""
-{self.hostCommonExtraVulkanHeaders}
-#include "goldfish_vk_private_defs.h"
-#include <string.h>
-#include <functional>
-using OnFailCompareFunc = std::function<void(const char*)>;
-"""
- poolInclude = f"""
-{self.hostCommonExtraVulkanHeaders}
-#include "goldfish_vk_private_defs.h"
-#include "{self.baseLibDirPrefix}/BumpPool.h"
-using android::base::Allocator;
-using android::base::BumpPool;
-"""
- handleMapInclude = f"""
-{self.hostCommonExtraVulkanHeaders}
-#include "goldfish_vk_private_defs.h"
-#include "VulkanHandleMapping.h"
-"""
- transformIncludeGuest = """
-#include "goldfish_vk_private_defs.h"
-"""
- transformInclude = f"""
-{self.hostCommonExtraVulkanHeaders}
-#include "goldfish_vk_private_defs.h"
-#include "goldfish_vk_extension_structs.h"
-"""
- transformImplIncludeGuest = """
-#include "ResourceTracker.h"
-"""
- transformImplInclude = """
-#include "VkDecoderGlobalState.h"
-"""
- deepcopyInclude = """
-#include "vk_util.h"
-"""
- poolIncludeGuest = f"""
-#include "goldfish_vk_private_defs.h"
-#include "{self.guestBaseLibDirPrefix}/BumpPool.h"
-using android::base::Allocator;
-using android::base::BumpPool;
-// Stuff we are not going to use but if included,
-// will cause compile errors. These are Android Vulkan
-// required extensions, but the approach will be to
-// implement them completely on the guest side.
-#undef VK_KHR_android_surface
-#undef VK_ANDROID_external_memory_android_hardware_buffer
-"""
- handleMapIncludeGuest = """
-#include "goldfish_vk_private_defs.h"
-#include "VulkanHandleMapping.h"
-// Stuff we are not going to use but if included,
-// will cause compile errors. These are Android Vulkan
-// required extensions, but the approach will be to
-// implement them completely on the guest side.
-#undef VK_KHR_android_surface
-#undef VK_ANDROID_external_memory_android_hardware_buffer
-"""
- dispatchHeaderDefs = f"""
-{self.hostCommonExtraVulkanHeaders}
-#include "goldfish_vk_private_defs.h"
-namespace gfxstream {{
-namespace vk {{
-
-struct VulkanDispatch;
-
-}} // namespace vk
-}} // namespace gfxstream
-using DlOpenFunc = void* (void);
-using DlSymFunc = void* (void*, const char*);
-"""
-
- extensionStructsInclude = f"""
-{self.hostCommonExtraVulkanHeaders}
-#include "goldfish_vk_private_defs.h"
-"""
-
- extensionStructsIncludeGuest = """
-#include "vk_platform_compat.h"
-#include "goldfish_vk_private_defs.h"
-// Stuff we are not going to use but if included,
-// will cause compile errors. These are Android Vulkan
-// required extensions, but the approach will be to
-// implement them completely on the guest side.
-#undef VK_KHR_android_surface
-#undef VK_ANDROID_external_memory_android_hardware_buffer
-"""
- commonCerealImplIncludes = """
-#include "goldfish_vk_extension_structs.h"
-#include "goldfish_vk_private_defs.h"
-#include <string.h>
-"""
- commonCerealIncludesGuest = """
-#include "vk_platform_compat.h"
-"""
- commonCerealImplIncludesGuest = """
-#include "goldfish_vk_extension_structs_guest.h"
-#include "goldfish_vk_private_defs.h"
-
-#include <cstring>
-"""
- countingIncludes = """
-#include "vk_platform_compat.h"
-#include "goldfish_vk_private_defs.h"
-"""
-
- dispatchImplIncludes = """
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-"""
-
- decoderSnapshotHeaderIncludes = f"""
-#include <memory>
-#include "{self.utilsHeaderDirPrefix}/GfxApiLogger.h"
-#include "{self.baseLibDirPrefix}/HealthMonitor.h"
-#include "common/goldfish_vk_private_defs.h"
-"""
- decoderSnapshotImplIncludes = f"""
-#include "VulkanHandleMapping.h"
-#include "VkDecoderGlobalState.h"
-#include "VkReconstruction.h"
-
-#include "{self.baseLibDirPrefix}/synchronization/Lock.h"
-"""
-
- decoderHeaderIncludes = f"""
-#include "VkDecoderContext.h"
-
-#include <memory>
-
-namespace android {{
-namespace base {{
-class BumpPool;
-}} // namespace android
-}} // namespace base
-
-"""
-
- decoderImplIncludes = f"""
-#include "common/goldfish_vk_marshaling.h"
-#include "common/goldfish_vk_reserved_marshaling.h"
-#include "common/goldfish_vk_private_defs.h"
-#include "common/goldfish_vk_transform.h"
-
-#include "{self.baseLibDirPrefix}/BumpPool.h"
-#include "{self.baseLibDirPrefix}/system/System.h"
-#include "{self.baseLibDirPrefix}/Tracing.h"
-#include "{self.baseLibDirPrefix}/Metrics.h"
-#include "render-utils/IOStream.h"
-#include "host/FrameBuffer.h"
-#include "host-common/feature_control.h"
-#include "host-common/GfxstreamFatalError.h"
-#include "host-common/logging.h"
-
-#include "VkDecoderGlobalState.h"
-#include "VkDecoderSnapshot.h"
-
-#include "VulkanDispatch.h"
-#include "%s.h"
-
-#include <functional>
-#include <optional>
-#include <unordered_map>
-""" % VULKAN_STREAM_TYPE
-
- def createVkExtensionStructureTypePreamble(extensionName: str) -> str:
- return f"""
-#define {extensionName}_ENUM(type,id) \
- ((type)(1000000000 + (1000 * ({extensionName}_NUMBER - 1)) + (id)))
-"""
- self.guest_encoder_tag = "guest_encoder"
- self.guest_hal_tag = "guest_hal"
- self.host_tag = "host"
-
- default_guest_abs_encoder_destination = \
- os.path.join(
- os.getcwd(),
- "..", "..",
- "device", "generic", "goldfish-opengl",
- "system", "vulkan_enc")
- self.guest_abs_encoder_destination = \
- envGetOrDefault("VK_CEREAL_GUEST_ENCODER_DIR",
- default_guest_abs_encoder_destination)
-
- default_guest_abs_hal_destination = \
- os.path.join(
- os.getcwd(),
- "..", "..",
- "device", "generic", "goldfish-opengl",
- "system", "vulkan")
- self.guest_abs_hal_destination = \
- envGetOrDefault("VK_CEREAL_GUEST_HAL_DIR",
- default_guest_abs_hal_destination)
-
- default_host_abs_decoder_destination = \
- os.path.join(
- os.getcwd(),
- "android", "android-emugl", "host",
- "libs", "libOpenglRender", "vulkan")
- self.host_abs_decoder_destination = \
- envGetOrDefault("VK_CEREAL_HOST_DECODER_DIR",
- default_host_abs_decoder_destination)
- self.host_script_destination = envGetOrDefault("VK_CEREAL_HOST_SCRIPTS_DIR")
- assert(self.host_script_destination is not None)
-
- self.addGuestEncoderModule(
- "VkEncoder",
- extraHeader = encoderInclude,
- extraImpl = encoderImplInclude)
-
- self.addGuestEncoderModule("goldfish_vk_extension_structs_guest",
- extraHeader=extensionStructsIncludeGuest)
- self.addGuestEncoderModule("goldfish_vk_marshaling_guest",
- extraHeader=commonCerealIncludesGuest + marshalIncludeGuest,
- extraImpl=commonCerealImplIncludesGuest)
- self.addGuestEncoderModule("goldfish_vk_reserved_marshaling_guest",
- extraHeader=commonCerealIncludesGuest + reservedmarshalIncludeGuest,
- extraImpl=commonCerealImplIncludesGuest + reservedmarshalImplIncludeGuest)
- self.addGuestEncoderModule("goldfish_vk_deepcopy_guest",
- extraHeader=commonCerealIncludesGuest + poolIncludeGuest,
- extraImpl=commonCerealImplIncludesGuest + deepcopyInclude)
- self.addGuestEncoderModule("goldfish_vk_counting_guest",
- extraHeader=countingIncludes,
- extraImpl=commonCerealImplIncludesGuest)
- self.addGuestEncoderModule("goldfish_vk_handlemap_guest",
- extraHeader=commonCerealIncludesGuest + handleMapIncludeGuest,
- extraImpl=commonCerealImplIncludesGuest)
- self.addGuestEncoderModule("goldfish_vk_transform_guest",
- extraHeader=commonCerealIncludesGuest + transformIncludeGuest,
- extraImpl=commonCerealImplIncludesGuest + transformImplIncludeGuest)
- self.addGuestEncoderModule(
- "vulkan_gfxstream_structure_type", headerOnly=True, suppressFeatureGuards=True,
- moduleName="vulkan_gfxstream_structure_type_guest", useNamespace=False,
- suppressVulkanHeaders=True,
- extraHeader=createVkExtensionStructureTypePreamble('VK_GOOGLE_GFXSTREAM'))
-
- self.addGuestEncoderModule("func_table", extraImpl=functableImplInclude)
-
- self.addCppModule("common", "goldfish_vk_extension_structs",
- extraHeader=extensionStructsInclude)
- self.addCppModule("common", "goldfish_vk_marshaling",
- extraHeader=vulkanStreamIncludeHost,
- extraImpl=commonCerealImplIncludes)
- self.addCppModule("common", "goldfish_vk_reserved_marshaling",
- extraHeader=vulkanStreamIncludeHost,
- extraImpl=commonCerealImplIncludes)
- self.addCppModule("common", "goldfish_vk_testing",
- extraHeader=testingInclude,
- extraImpl=commonCerealImplIncludes)
- self.addCppModule("common", "goldfish_vk_deepcopy",
- extraHeader=poolInclude,
- extraImpl=commonCerealImplIncludes + deepcopyInclude)
- self.addCppModule("common", "goldfish_vk_handlemap",
- extraHeader=handleMapInclude,
- extraImpl=commonCerealImplIncludes)
- self.addCppModule("common", "goldfish_vk_dispatch",
- extraHeader=dispatchHeaderDefs,
- extraImpl=dispatchImplIncludes)
- self.addCppModule("common", "goldfish_vk_transform",
- extraHeader=transformInclude,
- extraImpl=transformImplInclude)
- self.addHostModule("VkDecoder",
- extraHeader=decoderHeaderIncludes,
- extraImpl=decoderImplIncludes,
- useNamespace=False)
- self.addHostModule("VkDecoderSnapshot",
- extraHeader=decoderSnapshotHeaderIncludes,
- extraImpl=decoderSnapshotImplIncludes,
- useNamespace=False)
- self.addHostModule("VkSubDecoder",
- extraHeader="",
- extraImpl="",
- useNamespace=False,
- implOnly=True)
-
- self.addModule(cereal.PyScript(self.host_tag, "vulkan_printer", customAbsDir=Path(
- self.host_script_destination) / "print_gfx_logs"), moduleName="ApiLogDecoder")
- self.addHostModule(
- "vulkan_gfxstream_structure_type", headerOnly=True, suppressFeatureGuards=True,
- moduleName="vulkan_gfxstream_structure_type_host", useNamespace=False,
- suppressVulkanHeaders=True,
- extraHeader=createVkExtensionStructureTypePreamble('VK_GOOGLE_GFXSTREAM'))
- self.addHostModule(
- "vk_android_native_buffer_structure_type", headerOnly=True, suppressFeatureGuards=True,
- useNamespace=False, suppressVulkanHeaders=True,
- extraHeader=createVkExtensionStructureTypePreamble('VK_ANDROID_NATIVE_BUFFER'))
-
- self.addWrapper(cereal.VulkanEncoder, "VkEncoder")
- self.addWrapper(cereal.VulkanExtensionStructs, "goldfish_vk_extension_structs_guest")
- self.addWrapper(cereal.VulkanMarshaling, "goldfish_vk_marshaling_guest", variant = "guest")
- self.addWrapper(cereal.VulkanReservedMarshaling, "goldfish_vk_reserved_marshaling_guest", variant = "guest")
- self.addWrapper(cereal.VulkanDeepcopy, "goldfish_vk_deepcopy_guest")
- self.addWrapper(cereal.VulkanCounting, "goldfish_vk_counting_guest")
- self.addWrapper(cereal.VulkanHandleMap, "goldfish_vk_handlemap_guest")
- self.addWrapper(cereal.VulkanTransform, "goldfish_vk_transform_guest")
- self.addWrapper(cereal.VulkanFuncTable, "func_table")
- self.addWrapper(cereal.VulkanExtensionStructs, "goldfish_vk_extension_structs")
- self.addWrapper(cereal.VulkanMarshaling, "goldfish_vk_marshaling")
- self.addWrapper(cereal.VulkanReservedMarshaling, "goldfish_vk_reserved_marshaling", variant = "host")
- self.addWrapper(cereal.VulkanTesting, "goldfish_vk_testing")
- self.addWrapper(cereal.VulkanDeepcopy, "goldfish_vk_deepcopy")
- self.addWrapper(cereal.VulkanHandleMap, "goldfish_vk_handlemap")
- self.addWrapper(cereal.VulkanDispatch, "goldfish_vk_dispatch")
- self.addWrapper(cereal.VulkanTransform, "goldfish_vk_transform", resourceTrackerTypeName="VkDecoderGlobalState")
- self.addWrapper(cereal.VulkanDecoder, "VkDecoder")
- self.addWrapper(cereal.VulkanDecoderSnapshot, "VkDecoderSnapshot")
- self.addWrapper(cereal.VulkanSubDecoder, "VkSubDecoder")
- self.addWrapper(cereal.ApiLogDecoder, "ApiLogDecoder")
- self.addWrapper(cereal.VulkanGfxstreamStructureType,
- "vulkan_gfxstream_structure_type_guest")
- self.addWrapper(cereal.VulkanGfxstreamStructureType, "vulkan_gfxstream_structure_type_host")
- self.addWrapper(cereal.VulkanAndroidNativeBufferStructureType,
- "vk_android_native_buffer_structure_type")
-
- self.guestAndroidMkCppFiles = ""
- self.hostCMakeCppFiles = ""
- self.hostDecoderCMakeCppFiles = ""
-
- def addSrcEntry(m):
- mkSrcEntry = m.getMakefileSrcEntry()
- cmakeSrcEntry = m.getCMakeSrcEntry()
- if m.directory == self.guest_encoder_tag:
- self.guestAndroidMkCppFiles += mkSrcEntry
- elif m.directory == self.host_tag:
- self.hostDecoderCMakeCppFiles += cmakeSrcEntry
- elif m.directory != self.guest_hal_tag:
- self.hostCMakeCppFiles += cmakeSrcEntry
-
- self.forEachModule(addSrcEntry)
-
- def addGuestEncoderModule(
- self, basename, extraHeader="", extraImpl="", useNamespace=True, headerOnly=False,
- suppressFeatureGuards=False, moduleName=None, suppressVulkanHeaders=False):
- if not os.path.exists(self.guest_abs_encoder_destination):
- print("Path [%s] not found (guest encoder path), skipping" % self.guest_abs_encoder_destination)
- return
- self.addCppModule(self.guest_encoder_tag, basename, extraHeader=extraHeader,
- extraImpl=extraImpl, customAbsDir=self.guest_abs_encoder_destination,
- useNamespace=useNamespace, headerOnly=headerOnly,
- suppressFeatureGuards=suppressFeatureGuards, moduleName=moduleName,
- suppressVulkanHeaders=suppressVulkanHeaders)
-
- def addGuestHalModule(self, basename, extraHeader = "", extraImpl = "", useNamespace = True):
- if not os.path.exists(self.guest_abs_hal_destination):
- print("Path [%s] not found (guest encoder path), skipping" % self.guest_abs_encoder_destination)
- return
- self.addCppModule(self.guest_hal_tag,
- basename,
- extraHeader = extraHeader,
- extraImpl = extraImpl,
- customAbsDir = self.guest_abs_hal_destination,
- useNamespace = useNamespace)
-
- def addHostModule(
- self, basename, extraHeader="", extraImpl="", useNamespace=True, implOnly=False,
- suppress=False, headerOnly=False, suppressFeatureGuards=False, moduleName=None,
- suppressVulkanHeaders=False):
- if not os.path.exists(self.host_abs_decoder_destination):
- print("Path [%s] not found (host encoder path), skipping" %
- self.host_abs_decoder_destination)
- return
- if not suppressVulkanHeaders:
- extraHeader = self.hostCommonExtraVulkanHeaders + '\n' + extraHeader
- self.addCppModule(
- self.host_tag, basename, extraHeader=extraHeader, extraImpl=extraImpl,
- customAbsDir=self.host_abs_decoder_destination, useNamespace=useNamespace,
- implOnly=implOnly, suppress=suppress, headerOnly=headerOnly,
- suppressFeatureGuards=suppressFeatureGuards, moduleName=moduleName,
- suppressVulkanHeaders=suppressVulkanHeaders)
-
- def addModule(self, module, moduleName=None):
- if moduleName is None:
- moduleName = module.basename
- self.moduleList.append(moduleName)
- self.modules[moduleName] = module
-
- def addCppModule(
- self, directory, basename, extraHeader="", extraImpl="", customAbsDir=None,
- useNamespace=True, implOnly=False, suppress=False, headerOnly=False,
- suppressFeatureGuards=False, moduleName=None, suppressVulkanHeaders=False):
- module = cereal.Module(
- directory, basename, customAbsDir=customAbsDir, suppress=suppress, implOnly=implOnly,
- headerOnly=headerOnly, suppressFeatureGuards=suppressFeatureGuards)
- self.addModule(module, moduleName=moduleName)
- module.headerPreamble = copyrightHeader
- module.headerPreamble += \
- autogeneratedHeaderTemplate % \
- (basename, "(header) generated by %s" % banner_command(sys.argv))
-
-
- namespaceBegin = """
-namespace gfxstream {
-namespace vk {
-""" if useNamespace else ""
-
- namespaceEnd = """
-} // namespace vk"
-} // namespace gfxstream
-""" if useNamespace else ""
-
- module.headerPreamble += "#pragma once\n"
- if (not suppressVulkanHeaders):
- module.headerPreamble += "#include <vulkan/vulkan.h>\n"
- module.headerPreamble += '#include "vulkan_gfxstream.h"\n'
- module.headerPreamble += extraHeader + '\n'
- if namespaceBegin:
- module.headerPreamble += namespaceBegin + '\n'
-
- module.implPreamble = copyrightHeader
- module.implPreamble += \
- autogeneratedHeaderTemplate % \
- (basename, "(impl) generated by %s" % \
- banner_command(sys.argv))
- if not implOnly:
- module.implPreamble += """
-#include "%s.h"
-
-%s
-
-%s
-
-""" % (basename, extraImpl, namespaceBegin)
-
- module.headerPostamble = """
-%s
-""" % namespaceEnd
- module.implPostamble = """
-%s
-""" % namespaceEnd
-
- def addWrapper(self, moduleType, moduleName, **kwargs):
- if moduleName not in self.modules:
- print(f'Unknown module: {moduleName}. All known modules are: {", ".join(self.modules)}.')
- return
- self.wrappers.append(
- moduleType(
- self.modules[moduleName],
- self.typeInfo, **kwargs))
-
- def forEachModule(self, func):
- for moduleName in self.moduleList:
- func(self.modules[moduleName])
-
- def forEachWrapper(self, func):
- for wrapper in self.wrappers:
- func(wrapper)
-
-## Overrides####################################################################
-
- def beginFile(self, genOpts):
- OutputGenerator.beginFile(self, genOpts, suppressEnabled)
-
- if suppressEnabled:
- def enableSuppression(m):
- m.suppress = True
- self.forEachModule(enableSuppression)
- self.modules[suppressExceptModule].suppress = False
-
- if not suppressEnabled:
- write(self.host_cmake_generator(self.hostCMakeCppFiles),
- file = self.outFile)
-
- guestEncoderAndroidMkPath = \
- os.path.join( \
- self.guest_abs_encoder_destination,
- "Android.mk")
-
- self.forEachModule(lambda m: m.begin(self.genOpts.directory))
- self.forEachWrapper(lambda w: w.onBegin())
-
- def endFile(self):
- OutputGenerator.endFile(self)
-
- self.typeInfo.onEnd()
-
- self.forEachWrapper(lambda w: w.onEnd())
- self.forEachModule(lambda m: m.end())
-
- def beginFeature(self, interface, emit):
- # Start processing in superclass
- OutputGenerator.beginFeature(self, interface, emit)
-
- self.typeInfo.onBeginFeature(self.featureName, self.featureType)
-
- self.forEachModule(
- lambda m: m.appendHeader("#ifdef %s\n" % self.featureName)
- if isinstance(m, cereal.Module) and not m.suppressFeatureGuards else None)
- self.forEachModule(
- lambda m: m.appendImpl("#ifdef %s\n" % self.featureName)
- if isinstance(m, cereal.Module) and not m.suppressFeatureGuards else None)
- self.forEachWrapper(lambda w: w.onBeginFeature(self.featureName, self.featureType))
- # functable needs to understand the feature type (device vs instance) of each cmd
- for features in interface.findall('require'):
- for c in features.findall('command'):
- self.forEachWrapper(lambda w: w.onFeatureNewCmd(c.get('name')))
-
- def endFeature(self):
- # Finish processing in superclass
- OutputGenerator.endFeature(self)
-
- self.typeInfo.onEndFeature()
-
- self.forEachModule(lambda m: m.appendHeader("#endif\n") if isinstance(
- m, cereal.Module) and not m.suppressFeatureGuards else None)
- self.forEachModule(lambda m: m.appendImpl("#endif\n") if isinstance(
- m, cereal.Module) and not m.suppressFeatureGuards else None)
- self.forEachWrapper(lambda w: w.onEndFeature())
-
- def genType(self, typeinfo: TypeInfo, name, alias):
- OutputGenerator.genType(self, typeinfo, name, alias)
- self.typeInfo.onGenType(typeinfo, name, alias)
- self.forEachWrapper(lambda w: w.onGenType(typeinfo, name, alias))
-
- def genStruct(self, typeinfo, typeName, alias):
- OutputGenerator.genStruct(self, typeinfo, typeName, alias)
- self.typeInfo.onGenStruct(typeinfo, typeName, alias)
- self.forEachWrapper(lambda w: w.onGenStruct(typeinfo, typeName, alias))
-
- def genGroup(self, groupinfo: GroupInfo, groupName, alias = None):
- OutputGenerator.genGroup(self, groupinfo, groupName, alias)
- self.typeInfo.onGenGroup(groupinfo, groupName, alias)
- self.forEachWrapper(lambda w: w.onGenGroup(groupinfo, groupName, alias))
-
- def genEnum(self, enuminfo: EnumInfo, name, alias):
- OutputGenerator.genEnum(self, enuminfo, name, alias)
- self.typeInfo.onGenEnum(enuminfo, name, alias)
- self.forEachWrapper(lambda w: w.onGenEnum(enuminfo, name, alias))
-
- def genCmd(self, cmdinfo, name, alias):
- OutputGenerator.genCmd(self, cmdinfo, name, alias)
- self.typeInfo.onGenCmd(cmdinfo, name, alias)
- self.forEachWrapper(lambda w: w.onGenCmd(cmdinfo, name, alias))
diff --git a/codegen/vulkan/scripts/cgenerator.py b/codegen/vulkan/scripts/cgenerator.py
deleted file mode 100644
index 56146021..00000000
--- a/codegen/vulkan/scripts/cgenerator.py
+++ /dev/null
@@ -1,420 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-import os
-import re
-from generator import (GeneratorOptions, OutputGenerator, noneStr,
- regSortFeatures, write)
-
-
-class CGeneratorOptions(GeneratorOptions):
- """CGeneratorOptions - subclass of GeneratorOptions.
-
- Adds options used by COutputGenerator objects during C language header
- generation."""
-
- def __init__(self,
- prefixText="",
- genFuncPointers=True,
- protectFile=True,
- protectFeature=True,
- protectProto=None,
- protectProtoStr=None,
- apicall='',
- apientry='',
- apientryp='',
- indentFuncProto=True,
- indentFuncPointer=False,
- alignFuncParam=0,
- genEnumBeginEndRange=False,
- genAliasMacro=False,
- aliasMacro='',
- misracstyle=False,
- misracppstyle=False,
- **kwargs
- ):
- """Constructor.
- Additional parameters beyond parent class:
-
- - prefixText - list of strings to prefix generated header with
- (usually a copyright statement + calling convention macros).
- - protectFile - True if multiple inclusion protection should be
- generated (based on the filename) around the entire header.
- - protectFeature - True if #ifndef..#endif protection should be
- generated around a feature interface in the header file.
- - genFuncPointers - True if function pointer typedefs should be
- generated
- - protectProto - If conditional protection should be generated
- around prototype declarations, set to either '#ifdef'
- to require opt-in (#ifdef protectProtoStr) or '#ifndef'
- to require opt-out (#ifndef protectProtoStr). Otherwise
- set to None.
- - protectProtoStr - #ifdef/#ifndef symbol to use around prototype
- declarations, if protectProto is set
- - apicall - string to use for the function declaration prefix,
- such as APICALL on Windows.
- - apientry - string to use for the calling convention macro,
- in typedefs, such as APIENTRY.
- - apientryp - string to use for the calling convention macro
- in function pointer typedefs, such as APIENTRYP.
- - indentFuncProto - True if prototype declarations should put each
- parameter on a separate line
- - indentFuncPointer - True if typedefed function pointers should put each
- parameter on a separate line
- - alignFuncParam - if nonzero and parameters are being put on a
- separate line, align parameter names at the specified column
- - genEnumBeginEndRange - True if BEGIN_RANGE / END_RANGE macros should
- be generated for enumerated types
- - genAliasMacro - True if the OpenXR alias macro should be generated
- for aliased types (unclear what other circumstances this is useful)
- - aliasMacro - alias macro to inject when genAliasMacro is True
- - misracstyle - generate MISRA C-friendly headers
- - misracppstyle - generate MISRA C++-friendly headers"""
-
- GeneratorOptions.__init__(self, **kwargs)
-
- self.prefixText = prefixText
- """list of strings to prefix generated header with (usually a copyright statement + calling convention macros)."""
-
- self.genFuncPointers = genFuncPointers
- """True if function pointer typedefs should be generated"""
-
- self.protectFile = protectFile
- """True if multiple inclusion protection should be generated (based on the filename) around the entire header."""
-
- self.protectFeature = protectFeature
- """True if #ifndef..#endif protection should be generated around a feature interface in the header file."""
-
- self.protectProto = protectProto
- """If conditional protection should be generated around prototype declarations, set to either '#ifdef' to require opt-in (#ifdef protectProtoStr) or '#ifndef' to require opt-out (#ifndef protectProtoStr). Otherwise set to None."""
-
- self.protectProtoStr = protectProtoStr
- """#ifdef/#ifndef symbol to use around prototype declarations, if protectProto is set"""
-
- self.apicall = apicall
- """string to use for the function declaration prefix, such as APICALL on Windows."""
-
- self.apientry = apientry
- """string to use for the calling convention macro, in typedefs, such as APIENTRY."""
-
- self.apientryp = apientryp
- """string to use for the calling convention macro in function pointer typedefs, such as APIENTRYP."""
-
- self.indentFuncProto = indentFuncProto
- """True if prototype declarations should put each parameter on a separate line"""
-
- self.indentFuncPointer = indentFuncPointer
- """True if typedefed function pointers should put each parameter on a separate line"""
-
- self.alignFuncParam = alignFuncParam
- """if nonzero and parameters are being put on a separate line, align parameter names at the specified column"""
-
- self.genEnumBeginEndRange = genEnumBeginEndRange
- """True if BEGIN_RANGE / END_RANGE macros should be generated for enumerated types"""
-
- self.genAliasMacro = genAliasMacro
- """True if the OpenXR alias macro should be generated for aliased types (unclear what other circumstances this is useful)"""
-
- self.aliasMacro = aliasMacro
- """alias macro to inject when genAliasMacro is True"""
-
- self.misracstyle = misracstyle
- """generate MISRA C-friendly headers"""
-
- self.misracppstyle = misracppstyle
- """generate MISRA C++-friendly headers"""
-
- self.codeGenerator = True
- """True if this generator makes compilable code"""
-
-
-class COutputGenerator(OutputGenerator):
- """Generates C-language API interfaces."""
-
- # This is an ordered list of sections in the header file.
- TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum',
- 'group', 'bitmask', 'funcpointer', 'struct']
- ALL_SECTIONS = TYPE_SECTIONS + ['commandPointer', 'command']
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- # Internal state - accumulators for different inner block text
- self.sections = {section: [] for section in self.ALL_SECTIONS}
- self.feature_not_empty = False
- self.may_alias = None
-
- def beginFile(self, genOpts):
- OutputGenerator.beginFile(self, genOpts)
- # C-specific
- #
- # Multiple inclusion protection & C++ wrappers.
- if genOpts.protectFile and self.genOpts.filename:
- headerSym = re.sub(r'\.h', '_h_',
- os.path.basename(self.genOpts.filename)).upper()
- write('#ifndef', headerSym, file=self.outFile)
- write('#define', headerSym, '1', file=self.outFile)
- self.newline()
-
- # User-supplied prefix text, if any (list of strings)
- if genOpts.prefixText:
- for s in genOpts.prefixText:
- write(s, file=self.outFile)
-
- # C++ extern wrapper - after prefix lines so they can add includes.
- self.newline()
- write('#ifdef __cplusplus', file=self.outFile)
- write('extern "C" {', file=self.outFile)
- write('#endif', file=self.outFile)
- self.newline()
-
- def endFile(self):
- # C-specific
- # Finish C++ wrapper and multiple inclusion protection
- self.newline()
- write('#ifdef __cplusplus', file=self.outFile)
- write('}', file=self.outFile)
- write('#endif', file=self.outFile)
- if self.genOpts.protectFile and self.genOpts.filename:
- self.newline()
- write('#endif', file=self.outFile)
- # Finish processing in superclass
- OutputGenerator.endFile(self)
-
- def beginFeature(self, interface, emit):
- # Start processing in superclass
- OutputGenerator.beginFeature(self, interface, emit)
- # C-specific
- # Accumulate includes, defines, types, enums, function pointer typedefs,
- # end function prototypes separately for this feature. They're only
- # printed in endFeature().
- self.sections = {section: [] for section in self.ALL_SECTIONS}
- self.feature_not_empty = False
-
- def endFeature(self):
- "Actually write the interface to the output file."
- # C-specific
- if self.emit:
- if self.feature_not_empty:
- if self.genOpts.conventions.writeFeature(self.featureExtraProtect, self.genOpts.filename):
- self.newline()
- if self.genOpts.protectFeature:
- write('#ifndef', self.featureName, file=self.outFile)
- # If type declarations are needed by other features based on
- # this one, it may be necessary to suppress the ExtraProtect,
- # or move it below the 'for section...' loop.
- if self.featureExtraProtect is not None:
- write('#ifdef', self.featureExtraProtect, file=self.outFile)
- self.newline()
- write('#define', self.featureName, '1', file=self.outFile)
- for section in self.TYPE_SECTIONS:
- contents = self.sections[section]
- if contents:
- write('\n'.join(contents), file=self.outFile)
- if self.genOpts.genFuncPointers and self.sections['commandPointer']:
- write('\n'.join(self.sections['commandPointer']), file=self.outFile)
- self.newline()
- if self.sections['command']:
- if self.genOpts.protectProto:
- write(self.genOpts.protectProto,
- self.genOpts.protectProtoStr, file=self.outFile)
- write('\n'.join(self.sections['command']), end='', file=self.outFile)
- if self.genOpts.protectProto:
- write('#endif', file=self.outFile)
- else:
- self.newline()
- if self.featureExtraProtect is not None:
- write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile)
- if self.genOpts.protectFeature:
- write('#endif /*', self.featureName, '*/', file=self.outFile)
- # Finish processing in superclass
- OutputGenerator.endFeature(self)
-
- def appendSection(self, section, text):
- "Append a definition to the specified section"
- # self.sections[section].append('SECTION: ' + section + '\n')
- self.sections[section].append(text)
- self.feature_not_empty = True
-
- def genType(self, typeinfo, name, alias):
- "Generate type."
- OutputGenerator.genType(self, typeinfo, name, alias)
- typeElem = typeinfo.elem
-
- # Vulkan:
- # Determine the category of the type, and the type section to add
- # its definition to.
- # 'funcpointer' is added to the 'struct' section as a workaround for
- # internal issue #877, since structures and function pointer types
- # can have cross-dependencies.
- category = typeElem.get('category')
- if category == 'funcpointer':
- section = 'struct'
- else:
- section = category
-
- if category in ('struct', 'union'):
- # If the type is a struct type, generate it using the
- # special-purpose generator.
- self.genStruct(typeinfo, name, alias)
- else:
- # OpenXR: this section was not under 'else:' previously, just fell through
- if alias:
- # If the type is an alias, just emit a typedef declaration
- body = 'typedef ' + alias + ' ' + name + ';\n'
- else:
- # Replace <apientry /> tags with an APIENTRY-style string
- # (from self.genOpts). Copy other text through unchanged.
- # If the resulting text is an empty string, don't emit it.
- body = noneStr(typeElem.text)
- for elem in typeElem:
- if elem.tag == 'apientry':
- body += self.genOpts.apientry + noneStr(elem.tail)
- else:
- body += noneStr(elem.text) + noneStr(elem.tail)
- if body:
- # Add extra newline after multi-line entries.
- if '\n' in body[0:-1]:
- body += '\n'
- self.appendSection(section, body)
-
- def genProtectString(self, protect_str):
- """Generate protection string.
-
- Protection strings are the strings defining the OS/Platform/Graphics
- requirements for a given OpenXR command. When generating the
- language header files, we need to make sure the items specific to a
- graphics API or OS platform are properly wrapped in #ifs."""
- protect_if_str = ''
- protect_end_str = ''
- if not protect_str:
- return (protect_if_str, protect_end_str)
-
- if ',' in protect_str:
- protect_list = protect_str.split(",")
- protect_defs = ('defined(%s)' % d for d in protect_list)
- protect_def_str = ' && '.join(protect_defs)
- protect_if_str = '#if %s\n' % protect_def_str
- protect_end_str = '#endif // %s\n' % protect_def_str
- else:
- protect_if_str = '#ifdef %s\n' % protect_str
- protect_end_str = '#endif // %s\n' % protect_str
-
- return (protect_if_str, protect_end_str)
-
- def typeMayAlias(self, typeName):
- if not self.may_alias:
- # First time we've asked if a type may alias.
- # So, let's populate the set of all names of types that may.
-
- # Everyone with an explicit mayalias="true"
- self.may_alias = set(typeName
- for typeName, data in self.registry.typedict.items()
- if data.elem.get('mayalias') == 'true')
-
- # Every type mentioned in some other type's parentstruct attribute.
- parent_structs = (otherType.elem.get('parentstruct')
- for otherType in self.registry.typedict.values())
- self.may_alias.update(set(x for x in parent_structs
- if x is not None))
- return typeName in self.may_alias
-
- def genStruct(self, typeinfo, typeName, alias):
- """Generate struct (e.g. C "struct" type).
-
- This is a special case of the <type> tag where the contents are
- interpreted as a set of <member> tags instead of freeform C
- C type declarations. The <member> tags are just like <param>
- tags - they are a declaration of a struct or union member.
- Only simple member declarations are supported (no nested
- structs etc.)
-
- If alias is not None, then this struct aliases another; just
- generate a typedef of that alias."""
- OutputGenerator.genStruct(self, typeinfo, typeName, alias)
-
- typeElem = typeinfo.elem
-
- if alias:
- body = 'typedef ' + alias + ' ' + typeName + ';\n'
- else:
- body = ''
- (protect_begin, protect_end) = self.genProtectString(typeElem.get('protect'))
- if protect_begin:
- body += protect_begin
- body += 'typedef ' + typeElem.get('category')
-
- # This is an OpenXR-specific alternative where aliasing refers
- # to an inheritance hierarchy of types rather than C-level type
- # aliases.
- if self.genOpts.genAliasMacro and self.typeMayAlias(typeName):
- body += ' ' + self.genOpts.aliasMacro
-
- body += ' ' + typeName + ' {\n'
-
- targetLen = self.getMaxCParamTypeLength(typeinfo)
- for member in typeElem.findall('.//member'):
- body += self.makeCParamDecl(member, targetLen + 4)
- body += ';\n'
- body += '} ' + typeName + ';\n'
- if protect_end:
- body += protect_end
-
- self.appendSection('struct', body)
-
- def genGroup(self, groupinfo, groupName, alias=None):
- """Generate groups (e.g. C "enum" type).
-
- These are concatenated together with other types.
-
- If alias is not None, it is the name of another group type
- which aliases this type; just generate that alias."""
- OutputGenerator.genGroup(self, groupinfo, groupName, alias)
- groupElem = groupinfo.elem
-
- # After either enumerated type or alias paths, add the declaration
- # to the appropriate section for the group being defined.
- if groupElem.get('type') == 'bitmask':
- section = 'bitmask'
- else:
- section = 'group'
-
- if alias:
- # If the group name is aliased, just emit a typedef declaration
- # for the alias.
- body = 'typedef ' + alias + ' ' + groupName + ';\n'
- self.appendSection(section, body)
- else:
- (section, body) = self.buildEnumCDecl(self.genOpts.genEnumBeginEndRange, groupinfo, groupName)
- self.appendSection(section, "\n" + body)
-
- def genEnum(self, enuminfo, name, alias):
- """Generate the C declaration for a constant (a single <enum> value)."""
-
- OutputGenerator.genEnum(self, enuminfo, name, alias)
-
- body = self.buildConstantCDecl(enuminfo, name, alias)
- self.appendSection('enum', body)
-
- def genCmd(self, cmdinfo, name, alias):
- "Command generation"
- OutputGenerator.genCmd(self, cmdinfo, name, alias)
-
- # if alias:
- # prefix = '// ' + name + ' is an alias of command ' + alias + '\n'
- # else:
- # prefix = ''
-
- prefix = ''
- decls = self.makeCDecls(cmdinfo.elem)
- self.appendSection('command', prefix + decls[0] + '\n')
- if self.genOpts.genFuncPointers:
- self.appendSection('commandPointer', decls[1])
-
- def misracstyle(self):
- return self.genOpts.misracstyle;
-
- def misracppstyle(self):
- return self.genOpts.misracppstyle;
diff --git a/codegen/vulkan/scripts/checkXrefs b/codegen/vulkan/scripts/checkXrefs
deleted file mode 100755
index 6d5dc7d7..00000000
--- a/codegen/vulkan/scripts/checkXrefs
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/sh
-#
-# Copyright 2015-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# checkXrefs - check internal links in a Vulkan HTML spec
-# Usage: checkXrefs file.html
-# Prints a list of internal hrefs with no corresponding anchors.
-# (There are many anchors with no corresponding hrefs - this is OK).
-
-xrefs=`tempfile`
-ids=`tempfile`
-
-sed -e 's/ href="#/\nhref="#/g' < $1 | \
- grep 'href="#' | \
- sed -e 's/href="#//g' -e 's/"[ >].*//g' | \
- sort | uniq > $xrefs
-sed -e 's/ id="/\nid="/g' < $1 | \
- grep 'id="' | \
- sed -e 's/id="//g' -e 's/"[ >].*//g' | \
- sort | uniq > $ids
-
-comm -23 $xrefs $ids
-
-rm $xrefs $ids 1>&2
diff --git a/codegen/vulkan/scripts/check_html_xrefs.py b/codegen/vulkan/scripts/check_html_xrefs.py
deleted file mode 100755
index 0081e6c0..00000000
--- a/codegen/vulkan/scripts/check_html_xrefs.py
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2020-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# check_html_xrefs - simple-minded check for internal xrefs in spec HTML
-# that don't exist.
-
-# Usage: check_html_xrefs file
-# Just reports bad xrefs, not where they occur
-
-import argparse
-import re
-from lxml import etree
-
-SECTNAME = re.compile(r'sect(?P<level>\d+)')
-
-def find_parent_ids(elem, href):
- """Find section titles in parents, which are the 'id' elements of '<hN'
- children of '<div class="sectM"' tags, and N = M + 1. This may be
- specific to the Vulkan spec, though - hierarchy could be different in
- other asciidoctor documents. Returns a list of [ anchor, title ].
-
- elem - this node
- href - href link text of elem"""
-
- # Find parent <div> with class="sect#"
- parent = elem.getparent()
- while parent is not None:
- if parent.tag == 'div':
- cssclass = parent.get('class')
- matches = SECTNAME.match(cssclass)
- if matches is not None:
- level = int(matches.group('level'))
- # Look for corresponding header tag in this div
- helem = parent.find('./h{}'.format(level+1))
- if helem is not None:
- return [ helem.get('id'), ''.join(helem.itertext()) ]
- parent = parent.getparent()
- return [ '** NO PARENT NODE IDENTIFIED **', '' ]
-
-if __name__ == '__main__':
- parser = argparse.ArgumentParser()
-
- parser.add_argument('files', metavar='filename', nargs='*',
- help='Path to registry XML')
- args = parser.parse_args()
-
- for filename in args.files:
- parser = etree.HTMLParser()
- tree = etree.parse(filename, parser)
-
- # Find all 'id' elements
- id_elems = tree.findall('.//*[@id]')
- ids = set()
- for elem in id_elems:
- id = elem.get('id')
- if id in ids:
- True
- # print('Duplicate ID attribute:', id)
- else:
- ids.add(id)
-
- # Find all internal 'href' attributes and see if they're valid
- # Keep an [element, href] list for tracking parents
- # Also keep a count of each href
- ref_elems = tree.findall('.//a[@href]')
- refs = []
- count = {}
- for elem in ref_elems:
- href = elem.get('href')
- # If not a local href, skip it
- if href[0] == '#':
- # If there's a corresponding id, skip it
- href = href[1:]
- if href not in ids:
- if href in count:
- refs.append((elem, href))
- True
- count[href] = count[href] + 1
- else:
- refs.append((elem, href))
- count[href] = 1
- else:
- True
- # print('Skipping external href:', ref)
-
- # Check for hrefs not found in ids
- print('Bad links in {}:'.format(filename))
- for (elem, href) in refs:
- parents = find_parent_ids(elem, href)
- print('{:<40} in {:<28} ({})'.format(href, parents[0], parents[1]))
diff --git a/codegen/vulkan/scripts/check_spec_links.py b/codegen/vulkan/scripts/check_spec_links.py
deleted file mode 100755
index 16cfe438..00000000
--- a/codegen/vulkan/scripts/check_spec_links.py
+++ /dev/null
@@ -1,164 +0,0 @@
-#!/usr/bin/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 MacroCheckerFile
-from spec_tools.main import checkerMain
-from spec_tools.shared import (AUTO_FIX_STRING, EXTENSION_CATEGORY, MessageId,
- MessageType)
-
-###
-# "Configuration" constants
-
-FREEFORM_CATEGORY = 'freeform'
-
-# defines mentioned in spec but not needed in registry
-EXTRA_DEFINES = (
- 'VKAPI_ATTR',
- 'VKAPI_CALL',
- 'VKAPI_PTR',
- 'VK_NO_STDDEF_H',
- 'VK_NO_STDINT_H',
- )
-
-# Extra freeform refpages in addition to EXTRA_DEFINES
-EXTRA_REFPAGES = (
- 'VK_VERSION_1_0',
- 'VK_VERSION_1_1',
- 'VK_VERSION_1_2',
- 'WSIheaders',
- 'provisional-headers',
- )
-
-# 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
-DEFAULT_DISABLED_MESSAGES = set((
- MessageId.LEGACY,
- MessageId.REFPAGE_MISSING,
- MessageId.MISSING_MACRO,
- MessageId.EXTENSION,
- # TODO *text macro checking actually needs fixing for Vulkan
- MessageId.MISUSED_TEXT,
- MessageId.MISSING_TEXT
-))
-
-CWD = Path('.').resolve()
-
-
-class VulkanEntityDatabase(EntityDatabase):
- """Vulkan-specific subclass of EntityDatabase."""
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self._conditionally_recognized = set(('fname', 'sname'))
-
- def makeRegistry(self):
- registryFile = str(ROOT / 'xml/vk.xml')
- registry = Registry()
- registry.loadFile(registryFile)
- return registry
-
- def getNamePrefix(self):
- return "vk"
-
- def getPlatformRequires(self):
- return 'vk_platform'
-
- def getSystemTypes(self):
- return SYSTEM_TYPES
-
- def populateMacros(self):
- self.addMacros('t', ['link', 'name'], ['funcpointers', 'flags'])
-
- def populateEntities(self):
- # These are not mentioned in the XML
- for name in EXTRA_DEFINES:
- self.addEntity(name, 'dlink',
- category=FREEFORM_CATEGORY, generates=False)
- for name in EXTRA_REFPAGES:
- self.addEntity(name, 'code',
- category=FREEFORM_CATEGORY, generates=False)
-
- def shouldBeRecognized(self, macro, entity_name):
- """Determine, based on the macro and the name provided, if we should expect to recognize the entity."""
- if super().shouldBeRecognized(macro, entity_name):
- return True
-
- # The *name: macros in Vulkan should also be recognized if the entity name matches the pattern.
- if macro in self._conditionally_recognized and self.likelyRecognizedEntity(entity_name):
- return True
- return False
-
-
-class VulkanMacroCheckerFile(MacroCheckerFile):
- """Vulkan-specific subclass of MacroCheckerFile."""
-
- def handleWrongMacro(self, msg, data):
- """Report an appropriate message when we found that the macro used is incorrect.
-
- May be overridden depending on each API's behavior regarding macro misuse:
- e.g. in some cases, it may be considered a MessageId.LEGACY warning rather than
- a MessageId.WRONG_MACRO or MessageId.EXTENSION.
- """
- message_type = MessageType.WARNING
- message_id = MessageId.WRONG_MACRO
- group = 'macro'
-
- if data.category == EXTENSION_CATEGORY:
- # Ah, this is an extension
- msg.append(
- 'This is apparently an extension name, which should be marked up as a link.')
- message_id = MessageId.EXTENSION
- group = None # replace the whole thing
- else:
- # Non-extension, we found the macro though.
- if data.macro[0] == self.macro[0] and data.macro[1:] == 'link' and self.macro[1:] == 'name':
- # First letter matches, old is 'name', new is 'link':
- # This is legacy markup
- msg.append(
- 'This is legacy markup that has not been updated yet.')
- message_id = MessageId.LEGACY
- else:
- # Not legacy, just wrong.
- message_type = MessageType.ERROR
-
- msg.append(AUTO_FIX_STRING)
- self.diag(message_type, message_id, msg,
- group=group, replacement=self.makeMacroMarkup(data=data), fix=self.makeFix(data=data))
-
-
-def makeMacroChecker(enabled_messages):
- """Create a correctly-configured MacroChecker instance."""
- entity_db = VulkanEntityDatabase()
- return MacroChecker(enabled_messages, entity_db, VulkanMacroCheckerFile, ROOT)
-
-
-if __name__ == '__main__':
- default_enabled_messages = set(MessageId).difference(
- DEFAULT_DISABLED_MESSAGES)
-
- all_docs = [str(fn)
- for fn in sorted((ROOT / 'chapters/').glob('**/*.txt'))]
- all_docs.extend([str(fn)
- for fn in sorted((ROOT / 'appendices/').glob('**/*.txt'))])
-
- checkerMain(default_enabled_messages, makeMacroChecker,
- all_docs)
diff --git a/codegen/vulkan/scripts/ci/check_undefined b/codegen/vulkan/scripts/ci/check_undefined
deleted file mode 100755
index b747b1db..00000000
--- a/codegen/vulkan/scripts/ci/check_undefined
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-
-# Copyright 2020-2021 The Khronos Group, Inc.
-# SPDX-License-Identifier: Apache-2.0
-
-# scripts/ci/check_undefined
-# Check for non-tagged 'undefined' in spec sources.
-# Skip appendices/VK* files, which are non-normative.
-# Ideally we would skip NOTES too, but that would require parsing.
-
-undefined=/tmp/undefined
-ls chapters/*txt chapters/*/*txt appendices/[A-UW-Za-z]*txt | \
- xargs egrep -E '(^|[[:space:]])undefined($|[^:])' > $undefined
-if test `cat $undefined | wc -l` -gt 0 ; then
- echo "*** Found un-tagged uses of 'undefined'"
- cat $undefined
- rm $undefined
- exit 1
-else
- rm $undefined
- exit 0
-fi
diff --git a/codegen/vulkan/scripts/comment_convert.py b/codegen/vulkan/scripts/comment_convert.py
deleted file mode 100755
index f1fa938c..00000000
--- a/codegen/vulkan/scripts/comment_convert.py
+++ /dev/null
@@ -1,203 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (c) 2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-#
-# Purpose: This script converts leading comments on some Python
-# classes and functions into docstrings.
-# It doesn't attempt to deal with line continuations, etc.
-# so you may want to "join line" on your def statements
-# temporarily before running.
-
-import re
-
-from spec_tools.file_process import LinewiseFileProcessor
-
-COMMENT_RE = re.compile(r" *#(!.*| (?P<content>.*))?")
-CONVERTIBLE_DEF_RE = re.compile(r"(?P<indentation> *)(def|class) .*:")
-
-
-class CommentConverter(LinewiseFileProcessor):
- def __init__(self, single_line_quotes=False, allow_blank_lines=False):
- super().__init__()
- self.comment_lines = []
- "Temporary storage for contiguous comment lines."
-
- self.trailing_empty_lines = []
- "Temporary storage for empty lines following a comment."
-
- self.output_lines = []
- "Fully-processed output lines."
-
- self.single_line_quotes = single_line_quotes
- "Whether we generate simple, single-line quotes for single line comments."
-
- self.allow_blank_lines = allow_blank_lines
- "Whether we allow blank lines between a comment and the thing it's considered to document."
-
- self.done_with_initial_comment = False
- "Have we read our first non-comment line yet?"
-
- def output_line(self, line=None):
- if line:
- self.output_lines.append(line)
- else:
- self.output_lines.append("")
-
- def output_normal_line(self, line):
- # flush any comment lines we had stored and output this line.
- self.dump_comment_lines()
- self.output_line(line)
-
- def dump_comment_lines(self):
- # Early out for empty
- if not self.comment_lines:
- return
-
- for line in self.comment_lines:
- self.output_line(line)
- self.comment_lines = []
-
- for line in self.trailing_empty_lines:
- self.output_line(line)
- self.trailing_empty_lines = []
-
- def dump_converted_comment_lines(self, indent):
- # Early out for empty
- if not self.comment_lines:
- return
-
- for line in self.trailing_empty_lines:
- self.output_line(line)
- self.trailing_empty_lines = []
-
- indent = indent + ' '
-
- def extract(line):
- match = COMMENT_RE.match(line)
- content = match.group('content')
- if content:
- return content
- return ""
-
- # Extract comment content
- lines = [extract(line) for line in self.comment_lines]
-
- # Drop leading empty comments.
- while lines and not lines[0].strip():
- lines.pop(0)
-
- # Drop trailing empty comments.
- while lines and not lines[-1].strip():
- lines.pop()
-
- # Add single- or multi-line-string quote
- if self.single_line_quotes \
- and len(lines) == 1 \
- and '"' not in lines[0]:
- quote = '"'
- else:
- quote = '"""'
- lines[0] = quote + lines[0]
- lines[-1] = lines[-1] + quote
-
- # Output lines, indenting content as required.
- for line in lines:
- if line:
- self.output_line(indent + line)
- else:
- # Don't indent empty comment lines
- self.output_line()
-
- # Clear stored comment lines since we processed them
- self.comment_lines = []
-
- def queue_comment_line(self, line):
- if self.trailing_empty_lines:
- # If we had blank lines between comment lines, they are separate blocks
- self.dump_comment_lines()
- self.comment_lines.append(line)
-
- def handle_empty_line(self, line):
- """Handle an empty line.
-
- Contiguous empty lines between a comment and something documentable do not
- disassociate the comment from the documentable thing.
- We have someplace else to store these lines in case there isn't something
- documentable coming up."""
- if self.comment_lines and self.allow_blank_lines:
- self.trailing_empty_lines.append(line)
- else:
- self.output_normal_line(line)
-
- def is_next_line_doc_comment(self):
- next_line = self.next_line_rstripped
- if next_line is None:
- return False
-
- return next_line.strip().startswith('"')
-
- def process_line(self, line_num, line):
- line = line.rstrip()
- comment_match = COMMENT_RE.match(line)
- def_match = CONVERTIBLE_DEF_RE.match(line)
-
- # First check if this is a comment line.
- if comment_match:
- if self.done_with_initial_comment:
- self.queue_comment_line(line)
- else:
- self.output_line(line)
- else:
- # If not a comment line, then by definition we're done with the comment header.
- self.done_with_initial_comment = True
- if not line.strip():
- self.handle_empty_line(line)
- elif def_match and not self.is_next_line_doc_comment():
- # We got something we can make a docstring for:
- # print the thing the docstring is for first,
- # then the converted comment.
-
- indent = def_match.group('indentation')
- self.output_line(line)
- self.dump_converted_comment_lines(indent)
- else:
- # Can't make a docstring for this line:
- self.output_normal_line(line)
-
- def process(self, fn, write=False):
- self.process_file(fn)
-
- if write:
- with open(fn, 'w', encoding='utf-8') as fp:
- for line in self.output_lines:
- fp.write(line)
- fp.write('\n')
-
- # Reset state
- self.__init__(self.single_line_quotes, self.allow_blank_lines)
-
-
-def main():
- import argparse
-
- parser = argparse.ArgumentParser()
- parser.add_argument('filenames', metavar='filename',
- type=str, nargs='+',
- help='A Python file to transform.')
- parser.add_argument('-b', '--blanklines', action='store_true',
- help='Allow blank lines between a comment and a define and still convert that comment.')
-
- args = parser.parse_args()
-
- converter = CommentConverter(allow_blank_lines=args.blanklines)
- for fn in args.filenames:
- print("Processing", fn)
- converter.process(fn, write=True)
-
-
-if __name__ == "__main__":
- main()
diff --git a/codegen/vulkan/scripts/compImages.sh b/codegen/vulkan/scripts/compImages.sh
deleted file mode 100755
index d9f3670f..00000000
--- a/codegen/vulkan/scripts/compImages.sh
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2020-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# compareImages - compare all asciidoctor images in two branches
-# Usage: compareImages branch1 branch2
-
-# Where to put temporary files
-compare=compare
-
-branch1=$1
-branch2=$2
-
-echo "Preparing test tree under compare/"
-rm -rf $compare
-
-echo "Gathering images under compare/$1 compare/$2"
-if git checkout $branch1 ; then
- img1=$compare/$branch1
- files1=$compare/$branch1-files
- mkdir -p $img1
- cp images/*.svg $img1
- (cd $img1 ; ls) > $files1
-else
- echo "Can't switch to branch $branch1"
- rm -rf $compare
- exit 1
-fi
-
-if git checkout $branch2 ; then
- img2=$compare/$branch2
- files2=$compare/$branch2-files
- mkdir -p $img2
- cp images/*.svg $img2
- (cd $img2 ; ls) > $files2
-else
- echo "Can't switch to branch $branch2"
- rm -rf $compare
- exit 1
-fi
-
-srcfile=compare/compImages.adoc
-
-# Boilerplate header
-echo "= Image Comparison of Vulkan images in $branch1 $branch2
-:data-uri:
-:icons: font
-include::../config/attribs.txt[]
-" > $srcfile
-
-
-# Files common to both branches
-echo "== Images Common to Both Branches
-" >> $srcfile
-
-# Identical images
-identical=()
-
-# Where to generate comparison images
-compdir=$compare/compare
-mkdir -p $compdir
-
-for file in `comm -12 $files1 $files2` ; do
- echo "Comparing $file"
- if diff -q $img1/$file $img2/$file > /dev/null ; then
- identical+=( $file )
- # Files are identical
- else
- # sum1=`sum $img1/$file | awk '{print $1}'`
- # sum2=`sum $img2/$file | awk '{print $1}'`
- #
- # if test $sum1 -eq $sum2 ; then
-
- # Generate comparison image
- compfile="$compdir/$file"
- compare $img1/$file $img2/$file $compfile
-
- echo "=== $file
-
-image::$branch1/$file[title=\"$file in $branch1\",align=\"center\",opts=\"inline\"]
-
-image::$branch2/$file[title=\"$file in $branch2\",align=\"center\",opts=\"inline\"]
-
-image::compare/$file[title=\"Comparison of branches\",align=\"center\",opts=\"inline\"]
-
-<<<
-
-" >> $srcfile
-
- fi
-done
-
-
-# Identical files
-echo "== Identical images
-" >> $srcfile
-
-for file in ${identical[@]} ; do
- echo " * $file" >> $srcfile
-done
-echo >> $srcfile
-
-
-# Files only in first branch
-echo "== Images only in $branch1
-" >> $srcfile
-
-for file in `comm -23 $files1 $files2` ; do
- echo " * $file" >> $srcfile
-done
-echo >> $srcfile
-
-
-# Files only in second branch
-echo "== Images only in $branch2
-" >> $srcfile
-
-for file in `comm -13 $files1 $files2` ; do
- echo " * $file" >> $srcfile
-done
-echo >> $srcfile
-
-outfile=$compare/`basename $srcfile .adoc`.pdf
-echo "Generating $outfile from $srcfile"
-asciidoctor -b pdf -r asciidoctor-pdf -o $outfile $srcfile
diff --git a/codegen/vulkan/scripts/conventions.py b/codegen/vulkan/scripts/conventions.py
deleted file mode 100644
index edf90596..00000000
--- a/codegen/vulkan/scripts/conventions.py
+++ /dev/null
@@ -1,358 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# Base class for working-group-specific style conventions,
-# used in generation.
-
-from enum import Enum
-
-# Type categories that respond "False" to isStructAlwaysValid
-# basetype is home to typedefs like ..Bool32
-CATEGORIES_REQUIRING_VALIDATION = set(('handle',
- 'enum',
- 'bitmask',
- 'basetype',
- None))
-
-# These are basic C types pulled in via openxr_platform_defines.h
-TYPES_KNOWN_ALWAYS_VALID = set(('char',
- 'float',
- 'int8_t', 'uint8_t',
- 'int32_t', 'uint32_t',
- 'int64_t', 'uint64_t',
- 'size_t',
- 'uintptr_t',
- 'int',
- ))
-
-
-class ProseListFormats(Enum):
- """A connective, possibly with a quantifier."""
- AND = 0
- EACH_AND = 1
- OR = 2
- ANY_OR = 3
-
- @classmethod
- def from_string(cls, s):
- if s == 'or':
- return cls.OR
- if s == 'and':
- return cls.AND
- return None
-
- @property
- def connective(self):
- if self in (ProseListFormats.OR, ProseListFormats.ANY_OR):
- return 'or'
- return 'and'
-
- def quantifier(self, n):
- """Return the desired quantifier for a list of a given length."""
- if self == ProseListFormats.ANY_OR:
- if n > 1:
- return 'any of '
- elif self == ProseListFormats.EACH_AND:
- if n > 2:
- return 'each of '
- if n == 2:
- return 'both of '
- return ''
-
-
-class ConventionsBase:
- """WG-specific conventions."""
-
- def __init__(self):
- self._command_prefix = None
- self._type_prefix = None
-
- def formatExtension(self, name):
- """Mark up an extension name as a link the spec."""
- return '`apiext:{}`'.format(name)
-
- @property
- def null(self):
- """Preferred spelling of NULL."""
- raise NotImplementedError
-
- def makeProseList(self, elements, fmt=ProseListFormats.AND, with_verb=False, *args, **kwargs):
- """Make a (comma-separated) list for use in prose.
-
- Adds a connective (by default, 'and')
- before the last element if there are more than 1.
-
- Adds the right one of "is" or "are" to the end if with_verb is true.
-
- Optionally adds a quantifier (like 'any') before a list of 2 or more,
- if specified by fmt.
-
- Override with a different method or different call to
- _implMakeProseList if you want to add a comma for two elements,
- or not use a serial comma.
- """
- return self._implMakeProseList(elements, fmt, with_verb, *args, **kwargs)
-
- @property
- def struct_macro(self):
- """Get the appropriate format macro for a structure.
-
- May override.
- """
- return 'slink:'
-
- @property
- def external_macro(self):
- """Get the appropriate format macro for an external type like uint32_t.
-
- May override.
- """
- return 'code:'
-
- def makeStructName(self, name):
- """Prepend the appropriate format macro for a structure to a structure type name.
-
- Uses struct_macro, so just override that if you want to change behavior.
- """
- return self.struct_macro + name
-
- def makeExternalTypeName(self, name):
- """Prepend the appropriate format macro for an external type like uint32_t to a type name.
-
- Uses external_macro, so just override that if you want to change behavior.
- """
- return self.external_macro + name
-
- def _implMakeProseList(self, elements, fmt, with_verb, comma_for_two_elts=False, serial_comma=True):
- """Internal-use implementation to make a (comma-separated) list for use in prose.
-
- Adds a connective (by default, 'and')
- before the last element if there are more than 1,
- and only includes commas if there are more than 2
- (if comma_for_two_elts is False).
-
- Adds the right one of "is" or "are" to the end if with_verb is true.
-
- Optionally adds a quantifier (like 'any') before a list of 2 or more,
- if specified by fmt.
-
- Don't edit these defaults, override self.makeProseList().
- """
- assert(serial_comma) # didn't implement what we didn't need
- if isinstance(fmt, str):
- fmt = ProseListFormats.from_string(fmt)
-
- my_elts = list(elements)
- if len(my_elts) > 1:
- my_elts[-1] = '{} {}'.format(fmt.connective, my_elts[-1])
-
- if not comma_for_two_elts and len(my_elts) <= 2:
- prose = ' '.join(my_elts)
- else:
- prose = ', '.join(my_elts)
-
- quantifier = fmt.quantifier(len(my_elts))
-
- parts = [quantifier, prose]
-
- if with_verb:
- if len(my_elts) > 1:
- parts.append(' are')
- else:
- parts.append(' is')
- return ''.join(parts)
-
- @property
- def file_suffix(self):
- """Return suffix of generated Asciidoctor files"""
- raise NotImplementedError
-
- def api_name(self, spectype=None):
- """Return API or specification name for citations in ref pages.
-
- spectype is the spec this refpage is for.
- 'api' (the default value) is the main API Specification.
- If an unrecognized spectype is given, returns None.
-
- Must implement."""
- raise NotImplementedError
-
- def should_insert_may_alias_macro(self, genOpts):
- """Return true if we should insert a "may alias" macro in this file.
-
- Only used by OpenXR right now."""
- return False
-
- @property
- def command_prefix(self):
- """Return the expected prefix of commands/functions.
-
- Implemented in terms of api_prefix."""
- if not self._command_prefix:
- self._command_prefix = self.api_prefix[:].replace('_', '').lower()
- return self._command_prefix
-
- @property
- def type_prefix(self):
- """Return the expected prefix of type names.
-
- Implemented in terms of command_prefix (and in turn, api_prefix)."""
- if not self._type_prefix:
- self._type_prefix = ''.join(
- (self.command_prefix[0:1].upper(), self.command_prefix[1:]))
- return self._type_prefix
-
- @property
- def api_prefix(self):
- """Return API token prefix.
-
- Typically two uppercase letters followed by an underscore.
-
- Must implement."""
- raise NotImplementedError
-
- @property
- def api_version_prefix(self):
- """Return API core version token prefix.
-
- Implemented in terms of api_prefix.
-
- May override."""
- return self.api_prefix + 'VERSION_'
-
- @property
- def KHR_prefix(self):
- """Return extension name prefix for KHR extensions.
-
- Implemented in terms of api_prefix.
-
- May override."""
- return self.api_prefix + 'KHR_'
-
- @property
- def EXT_prefix(self):
- """Return extension name prefix for EXT extensions.
-
- Implemented in terms of api_prefix.
-
- May override."""
- return self.api_prefix + 'EXT_'
-
- def writeFeature(self, featureExtraProtect, filename):
- """Return True if OutputGenerator.endFeature should write this feature.
-
- Defaults to always True.
- Used in COutputGenerator.
-
- May override."""
- return True
-
- def requires_error_validation(self, return_type):
- """Return True if the return_type element is an API result code
- requiring error validation.
-
- Defaults to always False.
-
- May override."""
- return False
-
- @property
- def required_errors(self):
- """Return a list of required error codes for validation.
-
- Defaults to an empty list.
-
- May override."""
- return []
-
- def is_voidpointer_alias(self, tag, text, tail):
- """Return True if the declaration components (tag,text,tail) of an
- element represents a void * type.
-
- Defaults to a reasonable implementation.
-
- May override."""
- return tag == 'type' and text == 'void' and tail.startswith('*')
-
- def make_voidpointer_alias(self, tail):
- """Reformat a void * declaration to include the API alias macro.
-
- Defaults to a no-op.
-
- Must override if you actually want to use this feature in your project."""
- return tail
-
- def category_requires_validation(self, category):
- """Return True if the given type 'category' always requires validation.
-
- Defaults to a reasonable implementation.
-
- May override."""
- return category in CATEGORIES_REQUIRING_VALIDATION
-
- def type_always_valid(self, typename):
- """Return True if the given type name is always valid (never requires validation).
-
- This is for things like integers.
-
- Defaults to a reasonable implementation.
-
- May override."""
- return typename in TYPES_KNOWN_ALWAYS_VALID
-
- @property
- def should_skip_checking_codes(self):
- """Return True if more than the basic validation of return codes should
- be skipped for a command."""
-
- return False
-
- @property
- def generate_index_terms(self):
- """Return True if asiidoctor index terms should be generated as part
- of an API interface from the docgenerator."""
-
- return False
-
- @property
- def generate_enum_table(self):
- """Return True if asciidoctor tables describing enumerants in a
- group should be generated as part of group generation."""
- return False
-
- @property
- def generate_max_enum_in_docs(self):
- """Return True if MAX_ENUM tokens should be generated in
- documentation includes."""
- return False
-
-
- def extension_include_string(self, ext):
- """Return format string for include:: line for an extension appendix
- file. ext is an object with the following members:
- - name - extension string string
- - vendor - vendor portion of name
- - barename - remainder of name
-
- Must implement."""
- raise NotImplementedError
-
- @property
- def refpage_generated_include_path(self):
- """Return path relative to the generated reference pages, to the
- generated API include files.
-
- Must implement."""
- raise NotImplementedError
-
- def valid_flag_bit(self, bitpos):
- """Return True if bitpos is an allowed numeric bit position for
- an API flag.
-
- Behavior depends on the data type used for flags (which may be 32
- or 64 bits), and may depend on assumptions about compiler
- handling of sign bits in enumerated types, as well."""
- return True
diff --git a/codegen/vulkan/scripts/deperiodize_vuids.py b/codegen/vulkan/scripts/deperiodize_vuids.py
deleted file mode 100755
index c02a1581..00000000
--- a/codegen/vulkan/scripts/deperiodize_vuids.py
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2020 Petr Kraus
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# Removes periods after Valid Usage sentence in the spec
-#
-# Usage:
-# cd <root of Vulkan-Docs repo>
-# ./scripts/deperiodize_vuids.py
-
-import os,re
-
-def deperiodizeFile(filename):
- print(' Deperiodizing = %s' % filename)
-
- with open(filename, 'r', encoding='utf8', newline='\n') as f:
- data = f.read()
-
- # Remove periods from VUs
- data = re.sub( r'( \* \[\[VUID\-[\s\S]+?)\.?(?=(\n \* \[\[VUID\-)|(\n\*\*\*\*)|(\n// )|(\ninclude::)|(\nendif::)|(\nifdef::)|(\nifndef::))', r'\g<1>', data )
-
- with open(filename, 'w', encoding='utf8', newline='\n') as f:
- data = f.write(data)
-
-def deperiodizeFolder(folder):
- print(' Parsing = %s' % folder)
- for root, subdirs, files in os.walk(folder):
- for file in files:
- if file.endswith(".txt"):
- file_path = os.path.join(root, file)
- deperiodizeFile(file_path)
- for subdir in subdirs:
- sub_folder = os.path.join(root, subdir)
- deperiodizeFolder(sub_folder)
-
-if __name__ == '__main__':
- deperiodizeFolder(os.getcwd() + '/chapters')
- deperiodizeFolder(os.getcwd() + '/appendices')
diff --git a/codegen/vulkan/scripts/docgenerator.py b/codegen/vulkan/scripts/docgenerator.py
deleted file mode 100644
index bb86eb50..00000000
--- a/codegen/vulkan/scripts/docgenerator.py
+++ /dev/null
@@ -1,482 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-from pathlib import Path
-
-from generator import GeneratorOptions, OutputGenerator, noneStr, write
-
-ENUM_TABLE_PREFIX = """
-[cols=",",options="header",]
-|=======================================================================
-|Enum |Description"""
-
-ENUM_TABLE_SUFFIX = """|======================================================================="""
-
-FLAG_BLOCK_PREFIX = """.Flag Descriptions
-****"""
-
-FLAG_BLOCK_SUFFIX = """****"""
-
-def orgLevelKey(name):
- # Sort key for organization levels of features / extensions
- # From highest to lowest, core versions, KHR extensions, EXT extensions,
- # and vendor extensions
-
- prefixes = (
- 'VK_VERSION_',
- 'VKSC_VERSION_',
- 'VK_KHR_',
- 'VK_EXT_')
-
- i = 0
- for prefix in prefixes:
- if name.startswith(prefix):
- return i
- i += 1
-
- # Everything else (e.g. vendor extensions) is least important
- return i
-
-class DocGeneratorOptions(GeneratorOptions):
- """DocGeneratorOptions - subclass of GeneratorOptions for
- generating declaration snippets for the spec.
-
- Shares many members with CGeneratorOptions, since
- both are writing C-style declarations."""
-
- def __init__(self,
- prefixText="",
- apicall='',
- apientry='',
- apientryp='',
- indentFuncProto=True,
- indentFuncPointer=False,
- alignFuncParam=0,
- secondaryInclude=False,
- expandEnumerants=True,
- extEnumerantAdditions=False,
- extEnumerantFormatString=" (Added by the {} extension)",
- **kwargs):
- """Constructor.
-
- Since this generator outputs multiple files at once,
- the filename is just a "stamp" to indicate last generation time.
-
- Shares many parameters/members with CGeneratorOptions, since
- both are writing C-style declarations:
-
- - prefixText - list of strings to prefix generated header with
- (usually a copyright statement + calling convention macros).
- - apicall - string to use for the function declaration prefix,
- such as APICALL on Windows.
- - apientry - string to use for the calling convention macro,
- in typedefs, such as APIENTRY.
- - apientryp - string to use for the calling convention macro
- in function pointer typedefs, such as APIENTRYP.
- - indentFuncProto - True if prototype declarations should put each
- parameter on a separate line
- - indentFuncPointer - True if typedefed function pointers should put each
- parameter on a separate line
- - alignFuncParam - if nonzero and parameters are being put on a
- separate line, align parameter names at the specified column
-
- Additional parameters/members:
-
- - expandEnumerants - if True, add BEGIN/END_RANGE macros in enumerated
- type declarations
- - secondaryInclude - if True, add secondary (no xref anchor) versions
- of generated files
- - extEnumerantAdditions - if True, include enumerants added by extensions
- in comment tables for core enumeration types.
- - extEnumerantFormatString - A format string for any additional message for
- enumerants from extensions if extEnumerantAdditions is True. The correctly-
- marked-up extension name will be passed.
- """
- GeneratorOptions.__init__(self, **kwargs)
- self.prefixText = prefixText
- """list of strings to prefix generated header with (usually a copyright statement + calling convention macros)."""
-
- self.apicall = apicall
- """string to use for the function declaration prefix, such as APICALL on Windows."""
-
- self.apientry = apientry
- """string to use for the calling convention macro, in typedefs, such as APIENTRY."""
-
- self.apientryp = apientryp
- """string to use for the calling convention macro in function pointer typedefs, such as APIENTRYP."""
-
- self.indentFuncProto = indentFuncProto
- """True if prototype declarations should put each parameter on a separate line"""
-
- self.indentFuncPointer = indentFuncPointer
- """True if typedefed function pointers should put each parameter on a separate line"""
-
- self.alignFuncParam = alignFuncParam
- """if nonzero and parameters are being put on a separate line, align parameter names at the specified column"""
-
- self.secondaryInclude = secondaryInclude
- """if True, add secondary (no xref anchor) versions of generated files"""
-
- self.expandEnumerants = expandEnumerants
- """if True, add BEGIN/END_RANGE macros in enumerated type declarations"""
-
- self.extEnumerantAdditions = extEnumerantAdditions
- """if True, include enumerants added by extensions in comment tables for core enumeration types."""
-
- self.extEnumerantFormatString = extEnumerantFormatString
- """A format string for any additional message for
- enumerants from extensions if extEnumerantAdditions is True. The correctly-
- marked-up extension name will be passed."""
-
-
-class DocOutputGenerator(OutputGenerator):
- """DocOutputGenerator - subclass of OutputGenerator.
-
- Generates AsciiDoc includes with C-language API interfaces, for reference
- pages and the corresponding specification. Similar to COutputGenerator,
- but each interface is written into a different file as determined by the
- options, only actual C types are emitted, and none of the boilerplate
- preprocessor code is emitted."""
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- # Keep track of all extension numbers
- self.extension_numbers = set()
-
- def beginFile(self, genOpts):
- OutputGenerator.beginFile(self, genOpts)
-
- # This should be a separate conventions property rather than an
- # inferred type name pattern for different APIs.
- self.result_type = genOpts.conventions.type_prefix + "Result"
-
- def endFile(self):
- OutputGenerator.endFile(self)
-
- def beginFeature(self, interface, emit):
- # Start processing in superclass
- OutputGenerator.beginFeature(self, interface, emit)
-
- # Decide if we're in a core <feature> or an <extension>
- self.in_core = (interface.tag == 'feature')
-
- # Verify that each <extension> has a unique number during doc
- # generation
- # TODO move this to consistency_tools
- if not self.in_core:
- extension_number = interface.get('number')
- if extension_number is not None and extension_number != "0":
- if extension_number in self.extension_numbers:
- self.logMsg('error', 'Duplicate extension number ', extension_number, ' detected in feature ', interface.get('name'), '\n')
- exit(1)
- else:
- self.extension_numbers.add(extension_number)
-
- def endFeature(self):
- # Finish processing in superclass
- OutputGenerator.endFeature(self)
-
- def genRequirements(self, name, mustBeFound = True):
- """Generate text showing what core versions and extensions introduce
- an API. This relies on the map in api.py, which may be loaded at
- runtime into self.apidict. If not present, no message is
- generated.
-
- - name - name of the API
- - mustBeFound - If True, when requirements for 'name' cannot be
- determined, a warning comment is generated.
- """
-
- if self.apidict:
- if name in self.apidict.requiredBy:
- # It's possible to get both 'A with B' and 'B with A' for
- # the same API.
- # To simplify this, sort the (base,dependency) requirements
- # and put them in a set to ensure they're unique.
- features = set()
- for (base,dependency) in self.apidict.requiredBy[name]:
- if dependency is not None:
- l = sorted(
- sorted((base, dependency)),
- key=orgLevelKey)
- features.add(' with '.join(l))
- else:
- features.add(base)
- # Sort the overall dependencies so core versions are first
- provider = ', '.join(sorted(features, key=orgLevelKey))
- return f'// Provided by {provider}\n'
- else:
- if mustBeFound:
- self.logMsg('warn', 'genRequirements: API {} not found'.format(name))
- return ''
- else:
- # No API dictionary available, return nothing
- return ''
-
- def writeInclude(self, directory, basename, contents):
- """Generate an include file.
-
- - directory - subdirectory to put file in
- - basename - base name of the file
- - contents - contents of the file (Asciidoc boilerplate aside)"""
- # Create subdirectory, if needed
- directory = self.genOpts.directory + '/' + directory
- self.makeDir(directory)
-
- # Create file
- filename = directory + '/' + basename + '.txt'
- self.logMsg('diag', '# Generating include file:', filename)
- fp = open(filename, 'w', encoding='utf-8')
-
- # Asciidoc anchor
- write(self.genOpts.conventions.warning_comment, file=fp)
- write('[[{0},{0}]]'.format(basename), file=fp)
-
- if self.genOpts.conventions.generate_index_terms:
- index_terms = []
- if basename.startswith(self.conventions.command_prefix):
- index_terms.append(basename[2:] + " (function)")
- elif basename.startswith(self.conventions.type_prefix):
- index_terms.append(basename[2:] + " (type)")
- elif basename.startswith(self.conventions.api_prefix):
- index_terms.append(basename[len(self.conventions.api_prefix):] + " (define)")
- index_terms.append(basename)
- write('indexterm:[{}]'.format(','.join(index_terms)), file=fp)
-
- write('[source,c++]', file=fp)
- write('----', file=fp)
- write(contents, file=fp)
- write('----', file=fp)
- fp.close()
-
- if self.genOpts.secondaryInclude:
- # Create secondary no cross-reference include file
- filename = directory + '/' + basename + '.no-xref.txt'
- self.logMsg('diag', '# Generating include file:', filename)
- fp = open(filename, 'w', encoding='utf-8')
-
- # Asciidoc anchor
- write(self.genOpts.conventions.warning_comment, file=fp)
- write('// Include this no-xref version without cross reference id for multiple includes of same file', file=fp)
- write('[source,c++]', file=fp)
- write('----', file=fp)
- write(contents, file=fp)
- write('----', file=fp)
- fp.close()
-
- def writeTable(self, basename, values):
- """Output a table of enumerants."""
- directory = Path(self.genOpts.directory) / 'enums'
- self.makeDir(str(directory))
-
- filename = str(directory / '{}.comments.txt'.format(basename))
- self.logMsg('diag', '# Generating include file:', filename)
-
- with open(filename, 'w', encoding='utf-8') as fp:
- write(self.conventions.warning_comment, file=fp)
- write(ENUM_TABLE_PREFIX, file=fp)
-
- for data in values:
- write("|ename:{}".format(data['name']), file=fp)
- write("|{}".format(data['comment']), file=fp)
-
- write(ENUM_TABLE_SUFFIX, file=fp)
-
- def writeFlagBox(self, basename, values):
- """Output a box of flag bit comments."""
- directory = Path(self.genOpts.directory) / 'enums'
- self.makeDir(str(directory))
-
- filename = str(directory / '{}.comments.txt'.format(basename))
- self.logMsg('diag', '# Generating include file:', filename)
-
- with open(filename, 'w', encoding='utf-8') as fp:
- write(self.conventions.warning_comment, file=fp)
- write(FLAG_BLOCK_PREFIX, file=fp)
-
- for data in values:
- write("* ename:{} -- {}".format(data['name'],
- data['comment']),
- file=fp)
-
- write(FLAG_BLOCK_SUFFIX, file=fp)
-
- def genType(self, typeinfo, name, alias):
- """Generate type."""
- OutputGenerator.genType(self, typeinfo, name, alias)
- typeElem = typeinfo.elem
- # If the type is a struct type, traverse the embedded <member> tags
- # generating a structure. Otherwise, emit the tag text.
- category = typeElem.get('category')
-
- if category in ('struct', 'union'):
- # If the type is a struct type, generate it using the
- # special-purpose generator.
- self.genStruct(typeinfo, name, alias)
- elif category not in OutputGenerator.categoryToPath:
- # If there's no path, don't write output
- self.logMsg('diag', 'NOT writing include for {} category {}'.format(
- name, category))
- else:
- body = self.genRequirements(name)
- if alias:
- # If the type is an alias, just emit a typedef declaration
- body += 'typedef ' + alias + ' ' + name + ';\n'
- self.writeInclude(OutputGenerator.categoryToPath[category],
- name, body)
- else:
- # Replace <apientry /> tags with an APIENTRY-style string
- # (from self.genOpts). Copy other text through unchanged.
- # If the resulting text is an empty string, don't emit it.
- body += noneStr(typeElem.text)
- for elem in typeElem:
- if elem.tag == 'apientry':
- body += self.genOpts.apientry + noneStr(elem.tail)
- else:
- body += noneStr(elem.text) + noneStr(elem.tail)
-
- if body:
- self.writeInclude(OutputGenerator.categoryToPath[category],
- name, body + '\n')
- else:
- self.logMsg('diag', 'NOT writing empty include file for type', name)
-
- def genStruct(self, typeinfo, typeName, alias):
- """Generate struct."""
- OutputGenerator.genStruct(self, typeinfo, typeName, alias)
-
- typeElem = typeinfo.elem
-
- body = self.genRequirements(typeName)
- if alias:
- body += 'typedef ' + alias + ' ' + typeName + ';\n'
- else:
- body += 'typedef ' + typeElem.get('category') + ' ' + typeName + ' {\n'
-
- targetLen = self.getMaxCParamTypeLength(typeinfo)
- for member in typeElem.findall('.//member'):
- body += self.makeCParamDecl(member, targetLen + 4)
- body += ';\n'
- body += '} ' + typeName + ';'
-
- self.writeInclude('structs', typeName, body)
-
- def genEnumTable(self, groupinfo, groupName):
- """Generate tables of enumerant values and short descriptions from
- the XML."""
-
- values = []
- got_comment = False
- missing_comments = []
- for elem in groupinfo.elem.findall('enum'):
- if not elem.get('required'):
- continue
- name = elem.get('name')
-
- data = {
- 'name': name,
- }
-
- (numVal, strVal) = self.enumToValue(elem, True)
- data['value'] = numVal
-
- extname = elem.get('extname')
-
- added_by_extension_to_core = (extname is not None and self.in_core)
- if added_by_extension_to_core and not self.genOpts.extEnumerantAdditions:
- # We're skipping such values
- continue
-
- comment = elem.get('comment')
- if comment:
- got_comment = True
- elif name.endswith('_UNKNOWN') and numVal == 0:
- # This is a placeholder for 0-initialization to be clearly invalid.
- # Just skip this silently
- continue
- else:
- # Skip but record this in case it's an odd-one-out missing a comment.
- missing_comments.append(name)
- continue
-
- if added_by_extension_to_core and self.genOpts.extEnumerantFormatString:
- # Add a note to the comment
- comment += self.genOpts.extEnumerantFormatString.format(
- self.conventions.formatExtension(extname))
-
- data['comment'] = comment
- values.append(data)
-
- if got_comment:
- # If any had a comment, output it.
-
- if missing_comments:
- self.logMsg('warn', 'The following values for', groupName,
- 'were omitted from the table due to missing comment attributes:',
- ', '.join(missing_comments))
-
- group_type = groupinfo.elem.get('type')
- if groupName == self.result_type:
- # Split this into success and failure
- self.writeTable(groupName + '.success',
- (data for data in values
- if data['value'] >= 0))
- self.writeTable(groupName + '.error',
- (data for data in values
- if data['value'] < 0))
- elif group_type == 'bitmask':
- self.writeFlagBox(groupName, values)
- elif group_type == 'enum':
- self.writeTable(groupName, values)
- else:
- raise RuntimeError("Unrecognized enums type: " + str(group_type))
-
- def genGroup(self, groupinfo, groupName, alias):
- """Generate group (e.g. C "enum" type)."""
- OutputGenerator.genGroup(self, groupinfo, groupName, alias)
-
- body = self.genRequirements(groupName)
- if alias:
- # If the group name is aliased, just emit a typedef declaration
- # for the alias.
- body += 'typedef ' + alias + ' ' + groupName + ';\n'
- else:
- expand = self.genOpts.expandEnumerants
- (_, enumbody) = self.buildEnumCDecl(expand, groupinfo, groupName)
- body += enumbody
- if self.genOpts.conventions.generate_enum_table:
- self.genEnumTable(groupinfo, groupName)
-
- self.writeInclude('enums', groupName, body)
-
- def genEnum(self, enuminfo, name, alias):
- """Generate the C declaration for a constant (a single <enum> value)."""
-
- OutputGenerator.genEnum(self, enuminfo, name, alias)
-
- body = self.buildConstantCDecl(enuminfo, name, alias)
-
- self.writeInclude('enums', name, body)
-
- def genCmd(self, cmdinfo, name, alias):
- "Generate command."
- OutputGenerator.genCmd(self, cmdinfo, name, alias)
-
- return_type = cmdinfo.elem.find('proto/type')
- if self.genOpts.conventions.requires_error_validation(return_type):
- # This command returns an API result code, so check that it
- # returns at least the required errors.
- # TODO move this to consistency_tools
- required_errors = set(self.genOpts.conventions.required_errors)
- errorcodes = cmdinfo.elem.get('errorcodes').split(',')
- if not required_errors.issubset(set(errorcodes)):
- self.logMsg('error', 'Missing required error code for command: ', name, '\n')
- exit(1)
-
- body = self.genRequirements(name)
- decls = self.makeCDecls(cmdinfo.elem)
- body += decls[0]
- self.writeInclude('protos', name, body)
diff --git a/codegen/vulkan/scripts/extensionmetadocgenerator.py b/codegen/vulkan/scripts/extensionmetadocgenerator.py
deleted file mode 100644
index 07d2c947..00000000
--- a/codegen/vulkan/scripts/extensionmetadocgenerator.py
+++ /dev/null
@@ -1,665 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-import os
-import re
-import sys
-from functools import total_ordering
-from generator import GeneratorOptions, OutputGenerator, regSortFeatures, write
-
-class ExtensionMetaDocGeneratorOptions(GeneratorOptions):
- """ExtensionMetaDocGeneratorOptions - subclass of GeneratorOptions.
-
- Represents options during extension metainformation generation for Asciidoc"""
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
-
-EXT_NAME_DECOMPOSE_RE = re.compile(r'[A-Z]+_(?P<tag>[A-Z]+)_(?P<name>[\w_]+)')
-
-
-@total_ordering
-class Extension:
- def __init__(self,
- generator, # needed for logging and API conventions
- filename,
- name,
- number,
- ext_type,
- requires,
- requiresCore,
- contact,
- promotedTo,
- deprecatedBy,
- obsoletedBy,
- provisional,
- revision,
- specialuse ):
- self.generator = generator
- self.conventions = generator.genOpts.conventions
- self.filename = filename
- self.name = name
- self.number = number
- self.ext_type = ext_type
- self.requires = requires
- self.requiresCore = requiresCore
- self.contact = contact
- self.promotedTo = promotedTo
- self.deprecatedBy = deprecatedBy
- self.obsoletedBy = obsoletedBy
- self.provisional = provisional
- self.revision = revision
- self.specialuse = specialuse
-
- self.deprecationType = None
- self.supercedingAPIVersion = None
- self.supercedingExtension = None
-
- if self.promotedTo is not None and self.deprecatedBy is not None and self.obsoletedBy is not None:
- self.generator.logMsg('warn', 'All \'promotedto\', \'deprecatedby\' and \'obsoletedby\' attributes used on extension ' + self.name + '! Ignoring \'promotedto\' and \'deprecatedby\'.')
- elif self.promotedTo is not None and self.deprecatedBy is not None:
- self.generator.logMsg('warn', 'Both \'promotedto\' and \'deprecatedby\' attributes used on extension ' + self.name + '! Ignoring \'deprecatedby\'.')
- elif self.promotedTo is not None and self.obsoletedBy is not None:
- self.generator.logMsg('warn', 'Both \'promotedto\' and \'obsoletedby\' attributes used on extension ' + self.name + '! Ignoring \'promotedto\'.')
- elif self.deprecatedBy is not None and self.obsoletedBy is not None:
- self.generator.logMsg('warn', 'Both \'deprecatedby\' and \'obsoletedby\' attributes used on extension ' + self.name + '! Ignoring \'deprecatedby\'.')
-
- supercededBy = None
- if self.promotedTo is not None:
- self.deprecationType = 'promotion'
- supercededBy = promotedTo
- elif self.deprecatedBy is not None:
- self.deprecationType = 'deprecation'
- supercededBy = deprecatedBy
- elif self.obsoletedBy is not None:
- self.deprecationType = 'obsoletion'
- supercededBy = obsoletedBy
-
- if supercededBy is not None:
- if supercededBy == '' and not self.deprecationType == 'promotion':
- pass # supercedingAPIVersion, supercedingExtension is None
- elif supercededBy.startswith(self.conventions.api_version_prefix):
- self.supercedingAPIVersion = supercededBy
- elif supercededBy.startswith(self.conventions.api_prefix):
- self.supercedingExtension = supercededBy
- else:
- self.generator.logMsg('error', 'Unrecognized ' + self.deprecationType + ' attribute value \'' + supercededBy + '\'!')
-
- match = EXT_NAME_DECOMPOSE_RE.match(self.name)
- self.vendor = match.group('tag')
- self.bare_name = match.group('name')
-
- def __str__(self):
- return self.name
- def __eq__(self, other):
- return self.name == other.name
- def __ne__(self, other):
- return self.name != other.name
-
- def __lt__(self, other):
- self_is_KHR = self.name.startswith(self.conventions.KHR_prefix)
- self_is_EXT = self.name.startswith(self.conventions.EXT_prefix)
- other_is_KHR = other.name.startswith(self.conventions.KHR_prefix)
- other_is_EXT = other.name.startswith(self.conventions.EXT_prefix)
-
- swap = False
- if self_is_KHR and not other_is_KHR:
- return not swap
- if other_is_KHR and not self_is_KHR:
- return swap
- if self_is_EXT and not other_is_EXT:
- return not swap
- if other_is_EXT and not self_is_EXT:
- return swap
-
- return self.name < other.name
-
- def typeToStr(self):
- if self.ext_type == 'instance':
- return 'Instance extension'
- if self.ext_type == 'device':
- return 'Device extension'
-
- if self.ext_type is not None:
- self.generator.logMsg('warn', 'The type attribute of ' + self.name + ' extension is neither \'instance\' nor \'device\'. That is invalid (at the time this script was written).')
- else: # should be unreachable
- self.generator.logMsg('error', 'Logic error in typeToStr(): Missing type attribute!')
- return None
-
- def specLink(self, xrefName, xrefText, isRefpage = False):
- """Generate a string containing a link to a specification anchor in
- asciidoctor markup form.
-
- - xrefName - anchor name in the spec
- - xrefText - text to show for the link, or None
- - isRefpage = True if generating a refpage include, False if
- generating a specification extension appendix include"""
-
- if isRefpage:
- # Always link into API spec
- specURL = self.conventions.specURL('api')
- return 'link:{}#{}[{}^]'.format(specURL, xrefName, xrefText)
- else:
- return '<<' + xrefName + ', ' + xrefText + '>>'
-
- def conditionalLinkCoreAPI(self, apiVersion, linkSuffix, isRefpage):
- versionMatch = re.match(self.conventions.api_version_prefix + r'(\d+)_(\d+)', apiVersion)
- major = versionMatch.group(1)
- minor = versionMatch.group(2)
-
- dottedVersion = major + '.' + minor
-
- xrefName = 'versions-' + dottedVersion + linkSuffix
- xrefText = self.conventions.api_name() + ' ' + dottedVersion
-
- doc = 'ifdef::' + apiVersion + '[]\n'
- doc += ' ' + self.specLink(xrefName, xrefText, isRefpage) + '\n'
- doc += 'endif::' + apiVersion + '[]\n'
- doc += 'ifndef::' + apiVersion + '[]\n'
- doc += ' ' + self.conventions.api_name() + ' ' + dottedVersion + '\n'
- doc += 'endif::' + apiVersion + '[]\n'
-
- return doc
-
- def conditionalLinkExt(self, extName, indent = ' '):
- doc = 'ifdef::' + extName + '[]\n'
- doc += indent + self.conventions.formatExtension(extName) + '\n'
- doc += 'endif::' + extName + '[]\n'
- doc += 'ifndef::' + extName + '[]\n'
- doc += indent + '`' + extName + '`\n'
- doc += 'endif::' + extName + '[]\n'
-
- return doc
-
- def resolveDeprecationChain(self, extensionsList, succeededBy, isRefpage, file):
- ext = next(x for x in extensionsList if x.name == succeededBy)
-
- if ext.deprecationType:
- if ext.deprecationType == 'promotion':
- if ext.supercedingAPIVersion:
- write(' ** Which in turn was _promoted_ to\n' + ext.conditionalLinkCoreAPI(ext.supercedingAPIVersion, '-promotions', isRefpage), file=file)
- else: # ext.supercedingExtension
- write(' ** Which in turn was _promoted_ to extension\n' + ext.conditionalLinkExt(ext.supercedingExtension), file=file)
- ext.resolveDeprecationChain(extensionsList, ext.supercedingExtension, file)
- elif ext.deprecationType == 'deprecation':
- if ext.supercedingAPIVersion:
- write(' ** Which in turn was _deprecated_ by\n' + ext.conditionalLinkCoreAPI(ext.supercedingAPIVersion, '-new-feature', isRefpage), file=file)
- elif ext.supercedingExtension:
- write(' ** Which in turn was _deprecated_ by\n' + ext.conditionalLinkExt(ext.supercedingExtension) + ' extension', file=file)
- ext.resolveDeprecationChain(extensionsList, ext.supercedingExtension, file)
- else:
- write(' ** Which in turn was _deprecated_ without replacement', file=file)
- elif ext.deprecationType == 'obsoletion':
- if ext.supercedingAPIVersion:
- write(' ** Which in turn was _obsoleted_ by\n' + ext.conditionalLinkCoreAPI(ext.supercedingAPIVersion, '-new-feature', isRefpage), file=file)
- elif ext.supercedingExtension:
- write(' ** Which in turn was _obsoleted_ by\n' + ext.conditionalLinkExt(ext.supercedingExtension) + ' extension', file=file)
- ext.resolveDeprecationChain(extensionsList, ext.supercedingExtension, file)
- else:
- write(' ** Which in turn was _obsoleted_ without replacement', file=file)
- else: # should be unreachable
- self.generator.logMsg('error', 'Logic error in resolveDeprecationChain(): deprecationType is neither \'promotion\', \'deprecation\' nor \'obsoletion\'!')
-
-
- def writeTag(self, tag, value, isRefpage, fp):
- """Write a tag and (if non-None) a tag value to a file.
-
- - tag - string tag name
- - value - tag value, or None
- - isRefpage - controls style in which the tag is marked up
- - fp - open file pointer to write to"""
-
- if isRefpage:
- # Use subsection headers for the tag name
- tagPrefix = '== '
- tagSuffix = ''
- else:
- # Use an bolded item list for the tag name
- tagPrefix = '*'
- tagSuffix = '*::'
-
- write(tagPrefix + tag + tagSuffix, file=fp)
- if value is not None:
- write(value, file=fp)
-
- if isRefpage:
- write('', file=fp)
-
- def makeMetafile(self, extensionsList, isRefpage = False):
- """Generate a file containing extension metainformation in
- asciidoctor markup form.
-
- - extensionsList - list of extensions spec is being generated against
- - isRefpage - True if generating a refpage include, False if
- generating a specification extension appendix include"""
-
- if isRefpage:
- filename = self.filename.replace('meta/', 'meta/refpage.')
- else:
- filename = self.filename
-
- fp = self.generator.newFile(filename)
-
- if not isRefpage:
- write('[[' + self.name + ']]', file=fp)
- write('=== ' + self.name, file=fp)
- write('', file=fp)
-
- self.writeTag('Name String', '`' + self.name + '`', isRefpage, fp)
- self.writeTag('Extension Type', self.typeToStr(), isRefpage, fp)
-
- self.writeTag('Registered Extension Number', self.number, isRefpage, fp)
- self.writeTag('Revision', self.revision, isRefpage, fp)
-
- # Only API extension dependencies are coded in XML, others are explicit
- self.writeTag('Extension and Version Dependencies', None, isRefpage, fp)
-
- write(' * Requires ' + self.conventions.api_name() + ' ' + self.requiresCore, file=fp)
- if self.requires:
- for dep in self.requires.split(','):
- write(' * Requires', self.conventions.formatExtension(dep),
- file=fp)
- if self.provisional == 'true':
- write(' * *This is a _provisional_ extension and must: be used with caution.', file=fp)
- write(' See the ' +
- self.specLink(xrefName = 'boilerplate-provisional-header',
- xrefText = 'description',
- isRefpage = isRefpage) +
- ' of provisional header files for enablement and stability details.*', file=fp)
- write('', file=fp)
-
- if self.deprecationType:
- self.writeTag('Deprecation state', None, isRefpage, fp)
-
- if self.deprecationType == 'promotion':
- if self.supercedingAPIVersion:
- write(' * _Promoted_ to\n' + self.conditionalLinkCoreAPI(self.supercedingAPIVersion, '-promotions', isRefpage), file=fp)
- else: # ext.supercedingExtension
- write(' * _Promoted_ to\n' + self.conditionalLinkExt(self.supercedingExtension) + ' extension', file=fp)
- self.resolveDeprecationChain(extensionsList, self.supercedingExtension, isRefpage, fp)
- elif self.deprecationType == 'deprecation':
- if self.supercedingAPIVersion:
- write(' * _Deprecated_ by\n' + self.conditionalLinkCoreAPI(self.supercedingAPIVersion, '-new-features', isRefpage), file=fp)
- elif self.supercedingExtension:
- write(' * _Deprecated_ by\n' + self.conditionalLinkExt(self.supercedingExtension) + ' extension' , file=fp)
- self.resolveDeprecationChain(extensionsList, self.supercedingExtension, isRefpage, fp)
- else:
- write(' * _Deprecated_ without replacement' , file=fp)
- elif self.deprecationType == 'obsoletion':
- if self.supercedingAPIVersion:
- write(' * _Obsoleted_ by\n' + self.conditionalLinkCoreAPI(self.supercedingAPIVersion, '-new-features', isRefpage), file=fp)
- elif self.supercedingExtension:
- write(' * _Obsoleted_ by\n' + self.conditionalLinkExt(self.supercedingExtension) + ' extension' , file=fp)
- self.resolveDeprecationChain(extensionsList, self.supercedingExtension, isRefpage, fp)
- else:
- # TODO: Does not make sense to retroactively ban use of extensions from 1.0.
- # Needs some tweaks to the semantics and this message, when such extension(s) occur.
- write(' * _Obsoleted_ without replacement' , file=fp)
- else: # should be unreachable
- self.generator.logMsg('error', 'Logic error in makeMetafile(): deprecationType is neither \'promotion\', \'deprecation\' nor \'obsoletion\'!')
- write('', file=fp)
-
- if self.specialuse is not None:
- specialuses = self.specialuse.split(',')
- if len(specialuses) > 1:
- header = 'Special Uses'
- else:
- header = 'Special Use'
- self.writeTag(header, None, isRefpage, fp)
-
- for use in specialuses:
- # Each specialuse attribute value expands an asciidoctor
- # attribute of the same name, instead of using the shorter,
- # and harder to understand attribute
- write('* {}'.format(
- self.specLink(
- xrefName = self.conventions.special_use_section_anchor,
- xrefText = '{' + use + '}',
- isRefpage = isRefpage)), file=fp)
- write('', file=fp)
-
- if self.conventions.write_contacts:
- self.writeTag('Contact', None, isRefpage, fp)
-
- contacts = self.contact.split(',')
- for contact in contacts:
- contactWords = contact.strip().split()
- name = ' '.join(contactWords[:-1])
- handle = contactWords[-1]
- if handle.startswith('gitlab:'):
- prettyHandle = 'icon:gitlab[alt=GitLab, role="red"]' + handle.replace('gitlab:@', '')
- elif handle.startswith('@'):
- issuePlaceholderText = '[' + self.name + '] ' + handle
- issuePlaceholderText += '%0A<<Here describe the issue or question you have about the ' + self.name + ' extension>>'
- trackerLink = 'link:++https://github.com/KhronosGroup/Vulkan-Docs/issues/new?body=' + issuePlaceholderText + '++'
- prettyHandle = trackerLink + '[icon:github[alt=GitHub,role="black"]' + handle[1:] + ',window=_blank,opts=nofollow]'
- else:
- prettyHandle = handle
-
- write(' * ' + name + ' ' + prettyHandle, file=fp)
- write('', file=fp)
-
- # Check if a proposal document for this extension exists in the
- # current repository, and link to the same document (parameterized
- # by a URL prefix attribute) if it does.
- # The assumption is that a proposal document for an extension
- # VK_name will be located in 'proposals/VK_name.asciidoc' relative
- # to the repository root, and that this script will be invoked from
- # the repository root.
- path = 'proposals/{}.asciidoc'.format(self.name)
- if os.path.exists(path) and os.access(path, os.R_OK):
- self.writeTag('Extension Proposal',
- 'link:{{specRepositoryURL}}/{}[{}]'.format(path, self.name), isRefpage, fp)
-
- # If this is metadata to be included in a refpage, adjust the
- # leveloffset to account for the relative structure of the extension
- # appendices vs. refpages.
- if isRefpage:
- write(':leveloffset: -1', file=fp)
-
- fp.close()
-
-class ExtensionMetaDocOutputGenerator(OutputGenerator):
- """ExtensionMetaDocOutputGenerator - subclass of OutputGenerator.
-
- Generates AsciiDoc includes with metainformation for the API extension
- appendices. The fields used from <extension> tags in the API XML are:
-
- - name extension name string
- - number extension number (optional)
- - contact name and GitHub login or email address (optional)
- - type 'instance' | 'device' (optional)
- - requires list of comma-separated required API extensions (optional)
- - requiresCore required core version of API (optional)
- - promotedTo extension or API version it was promoted to
- - deprecatedBy extension or API version which deprecated this extension,
- or empty string if deprecated without replacement
- - obsoletedBy extension or API version which obsoleted this extension,
- or empty string if obsoleted without replacement
- - provisional 'true' if this extension is released provisionally"""
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.extensions = []
- # List of strings containing all vendor tags
- self.vendor_tags = []
- self.file_suffix = ''
-
- def newFile(self, filename):
- self.logMsg('diag', '# Generating include file:', filename)
- fp = open(filename, 'w', encoding='utf-8')
- write(self.genOpts.conventions.warning_comment, file=fp)
- return fp
-
- def beginFile(self, genOpts):
- OutputGenerator.beginFile(self, genOpts)
-
- self.directory = self.genOpts.directory
- self.file_suffix = self.genOpts.conventions.file_suffix
-
- # Iterate over all 'tag' Elements and add the names of all the valid vendor
- # tags to the list
- root = self.registry.tree.getroot()
- for tag in root.findall('tags/tag'):
- self.vendor_tags.append(tag.get('name'))
-
- # Create subdirectory, if needed
- self.makeDir(self.directory)
-
- def conditionalExt(self, extName, content, ifdef = None, condition = None):
- doc = ''
-
- innerdoc = 'ifdef::' + extName + '[]\n'
- innerdoc += content + '\n'
- innerdoc += 'endif::' + extName + '[]\n'
-
- if ifdef:
- if ifdef == 'ifndef':
- if condition:
- doc += 'ifndef::' + condition + '[]\n'
- doc += innerdoc
- doc += 'endif::' + condition + '[]\n'
- else: # no condition is as if condition is defined; "nothing" is always defined :p
- pass # so no output
- elif ifdef == 'ifdef':
- if condition:
- doc += 'ifdef::' + condition + '+' + extName + '[]\n'
- doc += content + '\n' # does not include innerdoc; the ifdef was merged with the one above
- doc += 'endif::' + condition + '+' + extName + '[]\n'
- else: # no condition is as if condition is defined; "nothing" is always defined :p
- doc += innerdoc
- else: # should be unreachable
- raise RuntimeError('Should be unreachable: ifdef is neither \'ifdef \' nor \'ifndef\'!')
- else:
- doc += innerdoc
-
- return doc
-
- def makeExtensionInclude(self, ext):
- return self.conventions.extension_include_string(ext)
-
- def endFile(self):
- self.extensions.sort()
-
- # Generate metadoc extension files, in refpage and non-refpage form
- for ext in self.extensions:
- ext.makeMetafile(self.extensions, isRefpage = False)
- if self.conventions.write_refpage_include:
- ext.makeMetafile(self.extensions, isRefpage = True)
-
- # Generate list of promoted extensions
- promotedExtensions = {}
- for ext in self.extensions:
- if ext.deprecationType == 'promotion' and ext.supercedingAPIVersion:
- promotedExtensions.setdefault(ext.supercedingAPIVersion, []).append(ext)
-
- for coreVersion, extensions in promotedExtensions.items():
- promoted_extensions_fp = self.newFile(self.directory + '/promoted_extensions_' + coreVersion + self.file_suffix)
-
- for ext in extensions:
- indent = ''
- write(' * {blank}\n+\n' + ext.conditionalLinkExt(ext.name, indent), file=promoted_extensions_fp)
-
- promoted_extensions_fp.close()
-
- # Re-sort to match earlier behavior
- # TODO: Remove this extra sort when re-arranging section order OK.
-
- def makeSortKey(ext):
- name = ext.name.lower()
- prefixes = self.conventions.extension_index_prefixes
- for i, prefix in enumerate(prefixes):
- if ext.name.startswith(prefix):
- return (i, name)
- return (len(prefixes), name)
-
- self.extensions.sort(key=makeSortKey)
-
- # Generate include directives for the extensions appendix, grouping
- # extensions by status (current, deprecated, provisional, etc.)
- with self.newFile(self.directory + '/current_extensions_appendix' + self.file_suffix) as current_extensions_appendix_fp, \
- self.newFile(self.directory + '/deprecated_extensions_appendix' + self.file_suffix) as deprecated_extensions_appendix_fp, \
- self.newFile(self.directory + '/current_extension_appendices' + self.file_suffix) as current_extension_appendices_fp, \
- self.newFile(self.directory + '/current_extension_appendices_toc' + self.file_suffix) as current_extension_appendices_toc_fp, \
- self.newFile(self.directory + '/deprecated_extension_appendices' + self.file_suffix) as deprecated_extension_appendices_fp, \
- self.newFile(self.directory + '/deprecated_extension_appendices_toc' + self.file_suffix) as deprecated_extension_appendices_toc_fp, \
- self.newFile(self.directory + '/deprecated_extensions_guard_macro' + self.file_suffix) as deprecated_extensions_guard_macro_fp, \
- self.newFile(self.directory + '/provisional_extensions_appendix' + self.file_suffix) as provisional_extensions_appendix_fp, \
- self.newFile(self.directory + '/provisional_extension_appendices' + self.file_suffix) as provisional_extension_appendices_fp, \
- self.newFile(self.directory + '/provisional_extension_appendices_toc' + self.file_suffix) as provisional_extension_appendices_toc_fp, \
- self.newFile(self.directory + '/provisional_extensions_guard_macro' + self.file_suffix) as provisional_extensions_guard_macro_fp:
-
- write('', file=current_extensions_appendix_fp)
- write('include::deprecated_extensions_guard_macro' + self.file_suffix + '[]', file=current_extensions_appendix_fp)
- write('', file=current_extensions_appendix_fp)
- write('ifndef::HAS_DEPRECATED_EXTENSIONS[]', file=current_extensions_appendix_fp)
- write('[[extension-appendices-list]]', file=current_extensions_appendix_fp)
- write('== List of Extensions', file=current_extensions_appendix_fp)
- write('endif::HAS_DEPRECATED_EXTENSIONS[]', file=current_extensions_appendix_fp)
- write('ifdef::HAS_DEPRECATED_EXTENSIONS[]', file=current_extensions_appendix_fp)
- write('[[extension-appendices-list]]', file=current_extensions_appendix_fp)
- write('== List of Current Extensions', file=current_extensions_appendix_fp)
- write('endif::HAS_DEPRECATED_EXTENSIONS[]', file=current_extensions_appendix_fp)
- write('', file=current_extensions_appendix_fp)
- write('include::current_extension_appendices_toc' + self.file_suffix + '[]', file=current_extensions_appendix_fp)
- write('\n<<<\n', file=current_extensions_appendix_fp)
- write('include::current_extension_appendices' + self.file_suffix + '[]', file=current_extensions_appendix_fp)
-
- write('', file=deprecated_extensions_appendix_fp)
- write('include::deprecated_extensions_guard_macro' + self.file_suffix + '[]', file=deprecated_extensions_appendix_fp)
- write('', file=deprecated_extensions_appendix_fp)
- write('ifdef::HAS_DEPRECATED_EXTENSIONS[]', file=deprecated_extensions_appendix_fp)
- write('[[deprecated-extension-appendices-list]]', file=deprecated_extensions_appendix_fp)
- write('== List of Deprecated Extensions', file=deprecated_extensions_appendix_fp)
- write('include::deprecated_extension_appendices_toc' + self.file_suffix + '[]', file=deprecated_extensions_appendix_fp)
- write('\n<<<\n', file=deprecated_extensions_appendix_fp)
- write('include::deprecated_extension_appendices' + self.file_suffix + '[]', file=deprecated_extensions_appendix_fp)
- write('endif::HAS_DEPRECATED_EXTENSIONS[]', file=deprecated_extensions_appendix_fp)
-
- # add include guards to allow multiple includes
- write('ifndef::DEPRECATED_EXTENSIONS_GUARD_MACRO_INCLUDE_GUARD[]', file=deprecated_extensions_guard_macro_fp)
- write(':DEPRECATED_EXTENSIONS_GUARD_MACRO_INCLUDE_GUARD:\n', file=deprecated_extensions_guard_macro_fp)
- write('ifndef::PROVISIONAL_EXTENSIONS_GUARD_MACRO_INCLUDE_GUARD[]', file=provisional_extensions_guard_macro_fp)
- write(':PROVISIONAL_EXTENSIONS_GUARD_MACRO_INCLUDE_GUARD:\n', file=provisional_extensions_guard_macro_fp)
-
- write('', file=provisional_extensions_appendix_fp)
- write('include::provisional_extensions_guard_macro' + self.file_suffix + '[]', file=provisional_extensions_appendix_fp)
- write('', file=provisional_extensions_appendix_fp)
- write('ifdef::HAS_PROVISIONAL_EXTENSIONS[]', file=provisional_extensions_appendix_fp)
- write('[[provisional-extension-appendices-list]]', file=provisional_extensions_appendix_fp)
- write('== List of Provisional Extensions', file=provisional_extensions_appendix_fp)
- write('include::provisional_extension_appendices_toc' + self.file_suffix + '[]', file=provisional_extensions_appendix_fp)
- write('\n<<<\n', file=provisional_extensions_appendix_fp)
- write('include::provisional_extension_appendices' + self.file_suffix + '[]', file=provisional_extensions_appendix_fp)
- write('endif::HAS_PROVISIONAL_EXTENSIONS[]', file=provisional_extensions_appendix_fp)
-
- for ext in self.extensions:
- include = self.makeExtensionInclude(ext)
- link = ' * ' + self.conventions.formatExtension(ext.name)
- if ext.provisional == 'true':
- write(self.conditionalExt(ext.name, include), file=provisional_extension_appendices_fp)
- write(self.conditionalExt(ext.name, link), file=provisional_extension_appendices_toc_fp)
- write(self.conditionalExt(ext.name, ':HAS_PROVISIONAL_EXTENSIONS:'), file=provisional_extensions_guard_macro_fp)
- elif ext.deprecationType is None:
- write(self.conditionalExt(ext.name, include), file=current_extension_appendices_fp)
- write(self.conditionalExt(ext.name, link), file=current_extension_appendices_toc_fp)
- else:
- condition = ext.supercedingAPIVersion if ext.supercedingAPIVersion else ext.supercedingExtension # potentially None too
-
- write(self.conditionalExt(ext.name, include, 'ifndef', condition), file=current_extension_appendices_fp)
- write(self.conditionalExt(ext.name, link, 'ifndef', condition), file=current_extension_appendices_toc_fp)
-
- write(self.conditionalExt(ext.name, include, 'ifdef', condition), file=deprecated_extension_appendices_fp)
- write(self.conditionalExt(ext.name, link, 'ifdef', condition), file=deprecated_extension_appendices_toc_fp)
-
- write(self.conditionalExt(ext.name, ':HAS_DEPRECATED_EXTENSIONS:', 'ifdef', condition), file=deprecated_extensions_guard_macro_fp)
-
- write('endif::DEPRECATED_EXTENSIONS_GUARD_MACRO_INCLUDE_GUARD[]', file=deprecated_extensions_guard_macro_fp)
- write('endif::PROVISIONAL_EXTENSIONS_GUARD_MACRO_INCLUDE_GUARD[]', file=provisional_extensions_guard_macro_fp)
-
- OutputGenerator.endFile(self)
-
- def beginFeature(self, interface, emit):
- # Start processing in superclass
- OutputGenerator.beginFeature(self, interface, emit)
-
- if interface.tag != 'extension':
- self.logMsg('diag', 'beginFeature: ignoring non-extension feature', self.featureName)
- return
-
- # These attributes must exist
- name = self.featureName
- number = self.getAttrib(interface, 'number')
- ext_type = self.getAttrib(interface, 'type')
- revision = self.getSpecVersion(interface, name)
-
- # These attributes are optional
- OPTIONAL = False
- requires = self.getAttrib(interface, 'requires', OPTIONAL)
- requiresCore = self.getAttrib(interface, 'requiresCore', OPTIONAL, '1.0') # TODO update this line with update_version.py
- contact = self.getAttrib(interface, 'contact', OPTIONAL)
- promotedTo = self.getAttrib(interface, 'promotedto', OPTIONAL)
- deprecatedBy = self.getAttrib(interface, 'deprecatedby', OPTIONAL)
- obsoletedBy = self.getAttrib(interface, 'obsoletedby', OPTIONAL)
- provisional = self.getAttrib(interface, 'provisional', OPTIONAL, 'false')
- specialuse = self.getAttrib(interface, 'specialuse', OPTIONAL)
-
- filename = self.directory + '/' + name + self.file_suffix
-
- extdata = Extension(
- generator = self,
- filename = filename,
- name = name,
- number = number,
- ext_type = ext_type,
- requires = requires,
- requiresCore = requiresCore,
- contact = contact,
- promotedTo = promotedTo,
- deprecatedBy = deprecatedBy,
- obsoletedBy = obsoletedBy,
- provisional = provisional,
- revision = revision,
- specialuse = specialuse)
- self.extensions.append(extdata)
-
-
- def endFeature(self):
- # Finish processing in superclass
- OutputGenerator.endFeature(self)
-
- def getAttrib(self, elem, attribute, required=True, default=None):
- """Query an attribute from an element, or return a default value
-
- - elem - element to query
- - attribute - attribute name
- - required - whether attribute must exist
- - default - default value if attribute not present"""
- attrib = elem.get(attribute, default)
- if required and (attrib is None):
- name = elem.get('name', 'UNKNOWN')
- self.logMsg('error', 'While processing \'' + self.featureName + ', <' + elem.tag + '> \'' + name + '\' does not contain required attribute \'' + attribute + '\'')
- return attrib
-
- def numbersToWords(self, name):
- allowlist = ['WIN32', 'INT16', 'D3D1']
-
- # temporarily replace allowlist items
- for i, w in enumerate(allowlist):
- name = re.sub(w, '{' + str(i) + '}', name)
-
- name = re.sub(r'(?<=[A-Z])(\d+)(?![A-Z])', r'_\g<1>', name)
-
- # undo allowlist substitution
- for i, w in enumerate(allowlist):
- name = re.sub('\\{' + str(i) + '}', w, name)
-
- return name
-
- def getSpecVersion(self, elem, extname, default=None):
- """Determine the extension revision from the EXTENSION_NAME_SPEC_VERSION
- enumerant.
-
- - elem - <extension> element to query
- - extname - extension name from the <extension> 'name' attribute
- - default - default value if SPEC_VERSION token not present"""
- # The literal enumerant name to match
- versioningEnumName = self.numbersToWords(extname.upper()) + '_SPEC_VERSION'
-
- for enum in elem.findall('./require/enum'):
- enumName = self.getAttrib(enum, 'name')
- if enumName == versioningEnumName:
- return self.getAttrib(enum, 'value')
-
- #if not found:
- for enum in elem.findall('./require/enum'):
- enumName = self.getAttrib(enum, 'name')
- if enumName.find('SPEC_VERSION') != -1:
- self.logMsg('diag', 'Missing ' + versioningEnumName + '! Potential misnamed candidate ' + enumName + '.')
- return self.getAttrib(enum, 'value')
-
- self.logMsg('error', 'Missing ' + versioningEnumName + '!')
- return default
diff --git a/codegen/vulkan/scripts/genRef.py b/codegen/vulkan/scripts/genRef.py
deleted file mode 100755
index f108204d..00000000
--- a/codegen/vulkan/scripts/genRef.py
+++ /dev/null
@@ -1,1087 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2016-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# genRef.py - create API ref pages from spec source files
-#
-# Usage: genRef.py files
-
-import argparse
-import io
-import os
-import re
-import sys
-from collections import OrderedDict
-from reflib import (findRefs, fixupRefs, loadFile, logDiag, logWarn,
- printPageInfo, setLogFile)
-from reg import Registry
-from vkconventions import VulkanConventions as APIConventions
-
-
-# refpage 'type' attributes which are API entities and contain structured
-# content such as API includes, valid usage blocks, etc.
-refpage_api_types = (
- 'basetypes',
- 'consts',
- 'defines',
- 'enums',
- 'flags',
- 'funcpointers',
- 'handles',
- 'protos',
- 'structs',
-)
-
-# Other refpage types - SPIR-V builtins, API feature blocks, etc. - which do
-# not have structured content.
-refpage_other_types = (
- 'builtins',
- 'feature',
- 'freeform',
- 'spirv'
-)
-
-def makeExtensionInclude(name):
- """Return an include command, given an extension name."""
- return 'include::{}/refpage.{}{}[]'.format(
- conventions.specification_path,
- name,
- conventions.file_suffix)
-
-
-def makeAPIInclude(type, name):
- """Return an include command for a generated API interface
- - type - type of the API, e.g. 'flags', 'handles', etc
- - name - name of the API"""
-
- return 'include::{}/api/{}/{}{}\n'.format(
- conventions.refpage_generated_include_path,
- type, name, conventions.file_suffix)
-
-
-def isextension(name):
- """Return True if name is an API extension name (ends with an upper-case
- author ID).
-
- This assumes that author IDs are at least two characters."""
- return name[-2:].isalpha() and name[-2:].isupper()
-
-
-def printCopyrightSourceComments(fp):
- """Print Khronos CC-BY copyright notice on open file fp.
-
- Writes an asciidoc comment block, which copyrights the source
- file."""
- print('// Copyright 2014-2021 The Khronos Group, Inc.', file=fp)
- print('//', file=fp)
- # This works around constraints of the 'reuse' tool
- print('// SPDX' + '-License-Identifier: CC-BY-4.0', file=fp)
- print('', file=fp)
-
-
-def printFooter(fp, leveloffset=0):
- """Print footer material at the end of each refpage on open file fp.
-
- If generating separate refpages, adds the copyright.
- If generating the single combined refpage, just add a separator.
-
- - leveloffset - number of levels to bias section titles up or down."""
-
- # Generate the section header.
- # Default depth is 2.
- depth = max(0, leveloffset + 2)
- prefix = '=' * depth
-
- print('ifdef::doctype-manpage[]',
- f'{prefix} Copyright',
- '',
- 'include::{config}/copyright-ccby.txt[]',
- 'endif::doctype-manpage[]',
- '',
- 'ifndef::doctype-manpage[]',
- '<<<',
- 'endif::doctype-manpage[]',
- '',
- sep='\n', file=fp)
-
-
-def macroPrefix(name):
- """Add a spec asciidoc macro prefix to an API name, depending on its type
- (protos, structs, enums, etc.).
-
- If the name is not recognized, use the generic link macro 'reflink:'."""
- if name in api.basetypes:
- return 'basetype:' + name
- if name in api.defines:
- return 'dlink:' + name
- if name in api.enums:
- return 'elink:' + name
- if name in api.flags:
- return 'tlink:' + name
- if name in api.funcpointers:
- return 'tlink:' + name
- if name in api.handles:
- return 'slink:' + name
- if name in api.protos:
- return 'flink:' + name
- if name in api.structs:
- return 'slink:' + name
- if name == 'TBD':
- return 'No cross-references are available'
- return 'reflink:' + name
-
-
-def seeAlsoList(apiName, explicitRefs=None, apiAliases=[]):
- """Return an asciidoc string with a list of 'See Also' references for the
- API entity 'apiName', based on the relationship mapping in the api module.
-
- 'explicitRefs' is a list of additional cross-references.
-
- If apiAliases is not None, it is a list of aliases of apiName whose
- cross-references will also be included.
-
- If no relationships are available, return None."""
-
- refs = set(())
-
- # apiName and its aliases are treated equally
- allApis = apiAliases.copy()
- allApis.append(apiName)
-
- # Add all the implicit references to refs
- for name in allApis:
- if name in api.mapDict:
- refs.update(api.mapDict[name])
-
- # Add all the explicit references
- if explicitRefs is not None:
- if isinstance(explicitRefs, str):
- explicitRefs = explicitRefs.split()
- refs.update(name for name in explicitRefs)
-
- # Add extensions / core versions based on dependencies
- for name in allApis:
- if name in api.requiredBy:
- for (base,dependency) in api.requiredBy[name]:
- refs.add(base)
- if dependency is not None:
- refs.add(dependency)
-
- if len(refs) == 0:
- return None
- else:
- return ', '.join(macroPrefix(name) for name in sorted(refs)) + '\n'
-
-
-def remapIncludes(lines, baseDir, specDir):
- """Remap include directives in a list of lines so they can be extracted to a
- different directory.
-
- Returns remapped lines.
-
- - lines - text to remap
- - baseDir - target directory
- - specDir - source directory"""
- # This should be compiled only once
- includePat = re.compile(r'^include::(?P<path>.*)\[\]')
-
- newLines = []
- for line in lines:
- matches = includePat.search(line)
- if matches is not None:
- path = matches.group('path')
-
- if path[0] != '{':
- # Relative path to include file from here
- incPath = specDir + '/' + path
- # Remap to be relative to baseDir
- newPath = os.path.relpath(incPath, baseDir)
- newLine = 'include::' + newPath + '[]\n'
- logDiag('remapIncludes: remapping', line, '->', newLine)
- newLines.append(newLine)
- else:
- # An asciidoctor variable starts the path.
- # This must be an absolute path, not needing to be rewritten.
- newLines.append(line)
- else:
- newLines.append(line)
- return newLines
-
-
-def refPageShell(pageName, pageDesc, fp, head_content = None, sections=None, tail_content=None, man_section=3):
- """Generate body of a reference page.
-
- - pageName - string name of the page
- - pageDesc - string short description of the page
- - fp - file to write to
- - head_content - text to include before the sections
- - sections - iterable returning (title,body) for each section.
- - tail_content - text to include after the sections
- - man_section - Unix man page section"""
-
- printCopyrightSourceComments(fp)
-
- print(':data-uri:',
- ':icons: font',
- conventions.extra_refpage_headers,
- '',
- sep='\n', file=fp)
-
- s = '{}({})'.format(pageName, man_section)
- print('= ' + s,
- '',
- sep='\n', file=fp)
- if pageDesc.strip() == '':
- pageDesc = 'NO SHORT DESCRIPTION PROVIDED'
- logWarn('refPageHead: no short description provided for', pageName)
-
- print('== Name',
- '{} - {}'.format(pageName, pageDesc),
- '',
- sep='\n', file=fp)
-
- if head_content is not None:
- print(head_content,
- '',
- sep='\n', file=fp)
-
- if sections is not None:
- for title, content in sections.items():
- print('== {}'.format(title),
- '',
- content,
- '',
- sep='\n', file=fp)
-
- if tail_content is not None:
- print(tail_content,
- '',
- sep='\n', file=fp)
-
-
-def refPageHead(pageName, pageDesc, specText, fieldName, fieldText, descText, fp):
- """Generate header of a reference page.
-
- - pageName - string name of the page
- - pageDesc - string short description of the page
- - specType - string containing 'spec' field from refpage open block, or None.
- Used to determine containing spec name and URL.
- - specText - string that goes in the "C Specification" section
- - fieldName - string heading an additional section following specText, if not None
- - fieldText - string that goes in the additional section
- - descText - string that goes in the "Description" section
- - fp - file to write to"""
- sections = OrderedDict()
-
- if specText is not None:
- sections['C Specification'] = specText
-
- if fieldName is not None:
- sections[fieldName] = fieldText
-
- if descText is None or descText.strip() == '':
- logWarn('refPageHead: no description provided for', pageName)
-
- if descText is not None:
- sections['Description'] = descText
-
- refPageShell(pageName, pageDesc, fp, head_content=None, sections=sections)
-
-
-def refPageTail(pageName,
- specType=None,
- specAnchor=None,
- seeAlso=None,
- fp=None,
- auto=False,
- leveloffset=0):
- """Generate end boilerplate of a reference page.
-
- - pageName - name of the page
- - specType - None or the 'spec' attribute from the refpage block,
- identifying the specification name and URL this refpage links to.
- - specAnchor - None or the 'anchor' attribute from the refpage block,
- identifying the anchor in the specification this refpage links to. If
- None, the pageName is assumed to be a valid anchor.
- - seeAlso - text of the "See Also" section
- - fp - file to write the page to
- - auto - True if this is an entirely generated refpage, False if it's
- handwritten content from the spec.
- - leveloffset - number of levels to bias section titles up or down."""
-
- specName = conventions.api_name(specType)
- specURL = conventions.specURL(specType)
- if specAnchor is None:
- specAnchor = pageName
-
- if seeAlso is None:
- seeAlso = 'No cross-references are available\n'
-
- notes = [
- 'For more information, see the {}#{}[{} Specification^]'.format(
- specURL, specAnchor, specName),
- '',
- ]
-
- if auto:
- notes.extend((
- 'This page is a generated document.',
- 'Fixes and changes should be made to the generator scripts, '
- 'not directly.',
- ))
- else:
- notes.extend((
- 'This page is extracted from the ' + specName + ' Specification. ',
- 'Fixes and changes should be made to the Specification, '
- 'not directly.',
- ))
-
- # Generate the section header.
- # Default depth is 2.
- depth = max(0, leveloffset + 2)
- prefix = '=' * depth
-
- print(f'{prefix} See Also',
- '',
- seeAlso,
- '',
- sep='\n', file=fp)
-
- print(f'{prefix} Document Notes',
- '',
- '\n'.join(notes),
- '',
- sep='\n', file=fp)
-
- printFooter(fp, leveloffset)
-
-
-def xrefRewriteInitialize():
- """Initialize substitution patterns for asciidoctor xrefs."""
-
- global refLinkPattern, refLinkSubstitute
- global refLinkTextPattern, refLinkTextSubstitute
- global specLinkPattern, specLinkSubstitute
-
- # These are xrefs to Vulkan API entities, rewritten to link to refpages
- # The refLink variants are for xrefs with only an anchor and no text.
- # The refLinkText variants are for xrefs with both anchor and text
- refLinkPattern = re.compile(r'<<([Vv][Kk][^>,]+)>>')
- refLinkSubstitute = r'link:\1.html[\1^]'
-
- refLinkTextPattern = re.compile(r'<<([Vv][Kk][^>,]+)[,]?[ \t\n]*([^>,]*)>>')
- refLinkTextSubstitute = r'link:\1.html[\2^]'
-
- # These are xrefs to other anchors, rewritten to link to the spec
- specLinkPattern = re.compile(r'<<([^>,]+)[,]?[ \t\n]*([^>,]*)>>')
-
- # Unfortunately, specLinkSubstitute depends on the link target,
- # so can't be constructed in advance.
- specLinkSubstitute = None
-
-
-def xrefRewrite(text, specURL):
- """Rewrite asciidoctor xrefs in text to resolve properly in refpages.
- Xrefs which are to Vulkan refpages are rewritten to link to those
- refpages. The remainder are rewritten to generate external links into
- the supplied specification document URL.
-
- - text - string to rewrite, or None
- - specURL - URL to target
-
- Returns rewritten text, or None, respectively"""
-
- global refLinkPattern, refLinkSubstitute
- global refLinkTextPattern, refLinkTextSubstitute
- global specLinkPattern, specLinkSubstitute
-
- specLinkSubstitute = r'link:{}#\1[\2^]'.format(specURL)
-
- if text is not None:
- text, _ = refLinkPattern.subn(refLinkSubstitute, text)
- text, _ = refLinkTextPattern.subn(refLinkTextSubstitute, text)
- text, _ = specLinkPattern.subn(specLinkSubstitute, text)
-
- return text
-
-def emitPage(baseDir, specDir, pi, file):
- """Extract a single reference page into baseDir.
-
- - baseDir - base directory to emit page into
- - specDir - directory extracted page source came from
- - pi - pageInfo for this page relative to file
- - file - list of strings making up the file, indexed by pi"""
- pageName = baseDir + '/' + pi.name + '.txt'
-
- # Add a dictionary entry for this page
- global genDict
- genDict[pi.name] = None
- logDiag('emitPage:', pageName)
-
- # Short description
- if pi.desc is None:
- pi.desc = '(no short description available)'
-
- # Member/parameter section label and text, if there is one
- field = None
- fieldText = None
-
- # Only do structural checks on API pages
- if pi.type in refpage_api_types:
- if pi.include is None:
- logWarn('emitPage:', pageName, 'INCLUDE is None, no page generated')
- return
-
- # Specification text
- lines = remapIncludes(file[pi.begin:pi.include + 1], baseDir, specDir)
- specText = ''.join(lines)
-
- if pi.param is not None:
- if pi.type == 'structs':
- field = 'Members'
- elif pi.type in ['protos', 'funcpointers']:
- field = 'Parameters'
- else:
- logWarn('emitPage: unknown field type:', pi.type,
- 'for', pi.name)
- lines = remapIncludes(file[pi.param:pi.body], baseDir, specDir)
- fieldText = ''.join(lines)
-
- # Description text
- if pi.body != pi.include:
- lines = remapIncludes(file[pi.body:pi.end + 1], baseDir, specDir)
- descText = ''.join(lines)
- else:
- descText = None
- logWarn('emitPage: INCLUDE == BODY, so description will be empty for', pi.name)
- if pi.begin != pi.include:
- logWarn('emitPage: Note: BEGIN != INCLUDE, so the description might be incorrectly located before the API include!')
- elif pi.type in refpage_other_types:
- specText = None
- descText = ''.join(file[pi.begin:pi.end + 1])
- else:
- # This should be caught in the spec markup checking tests
- logErr(f"emitPage: refpage type='{pi.type}' is unrecognized")
-
- # Rewrite asciidoctor xrefs to resolve properly in refpages
- specURL = conventions.specURL(pi.spec)
-
- specText = xrefRewrite(specText, specURL)
- fieldText = xrefRewrite(fieldText, specURL)
- descText = xrefRewrite(descText, specURL)
-
- fp = open(pageName, 'w', encoding='utf-8')
- refPageHead(pi.name,
- pi.desc,
- specText,
- field, fieldText,
- descText,
- fp)
- refPageTail(pageName=pi.name,
- specType=pi.spec,
- specAnchor=pi.anchor,
- seeAlso=seeAlsoList(pi.name, pi.refs, pi.alias.split()),
- fp=fp,
- auto=False)
- fp.close()
-
-
-def autoGenEnumsPage(baseDir, pi, file):
- """Autogenerate a single reference page in baseDir.
-
- Script only knows how to do this for /enums/ pages, at present.
-
- - baseDir - base directory to emit page into
- - pi - pageInfo for this page relative to file
- - file - list of strings making up the file, indexed by pi"""
- pageName = baseDir + '/' + pi.name + '.txt'
- fp = open(pageName, 'w', encoding='utf-8')
-
- # Add a dictionary entry for this page
- global genDict
- genDict[pi.name] = None
- logDiag('autoGenEnumsPage:', pageName)
-
- # Short description
- if pi.desc is None:
- pi.desc = '(no short description available)'
-
- # Description text. Allow for the case where an enum definition
- # is not embedded.
- if not pi.embed:
- embedRef = ''
- else:
- embedRef = ''.join((
- ' * The reference page for ',
- macroPrefix(pi.embed),
- ', where this interface is defined.\n'))
-
- txt = ''.join((
- 'For more information, see:\n\n',
- embedRef,
- ' * The See Also section for other reference pages using this type.\n',
- ' * The ' + apiName + ' Specification.\n'))
-
- refPageHead(pi.name,
- pi.desc,
- ''.join(file[pi.begin:pi.include + 1]),
- None, None,
- txt,
- fp)
- refPageTail(pageName=pi.name,
- specType=pi.spec,
- specAnchor=pi.anchor,
- seeAlso=seeAlsoList(pi.name, pi.refs, pi.alias.split()),
- fp=fp,
- auto=True)
- fp.close()
-
-
-# Pattern to break apart an API *Flags{authorID} name, used in
-# autoGenFlagsPage.
-flagNamePat = re.compile(r'(?P<name>\w+)Flags(?P<author>[A-Z]*)')
-
-
-def autoGenFlagsPage(baseDir, flagName):
- """Autogenerate a single reference page in baseDir for an API *Flags type.
-
- - baseDir - base directory to emit page into
- - flagName - API *Flags name"""
- pageName = baseDir + '/' + flagName + '.txt'
- fp = open(pageName, 'w', encoding='utf-8')
-
- # Add a dictionary entry for this page
- global genDict
- genDict[flagName] = None
- logDiag('autoGenFlagsPage:', pageName)
-
- # Short description
- matches = flagNamePat.search(flagName)
- if matches is not None:
- name = matches.group('name')
- author = matches.group('author')
- logDiag('autoGenFlagsPage: split name into', name, 'Flags', author)
- flagBits = name + 'FlagBits' + author
- desc = 'Bitmask of ' + flagBits
- else:
- logWarn('autoGenFlagsPage:', pageName, 'does not end in "Flags{author ID}". Cannot infer FlagBits type.')
- flagBits = None
- desc = 'Unknown ' + apiName + ' flags type'
-
- # Description text
- if flagBits is not None:
- txt = ''.join((
- 'etext:' + flagName,
- ' is a mask of zero or more elink:' + flagBits + '.\n',
- 'It is used as a member and/or parameter of the structures and commands\n',
- 'in the See Also section below.\n'))
- else:
- txt = ''.join((
- 'etext:' + flagName,
- ' is an unknown ' + apiName + ' type, assumed to be a bitmask.\n'))
-
- refPageHead(flagName,
- desc,
- makeAPIInclude('flags', flagName),
- None, None,
- txt,
- fp)
- refPageTail(pageName=flagName,
- specType=pi.spec,
- specAnchor=pi.anchor,
- seeAlso=seeAlsoList(flagName, None),
- fp=fp,
- auto=True)
- fp.close()
-
-
-def autoGenHandlePage(baseDir, handleName):
- """Autogenerate a single handle page in baseDir for an API handle type.
-
- - baseDir - base directory to emit page into
- - handleName - API handle name"""
- # @@ Need to determine creation function & add handles/ include for the
- # @@ interface in generator.py.
- pageName = baseDir + '/' + handleName + '.txt'
- fp = open(pageName, 'w', encoding='utf-8')
-
- # Add a dictionary entry for this page
- global genDict
- genDict[handleName] = None
- logDiag('autoGenHandlePage:', pageName)
-
- # Short description
- desc = apiName + ' object handle'
-
- descText = ''.join((
- 'sname:' + handleName,
- ' is an object handle type, referring to an object used\n',
- 'by the ' + apiName + ' implementation. These handles are created or allocated\n',
- 'by the @@ TBD @@ function, and used by other ' + apiName + ' structures\n',
- 'and commands in the See Also section below.\n'))
-
- refPageHead(handleName,
- desc,
- makeAPIInclude('handles', handleName),
- None, None,
- descText,
- fp)
- refPageTail(pageName=handleName,
- specType=pi.spec,
- specAnchor=pi.anchor,
- seeAlso=seeAlsoList(handleName, None),
- fp=fp,
- auto=True)
- fp.close()
-
-
-def genRef(specFile, baseDir):
- """Extract reference pages from a spec asciidoc source file.
-
- - specFile - filename to extract from
- - baseDir - output directory to generate page in"""
- file = loadFile(specFile)
- if file is None:
- return
-
- # Save the path to this file for later use in rewriting relative includes
- specDir = os.path.dirname(os.path.abspath(specFile))
-
- pageMap = findRefs(file, specFile)
- logDiag(specFile + ': found', len(pageMap.keys()), 'potential pages')
-
- sys.stderr.flush()
-
- # Fix up references in pageMap
- fixupRefs(pageMap, specFile, file)
-
- # Create each page, if possible
- pages = {}
-
- for name in sorted(pageMap):
- pi = pageMap[name]
-
- # Only generate the page if it's in the requested build
- # 'freeform' pages are always generated
- # 'feature' pages (core versions & extensions) are generated if they're in
- # the requested feature list
- # All other pages (APIs) are generated if they're in the API map for
- # the build.
- if pi.type in refpage_api_types:
- if name not in api.typeCategory:
- # Also check aliases of name - api.nonexistent is the same
- # mapping used to rewrite *link: macros in this build.
- if name not in api.nonexistent:
- logWarn(f'genRef: NOT generating feature page {name} - API not in this build')
- continue
- else:
- logWarn(f'genRef: generating feature page {name} because its alias {api.nonexistent[name]} exists')
- elif pi.type in refpage_other_types:
- # The only non-API type which can be checked is a feature refpage
- if pi.type == 'feature':
- if name not in api.features:
- logWarn(f'genRef: NOT generating feature page {name} - feature not in this build')
- continue
-
- printPageInfo(pi, file)
-
- if pi.Warning:
- logDiag('genRef:', pi.name + ':', pi.Warning)
-
- if pi.extractPage:
- emitPage(baseDir, specDir, pi, file)
- elif pi.type == 'enums':
- autoGenEnumsPage(baseDir, pi, file)
- elif pi.type == 'flags':
- autoGenFlagsPage(baseDir, pi.name)
- else:
- # Don't extract this page
- logWarn('genRef: Cannot extract or autogenerate:', pi.name)
-
- pages[pi.name] = pi
- for alias in pi.alias.split():
- pages[alias] = pi
-
- return pages
-
-
-def genSinglePageRef(baseDir):
- """Generate baseDir/apispec.txt, the single-page version of the ref pages.
-
- This assumes there's a page for everything in the api module dictionaries.
- Extensions (KHR, EXT, etc.) are currently skipped"""
- # Accumulate head of page
- head = io.StringIO()
-
- printCopyrightSourceComments(head)
-
- print('= ' + apiName + ' API Reference Pages',
- ':data-uri:',
- ':icons: font',
- ':doctype: book',
- ':numbered!:',
- ':max-width: 200',
- ':data-uri:',
- ':toc2:',
- ':toclevels: 2',
- '',
- sep='\n', file=head)
-
- print('== Copyright', file=head)
- print('', file=head)
- print('include::{config}/copyright-ccby.txt[]', file=head)
- print('', file=head)
- # Inject the table of contents. Asciidoc really ought to be generating
- # this for us.
-
- sections = [
- [api.protos, 'protos', apiName + ' Commands'],
- [api.handles, 'handles', 'Object Handles'],
- [api.structs, 'structs', 'Structures'],
- [api.enums, 'enums', 'Enumerations'],
- [api.flags, 'flags', 'Flags'],
- [api.funcpointers, 'funcpointers', 'Function Pointer Types'],
- [api.basetypes, 'basetypes', apiName + ' Scalar types'],
- [api.defines, 'defines', 'C Macro Definitions'],
- [extensions, 'extensions', apiName + ' Extensions']
- ]
-
- # Accumulate body of page
- body = io.StringIO()
-
- for (apiDict, label, title) in sections:
- # Add section title/anchor header to body
- anchor = '[[' + label + ',' + title + ']]'
- print(anchor,
- '== ' + title,
- '',
- ':leveloffset: 2',
- '',
- sep='\n', file=body)
-
- if label == 'extensions':
- # preserve order of extensions since we already sorted the way we want.
- keys = apiDict.keys()
- else:
- keys = sorted(apiDict.keys())
-
- for refPage in keys:
- # Don't generate links for aliases, which are included with the
- # aliased page
- if refPage not in api.alias:
- # Add page to body
- if 'FlagBits' in refPage and conventions.unified_flag_refpages:
- # OpenXR does not create separate ref pages for FlagBits:
- # the FlagBits includes go in the Flags refpage.
- # Previously the Vulkan script would only emit non-empty
- # Vk*Flags pages, via the logic
- # if refPage not in api.flags or api.flags[refPage] is not None
- # emit page
- # Now, all are emitted.
- continue
- else:
- print('include::' + refPage + '.txt[]', file=body)
- else:
- # Alternatively, we could (probably should) link to the
- # aliased refpage
- logWarn('(Benign) Not including', refPage,
- 'in single-page reference',
- 'because it is an alias of', api.alias[refPage])
-
- print('\n' + ':leveloffset: 0' + '\n', file=body)
-
- # Write head and body to the output file
- pageName = baseDir + '/apispec.txt'
- fp = open(pageName, 'w', encoding='utf-8')
-
- print(head.getvalue(), file=fp, end='')
- print(body.getvalue(), file=fp, end='')
-
- head.close()
- body.close()
- fp.close()
-
-
-def genExtension(baseDir, extpath, name, info):
- """Generate refpage, and add dictionary entry for an extension
-
- - baseDir - output directory to generate page in
- - extpath - None, or path to per-extension specification sources if
- those are to be included in extension refpages
- - name - extension name
- - info - <extension> Element from XML"""
-
- # Add a dictionary entry for this page
- global genDict
- genDict[name] = None
- declares = []
- elem = info.elem
-
- # Type of extension (instance, device, etc.)
- ext_type = elem.get('type')
-
- # Autogenerate interfaces from <extension> entry
- for required in elem.find('require'):
- req_name = required.get('name')
- if not req_name:
- # This isn't what we're looking for
- continue
- if req_name.endswith('_SPEC_VERSION') or req_name.endswith('_EXTENSION_NAME'):
- # Don't link to spec version or extension name - those ref pages aren't created.
- continue
-
- if required.get('extends'):
- # These are either extensions of enumerated types, or const enum
- # values: neither of which get a ref page - although we could
- # include the enumerated types in the See Also list.
- continue
-
- if req_name not in genDict:
- logWarn('ERROR: {} (in extension {}) does not have a ref page.'.format(req_name, name))
-
- declares.append(req_name)
-
- # import pdb
- # pdb.set_trace()
-
- appbody = None
- if extpath is not None:
- appfp = open('{}/{}.txt'.format(extpath, name), 'r', encoding='utf-8')
- if appfp is not None:
- appbody = appfp.read()
-
- # Transform internal links to crosslinks
- specURL = conventions.specURL()
- appbody = xrefRewrite(appbody, specURL)
- else:
- logWarn('Cannot find extension appendix for', name)
-
- # Fall through to autogenerated page
- extpath = None
- appbody = None
- appfp.close()
-
- # Include the extension appendix without an extra title
- # head_content = 'include::{{appendices}}/{}.txt[]'.format(name)
-
- # Write the extension refpage
- pageName = baseDir + '/' + name + '.txt'
- logDiag('genExtension:', pageName)
- fp = open(pageName, 'w', encoding='utf-8')
-
- # There are no generated titled sections
- sections = None
-
- # 'See link:{html_spec_relative}#%s[ %s] in the main specification for complete information.' % (
- # name, name)
- refPageShell(name,
- "{} extension".format(ext_type),
- fp,
- appbody,
- sections=sections)
-
- # The generated metadata include moved the leveloffset attribute by -1
- # to account for the relative structuring of the spec extension appendix
- # section structure vs. the refpages.
- # This restores leveloffset for the boilerplate in refPageTail.
- refPageTail(pageName=name,
- specType=None,
- specAnchor=name,
- seeAlso=seeAlsoList(name, declares),
- fp=fp,
- auto=True,
- leveloffset=1)
- fp.close()
-
-
-if __name__ == '__main__':
- global genDict, extensions, conventions, apiName
- genDict = {}
- extensions = OrderedDict()
- conventions = APIConventions()
- apiName = conventions.api_name('api')
-
- parser = argparse.ArgumentParser()
-
- parser.add_argument('-diag', action='store', dest='diagFile',
- help='Set the diagnostic file')
- parser.add_argument('-warn', action='store', dest='warnFile',
- help='Set the warning file')
- parser.add_argument('-log', action='store', dest='logFile',
- help='Set the log file for both diagnostics and warnings')
- parser.add_argument('-genpath', action='store',
- default='gen',
- help='Path to directory containing generated files')
- parser.add_argument('-basedir', action='store', dest='baseDir',
- default=None,
- help='Set the base directory in which pages are generated')
- parser.add_argument('-noauto', action='store_true',
- help='Don\'t generate inferred ref pages automatically')
- parser.add_argument('files', metavar='filename', nargs='*',
- help='a filename to extract ref pages from')
- parser.add_argument('--version', action='version', version='%(prog)s 1.0')
- parser.add_argument('-extension', action='append',
- default=[],
- help='Specify an extension or extensions to add to targets')
- parser.add_argument('-rewrite', action='store',
- default=None,
- help='Name of output file to write Apache mod_rewrite directives to')
- parser.add_argument('-toc', action='store',
- default=None,
- help='Name of output file to write an alphabetical TOC to')
- parser.add_argument('-registry', action='store',
- default=conventions.registry_path,
- help='Use specified registry file instead of default')
- parser.add_argument('-extpath', action='store',
- default=None,
- help='Use extension descriptions from this directory instead of autogenerating extension refpages')
-
- results = parser.parse_args()
-
- # Look for api.py in the specified directory
- if results.genpath is not None:
- sys.path.insert(0, results.genpath)
- import api
-
- setLogFile(True, True, results.logFile)
- setLogFile(True, False, results.diagFile)
- setLogFile(False, True, results.warnFile)
-
- # Initialize static rewrite patterns for spec xrefs
- xrefRewriteInitialize()
-
- if results.baseDir is None:
- baseDir = results.genpath + '/ref'
- else:
- baseDir = results.baseDir
-
- # Dictionary of pages & aliases
- pages = {}
-
- for file in results.files:
- d = genRef(file, baseDir)
- pages.update(d)
-
- # Now figure out which pages *weren't* generated from the spec.
- # This relies on the dictionaries of API constructs in the api module.
-
- if not results.noauto:
- registry = Registry()
- registry.loadFile(results.registry)
-
- if conventions.write_refpage_include:
- # Only extensions with a supported="..." attribute in this set
- # will be considered for extraction/generation.
- supported_strings = set((conventions.xml_api_name,))
- ext_names = set(k for k, v in registry.extdict.items()
- if v.supported in supported_strings)
-
- desired_extensions = ext_names.intersection(set(results.extension))
- for prefix in conventions.extension_index_prefixes:
- # Splits up into chunks, sorted within each chunk.
- filtered_extensions = sorted(
- [name for name in desired_extensions
- if name.startswith(prefix) and name not in extensions])
- for name in filtered_extensions:
- # logWarn('NOT autogenerating extension refpage for', name)
- extensions[name] = None
- genExtension(baseDir, results.extpath, name, registry.extdict[name])
-
- # autoGenFlagsPage is no longer needed because they are added to
- # the spec sources now.
- # for page in api.flags:
- # if page not in genDict:
- # autoGenFlagsPage(baseDir, page)
-
- # autoGenHandlePage is no longer needed because they are added to
- # the spec sources now.
- # for page in api.structs:
- # if typeCategory[page] == 'handle':
- # autoGenHandlePage(baseDir, page)
-
- sections = [
- (api.flags, 'Flag Types'),
- (api.enums, 'Enumerated Types'),
- (api.structs, 'Structures'),
- (api.protos, 'Prototypes'),
- (api.funcpointers, 'Function Pointers'),
- (api.basetypes, apiName + ' Scalar Types'),
- (extensions, apiName + ' Extensions'),
- ]
-
- # Summarize pages that weren't generated, for good or bad reasons
-
- for (apiDict, title) in sections:
- # OpenXR was keeping a 'flagged' state which only printed out a
- # warning for the first non-generated page, but was otherwise
- # unused. This doesn't seem helpful.
- for page in apiDict:
- if page not in genDict:
- # Page was not generated - why not?
- if page in api.alias:
- logWarn('(Benign, is an alias) Ref page for', title, page, 'is aliased into', api.alias[page])
- elif page in api.flags and api.flags[page] is None:
- logWarn('(Benign, no FlagBits defined) No ref page generated for ', title,
- page)
- else:
- # Could introduce additional logic to detect
- # external types and not emit them.
- logWarn('No ref page generated for ', title, page)
-
- genSinglePageRef(baseDir)
-
- if results.rewrite:
- # Generate Apache rewrite directives for refpage aliases
- fp = open(results.rewrite, 'w', encoding='utf-8')
-
- for page in sorted(pages):
- p = pages[page]
- rewrite = p.name
-
- if page != rewrite:
- print('RewriteRule ^', page, '.html$ ', rewrite, '.html',
- sep='', file=fp)
- fp.close()
-
- if results.toc:
- # Generate dynamic portion of refpage TOC
- fp = open(results.toc, 'w', encoding='utf-8')
-
- # Run through dictionary of pages generating an TOC
- print(12 * ' ', '<li class="Level1">Alphabetic Contents', sep='', file=fp)
- print(16 * ' ', '<ul class="Level2">', sep='', file=fp)
- lastLetter = None
-
- for page in sorted(pages, key=str.upper):
- p = pages[page]
- letter = page[0:1].upper()
-
- if letter != lastLetter:
- if lastLetter:
- # End previous block
- print(24 * ' ', '</ul>', sep='', file=fp)
- print(20 * ' ', '</li>', sep='', file=fp)
- # Start new block
- print(20 * ' ', '<li>', letter, sep='', file=fp)
- print(24 * ' ', '<ul class="Level3">', sep='', file=fp)
- lastLetter = letter
-
- # Add this page to the list
- print(28 * ' ', '<li><a href="', p.name, '.html" ',
- 'target="pagedisplay">', page, '</a></li>',
- sep='', file=fp)
-
- if lastLetter:
- # Close the final letter block
- print(24 * ' ', '</ul>', sep='', file=fp)
- print(20 * ' ', '</li>', sep='', file=fp)
-
- # Close the list
- print(16 * ' ', '</ul>', sep='', file=fp)
- print(12 * ' ', '</li>', sep='', file=fp)
-
- # print('name {} -> page {}'.format(page, pages[page].name))
-
- fp.close()
diff --git a/codegen/vulkan/scripts/genRelease b/codegen/vulkan/scripts/genRelease
deleted file mode 100755
index f3c4a2ab..00000000
--- a/codegen/vulkan/scripts/genRelease
+++ /dev/null
@@ -1,211 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2016-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-import argparse
-import subprocess
-import sys
-
-from genspec import *
-
-# Eventually, these may be defined by extDependency.py
-allVersions = [ 'VK_VERSION_1_0', 'VK_VERSION_1_1', 'VK_VERSION_1_2' ]
-Version1_1 = [ 'VK_VERSION_1_0', 'VK_VERSION_1_1' ]
-Version1_0 = [ 'VK_VERSION_1_0' ]
-
-if __name__ == '__main__':
- parser = argparse.ArgumentParser()
-
- parser.add_argument('-internal', action='store_true',
- help='Generate internal build, not public')
- parser.add_argument('-norefpages', action='store_true',
- help='Do not generate refpages')
- parser.add_argument('-singlerefpage', action='store_true',
- help='Generate single-page refpage - NOT SUPPORTED')
- parser.add_argument('-chunked', action='store_true',
- help='Generate chunked HTML outputs')
- parser.add_argument('-pdf', action='store_true',
- help='Generate PDF outputs')
-
- parser.add_argument('-nov12', action='store_false', dest='v12',
- help='Suppress Vulkan 1.2 targets')
- parser.add_argument('-v11', action='store_true',
- help='Generate Vulkan 1.1 targets')
- parser.add_argument('-v10', action='store_true',
- help='Generate Vulkan 1.0 targets')
-
- parser.add_argument('-nocorespec', action='store_false', dest='corespec',
- help='Do not generate core API-only targets')
- parser.add_argument('-nokhrspec', action='store_false', dest='khrspec',
- help='Do not generate core API + KHR extensions-only targets')
- parser.add_argument('-noallspec', action='store_false', dest='allspec',
- help='Do not generate full API + all extensions targets')
-
- parser.add_argument('-genpath', action='store',
- default='gen',
- help='Path to directory containing generated files')
- parser.add_argument('-repodir', action='store', dest='repoDir',
- default=None,
- help='Set the repository directory to build from (overrides defaults)')
- parser.add_argument('-outdir', action='store', dest='outDir',
- default=None,
- help='Set the output directory to build into (overrides defaults)')
-
- args = parser.parse_args()
-
- # Ensure gen/extDependency.py is up-to-date before we import it.
- # If it is up to date, 'make' will print a useless warning without '-s'.
- subprocess.check_call(['make', '-s', 'GENERATED=' + args.genpath, 'extDependency'])
-
- # Alter sys.path to import extDependency.py
- sys.path.insert(0, args.genpath)
-
- from extDependency import allExts, khrExts
-
- if args.internal:
- # For internal build & pseudo-release
- if args.repoDir == None:
- args.repoDir = '/home/tree/git/vulkan'
- if args.outDir == None:
- args.outDir = '/home/tree/git/vulkan/out'
- else:
- # For public release
- if args.repoDir == None:
- args.repoDir = '/home/tree/git/Vulkan-Docs'
- if args.outDir == None:
- args.outDir = '/home/tree/git/registry/vulkan/specs'
-
- refPageTargets = ''
-
- if not args.norefpages:
- # Generate separate reference pages
- refPageTargets += ' manhtmlpages'
-
- if args.singlerefpage:
- # Generate single-page refpage.
- refPageTargets += ' manhtml'
- if args.pdf:
- refPageTargets += ' manpdf'
- print('echo Info: single-page refpage targets are NOT SUPPORTED')
-
- specTargets = ' html'
- if args.chunked:
- specTargets += ' chunked'
- if args.pdf:
- specTargets += ' pdf'
-
- print('echo Info: Building release from', args.repoDir, 'to', args.outDir)
- print('echo Info: Building spec targets', specTargets)
- print('')
-
- # Current Vulkan 1.2 specs
- if args.v12:
- if args.allspec:
- # Build ref pages and validusage targets only for 1.2 + all exts
- # Formerly set xmlTargets = 'clobber install', but we no longer
- # generate headers in the registry tree.
- buildBranch(targetDir = '1.2-extensions',
- versions = allVersions,
- extensions = allExts,
- ratified = False,
- apititle = '(with all registered Vulkan extensions)',
- specTargets = specTargets + ' validusage' + refPageTargets,
- repoDir = args.repoDir,
- outDir = args.outDir)
-
- if args.khrspec:
- buildBranch(targetDir = '1.2-khr-extensions',
- versions = allVersions,
- extensions = khrExts,
- ratified = True,
- apititle = '(with KHR extensions)',
- specTargets = specTargets,
- repoDir = args.repoDir,
- outDir = args.outDir)
-
- if args.corespec:
- # Build style guide and registry documentation targets only for 1.2
- # + no extensions.
- buildBranch(targetDir = '1.2',
- versions = allVersions,
- extensions = None,
- ratified = True,
- apititle = None,
- specTargets = specTargets + ' styleguide registry',
- repoDir = args.repoDir,
- outDir = args.outDir,
- needRefSources = True)
-
- # Vulkan 1.1 specs
- if args.v11:
- if args.allspec:
- buildBranch(targetDir = '1.1-extensions',
- versions = Version1_1,
- extensions = allExts,
- ratified = False,
- apititle = '(with all registered Vulkan extensions)',
- specTargets = specTargets,
- repoDir = args.repoDir,
- outDir = args.outDir)
-
- if args.khrspec:
- buildBranch(targetDir = '1.1-khr-extensions',
- versions = Version1_1,
- extensions = khrExts,
- ratified = True,
- apititle = '(with KHR extensions)',
- specTargets = specTargets,
- repoDir = args.repoDir,
- outDir = args.outDir)
-
- if args.corespec:
- buildBranch(targetDir = '1.1',
- versions = Version1_1,
- extensions = None,
- ratified = True,
- apititle = None,
- specTargets = specTargets,
- repoDir = args.repoDir,
- outDir = args.outDir)
- else:
- print('echo Info: Not building 1.1 specs yet')
-
-
- # Vulkan 1.0 specs.
- if args.v10:
- if args.allspec:
- buildBranch(targetDir = '1.0-extensions',
- versions = Version1_0,
- extensions = allExts,
- ratified = False,
- apititle = '(with all registered Vulkan extensions)',
- specTargets = specTargets,
- repoDir = args.repoDir,
- outDir = args.outDir)
-
- if args.khrspec:
- buildBranch(targetDir = '1.0-wsi_extensions',
- versions = Version1_0,
- extensions = khrExts,
- ratified = True,
- apititle = '(with KHR extensions)',
- specTargets = specTargets,
- repoDir = args.repoDir,
- outDir = args.outDir)
-
- if args.corespec:
- buildBranch(targetDir = '1.0',
- versions = Version1_0,
- extensions = None,
- ratified = True,
- apititle = None,
- specTargets = specTargets,
- repoDir = args.repoDir,
- outDir = args.outDir)
- else:
- print('echo Info: Not building 1.0 specs yet')
-
- print('echo Info: post-generation cleanup')
- createTags(releaseNum(), buildOnFriday())
diff --git a/codegen/vulkan/scripts/genanchorlinks.py b/codegen/vulkan/scripts/genanchorlinks.py
deleted file mode 100644
index c589bb30..00000000
--- a/codegen/vulkan/scripts/genanchorlinks.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2020-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# Script that adds href to <a> anchors
-
-import os,sys,re
-
-def genAnchorLinks(in_file, out_file):
- try:
- with open(in_file, 'r', encoding='utf8') as f: data = f.read()
- except FileNotFoundError:
- print('Error: File %s does not exist.' % in_file)
- sys.exit(2)
-
- data = re.sub( r'(<a )(id="(VUID\-[\w\-:]+)")(>)', '\g<1>\g<2> href="#\g<3>"\g<4>', data)
- with open(out_file, 'w', encoding='utf8') as f: data = f.write(data)
-
-if __name__ == '__main__':
- if len(sys.argv) != 3:
- print('Error: genanchorlinks.py requires two arguments.')
- print('Usage: genanchorlinks.py infile.html outfile.html')
- sys.exit(1)
- genAnchorLinks(sys.argv[1], sys.argv[2])
diff --git a/codegen/vulkan/scripts/generator.py b/codegen/vulkan/scripts/generator.py
deleted file mode 100644
index cb5f0f59..00000000
--- a/codegen/vulkan/scripts/generator.py
+++ /dev/null
@@ -1,1204 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-"""Base class for source/header/doc generators, as well as some utility functions."""
-
-from __future__ import unicode_literals
-
-import io
-import os
-import pdb
-import re
-import shutil
-import sys
-import tempfile
-try:
- from pathlib import Path
-except ImportError:
- from pathlib2 import Path
-
-from spec_tools.util import getElemName, getElemType
-
-
-def write(*args, **kwargs):
- file = kwargs.pop('file', sys.stdout)
- end = kwargs.pop('end', '\n')
- file.write(' '.join(str(arg) for arg in args))
- file.write(end)
-
-
-def noneStr(s):
- """Return string argument, or "" if argument is None.
-
- Used in converting etree Elements into text.
- s - string to convert"""
- if s:
- return s
- return ""
-
-
-def enquote(s):
- """Return string argument with surrounding quotes,
- for serialization into Python code."""
- if s:
- if isinstance(s, str):
- return "'{}'".format(s)
- else:
- return s
- return None
-
-
-def regSortCategoryKey(feature):
- """Sort key for regSortFeatures.
- Sorts by category of the feature name string:
-
- - Core API features (those defined with a `<feature>` tag)
- - ARB/KHR/OES (Khronos extensions)
- - other (EXT/vendor extensions)"""
-
- if feature.elem.tag == 'feature':
- return 0
- if (feature.category == 'ARB'
- or feature.category == 'KHR'
- or feature.category == 'OES'):
- return 1
-
- return 2
-
-
-def regSortOrderKey(feature):
- """Sort key for regSortFeatures - key is the sortorder attribute."""
-
- # print("regSortOrderKey {} -> {}".format(feature.name, feature.sortorder))
- return feature.sortorder
-
-
-def regSortFeatureVersionKey(feature):
- """Sort key for regSortFeatures - key is the feature version.
- `<extension>` elements all have version number 0."""
-
- return float(feature.versionNumber)
-
-
-def regSortExtensionNumberKey(feature):
- """Sort key for regSortFeatures - key is the extension number.
- `<feature>` elements all have extension number 0."""
-
- return int(feature.number)
-
-
-def regSortFeatures(featureList):
- """Default sort procedure for features.
-
- - Sorts by explicit sort order (default 0) relative to other features
- - then by feature category ('feature' or 'extension'),
- - then by version number (for features)
- - then by extension number (for extensions)"""
- featureList.sort(key=regSortExtensionNumberKey)
- featureList.sort(key=regSortFeatureVersionKey)
- featureList.sort(key=regSortCategoryKey)
- featureList.sort(key=regSortOrderKey)
-
-
-class GeneratorOptions:
- """Base class for options used during header/documentation production.
-
- These options are target language independent, and used by
- Registry.apiGen() and by base OutputGenerator objects."""
-
- def __init__(self,
- conventions=None,
- filename=None,
- directory='.',
- genpath=None,
- apiname=None,
- profile=None,
- versions='.*',
- emitversions='.*',
- defaultExtensions=None,
- addExtensions=None,
- removeExtensions=None,
- emitExtensions=None,
- emitSpirv=None,
- reparentEnums=True,
- sortProcedure=regSortFeatures,
- requireCommandAliases=False,
- ):
- """Constructor.
-
- Arguments:
-
- - conventions - may be mandatory for some generators:
- an object that implements ConventionsBase
- - filename - basename of file to generate, or None to write to stdout.
- - directory - directory in which to generate files
- - genpath - path to previously generated files, such as api.py
- - apiname - string matching `<api>` 'apiname' attribute, e.g. 'gl'.
- - profile - string specifying API profile , e.g. 'core', or None.
- - versions - regex matching API versions to process interfaces for.
- Normally `'.*'` or `'[0-9][.][0-9]'` to match all defined versions.
- - emitversions - regex matching API versions to actually emit
- interfaces for (though all requested versions are considered
- when deciding which interfaces to generate). For GL 4.3 glext.h,
- this might be `'1[.][2-5]|[2-4][.][0-9]'`.
- - defaultExtensions - If not None, a string which must in its
- entirety match the pattern in the "supported" attribute of
- the `<extension>`. Defaults to None. Usually the same as apiname.
- - addExtensions - regex matching names of additional extensions
- to include. Defaults to None.
- - removeExtensions - regex matching names of extensions to
- remove (after defaultExtensions and addExtensions). Defaults
- to None.
- - emitExtensions - regex matching names of extensions to actually emit
- interfaces for (though all requested versions are considered when
- deciding which interfaces to generate).
- to None.
- - emitSpirv - regex matching names of extensions and capabilities
- to actually emit interfaces for.
- - reparentEnums - move <enum> elements which extend an enumerated
- type from <feature> or <extension> elements to the target <enums>
- element. This is required for almost all purposes, but the
- InterfaceGenerator relies on the list of interfaces in the <feature>
- or <extension> being complete. Defaults to True.
- - sortProcedure - takes a list of FeatureInfo objects and sorts
- them in place to a preferred order in the generated output.
- Default is core API versions, ARB/KHR/OES extensions, all other
- extensions, by core API version number or extension number in each
- group.
-
- The regex patterns can be None or empty, in which case they match
- nothing."""
- self.conventions = conventions
- """may be mandatory for some generators:
- an object that implements ConventionsBase"""
-
- self.filename = filename
- "basename of file to generate, or None to write to stdout."
-
- self.genpath = genpath
- """path to previously generated files, such as api.py"""
-
- self.directory = directory
- "directory in which to generate filename"
-
- self.apiname = apiname
- "string matching `<api>` 'apiname' attribute, e.g. 'gl'."
-
- self.profile = profile
- "string specifying API profile , e.g. 'core', or None."
-
- self.versions = self.emptyRegex(versions)
- """regex matching API versions to process interfaces for.
- Normally `'.*'` or `'[0-9][.][0-9]'` to match all defined versions."""
-
- self.emitversions = self.emptyRegex(emitversions)
- """regex matching API versions to actually emit
- interfaces for (though all requested versions are considered
- when deciding which interfaces to generate). For GL 4.3 glext.h,
- this might be `'1[.][2-5]|[2-4][.][0-9]'`."""
-
- self.defaultExtensions = defaultExtensions
- """If not None, a string which must in its
- entirety match the pattern in the "supported" attribute of
- the `<extension>`. Defaults to None. Usually the same as apiname."""
-
- self.addExtensions = self.emptyRegex(addExtensions)
- """regex matching names of additional extensions
- to include. Defaults to None."""
-
- self.removeExtensions = self.emptyRegex(removeExtensions)
- """regex matching names of extensions to
- remove (after defaultExtensions and addExtensions). Defaults
- to None."""
-
- self.emitExtensions = self.emptyRegex(emitExtensions)
- """regex matching names of extensions to actually emit
- interfaces for (though all requested versions are considered when
- deciding which interfaces to generate)."""
-
- self.emitSpirv = self.emptyRegex(emitSpirv)
- """regex matching names of extensions and capabilities
- to actually emit interfaces for."""
-
- self.reparentEnums = reparentEnums
- """boolean specifying whether to remove <enum> elements from
- <feature> or <extension> when extending an <enums> type."""
-
- self.sortProcedure = sortProcedure
- """takes a list of FeatureInfo objects and sorts
- them in place to a preferred order in the generated output.
- Default is core API versions, ARB/KHR/OES extensions, all
- other extensions, alphabetically within each group."""
-
- self.codeGenerator = False
- """True if this generator makes compilable code"""
-
- self.requireCommandAliases = requireCommandAliases
- """True if alias= attributes of <command> tags are transitively
- required."""
-
- def emptyRegex(self, pat):
- """Substitute a regular expression which matches no version
- or extension names for None or the empty string."""
- if not pat:
- return '_nomatch_^'
-
- return pat
-
-
-class OutputGenerator:
- """Generate specified API interfaces in a specific style, such as a C header.
-
- Base class for generating API interfaces.
- Manages basic logic, logging, and output file control.
- Derived classes actually generate formatted output.
- """
-
- # categoryToPath - map XML 'category' to include file directory name
- categoryToPath = {
- 'bitmask': 'flags',
- 'enum': 'enums',
- 'funcpointer': 'funcpointers',
- 'handle': 'handles',
- 'define': 'defines',
- 'basetype': 'basetypes',
- }
-
- def breakName(self, name, msg):
- """Break into debugger if this is a special name"""
-
- # List of string names to break on
- bad = (
- )
-
- if name in bad and True:
- print('breakName {}: {}'.format(name, msg))
- pdb.set_trace()
-
- def __init__(self, errFile=sys.stderr, warnFile=sys.stderr, diagFile=sys.stdout):
- """Constructor
-
- - errFile, warnFile, diagFile - file handles to write errors,
- warnings, diagnostics to. May be None to not write."""
- self.outFile = None
- self.errFile = errFile
- self.warnFile = warnFile
- self.diagFile = diagFile
- # Internal state
- self.featureName = None
- self.featureType = None
- self.genOpts = None
- self.registry = None
- self.featureDictionary = {}
- # Used for extension enum value generation
- self.extBase = 1000000000
- self.extBlockSize = 1000
- self.madeDirs = {}
-
- # API dictionary, which may be loaded by the beginFile method of
- # derived generators.
- self.apidict = None
-
- def logMsg(self, level, *args):
- """Write a message of different categories to different
- destinations.
-
- - `level`
- - 'diag' (diagnostic, voluminous)
- - 'warn' (warning)
- - 'error' (fatal error - raises exception after logging)
-
- - `*args` - print()-style arguments to direct to corresponding log"""
- if level == 'error':
- strfile = io.StringIO()
- write('ERROR:', *args, file=strfile)
- if self.errFile is not None:
- write(strfile.getvalue(), file=self.errFile)
- raise UserWarning(strfile.getvalue())
- elif level == 'warn':
- if self.warnFile is not None:
- write('WARNING:', *args, file=self.warnFile)
- elif level == 'diag':
- if self.diagFile is not None:
- write('DIAG:', *args, file=self.diagFile)
- else:
- raise UserWarning(
- '*** FATAL ERROR in Generator.logMsg: unknown level:' + level)
-
- def enumToValue(self, elem, needsNum, bitwidth = 32, forceSuffix = False):
- """Parse and convert an `<enum>` tag into a value.
-
- Returns a list:
-
- - first element - integer representation of the value, or None
- if needsNum is False. The value must be a legal number
- if needsNum is True.
- - second element - string representation of the value
-
- There are several possible representations of values.
-
- - A 'value' attribute simply contains the value.
- - A 'bitpos' attribute defines a value by specifying the bit
- position which is set in that value.
- - An 'offset','extbase','extends' triplet specifies a value
- as an offset to a base value defined by the specified
- 'extbase' extension name, which is then cast to the
- typename specified by 'extends'. This requires probing
- the registry database, and imbeds knowledge of the
- API extension enum scheme in this function.
- - An 'alias' attribute contains the name of another enum
- which this is an alias of. The other enum must be
- declared first when emitting this enum."""
- name = elem.get('name')
- numVal = None
- if 'value' in elem.keys():
- value = elem.get('value')
- # print('About to translate value =', value, 'type =', type(value))
- if needsNum:
- numVal = int(value, 0)
- # If there's a non-integer, numeric 'type' attribute (e.g. 'u' or
- # 'ull'), append it to the string value.
- # t = enuminfo.elem.get('type')
- # if t is not None and t != '' and t != 'i' and t != 's':
- # value += enuminfo.type
- if forceSuffix:
- if bitwidth == 64:
- value = value + 'ULL'
- else:
- value = value + 'U'
- self.logMsg('diag', 'Enum', name, '-> value [', numVal, ',', value, ']')
- return [numVal, value]
- if 'bitpos' in elem.keys():
- value = elem.get('bitpos')
- bitpos = int(value, 0)
- numVal = 1 << bitpos
- value = '0x%08x' % numVal
- if bitwidth == 64:
- value = value + 'ULL'
- elif forceSuffix:
- value = value + 'U'
- self.logMsg('diag', 'Enum', name, '-> bitpos [', numVal, ',', value, ']')
- return [numVal, value]
- if 'offset' in elem.keys():
- # Obtain values in the mapping from the attributes
- enumNegative = False
- offset = int(elem.get('offset'), 0)
- extnumber = int(elem.get('extnumber'), 0)
- extends = elem.get('extends')
- if 'dir' in elem.keys():
- enumNegative = True
- self.logMsg('diag', 'Enum', name, 'offset =', offset,
- 'extnumber =', extnumber, 'extends =', extends,
- 'enumNegative =', enumNegative)
- # Now determine the actual enumerant value, as defined
- # in the "Layers and Extensions" appendix of the spec.
- numVal = self.extBase + (extnumber - 1) * self.extBlockSize + offset
- if enumNegative:
- numVal *= -1
- value = '%d' % numVal
- # More logic needed!
- self.logMsg('diag', 'Enum', name, '-> offset [', numVal, ',', value, ']')
- return [numVal, value]
- if 'alias' in elem.keys():
- return [None, elem.get('alias')]
- return [None, None]
-
- def checkDuplicateEnums(self, enums):
- """Check enumerated values for duplicates.
-
- - enums - list of `<enum>` Elements
-
- returns the list with duplicates stripped"""
- # Dictionaries indexed by name and numeric value.
- # Entries are [ Element, numVal, strVal ] matching name or value
-
- nameMap = {}
- valueMap = {}
-
- stripped = []
- for elem in enums:
- name = elem.get('name')
- (numVal, strVal) = self.enumToValue(elem, True)
-
- if name in nameMap:
- # Duplicate name found; check values
- (name2, numVal2, strVal2) = nameMap[name]
-
- # Duplicate enum values for the same name are benign. This
- # happens when defining the same enum conditionally in
- # several extension blocks.
- if (strVal2 == strVal or (numVal is not None
- and numVal == numVal2)):
- True
- # self.logMsg('info', 'checkDuplicateEnums: Duplicate enum (' + name +
- # ') found with the same value:' + strVal)
- else:
- self.logMsg('warn', 'checkDuplicateEnums: Duplicate enum (' + name
- + ') found with different values:' + strVal
- + ' and ' + strVal2)
-
- # Don't add the duplicate to the returned list
- continue
- elif numVal in valueMap:
- # Duplicate value found (such as an alias); report it, but
- # still add this enum to the list.
- (name2, numVal2, strVal2) = valueMap[numVal]
-
- msg = 'Two enums found with the same value: {} = {} = {}'.format(
- name, name2.get('name'), strVal)
- self.logMsg('error', msg)
-
- # Track this enum to detect followon duplicates
- nameMap[name] = [elem, numVal, strVal]
- if numVal is not None:
- valueMap[numVal] = [elem, numVal, strVal]
-
- # Add this enum to the list
- stripped.append(elem)
-
- # Return the list
- return stripped
-
- def misracstyle(self):
- return False;
-
- def misracppstyle(self):
- return False;
-
- def buildEnumCDecl(self, expand, groupinfo, groupName):
- """Generate the C declaration for an enum"""
- groupElem = groupinfo.elem
-
- # Determine the required bit width for the enum group.
- # 32 is the default, which generates C enum types for the values.
- bitwidth = 32
-
- # If the constFlagBits preference is set, 64 is the default for bitmasks
- if self.genOpts.conventions.constFlagBits and groupElem.get('type') == 'bitmask':
- bitwidth = 64
-
- # Check for an explicitly defined bitwidth, which will override any defaults.
- if groupElem.get('bitwidth'):
- try:
- bitwidth = int(groupElem.get('bitwidth'))
- except ValueError as ve:
- self.logMsg('error', 'Invalid value for bitwidth attribute (', groupElem.get('bitwidth'), ') for ', groupName, ' - must be an integer value\n')
- exit(1)
-
- usebitmask = False
- usedefine = False
-
- # Bitmask flags can be generated as either "static const uint{32,64}_t" values,
- # or as 32-bit C enums. 64-bit types must use uint64_t values.
- if groupElem.get('type') == 'bitmask':
- if bitwidth > 32 or self.misracppstyle():
- usebitmask = True
- if self.misracstyle():
- usedefine = True
-
- if usedefine or usebitmask:
- # Validate the bitwidth and generate values appropriately
- if bitwidth > 64:
- self.logMsg('error', 'Invalid value for bitwidth attribute (', groupElem.get('bitwidth'), ') for bitmask type ', groupName, ' - must be less than or equal to 64\n')
- exit(1)
- else:
- return self.buildEnumCDecl_BitmaskOrDefine(groupinfo, groupName, bitwidth, usedefine)
- else:
- # Validate the bitwidth and generate values appropriately
- if bitwidth > 32:
- self.logMsg('error', 'Invalid value for bitwidth attribute (', groupElem.get('bitwidth'), ') for enum type ', groupName, ' - must be less than or equal to 32\n')
- exit(1)
- else:
- return self.buildEnumCDecl_Enum(expand, groupinfo, groupName)
-
- def buildEnumCDecl_BitmaskOrDefine(self, groupinfo, groupName, bitwidth, usedefine):
- """Generate the C declaration for an "enum" that is actually a
- set of flag bits"""
- groupElem = groupinfo.elem
- flagTypeName = groupElem.get('name')
-
- # Prefix
- body = "// Flag bits for " + flagTypeName + "\n"
-
- if bitwidth == 64:
- body += "typedef VkFlags64 %s;\n" % flagTypeName;
- else:
- body += "typedef VkFlags %s;\n" % flagTypeName;
-
- # Maximum allowable value for a flag (unsigned 64-bit integer)
- maxValidValue = 2**(64) - 1
- minValidValue = 0
-
- # Get a list of nested 'enum' tags.
- enums = groupElem.findall('enum')
-
- # Check for and report duplicates, and return a list with them
- # removed.
- enums = self.checkDuplicateEnums(enums)
-
- # Accumulate non-numeric enumerant values separately and append
- # them following the numeric values, to allow for aliases.
- # NOTE: this doesn't do a topological sort yet, so aliases of
- # aliases can still get in the wrong order.
- aliasText = ''
-
- # Loop over the nested 'enum' tags.
- for elem in enums:
- # Convert the value to an integer and use that to track min/max.
- # Values of form -(number) are accepted but nothing more complex.
- # Should catch exceptions here for more complex constructs. Not yet.
- (numVal, strVal) = self.enumToValue(elem, True, bitwidth, True)
- name = elem.get('name')
-
- # Range check for the enum value
- if numVal is not None and (numVal > maxValidValue or numVal < minValidValue):
- self.logMsg('error', 'Allowable range for flag types in C is [', minValidValue, ',', maxValidValue, '], but', name, 'flag has a value outside of this (', strVal, ')\n')
- exit(1)
-
- decl = self.genRequirements(name, mustBeFound = False)
-
- if self.isEnumRequired(elem):
- protect = elem.get('protect')
- if protect is not None:
- body += '#ifdef {}\n'.format(protect)
-
- if usedefine:
- decl += "#define {} {}\n".format(name, strVal)
- elif self.misracppstyle():
- decl += "static constexpr {} {} {{{}}};\n".format(flagTypeName, name, strVal)
- else:
- # Some C compilers only allow initializing a 'static const' variable with a literal value.
- # So initializing an alias from another 'static const' value would fail to compile.
- # Work around this by chasing the aliases to get the actual value.
- while numVal is None:
- alias = self.registry.tree.find("enums/enum[@name='" + strVal + "']")
- (numVal, strVal) = self.enumToValue(alias, True, bitwidth, True)
- decl += "static const {} {} = {};\n".format(flagTypeName, name, strVal)
-
- if numVal is not None:
- body += decl
- else:
- aliasText += decl
-
- if protect is not None:
- body += '#endif\n'
-
- # Now append the non-numeric enumerant values
- body += aliasText
-
- # Postfix
-
- return ("bitmask", body)
-
- def buildEnumCDecl_Enum(self, expand, groupinfo, groupName):
- """Generate the C declaration for an enumerated type"""
- groupElem = groupinfo.elem
-
- # Break the group name into prefix and suffix portions for range
- # enum generation
- expandName = re.sub(r'([0-9]+|[a-z_])([A-Z0-9])', r'\1_\2', groupName).upper()
- expandPrefix = expandName
- expandSuffix = ''
- expandSuffixMatch = re.search(r'[A-Z][A-Z]+$', groupName)
- if expandSuffixMatch:
- expandSuffix = '_' + expandSuffixMatch.group()
- # Strip off the suffix from the prefix
- expandPrefix = expandName.rsplit(expandSuffix, 1)[0]
-
- # Prefix
- body = ["typedef enum %s {" % groupName]
-
- # @@ Should use the type="bitmask" attribute instead
- isEnum = ('FLAG_BITS' not in expandPrefix)
-
- # Allowable range for a C enum - which is that of a signed 32-bit integer
- maxValidValue = 2**(32 - 1) - 1
- minValidValue = (maxValidValue * -1) - 1
-
-
- # Get a list of nested 'enum' tags.
- enums = groupElem.findall('enum')
-
- # Check for and report duplicates, and return a list with them
- # removed.
- enums = self.checkDuplicateEnums(enums)
-
- # Loop over the nested 'enum' tags. Keep track of the minimum and
- # maximum numeric values, if they can be determined; but only for
- # core API enumerants, not extension enumerants. This is inferred
- # by looking for 'extends' attributes.
- minName = None
-
- # Accumulate non-numeric enumerant values separately and append
- # them following the numeric values, to allow for aliases.
- # NOTE: this doesn't do a topological sort yet, so aliases of
- # aliases can still get in the wrong order.
- aliasText = []
-
- for elem in enums:
- # Convert the value to an integer and use that to track min/max.
- # Values of form -(number) are accepted but nothing more complex.
- # Should catch exceptions here for more complex constructs. Not yet.
- (numVal, strVal) = self.enumToValue(elem, True)
- name = elem.get('name')
-
- # Extension enumerants are only included if they are required
- if self.isEnumRequired(elem):
- decl = ''
-
- protect = elem.get('protect')
- if protect is not None:
- decl += '#ifdef {}\n'.format(protect)
-
- # Indent requirements comment, if there is one
- requirements = self.genRequirements(name, mustBeFound = False)
- if requirements != '':
- requirements = ' ' + requirements
- decl += requirements
- decl += ' {} = {},'.format(name, strVal)
-
- if protect is not None:
- decl += '\n#endif'
-
- if numVal is not None:
- body.append(decl)
- else:
- aliasText.append(decl)
-
- # Range check for the enum value
- if numVal is not None and (numVal > maxValidValue or numVal < minValidValue):
- self.logMsg('error', 'Allowable range for C enum types is [', minValidValue, ',', maxValidValue, '], but', name, 'has a value outside of this (', strVal, ')\n')
- exit(1)
-
- # Don't track min/max for non-numbers (numVal is None)
- if isEnum and numVal is not None and elem.get('extends') is None:
- if minName is None:
- minName = maxName = name
- minValue = maxValue = numVal
- elif numVal < minValue:
- minName = name
- minValue = numVal
- elif numVal > maxValue:
- maxName = name
- maxValue = numVal
-
- # Now append the non-numeric enumerant values
- body.extend(aliasText)
-
- # Generate min/max value tokens - legacy use case.
- if isEnum and expand:
- body.extend((" {}_BEGIN_RANGE{} = {},".format(expandPrefix, expandSuffix, minName),
- " {}_END_RANGE{} = {},".format(
- expandPrefix, expandSuffix, maxName),
- " {}_RANGE_SIZE{} = ({} - {} + 1),".format(expandPrefix, expandSuffix, maxName, minName)))
-
- # Generate a range-padding value to ensure the enum is 32 bits, but
- # only in code generators, so it doesn't appear in documentation
- if (self.genOpts.codeGenerator or
- self.conventions.generate_max_enum_in_docs):
- body.append(" {}_MAX_ENUM{} = 0x7FFFFFFF".format(
- expandPrefix, expandSuffix))
-
- # Postfix
- body.append("} %s;" % groupName)
-
- # Determine appropriate section for this declaration
- if groupElem.get('type') == 'bitmask':
- section = 'bitmask'
- else:
- section = 'group'
-
- return (section, '\n'.join(body))
-
- def buildConstantCDecl(self, enuminfo, name, alias):
- """Generate the C declaration for a constant (a single <enum>
- value).
-
- <enum> tags may specify their values in several ways, but are
- usually just integers or floating-point numbers."""
-
- (_, strVal) = self.enumToValue(enuminfo.elem, False)
-
- if self.misracppstyle() and enuminfo.elem.get('type') and not alias:
- # Generate e.g.: static constexpr uint32_t x = ~static_cast<uint32_t>(1U);
- # This appeases MISRA "underlying type" rules.
- typeStr = enuminfo.elem.get('type');
- invert = '~' in strVal
- number = strVal.strip("()~UL")
- if typeStr != "float":
- number += 'U'
- strVal = "~" if invert else ""
- strVal += "static_cast<" + typeStr + ">(" + number + ")"
- body = 'static constexpr ' + typeStr.ljust(9) + name.ljust(33) + ' {' + strVal + '};'
- elif enuminfo.elem.get('type') and not alias:
- # Generate e.g.: #define x (~0ULL)
- typeStr = enuminfo.elem.get('type');
- invert = '~' in strVal
- paren = '(' in strVal
- number = strVal.strip("()~UL")
- if typeStr != "float":
- if typeStr == "uint64_t":
- number += 'ULL'
- else:
- number += 'U'
- strVal = "~" if invert else ""
- strVal += number
- if paren:
- strVal = "(" + strVal + ")";
- body = '#define ' + name.ljust(33) + ' ' + strVal;
- else:
- body = '#define ' + name.ljust(33) + ' ' + strVal
-
- return body
-
- def makeDir(self, path):
- """Create a directory, if not already done.
-
- Generally called from derived generators creating hierarchies."""
- self.logMsg('diag', 'OutputGenerator::makeDir(' + path + ')')
- if path not in self.madeDirs:
- # This can get race conditions with multiple writers, see
- # https://stackoverflow.com/questions/273192/
- if not os.path.exists(path):
- os.makedirs(path)
- self.madeDirs[path] = None
-
- def beginFile(self, genOpts, suppress = False):
- """Start a new interface file
-
- - genOpts - GeneratorOptions controlling what's generated and how"""
- self.suppress = suppress
- self.genOpts = genOpts
- self.should_insert_may_alias_macro = \
- self.genOpts.conventions.should_insert_may_alias_macro(self.genOpts)
-
- # Try to import the API dictionary, api.py, if it exists. Nothing in
- # api.py cannot be extracted directly from the XML, and in the
- # future we should do that.
- if self.genOpts.genpath is not None:
- try:
- sys.path.insert(0, self.genOpts.genpath)
- import api
- self.apidict = api
- except ImportError:
- self.apidict = None
-
- self.conventions = genOpts.conventions
-
- # Open a temporary file for accumulating output.
- if self.genOpts.filename is not None and not self.suppress:
- self.outFile = tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', newline='\n', delete=False)
- else:
- self.outFile = sys.stdout
-
- def endFile(self):
- if self.errFile:
- self.errFile.flush()
- if self.warnFile:
- self.warnFile.flush()
- if self.diagFile:
- self.diagFile.flush()
- if self.outFile != sys.stdout and self.outFile != sys.stderr:
- self.outFile.close()
-
- # On successfully generating output, move the temporary file to the
- # target file.
- if self.genOpts.filename is not None:
- if sys.platform == 'win32':
- directory = Path(self.genOpts.directory)
- if not Path.exists(directory):
- os.makedirs(directory)
- shutil.copy(self.outFile.name, self.genOpts.directory + '/' + self.genOpts.filename)
- os.remove(self.outFile.name)
- self.genOpts = None
-
- def beginFeature(self, interface, emit):
- """Write interface for a feature and tag generated features as having been done.
-
- - interface - element for the `<version>` / `<extension>` to generate
- - emit - actually write to the header only when True"""
- self.emit = emit
- self.featureName = interface.get('name')
- self.featureType = interface.get('type')
- # If there's an additional 'protect' attribute in the feature, save it
- self.featureExtraProtect = interface.get('protect')
-
- def endFeature(self):
- """Finish an interface file, closing it when done.
-
- Derived classes responsible for emitting feature"""
- self.featureName = None
- self.featureType = None
- self.featureExtraProtect = None
-
- def genRequirements(self, name, mustBeFound = True):
- """Generate text showing what core versions and extensions introduce
- an API. This exists in the base Generator class because it's used by
- the shared enumerant-generating interfaces (buildEnumCDecl, etc.).
- Here it returns an empty string for most generators, but can be
- overridden by e.g. DocGenerator.
-
- - name - name of the API
- - mustBeFound - If True, when requirements for 'name' cannot be
- determined, a warning comment is generated.
- """
-
- return ''
-
- def validateFeature(self, featureType, featureName):
- """Validate we're generating something only inside a `<feature>` tag"""
- if self.featureName is None:
- raise UserWarning('Attempt to generate', featureType,
- featureName, 'when not in feature')
-
- def genType(self, typeinfo, name, alias):
- """Generate interface for a type
-
- - typeinfo - TypeInfo for a type
-
- Extend to generate as desired in your derived class."""
- self.validateFeature('type', name)
-
- def genStruct(self, typeinfo, typeName, alias):
- """Generate interface for a C "struct" type.
-
- - typeinfo - TypeInfo for a type interpreted as a struct
-
- Extend to generate as desired in your derived class."""
- self.validateFeature('struct', typeName)
-
- # The mixed-mode <member> tags may contain no-op <comment> tags.
- # It is convenient to remove them here where all output generators
- # will benefit.
- for member in typeinfo.elem.findall('.//member'):
- for comment in member.findall('comment'):
- member.remove(comment)
-
- def genGroup(self, groupinfo, groupName, alias):
- """Generate interface for a group of enums (C "enum")
-
- - groupinfo - GroupInfo for a group.
-
- Extend to generate as desired in your derived class."""
-
- self.validateFeature('group', groupName)
-
- def genEnum(self, enuminfo, typeName, alias):
- """Generate interface for an enum (constant).
-
- - enuminfo - EnumInfo for an enum
- - name - enum name
-
- Extend to generate as desired in your derived class."""
- self.validateFeature('enum', typeName)
-
- def genCmd(self, cmd, cmdinfo, alias):
- """Generate interface for a command.
-
- - cmdinfo - CmdInfo for a command
-
- Extend to generate as desired in your derived class."""
- self.validateFeature('command', cmdinfo)
-
- def genSpirv(self, spirv, spirvinfo, alias):
- """Generate interface for a spirv element.
-
- - spirvinfo - SpirvInfo for a command
-
- Extend to generate as desired in your derived class."""
- return
-
- def makeProtoName(self, name, tail):
- """Turn a `<proto>` `<name>` into C-language prototype
- and typedef declarations for that name.
-
- - name - contents of `<name>` tag
- - tail - whatever text follows that tag in the Element"""
- return self.genOpts.apientry + name + tail
-
- def makeTypedefName(self, name, tail):
- """Make the function-pointer typedef name for a command."""
- return '(' + self.genOpts.apientryp + 'PFN_' + name + tail + ')'
-
- def makeCParamDecl(self, param, aligncol):
- """Return a string which is an indented, formatted
- declaration for a `<param>` or `<member>` block (e.g. function parameter
- or structure/union member).
-
- - param - Element (`<param>` or `<member>`) to format
- - aligncol - if non-zero, attempt to align the nested `<name>` element
- at this column"""
- indent = ' '
- paramdecl = indent
- prefix = noneStr(param.text)
-
- for elem in param:
- text = noneStr(elem.text)
- tail = noneStr(elem.tail)
-
- if self.should_insert_may_alias_macro and self.genOpts.conventions.is_voidpointer_alias(elem.tag, text, tail):
- # OpenXR-specific macro insertion - but not in apiinc for the spec
- tail = self.genOpts.conventions.make_voidpointer_alias(tail)
- if elem.tag == 'name' and aligncol > 0:
- self.logMsg('diag', 'Aligning parameter', elem.text, 'to column', self.genOpts.alignFuncParam)
- # Align at specified column, if possible
- paramdecl = paramdecl.rstrip()
- oldLen = len(paramdecl)
- # This works around a problem where very long type names -
- # longer than the alignment column - would run into the tail
- # text.
- paramdecl = paramdecl.ljust(aligncol - 1) + ' '
- newLen = len(paramdecl)
- self.logMsg('diag', 'Adjust length of parameter decl from', oldLen, 'to', newLen, ':', paramdecl)
-
- if (self.misracppstyle() and prefix.find('const ') != -1):
- # Change pointer type order from e.g. "const void *" to "void const *".
- # If the string starts with 'const', reorder it to be after the first type.
- paramdecl += prefix.replace('const ', '') + text + ' const' + tail
- else:
- paramdecl += prefix + text + tail
-
- # Clear prefix for subsequent iterations
- prefix = ''
- if aligncol == 0:
- # Squeeze out multiple spaces other than the indentation
- paramdecl = indent + ' '.join(paramdecl.split())
- return paramdecl
-
- def getCParamTypeLength(self, param):
- """Return the length of the type field is an indented, formatted
- declaration for a `<param>` or `<member>` block (e.g. function parameter
- or structure/union member).
-
- - param - Element (`<param>` or `<member>`) to identify"""
-
- # Allow for missing <name> tag
- newLen = 0
- paramdecl = ' ' + noneStr(param.text)
- for elem in param:
- text = noneStr(elem.text)
- tail = noneStr(elem.tail)
-
- if self.should_insert_may_alias_macro and self.genOpts.conventions.is_voidpointer_alias(elem.tag, text, tail):
- # OpenXR-specific macro insertion
- tail = self.genOpts.conventions.make_voidpointer_alias(tail)
- if elem.tag == 'name':
- # Align at specified column, if possible
- newLen = len(paramdecl.rstrip())
- self.logMsg('diag', 'Identifying length of', elem.text, 'as', newLen)
- paramdecl += text + tail
-
- return newLen
-
- def getMaxCParamTypeLength(self, info):
- """Return the length of the longest type field for a member/parameter.
-
- - info - TypeInfo or CommandInfo.
- """
- lengths = (self.getCParamTypeLength(member)
- for member in info.getMembers())
- return max(lengths)
-
- def getHandleParent(self, typename):
- """Get the parent of a handle object."""
- info = self.registry.typedict.get(typename)
- if info is None:
- return None
-
- elem = info.elem
- if elem is not None:
- return elem.get('parent')
-
- return None
-
- def iterateHandleAncestors(self, typename):
- """Iterate through the ancestors of a handle type."""
- current = self.getHandleParent(typename)
- while current is not None:
- yield current
- current = self.getHandleParent(current)
-
- def getHandleAncestors(self, typename):
- """Get the ancestors of a handle object."""
- return list(self.iterateHandleAncestors(typename))
-
- def getTypeCategory(self, typename):
- """Get the category of a type."""
- info = self.registry.typedict.get(typename)
- if info is None:
- return None
-
- elem = info.elem
- if elem is not None:
- return elem.get('category')
- return None
-
- def isStructAlwaysValid(self, structname):
- """Try to do check if a structure is always considered valid (i.e. there's no rules to its acceptance)."""
- # A conventions object is required for this call.
- if not self.conventions:
- raise RuntimeError("To use isStructAlwaysValid, be sure your options include a Conventions object.")
-
- if self.conventions.type_always_valid(structname):
- return True
-
- category = self.getTypeCategory(structname)
- if self.conventions.category_requires_validation(category):
- return False
-
- info = self.registry.typedict.get(structname)
- assert(info is not None)
-
- members = info.getMembers()
-
- for member in members:
- member_name = getElemName(member)
- if member_name in (self.conventions.structtype_member_name,
- self.conventions.nextpointer_member_name):
- return False
-
- if member.get('noautovalidity'):
- return False
-
- member_type = getElemType(member)
-
- if member_type in ('void', 'char') or self.paramIsArray(member) or self.paramIsPointer(member):
- return False
-
- if self.conventions.type_always_valid(member_type):
- continue
-
- member_category = self.getTypeCategory(member_type)
-
- if self.conventions.category_requires_validation(member_category):
- return False
-
- if member_category in ('struct', 'union'):
- if self.isStructAlwaysValid(member_type) is False:
- return False
-
- return True
-
- def isEnumRequired(self, elem):
- """Return True if this `<enum>` element is
- required, False otherwise
-
- - elem - `<enum>` element to test"""
- required = elem.get('required') is not None
- self.logMsg('diag', 'isEnumRequired:', elem.get('name'),
- '->', required)
- return required
-
- # @@@ This code is overridden by equivalent code now run in
- # @@@ Registry.generateFeature
-
- required = False
-
- extname = elem.get('extname')
- if extname is not None:
- # 'supported' attribute was injected when the <enum> element was
- # moved into the <enums> group in Registry.parseTree()
- if self.genOpts.defaultExtensions == elem.get('supported'):
- required = True
- elif re.match(self.genOpts.addExtensions, extname) is not None:
- required = True
- elif elem.get('version') is not None:
- required = re.match(self.genOpts.emitversions, elem.get('version')) is not None
- else:
- required = True
-
- return required
-
- def makeCDecls(self, cmd):
- """Return C prototype and function pointer typedef for a
- `<command>` Element, as a two-element list of strings.
-
- - cmd - Element containing a `<command>` tag"""
- proto = cmd.find('proto')
- params = cmd.findall('param')
- # Begin accumulating prototype and typedef strings
- pdecl = self.genOpts.apicall
- tdecl = 'typedef '
-
- # Insert the function return type/name.
- # For prototypes, add APIENTRY macro before the name
- # For typedefs, add (APIENTRY *<name>) around the name and
- # use the PFN_cmdnameproc naming convention.
- # Done by walking the tree for <proto> element by element.
- # etree has elem.text followed by (elem[i], elem[i].tail)
- # for each child element and any following text
- # Leading text
- pdecl += noneStr(proto.text)
- tdecl += noneStr(proto.text)
- # For each child element, if it's a <name> wrap in appropriate
- # declaration. Otherwise append its contents and tail contents.
- for elem in proto:
- text = noneStr(elem.text)
- tail = noneStr(elem.tail)
- if elem.tag == 'name':
- pdecl += self.makeProtoName(text, tail)
- tdecl += self.makeTypedefName(text, tail)
- else:
- pdecl += text + tail
- tdecl += text + tail
-
- if self.genOpts.alignFuncParam == 0:
- # Squeeze out multiple spaces - there is no indentation
- pdecl = ' '.join(pdecl.split())
- tdecl = ' '.join(tdecl.split())
-
- # Now add the parameter declaration list, which is identical
- # for prototypes and typedefs. Concatenate all the text from
- # a <param> node without the tags. No tree walking required
- # since all tags are ignored.
- # Uses: self.indentFuncProto
- # self.indentFuncPointer
- # self.alignFuncParam
- n = len(params)
- # Indented parameters
- if n > 0:
- indentdecl = '(\n'
- indentdecl += ',\n'.join(self.makeCParamDecl(p, self.genOpts.alignFuncParam)
- for p in params)
- indentdecl += ');'
- else:
- indentdecl = '(void);'
- # Non-indented parameters
- paramdecl = '('
- if n > 0:
- paramnames = []
- if self.misracppstyle():
- for p in params:
- param = ''
- firstIter = True;
- for t in p.itertext():
- if (firstIter):
- prefix = t
- firstIter = False
- else:
- # Change pointer type order from e.g. "const void *" to "void const *".
- # If the string starts with 'const', reorder it to be after the first type.
- if (prefix.find('const ') != -1):
- param += prefix.replace('const ', '') + t + ' const '
- else:
- param += prefix + t
- # Clear prefix for subsequent iterations
- prefix = ''
- paramnames.append(param);
- else:
- paramnames = (''.join(t for t in p.itertext())
- for p in params)
- paramdecl += ', '.join(paramnames)
- else:
- paramdecl += 'void'
- paramdecl += ");"
- return [pdecl + indentdecl, tdecl + paramdecl]
-
- def newline(self):
- """Print a newline to the output file (utility function)"""
- write('', file=self.outFile)
-
- def setRegistry(self, registry):
- self.registry = registry
diff --git a/codegen/vulkan/scripts/genspec.py b/codegen/vulkan/scripts/genspec.py
deleted file mode 100644
index dfa55cca..00000000
--- a/codegen/vulkan/scripts/genspec.py
+++ /dev/null
@@ -1,164 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2016-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-"""This script builds a full release package including XHTML and PDF
-versions of the specification, including an optional list of
-extensions. Other files in the release directory are removed,
-including man pages, XHTML chunked, HTML, validity output, etc.
-
-The current branch must be fully committed and up to date when the
-script is run, with no outstanding un-added / un-committed files.
-After completing the build, suggestions for creating tags are made."""
-
-import time
-from datetime import date, timedelta
-
-
-def releaseNum():
- """Return the Vulkan release number, used for tags."""
- return '$REVISION'
-
-
-def buildOnFriday():
- """Return a date for the current, or upcoming if not already, Friday,
- which is when releases happen."""
- today = date.today()
- friday = today + timedelta((4 - today.weekday()) % 7)
- return friday
-
-
-def buildRelease(label,
- versions,
- extensions,
- ratified,
- outdir,
- apititle,
- xmlDir, xmlTargets,
- specDir, specTargets,
- miscSrc=None, miscDst=None, needRefSources=False):
- """Build a release.
-
- - `label` = textual label to use for target being generated
- - `versions` = list of core API versions to include
- - `extensions` = list of extension names to include
- - `ratified` = True if this is a ratified spec (one built without non-KHR extensions)
- - `outdir` = directory to generate specs in
- - `apititle` = extra title to apply to the specification
- - `xmlDir` = directory containing registry XML
- - `xmlTargets` = targets to build in xml/
- - `specDir` = directory containing spec source & Makefile
- - `specTargets` = targets to build
- - `miscSrc` = path to copy misc files from, if non-None
- - `miscDst` = path to copy misc files to, if non-None
- - `needRefSources` = True if ref pages must be extracted from the spec sources"""
-
- print('echo Info: Generating target=' + label,
- 'outdir=' + outdir)
-
- outarg = 'OUTDIR=' + outdir
-
- if versions != None and len(versions) > 0:
- versarg = 'VERSIONS="' + ' '.join(versions) + '"'
- else:
- versarg = ''
-
- if extensions != None and len(extensions) > 0:
- extarg = 'EXTENSIONS="' + ' '.join(extensions) + '"'
- else:
- extarg = ''
-
- if ratified:
- ratifiedarg = 'EXTRAATTRIBS="-a ratified_core_spec"'
- else:
- ratifiedarg = ''
-
- if apititle != None:
- titlearg = 'APITITLE="' + apititle + '"'
- else:
- titlearg = ''
-
- # print('echo Info: Creating directory and cleaning spec in', outdir)
- print('mkdir -p', outdir)
- print('(cd ', outdir, '&& rm -rf',
- 'html chunked pdf',
- 'man config checks',
- 'vkspec.html styleguide.html apispec.html apispec.pdf registry.html',
- ')')
-
- if xmlTargets != '':
- # print('echo Info: Generating headers and spec include files')
- print('cd', xmlDir)
- print('make', outarg, xmlTargets)
-
- # print('echo Info: Generating ref pages sources and spec targets')
- print('cd', specDir)
- print('make', outarg, 'clean')
- # This is a temporary workaround for a dependency bug - if any of the
- # specTargets require ref page sources, and they aren't already present
- # at the time the make is invoked, that target will not be built.
- if needRefSources:
- print('make', outarg, versarg, extarg, 'refpages')
- # Now make the actual targets.
- print('make -O -k -j 8',
- outarg, versarg, extarg, ratifiedarg, titlearg,
- 'NOTEOPTS="-a implementation-guide"',
- specTargets)
-
- if miscSrc != None and miscDst != None:
- print('mkdir -p', miscDst)
- print('cp', miscSrc + '/*.txt', miscDst + '/')
-
- print('')
-
-
-def buildBranch(targetDir = '',
- versions = '',
- extensions = '',
- ratified = False,
- apititle = '(NO TITLE SPECIFIED)',
- xmlTargets = '',
- specTargets = '',
- repoDir = '',
- outDir = '',
- needRefSources=False):
- """Build all target documents.
-
- - `repoDir` = path to the Vulkan git repo containing the specs
- - `outDir` = path to the output base directory in which targets are generated"""
-
- # Directory with vk.xml and generation tools
- xmlDir = repoDir + '/xml'
- # Directory with spec sources
- specDir = repoDir
- # Directory containing misc. files to copy to registry.
- # At present there are none, since GLSL extensions have moved to the
- # GLSL repository and are redirected from the Vulkan registy website.
- # These should be relative to repoDir and outDir, respectively
- miscSrc = None
- miscDst = None
-
- buildRelease(targetDir,
- versions,
- extensions,
- ratified,
- outDir + '/' + targetDir,
- apititle,
- xmlDir, xmlTargets,
- specDir, specTargets,
- miscSrc, miscDst,
- needRefSources)
-
-
-def createTags(releaseNum, tagdate):
- """Print commands to tag the git branches.
-
- - `releaseNum` = release number of this spec update, to tag the tree with
- - `tagdate` = date (used to be used to tag the tree with)"""
- # Tag date in YYYYMMDD format
- now = tagdate.strftime('%Y%m%d')
-
- print('echo To tag the spec branch for this release, execute the command:')
- print('echo git tag -a -m \\"Tag Vulkan API specification for 1.2.' +
- releaseNum, 'release\\"', 'v1.2.' + releaseNum)
diff --git a/codegen/vulkan/scripts/genvk.py b/codegen/vulkan/scripts/genvk.py
deleted file mode 100755
index 02cd1a5c..00000000
--- a/codegen/vulkan/scripts/genvk.py
+++ /dev/null
@@ -1,854 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-import argparse
-import pdb
-import re
-import sys
-import time
-import xml.etree.ElementTree as etree
-
-from cgenerator import CGeneratorOptions, COutputGenerator
-from cerealgenerator import CerealGenerator
-from docgenerator import DocGeneratorOptions, DocOutputGenerator
-from extensionmetadocgenerator import (ExtensionMetaDocGeneratorOptions,
- ExtensionMetaDocOutputGenerator)
-from interfacedocgenerator import InterfaceDocGenerator
-from generator import write
-from spirvcapgenerator import SpirvCapabilityOutputGenerator
-from hostsyncgenerator import HostSynchronizationOutputGenerator
-from pygenerator import PyOutputGenerator
-from rubygenerator import RubyOutputGenerator
-from reflib import logDiag, logWarn, setLogFile
-from reg import Registry
-from validitygenerator import ValidityOutputGenerator
-from vkconventions import VulkanConventions
-
-
-# Simple timer functions
-startTime = None
-
-
-def startTimer(timeit):
- global startTime
- if timeit:
- startTime = time.process_time()
-
-
-def endTimer(timeit, msg):
- global startTime
- if timeit:
- endTime = time.process_time()
- logDiag(msg, endTime - startTime)
- startTime = None
-
-
-def makeREstring(strings, default=None, strings_are_regex=False):
- """Turn a list of strings into a regexp string matching exactly those strings."""
- if strings or default is None:
- if not strings_are_regex:
- strings = (re.escape(s) for s in strings)
- return '^(' + '|'.join(strings) + ')$'
- return default
-
-
-def makeGenOpts(args):
- """Returns a directory of [ generator function, generator options ] indexed
- by specified short names. The generator options incorporate the following
- parameters:
-
- args is an parsed argument object; see below for the fields that are used."""
- global genOpts
- genOpts = {}
-
- # Default class of extensions to include, or None
- defaultExtensions = args.defaultExtensions
-
- # Additional extensions to include (list of extensions)
- extensions = args.extension
-
- # Extensions to remove (list of extensions)
- removeExtensions = args.removeExtensions
-
- # Extensions to emit (list of extensions)
- emitExtensions = args.emitExtensions
-
- # SPIR-V capabilities / features to emit (list of extensions & capabilities)
- emitSpirv = args.emitSpirv
-
- # Features to include (list of features)
- features = args.feature
-
- # Whether to disable inclusion protect in headers
- protect = args.protect
-
- # Output target directory
- directory = args.directory
-
- # Path to generated files, particularly api.py
- genpath = args.genpath
-
- # Generate MISRA C-friendly headers
- misracstyle = args.misracstyle;
-
- # Generate MISRA C++-friendly headers
- misracppstyle = args.misracppstyle;
-
- # Descriptive names for various regexp patterns used to select
- # versions and extensions
- allSpirv = allFeatures = allExtensions = r'.*'
-
- # Turn lists of names/patterns into matching regular expressions
- addExtensionsPat = makeREstring(extensions, None)
- removeExtensionsPat = makeREstring(removeExtensions, None)
- emitExtensionsPat = makeREstring(emitExtensions, allExtensions)
- emitSpirvPat = makeREstring(emitSpirv, allSpirv)
- featuresPat = makeREstring(features, allFeatures)
-
- # Copyright text prefixing all headers (list of strings).
- # The SPDX formatting below works around constraints of the 'reuse' tool
- prefixStrings = [
- '/*',
- '** Copyright 2015-2021 The Khronos Group Inc.',
- '**',
- '** SPDX' + '-License-Identifier: Apache-2.0',
- '*/',
- ''
- ]
-
- # Text specific to Vulkan headers
- vkPrefixStrings = [
- '/*',
- '** This header is generated from the Khronos Vulkan XML API Registry.',
- '**',
- '*/',
- ''
- ]
-
- # Defaults for generating re-inclusion protection wrappers (or not)
- protectFile = protect
-
- # An API style conventions object
- conventions = VulkanConventions()
-
- # API include files for spec and ref pages
- # Overwrites include subdirectories in spec source tree
- # The generated include files do not include the calling convention
- # macros (apientry etc.), unlike the header files.
- # Because the 1.0 core branch includes ref pages for extensions,
- # all the extension interfaces need to be generated, even though
- # none are used by the core spec itself.
- genOpts['apiinc'] = [
- DocOutputGenerator,
- DocGeneratorOptions(
- conventions = conventions,
- filename = 'timeMarker',
- directory = directory,
- genpath = genpath,
- apiname = 'vulkan',
- profile = None,
- versions = featuresPat,
- emitversions = featuresPat,
- defaultExtensions = None,
- addExtensions = addExtensionsPat,
- removeExtensions = removeExtensionsPat,
- emitExtensions = emitExtensionsPat,
- prefixText = prefixStrings + vkPrefixStrings,
- apicall = '',
- apientry = '',
- apientryp = '*',
- alignFuncParam = 48,
- expandEnumerants = False)
- ]
-
- # Python representation of API information, used by scripts that
- # don't need to load the full XML.
- genOpts['api.py'] = [
- PyOutputGenerator,
- DocGeneratorOptions(
- conventions = conventions,
- filename = 'api.py',
- directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
- versions = featuresPat,
- emitversions = featuresPat,
- defaultExtensions = None,
- addExtensions = addExtensionsPat,
- removeExtensions = removeExtensionsPat,
- emitExtensions = emitExtensionsPat,
- reparentEnums = False)
- ]
-
- # Ruby representation of API information, used by scripts that
- # don't need to load the full XML.
- genOpts['api.rb'] = [
- RubyOutputGenerator,
- DocGeneratorOptions(
- conventions = conventions,
- filename = 'api.rb',
- directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
- versions = featuresPat,
- emitversions = featuresPat,
- defaultExtensions = None,
- addExtensions = addExtensionsPat,
- removeExtensions = removeExtensionsPat,
- emitExtensions = emitExtensionsPat,
- reparentEnums = False)
- ]
-
-
- # API validity files for spec
- #
- # requireCommandAliases is set to True because we need validity files
- # for the command something is promoted to even when the promoted-to
- # feature is not included. This avoids wordy includes of validity files.
- genOpts['validinc'] = [
- ValidityOutputGenerator,
- DocGeneratorOptions(
- conventions = conventions,
- filename = 'timeMarker',
- directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
- versions = featuresPat,
- emitversions = featuresPat,
- defaultExtensions = None,
- addExtensions = addExtensionsPat,
- removeExtensions = removeExtensionsPat,
- emitExtensions = emitExtensionsPat,
- requireCommandAliases = True,
- )
- ]
-
- # Serializer for spec
- genOpts['cereal'] = [
- CerealGenerator,
- CGeneratorOptions(
- conventions = conventions,
- filename = "CMakeLists.txt",
- directory = directory,
- apiname = 'vulkan',
- profile = None,
- versions = featuresPat,
- emitversions = featuresPat,
- defaultExtensions = defaultExtensions,
- addExtensions = None,
- removeExtensions = removeExtensionsPat,
- emitExtensions = emitExtensionsPat,
- prefixText = prefixStrings + vkPrefixStrings,
- genFuncPointers = True,
- protectFile = protectFile,
- protectFeature = False,
- protectProto = '#ifndef',
- protectProtoStr = 'VK_NO_PROTOTYPES',
- apicall = 'VKAPI_ATTR ',
- apientry = 'VKAPI_CALL ',
- apientryp = 'VKAPI_PTR *',
- alignFuncParam = 48)
- ]
-
- gfxstreamPrefixStrings = [
- '// Copyright (C) 2022 The Android Open Source Project',
- '// Copyright (C) 2022 Google Inc.',
- '//',
- '// Licensed under the Apache License, Version 2.0 (the "License");',
- '// you may not use this file except in compliance with the License.',
- '// You may obtain a copy of the License at',
- '//',
- '// http://www.apache.org/licenses/LICENSE-2.0',
- '//',
- '// Unless required by applicable law or agreed to in writing, software',
- '// distributed under the License is distributed on an "AS IS" BASIS,',
- '// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.',
- '// See the License for the specific language governing permissions and',
- '// limitations under the License.',
- '//',
- '// Autogenerated header vulkan_gfxstream.h',
- '// Please do not modify directly;',
- '// re-run gfxstream-protocols/scripts/generate-vulkan-sources.sh,',
- '// or directly from Python by calling the genvk.py script with correct parameters.',
- '',
- '#pragma once',
- '#ifdef VK_GFXSTREAM_STRUCTURE_TYPE_EXT',
- '#include "vulkan_gfxstream_structure_type.h"',
- '#endif',
- ]
- # gfxstream specific header
- genOpts['vulkan_gfxstream.h'] = [
- COutputGenerator,
- CGeneratorOptions(
- conventions = conventions,
- filename = 'vulkan_gfxstream.h',
- directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
- versions = featuresPat,
- emitversions = None,
- defaultExtensions = None,
- addExtensions = makeREstring(['VK_GOOGLE_gfxstream'], None),
- removeExtensions = None,
- emitExtensions = makeREstring(['VK_GOOGLE_gfxstream'], None),
- prefixText = gfxstreamPrefixStrings,
- genFuncPointers = True,
- # Use #pragma once in the prefixText instead, so that we can put the copyright comments
- # at the beginning of the file.
- protectFile = False,
- protectFeature = False,
- protectProto = '#ifndef',
- protectProtoStr = 'VK_NO_PROTOTYPES',
- apicall = 'VKAPI_ATTR ',
- apientry = 'VKAPI_CALL ',
- apientryp = 'VKAPI_PTR *',
- alignFuncParam = 48,
- misracstyle = misracstyle,
- misracppstyle = misracppstyle)
- ]
-
- androidNativeBufferPrefixStrings = [
- '// Copyright (C) 2022 The Android Open Source Project',
- '// Copyright (C) 2022 Google Inc.',
- '//',
- '// Licensed under the Apache License, Version 2.0 (the "License");',
- '// you may not use this file except in compliance with the License.',
- '// You may obtain a copy of the License at',
- '//',
- '// http://www.apache.org/licenses/LICENSE-2.0',
- '//',
- '// Unless required by applicable law or agreed to in writing, software',
- '// distributed under the License is distributed on an "AS IS" BASIS,',
- '// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.',
- '// See the License for the specific language governing permissions and',
- '// limitations under the License.',
- '//',
- '// Autogenerated header vk_android_native_buffer.h',
- '// Please do not modify directly;',
- '// re-run gfxstream-protocols/scripts/generate-vulkan-sources.sh,',
- '// or directly from Python by calling the genvk.py script with correct parameters.',
- '',
- '#pragma once',
- '#ifndef VK_ANDROID_native_buffer',
- '#include "vk_android_native_buffer_structure_type.h"',
- '#endif /* VK_ANDROID_native_buffer */',
- ]
- # header
- genOpts['vk_android_native_buffer.h'] = [
- COutputGenerator,
- CGeneratorOptions(
- conventions = conventions,
- filename = 'vk_android_native_buffer.h',
- directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
- versions = featuresPat,
- emitversions = None,
- defaultExtensions = None,
- addExtensions = makeREstring(['VK_ANDROID_native_buffer'], None),
- removeExtensions = None,
- emitExtensions = makeREstring(['VK_ANDROID_native_buffer'], None),
- prefixText = androidNativeBufferPrefixStrings,
- genFuncPointers = True,
- # Use #pragma once in the prefixText instead, so that we can put the copyright comments
- # at the beginning of the file.
- protectFile = False,
- protectFeature = True,
- protectProto = '#ifndef',
- protectProtoStr = 'VK_NO_PROTOTYPES',
- apicall = 'VKAPI_ATTR ',
- apientry = 'VKAPI_CALL ',
- apientryp = 'VKAPI_PTR *',
- alignFuncParam = 48,
- misracstyle = misracstyle,
- misracppstyle = misracppstyle)
- ]
-
- # API host sync table files for spec
- genOpts['hostsyncinc'] = [
- HostSynchronizationOutputGenerator,
- DocGeneratorOptions(
- conventions = conventions,
- filename = 'timeMarker',
- directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
- versions = featuresPat,
- emitversions = featuresPat,
- defaultExtensions = None,
- addExtensions = addExtensionsPat,
- removeExtensions = removeExtensionsPat,
- emitExtensions = emitExtensionsPat,
- reparentEnums = False)
- ]
-
- # Extension metainformation for spec extension appendices
- # Includes all extensions by default, but only so that the generated
- # 'promoted_extensions_*' files refer to all extensions that were
- # promoted to a core version.
- genOpts['extinc'] = [
- ExtensionMetaDocOutputGenerator,
- ExtensionMetaDocGeneratorOptions(
- conventions = conventions,
- filename = 'timeMarker',
- directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
- versions = featuresPat,
- emitversions = None,
- defaultExtensions = defaultExtensions,
- addExtensions = addExtensionsPat,
- removeExtensions = None,
- emitExtensions = emitExtensionsPat)
- ]
-
- # Version and extension interface docs for version/extension appendices
- # Includes all extensions by default.
- genOpts['interfaceinc'] = [
- InterfaceDocGenerator,
- DocGeneratorOptions(
- conventions = conventions,
- filename = 'timeMarker',
- directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
- versions = featuresPat,
- emitversions = featuresPat,
- defaultExtensions = None,
- addExtensions = addExtensionsPat,
- removeExtensions = removeExtensionsPat,
- emitExtensions = emitExtensionsPat,
- reparentEnums = False)
- ]
-
- genOpts['spirvcapinc'] = [
- SpirvCapabilityOutputGenerator,
- DocGeneratorOptions(
- conventions = conventions,
- filename = 'timeMarker',
- directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
- versions = featuresPat,
- emitversions = featuresPat,
- defaultExtensions = None,
- addExtensions = addExtensionsPat,
- removeExtensions = removeExtensionsPat,
- emitExtensions = emitExtensionsPat,
- emitSpirv = emitSpirvPat,
- reparentEnums = False)
- ]
-
- # Platform extensions, in their own header files
- # Each element of the platforms[] array defines information for
- # generating a single platform:
- # [0] is the generated header file name
- # [1] is the set of platform extensions to generate
- # [2] is additional extensions whose interfaces should be considered,
- # but suppressed in the output, to avoid duplicate definitions of
- # dependent types like VkDisplayKHR and VkSurfaceKHR which come from
- # non-platform extensions.
-
- # Track all platform extensions, for exclusion from vulkan_core.h
- allPlatformExtensions = []
-
- # Extensions suppressed for all WSI platforms (WSI extensions required
- # by all platforms)
- commonSuppressExtensions = [ 'VK_KHR_display', 'VK_KHR_swapchain' ]
-
- # Extensions required and suppressed for beta "platform". This can
- # probably eventually be derived from the requires= attributes of
- # the extension blocks.
- betaRequireExtensions = [
- 'VK_KHR_portability_subset',
- 'VK_KHR_video_queue',
- 'VK_KHR_video_decode_queue',
- 'VK_KHR_video_encode_queue',
- 'VK_EXT_video_decode_h264',
- 'VK_EXT_video_decode_h265',
- 'VK_EXT_video_encode_h264',
- 'VK_EXT_video_encode_h265',
- ]
-
- betaSuppressExtensions = []
-
- platforms = [
- [ 'vulkan_android.h', [ 'VK_KHR_android_surface',
- 'VK_ANDROID_external_memory_android_hardware_buffer'
- ], commonSuppressExtensions +
- [ 'VK_KHR_format_feature_flags2',
- ] ],
- [ 'vulkan_fuchsia.h', [ 'VK_FUCHSIA_imagepipe_surface',
- 'VK_FUCHSIA_external_memory',
- 'VK_FUCHSIA_external_semaphore',
- 'VK_FUCHSIA_buffer_collection' ], commonSuppressExtensions ],
- [ 'vulkan_ggp.h', [ 'VK_GGP_stream_descriptor_surface',
- 'VK_GGP_frame_token' ], commonSuppressExtensions ],
- [ 'vulkan_ios.h', [ 'VK_MVK_ios_surface' ], commonSuppressExtensions ],
- [ 'vulkan_macos.h', [ 'VK_MVK_macos_surface' ], commonSuppressExtensions ],
- [ 'vulkan_vi.h', [ 'VK_NN_vi_surface' ], commonSuppressExtensions ],
- [ 'vulkan_wayland.h', [ 'VK_KHR_wayland_surface' ], commonSuppressExtensions ],
- [ 'vulkan_win32.h', [ 'VK_.*_win32(|_.*)', 'VK_EXT_full_screen_exclusive' ],
- commonSuppressExtensions +
- [ 'VK_KHR_external_semaphore',
- 'VK_KHR_external_memory_capabilities',
- 'VK_KHR_external_fence',
- 'VK_KHR_external_fence_capabilities',
- 'VK_KHR_get_surface_capabilities2',
- 'VK_NV_external_memory_capabilities',
- ] ],
- [ 'vulkan_xcb.h', [ 'VK_KHR_xcb_surface' ], commonSuppressExtensions ],
- [ 'vulkan_xlib.h', [ 'VK_KHR_xlib_surface' ], commonSuppressExtensions ],
- [ 'vulkan_directfb.h', [ 'VK_EXT_directfb_surface' ], commonSuppressExtensions ],
- [ 'vulkan_xlib_xrandr.h', [ 'VK_EXT_acquire_xlib_display' ], commonSuppressExtensions ],
- [ 'vulkan_metal.h', [ 'VK_EXT_metal_surface' ], commonSuppressExtensions ],
- [ 'vulkan_screen.h', [ 'VK_QNX_screen_surface' ], commonSuppressExtensions ],
- [ 'vulkan_beta.h', betaRequireExtensions, betaSuppressExtensions ],
- ]
-
- for platform in platforms:
- headername = platform[0]
-
- allPlatformExtensions += platform[1]
-
- addPlatformExtensionsRE = makeREstring(
- platform[1] + platform[2], strings_are_regex=True)
- emitPlatformExtensionsRE = makeREstring(
- platform[1], strings_are_regex=True)
-
- opts = CGeneratorOptions(
- conventions = conventions,
- filename = headername,
- directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
- versions = featuresPat,
- emitversions = None,
- defaultExtensions = None,
- addExtensions = addPlatformExtensionsRE,
- removeExtensions = None,
- emitExtensions = emitPlatformExtensionsRE,
- prefixText = prefixStrings + vkPrefixStrings,
- genFuncPointers = True,
- protectFile = protectFile,
- protectFeature = False,
- protectProto = '#ifndef',
- protectProtoStr = 'VK_NO_PROTOTYPES',
- apicall = 'VKAPI_ATTR ',
- apientry = 'VKAPI_CALL ',
- apientryp = 'VKAPI_PTR *',
- alignFuncParam = 48,
- misracstyle = misracstyle,
- misracppstyle = misracppstyle)
-
- genOpts[headername] = [ COutputGenerator, opts ]
-
- # Header for core API + extensions.
- # To generate just the core API,
- # change to 'defaultExtensions = None' below.
- #
- # By default this adds all enabled, non-platform extensions.
- # It removes all platform extensions (from the platform headers options
- # constructed above) as well as any explicitly specified removals.
-
- removeExtensionsPat = makeREstring(
- allPlatformExtensions + removeExtensions, None, strings_are_regex=True)
-
- genOpts['vulkan_core.h'] = [
- COutputGenerator,
- CGeneratorOptions(
- conventions = conventions,
- filename = 'vulkan_core.h',
- directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
- versions = featuresPat,
- emitversions = featuresPat,
- defaultExtensions = defaultExtensions,
- addExtensions = addExtensionsPat,
- removeExtensions = removeExtensionsPat,
- emitExtensions = emitExtensionsPat,
- prefixText = prefixStrings + vkPrefixStrings,
- genFuncPointers = True,
- protectFile = protectFile,
- protectFeature = False,
- protectProto = '#ifndef',
- protectProtoStr = 'VK_NO_PROTOTYPES',
- apicall = 'VKAPI_ATTR ',
- apientry = 'VKAPI_CALL ',
- apientryp = 'VKAPI_PTR *',
- alignFuncParam = 48,
- misracstyle = misracstyle,
- misracppstyle = misracppstyle)
- ]
-
- # Unused - vulkan10.h target.
- # It is possible to generate a header with just the Vulkan 1.0 +
- # extension interfaces defined, but since the promoted KHR extensions
- # are now defined in terms of the 1.1 interfaces, such a header is very
- # similar to vulkan_core.h.
- genOpts['vulkan10.h'] = [
- COutputGenerator,
- CGeneratorOptions(
- conventions = conventions,
- filename = 'vulkan10.h',
- directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
- versions = 'VK_VERSION_1_0',
- emitversions = 'VK_VERSION_1_0',
- defaultExtensions = None,
- addExtensions = None,
- removeExtensions = None,
- emitExtensions = None,
- prefixText = prefixStrings + vkPrefixStrings,
- genFuncPointers = True,
- protectFile = protectFile,
- protectFeature = False,
- protectProto = '#ifndef',
- protectProtoStr = 'VK_NO_PROTOTYPES',
- apicall = 'VKAPI_ATTR ',
- apientry = 'VKAPI_CALL ',
- apientryp = 'VKAPI_PTR *',
- alignFuncParam = 48,
- misracstyle = misracstyle,
- misracppstyle = misracppstyle)
- ]
-
- # Unused - vulkan11.h target.
- # It is possible to generate a header with just the Vulkan 1.0 +
- # extension interfaces defined, but since the promoted KHR extensions
- # are now defined in terms of the 1.1 interfaces, such a header is very
- # similar to vulkan_core.h.
- genOpts['vulkan11.h'] = [
- COutputGenerator,
- CGeneratorOptions(
- conventions = conventions,
- filename = 'vulkan11.h',
- directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
- versions = '^VK_VERSION_1_[01]$',
- emitversions = '^VK_VERSION_1_[01]$',
- defaultExtensions = None,
- addExtensions = None,
- removeExtensions = None,
- emitExtensions = None,
- prefixText = prefixStrings + vkPrefixStrings,
- genFuncPointers = True,
- protectFile = protectFile,
- protectFeature = False,
- protectProto = '#ifndef',
- protectProtoStr = 'VK_NO_PROTOTYPES',
- apicall = 'VKAPI_ATTR ',
- apientry = 'VKAPI_CALL ',
- apientryp = 'VKAPI_PTR *',
- alignFuncParam = 48,
- misracstyle = misracstyle,
- misracppstyle = misracppstyle)
- ]
-
- genOpts['alias.h'] = [
- COutputGenerator,
- CGeneratorOptions(
- conventions = conventions,
- filename = 'alias.h',
- directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
- versions = featuresPat,
- emitversions = featuresPat,
- defaultExtensions = defaultExtensions,
- addExtensions = None,
- removeExtensions = removeExtensionsPat,
- emitExtensions = emitExtensionsPat,
- prefixText = None,
- genFuncPointers = False,
- protectFile = False,
- protectFeature = False,
- protectProto = '',
- protectProtoStr = '',
- apicall = '',
- apientry = '',
- apientryp = '',
- alignFuncParam = 36)
- ]
-
-
-def genTarget(args):
- """Create an API generator and corresponding generator options based on
- the requested target and command line options.
-
- This is encapsulated in a function so it can be profiled and/or timed.
- The args parameter is an parsed argument object containing the following
- fields that are used:
-
- - target - target to generate
- - directory - directory to generate it in
- - protect - True if re-inclusion wrappers should be created
- - extensions - list of additional extensions to include in generated interfaces"""
-
- # Create generator options with parameters specified on command line
- makeGenOpts(args)
-
- # pdb.set_trace()
-
- # Select a generator matching the requested target
- if args.target in genOpts:
- createGenerator = genOpts[args.target][0]
- options = genOpts[args.target][1]
-
- logDiag('* Building', options.filename)
- logDiag('* options.versions =', options.versions)
- logDiag('* options.emitversions =', options.emitversions)
- logDiag('* options.defaultExtensions =', options.defaultExtensions)
- logDiag('* options.addExtensions =', options.addExtensions)
- logDiag('* options.removeExtensions =', options.removeExtensions)
- logDiag('* options.emitExtensions =', options.emitExtensions)
-
- gen = createGenerator(errFile=errWarn,
- warnFile=errWarn,
- diagFile=diag)
- return (gen, options)
- else:
- logErr('No generator options for unknown target:', args.target)
- return None
-
-
-# -feature name
-# -extension name
-# For both, "name" may be a single name, or a space-separated list
-# of names, or a regular expression.
-if __name__ == '__main__':
- parser = argparse.ArgumentParser()
-
- parser.add_argument('-defaultExtensions', action='store',
- default='vulkan',
- help='Specify a single class of extensions to add to targets')
- parser.add_argument('-extension', action='append',
- default=[],
- help='Specify an extension or extensions to add to targets')
- parser.add_argument('-removeExtensions', action='append',
- default=[],
- help='Specify an extension or extensions to remove from targets')
- parser.add_argument('-emitExtensions', action='append',
- default=[],
- help='Specify an extension or extensions to emit in targets')
- parser.add_argument('-emitSpirv', action='append',
- default=[],
- help='Specify a SPIR-V extension or capability to emit in targets')
- parser.add_argument('-feature', action='append',
- default=[],
- help='Specify a core API feature name or names to add to targets')
- parser.add_argument('-debug', action='store_true',
- help='Enable debugging')
- parser.add_argument('-dump', action='store_true',
- help='Enable dump to stderr')
- parser.add_argument('-diagfile', action='store',
- default=None,
- help='Write diagnostics to specified file')
- parser.add_argument('-errfile', action='store',
- default=None,
- help='Write errors and warnings to specified file instead of stderr')
- parser.add_argument('-noprotect', dest='protect', action='store_false',
- help='Disable inclusion protection in output headers')
- parser.add_argument('-profile', action='store_true',
- help='Enable profiling')
- parser.add_argument('-registry', action='store',
- default='vk.xml',
- help='Use specified registry file instead of vk.xml')
- parser.add_argument('-time', action='store_true',
- help='Enable timing')
- parser.add_argument('-validate', action='store_true',
- help='Validate the registry properties and exit')
- parser.add_argument('-genpath', action='store', default='gen',
- help='Path to generated files')
- parser.add_argument('-o', action='store', dest='directory',
- default='.',
- help='Create target and related files in specified directory')
- parser.add_argument('target', metavar='target', nargs='?',
- help='Specify target')
- parser.add_argument('-quiet', action='store_true', default=True,
- help='Suppress script output during normal execution.')
- parser.add_argument('-verbose', action='store_false', dest='quiet', default=True,
- help='Enable script output during normal execution.')
- parser.add_argument('-misracstyle', dest='misracstyle', action='store_true',
- help='generate MISRA C-friendly headers')
- parser.add_argument('-misracppstyle', dest='misracppstyle', action='store_true',
- help='generate MISRA C++-friendly headers')
-
- args = parser.parse_args()
-
- # This splits arguments which are space-separated lists
- args.feature = [name for arg in args.feature for name in arg.split()]
- args.extension = [name for arg in args.extension for name in arg.split()]
-
- # create error/warning & diagnostic files
- if args.errfile:
- errWarn = open(args.errfile, 'w', encoding='utf-8')
- else:
- errWarn = sys.stderr
-
- if args.diagfile:
- diag = open(args.diagfile, 'w', encoding='utf-8')
- else:
- diag = None
-
- if args.time:
- # Log diagnostics and warnings
- setLogFile(setDiag = True, setWarn = True, filename = '-')
-
- (gen, options) = (None, None)
- if not args.validate:
- # Create the API generator & generator options
- (gen, options) = genTarget(args)
-
- # Create the registry object with the specified generator and generator
- # options. The options are set before XML loading as they may affect it.
- reg = Registry(gen, options)
-
- # Parse the specified registry XML into an ElementTree object
- startTimer(args.time)
- tree = etree.parse(args.registry)
- endTimer(args.time, '* Time to make ElementTree =')
-
- # Load the XML tree into the registry object
- startTimer(args.time)
- reg.loadElementTree(tree)
- endTimer(args.time, '* Time to parse ElementTree =')
-
- if args.validate:
- success = reg.validateRegistry()
- sys.exit(0 if success else 1)
-
- if args.dump:
- logDiag('* Dumping registry to regdump.txt')
- reg.dumpReg(filehandle=open('regdump.txt', 'w', encoding='utf-8'))
-
- # Finally, use the output generator to create the requested target
- if args.debug:
- pdb.run('reg.apiGen()')
- else:
- startTimer(args.time)
- reg.apiGen()
- endTimer(args.time, '* Time to generate ' + options.filename + ' =')
-
- if not args.quiet:
- logDiag('* Generated', options.filename)
diff --git a/codegen/vulkan/scripts/globalizeIncludes b/codegen/vulkan/scripts/globalizeIncludes
deleted file mode 100755
index 3fad7776..00000000
--- a/codegen/vulkan/scripts/globalizeIncludes
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-#
-# Copyright 2019-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# globalizeIncludes - rewrites generated include::, and image:/image::
-# asciidoctor directives in specified Vulkan specification source files to
-# be relative to specified attributes {generated} and {images}, ensuring
-# they work properly when extracted to reference pages.
-#
-# usage: globalizeIncludes filenames
-# Updates specified files in-place, so make sure they're backed up first.
-
-sed -i -E \
- -e 's#image:images/#image:{images}/#g' \
- -e 's#image::images/#image::{images}/#g' \
- -e 's#include::(\.\./)*(api|validity|hostsynctable)#include::{generated}/\2#g' \
- $*
-
-# Not yet:
-# -e 's#include::meta/#include::{generated}/meta/#g' \
diff --git a/codegen/vulkan/scripts/hostsyncgenerator.py b/codegen/vulkan/scripts/hostsyncgenerator.py
deleted file mode 100644
index a94db149..00000000
--- a/codegen/vulkan/scripts/hostsyncgenerator.py
+++ /dev/null
@@ -1,154 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-from generator import OutputGenerator, write
-from spec_tools.attributes import ExternSyncEntry
-from spec_tools.validity import ValidityCollection, ValidityEntry
-from spec_tools.util import getElemName
-
-
-class HostSynchronizationOutputGenerator(OutputGenerator):
- """HostSynchronizationOutputGenerator - subclass of OutputGenerator.
- Generates AsciiDoc includes of the externsync parameter table for the
- fundamentals chapter of the API specification. Similar to
- DocOutputGenerator.
-
- ---- methods ----
- HostSynchronizationOutputGenerator(errFile, warnFile, diagFile) - args as for
- OutputGenerator. Defines additional internal state.
- ---- methods overriding base class ----
- genCmd(cmdinfo)"""
- # Generate Host Synchronized Parameters in a table at the top of the spec
-
- threadsafety = {
- 'parameters': ValidityCollection(),
- 'parameterlists': ValidityCollection(),
- 'implicit': ValidityCollection()
- }
-
- def makeParameterName(self, name):
- return 'pname:' + name
-
- def makeFLink(self, name):
- return 'flink:' + name
-
- def writeBlock(self, basename, title, contents):
- """Generate an include file.
-
- - directory - subdirectory to put file in
- - basename - base name of the file
- - contents - contents of the file (Asciidoc boilerplate aside)"""
- filename = self.genOpts.directory + '/' + basename
- self.logMsg('diag', '# Generating include file:', filename)
- with open(filename, 'w', encoding='utf-8') as fp:
- write(self.genOpts.conventions.warning_comment, file=fp)
-
- if contents:
- write('.%s' % title, file=fp)
- write('****', file=fp)
- write(contents, file=fp, end='')
- write('****', file=fp)
- write('', file=fp)
- else:
- self.logMsg('diag', '# No contents for:', filename)
-
- def writeInclude(self):
- "Generates the asciidoc include files."""
- self.writeBlock('parameters.txt',
- 'Externally Synchronized Parameters',
- self.threadsafety['parameters'])
- self.writeBlock('parameterlists.txt',
- 'Externally Synchronized Parameter Lists',
- self.threadsafety['parameterlists'])
- self.writeBlock('implicit.txt',
- 'Implicit Externally Synchronized Parameters',
- self.threadsafety['implicit'])
-
- def paramIsArray(self, param):
- """Check if the parameter passed in is a pointer to an array."""
- return param.get('len') is not None
-
- def paramIsPointer(self, param):
- """Check if the parameter passed in is a pointer."""
- tail = param.find('type').tail
- return tail is not None and '*' in tail
-
- def makeThreadSafetyBlocks(self, cmd, paramtext):
- # See also makeThreadSafetyBlock in validitygenerator.py - similar but not entirely identical
- protoname = cmd.find('proto/name').text
-
- # Find and add any parameters that are thread unsafe
- explicitexternsyncparams = cmd.findall(paramtext + "[@externsync]")
- if explicitexternsyncparams is not None:
- for param in explicitexternsyncparams:
- self.makeThreadSafetyForParam(protoname, param)
-
- # Find and add any "implicit" parameters that are thread unsafe
- implicitexternsyncparams = cmd.find('implicitexternsyncparams')
- if implicitexternsyncparams is not None:
- for elem in implicitexternsyncparams:
- entry = ValidityEntry()
- entry += elem.text
- entry += ' in '
- entry += self.makeFLink(protoname)
- self.threadsafety['implicit'] += entry
-
- # Add a VU for any command requiring host synchronization.
- # This could be further parameterized, if a future non-Vulkan API
- # requires it.
- if self.genOpts.conventions.is_externsync_command(protoname):
- entry = ValidityEntry()
- entry += 'The sname:VkCommandPool that pname:commandBuffer was allocated from, in '
- entry += self.makeFLink(protoname)
- self.threadsafety['implicit'] += entry
-
- def makeThreadSafetyForParam(self, protoname, param):
- """Create thread safety validity for a single param of a command."""
- externsyncattribs = ExternSyncEntry.parse_externsync_from_param(param)
- param_name = getElemName(param)
-
- for attrib in externsyncattribs:
- entry = ValidityEntry()
- is_array = False
- if attrib.entirely_extern_sync:
- # "true" or "true_with_children"
- if self.paramIsArray(param):
- entry += 'Each element of the '
- is_array = True
- elif self.paramIsPointer(param):
- entry += 'The object referenced by the '
- else:
- entry += 'The '
-
- entry += self.makeParameterName(param_name)
- entry += ' parameter'
-
- if attrib.children_extern_sync:
- entry += ', and any child handles,'
-
- else:
- # parameter/member reference
- readable = attrib.get_human_readable(make_param_name=self.makeParameterName)
- is_array = (' element of ' in readable)
- entry += readable
-
- entry += ' in '
- entry += self.makeFLink(protoname)
-
- if is_array:
- self.threadsafety['parameterlists'] += entry
- else:
- self.threadsafety['parameters'] += entry
-
- def genCmd(self, cmdinfo, name, alias):
- "Generate command."
- OutputGenerator.genCmd(self, cmdinfo, name, alias)
-
- # @@@ (Jon) something needs to be done here to handle aliases, probably
-
- self.makeThreadSafetyBlocks(cmdinfo.elem, 'param')
-
- self.writeInclude()
diff --git a/codegen/vulkan/scripts/htmldiff/htmldiff b/codegen/vulkan/scripts/htmldiff/htmldiff
deleted file mode 100755
index a3361c75..00000000
--- a/codegen/vulkan/scripts/htmldiff/htmldiff
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/usr/bin/env python3
-#
-# Modified from the htmldiff script developed by Dominique Hazael-Massieux
-# for the http://services.w3.org/htmldiff website.
-# License information found at https://github.com/w3c/htmldiff-ui/blob/master/LICENSE
-# for "htmldiffy.py".
-#
-# Copyright (c) 2008-2020 w3c
-# Copyright (c) 2016-2021, The Khronos Group Inc.
-# SPDX-License-Identifier: MIT
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-import atexit
-import os
-import re
-import sys
-import tempfile
-import tidy
-
-from subprocess import Popen, PIPE
-
-def tidyFile(filename):
- ifp = open(filename, 'r')
-
- # option for tidy
- options = dict(tidy_mark=0,show_warnings=0,quiet=1,char_encoding='utf8')
- html5 = re.search(r"<!doctype\s+html\s*>", ifp.read(4096),
- re.IGNORECASE)
- ifp.seek(0)
- html5_options = {'add_xml_space': 'no',
- 'output_xhtml': 'no',
- 'tidy_mark': 'no',
- 'new_blocklevel_tags': 'article,aside,canvas,dialog,details,figcaption,figure,footer,header,hgroup,menu,nav,section,main,summary,math,semantics,mrow,mfenced,mtable,mtr,mtd,mi,mn,msub,mo,mfrac,munderover,mtext,svg,g,image,rect,text,desc,line,path,polygon,ellipse,tspan,defs,feoffset,fecolormatrix,filter,fegaussianblur,feblend,marker,circle',
- 'new_inline_tags': 'video,audio,canvas,ruby,rt,rp,time,meter,progress,track,source,emu-val,emu-nt,emu-t,mark',
- 'break_before_br': 'no',
- 'vertical_space': 'no',
- 'enclose_text': 'no',
- 'numeric_entities': 'yes',
- 'wrap': '1000',
- 'wrap_attributes': 'no',
- 'drop_empty_paras': 'no'
- }
- if html5:
- options.update(html5_options)
- newtidy = tidy.parseString(ifp.read(), **options)
- if len(newtidy.errors) > 0:
- if not html5:
- ifp.seek(0)
- options.update(html5_options)
- newtidy = tidy.parseString(ifp.read(), **options)
- ifp.close()
-
- fp = tempfile.NamedTemporaryFile(
- mode='w+', prefix='htmldiff-', suffix='.html')
- atexit.register(fp.close)
- fp.write(str(newtidy))
- fp.flush()
- fp.seek(0)
-
- # sys.stderr.write('tidyFile: tempfile name %s\n' % fp.name)
-
- if (newtidy.errors):
- sys.stderr.write('tidyFile: tidy.parseString error: %s\n' % str(newtidy.errors))
- return fp
-
-def call_perl(args):
-
- scriptdir = os.path.abspath(os.path.dirname(sys.argv[0]))
- perlscript = os.path.join(scriptdir, 'htmldiff.pl')
- cmd = [perlscript]
- cmd.extend(args)
- p = Popen(cmd,
- text=True,
- stdin=PIPE, stdout=PIPE, stderr=PIPE)
- sys.stdout.flush()
- sys.stderr.flush()
- (out, err) = p.communicate()
- p.stdin.close()
- if err:
- print(out)
- sys.stderr.write('htmldiff: An error occurred when running htmldiff.pl on the documents: %s\n'% str(err))
- exit(1)
- else:
- print(out)
- exit(0)
-
-def usage():
- # didn't investigate fully what -c does - something about mhtml comments?
- sys.stderr.write("""htmldiff: need two filename args file1 file2
-
-May also pass arguments:
- -l Make diff highlights links that jump to the following diff
- -t Add a script to optionally hide old text via button
- -o Complete omit old text
- -h show this text
-""")
- sys.exit(1)
-
-if __name__ == '__main__':
-
- docs = []
- passthru_args = []
- for arg in sys.argv[1:]:
- if arg in ('-c', '-l', '-t', '-o'):
- passthru_args.append(arg)
- elif arg == '-h':
- usage()
- else:
- docs.append(arg)
-
- if (len(docs) != 2):
- usage()
- refdoc = tidyFile(docs[0])
-
- newdoc = tidyFile(docs[1])
- passthru_args.append(refdoc.name)
- passthru_args.append(newdoc.name)
- call_perl(passthru_args)
diff --git a/codegen/vulkan/scripts/htmldiff/htmldiff.pl b/codegen/vulkan/scripts/htmldiff/htmldiff.pl
deleted file mode 100755
index af2a6cd2..00000000
--- a/codegen/vulkan/scripts/htmldiff/htmldiff.pl
+++ /dev/null
@@ -1,581 +0,0 @@
-#!/usr/bin/perl
-#
-# htmldiff - present a diff marked version of two html documents
-#
-# Copyright (c) 1998-2006 MACS, Inc.
-#
-# Copyright (c) 2007 SiSco, Inc.
-#
-# SPDX-License-Identifier: MIT
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-# See http://www.themacs.com for more information.
-#
-# usage: htmldiff [[-c] [-l] [-o] oldversion newversion [output]]
-#
-# -c - disable metahtml comment processing
-# -o - disable outputting of old text
-# -l - use navindex to create sequence of diffs
-# oldversion - the previous version of the document
-# newversion - the newer version of the document
-# output - a filename to place the output in. If omitted, the output goes to
-# standard output.
-#
-# if invoked with no options or arguments, operates as a CGI script. It then
-# takes the following parameters:
-#
-# oldfile - the URL of the original file
-# newfile - the URL of the new file
-# mhtml - a flag to indicate whether it should be aware of MetaHTML comments.
-#
-# requires GNU diff utility
-# also requires the perl modules Getopt::Std
-#
-# NOTE: The markup created by htmldiff may not validate against the HTML 4.0
-# DTD. This is because the algorithm is realtively simple, and there are
-# places in the markup content model where the span element is not allowed.
-# Htmldiff is NOT aware of these places.
-#
-# $Source: /u/sources/public/2009/htmldiff/htmldiff.pl,v $
-# $Revision: 1.3 $
-#
-# $Log: htmldiff.pl,v $
-# Revision 1.3 2016/10/24 15:06:51 dom
-# Summary: Use nav script always
-#
-# Revision 1.2 2016/10/24 15:04:28 dom
-# Add navigation script
-#
-# Revision 1.1 2014-01-06 08:04:51 dom
-# added copy of htmldiff perl script since aptest.com repo no longer available
-#
-# Revision 1.5 2008/03/05 13:23:16 ahby
-# Fixed a problem with leading whitespace before markup.
-#
-# Revision 1.4 2007/12/13 13:09:16 ahby
-# Updated copyright and license.
-#
-# Revision 1.3 2007/12/13 12:53:34 ahby
-# Changed use of span to ins and del
-#
-# Revision 1.2 2002/02/13 16:27:23 ahby
-# Changed processing model.
-# Improved handling of old text and changed styles.
-#
-# Revision 1.1 2000/07/12 12:20:04 ahby
-# Updated to remove empty spans - this fixes validation problems under
-# strict.
-#
-# Revision 1.11 1999/12/08 19:46:45 ahby
-# Fixed validation errors introduced by placing markup where it didn't
-# belong.
-#
-# Revision 1.10 1999/10/18 13:42:58 ahby
-# Added -o to the usage message.
-#
-# Revision 1.9 1999/05/04 12:29:11 ahby
-# Added an option to turn off the display of old text.
-#
-# Revision 1.8 1999/04/09 14:37:27 ahby
-# Fixed a perl syntax error.
-#
-# Revision 1.7 1999/04/09 14:35:49 ahby
-# Added reference to MACS homepage.
-#
-# Revision 1.6 1999/04/09 14:35:09 ahby
-# Added comment about validity of generated markup.
-#
-# Revision 1.5 1999/02/22 22:17:54 ahby
-# Changed to use stylesheets.
-# Changed to rely upon span.
-# Changed to work around content model problems.
-#
-# Revision 1.4 1999/02/08 02:32:22 ahby
-# Added a copyright statement.
-#
-# Revision 1.3 1999/02/08 02:30:40 ahby
-# Added header processing.
-#
-# Revision 1.2 1998/12/10 17:31:31 ahby
-# Fixed to escape less-thans in change blocks and to not permit change
-# markup within specific elements (like TITLE).
-#
-# Revision 1.1 1998/11/26 00:09:22 ahby
-# Initial revision
-#
-#
-
-use Getopt::Std;
-
-sub usage {
- print STDERR "htmldiff [-c] [-o] oldversion newversion [output]\n";
- exit;
-}
-
-sub url_encode {
- my $str = shift;
- $str =~ s/([\x00-\x1f\x7F-\xFF])/
- sprintf ('%%%02x', ord ($1))/eg;
- return $str;
-}
-
-# markit - diff-mark the streams
-#
-# markit(file1, file2)
-#
-# markit relies upon GNUdiff to mark up the text.
-#
-# The markup is encoded using special control sequences:
-#
-# a block wrapped in control-a is deleted text
-# a block wrapped in control-b is old text
-# a block wrapped in control-c is new text
-#
-# The main processing loop attempts to wrap the text blocks in appropriate
-# SPANs based upon the type of text that it is.
-#
-# When the loop encounters a < in the text, it stops the span. Then it outputs
-# the element that is defined, then it restarts the span.
-
-sub markit {
- my $retval = "";
- my($file1) = shift;
- my($file2) = shift;
-# my $old="<span class=\\\"diff-old-a\\\">deleted text: </span>%c'\012'%c'\001'%c'\012'%<%c'\012'%c'\001'%c'\012'";
- my $old="%c'\012'%c'\001'%c'\012'%<%c'\012'%c'\001'%c'\012'";
- my $new="%c'\012'%c'\003'%c'\012'%>%c'\012'%c'\003'%c'\012'";
- my $unchanged="%=";
- my $changed="%c'\012'%c'\001'%c'\012'%<%c'\012'%c'\001'%c'\012'%c'\004'%c'\012'%>%c'\012'%c'\004'%c'\012'";
- if ($opt_o) {
- $old = "";
- $changed = "%c'\012'%c'\004'%c'\012'%>%c'\012'%c'\004'%c'\012'";
- }
-# my $old="%c'\002'<font color=\\\"purple\\\" size=\\\"-2\\\">deleted text:</font><s>%c'\012'%c'\001'%c'\012'%<%c'\012'%c'\001'%c'\012'</s>%c'\012'%c'\002'";
-# my $new="%c'\002'<font color=\\\"purple\\\"><u>%c'\012'%c'\002'%>%c'\002'</u></font>%c'\002'%c'\012'";
-# my $unchanged="%=";
-# my $changed="%c'\002'<s>%c'\012'%c'\001'%c'\012'%<%c'\012'%c'\001'%c'\012'</s><font color=\\\"purple\\\"><u>%c'\002'%c'\012'%>%c'\012'%c'\002'</u></font>%c'\002'%c'\012'";
-
- my @span;
- $span[0]="</span>";
- $span[1]="<del class=\"diff-old\">";
- $span[2]="<del class=\"diff-old\">";
- $span[3]="<ins class=\"diff-new\">";
- $span[4]="<ins class=\"diff-chg\">";
-
- my @diffEnd ;
- $diffEnd[1] = '</del>';
- $diffEnd[2] = '</del>';
- $diffEnd[3] = '</ins>';
- $diffEnd[4] = '</ins>';
-
- my $diffcounter = 0;
-
- open(FILE, qq(diff -d --old-group-format="$old" --new-group-format="$new" --changed-group-format="$changed" --unchanged-group-format="$unchanged" $file1 $file2 |)) || die("Diff failed: $!");
-# system (qq(diff --old-group-format="$old" --new-group-format="$new" --changed-group-format="$changed" --unchanged-group-format="$unchanged" $file1 $file2 > /tmp/output));
-
- my $state = 0;
- my $inblock = 0;
- my $temp = "";
- my $lineCount = 0;
-
-# strategy:
-#
-# process the output of diff...
-#
-# a link with control A-D means the start/end of the corresponding ordinal
-# state (1-4). Resting state is state 0.
-#
-# While in a state, accumulate the contents for that state. When exiting the
-# state, determine if it is appropriate to emit the contents with markup or
-# not (basically, if the accumulated buffer contains only empty lines or lines
-# with markup, then we don't want to emit the wrappers. We don't need them.
-#
-# Note that if there is markup in the "old" block, that markup is silently
-# removed. It isn't really that interesting, and it messes up the output
-# something fierce.
-
- while (<FILE>) {
- my $nextCounter = $diffcounter + 1;
- my $anchor = $opt_l ? qq[<a tabindex="$diffcounter" id="diff-$diffcounter" href="#diff-$nextCounter">] : "" ;
- my $anchorEnd = $opt_l ? q[</a>] : "" ;
- $lineCount ++;
- if ($state == 0) { # if we are resting and we find a marker,
- # then we must be entering a block
- if (m/^([\001-\004])/) {
- $state = ord($1);
- $_ = "";
- }
-# if (m/^\001/) {
-# $state = 1;
-# s/^/$span[1]/;
-# } elsif (m/^\002/) {
-# $state = 2;
-# s/^/$span[2]/;
-# } elsif (m/^\003/) {
-# $state = 3;
-# s/^/$span[3]/;
-# } elsif (m/^\004/) {
-# $state = 4;
-# s/^/$span[4]/;
-# }
- } else {
- # if we are in "old" state, remove markup
- if (($state == 1) || ($state == 2)) {
- s/\<.*\>//; # get rid of any old markup
- s/\</&lt;/g; # escape any remaining STAG or ETAGs
- s/\>/&gt;/g;
- }
- # if we found another marker, we must be exiting the state
- if (m/^([\001-\004])/) {
- if ($temp ne "") {
- $_ = $span[$state] . $anchor . $temp . $anchorEnd . $diffEnd[$state] . "\n";
- $temp = "";
- $diffcounter++;
- } else {
- $_ = "" ;
- }
- $state = 0;
- } elsif (m/^\s*\</) { # otherwise, is this line markup?
- # if it is markup AND we haven't seen anything else yet,
- # then we will emit the markup
- if ($temp eq "") {
- $retval .= $_;
- $_ = "";
- } else { # we wrap it with the state switches and hold it
- s/^/$anchorEnd$diffEnd[$state]/;
- s/$/$span[$state]$anchor/;
- $temp .= $_;
- $_ = "";
- $diffcounter++;
- }
- } else {
- if (m/.+/) {
- $temp .= $_;
- $_ = "";
- }
- }
- }
-
- s/\001//g;
- s/\002//g;
- s/\003//g;
- s/\004//g;
- if ($_ !~ m/^$/) {
- $retval .= $_;
- }
- }
- close FILE;
- $retval =~ s/$span[1]\n+$diffEnd[1]//g;
- $retval =~ s/$span[2]\n+$diffEnd[2]//g;
- $retval =~ s/$span[3]\n+$diffEnd[3]//g;
- $retval =~ s/$span[4]\n+$diffEnd[4]//g;
- $retval =~ s/$span[1]\n*$//g;
- $retval =~ s/$span[2]\n*$//g;
- $retval =~ s/$span[3]\n*$//g;
- $retval =~ s/$span[4]\n*$//g;
- return $retval;
-}
-
-sub splitit {
- my $filename = shift;
- my $headertmp = shift;
- my $inheader=0;
- my $preformatted=0;
- my $inelement=0;
- my $retval = "";
- my $styles = q(<style type='text/css'>
-.diff-old-a {
- font-size: smaller;
- color: red;
-}
-.diff-new a { text-decoration: none; }
-.diff-new { background-color: yellow; }
-.diff-chg { background-color: lime; }
-.diff-chg a { text-decoration: none; }
-.diff-new:before,
-.diff-new:after
- { content: "\2191" }
-.diff-chg:before, .diff-chg:after
- { content: "\2195" }
-.diff-old { text-decoration: line-through; background-color: #FBB; }
-.diff-old:before,
-.diff-old:after
- { content: "\2193" }
-.diff-old a { text-decoration: none; }
-:focus { border: thin red solid}
-</style>
-<script src="https://www.w3.org/2016/10/htmldiff-nav.js"></script>);
- if ($opt_t) {
- $styles .= q(
-<script type="text/javascript">
-<!--
-function setOldDisplay() {
- for ( var s = 0; s < document.styleSheets.length; s++ ) {
- var css = document.styleSheets[s];
- var mydata ;
- try { mydata = css.cssRules ;
- if ( ! mydata ) mydata = css.rules;
- for ( var r = 0; r < mydata.length; r++ ) {
- if ( mydata[r].selectorText == '.diff-old' ) {
- mydata[r].style.display = ( mydata[r].style.display == '' ) ? 'none'
-: '';
- return;
- }
- }
- } catch(e) {} ;
- }
-}
--->
-</script>
-);
-
- }
-
- if ($stripheader) {
- open(HEADER, ">$headertmp");
- }
-
- my $incomment = 0;
- my $inhead = 1;
- open(FILE, $filename) || die("File $filename cannot be opened: $!");
- while (<FILE>) {
- if ($inhead == 1) {
- if (m/\<\/head/i) {
- print HEADER $styles;
- }
- if (m/\<body/i) {
- $inhead = 0;
- print HEADER;
- if ($opt_t) {
- print HEADER q(
-<form action=""><input type="button" onclick="setOldDisplay()" value="Show/Hide Old Content" /></form>
-);
- }
- if ($opt_l) {
- print HEADER q(
- <p><em>NOTE: Click highlighted diff text to jump to the following difference.</em></p>
- );
- }
- close HEADER;
- } else {
- print HEADER;
- }
- } else {
- if ($incomment) {
- if (m;-->;) {
- $incomment = 0;
- s/.*-->//;
- } else {
- next;
- }
- }
- if (m;<!--;) {
- while (m;<!--.*-->;) {
- s/<!--.*?-->//;
- }
- if (m;<!--; ) {
- $incomment = 1;
- s/<!--.*//;
- }
- }
- if (m/\<pre/i) {
- $preformatted = 1;
- }
- if (m/\<\/pre\>/i) {
- $preformatted = 0;
- }
- if ($preformatted) {
- $retval .= $_;
- } elsif ($mhtmlcomments && /^;;;/) {
- $retval .= $_;
- } else {
- my @list = split(' ');
- foreach $element (@list) {
- if ($element =~ m/\<H[1-6]/i) {
-# $inheader = 1;
- }
- if ($inheader == 0) {
- $element =~ s/</\n</g;
- $element =~ s/^\n//;
- $element =~ s/>/>\n/g;
- $element =~ s/\n$//;
- $element =~ s/>\n([.,:!]+)/>$1/g;
- }
- if ($element =~ m/\<\/H[1-6]\>/i) {
- $inheader = 0;
- }
- $retval .= "$element";
- $inelement += ($element =~ s/</&lt;/g);
- $inelement -= ($element =~ s/>/&gt;/g);
- if ($inelement < 0) {
- $inelement = 0;
- }
- if (($inelement == 0) && ($inheader == 0)) {
- $retval .= "\n";
- } else {
- $retval .= " ";
- }
- }
- undef @list;
- }
- }
- }
- $retval .= "\n";
- close FILE;
- return $retval;
-}
-
-$mhtmlcomments = 1;
-
-sub cli {
- getopts("clto") || usage();
-
- if ($opt_c) {$mhtmlcomments = 0;}
-
- if (@ARGV < 2) { usage(); }
-
- $file1 = $ARGV[0];
- $file2 = $ARGV[1];
- $file3 = $ARGV[2];
-
- $tmp = splitit($file1, $headertmp1);
- open (FILE, ">$tmp1");
- print FILE $tmp;
- close FILE;
-
- $tmp = splitit($file2, $headertmp2);
- open (FILE, ">$tmp2");
- print FILE $tmp;
- close FILE;
-
- $output = "";
-
- if ($stripheader) {
- open(FILE, $headertmp2);
- while (<FILE>) {
- $output .= $_;
- }
- close(FILE);
- }
-
- $output .= markit($tmp1, $tmp2);
-
- if ($file3) {
- open(FILE, ">$file3");
- print FILE $output;
- close FILE;
- } else {
- print $output;
- }
-}
-
-sub cgi {
-# use LWP::UserAgent;
-# use CGI;
-
- my $query = new CGI;
- my $url1 = $query->param("oldfile");
- my $url2 = $query->param("newfile");
- my $mhtml = $query->param("mhtml");
-
- my $file1 = "/tmp/htdcgi1.$$";
- my $file2 = "/tmp/htdcgi2.$$";
-
- my $ua = new LWP::UserAgent;
- $ua->agent("MACS, Inc. HTMLdiff/0.9 " . $ua->agent);
-
- # Create a request
-
- my $req1 = new HTTP::Request GET => $url1;
-
- my $res1 = $ua->request($req1, $file1);
- if ($res1->is_error) {
- print $res1->error_as_HTML();
- print "<p>The URL $url1 could not be found. Please check it and try again.</p>";
- return;
- }
-
- my $req2 = new HTTP::Request GET => $url2;
-
- my $res2 = $ua->request($req2, $file2);
- if ($res2->is_error) {
- print $res2->error_as_HTML();
- print "<p>The URL $url2 could not be found. Please check it and try again.</p>";
- return;
- }
-
- $split1 = splitit($file1, $headertmp1);
- open (FILE, ">$tmp1");
- print FILE $split1;
- close FILE;
-
- $split2 = splitit($file2, $headertmp2);
- open (FILE, ">$tmp2");
- print FILE $split2;
- close FILE;
-
- $output = "";
-
- if ($stripheader) {
- open(FILE, $headertmp2);
- while (<FILE>) {
- $output .= $_;
- }
- close(FILE);
- }
-
- $output .= markit($tmp1, $tmp2);
-
- my $base=$res2->base;
-
- if ($base !~ /\/$/) {
- $base =~ s/[^\/]*$//;
- }
-
- if ( $output !~ /<base/i ) {
- $output =~ s/<head>/<head>\n<base href="$base">/i ||
- $output =~ s/<html>/<html>\n<base href="$base">/i ;
- }
-
- print $query->header(-type=>'text/html',-nph=>1);
- print $output;
-
- unlink $file1;
- unlink $file2;
-
-}
-
-$tmp1="/tmp/htdtmp1.$$";
-$headertmp1="/tmp/htdhtmp1.$$";
-$tmp2="/tmp/htdtmp2.$$";
-$headertmp2="/tmp/htdhtmp2.$$";
-$stripheader = 1;
-
-if (@ARGV == 0) {
- cgi(); # if no arguments, we must be operating as a cgi script
-} else {
- cli(); # if there are arguments, then we are operating as a CLI
-}
-
-unlink $tmp1;
-unlink $headertmp1;
-unlink $tmp2;
-unlink $headertmp2;
diff --git a/codegen/vulkan/scripts/indexExt.py b/codegen/vulkan/scripts/indexExt.py
deleted file mode 100755
index 4eeb4f3b..00000000
--- a/codegen/vulkan/scripts/indexExt.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2017-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# Construct an HTML fragment indexing extension appendices in vkspec.html.
-# This is run only when publishing an update spec, to update the Vulkan
-# registry.
-
-import argparse,io,os,re,string,sys,copy
-import xml.etree.ElementTree as etree
-
-def listExts(vendor, ext, tag):
- prefix = ' <li> <b> '
- suffix = ' </b> </li>'
-
- if vendor in tag:
- desc = vendor + ' Extensions (' + tag[vendor] + ')'
- else:
- desc = vendor + ' Extensions (full vendor description unavailable)'
- print(prefix, desc, suffix)
-
- # (OLD) Links to the extension appendix in the single-page HTML document.
- # This is very slow to load.
- # fmtString = ' <li> <a href="specs/1.2-extensions/html/vkspec.html#{0}"> {0} </a> </li>'
-
- # This links to the individual per-extension refpages, which are a
- # slightly modified version of the extension appendices, and far faster
- # to load.
- fmtString = ' <li> <a href="specs/1.2-extensions/man/html/{0}.html"> {0} </a> </li>'
-
- for name in sorted(ext[vendor]):
- print(fmtString.format(name))
-
-# -extension name - may be a single extension name, a a space-separated list
-# of names, or a regular expression.
-if __name__ == '__main__':
- parser = argparse.ArgumentParser()
-
- parser.add_argument('-registry', action='store',
- default='vk.xml',
- help='Use specified registry file instead of vk.xml')
- parser.add_argument('-quiet', action='store_true', default=False,
- help='Suppress script output during normal execution.')
-
- args = parser.parse_args()
-
- tree = etree.parse(args.registry)
-
- # Dictionary of vendor tags -> author name mappings
- tag = {}
-
- # Loop over all vendor tags, tracking the full corresponding author name
- for elem in tree.findall('tags/tag'):
- vendor = elem.get('name')
- author = elem.get('author')
-
- tag[vendor] = author
-
- # Dictionary of supported extensions, indexed by vendor prefix
- ext = {}
-
- # Loop over all extensions, add supported names to the dictionary
- for elem in tree.findall('extensions/extension'):
- name = elem.get('name')
- supported = elem.get('supported')
-
- if supported == 'vulkan':
- # Relies on name being in the form VK_<vendor>_stuff
- (vk, vendor) = name.split('_')[0:2]
-
- if not vendor in ext:
- ext[vendor] = []
- ext[vendor].append(name)
-
- # Emit HTML fragment indexing the extensions
-
- print('<ul>')
-
- for vendor in ['KHR', 'EXT']:
- if vendor in ext:
- listExts(vendor, ext, tag)
- del ext[vendor]
-
- for vendor in sorted(ext.keys()):
- listExts(vendor, ext, tag)
- del ext[vendor]
-
- print('</ul>')
diff --git a/codegen/vulkan/scripts/interfacedocgenerator.py b/codegen/vulkan/scripts/interfacedocgenerator.py
deleted file mode 100644
index 05fafbc0..00000000
--- a/codegen/vulkan/scripts/interfacedocgenerator.py
+++ /dev/null
@@ -1,118 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-import re
-from generator import OutputGenerator, write
-
-def interfaceDocSortKey(item):
- if item == None:
- return '\0'
- else:
- return item.casefold()
-
-class InterfaceDocGenerator(OutputGenerator):
- """InterfaceDocGenerator - subclass of OutputGenerator.
- Generates AsciiDoc includes of the interfaces added by a an API version
- or extension."""
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.features = []
-
- def beginFile(self, genOpts):
- OutputGenerator.beginFile(self, genOpts)
-
- # Create subdirectory, if needed
- self.makeDir(self.genOpts.directory)
-
- def beginFeature(self, interface, emit):
- # Start processing in superclass
- OutputGenerator.beginFeature(self, interface, emit)
-
- self.features.append( self.featureName )
-
- def endFeature(self):
- # Finish processing in superclass
- OutputGenerator.endFeature(self)
-
- def writeNewInterfaces(self, feature, key, title, markup, fp):
- dict = self.featureDictionary[feature][key]
-
- parentmarkup = markup
- if key == 'enumconstant':
- parentmarkup = 'elink:'
-
- if dict:
- write('=== ' + title, file=fp)
- write('',file=fp)
-
- # Loop through required blocks, sorted so they start with "core" features
- for required in sorted(dict, key = interfaceDocSortKey):
- if required is not None:
- requiredlink = 'apiext:' + required
- match = re.search("[A-Z]+_VERSION_([0-9]+)_([0-9]+)",required)
- if match is not None:
- major = match.group(1)
- minor = match.group(2)
- version = major + '.' + minor
- requiredlink = '<<versions-' + version + ', Version ' + version + '>>'
-
- write('ifdef::' + required + '[]', file=fp)
- write('If ' + requiredlink + ' is supported:', file=fp)
- write('',file=fp)
-
- # Commands are relatively straightforward
- if key == 'command':
- for api in sorted(dict[required]):
- write(' * ' + markup + api, file=fp)
- # Types and constants are potentially parented, so need to handle that
- else:
- # Loop through parents, sorted so they start with unparented items
- for parent in sorted(dict[required], key = interfaceDocSortKey):
- parentstring = ''
- if parent:
- parentstring = parentmarkup + (', ' + markup).join(parent.split(','))
- write(' * Extending ' + parentstring + ':', file=fp)
- for api in sorted(dict[required][parent]):
- write(' ** ' + markup + api, file=fp)
- else:
- for api in sorted(dict[required][parent]):
- write(' * ' + markup + api, file=fp)
-
- if required is not None:
- write('endif::' + required + '[]', file=fp)
- write('',file=fp)
-
- def makeInterfaceFile(self, feature):
- """Generate a file containing feature interface documentation in
- asciidoctor markup form.
-
- - feature - name of the feature being generated"""
-
- filename = feature + self.genOpts.conventions.file_suffix
- fp = open(self.genOpts.directory + '/' + filename, 'w', encoding='utf-8')
-
- # Write out the lists of new interfaces added by the feature
- self.writeNewInterfaces(feature, 'define', 'New Macros', 'dlink:', fp)
- self.writeNewInterfaces(feature, 'basetype', 'New Base Types', 'basetype:',fp)
- self.writeNewInterfaces(feature, 'handle', 'New Object Types', 'slink:', fp)
- self.writeNewInterfaces(feature, 'command', 'New Commands', 'flink:', fp)
- self.writeNewInterfaces(feature, 'struct', 'New Structures', 'slink:', fp)
- self.writeNewInterfaces(feature, 'union', 'New Unions', 'slink:', fp)
- self.writeNewInterfaces(feature, 'funcpointer', 'New Function Pointers','tlink:', fp)
- self.writeNewInterfaces(feature, 'enum', 'New Enums', 'elink:', fp)
- self.writeNewInterfaces(feature, 'bitmask', 'New Bitmasks', 'tlink:', fp)
- self.writeNewInterfaces(feature, 'include', 'New Headers', 'code:', fp)
- self.writeNewInterfaces(feature, 'enumconstant','New Enum Constants', 'ename:', fp)
-
- fp.close()
-
- def endFile(self):
- # Generate metadoc feature files, in refpage and non-refpage form
- for feature in self.features:
- self.makeInterfaceFile(feature)
-
- OutputGenerator.endFile(self)
diff --git a/codegen/vulkan/scripts/linkcheck.py b/codegen/vulkan/scripts/linkcheck.py
deleted file mode 100755
index 252112b0..00000000
--- a/codegen/vulkan/scripts/linkcheck.py
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/usr/bin/python3
-# Copyright 2013-2021 The Khronos Group Inc.
-# SPDX-License-Identifier: Apache-2.0
-
-# linkcheck - check internal links of the specified HTML file against
-# internal anchors and report inconsistencies.
-#
-# Usage: linkcheck file.html
-
-import argparse
-from lxml import etree as et
-
-def printSet(s):
- for key in sorted(s):
- print(' {}'.format(key))
-
-def checkLinks(file, args):
- parser = et.HTMLParser()
- tree = et.parse(file, parser)
-
- # Remove all <svg> elements, which just add noise to the cross-referencing
- for svg in tree.findall('//svg'):
- svg.getparent().remove(svg)
-
- # Extract elements with href= and id= attributes
- hrefs = tree.findall('//*[@href]')
- ids = tree.findall('//*[@id]')
-
- # Extract xref name from each xref
- internals = set()
- externals = set()
-
- for e in hrefs:
- # Don't track '<link>' tags from HTML headers
- if e.tag != 'link':
- xref = e.get('href')
-
- if xref[0:1] == '#':
- # Internal anchor
- internals.add(xref[1:])
- else:
- externals.add(xref)
-
- # Extract anchor name from each id
- anchors = set()
-
- for e in ids:
- # Don't track SVG '<g>' tags
- if e.tag != 'g':
- anchors.add(e.get('id'))
-
- # Intersect them to find inconsistencies
- xrefsOnly = internals.difference(anchors)
- anchorsOnly = anchors.difference(internals)
-
- # print('External xrefs:', len(externals))
- # printSet(externals)
- #
- # print('Internal xrefs:', len(internals))
- # print('Anchors: ', len(anchors))
-
- print('Internal xrefs not in anchors:', len(xrefsOnly))
- printSet(xrefsOnly)
-
- if args.anchors:
- print('Internal anchors not in xrefs:', len(anchorsOnly))
- printSet(anchorsOnly)
-
-# Patterns used to recognize interesting lines in an asciidoc source file.
-# These patterns are only compiled once.
-
-if __name__ == '__main__':
- parser = argparse.ArgumentParser()
-
- parser.add_argument('files', metavar='filename', nargs='*',
- help='a filename to promote text in')
- parser.add_argument('-anchors', action='store_true',
- help='Report orphaned anchors')
-
-
- args = parser.parse_args()
-
- for file in args.files:
- checkLinks(file, args)
diff --git a/codegen/vulkan/scripts/make_ext_dependency.py b/codegen/vulkan/scripts/make_ext_dependency.py
deleted file mode 100755
index 51571286..00000000
--- a/codegen/vulkan/scripts/make_ext_dependency.py
+++ /dev/null
@@ -1,243 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2017-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-"""Generate a mapping of extension name -> all required extension names for that extension.
-
-This script generates a list of all extensions, and of just KHR
-extensions, that are placed into a Bash script and/or Python script. This
-script can then be sources or executed to set a variable (e.g. khrExts),
-Frontend scripts such as 'makeAllExts' and 'makeKHR' use this information
-to set the EXTENSIONS Makefile variable when building the spec.
-
-Sample Usage:
-
-python3 scripts/make_ext_dependency.py -outscript=temp.sh
-source temp.sh
-make EXTENSIONS="$khrExts" html
-rm temp.sh
-"""
-
-import argparse
-import errno
-import xml.etree.ElementTree as etree
-from pathlib import Path
-
-from vkconventions import VulkanConventions as APIConventions
-
-
-def enQuote(key):
- return "'" + str(key) + "'"
-
-
-def shList(names):
- """Return a sortable (list or set) of names as a string encoding
- of a Bash or Python list, sorted on the names."""
- s = ('"' +
- ' '.join(str(key) for key in sorted(names)) +
- '"')
- return s
-
-
-def pyList(names):
- if names is not None:
- return ('[ ' +
- ', '.join(enQuote(key) for key in sorted(names)) +
- ' ]')
- else:
- return '[ ]'
-
-class DiGraph:
- """A directed graph.
-
- The implementation and API mimic that of networkx.DiGraph in networkx-1.11.
- networkx implements graphs as nested dicts; it's dicts all the way down, no
- lists.
-
- Some major differences between this implementation and that of
- networkx-1.11 are:
-
- * This omits edge and node attribute data, because we never use them
- yet they add additional code complexity.
-
- * This returns iterator objects when possible instead of collection
- objects, because it simplifies the implementation and should provide
- better performance.
- """
-
- def __init__(self):
- self.__nodes = {}
-
- def add_node(self, node):
- if node not in self.__nodes:
- self.__nodes[node] = DiGraphNode()
-
- def add_edge(self, src, dest):
- self.add_node(src)
- self.add_node(dest)
- self.__nodes[src].adj.add(dest)
-
- def nodes(self):
- """Iterate over the nodes in the graph."""
- return self.__nodes.keys()
-
- def descendants(self, node):
- """
- Iterate over the nodes reachable from the given start node, excluding
- the start node itself. Each node in the graph is yielded at most once.
- """
-
- # Implementation detail: Do a breadth-first traversal because it's
- # easier than depth-first.
-
- # All nodes seen during traversal.
- seen = set()
-
- # The stack of nodes that need visiting.
- visit_me = []
-
- # Bootstrap the traversal.
- seen.add(node)
- for x in self.__nodes[node].adj:
- if x not in seen:
- seen.add(x)
- visit_me.append(x)
-
- while visit_me:
- x = visit_me.pop()
- assert x in seen
- yield x
-
- for y in self.__nodes[x].adj:
- if y not in seen:
- seen.add(y)
- visit_me.append(y)
-
-
-class DiGraphNode:
-
- def __init__(self):
- # Set of adjacent of nodes.
- self.adj = set()
-
-
-def make_dir(fn):
- outdir = Path(fn).parent
- try:
- outdir.mkdir(parents=True)
- except OSError as e:
- if e.errno != errno.EEXIST:
- raise
-
-
-# API conventions object
-conventions = APIConventions()
-
-# -extension name - may be a single extension name, a space-separated list
-# of names, or a regular expression.
-if __name__ == '__main__':
- parser = argparse.ArgumentParser()
-
- parser.add_argument('-registry', action='store',
- default=conventions.registry_path,
- help='Use specified registry file instead of ' + conventions.registry_path)
- parser.add_argument('-outscript', action='store',
- default=None,
- help='Shell script to create')
- parser.add_argument('-outpy', action='store',
- default=None,
- help='Python script to create')
- parser.add_argument('-test', action='store',
- default=None,
- help='Specify extension to find dependencies of')
- parser.add_argument('-quiet', action='store_true', default=False,
- help='Suppress script output during normal execution.')
-
- args = parser.parse_args()
-
- tree = etree.parse(args.registry)
-
- # Loop over all supported extensions, creating a digraph of the
- # extension dependencies in the 'requires' attribute, which is a
- # comma-separated list of extension names. Also track lists of
- # all extensions and all KHR extensions.
-
- allExts = set()
- khrExts = set()
- g = DiGraph()
-
- for elem in tree.findall('extensions/extension'):
- name = elem.get('name')
- supported = elem.get('supported')
-
- # This works for the present form of the 'supported' attribute,
- # which is a comma-separate list of XML API names
- if conventions.xml_api_name in supported.split(','):
- allExts.add(name)
-
- if 'KHR' in name:
- khrExts.add(name)
-
- deps = elem.get('requires')
- if deps:
- deps = deps.split(',')
-
- for dep in deps:
- g.add_edge(name, dep)
- else:
- g.add_node(name)
- else:
- # Skip unsupported extensions
- pass
-
- if args.outscript:
- make_dir(args.outscript)
- fp = open(args.outscript, 'w', encoding='utf-8')
-
- print('#!/bin/bash', file=fp)
- print('# Generated from make_ext_dependency.py', file=fp)
- print('# Specify maps of all extensions required by an enabled extension', file=fp)
- print('', file=fp)
- print('declare -A extensions', file=fp)
-
- # When printing lists of extensions, sort them so that the output script
- # remains as stable as possible as extensions are added to the API XML.
-
- for ext in sorted(g.nodes()):
- children = list(g.descendants(ext))
-
- # Only emit an ifdef block if an extension has dependencies
- if children:
- print('extensions[' + ext + ']=' + shList(children), file=fp)
-
- print('', file=fp)
- print('# Define lists of all extensions and KHR extensions', file=fp)
- print('allExts=' + shList(allExts), file=fp)
- print('khrExts=' + shList(khrExts), file=fp)
-
- fp.close()
-
- if args.outpy:
- make_dir(args.outpy)
- fp = open(args.outpy, 'w', encoding='utf-8')
-
- print('#!/usr/bin/env python', file=fp)
- print('# Generated from make_ext_dependency.py', file=fp)
- print('# Specify maps of all extensions required by an enabled extension', file=fp)
- print('', file=fp)
- print('extensions = {}', file=fp)
-
- # When printing lists of extensions, sort them so that the output script
- # remains as stable as possible as extensions are added to the API XML.
-
- for ext in sorted(g.nodes()):
- children = list(g.descendants(ext))
- print("extensions['" + ext + "'] = " + pyList(children), file=fp)
-
- print('', file=fp)
- print('# Define lists of all extensions and KHR extensions', file=fp)
- print('allExts = ' + pyList(allExts), file=fp)
- print('khrExts = ' + pyList(khrExts), file=fp)
-
- fp.close()
diff --git a/codegen/vulkan/scripts/makemanaliases.py b/codegen/vulkan/scripts/makemanaliases.py
deleted file mode 100755
index df44a8a9..00000000
--- a/codegen/vulkan/scripts/makemanaliases.py
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2020-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-"""Script to create symbolic links for aliases in reference pages
- Usage: makemanaliases.py -refdir refpage-output-directory"""
-
-import argparse
-import os
-import sys
-
-if __name__ == '__main__':
- parser = argparse.ArgumentParser()
-
- parser.add_argument('-genpath', action='store',
- default=None,
- help='Path to directory containing generated *api.py module')
- parser.add_argument('-refdir', action='store',
- required=True,
- help='Path to directory containing reference pages to symlink')
-
- args = parser.parse_args()
-
- # Look for api.py in the specified directory
- if args.genpath is not None:
- sys.path.insert(0, args.genpath)
- import api
-
- # Change to refpage directory
- try:
- os.chdir(args.refdir)
- except:
- print('Cannot chdir to', args.refdir, file=sys.stderr)
- sys.exit(1)
-
- # For each alias in the API alias map, create a symlink if it
- # doesn't exist - and warn if it does exist.
-
- for key in api.alias:
- alias = key + '.html'
- src = api.alias[key] + '.html'
-
- if not os.access(src, os.R_OK):
- # This shouldn't happen, but is possible if the api module isn't
- # generated for the same set of APIs as were the refpages.
- print('No source file', src, file=sys.stderr)
- continue
-
- if os.access(alias, os.R_OK):
- # If the link already exists, that's not necc. a problem, so
- # don't fail, but it should be checked out
- print('Unexpected alias file "' + alias + '" exists, skipping',
- file=sys.stderr)
- else:
- # Create link from alias refpage to page for what it's aliasing
- os.symlink(src, alias)
diff --git a/codegen/vulkan/scripts/promote.py b/codegen/vulkan/scripts/promote.py
deleted file mode 100755
index c6b73ba4..00000000
--- a/codegen/vulkan/scripts/promote.py
+++ /dev/null
@@ -1,173 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2016-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# Retroactively insert markup in show both 1.1 core features and KHR
-# extensions they were promoted from.
-
-# Usage: promote.py [-overwrite] [-out dir] [-suffix str] files
-# -overwrite updates in place (can be risky, make sure there are backups)
-# -out specifies directory to create output file in, default 'out'
-# -suffix specifies suffix to add to output files, default ''
-# files are asciidoc source files from the Vulkan spec to reflow.
-
-# For error and file-loading interfaces only
-import argparse, copy, os, pdb, re, string, sys
-from reflib import *
-from promoted import *
-
-global anchor
-anchor = 0
-
-def anchorname(anchor):
- return 'promoted-' + str(anchor)
-
-def printanchor(fp):
- # Anchor index for navigation
- global anchor
-
- print('[[' + anchorname(anchor) + ']]', file=fp)
- print('This anchor:', anchorname(anchor), file=fp)
- print('<<' + anchorname(anchor+1) + ', OINK>>', file=fp)
- anchor = anchor + 1
-
-# promote a core interface and include the extension it was promoted from
-# line - matching line with 1.1 interface
-# type - 'protos', 'structs', 'flags', 'enums'
-# name - interface name
-# extension - name of extension interface was promoted from
-# fp - output filename
-def promote(line, type, name, extension, fp):
- if type == 'protos':
- # printanchor(fp)
- print('ifdef::VK_VERSION_1_1[]', file=fp)
- print(line, file=fp, end='')
- print('endif::VK_VERSION_1_1[]', file=fp)
- print('', file=fp)
- print('ifdef::VK_VERSION_1_1+' + extension +
- '[or the equivalent command]', file=fp)
- print('', file=fp)
- print('ifdef::' + extension + '[]', file=fp)
- print('include::../api/' + type + '/' + name + 'KHR.txt[]', file=fp)
- print('endif::' + extension + '[]', file=fp)
- del promoted[name]
- elif type == 'structs' or type == 'enums' or type == 'flags' or type == 'handles':
- # printanchor(fp)
- print(line, file=fp, end='')
- print('', file=fp)
- print('ifdef::' + extension + '[]', file=fp)
- print('or the equivalent', file=fp)
- print('', file=fp)
- print('include::../api/' + type + '/' + name + 'KHR.txt[]', file=fp)
- print('endif::' + extension + '[]', file=fp)
- del promoted[name]
- else:
- logWarn('Unrecognized promoted type', type, 'for interface', name)
- print(line, file=fp, end='')
-
-
-def promoteFile(filename, args):
- logDiag('promote: filename', filename)
-
- lines = loadFile(filename)
- if (lines == None):
- return
-
- # Output file handle and promote object for this file. There are no race
- # conditions on overwriting the input, but it's not recommended unless
- # you have backing store such as git.
-
- if args.overwrite:
- outFilename = filename
- else:
- outFilename = args.outDir + '/' + os.path.basename(filename) + args.suffix
-
- try:
- fp = open(outFilename, 'w', encoding='utf8')
- True
- except:
- logWarn('Cannot open output file', filename, ':', sys.exc_info()[0])
- return None
-
- lineno = 0
- for line in lines:
- lineno = lineno + 1
-
- matches = includePat.search(line)
- if matches != None:
- type = matches.group('type')
- name = matches.group('name')
- if name in promoted:
- extension = promoted[name]['extension']
- if extension:
- # Promote core interface
- promote(line, type, name, promoted[name]['extension'], fp)
- continue
- # Fallthrough
- print(line, file=fp, end='')
-
- fp.close()
-
-def promoteAllAdocFiles(folder_to_promote, args):
- for root, subdirs, files in os.walk(folder_to_promote):
- for file in files:
- if file.endswith(".txt"):
- file_path = os.path.join(root, file)
- promoteFile(file_path, args)
- for subdir in subdirs:
- sub_folder = os.path.join(root, subdir)
- print('Sub-folder = %s' % sub_folder)
- if not (subdir.lower() == "scripts") and not (subdir.lower() == "style"):
- print(' Parsing = %s' % sub_folder)
- promoteAllAdocFiles(sub_folder, args)
- else:
- print(' Skipping = %s' % sub_folder)
-
-# Patterns used to recognize interesting lines in an asciidoc source file.
-# These patterns are only compiled once.
-
-if __name__ == '__main__':
- parser = argparse.ArgumentParser()
-
- parser.add_argument('-diag', action='store', dest='diagFile',
- help='Set the diagnostic file')
- parser.add_argument('-warn', action='store', dest='warnFile',
- help='Set the warning file')
- parser.add_argument('-log', action='store', dest='logFile',
- help='Set the log file for both diagnostics and warnings')
- parser.add_argument('-overwrite', action='store_true',
- help='Overwrite input filenames instead of writing different output filenames')
- parser.add_argument('-out', action='store', dest='outDir',
- default='out',
- help='Set the output directory in which updated files are generated (default: out)')
- parser.add_argument('-suffix', action='store', dest='suffix',
- default='',
- help='Set the suffix added to updated file names (default: none)')
- parser.add_argument('files', metavar='filename', nargs='*',
- help='a filename to promote text in')
- parser.add_argument('--version', action='version', version='%(prog)s 1.0')
-
- args = parser.parse_args()
-
- setLogFile(True, True, args.logFile)
- setLogFile(True, False, args.diagFile)
- setLogFile(False, True, args.warnFile)
-
- if args.overwrite:
- logWarn('promote.py: will overwrite all input files')
-
- # If no files are specified, promote the entire specification chapters folder
- if len(args.files) == 0:
- folder_to_promote = os.getcwd()
- folder_to_promote += '/chapters'
- promoteAllAdocFiles(folder_to_promote, args)
- else:
- for file in args.files:
- promoteFile(file, args)
-
- print('At end, promoted interfaces remaining:')
- for key in promoted:
- if promoted[key]['extension'] != None:
- print('\t' + key)
diff --git a/codegen/vulkan/scripts/pygenerator.py b/codegen/vulkan/scripts/pygenerator.py
deleted file mode 100644
index 798ac322..00000000
--- a/codegen/vulkan/scripts/pygenerator.py
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-from generator import OutputGenerator, enquote, write
-from scriptgenerator import ScriptOutputGenerator
-import pprint
-
-class PyOutputGenerator(ScriptOutputGenerator):
- """PyOutputGenerator - subclass of ScriptOutputGenerator.
- Generates Python data structures describing API names and
- relationships."""
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- def beginDict(self, name):
- """String starting definition of a named dictionary"""
- return f'{name} = {{'
-
- def endDict(self):
- """ String ending definition of a named dictionary"""
- return '}'
-
- def writeDict(self, dict, name, printValues = True):
- """Write dictionary as a Python dictionary with the given name.
- If printValues is False, just output keys with None values."""
-
- write(self.beginDict(name), file=self.outFile)
- for key in sorted(dict):
- if printValues:
- value = enquote(dict[key])
- else:
- value = 'None'
- write(f'{enquote(key)} : {value},', file=self.outFile)
- write(self.endDict(), file=self.outFile)
-
- def writeList(self, l, name):
- """Write list l as a Ruby hash with the given name"""
-
- self.writeDict(l, name, printValues = False)
-
- def endFile(self):
- # Creates the inverse mapping of nonexistent APIs to their aliases.
- super().createInverseMap()
-
- # Print out all the dictionaries as Python strings.
- # Could just print(dict) but that's not human-readable
- dicts = ( [ self.basetypes, 'basetypes' ],
- [ self.consts, 'consts' ],
- [ self.enums, 'enums' ],
- [ self.flags, 'flags' ],
- [ self.funcpointers, 'funcpointers' ],
- [ self.protos, 'protos' ],
- [ self.structs, 'structs' ],
- [ self.handles, 'handles' ],
- [ self.defines, 'defines' ],
- [ self.typeCategory, 'typeCategory' ],
- [ self.alias, 'alias' ],
- [ self.nonexistent, 'nonexistent' ],
- )
-
- for (dict, name) in dicts:
- self.writeDict(dict, name)
-
- # Dictionary containing the relationships of a type
- # (e.g. a dictionary with each related type as keys).
- # Could just print(self.mapDict), but prefer something
- # human-readable and stable-ordered
- write(self.beginDict('mapDict'), file=self.outFile)
- for baseType in sorted(self.mapDict.keys()):
- write('{} : {},'.format(enquote(baseType),
- pprint.pformat(self.mapDict[baseType])), file=self.outFile)
- write(self.endDict(), file=self.outFile)
-
- # List of included feature names
- self.writeList(sorted(self.features), 'features')
-
- # Generate feature <-> interface mappings
- for feature in self.features:
- self.mapInterfaces(feature)
-
- # Write out the reverse map from APIs to requiring features
- write(self.beginDict('requiredBy'), file=self.outFile)
- for api in sorted(self.apimap):
- # Sort requirements by first feature in each one
- deps = sorted(self.apimap[api], key = lambda dep: dep[0])
- reqs = ', '.join('({}, {})'.format(enquote(dep[0]), enquote(dep[1])) for dep in deps)
- write('{} : [{}],'.format(enquote(api), reqs), file=self.outFile)
- write(self.endDict(), file=self.outFile)
-
- super().endFile()
diff --git a/codegen/vulkan/scripts/reflib.py b/codegen/vulkan/scripts/reflib.py
deleted file mode 100644
index bab7d30e..00000000
--- a/codegen/vulkan/scripts/reflib.py
+++ /dev/null
@@ -1,666 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2016-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# Utility functions for automatic ref page generation and other script stuff
-
-import io
-import re
-import sys
-import subprocess
-
-# global errFile, warnFile, diagFile
-
-errFile = sys.stderr
-warnFile = sys.stdout
-diagFile = None
-logSourcefile = None
-logProcname = None
-logLine = None
-
-def unescapeQuotes(s):
- """Remove \' escape sequences in a string (refpage description)"""
- return s.replace('\\\'', '\'')
-
-def write(*args, **kwargs ):
- file = kwargs.pop('file',sys.stdout)
- end = kwargs.pop('end','\n')
- file.write(' '.join(str(arg) for arg in args))
- file.write(end)
-
-def setLogSourcefile(filename):
- """Metadata which may be printed (if not None) for diagnostic messages"""
- global logSourcefile
- logSourcefile = filename
-
-def setLogProcname(procname):
- global logProcname
- logProcname = procname
-
-def setLogLine(line):
- global logLine
- logLine = line
-
-def logHeader(severity):
- """Generate prefix for a diagnostic line using metadata and severity"""
- global logSourcefile, logProcname, logLine
-
- msg = severity + ': '
- if logProcname:
- msg = msg + ' in ' + logProcname
- if logSourcefile:
- msg = msg + ' for ' + logSourcefile
- if logLine:
- msg = msg + ' line ' + str(logLine)
- return msg + ' '
-
-def setLogFile(setDiag, setWarn, filename):
- """Set the file handle to log either or both warnings and diagnostics to.
-
- - setDiag and setWarn are True if the corresponding handle is to be set.
- - filename is None for no logging, '-' for stdout, or a pathname."""
- global diagFile, warnFile
-
- if filename is None:
- return
-
- if filename == '-':
- fp = sys.stdout
- else:
- fp = open(filename, 'w', encoding='utf-8')
-
- if setDiag:
- diagFile = fp
- if setWarn:
- warnFile = fp
-
-def logDiag(*args, **kwargs):
- file = kwargs.pop('file', diagFile)
- end = kwargs.pop('end','\n')
- if file is not None:
- file.write(logHeader('DIAG') + ' '.join(str(arg) for arg in args))
- file.write(end)
-
-def logWarn(*args, **kwargs):
- file = kwargs.pop('file', warnFile)
- end = kwargs.pop('end','\n')
- if file is not None:
- file.write(logHeader('WARN') + ' '.join(str(arg) for arg in args))
- file.write(end)
-
-def logErr(*args, **kwargs):
- file = kwargs.pop('file', errFile)
- end = kwargs.pop('end','\n')
-
- strfile = io.StringIO()
- strfile.write(logHeader('ERROR') + ' '.join(str(arg) for arg in args))
- strfile.write(end)
-
- if file is not None:
- file.write(strfile.getvalue())
- sys.exit(1)
-
-def isempty(s):
- """Return True if s is nothing but white space, False otherwise"""
- return len(''.join(s.split())) == 0
-
-class pageInfo:
- """Information about a ref page relative to the file it's extracted from."""
- def __init__(self):
- self.extractPage = True
- """True if page should be extracted"""
-
- self.Warning = None
- """string warning if page is suboptimal or can't be generated"""
-
- self.embed = False
- """False or the name of the ref page this include is embedded within"""
-
- self.type = None
- """refpage type attribute - 'structs', 'protos', 'freeform', etc."""
-
- self.name = None
- """struct/proto/enumerant/etc. name"""
-
- self.desc = None
- """short description of ref page"""
-
- self.begin = None
- """index of first line of the page (heuristic or // refBegin)"""
-
- self.include = None
- """index of include:: line defining the page"""
-
- self.param = None
- """index of first line of parameter/member definitions"""
-
- self.body = None
- """index of first line of body text"""
-
- self.validity = None
- """index of validity include"""
-
- self.end = None
- """index of last line of the page (heuristic validity include, or // refEnd)"""
-
- self.alias = ''
- """aliases of this name, if supplied, or ''"""
-
- self.refs = ''
- """cross-references on // refEnd line, if supplied"""
-
- self.spec = None
- """'spec' attribute in refpage open block, if supplied, or None for the default ('api') type"""
-
- self.anchor = None
- """'anchor' attribute in refpage open block, if supplied, or inferred to be the same as the 'name'"""
-
-def printPageInfoField(desc, line, file):
- """Print a single field of a pageInfo struct, possibly None.
-
- - desc - string description of field
- - line - field value or None
- - file - indexed by line"""
- if line is not None:
- logDiag(desc + ':', line + 1, '\t-> ', file[line], end='')
- else:
- logDiag(desc + ':', line)
-
-def printPageInfo(pi, file):
- """Print out fields of a pageInfo struct
-
- - pi - pageInfo
- - file - indexed by pageInfo"""
- logDiag('TYPE: ', pi.type)
- logDiag('NAME: ', pi.name)
- logDiag('WARNING:', pi.Warning)
- logDiag('EXTRACT:', pi.extractPage)
- logDiag('EMBED: ', pi.embed)
- logDiag('DESC: ', pi.desc)
- printPageInfoField('BEGIN ', pi.begin, file)
- printPageInfoField('INCLUDE ', pi.include, file)
- printPageInfoField('PARAM ', pi.param, file)
- printPageInfoField('BODY ', pi.body, file)
- printPageInfoField('VALIDITY', pi.validity, file)
- printPageInfoField('END ', pi.end, file)
- logDiag('REFS: "' + pi.refs + '"')
-
-def prevPara(file, line):
- """Go back one paragraph from the specified line and return the line number
- of the first line of that paragraph.
-
- Paragraphs are delimited by blank lines. It is assumed that the
- current line is the first line of a paragraph.
-
- - file is an array of strings
- - line is the starting point (zero-based)"""
- # Skip over current paragraph
- while (line >= 0 and not isempty(file[line])):
- line = line - 1
- # Skip over white space
- while (line >= 0 and isempty(file[line])):
- line = line - 1
- # Skip to first line of previous paragraph
- while (line >= 1 and not isempty(file[line-1])):
- line = line - 1
- return line
-
-def nextPara(file, line):
- """Go forward one paragraph from the specified line and return the line
- number of the first line of that paragraph.
-
- Paragraphs are delimited by blank lines. It is assumed that the
- current line is standalone (which is bogus).
-
- - file is an array of strings
- - line is the starting point (zero-based)"""
- maxLine = len(file) - 1
- # Skip over current paragraph
- while (line != maxLine and not isempty(file[line])):
- line = line + 1
- # Skip over white space
- while (line != maxLine and isempty(file[line])):
- line = line + 1
- return line
-
-def lookupPage(pageMap, name):
- """Return (creating if needed) the pageInfo entry in pageMap for name"""
- if name not in pageMap:
- pi = pageInfo()
- pi.name = name
- pageMap[name] = pi
- else:
- pi = pageMap[name]
- return pi
-
-def loadFile(filename):
- """Load a file into a list of strings. Return the list or None on failure"""
- try:
- fp = open(filename, 'r', encoding='utf-8')
- except:
- logWarn('Cannot open file', filename, ':', sys.exc_info()[0])
- return None
-
- file = fp.readlines()
- fp.close()
-
- return file
-
-def clampToBlock(line, minline, maxline):
- """Clamp a line number to be in the range [minline,maxline].
-
- If the line number is None, just return it.
- If minline is None, don't clamp to that value."""
- if line is None:
- return line
- if minline and line < minline:
- return minline
- if line > maxline:
- return maxline
-
- return line
-
-def fixupRefs(pageMap, specFile, file):
- """Fill in missing fields in pageInfo structures, to the extent they can be
- inferred.
-
- - pageMap - dictionary of pageInfo structures
- - specFile - filename
- - file - list of strings making up the file, indexed by pageInfo"""
- # All potential ref pages are now in pageMap. Process them to
- # identify actual page start/end/description boundaries, if
- # not already determined from the text.
- for name in sorted(pageMap.keys()):
- pi = pageMap[name]
-
- # # If nothing is found but an include line with no begin, validity,
- # # or end, this is not intended as a ref page (yet). Set the begin
- # # line to the include line, so autogeneration can at least
- # # pull the include out, but mark it not to be extracted.
- # # Examples include the host sync table includes in
- # # chapters/fundamentals.txt and the table of Vk*Flag types in
- # # appendices/boilerplate.txt.
- # if pi.begin is None and pi.validity is None and pi.end is None:
- # pi.begin = pi.include
- # pi.extractPage = False
- # pi.Warning = 'No begin, validity, or end lines identified'
- # continue
-
- # Using open block delimiters, ref pages must *always* have a
- # defined begin and end. If either is undefined, that's fatal.
- if pi.begin is None:
- pi.extractPage = False
- pi.Warning = 'Can\'t identify begin of ref page open block'
- continue
-
- if pi.end is None:
- pi.extractPage = False
- pi.Warning = 'Can\'t identify end of ref page open block'
- continue
-
- # If there's no description of the page, infer one from the type
- if pi.desc is None:
- if pi.type is not None:
- # pi.desc = pi.type[0:len(pi.type)-1] + ' (no short description available)'
- pi.Warning = 'No short description available; could infer from the type and name'
- else:
- pi.extractPage = False
- pi.Warning = 'No short description available, cannot infer from the type'
- continue
-
- # Try to determine where the parameter and body sections of the page
- # begin. funcpointer, proto, and struct pages infer the location of
- # the parameter and body sections. Other pages infer the location of
- # the body, but have no parameter sections.
- #
- #@ Probably some other types infer this as well - refer to list of
- #@ all page types in genRef.py:emitPage()
- if pi.include is not None:
- if pi.type in ['funcpointers', 'protos', 'structs']:
- pi.param = nextPara(file, pi.include)
- if pi.body is None:
- pi.body = nextPara(file, pi.param)
- else:
- if pi.body is None:
- pi.body = nextPara(file, pi.include)
- else:
- pi.Warning = 'Page does not have an API definition include::'
-
- # It's possible for the inferred param and body lines to run past
- # the end of block, if, for example, there is no parameter section.
- pi.param = clampToBlock(pi.param, pi.include, pi.end)
- pi.body = clampToBlock(pi.body, pi.param, pi.end)
-
- # We can get to this point with .include, .param, and .validity
- # all being None, indicating those sections weren't found.
-
- logDiag('fixupRefs: after processing,', pi.name, 'looks like:')
- printPageInfo(pi, file)
-
- # Now that all the valid pages have been found, try to make some
- # inferences about invalid pages.
- #
- # If a reference without a .end is entirely inside a valid reference,
- # then it's intentionally embedded - may want to create an indirect
- # page that links into the embedding page. This is done by a very
- # inefficient double loop, but the loop depth is small.
- for name in sorted(pageMap.keys()):
- pi = pageMap[name]
-
- if pi.end is None:
- for embedName in sorted(pageMap.keys()):
- logDiag('fixupRefs: comparing', pi.name, 'to', embedName)
- embed = pageMap[embedName]
- # Don't check embeddings which are themselves invalid
- if not embed.extractPage:
- logDiag('Skipping check for embedding in:', embed.name)
- continue
- if embed.begin is None or embed.end is None:
- logDiag('fixupRefs:', name + ':',
- 'can\'t compare to unanchored ref:', embed.name,
- 'in', specFile, 'at line', pi.include )
- printPageInfo(pi, file)
- printPageInfo(embed, file)
- # If an embed is found, change the error to a warning
- elif (pi.include is not None and pi.include >= embed.begin and
- pi.include <= embed.end):
- logDiag('fixupRefs: Found embed for:', name,
- 'inside:', embedName,
- 'in', specFile, 'at line', pi.include )
- pi.embed = embed.name
- pi.Warning = 'Embedded in definition for ' + embed.name
- break
- else:
- logDiag('fixupRefs: No embed match for:', name,
- 'inside:', embedName, 'in', specFile,
- 'at line', pi.include)
-
-
-# Patterns used to recognize interesting lines in an asciidoc source file.
-# These patterns are only compiled once.
-INCSVAR_DEF = re.compile(r':INCS-VAR: (?P<value>.*)')
-endifPat = re.compile(r'^endif::(?P<condition>[\w_+,]+)\[\]')
-beginPat = re.compile(r'^\[open,(?P<attribs>refpage=.*)\]')
-# attribute key/value pairs of an open block
-attribStr = r"([a-z]+)='([^'\\]*(?:\\.[^'\\]*)*)'"
-attribPat = re.compile(attribStr)
-bodyPat = re.compile(r'^// *refBody')
-errorPat = re.compile(r'^// *refError')
-
-# This regex transplanted from check_spec_links
-# It looks for either OpenXR or Vulkan generated file conventions, and for
-# the api/validity include (generated_type), protos/struct/etc path
-# (category), and API name (entity_name). It could be put into the API
-# conventions object.
-INCLUDE = re.compile(
- r'include::(?P<directory_traverse>((../){1,4}|\{INCS-VAR\}/|\{generated\}/)(generated/)?)(?P<generated_type>[\w]+)/(?P<category>\w+)/(?P<entity_name>[^./]+).txt[\[][\]]')
-
-
-def findRefs(file, filename):
- """Identify reference pages in a list of strings, returning a dictionary of
- pageInfo entries for each one found, or None on failure."""
- setLogSourcefile(filename)
- setLogProcname('findRefs')
-
- # To reliably detect the open blocks around reference pages, we must
- # first detect the '[open,refpage=...]' markup delimiting the block;
- # skip past the '--' block delimiter on the next line; and identify the
- # '--' block delimiter closing the page.
- # This can't be done solely with pattern matching, and requires state to
- # track 'inside/outside block'.
- # When looking for open blocks, possible states are:
- # 'outside' - outside a block
- # 'start' - have found the '[open...]' line
- # 'inside' - have found the following '--' line
- openBlockState = 'outside'
-
- # Dictionary of interesting line numbers and strings related to an API
- # name
- pageMap = {}
-
- numLines = len(file)
- line = 0
-
- # Track the pageInfo object corresponding to the current open block
- pi = None
- incsvar = None
-
- while (line < numLines):
- setLogLine(line)
-
- # Look for a file-wide definition
- matches = INCSVAR_DEF.match(file[line])
- if matches:
- incsvar = matches.group('value')
- logDiag('Matched INCS-VAR definition:', incsvar)
-
- line = line + 1
- continue
-
- # Perform INCS-VAR substitution immediately.
- if incsvar and '{INCS-VAR}' in file[line]:
- newLine = file[line].replace('{INCS-VAR}', incsvar)
- logDiag('PERFORMING SUBSTITUTION', file[line], '->', newLine)
- file[line] = newLine
-
- # Only one of the patterns can possibly match. Add it to
- # the dictionary for that name.
-
- # [open,refpage=...] starting a refpage block
- matches = beginPat.search(file[line])
- if matches is not None:
- logDiag('Matched open block pattern')
- attribs = matches.group('attribs')
-
- # If the previous open block wasn't closed, raise an error
- if openBlockState != 'outside':
- logErr('Nested open block starting at line', line, 'of',
- filename)
-
- openBlockState = 'start'
-
- # Parse the block attributes
- matches = attribPat.findall(attribs)
-
- # Extract each attribute
- name = None
- desc = None
- refpage_type = None
- spec_type = None
- anchor = None
- alias = None
- xrefs = None
-
- for (key,value) in matches:
- logDiag('got attribute', key, '=', value)
- if key == 'refpage':
- name = value
- elif key == 'desc':
- desc = unescapeQuotes(value)
- elif key == 'type':
- refpage_type = value
- elif key == 'spec':
- spec_type = value
- elif key == 'anchor':
- anchor = value
- elif key == 'alias':
- alias = value
- elif key == 'xrefs':
- xrefs = value
- else:
- logWarn('unknown open block attribute:', key)
-
- if name is None or desc is None or refpage_type is None:
- logWarn('missing one or more required open block attributes:'
- 'refpage, desc, or type')
- # Leave pi is None so open block delimiters are ignored
- else:
- pi = lookupPage(pageMap, name)
- pi.desc = desc
- # Must match later type definitions in interface/validity includes
- pi.type = refpage_type
- pi.spec = spec_type
- pi.anchor = anchor
- if alias:
- pi.alias = alias
- if xrefs:
- pi.refs = xrefs
- logDiag('open block for', name, 'added DESC =', desc,
- 'TYPE =', refpage_type, 'ALIAS =', alias,
- 'XREFS =', xrefs, 'SPEC =', spec_type,
- 'ANCHOR =', anchor)
-
- line = line + 1
- continue
-
- # '--' starting or ending and open block
- if file[line].rstrip() == '--':
- if openBlockState == 'outside':
- # Only refpage open blocks should use -- delimiters
- logWarn('Unexpected double-dash block delimiters')
- elif openBlockState == 'start':
- # -- delimiter following [open,refpage=...]
- openBlockState = 'inside'
-
- if pi is None:
- logWarn('no pageInfo available for opening -- delimiter')
- else:
- pi.begin = line + 1
- logDiag('opening -- delimiter: added BEGIN =', pi.begin)
- elif openBlockState == 'inside':
- # -- delimiter ending an open block
- if pi is None:
- logWarn('no pageInfo available for closing -- delimiter')
- else:
- pi.end = line - 1
- logDiag('closing -- delimiter: added END =', pi.end)
-
- openBlockState = 'outside'
- pi = None
- else:
- logWarn('unknown openBlockState:', openBlockState)
-
- line = line + 1
- continue
-
- matches = INCLUDE.search(file[line])
- if matches is not None:
- # Something got included, not sure what yet.
- gen_type = matches.group('generated_type')
- refpage_type = matches.group('category')
- name = matches.group('entity_name')
-
- # This will never match in OpenCL
- if gen_type == 'validity':
- logDiag('Matched validity pattern')
- if pi is not None:
- if pi.type and refpage_type != pi.type:
- logWarn('ERROR: pageMap[' + name + '] type:',
- pi.type, 'does not match type:', refpage_type)
- pi.type = refpage_type
- pi.validity = line
- logDiag('added TYPE =', pi.type, 'VALIDITY =', pi.validity)
- else:
- logWarn('validity include:: line NOT inside block')
-
- line = line + 1
- continue
-
- if gen_type == 'api':
- logDiag('Matched include pattern')
- if pi is not None:
- if pi.include is not None:
- logDiag('found multiple includes for this block')
- if pi.type and refpage_type != pi.type:
- logWarn('ERROR: pageMap[' + name + '] type:',
- pi.type, 'does not match type:', refpage_type)
- pi.type = refpage_type
- pi.include = line
- logDiag('added TYPE =', pi.type, 'INCLUDE =', pi.include)
- else:
- logWarn('interface include:: line NOT inside block')
-
- line = line + 1
- continue
-
- logDiag('ignoring unrecognized include line ', matches.group())
-
- # Vulkan 1.1 markup allows the last API include construct to be
- # followed by an asciidoctor endif:: construct (and also preceded,
- # at some distance).
- # This looks for endif:: immediately following an include:: line
- # and, if found, moves the include boundary to this line.
- matches = endifPat.search(file[line])
- if matches is not None and pi is not None:
- if pi.include == line - 1:
- logDiag('Matched endif pattern following include; moving include')
- pi.include = line
- else:
- logDiag('Matched endif pattern (not following include)')
-
- line = line + 1
- continue
-
- matches = bodyPat.search(file[line])
- if matches is not None:
- logDiag('Matched // refBody pattern')
- if pi is not None:
- pi.body = line
- logDiag('added BODY =', pi.body)
- else:
- logWarn('// refBody line NOT inside block')
-
- line = line + 1
- continue
-
- # OpenCL spec uses // refError to tag "validity" (Errors) language,
- # instead of /validity/ includes.
- matches = errorPat.search(file[line])
- if matches is not None:
- logDiag('Matched // refError pattern')
- if pi is not None:
- pi.validity = line
- logDiag('added VALIDITY (refError) =', pi.validity)
- else:
- logWarn('// refError line NOT inside block')
-
- line = line + 1
- continue
-
- line = line + 1
- continue
-
- if pi is not None:
- logErr('Unclosed open block at EOF!')
-
- setLogSourcefile(None)
- setLogProcname(None)
- setLogLine(None)
-
- return pageMap
-
-
-def getBranch():
- """Determine current git branch
-
- Returns (branch name, ''), or (None, stderr output) if the branch name
- can't be determined"""
-
- command = [ 'git', 'symbolic-ref', '--short', 'HEAD' ]
- results = subprocess.run(command,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
-
- # git command failed
- if len(results.stderr) > 0:
- return (None, results.stderr)
-
- # Remove newline from output and convert to a string
- branch = results.stdout.rstrip().decode()
- if len(branch) > 0:
- # Strip trailing newline
- branch = results.stdout.decode()[0:-1]
-
- return (branch, '')
diff --git a/codegen/vulkan/scripts/reflow.py b/codegen/vulkan/scripts/reflow.py
deleted file mode 100755
index 1897b05c..00000000
--- a/codegen/vulkan/scripts/reflow.py
+++ /dev/null
@@ -1,912 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2016-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-"""Used for automatic reflow of spec sources to satisfy the agreed layout to
-minimize git churn. Most of the logic has to do with detecting asciidoc
-markup or block types that *shouldn't* be reflowed (tables, code) and
-ignoring them. It's very likely there are many asciidoc constructs not yet
-accounted for in the script, our usage of asciidoc markup is intentionally
-somewhat limited.
-
-Also used to insert identifying tags on explicit Valid Usage statements.
-
-Usage: `reflow.py [-noflow] [-tagvu] [-nextvu #] [-overwrite] [-out dir] [-suffix str] files`
-
-- `-noflow` acts as a passthrough, instead of reflowing text. Other
- processing may occur.
-- `-tagvu` generates explicit VUID tag for Valid Usage statements which
- don't already have them.
-- `-nextvu #` starts VUID tag generation at the specified # instead of
- the value wired into the `reflow.py` script.
-- `-overwrite` updates in place (can be risky, make sure there are backups)
-- `-check FAIL|WARN` runs some simple sanity checks on markup. If the checks
- fail and the WARN option is given, the script will simply print a warning
- message. If the checks fail and the FAIL option is given, the script will
- exit with an error code. FAIL is for use with continuous integration
- scripts enforcing the checks.
-- `-out` specifies directory to create output file in, default 'out'
-- `-suffix` specifies suffix to add to output files, default ''
-- `files` are asciidoc source files from the spec to reflow.
-"""
-# For error and file-loading interfaces only
-import argparse
-import os
-import re
-import sys
-from reflib import loadFile, logDiag, logWarn, logErr, setLogFile, getBranch
-
-# Vulkan-specific - will consolidate into scripts/ like OpenXR soon
-sys.path.insert(0, 'xml')
-
-from vkconventions import VulkanConventions as APIConventions
-conventions = APIConventions()
-
-# Markup that always ends a paragraph
-# empty line or whitespace
-# [block options]
-# [[anchor]]
-# // comment
-# <<<< page break
-# :attribute-setting
-# macro-directive::terms
-# + standalone list item continuation
-# label:: labelled list - label must be standalone
-endPara = re.compile(r'^( *|\[.*\]|//.*|<<<<|:.*|[a-z]+::.*|\+|.*::)$')
-
-# Special case of markup ending a paragraph, used to track the current
-# command/structure. This allows for either OpenXR or Vulkan API path
-# conventions. Nominally it should use the file suffix defined by the API
-# conventions (conventions.file_suffix), except that XR uses '.txt' for
-# generated API include files, not '.adoc' like its other includes.
-includePat = re.compile(
- r'include::(?P<directory_traverse>((../){1,4}|\{INCS-VAR\}/|\{generated\}/)(generated/)?)(?P<generated_type>[\w]+)/(?P<category>\w+)/(?P<entity_name>[^./]+).txt[\[][\]]')
-
-# Find the first pname: or code: pattern in a Valid Usage statement
-pnamePat = re.compile(r'pname:(?P<param>\{?\w+\}?)')
-codePat = re.compile(r'code:(?P<param>\w+)')
-
-# Markup that's OK in a contiguous paragraph but otherwise passed through
-# .anything (except .., which indicates a literal block)
-# === Section Titles
-endParaContinue = re.compile(r'^(\.[^.].*|=+ .*)$')
-
-# Markup for block delimiters whose contents *should* be reformatted
-# -- (exactly two) (open block)
-# **** (4 or more) (sidebar block - why do we have these?!)
-# ==== (4 or more) (example block)
-# ____ (4 or more) (quote block)
-blockReflow = re.compile(r'^(--|[*=_]{4,})$')
-
-# Fake block delimiters for "common" VU statements
-blockCommonReflow = '// Common Valid Usage\n'
-
-# Markup for block delimiters whose contents should *not* be reformatted
-# |=== (3 or more) (table)
-# ++++ (4 or more) (passthrough block)
-# .... (4 or more) (literal block)
-# //// (4 or more) (comment block)
-# ---- (4 or more) (listing block)
-# ``` (3 or more) (listing block)
-# **** (4 or more) (sidebar block)
-blockPassthrough = re.compile(r'^(\|={3,}|[`]{3}|[\-+./~]{4,})$')
-
-# Markup for introducing lists (hanging paragraphs)
-# * bullet
-# ** bullet
-# -- bullet
-# . bullet
-# :: bullet (no longer supported by asciidoctor 2)
-# {empty}:: bullet
-# 1. list item
-beginBullet = re.compile(r'^ *([*\-.]+|\{empty\}::|::|[0-9]+[.]) ')
-
-# Start of an asciidoctor conditional
-# ifdef::
-# ifndef::
-conditionalStart = re.compile(r'^(ifdef|ifndef)::')
-
-# Text that (may) not end sentences
-
-# A single letter followed by a period, typically a middle initial.
-endInitial = re.compile(r'^[A-Z]\.$')
-# An abbreviation, which doesn't (usually) end a line.
-endAbbrev = re.compile(r'(e\.g|i\.e|c\.f|vs)\.$', re.IGNORECASE)
-
-class ReflowState:
- """State machine for reflowing.
-
- Represents the state of the reflow operation"""
- def __init__(self,
- filename,
- margin = 76,
- file = sys.stdout,
- breakPeriod = True,
- reflow = True,
- nextvu = None,
- maxvu = None):
-
- self.blockStack = [ None ]
- """The last element is a line with the asciidoc block delimiter that's currently in effect,
- such as '--', '----', '****', '======', or '+++++++++'.
- This affects whether or not the block contents should be formatted."""
-
- self.reflowStack = [ True ]
- """The last element is True or False if the current blockStack contents
- should be reflowed."""
- self.vuStack = [ False ]
- """the last element is True or False if the current blockStack contents
- are an explicit Valid Usage block."""
-
- self.margin = margin
- """margin to reflow text to."""
-
- self.para = []
- """list of lines in the paragraph being accumulated.
- When this is non-empty, there is a current paragraph."""
-
- self.lastTitle = False
- """true if the previous line was a document title line
- (e.g. :leveloffset: 0 - no attempt to track changes to this is made)."""
-
- self.leadIndent = 0
- """indent level (in spaces) of the first line of a paragraph."""
-
- self.hangIndent = 0
- """indent level of the remaining lines of a paragraph."""
-
- self.file = file
- """file handle to write to."""
-
- self.filename = filename
- """base name of file being read from."""
-
- self.lineNumber = 0
- """line number being read from the input file."""
-
- self.breakPeriod = breakPeriod
- """True if justification should break to a new line after the end of a sentence."""
-
- self.breakInitial = True
- """True if justification should break to a new line after
- something that appears to be an initial in someone's name. **TBD**"""
-
- self.reflow = reflow
- """True if text should be reflowed, False to pass through unchanged."""
-
- self.vuPrefix = 'VUID'
- """Prefix of generated Valid Usage tags"""
-
- self.vuFormat = '{0}-{1}-{2}-{3:0>5d}'
- """Format string for generating Valid Usage tags.
- First argument is vuPrefix, second is command/struct name, third is parameter name, fourth is the tag number."""
-
- self.nextvu = nextvu
- """Integer to start tagging un-numbered Valid Usage statements with,
- or None if no tagging should be done."""
-
- self.maxvu = maxvu
- """Maximum tag to use for Valid Usage statements, or None if no
- tagging should be done."""
-
- self.defaultApiName = '{refpage}'
- self.apiName = self.defaultApiName
- """String name of a Vulkan structure or command for VUID tag
- generation, or {refpage} if one hasn't been included in this file
- yet."""
-
- def incrLineNumber(self):
- self.lineNumber = self.lineNumber + 1
-
- def printLines(self, lines):
- """Print an array of lines with newlines already present"""
- if len(lines) > 0:
- logDiag(':: printLines:', len(lines), 'lines: ', lines[0], end='')
-
- if self.file is not None:
- for line in lines:
- print(line, file=self.file, end='')
-
- def endSentence(self, word):
- """Return True if word ends with a sentence-period, False otherwise.
-
- Allows for contraction cases which won't end a line:
-
- - A single letter (if breakInitial is True)
- - Abbreviations: 'c.f.', 'e.g.', 'i.e.' (or mixed-case versions)"""
- if (word[-1:] != '.' or
- endAbbrev.search(word) or
- (self.breakInitial and endInitial.match(word))):
- return False
-
- return True
-
- def vuidAnchor(self, word):
- """Return True if word is a Valid Usage ID Tag anchor."""
- return (word[0:7] == '[[VUID-')
-
- def isOpenBlockDelimiter(self, line):
- """Returns True if line is an open block delimiter."""
- return line[0:2] == '--'
-
- def reflowPara(self):
- """Reflow the current paragraph, respecting the paragraph lead and
- hanging indentation levels.
-
- The algorithm also respects trailing '+' signs that indicate embedded newlines,
- and will not reflow a very long word immediately after a bullet point.
-
- Just return the paragraph unchanged if the -noflow argument was
- given."""
- if not self.reflow:
- return self.para
-
- logDiag('reflowPara lead indent = ', self.leadIndent,
- 'hangIndent =', self.hangIndent,
- 'para:', self.para[0], end='')
-
- # Total words processed (we care about the *first* word vs. others)
- wordCount = 0
-
- # Tracks the *previous* word processed. It must not be empty.
- prevWord = ' '
-
- # Track the previous line and paragraph being indented, if any
- outLine = None
- outPara = []
-
- for line in self.para:
- line = line.rstrip()
- words = line.split()
-
- # logDiag('reflowPara: input line =', line)
- numWords = len(words) - 1
-
- for i in range(0, numWords + 1):
- word = words[i]
- wordLen = len(word)
- wordCount += 1
-
- endEscape = False
- if i == numWords and word == '+':
- # Trailing ' +' must stay on the same line
- endEscape = word
- # logDiag('reflowPara last word of line =', word, 'prevWord =', prevWord, 'endEscape =', endEscape)
- else:
- pass
- # logDiag('reflowPara wordCount =', wordCount, 'word =', word, 'prevWord =', prevWord)
-
- if wordCount == 1:
- # The first word of the paragraph is treated specially.
- # The loop logic becomes trickier if all this code is
- # done prior to looping over lines and words, so all the
- # setup logic is done here.
-
- outPara = []
- outLine = ''.ljust(self.leadIndent) + word
- outLineLen = self.leadIndent + wordLen
-
- # If the paragraph begins with a bullet point, generate
- # a hanging indent level if there isn't one already.
- if beginBullet.match(self.para[0]):
- bulletPoint = True
- if len(self.para) > 1:
- logDiag('reflowPara first line matches bullet point',
- 'but indent already hanging @ input line',
- self.lineNumber)
- else:
- logDiag('reflowPara first line matches bullet point -'
- 'single line, assuming hangIndent @ input line',
- self.lineNumber)
- self.hangIndent = outLineLen + 1
- else:
- bulletPoint = False
- else:
- # Possible actions to take with this word
- #
- # addWord - add word to current line
- # closeLine - append line and start a new (null) one
- # startLine - add word to a new line
-
- # Default behavior if all the tests below fail is to add
- # this word to the current line, and keep accumulating
- # that line.
- (addWord, closeLine, startLine) = (True, False, False)
-
- # How long would this line be if the word were added?
- newLen = outLineLen + 1 + wordLen
-
- # Are we on the first word following a bullet point?
- firstBullet = (wordCount == 2 and bulletPoint)
-
- if endEscape:
- # If the new word ends the input line with ' +',
- # add it to the current line.
-
- (addWord, closeLine, startLine) = (True, True, False)
- elif self.vuidAnchor(word):
- # If the new word is a Valid Usage anchor, break the
- # line afterwards. Note that this should only happen
- # immediately after a bullet point, but we don't
- # currently check for this.
- (addWord, closeLine, startLine) = (True, True, False)
- elif newLen > self.margin:
- if firstBullet:
- # If the word follows a bullet point, add it to
- # the current line no matter its length.
-
- (addWord, closeLine, startLine) = (True, True, False)
- elif beginBullet.match(word + ' '):
- # If the word *is* a bullet point, add it to
- # the current line no matter its length.
- # This avoids an innocent inline '-' or '*'
- # turning into a bogus bullet point.
-
- (addWord, closeLine, startLine) = (True, True, False)
- else:
- # The word overflows, so add it to a new line.
-
- (addWord, closeLine, startLine) = (False, True, True)
- elif (self.breakPeriod and
- (wordCount > 2 or not firstBullet) and
- self.endSentence(prevWord)):
- # If the previous word ends a sentence and
- # breakPeriod is set, start a new line.
- # The complicated logic allows for leading bullet
- # points which are periods (implicitly numbered lists).
- # @@@ But not yet for explicitly numbered lists.
-
- (addWord, closeLine, startLine) = (False, True, True)
-
- # Add a word to the current line
- if addWord:
- if outLine:
- outLine += ' ' + word
- outLineLen = newLen
- else:
- # Fall through to startLine case if there's no
- # current line yet.
- startLine = True
-
- # Add current line to the output paragraph. Force
- # starting a new line, although we don't yet know if it
- # will ever have contents.
- if closeLine:
- if outLine:
- outPara.append(outLine + '\n')
- outLine = None
-
- # Start a new line and add a word to it
- if startLine:
- outLine = ''.ljust(self.hangIndent) + word
- outLineLen = self.hangIndent + wordLen
-
- # Track the previous word, for use in breaking at end of
- # a sentence
- prevWord = word
-
- # Add this line to the output paragraph.
- if outLine:
- outPara.append(outLine + '\n')
-
- return outPara
-
- def emitPara(self):
- """Emit a paragraph, possibly reflowing it depending on the block context.
-
- Resets the paragraph accumulator."""
- if self.para != []:
- if self.vuStack[-1] and self.nextvu is not None:
- # If:
- # - this paragraph is in a Valid Usage block,
- # - VUID tags are being assigned,
- # Try to assign VUIDs
-
- if nestedVuPat.search(self.para[0]):
- # Check for nested bullet points. These should not be
- # assigned VUIDs, nor present at all, because they break
- # the VU extractor.
- logWarn(self.filename + ': Invalid nested bullet point in VU block:', self.para[0])
- elif self.vuPrefix not in self.para[0]:
- # If:
- # - a tag is not already present, and
- # - the paragraph is a properly marked-up list item
- # Then add a VUID tag starting with the next free ID.
-
- # Split the first line after the bullet point
- matches = vuPat.search(self.para[0])
- if matches is not None:
- logDiag('findRefs: Matched vuPat on line:', self.para[0], end='')
- head = matches.group('head')
- tail = matches.group('tail')
-
- # Use the first pname: or code: tag in the paragraph as
- # the parameter name in the VUID tag. This won't always
- # be correct, but should be highly reliable.
- for vuLine in self.para:
- matches = pnamePat.search(vuLine)
- if matches is not None:
- break
- matches = codePat.search(vuLine)
- if matches is not None:
- break
-
- if matches is not None:
- paramName = matches.group('param')
- else:
- paramName = 'None'
- logWarn(self.filename,
- 'No param name found for VUID tag on line:',
- self.para[0])
-
- newline = (head + ' [[' +
- self.vuFormat.format(self.vuPrefix,
- self.apiName,
- paramName,
- self.nextvu) + ']] ' + tail)
-
- logDiag('Assigning', self.vuPrefix, self.apiName, self.nextvu,
- ' on line:', self.para[0], '->', newline, 'END')
-
- # Don't actually assign the VUID unless it's in the reserved range
- if self.nextvu <= self.maxvu:
- if self.nextvu == self.maxvu:
- logWarn('Skipping VUID assignment, no more VUIDs available')
- self.para[0] = newline
- self.nextvu = self.nextvu + 1
- # else:
- # There are only a few cases of this, and they're all
- # legitimate. Leave detecting this case to another tool
- # or hand inspection.
- # logWarn(self.filename + ': Unexpected non-bullet item in VU block (harmless if following an ifdef):',
- # self.para[0])
-
- if self.reflowStack[-1]:
- self.printLines(self.reflowPara())
- else:
- self.printLines(self.para)
-
- # Reset the paragraph, including its indentation level
- self.para = []
- self.leadIndent = 0
- self.hangIndent = 0
-
- def endPara(self, line):
- """'line' ends a paragraph and should itself be emitted.
- line may be None to indicate EOF or other exception."""
- logDiag('endPara line', self.lineNumber, ': emitting paragraph')
-
- # Emit current paragraph, this line, and reset tracker
- self.emitPara()
-
- if line:
- self.printLines( [ line ] )
-
- def endParaContinue(self, line):
- """'line' ends a paragraph (unless there's already a paragraph being
- accumulated, e.g. len(para) > 0 - currently not implemented)"""
- self.endPara(line)
-
- def endBlock(self, line, reflow = False, vuBlock = False):
- """'line' begins or ends a block.
-
- If beginning a block, tag whether or not to reflow the contents.
-
- vuBlock is True if the previous line indicates this is a Valid Usage block."""
- self.endPara(line)
-
- if self.blockStack[-1] == line:
- logDiag('endBlock line', self.lineNumber,
- ': popping block end depth:', len(self.blockStack),
- ':', line, end='')
-
- # Reset apiName at the end of an open block.
- # Open blocks cannot be nested (at present), so this is safe.
- if self.isOpenBlockDelimiter(line):
- logDiag('reset apiName to empty at line', self.lineNumber)
- self.apiName = self.defaultApiName
- else:
- logDiag('NOT resetting apiName to default at line', self.lineNumber)
-
- self.blockStack.pop()
- self.reflowStack.pop()
- self.vuStack.pop()
- else:
- # Start a block
- self.blockStack.append(line)
- self.reflowStack.append(reflow)
- self.vuStack.append(vuBlock)
-
- logDiag('endBlock reflow =', reflow, ' line', self.lineNumber,
- ': pushing block start depth', len(self.blockStack),
- ':', line, end='')
-
- def endParaBlockReflow(self, line, vuBlock):
- """'line' begins or ends a block. The paragraphs in the block *should* be
- reformatted (e.g. a NOTE)."""
- self.endBlock(line, reflow = True, vuBlock = vuBlock)
-
- def endParaBlockPassthrough(self, line):
- """'line' begins or ends a block. The paragraphs in the block should
- *not* be reformatted (e.g. a code listing)."""
- self.endBlock(line, reflow = False)
-
- def addLine(self, line):
- """'line' starts or continues a paragraph.
-
- Paragraphs may have "hanging indent", e.g.
-
- ```
- * Bullet point...
- ... continued
- ```
-
- In this case, when the higher indentation level ends, so does the
- paragraph."""
- logDiag('addLine line', self.lineNumber, ':', line, end='')
-
- # See https://stackoverflow.com/questions/13648813/what-is-the-pythonic-way-to-count-the-leading-spaces-in-a-string
- indent = len(line) - len(line.lstrip())
-
- # A hanging paragraph ends due to a less-indented line.
- if self.para != [] and indent < self.hangIndent:
- logDiag('addLine: line reduces indentation, emit paragraph')
- self.emitPara()
-
- # A bullet point (or something that looks like one) always ends the
- # current paragraph.
- if beginBullet.match(line):
- logDiag('addLine: line matches beginBullet, emit paragraph')
- self.emitPara()
-
- if self.para == []:
- # Begin a new paragraph
- self.para = [ line ]
- self.leadIndent = indent
- self.hangIndent = indent
- else:
- # Add a line to a paragraph. Increase the hanging indentation
- # level - once.
- if self.hangIndent == self.leadIndent:
- self.hangIndent = indent
- self.para.append(line)
-
-def apiMatch(oldname, newname):
- """Returns whether oldname and newname match, up to an API suffix.
- This should use the API map instead of this heuristic, since aliases
- like VkPhysicalDeviceVariablePointerFeatures ->
- VkPhysicalDeviceVariablePointersFeatures are not recognized."""
- upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
- return oldname.rstrip(upper) == newname.rstrip(upper)
-
-def reflowFile(filename, args):
- logDiag('reflow: filename', filename)
-
- lines = loadFile(filename)
- if lines is None:
- return
-
- # Output file handle and reflow object for this file. There are no race
- # conditions on overwriting the input, but it's not recommended unless
- # you have backing store such as git.
-
- if args.overwrite:
- outFilename = filename
- else:
- outFilename = args.outDir + '/' + os.path.basename(filename) + args.suffix
-
- if args.nowrite:
- fp = None
- else:
- try:
- fp = open(outFilename, 'w', encoding='utf8')
- except:
- logWarn('Cannot open output file', outFilename, ':', sys.exc_info()[0])
- return
-
- state = ReflowState(filename,
- margin = args.margin,
- file = fp,
- reflow = not args.noflow,
- nextvu = args.nextvu,
- maxvu = args.maxvu)
-
- for line in lines:
- state.incrLineNumber()
-
- # Is this a title line (leading '= ' followed by text)?
- thisTitle = False
-
- matches = vuidPat.search(line)
- if matches is not None:
- # If we found a VUID pattern, add the (filename,line) it was
- # found at to a list for that VUID, to find duplicates.
- vuid = matches.group('vuid')
- if vuid not in args.vuidDict:
- args.vuidDict[vuid] = []
- args.vuidDict[vuid].append([filename, line])
-
- # The logic here is broken. If we're in a non-reflowable block and
- # this line *doesn't* end the block, it should always be
- # accumulated.
-
- # Test for a blockCommonReflow delimiter comment first, to avoid
- # treating it solely as a end-Paragraph marker comment.
- if line == blockCommonReflow:
- # Starting or ending a pseudo-block for "common" VU statements.
- state.endParaBlockReflow(line, vuBlock = True)
-
- elif blockReflow.match(line):
- # Starting or ending a block whose contents may be reflowed.
- # Blocks cannot be nested.
-
- # Is this is an explicit Valid Usage block?
- vuBlock = (state.lineNumber > 1 and
- lines[state.lineNumber-2] == '.Valid Usage\n')
-
- state.endParaBlockReflow(line, vuBlock)
-
- elif endPara.match(line):
- # Ending a paragraph. Emit the current paragraph, if any, and
- # prepare to begin a new paragraph.
-
- state.endPara(line)
-
- # If this is an include:: line starting the definition of a
- # structure or command, track that for use in VUID generation.
-
- matches = includePat.search(line)
- if matches is not None:
- generated_type = matches.group('generated_type')
- include_type = matches.group('category')
- if generated_type == 'api' and include_type in ('protos', 'structs', 'funcpointers'):
- apiName = matches.group('entity_name')
- if state.apiName != state.defaultApiName:
- # This happens when there are multiple API include
- # lines in a single block. The style guideline is to
- # always place the API which others are promoted to
- # first. In virtually all cases, the promoted API
- # will differ solely in the vendor suffix (or
- # absence of it), which is benign.
- if not apiMatch(state.apiName, apiName):
- logDiag(f'Promoted API name mismatch at line {state.lineNumber}: {apiName} does not match state.apiName (this is OK if it is just a spelling alias)')
- else:
- state.apiName = apiName
-
- elif endParaContinue.match(line):
- # For now, always just end the paragraph.
- # Could check see if len(para) > 0 to accumulate.
-
- state.endParaContinue(line)
-
- # If it's a title line, track that
- if line[0:2] == '= ':
- thisTitle = True
-
- elif blockPassthrough.match(line):
- # Starting or ending a block whose contents must not be reflowed.
- # These are tables, etc. Blocks cannot be nested.
-
- state.endParaBlockPassthrough(line)
- elif state.lastTitle:
- # The previous line was a document title line. This line
- # is the author / credits line and must not be reflowed.
-
- state.endPara(line)
- else:
- # Just accumulate a line to the current paragraph. Watch out for
- # hanging indents / bullet-points and track that indent level.
-
- state.addLine(line)
-
- # This test looks for disallowed conditionals inside Valid Usage
- # blocks, by checking if (a) this line does not start a new VU
- # (bullet point) and (b) the previous line starts an asciidoctor
- # conditional (ifdef:: or ifndef::).
-
- if (args.check
- and state.vuStack[-1]
- and not beginBullet.match(line)
- and conditionalStart.match(lines[state.lineNumber-2])):
-
- logWarn('Detected embedded Valid Usage conditional: {}:{}'.format(
- filename, state.lineNumber - 1))
- # Keep track of warning check count
- args.warnCount = args.warnCount + 1
-
- state.lastTitle = thisTitle
-
- # Cleanup at end of file
- state.endPara(None)
-
- # Check for sensible block nesting
- if len(state.blockStack) > 1:
- logWarn('file', filename,
- 'mismatched asciidoc block delimiters at EOF:',
- state.blockStack[-1])
-
- if fp is not None:
- fp.close()
-
- # Update the 'nextvu' value
- if args.nextvu != state.nextvu:
- logWarn('Updated nextvu to', state.nextvu, 'after file', filename)
- args.nextvu = state.nextvu
-
-def reflowAllAdocFiles(folder_to_reflow, args):
- for root, subdirs, files in os.walk(folder_to_reflow):
- for file in files:
- if file.endswith(conventions.file_suffix):
- file_path = os.path.join(root, file)
- reflowFile(file_path, args)
- for subdir in subdirs:
- sub_folder = os.path.join(root, subdir)
- print('Sub-folder = %s' % sub_folder)
- if subdir.lower() not in conventions.spec_no_reflow_dirs:
- print(' Parsing = %s' % sub_folder)
- reflowAllAdocFiles(sub_folder, args)
- else:
- print(' Skipping = %s' % sub_folder)
-
-# Patterns used to recognize interesting lines in an asciidoc source file.
-# These patterns are only compiled once.
-
-# Explicit Valid Usage list item with one or more leading asterisks
-# The re.DOTALL is needed to prevent vuPat.search() from stripping
-# the trailing newline.
-vuPat = re.compile(r'^(?P<head> [*]+)( *)(?P<tail>.*)', re.DOTALL)
-
-# VUID with the numeric portion captured in the match object
-vuidPat = re.compile(r'VUID-[^-]+-[^-]+-(?P<vuid>[0-9]+)')
-
-# Pattern matching leading nested bullet points
-global nestedVuPat
-nestedVuPat = re.compile(r'^ \*\*')
-
-if __name__ == '__main__':
- parser = argparse.ArgumentParser()
-
- parser.add_argument('-diag', action='store', dest='diagFile',
- help='Set the diagnostic file')
- parser.add_argument('-warn', action='store', dest='warnFile',
- help='Set the warning file')
- parser.add_argument('-log', action='store', dest='logFile',
- help='Set the log file for both diagnostics and warnings')
- parser.add_argument('-overwrite', action='store_true',
- help='Overwrite input filenames instead of writing different output filenames')
- parser.add_argument('-out', action='store', dest='outDir',
- default='out',
- help='Set the output directory in which updated files are generated (default: out)')
- parser.add_argument('-nowrite', action='store_true',
- help='Do not write output files, for use with -check')
- parser.add_argument('-check', action='store', dest='check',
- help='Run markup checks and warn if WARN option is given, error exit if FAIL option is given')
- parser.add_argument('-checkVUID', action='store', dest='checkVUID',
- help='Detect duplicated VUID numbers and warn if WARN option is given, error exit if FAIL option is given')
- parser.add_argument('-tagvu', action='store_true',
- help='Tag un-tagged Valid Usage statements starting at the value wired into reflow.py')
- parser.add_argument('-nextvu', action='store', dest='nextvu', type=int,
- default=None,
- help='Specify start VUID to use instead of the value wired into vuidCounts.py')
- parser.add_argument('-maxvu', action='store', dest='maxvu', type=int,
- default=None,
- help='Specify maximum VUID instead of the value wired into vuidCounts.py')
- parser.add_argument('-branch', action='store', dest='branch',
- help='Specify branch to assign VUIDs for')
- parser.add_argument('-noflow', action='store_true', dest='noflow',
- help='Do not reflow text. Other actions may apply')
- parser.add_argument('-margin', action='store', type=int, dest='margin',
- default='76',
- help='Width to reflow text, defaults to 76 characters')
- parser.add_argument('-suffix', action='store', dest='suffix',
- default='',
- help='Set the suffix added to updated file names (default: none)')
- parser.add_argument('files', metavar='filename', nargs='*',
- help='a filename to reflow text in')
- parser.add_argument('--version', action='version', version='%(prog)s 1.0')
-
- args = parser.parse_args()
-
- setLogFile(True, True, args.logFile)
- setLogFile(True, False, args.diagFile)
- setLogFile(False, True, args.warnFile)
-
- print('args.margin = ', args.margin)
-
- if args.overwrite:
- logWarn("reflow.py: will overwrite all input files")
-
- errors = ''
- if args.branch is None:
- (args.branch, errors) = getBranch()
- if args.branch is None:
- # This is not fatal unless VUID assignment is required
- if args.tagvu:
- logErr('Cannot determine current git branch, so cannot assign VUIDs:', errors)
-
- if args.tagvu and args.nextvu is None:
- # Moved here since vuidCounts is only needed in the internal
- # repository
- from vuidCounts import vuidCounts
-
- if args.branch not in vuidCounts:
- logErr('Branch', args.branch, 'not in vuidCounts, cannot continue')
- maxVUID = vuidCounts[args.branch][1]
- startVUID = vuidCounts[args.branch][2]
- args.nextvu = startVUID
- args.maxvu = maxVUID
-
- if args.nextvu is not None:
- logWarn('Tagging untagged Valid Usage statements starting at', args.nextvu)
-
- # Count of markup check warnings encountered
- # This is added to the argparse structure
- args.warnCount = 0
-
- # Dictionary of VUID numbers found, containing a list of (file, line) on
- # which that number was found
- # This is added to the argparse structure
- args.vuidDict = {}
-
- # If no files are specified, reflow the entire specification chapters folder
- if not args.files:
- folder_to_reflow = conventions.spec_reflow_path
- logWarn('Reflowing all asciidoc files under', folder_to_reflow)
- reflowAllAdocFiles(folder_to_reflow, args)
- else:
- for file in args.files:
- reflowFile(file, args)
-
- if args.warnCount > 0:
- if args.check == 'FAIL':
- logErr('Failed with', args.warnCount, 'markup errors detected.\n' +
- 'To fix these, you can take actions such as:\n' +
- ' * Moving conditionals outside VU start / end without changing VU meaning\n' +
- ' * Refactor conditional text using terminology defined conditionally outside the VU itself\n' +
- ' * Remove the conditional (allowable when this just affects command / structure / enum names)\n')
- else:
- logWarn('Total warning count for markup issues is', args.warnCount)
-
- # Look for duplicated VUID numbers
- if args.checkVUID:
- dupVUIDs = 0
- for vuid in sorted(args.vuidDict):
- found = args.vuidDict[vuid]
- if len(found) > 1:
- logWarn('Duplicate VUID number {} found in files:'.format(vuid))
- for (file, line) in found:
- logWarn(' {}: {}'.format(file, line))
- dupVUIDs = dupVUIDs + 1
-
- if dupVUIDs > 0:
- if args.checkVUID == 'FAIL':
- logErr('Failed with', dupVUIDs, 'duplicated VUID numbers found.\n' +
- 'To fix this, either convert these to commonvalidity VUs if possible, or strip\n' +
- 'the VUIDs from all but one of the duplicates and regenerate new ones.')
- else:
- logWarn('Total number of duplicated VUID numbers is', dupVUIDs)
-
- if args.nextvu is not None and args.nextvu != startVUID:
- # Update next free VUID to assign
- vuidCounts[args.branch][2] = args.nextvu
- try:
- reflow_count_file_path = os.path.dirname(os.path.realpath(__file__))
- reflow_count_file_path += '/vuidCounts.py'
- reflow_count_file = open(reflow_count_file_path, 'w', encoding='utf8')
- print('# Do not edit this file!', file=reflow_count_file)
- print('# VUID ranges reserved for branches', file=reflow_count_file)
- print('# Key is branch name, value is [ start, end, nextfree ]', file=reflow_count_file)
- print('vuidCounts = {', file=reflow_count_file)
- for key in sorted(vuidCounts):
- print(" '{}': [ {}, {}, {} ],".format(
- key,
- vuidCounts[key][0],
- vuidCounts[key][1],
- vuidCounts[key][2]),
- file=reflow_count_file)
- print('}', file=reflow_count_file)
- reflow_count_file.close()
- except:
- logWarn('Cannot open output count file vuidCounts.py', ':', sys.exc_info()[0])
diff --git a/codegen/vulkan/scripts/reg.py b/codegen/vulkan/scripts/reg.py
deleted file mode 100644
index 254cfbdb..00000000
--- a/codegen/vulkan/scripts/reg.py
+++ /dev/null
@@ -1,1466 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-"""Types and classes for manipulating an API registry."""
-
-import copy
-import re
-import sys
-import xml.etree.ElementTree as etree
-from collections import defaultdict, namedtuple
-from generator import OutputGenerator, GeneratorOptions, write
-import pdb
-
-def apiNameMatch(str, supported):
- """Return whether a required api name matches a pattern specified for an
- XML <feature> 'api' attribute or <extension> 'supported' attribute.
-
- - str - api name such as 'vulkan' or 'openxr'
- - supported - comma-separated list of XML API names"""
-
- return (str is not None and str in supported.split(','))
-
-
-def matchAPIProfile(api, profile, elem):
- """Return whether an API and profile
- being generated matches an element's profile
-
- - api - string naming the API to match
- - profile - string naming the profile to match
- - elem - Element which (may) have 'api' and 'profile'
- attributes to match to.
-
- If a tag is not present in the Element, the corresponding API
- or profile always matches.
-
- Otherwise, the tag must exactly match the API or profile.
-
- Thus, if 'profile' = core:
-
- - `<remove>` with no attribute will match
- - `<remove profile="core">` will match
- - `<remove profile="compatibility">` will not match
-
- Possible match conditions:
-
- ```
- Requested Element
- Profile Profile
- --------- --------
- None None Always matches
- 'string' None Always matches
- None 'string' Does not match. Can't generate multiple APIs
- or profiles, so if an API/profile constraint
- is present, it must be asked for explicitly.
- 'string' 'string' Strings must match
- ```
-
- ** In the future, we will allow regexes for the attributes,
- not just strings, so that `api="^(gl|gles2)"` will match. Even
- this isn't really quite enough, we might prefer something
- like `"gl(core)|gles1(common-lite)"`."""
- # Match 'api', if present
- elem_api = elem.get('api')
- if elem_api:
- if api is None:
- raise UserWarning("No API requested, but 'api' attribute is present with value '"
- + elem_api + "'")
- elif api != elem_api:
- # Requested API doesn't match attribute
- return False
- elem_profile = elem.get('profile')
- if elem_profile:
- if profile is None:
- raise UserWarning("No profile requested, but 'profile' attribute is present with value '"
- + elem_profile + "'")
- elif profile != elem_profile:
- # Requested profile doesn't match attribute
- return False
- return True
-
-
-class BaseInfo:
- """Base class for information about a registry feature
- (type/group/enum/command/API/extension).
-
- Represents the state of a registry feature, used during API generation.
- """
-
- def __init__(self, elem):
- self.required = False
- """should this feature be defined during header generation
- (has it been removed by a profile or version)?"""
-
- self.declared = False
- "has this feature been defined already?"
-
- self.elem = elem
- "etree Element for this feature"
-
- def resetState(self):
- """Reset required/declared to initial values. Used
- prior to generating a new API interface."""
- self.required = False
- self.declared = False
-
- def compareKeys(self, info, key, required = False):
- """Return True if self.elem and info.elem have the same attribute
- value for key.
- If 'required' is not True, also returns True if neither element
- has an attribute value for key."""
-
- if required and key not in self.elem.keys():
- return False
- return self.elem.get(key) == info.elem.get(key)
-
- def compareElem(self, info, infoName):
- """Return True if self.elem and info.elem have the same definition.
- info - the other object
- infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' /
- 'extension'"""
-
- if infoName == 'enum':
- if self.compareKeys(info, 'extends'):
- # Either both extend the same type, or no type
- if (self.compareKeys(info, 'value', required = True) or
- self.compareKeys(info, 'bitpos', required = True)):
- # If both specify the same value or bit position,
- # they're equal
- return True
- elif (self.compareKeys(info, 'extnumber') and
- self.compareKeys(info, 'offset') and
- self.compareKeys(info, 'dir')):
- # If both specify the same relative offset, they're equal
- return True
- elif (self.compareKeys(info, 'alias')):
- # If both are aliases of the same value
- return True
- else:
- return False
- else:
- # The same enum can't extend two different types
- return False
- else:
- # Non-<enum>s should never be redefined
- return False
-
-
-class TypeInfo(BaseInfo):
- """Registry information about a type. No additional state
- beyond BaseInfo is required."""
-
- def __init__(self, elem):
- BaseInfo.__init__(self, elem)
- self.additionalValidity = []
- self.removedValidity = []
-
- def getMembers(self):
- """Get a collection of all member elements for this type, if any."""
- return self.elem.findall('member')
-
- def resetState(self):
- BaseInfo.resetState(self)
- self.additionalValidity = []
- self.removedValidity = []
-
-
-class GroupInfo(BaseInfo):
- """Registry information about a group of related enums
- in an <enums> block, generally corresponding to a C "enum" type."""
-
- def __init__(self, elem):
- BaseInfo.__init__(self, elem)
-
-
-class EnumInfo(BaseInfo):
- """Registry information about an enum"""
-
- def __init__(self, elem):
- BaseInfo.__init__(self, elem)
- self.type = elem.get('type')
- """numeric type of the value of the <enum> tag
- ( '' for GLint, 'u' for GLuint, 'ull' for GLuint64 )"""
- if self.type is None:
- self.type = ''
-
-
-class CmdInfo(BaseInfo):
- """Registry information about a command"""
-
- def __init__(self, elem):
- BaseInfo.__init__(self, elem)
- self.additionalValidity = []
- self.removedValidity = []
-
- def getParams(self):
- """Get a collection of all param elements for this command, if any."""
- return self.elem.findall('param')
-
- def resetState(self):
- BaseInfo.resetState(self)
- self.additionalValidity = []
- self.removedValidity = []
-
-
-class FeatureInfo(BaseInfo):
- """Registry information about an API <feature>
- or <extension>."""
-
- def __init__(self, elem):
- BaseInfo.__init__(self, elem)
- self.name = elem.get('name')
- "feature name string (e.g. 'VK_KHR_surface')"
-
- self.emit = False
- "has this feature been defined already?"
-
- self.sortorder = int(elem.get('sortorder', 0))
- """explicit numeric sort key within feature and extension groups.
- Defaults to 0."""
-
- # Determine element category (vendor). Only works
- # for <extension> elements.
- if elem.tag == 'feature':
- # Element category (vendor) is meaningless for <feature>
- self.category = 'VERSION'
- """category, e.g. VERSION or khr/vendor tag"""
-
- self.version = elem.get('name')
- """feature name string"""
-
- self.versionNumber = elem.get('number')
- """versionNumber - API version number, taken from the 'number'
- attribute of <feature>. Extensions do not have API version
- numbers and are assigned number 0."""
-
- self.number = "0"
- self.supported = None
- else:
- # Extract vendor portion of <APIprefix>_<vendor>_<name>
- self.category = self.name.split('_', 2)[1]
- self.version = "0"
- self.versionNumber = "0"
- self.number = elem.get('number')
- """extension number, used for ordering and for assigning
- enumerant offsets. <feature> features do not have extension
- numbers and are assigned number 0."""
-
- # If there's no 'number' attribute, use 0, so sorting works
- if self.number is None:
- self.number = 0
- self.supported = elem.get('supported')
-
-class SpirvInfo(BaseInfo):
- """Registry information about an API <spirvextensions>
- or <spirvcapability>."""
-
- def __init__(self, elem):
- BaseInfo.__init__(self, elem)
-
-class Registry:
- """Object representing an API registry, loaded from an XML file."""
-
- def __init__(self, gen=None, genOpts=None):
- if gen is None:
- # If not specified, give a default object so messaging will work
- self.gen = OutputGenerator()
- else:
- self.gen = gen
- "Output generator used to write headers / messages"
-
- if genOpts is None:
- self.genOpts = GeneratorOptions()
- else:
- self.genOpts = genOpts
- "Options controlling features to write and how to format them"
-
- self.gen.registry = self
- self.gen.genOpts = self.genOpts
- self.gen.genOpts.registry = self
-
- self.tree = None
- "ElementTree containing the root `<registry>`"
-
- self.typedict = {}
- "dictionary of TypeInfo objects keyed by type name"
-
- self.groupdict = {}
- "dictionary of GroupInfo objects keyed by group name"
-
- self.enumdict = {}
- "dictionary of EnumInfo objects keyed by enum name"
-
- self.cmddict = {}
- "dictionary of CmdInfo objects keyed by command name"
-
- self.apidict = {}
- "dictionary of FeatureInfo objects for `<feature>` elements keyed by API name"
-
- self.extensions = []
- "list of `<extension>` Elements"
-
- self.extdict = {}
- "dictionary of FeatureInfo objects for `<extension>` elements keyed by extension name"
-
- self.spirvextdict = {}
- "dictionary of FeatureInfo objects for `<spirvextension>` elements keyed by spirv extension name"
-
- self.spirvcapdict = {}
- "dictionary of FeatureInfo objects for `<spirvcapability>` elements keyed by spirv capability name"
-
- self.emitFeatures = False
- """True to actually emit features for a version / extension,
- or False to just treat them as emitted"""
-
- self.breakPat = None
- "regexp pattern to break on when generating names"
- # self.breakPat = re.compile('VkFenceImportFlagBits.*')
-
- self.requiredextensions = [] # Hack - can remove it after validity generator goes away
-
- # ** Global types for automatic source generation **
- # Length Member data
- self.commandextensiontuple = namedtuple('commandextensiontuple',
- ['command', # The name of the command being modified
- 'value', # The value to append to the command
- 'extension']) # The name of the extension that added it
- self.validextensionstructs = defaultdict(list)
- self.commandextensionsuccesses = []
- self.commandextensionerrors = []
-
- self.filename = None
-
- def loadElementTree(self, tree):
- """Load ElementTree into a Registry object and parse it."""
- self.tree = tree
- self.parseTree()
-
- def loadFile(self, file):
- """Load an API registry XML file into a Registry object and parse it"""
- self.filename = file
- self.tree = etree.parse(file)
- self.parseTree()
-
- def setGenerator(self, gen):
- """Specify output generator object.
-
- `None` restores the default generator."""
- self.gen = gen
- self.gen.setRegistry(self)
-
- def addElementInfo(self, elem, info, infoName, dictionary):
- """Add information about an element to the corresponding dictionary.
-
- Intended for internal use only.
-
- - elem - `<type>`/`<enums>`/`<enum>`/`<command>`/`<feature>`/`<extension>`/`<spirvextension>`/`<spirvcapability>` Element
- - info - corresponding {Type|Group|Enum|Cmd|Feature|Spirv}Info object
- - infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 'extension' / 'spirvextension' / 'spirvcapability'
- - dictionary - self.{type|group|enum|cmd|api|ext|spirvext|spirvcap}dict
-
- If the Element has an 'api' attribute, the dictionary key is the
- tuple (name,api). If not, the key is the name. 'name' is an
- attribute of the Element"""
- # self.gen.logMsg('diag', 'Adding ElementInfo.required =',
- # info.required, 'name =', elem.get('name'))
- api = elem.get('api')
- if api:
- key = (elem.get('name'), api)
- else:
- key = elem.get('name')
- if key in dictionary:
- if not dictionary[key].compareElem(info, infoName):
- self.gen.logMsg('warn', 'Attempt to redefine', key,
- '(this should not happen)')
- else:
- True
- else:
- dictionary[key] = info
-
- def lookupElementInfo(self, fname, dictionary):
- """Find a {Type|Enum|Cmd}Info object by name.
-
- Intended for internal use only.
-
- If an object qualified by API name exists, use that.
-
- - fname - name of type / enum / command
- - dictionary - self.{type|enum|cmd}dict"""
- key = (fname, self.genOpts.apiname)
- if key in dictionary:
- # self.gen.logMsg('diag', 'Found API-specific element for feature', fname)
- return dictionary[key]
- if fname in dictionary:
- # self.gen.logMsg('diag', 'Found generic element for feature', fname)
- return dictionary[fname]
-
- return None
-
- def breakOnName(self, regexp):
- """Specify a feature name regexp to break on when generating features."""
- self.breakPat = re.compile(regexp)
-
- def parseTree(self):
- """Parse the registry Element, once created"""
- # This must be the Element for the root <registry>
- self.reg = self.tree.getroot()
-
- # Create dictionary of registry types from toplevel <types> tags
- # and add 'name' attribute to each <type> tag (where missing)
- # based on its <name> element.
- #
- # There's usually one <types> block; more are OK
- # Required <type> attributes: 'name' or nested <name> tag contents
- self.typedict = {}
- for type_elem in self.reg.findall('types/type'):
- # If the <type> doesn't already have a 'name' attribute, set
- # it from contents of its <name> tag.
- if type_elem.get('name') is None:
- type_elem.set('name', type_elem.find('name').text)
- self.addElementInfo(type_elem, TypeInfo(type_elem), 'type', self.typedict)
-
- # Create dictionary of registry enum groups from <enums> tags.
- #
- # Required <enums> attributes: 'name'. If no name is given, one is
- # generated, but that group can't be identified and turned into an
- # enum type definition - it's just a container for <enum> tags.
- self.groupdict = {}
- for group in self.reg.findall('enums'):
- self.addElementInfo(group, GroupInfo(group), 'group', self.groupdict)
-
- # Create dictionary of registry enums from <enum> tags
- #
- # <enums> tags usually define different namespaces for the values
- # defined in those tags, but the actual names all share the
- # same dictionary.
- # Required <enum> attributes: 'name', 'value'
- # For containing <enums> which have type="enum" or type="bitmask",
- # tag all contained <enum>s are required. This is a stopgap until
- # a better scheme for tagging core and extension enums is created.
- self.enumdict = {}
- for enums in self.reg.findall('enums'):
- required = (enums.get('type') is not None)
- for enum in enums.findall('enum'):
- enumInfo = EnumInfo(enum)
- enumInfo.required = required
- self.addElementInfo(enum, enumInfo, 'enum', self.enumdict)
-
- # Create dictionary of registry commands from <command> tags
- # and add 'name' attribute to each <command> tag (where missing)
- # based on its <proto><name> element.
- #
- # There's usually only one <commands> block; more are OK.
- # Required <command> attributes: 'name' or <proto><name> tag contents
- self.cmddict = {}
- # List of commands which alias others. Contains
- # [ aliasName, element ]
- # for each alias
- cmdAlias = []
- for cmd in self.reg.findall('commands/command'):
- # If the <command> doesn't already have a 'name' attribute, set
- # it from contents of its <proto><name> tag.
- name = cmd.get('name')
- if name is None:
- name = cmd.set('name', cmd.find('proto/name').text)
- ci = CmdInfo(cmd)
- self.addElementInfo(cmd, ci, 'command', self.cmddict)
- alias = cmd.get('alias')
- if alias:
- cmdAlias.append([name, alias, cmd])
-
- # Now loop over aliases, injecting a copy of the aliased command's
- # Element with the aliased prototype name replaced with the command
- # name - if it exists.
- for (name, alias, cmd) in cmdAlias:
- if alias in self.cmddict:
- aliasInfo = self.cmddict[alias]
- cmdElem = copy.deepcopy(aliasInfo.elem)
- cmdElem.find('proto/name').text = name
- cmdElem.set('name', name)
- cmdElem.set('alias', alias)
- ci = CmdInfo(cmdElem)
- # Replace the dictionary entry for the CmdInfo element
- self.cmddict[name] = ci
-
- # @ newString = etree.tostring(base, encoding="unicode").replace(aliasValue, aliasName)
- # @elem.append(etree.fromstring(replacement))
- else:
- self.gen.logMsg('warn', 'No matching <command> found for command',
- cmd.get('name'), 'alias', alias)
-
- # Create dictionaries of API and extension interfaces
- # from toplevel <api> and <extension> tags.
- self.apidict = {}
- for feature in self.reg.findall('feature'):
- featureInfo = FeatureInfo(feature)
- self.addElementInfo(feature, featureInfo, 'feature', self.apidict)
-
- # Add additional enums defined only in <feature> tags
- # to the corresponding enumerated type.
- # When seen here, the <enum> element, processed to contain the
- # numeric enum value, is added to the corresponding <enums>
- # element, as well as adding to the enum dictionary. It is no
- # longer removed from the <require> element it is introduced in.
- # Instead, generateRequiredInterface ignores <enum> elements
- # that extend enumerated types.
- #
- # For <enum> tags which are actually just constants, if there's
- # no 'extends' tag but there is a 'value' or 'bitpos' tag, just
- # add an EnumInfo record to the dictionary. That works because
- # output generation of constants is purely dependency-based, and
- # doesn't need to iterate through the XML tags.
- for elem in feature.findall('require'):
- for enum in elem.findall('enum'):
- addEnumInfo = False
- groupName = enum.get('extends')
- if groupName is not None:
- # self.gen.logMsg('diag', 'Found extension enum',
- # enum.get('name'))
- # Add version number attribute to the <enum> element
- enum.set('version', featureInfo.version)
- # Look up the GroupInfo with matching groupName
- if groupName in self.groupdict:
- # self.gen.logMsg('diag', 'Matching group',
- # groupName, 'found, adding element...')
- gi = self.groupdict[groupName]
- gi.elem.append(copy.deepcopy(enum))
- else:
- self.gen.logMsg('warn', 'NO matching group',
- groupName, 'for enum', enum.get('name'), 'found.')
- addEnumInfo = True
- elif enum.get('value') or enum.get('bitpos') or enum.get('alias'):
- # self.gen.logMsg('diag', 'Adding extension constant "enum"',
- # enum.get('name'))
- addEnumInfo = True
- if addEnumInfo:
- enumInfo = EnumInfo(enum)
- self.addElementInfo(enum, enumInfo, 'enum', self.enumdict)
-
- self.extensions = self.reg.findall('extensions/extension')
- self.extdict = {}
- for feature in self.extensions:
- featureInfo = FeatureInfo(feature)
- self.addElementInfo(feature, featureInfo, 'extension', self.extdict)
-
- # Add additional enums defined only in <extension> tags
- # to the corresponding core type.
- # Algorithm matches that of enums in a "feature" tag as above.
- #
- # This code also adds a 'extnumber' attribute containing the
- # extension number, used for enumerant value calculation.
- for elem in feature.findall('require'):
- for enum in elem.findall('enum'):
- addEnumInfo = False
- groupName = enum.get('extends')
- if groupName is not None:
- # self.gen.logMsg('diag', 'Found extension enum',
- # enum.get('name'))
-
- # Add <extension> block's extension number attribute to
- # the <enum> element unless specified explicitly, such
- # as when redefining an enum in another extension.
- extnumber = enum.get('extnumber')
- if not extnumber:
- enum.set('extnumber', featureInfo.number)
-
- enum.set('extname', featureInfo.name)
- enum.set('supported', featureInfo.supported)
- # Look up the GroupInfo with matching groupName
- if groupName in self.groupdict:
- # self.gen.logMsg('diag', 'Matching group',
- # groupName, 'found, adding element...')
- gi = self.groupdict[groupName]
- gi.elem.append(copy.deepcopy(enum))
- else:
- self.gen.logMsg('warn', 'NO matching group',
- groupName, 'for enum', enum.get('name'), 'found.')
- addEnumInfo = True
- elif enum.get('value') or enum.get('bitpos') or enum.get('alias'):
- # self.gen.logMsg('diag', 'Adding extension constant "enum"',
- # enum.get('name'))
- addEnumInfo = True
- if addEnumInfo:
- enumInfo = EnumInfo(enum)
- self.addElementInfo(enum, enumInfo, 'enum', self.enumdict)
-
- # Construct a "validextensionstructs" list for parent structures
- # based on "structextends" tags in child structures
- disabled_types = []
- for disabled_ext in self.reg.findall('extensions/extension[@supported="disabled"]'):
- for type_elem in disabled_ext.findall("*/type"):
- disabled_types.append(type_elem.get('name'))
- for type_elem in self.reg.findall('types/type'):
- if type_elem.get('name') not in disabled_types:
- parentStructs = type_elem.get('structextends')
- if parentStructs is not None:
- for parent in parentStructs.split(','):
- # self.gen.logMsg('diag', type.get('name'), 'extends', parent)
- self.validextensionstructs[parent].append(type_elem.get('name'))
- # Sort the lists so they don't depend on the XML order
- for parent in self.validextensionstructs:
- self.validextensionstructs[parent].sort()
-
- # Parse out all spirv tags in dictionaries
- # Use addElementInfo to catch duplicates
- for spirv in self.reg.findall('spirvextensions/spirvextension'):
- spirvInfo = SpirvInfo(spirv)
- self.addElementInfo(spirv, spirvInfo, 'spirvextension', self.spirvextdict)
- for spirv in self.reg.findall('spirvcapabilities/spirvcapability'):
- spirvInfo = SpirvInfo(spirv)
- self.addElementInfo(spirv, spirvInfo, 'spirvcapability', self.spirvcapdict)
-
- def dumpReg(self, maxlen=120, filehandle=sys.stdout):
- """Dump all the dictionaries constructed from the Registry object.
-
- Diagnostic to dump the dictionaries to specified file handle (default stdout).
- Truncates type / enum / command elements to maxlen characters (default 120)"""
- write('***************************************', file=filehandle)
- write(' ** Dumping Registry contents **', file=filehandle)
- write('***************************************', file=filehandle)
- write('// Types', file=filehandle)
- for name in self.typedict:
- tobj = self.typedict[name]
- write(' Type', name, '->', etree.tostring(tobj.elem)[0:maxlen], file=filehandle)
- write('// Groups', file=filehandle)
- for name in self.groupdict:
- gobj = self.groupdict[name]
- write(' Group', name, '->', etree.tostring(gobj.elem)[0:maxlen], file=filehandle)
- write('// Enums', file=filehandle)
- for name in self.enumdict:
- eobj = self.enumdict[name]
- write(' Enum', name, '->', etree.tostring(eobj.elem)[0:maxlen], file=filehandle)
- write('// Commands', file=filehandle)
- for name in self.cmddict:
- cobj = self.cmddict[name]
- write(' Command', name, '->', etree.tostring(cobj.elem)[0:maxlen], file=filehandle)
- write('// APIs', file=filehandle)
- for key in self.apidict:
- write(' API Version ', key, '->',
- etree.tostring(self.apidict[key].elem)[0:maxlen], file=filehandle)
- write('// Extensions', file=filehandle)
- for key in self.extdict:
- write(' Extension', key, '->',
- etree.tostring(self.extdict[key].elem)[0:maxlen], file=filehandle)
- write('// SPIR-V', file=filehandle)
- for key in self.spirvextdict:
- write(' SPIR-V Extension', key, '->',
- etree.tostring(self.spirvextdict[key].elem)[0:maxlen], file=filehandle)
- for key in self.spirvcapdict:
- write(' SPIR-V Capability', key, '->',
- etree.tostring(self.spirvcapdict[key].elem)[0:maxlen], file=filehandle)
-
- def markTypeRequired(self, typename, required):
- """Require (along with its dependencies) or remove (but not its dependencies) a type.
-
- - typename - name of type
- - required - boolean (to tag features as required or not)
- """
- self.gen.logMsg('diag', 'tagging type:', typename, '-> required =', required)
- # Get TypeInfo object for <type> tag corresponding to typename
- typeinfo = self.lookupElementInfo(typename, self.typedict)
- if typeinfo is not None:
- if required:
- # Tag type dependencies in 'alias' and 'required' attributes as
- # required. This does not un-tag dependencies in a <remove>
- # tag. See comments in markRequired() below for the reason.
- for attrib_name in ['requires', 'alias']:
- depname = typeinfo.elem.get(attrib_name)
- if depname:
- self.gen.logMsg('diag', 'Generating dependent type',
- depname, 'for', attrib_name, 'type', typename)
- # Don't recurse on self-referential structures.
- if typename != depname:
- self.markTypeRequired(depname, required)
- else:
- self.gen.logMsg('diag', 'type', typename, 'is self-referential')
- # Tag types used in defining this type (e.g. in nested
- # <type> tags)
- # Look for <type> in entire <command> tree,
- # not just immediate children
- for subtype in typeinfo.elem.findall('.//type'):
- self.gen.logMsg('diag', 'markRequired: type requires dependent <type>', subtype.text)
- if typename != subtype.text:
- self.markTypeRequired(subtype.text, required)
- else:
- self.gen.logMsg('diag', 'type', typename, 'is self-referential')
- # Tag enums used in defining this type, for example in
- # <member><name>member</name>[<enum>MEMBER_SIZE</enum>]</member>
- for subenum in typeinfo.elem.findall('.//enum'):
- self.gen.logMsg('diag', 'markRequired: type requires dependent <enum>', subenum.text)
- self.markEnumRequired(subenum.text, required)
- # Tag type dependency in 'bitvalues' attributes as
- # required. This ensures that the bit values for a flag
- # are emitted
- depType = typeinfo.elem.get('bitvalues')
- if depType:
- self.gen.logMsg('diag', 'Generating bitflag type',
- depType, 'for type', typename)
- self.markTypeRequired(depType, required)
- group = self.lookupElementInfo(depType, self.groupdict)
- if group is not None:
- group.flagType = typeinfo
-
- typeinfo.required = required
- elif '.h' not in typename:
- self.gen.logMsg('warn', 'type:', typename, 'IS NOT DEFINED')
-
- def markEnumRequired(self, enumname, required):
- """Mark an enum as required or not.
-
- - enumname - name of enum
- - required - boolean (to tag features as required or not)"""
-
- self.gen.logMsg('diag', 'tagging enum:', enumname, '-> required =', required)
- enum = self.lookupElementInfo(enumname, self.enumdict)
- if enum is not None:
- # If the enum is part of a group, and is being removed, then
- # look it up in that <group> tag and remove it there, so that it
- # isn't visible to generators (which traverse the <group> tag
- # elements themselves).
- # This isn't the most robust way of doing this, since a removed
- # enum that's later required again will no longer have a group
- # element, but it makes the change non-intrusive on generator
- # code.
- if required is False:
- groupName = enum.elem.get('extends')
- if groupName is not None:
- # Look up the Info with matching groupName
- if groupName in self.groupdict:
- gi = self.groupdict[groupName]
- gienum = gi.elem.find("enum[@name='" + enumname + "']")
- if gienum is not None:
- # Remove copy of this enum from the group
- gi.elem.remove(gienum)
- else:
- self.gen.logMsg('warn', 'Cannot remove enum',
- enumname, 'not found in group',
- groupName)
- else:
- self.gen.logMsg('warn', 'Cannot remove enum',
- enumname, 'from nonexistent group',
- groupName)
-
- enum.required = required
- # Tag enum dependencies in 'alias' attribute as required
- depname = enum.elem.get('alias')
- if depname:
- self.gen.logMsg('diag', 'Generating dependent enum',
- depname, 'for alias', enumname, 'required =', enum.required)
- self.markEnumRequired(depname, required)
- else:
- self.gen.logMsg('warn', 'enum:', enumname, 'IS NOT DEFINED')
-
- def markCmdRequired(self, cmdname, required):
- """Mark a command as required or not.
-
- - cmdname - name of command
- - required - boolean (to tag features as required or not)"""
- self.gen.logMsg('diag', 'tagging command:', cmdname, '-> required =', required)
- cmd = self.lookupElementInfo(cmdname, self.cmddict)
- if cmd is not None:
- cmd.required = required
-
- # Tag command dependencies in 'alias' attribute as required
- #
- # This is usually not done, because command 'aliases' are not
- # actual C language aliases like type and enum aliases. Instead
- # they are just duplicates of the function signature of the
- # alias. This means that there is no dependency of a command
- # alias on what it aliases. One exception is validity includes,
- # where the spec markup needs the promoted-to validity include
- # even if only the promoted-from command is being built.
- if self.genOpts.requireCommandAliases:
- depname = cmd.elem.get('alias')
- if depname:
- self.gen.logMsg('diag', 'Generating dependent command',
- depname, 'for alias', cmdname)
- self.markCmdRequired(depname, required)
-
- # Tag all parameter types of this command as required.
- # This DOES NOT remove types of commands in a <remove>
- # tag, because many other commands may use the same type.
- # We could be more clever and reference count types,
- # instead of using a boolean.
- if required:
- # Look for <type> in entire <command> tree,
- # not just immediate children
- for type_elem in cmd.elem.findall('.//type'):
- self.gen.logMsg('diag', 'markRequired: command implicitly requires dependent type', type_elem.text)
- self.markTypeRequired(type_elem.text, required)
- else:
- self.gen.logMsg('warn', 'command:', cmdname, 'IS NOT DEFINED')
-
- def markRequired(self, featurename, feature, required):
- """Require or remove features specified in the Element.
-
- - featurename - name of the feature
- - feature - Element for `<require>` or `<remove>` tag
- - required - boolean (to tag features as required or not)"""
- self.gen.logMsg('diag', 'markRequired (feature = <too long to print>, required =', required, ')')
-
- # Loop over types, enums, and commands in the tag
- # @@ It would be possible to respect 'api' and 'profile' attributes
- # in individual features, but that's not done yet.
- for typeElem in feature.findall('type'):
- self.markTypeRequired(typeElem.get('name'), required)
- for enumElem in feature.findall('enum'):
- self.markEnumRequired(enumElem.get('name'), required)
- for cmdElem in feature.findall('command'):
- self.markCmdRequired(cmdElem.get('name'), required)
-
- # Extensions may need to extend existing commands or other items in the future.
- # So, look for extend tags.
- for extendElem in feature.findall('extend'):
- extendType = extendElem.get('type')
- if extendType == 'command':
- commandName = extendElem.get('name')
- successExtends = extendElem.get('successcodes')
- if successExtends is not None:
- for success in successExtends.split(','):
- self.commandextensionsuccesses.append(self.commandextensiontuple(command=commandName,
- value=success,
- extension=featurename))
- errorExtends = extendElem.get('errorcodes')
- if errorExtends is not None:
- for error in errorExtends.split(','):
- self.commandextensionerrors.append(self.commandextensiontuple(command=commandName,
- value=error,
- extension=featurename))
- else:
- self.gen.logMsg('warn', 'extend type:', extendType, 'IS NOT SUPPORTED')
-
- def getAlias(self, elem, dict):
- """Check for an alias in the same require block.
-
- - elem - Element to check for an alias"""
-
- # Try to find an alias
- alias = elem.get('alias')
- if alias is None:
- name = elem.get('name')
- typeinfo = self.lookupElementInfo(name, dict)
- alias = typeinfo.elem.get('alias')
-
- return alias
-
- def checkForCorrectionAliases(self, alias, require, tag):
- """Check for an alias in the same require block.
-
- - alias - String name of the alias
- - require - `<require>` block from the registry
- - tag - tag to look for in the require block"""
-
- # For the time being, the code below is bypassed. It has the effect
- # of excluding "spelling aliases" created to comply with the style
- # guide, but this leaves references out of the specification and
- # causes broken internal links.
- #
- # if alias and require.findall(tag + "[@name='" + alias + "']"):
- # return True
-
- return False
-
- def fillFeatureDictionary(self, interface, featurename, api, profile):
- """Capture added interfaces for a `<version>` or `<extension>`.
-
- - interface - Element for `<version>` or `<extension>`, containing
- `<require>` and `<remove>` tags
- - featurename - name of the feature
- - api - string specifying API name being generated
- - profile - string specifying API profile being generated"""
-
- # Explicitly initialize known types - errors for unhandled categories
- self.gen.featureDictionary[featurename] = {
- "enumconstant": {},
- "command": {},
- "enum": {},
- "struct": {},
- "handle": {},
- "basetype": {},
- "include": {},
- "define": {},
- "bitmask": {},
- "union": {},
- "funcpointer": {},
- }
-
- # <require> marks things that are required by this version/profile
- for require in interface.findall('require'):
- if matchAPIProfile(api, profile, require):
-
- # Determine the required extension or version needed for a require block
- # Assumes that only one of these is specified
- required_key = require.get('feature')
- if required_key is None:
- required_key = require.get('extension')
-
- # Loop over types, enums, and commands in the tag
- for typeElem in require.findall('type'):
- typename = typeElem.get('name')
- typeinfo = self.lookupElementInfo(typename, self.typedict)
-
- if typeinfo:
- # Remove aliases in the same extension/feature; these are always added as a correction. Don't need the original to be visible.
- alias = self.getAlias(typeElem, self.typedict)
- if not self.checkForCorrectionAliases(alias, require, 'type'):
- # Resolve the type info to the actual type, so we get an accurate read for 'structextends'
- while alias:
- typeinfo = self.lookupElementInfo(alias, self.typedict)
- alias = typeinfo.elem.get('alias')
-
- typecat = typeinfo.elem.get('category')
- typeextends = typeinfo.elem.get('structextends')
- if not required_key in self.gen.featureDictionary[featurename][typecat]:
- self.gen.featureDictionary[featurename][typecat][required_key] = {}
- if not typeextends in self.gen.featureDictionary[featurename][typecat][required_key]:
- self.gen.featureDictionary[featurename][typecat][required_key][typeextends] = []
- self.gen.featureDictionary[featurename][typecat][required_key][typeextends].append(typename)
- else:
- self.gen.logMsg('warn', 'fillFeatureDictionary: NOT filling for {}'.format(typename))
-
-
- for enumElem in require.findall('enum'):
- enumname = enumElem.get('name')
- typeinfo = self.lookupElementInfo(enumname, self.enumdict)
-
- # Remove aliases in the same extension/feature; these are always added as a correction. Don't need the original to be visible.
- alias = self.getAlias(enumElem, self.enumdict)
- if not self.checkForCorrectionAliases(alias, require, 'enum'):
- enumextends = enumElem.get('extends')
- if not required_key in self.gen.featureDictionary[featurename]['enumconstant']:
- self.gen.featureDictionary[featurename]['enumconstant'][required_key] = {}
- if not enumextends in self.gen.featureDictionary[featurename]['enumconstant'][required_key]:
- self.gen.featureDictionary[featurename]['enumconstant'][required_key][enumextends] = []
- self.gen.featureDictionary[featurename]['enumconstant'][required_key][enumextends].append(enumname)
- else:
- self.gen.logMsg('warn', 'fillFeatureDictionary: NOT filling for {}'.format(typename))
-
- for cmdElem in require.findall('command'):
- # Remove aliases in the same extension/feature; these are always added as a correction. Don't need the original to be visible.
- alias = self.getAlias(cmdElem, self.cmddict)
- if not self.checkForCorrectionAliases(alias, require, 'command'):
- if not required_key in self.gen.featureDictionary[featurename]['command']:
- self.gen.featureDictionary[featurename]['command'][required_key] = []
- self.gen.featureDictionary[featurename]['command'][required_key].append(cmdElem.get('name'))
- else:
- self.gen.logMsg('warn', 'fillFeatureDictionary: NOT filling for {}'.format(typename))
-
- def requireAndRemoveFeatures(self, interface, featurename, api, profile):
- """Process `<require>` and `<remove>` tags for a `<version>` or `<extension>`.
-
- - interface - Element for `<version>` or `<extension>`, containing
- `<require>` and `<remove>` tags
- - featurename - name of the feature
- - api - string specifying API name being generated
- - profile - string specifying API profile being generated"""
-
- # <require> marks things that are required by this version/profile
- for feature in interface.findall('require'):
- if matchAPIProfile(api, profile, feature):
- self.markRequired(featurename, feature, True)
-
- # <remove> marks things that are removed by this version/profile
- for feature in interface.findall('remove'):
- if matchAPIProfile(api, profile, feature):
- self.markRequired(featurename, feature, False)
-
- def assignAdditionalValidity(self, interface, api, profile):
- # Loop over all usage inside all <require> tags.
- for feature in interface.findall('require'):
- if matchAPIProfile(api, profile, feature):
- for v in feature.findall('usage'):
- if v.get('command'):
- self.cmddict[v.get('command')].additionalValidity.append(copy.deepcopy(v))
- if v.get('struct'):
- self.typedict[v.get('struct')].additionalValidity.append(copy.deepcopy(v))
-
- # Loop over all usage inside all <remove> tags.
- for feature in interface.findall('remove'):
- if matchAPIProfile(api, profile, feature):
- for v in feature.findall('usage'):
- if v.get('command'):
- self.cmddict[v.get('command')].removedValidity.append(copy.deepcopy(v))
- if v.get('struct'):
- self.typedict[v.get('struct')].removedValidity.append(copy.deepcopy(v))
-
- def generateFeature(self, fname, ftype, dictionary):
- """Generate a single type / enum group / enum / command,
- and all its dependencies as needed.
-
- - fname - name of feature (`<type>`/`<enum>`/`<command>`)
- - ftype - type of feature, 'type' | 'enum' | 'command'
- - dictionary - of *Info objects - self.{type|enum|cmd}dict"""
-
- self.gen.logMsg('diag', 'generateFeature: generating', ftype, fname)
- f = self.lookupElementInfo(fname, dictionary)
- if f is None:
- # No such feature. This is an error, but reported earlier
- self.gen.logMsg('diag', 'No entry found for feature', fname,
- 'returning!')
- return
-
- # If feature isn't required, or has already been declared, return
- if not f.required:
- self.gen.logMsg('diag', 'Skipping', ftype, fname, '(not required)')
- return
- if f.declared:
- self.gen.logMsg('diag', 'Skipping', ftype, fname, '(already declared)')
- return
- # Always mark feature declared, as though actually emitted
- f.declared = True
-
- # Determine if this is an alias, and of what, if so
- alias = f.elem.get('alias')
- if alias:
- self.gen.logMsg('diag', fname, 'is an alias of', alias)
-
- # Pull in dependent declaration(s) of the feature.
- # For types, there may be one type in the 'requires' attribute of
- # the element, one in the 'alias' attribute, and many in
- # embedded <type> and <enum> tags within the element.
- # For commands, there may be many in <type> tags within the element.
- # For enums, no dependencies are allowed (though perhaps if you
- # have a uint64 enum, it should require that type).
- genProc = None
- followupFeature = None
- if ftype == 'type':
- genProc = self.gen.genType
-
- # Generate type dependencies in 'alias' and 'requires' attributes
- if alias:
- self.generateFeature(alias, 'type', self.typedict)
- requires = f.elem.get('requires')
- if requires:
- self.gen.logMsg('diag', 'Generating required dependent type',
- requires)
- self.generateFeature(requires, 'type', self.typedict)
-
- # Generate types used in defining this type (e.g. in nested
- # <type> tags)
- # Look for <type> in entire <command> tree,
- # not just immediate children
- for subtype in f.elem.findall('.//type'):
- self.gen.logMsg('diag', 'Generating required dependent <type>',
- subtype.text)
- self.generateFeature(subtype.text, 'type', self.typedict)
-
- # Generate enums used in defining this type, for example in
- # <member><name>member</name>[<enum>MEMBER_SIZE</enum>]</member>
- for subtype in f.elem.findall('.//enum'):
- self.gen.logMsg('diag', 'Generating required dependent <enum>',
- subtype.text)
- self.generateFeature(subtype.text, 'enum', self.enumdict)
-
- # If the type is an enum group, look up the corresponding
- # group in the group dictionary and generate that instead.
- if f.elem.get('category') == 'enum':
- self.gen.logMsg('diag', 'Type', fname, 'is an enum group, so generate that instead')
- group = self.lookupElementInfo(fname, self.groupdict)
- if alias is not None:
- # An alias of another group name.
- # Pass to genGroup with 'alias' parameter = aliased name
- self.gen.logMsg('diag', 'Generating alias', fname,
- 'for enumerated type', alias)
- # Now, pass the *aliased* GroupInfo to the genGroup, but
- # with an additional parameter which is the alias name.
- genProc = self.gen.genGroup
- f = self.lookupElementInfo(alias, self.groupdict)
- elif group is None:
- self.gen.logMsg('warn', 'Skipping enum type', fname,
- ': No matching enumerant group')
- return
- else:
- genProc = self.gen.genGroup
- f = group
-
- # @ The enum group is not ready for generation. At this
- # @ point, it contains all <enum> tags injected by
- # @ <extension> tags without any verification of whether
- # @ they're required or not. It may also contain
- # @ duplicates injected by multiple consistent
- # @ definitions of an <enum>.
-
- # @ Pass over each enum, marking its enumdict[] entry as
- # @ required or not. Mark aliases of enums as required,
- # @ too.
-
- enums = group.elem.findall('enum')
-
- self.gen.logMsg('diag', 'generateFeature: checking enums for group', fname)
-
- # Check for required enums, including aliases
- # LATER - Check for, report, and remove duplicates?
- enumAliases = []
- for elem in enums:
- name = elem.get('name')
-
- required = False
-
- extname = elem.get('extname')
- version = elem.get('version')
- if extname is not None:
- # 'supported' attribute was injected when the <enum> element was
- # moved into the <enums> group in Registry.parseTree()
- if self.genOpts.defaultExtensions == elem.get('supported'):
- required = True
- elif re.match(self.genOpts.addExtensions, extname) is not None:
- required = True
- elif version is not None:
- required = re.match(self.genOpts.emitversions, version) is not None
- else:
- required = True
-
- self.gen.logMsg('diag', '* required =', required, 'for', name)
- if required:
- # Mark this element as required (in the element, not the EnumInfo)
- elem.set('required', 'true')
- # If it's an alias, track that for later use
- enumAlias = elem.get('alias')
- if enumAlias:
- enumAliases.append(enumAlias)
- for elem in enums:
- name = elem.get('name')
- if name in enumAliases:
- elem.set('required', 'true')
- self.gen.logMsg('diag', '* also need to require alias', name)
- if f.elem.get('category') == 'bitmask':
- followupFeature = f.elem.get('bitvalues')
- elif ftype == 'command':
- # Generate command dependencies in 'alias' attribute
- if alias:
- self.generateFeature(alias, 'command', self.cmddict)
-
- genProc = self.gen.genCmd
- for type_elem in f.elem.findall('.//type'):
- depname = type_elem.text
- self.gen.logMsg('diag', 'Generating required parameter type',
- depname)
- self.generateFeature(depname, 'type', self.typedict)
- elif ftype == 'enum':
- # Generate enum dependencies in 'alias' attribute
- if alias:
- self.generateFeature(alias, 'enum', self.enumdict)
- genProc = self.gen.genEnum
-
- # Actually generate the type only if emitting declarations
- if self.emitFeatures:
- self.gen.logMsg('diag', 'Emitting', ftype, 'decl for', fname)
- genProc(f, fname, alias)
- else:
- self.gen.logMsg('diag', 'Skipping', ftype, fname,
- '(should not be emitted)')
-
- if followupFeature:
- self.gen.logMsg('diag', 'Generating required bitvalues <enum>',
- followupFeature)
- self.generateFeature(followupFeature, "type", self.typedict)
-
- def generateRequiredInterface(self, interface):
- """Generate all interfaces required by an API version or extension.
-
- - interface - Element for `<version>` or `<extension>`"""
-
- # Loop over all features inside all <require> tags.
- for features in interface.findall('require'):
- for t in features.findall('type'):
- self.generateFeature(t.get('name'), 'type', self.typedict)
- for e in features.findall('enum'):
- # If this is an enum extending an enumerated type, don't
- # generate it - this has already been done in reg.parseTree,
- # by copying this element into the enumerated type.
- enumextends = e.get('extends')
- if not enumextends:
- self.generateFeature(e.get('name'), 'enum', self.enumdict)
- for c in features.findall('command'):
- self.generateFeature(c.get('name'), 'command', self.cmddict)
-
- def generateSpirv(self, spirv, dictionary):
- if spirv is None:
- self.gen.logMsg('diag', 'No entry found for element', name,
- 'returning!')
- return
-
- name = spirv.elem.get('name')
- # No known alias for spirv elements
- alias = None
- if spirv.emit:
- genProc = self.gen.genSpirv
- genProc(spirv, name, alias)
-
- def stripUnsupportedAPIs(self, dictionary, attribute, supportedDictionary):
- """Strip unsupported APIs from attributes of APIs.
- dictionary - *Info dictionary of APIs to be updated
- attribute - attribute name to look for in each API
- supportedDictionary - dictionary in which to look for supported
- API elements in the attribute"""
-
- for key in dictionary:
- eleminfo = dictionary[key]
- attribstring = eleminfo.elem.get(attribute)
- if attribstring is not None:
- apis = []
- stripped = False
- for api in attribstring.split(','):
- ##print('Checking API {} referenced by {}'.format(api, key))
- if supportedDictionary[api].required:
- apis.append(api)
- else:
- stripped = True
- ##print('\t**STRIPPING API {} from {}'.format(api, key))
-
- # Update the attribute after stripping stuff.
- # Could sort apis before joining, but it's not a clear win
- if stripped:
- eleminfo.elem.set(attribute, ','.join(apis))
-
- def apiGen(self):
- """Generate interface for specified versions using the current
- generator and generator options"""
-
- self.gen.logMsg('diag', '*******************************************')
- self.gen.logMsg('diag', ' Registry.apiGen file:', self.genOpts.filename,
- 'api:', self.genOpts.apiname,
- 'profile:', self.genOpts.profile)
- self.gen.logMsg('diag', '*******************************************')
-
- # Could reset required/declared flags for all features here.
- # This has been removed as never used. The initial motivation was
- # the idea of calling apiGen() repeatedly for different targets, but
- # this has never been done. The 20% or so build-time speedup that
- # might result is not worth the effort to make it actually work.
- #
- #@@ self.apiReset()
-
- # Compile regexps used to select versions & extensions
- regVersions = re.compile(self.genOpts.versions)
- regEmitVersions = re.compile(self.genOpts.emitversions)
- regAddExtensions = re.compile(self.genOpts.addExtensions)
- regRemoveExtensions = re.compile(self.genOpts.removeExtensions)
- regEmitExtensions = re.compile(self.genOpts.emitExtensions)
- regEmitSpirv = re.compile(self.genOpts.emitSpirv)
-
- # Get all matching API feature names & add to list of FeatureInfo
- # Note we used to select on feature version attributes, not names.
- features = []
- apiMatch = False
- for key in self.apidict:
- fi = self.apidict[key]
- api = fi.elem.get('api')
- if apiNameMatch(self.genOpts.apiname, api):
- apiMatch = True
- if regVersions.match(fi.name):
- # Matches API & version #s being generated. Mark for
- # emission and add to the features[] list .
- # @@ Could use 'declared' instead of 'emit'?
- fi.emit = (regEmitVersions.match(fi.name) is not None)
- features.append(fi)
- if not fi.emit:
- self.gen.logMsg('diag', 'NOT tagging feature api =', api,
- 'name =', fi.name, 'version =', fi.version,
- 'for emission (does not match emitversions pattern)')
- else:
- self.gen.logMsg('diag', 'Including feature api =', api,
- 'name =', fi.name, 'version =', fi.version,
- 'for emission (matches emitversions pattern)')
- else:
- self.gen.logMsg('diag', 'NOT including feature api =', api,
- 'name =', fi.name, 'version =', fi.version,
- '(does not match requested versions)')
- else:
- self.gen.logMsg('diag', 'NOT including feature api =', api,
- 'name =', fi.name,
- '(does not match requested API)')
- if not apiMatch:
- self.gen.logMsg('warn', 'No matching API versions found!')
-
- # Get all matching extensions, in order by their extension number,
- # and add to the list of features.
- # Start with extensions tagged with 'api' pattern matching the API
- # being generated. Add extensions matching the pattern specified in
- # regExtensions, then remove extensions matching the pattern
- # specified in regRemoveExtensions
- for (extName, ei) in sorted(self.extdict.items(), key=lambda x: x[1].number if x[1].number is not None else '0'):
- extName = ei.name
- include = False
-
- # Include extension if defaultExtensions is not None and is
- # exactly matched by the 'supported' attribute.
- if apiNameMatch(self.genOpts.defaultExtensions,
- ei.elem.get('supported')):
- self.gen.logMsg('diag', 'Including extension',
- extName, "(defaultExtensions matches the 'supported' attribute)")
- include = True
-
- # Include additional extensions if the extension name matches
- # the regexp specified in the generator options. This allows
- # forcing extensions into an interface even if they're not
- # tagged appropriately in the registry.
- # However we still respect the 'supported' attribute.
- if regAddExtensions.match(extName) is not None:
- if not apiNameMatch(self.genOpts.apiname, ei.elem.get('supported')):
- self.gen.logMsg('diag', 'NOT including extension',
- extName, '(matches explicitly requested, but does not match the \'supported\' attribute)')
- include = False
- else:
- self.gen.logMsg('diag', 'Including extension',
- extName, '(matches explicitly requested extensions to add)')
- include = True
- # Remove extensions if the name matches the regexp specified
- # in generator options. This allows forcing removal of
- # extensions from an interface even if they're tagged that
- # way in the registry.
- if regRemoveExtensions.match(extName) is not None:
- self.gen.logMsg('diag', 'Removing extension',
- extName, '(matches explicitly requested extensions to remove)')
- include = False
-
- # If the extension is to be included, add it to the
- # extension features list.
- if include:
- ei.emit = (regEmitExtensions.match(extName) is not None)
- features.append(ei)
- if not ei.emit:
- self.gen.logMsg('diag', 'NOT tagging extension',
- extName,
- 'for emission (does not match emitextensions pattern)')
-
- # Hack - can be removed when validity generator goes away
- # (Jon) I'm not sure what this does, or if it should respect
- # the ei.emit flag above.
- self.requiredextensions.append(extName)
- else:
- self.gen.logMsg('diag', 'NOT including extension',
- extName, '(does not match api attribute or explicitly requested extensions)')
-
- # Add all spirv elements to list
- # generators decide to emit them all or not
- # Currently no filtering as no client of these elements needs filtering
- spirvexts = []
- for key in self.spirvextdict:
- si = self.spirvextdict[key]
- si.emit = (regEmitSpirv.match(key) is not None)
- spirvexts.append(si)
- spirvcaps = []
- for key in self.spirvcapdict:
- si = self.spirvcapdict[key]
- si.emit = (regEmitSpirv.match(key) is not None)
- spirvcaps.append(si)
-
- # Sort the features list, if a sort procedure is defined
- if self.genOpts.sortProcedure:
- self.genOpts.sortProcedure(features)
- # print('sortProcedure ->', [f.name for f in features])
-
- # Pass 1: loop over requested API versions and extensions tagging
- # types/commands/features as required (in an <require> block) or no
- # longer required (in an <remove> block). It is possible to remove
- # a feature in one version and restore it later by requiring it in
- # a later version.
- # If a profile other than 'None' is being generated, it must
- # match the profile attribute (if any) of the <require> and
- # <remove> tags.
- self.gen.logMsg('diag', 'PASS 1: TAG FEATURES')
- for f in features:
- self.gen.logMsg('diag', 'PASS 1: Tagging required and removed features for',
- f.name)
- self.fillFeatureDictionary(f.elem, f.name, self.genOpts.apiname, self.genOpts.profile)
- self.requireAndRemoveFeatures(f.elem, f.name, self.genOpts.apiname, self.genOpts.profile)
- self.assignAdditionalValidity(f.elem, self.genOpts.apiname, self.genOpts.profile)
-
- # Now, strip references to APIs that are not required.
- # At present such references may occur in:
- # Structs in <type category="struct"> 'structextends' attributes
- # Enums in <command> 'successcodes' and 'errorcodes' attributes
- self.stripUnsupportedAPIs(self.typedict, 'structextends', self.typedict)
- self.stripUnsupportedAPIs(self.cmddict, 'successcodes', self.enumdict)
- self.stripUnsupportedAPIs(self.cmddict, 'errorcodes', self.enumdict)
-
- # @@May need to strip <spirvcapability> / <spirvextension> <enable>
- # tags of these forms:
- # <enable version="VK_API_VERSION_1_0"/>
- # <enable struct="VkPhysicalDeviceFeatures" feature="geometryShader" requires="VK_VERSION_1_0"/>
- # <enable extension="VK_KHR_shader_draw_parameters"/>
- # <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderDenormPreserveFloat16" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
-
- # Pass 2: loop over specified API versions and extensions printing
- # declarations for required things which haven't already been
- # generated.
- self.gen.logMsg('diag', 'PASS 2: GENERATE INTERFACES FOR FEATURES')
- self.gen.beginFile(self.genOpts)
- for f in features:
- self.gen.logMsg('diag', 'PASS 2: Generating interface for',
- f.name)
- emit = self.emitFeatures = f.emit
- if not emit:
- self.gen.logMsg('diag', 'PASS 2: NOT declaring feature',
- f.elem.get('name'), 'because it is not tagged for emission')
- # Generate the interface (or just tag its elements as having been
- # emitted, if they haven't been).
- self.gen.beginFeature(f.elem, emit)
- self.generateRequiredInterface(f.elem)
- self.gen.endFeature()
- # Generate spirv elements
- for s in spirvexts:
- self.generateSpirv(s, self.spirvextdict)
- for s in spirvcaps:
- self.generateSpirv(s, self.spirvcapdict)
- self.gen.endFile()
-
- def apiReset(self):
- """Reset type/enum/command dictionaries before generating another API.
-
- Use between apiGen() calls to reset internal state."""
- for datatype in self.typedict:
- self.typedict[datatype].resetState()
- for enum in self.enumdict:
- self.enumdict[enum].resetState()
- for cmd in self.cmddict:
- self.cmddict[cmd].resetState()
- for cmd in self.apidict:
- self.apidict[cmd].resetState()
-
- def __validateStructLimittypes(self, struct):
- """Validate 'limittype' attributes for a single struct."""
- limittypeDiags = namedtuple('limittypeDiags', ['missing', 'invalid'])
- badFields = defaultdict(lambda : limittypeDiags(missing=[], invalid=[]))
- validLimittypes = { 'min', 'max', 'bitmask', 'range', 'struct', 'noauto' }
- for member in struct.getMembers():
- memberName = member.findtext('name')
- if memberName in ['sType', 'pNext']:
- continue
- limittype = member.get('limittype')
- if not limittype:
- badFields[struct.elem.get('name')].missing.append(memberName)
- elif limittype == 'struct':
- typeName = member.findtext('type')
- memberType = self.typedict[typeName]
- badFields.update(self.__validateStructLimittypes(memberType))
- elif limittype not in validLimittypes:
- badFields[struct.elem.get('name')].invalid.append(memberName)
- return badFields
-
- def __validateLimittype(self):
- """Validate 'limittype' attributes."""
- self.gen.logMsg('diag', 'VALIDATING LIMITTYPE ATTRIBUTES')
- badFields = self.__validateStructLimittypes(self.typedict['VkPhysicalDeviceProperties2'])
- for featStructName in self.validextensionstructs['VkPhysicalDeviceProperties2']:
- featStruct = self.typedict[featStructName]
- badFields.update(self.__validateStructLimittypes(featStruct))
-
- if badFields:
- self.gen.logMsg('diag', 'SUMMARY OF FIELDS WITH INCORRECT LIMITTYPES')
- for key in sorted(badFields.keys()):
- diags = badFields[key]
- if diags.missing:
- self.gen.logMsg('diag', ' ', key, 'missing limittype:', ', '.join(badFields[key].missing))
- if diags.invalid:
- self.gen.logMsg('diag', ' ', key, 'invalid limittype:', ', '.join(badFields[key].invalid))
- return False
- return True
-
- def validateRegistry(self):
- """Validate properties of the registry."""
- return self.__validateLimittype()
diff --git a/codegen/vulkan/scripts/rubygenerator.py b/codegen/vulkan/scripts/rubygenerator.py
deleted file mode 100644
index 8042d9b8..00000000
--- a/codegen/vulkan/scripts/rubygenerator.py
+++ /dev/null
@@ -1,120 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-from generator import OutputGenerator, enquote, write
-from scriptgenerator import ScriptOutputGenerator
-
-def nilquote(s):
- if s:
- return enquote(s)
- else:
- return 'nil'
-
-def makeHash(name):
- return '@{} = {{'.format(name)
-
-class RubyOutputGenerator(ScriptOutputGenerator):
- """RubyOutputGenerator - subclass of ScriptOutputGenerator.
- Generates Ruby data structures describing API names and
- relationships."""
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- def beginDict(self, name):
- """String starting definition of a named dictionary"""
- return f'@{name} = {{'
-
- def endDict(self):
- """ String ending definition of a named dictionary"""
- return '}'
-
- def writeDict(self, dict, name, printValues = True):
- """Write dictionary as a Ruby hash with the given name.
- If printValues is False, just output keys with nil values."""
-
- write(self.beginDict(name), file=self.outFile)
- for key in sorted(dict):
- if printValues:
- value = nilquote(dict[key])
- else:
- value = 'nil'
- write(f'{enquote(key)} => {value},', file=self.outFile)
- write(self.endDict(), file=self.outFile)
-
- def writeList(self, l, name):
- """Write list l as a Ruby hash with the given name"""
-
- self.writeDict(l, name, printValues = False)
-
- def makeAccessor(self, name):
- """Create an accessor method for the hash 'name'"""
- write('def {}'.format(name), file=self.outFile)
- write(' @{}'.format(name), file=self.outFile)
- write('end', file=self.outFile)
-
- def endFile(self):
- # Creates the inverse mapping of nonexistent APIs to their aliases.
- super().createInverseMap()
-
- # Print out all the dictionaries as Ruby strings.
- # Use a simple container class for namespace control
- write('class APInames\n', ' def initialize', file=self.outFile)
-
- dicts = ( [ self.basetypes, 'basetypes' ],
- [ self.consts, 'consts' ],
- [ self.enums, 'enums' ],
- [ self.flags, 'flags' ],
- [ self.funcpointers, 'funcpointers' ],
- [ self.protos, 'protos' ],
- [ self.structs, 'structs' ],
- [ self.handles, 'handles' ],
- [ self.defines, 'defines' ],
- [ self.typeCategory, 'typeCategory' ],
- [ self.alias, 'aliases' ],
- [ self.nonexistent, 'nonexistent' ],
- )
- for (dict, name) in dicts:
- self.writeDict(dict, name)
-
- # Dictionary containing the relationships of a type
- # (e.g. a dictionary with each related type as keys).
- write(self.beginDict('mapDict'), file=self.outFile)
- for baseType in sorted(self.mapDict):
- # Not actually including the relationships yet
- write('{} => {},'.format(enquote(baseType), 'nil'),
- file=self.outFile)
- write(self.endDict(), file=self.outFile)
-
- # List of included feature names
- self.writeList(sorted(self.features), 'features')
-
- # Generate feature <-> interface mappings
- for feature in self.features:
- self.mapInterfaces(feature)
-
- # Write out the reverse map from APIs to requiring features
- write(self.beginDict('requiredBy'), file=self.outFile)
- for api in sorted(self.apimap):
- # Sort requirements by first feature in each one
- deps = sorted(self.apimap[api], key = lambda dep: dep[0])
- reqs = ', '.join('[{}, {}]'.format(nilquote(dep[0]), nilquote(dep[1])) for dep in deps)
- write('{} => [{}],'.format(enquote(api), reqs), file=self.outFile)
- write(self.endDict(), file=self.outFile)
-
- # Remainder of the class definition
- # End initialize method
- write('end', file=self.outFile)
-
- # Accessor methods
- for (_, name) in dicts:
- self.makeAccessor(name)
- self.makeAccessor('features')
-
- # Class end
- write('end', file=self.outFile)
-
- super().endFile()
diff --git a/codegen/vulkan/scripts/scriptgenerator.py b/codegen/vulkan/scripts/scriptgenerator.py
deleted file mode 100644
index 204639de..00000000
--- a/codegen/vulkan/scripts/scriptgenerator.py
+++ /dev/null
@@ -1,380 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-from generator import OutputGenerator, enquote, noneStr
-
-def mostOfficial(api, newapi):
- """Return the 'most official' of two related names, api and newapi.
- KHR is more official than EXT is more official than everything else.
- If there is ambiguity, return api."""
-
- if api[-3:] == 'KHR':
- return api
- if newapi[-3:] == 'KHR':
- return newapi;
- if api[-3:] == 'EXT':
- return api
- if newapi[-3:] == 'EXT':
- return newapi;
- return api
-
-class ScriptOutputGenerator(OutputGenerator):
- """ScriptOutputGenerator - subclass of OutputGenerator.
- Base class to Generate script (Python/Ruby/etc.) data structures
- describing API names and relationships.
- Similar to DocOutputGenerator, but writes a single file."""
-
- def apiName(self, name):
- """Return True if name is in the reserved API namespace.
-
- Delegates to the conventions object. """
- return self.genOpts.conventions.is_api_name(name)
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- # Track features being generated
- self.features = []
-
- # Reverse map from interface names to features requiring them
- self.apimap = {}
-
- # Reverse map from unsupported APIs in this build to aliases which
- # are supported
- self.nonexistent = {}
-
- def beginFile(self, genOpts):
- OutputGenerator.beginFile(self, genOpts)
- #
- # Dictionaries are keyed by the name of the entity (e.g.
- # self.structs is keyed by structure names). Values are
- # the names of related entities (e.g. structs contain
- # a list of type names of members, enums contain a list
- # of enumerants belong to the enumerated type, etc.), or
- # just None if there are no directly related entities.
- #
- # Collect the mappings, then emit the Python script in endFile
- self.basetypes = {}
- self.consts = {}
- self.enums = {}
- self.flags = {}
- self.funcpointers = {}
- self.protos = {}
- self.structs = {}
- self.handles = {}
- self.defines = {}
- self.alias = {}
- # Dictionary containing the type of a type name
- # (e.g. the string name of the dictionary with its contents).
- self.typeCategory = {}
- self.mapDict = {}
-
- def addInterfaceMapping(self, api, feature, required):
- """Add a reverse mapping in self.apimap from an API to a feature
- requiring that API.
-
- - api - name of the API
- - feature - name of the feature requiring it
- - required - None, or an additional feature dependency within
- 'feature' """
-
- # Each entry in self.apimap contains one or more
- # ( feature, required ) tuples.
- deps = ( feature, required )
-
- if api in self.apimap:
- self.apimap[api].append(deps)
- else:
- self.apimap[api] = [ deps ]
-
- def mapInterfaceKeys(self, feature, key):
- """Construct reverse mapping of APIs to features requiring them in
- self.apimap.
-
- - feature - name of the feature being generated
- - key - API category - 'define', 'basetype', etc."""
-
- dict = self.featureDictionary[feature][key]
-
- if dict:
- # Not clear why handling of command vs. type APIs is different -
- # see interfacedocgenerator.py, which this was based on.
- if key == 'command':
- for required in dict:
- for api in dict[required]:
- self.addInterfaceMapping(api, feature, required)
- else:
- for required in dict:
- for parent in dict[required]:
- for api in dict[required][parent]:
- self.addInterfaceMapping(api, feature, required)
-
- def mapInterfaces(self, feature):
- """Construct reverse mapping of APIs to features requiring them in
- self.apimap.
-
- - feature - name of the feature being generated"""
-
- # Map each category of interface
- self.mapInterfaceKeys(feature, 'basetype')
- self.mapInterfaceKeys(feature, 'bitmask')
- self.mapInterfaceKeys(feature, 'command')
- self.mapInterfaceKeys(feature, 'define')
- self.mapInterfaceKeys(feature, 'enum')
- self.mapInterfaceKeys(feature, 'enumconstant')
- self.mapInterfaceKeys(feature, 'funcpointer')
- self.mapInterfaceKeys(feature, 'handle')
- self.mapInterfaceKeys(feature, 'include')
- self.mapInterfaceKeys(feature, 'struct')
- self.mapInterfaceKeys(feature, 'union')
-
- def endFile(self):
- super().endFile()
-
- def beginFeature(self, interface, emit):
- # Start processing in superclass
- OutputGenerator.beginFeature(self, interface, emit)
-
- # Add this feature to the list being tracked
- self.features.append( self.featureName )
-
- def endFeature(self):
- # Finish processing in superclass
- OutputGenerator.endFeature(self)
-
- def addName(self, dict, name, value):
- """Add a string entry to the dictionary, quoting it so it gets
- printed out correctly in self.endFile()."""
- dict[name] = value
-
- def addMapping(self, baseType, refType):
- """Add a mapping between types to mapDict.
-
- Only include API types, so we don't end up with a lot of useless uint32_t and void types."""
- if not self.apiName(baseType) or not self.apiName(refType):
- self.logMsg('diag', 'ScriptOutputGenerator::addMapping: IGNORE map from', baseType, '<->', refType)
- return
-
- self.logMsg('diag', 'ScriptOutputGenerator::addMapping: map from',
- baseType, '<->', refType)
-
- if baseType not in self.mapDict:
- baseDict = {}
- self.mapDict[baseType] = baseDict
- else:
- baseDict = self.mapDict[baseType]
- if refType not in self.mapDict:
- refDict = {}
- self.mapDict[refType] = refDict
- else:
- refDict = self.mapDict[refType]
-
- baseDict[refType] = None
- refDict[baseType] = None
-
- def breakCheck(self, procname, name):
- """Debugging aid - call from procname to break on API 'name' if it
- matches logic in this call."""
-
- pat = 'VkExternalFenceFeatureFlagBits'
- if name[0:len(pat)] == pat:
- print('{}(name = {}) matches {}'.format(procname, name, pat))
- import pdb
- pdb.set_trace()
-
- def genType(self, typeinfo, name, alias):
- """Generate type.
-
- - For 'struct' or 'union' types, defer to genStruct() to
- add to the dictionary.
- - For 'bitmask' types, add the type name to the 'flags' dictionary,
- with the value being the corresponding 'enums' name defining
- the acceptable flag bits.
- - For 'enum' types, add the type name to the 'enums' dictionary,
- with the value being '@STOPHERE@' (because this case seems
- never to happen).
- - For 'funcpointer' types, add the type name to the 'funcpointers'
- dictionary.
- - For 'handle' and 'define' types, add the handle or #define name
- to the 'struct' dictionary, because that's how the spec sources
- tag these types even though they aren't structs."""
- OutputGenerator.genType(self, typeinfo, name, alias)
-
- typeElem = typeinfo.elem
- # If the type is a struct type, traverse the embedded <member> tags
- # generating a structure. Otherwise, emit the tag text.
- category = typeElem.get('category')
-
- # Add a typeCategory{} entry for the category of this type.
- self.addName(self.typeCategory, name, category)
-
- if category in ('struct', 'union'):
- self.genStruct(typeinfo, name, alias)
- else:
- if alias:
- # Add name -> alias mapping
- self.addName(self.alias, name, alias)
-
- # Always emit an alias (?!)
- count = 1
-
- # May want to only emit full type definition when not an alias?
- else:
- # Extract the type name
- # (from self.genOpts). Copy other text through unchanged.
- # If the resulting text is an empty string, don't emit it.
- count = len(noneStr(typeElem.text))
- for elem in typeElem:
- count += len(noneStr(elem.text)) + len(noneStr(elem.tail))
-
- if count > 0:
- if category == 'bitmask':
- requiredEnum = typeElem.get('requires')
- self.addName(self.flags, name, requiredEnum)
-
- # This happens when the Flags type is defined, but no
- # FlagBits are defined yet.
- if requiredEnum is not None:
- self.addMapping(name, requiredEnum)
- elif category == 'enum':
- # This case does not seem to come up. It nominally would
- # result from
- # <type name="Something" category="enum"/>,
- # but the output generator doesn't emit them directly.
- self.logMsg('warn', 'ScriptOutputGenerator::genType: invalid \'enum\' category for name:', name)
- elif category == 'funcpointer':
- self.funcpointers[name] = None
- elif category == 'handle':
- self.handles[name] = None
- elif category == 'define':
- self.defines[name] = None
- elif category == 'basetype':
- # Don't add an entry for base types that are not API types
- # e.g. an API Bool type gets an entry, uint32_t does not
- if self.apiName(name):
- self.basetypes[name] = None
- self.addName(self.typeCategory, name, 'basetype')
- else:
- self.logMsg('diag', 'ScriptOutputGenerator::genType: unprocessed type:', name, 'category:', category)
- else:
- self.logMsg('diag', 'ScriptOutputGenerator::genType: unprocessed type:', name)
-
- def genStruct(self, typeinfo, typeName, alias):
- """Generate struct (e.g. C "struct" type).
-
- Add the struct name to the 'structs' dictionary, with the
- value being an ordered list of the struct member names."""
- OutputGenerator.genStruct(self, typeinfo, typeName, alias)
-
- if alias:
- # Add name -> alias mapping
- self.addName(self.alias, typeName, alias)
- else:
- # May want to only emit definition on this branch
- True
-
- members = [member.text for member in typeinfo.elem.findall('.//member/name')]
- self.structs[typeName] = members
- memberTypes = [member.text for member in typeinfo.elem.findall('.//member/type')]
- for member_type in memberTypes:
- self.addMapping(typeName, member_type)
-
- def genGroup(self, groupinfo, groupName, alias):
- """Generate group (e.g. C "enum" type).
-
- These are concatenated together with other types.
-
- - Add the enum type name to the 'enums' dictionary, with
- the value being an ordered list of the enumerant names.
- - Add each enumerant name to the 'consts' dictionary, with
- the value being the enum type the enumerant is part of."""
- OutputGenerator.genGroup(self, groupinfo, groupName, alias)
- groupElem = groupinfo.elem
-
- # Add a typeCategory{} entry for the category of this type.
- self.addName(self.typeCategory, groupName, 'group')
-
- if alias:
- # Add name -> alias mapping
- self.addName(self.alias, groupName, alias)
- else:
- # May want to only emit definition on this branch
- True
-
- # Add each nested 'enum' tag
- enumerants = [elem.get('name') for elem in groupElem.findall('enum')]
- for name in enumerants:
- self.addName(self.consts, name, groupName)
-
- # Sort enums for output stability, since their order is irrelevant
- self.enums[groupName] = sorted(enumerants)
-
- def genEnum(self, enuminfo, name, alias):
- """Generate enumerant (compile-time constants).
-
- - Add the constant name to the 'consts' dictionary, with the
- value being None to indicate that the constant isn't
- an enumeration value."""
- OutputGenerator.genEnum(self, enuminfo, name, alias)
-
- if name not in self.consts:
- # Add a typeCategory{} entry for the category of this type.
- self.addName(self.typeCategory, name, 'consts')
- self.consts[name] = None
- # Otherwise, don't add it to the consts dictionary because it's
- # already present. This happens due to the generator 'reparentEnums'
- # parameter being False, so each extension enum appears in both the
- # <enums> type and in the <extension> or <feature> it originally
- # came from.
-
- def genCmd(self, cmdinfo, name, alias):
- """Generate command.
-
- - Add the command name to the 'protos' dictionary, with the
- value being an ordered list of the parameter names."""
- OutputGenerator.genCmd(self, cmdinfo, name, alias)
-
- # Add a typeCategory{} entry for the category of this type.
- self.addName(self.typeCategory, name, 'protos')
-
- if alias:
- # Add name -> alias mapping
- self.addName(self.alias, name, alias)
- else:
- # May want to only emit definition on this branch
- True
-
- params = [param.text for param in cmdinfo.elem.findall('param/name')]
- self.protos[name] = params
- paramTypes = [param.text for param in cmdinfo.elem.findall('param/type')]
- for param_type in paramTypes:
- self.addMapping(name, param_type)
-
- def createInverseMap(self):
- """This creates the inverse mapping of nonexistent APIs in this
- build to their aliases which are supported. Must be called by
- language-specific subclasses before emitting that mapping."""
-
- # Map from APIs not supported in this build to aliases that are.
- # When there are multiple valid choices for remapping, choose the
- # most-official suffixed one (KHR > EXT > vendor).
- for key in self.alias:
- # If the API key is aliased to something which doesn't exist,
- # then add the thing that doesn't exist to the nonexistent map.
- # This is used in spec macros to make promoted extension links
- # in specs built without the promoted interface refer to the
- # older interface instead.
-
- invkey = self.alias[key]
-
- if invkey not in self.typeCategory:
- if invkey in self.nonexistent:
- # Potentially remap existing mapping to a more official
- # alias.
- self.nonexistent[invkey] = mostOfficial(self.nonexistent[invkey], key)
- else:
- # Create remapping to an alias
- self.nonexistent[invkey] = key
diff --git a/codegen/vulkan/scripts/spec_tools/__init__.py b/codegen/vulkan/scripts/spec_tools/__init__.py
deleted file mode 100644
index 34c01f39..00000000
--- a/codegen/vulkan/scripts/spec_tools/__init__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright (c) 2018-2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
diff --git a/codegen/vulkan/scripts/spec_tools/algo.py b/codegen/vulkan/scripts/spec_tools/algo.py
deleted file mode 100644
index 3b4c81f4..00000000
--- a/codegen/vulkan/scripts/spec_tools/algo.py
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright (c) 2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-"""RecursiveMemoize serves as a base class for a function modeled
-as a dictionary computed on-the-fly."""
-
-
-class RecursiveMemoize:
- """Base class for functions that are recursive.
-
- Derive and implement `def compute(self, key):` to perform the computation:
- you may use __getitem__ (aka self[otherkey]) to access the results for
- another key. Each value will be computed at most once. Your
- function should never return None, since it is used as a sentinel here.
-
- """
-
- def __init__(self, func, key_iterable=None, permit_cycles=False):
- """Initialize data structures, and optionally compute/cache the answer
- for all elements of an iterable.
-
- If permit_cycles is False, then __getitem__ on something that's
- currently being computed raises an exception.
- If permit_cycles is True, then __getitem__ on something that's
- currently being computed returns None.
- """
- self._compute = func
- self.permit_cycles = permit_cycles
- self.d = {}
- if key_iterable:
- # If we were given an iterable, let's populate those.
- for key in key_iterable:
- _ = self[key]
-
- def __getitem__(self, key):
- """Access the result of computing the function on the input.
-
- Performed lazily and cached.
- Implement `def compute(self, key):` with the actual function,
- which will be called on demand."""
- if key in self.d:
- ret = self.d[key]
- # Detect "we're computing this" sentinel and
- # fail if cycles not permitted
- if ret is None and not self.permit_cycles:
- raise RuntimeError("Cycle detected when computing function: " +
- "f({}) depends on itself".format(key))
- # return the memoized value
- # (which might be None if we're in a cycle that's permitted)
- return ret
-
- # Set sentinel for "we're computing this"
- self.d[key] = None
- # Delegate to function to actually compute
- ret = self._compute(key)
- # Memoize
- self.d[key] = ret
-
- return ret
-
- def get_dict(self):
- """Return the dictionary where memoized results are stored.
-
- DO NOT MODIFY!"""
- return self.d
diff --git a/codegen/vulkan/scripts/spec_tools/attributes.py b/codegen/vulkan/scripts/spec_tools/attributes.py
deleted file mode 100644
index ef771811..00000000
--- a/codegen/vulkan/scripts/spec_tools/attributes.py
+++ /dev/null
@@ -1,114 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-"""Utilities for working with attributes of the XML registry."""
-
-import re
-
-_PARAM_REF_NAME_RE = re.compile(
- r"(?P<name>[\w]+)(?P<brackets>\[\])?(?P<delim>\.|::|->)?")
-
-
-def _split_param_ref(val):
- return [name for name, _, _ in _PARAM_REF_NAME_RE.findall(val)]
-
-
-def _human_readable_deref(val, make_param_name=None):
- """Turn the "name[].member[]" notation into plain English."""
- parts = []
- matches = _PARAM_REF_NAME_RE.findall(val)
- for name, brackets, delim in reversed(matches):
- if make_param_name:
- name = make_param_name(name)
- if delim:
- parts.append('member of')
- if brackets:
- parts.append('each element of')
- parts.append('the')
- parts.append(name)
- parts.append('parameter')
- return ' '.join(parts)
-
-
-class LengthEntry:
- """An entry in a (comma-separated) len attribute"""
- NULL_TERMINATED_STRING = 'null-terminated'
- MATH_STRING = 'latexmath:'
-
- def __init__(self, val):
- self.full_reference = val
- self.other_param_name = None
- self.null_terminated = False
- self.number = None
- self.math = None
- self.param_ref_parts = None
- if val == LengthEntry.NULL_TERMINATED_STRING:
- self.null_terminated = True
- return
-
- if val.startswith(LengthEntry.MATH_STRING):
- self.math = val.replace(LengthEntry.MATH_STRING, '')[1:-1]
- return
-
- if val.isdigit():
- self.number = int(val)
- return
-
- # Must be another param name.
- self.param_ref_parts = _split_param_ref(val)
- self.other_param_name = self.param_ref_parts[0]
-
- def __str__(self):
- return self.full_reference
-
- def get_human_readable(self, make_param_name=None):
- assert(self.other_param_name)
- return _human_readable_deref(self.full_reference, make_param_name=make_param_name)
-
- def __repr__(self):
- "Formats an object for repr(), debugger display, etc."
- return 'spec_tools.attributes.LengthEntry("{}")'.format(self.full_reference)
-
- @staticmethod
- def parse_len_from_param(param):
- """Get a list of LengthEntry."""
- len_str = param.get('len')
- if len_str is None:
- return None
- return [LengthEntry(elt) for elt in len_str.split(',')]
-
-
-class ExternSyncEntry:
- """An entry in a (comma-separated) externsync attribute"""
-
- TRUE_STRING = 'true'
- TRUE_WITH_CHILDREN_STRING = 'true_with_children'
-
- def __init__(self, val):
- self.full_reference = val
- self.entirely_extern_sync = (val in (ExternSyncEntry.TRUE_STRING, ExternSyncEntry.TRUE_WITH_CHILDREN_STRING))
- self.children_extern_sync = (val == ExternSyncEntry.TRUE_WITH_CHILDREN_STRING)
- if self.entirely_extern_sync:
- return
-
- self.param_ref_parts = _split_param_ref(val)
- self.member = self.param_ref_parts[0]
-
- def get_human_readable(self, make_param_name=None):
- assert(not self.entirely_extern_sync)
- return _human_readable_deref(self.full_reference, make_param_name=make_param_name)
-
- @staticmethod
- def parse_externsync_from_param(param):
- """Get a list of ExternSyncEntry."""
- sync_str = param.get('externsync')
- if sync_str is None:
- return None
- return [ExternSyncEntry(elt) for elt in sync_str.split(',')]
-
- def __repr__(self):
- "Formats an object for repr(), debugger display, etc."
- return 'spec_tools.attributes.ExternSyncEntry("{}")'.format(self.full_reference)
-
diff --git a/codegen/vulkan/scripts/spec_tools/base_printer.py b/codegen/vulkan/scripts/spec_tools/base_printer.py
deleted file mode 100644
index f48905ac..00000000
--- a/codegen/vulkan/scripts/spec_tools/base_printer.py
+++ /dev/null
@@ -1,213 +0,0 @@
-"""Provides the BasePrinter base class for MacroChecker/Message output techniques."""
-
-# Copyright (c) 2018-2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-
-from abc import ABC, abstractmethod
-from pathlib import Path
-
-from .macro_checker import MacroChecker
-from .macro_checker_file import MacroCheckerFile
-from .shared import EntityData, Message, MessageContext, MessageType
-
-
-def getColumn(message_context):
- """Return the (zero-based) column number of the message context.
-
- If a group is specified: returns the column of the start of the group.
- If no group, but a match is specified: returns the column of the start of
- the match.
- If no match: returns column 0 (whole line).
- """
- if not message_context.match:
- # whole line
- return 0
- if message_context.group is not None:
- return message_context.match.start(message_context.group)
- return message_context.match.start()
-
-
-class BasePrinter(ABC):
- """Base class for a way of outputting results of a checker execution."""
-
- def __init__(self):
- """Constructor."""
- self._cwd = None
-
- def close(self):
- """Write the tail end of the output and close it, if applicable.
-
- Override if you want to print a summary or are writing to a file.
- """
- pass
-
- ###
- # Output methods: these should all print/output directly.
- def output(self, obj):
- """Output any object.
-
- Delegates to other output* methods, if type known,
- otherwise uses self.outputFallback().
- """
- if isinstance(obj, Message):
- self.outputMessage(obj)
- elif isinstance(obj, MacroCheckerFile):
- self.outputCheckerFile(obj)
- elif isinstance(obj, MacroChecker):
- self.outputChecker(obj)
- else:
- self.outputFallback(self.formatBrief(obj))
-
- @abstractmethod
- def outputResults(self, checker, broken_links=True,
- missing_includes=False):
- """Output the full results of a checker run.
-
- Must be implemented.
-
- Typically will call self.output() on the MacroChecker,
- as well as calling self.outputBrokenAndMissing()
- """
- raise NotImplementedError
-
- @abstractmethod
- def outputBrokenLinks(self, checker, broken):
- """Output the collection of broken links.
-
- `broken` is a dictionary of entity names: usage contexts.
-
- Must be implemented.
-
- Called by self.outputBrokenAndMissing() if requested.
- """
- raise NotImplementedError
-
- @abstractmethod
- def outputMissingIncludes(self, checker, missing):
- """Output a table of missing includes.
-
- `missing` is a iterable entity names.
-
- Must be implemented.
-
- Called by self.outputBrokenAndMissing() if requested.
- """
- raise NotImplementedError
-
- def outputChecker(self, checker):
- """Output the contents of a MacroChecker object.
-
- Default implementation calls self.output() on every MacroCheckerFile.
- """
- for f in checker.files:
- self.output(f)
-
- def outputCheckerFile(self, fileChecker):
- """Output the contents of a MacroCheckerFile object.
-
- Default implementation calls self.output() on every Message.
- """
- for m in fileChecker.messages:
- self.output(m)
-
- def outputBrokenAndMissing(self, checker, broken_links=True,
- missing_includes=False):
- """Outputs broken links and missing includes, if desired.
-
- Delegates to self.outputBrokenLinks() (if broken_links==True)
- and self.outputMissingIncludes() (if missing_includes==True).
- """
- if broken_links:
- broken = checker.getBrokenLinks()
- if broken:
- self.outputBrokenLinks(checker, broken)
- if missing_includes:
- missing = checker.getMissingUnreferencedApiIncludes()
- if missing:
- self.outputMissingIncludes(checker, missing)
-
- @abstractmethod
- def outputMessage(self, msg):
- """Output a Message.
-
- Must be implemented.
- """
- raise NotImplementedError
-
- @abstractmethod
- def outputFallback(self, msg):
- """Output some text in a general way.
-
- Must be implemented.
- """
- raise NotImplementedError
-
- ###
- # Format methods: these should all return a string.
- def formatContext(self, context, _message_type=None):
- """Format a message context in a verbose way, if applicable.
-
- May override, default implementation delegates to
- self.formatContextBrief().
- """
- return self.formatContextBrief(context)
-
- def formatContextBrief(self, context, _with_color=True):
- """Format a message context in a brief way.
-
- May override, default is relativeFilename:line:column
- """
- return '{}:{}:{}'.format(self.getRelativeFilename(context.filename),
- context.lineNum, getColumn(context))
-
- def formatMessageTypeBrief(self, message_type, _with_color=True):
- """Format a message type in a brief way.
-
- May override, default is message_type:
- """
- return '{}:'.format(message_type)
-
- def formatEntityBrief(self, entity_data, _with_color=True):
- """Format an entity in a brief way.
-
- May override, default is macro:entity.
- """
- return '{}:{}'.format(entity_data.macro, entity_data.entity)
-
- def formatBrief(self, obj, with_color=True):
- """Format any object in a brief way.
-
- Delegates to other format*Brief methods, if known,
- otherwise uses str().
- """
- if isinstance(obj, MessageContext):
- return self.formatContextBrief(obj, with_color)
- if isinstance(obj, MessageType):
- return self.formatMessageTypeBrief(obj, with_color)
- if isinstance(obj, EntityData):
- return self.formatEntityBrief(obj, with_color)
- return str(obj)
-
- @property
- def cwd(self):
- """Get the current working directory, fully resolved.
-
- Lazy initialized.
- """
- if not self._cwd:
- self._cwd = Path('.').resolve()
- return self._cwd
-
- ###
- # Helper function
- def getRelativeFilename(self, fn):
- """Return the given filename relative to the current directory,
- if possible.
- """
- try:
- return str(Path(fn).relative_to(self.cwd))
- except ValueError:
- return str(Path(fn))
diff --git a/codegen/vulkan/scripts/spec_tools/consistency_tools.py b/codegen/vulkan/scripts/spec_tools/consistency_tools.py
deleted file mode 100644
index c256a724..00000000
--- a/codegen/vulkan/scripts/spec_tools/consistency_tools.py
+++ /dev/null
@@ -1,697 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright (c) 2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-"""Provides utilities to write a script to verify XML registry consistency."""
-
-import re
-
-import networkx as nx
-
-from .algo import RecursiveMemoize
-from .attributes import ExternSyncEntry, LengthEntry
-from .data_structures import DictOfStringSets
-from .util import findNamedElem, getElemName
-
-
-class XMLChecker:
- def __init__(self, entity_db, conventions, manual_types_to_codes=None,
- forward_only_types_to_codes=None,
- reverse_only_types_to_codes=None,
- suppressions=None):
- """Set up data structures.
-
- May extend - call:
- `super().__init__(db, conventions, manual_types_to_codes)`
- as the last statement in your function.
-
- manual_types_to_codes is a dictionary of hard-coded
- "manual" return codes:
- the codes of the value are available for a command if-and-only-if
- the key type is passed as an input.
-
- forward_only_types_to_codes is additional entries to the above
- that should only be used in the "forward" direction
- (arg type implies return code)
-
- reverse_only_types_to_codes is additional entries to
- manual_types_to_codes that should only be used in the
- "reverse" direction
- (return code implies arg type)
- """
- self.fail = False
- self.entity = None
- self.errors = DictOfStringSets()
- self.warnings = DictOfStringSets()
- self.db = entity_db
- self.reg = entity_db.registry
- self.handle_data = HandleData(self.reg)
- self.conventions = conventions
-
- self.CONST_RE = re.compile(r"\bconst\b")
- self.ARRAY_RE = re.compile(r"\[[^]]+\]")
-
- # Init memoized properties
- self._handle_data = None
-
- if not manual_types_to_codes:
- manual_types_to_codes = {}
- if not reverse_only_types_to_codes:
- reverse_only_types_to_codes = {}
- if not forward_only_types_to_codes:
- forward_only_types_to_codes = {}
-
- reverse_codes = DictOfStringSets(reverse_only_types_to_codes)
- forward_codes = DictOfStringSets(forward_only_types_to_codes)
- for k, v in manual_types_to_codes.items():
- forward_codes.add(k, v)
- reverse_codes.add(k, v)
-
- self.forward_only_manual_types_to_codes = forward_codes.get_dict()
- self.reverse_only_manual_types_to_codes = reverse_codes.get_dict()
-
- # The presence of some types as input to a function imply the
- # availability of some return codes.
- self.input_type_to_codes = compute_type_to_codes(
- self.handle_data,
- forward_codes,
- extra_op=self.add_extra_codes)
-
- # Some return codes require a type (or its child) in the input.
- self.codes_requiring_input_type = compute_codes_requiring_type(
- self.handle_data,
- reverse_codes
- )
-
- specified_codes = set(self.codes_requiring_input_type.keys())
- for codes in self.forward_only_manual_types_to_codes.values():
- specified_codes.update(codes)
- for codes in self.reverse_only_manual_types_to_codes.values():
- specified_codes.update(codes)
- for codes in self.input_type_to_codes.values():
- specified_codes.update(codes)
-
- unrecognized = specified_codes - self.return_codes
- if unrecognized:
- raise RuntimeError("Return code mentioned in script that isn't in the registry: " +
- ', '.join(unrecognized))
-
- self.referenced_input_types = ReferencedTypes(self.db, self.is_input)
- self.referenced_api_types = ReferencedTypes(self.db, self.is_api_type)
- if not suppressions:
- suppressions = {}
- self.suppressions = DictOfStringSets(suppressions)
-
- def is_api_type(self, member_elem):
- """Return true if the member/parameter ElementTree passed is from this API.
-
- May override or extend."""
- membertext = "".join(member_elem.itertext())
-
- return self.conventions.type_prefix in membertext
-
- def is_input(self, member_elem):
- """Return true if the member/parameter ElementTree passed is
- considered "input".
-
- May override or extend."""
- membertext = "".join(member_elem.itertext())
-
- if self.conventions.type_prefix not in membertext:
- return False
-
- ret = True
- # Const is always input.
- if self.CONST_RE.search(membertext):
- ret = True
-
- # Arrays and pointers that aren't const are always output.
- elif "*" in membertext:
- ret = False
- elif self.ARRAY_RE.search(membertext):
- ret = False
-
- return ret
-
- def add_extra_codes(self, types_to_codes):
- """Add any desired entries to the types-to-codes DictOfStringSets
- before performing "ancestor propagation".
-
- Passed to compute_type_to_codes as the extra_op.
-
- May override."""
- pass
-
- def should_skip_checking_codes(self, name):
- """Return True if more than the basic validation of return codes should
- be skipped for a command.
-
- May override."""
-
- return self.conventions.should_skip_checking_codes
-
- def get_codes_for_command_and_type(self, cmd_name, type_name):
- """Return a set of error codes expected due to having
- an input argument of type type_name.
-
- The cmd_name is passed for use by extending methods.
-
- May extend."""
- return self.input_type_to_codes.get(type_name, set())
-
- def check(self):
- """Iterate through the registry, looking for consistency problems.
-
- Outputs error messages at the end."""
- # Iterate through commands, looking for consistency problems.
- for name, info in self.reg.cmddict.items():
- self.set_error_context(entity=name, elem=info.elem)
-
- self.check_command(name, info)
-
- for name, info in self.reg.typedict.items():
- cat = info.elem.get('category')
- if not cat:
- # This is an external thing, skip it.
- continue
- self.set_error_context(entity=name, elem=info.elem)
-
- self.check_type(name, info, cat)
-
- # check_extension is called for all extensions, even 'disabled'
- # ones, but some checks may be skipped depending on extension
- # status.
- for name, info in self.reg.extdict.items():
- self.set_error_context(entity=name, elem=info.elem)
- self.check_extension(name, info)
-
- entities_with_messages = set(
- self.errors.keys()).union(self.warnings.keys())
- if entities_with_messages:
- print('xml_consistency/consistency_tools error and warning messages follow.')
-
- for entity in entities_with_messages:
- print()
- print('-------------------')
- print('Messages for', entity)
- print()
- messages = self.errors.get(entity)
- if messages:
- for m in messages:
- print('Error:', m)
-
- messages = self.warnings.get(entity)
- if messages:
- for m in messages:
- print('Warning:', m)
-
- def check_param(self, param):
- """Check a member of a struct or a param of a function.
-
- Called from check_params.
-
- May extend."""
- param_name = getElemName(param)
- externsyncs = ExternSyncEntry.parse_externsync_from_param(param)
- if externsyncs:
- for entry in externsyncs:
- if entry.entirely_extern_sync:
- if len(externsyncs) > 1:
- self.record_error("Comma-separated list in externsync attribute includes 'true' for",
- param_name)
- else:
- # member name
- # TODO only looking at the superficial feature here,
- # not entry.param_ref_parts
- if entry.member != param_name:
- self.record_error("externsync attribute for", param_name,
- "refers to some other member/parameter:", entry.member)
-
- def check_params(self, params):
- """Check the members of a struct or params of a function.
-
- Called from check_type and check_command.
-
- May extend."""
- for param in params:
- self.check_param(param)
-
- # Check for parameters referenced by len= attribute
- lengths = LengthEntry.parse_len_from_param(param)
- if lengths:
- for entry in lengths:
- if not entry.other_param_name:
- continue
- # TODO only looking at the superficial feature here,
- # not entry.param_ref_parts
- other_param = findNamedElem(params, entry.other_param_name)
- if other_param is None:
- self.record_error("References a non-existent parameter/member in the length of",
- getElemName(param), ":", entry.other_param_name)
-
- def check_type(self, name, info, category):
- """Check a type's XML data for consistency.
-
- Called from check.
-
- May extend."""
- if category == 'struct':
- if not name.startswith(self.conventions.type_prefix):
- self.record_error("Name does not start with",
- self.conventions.type_prefix)
- members = info.elem.findall('member')
- self.check_params(members)
-
- # Check the structure type member, if present.
- type_member = findNamedElem(
- members, self.conventions.structtype_member_name)
- if type_member is not None:
- val = type_member.get('values')
- if val:
- expected = self.conventions.generate_structure_type_from_name(
- name)
- if val != expected:
- self.record_error("Type has incorrect type-member value: expected",
- expected, "got", val)
-
- elif category == "bitmask":
- if 'Flags' not in name:
- self.record_error("Name of bitmask doesn't include 'Flags'")
-
- def check_extension(self, name, info):
- """Check an extension's XML data for consistency.
-
- Called from check.
-
- May extend."""
- pass
-
- def check_command(self, name, info):
- """Check a command's XML data for consistency.
-
- Called from check.
-
- May extend."""
- elem = info.elem
-
- self.check_params(elem.findall('param'))
-
- # Some minimal return code checking
- errorcodes = elem.get("errorcodes")
- if errorcodes:
- errorcodes = errorcodes.split(",")
- else:
- errorcodes = []
-
- successcodes = elem.get("successcodes")
- if successcodes:
- successcodes = successcodes.split(",")
- else:
- successcodes = []
-
- if not successcodes and not errorcodes:
- # Early out if no return codes.
- return
-
- # Create a set for each group of codes, and check that
- # they aren't duplicated within or between groups.
- errorcodes_set = set(errorcodes)
- if len(errorcodes) != len(errorcodes_set):
- self.record_error("Contains a duplicate in errorcodes")
-
- successcodes_set = set(successcodes)
- if len(successcodes) != len(successcodes_set):
- self.record_error("Contains a duplicate in successcodes")
-
- if not successcodes_set.isdisjoint(errorcodes_set):
- self.record_error("Has errorcodes and successcodes that overlap")
-
- self.check_command_return_codes_basic(
- name, info, successcodes_set, errorcodes_set)
-
- # Continue to further return code checking if not "complicated"
- if not self.should_skip_checking_codes(name):
- codes_set = successcodes_set.union(errorcodes_set)
- self.check_command_return_codes(
- name, info, successcodes_set, errorcodes_set, codes_set)
-
- def check_command_return_codes_basic(self, name, info,
- successcodes, errorcodes):
- """Check a command's return codes for consistency.
-
- Called from check_command on every command.
-
- May extend."""
-
- # Check that all error codes include _ERROR_,
- # and that no success codes do.
- for code in errorcodes:
- if "_ERROR_" not in code:
- self.record_error(
- code, "in errorcodes but doesn't contain _ERROR_")
-
- for code in successcodes:
- if "_ERROR_" in code:
- self.record_error(code, "in successcodes but contain _ERROR_")
-
- def check_command_return_codes(self, name, type_info,
- successcodes, errorcodes,
- codes):
- """Check a command's return codes in-depth for consistency.
-
- Called from check_command, only if
- `self.should_skip_checking_codes(name)` is False.
-
- May extend."""
- referenced_input = self.referenced_input_types[name]
- referenced_types = self.referenced_api_types[name]
-
- # Check that we have all the codes we expect, based on input types.
- for referenced_type in referenced_input:
- required_codes = self.get_codes_for_command_and_type(
- name, referenced_type)
- missing_codes = required_codes - codes
- if missing_codes:
- path = self.referenced_input_types.shortest_path(
- name, referenced_type)
- path_str = " -> ".join(path)
- self.record_error("Missing expected return code(s)",
- ",".join(missing_codes),
- "implied because of input of type",
- referenced_type,
- "found via path",
- path_str)
-
- # Check that, for each code returned by this command that we can
- # associate with a type, we have some type that can provide it.
- # e.g. can't have INSTANCE_LOST without an Instance
- # (or child of Instance).
- for code in codes:
-
- required_types = self.codes_requiring_input_type.get(code)
- if not required_types:
- # This code doesn't have a known requirement
- continue
-
- # TODO: do we look at referenced_types or referenced_input here?
- # the latter is stricter
- if not referenced_types.intersection(required_types):
- self.record_error("Unexpected return code", code,
- "- none of these types:",
- required_types,
- "found in the set of referenced types",
- referenced_types)
-
- ###
- # Utility properties/methods
- ###
-
- def set_error_context(self, entity=None, elem=None):
- """Set the entity and/or element for future record_error calls."""
- self.entity = entity
- self.elem = elem
- self.name = getElemName(elem)
- self.entity_suppressions = self.suppressions.get(getElemName(elem))
-
- def record_error(self, *args, **kwargs):
- """Record failure and an error message for the current context."""
- message = " ".join((str(x) for x in args))
-
- if self._is_message_suppressed(message):
- return
-
- message = self._prepend_sourceline_to_message(message, **kwargs)
- self.fail = True
- self.errors.add(self.entity, message)
-
- def record_warning(self, *args, **kwargs):
- """Record a warning message for the current context."""
- message = " ".join((str(x) for x in args))
-
- if self._is_message_suppressed(message):
- return
-
- message = self._prepend_sourceline_to_message(message, **kwargs)
- self.warnings.add(self.entity, message)
-
- def _is_message_suppressed(self, message):
- """Return True if the given message, for this entity, should be suppressed."""
- if not self.entity_suppressions:
- return False
- for suppress in self.entity_suppressions:
- if suppress in message:
- return True
-
- return False
-
- def _prepend_sourceline_to_message(self, message, **kwargs):
- """Prepend a file and/or line reference to the message, if possible.
-
- If filename is given as a keyword argument, it is used on its own.
-
- If filename is not given, this will attempt to retrieve the filename and line from an XML element.
- If 'elem' is given as a keyword argument and is not None, it is used to find the line.
- If 'elem' is given as None, no XML elements are looked at.
- If 'elem' is not supplied, the error context element is used.
-
- If using XML, the filename, if available, is retrieved from the Registry class.
- If using XML and python-lxml is installed, the source line is retrieved from whatever element is chosen."""
- fn = kwargs.get('filename')
- sourceline = None
-
- if fn is None:
- elem = kwargs.get('elem', self.elem)
- if elem is not None:
- sourceline = getattr(elem, 'sourceline', None)
- if self.reg.filename:
- fn = self.reg.filename
-
- if fn is None and sourceline is None:
- return message
-
- if fn is None:
- return "Line {}: {}".format(sourceline, message)
-
- if sourceline is None:
- return "{}: {}".format(fn, message)
-
- return "{}:{}: {}".format(fn, sourceline, message)
-
-
-class HandleParents(RecursiveMemoize):
- def __init__(self, handle_types):
- self.handle_types = handle_types
-
- def compute(handle_type):
- immediate_parent = self.handle_types[handle_type].elem.get(
- 'parent')
-
- if immediate_parent is None:
- # No parents, no need to recurse
- return []
-
- # Support multiple (alternate) parents
- immediate_parents = immediate_parent.split(',')
-
- # Recurse, combine, and return
- all_parents = immediate_parents[:]
- for parent in immediate_parents:
- all_parents.extend(self[parent])
- return all_parents
-
- super().__init__(compute, handle_types.keys())
-
-
-def _always_true(x):
- return True
-
-
-class ReferencedTypes(RecursiveMemoize):
- """Find all types(optionally matching a predicate) that are referenced
- by a struct or function, recursively."""
-
- def __init__(self, db, predicate=None):
- """Initialize.
-
- Provide an EntityDB object and a predicate function."""
- self.db = db
-
- self.predicate = predicate
- if not self.predicate:
- # Default predicate is "anything goes"
- self.predicate = _always_true
-
- self._directly_referenced = {}
- self.graph = nx.DiGraph()
-
- def compute(type_name):
- """Compute and return all types referenced by type_name, recursively, that satisfy the predicate.
-
- Called by the [] operator in the base class."""
- types = self.directly_referenced(type_name)
- if not types:
- return types
-
- all_types = set()
- all_types.update(types)
- for t in types:
- referenced = self[t]
- if referenced is not None:
- # If not leading to a cycle
- all_types.update(referenced)
- return all_types
-
- # Initialize base class
- super().__init__(compute, permit_cycles=True)
-
- def shortest_path(self, source, target):
- """Get the shortest path between one type/function name and another."""
- # Trigger computation
- _ = self[source]
-
- return nx.algorithms.shortest_path(self.graph, source=source, target=target)
-
- def directly_referenced(self, type_name):
- """Get all types referenced directly by type_name that satisfy the predicate.
-
- Memoizes its results."""
- if type_name not in self._directly_referenced:
- members = self.db.getMemberElems(type_name)
- if members:
- types = ((member, member.find("type")) for member in members)
- self._directly_referenced[type_name] = set(type_elem.text for (member, type_elem) in types
- if type_elem is not None and self.predicate(member))
-
- else:
- self._directly_referenced[type_name] = set()
-
- # Update graph
- self.graph.add_node(type_name)
- self.graph.add_edges_from((type_name, t)
- for t in self._directly_referenced[type_name])
-
- return self._directly_referenced[type_name]
-
-
-class HandleData:
- """Data about all the handle types available in an API specification."""
-
- def __init__(self, registry):
- self.reg = registry
- self._handle_types = None
- self._ancestors = None
- self._descendants = None
-
- @property
- def handle_types(self):
- """Return a dictionary of handle type names to type info."""
- if not self._handle_types:
- # First time requested - compute it.
- self._handle_types = {
- type_name: type_info
- for type_name, type_info in self.reg.typedict.items()
- if type_info.elem.get('category') == 'handle'
- }
- return self._handle_types
-
- @property
- def ancestors_dict(self):
- """Return a dictionary of handle type names to sets of ancestors."""
- if not self._ancestors:
- # First time requested - compute it.
- self._ancestors = HandleParents(self.handle_types).get_dict()
- return self._ancestors
-
- @property
- def descendants_dict(self):
- """Return a dictionary of handle type names to sets of descendants."""
- if not self._descendants:
- # First time requested - compute it.
-
- handle_parents = self.ancestors_dict
-
- def get_descendants(handle):
- return set(h for h in handle_parents.keys()
- if handle in handle_parents[h])
-
- self._descendants = {
- h: get_descendants(h)
- for h in handle_parents.keys()
- }
- return self._descendants
-
-
-def compute_type_to_codes(handle_data, types_to_codes, extra_op=None):
- """Compute a DictOfStringSets of input type to required return codes.
-
- - handle_data is a HandleData instance.
- - d is a dictionary of type names to strings or string collections of
- return codes.
- - extra_op, if any, is called after populating the output from the input
- dictionary, but before propagation of parent codes to child types.
- extra_op is called with the in-progress DictOfStringSets.
-
- Returns a DictOfStringSets of input type name to set of required return
- code names.
- """
- # Initialize with the supplied "manual" codes
- types_to_codes = DictOfStringSets(types_to_codes)
-
- # Dynamically generate more codes, if desired
- if extra_op:
- extra_op(types_to_codes)
-
- # Final post-processing
-
- # Any handle can result in its parent handle's codes too.
-
- handle_ancestors = handle_data.ancestors_dict
-
- extra_handle_codes = {}
- for handle_type, ancestors in handle_ancestors.items():
- codes = set()
- # The sets of return codes corresponding to each ancestor type.
- ancestors_codes = (types_to_codes.get(ancestor, set())
- for ancestor in ancestors)
- codes.union(*ancestors_codes)
- # for parent_codes in ancestors_codes:
- # codes.update(parent_codes)
- extra_handle_codes[handle_type] = codes
-
- for handle_type, extras in extra_handle_codes.items():
- types_to_codes.add(handle_type, extras)
-
- return types_to_codes
-
-
-def compute_codes_requiring_type(handle_data, types_to_codes, registry=None):
- """Compute a DictOfStringSets of return codes to a set of input types able
- to provide the ability to generate that code.
-
- handle_data is a HandleData instance.
- d is a dictionary of input types to associated return codes(same format
- as for input to compute_type_to_codes, may use same dict).
- This will invert that relationship, and also permit any "child handles"
- to satisfy a requirement for a parent in producing a code.
-
- Returns a DictOfStringSets of return code name to the set of parameter
- types that would allow that return code.
- """
- # Use DictOfStringSets to normalize the input into a dict with values
- # that are sets of strings
- in_dict = DictOfStringSets(types_to_codes)
-
- handle_descendants = handle_data.descendants_dict
-
- out = DictOfStringSets()
- for in_type, code_set in in_dict.items():
- descendants = handle_descendants.get(in_type)
- for code in code_set:
- out.add(code, in_type)
- if descendants:
- out.add(code, descendants)
-
- return out
diff --git a/codegen/vulkan/scripts/spec_tools/console_printer.py b/codegen/vulkan/scripts/spec_tools/console_printer.py
deleted file mode 100644
index 18acabfd..00000000
--- a/codegen/vulkan/scripts/spec_tools/console_printer.py
+++ /dev/null
@@ -1,274 +0,0 @@
-"""Defines ConsolePrinter, a BasePrinter subclass for appealing console output."""
-
-# Copyright (c) 2018-2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-
-from sys import stdout
-
-from .base_printer import BasePrinter
-from .shared import (colored, getHighlightedRange, getInterestedRange,
- toNameAndLine)
-
-try:
- from tabulate import tabulate_impl
- HAVE_TABULATE = True
-except ImportError:
- HAVE_TABULATE = False
-
-
-def colWidth(collection, columnNum):
- """Compute the required width of a column in a collection of row-tuples."""
- MIN_PADDING = 5
- return MIN_PADDING + max((len(row[columnNum]) for row in collection))
-
-
-def alternateTabulate(collection, headers=None):
- """Minimal re-implementation of the tabulate module."""
- # We need a list, not a generator or anything else.
- if not isinstance(collection, list):
- collection = list(collection)
-
- # Empty collection means no table
- if not collection:
- return None
-
- if headers is None:
- fullTable = collection
- else:
- underline = ['-' * len(header) for header in headers]
- fullTable = [headers, underline] + collection
- widths = [colWidth(collection, colNum)
- for colNum in range(len(fullTable[0]))]
- widths[-1] = None
-
- lines = []
- for row in fullTable:
- fields = []
- for data, width in zip(row, widths):
- if width:
- spaces = ' ' * (width - len(data))
- fields.append(data + spaces)
- else:
- fields.append(data)
- lines.append(''.join(fields))
- return '\n'.join(lines)
-
-
-def printTabulated(collection, headers=None):
- """Call either tabulate.tabulate(), or our internal alternateTabulate()."""
- if HAVE_TABULATE:
- tabulated = tabulate_impl(collection, headers=headers)
- else:
- tabulated = alternateTabulate(collection, headers=headers)
- if tabulated:
- print(tabulated)
-
-
-def printLineSubsetWithHighlighting(
- line, start, end, highlightStart=None, highlightEnd=None, maxLen=120, replacement=None):
- """Print a (potential subset of a) line, with highlighting/underline and optional replacement.
-
- Will print at least the characters line[start:end], and potentially more if possible
- to do so without making the output too wide.
- Will highlight (underline) line[highlightStart:highlightEnd], where the default
- value for highlightStart is simply start, and the default value for highlightEnd is simply end.
- Replacment, if supplied, will be aligned with the highlighted range.
-
- Output is intended to look like part of a Clang compile error/warning message.
- """
- # Fill in missing start/end with start/end of range.
- if highlightStart is None:
- highlightStart = start
- if highlightEnd is None:
- highlightEnd = end
-
- # Expand interested range start/end.
- start = min(start, highlightStart)
- end = max(end, highlightEnd)
-
- tildeLength = highlightEnd - highlightStart - 1
- caretLoc = highlightStart
- continuation = '[...]'
-
- if len(line) > maxLen:
- # Too long
-
- # the max is to handle -1 from .find() (which indicates "not found")
- followingSpaceIndex = max(end, line.find(' ', min(len(line), end + 1)))
-
- # Maximum length has decreased by at least
- # the length of a single continuation we absolutely need.
- maxLen -= len(continuation)
-
- if followingSpaceIndex <= maxLen:
- # We can grab the whole beginning of the line,
- # and not adjust caretLoc
- line = line[:maxLen] + continuation
-
- elif (len(line) - followingSpaceIndex) < 5:
- # We need to truncate the beginning,
- # but we're close to the end of line.
- newBeginning = len(line) - maxLen
-
- caretLoc += len(continuation)
- caretLoc -= newBeginning
- line = continuation + line[newBeginning:]
- else:
- # Need to truncate the beginning of the string too.
- newEnd = followingSpaceIndex
-
- # Now we need two continuations
- # (and to adjust caret to the right accordingly)
- maxLen -= len(continuation)
- caretLoc += len(continuation)
-
- newBeginning = newEnd - maxLen
- caretLoc -= newBeginning
-
- line = continuation + line[newBeginning:newEnd] + continuation
-
- stdout.buffer.write(line.encode('utf-8'))
- print()
-
- spaces = ' ' * caretLoc
- tildes = '~' * tildeLength
- print(spaces + colored('^' + tildes, 'green'))
- if replacement is not None:
- print(spaces + colored(replacement, 'green'))
-
-
-class ConsolePrinter(BasePrinter):
- """Implementation of BasePrinter for generating diagnostic reports in colored, helpful console output."""
-
- def __init__(self):
- self.show_script_location = False
- super().__init__()
-
- ###
- # Output methods: these all print directly.
- def outputResults(self, checker, broken_links=True,
- missing_includes=False):
- """Output the full results of a checker run.
-
- Includes the diagnostics, broken links (if desired),
- and missing includes (if desired).
- """
- self.output(checker)
- if broken_links:
- broken = checker.getBrokenLinks()
- if broken:
- self.outputBrokenLinks(checker, broken)
- if missing_includes:
- missing = checker.getMissingUnreferencedApiIncludes()
- if missing:
- self.outputMissingIncludes(checker, missing)
-
- def outputBrokenLinks(self, checker, broken):
- """Output a table of broken links.
-
- Called by self.outputBrokenAndMissing() if requested.
- """
- print('Missing API includes that are referenced by a linking macro: these result in broken links in the spec!')
-
- def makeRowOfBroken(entity, uses):
- fn = checker.findEntity(entity).filename
- anchor = '[[{}]]'.format(entity)
- locations = ', '.join((toNameAndLine(context, root_path=checker.root_path)
- for context in uses))
- return (fn, anchor, locations)
- printTabulated((makeRowOfBroken(entity, uses)
- for entity, uses in sorted(broken.items())),
- headers=['Include File', 'Anchor in lieu of include', 'Links to this entity'])
-
- def outputMissingIncludes(self, checker, missing):
- """Output a table of missing includes.
-
- Called by self.outputBrokenAndMissing() if requested.
- """
- missing = list(sorted(missing))
- if not missing:
- # Exit if none
- return
- print(
- 'Missing, but unreferenced, API includes/anchors - potentially not-documented entities:')
-
- def makeRowOfMissing(entity):
- fn = checker.findEntity(entity).filename
- anchor = '[[{}]]'.format(entity)
- return (fn, anchor)
- printTabulated((makeRowOfMissing(entity) for entity in missing),
- headers=['Include File', 'Anchor in lieu of include'])
-
- def outputMessage(self, msg):
- """Output a Message, with highlighted range and replacement, if appropriate."""
- highlightStart, highlightEnd = getHighlightedRange(msg.context)
-
- if '\n' in msg.context.filename:
- # This is a multi-line string "filename".
- # Extra blank line and delimiter line for readability:
- print()
- print('--------------------------------------------------------------------')
-
- fileAndLine = colored('{}:'.format(
- self.formatBrief(msg.context)), attrs=['bold'])
-
- headingSize = len('{context}: {mtype}: '.format(
- context=self.formatBrief(msg.context),
- mtype=self.formatBrief(msg.message_type, False)))
- indent = ' ' * headingSize
- printedHeading = False
-
- lines = msg.message[:]
- if msg.see_also:
- lines.append('See also:')
- lines.extend((' {}'.format(self.formatBrief(see))
- for see in msg.see_also))
-
- if msg.fix:
- lines.append('Note: Auto-fix available')
-
- for line in msg.message:
- if not printedHeading:
- scriptloc = ''
- if msg.script_location and self.show_script_location:
- scriptloc = ', ' + msg.script_location
- print('{fileLine} {mtype} {msg} (-{arg}{loc})'.format(
- fileLine=fileAndLine, mtype=msg.message_type.formattedWithColon(),
- msg=colored(line, attrs=['bold']), arg=msg.message_id.enable_arg(), loc=scriptloc))
- printedHeading = True
- else:
- print(colored(indent + line, attrs=['bold']))
-
- if len(msg.message) > 1:
- # extra blank line after multiline message
- print('')
-
- start, end = getInterestedRange(msg.context)
- printLineSubsetWithHighlighting(
- msg.context.line,
- start, end,
- highlightStart, highlightEnd,
- replacement=msg.replacement)
-
- def outputFallback(self, obj):
- """Output by calling print."""
- print(obj)
-
- ###
- # Format methods: these all return a string.
- def formatFilename(self, fn, _with_color=True):
- """Format a local filename, as a relative path if possible."""
- return self.getRelativeFilename(fn)
-
- def formatMessageTypeBrief(self, message_type, with_color=True):
- """Format a message type briefly, applying color if desired and possible.
-
- Delegates to the superclass if not formatting with color.
- """
- if with_color:
- return message_type.formattedWithColon()
- return super(ConsolePrinter, self).formatMessageTypeBrief(
- message_type, with_color)
diff --git a/codegen/vulkan/scripts/spec_tools/data_structures.py b/codegen/vulkan/scripts/spec_tools/data_structures.py
deleted file mode 100644
index f2808cf1..00000000
--- a/codegen/vulkan/scripts/spec_tools/data_structures.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright (c) 2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-"""Provides general-purpose data structures."""
-
-
-class DictOfStringSets:
- """A dictionary where the values are sets of strings.
-
- Has some convenience functions to allow easier maintenance via
- the .add method."""
-
- def __init__(self, d=None):
- self.d = {}
- if d:
- for k, v in d.items():
- self.add(k, v)
-
- def __getitem__(self, k):
- return self.d[k]
-
- def __contains__(self, k):
- return k in self.d
-
- def get(self, k, default=None):
- return self.d.get(k, default)
-
- def get_dict(self):
- return self.d
-
- def items(self):
- """Return an iterator like dict().items()."""
- return self.d.items()
-
- def keys(self):
- """Return an iterator over keys."""
- return self.d.keys()
-
- def values(self):
- """Return an iterator over values."""
- return self.d.values()
-
- def add_key(self, k):
- """Ensure the set for the given key exists."""
- if k not in self.d:
- self.d[k] = set()
-
- def add(self, k, v):
- self.add_key(k)
- if isinstance(v, str):
- v = (v, )
- if not isinstance(v, set):
- v = set(v)
- self.d[k].update(v)
diff --git a/codegen/vulkan/scripts/spec_tools/entity_db.py b/codegen/vulkan/scripts/spec_tools/entity_db.py
deleted file mode 100644
index 9a8dcfb1..00000000
--- a/codegen/vulkan/scripts/spec_tools/entity_db.py
+++ /dev/null
@@ -1,659 +0,0 @@
-"""Provides EntityDatabase, a class that keeps track of spec-defined entities and associated macros."""
-
-# Copyright (c) 2018-2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-
-from abc import ABC, abstractmethod
-
-from .shared import (CATEGORIES_WITH_VALIDITY, EXTENSION_CATEGORY,
- NON_EXISTENT_MACROS, EntityData)
-from .util import getElemName
-
-
-def _entityToDict(data):
- return {
- 'macro': data.macro,
- 'filename': data.filename,
- 'category': data.category,
- 'directory': data.directory
- }
-
-
-class EntityDatabase(ABC):
- """Parsed and processed information from the registry XML.
-
- Must be subclasses for each specific API.
- """
-
- ###
- # Methods that must be implemented in subclasses.
- ###
- @abstractmethod
- def makeRegistry(self):
- """Return a Registry object that has already had loadFile() and parseTree() called.
-
- Called only once during construction.
- """
- raise NotImplementedError
-
- @abstractmethod
- def getNamePrefix(self):
- """Return the (two-letter) prefix of all entity names for this API.
-
- Called only once during construction.
- """
- raise NotImplementedError
-
- @abstractmethod
- def getPlatformRequires(self):
- """Return the 'requires' string associated with external/platform definitions.
-
- This is the string found in the requires attribute of the XML for entities that
- are externally defined in a platform include file, like the question marks in:
-
- <type requires="???" name="int8_t"/>
-
- In Vulkan, this is 'vk_platform'.
-
- Called only once during construction.
- """
- raise NotImplementedError
-
- ###
- # Methods that it is optional to **override**
- ###
- def getSystemTypes(self):
- """Return an enumerable of strings that name system types.
-
- System types use the macro `code`, and they do not generate API/validity includes.
-
- Called only once during construction.
- """
- return []
-
- def getGeneratedDirs(self):
- """Return a sequence of strings that are the subdirectories of generates API includes.
-
- Called only once during construction.
- """
- return ['basetypes',
- 'defines',
- 'enums',
- 'flags',
- 'funcpointers',
- 'handles',
- 'protos',
- 'structs']
-
- def populateMacros(self):
- """Perform API-specific calls, if any, to self.addMacro() and self.addMacros().
-
- It is recommended to implement/override this and call
- self.addMacros(..., ..., [..., "flags"]),
- since the base implementation, in _basicPopulateMacros(),
- does not add any macros as pertaining to the category "flags".
-
- Called only once during construction.
- """
- pass
-
- def populateEntities(self):
- """Perform API-specific calls, if any, to self.addEntity()."""
- pass
-
- def getEntitiesWithoutValidity(self):
- """Return an enumerable of entity names that do not generate validity includes."""
- return [self.mixed_case_name_prefix +
- x for x in ['BaseInStructure', 'BaseOutStructure']]
-
- def getExclusionSet(self):
- """Return a set of "support=" attribute strings that should not be included in the database.
-
- Called only during construction."""
- return set(('disabled',))
-
- ###
- # Methods that it is optional to **extend**
- ###
- def handleType(self, name, info, requires):
- """Add entities, if appropriate, for an item in registry.typedict.
-
- Called at construction for every name, info in registry.typedict.items()
- not immediately skipped,
- to perform the correct associated addEntity() call, if applicable.
- The contents of the requires attribute, if any, is passed in requires.
-
- May be extended by API-specific code to handle some cases preferentially,
- then calling the super implementation to handle the rest.
- """
- if requires == self.platform_requires:
- # Ah, no, don't skip this, it's just in the platform header file.
- # TODO are these code or basetype?
- self.addEntity(name, 'code', elem=info.elem, generates=False)
- return
-
- protect = info.elem.get('protect')
- if protect:
- self.addEntity(protect, 'dlink',
- category='configdefines', generates=False)
-
- alias = info.elem.get('alias')
- if alias:
- self.addAlias(name, alias)
-
- cat = info.elem.get('category')
- if cat == 'struct':
- self.addEntity(name, 'slink', elem=info.elem)
-
- elif cat == 'union':
- # TODO: is this right?
- self.addEntity(name, 'slink', elem=info.elem)
-
- elif cat == 'enum':
- self.addEntity(
- name, 'elink', elem=info.elem)
-
- elif cat == 'handle':
- self.addEntity(name, 'slink', elem=info.elem,
- category='handles')
-
- elif cat == 'bitmask':
- self.addEntity(
- name, 'tlink', elem=info.elem, category='flags')
-
- elif cat == 'basetype':
- self.addEntity(name, 'basetype',
- elem=info.elem)
-
- elif cat == 'define':
- self.addEntity(name, 'dlink', elem=info.elem)
-
- elif cat == 'funcpointer':
- self.addEntity(name, 'tlink', elem=info.elem)
-
- elif cat == 'include':
- # skip
- return
-
- elif cat is None:
- self.addEntity(name, 'code', elem=info.elem, generates=False)
-
- else:
- raise RuntimeError('unrecognized category {}'.format(cat))
-
- def handleCommand(self, name, info):
- """Add entities, if appropriate, for an item in registry.cmddict.
-
- Called at construction for every name, info in registry.cmddict.items().
- Calls self.addEntity() accordingly.
- """
- self.addEntity(name, 'flink', elem=info.elem,
- category='commands', directory='protos')
-
- def handleExtension(self, name, info):
- """Add entities, if appropriate, for an item in registry.extdict.
-
- Called at construction for every name, info in registry.extdict.items().
- Calls self.addEntity() accordingly.
- """
- if info.supported in self._supportExclusionSet:
- # Don't populate with disabled extensions.
- return
-
- # Only get the protect strings and name from extensions
-
- self.addEntity(name, None, category=EXTENSION_CATEGORY,
- generates=False)
- protect = info.elem.get('protect')
- if protect:
- self.addEntity(protect, 'dlink',
- category='configdefines', generates=False)
-
- def handleEnumValue(self, name, info):
- """Add entities, if appropriate, for an item in registry.enumdict.
-
- Called at construction for every name, info in registry.enumdict.items().
- Calls self.addEntity() accordingly.
- """
- self.addEntity(name, 'ename', elem=info.elem,
- category='enumvalues', generates=False)
-
- ###
- # END of methods intended to be implemented, overridden, or extended in child classes!
- ###
-
- ###
- # Accessors
- ###
- def findMacroAndEntity(self, macro, entity):
- """Look up EntityData by macro and entity pair.
-
- Does **not** resolve aliases."""
- return self._byMacroAndEntity.get((macro, entity))
-
- def findEntity(self, entity):
- """Look up EntityData by entity name (case-sensitive).
-
- If it fails, it will try resolving aliases.
- """
- result = self._byEntity.get(entity)
- if result:
- return result
-
- alias_set = self._aliasSetsByEntity.get(entity)
- if alias_set:
- for alias in alias_set:
- if alias in self._byEntity:
- return self.findEntity(alias)
-
- assert(not "Alias without main entry!")
-
- return None
-
- def findEntityCaseInsensitive(self, entity):
- """Look up EntityData by entity name (case-insensitive).
-
- Does **not** resolve aliases."""
- return self._byLowercaseEntity.get(entity.lower())
-
- def getMemberElems(self, commandOrStruct):
- """Given a command or struct name, retrieve the ETree elements for each member/param.
-
- Returns None if the entity is not found or doesn't have members/params.
- """
- data = self.findEntity(commandOrStruct)
-
- if not data:
- return None
- if data.elem is None:
- return None
- if data.macro == 'slink':
- tag = 'member'
- else:
- tag = 'param'
- return data.elem.findall('.//{}'.format(tag))
-
- 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.
- """
- members = self.getMemberElems(commandOrStruct)
- if not members:
- return []
- ret = []
- for member in members:
- name_tag = member.find('name')
- if name_tag:
- ret.append(name_tag.text)
- return ret
-
- def getEntityJson(self):
- """Dump the internal entity dictionary to JSON for debugging."""
- import json
- d = {entity: _entityToDict(data)
- for entity, data in self._byEntity.items()}
- return json.dumps(d, sort_keys=True, indent=4)
-
- def entityHasValidity(self, entity):
- """Estimate if we expect to see a validity include for an entity name.
-
- Returns None if the entity name is not known,
- otherwise a boolean: True if a validity include is expected.
-
- Related to Generator.isStructAlwaysValid.
- """
- data = self.findEntity(entity)
- if not data:
- return None
-
- if entity in self.entities_without_validity:
- return False
-
- if data.category == 'protos':
- # All protos have validity
- return True
-
- if data.category not in CATEGORIES_WITH_VALIDITY:
- return False
-
- # Handle structs here.
- members = self.getMemberElems(entity)
- if not members:
- return None
- for member in members:
- member_name = getElemName(member)
- member_type = member.find('type').text
- member_category = member.get('category')
-
- if member_name in ('next', 'type'):
- return True
-
- if member_type in ('void', 'char'):
- return True
-
- if member.get('noautovalidity'):
- # Not generating validity for this member, skip it
- continue
-
- if member.get('len'):
- # Array
- return True
-
- typetail = member.find('type').tail
- if typetail and '*' in typetail:
- # Pointer
- return True
-
- if member_category in ('handle', 'enum', 'bitmask'):
- return True
-
- if member.get('category') in ('struct', 'union') \
- and self.entityHasValidity(member_type):
- # struct or union member - recurse
- return True
-
- # Got this far - no validity needed
- return False
-
- def entityGenerates(self, entity_name):
- """Return True if the named entity generates include file(s)."""
- return entity_name in self._generating_entities
-
- @property
- def generating_entities(self):
- """Return a sequence of all generating entity names."""
- return self._generating_entities.keys()
-
- def shouldBeRecognized(self, macro, entity_name):
- """Determine, based on the macro and the name provided, if we should expect to recognize the entity.
-
- True if it is linked. Specific APIs may also provide additional cases where it is True."""
- return self.isLinkedMacro(macro)
-
- def likelyRecognizedEntity(self, entity_name):
- """Guess (based on name prefix alone) if an entity is likely to be recognized."""
- return entity_name.lower().startswith(self.name_prefix)
-
- def isLinkedMacro(self, macro):
- """Identify if a macro is considered a "linked" macro."""
- return macro in self._linkedMacros
-
- def isValidMacro(self, macro):
- """Identify if a macro is known and valid."""
- if macro not in self._categoriesByMacro:
- return False
-
- return macro not in NON_EXISTENT_MACROS
-
- def getCategoriesForMacro(self, macro):
- """Identify the categories associated with a (known, valid) macro."""
- if macro in self._categoriesByMacro:
- return self._categoriesByMacro[macro]
- return None
-
- def areAliases(self, first_entity_name, second_entity_name):
- """Return true if the two entity names are equivalent (aliases of each other)."""
- alias_set = self._aliasSetsByEntity.get(first_entity_name)
- if not alias_set:
- # If this assert fails, we have goofed in addAlias
- assert(second_entity_name not in self._aliasSetsByEntity)
-
- return False
-
- return second_entity_name in alias_set
-
- @property
- def macros(self):
- """Return the collection of all known entity-related markup macros."""
- return self._categoriesByMacro.keys()
-
- ###
- # Methods only used during initial setup/population of this data structure
- ###
- def addMacro(self, macro, categories, link=False):
- """Add a single markup macro to the collection of categories by macro.
-
- Also adds the macro to the set of linked macros if link=True.
-
- If a macro has already been supplied to a call, later calls for that macro have no effect.
- """
- if macro in self._categoriesByMacro:
- return
- self._categoriesByMacro[macro] = categories
- if link:
- self._linkedMacros.add(macro)
-
- def addMacros(self, letter, macroTypes, categories):
- """Add markup macros associated with a leading letter to the collection of categories by macro.
-
- Also, those macros created using 'link' in macroTypes will also be added to the set of linked macros.
-
- Basically automates a number of calls to addMacro().
- """
- for macroType in macroTypes:
- macro = letter + macroType
- self.addMacro(macro, categories, link=(macroType == 'link'))
-
- def addAlias(self, entityName, aliasName):
- """Record that entityName is an alias for aliasName."""
- # See if we already have something with this as the alias.
- alias_set = self._aliasSetsByEntity.get(aliasName)
- other_alias_set = self._aliasSetsByEntity.get(entityName)
- if alias_set and other_alias_set:
- # If this fails, we need to merge sets and update.
- assert(alias_set is other_alias_set)
-
- if not alias_set:
- # Try looking by the other name.
- alias_set = other_alias_set
-
- if not alias_set:
- # Nope, this is a new set.
- alias_set = set()
- self._aliasSets.append(alias_set)
-
- # Add both names to the set
- alias_set.add(entityName)
- alias_set.add(aliasName)
-
- # Associate the set with each name
- self._aliasSetsByEntity[aliasName] = alias_set
- self._aliasSetsByEntity[entityName] = alias_set
-
- def addEntity(self, entityName, macro, category=None, elem=None,
- generates=None, directory=None, filename=None):
- """Add an entity (command, structure type, enum, enum value, etc) in the database.
-
- If an entityName has already been supplied to a call, later calls for that entityName have no effect.
-
- Arguments:
- entityName -- the name of the entity.
- macro -- the macro (without the trailing colon) that should be used to refer to this entity.
-
- Optional keyword arguments:
- category -- If not manually specified, looked up based on the macro.
- elem -- The ETree element associated with the entity in the registry XML.
- generates -- Indicates whether this entity generates api and validity include files.
- Default depends on directory (or if not specified, category).
- directory -- The directory that include files (under api/ and validity/) are generated in.
- If not specified (and generates is True), the default is the same as the category,
- which is almost always correct.
- filename -- The relative filename (under api/ or validity/) where includes are generated for this.
- This only matters if generates is True (default). If not specified and generates is True,
- one will be generated based on directory and entityName.
- """
- # Probably dealt with in handleType(), but just in case it wasn't.
- if elem is not None:
- alias = elem.get('alias')
- if alias:
- self.addAlias(entityName, alias)
-
- if entityName in self._byEntity:
- # skip if already recorded.
- return
-
- # Look up category based on the macro, if category isn't specified.
- if category is None:
- category = self._categoriesByMacro.get(macro)[0]
-
- if generates is None:
- potential_dir = directory or category
- generates = potential_dir in self._generated_dirs
-
- # If directory isn't specified and this entity generates,
- # the directory is the same as the category.
- if directory is None and generates:
- directory = category
-
- # Don't generate a filename if this entity doesn't generate includes.
- if filename is None and generates:
- filename = '{}/{}.txt'.format(directory, entityName)
-
- data = EntityData(
- entity=entityName,
- macro=macro,
- elem=elem,
- filename=filename,
- category=category,
- directory=directory
- )
- if entityName.lower() not in self._byLowercaseEntity:
- self._byLowercaseEntity[entityName.lower()] = []
-
- self._byEntity[entityName] = data
- self._byLowercaseEntity[entityName.lower()].append(data)
- self._byMacroAndEntity[(macro, entityName)] = data
- if generates and filename is not None:
- self._generating_entities[entityName] = data
-
- def __init__(self):
- """Constructor: Do not extend or override.
-
- Changing the behavior of other parts of this logic should be done by
- implementing, extending, or overriding (as documented):
-
- - Implement makeRegistry()
- - Implement getNamePrefix()
- - Implement getPlatformRequires()
- - Override getSystemTypes()
- - Override populateMacros()
- - Override populateEntities()
- - Extend handleType()
- - Extend handleCommand()
- - Extend handleExtension()
- - Extend handleEnumValue()
- """
- # Internal data that we don't want consumers of the class touching for fear of
- # breaking invariants
- self._byEntity = {}
- self._byLowercaseEntity = {}
- self._byMacroAndEntity = {}
- self._categoriesByMacro = {}
- self._linkedMacros = set()
- self._aliasSetsByEntity = {}
- self._aliasSets = []
-
- self._registry = None
-
- # Retrieve from subclass, if overridden, then store locally.
- self._supportExclusionSet = set(self.getExclusionSet())
-
- # Entities that get a generated/api/category/entity.txt file.
- self._generating_entities = {}
-
- # Name prefix members
- self.name_prefix = self.getNamePrefix().lower()
- self.mixed_case_name_prefix = self.name_prefix[:1].upper(
- ) + self.name_prefix[1:]
- # Regex string for the name prefix that is case-insensitive.
- self.case_insensitive_name_prefix_pattern = ''.join(
- ('[{}{}]'.format(c.upper(), c) for c in self.name_prefix))
-
- self.platform_requires = self.getPlatformRequires()
-
- self._generated_dirs = set(self.getGeneratedDirs())
-
- # Note: Default impl requires self.mixed_case_name_prefix
- self.entities_without_validity = set(self.getEntitiesWithoutValidity())
-
- # TODO: Where should flags actually go? Not mentioned in the style guide.
- # TODO: What about flag wildcards? There are a few such uses...
-
- # Abstract method: subclass must implement to define macros for flags
- self.populateMacros()
-
- # Now, do default macro population
- self._basicPopulateMacros()
-
- # Abstract method: subclass must implement to add any "not from the registry" (and not system type)
- # entities
- self.populateEntities()
-
- # Now, do default entity population
- self._basicPopulateEntities(self.registry)
-
- ###
- # Methods only used internally during initial setup/population of this data structure
- ###
- @property
- def registry(self):
- """Return a Registry."""
- if not self._registry:
- self._registry = self.makeRegistry()
- return self._registry
-
- def _basicPopulateMacros(self):
- """Contains calls to self.addMacro() and self.addMacros().
-
- If you need to change any of these, do so in your override of populateMacros(),
- which will be called first.
- """
- self.addMacro('basetype', ['basetypes'])
- self.addMacro('code', ['code'])
- self.addMacros('f', ['link', 'name', 'text'], ['protos'])
- self.addMacros('s', ['link', 'name', 'text'], ['structs', 'handles'])
- self.addMacros('e', ['link', 'name', 'text'], ['enums'])
- self.addMacros('p', ['name', 'text'], ['parameter', 'member'])
- self.addMacros('t', ['link', 'name'], ['funcpointers'])
- self.addMacros('d', ['link', 'name'], ['defines', 'configdefines'])
-
- for macro in NON_EXISTENT_MACROS:
- # Still search for them
- self.addMacro(macro, None)
-
- def _basicPopulateEntities(self, registry):
- """Contains typical calls to self.addEntity().
-
- If you need to change any of these, do so in your override of populateEntities(),
- which will be called first.
- """
- system_types = set(self.getSystemTypes())
- for t in system_types:
- self.addEntity(t, 'code', generates=False)
-
- for name, info in registry.typedict.items():
- if name in system_types:
- # We already added these.
- continue
-
- requires = info.elem.get('requires')
-
- if requires and not requires.lower().startswith(self.name_prefix):
- # This is an externally-defined type, will skip it.
- continue
-
- # OK, we might actually add an entity here
- self.handleType(name=name, info=info, requires=requires)
-
- for name, info in registry.enumdict.items():
- self.handleEnumValue(name, info)
-
- for name, info in registry.cmddict.items():
- self.handleCommand(name, info)
-
- for name, info in registry.extdict.items():
- self.handleExtension(name, info)
diff --git a/codegen/vulkan/scripts/spec_tools/file_process.py b/codegen/vulkan/scripts/spec_tools/file_process.py
deleted file mode 100644
index f0d4c608..00000000
--- a/codegen/vulkan/scripts/spec_tools/file_process.py
+++ /dev/null
@@ -1,119 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright (c) 2018-2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-"Utilities for processing files."
-
-from pathlib import Path
-
-
-class LinewiseFileProcessor:
- """A base class for code that processes an input file (or file handle) one line at a time."""
-
- def __init__(self):
- self._lines = []
- self._line_num = 0
- self._next_line = None
- self._line = ''
- self._filename = Path()
-
- @property
- def filename(self):
- """The Path object of the currently processed file"""
- return self._filename
-
- @property
- def relative_filename(self):
- """The current file's Path relative to the current working directory"""
- return self.filename.relative_to(Path('.').resolve())
-
- @property
- def line(self):
- """The current line, including any trailing whitespace and the line ending."""
- return self._line
-
- @property
- def line_number(self):
- """Get 1-indexed line number."""
- return self._line_num
-
- @property
- def line_rstripped(self):
- """The current line without any trailing whitespace."""
- if self.line is None:
- return None
- return self.line.rstrip()
-
- @property
- def trailing_whitespace(self):
- """The trailing whitespace of the current line that gets removed when accessing rstrippedLine"""
- non_whitespace_length = len(self.line_rstripped)
- return self.line[non_whitespace_length:]
-
- @property
- def next_line(self):
- """Peek at the next line, if any."""
- return self._next_line
-
- @property
- def next_line_rstripped(self):
- """Peek at the next line, if any, without any trailing whitespace."""
- if self.next_line is None:
- return None
- return self.next_line.rstrip()
-
- def get_preceding_line(self, relative_index=-1):
- """Retrieve the line at an line number at the given relative index, if one exists. Returns None if there is no line there."""
- if relative_index >= 0:
- raise RuntimeError(
- 'relativeIndex must be negative, to retrieve a preceding line.')
- if relative_index + self.line_number <= 0:
- # There is no line at this index
- return None
- return self._lines[self.line_number + relative_index - 1]
-
- def get_preceding_lines(self, num):
- """Get *up to* the preceding num lines. Fewer may be returned if the requested number aren't available."""
- return self._lines[- (num + 1):-1]
-
- def process_line(self, line_num, line):
- """Implement in your subclass to handle each new line."""
- raise NotImplementedError
-
- def _process_file_handle(self, file_handle):
- # These are so we can process one line earlier than we're actually iterating thru.
- processing_line_num = None
- processing_line = None
-
- def do_process_line():
- self._line_num = processing_line_num
- self._line = processing_line
- if processing_line is not None:
- self._lines.append(processing_line)
- self.process_line(processing_line_num, processing_line)
-
- for line_num, line in enumerate(file_handle, 1):
- self._next_line = line
- do_process_line()
- processing_line_num = line_num
- processing_line = line
-
- # Finally process the left-over line
- self._next_line = None
- do_process_line()
-
- def process_file(self, filename, file_handle=None):
- """Main entry point - call with a filename and optionally the file handle to read from."""
- if isinstance(filename, str):
- filename = Path(filename).resolve()
-
- self._filename = filename
-
- if file_handle:
- self._process_file_handle(file_handle)
- else:
- with self._filename.open('r', encoding='utf-8') as f:
- self._process_file_handle(f)
diff --git a/codegen/vulkan/scripts/spec_tools/html_printer.py b/codegen/vulkan/scripts/spec_tools/html_printer.py
deleted file mode 100644
index eb1df406..00000000
--- a/codegen/vulkan/scripts/spec_tools/html_printer.py
+++ /dev/null
@@ -1,436 +0,0 @@
-"""Defines HTMLPrinter, a BasePrinter subclass for a single-page HTML results file."""
-
-# Copyright (c) 2018-2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-
-import html
-import re
-from collections import namedtuple
-
-from .base_printer import BasePrinter, getColumn
-from .shared import (MessageContext, MessageType, generateInclude,
- getHighlightedRange)
-
-# Bootstrap styles (for constructing CSS class names) associated with MessageType values.
-MESSAGE_TYPE_STYLES = {
- MessageType.ERROR: 'danger',
- MessageType.WARNING: 'warning',
- MessageType.NOTE: 'secondary'
-}
-
-
-# HTML Entity for a little emoji-icon associated with MessageType values.
-MESSAGE_TYPE_ICONS = {
- MessageType.ERROR: '&#x2297;', # makeIcon('times-circle'),
- MessageType.WARNING: '&#9888;', # makeIcon('exclamation-triangle'),
- MessageType.NOTE: '&#x2139;' # makeIcon('info-circle')
-}
-
-LINK_ICON = '&#128279;' # link icon
-
-
-class HTMLPrinter(BasePrinter):
- """Implementation of BasePrinter for generating diagnostic reports in HTML format.
-
- Generates a single file containing neatly-formatted messages.
-
- The HTML file loads Bootstrap 4 as well as 'prism' syntax highlighting from CDN.
- """
-
- def __init__(self, filename):
- """Construct by opening the file."""
- self.f = open(filename, 'w', encoding='utf-8')
- self.f.write("""<!doctype html>
- <html lang="en"><head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/themes/prism.min.css" integrity="sha256-N1K43s+8twRa+tzzoF3V8EgssdDiZ6kd9r8Rfgg8kZU=" crossorigin="anonymous" />
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/plugins/line-numbers/prism-line-numbers.min.css" integrity="sha256-Afz2ZJtXw+OuaPX10lZHY7fN1+FuTE/KdCs+j7WZTGc=" crossorigin="anonymous" />
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/plugins/line-highlight/prism-line-highlight.min.css" integrity="sha256-FFGTaA49ZxFi2oUiWjxtTBqoda+t1Uw8GffYkdt9aco=" crossorigin="anonymous" />
- <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
- <style>
- pre {
- overflow-x: scroll;
- white-space: nowrap;
- }
- </style>
- <title>check_spec_links results</title>
- </head>
- <body>
- <div class="container">
- <h1><code>check_spec_links.py</code> Scan Results</h1>
- """)
- #
- self.filenameTransformer = re.compile(r'[^\w]+')
- self.fileRange = {}
- self.fileLines = {}
- self.backLink = namedtuple(
- 'BackLink', ['lineNum', 'col', 'end_col', 'target', 'tooltip', 'message_type'])
- self.fileBackLinks = {}
-
- self.nextAnchor = 0
- super().__init__()
-
- def close(self):
- """Write the tail end of the file and close it."""
- self.f.write("""
- </div>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/prism.min.js" integrity="sha256-jc6y1s/Y+F+78EgCT/lI2lyU7ys+PFYrRSJ6q8/R8+o=" crossorigin="anonymous"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/plugins/keep-markup/prism-keep-markup.min.js" integrity="sha256-mP5i3m+wTxxOYkH+zXnKIG5oJhXLIPQYoiicCV1LpkM=" crossorigin="anonymous"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/components/prism-asciidoc.min.js" integrity="sha256-NHPE1p3VBIdXkmfbkf/S0hMA6b4Ar4TAAUlR+Rlogoc=" crossorigin="anonymous"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/plugins/line-numbers/prism-line-numbers.min.js" integrity="sha256-JfF9MVfGdRUxzT4pecjOZq6B+F5EylLQLwcQNg+6+Qk=" crossorigin="anonymous"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/plugins/line-highlight/prism-line-highlight.min.js" integrity="sha256-DEl9ZQE+lseY13oqm2+mlUr+sVI18LG813P+kzzIm8o=" crossorigin="anonymous"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.slim.min.js" integrity="sha256-3edrmyuQ0w65f8gfBsqowzjJe2iM6n0nKciPUp8y+7E=" crossorigin="anonymous"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/esm/popper.min.js" integrity="sha256-T0gPN+ySsI9ixTd/1ciLl2gjdLJLfECKvkQjJn98lOs=" crossorigin="anonymous"></script>
- <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
- <script>
- $(function () {
- $('[data-toggle="tooltip"]').tooltip();
- function autoExpand() {
- var hash = window.location.hash;
- if (!hash) {
- return;
- }
- $(hash).parents().filter('.collapse').collapse('show');
- }
- window.addEventListener('hashchange', autoExpand);
- $(document).ready(autoExpand);
- $('.accordion').on('shown.bs.collapse', function(e) {
- e.target.parentNode.scrollIntoView();
- })
- })
- </script>
- </body></html>
- """)
- self.f.close()
-
- ###
- # Output methods: these all write to the HTML file.
- def outputResults(self, checker, broken_links=True,
- missing_includes=False):
- """Output the full results of a checker run.
-
- Includes the diagnostics, broken links (if desired),
- missing includes (if desired), and excerpts of all files with diagnostics.
- """
- self.output(checker)
- self.outputBrokenAndMissing(
- checker, broken_links=broken_links, missing_includes=missing_includes)
-
- self.f.write("""
- <div class="container">
- <h2>Excerpts of referenced files</h2>""")
- for fn in self.fileRange:
- self.outputFileExcerpt(fn)
- self.f.write('</div><!-- .container -->\n')
-
- def outputChecker(self, checker):
- """Output the contents of a MacroChecker object.
-
- Starts and ends the accordion populated by outputCheckerFile().
- """
- self.f.write(
- '<div class="container"><h2>Per-File Warnings and Errors</h2>\n')
- self.f.write('<div class="accordion" id="fileAccordion">\n')
- super(HTMLPrinter, self).outputChecker(checker)
- self.f.write("""</div><!-- #fileAccordion -->
- </div><!-- .container -->\n""")
-
- def outputCheckerFile(self, fileChecker):
- """Output the contents of a MacroCheckerFile object.
-
- Stashes the lines of the file for later excerpts,
- and outputs any diagnostics in an accordion card.
- """
- # Save lines for later
- self.fileLines[fileChecker.filename] = fileChecker.lines
-
- if not fileChecker.numDiagnostics():
- return
-
- self.f.write("""
- <div class="card">
- <div class="card-header" id="{id}-file-heading">
- <div class="row">
- <div class="col">
- <button data-target="#collapse-{id}" class="btn btn-link btn-primary mb-0 collapsed" type="button" data-toggle="collapse" aria-expanded="false" aria-controls="collapse-{id}">
- {relativefn}
- </button>
- </div>
- """.format(id=self.makeIdentifierFromFilename(fileChecker.filename), relativefn=html.escape(self.getRelativeFilename(fileChecker.filename))))
- self.f.write('<div class="col-1">')
- warnings = fileChecker.numMessagesOfType(MessageType.WARNING)
- if warnings > 0:
- self.f.write("""<span class="badge badge-warning" data-toggle="tooltip" title="{num} warnings in this file">
- {icon}
- {num}<span class="sr-only"> warnings</span></span>""".format(num=warnings, icon=MESSAGE_TYPE_ICONS[MessageType.WARNING]))
- self.f.write('</div>\n<div class="col-1">')
- errors = fileChecker.numMessagesOfType(MessageType.ERROR)
- if errors > 0:
- self.f.write("""<span class="badge badge-danger" data-toggle="tooltip" title="{num} errors in this file">
- {icon}
- {num}<span class="sr-only"> errors</span></span>""".format(num=errors, icon=MESSAGE_TYPE_ICONS[MessageType.ERROR]))
- self.f.write("""
- </div><!-- .col-1 -->
- </div><!-- .row -->
- </div><!-- .card-header -->
- <div id="collapse-{id}" class="collapse" aria-labelledby="{id}-file-heading" data-parent="#fileAccordion">
- <div class="card-body">
- """.format(id=self.makeIdentifierFromFilename(fileChecker.filename)))
- super(HTMLPrinter, self).outputCheckerFile(fileChecker)
-
- self.f.write("""
- </div><!-- .card-body -->
- </div><!-- .collapse -->
- </div><!-- .card -->
- <!-- ..................................... -->
- """.format(id=self.makeIdentifierFromFilename(fileChecker.filename)))
-
- def outputMessage(self, msg):
- """Output a Message."""
- anchor = self.getUniqueAnchor()
-
- self.recordUsage(msg.context,
- linkBackTarget=anchor,
- linkBackTooltip='{}: {} [...]'.format(
- msg.message_type, msg.message[0]),
- linkBackType=msg.message_type)
-
- self.f.write("""
- <div class="card">
- <div class="card-body">
- <h5 class="card-header bg bg-{style}" id="{anchor}">{icon} {t} Line {lineNum}, Column {col} (-{arg})</h5>
- <p class="card-text">
- """.format(
- anchor=anchor,
- icon=MESSAGE_TYPE_ICONS[msg.message_type],
- style=MESSAGE_TYPE_STYLES[msg.message_type],
- t=self.formatBrief(msg.message_type),
- lineNum=msg.context.lineNum,
- col=getColumn(msg.context),
- arg=msg.message_id.enable_arg()))
- self.f.write(self.formatContext(msg.context))
- self.f.write('<br/>')
- for line in msg.message:
- self.f.write(html.escape(line))
- self.f.write('<br />\n')
- self.f.write('</p>\n')
- if msg.see_also:
- self.f.write('<p>See also:</p><ul>\n')
- for see in msg.see_also:
- if isinstance(see, MessageContext):
- self.f.write(
- '<li>{}</li>\n'.format(self.formatContext(see)))
- self.recordUsage(see,
- linkBackTarget=anchor,
- linkBackType=MessageType.NOTE,
- linkBackTooltip='see-also associated with {} at {}'.format(msg.message_type, self.formatContextBrief(see)))
- else:
- self.f.write('<li>{}</li>\n'.format(self.formatBrief(see)))
- self.f.write('</ul>')
- if msg.replacement is not None:
- self.f.write(
- '<div class="alert alert-primary">Hover the highlight text to view suggested replacement.</div>')
- if msg.fix is not None:
- self.f.write(
- '<div class="alert alert-info">Note: Auto-fix available.</div>')
- if msg.script_location:
- self.f.write(
- '<p>Message originated at <code>{}</code></p>'.format(msg.script_location))
- self.f.write('<pre class="line-numbers language-asciidoc" data-start="{}"><code>'.format(
- msg.context.lineNum))
- highlightStart, highlightEnd = getHighlightedRange(msg.context)
- self.f.write(html.escape(msg.context.line[:highlightStart]))
- self.f.write(
- '<span class="border border-{}"'.format(MESSAGE_TYPE_STYLES[msg.message_type]))
- if msg.replacement is not None:
- self.f.write(
- ' data-toggle="tooltip" title="{}"'.format(msg.replacement))
- self.f.write('>')
- self.f.write(html.escape(
- msg.context.line[highlightStart:highlightEnd]))
- self.f.write('</span>')
- self.f.write(html.escape(msg.context.line[highlightEnd:]))
- self.f.write('</code></pre></div></div>')
-
- def outputBrokenLinks(self, checker, broken):
- """Output a table of broken links.
-
- Called by self.outputBrokenAndMissing() if requested.
- """
- self.f.write("""
- <div class="container">
- <h2>Missing Referenced API Includes</h2>
- <p>Items here have been referenced by a linking macro, so these are all broken links in the spec!</p>
- <table class="table table-striped">
- <thead>
- <th scope="col">Add line to include this file</th>
- <th scope="col">or add this macro instead</th>
- <th scope="col">Links to this entity</th></thead>
- """)
-
- for entity_name, uses in sorted(broken.items()):
- category = checker.findEntity(entity_name).category
- anchor = self.getUniqueAnchor()
- asciidocAnchor = '[[{}]]'.format(entity_name)
- include = generateInclude(dir_traverse='../../generated/',
- generated_type='api',
- category=category,
- entity=entity_name)
- self.f.write("""
- <tr id={}>
- <td><code class="text-dark language-asciidoc">{}</code></td>
- <td><code class="text-dark">{}</code></td>
- <td><ul class="list-inline">
- """.format(anchor, include, asciidocAnchor))
- for context in uses:
- self.f.write(
- '<li class="list-inline-item">{}</li>'.format(self.formatContext(context, MessageType.NOTE)))
- self.recordUsage(
- context,
- linkBackTooltip='Link broken in spec: {} not seen'.format(
- include),
- linkBackTarget=anchor,
- linkBackType=MessageType.NOTE)
- self.f.write("""</ul></td></tr>""")
- self.f.write("""</table></div>""")
-
- def outputMissingIncludes(self, checker, missing):
- """Output a table of missing includes.
-
- Called by self.outputBrokenAndMissing() if requested.
- """
- self.f.write("""
- <div class="container">
- <h2>Missing Unreferenced API Includes</h2>
- <p>These items are expected to be generated in the spec build process, but aren't included.
- However, as they also are not referenced by any linking macros, they aren't broken links - at worst they are undocumented entities,
- at best they are errors in <code>check_spec_links.py</code> logic computing which entities get generated files.</p>
- <table class="table table-striped">
- <thead>
- <th scope="col">Add line to include this file</th>
- <th scope="col">or add this macro instead</th>
- """)
-
- for entity in sorted(missing):
- fn = checker.findEntity(entity).filename
- anchor = '[[{}]]'.format(entity)
- self.f.write("""
- <tr>
- <td><code class="text-dark">{filename}</code></td>
- <td><code class="text-dark">{anchor}</code></td>
- """.format(filename=fn, anchor=anchor))
- self.f.write("""</table></div>""")
-
- def outputFileExcerpt(self, filename):
- """Output a card containing an excerpt of a file, sufficient to show locations of all diagnostics plus some context.
-
- Called by self.outputResults().
- """
- self.f.write("""<div class="card">
- <div class="card-header" id="heading-{id}"><h5 class="mb-0">
- <button class="btn btn-link" type="button">
- {fn}
- </button></h5></div><!-- #heading-{id} -->
- <div class="card-body">
- """.format(id=self.makeIdentifierFromFilename(filename), fn=self.getRelativeFilename(filename)))
- lines = self.fileLines[filename]
- r = self.fileRange[filename]
- self.f.write("""<pre class="line-numbers language-asciidoc line-highlight" id="excerpt-{id}" data-start="{start}"><code>""".format(
- id=self.makeIdentifierFromFilename(filename),
- start=r.start))
- for lineNum, line in enumerate(
- lines[(r.start - 1):(r.stop - 1)], r.start):
- # self.f.write(line)
- lineLinks = [x for x in self.fileBackLinks[filename]
- if x.lineNum == lineNum]
- for col, char in enumerate(line):
- colLinks = (x for x in lineLinks if x.col == col)
- for link in colLinks:
- # TODO right now the syntax highlighting is interfering with the link! so the link-generation is commented out,
- # only generating the emoji icon.
-
- # self.f.write('<a href="#{target}" title="{title}" data-toggle="tooltip" data-container="body">{icon}'.format(
- # target=link.target, title=html.escape(link.tooltip),
- # icon=MESSAGE_TYPE_ICONS[link.message_type]))
- self.f.write(MESSAGE_TYPE_ICONS[link.message_type])
- self.f.write('<span class="sr-only">Cross reference: {t} {title}</span>'.format(
- title=html.escape(link.tooltip, False), t=link.message_type))
-
- # self.f.write('</a>')
-
- # Write the actual character
- self.f.write(html.escape(char))
- self.f.write('\n')
-
- self.f.write('</code></pre>')
- self.f.write('</div><!-- .card-body -->\n')
- self.f.write('</div><!-- .card -->\n')
-
- def outputFallback(self, obj):
- """Output some text in a general way."""
- self.f.write(obj)
-
- ###
- # Format method: return a string.
- def formatContext(self, context, message_type=None):
- """Format a message context in a verbose way."""
- if message_type is None:
- icon = LINK_ICON
- else:
- icon = MESSAGE_TYPE_ICONS[message_type]
- return 'In context: <a href="{href}">{icon}{relative}:{lineNum}:{col}</a>'.format(
- href=self.getAnchorLinkForContext(context),
- icon=icon,
- # id=self.makeIdentifierFromFilename(context.filename),
- relative=self.getRelativeFilename(context.filename),
- lineNum=context.lineNum,
- col=getColumn(context))
-
- ###
- # Internal methods: not mandated by parent class.
- def recordUsage(self, context, linkBackTooltip=None,
- linkBackTarget=None, linkBackType=MessageType.NOTE):
- """Internally record a 'usage' of something.
-
- Increases the range of lines that are included in the excerpts,
- and records back-links if appropriate.
- """
- BEFORE_CONTEXT = 6
- AFTER_CONTEXT = 3
- # Clamp because we need accurate start line number to make line number
- # display right
- start = max(1, context.lineNum - BEFORE_CONTEXT)
- stop = context.lineNum + AFTER_CONTEXT + 1
- if context.filename not in self.fileRange:
- self.fileRange[context.filename] = range(start, stop)
- self.fileBackLinks[context.filename] = []
- else:
- oldRange = self.fileRange[context.filename]
- self.fileRange[context.filename] = range(
- min(start, oldRange.start), max(stop, oldRange.stop))
-
- if linkBackTarget is not None:
- start_col, end_col = getHighlightedRange(context)
- self.fileBackLinks[context.filename].append(self.backLink(
- lineNum=context.lineNum, col=start_col, end_col=end_col,
- target=linkBackTarget, tooltip=linkBackTooltip,
- message_type=linkBackType))
-
- def makeIdentifierFromFilename(self, fn):
- """Compute an acceptable HTML anchor name from a filename."""
- return self.filenameTransformer.sub('_', self.getRelativeFilename(fn))
-
- def getAnchorLinkForContext(self, context):
- """Compute the anchor link to the excerpt for a MessageContext."""
- return '#excerpt-{}.{}'.format(
- self.makeIdentifierFromFilename(context.filename), context.lineNum)
-
- def getUniqueAnchor(self):
- """Create and return a new unique string usable as a link anchor."""
- anchor = 'anchor-{}'.format(self.nextAnchor)
- self.nextAnchor += 1
- return anchor
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)
diff --git a/codegen/vulkan/scripts/spec_tools/macro_checker_file.py b/codegen/vulkan/scripts/spec_tools/macro_checker_file.py
deleted file mode 100644
index 3bca17a5..00000000
--- a/codegen/vulkan/scripts/spec_tools/macro_checker_file.py
+++ /dev/null
@@ -1,1592 +0,0 @@
-"""Provides MacroCheckerFile, a subclassable type that validates a single file in the spec."""
-
-# Copyright (c) 2018-2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-
-import logging
-import re
-from collections import OrderedDict, namedtuple
-from enum import Enum
-from inspect import currentframe
-
-from .shared import (AUTO_FIX_STRING, CATEGORIES_WITH_VALIDITY,
- EXTENSION_CATEGORY, NON_EXISTENT_MACROS, EntityData,
- Message, MessageContext, MessageId, MessageType,
- generateInclude, toNameAndLine)
-
-# Code blocks may start and end with any number of ----
-CODE_BLOCK_DELIM = '----'
-
-# Mostly for ref page blocks, but also used elsewhere?
-REF_PAGE_LIKE_BLOCK_DELIM = '--'
-
-# For insets/blocks like the implicit valid usage
-# TODO think it must start with this - does it have to be exactly this?
-BOX_BLOCK_DELIM = '****'
-
-
-INTERNAL_PLACEHOLDER = re.compile(
- r'(?P<delim>__+)([a-zA-Z]+)(?P=delim)'
-)
-
-# Matches a generated (api or validity) include line.
-INCLUDE = re.compile(
- r'include::(?P<directory_traverse>((../){1,4}|\{(INCS-VAR|generated)\}/)(generated/)?)(?P<generated_type>[\w]+)/(?P<category>\w+)/(?P<entity_name>[^./]+).txt[\[][\]]')
-
-# Matches an [[AnchorLikeThis]]
-ANCHOR = re.compile(r'\[\[(?P<entity_name>[^\]]+)\]\]')
-
-# Looks for flink:foo:: or slink::foo:: at the end of string:
-# used to detect explicit pname context.
-PRECEDING_MEMBER_REFERENCE = re.compile(
- r'\b(?P<macro>[fs](text|link)):(?P<entity_name>[\w*]+)::$')
-
-# Matches something like slink:foo::pname:bar as well as
-# the under-marked-up slink:foo::bar.
-MEMBER_REFERENCE = re.compile(
- r'\b(?P<first_part>(?P<scope_macro>[fs](text|link)):(?P<scope>[\w*]+))(?P<double_colons>::)(?P<second_part>(?P<member_macro>pname:?)(?P<entity_name>[\w]+))\b'
-)
-
-# Matches if a string ends while a link is still "open".
-# (first half of a link being broken across two lines,
-# or containing our interested area when matched against the text preceding).
-# Used to skip checking in some places.
-OPEN_LINK = re.compile(
- r'.*(?<!`)<<[^>]*$'
-)
-
-# Matches if a string begins and is followed by a link "close" without a matching open.
-# (second half of a link being broken across two lines)
-# Used to skip checking in some places.
-CLOSE_LINK = re.compile(
- r'[^<]*>>.*$'
-)
-
-# Matches if a line should be skipped without further considering.
-# Matches lines starting with:
-# - `ifdef:`
-# - `endif:`
-# - `todo` (followed by something matching \b, like : or (. capitalization ignored)
-SKIP_LINE = re.compile(
- r'^(ifdef:)|(endif:)|([tT][oO][dD][oO]\b).*'
-)
-
-# Matches the whole inside of a refpage tag.
-BRACKETS = re.compile(r'\[(?P<tags>.*)\]')
-
-# Matches a key='value' pair from a ref page tag.
-REF_PAGE_ATTRIB = re.compile(
- r"(?P<key>[a-z]+)='(?P<value>[^'\\]*(?:\\.[^'\\]*)*)'")
-
-
-class Attrib(Enum):
- """Attributes of a ref page."""
-
- REFPAGE = 'refpage'
- DESC = 'desc'
- TYPE = 'type'
- ALIAS = 'alias'
- XREFS = 'xrefs'
- ANCHOR = 'anchor'
-
-
-VALID_REF_PAGE_ATTRIBS = set(
- (e.value for e in Attrib))
-
-AttribData = namedtuple('AttribData', ['match', 'key', 'value'])
-
-
-def makeAttribFromMatch(match):
- """Turn a match of REF_PAGE_ATTRIB into an AttribData value."""
- return AttribData(match=match, key=match.group(
- 'key'), value=match.group('value'))
-
-
-def parseRefPageAttribs(line):
- """Parse a ref page tag into a dictionary of attribute_name: AttribData."""
- return {m.group('key'): makeAttribFromMatch(m)
- for m in REF_PAGE_ATTRIB.finditer(line)}
-
-
-def regenerateIncludeFromMatch(match, generated_type):
- """Create an include directive from an INCLUDE match and a (new or replacement) generated_type."""
- return generateInclude(
- match.group('directory_traverse'),
- generated_type,
- match.group('category'),
- match.group('entity_name'))
-
-
-BlockEntry = namedtuple(
- 'BlockEntry', ['delimiter', 'context', 'block_type', 'refpage'])
-
-
-class BlockType(Enum):
- """Enumeration of the various distinct block types known."""
- CODE = 'code'
- REF_PAGE_LIKE = 'ref-page-like' # with or without a ref page tag before
- BOX = 'box'
-
- @classmethod
- def lineToBlockType(self, line):
- """Return a BlockType if the given line is a block delimiter.
-
- Returns None otherwise.
- """
- if line == REF_PAGE_LIKE_BLOCK_DELIM:
- return BlockType.REF_PAGE_LIKE
- if line.startswith(CODE_BLOCK_DELIM):
- return BlockType.CODE
- if line.startswith(BOX_BLOCK_DELIM):
- return BlockType.BOX
-
- return None
-
-
-def _pluralize(word, num):
- if num == 1:
- return word
- if word.endswith('y'):
- return word[:-1] + 'ies'
- return word + 's'
-
-
-def _s_suffix(num):
- """Simplify pluralization."""
- if num > 1:
- return 's'
- return ''
-
-
-def shouldEntityBeText(entity, subscript):
- """Determine if an entity name appears to use placeholders, wildcards, etc. and thus merits use of a *text macro.
-
- Call with the entity and subscript groups from a match of MacroChecker.macro_re.
- """
- entity_only = entity
- if subscript:
- if subscript == '[]' or subscript == '[i]' or subscript.startswith(
- '[_') or subscript.endswith('_]'):
- return True
- entity_only = entity[:-len(subscript)]
-
- if ('*' in entity) or entity.startswith('_') or entity_only.endswith('_'):
- return True
-
- if INTERNAL_PLACEHOLDER.search(entity):
- return True
- return False
-
-
-class MacroCheckerFile(object):
- """Object performing processing of a single AsciiDoctor file from a specification.
-
- For testing purposes, may also process a string as if it were a file.
- """
-
- def __init__(self, checker, filename, enabled_messages, stream_maker):
- """Construct a MacroCheckerFile object.
-
- Typically called by MacroChecker.processFile or MacroChecker.processString().
-
- Arguments:
- checker -- A MacroChecker object.
- filename -- A string to use in messages to refer to this checker, typically the file name.
- enabled_messages -- A set() of MessageId values that should be considered "enabled" and thus stored.
- stream_maker -- An object with a makeStream() method that returns a stream.
- """
- self.checker = checker
- self.filename = filename
- self.stream_maker = stream_maker
- self.enabled_messages = enabled_messages
- self.missing_validity_suppressions = set(
- self.getMissingValiditySuppressions())
-
- self.logger = logging.getLogger(__name__)
- self.logger.addHandler(logging.NullHandler())
-
- self.fixes = set()
- self.messages = []
-
- self.pname_data = None
- self.pname_mentions = {}
-
- self.refpage_includes = {}
-
- self.lines = []
-
- # For both of these:
- # keys: entity name
- # values: MessageContext
- self.fs_api_includes = {}
- self.validity_includes = {}
-
- self.in_code_block = False
- self.in_ref_page = False
- self.prev_line_ref_page_tag = None
- self.current_ref_page = None
-
- # Stack of block-starting delimiters.
- self.block_stack = []
-
- # Regexes that are members because they depend on the name prefix.
- self.suspected_missing_macro_re = self.checker.suspected_missing_macro_re
- self.heading_command_re = self.checker.heading_command_re
-
- ###
- # Main process/checking methods, arranged roughly from largest scope to smallest scope.
- ###
-
- def process(self):
- """Check the stream (file, string) created by the streammaker supplied to the constructor.
-
- This is the top-level method for checking a spec file.
- """
- self.logger.info("processing file %s", self.filename)
-
- # File content checks - performed line-by-line
- with self.stream_maker.make_stream() as f:
- # Iterate through lines, calling processLine on each.
- for lineIndex, line in enumerate(f):
- trimmedLine = line.rstrip()
- self.lines.append(trimmedLine)
- self.processLine(lineIndex + 1, trimmedLine)
-
- # End of file checks follow:
-
- # Check "state" at end of file: should have blocks closed.
- if self.prev_line_ref_page_tag:
- self.error(MessageId.REFPAGE_BLOCK,
- "Reference page tag seen, but block not opened before end of file.",
- context=self.storeMessageContext(match=None))
-
- if self.block_stack:
- locations = (x.context for x in self.block_stack)
- formatted_locations = ['{} opened at {}'.format(x.delimiter, self.getBriefLocation(x.context))
- for x in self.block_stack]
- self.logger.warning("Unclosed blocks: %s",
- ', '.join(formatted_locations))
-
- self.error(MessageId.UNCLOSED_BLOCK,
- ["Reached end of page, with these unclosed blocks remaining:"] +
- formatted_locations,
- context=self.storeMessageContext(match=None),
- see_also=locations)
-
- # Check that every include of an /api/ file in the protos or structs category
- # had a matching /validity/ include
- for entity, includeContext in self.fs_api_includes.items():
- if not self.checker.entity_db.entityHasValidity(entity):
- continue
-
- if entity in self.missing_validity_suppressions:
- continue
-
- if entity not in self.validity_includes:
- self.warning(MessageId.MISSING_VALIDITY_INCLUDE,
- ['Saw /api/ include for {}, but no matching /validity/ include'.format(entity),
- 'Expected a line with ' + regenerateIncludeFromMatch(includeContext.match, 'validity')],
- context=includeContext)
-
- # Check that we never include a /validity/ file
- # without a matching /api/ include
- for entity, includeContext in self.validity_includes.items():
- if entity not in self.fs_api_includes:
- self.error(MessageId.MISSING_API_INCLUDE,
- ['Saw /validity/ include for {}, but no matching /api/ include'.format(entity),
- 'Expected a line with ' + regenerateIncludeFromMatch(includeContext.match, 'api')],
- context=includeContext)
-
- if not self.numDiagnostics():
- # no problems, exit quietly
- return
-
- print('\nFor file {}:'.format(self.filename))
-
- self.printMessageCounts()
- numFixes = len(self.fixes)
- if numFixes > 0:
- fixes = ', '.join(('{} -> {}'.format(search, replace)
- for search, replace in self.fixes))
-
- print('{} unique auto-fix {} recorded: {}'.format(numFixes,
- _pluralize('pattern', numFixes), fixes))
-
- def processLine(self, lineNum, line):
- """Check the contents of a single line from a file.
-
- Eventually populates self.match, self.entity, self.macro,
- before calling processMatch.
- """
- self.lineNum = lineNum
- self.line = line
- self.match = None
- self.entity = None
- self.macro = None
-
- self.logger.debug("processing line %d", lineNum)
-
- if self.processPossibleBlockDelimiter():
- # This is a block delimiter - proceed to next line.
- # Block-type-specific stuff goes in processBlockOpen and processBlockClosed.
- return
-
- if self.in_code_block:
- # We do no processing in a code block.
- return
-
- ###
- # Detect if the previous line was [open,...] starting a refpage
- # but this line isn't --
- # If the line is some other block delimiter,
- # the related code in self.processPossibleBlockDelimiter()
- # would have handled it.
- # (because execution would never get to here for that line)
- if self.prev_line_ref_page_tag:
- self.handleExpectedRefpageBlock()
-
- ###
- # Detect headings
- if line.startswith('=='):
- # Headings cause us to clear our pname_context
- self.pname_data = None
-
- command = self.heading_command_re.match(line)
- if command:
- data = self.checker.findEntity(command)
- if data:
- self.pname_data = data
- return
-
- ###
- # Detect [open, lines for manpages
- if line.startswith('[open,'):
- self.checkRefPage()
- return
-
- ###
- # Skip comments
- if line.lstrip().startswith('//'):
- return
-
- ###
- # Skip ifdef/endif
- if SKIP_LINE.match(line):
- return
-
- ###
- # Detect include:::....[] lines
- match = INCLUDE.match(line)
- if match:
- self.match = match
- entity = match.group('entity_name')
-
- data = self.checker.findEntity(entity)
- if not data:
- self.error(MessageId.UNKNOWN_INCLUDE,
- 'Saw include for {}, but that entity is unknown.'.format(entity))
- self.pname_data = None
- return
-
- self.pname_data = data
-
- if match.group('generated_type') == 'api':
- self.recordInclude(self.checker.apiIncludes)
-
- # Set mentions to None. The first time we see something like `* pname:paramHere`,
- # we will set it to an empty set
- self.pname_mentions[entity] = None
-
- if match.group('category') in CATEGORIES_WITH_VALIDITY:
- self.fs_api_includes[entity] = self.storeMessageContext()
-
- if entity in self.validity_includes:
- name_and_line = toNameAndLine(
- self.validity_includes[entity], root_path=self.checker.root_path)
- self.error(MessageId.API_VALIDITY_ORDER,
- ['/api/ include found for {} after a corresponding /validity/ include'.format(entity),
- 'Validity include located at {}'.format(name_and_line)])
-
- elif match.group('generated_type') == 'validity':
- self.recordInclude(self.checker.validityIncludes)
- self.validity_includes[entity] = self.storeMessageContext()
-
- if entity not in self.pname_mentions:
- self.error(MessageId.API_VALIDITY_ORDER,
- '/validity/ include found for {} without a preceding /api/ include'.format(entity))
- return
-
- if self.pname_mentions[entity]:
- # Got a validity include and we have seen at least one * pname: line
- # since we got the API include
- # so we can warn if we haven't seen a reference to every
- # parameter/member.
- members = self.checker.getMemberNames(entity)
- missing = [member for member in members
- if member not in self.pname_mentions[entity]]
- if missing:
- self.error(MessageId.UNDOCUMENTED_MEMBER,
- ['Validity include found for {}, but not all members/params apparently documented'.format(entity),
- 'Members/params not mentioned with pname: {}'.format(', '.join(missing))])
-
- # If we found an include line, we're done with this line.
- return
-
- if self.pname_data is not None and '* pname:' in line:
- context_entity = self.pname_data.entity
- if self.pname_mentions[context_entity] is None:
- # First time seeting * pname: after an api include, prepare the set that
- # tracks
- self.pname_mentions[context_entity] = set()
-
- ###
- # Detect [[Entity]] anchors
- for match in ANCHOR.finditer(line):
- entity = match.group('entity_name')
- if self.checker.findEntity(entity):
- # We found an anchor with the same name as an entity:
- # treat it (mostly) like an API include
- self.match = match
- self.recordInclude(self.checker.apiIncludes,
- generated_type='api (manual anchor)')
-
- ###
- # Detect :: without pname
- for match in MEMBER_REFERENCE.finditer(line):
- if not match.group('member_macro'):
- self.match = match
- # Got :: but not followed by pname
-
- search = match.group()
- replacement = match.group(
- 'first_part') + '::pname:' + match.group('second_part')
- self.error(MessageId.MEMBER_PNAME_MISSING,
- 'Found a function parameter or struct member reference with :: but missing pname:',
- group='double_colons',
- replacement='::pname:',
- fix=(search, replacement))
-
- # check pname here because it won't come up in normal iteration below
- # because of the missing macro
- self.entity = match.group('entity_name')
- self.checkPname(match.group('scope'))
-
- ###
- # Look for things that seem like a missing macro.
- for match in self.suspected_missing_macro_re.finditer(line):
- if OPEN_LINK.match(line, endpos=match.start()):
- # this is in a link, skip it.
- continue
- if CLOSE_LINK.match(line[match.end():]):
- # this is in a link, skip it.
- continue
-
- entity = match.group('entity_name')
- self.match = match
- self.entity = entity
- data = self.checker.findEntity(entity)
- if data:
-
- if data.category == EXTENSION_CATEGORY:
- # Ah, this is an extension
- self.warning(MessageId.EXTENSION, "Seems like this is an extension name that was not linked.",
- group='entity_name', replacement=self.makeExtensionLink())
- else:
- self.warning(MessageId.MISSING_MACRO,
- ['Seems like a "{}" macro was omitted for this reference to a known entity in category "{}".'.format(data.macro, data.category),
- 'Wrap in ` ` to silence this if you do not want a verified macro here.'],
- group='entity_name',
- replacement=self.makeMacroMarkup(data.macro))
- else:
-
- dataArray = self.checker.findEntityCaseInsensitive(entity)
- # We might have found the goof...
-
- if dataArray:
- if len(dataArray) == 1:
- # Yep, found the goof:
- # incorrect macro and entity capitalization
- data = dataArray[0]
- if data.category == EXTENSION_CATEGORY:
- # Ah, this is an extension
- self.warning(MessageId.EXTENSION,
- "Seems like this is an extension name that was not linked.",
- group='entity_name', replacement=self.makeExtensionLink(data.entity))
- else:
- self.warning(MessageId.MISSING_MACRO,
- 'Seems like a macro was omitted for this reference to a known entity in category "{}", found by searching case-insensitively.'.format(
- data.category),
- replacement=self.makeMacroMarkup(data=data))
-
- else:
- # Ugh, more than one resolution
-
- self.warning(MessageId.MISSING_MACRO,
- ['Seems like a macro was omitted for this reference to a known entity, found by searching case-insensitively.',
- 'More than one apparent match.'],
- group='entity_name', see_also=dataArray[:])
-
- ###
- # Main operations: detect markup macros
- for match in self.checker.macro_re.finditer(line):
- self.match = match
- self.macro = match.group('macro')
- self.entity = match.group('entity_name')
- self.subscript = match.group('subscript')
- self.processMatch()
-
- def processPossibleBlockDelimiter(self):
- """Look at the current line, and if it's a delimiter, update the block stack.
-
- Calls self.processBlockDelimiter() as required.
-
- Returns True if a delimiter was processed, False otherwise.
- """
- line = self.line
- new_block_type = BlockType.lineToBlockType(line)
- if not new_block_type:
- return False
-
- ###
- # Detect if the previous line was [open,...] starting a refpage
- # but this line is some block delimiter other than --
- # Must do this here because if we get a different block open instead of the one we want,
- # the order of block opening will be wrong.
- if new_block_type != BlockType.REF_PAGE_LIKE and self.prev_line_ref_page_tag:
- self.handleExpectedRefpageBlock()
-
- # Delegate to the main process for delimiters.
- self.processBlockDelimiter(line, new_block_type)
-
- return True
-
- def processBlockDelimiter(self, line, new_block_type, context=None):
- """Update the block stack based on the current or supplied line.
-
- Calls self.processBlockOpen() or self.processBlockClosed() as required.
-
- Called by self.processPossibleBlockDelimiter() both in normal operation, as well as
- when "faking" a ref page block open.
-
- Returns BlockProcessResult.
- """
- if not context:
- context = self.storeMessageContext()
-
- location = self.getBriefLocation(context)
-
- top = self.getInnermostBlockEntry()
- top_delim = self.getInnermostBlockDelimiter()
- if top_delim == line:
- self.processBlockClosed()
- return
-
- if top and top.block_type == new_block_type:
- # Same block type, but not matching - might be an error?
- # TODO maybe create a diagnostic here?
- self.logger.warning(
- "processPossibleBlockDelimiter: %s: Matched delimiter type %s, but did not exactly match current delim %s to top of stack %s, may be a typo?",
- location, new_block_type, line, top_delim)
-
- # Empty stack, or top doesn't match us.
- self.processBlockOpen(new_block_type, delimiter=line)
-
- def processBlockOpen(self, block_type, context=None, delimiter=None):
- """Do any block-type-specific processing and push the new block.
-
- Must call self.pushBlock().
- May be overridden (carefully) or extended.
-
- Called by self.processBlockDelimiter().
- """
- if block_type == BlockType.REF_PAGE_LIKE:
- if self.prev_line_ref_page_tag:
- if self.current_ref_page:
- refpage = self.current_ref_page
- else:
- refpage = '?refpage-with-invalid-tag?'
-
- self.logger.info(
- 'processBlockOpen: Opening refpage for %s', refpage)
- # Opening of refpage block "consumes" the preceding ref
- # page context
- self.prev_line_ref_page_tag = None
- self.pushBlock(block_type, refpage=refpage,
- context=context, delimiter=delimiter)
- self.in_ref_page = True
- return
-
- if block_type == BlockType.CODE:
- self.in_code_block = True
-
- self.pushBlock(block_type, context=context, delimiter=delimiter)
-
- def processBlockClosed(self):
- """Do any block-type-specific processing and pop the top block.
-
- Must call self.popBlock().
- May be overridden (carefully) or extended.
-
- Called by self.processPossibleBlockDelimiter().
- """
- old_top = self.popBlock()
-
- if old_top.block_type == BlockType.CODE:
- self.in_code_block = False
-
- elif old_top.block_type == BlockType.REF_PAGE_LIKE and old_top.refpage:
- self.logger.info(
- 'processBlockClosed: Closing refpage for %s', old_top.refpage)
- # leaving a ref page so reset associated state.
- self.current_ref_page = None
- self.prev_line_ref_page_tag = None
- self.in_ref_page = False
-
- def processMatch(self):
- """Process a match of the macro:entity regex for correctness."""
- match = self.match
- entity = self.entity
- macro = self.macro
-
- ###
- # Track entities that we're actually linking to.
- ###
- if self.checker.entity_db.isLinkedMacro(macro):
- self.checker.addLinkToEntity(entity, self.storeMessageContext())
-
- ###
- # Link everything that should be, and nothing that shouldn't be
- ###
- if self.checkRecognizedEntity():
- # if this returns true,
- # then there is no need to do the remaining checks on this match
- return
-
- ###
- # Non-existent macros
- if macro in NON_EXISTENT_MACROS:
- self.error(MessageId.BAD_MACRO, '{} is not a macro provided in the specification, despite resembling other macros.'.format(
- macro), group='macro')
-
- ###
- # Wildcards (or leading underscore, or square brackets)
- # if and only if a 'text' macro
- self.checkText()
-
- # Do some validation of pname references.
- if macro == 'pname':
- # See if there's an immediately-preceding entity
- preceding = self.line[:match.start()]
- scope = PRECEDING_MEMBER_REFERENCE.search(preceding)
- if scope:
- # Yes there is, check it out.
- self.checkPname(scope.group('entity_name'))
- elif self.current_ref_page is not None:
- # No, but there is a current ref page: very reliable
- self.checkPnameImpliedContext(self.current_ref_page)
- elif self.pname_data is not None:
- # No, but there is a pname_context - better than nothing.
- self.checkPnameImpliedContext(self.pname_data)
- else:
- # no, and no existing context we can imply:
- # can't check this.
- pass
-
- def checkRecognizedEntity(self):
- """Check the current macro:entity match to see if it is recognized.
-
- Returns True if there is no need to perform further checks on this match.
-
- Helps avoid duplicate warnings/errors: typically each macro should have at most
- one of this class of errors.
- """
- entity = self.entity
- macro = self.macro
- if self.checker.findMacroAndEntity(macro, entity) is not None:
- # We know this macro-entity combo
- return True
-
- # We don't know this macro-entity combo.
- possibleCats = self.checker.entity_db.getCategoriesForMacro(macro)
- if possibleCats is None:
- possibleCats = ['???']
- msg = ['Definition of link target {} with macro {} (used for {} {}) does not exist.'.format(
- entity,
- macro,
- _pluralize('category', len(possibleCats)),
- ', '.join(possibleCats))]
-
- data = self.checker.findEntity(entity)
- if data:
- # We found the goof: incorrect macro
- msg.append('Apparently matching entity in category {} found.'.format(
- data.category))
- self.handleWrongMacro(msg, data)
- return True
-
- see_also = []
- dataArray = self.checker.findEntityCaseInsensitive(entity)
- if dataArray:
- # We might have found the goof...
-
- if len(dataArray) == 1:
- # Yep, found the goof:
- # incorrect macro and entity capitalization
- data = dataArray[0]
- msg.append('Apparently matching entity in category {} found by searching case-insensitively.'.format(
- data.category))
- self.handleWrongMacro(msg, data)
- return True
- else:
- # Ugh, more than one resolution
- msg.append(
- 'More than one apparent match found by searching case-insensitively, cannot auto-fix.')
- see_also = dataArray[:]
-
- # OK, so we don't recognize this entity (and couldn't auto-fix it).
-
- if self.checker.entity_db.shouldBeRecognized(macro, entity):
- # We should know the target - it's a link macro,
- # or there's some reason the entity DB thinks we should know it.
- if self.checker.likelyRecognizedEntity(entity):
- # Should be linked and it matches our pattern,
- # so probably not wrong macro.
- # Human brains required.
- if not self.checkText():
- self.error(MessageId.BAD_ENTITY, msg + ['Might be a misspelling, or, less likely, the wrong macro.'],
- see_also=see_also)
- else:
- # Doesn't match our pattern,
- # so probably should be name instead of link.
- newMacro = macro[0] + 'name'
- if self.checker.entity_db.isValidMacro(newMacro):
- self.error(MessageId.BAD_ENTITY, msg +
- ['Entity name does not fit the pattern for this API, which would mean it should be a "name" macro instead of a "link" macro'],
- group='macro', replacement=newMacro, fix=self.makeFix(newMacro=newMacro), see_also=see_also)
- else:
- self.error(MessageId.BAD_ENTITY, msg +
- ['Entity name does not fit the pattern for this API, which would mean it should be a "name" macro instead of a "link" macro',
- 'However, {} is not a known macro so cannot auto-fix.'.format(newMacro)], see_also=see_also)
-
- elif macro == 'ename':
- # TODO This might be an ambiguity in the style guide - ename might be a known enumerant value,
- # or it might be an enumerant value in an external library, etc. that we don't know about - so
- # hard to check this.
- if self.checker.likelyRecognizedEntity(entity):
- if not self.checkText():
- self.warning(MessageId.BAD_ENUMERANT, msg +
- ['Unrecognized ename:{} that we would expect to recognize since it fits the pattern for this API.'.format(entity)], see_also=see_also)
- else:
- # This is fine:
- # it doesn't need to be recognized since it's not linked.
- pass
- # Don't skip other tests.
- return False
-
- def checkText(self):
- """Evaluate the usage (or non-usage) of a *text macro.
-
- Wildcards (or leading or trailing underscore, or square brackets with
- nothing or a placeholder) if and only if a 'text' macro.
-
- Called by checkRecognizedEntity() when appropriate.
- """
- macro = self.macro
- entity = self.entity
- shouldBeText = shouldEntityBeText(entity, self.subscript)
- if shouldBeText and not self.macro.endswith(
- 'text') and not self.macro == 'code':
- newMacro = macro[0] + 'text'
- if self.checker.entity_db.getCategoriesForMacro(newMacro):
- self.error(MessageId.MISSING_TEXT,
- ['Asterisk/leading or trailing underscore/bracket found - macro should end with "text:", probably {}:'.format(newMacro),
- AUTO_FIX_STRING],
- group='macro', replacement=newMacro, fix=self.makeFix(newMacro=newMacro))
- else:
- self.error(MessageId.MISSING_TEXT,
- ['Asterisk/leading or trailing underscore/bracket found, so macro should end with "text:".',
- 'However {}: is not a known macro so cannot auto-fix.'.format(newMacro)],
- group='macro')
- return True
- elif macro.endswith('text') and not shouldBeText:
- msg = [
- "No asterisk/leading or trailing underscore/bracket in the entity, so this might be a mistaken use of the 'text' macro {}:".format(macro)]
- data = self.checker.findEntity(entity)
- if data:
- # We found the goof: incorrect macro
- msg.append('Apparently matching entity in category {} found.'.format(
- data.category))
- msg.append(AUTO_FIX_STRING)
- replacement = self.makeFix(data=data)
- if data.category == EXTENSION_CATEGORY:
- self.error(MessageId.EXTENSION, msg,
- replacement=replacement, fix=replacement)
- else:
- self.error(MessageId.WRONG_MACRO, msg,
- group='macro', replacement=data.macro, fix=replacement)
- else:
- if self.checker.likelyRecognizedEntity(entity):
- # This is a use of *text: for something that fits the pattern but isn't in the spec.
- # This is OK.
- return False
- msg.append('Entity not found in spec, either.')
- if macro[0] != 'e':
- # Only suggest a macro if we aren't in elink/ename/etext,
- # since ename and elink are not related in an equivalent way
- # to the relationship between flink and fname.
- newMacro = macro[0] + 'name'
- if self.checker.entity_db.getCategoriesForMacro(newMacro):
- msg.append(
- 'Consider if {}: might be the correct macro to use here.'.format(newMacro))
- else:
- msg.append(
- 'Cannot suggest a new macro because {}: is not a known macro.'.format(newMacro))
- self.warning(MessageId.MISUSED_TEXT, msg)
- return True
- return False
-
- def checkPnameImpliedContext(self, pname_context):
- """Handle pname: macros not immediately preceded by something like flink:entity or slink:entity.
-
- Also records pname: mentions of members/parameters for completeness checking in doc blocks.
-
- Contains call to self.checkPname().
- Called by self.processMatch()
- """
- self.checkPname(pname_context.entity)
- if pname_context.entity in self.pname_mentions and \
- self.pname_mentions[pname_context.entity] is not None:
- # Record this mention,
- # in case we're in the documentation block.
- self.pname_mentions[pname_context.entity].add(self.entity)
-
- def checkPname(self, pname_context):
- """Check the current match (as a pname: usage) with the given entity as its 'pname context', if possible.
-
- e.g. slink:foo::pname:bar, pname_context would be 'foo', while self.entity would be 'bar', etc.
-
- Called by self.processLine(), self.processMatch(), as well as from self.checkPnameImpliedContext().
- """
- if '*' in pname_context:
- # This context has a placeholder, can't verify it.
- return
-
- entity = self.entity
-
- context_data = self.checker.findEntity(pname_context)
- members = self.checker.getMemberNames(pname_context)
-
- if context_data and not members:
- # This is a recognized parent entity that doesn't have detectable member names,
- # skip validation
- # TODO: Annotate parameters of function pointer types with <name>
- # and <param>?
- return
- if not members:
- self.warning(MessageId.UNRECOGNIZED_CONTEXT,
- 'pname context entity was un-recognized {}'.format(pname_context))
- return
-
- if entity not in members:
- self.warning(MessageId.UNKNOWN_MEMBER, ["Could not find member/param named '{}' in {}".format(entity, pname_context),
- 'Known {} mamber/param names are: {}'.format(
- pname_context, ', '.join(members))], group='entity_name')
-
- def checkIncludeRefPageRelation(self, entity, generated_type):
- """Identify if our current ref page (or lack thereof) is appropriate for an include just recorded.
-
- Called by self.recordInclude().
- """
- if not self.in_ref_page:
- # Not in a ref page block: This probably means this entity needs a
- # ref-page block added.
- self.handleIncludeMissingRefPage(entity, generated_type)
- return
-
- if not isinstance(self.current_ref_page, EntityData):
- # This isn't a fully-valid ref page, so can't check the includes any better.
- return
-
- ref_page_entity = self.current_ref_page.entity
- if ref_page_entity not in self.refpage_includes:
- self.refpage_includes[ref_page_entity] = set()
- expected_ref_page_entity = self.computeExpectedRefPageFromInclude(
- entity)
- self.refpage_includes[ref_page_entity].add((generated_type, entity))
-
- if ref_page_entity == expected_ref_page_entity:
- # OK, this is a total match.
- pass
- elif self.checker.entity_db.areAliases(expected_ref_page_entity, ref_page_entity):
- # This appears to be a promoted synonym which is OK.
- pass
- else:
- # OK, we are in a ref page block that doesn't match
- self.handleIncludeMismatchRefPage(entity, generated_type)
-
- def checkRefPage(self):
- """Check if the current line (a refpage tag) meets requirements.
-
- Called by self.processLine().
- """
- line = self.line
-
- # Should always be found
- self.match = BRACKETS.match(line)
-
- data = None
- directory = None
- if self.in_ref_page:
- msg = ["Found reference page markup, but we are already in a refpage block.",
- "The block before the first message of this type is most likely not closed.", ]
- # Fake-close the previous ref page, if it's trivial to do so.
- if self.getInnermostBlockEntry().block_type == BlockType.REF_PAGE_LIKE:
- msg.append(
- "Pretending that there was a line with `--` immediately above to close that ref page, for more readable messages.")
- self.processBlockDelimiter(
- REF_PAGE_LIKE_BLOCK_DELIM, BlockType.REF_PAGE_LIKE)
- else:
- msg.append(
- "Ref page wasn't the last block opened, so not pretending to auto-close it for more readable messages.")
-
- self.error(MessageId.REFPAGE_BLOCK, msg)
-
- attribs = parseRefPageAttribs(line)
-
- unknown_attribs = set(attribs.keys()).difference(
- VALID_REF_PAGE_ATTRIBS)
- if unknown_attribs:
- self.error(MessageId.REFPAGE_UNKNOWN_ATTRIB,
- "Found unknown attrib(s) in reference page markup: " + ','.join(unknown_attribs))
-
- # Required field: refpage='xrValidEntityHere'
- if Attrib.REFPAGE.value in attribs:
- attrib = attribs[Attrib.REFPAGE.value]
- text = attrib.value
- self.entity = text
-
- context = self.storeMessageContext(
- group='value', match=attrib.match)
- if self.checker.seenRefPage(text):
- self.error(MessageId.REFPAGE_DUPLICATE,
- ["Found reference page markup when we already saw refpage='{}' elsewhere.".format(
- text),
- "This (or the other mention) may be a copy-paste error."],
- context=context)
- self.checker.addRefPage(text)
-
- # Skip entity check if it's a spir-v built in
- type = ''
- if Attrib.TYPE.value in attribs:
- type = attribs[Attrib.TYPE.value].value
-
- if type != 'builtins' and type != 'spirv':
- data = self.checker.findEntity(text)
- self.current_ref_page = data
- if data:
- # OK, this is a known entity that we're seeing a refpage for.
- directory = data.directory
- else:
- # TODO suggest fixes here if applicable
- self.error(MessageId.REFPAGE_NAME,
- [ "Found reference page markup, but refpage='{}' type='{}' does not refer to a recognized entity".format(
- text, type),
- 'If this is intentional, add the entity to EXTRA_DEFINES or EXTRA_REFPAGES in check_spec_links.py.' ],
- context=context)
-
- else:
- self.error(MessageId.REFPAGE_TAG,
- "Found apparent reference page markup, but missing refpage='...'",
- group=None)
-
- # Required field: desc='preferably non-empty'
- if Attrib.DESC.value in attribs:
- attrib = attribs[Attrib.DESC.value]
- text = attrib.value
- if not text:
- context = self.storeMessageContext(
- group=None, match=attrib.match)
- self.warning(MessageId.REFPAGE_MISSING_DESC,
- "Found reference page markup, but desc='' is empty",
- context=context)
- else:
- self.error(MessageId.REFPAGE_TAG,
- "Found apparent reference page markup, but missing desc='...'",
- group=None)
-
- # Required field: type='protos' for example
- # (used by genRef.py to compute the macro to use)
- if Attrib.TYPE.value in attribs:
- attrib = attribs[Attrib.TYPE.value]
- text = attrib.value
- if directory and not text == directory:
- context = self.storeMessageContext(
- group='value', match=attrib.match)
- self.error(MessageId.REFPAGE_TYPE,
- "Found reference page markup, but type='{}' is not the expected value '{}'".format(
- text, directory),
- context=context)
- else:
- self.error(MessageId.REFPAGE_TAG,
- "Found apparent reference page markup, but missing type='...'",
- group=None)
-
- # Optional field: alias='spaceDelimited validEntities'
- # Currently does nothing. Could modify checkRefPageXrefs to also
- # check alias= attribute value
- # if Attrib.ALIAS.value in attribs:
- # # This field is optional
- # self.checkRefPageXrefs(attribs[Attrib.XREFS.value])
-
- # Optional field: xrefs='spaceDelimited validEntities'
- if Attrib.XREFS.value in attribs:
- # This field is optional
- self.checkRefPageXrefs(attribs[Attrib.XREFS.value])
- self.prev_line_ref_page_tag = self.storeMessageContext()
-
- def checkRefPageXrefs(self, xrefs_attrib):
- """Check all cross-refs indicated in an xrefs attribute for a ref page.
-
- Called by self.checkRefPage().
-
- Argument:
- xrefs_attrib -- A match of REF_PAGE_ATTRIB where the group 'key' is 'xrefs'.
- """
- text = xrefs_attrib.value
- context = self.storeMessageContext(
- group='value', match=xrefs_attrib.match)
-
- def splitRefs(s):
- """Split the string on whitespace, into individual references."""
- return s.split() # [x for x in s.split() if x]
-
- def remakeRefs(refs):
- """Re-create a xrefs string from something list-shaped."""
- return ' '.join(refs)
-
- refs = splitRefs(text)
-
- # Pre-checking if messages are enabled, so that we can correctly determine
- # the current string following any auto-fixes:
- # the fixes for messages directly in this method would interact,
- # and thus must be in the order specified here.
-
- if self.messageEnabled(MessageId.REFPAGE_XREFS_COMMA) and ',' in text:
- old_text = text
- # Re-split after replacing commas.
- refs = splitRefs(text.replace(',', ' '))
- # Re-create the space-delimited text.
- text = remakeRefs(refs)
- self.error(MessageId.REFPAGE_XREFS_COMMA,
- "Found reference page markup, with an unexpected comma in the (space-delimited) xrefs attribute",
- context=context,
- replacement=text,
- fix=(old_text, text))
-
- # We could conditionally perform this creation, but the code complexity would increase substantially,
- # for presumably minimal runtime improvement.
- unique_refs = OrderedDict.fromkeys(refs)
- if self.messageEnabled(MessageId.REFPAGE_XREF_DUPE) and len(unique_refs) != len(refs):
- # TODO is it safe to auto-fix here?
- old_text = text
- text = remakeRefs(unique_refs.keys())
- self.warning(MessageId.REFPAGE_XREF_DUPE,
- ["Reference page for {} contains at least one duplicate in its cross-references.".format(
- self.entity),
- "Look carefully to see if this is a copy and paste error and should be changed to a different but related entity:",
- "auto-fix simply removes the duplicate."],
- context=context,
- replacement=text,
- fix=(old_text, text))
-
- if self.messageEnabled(MessageId.REFPAGE_SELF_XREF) and self.entity and self.entity in unique_refs:
- # Not modifying unique_refs here because that would accidentally affect the whitespace auto-fix.
- new_text = remakeRefs(
- [x for x in unique_refs.keys() if x != self.entity])
-
- # DON'T AUTOFIX HERE because these are likely copy-paste between related entities:
- # e.g. a Create function and the associated CreateInfo struct.
- self.warning(MessageId.REFPAGE_SELF_XREF,
- ["Reference page for {} included itself in its cross-references.".format(self.entity),
- "This is typically a copy and paste error, and the dupe should likely be changed to a different but related entity.",
- "Not auto-fixing for this reason."],
- context=context,
- replacement=new_text,)
-
- # We didn't have another reason to replace the whole attribute value,
- # so let's make sure it doesn't have any extra spaces
- if self.messageEnabled(MessageId.REFPAGE_WHITESPACE) and xrefs_attrib.value == text:
- old_text = text
- text = remakeRefs(unique_refs.keys())
- if old_text != text:
- self.warning(MessageId.REFPAGE_WHITESPACE,
- ["Cross-references for reference page for {} had non-minimal whitespace,".format(self.entity),
- "and no other enabled message has re-constructed this value already."],
- context=context,
- replacement=text,
- fix=(old_text, text))
-
- for entity in unique_refs.keys():
- self.checkRefPageXref(entity, context)
-
- def checkRefPageXref(self, referenced_entity, line_context):
- """Check a single cross-reference entry for a refpage.
-
- Called by self.checkRefPageXrefs().
-
- Arguments:
- referenced_entity -- The individual entity under consideration from the xrefs='...' string.
- line_context -- A MessageContext referring to the entire line.
- """
- data = self.checker.findEntity(referenced_entity)
- if data:
- # This is OK
- return
- context = line_context
- match = re.search(r'\b{}\b'.format(referenced_entity), self.line)
- if match:
- context = self.storeMessageContext(
- group=None, match=match)
- msg = ["Found reference page markup, with an unrecognized entity listed: {}".format(
- referenced_entity)]
-
- see_also = None
- dataArray = self.checker.findEntityCaseInsensitive(
- referenced_entity)
-
- if dataArray:
- # We might have found the goof...
-
- if len(dataArray) == 1:
- # Yep, found the goof - incorrect entity capitalization
- data = dataArray[0]
- new_entity = data.entity
- self.error(MessageId.REFPAGE_XREFS, msg + [
- 'Apparently matching entity in category {} found by searching case-insensitively.'.format(
- data.category),
- AUTO_FIX_STRING],
- replacement=new_entity,
- fix=(referenced_entity, new_entity),
- context=context)
- return
-
- # Ugh, more than one resolution
- msg.append(
- 'More than one apparent match found by searching case-insensitively, cannot auto-fix.')
- see_also = dataArray[:]
- else:
- # Probably not just a typo
- msg.append(
- 'If this is intentional, add the entity to EXTRA_DEFINES or EXTRA_REFPAGES in check_spec_links.py.')
-
- # Multiple or no resolutions found
- self.error(MessageId.REFPAGE_XREFS,
- msg,
- see_also=see_also,
- context=context)
-
- ###
- # Message-related methods.
- ###
-
- def warning(self, message_id, messageLines, context=None, group=None,
- replacement=None, fix=None, see_also=None, frame=None):
- """Log a warning for the file, if the message ID is enabled.
-
- Wrapper around self.diag() that automatically sets severity as well as frame.
-
- Arguments:
- message_id -- A MessageId value.
- messageLines -- A string or list of strings containing a human-readable error description.
-
- Optional, named arguments:
- context -- A MessageContext. If None, will be constructed from self.match and group.
- group -- The name of the regex group in self.match that contains the problem. Only used if context is None.
- If needed and is None, self.group is used instead.
- replacement -- The string, if any, that should be suggested as a replacement for the group in question.
- Does not create an auto-fix: sometimes we want to show a possible fix but aren't confident enough
- (or can't easily phrase a regex) to do it automatically.
- fix -- A (old text, new text) pair if this error is auto-fixable safely.
- see_also -- An optional array of other MessageContext locations relevant to this message.
- frame -- The 'inspect' stack frame corresponding to the location that raised this message.
- If None, will assume it is the direct caller of self.warning().
- """
- if not frame:
- frame = currentframe().f_back
- self.diag(MessageType.WARNING, message_id, messageLines, group=group,
- replacement=replacement, context=context, fix=fix, see_also=see_also, frame=frame)
-
- def error(self, message_id, messageLines, group=None, replacement=None,
- context=None, fix=None, see_also=None, frame=None):
- """Log an error for the file, if the message ID is enabled.
-
- Wrapper around self.diag() that automatically sets severity as well as frame.
-
- Arguments:
- message_id -- A MessageId value.
- messageLines -- A string or list of strings containing a human-readable error description.
-
- Optional, named arguments:
- context -- A MessageContext. If None, will be constructed from self.match and group.
- group -- The name of the regex group in self.match that contains the problem. Only used if context is None.
- If needed and is None, self.group is used instead.
- replacement -- The string, if any, that should be suggested as a replacement for the group in question.
- Does not create an auto-fix: sometimes we want to show a possible fix but aren't confident enough
- (or can't easily phrase a regex) to do it automatically.
- fix -- A (old text, new text) pair if this error is auto-fixable safely.
- see_also -- An optional array of other MessageContext locations relevant to this message.
- frame -- The 'inspect' stack frame corresponding to the location that raised this message.
- If None, will assume it is the direct caller of self.error().
- """
- if not frame:
- frame = currentframe().f_back
- self.diag(MessageType.ERROR, message_id, messageLines, group=group,
- replacement=replacement, context=context, fix=fix, see_also=see_also, frame=frame)
-
- def diag(self, severity, message_id, messageLines, context=None, group=None,
- replacement=None, fix=None, see_also=None, frame=None):
- """Log a diagnostic for the file, if the message ID is enabled.
-
- Also records the auto-fix, if applicable.
-
- Arguments:
- severity -- A MessageType value.
- message_id -- A MessageId value.
- messageLines -- A string or list of strings containing a human-readable error description.
-
- Optional, named arguments:
- context -- A MessageContext. If None, will be constructed from self.match and group.
- group -- The name of the regex group in self.match that contains the problem. Only used if context is None.
- If needed and is None, self.group is used instead.
- replacement -- The string, if any, that should be suggested as a replacement for the group in question.
- Does not create an auto-fix: sometimes we want to show a possible fix but aren't confident enough
- (or can't easily phrase a regex) to do it automatically.
- fix -- A (old text, new text) pair if this error is auto-fixable safely.
- see_also -- An optional array of other MessageContext locations relevant to this message.
- frame -- The 'inspect' stack frame corresponding to the location that raised this message.
- If None, will assume it is the direct caller of self.diag().
- """
- if not self.messageEnabled(message_id):
- self.logger.debug(
- 'Discarding a %s message because it is disabled.', message_id)
- return
-
- if isinstance(messageLines, str):
- messageLines = [messageLines]
-
- self.logger.info('Recording a %s message: %s',
- message_id, ' '.join(messageLines))
-
- # Ensure all auto-fixes are marked as such.
- if fix is not None and AUTO_FIX_STRING not in messageLines:
- messageLines.append(AUTO_FIX_STRING)
-
- if not frame:
- frame = currentframe().f_back
- if context is None:
- message = Message(message_id=message_id,
- message_type=severity,
- message=messageLines,
- context=self.storeMessageContext(group=group),
- replacement=replacement,
- see_also=see_also,
- fix=fix,
- frame=frame)
- else:
- message = Message(message_id=message_id,
- message_type=severity,
- message=messageLines,
- context=context,
- replacement=replacement,
- see_also=see_also,
- fix=fix,
- frame=frame)
- if fix is not None:
- self.fixes.add(fix)
- self.messages.append(message)
-
- def messageEnabled(self, message_id):
- """Return true if the given message ID is enabled."""
- return message_id in self.enabled_messages
-
- ###
- # Accessors for externally-interesting information
-
- def numDiagnostics(self):
- """Count the total number of diagnostics (errors or warnings) for this file."""
- return len(self.messages)
-
- def numErrors(self):
- """Count the total number of errors for this file."""
- return self.numMessagesOfType(MessageType.ERROR)
-
- def numMessagesOfType(self, message_type):
- """Count the number of messages of a particular type (severity)."""
- return len(
- [msg for msg in self.messages if msg.message_type == message_type])
-
- def hasFixes(self):
- """Return True if any messages included auto-fix patterns."""
- return len(self.fixes) > 0
-
- ###
- # Assorted internal methods.
- def printMessageCounts(self):
- """Print a simple count of each MessageType of diagnostics."""
- for message_type in [MessageType.ERROR, MessageType.WARNING]:
- count = self.numMessagesOfType(message_type)
- if count > 0:
- print('{num} {mtype}{s} generated.'.format(
- num=count, mtype=message_type, s=_s_suffix(count)))
-
- def dumpInternals(self):
- """Dump internal variables to screen, for debugging."""
- print('self.lineNum: ', self.lineNum)
- print('self.line:', self.line)
- print('self.prev_line_ref_page_tag: ', self.prev_line_ref_page_tag)
- print('self.current_ref_page:', self.current_ref_page)
-
- def getMissingValiditySuppressions(self):
- """Return an enumerable of entity names that we shouldn't warn about missing validity.
-
- May override.
- """
- return []
-
- def recordInclude(self, include_dict, generated_type=None):
- """Store the current line as being the location of an include directive or equivalent.
-
- Reports duplicate include errors, as well as include/ref-page mismatch or missing ref-page,
- by calling self.checkIncludeRefPageRelation() for "actual" includes (where generated_type is None).
-
- Arguments:
- include_dict -- The include dictionary to update: one of self.apiIncludes or self.validityIncludes.
- generated_type -- The type of include (e.g. 'api', 'valid', etc). By default, extracted from self.match.
- """
- entity = self.match.group('entity_name')
- if generated_type is None:
- generated_type = self.match.group('generated_type')
-
- # Only checking the ref page relation if it's retrieved from regex.
- # Otherwise it might be a manual anchor recorded as an include,
- # etc.
- self.checkIncludeRefPageRelation(entity, generated_type)
-
- if entity in include_dict:
- self.error(MessageId.DUPLICATE_INCLUDE,
- "Included {} docs for {} when they were already included.".format(generated_type,
- entity), see_also=include_dict[entity])
- include_dict[entity].append(self.storeMessageContext())
- else:
- include_dict[entity] = [self.storeMessageContext()]
-
- def getInnermostBlockEntry(self):
- """Get the BlockEntry for the top block delim on our stack."""
- if not self.block_stack:
- return None
- return self.block_stack[-1]
-
- def getInnermostBlockDelimiter(self):
- """Get the delimiter for the top block on our stack."""
- top = self.getInnermostBlockEntry()
- if not top:
- return None
- return top.delimiter
-
- def pushBlock(self, block_type, refpage=None, context=None, delimiter=None):
- """Push a new entry on the block stack."""
- if not delimiter:
- self.logger.info("pushBlock: not given delimiter")
- delimiter = self.line
- if not context:
- context = self.storeMessageContext()
-
- old_top_delim = self.getInnermostBlockDelimiter()
-
- self.block_stack.append(BlockEntry(
- delimiter=delimiter,
- context=context,
- refpage=refpage,
- block_type=block_type))
-
- location = self.getBriefLocation(context)
- self.logger.info(
- "pushBlock: %s: Pushed %s delimiter %s, previous top was %s, now %d elements on the stack",
- location, block_type.value, delimiter, old_top_delim, len(self.block_stack))
-
- self.dumpBlockStack()
-
- def popBlock(self):
- """Pop and return the top entry from the block stack."""
- old_top = self.block_stack.pop()
- location = self.getBriefLocation(old_top.context)
- self.logger.info(
- "popBlock: %s: popping %s delimiter %s, now %d elements on the stack",
- location, old_top.block_type.value, old_top.delimiter, len(self.block_stack))
-
- self.dumpBlockStack()
-
- return old_top
-
- def dumpBlockStack(self):
- self.logger.debug('Block stack, top first:')
- for distFromTop, x in enumerate(reversed(self.block_stack)):
- self.logger.debug(' - block_stack[%d]: Line %d: "%s" refpage=%s',
- -1 - distFromTop,
- x.context.lineNum, x.delimiter, x.refpage)
-
- def getBriefLocation(self, context):
- """Format a context briefly - omitting the filename if it has newlines in it."""
- if '\n' in context.filename:
- return 'input string line {}'.format(context.lineNum)
- return '{}:{}'.format(
- context.filename, context.lineNum)
-
- ###
- # Handlers for a variety of diagnostic-meriting conditions
- #
- # Split out for clarity and for allowing fine-grained override on a per-project basis.
- ###
-
- def handleIncludeMissingRefPage(self, entity, generated_type):
- """Report a message about an include outside of a ref-page block."""
- msg = ["Found {} include for {} outside of a reference page block.".format(generated_type, entity),
- "This is probably a missing reference page block."]
- refpage = self.computeExpectedRefPageFromInclude(entity)
- data = self.checker.findEntity(refpage)
- if data:
- msg.append('Expected ref page block might start like:')
- msg.append(self.makeRefPageTag(refpage, data=data))
- else:
- msg.append(
- "But, expected ref page entity name {} isn't recognized...".format(refpage))
- self.warning(MessageId.REFPAGE_MISSING, msg)
-
- def handleIncludeMismatchRefPage(self, entity, generated_type):
- """Report a message about an include not matching its containing ref-page block."""
- self.warning(MessageId.REFPAGE_MISMATCH, "Found {} include for {}, inside the reference page block of {}".format(
- generated_type, entity, self.current_ref_page.entity))
-
- def handleWrongMacro(self, msg, data):
- """Report an appropriate message when we found that the macro used is incorrect.
-
- May be overridden depending on each API's behavior regarding macro misuse:
- e.g. in some cases, it may be considered a MessageId.LEGACY warning rather than
- a MessageId.WRONG_MACRO or MessageId.EXTENSION.
- """
- message_type = MessageType.WARNING
- message_id = MessageId.WRONG_MACRO
- group = 'macro'
-
- if data.category == EXTENSION_CATEGORY:
- # Ah, this is an extension
- msg.append(
- 'This is apparently an extension name, which should be marked up as a link.')
- message_id = MessageId.EXTENSION
- group = None # replace the whole thing
- else:
- # Non-extension, we found the macro though.
- message_type = MessageType.ERROR
- msg.append(AUTO_FIX_STRING)
- self.diag(message_type, message_id, msg,
- group=group, replacement=self.makeMacroMarkup(data=data), fix=self.makeFix(data=data))
-
- def handleExpectedRefpageBlock(self):
- """Handle expecting to see -- to start a refpage block, but not seeing that at all."""
- self.error(MessageId.REFPAGE_BLOCK,
- ["Expected, but did not find, a line containing only -- following a reference page tag,",
- "Pretending to insert one, for more readable messages."],
- see_also=[self.prev_line_ref_page_tag])
- # Fake "in ref page" regardless, to avoid spurious extra errors.
- self.processBlockDelimiter('--', BlockType.REF_PAGE_LIKE,
- context=self.prev_line_ref_page_tag)
-
- ###
- # Construct related values (typically named tuples) based on object state and supplied arguments.
- #
- # Results are typically supplied to another method call.
- ###
-
- def storeMessageContext(self, group=None, match=None):
- """Create message context from corresponding instance variables.
-
- Arguments:
- group -- The regex group name, if any, identifying the part of the match to highlight.
- match -- The regex match. If None, will use self.match.
- """
- if match is None:
- match = self.match
- return MessageContext(filename=self.filename,
- lineNum=self.lineNum,
- line=self.line,
- match=match,
- group=group)
-
- def makeFix(self, newMacro=None, newEntity=None, data=None):
- """Construct a fix pair for replacing the old macro:entity with new.
-
- Wrapper around self.makeSearch() and self.makeMacroMarkup().
- """
- return (self.makeSearch(), self.makeMacroMarkup(
- newMacro, newEntity, data))
-
- def makeSearch(self):
- """Construct the string self.macro:self.entity, for use in the old text part of a fix pair."""
- return '{}:{}'.format(self.macro, self.entity)
-
- def makeMacroMarkup(self, newMacro=None, newEntity=None, data=None):
- """Construct appropriate markup for referring to an entity.
-
- Typically constructs macro:entity, but can construct `<<EXTENSION_NAME>>` if the supplied
- entity is identified as an extension.
-
- Arguments:
- newMacro -- The macro to use. Defaults to data.macro (if available), otherwise self.macro.
- newEntity -- The entity to use. Defaults to data.entity (if available), otherwise self.entity.
- data -- An EntityData value corresponding to this entity. If not provided, will be looked up by newEntity.
- """
- if not newEntity:
- if data:
- newEntity = data.entity
- else:
- newEntity = self.entity
- if not newMacro:
- if data:
- newMacro = data.macro
- else:
- newMacro = self.macro
- if not data:
- data = self.checker.findEntity(newEntity)
- if data and data.category == EXTENSION_CATEGORY:
- return self.makeExtensionLink(newEntity)
- return '{}:{}'.format(newMacro, newEntity)
-
- def makeExtensionLink(self, newEntity=None):
- """Create a correctly-formatted link to an extension.
-
- Result takes the form `<<EXTENSION_NAME>>`.
-
- Argument:
- newEntity -- The extension name to link to. Defaults to self.entity.
- """
- if not newEntity:
- newEntity = self.entity
- return '`<<{}>>`'.format(newEntity)
-
- def computeExpectedRefPageFromInclude(self, entity):
- """Compute the expected ref page entity based on an include entity name."""
- # No-op in general.
- return entity
-
- def makeRefPageTag(self, entity, data=None,
- ref_type=None, desc='', xrefs=None):
- """Construct a ref page tag string from attribute values."""
- if ref_type is None and data is not None:
- ref_type = data.directory
- if ref_type is None:
- ref_type = "????"
- return "[open,refpage='{}',type='{}',desc='{}',xrefs='{}']".format(
- entity, ref_type, desc, ' '.join(xrefs or []))
diff --git a/codegen/vulkan/scripts/spec_tools/main.py b/codegen/vulkan/scripts/spec_tools/main.py
deleted file mode 100644
index 2cd4f69c..00000000
--- a/codegen/vulkan/scripts/spec_tools/main.py
+++ /dev/null
@@ -1,244 +0,0 @@
-"""Provides a re-usable command-line interface to a MacroChecker."""
-
-# Copyright (c) 2018-2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-
-
-import argparse
-import logging
-import re
-from pathlib import Path
-
-from .shared import MessageId
-
-
-def checkerMain(default_enabled_messages, make_macro_checker,
- all_docs, available_messages=None):
- """Perform the bulk of the work for a command-line interface to a MacroChecker.
-
- Arguments:
- default_enabled_messages -- The MessageId values that should be enabled by default.
- make_macro_checker -- A function that can be called with a set of enabled MessageId to create a
- properly-configured MacroChecker.
- all_docs -- A list of all spec documentation files.
- available_messages -- a list of all MessageId values that can be generated for this project.
- Defaults to every value. (e.g. some projects don't have MessageId.LEGACY)
- """
- enabled_messages = set(default_enabled_messages)
- if not available_messages:
- available_messages = list(MessageId)
-
- disable_args = []
- enable_args = []
-
- parser = argparse.ArgumentParser()
- parser.add_argument(
- "--scriptlocation",
- help="Append the script location generated a message to the output.",
- action="store_true")
- parser.add_argument(
- "--verbose",
- "-v",
- help="Output 'info'-level development logging messages.",
- action="store_true")
- parser.add_argument(
- "--debug",
- "-d",
- help="Output 'debug'-level development logging messages (more verbose than -v).",
- action="store_true")
- parser.add_argument(
- "-Werror",
- "--warning_error",
- help="Make warnings act as errors, exiting with non-zero error code",
- action="store_true")
- parser.add_argument(
- "--include_warn",
- help="List all expected but unseen include files, not just those that are referenced.",
- action='store_true')
- parser.add_argument(
- "-Wmissing_refpages",
- help="List all entities with expected but unseen ref page blocks. NOT included in -Wall!",
- action='store_true')
- parser.add_argument(
- "--include_error",
- help="Make expected but unseen include files cause exiting with non-zero error code",
- action='store_true')
- parser.add_argument(
- "--broken_error",
- help="Make missing include/anchor for linked-to entities cause exiting with non-zero error code. Weaker version of --include_error.",
- action='store_true')
- parser.add_argument(
- "--dump_entities",
- help="Just dump the parsed entity data to entities.json and exit.",
- action='store_true')
- parser.add_argument(
- "--html",
- help="Output messages to the named HTML file instead of stdout.")
- parser.add_argument(
- "file",
- help="Only check the indicated file(s). By default, all chapters and extensions are checked.",
- nargs="*")
- parser.add_argument(
- "--ignore_count",
- type=int,
- help="Ignore up to the given number of errors without exiting with a non-zero error code.")
- parser.add_argument("-Wall",
- help="Enable all warning categories.",
- action='store_true')
-
- for message_id in MessageId:
- enable_arg = message_id.enable_arg()
- enable_args.append((message_id, enable_arg))
-
- disable_arg = message_id.disable_arg()
- disable_args.append((message_id, disable_arg))
- if message_id in enabled_messages:
- parser.add_argument('-' + disable_arg, action="store_true",
- help="Disable message category {}: {}".format(str(message_id), message_id.desc()))
- # Don't show the enable flag in help since it's enabled by default
- parser.add_argument('-' + enable_arg, action="store_true",
- help=argparse.SUPPRESS)
- else:
- parser.add_argument('-' + enable_arg, action="store_true",
- help="Enable message category {}: {}".format(str(message_id), message_id.desc()))
- # Don't show the disable flag in help since it's disabled by
- # default
- parser.add_argument('-' + disable_arg, action="store_true",
- help=argparse.SUPPRESS)
-
- args = parser.parse_args()
-
- arg_dict = vars(args)
- for message_id, arg in enable_args:
- if args.Wall or (arg in arg_dict and arg_dict[arg]):
- enabled_messages.add(message_id)
-
- for message_id, arg in disable_args:
- if arg in arg_dict and arg_dict[arg]:
- enabled_messages.discard(message_id)
-
- if args.verbose:
- logging.basicConfig(level='INFO')
-
- if args.debug:
- logging.basicConfig(level='DEBUG')
-
- checker = make_macro_checker(enabled_messages)
-
- if args.dump_entities:
- with open('entities.json', 'w', encoding='utf-8') as f:
- f.write(checker.getEntityJson())
- exit(0)
-
- if args.file:
- files = (str(Path(f).resolve()) for f in args.file)
- else:
- files = all_docs
-
- for fn in files:
- checker.processFile(fn)
-
- if args.html:
- from .html_printer import HTMLPrinter
- printer = HTMLPrinter(args.html)
- else:
- from .console_printer import ConsolePrinter
- printer = ConsolePrinter()
-
- if args.scriptlocation:
- printer.show_script_location = True
-
- if args.file:
- printer.output("Only checked specified files.")
- for f in args.file:
- printer.output(f)
- else:
- printer.output("Checked all chapters and extensions.")
-
- if args.warning_error:
- numErrors = checker.numDiagnostics()
- else:
- numErrors = checker.numErrors()
-
- check_includes = args.include_warn
- check_broken = not args.file
-
- if args.file and check_includes:
- print('Note: forcing --include_warn off because only checking supplied files.')
- check_includes = False
-
- printer.outputResults(checker, broken_links=(not args.file),
- missing_includes=check_includes)
-
- if check_broken:
- numErrors += len(checker.getBrokenLinks())
-
- if args.file and args.include_error:
- print('Note: forcing --include_error off because only checking supplied files.')
- args.include_error = False
- if args.include_error:
- numErrors += len(checker.getMissingUnreferencedApiIncludes())
-
- check_missing_refpages = args.Wmissing_refpages
- if args.file and check_missing_refpages:
- print('Note: forcing -Wmissing_refpages off because only checking supplied files.')
- check_missing_refpages = False
-
- if check_missing_refpages:
- missing = checker.getMissingRefPages()
- if missing:
- printer.output("Expected, but did not find, ref page blocks for the following {} entities: {}".format(
- len(missing),
- ', '.join(missing)
- ))
- if args.warning_error:
- numErrors += len(missing)
-
- printer.close()
-
- if args.broken_error and not args.file:
- numErrors += len(checker.getBrokenLinks())
-
- if checker.hasFixes():
- fixFn = 'applyfixes.sh'
- print('Saving shell script to apply fixes as {}'.format(fixFn))
- with open(fixFn, 'w', encoding='utf-8') as f:
- f.write('#!/bin/sh -e\n')
- for fileChecker in checker.files:
- wroteComment = False
- for msg in fileChecker.messages:
- if msg.fix is not None:
- if not wroteComment:
- f.write('\n# {}\n'.format(fileChecker.filename))
- wroteComment = True
- search, replace = msg.fix
- f.write(
- r"sed -i -r 's~\b{}\b~{}~g' {}".format(
- re.escape(search),
- replace,
- fileChecker.filename))
- f.write('\n')
-
- print('Total number of errors with this run: {}'.format(numErrors))
-
- if args.ignore_count:
- if numErrors > args.ignore_count:
- # Exit with non-zero error code so that we "fail" CI, etc.
- print('Exceeded specified limit of {}, so exiting with error'.format(
- args.ignore_count))
- exit(1)
- else:
- print('At or below specified limit of {}, so exiting with success'.format(
- args.ignore_count))
- exit(0)
-
- if numErrors:
- # Exit with non-zero error code so that we "fail" CI, etc.
- print('Exiting with error')
- exit(1)
- else:
- print('Exiting with success')
- exit(0)
diff --git a/codegen/vulkan/scripts/spec_tools/shared.py b/codegen/vulkan/scripts/spec_tools/shared.py
deleted file mode 100644
index bb6f1657..00000000
--- a/codegen/vulkan/scripts/spec_tools/shared.py
+++ /dev/null
@@ -1,257 +0,0 @@
-"""Types, constants, and utility functions used by multiple sub-modules in spec_tools."""
-
-# Copyright (c) 2018-2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-
-import platform
-from collections import namedtuple
-from enum import Enum
-from inspect import getframeinfo
-from pathlib import Path
-from sys import stdout
-
-# if we have termcolor and we know our stdout is a TTY,
-# pull it in and use it.
-if hasattr(stdout, 'isatty') and stdout.isatty():
- try:
- from termcolor import colored as colored_impl
- HAVE_COLOR = True
- except ImportError:
- HAVE_COLOR = False
-elif platform.system() == 'Windows':
- try:
- from termcolor import colored as colored_impl
- import colorama
- colorama.init()
- HAVE_COLOR = True
- except ImportError:
- HAVE_COLOR = False
-
-else:
- HAVE_COLOR = False
-
-
-def colored(s, color=None, attrs=None):
- """Call termcolor.colored with same arguments if this is a tty and it is available."""
- if HAVE_COLOR:
- return colored_impl(s, color, attrs=attrs)
- return s
-
-
-###
-# Constants used in multiple places.
-AUTO_FIX_STRING = 'Note: Auto-fix available.'
-EXTENSION_CATEGORY = 'extension'
-CATEGORIES_WITH_VALIDITY = set(('protos', 'structs'))
-NON_EXISTENT_MACROS = set(('plink', 'ttext', 'dtext'))
-
-###
-# MessageContext: All the information about where a message relates to.
-MessageContext = namedtuple('MessageContext',
- ['filename', 'lineNum', 'line',
- 'match', 'group'])
-
-
-def getInterestedRange(message_context):
- """Return a (start, end) pair of character index for the match in a MessageContext."""
- if not message_context.match:
- # whole line
- return (0, len(message_context.line))
- return (message_context.match.start(), message_context.match.end())
-
-
-def getHighlightedRange(message_context):
- """Return a (start, end) pair of character index for the highlighted range in a MessageContext."""
- if message_context.group is not None and message_context.match is not None:
- return (message_context.match.start(message_context.group),
- message_context.match.end(message_context.group))
- # no group (whole match) or no match (whole line)
- return getInterestedRange(message_context)
-
-
-def toNameAndLine(context, root_path=None):
- """Convert MessageContext into a simple filename:line string."""
- my_fn = Path(context.filename)
- if root_path:
- my_fn = my_fn.relative_to(root_path)
- return '{}:{}'.format(str(my_fn), context.lineNum)
-
-
-def generateInclude(dir_traverse, generated_type, category, entity):
- """Create an include:: directive for geneated api or validity from the various pieces."""
- return 'include::{directory_traverse}{generated_type}/{category}/{entity_name}.txt[]'.format(
- directory_traverse=dir_traverse,
- generated_type=generated_type,
- category=category,
- entity_name=entity)
-
-
-# Data stored per entity (function, struct, enumerant type, enumerant, extension, etc.)
-EntityData = namedtuple(
- 'EntityData', ['entity', 'macro', 'elem', 'filename', 'category', 'directory'])
-
-
-class MessageType(Enum):
- """Type of a message."""
-
- WARNING = 1
- ERROR = 2
- NOTE = 3
-
- def __str__(self):
- """Format a MessageType as a lowercase string."""
- return str(self.name).lower()
-
- def formattedWithColon(self):
- """Format a MessageType as a colored, lowercase string followed by a colon."""
- if self == MessageType.WARNING:
- return colored(str(self) + ':', 'magenta', attrs=['bold'])
- if self == MessageType.ERROR:
- return colored(str(self) + ':', 'red', attrs=['bold'])
- return str(self) + ':'
-
-
-class MessageId(Enum):
- """Enumerates the varieties of messages that can be generated.
-
- Control over enabled messages with -Wbla or -Wno_bla is per-MessageId.
- """
-
- MISSING_TEXT = 1
- LEGACY = 2
- WRONG_MACRO = 3
- MISSING_MACRO = 4
- BAD_ENTITY = 5
- BAD_ENUMERANT = 6
- BAD_MACRO = 7
- UNRECOGNIZED_CONTEXT = 8
- UNKNOWN_MEMBER = 9
- DUPLICATE_INCLUDE = 10
- UNKNOWN_INCLUDE = 11
- API_VALIDITY_ORDER = 12
- UNDOCUMENTED_MEMBER = 13
- MEMBER_PNAME_MISSING = 14
- MISSING_VALIDITY_INCLUDE = 15
- MISSING_API_INCLUDE = 16
- MISUSED_TEXT = 17
- EXTENSION = 18
- REFPAGE_TAG = 19
- REFPAGE_MISSING_DESC = 20
- REFPAGE_XREFS = 21
- REFPAGE_XREFS_COMMA = 22
- REFPAGE_TYPE = 23
- REFPAGE_NAME = 24
- REFPAGE_BLOCK = 25
- REFPAGE_MISSING = 26
- REFPAGE_MISMATCH = 27
- REFPAGE_UNKNOWN_ATTRIB = 28
- REFPAGE_SELF_XREF = 29
- REFPAGE_XREF_DUPE = 30
- REFPAGE_WHITESPACE = 31
- REFPAGE_DUPLICATE = 32
- UNCLOSED_BLOCK = 33
-
- def __str__(self):
- """Format as a lowercase string."""
- return self.name.lower()
-
- def enable_arg(self):
- """Return the corresponding Wbla string to make the 'enable this message' argument."""
- return 'W{}'.format(self.name.lower())
-
- def disable_arg(self):
- """Return the corresponding Wno_bla string to make the 'enable this message' argument."""
- return 'Wno_{}'.format(self.name.lower())
-
- def desc(self):
- """Return a brief description of the MessageId suitable for use in --help."""
- return MessageId.DESCRIPTIONS[self]
-
-
-MessageId.DESCRIPTIONS = {
- MessageId.MISSING_TEXT: "a *text: macro is expected but not found",
- MessageId.LEGACY: "legacy usage of *name: macro when *link: is applicable",
- MessageId.WRONG_MACRO: "wrong macro used for an entity",
- MessageId.MISSING_MACRO: "a macro might be missing",
- MessageId.BAD_ENTITY: "entity not recognized, etc.",
- MessageId.BAD_ENUMERANT: "unrecognized enumerant value used in ename:",
- MessageId.BAD_MACRO: "unrecognized macro used",
- MessageId.UNRECOGNIZED_CONTEXT: "pname used with an unrecognized context",
- MessageId.UNKNOWN_MEMBER: "pname used but member/argument by that name not found",
- MessageId.DUPLICATE_INCLUDE: "duplicated include line",
- MessageId.UNKNOWN_INCLUDE: "include line specified file we wouldn't expect to exists",
- MessageId.API_VALIDITY_ORDER: "saw API include after validity include",
- MessageId.UNDOCUMENTED_MEMBER: "saw an apparent struct/function documentation, but missing a member",
- MessageId.MEMBER_PNAME_MISSING: "pname: missing from a 'scope' operator",
- MessageId.MISSING_VALIDITY_INCLUDE: "missing validity include",
- MessageId.MISSING_API_INCLUDE: "missing API include",
- MessageId.MISUSED_TEXT: "a *text: macro is found but not expected",
- MessageId.EXTENSION: "an extension name is incorrectly marked",
- MessageId.REFPAGE_TAG: "a refpage tag is missing an expected field",
- MessageId.REFPAGE_MISSING_DESC: "a refpage tag has an empty description",
- MessageId.REFPAGE_XREFS: "an unrecognized entity is mentioned in xrefs of a refpage tag",
- MessageId.REFPAGE_XREFS_COMMA: "a comma was founds in xrefs of a refpage tag, which is space-delimited",
- MessageId.REFPAGE_TYPE: "a refpage tag has an incorrect type field",
- MessageId.REFPAGE_NAME: "a refpage tag has an unrecognized entity name in its refpage field",
- MessageId.REFPAGE_BLOCK: "a refpage block is not correctly opened or closed.",
- MessageId.REFPAGE_MISSING: "an API include was found outside of a refpage block.",
- MessageId.REFPAGE_MISMATCH: "an API or validity include was found in a non-matching refpage block.",
- MessageId.REFPAGE_UNKNOWN_ATTRIB: "a refpage tag has an unrecognized attribute",
- MessageId.REFPAGE_SELF_XREF: "a refpage tag has itself in the list of cross-references",
- MessageId.REFPAGE_XREF_DUPE: "a refpage cross-references list has at least one duplicate",
- MessageId.REFPAGE_WHITESPACE: "a refpage cross-references list has non-minimal whitespace",
- MessageId.REFPAGE_DUPLICATE: "a refpage tag has been seen for a single entity for a second time",
- MessageId.UNCLOSED_BLOCK: "one or more blocks remain unclosed at the end of a file"
-}
-
-
-class Message(object):
- """An Error, Warning, or Note with a MessageContext, MessageId, and message text.
-
- May optionally have a replacement, a see_also array, an auto-fix,
- and a stack frame where the message was created.
- """
-
- def __init__(self, message_id, message_type, message, context,
- replacement=None, see_also=None, fix=None, frame=None):
- """Construct a Message.
-
- Typically called by MacroCheckerFile.diag().
- """
- self.message_id = message_id
-
- self.message_type = message_type
-
- if isinstance(message, str):
- self.message = [message]
- else:
- self.message = message
-
- self.context = context
- if context is not None and context.match is not None and context.group is not None:
- if context.group not in context.match.groupdict():
- raise RuntimeError(
- 'Group "{}" does not exist in the match'.format(context.group))
-
- self.replacement = replacement
-
- self.fix = fix
-
- if see_also is None:
- self.see_also = None
- elif isinstance(see_also, MessageContext):
- self.see_also = [see_also]
- else:
- self.see_also = see_also
-
- self.script_location = None
- if frame:
- try:
- frameinfo = getframeinfo(frame)
- self.script_location = "{}:{}".format(
- frameinfo.filename, frameinfo.lineno)
- finally:
- del frame
diff --git a/codegen/vulkan/scripts/spec_tools/util.py b/codegen/vulkan/scripts/spec_tools/util.py
deleted file mode 100644
index b8906798..00000000
--- a/codegen/vulkan/scripts/spec_tools/util.py
+++ /dev/null
@@ -1,58 +0,0 @@
-"""Utility functions not closely tied to other spec_tools types."""
-# Copyright 2018-2019 Collabora, Ltd.
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-
-def getElemName(elem, default=None):
- """Get the name associated with an element, either a name child or name attribute."""
- name_elem = elem.find('name')
- if name_elem is not None:
- return name_elem.text
- # Fallback if there is no child.
- return elem.get('name', default)
-
-
-def getElemType(elem, default=None):
- """Get the type associated with an element, either a type child or type attribute."""
- type_elem = elem.find('type')
- if type_elem is not None:
- return type_elem.text
- # Fallback if there is no child.
- return elem.get('type', default)
-
-
-def findFirstWithPredicate(collection, pred):
- """Return the first element that satisfies the predicate, or None if none exist.
-
- NOTE: Some places where this is used might be better served by changing to a dictionary.
- """
- for elt in collection:
- if pred(elt):
- return elt
- return None
-
-
-def findNamedElem(elems, name):
- """Traverse a collection of elements with 'name' nodes or attributes, looking for and returning one with the right name.
-
- NOTE: Many places where this is used might be better served by changing to a dictionary.
- """
- return findFirstWithPredicate(elems, lambda elem: getElemName(elem) == name)
-
-
-def findTypedElem(elems, typename):
- """Traverse a collection of elements with 'type' nodes or attributes, looking for and returning one with the right typename.
-
- NOTE: Many places where this is used might be better served by changing to a dictionary.
- """
- return findFirstWithPredicate(elems, lambda elem: getElemType(elem) == typename)
-
-
-def findNamedObject(collection, name):
- """Traverse a collection of elements with 'name' attributes, looking for and returning one with the right name.
-
- NOTE: Many places where this is used might be better served by changing to a dictionary.
- """
- return findFirstWithPredicate(collection, lambda elt: elt.name == name)
diff --git a/codegen/vulkan/scripts/spec_tools/validity.py b/codegen/vulkan/scripts/spec_tools/validity.py
deleted file mode 100644
index 745ba013..00000000
--- a/codegen/vulkan/scripts/spec_tools/validity.py
+++ /dev/null
@@ -1,216 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-import re
-
-
-_A_VS_AN_RE = re.compile(r' a ([a-z]+:)?([aAeEiIoOxX]\w+\b)(?!:)')
-
-_STARTS_WITH_MACRO_RE = re.compile(r'^[a-z]+:.*')
-
-
-def _checkAnchorComponents(anchor):
- """Raise an exception if any component of a VUID anchor name is illegal."""
- if anchor:
- # Any other invalid things in an anchor name should be detected here.
- if any((' ' in anchor_part for anchor_part in anchor)):
- raise RuntimeError("Illegal component of a VUID anchor name!")
-
-
-def _fix_a_vs_an(s):
- """Fix usage (often generated) of the indefinite article 'a' when 'an' is appropriate.
-
- Explicitly excludes the markup macros."""
- return _A_VS_AN_RE.sub(r' an \1\2', s)
-
-
-class ValidityCollection:
- """Combines validity for a single entity."""
-
- def __init__(self, entity_name=None, conventions=None, strict=True):
- self.entity_name = entity_name
- self.conventions = conventions
- self.lines = []
- self.strict = strict
-
- def possiblyAddExtensionRequirement(self, extension_name, entity_preface):
- """Add an extension-related validity statement if required.
-
- entity_preface is a string that goes between "must be enabled prior to "
- and the name of the entity, and normally ends in a macro.
- For instance, might be "calling flink:" for a function.
- """
- if extension_name and not extension_name.startswith(self.conventions.api_version_prefix):
- msg = 'The {} extension must: be enabled prior to {}{}'.format(
- self.conventions.formatExtension(extension_name), entity_preface, self.entity_name)
- self.addValidityEntry(msg, anchor=('extension', 'notenabled'))
-
- def addValidityEntry(self, msg, anchor=None):
- """Add a validity entry, optionally with a VUID anchor.
-
- If any trailing arguments are supplied,
- an anchor is generated by concatenating them with dashes
- at the end of the VUID anchor name.
- """
- if not msg:
- raise RuntimeError("Tried to add a blank validity line!")
- parts = ['*']
- _checkAnchorComponents(anchor)
- if anchor:
- if not self.entity_name:
- raise RuntimeError('Cannot add a validity entry with an anchor to a collection that does not know its entity name.')
- parts.append('[[{}]]'.format(
- '-'.join(['VUID', self.entity_name] + list(anchor))))
- parts.append(msg)
- combined = _fix_a_vs_an(' '.join(parts))
- if combined in self.lines:
- raise RuntimeError("Duplicate validity added!")
- self.lines.append(combined)
-
- def addText(self, msg):
- """Add already formatted validity text."""
- if self.strict:
- raise RuntimeError('addText called when collection in strict mode')
- if not msg:
- return
- msg = msg.rstrip()
- if not msg:
- return
- self.lines.append(msg)
-
- def _extend(self, lines):
- lines = list(lines)
- dupes = set(lines).intersection(self.lines)
- if dupes:
- raise RuntimeError("The two sets contain some shared entries! " + str(dupes))
- self.lines.extend(lines)
-
- def __iadd__(self, other):
- """Perform += with a string, iterable, or ValidityCollection."""
- if other is None:
- pass
- elif isinstance(other, str):
- if self.strict:
- raise RuntimeError(
- 'Collection += a string when collection in strict mode')
- if not other:
- # empty string
- pass
- elif other.startswith('*'):
- # Handle already-formatted
- self.addText(other)
- else:
- # Do the formatting ourselves.
- self.addValidityEntry(other)
- elif isinstance(other, ValidityEntry):
- if other:
- if other.verbose:
- print(self.entity_name, 'Appending', str(other))
- self.addValidityEntry(str(other), anchor=other.anchor)
- elif isinstance(other, ValidityCollection):
- if not self.entity_name == other.entity_name:
- raise RuntimeError(
- "Trying to combine two ValidityCollections for different entities!")
- self._extend(other.lines)
- else:
- # Deal with other iterables.
- self._extend(other)
-
- return self
-
- def __bool__(self):
- """Is the collection non-empty?"""
- empty = not self.lines
- return not empty
-
- @property
- def text(self):
- """Access validity statements as a single string or None."""
- if not self.lines:
- return None
- return '\n'.join(self.lines) + '\n'
-
- def __str__(self):
- """Access validity statements as a single string or empty string."""
- if not self:
- return ''
- return self.text
-
- def __repr__(self):
- return '<ValidityCollection: {}>'.format(self.lines)
-
-
-class ValidityEntry:
- """A single validity line in progress."""
-
- def __init__(self, text=None, anchor=None):
- """Prepare to add a validity entry, optionally with a VUID anchor.
-
- An anchor is generated by concatenating the elements of the anchor tuple with dashes
- at the end of the VUID anchor name.
- """
- _checkAnchorComponents(anchor)
- if isinstance(anchor, str):
- # anchor needs to be a tuple
- anchor = (anchor,)
-
- # VUID does not allow special chars except ":"
- if anchor is not None:
- anchor = [(anchor_value.replace('->', '::').replace('.', '::')) for anchor_value in anchor]
-
- self.anchor = anchor
- self.parts = []
- self.verbose = False
- if text:
- self.append(text)
-
- def append(self, part):
- """Append a part of a string.
-
- If this is the first entry part and the part doesn't start
- with a markup macro, the first character will be capitalized."""
- if not self.parts and not _STARTS_WITH_MACRO_RE.match(part):
- self.parts.append(part[:1].upper())
- self.parts.append(part[1:])
- else:
- self.parts.append(part)
- if self.verbose:
- print('ValidityEntry', id(self), 'after append:', str(self))
-
- def drop_end(self, n):
- """Remove up to n trailing characters from the string."""
- temp = str(self)
- n = min(len(temp), n)
- self.parts = [temp[:-n]]
-
- def __iadd__(self, other):
- """Perform += with a string,"""
- self.append(other)
- return self
-
- def __bool__(self):
- """Return true if we have something more than just an anchor."""
- empty = not self.parts
- return not empty
-
- def __str__(self):
- """Access validity statement as a single string or empty string."""
- if not self:
- raise RuntimeError("No parts added?")
- return ''.join(self.parts).strip()
-
- def __repr__(self):
- parts = ['<ValidityEntry: ']
- if self:
- parts.append('"')
- parts.append(str(self))
- parts.append('"')
- else:
- parts.append('EMPTY')
- if self.anchor:
- parts.append(', anchor={}'.format('-'.join(self.anchor)))
- parts.append('>')
- return ''.join(parts)
diff --git a/codegen/vulkan/scripts/spirvcapgenerator.py b/codegen/vulkan/scripts/spirvcapgenerator.py
deleted file mode 100644
index 85740f34..00000000
--- a/codegen/vulkan/scripts/spirvcapgenerator.py
+++ /dev/null
@@ -1,308 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-from generator import OutputGenerator, write
-from spec_tools.attributes import ExternSyncEntry
-from spec_tools.util import getElemName
-
-import pdb
-
-def makeLink(link, altlink = None):
- """Create an asciidoctor link, optionally with altlink text
- if provided"""
-
- if altlink is not None:
- return '<<{},{}>>'.format(link, altlink)
- else:
- return '<<{}>>'.format(link)
-
-class SpirvCapabilityOutputGenerator(OutputGenerator):
- """SpirvCapabilityOutputGenerator - subclass of OutputGenerator.
- Generates AsciiDoc includes of the SPIR-V capabilities table for the
- features chapter of the API specification.
-
- ---- methods ----
- SpirvCapabilityOutputGenerator(errFile, warnFile, diagFile) - args as for
- OutputGenerator. Defines additional internal state.
- ---- methods overriding base class ----
- genCmd(cmdinfo)"""
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- def beginFile(self, genOpts):
- OutputGenerator.beginFile(self, genOpts)
-
- # Accumulate SPIR-V capability and feature information
- self.spirv = []
-
- def getCondition(self, enable):
- """Return a strings which is the condition under which an
- enable is supported.
-
- - enable - ElementTree corresponding to an <enable> XML tag for a
- SPIR-V capability or extension"""
-
- if enable.get('version'):
- # Turn VK_API_VERSION_1_0 -> VK_VERSION_1_0
- return enable.get('version').replace('API_', '')
- elif enable.get('extension'):
- return enable.get('extension')
- elif enable.get('struct') or enable.get('property'):
- return enable.get('requires')
- else:
- self.logMsg('error', 'Unrecognized SPIR-V enable')
- return ''
-
- def getConditions(self, enables):
- """Return a sorted list of strings which are conditions under which
- one or more of the enables is supported.
-
- - enables - ElementTree corresponding to a <spirvcapability> or
- <spirvextension> XML tag"""
-
- conditions = set()
- for enable in enables.findall('enable'):
- condition = self.getCondition(enable)
- if condition != None:
- conditions.add(condition)
- return sorted(conditions)
-
- def endFile(self):
- captable = []
- exttable = []
-
- # How to "indent" a pseudo-column for better use of space.
- # {captableindent} is defined in appendices/spirvenv.txt
- indent = '{captableindent}'
-
- for elem in self.spirv:
- conditions = self.getConditions(elem)
-
- # Combine all conditions for enables and surround the row with
- # them
- if len(conditions) > 0:
- condition_string = ','.join(conditions)
- prefix = [ 'ifdef::{}[]'.format(condition_string) ]
- suffix = [ 'endif::{}[]'.format(condition_string) ]
- else:
- prefix = []
- suffix = []
-
- body = []
-
- # Generate an anchor for each capability
- if elem.tag == 'spirvcapability':
- anchor = '[[spirvenv-capabilities-table-{}]]'.format(
- elem.get('name'))
- else:
- # <spirvextension> entries don't get anchors
- anchor = ''
-
- # First "cell" in a table row, and a break for the other "cells"
- body.append('| {}code:{} +'.format(anchor, elem.get('name')))
-
- # Iterate over each enable emitting a formatting tag for it
- # Protect the term if there is a version or extension
- # requirement, and if there are multiple enables (otherwise,
- # the ifdef protecting the entire row will suffice).
-
- enables = [e for e in elem.findall('enable')]
-
- remaining = len(enables)
- for subelem in enables:
- remaining -= 1
-
- # Sentinel value
- linktext = None
- if subelem.get('version'):
- version = subelem.get('version')
-
- # Convert API enum VK_API_VERSION_m_n to conditional
- # used for spec builds (VK_VERSION_m_n)
- enable = version.replace('API_', '')
- # Convert API enum to anchor for version appendices (versions-m.n)
- link = 'versions-' + version[-3:].replace('_', '.')
- altlink = version
-
- linktext = makeLink(link, altlink)
- elif subelem.get('extension'):
- extension = subelem.get('extension')
-
- enable = extension
- link = extension
- altlink = None
-
- # This uses the extension name macro, rather than
- # asciidoc markup
- linktext = '`apiext:{}`'.format(extension)
- elif subelem.get('struct'):
- struct = subelem.get('struct')
- feature = subelem.get('feature')
- requires = subelem.get('requires')
- alias = subelem.get('alias')
-
- link_name = feature
- # For cases, like bufferDeviceAddressEXT where need manual help
- if alias:
- link_name = alias
-
- enable = requires
- link = 'features-' + link_name
- altlink = 'sname:{}::pname:{}'.format(struct, feature)
-
- linktext = makeLink(link, altlink)
- else:
- property = subelem.get('property')
- member = subelem.get('member')
- requires = subelem.get('requires')
- value = subelem.get('value')
-
- enable = requires
- # Properties should have a "feature" prefix
- link = 'limits-' + member
- # Display the property value by itself if it is not a boolean (matches original table)
- # DenormPreserve is an example where it makes sense to just show the
- # member value as it is just a boolean and the name implies "true"
- # GroupNonUniformVote is an example where the whole name is too long
- # better to just display the value
- if value == "VK_TRUE":
- altlink = 'sname:{}::pname:{}'.format(property, member)
- else:
- altlink = '{}'.format(value)
-
- linktext = makeLink(link, altlink)
-
- # If there are no more enables, don't continue the last line
- if remaining > 0:
- continuation = ' +'
- else:
- continuation = ''
-
- # condition_string != enable is a small optimization
- if enable is not None and condition_string != enable:
- body.append('ifdef::{}[]'.format(enable))
- body.append('{} {}{}'.format(indent, linktext, continuation))
- if enable is not None and condition_string != enable:
- body.append('endif::{}[]'.format(enable))
-
- if elem.tag == 'spirvcapability':
- captable += prefix + body + suffix
- else:
- exttable += prefix + body + suffix
-
- # Generate the asciidoc include files
- self.writeBlock('captable.txt', captable)
- self.writeBlock('exttable.txt', exttable)
-
- # Finish processing in superclass
- OutputGenerator.endFile(self)
-
- def writeBlock(self, basename, contents):
- """Generate an include file.
-
- - directory - subdirectory to put file in
- - basename - base name of the file
- - contents - contents of the file (Asciidoc boilerplate aside)"""
-
- filename = self.genOpts.directory + '/' + basename
- self.logMsg('diag', '# Generating include file:', filename)
- with open(filename, 'w', encoding='utf-8') as fp:
- write(self.genOpts.conventions.warning_comment, file=fp)
-
- if len(contents) > 0:
- for str in contents:
- write(str, file=fp)
- else:
- self.logMsg('diag', '# No contents for:', filename)
-
- def paramIsArray(self, param):
- """Check if the parameter passed in is a pointer to an array."""
- return param.get('len') is not None
-
- def paramIsPointer(self, param):
- """Check if the parameter passed in is a pointer."""
- tail = param.find('type').tail
- return tail is not None and '*' in tail
-
- def makeThreadSafetyBlocks(self, cmd, paramtext):
- # See also makeThreadSafetyBlock in validitygenerator.py - similar but not entirely identical
- protoname = cmd.find('proto/name').text
-
- # Find and add any parameters that are thread unsafe
- explicitexternsyncparams = cmd.findall(paramtext + "[@externsync]")
- if explicitexternsyncparams is not None:
- for param in explicitexternsyncparams:
- self.makeThreadSafetyForParam(protoname, param)
-
- # Find and add any "implicit" parameters that are thread unsafe
- implicitexternsyncparams = cmd.find('implicitexternsyncparams')
- if implicitexternsyncparams is not None:
- for elem in implicitexternsyncparams:
- entry = ValidityEntry()
- entry += elem.text
- entry += ' in '
- entry += self.makeFLink(protoname)
- self.threadsafety['implicit'] += entry
-
- # Add a VU for any command requiring host synchronization.
- # This could be further parameterized, if a future non-Vulkan API
- # requires it.
- if self.genOpts.conventions.is_externsync_command(protoname):
- entry = ValidityEntry()
- entry += 'The sname:VkCommandPool that pname:commandBuffer was allocated from, in '
- entry += self.makeFLink(protoname)
- self.threadsafety['implicit'] += entry
-
- def makeThreadSafetyForParam(self, protoname, param):
- """Create thread safety validity for a single param of a command."""
- externsyncattribs = ExternSyncEntry.parse_externsync_from_param(param)
- param_name = getElemName(param)
-
- for attrib in externsyncattribs:
- entry = ValidityEntry()
- is_array = False
- if attrib.entirely_extern_sync:
- # "true" or "true_with_children"
- if self.paramIsArray(param):
- entry += 'Each element of the '
- is_array = True
- elif self.paramIsPointer(param):
- entry += 'The object referenced by the '
- else:
- entry += 'The '
-
- entry += self.makeParameterName(param_name)
- entry += ' parameter'
-
- if attrib.children_extern_sync:
- entry += ', and any child handles,'
-
- else:
- # parameter/member reference
- readable = attrib.get_human_readable(make_param_name=self.makeParameterName)
- is_array = (' element of ' in readable)
- entry += readable
-
- entry += ' in '
- entry += self.makeFLink(protoname)
-
- if is_array:
- self.threadsafety['parameterlists'] += entry
- else:
- self.threadsafety['parameters'] += entry
-
- def genSpirv(self, capinfo, name, alias):
- """Generate SPIR-V capabilities
-
- capinfo - dictionary entry for an XML <spirvcapability> or
- <spirvextension> element
- name - name attribute of capinfo.elem"""
-
- OutputGenerator.genSpirv(self, capinfo, name, alias)
-
- # Just accumulate each element, process in endFile
- self.spirv.append(capinfo.elem)
diff --git a/codegen/vulkan/scripts/testSpecVersion.py b/codegen/vulkan/scripts/testSpecVersion.py
deleted file mode 100755
index 4ead2b63..00000000
--- a/codegen/vulkan/scripts/testSpecVersion.py
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright 2017-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# testSpecVersion - check if SPEC_VERSION values for an unpublished
-# extension branch meet the requirement of being 1.
-#
-# Usage: textSpecVersion.py [-branch branchname] [-registry file]
-#
-# Checks for an XML <extension> matching the branch name specified
-# on the command line, or the current branch if not specified.
-#
-# If not found, the branch is not an extension staging branch; succeed.
-# If found, but extension is disabled, don't run the test; succeed.
-# If found, and extension SPEC_VERSION has a value of '1', succeed.
-# Otherwise, fail.
-
-import argparse
-import sys
-import xml.etree.ElementTree as etree
-from reflib import getBranch
-
-if __name__ == '__main__':
- parser = argparse.ArgumentParser()
-
- parser.add_argument('-branch', action='store',
- default=None,
- help='Specify branch to check against')
- parser.add_argument('-registry', action='store',
- default='xml/vk.xml',
- help='Use specified registry file instead of vk.xml')
- args = parser.parse_args()
-
- try:
- tree = etree.parse(args.registry)
- except:
- print('ERROR - cannot open registry XML file', args.registry)
- sys.exit(1)
-
- errors = ''
- if args.branch is None:
- (args.branch, errors) = getBranch()
- if args.branch is None:
- print('ERROR - Cannot determine current git branch:', errors)
- sys.exit(1)
-
- elem = tree.find('extensions/extension[@name="' + args.branch + '"]')
-
- if elem == None:
- print('Success - assuming', args.branch, 'is not an extension branch')
- sys.exit(0)
-
- supported = elem.get('supported')
- if supported == 'disabled':
- print('Success - branch name', args.branch, 'matches, but extension is disabled')
- sys.exit(0)
-
- for enum in elem.findall('require/enum'):
- name = enum.get('name')
-
- if name is not None and name[-13:] == '_SPEC_VERSION':
- value = enum.get('value')
- if value == '1':
- print('Success - {} = 1 for branch {}'.format(
- name, args.branch))
- sys.exit(0)
- else:
- print('ERROR - {} = {} for branch {}, but must be 1'.format(
- name, value, args.branch))
- sys.exit(1)
-
- print('ERROR - no SPEC_VERSION token found for branch', args.branch)
- sys.exit(1)
diff --git a/codegen/vulkan/scripts/test_check_spec_links.py b/codegen/vulkan/scripts/test_check_spec_links.py
deleted file mode 100644
index b0c82e38..00000000
--- a/codegen/vulkan/scripts/test_check_spec_links.py
+++ /dev/null
@@ -1,643 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright (c) 2018-2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-#
-# Purpose: This file contains tests for check_spec_links.py
-
-import pytest
-
-from check_spec_links import MessageId, makeMacroChecker
-from spec_tools.console_printer import ConsolePrinter
-from spec_tools.macro_checker_file import shouldEntityBeText
-
-# API-specific constants
-PROTO = 'vkCreateInstance'
-STRUCT = 'VkInstanceCreateInfo'
-EXT = 'VK_KHR_display'
-
-
-class CheckerWrapper(object):
- """Little wrapper object for a MacroChecker.
-
- Intended for use in making test assertions shorter and easier to read."""
-
- def __init__(self, capsys):
- self.ckr = makeMacroChecker(set())
- self.capsys = capsys
-
- def enabled(self, enabled_messages):
- """Updates the checker's enable message type set, from an iterable."""
- self.ckr.enabled_messages = set(enabled_messages)
- return self
-
- def check(self, string):
- """Checks a string (as if it were a file), outputs the results to the console, then returns the MacroCheckerFile."""
-
- # Flush the captured output.
- _ = self.capsys.readouterr()
-
- # Process
- f = self.ckr.processString(string + '\n')
-
- # Dump messages
- ConsolePrinter().output(f)
- return f
-
-
-@pytest.fixture
-def ckr(capsys):
- """Fixture - add an arg named ckr to your test function to automatically get one passed to you."""
- return CheckerWrapper(capsys)
-
-
-def msgReplacement(file_checker, which=0):
- """Return the replacement text associated with the specified message."""
- assert(len(file_checker.messages) > which)
- msg = file_checker.messages[which]
- from pprint import pprint
- pprint(msg.script_location)
- pprint(msg.replacement)
- pprint(msg.fix)
- return msg.replacement
-
-
-def loneMsgReplacement(file_checker):
- """Assert there's only one message in a file checker, and return the replacement text associated with it."""
- assert(len(file_checker.messages) == 1)
- return msgReplacement(file_checker)
-
-
-def message(file_checker, which=0):
- """Return a string of the message lines associated with the message of a file checker."""
- assert(len(file_checker.messages) > which)
- return "\n".join(file_checker.messages[which].message)
-
-
-def allMessages(file_checker):
- """Return a list of strings, each being the combination of the message lines of a message from a file checker."""
- return ['\n'.join(msg.message) for msg in file_checker.messages]
-
-
-def test_missing_macro(ckr):
- """Verify correct functioning of MessageId.MISSING_MACRO."""
- ckr.enabled([MessageId.MISSING_MACRO])
-
- # This should have a missing macro warning
- assert(ckr.check('with %s by' % PROTO).numDiagnostics() == 1)
-
- # These 3 should not have a missing macro warning because of their context
- # (in a link)
- assert(not ckr.check('<<%s' % PROTO).messages)
- # These 2 are simulating links that broke over lines
- assert(not ckr.check('%s>>' % PROTO).messages)
- assert(not ckr.check(
- '%s asdf>> table' % PROTO).messages)
-
-
-def test_entity_detection(ckr):
- ckr.enabled([MessageId.BAD_ENTITY])
- # Should complain about BAD_ENTITY
- assert(ckr.check('flink:abcd').numDiagnostics() == 1)
-
- # Should just give BAD_ENTITY (an error), not MISSING_TEXT (a warning).
- # Verifying that wrapping in asterisks (for formatting) doesn't get picked up as
- # an asterisk in the entity name (a placeholder).
- ckr.enabled(
- [MessageId.MISSING_TEXT, MessageId.BAD_ENTITY])
- assert(ckr.check('*flink:abcd*').numErrors() == 1)
-
-
-def test_wrong_macro(ckr):
- ckr.enabled([MessageId.WRONG_MACRO])
- # Should error - this ought to be code:uint32_t
- assert(ckr.check('basetype:uint32_t').numErrors() == 1)
-
- # This shouldn't error
- assert(ckr.check('code:uint32_t').numErrors() == 0)
-
-
-def test_should_entity_be_text():
- # These 5 are all examples of patterns that would merit usage of a ptext/etext/etc
- # macro, for various reasons:
-
- # has variable in subscript
- assert(shouldEntityBeText('pBuffers[i]', '[i]'))
- assert(shouldEntityBeText('API_ENUM_[X]', '[X]'))
-
- # has asterisk
- assert(shouldEntityBeText('maxPerStage*', None))
-
- # double-underscores make italicized placeholders
- # (triple are double-underscores delimited by underscores...)
- assert(shouldEntityBeText('API_ENUM[__x__]', '[__x__]'))
- assert(shouldEntityBeText('API_ENUM___i___EXT', None))
-
- # This shouldn't be a *text: macro because it only has single underscores
- assert(False == shouldEntityBeText('API_ENUM_i_EXT', None))
-
-
-def test_misused_text(ckr):
- # Tests the same patterns as test_should_entity_be_text(),
- # but in a whole checker
- ckr.enabled([MessageId.MISUSED_TEXT])
-
- assert(ckr.check('etext:API_ENUM_').numDiagnostics() == 0)
- assert(ckr.check('etext:API_ENUM_[X]').numDiagnostics() == 0)
- assert(ckr.check('etext:API_ENUM[i]').numDiagnostics() == 0)
- assert(ckr.check('etext:API_ENUM[__x__]').numDiagnostics() == 0)
-
- # Should be OK, since __i__ is a placeholder here
- assert(ckr.check('etext:API_ENUM___i___EXT').numDiagnostics() == 0)
-
- # This shouldn't be a *text: macro because it only has single underscores
- assert(ckr.check('API_ENUM_i_EXT').numDiagnostics() == 0)
-
-
-def test_extension(ckr):
- ckr.enabled(set(MessageId))
- # Check formatting of extension names:
- # the following is the canonical way to refer to an extension
- # (link wrapped in backticks)
- expected_replacement = '`<<%s>>`' % EXT
-
- # Extension name mentioned without any markup, should be added
- assert(loneMsgReplacement(ckr.check('asdf %s asdf' % EXT))
- == expected_replacement)
-
- # Extension name mentioned without any markup and wrong case,
- # should be added and have case fixed
- assert(loneMsgReplacement(ckr.check('asdf %s asdf' % EXT.upper()))
- == expected_replacement)
-
- # Extension name using wrong/old macro: ename isn't for extensions.
- assert(loneMsgReplacement(ckr.check('asdf ename:%s asdf' % EXT))
- == expected_replacement)
-
- # Extension name using wrong macro: elink isn't for extensions.
- assert(loneMsgReplacement(ckr.check('asdf elink:%s asdf' % EXT))
- == expected_replacement)
-
- # Extension name using wrong macro and wrong case: should have markup and
- # case fixed
- assert(loneMsgReplacement(ckr.check('asdf elink:%s asdf' % EXT.upper()))
- == expected_replacement)
-
- # This shouldn't cause errors because this is how we want it to look.
- assert(not ckr.check('asdf `<<%s>>` asdf' % EXT).messages)
-
- # This doesn't (shouldn't?) cause errors because just backticks on their own
- # "escape" names from the "missing markup" tests.
- assert(not ckr.check('asdf `%s` asdf' % EXT).messages)
-
- # TODO can we auto-correct this to add the backticks?
- # Doesn't error now, but would be nice if it did...
- assert(not ckr.check('asdf <<%s>> asdf' % EXT).messages)
-
-
-def test_refpage_tag(ckr):
- ckr.enabled([MessageId.REFPAGE_TAG])
-
- # Should error: missing refpage='' field
- assert(ckr.check("[open,desc='',type='',xrefs='']").numErrors() == 1)
- # Should error: missing desc='' field
- assert(ckr.check("[open,refpage='',type='',xrefs='']").numErrors() == 1)
- # Should error: missing type='' field
- assert(ckr.check("[open,refpage='',desc='',xrefs='']").numErrors() == 1)
-
- # Should not error: missing xrefs field is optional
- assert(not ckr.check("[open,refpage='',desc='',type='']").messages)
-
- # Should error, due to missing refpage, but not crash due to message printing (note the unicode smart quote)
- assert(ckr.check("[open,desc='',type='',xrefs=’']").numDiagnostics() == 1)
-
-
-def test_refpage_name(ckr):
- ckr.enabled([MessageId.REFPAGE_NAME])
- # Should not error: actually exists.
- assert(ckr.check(
- "[open,refpage='%s',desc='',type='']" % PROTO).numDiagnostics() == 0)
-
- # Should error: does not exist.
- assert(
- ckr.check("[open,refpage='bogus',desc='',type='']").numDiagnostics() == 1)
-
-
-def test_refpage_missing_desc(ckr):
- ckr.enabled([MessageId.REFPAGE_MISSING_DESC])
- # Should not warn: non-empty description actually exists.
- assert(ckr.check(
- "[open,refpage='',desc='non-empty description',type='']").numDiagnostics() == 0)
-
- # Should warn: desc field is empty.
- assert(
- ckr.check("[open,refpage='',desc='',type='']").numDiagnostics() == 1)
-
-
-def test_refpage_type(ckr):
- ckr.enabled([MessageId.REFPAGE_TYPE])
- # Should not error: this is of type 'protos'.
- assert(not ckr.check(
- "[open,refpage='%s',desc='',type='protos']" % PROTO).messages)
-
- # Should error: this is of type 'protos', not 'structs'.
- assert(
- ckr.check("[open,refpage='%s',desc='',type='structs']" % PROTO).messages)
-
-
-def test_refpage_xrefs(ckr):
- ckr.enabled([MessageId.REFPAGE_XREFS])
- # Should not error: this is a valid entity to have an xref to.
- assert(not ckr.check(
- "[open,refpage='',desc='',type='protos',xrefs='%s']" % STRUCT).messages)
-
- # case difference:
- # should error but offer a replacement.
- assert(loneMsgReplacement(ckr.check("[open,refpage='',xrefs='%s']" % STRUCT.lower()))
- == STRUCT)
-
- # Should error: not a valid entity.
- assert(ckr.check(
- "[open,refpage='',desc='',type='protos',xrefs='bogus']").numDiagnostics() == 1)
-
-
-def test_refpage_xrefs_comma(ckr):
- ckr.enabled([MessageId.REFPAGE_XREFS_COMMA])
- # Should not error: no commas in the xrefs field
- assert(not ckr.check(
- "[open,refpage='',xrefs='abc']").messages)
-
- # Should error: commas shouldn't be there since it's space-delimited.
- assert(loneMsgReplacement(
- ckr.check("[open,refpage='',xrefs='abc,']")) == 'abc')
-
- # All should correct to the same thing.
- equivalent_tags_with_commas = [
- "[open,refpage='',xrefs='abc, 123']",
- "[open,refpage='',xrefs='abc,123']",
- "[open,refpage='',xrefs='abc , 123']"]
- for has_comma in equivalent_tags_with_commas:
- assert(loneMsgReplacement(ckr.check(has_comma)) == 'abc 123')
-
-
-def test_refpage_block(ckr):
- """Tests of the REFPAGE_BLOCK message."""
- ckr.enabled([MessageId.REFPAGE_BLOCK])
- # Should not error: have the tag, an open, and a close
- assert(not ckr.check(
- """[open,]
- --
- bla
- --""").messages)
- assert(not ckr.check(
- """[open,refpage='abc']
- --
- bla
- --
-
- [open,refpage='123']
- --
- bla2
- --""").messages)
-
- # Should have 1 error: file ends immediately after tag
- assert(ckr.check(
- "[open,]").numDiagnostics() == 1)
-
- # Should have 1 error: line after tag isn't --
- assert(ckr.check(
- """[open,]
- bla
- --""").numDiagnostics() == 1)
- # Checking precedence of checks: this should have 1 error because line after tag isn't --
- # (but it is something that causes a line to be handled differently)
- assert(ckr.check(
- """[open,]
- == Heading
- --""").numDiagnostics() == 1)
- assert(ckr.check(
- """[open,]
- ----
- this is in a code block
- ----
- --""").numDiagnostics() == 1)
-
- # Should have 1 error: tag inside refpage.
- tag_inside = """[open,]
- --
- bla
- [open,]
- --"""
- assert(ckr.check(tag_inside).numDiagnostics() == 1)
- assert("already in a refpage block" in
- message(ckr.check(tag_inside)))
-
-
-def test_refpage_missing(ckr):
- """Test the REFPAGE_MISSING message."""
- ckr.enabled([MessageId.REFPAGE_MISSING])
- # Should not error: have the tag, an open, and the include
- assert(not ckr.check(
- """[open,refpage='%s']
- --
- include::{generated}/api/protos/%s.txt[]""" % (PROTO, PROTO)).messages)
- assert(not ckr.check(
- """[open,refpage='%s']
- --
- include::{generated}/validity/protos/%s.txt[]""" % (PROTO, PROTO)).messages)
-
- # Should not error: manual anchors shouldn't trigger this.
- assert(not ckr.check("[[%s]]" % PROTO).messages)
-
- # Should have 1 error: file ends immediately after include
- assert(ckr.check(
- "include::{generated}/api/protos/%s.txt[]" % PROTO).numDiagnostics() == 1)
- assert(ckr.check(
- "include::{generated}/validity/protos/%s.txt[]" % PROTO).numDiagnostics() == 1)
-
- # Should have 1 error: include is before the refpage open
- assert(ckr.check(
- """include::{generated}/api/protos/%s.txt[]
- [open,refpage='%s']
- --""" % (PROTO, PROTO)).numDiagnostics() == 1)
- assert(ckr.check(
- """include::{generated}/validity/protos/%s.txt[]
- [open,refpage='%s']
- --""" % (PROTO, PROTO)).numDiagnostics() == 1)
-
-
-def test_refpage_mismatch(ckr):
- """Test the REFPAGE_MISMATCH message."""
- ckr.enabled([MessageId.REFPAGE_MISMATCH])
- # Should not error: have the tag, an open, and a matching include
- assert(not ckr.check(
- """[open,refpage='%s']
- --
- include::{generated}/api/protos/%s.txt[]""" % (PROTO, PROTO)).messages)
- assert(not ckr.check(
- """[open,refpage='%s']
- --
- include::{generated}/validity/protos/%s.txt[]""" % (PROTO, PROTO)).messages)
-
- # Should error: have the tag, an open, and a mis-matching include
- assert(ckr.check(
- """[open,refpage='%s']
- --
- include::{generated}/api/structs/%s.txt[]""" % (PROTO, STRUCT)).numDiagnostics() == 1)
- assert(ckr.check(
- """[open,refpage='%s']
- --
- include::{generated}/validity/structs/%s.txt[]""" % (PROTO, STRUCT)).numDiagnostics() == 1)
-
-
-def test_refpage_unknown_attrib(ckr):
- """Check the REFPAGE_UNKNOWN_ATTRIB message."""
- ckr.enabled([MessageId.REFPAGE_UNKNOWN_ATTRIB])
- # Should not error: these are known attribute names
- assert(not ckr.check(
- "[open,refpage='',desc='',type='',xrefs='']").messages)
-
- # Should error: xref isn't an attribute name.
- assert(ckr.check(
- "[open,xref='']").numDiagnostics() == 1)
-
-
-def test_refpage_self_xref(ckr):
- """Check the REFPAGE_SELF_XREF message."""
- ckr.enabled([MessageId.REFPAGE_SELF_XREF])
- # Should not error: not self-referencing
- assert(not ckr.check(
- "[open,refpage='abc',xrefs='']").messages)
- assert(not ckr.check(
- "[open,refpage='abc',xrefs='123']").messages)
-
- # Should error: self-referencing isn't an attribute name.
- assert(loneMsgReplacement(
- ckr.check("[open,refpage='abc',xrefs='abc']")) == '')
- assert(loneMsgReplacement(
- ckr.check("[open,refpage='abc',xrefs='abc 123']")) == '123')
- assert(loneMsgReplacement(
- ckr.check("[open,refpage='abc',xrefs='123 abc']")) == '123')
-
-
-def test_refpage_xref_dupe(ckr):
- """Check the REFPAGE_XREF_DUPE message."""
- ckr.enabled([MessageId.REFPAGE_XREF_DUPE])
- # Should not error: no dupes
- assert(not ckr.check("[open,xrefs='']").messages)
- assert(not ckr.check("[open,xrefs='123']").messages)
- assert(not ckr.check("[open,xrefs='abc 123']").messages)
-
- # Should error: one dupe.
- assert(loneMsgReplacement(
- ckr.check("[open,xrefs='abc abc']")) == 'abc')
- assert(loneMsgReplacement(
- ckr.check("[open,xrefs='abc abc']")) == 'abc')
- assert(loneMsgReplacement(
- ckr.check("[open,xrefs='abc abc abc']")) == 'abc')
- assert(loneMsgReplacement(
- ckr.check("[open,xrefs='abc 123 abc']")) == 'abc 123')
- assert(loneMsgReplacement(
- ckr.check("[open,xrefs='123 abc abc']")) == '123 abc')
-
-
-def test_REFPAGE_WHITESPACE(ckr):
- """Check the REFPAGE_WHITESPACE message."""
- ckr.enabled([MessageId.REFPAGE_WHITESPACE])
- # Should not error: no extra whitespace
- assert(not ckr.check("[open,xrefs='']").messages)
- assert(not ckr.check("[open,xrefs='123']").messages)
- assert(not ckr.check("[open,xrefs='abc 123']").messages)
-
- # Should error: some extraneous whitespace.
- assert(loneMsgReplacement(
- ckr.check("[open,xrefs=' \t ']")) == '')
- assert(loneMsgReplacement(
- ckr.check("[open,xrefs=' abc 123 ']")) == 'abc 123')
- assert(loneMsgReplacement(
- ckr.check("[open,xrefs=' abc\t123 xyz ']")) == 'abc 123 xyz')
-
- # Should *NOT* remove self-reference, just extra whitespace
- assert(loneMsgReplacement(
- ckr.check("[open,refpage='abc',xrefs=' abc 123 ']")) == 'abc 123')
-
- # Even if we turn on the self-reference warning
- ckr.enabled([MessageId.REFPAGE_WHITESPACE, MessageId.REFPAGE_SELF_XREF])
- assert(msgReplacement(
- ckr.check("[open,refpage='abc',xrefs=' abc 123 ']"), 1) == 'abc 123')
-
-
-def test_REFPAGE_DUPLICATE(ckr):
- """Check the REFPAGE_DUPLICATE message."""
- ckr.enabled([MessageId.REFPAGE_DUPLICATE])
- # Should not error: no duplicate refpages.
- assert(not ckr.check("[open,refpage='abc']").messages)
- assert(not ckr.check("[open,refpage='123']").messages)
-
- # Should error: repeated refpage
- assert(ckr.check(
- """[open,refpage='abc']
- [open,refpage='abc']""").messages)
-
- # Should error: repeated refpage with something intervening
- assert(ckr.check(
- """[open,refpage='abc']
- [open,refpage='123']
- [open,refpage='abc']""").messages)
-
-
-def test_UNCLOSED_BLOCK(ckr):
- """Check the UNCLOSED_BLOCK message."""
- ckr.enabled([MessageId.UNCLOSED_BLOCK])
- # These should all have 0 errors
- assert(not ckr.check("== Heading").messages)
- assert(not ckr.check(
- """****
- == Heading
- ****""").messages)
- assert(not ckr.check(
- """****
- contents
- ****""").messages)
- assert(not ckr.check(
- """****
- [source,c]
- ----
- this is code
- ----
- ****""").messages)
- assert(not ckr.check(
- """[open,]
- --
- 123
-
- [source,c]
- ----
- this is code
- ----
- ****
- * this is in a box
- ****
-
- Now we can close the ref page.
- --""").messages)
-
- # These should all have 1 error because I removed a block close.
- # Because some of them, the missing block close is an interior one, the stack might look weird,
- # but it's still only 1 error - no matter how many are left unclosed.
- assert(ckr.check(
- """****
- == Heading""").numDiagnostics() == 1)
- assert(ckr.check(
- """****
- contents""").numDiagnostics() == 1)
- assert(ckr.check(
- """****
- [source,c]
- ----
- this is code
- ****""").numDiagnostics() == 1)
- assert(ckr.check(
- """****
- [source,c]
- ----
- this is code
- ----""").numDiagnostics() == 1)
- assert(ckr.check(
- """[open,]
- --
- 123
-
- [source,c]
- ----
- this is code
- ----
- ****
- * this is in a box
- ****""").numDiagnostics() == 1)
- assert(ckr.check(
- """[open,]
- --
- 123
-
- [source,c]
- ----
- this is code
- ----
- ****
- * this is in a box
- --""").numDiagnostics() == 1)
- assert(ckr.check(
- """[open,]
- --
- 123
-
- [source,c]
- ----
- this is code
- ****
- * this is in a box
- ****
-
- Now we can close the ref page.
- --""").numDiagnostics() == 1)
- assert(ckr.check(
- """[open,]
- --
- 123
-
- [source,c]
- ----
- this is code
- ****
- * this is in a box
-
- Now we can close the ref page.
- --""").numDiagnostics() == 1)
- assert(ckr.check(
- """[open,]
- --
- 123
-
- [source,c]
- ----
- this is code
- ****
- * this is in a box""").numDiagnostics() == 1)
-
- # This should have 0 errors of UNCLOSED_BLOCK: the missing opening -- should get automatically fake-inserted,
- assert(not ckr.check(
- """[open,]
- == Heading
- --""").messages)
-
- # Should have 1 error: block left open at end of file
- assert(ckr.check(
- """[open,]
- --
- bla""").numDiagnostics() == 1)
-
-
-def test_code_block_tracking(ckr):
- """Check to make sure that no other messages get triggered in a code block."""
- ckr.enabled([MessageId.BAD_ENTITY])
-
- # Should have 1 error: not a valid entity
- assert(ckr.check("slink:BogusStruct").numDiagnostics() == 1)
- assert(ckr.check(
- """****
- * slink:BogusStruct
- ****""").numDiagnostics() == 1)
-
- # should have zero errors: the invalid entity is inside a code block,
- # so it shouldn't be parsed.
- # (In reality, it's mostly the MISSING_MACRO message that might interact with code block tracking,
- # but this is easier to test in an API-agnostic way.)
- assert(not ckr.check(
- """[source,c]
- ----
- This code happens to include the characters slink:BogusStruct
- ----""").messages)
diff --git a/codegen/vulkan/scripts/test_check_spec_links_api_specific.py b/codegen/vulkan/scripts/test_check_spec_links_api_specific.py
deleted file mode 100644
index 76ce6a9e..00000000
--- a/codegen/vulkan/scripts/test_check_spec_links_api_specific.py
+++ /dev/null
@@ -1,122 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright (c) 2018-2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-#
-# Purpose: This file contains tests for check_spec_links.py
-# that depend on the API being used.
-
-import pytest
-
-from check_spec_links import MacroChecker, MessageId, makeMacroChecker
-from spec_tools.console_printer import ConsolePrinter
-from spec_tools.macro_checker_file import shouldEntityBeText
-from test_check_spec_links import (CheckerWrapper, allMessages,
- loneMsgReplacement, message, msgReplacement)
-
-
-@pytest.fixture
-def ckr(capsys):
- """Fixture - add an arg named ckr to your test function to automatically get one passed to you."""
- return CheckerWrapper(capsys)
-
-
-def test_vulkan_refpage_mismatch(ckr):
- """Vulkan-specific tests of the REFPAGE_MISMATCH message."""
- ckr.enabled([MessageId.REFPAGE_MISMATCH])
- # Should error: this is actually a mismatch in Vulkan
- assert(ckr.check(
- """[open,refpage='VkQueueFlags']
- --
- include::{generated}/api/enums/VkQueueFlagBits.txt[]""").numDiagnostics() == 1)
- assert(ckr.check(
- """[open,refpage='VkQueueFlags']
- --
- include::{generated}/validity/enums/VkQueueFlagBits.txt[]""").numDiagnostics() == 1)
-
- # Should not error: this is just an alias
- assert(ckr.check(
- """[open,refpage='vkUpdateDescriptorSetWithTemplate']
- --
- include::{generated}/api/protos/vkUpdateDescriptorSetWithTemplateKHR.txt[]""").numDiagnostics() == 0)
-
-
-def test_vulkan_refpage_missing(ckr):
- """Vulkan-specific tests of the REFPAGE_MISSING message."""
- ckr.enabled([MessageId.REFPAGE_MISSING])
-
- # Should error: flags are expected to have their own ref page.
- assert(ckr.check(
- "include::{generated}/api/flags/VkQueueFlags.txt[]").numDiagnostics() == 1)
-
-
-def test_vulkan_refpage_block(ckr):
- """Vulkan-specific tests of the REFPAGE_BLOCK message."""
- ckr.enabled([MessageId.REFPAGE_BLOCK])
-
- # Should have no errors: Non-refpage usage of '--' is acceptable
- assert(not ckr.check(
- """--
- bla
- --""").messages)
-
- # Should have 1 error:
- # - line after tag isn't '--'
- result = ckr.check(
- """--
- [open,]
- bla
- --""")
- assert(result.numDiagnostics() == 1)
- # Internally, it's as if the following were the spec source, after putting in the "fake" lines
- # (each of the added lines comes from one message):
- #
- # --
- # [open,]
- # --
- # bla
- # --
- assert("but did not find, a line containing only -- following a reference page tag" in message(result))
-
-
-def test_vulkan_legacy(ckr):
- """Test the LEGACY message which is Vulkan-only."""
- ckr.enabled([MessageId.LEGACY])
- # Should complain about LEGACY
- assert(ckr.check('sname:VkDeviceMemory').numDiagnostics() == 1)
-
-
-def test_vulkan_alias(ckr):
- """Tests of the aliasing data structure, dependent on Vulkan-specific registry."""
- entity_db = ckr.ckr.entity_db
-
- assert(entity_db.areAliases(
- 'VkCommandPoolTrimFlagsKHR', 'VkCommandPoolTrimFlags'))
- # Try one reversed-order, though the assert in that method should fire if this is wrong.
- assert(entity_db.areAliases(
- 'VkCommandPoolTrimFlags', 'VkCommandPoolTrimFlagsKHR'))
-
- assert(entity_db.areAliases(
- 'VkDescriptorUpdateTemplateKHR', 'VkDescriptorUpdateTemplate'))
- assert(entity_db.areAliases('VkDescriptorUpdateTemplateTypeKHR',
- 'VkDescriptorUpdateTemplateType'))
- assert(entity_db.areAliases('VkQueueFamilyProperties2KHR',
- 'VkQueueFamilyProperties2'))
- assert(entity_db.areAliases('VK_COLORSPACE_SRGB_NONLINEAR_KHR',
- 'VK_COLOR_SPACE_SRGB_NONLINEAR_KHR'))
- assert(entity_db.areAliases('vkEnumeratePhysicalDeviceGroupsKHR',
- 'vkEnumeratePhysicalDeviceGroups'))
- assert(entity_db.areAliases(
- 'vkCmdDrawIndirectCountAMD', 'vkCmdDrawIndirectCountKHR'))
- assert(entity_db.areAliases('VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT',
- 'VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT'))
-
- assert(entity_db.areAliases('VK_LUID_SIZE_KHR', 'VK_LUID_SIZE'))
-
-def test_vulkan_entity_detection(ckr):
- ckr.enabled([MessageId.BAD_ENTITY])
- # Should complain about BAD_ENTITY even though it's sname
- assert(ckr.check('sname:VkInstanceCreateInfoBOGUS').numDiagnostics() == 1)
diff --git a/codegen/vulkan/scripts/test_entity_db.py b/codegen/vulkan/scripts/test_entity_db.py
deleted file mode 100644
index ef08794c..00000000
--- a/codegen/vulkan/scripts/test_entity_db.py
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright (c) 2018-2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-
-
-import pytest
-
-from check_spec_links import VulkanEntityDatabase
-
-
-@pytest.fixture
-def db():
- ret = VulkanEntityDatabase()
- # print(ret.getEntityJson())
- return ret
-
-
-def test_likely_recognized(db):
- assert(db.likelyRecognizedEntity('vkBla'))
- assert(db.likelyRecognizedEntity('VkBla'))
- assert(db.likelyRecognizedEntity('VK_BLA'))
-
-
-def test_db(db):
- assert(db.findEntity('vkCreateInstance'))
-
- # VKAPI_CALL is not referenced, so not added to EntityDatabase.
- # assert(db.findEntity('VKAPI_CALL'))
diff --git a/codegen/vulkan/scripts/translate_math.js b/codegen/vulkan/scripts/translate_math.js
deleted file mode 100644
index c2fd6d26..00000000
--- a/codegen/vulkan/scripts/translate_math.js
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2020-2021 The Khronos Group, Inc.
-//
-// SPDX-License-Identifier: Apache-2.0
-
-// Translates the latexmath in html on build time using KaTeX
-// Usage: nodejs translate_math.js katex/katex.min.js vkspec.html
-
-const katex = require(process.argv[2]);
-const fs = require("fs");
-const escapeRegex = require("escape-string-regexp");
-const he = require('he');
-
-const filepath = process.argv[3];
-
-var html = fs.readFileSync(filepath, "utf8");
-
-const delimiters = [
- //{ left: "$$", right: "$$", display: true},
- { left: "\\[", right: "\\]", display: true},
- //{ left: "$", right: "$", display: false},
- { left: "\\(", right: "\\)", display: false}
- ]
-
-for( var delim of delimiters ) {
- const regex = new RegExp( escapeRegex(delim.left) + "([\\S\\s]*?)" + escapeRegex(delim.right), "g");
- html = html.replace( regex,
- function(match, g1) {
- return katex.renderToString( he.decode(g1, {'strict': true}), {displayMode: delim.display, output: 'html', strict: true} );
- }
- );
-}
-
-fs.writeFileSync(filepath, html, 'utf8');
diff --git a/codegen/vulkan/scripts/validitygenerator.py b/codegen/vulkan/scripts/validitygenerator.py
deleted file mode 100755
index a3a84561..00000000
--- a/codegen/vulkan/scripts/validitygenerator.py
+++ /dev/null
@@ -1,1497 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-import re
-from collections import OrderedDict, namedtuple
-from functools import reduce
-from pathlib import Path
-
-from conventions import ProseListFormats as plf
-from generator import OutputGenerator, write
-from spec_tools.attributes import ExternSyncEntry, LengthEntry
-from spec_tools.util import (findNamedElem, findNamedObject, findTypedElem,
- getElemName, getElemType)
-from spec_tools.validity import ValidityCollection, ValidityEntry
-
-
-# For parsing/splitting queue bit names - Vulkan only
-QUEUE_BITS_RE = re.compile(r'([^,]+)')
-
-
-class UnhandledCaseError(RuntimeError):
- def __init__(self, msg=None):
- if msg:
- super().__init__('Got a case in the validity generator that we have not explicitly handled: ' + msg)
- else:
- super().__init__('Got a case in the validity generator that we have not explicitly handled.')
-
-
-def _genericIterateIntersection(a, b):
- """Iterate through all elements in a that are also in b.
-
- Somewhat like a set's intersection(),
- but not type-specific so it can work with OrderedDicts, etc.
- It also returns a generator instead of a set,
- so you can pick what container type you'd like,
- if any.
- """
- return (x for x in a if x in b)
-
-
-def _make_ordered_dict(gen):
- """Make an ordered dict (with None as the values) from a generator."""
- return OrderedDict(((x, None) for x in gen))
-
-
-def _orderedDictIntersection(a, b):
- return _make_ordered_dict(_genericIterateIntersection(a, b))
-
-
-def _genericIsDisjoint(a, b):
- """Return true if nothing in a is also in b.
-
- Like a set's is_disjoint(),
- but not type-specific so it can work with OrderedDicts, etc.
- """
- for _ in _genericIterateIntersection(a, b):
- return False
- # if we never enter the loop...
- return True
-
-
-def _parse_queue_bits(cmd):
- """Return a generator of queue bits, with underscores turned to spaces.
-
- Vulkan-only.
-
- Return None if the queues attribute is not specified."""
- queuetypes = cmd.get('queues')
- if not queuetypes:
- return None
- return (qt.replace('_', ' ')
- for qt in QUEUE_BITS_RE.findall(queuetypes))
-
-
-class ValidityOutputGenerator(OutputGenerator):
- """ValidityOutputGenerator - subclass of OutputGenerator.
-
- Generates AsciiDoc includes of valid usage information, for reference
- pages and the specification. Similar to DocOutputGenerator.
-
- ---- methods ----
- ValidityOutputGenerator(errFile, warnFile, diagFile) - args as for
- OutputGenerator. Defines additional internal state.
- ---- methods overriding base class ----
- beginFile(genOpts)
- endFile()
- beginFeature(interface, emit)
- endFeature()
- genCmd(cmdinfo)
- """
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- self.currentExtension = ''
-
- @property
- def null(self):
- """Preferred spelling of NULL.
-
- Delegates to the object implementing ConventionsBase.
- """
- return self.conventions.null
-
- @property
- def structtype_member_name(self):
- """Return name of the structure type member.
-
- Delegates to the object implementing ConventionsBase.
- """
- return self.conventions.structtype_member_name
-
- @property
- def nextpointer_member_name(self):
- """Return name of the structure pointer chain member.
-
- Delegates to the object implementing ConventionsBase.
- """
- return self.conventions.nextpointer_member_name
-
- def makeProseList(self, elements, fmt=plf.AND,
- comma_for_two_elts=False, *args, **kwargs):
- """Make a (comma-separated) list for use in prose.
-
- Adds a connective (by default, 'and')
- before the last element if there are more than 1.
-
- Optionally adds a quantifier (like 'any') before a list of 2 or more,
- if specified by fmt.
-
- Delegates to the object implementing ConventionsBase.
- """
- if not elements:
- raise ValueError(
- 'Cannot pass an empty list if you are trying to make a prose list.')
- return self.conventions.makeProseList(elements,
- fmt,
- with_verb=False,
- comma_for_two_elts=comma_for_two_elts,
- *args, **kwargs)
-
- def makeProseListIs(self, elements, fmt=plf.AND,
- comma_for_two_elts=False, *args, **kwargs):
- """Make a (comma-separated) list for use in prose, followed by either 'is' or 'are' as appropriate.
-
- Adds a connective (by default, 'and')
- before the last element if there are more than 1.
-
- Optionally adds a quantifier (like 'any') before a list of 2 or more,
- if specified by fmt.
-
- Delegates to the object implementing ConventionsBase.
- """
- if not elements:
- raise ValueError(
- 'Cannot pass an empty list if you are trying to make a prose list.')
- return self.conventions.makeProseList(elements,
- fmt,
- with_verb=True,
- comma_for_two_elts=comma_for_two_elts,
- *args, **kwargs)
-
- def makeValidityCollection(self, entity_name):
- """Create a ValidityCollection object, passing along our Conventions."""
- return ValidityCollection(entity_name, self.conventions)
-
- def beginFile(self, genOpts):
- if not genOpts.conventions:
- raise RuntimeError(
- 'Must specify conventions object to generator options')
- self.conventions = genOpts.conventions
- # Vulkan says 'must: be a valid pointer' a lot, OpenXR just says
- # 'must: be a pointer'.
- self.valid_pointer_text = ' '.join(
- (x for x in (self.conventions.valid_pointer_prefix, 'pointer') if x))
- OutputGenerator.beginFile(self, genOpts)
-
- def endFile(self):
- OutputGenerator.endFile(self)
-
- def beginFeature(self, interface, emit):
- # Start processing in superclass
- OutputGenerator.beginFeature(self, interface, emit)
- self.currentExtension = interface.get('name')
-
- def endFeature(self):
- # Finish processing in superclass
- OutputGenerator.endFeature(self)
-
- @property
- def struct_macro(self):
- """Get the appropriate format macro for a structure."""
- # delegate to conventions
- return self.conventions.struct_macro
-
- def makeStructName(self, name):
- """Prepend the appropriate format macro for a structure to a structure type name."""
- # delegate to conventions
- return self.conventions.makeStructName(name)
-
- def makeParameterName(self, name):
- """Prepend the appropriate format macro for a parameter/member to a parameter name."""
- return 'pname:' + name
-
- def makeBaseTypeName(self, name):
- """Prepend the appropriate format macro for a 'base type' to a type name."""
- return 'basetype:' + name
-
- def makeEnumerationName(self, name):
- """Prepend the appropriate format macro for an enumeration type to a enum type name."""
- return 'elink:' + name
-
- def makeFlagsName(self, name):
- """Prepend the appropriate format macro for a flags type to a flags type name."""
- return 'tlink:' + name
-
- def makeFuncPointerName(self, name):
- """Prepend the appropriate format macro for a function pointer type to a type name."""
- return 'tlink:' + name
-
- def makeExternalTypeName(self, name):
- """Prepend the appropriate format macro for an external type like uint32_t to a type name."""
- # delegate to conventions
- return self.conventions.makeExternalTypeName(name)
-
- def makeEnumerantName(self, name):
- """Prepend the appropriate format macro for an enumerate (value) to a enum value name."""
- return 'ename:' + name
-
- def writeInclude(self, directory, basename, validity: ValidityCollection,
- threadsafety, commandpropertiesentry=None,
- successcodes=None, errorcodes=None):
- """Generate an include file.
-
- directory - subdirectory to put file in (absolute or relative pathname)
- basename - base name of the file
- validity - ValidityCollection to write.
- threadsafety - List (may be empty) of thread safety statements to write.
- successcodes - Optional success codes to document.
- errorcodes - Optional error codes to document.
- """
- # Create subdirectory, if needed
- directory = Path(directory)
- if not directory.is_absolute():
- directory = Path(self.genOpts.directory) / directory
- self.makeDir(str(directory))
-
- # Create validity file
- filename = str(directory / (basename + '.txt'))
- self.logMsg('diag', '# Generating include file:', filename)
-
- with open(filename, 'w', encoding='utf-8') as fp:
- write(self.conventions.warning_comment, file=fp)
-
- # Valid Usage
- if validity:
- write('.Valid Usage (Implicit)', file=fp)
- write('****', file=fp)
- write(validity, file=fp, end='')
- write('****', file=fp)
- write('', file=fp)
-
- # Host Synchronization
- if threadsafety:
- # The heading of this block differs between projects, so an Asciidoc attribute is used.
- write('.{externsynctitle}', file=fp)
- write('****', file=fp)
- write(threadsafety, file=fp, end='')
- write('****', file=fp)
- write('', file=fp)
-
- # Command Properties - contained within a block, to avoid table numbering
- if commandpropertiesentry:
- write('.Command Properties', file=fp)
- write('****', file=fp)
- write('[options="header", width="100%"]', file=fp)
- write('|====', file=fp)
- write('|<<VkCommandBufferLevel,Command Buffer Levels>>|<<vkCmdBeginRenderPass,Render Pass Scope>>|<<VkQueueFlagBits,Supported Queue Types>>', file=fp)
- write(commandpropertiesentry, file=fp)
- write('|====', file=fp)
- write('****', file=fp)
- write('', file=fp)
-
- # Success Codes - contained within a block, to avoid table numbering
- if successcodes or errorcodes:
- write('.Return Codes', file=fp)
- write('****', file=fp)
- if successcodes:
- write('ifndef::doctype-manpage[]', file=fp)
- write('<<fundamentals-successcodes,Success>>::', file=fp)
- write('endif::doctype-manpage[]', file=fp)
- write('ifdef::doctype-manpage[]', file=fp)
- write('On success, this command returns::', file=fp)
- write('endif::doctype-manpage[]', file=fp)
- write(successcodes, file=fp)
- if errorcodes:
- write('ifndef::doctype-manpage[]', file=fp)
- write('<<fundamentals-errorcodes,Failure>>::', file=fp)
- write('endif::doctype-manpage[]', file=fp)
- write('ifdef::doctype-manpage[]', file=fp)
- write('On failure, this command returns::', file=fp)
- write('endif::doctype-manpage[]', file=fp)
- write(errorcodes, file=fp)
- write('****', file=fp)
- write('', file=fp)
-
- def paramIsPointer(self, param):
- """Check if the parameter passed in is a pointer."""
- tail = param.find('type').tail
- return tail is not None and '*' in tail
-
- def paramIsStaticArray(self, param):
- """Check if the parameter passed in is a static array."""
- tail = param.find('name').tail
- return tail and tail[0] == '['
-
- def paramIsConst(self, param):
- """Check if the parameter passed in has a type that mentions const."""
- return param.text is not None and 'const' in param.text
-
- def staticArrayLength(self, param):
- """Get the length of a parameter that's been identified as a static array."""
- paramenumsize = param.find('enum')
- if paramenumsize is not None:
- return paramenumsize.text
- # TODO switch to below when cosmetic changes OK
- # return self.makeEnumerantName(paramenumsize.text)
-
- return param.find('name').tail[1:-1]
-
- def paramIsArray(self, param):
- """Check if the parameter passed in is a pointer to an array."""
- return param.get('len') is not None
-
- def getHandleDispatchableAncestors(self, typename):
- """Get the ancestors of a handle object."""
- ancestors = []
- current = typename
- while True:
- current = self.getHandleParent(current)
- if current is None:
- return ancestors
- if self.isHandleTypeDispatchable(current):
- ancestors.append(current)
-
- def isHandleTypeDispatchable(self, handlename):
- """Check if a parent object is dispatchable or not."""
- handle = self.registry.tree.find(
- "types/type/[name='" + handlename + "'][@category='handle']")
- if handle is not None and getElemType(handle) == 'VK_DEFINE_HANDLE':
- return True
- else:
- return False
-
- def isHandleOptional(self, param, params):
- # Simple, if it's optional, return true
- if param.get('optional') is not None:
- return True
-
- # If no validity is being generated, it usually means that validity is complex and not absolute, so let's say yes.
- if param.get('noautovalidity') is not None:
- return True
-
- # If the parameter is an array and we haven't already returned, find out if any of the len parameters are optional
- if self.paramIsArray(param):
- for length in LengthEntry.parse_len_from_param(param):
- if not length.other_param_name:
- # don't care about constants or "null-terminated"
- continue
-
- other_param = findNamedElem(params, length.other_param_name)
- if other_param is None:
- self.logMsg('warn', length.other_param_name,
- 'is listed as a length for parameter', param, 'but no such parameter exists')
- if other_param and other_param.get('optional'):
- return True
-
- return False
-
- def makeOptionalPre(self, param):
- # Don't generate this stub for bitflags
- param_name = getElemName(param)
- paramtype = getElemType(param)
- type_category = self.getTypeCategory(paramtype)
- is_optional = param.get('optional').split(',')[0] == 'true'
- if type_category != 'bitmask' and is_optional:
- if self.paramIsArray(param) or self.paramIsPointer(param):
- optional_val = self.null
- elif type_category == 'handle':
- if self.isHandleTypeDispatchable(paramtype):
- optional_val = self.null
- else:
- optional_val = 'dlink:' + self.conventions.api_prefix + 'NULL_HANDLE'
- else:
- optional_val = self.conventions.zero
- return 'If {} is not {}, '.format(
- self.makeParameterName(param_name),
- optional_val)
-
- return ""
-
- def makeParamValidityPre(self, param, params, selector):
- """Make the start of an entry for a parameter's validity, including a chunk of text if it is an array."""
- param_name = getElemName(param)
- paramtype = getElemType(param)
-
- # General pre-amble. Check optionality and add stuff.
- entry = ValidityEntry(anchor=(param_name, 'parameter'))
- is_optional = param.get('optional') is not None and param.get('optional').split(',')[0] == 'true'
-
- # This is for a union member, and the valid member is chosen by an enum selection
- if selector:
- selection = param.get('selection')
-
- entry += 'If {} is {}, '.format(
- self.makeParameterName(selector),
- self.makeEnumerantName(selection))
-
- if is_optional:
- entry += "and "
- optionalpre = self.makeOptionalPre(param)
- entry += optionalpre[0].lower() + optionalpre[1:]
-
- return entry
-
- if self.paramIsStaticArray(param):
- if paramtype != 'char':
- entry += 'Any given element of '
- return entry
-
- if self.paramIsArray(param) and param.get('len') != LengthEntry.NULL_TERMINATED_STRING:
- # Find all the parameters that are called out as optional,
- # so we can document that they might be zero, and the array may be ignored
- optionallengths = []
- for length in LengthEntry.parse_len_from_param(param):
- if not length.other_param_name:
- # Only care about length entries that are parameter names
- continue
-
- other_param = findNamedElem(params, length.other_param_name)
- other_param_optional = (other_param is not None) and (
- other_param.get('optional') is not None)
-
- if other_param is None or not other_param_optional:
- # Don't care about not-found params or non-optional params
- continue
-
- if self.paramIsPointer(other_param):
- optionallengths.append(
- 'the value referenced by ' + self.makeParameterName(length.other_param_name))
- else:
- optionallengths.append(
- self.makeParameterName(length.other_param_name))
-
- # Document that these arrays may be ignored if any of the length values are 0
- if optionallengths or is_optional:
- entry += 'If '
- if optionallengths:
- entry += self.makeProseListIs(optionallengths, fmt=plf.OR)
- entry += ' not %s, ' % self.conventions.zero
- # TODO enabling this in OpenXR, as used in Vulkan, causes nonsensical things like
- # "If pname:propertyCapacityInput is not `0`, and pname:properties is not `NULL`, pname:properties must: be a pointer to an array of pname:propertyCapacityInput slink:XrApiLayerProperties structures"
- if optionallengths and is_optional:
- entry += 'and '
- if is_optional:
- entry += self.makeParameterName(param_name)
- # TODO switch when cosmetic changes OK
- # entry += ' is not {}, '.format(self.null)
- entry += ' is not `NULL`, '
- return entry
-
- if param.get('optional'):
- entry += self.makeOptionalPre(param)
- return entry
-
- # If none of the early returns happened, we at least return an empty
- # entry with an anchor.
- return entry
-
- def createValidationLineForParameterImpl(self, blockname, param, params, typetext, selector, parentname):
- """Make the generic validity portion used for all parameters.
-
- May return None if nothing to validate.
- """
- if param.get('noautovalidity') is not None:
- return None
-
- validity = self.makeValidityCollection(blockname)
- param_name = getElemName(param)
- paramtype = getElemType(param)
-
- entry = self.makeParamValidityPre(param, params, selector)
-
- # This is for a child member of a union
- if selector:
- entry += 'the {} member of {} must: be '.format(self.makeParameterName(param_name), self.makeParameterName(parentname))
- else:
- entry += '{} must: be '.format(self.makeParameterName(param_name))
-
- if self.paramIsStaticArray(param) and paramtype == 'char':
- # TODO this is a minor hack to determine if this is a command parameter or a struct member
- if self.paramIsConst(param) or blockname.startswith(self.conventions.type_prefix):
- entry += 'a null-terminated UTF-8 string whose length is less than or equal to '
- entry += self.staticArrayLength(param)
- else:
- # This is a command's output parameter
- entry += 'a character array of length %s ' % self.staticArrayLength(param)
- validity += entry
- return validity
-
- elif self.paramIsArray(param):
- # Arrays. These are hard to get right, apparently
-
- lengths = LengthEntry.parse_len_from_param(param)
-
- for i, length in enumerate(LengthEntry.parse_len_from_param(param)):
- if i == 0:
- # If the first index, make it singular.
- entry += 'a '
- array_text = 'an array'
- pointer_text = self.valid_pointer_text
- else:
- array_text = 'arrays'
- pointer_text = self.valid_pointer_text + 's'
-
- if length.null_terminated:
- # This should always be the last thing.
- # If it ever isn't for some bizarre reason, then this will need some massaging.
- entry += 'null-terminated '
- elif length.number == 1:
- entry += pointer_text
- entry += ' to '
- else:
- entry += pointer_text
- entry += ' to '
- entry += array_text
- entry += ' of '
- # Handle equations, which are currently denoted with latex
- if length.math:
- # Handle equations, which are currently denoted with latex
- entry += str(length)
- else:
- entry += self.makeParameterName(str(length))
- entry += ' '
-
- # Void pointers don't actually point at anything - remove the word "to"
- if paramtype == 'void':
- if lengths[-1].number == 1:
- if len(lengths) > 1:
- # Take care of the extra s added by the post array chunk function. #HACK#
- entry.drop_end(5)
- else:
- entry.drop_end(4)
-
- # This hasn't been hit, so this hasn't been tested recently.
- raise UnhandledCaseError(
- "Got void pointer param/member with last length 1")
- else:
- # An array of void values is a byte array.
- entry += 'byte'
-
- elif paramtype == 'char':
- # A null terminated array of chars is a string
- if lengths[-1].null_terminated:
- entry += 'UTF-8 string'
- else:
- # Else it's just a bunch of chars
- entry += 'char value'
-
- elif self.paramIsConst(param):
- # If a value is "const" that means it won't get modified, so it must be valid going into the function.
- if 'const' in param.text:
-
- if not self.isStructAlwaysValid(paramtype):
- entry += 'valid '
-
- # Check if the array elements are optional
- array_element_optional = param.get('optional') is not None \
- and len(param.get('optional').split(',')) == len(LengthEntry.parse_len_from_param(param)) + 1 \
- and param.get('optional').split(',')[-1] == 'true'
- if array_element_optional and self.getTypeCategory(paramtype) != 'bitmask': # bitmask is handled later
- entry += 'or dlink:' + self.conventions.api_prefix + 'NULL_HANDLE '
-
- entry += typetext
-
- # pluralize
- if len(lengths) > 1 or (lengths[0] != 1 and not lengths[0].null_terminated):
- entry += 's'
-
- return self.handleRequiredBitmask(blockname, param, paramtype, entry, 'true' if array_element_optional else None)
-
- if self.paramIsPointer(param):
- # Handle pointers - which are really special case arrays (i.e. they don't have a length)
- # TODO should do something here if someone ever uses some intricate comma-separated `optional`
- pointercount = param.find('type').tail.count('*')
-
- # Treat void* as an int
- if paramtype == 'void':
- optional = param.get('optional')
- # If there is only void*, it is just optional int - we don't need any language.
- if pointercount == 1 and optional is not None:
- return None # early return
- # Treat the inner-most void* as an int
- pointercount -= 1
-
- # Could be multi-level pointers (e.g. ppData - pointer to a pointer). Handle that.
- entry += 'a '
- entry += (self.valid_pointer_text + ' to a ') * pointercount
-
- # Handle void* and pointers to it
- if paramtype == 'void':
- if optional is None or optional.split(',')[pointercount]:
- # The last void* is just optional int (e.g. to be filled by the impl.)
- typetext = 'pointer value'
-
- # If a value is "const" that means it won't get modified, so it must be valid going into the function.
- elif self.paramIsConst(param) and paramtype != 'void':
- entry += 'valid '
-
- entry += typetext
- return self.handleRequiredBitmask(blockname, param, paramtype, entry, param.get('optional'))
-
- # Add additional line for non-optional bitmasks
- if self.getTypeCategory(paramtype) == 'bitmask':
- # TODO does not really handle if someone tries something like optional="true,false"
- # TODO OpenXR has 0 or a valid combination of flags, for optional things.
- # Vulkan doesn't...
- # isMandatory = param.get('optional') is None
- # if not isMandatory:
- # entry += self.conventions.zero
- # entry += ' or '
- # Non-pointer, non-optional things must be valid
- entry += 'a valid {}'.format(typetext)
-
- return self.handleRequiredBitmask(blockname, param, paramtype, entry, param.get('optional'))
-
- # Non-pointer, non-optional things must be valid
- entry += 'a valid {}'.format(typetext)
- return entry
-
- def handleRequiredBitmask(self, blockname, param, paramtype, entry, optional):
- # TODO does not really handle if someone tries something like optional="true,false"
- if self.getTypeCategory(paramtype) != 'bitmask' or optional == 'true':
- return entry
- if self.paramIsPointer(param) and not self.paramIsArray(param):
- # This is presumably an output parameter
- return entry
-
- param_name = getElemName(param)
- # If mandatory, then we need two entries instead of just one.
- validity = self.makeValidityCollection(blockname)
- validity += entry
-
- entry2 = ValidityEntry(anchor=(param_name, 'requiredbitmask'))
- if self.paramIsArray(param):
- entry2 += 'Each element of '
- entry2 += '{} must: not be {}'.format(
- self.makeParameterName(param_name), self.conventions.zero)
- validity += entry2
- return validity
-
- def createValidationLineForParameter(self, blockname, param, params, typecategory, selector, parentname):
- """Make an entire validation entry for a given parameter."""
- param_name = getElemName(param)
- paramtype = getElemType(param)
-
- is_array = self.paramIsArray(param)
- is_pointer = self.paramIsPointer(param)
- needs_recursive_validity = (is_array
- or is_pointer
- or not self.isStructAlwaysValid(paramtype))
- typetext = None
- if paramtype in ('void', 'char'):
- # Chars and void are special cases - we call the impl function,
- # but don't use the typetext.
- # A null-terminated char array is a string, else it's chars.
- # An array of void values is a byte array, a void pointer is just a pointer to nothing in particular
- typetext = ''
-
- elif typecategory == 'bitmask':
- bitsname = paramtype.replace('Flags', 'FlagBits')
- bitselem = self.registry.tree.find("enums[@name='" + bitsname + "']")
-
- # If bitsname is an alias, then use the alias to get bitselem.
- typeElem = self.registry.lookupElementInfo(bitsname, self.registry.typedict)
- if typeElem is not None:
- alias = self.registry.getAlias(typeElem.elem, self.registry.typedict)
- if alias is not None:
- bitselem = self.registry.tree.find("enums[@name='" + alias + "']")
-
- if bitselem is None or len(bitselem.findall('enum[@required="true"]')) == 0:
- # Empty bit mask: presumably just a placeholder (or only in
- # an extension not enabled for this build)
- entry = ValidityEntry(
- anchor=(param_name, 'zerobitmask'))
- entry += self.makeParameterName(param_name)
- entry += ' must: be '
- entry += self.conventions.zero
- # Early return
- return entry
-
- is_const = self.paramIsConst(param)
-
- if is_array:
- if is_const:
- # input an array of bitmask values
- template = 'combinations of {bitsname} value'
- else:
- template = '{paramtype} value'
- elif is_pointer:
- if is_const:
- template = 'combination of {bitsname} values'
- else:
- template = '{paramtype} value'
- else:
- template = 'combination of {bitsname} values'
-
- # The above few cases all use makeEnumerationName, just with different context.
- typetext = template.format(
- bitsname=self.makeEnumerationName(bitsname),
- paramtype=self.makeFlagsName(paramtype))
-
- elif typecategory == 'handle':
- typetext = '{} handle'.format(self.makeStructName(paramtype))
-
- elif typecategory == 'enum':
- typetext = '{} value'.format(self.makeEnumerationName(paramtype))
-
- elif typecategory == 'funcpointer':
- typetext = '{} value'.format(self.makeFuncPointerName(paramtype))
-
- elif typecategory == 'struct':
- if needs_recursive_validity:
- typetext = '{} structure'.format(
- self.makeStructName(paramtype))
-
- elif typecategory == 'union':
- if needs_recursive_validity:
- typetext = '{} union'.format(self.makeStructName(paramtype))
-
- elif self.paramIsArray(param) or self.paramIsPointer(param):
- # TODO sync cosmetic changes from OpenXR?
- typetext = '{} value'.format(self.makeBaseTypeName(paramtype))
-
- elif typecategory is None:
- if not self.isStructAlwaysValid(paramtype):
- typetext = '{} value'.format(
- self.makeExternalTypeName(paramtype))
-
- # "a valid uint32_t value" doesn't make much sense.
- pass
-
- # If any of the above conditions matched and set typetext,
- # we call using it.
- if typetext is not None:
- return self.createValidationLineForParameterImpl(
- blockname, param, params, typetext, selector, parentname)
- return None
-
- def makeHandleValidityParent(self, param, params):
- """Make a validity entry for a handle's parent object.
-
- Creates 'parent' VUID.
- """
- param_name = getElemName(param)
- paramtype = getElemType(param)
-
- # Deal with handle parents
- handleparent = self.getHandleParent(paramtype)
- if handleparent is None:
- return None
-
- otherparam = findTypedElem(params, handleparent)
- if otherparam is None:
- return None
-
- parent_name = getElemName(otherparam)
- entry = ValidityEntry(anchor=(param_name, 'parent'))
-
- is_optional = self.isHandleOptional(param, params)
-
- if self.paramIsArray(param):
- template = 'Each element of {}'
- if is_optional:
- template += ' that is a valid handle'
- elif is_optional:
- template = 'If {} is a valid handle, it'
- else:
- # not optional, not an array. Just say the parameter name.
- template = '{}'
-
- entry += template.format(self.makeParameterName(param_name))
-
- entry += ' must: have been created, allocated, or retrieved from {}'.format(
- self.makeParameterName(parent_name))
-
- return entry
-
- def makeAsciiDocHandlesCommonAncestor(self, blockname, handles, params):
- """Make an asciidoc validity entry for a common ancestors between handles.
-
- Only handles parent validity for signatures taking multiple handles
- any ancestors also being supplied to this function.
- (e.g. "Each of x, y, and z must: come from the same slink:ParentHandle")
- See self.makeAsciiDocHandleParent() for instances where the parent
- handle is named and also passed.
-
- Creates 'commonparent' VUID.
- """
- # TODO Replace with refactored code from OpenXR
- entry = None
-
- if len(handles) > 1:
- ancestormap = {}
- anyoptional = False
- # Find all the ancestors
- for param in handles:
- paramtype = getElemType(param)
-
- if not self.paramIsPointer(param) or (param.text and 'const' in param.text):
- ancestors = self.getHandleDispatchableAncestors(paramtype)
-
- ancestormap[param] = ancestors
-
- anyoptional |= self.isHandleOptional(param, params)
-
- # Remove redundant ancestor lists
- for param in handles:
- paramtype = getElemType(param)
-
- removals = []
- for ancestors in ancestormap.items():
- if paramtype in ancestors[1]:
- removals.append(ancestors[0])
-
- if removals != []:
- for removal in removals:
- del(ancestormap[removal])
-
- # Intersect
-
- if len(ancestormap.values()) > 1:
- current = list(ancestormap.values())[0]
- for ancestors in list(ancestormap.values())[1:]:
- current = [val for val in current if val in ancestors]
-
- if len(current) > 0:
- commonancestor = current[0]
-
- if len(ancestormap.keys()) > 1:
-
- entry = ValidityEntry(anchor=('commonparent',))
-
- parametertexts = []
- for param in ancestormap.keys():
- param_name = getElemName(param)
- parametertext = self.makeParameterName(param_name)
- if self.paramIsArray(param):
- parametertext = 'the elements of ' + parametertext
- parametertexts.append(parametertext)
-
- parametertexts.sort()
-
- if len(parametertexts) > 2:
- entry += 'Each of '
- else:
- entry += 'Both of '
-
- entry += self.makeProseList(parametertexts,
- comma_for_two_elts=True)
- if anyoptional is True:
- entry += ' that are valid handles of non-ignored parameters'
- entry += ' must: have been created, allocated, or retrieved from the same '
- entry += self.makeStructName(commonancestor)
-
- return entry
-
- def makeStructureTypeFromName(self, structname):
- """Create text for a structure type name, like ename:VK_STRUCTURE_TYPE_CREATE_INSTANCE_INFO"""
- return self.makeEnumerantName(self.conventions.generate_structure_type_from_name(structname))
-
- def makeStructureTypeValidity(self, structname):
- """Generate an validity line for the type value of a struct.
-
- Creates VUID named like the member name.
- """
- info = self.registry.typedict.get(structname)
- assert(info is not None)
-
- # If this fails (meaning we have something other than a struct in here),
- # then the caller is wrong:
- # probably passing the wrong value for structname.
- members = info.getMembers()
- assert(members)
-
- # If this fails, see caller: this should only get called for a struct type with a type value.
- param = findNamedElem(members, self.structtype_member_name)
- # OpenXR gets some structs without a type field in here, so can't assert
- assert(param is not None)
- # if param is None:
- # return None
-
- entry = ValidityEntry(
- anchor=(self.structtype_member_name, self.structtype_member_name))
- entry += self.makeParameterName(self.structtype_member_name)
- entry += ' must: be '
-
- values = param.get('values', '').split(',')
- if values:
- # Extract each enumerant value. They could be validated in the
- # same fashion as validextensionstructs in
- # makeStructureExtensionPointer, although that's not relevant in
- # the current extension struct model.
- entry += self.makeProseList((self.makeEnumerantName(v)
- for v in values), 'or')
- return entry
-
- if 'Base' in structname:
- # This type doesn't even have any values for its type,
- # and it seems like it might be a base struct that we'd expect to lack its own type,
- # so omit the entire statement
- return None
-
- self.logMsg('warn', 'No values were marked-up for the structure type member of',
- structname, 'so making one up!')
- entry += self.makeStructureTypeFromName(structname)
-
- return entry
-
- def makeStructureExtensionPointer(self, blockname, param):
- """Generate an validity line for the pointer chain member value of a struct."""
- param_name = getElemName(param)
-
- if param.get('validextensionstructs') is not None:
- self.logMsg('warn', blockname,
- 'validextensionstructs is deprecated/removed', '\n')
-
- entry = ValidityEntry(
- anchor=(param_name, self.nextpointer_member_name))
- validextensionstructs = self.registry.validextensionstructs.get(
- blockname)
- extensionstructs = []
- duplicatestructs = []
-
- if validextensionstructs is not None:
- # Check each structure name and skip it if not required by the
- # generator. This allows tagging extension structs in the XML
- # that are only included in validity when needed for the spec
- # being targeted.
- # Track the required structures, and of the required structures,
- # those that allow duplicates in the pNext chain.
- for struct in validextensionstructs:
- # Unpleasantly breaks encapsulation. Should be a method in the registry class
- t = self.registry.lookupElementInfo(
- struct, self.registry.typedict)
- if t is None:
- self.logMsg('warn', 'makeStructureExtensionPointer: struct', struct,
- 'is in a validextensionstructs= attribute but is not in the registry')
- elif t.required:
- extensionstructs.append('slink:' + struct)
- if t.elem.get('allowduplicate') == 'true':
- duplicatestructs.append('slink:' + struct)
- else:
- self.logMsg(
- 'diag', 'makeStructureExtensionPointer: struct', struct, 'IS NOT required')
-
- if not extensionstructs:
- entry += '{} must: be {}'.format(
- self.makeParameterName(param_name), self.null)
- return entry
-
- if len(extensionstructs) == 1:
- entry += '{} must: be {} or a pointer to a valid instance of {}'.format(self.makeParameterName(param_name), self.null,
- extensionstructs[0])
- else:
- # More than one extension struct.
- entry += 'Each {} member of any structure (including this one) in the pname:{} chain '.format(
- self.makeParameterName(param_name), self.nextpointer_member_name)
- entry += 'must: be either {} or a pointer to a valid instance of '.format(
- self.null)
-
- entry += self.makeProseList(extensionstructs, fmt=plf.OR)
-
- validity = self.makeValidityCollection(blockname)
- validity += entry
-
- # Generate VU statement requiring unique structures in the pNext
- # chain.
- # NOTE: OpenXR always allows non-unique type values. Instances other
- # than the first are just ignored
-
- vu = ('The pname:' +
- self.structtype_member_name +
- ' value of each struct in the pname:' +
- self.nextpointer_member_name +
- ' chain must: be unique')
- anchor = (self.conventions.member_used_for_unique_vuid, 'unique')
-
- # If duplicates of some structures are allowed, they are called out
- # explicitly.
- num = len(duplicatestructs)
- if num > 0:
- vu = (vu +
- ', with the exception of structures of type ' +
- self.makeProseList(duplicatestructs, fmt=plf.OR))
-
- validity.addValidityEntry(vu, anchor = anchor )
-
- return validity
-
- def addSharedStructMemberValidity(self, struct, blockname, param, validity):
- """Generate language to independently validate a parameter, for those validated even in output.
-
- Return value indicates whether it was handled internally (True) or if it may need more validity (False)."""
- param_name = getElemName(param)
- paramtype = getElemType(param)
- if param.get('noautovalidity') is None:
-
- if self.conventions.is_structure_type_member(paramtype, param_name):
- validity += self.makeStructureTypeValidity(blockname)
- return True
-
- if self.conventions.is_nextpointer_member(paramtype, param_name):
- # Vulkan: the addition of validity here is conditional unlike OpenXR.
- if struct.get('structextends') is None:
- validity += self.makeStructureExtensionPointer(
- blockname, param)
- return True
- return False
-
- def makeOutputOnlyStructValidity(self, cmd, blockname, params):
- """Generate all the valid usage information for a struct that's entirely output.
-
- That is, it is only ever filled out by the implementation other than
- the structure type and pointer chain members.
- Thus, we only create validity for the pointer chain member.
- """
- # Start the validity collection for this struct
- validity = self.makeValidityCollection(blockname)
-
- for param in params:
- self.addSharedStructMemberValidity(
- cmd, blockname, param, validity)
-
- return validity
-
- def isVKVersion11(self):
- """Returns true if VK_VERSION_1_1 is being emitted."""
- vk11 = re.match(self.registry.genOpts.emitversions, 'VK_VERSION_1_1') is not None
- return vk11
-
- def makeStructOrCommandValidity(self, cmd, blockname, params):
- """Generate all the valid usage information for a given struct or command."""
- validity = self.makeValidityCollection(blockname)
- handles = []
- arraylengths = dict()
- for param in params:
- param_name = getElemName(param)
- paramtype = getElemType(param)
-
- # Valid usage ID tags (VUID) are generated for various
- # conditions based on the name of the block (structure or
- # command), name of the element (member or parameter), and type
- # of VU statement.
-
- # Get the type's category
- typecategory = self.getTypeCategory(paramtype)
-
- if not self.addSharedStructMemberValidity(
- cmd, blockname, param, validity):
- if not param.get('selector'):
- validity += self.createValidationLineForParameter(
- blockname, param, params, typecategory, None, None)
- else:
- selector = param.get('selector')
- if typecategory != 'union':
- self.logMsg('warn', 'selector attribute set on non-union parameter', param_name, 'in', blockname)
-
- paraminfo = self.registry.lookupElementInfo(paramtype, self.registry.typedict)
-
- for member in paraminfo.getMembers():
- membertype = getElemType(member)
- membertypecategory = self.getTypeCategory(membertype)
-
- validity += self.createValidationLineForParameter(
- blockname, member, paraminfo.getMembers(), membertypecategory, selector, param_name)
-
- # Ensure that any parenting is properly validated, and list that a handle was found
- if typecategory == 'handle':
- handles.append(param)
-
- # Get the array length for this parameter
- lengths = LengthEntry.parse_len_from_param(param)
- if lengths:
- arraylengths.update({length.other_param_name: length
- for length in lengths
- if length.other_param_name})
-
- # For any vkQueue* functions, there might be queue type data
- if 'vkQueue' in blockname:
- # The queue type must be valid
- queuebits = _parse_queue_bits(cmd)
- if queuebits:
- entry = ValidityEntry(anchor=('queuetype',))
- entry += 'The pname:queue must: support '
- entry += self.makeProseList(queuebits,
- fmt=plf.OR, comma_for_two_elts=True)
- entry += ' operations'
- validity += entry
-
- if 'vkCmd' in blockname:
- # The commandBuffer parameter must be being recorded
- entry = ValidityEntry(anchor=('commandBuffer', 'recording'))
- entry += 'pname:commandBuffer must: be in the <<commandbuffers-lifecycle, recording state>>'
- validity += entry
-
- #
- # Start of valid queue type validation - command pool must have been
- # allocated against a queue with at least one of the valid queue types
- entry = ValidityEntry(anchor=('commandBuffer', 'cmdpool'))
-
- #
- # This test for vkCmdFillBuffer is a hack, since we have no path
- # to conditionally have queues enabled or disabled by an extension.
- # As the VU stuff is all moving out (hopefully soon), this hack solves the issue for now
- if blockname == 'vkCmdFillBuffer':
- entry += 'The sname:VkCommandPool that pname:commandBuffer was allocated from must: support '
- if self.isVKVersion11() or 'VK_KHR_maintenance1' in self.registry.requiredextensions:
- entry += 'transfer, graphics or compute operations'
- else:
- entry += 'graphics or compute operations'
- else:
- # The queue type must be valid
- queuebits = _parse_queue_bits(cmd)
- assert(queuebits)
- entry += 'The sname:VkCommandPool that pname:commandBuffer was allocated from must: support '
- entry += self.makeProseList(queuebits,
- fmt=plf.OR, comma_for_two_elts=True)
- entry += ' operations'
- validity += entry
-
- # Must be called inside/outside a render pass appropriately
- renderpass = cmd.get('renderpass')
-
- if renderpass != 'both':
- entry = ValidityEntry(anchor=('renderpass',))
- entry += 'This command must: only be called '
- entry += renderpass
- entry += ' of a render pass instance'
- validity += entry
-
- # Must be in the right level command buffer
- cmdbufferlevel = cmd.get('cmdbufferlevel')
-
- if cmdbufferlevel != 'primary,secondary':
- entry = ValidityEntry(anchor=('bufferlevel',))
- entry += 'pname:commandBuffer must: be a '
- entry += cmdbufferlevel
- entry += ' sname:VkCommandBuffer'
- validity += entry
-
- # Any non-optional arraylengths should specify they must be greater than 0
- array_length_params = ((param, getElemName(param))
- for param in params
- if getElemName(param) in arraylengths)
-
- for param, param_name in array_length_params:
- if param.get('optional') is not None:
- continue
-
- length = arraylengths[param_name]
- full_length = length.full_reference
-
- # Is this just a name of a param? If false, then it's some kind of qualified name (a member of a param for instance)
- simple_param_reference = (len(length.param_ref_parts) == 1)
- if not simple_param_reference:
- # Loop through to see if any parameters in the chain are optional
- array_length_parent = cmd
- array_length_optional = False
- for part in length.param_ref_parts:
- # Overwrite the param so it ends up as the bottom level parameter for later checks
- param = array_length_parent.find("*/[name='{}']".format(part))
-
- # If any parameter in the chain is optional, skip the implicit length requirement
- array_length_optional |= (param.get('optional') is not None)
-
- # Lookup the type of the parameter for the next loop iteration
- type = param.findtext('type')
- array_length_parent = self.registry.tree.find("./types/type/[@name='{}']".format(type))
-
- if array_length_optional:
- continue
-
- # Get all the array dependencies
- arrays = cmd.findall(
- "param/[@len='{}'][@optional='true']".format(full_length))
-
- # Get all the optional array dependencies, including those not generating validity for some reason
- optionalarrays = arrays + \
- cmd.findall(
- "param/[@len='{}'][@noautovalidity='true']".format(full_length))
-
- entry = ValidityEntry(anchor=(full_length, 'arraylength'))
- # Allow lengths to be arbitrary if all their dependents are optional
- if optionalarrays and len(optionalarrays) == len(arrays):
- entry += 'If '
- # TODO sync this section from OpenXR once cosmetic changes OK
-
- optional_array_names = (self.makeParameterName(getElemName(array))
- for array in optionalarrays)
- entry += self.makeProseListIs(optional_array_names,
- plf.ANY_OR, comma_for_two_elts=True)
-
- entry += ' not {}, '.format(self.null)
-
- # TODO end needs sync cosmetic
- if self.paramIsPointer(param):
- entry += 'the value referenced by '
-
- # Split and re-join here to insert pname: around ::
- entry += '::'.join(self.makeParameterName(part)
- for part in full_length.split('::'))
- # TODO replace the previous statement with the following when cosmetic changes OK
- # entry += length.get_human_readable(make_param_name=self.makeParameterName)
-
- entry += ' must: be greater than '
- entry += self.conventions.zero
- validity += entry
-
- # Find the parents of all objects referenced in this command
- for param in handles:
- # Don't detect a parent for return values!
- if not self.paramIsPointer(param) or self.paramIsConst(param):
- validity += self.makeHandleValidityParent(param, params)
-
- # Find the common ancestor of all objects referenced in this command
- validity += self.makeAsciiDocHandlesCommonAncestor(
- blockname, handles, params)
-
- return validity
-
- def makeThreadSafetyBlock(self, cmd, paramtext):
- """Generate thread-safety validity entries for cmd/structure"""
- # See also makeThreadSafetyBlock in validitygenerator.py
- validity = self.makeValidityCollection(getElemName(cmd))
-
- # This text varies between projects, so an Asciidoctor attribute is used.
- extsync_prefix = "{externsyncprefix} "
-
- # Find and add any parameters that are thread unsafe
- explicitexternsyncparams = cmd.findall(paramtext + "[@externsync]")
- if explicitexternsyncparams is not None:
- for param in explicitexternsyncparams:
- externsyncattribs = ExternSyncEntry.parse_externsync_from_param(
- param)
- param_name = getElemName(param)
-
- for attrib in externsyncattribs:
- entry = ValidityEntry()
- entry += extsync_prefix
- if attrib.entirely_extern_sync:
- if self.paramIsArray(param):
- entry += 'each member of '
- elif self.paramIsPointer(param):
- entry += 'the object referenced by '
-
- entry += self.makeParameterName(param_name)
-
- if attrib.children_extern_sync:
- entry += ', and any child handles,'
-
- else:
- entry += 'pname:'
- entry += str(attrib.full_reference)
- # TODO switch to the following when cosmetic changes OK
- # entry += attrib.get_human_readable(make_param_name=self.makeParameterName)
- entry += ' must: be externally synchronized'
- validity += entry
-
- # Vulkan-specific
- # For any vkCmd* functions, the command pool is externally synchronized
- if cmd.find('proto/name') is not None and 'vkCmd' in cmd.find('proto/name').text:
- entry = ValidityEntry()
- entry += extsync_prefix
- entry += 'the sname:VkCommandPool that pname:commandBuffer was allocated from must: be externally synchronized'
- validity += entry
-
- # Find and add any "implicit" parameters that are thread unsafe
- implicitexternsyncparams = cmd.find('implicitexternsyncparams')
- if implicitexternsyncparams is not None:
- for elem in implicitexternsyncparams:
- entry = ValidityEntry()
- entry += extsync_prefix
- entry += elem.text
- entry += ' must: be externally synchronized'
- validity += entry
-
- return validity
-
- def makeCommandPropertiesTableEntry(self, cmd, name):
-
- if 'vkCmd' in name:
- # Must be called inside/outside a render pass appropriately
- cmdbufferlevel = cmd.get('cmdbufferlevel')
- cmdbufferlevel = (' + \n').join(cmdbufferlevel.title().split(','))
-
- renderpass = cmd.get('renderpass')
- renderpass = renderpass.capitalize()
-
- #
- # This test for vkCmdFillBuffer is a hack, since we have no path
- # to conditionally have queues enabled or disabled by an extension.
- # As the VU stuff is all moving out (hopefully soon), this hack solves the issue for now
- if name == 'vkCmdFillBuffer':
- if self.isVKVersion11() or 'VK_KHR_maintenance1' in self.registry.requiredextensions:
- queues = 'Transfer + \nGraphics + \nCompute'
- else:
- queues = 'Graphics + \nCompute'
- else:
- queues = cmd.get('queues')
- queues = (' + \n').join(queues.title().split(','))
-
- return '|' + cmdbufferlevel + '|' + renderpass + '|' + queues
- elif 'vkQueue' in name:
- # Must be called inside/outside a render pass appropriately
-
- queues = cmd.get('queues')
- if queues is None:
- queues = 'Any'
- else:
- queues = (' + \n').join(queues.upper().split(','))
-
- return '|-|-|' + queues
-
- return None
-
-
- def findRequiredEnums(self, enums):
- """Check each enumerant name in the enums list and remove it if not
- required by the generator. This allows specifying success and error
- codes for extensions that are only included in validity when needed
- for the spec being targeted."""
- return self.keepOnlyRequired(enums, self.registry.enumdict)
-
- def findRequiredCommands(self, commands):
- """Check each command name in the commands list and remove it if not
- required by the generator.
-
- This will allow some state operations to take place before endFile."""
- return self.keepOnlyRequired(commands, self.registry.cmddict)
-
- def keepOnlyRequired(self, names, info_dict):
- """Check each element name in the supplied dictionary and remove it if not
- required by the generator.
-
- This will allow some operations to take place before endFile no matter the order of generation."""
- # TODO Unpleasantly breaks encapsulation. Should be a method in the registry class
-
- def is_required(name):
- info = self.registry.lookupElementInfo(name, info_dict)
- if info is None:
- return False
- if not info.required:
- self.logMsg('diag', 'keepOnlyRequired: element',
- name, 'IS NOT required, skipping')
- return info.required
-
- return [name
- for name in names
- if is_required(name)]
-
- def makeReturnCodeList(self, attrib, cmd, name):
- """Return a list of possible return codes for a function.
-
- attrib is either 'successcodes' or 'errorcodes'.
- """
- return_lines = []
- RETURN_CODE_FORMAT = '* ename:{}'
-
- codes_attr = cmd.get(attrib)
- if codes_attr:
- codes = self.findRequiredEnums(codes_attr.split(','))
- if codes:
- return_lines.extend((RETURN_CODE_FORMAT.format(code)
- for code in codes))
-
- applicable_ext_codes = (ext_code
- for ext_code in self.registry.commandextensionsuccesses
- if ext_code.command == name)
- for ext_code in applicable_ext_codes:
- line = RETURN_CODE_FORMAT.format(ext_code.value)
- if ext_code.extension:
- line += ' [only if {} is enabled]'.format(
- self.conventions.formatExtension(ext_code.extension))
-
- return_lines.append(line)
- if return_lines:
- return '\n'.join(return_lines)
-
- return None
-
- def makeSuccessCodes(self, cmd, name):
- return self.makeReturnCodeList('successcodes', cmd, name)
-
- def makeErrorCodes(self, cmd, name):
- return self.makeReturnCodeList('errorcodes', cmd, name)
-
- def genCmd(self, cmdinfo, name, alias):
- """Command generation."""
- OutputGenerator.genCmd(self, cmdinfo, name, alias)
-
- # @@@ (Jon) something needs to be done here to handle aliases, probably
-
- validity = self.makeValidityCollection(name)
-
- # OpenXR-only: make sure extension is enabled
- # validity.possiblyAddExtensionRequirement(self.currentExtension, 'calling flink:')
-
- validity += self.makeStructOrCommandValidity(
- cmdinfo.elem, name, cmdinfo.getParams())
-
- threadsafety = self.makeThreadSafetyBlock(cmdinfo.elem, 'param')
- commandpropertiesentry = None
-
- # Vulkan-specific
- commandpropertiesentry = self.makeCommandPropertiesTableEntry(
- cmdinfo.elem, name)
- successcodes = self.makeSuccessCodes(cmdinfo.elem, name)
- errorcodes = self.makeErrorCodes(cmdinfo.elem, name)
-
- # OpenXR-specific
- # self.generateStateValidity(validity, name)
-
- self.writeInclude('protos', name, validity, threadsafety,
- commandpropertiesentry, successcodes, errorcodes)
-
- def genStruct(self, typeinfo, typeName, alias):
- """Struct Generation."""
- OutputGenerator.genStruct(self, typeinfo, typeName, alias)
-
- # @@@ (Jon) something needs to be done here to handle aliases, probably
-
- # Anything that's only ever returned can't be set by the user, so shouldn't have any validity information.
- validity = self.makeValidityCollection(typeName)
- threadsafety = []
-
- # OpenXR-only: make sure extension is enabled
- # validity.possiblyAddExtensionRequirement(self.currentExtension, 'using slink:')
-
- if typeinfo.elem.get('category') != 'union':
- if typeinfo.elem.get('returnedonly') is None:
- validity += self.makeStructOrCommandValidity(
- typeinfo.elem, typeName, typeinfo.getMembers())
- threadsafety = self.makeThreadSafetyBlock(typeinfo.elem, 'member')
-
- else:
- # Need to generate structure type and next pointer chain member validation
- validity += self.makeOutputOnlyStructValidity(
- typeinfo.elem, typeName, typeinfo.getMembers())
-
- self.writeInclude('structs', typeName, validity,
- threadsafety, None, None, None)
-
- def genGroup(self, groupinfo, groupName, alias):
- """Group (e.g. C "enum" type) generation.
- For the validity generator, this just tags individual enumerants
- as required or not.
- """
- OutputGenerator.genGroup(self, groupinfo, groupName, alias)
-
- # @@@ (Jon) something needs to be done here to handle aliases, probably
-
- groupElem = groupinfo.elem
-
- # Loop over the nested 'enum' tags. Keep track of the minimum and
- # maximum numeric values, if they can be determined; but only for
- # core API enumerants, not extension enumerants. This is inferred
- # by looking for 'extends' attributes.
- for elem in groupElem.findall('enum'):
- name = elem.get('name')
- ei = self.registry.lookupElementInfo(name, self.registry.enumdict)
-
- # Tag enumerant as required or not
- ei.required = self.isEnumRequired(elem)
-
- def genType(self, typeinfo, name, alias):
- """Type Generation."""
- OutputGenerator.genType(self, typeinfo, name, alias)
-
- # @@@ (Jon) something needs to be done here to handle aliases, probably
-
- category = typeinfo.elem.get('category')
- if category in ('struct', 'union'):
- self.genStruct(typeinfo, name, alias)
diff --git a/codegen/vulkan/scripts/vkconventions.py b/codegen/vulkan/scripts/vkconventions.py
deleted file mode 100644
index a43f7121..00000000
--- a/codegen/vulkan/scripts/vkconventions.py
+++ /dev/null
@@ -1,274 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# Working-group-specific style conventions,
-# used in generation.
-
-import re
-import os
-
-from conventions import ConventionsBase
-
-
-# Modified from default implementation - see category_requires_validation() below
-CATEGORIES_REQUIRING_VALIDATION = set(('handle', 'enum', 'bitmask'))
-
-# Tokenize into "words" for structure types, approximately per spec "Implicit Valid Usage" section 2.7.2
-# This first set is for things we recognize explicitly as words,
-# as exceptions to the general regex.
-# Ideally these would be listed in the spec as exceptions, as OpenXR does.
-SPECIAL_WORDS = set((
- '16Bit', # VkPhysicalDevice16BitStorageFeatures
- '8Bit', # VkPhysicalDevice8BitStorageFeaturesKHR
- 'AABB', # VkGeometryAABBNV
- 'ASTC', # VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT
- 'D3D12', # VkD3D12FenceSubmitInfoKHR
- 'Float16', # VkPhysicalDeviceShaderFloat16Int8FeaturesKHR
- 'ImagePipe', # VkImagePipeSurfaceCreateInfoFUCHSIA
- 'Int64', # VkPhysicalDeviceShaderAtomicInt64FeaturesKHR
- 'Int8', # VkPhysicalDeviceShaderFloat16Int8FeaturesKHR
- 'MacOS', # VkMacOSSurfaceCreateInfoMVK
- 'RGBA10X6', # VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT
- 'Uint8', # VkPhysicalDeviceIndexTypeUint8FeaturesEXT
- 'Win32', # VkWin32SurfaceCreateInfoKHR
-))
-# A regex to match any of the SPECIAL_WORDS
-EXCEPTION_PATTERN = r'(?P<exception>{})'.format(
- '|'.join('(%s)' % re.escape(w) for w in SPECIAL_WORDS))
-MAIN_RE = re.compile(
- # the negative lookahead is to prevent the all-caps pattern from being too greedy.
- r'({}|([0-9]+)|([A-Z][a-z]+)|([A-Z][A-Z]*(?![a-z])))'.format(EXCEPTION_PATTERN))
-
-
-class VulkanConventions(ConventionsBase):
- @property
- def null(self):
- """Preferred spelling of NULL."""
- return '`NULL`'
-
- @property
- def struct_macro(self):
- """Get the appropriate format macro for a structure.
-
- Primarily affects generated valid usage statements.
- """
-
- return 'slink:'
-
- @property
- def constFlagBits(self):
- """Returns True if static const flag bits should be generated, False if an enumerated type should be generated."""
- return False
-
- @property
- def structtype_member_name(self):
- """Return name of the structure type member"""
- return 'sType'
-
- @property
- def nextpointer_member_name(self):
- """Return name of the structure pointer chain member"""
- return 'pNext'
-
- @property
- def valid_pointer_prefix(self):
- """Return prefix to pointers which must themselves be valid"""
- return 'valid'
-
- def is_structure_type_member(self, paramtype, paramname):
- """Determine if member type and name match the structure type member."""
- return paramtype == 'VkStructureType' and paramname == self.structtype_member_name
-
- def is_nextpointer_member(self, paramtype, paramname):
- """Determine if member type and name match the next pointer chain member."""
- return paramtype == 'void' and paramname == self.nextpointer_member_name
-
- def generate_structure_type_from_name(self, structname):
- """Generate a structure type name, like VK_STRUCTURE_TYPE_CREATE_INSTANCE_INFO"""
-
- structure_type_parts = []
- # Tokenize into "words"
- for elem in MAIN_RE.findall(structname):
- word = elem[0]
- if word == 'Vk':
- structure_type_parts.append('VK_STRUCTURE_TYPE')
- else:
- structure_type_parts.append(word.upper())
- name = '_'.join(structure_type_parts)
-
- # The simple-minded rules need modification for some structure names
- subpats = [
- [ r'_H_(26[45])_', r'_H\1_' ],
- [ r'_VULKAN_([0-9])([0-9])_', r'_VULKAN_\1_\2_' ],
- [ r'_DIRECT_FB_', r'_DIRECTFB_' ],
- ]
-
- for subpat in subpats:
- name = re.sub(subpat[0], subpat[1], name)
- return name
-
- @property
- def warning_comment(self):
- """Return warning comment to be placed in header of generated Asciidoctor files"""
- return '// WARNING: DO NOT MODIFY! This file is automatically generated from the vk.xml registry'
-
- @property
- def file_suffix(self):
- """Return suffix of generated Asciidoctor files"""
- return '.txt'
-
- def api_name(self, spectype='api'):
- """Return API or specification name for citations in ref pages.ref
- pages should link to for
-
- spectype is the spec this refpage is for: 'api' is the Vulkan API
- Specification. Defaults to 'api'. If an unrecognized spectype is
- given, returns None.
- """
- if spectype == 'api' or spectype is None:
- return 'Vulkan'
- else:
- return None
-
- @property
- def api_prefix(self):
- """Return API token prefix"""
- return 'VK_'
-
- @property
- def write_contacts(self):
- """Return whether contact list should be written to extension appendices"""
- return True
-
- @property
- def write_refpage_include(self):
- """Return whether refpage include should be written to extension appendices"""
- return True
-
- @property
- def member_used_for_unique_vuid(self):
- """Return the member name used in the VUID-...-...-unique ID."""
- return self.structtype_member_name
-
- def is_externsync_command(self, protoname):
- """Returns True if the protoname element is an API command requiring
- external synchronization
- """
- return protoname is not None and 'vkCmd' in protoname
-
- def is_api_name(self, name):
- """Returns True if name is in the reserved API namespace.
- For Vulkan, these are names with a case-insensitive 'vk' prefix, or
- a 'PFN_vk' function pointer type prefix.
- """
- return name[0:2].lower() == 'vk' or name[0:6] == 'PFN_vk'
-
- def specURL(self, spectype='api'):
- """Return public registry URL which ref pages should link to for the
- current all-extensions HTML specification, so xrefs in the
- asciidoc source that aren't to ref pages can link into it
- instead. N.b. this may need to change on a per-refpage basis if
- there are multiple documents involved.
- """
- return 'https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html'
-
- @property
- def xml_api_name(self):
- """Return the name used in the default API XML registry for the default API"""
- return 'vulkan'
-
- @property
- def registry_path(self):
- """Return relpath to the default API XML registry in this project."""
- return 'xml/vk.xml'
-
- @property
- def specification_path(self):
- """Return relpath to the Asciidoctor specification sources in this project."""
- return '{generated}/meta'
-
- @property
- def special_use_section_anchor(self):
- """Return asciidoctor anchor name in the API Specification of the
- section describing extension special uses in detail."""
- return 'extendingvulkan-compatibility-specialuse'
-
- @property
- def extra_refpage_headers(self):
- """Return any extra text to add to refpage headers."""
- return 'include::{config}/attribs.txt[]'
-
- @property
- def extension_index_prefixes(self):
- """Return a list of extension prefixes used to group extension refpages."""
- return ['VK_KHR', 'VK_EXT', 'VK']
-
- @property
- def unified_flag_refpages(self):
- """Return True if Flags/FlagBits refpages are unified, False if
- they're separate.
- """
- return False
-
- @property
- def spec_reflow_path(self):
- """Return the path to the spec source folder to reflow"""
- return os.getcwd()
-
- @property
- def spec_no_reflow_dirs(self):
- """Return a set of directories not to automatically descend into
- when reflowing spec text
- """
- return ('scripts', 'style')
-
- @property
- def zero(self):
- return '`0`'
-
- def category_requires_validation(self, category):
- """Return True if the given type 'category' always requires validation.
-
- Overridden because Vulkan doesn't require "valid" text for basetype in the spec right now."""
- return category in CATEGORIES_REQUIRING_VALIDATION
-
- @property
- def should_skip_checking_codes(self):
- """Return True if more than the basic validation of return codes should
- be skipped for a command.
-
- Vulkan mostly relies on the validation layers rather than API
- builtin error checking, so these checks are not appropriate.
-
- For example, passing in a VkFormat parameter will not potentially
- generate a VK_ERROR_FORMAT_NOT_SUPPORTED code."""
-
- return True
-
- def extension_include_string(self, ext):
- """Return format string for include:: line for an extension appendix
- file. ext is an object with the following members:
- - name - extension string string
- - vendor - vendor portion of name
- - barename - remainder of name"""
-
- return 'include::{{appendices}}/{name}{suffix}[]'.format(
- name=ext.name, suffix=self.file_suffix)
-
- @property
- def refpage_generated_include_path(self):
- """Return path relative to the generated reference pages, to the
- generated API include files."""
- return "{generated}"
-
- def valid_flag_bit(self, bitpos):
- """Return True if bitpos is an allowed numeric bit position for
- an API flag bit.
-
- Vulkan uses 32 bit Vk*Flags types, and assumes C compilers may
- cause Vk*FlagBits values with bit 31 set to result in a 64 bit
- enumerated type, so disallows such flags."""
- return bitpos >= 0 and bitpos < 31
diff --git a/codegen/vulkan/scripts/xml_consistency.py b/codegen/vulkan/scripts/xml_consistency.py
deleted file mode 100755
index 36514531..00000000
--- a/codegen/vulkan/scripts/xml_consistency.py
+++ /dev/null
@@ -1,390 +0,0 @@
-#!/usr/bin/python3
-#
-# Copyright (c) 2019 Collabora, Ltd.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
-#
-# Purpose: This script checks some "business logic" in the XML registry.
-
-import re
-import sys
-from pathlib import Path
-
-from check_spec_links import VulkanEntityDatabase as OrigEntityDatabase
-from reg import Registry
-from spec_tools.consistency_tools import XMLChecker
-from spec_tools.util import findNamedElem, getElemName, getElemType
-from vkconventions import VulkanConventions as APIConventions
-
-# These are extensions which do not follow the usual naming conventions,
-# specifying the alternate convention they follow
-EXTENSION_ENUM_NAME_SPELLING_CHANGE = {
- 'VK_EXT_swapchain_colorspace': 'VK_EXT_SWAPCHAIN_COLOR_SPACE',
-}
-
-# These are extensions whose names *look* like they end in version numbers,
-# but don't
-EXTENSION_NAME_VERSION_EXCEPTIONS = (
- 'VK_AMD_gpu_shader_int16',
- 'VK_EXT_index_type_uint8',
- 'VK_EXT_shader_image_atomic_int64',
- 'VK_EXT_video_decode_h264',
- 'VK_EXT_video_decode_h265',
- 'VK_EXT_video_encode_h264',
- 'VK_EXT_video_encode_h265',
- 'VK_KHR_external_fence_win32',
- 'VK_KHR_external_memory_win32',
- 'VK_KHR_external_semaphore_win32',
- 'VK_KHR_shader_atomic_int64',
- 'VK_KHR_shader_float16_int8',
- 'VK_KHR_spirv_1_4',
- 'VK_NV_external_memory_win32',
- 'VK_RESERVED_do_not_use_146',
- 'VK_RESERVED_do_not_use_94',
-)
-
-# Exceptions to pointer parameter naming rules
-# Keyed by (entity name, type, name).
-CHECK_PARAM_POINTER_NAME_EXCEPTIONS = {
- ('vkGetDrmDisplayEXT', 'VkDisplayKHR', 'display') : None,
-}
-
-# Exceptions to pNext member requiring an optional attribute
-CHECK_MEMBER_PNEXT_OPTIONAL_EXCEPTIONS = (
- 'VkVideoEncodeInfoKHR',
-)
-
-def get_extension_commands(reg):
- extension_cmds = set()
- for ext in reg.extensions:
- for cmd in ext.findall("./require/command[@name]"):
- extension_cmds.add(cmd.get("name"))
- return extension_cmds
-
-
-def get_enum_value_names(reg, enum_type):
- names = set()
- result_elem = reg.groupdict[enum_type].elem
- for val in result_elem.findall("./enum[@name]"):
- names.add(val.get("name"))
- return names
-
-
-# Regular expression matching an extension name ending in a (possible) version number
-EXTNAME_RE = re.compile(r'(?P<base>(\w+[A-Za-z]))(?P<version>\d+)')
-
-DESTROY_PREFIX = "vkDestroy"
-TYPEENUM = "VkStructureType"
-
-SPECIFICATION_DIR = Path(__file__).parent.parent
-REVISION_RE = re.compile(r' *[*] Revision (?P<num>[1-9][0-9]*),.*')
-
-
-def get_extension_source(extname):
- fn = '{}.txt'.format(extname)
- return str(SPECIFICATION_DIR / 'appendices' / fn)
-
-
-class EntityDatabase(OrigEntityDatabase):
-
- # Override base class method to not exclude 'disabled' extensions
- def getExclusionSet(self):
- """Return a set of "support=" attribute strings that should not be included in the database.
-
- Called only during construction."""
-
- return set(())
-
- def makeRegistry(self):
- try:
- import lxml.etree as etree
- HAS_LXML = True
- except ImportError:
- HAS_LXML = False
- if not HAS_LXML:
- return super().makeRegistry()
-
- registryFile = str(SPECIFICATION_DIR / 'xml/vk.xml')
- registry = Registry()
- registry.filename = registryFile
- registry.loadElementTree(etree.parse(registryFile))
- return registry
-
-
-class Checker(XMLChecker):
- def __init__(self):
- manual_types_to_codes = {
- # These are hard-coded "manual" return codes:
- # the codes of the value (string, list, or tuple)
- # are available for a command if-and-only-if
- # the key type is passed as an input.
- "VkFormat": "VK_ERROR_FORMAT_NOT_SUPPORTED"
- }
- forward_only = {
- # Like the above, but these are only valid in the
- # "type implies return code" direction
- }
- reverse_only = {
- # like the above, but these are only valid in the
- # "return code implies type or its descendant" direction
- # "XrDuration": "XR_TIMEOUT_EXPIRED"
- }
- # Some return codes are related in that only one of a set
- # may be returned by a command
- # (eg. XR_ERROR_SESSION_RUNNING and XR_ERROR_SESSION_NOT_RUNNING)
- self.exclusive_return_code_sets = tuple(
- # set(("XR_ERROR_SESSION_NOT_RUNNING", "XR_ERROR_SESSION_RUNNING")),
- )
- # Map of extension number -> [ list of extension names ]
- self.extension_number_reservations = {
- }
-
- # This is used to report collisions.
- conventions = APIConventions()
- db = EntityDatabase()
-
- self.extension_cmds = get_extension_commands(db.registry)
- self.return_codes = get_enum_value_names(db.registry, 'VkResult')
- self.structure_types = get_enum_value_names(db.registry, TYPEENUM)
-
- # Dict of entity name to a list of messages to suppress. (Exclude any context data and "Warning:"/"Error:")
- # Keys are entity names, values are tuples or lists of message text to suppress.
- suppressions = {}
-
- # Initialize superclass
- super().__init__(entity_db=db, conventions=conventions,
- manual_types_to_codes=manual_types_to_codes,
- forward_only_types_to_codes=forward_only,
- reverse_only_types_to_codes=reverse_only,
- suppressions=suppressions)
-
- def check_command_return_codes_basic(self, name, info,
- successcodes, errorcodes):
- """Check a command's return codes for consistency.
-
- Called on every command."""
- # Check that all extension commands can return the code associated
- # with trying to use an extension that wasn't enabled.
- # if name in self.extension_cmds and UNSUPPORTED not in errorcodes:
- # self.record_error("Missing expected return code",
- # UNSUPPORTED,
- # "implied due to being an extension command")
-
- codes = successcodes.union(errorcodes)
-
- # Check that all return codes are recognized.
- unrecognized = codes - self.return_codes
- if unrecognized:
- self.record_error("Unrecognized return code(s):",
- unrecognized)
-
- elem = info.elem
- params = [(getElemName(elt), elt) for elt in elem.findall('param')]
-
- def is_count_output(name, elt):
- # Must end with Count or Size,
- # not be const,
- # and be a pointer (detected by naming convention)
- return (name.endswith('Count') or name.endswith('Size')) \
- and (elt.tail is None or 'const' not in elt.tail) \
- and (name.startswith('p'))
-
- countParams = [elt
- for name, elt in params
- if is_count_output(name, elt)]
- if countParams:
- assert(len(countParams) == 1)
- if 'VK_INCOMPLETE' not in successcodes:
- self.record_error(
- "Apparent enumeration of an array without VK_INCOMPLETE in successcodes.")
-
- elif 'VK_INCOMPLETE' in successcodes:
- self.record_error(
- "VK_INCOMPLETE in successcodes of command that is apparently not an array enumeration.")
-
- def check_param(self, param):
- """Check a member of a struct or a param of a function.
-
- Called from check_params."""
- super().check_param(param)
-
- if not self.is_api_type(param):
- return
-
- param_text = "".join(param.itertext())
- param_name = getElemName(param)
-
- # Make sure the number of leading "p" matches the pointer count.
- pointercount = param.find('type').tail
- if pointercount:
- pointercount = pointercount.count('*')
- if pointercount:
- prefix = 'p' * pointercount
- if not param_name.startswith(prefix):
- param_type = param.find('type').text
- message = "Apparently incorrect pointer-related name prefix for {} - expected it to start with '{}'".format(
- param_text, prefix)
- if (self.entity, param_type, param_name) in CHECK_PARAM_POINTER_NAME_EXCEPTIONS:
- self.record_warning('(Allowed exception)', message, elem=param)
- else:
- self.record_error(message, elem=param)
-
- # Make sure pNext members have optional="true" attributes
- if param_name == self.conventions.nextpointer_member_name:
- optional = param.get('optional')
- if optional is None or optional != 'true':
- message = '{}.pNext member is missing \'optional="true"\' attribute'.format(self.entity)
- if self.entity in CHECK_MEMBER_PNEXT_OPTIONAL_EXCEPTIONS:
- self.record_warning('(Allowed exception)', message, elem=param)
- else:
- self.record_error(message, elem=param)
-
- def check_type(self, name, info, category):
- """Check a type's XML data for consistency.
-
- Called from check."""
-
- elem = info.elem
- type_elts = [elt
- for elt in elem.findall("member")
- if getElemType(elt) == TYPEENUM]
- if category == 'struct' and type_elts:
- if len(type_elts) > 1:
- self.record_error(
- "Have more than one member of type", TYPEENUM)
- else:
- type_elt = type_elts[0]
- val = type_elt.get('values')
- if val and val not in self.structure_types:
- self.record_error("Unknown structure type constant", val)
-
- # Check the pointer chain member, if present.
- next_name = self.conventions.nextpointer_member_name
- next_member = findNamedElem(info.elem.findall('member'), next_name)
- if next_member is not None:
- # Ensure that the 'optional' attribute is set to 'true'
- optional = next_member.get('optional')
- if optional is None or optional != 'true':
- message = '{}.{} member is missing \'optional="true"\' attribute'.format(name, next_name)
- if name in CHECK_MEMBER_PNEXT_OPTIONAL_EXCEPTIONS:
- self.record_warning('(Allowed exception)', message)
- else:
- self.record_error(message)
-
- elif category == "bitmask":
- if 'Flags' in name:
- expected_require = name.replace('Flags', 'FlagBits')
- require = info.elem.get('require')
- if require is not None and expected_require != require:
- self.record_error("Unexpected require attribute value:",
- "got", require,
- "but expected", expected_require)
- super().check_type(name, info, category)
-
- def check_extension(self, name, info):
- """Check an extension's XML data for consistency.
-
- Called from check."""
- elem = info.elem
- enums = elem.findall('./require/enum[@name]')
-
- # Look for other extensions using that number
- # Keep track of this extension number reservation
- ext_number = elem.get('number')
- if ext_number in self.extension_number_reservations:
- conflicts = self.extension_number_reservations[ext_number]
- self.record_error('Extension number {} has more than one reservation: {}, {}'.format(
- ext_number, name, ', '.join(conflicts)))
- self.extension_number_reservations[ext_number].append(name)
- else:
- self.extension_number_reservations[ext_number] = [ name ]
-
- # If extension name is not on the exception list and matches the
- # versioned-extension pattern, map the extension name to the version
- # name with the version as a separate word. Otherwise just map it to
- # the upper-case version of the extension name.
-
- matches = EXTNAME_RE.fullmatch(name)
- ext_versioned_name = False
- if name in EXTENSION_ENUM_NAME_SPELLING_CHANGE:
- ext_enum_name = EXTENSION_ENUM_NAME_SPELLING_CHANGE.get(name)
- elif matches is None or name in EXTENSION_NAME_VERSION_EXCEPTIONS:
- # This is the usual case, either a name that doesn't look
- # versioned, or one that does but is on the exception list.
- ext_enum_name = name.upper()
- else:
- # This is a versioned extension name.
- # Treat the version number as a separate word.
- base = matches.group('base')
- version = matches.group('version')
- ext_enum_name = base.upper() + '_' + version
- # Keep track of this case
- ext_versioned_name = True
-
- # Look for the expected SPEC_VERSION token name
- version_name = "{}_SPEC_VERSION".format(ext_enum_name)
- version_elem = findNamedElem(enums, version_name)
-
- if version_elem is None:
- # Did not find a SPEC_VERSION enum matching the extension name
- if ext_versioned_name:
- suffix = '\n\
- Make sure that trailing version numbers in extension names are treated\n\
- as separate words in extension enumerant names. If this is an extension\n\
- whose name ends in a number which is not a version, such as "...h264"\n\
- or "...int16", add it to EXTENSION_NAME_VERSION_EXCEPTIONS in\n\
- scripts/xml_consistency.py.'
- else:
- suffix = ''
- self.record_error('Missing version enum {}{}'.format(version_name, suffix))
- elif info.elem.get('supported') == self.conventions.xml_api_name:
- # Skip unsupported / disabled extensions for these checks
-
- fn = get_extension_source(name)
- revisions = []
- with open(fn, 'r', encoding='utf-8') as fp:
- for line in fp:
- line = line.rstrip()
- match = REVISION_RE.match(line)
- if match:
- revisions.append(int(match.group('num')))
- ver_from_xml = version_elem.get('value')
- if revisions:
- ver_from_text = str(max(revisions))
- if ver_from_xml != ver_from_text:
- self.record_error("Version enum mismatch: spec text indicates", ver_from_text,
- "but XML says", ver_from_xml)
- else:
- if ver_from_xml == '1':
- self.record_warning(
- "Cannot find version history in spec text - make sure it has lines starting exactly like '* Revision 1, ....'",
- filename=fn)
- else:
- self.record_warning("Cannot find version history in spec text, but XML reports a non-1 version number", ver_from_xml,
- " - make sure the spec text has lines starting exactly like '* Revision 1, ....'",
- filename=fn)
-
- name_define = "{}_EXTENSION_NAME".format(ext_enum_name)
- name_elem = findNamedElem(enums, name_define)
- if name_elem is None:
- self.record_error("Missing name enum", name_define)
- else:
- # Note: etree handles the XML entities here and turns &quot; back into "
- expected_name = '"{}"'.format(name)
- name_val = name_elem.get('value')
- if name_val != expected_name:
- self.record_error("Incorrect name enum: expected", expected_name,
- "got", name_val)
-
- super().check_extension(name, elem)
-
-
-if __name__ == "__main__":
-
- ckr = Checker()
- ckr.check()
-
- if ckr.fail:
- sys.exit(1)