1e5c31af7Sopenharmony_ci#!/usr/bin/python3
2e5c31af7Sopenharmony_ci
3e5c31af7Sopenharmony_ci# Copyright 2022-2024 The Khronos Group Inc.
4e5c31af7Sopenharmony_ci# Copyright 2003-2019 Paul McGuire
5e5c31af7Sopenharmony_ci# SPDX-License-Identifier: MIT
6e5c31af7Sopenharmony_ci
7e5c31af7Sopenharmony_ci# apirequirements.py - parse 'depends' expressions in API XML
8e5c31af7Sopenharmony_ci# Supported methods:
9e5c31af7Sopenharmony_ci#   dependency - the expression string
10e5c31af7Sopenharmony_ci#
11e5c31af7Sopenharmony_ci# evaluateDependency(dependency, isSupported) evaluates the expression,
12e5c31af7Sopenharmony_ci# returning a boolean result. isSupported takes an extension or version name
13e5c31af7Sopenharmony_ci# string and returns a boolean.
14e5c31af7Sopenharmony_ci#
15e5c31af7Sopenharmony_ci# dependencyLanguage(dependency) returns an English string equivalent
16e5c31af7Sopenharmony_ci# to the expression, suitable for header file comments.
17e5c31af7Sopenharmony_ci#
18e5c31af7Sopenharmony_ci# dependencyNames(dependency) returns a set of the extension and
19e5c31af7Sopenharmony_ci# version names in the expression.
20e5c31af7Sopenharmony_ci#
21e5c31af7Sopenharmony_ci# dependencyMarkup(dependency) returns a string containing asciidoctor
22e5c31af7Sopenharmony_ci# markup for English equivalent to the expression, suitable for extension
23e5c31af7Sopenharmony_ci# appendices.
24e5c31af7Sopenharmony_ci#
25e5c31af7Sopenharmony_ci# All may throw a ParseException if the expression cannot be parsed or is
26e5c31af7Sopenharmony_ci# not completely consumed by parsing.
27e5c31af7Sopenharmony_ci
28e5c31af7Sopenharmony_ci# Supported expressions at present:
29e5c31af7Sopenharmony_ci#   - extension names
30e5c31af7Sopenharmony_ci#   - '+' as AND connector
31e5c31af7Sopenharmony_ci#   - ',' as OR connector
32e5c31af7Sopenharmony_ci#   - parenthesization for grouping
33e5c31af7Sopenharmony_ci
34e5c31af7Sopenharmony_ci# Based on https://github.com/pyparsing/pyparsing/blob/master/examples/fourFn.py
35e5c31af7Sopenharmony_ci
36e5c31af7Sopenharmony_cifrom pyparsing import (
37e5c31af7Sopenharmony_ci    Literal,
38e5c31af7Sopenharmony_ci    Word,
39e5c31af7Sopenharmony_ci    Group,
40e5c31af7Sopenharmony_ci    Forward,
41e5c31af7Sopenharmony_ci    alphas,
42e5c31af7Sopenharmony_ci    alphanums,
43e5c31af7Sopenharmony_ci    Regex,
44e5c31af7Sopenharmony_ci    ParseException,
45e5c31af7Sopenharmony_ci    CaselessKeyword,
46e5c31af7Sopenharmony_ci    Suppress,
47e5c31af7Sopenharmony_ci    delimitedList,
48e5c31af7Sopenharmony_ci    infixNotation,
49e5c31af7Sopenharmony_ci)
50e5c31af7Sopenharmony_ciimport math
51e5c31af7Sopenharmony_ciimport operator
52e5c31af7Sopenharmony_ciimport pyparsing as pp
53e5c31af7Sopenharmony_ciimport re
54e5c31af7Sopenharmony_ci
55e5c31af7Sopenharmony_cifrom apiconventions import APIConventions as APIConventions
56e5c31af7Sopenharmony_ciconventions = APIConventions()
57e5c31af7Sopenharmony_ci
58e5c31af7Sopenharmony_cidef markupPassthrough(name):
59e5c31af7Sopenharmony_ci    """Pass a name (leaf or operator) through without applying markup"""
60e5c31af7Sopenharmony_ci    return name
61e5c31af7Sopenharmony_ci
62e5c31af7Sopenharmony_cidef leafMarkupAsciidoc(name):
63e5c31af7Sopenharmony_ci    """Markup a leaf name as an asciidoc link to an API version or extension
64e5c31af7Sopenharmony_ci       anchor.
65e5c31af7Sopenharmony_ci
66e5c31af7Sopenharmony_ci       - name - version or extension name"""
67e5c31af7Sopenharmony_ci
68e5c31af7Sopenharmony_ci    return conventions.formatVersionOrExtension(name)
69e5c31af7Sopenharmony_ci
70e5c31af7Sopenharmony_cidef leafMarkupC(name):
71e5c31af7Sopenharmony_ci    """Markup a leaf name as a C expression, using conventions of the
72e5c31af7Sopenharmony_ci       Vulkan Validation Layers
73e5c31af7Sopenharmony_ci
74e5c31af7Sopenharmony_ci       - name - version or extension name"""
75e5c31af7Sopenharmony_ci
76e5c31af7Sopenharmony_ci    (apivariant, major, minor) = apiVersionNameMatch(name)
77e5c31af7Sopenharmony_ci
78e5c31af7Sopenharmony_ci    if apivariant is not None:
79e5c31af7Sopenharmony_ci        return name
80e5c31af7Sopenharmony_ci    else:
81e5c31af7Sopenharmony_ci        return f'ext.{name}'
82e5c31af7Sopenharmony_ci
83e5c31af7Sopenharmony_ciopMarkupAsciidocMap = { '+' : 'and', ',' : 'or' }
84e5c31af7Sopenharmony_ci
85e5c31af7Sopenharmony_cidef opMarkupAsciidoc(op):
86e5c31af7Sopenharmony_ci    """Markup a operator as an asciidoc spec markup equivalent
87e5c31af7Sopenharmony_ci
88e5c31af7Sopenharmony_ci       - op - operator ('+' or ',')"""
89e5c31af7Sopenharmony_ci
90e5c31af7Sopenharmony_ci    return opMarkupAsciidocMap[op]
91e5c31af7Sopenharmony_ci
92e5c31af7Sopenharmony_ciopMarkupCMap = { '+' : '&&', ',' : '||' }
93e5c31af7Sopenharmony_ci
94e5c31af7Sopenharmony_cidef opMarkupC(op):
95e5c31af7Sopenharmony_ci    """Markup a operator as an C language equivalent
96e5c31af7Sopenharmony_ci
97e5c31af7Sopenharmony_ci       - op - operator ('+' or ',')"""
98e5c31af7Sopenharmony_ci
99e5c31af7Sopenharmony_ci    return opMarkupCMap[op]
100e5c31af7Sopenharmony_ci
101e5c31af7Sopenharmony_ci
102e5c31af7Sopenharmony_ci# Unfortunately global to be used in pyparsing
103e5c31af7Sopenharmony_ciexprStack = []
104e5c31af7Sopenharmony_ci
105e5c31af7Sopenharmony_cidef push_first(toks):
106e5c31af7Sopenharmony_ci    """Push a token on the global stack
107e5c31af7Sopenharmony_ci
108e5c31af7Sopenharmony_ci       - toks - first element is the token to push"""
109e5c31af7Sopenharmony_ci
110e5c31af7Sopenharmony_ci    exprStack.append(toks[0])
111e5c31af7Sopenharmony_ci
112e5c31af7Sopenharmony_ci# An identifier (version or extension name)
113e5c31af7Sopenharmony_cidependencyIdent = Word(alphanums + '_')
114e5c31af7Sopenharmony_ci
115e5c31af7Sopenharmony_ci# Infix expression for depends expressions
116e5c31af7Sopenharmony_cidependencyExpr = pp.infixNotation(dependencyIdent,
117e5c31af7Sopenharmony_ci    [ (pp.oneOf(', +'), 2, pp.opAssoc.LEFT), ])
118e5c31af7Sopenharmony_ci
119e5c31af7Sopenharmony_ci# BNF grammar for depends expressions
120e5c31af7Sopenharmony_ci_bnf = None
121e5c31af7Sopenharmony_cidef dependencyBNF():
122e5c31af7Sopenharmony_ci    """
123e5c31af7Sopenharmony_ci    boolop  :: '+' | ','
124e5c31af7Sopenharmony_ci    extname :: Char(alphas)
125e5c31af7Sopenharmony_ci    atom    :: extname | '(' expr ')'
126e5c31af7Sopenharmony_ci    expr    :: atom [ boolop atom ]*
127e5c31af7Sopenharmony_ci    """
128e5c31af7Sopenharmony_ci    global _bnf
129e5c31af7Sopenharmony_ci    if _bnf is None:
130e5c31af7Sopenharmony_ci        and_, or_ = map(Literal, '+,')
131e5c31af7Sopenharmony_ci        lpar, rpar = map(Suppress, '()')
132e5c31af7Sopenharmony_ci        boolop = and_ | or_
133e5c31af7Sopenharmony_ci
134e5c31af7Sopenharmony_ci        expr = Forward()
135e5c31af7Sopenharmony_ci        expr_list = delimitedList(Group(expr))
136e5c31af7Sopenharmony_ci        atom = (
137e5c31af7Sopenharmony_ci            boolop[...]
138e5c31af7Sopenharmony_ci            + (
139e5c31af7Sopenharmony_ci                (dependencyIdent).setParseAction(push_first)
140e5c31af7Sopenharmony_ci                | Group(lpar + expr + rpar)
141e5c31af7Sopenharmony_ci            )
142e5c31af7Sopenharmony_ci        )
143e5c31af7Sopenharmony_ci
144e5c31af7Sopenharmony_ci        expr <<= atom + (boolop + atom).setParseAction(push_first)[...]
145e5c31af7Sopenharmony_ci        _bnf = expr
146e5c31af7Sopenharmony_ci    return _bnf
147e5c31af7Sopenharmony_ci
148e5c31af7Sopenharmony_ci
149e5c31af7Sopenharmony_ci# map operator symbols to corresponding arithmetic operations
150e5c31af7Sopenharmony_ci_opn = {
151e5c31af7Sopenharmony_ci    '+': operator.and_,
152e5c31af7Sopenharmony_ci    ',': operator.or_,
153e5c31af7Sopenharmony_ci}
154e5c31af7Sopenharmony_ci
155e5c31af7Sopenharmony_cidef evaluateStack(stack, isSupported):
156e5c31af7Sopenharmony_ci    """Evaluate an expression stack, returning a boolean result.
157e5c31af7Sopenharmony_ci
158e5c31af7Sopenharmony_ci     - stack - the stack
159e5c31af7Sopenharmony_ci     - isSupported - function taking a version or extension name string and
160e5c31af7Sopenharmony_ci       returning True or False if that name is supported or not."""
161e5c31af7Sopenharmony_ci
162e5c31af7Sopenharmony_ci    op, num_args = stack.pop(), 0
163e5c31af7Sopenharmony_ci    if isinstance(op, tuple):
164e5c31af7Sopenharmony_ci        op, num_args = op
165e5c31af7Sopenharmony_ci
166e5c31af7Sopenharmony_ci    if op in '+,':
167e5c31af7Sopenharmony_ci        # Note: operands are pushed onto the stack in reverse order
168e5c31af7Sopenharmony_ci        op2 = evaluateStack(stack, isSupported)
169e5c31af7Sopenharmony_ci        op1 = evaluateStack(stack, isSupported)
170e5c31af7Sopenharmony_ci        return _opn[op](op1, op2)
171e5c31af7Sopenharmony_ci    elif op[0].isalpha():
172e5c31af7Sopenharmony_ci        return isSupported(op)
173e5c31af7Sopenharmony_ci    else:
174e5c31af7Sopenharmony_ci        raise Exception(f'invalid op: {op}')
175e5c31af7Sopenharmony_ci
176e5c31af7Sopenharmony_cidef evaluateDependency(dependency, isSupported):
177e5c31af7Sopenharmony_ci    """Evaluate a dependency expression, returning a boolean result.
178e5c31af7Sopenharmony_ci
179e5c31af7Sopenharmony_ci     - dependency - the expression
180e5c31af7Sopenharmony_ci     - isSupported - function taking a version or extension name string and
181e5c31af7Sopenharmony_ci       returning True or False if that name is supported or not."""
182e5c31af7Sopenharmony_ci
183e5c31af7Sopenharmony_ci    global exprStack
184e5c31af7Sopenharmony_ci    exprStack = []
185e5c31af7Sopenharmony_ci    results = dependencyBNF().parseString(dependency, parseAll=True)
186e5c31af7Sopenharmony_ci    val = evaluateStack(exprStack[:], isSupported)
187e5c31af7Sopenharmony_ci    return val
188e5c31af7Sopenharmony_ci
189e5c31af7Sopenharmony_cidef evalDependencyLanguage(stack, leafMarkup, opMarkup, parenthesize, root):
190e5c31af7Sopenharmony_ci    """Evaluate an expression stack, returning an English equivalent
191e5c31af7Sopenharmony_ci
192e5c31af7Sopenharmony_ci     - stack - the stack
193e5c31af7Sopenharmony_ci     - leafMarkup, opMarkup, parenthesize - same as dependencyLanguage
194e5c31af7Sopenharmony_ci     - root - True only if this is the outer (root) expression level"""
195e5c31af7Sopenharmony_ci
196e5c31af7Sopenharmony_ci    op, num_args = stack.pop(), 0
197e5c31af7Sopenharmony_ci    if isinstance(op, tuple):
198e5c31af7Sopenharmony_ci        op, num_args = op
199e5c31af7Sopenharmony_ci    if op in '+,':
200e5c31af7Sopenharmony_ci        # Could parenthesize, not needed yet
201e5c31af7Sopenharmony_ci        rhs = evalDependencyLanguage(stack, leafMarkup, opMarkup, parenthesize, root = False)
202e5c31af7Sopenharmony_ci        opname = opMarkup(op)
203e5c31af7Sopenharmony_ci        lhs = evalDependencyLanguage(stack, leafMarkup, opMarkup, parenthesize, root = False)
204e5c31af7Sopenharmony_ci        if parenthesize and not root:
205e5c31af7Sopenharmony_ci            return f'({lhs} {opname} {rhs})'
206e5c31af7Sopenharmony_ci        else:
207e5c31af7Sopenharmony_ci            return f'{lhs} {opname} {rhs}'
208e5c31af7Sopenharmony_ci    elif op[0].isalpha():
209e5c31af7Sopenharmony_ci        # This is an extension or feature name
210e5c31af7Sopenharmony_ci        return leafMarkup(op)
211e5c31af7Sopenharmony_ci    else:
212e5c31af7Sopenharmony_ci        raise Exception(f'invalid op: {op}')
213e5c31af7Sopenharmony_ci
214e5c31af7Sopenharmony_cidef dependencyLanguage(dependency, leafMarkup, opMarkup, parenthesize):
215e5c31af7Sopenharmony_ci    """Return an API dependency expression translated to a form suitable for
216e5c31af7Sopenharmony_ci       asciidoctor conditionals or header file comments.
217e5c31af7Sopenharmony_ci
218e5c31af7Sopenharmony_ci     - dependency - the expression
219e5c31af7Sopenharmony_ci     - leafMarkup - function taking an extension / version name and
220e5c31af7Sopenharmony_ci                    returning an equivalent marked up version
221e5c31af7Sopenharmony_ci     - opMarkup - function taking an operator ('+' / ',') name name and
222e5c31af7Sopenharmony_ci                  returning an equivalent marked up version
223e5c31af7Sopenharmony_ci     - parenthesize - True if parentheses should be used in the resulting
224e5c31af7Sopenharmony_ci                      expression, False otherwise"""
225e5c31af7Sopenharmony_ci
226e5c31af7Sopenharmony_ci    global exprStack
227e5c31af7Sopenharmony_ci    exprStack = []
228e5c31af7Sopenharmony_ci    results = dependencyBNF().parseString(dependency, parseAll=True)
229e5c31af7Sopenharmony_ci    return evalDependencyLanguage(exprStack, leafMarkup, opMarkup, parenthesize, root = True)
230e5c31af7Sopenharmony_ci
231e5c31af7Sopenharmony_ci# aka specmacros = False
232e5c31af7Sopenharmony_cidef dependencyLanguageComment(dependency):
233e5c31af7Sopenharmony_ci    """Return dependency expression translated to a form suitable for
234e5c31af7Sopenharmony_ci       comments in headers of emitted C code, as used by the
235e5c31af7Sopenharmony_ci       docgenerator."""
236e5c31af7Sopenharmony_ci    return dependencyLanguage(dependency, leafMarkup = markupPassthrough, opMarkup = opMarkupAsciidoc, parenthesize = True)
237e5c31af7Sopenharmony_ci
238e5c31af7Sopenharmony_ci# aka specmacros = True
239e5c31af7Sopenharmony_cidef dependencyLanguageSpecMacros(dependency):
240e5c31af7Sopenharmony_ci    """Return dependency expression translated to a form suitable for
241e5c31af7Sopenharmony_ci       comments in headers of emitted C code, as used by the
242e5c31af7Sopenharmony_ci       interfacegenerator."""
243e5c31af7Sopenharmony_ci    return dependencyLanguage(dependency, leafMarkup = leafMarkupAsciidoc, opMarkup = opMarkupAsciidoc, parenthesize = False)
244e5c31af7Sopenharmony_ci
245e5c31af7Sopenharmony_cidef dependencyLanguageC(dependency):
246e5c31af7Sopenharmony_ci    """Return dependency expression translated to a form suitable for
247e5c31af7Sopenharmony_ci       use in C expressions"""
248e5c31af7Sopenharmony_ci    return dependencyLanguage(dependency, leafMarkup = leafMarkupC, opMarkup = opMarkupC, parenthesize = True)
249e5c31af7Sopenharmony_ci
250e5c31af7Sopenharmony_cidef evalDependencyNames(stack):
251e5c31af7Sopenharmony_ci    """Evaluate an expression stack, returning the set of extension and
252e5c31af7Sopenharmony_ci       feature names used in the expression.
253e5c31af7Sopenharmony_ci
254e5c31af7Sopenharmony_ci     - stack - the stack"""
255e5c31af7Sopenharmony_ci
256e5c31af7Sopenharmony_ci    op, num_args = stack.pop(), 0
257e5c31af7Sopenharmony_ci    if isinstance(op, tuple):
258e5c31af7Sopenharmony_ci        op, num_args = op
259e5c31af7Sopenharmony_ci    if op in '+,':
260e5c31af7Sopenharmony_ci        # Do not evaluate the operation. We only care about the names.
261e5c31af7Sopenharmony_ci        return evalDependencyNames(stack) | evalDependencyNames(stack)
262e5c31af7Sopenharmony_ci    elif op[0].isalpha():
263e5c31af7Sopenharmony_ci        return { op }
264e5c31af7Sopenharmony_ci    else:
265e5c31af7Sopenharmony_ci        raise Exception(f'invalid op: {op}')
266e5c31af7Sopenharmony_ci
267e5c31af7Sopenharmony_cidef dependencyNames(dependency):
268e5c31af7Sopenharmony_ci    """Return a set of the extension and version names in an API dependency
269e5c31af7Sopenharmony_ci       expression. Used when determining transitive dependencies for spec
270e5c31af7Sopenharmony_ci       generation with specific extensions included.
271e5c31af7Sopenharmony_ci
272e5c31af7Sopenharmony_ci     - dependency - the expression"""
273e5c31af7Sopenharmony_ci
274e5c31af7Sopenharmony_ci    global exprStack
275e5c31af7Sopenharmony_ci    exprStack = []
276e5c31af7Sopenharmony_ci    results = dependencyBNF().parseString(dependency, parseAll=True)
277e5c31af7Sopenharmony_ci    # print(f'names(): stack = {exprStack}')
278e5c31af7Sopenharmony_ci    return evalDependencyNames(exprStack)
279e5c31af7Sopenharmony_ci
280e5c31af7Sopenharmony_cidef markupTraverse(expr, level = 0, root = True):
281e5c31af7Sopenharmony_ci    """Recursively process a dependency in infix form, transforming it into
282e5c31af7Sopenharmony_ci       asciidoctor markup with expression nesting indicated by indentation
283e5c31af7Sopenharmony_ci       level.
284e5c31af7Sopenharmony_ci
285e5c31af7Sopenharmony_ci       - expr - expression to process
286e5c31af7Sopenharmony_ci       - level - indentation level to render expression at
287e5c31af7Sopenharmony_ci       - root - True only on initial call"""
288e5c31af7Sopenharmony_ci
289e5c31af7Sopenharmony_ci    if level > 0:
290e5c31af7Sopenharmony_ci        prefix = '{nbsp}{nbsp}' * level * 2 + ' '
291e5c31af7Sopenharmony_ci    else:
292e5c31af7Sopenharmony_ci        prefix = ''
293e5c31af7Sopenharmony_ci    str = ''
294e5c31af7Sopenharmony_ci
295e5c31af7Sopenharmony_ci    for elem in expr:
296e5c31af7Sopenharmony_ci        if isinstance(elem, pp.ParseResults):
297e5c31af7Sopenharmony_ci            if not root:
298e5c31af7Sopenharmony_ci                nextlevel = level + 1
299e5c31af7Sopenharmony_ci            else:
300e5c31af7Sopenharmony_ci                # Do not indent the outer expression
301e5c31af7Sopenharmony_ci                nextlevel = level
302e5c31af7Sopenharmony_ci
303e5c31af7Sopenharmony_ci            str = str + markupTraverse(elem, level = nextlevel, root = False)
304e5c31af7Sopenharmony_ci        elif elem in ('+', ','):
305e5c31af7Sopenharmony_ci            str = str + f'{prefix}{opMarkupAsciidoc(elem)} +\n'
306e5c31af7Sopenharmony_ci        else:
307e5c31af7Sopenharmony_ci            str = str + f'{prefix}{leafMarkupAsciidoc(elem)} +\n'
308e5c31af7Sopenharmony_ci
309e5c31af7Sopenharmony_ci    return str
310e5c31af7Sopenharmony_ci
311e5c31af7Sopenharmony_cidef dependencyMarkup(dependency):
312e5c31af7Sopenharmony_ci    """Return asciidoctor markup for a human-readable equivalent of an API
313e5c31af7Sopenharmony_ci       dependency expression, suitable for use in extension appendix
314e5c31af7Sopenharmony_ci       metadata.
315e5c31af7Sopenharmony_ci
316e5c31af7Sopenharmony_ci     - dependency - the expression"""
317e5c31af7Sopenharmony_ci
318e5c31af7Sopenharmony_ci    parsed = dependencyExpr.parseString(dependency)
319e5c31af7Sopenharmony_ci    return markupTraverse(parsed)
320e5c31af7Sopenharmony_ci
321e5c31af7Sopenharmony_ciif __name__ == "__main__":
322e5c31af7Sopenharmony_ci    for str in [ 'VK_VERSION_1_0', 'cl_khr_extension_name', 'XR_VERSION_3_2', 'CL_VERSION_1_0' ]:
323e5c31af7Sopenharmony_ci        print(f'{str} -> {conventions.formatVersionOrExtension(str)}')
324e5c31af7Sopenharmony_ci    import sys
325e5c31af7Sopenharmony_ci    sys.exit(0)
326e5c31af7Sopenharmony_ci
327e5c31af7Sopenharmony_ci    termdict = {
328e5c31af7Sopenharmony_ci        'VK_VERSION_1_1' : True,
329e5c31af7Sopenharmony_ci        'false' : False,
330e5c31af7Sopenharmony_ci        'true' : True,
331e5c31af7Sopenharmony_ci    }
332e5c31af7Sopenharmony_ci    termSupported = lambda name: name in termdict and termdict[name]
333e5c31af7Sopenharmony_ci
334e5c31af7Sopenharmony_ci    def test(dependency, expected):
335e5c31af7Sopenharmony_ci        val = False
336e5c31af7Sopenharmony_ci        try:
337e5c31af7Sopenharmony_ci            val = evaluateDependency(dependency, termSupported)
338e5c31af7Sopenharmony_ci        except ParseException as pe:
339e5c31af7Sopenharmony_ci            print(dependency, f'failed parse: {dependency}')
340e5c31af7Sopenharmony_ci        except Exception as e:
341e5c31af7Sopenharmony_ci            print(dependency, f'failed eval: {dependency}')
342e5c31af7Sopenharmony_ci
343e5c31af7Sopenharmony_ci        if val == expected:
344e5c31af7Sopenharmony_ci            True
345e5c31af7Sopenharmony_ci            # print(f'{dependency} = {val} (as expected)')
346e5c31af7Sopenharmony_ci        else:
347e5c31af7Sopenharmony_ci            print(f'{dependency} ERROR: {val} != {expected}')
348e5c31af7Sopenharmony_ci
349e5c31af7Sopenharmony_ci    # Verify expressions are evaluated left-to-right
350e5c31af7Sopenharmony_ci
351e5c31af7Sopenharmony_ci    test('false,false+false', False)
352e5c31af7Sopenharmony_ci    test('false,false+true', False)
353e5c31af7Sopenharmony_ci    test('false,true+false', False)
354e5c31af7Sopenharmony_ci    test('false,true+true', True)
355e5c31af7Sopenharmony_ci    test('true,false+false', False)
356e5c31af7Sopenharmony_ci    test('true,false+true', True)
357e5c31af7Sopenharmony_ci    test('true,true+false', False)
358e5c31af7Sopenharmony_ci    test('true,true+true', True)
359e5c31af7Sopenharmony_ci
360e5c31af7Sopenharmony_ci    test('false,(false+false)', False)
361e5c31af7Sopenharmony_ci    test('false,(false+true)', False)
362e5c31af7Sopenharmony_ci    test('false,(true+false)', False)
363e5c31af7Sopenharmony_ci    test('false,(true+true)', True)
364e5c31af7Sopenharmony_ci    test('true,(false+false)', True)
365e5c31af7Sopenharmony_ci    test('true,(false+true)', True)
366e5c31af7Sopenharmony_ci    test('true,(true+false)', True)
367e5c31af7Sopenharmony_ci    test('true,(true+true)', True)
368e5c31af7Sopenharmony_ci
369e5c31af7Sopenharmony_ci
370e5c31af7Sopenharmony_ci    test('false+false,false', False)
371e5c31af7Sopenharmony_ci    test('false+false,true', True)
372e5c31af7Sopenharmony_ci    test('false+true,false', False)
373e5c31af7Sopenharmony_ci    test('false+true,true', True)
374e5c31af7Sopenharmony_ci    test('true+false,false', False)
375e5c31af7Sopenharmony_ci    test('true+false,true', True)
376e5c31af7Sopenharmony_ci    test('true+true,false', True)
377e5c31af7Sopenharmony_ci    test('true+true,true', True)
378e5c31af7Sopenharmony_ci
379e5c31af7Sopenharmony_ci    test('false+(false,false)', False)
380e5c31af7Sopenharmony_ci    test('false+(false,true)', False)
381e5c31af7Sopenharmony_ci    test('false+(true,false)', False)
382e5c31af7Sopenharmony_ci    test('false+(true,true)', False)
383e5c31af7Sopenharmony_ci    test('true+(false,false)', False)
384e5c31af7Sopenharmony_ci    test('true+(false,true)', True)
385e5c31af7Sopenharmony_ci    test('true+(true,false)', True)
386e5c31af7Sopenharmony_ci    test('true+(true,true)', True)
387e5c31af7Sopenharmony_ci
388e5c31af7Sopenharmony_ci    # Check formatting
389e5c31af7Sopenharmony_ci    for dependency in [
390e5c31af7Sopenharmony_ci        #'true',
391e5c31af7Sopenharmony_ci        #'true+true+false',
392e5c31af7Sopenharmony_ci        'true+false',
393e5c31af7Sopenharmony_ci        'true+(true+false),(false,true)',
394e5c31af7Sopenharmony_ci        #'true+((true+false),(false,true))',
395e5c31af7Sopenharmony_ci        'VK_VERSION_1_0+VK_KHR_display',
396e5c31af7Sopenharmony_ci        #'VK_VERSION_1_1+(true,false)',
397e5c31af7Sopenharmony_ci    ]:
398e5c31af7Sopenharmony_ci        print(f'expr = {dependency}\n{dependencyMarkup(dependency)}')
399e5c31af7Sopenharmony_ci        print(f'  spec language = {dependencyLanguageSpecMacros(dependency)}')
400e5c31af7Sopenharmony_ci        print(f'  comment language = {dependencyLanguageComment(dependency)}')
401e5c31af7Sopenharmony_ci        print(f'  C language = {dependencyLanguageC(dependency)}')
402e5c31af7Sopenharmony_ci        print(f'  names = {dependencyNames(dependency)}')
403e5c31af7Sopenharmony_ci        print(f'  value = {evaluateDependency(dependency, termSupported)}')
404