• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python3 -i
2#
3# Copyright 2013-2021 The Khronos Group Inc.
4#
5# SPDX-License-Identifier: Apache-2.0
6"""Utilities for working with attributes of the XML registry."""
7
8import re
9
10_PARAM_REF_NAME_RE = re.compile(
11    r"(?P<name>[\w]+)(?P<brackets>\[\])?(?P<delim>\.|::|->)?")
12
13
14def _split_param_ref(val):
15    return [name for name, _, _ in _PARAM_REF_NAME_RE.findall(val)]
16
17
18def _human_readable_deref(val, make_param_name=None):
19    """Turn the "name[].member[]" notation into plain English."""
20    parts = []
21    matches = _PARAM_REF_NAME_RE.findall(val)
22    for name, brackets, delim in reversed(matches):
23        if make_param_name:
24            name = make_param_name(name)
25        if delim:
26            parts.append('member of')
27        if brackets:
28            parts.append('each element of')
29        parts.append('the')
30        parts.append(name)
31    parts.append('parameter')
32    return ' '.join(parts)
33
34
35class LengthEntry:
36    """An entry in a (comma-separated) len attribute"""
37    NULL_TERMINATED_STRING = 'null-terminated'
38    MATH_STRING = 'latexmath:'
39
40    def __init__(self, val):
41        self.full_reference = val
42        self.other_param_name = None
43        self.null_terminated = False
44        self.number = None
45        self.math = None
46        self.param_ref_parts = None
47        if val == LengthEntry.NULL_TERMINATED_STRING:
48            self.null_terminated = True
49            return
50
51        if val.startswith(LengthEntry.MATH_STRING):
52            self.math = val.replace(LengthEntry.MATH_STRING, '')[1:-1]
53            return
54
55        if val.isdigit():
56            self.number = int(val)
57            return
58
59        # Must be another param name.
60        self.param_ref_parts = _split_param_ref(val)
61        self.other_param_name = self.param_ref_parts[0]
62
63    def __str__(self):
64        return self.full_reference
65
66    def get_human_readable(self, make_param_name=None):
67        assert(self.other_param_name)
68        return _human_readable_deref(self.full_reference, make_param_name=make_param_name)
69
70    def __repr__(self):
71        "Formats an object for repr(), debugger display, etc."
72        return 'spec_tools.attributes.LengthEntry("{}")'.format(self.full_reference)
73
74    @staticmethod
75    def parse_len_from_param(param):
76        """Get a list of LengthEntry."""
77        len_str = param.get('len')
78        if len_str is None:
79            return None
80        return [LengthEntry(elt) for elt in len_str.split(',')]
81
82
83class ExternSyncEntry:
84    """An entry in a (comma-separated) externsync attribute"""
85
86    TRUE_STRING = 'true'
87    TRUE_WITH_CHILDREN_STRING = 'true_with_children'
88
89    def __init__(self, val):
90        self.full_reference = val
91        self.entirely_extern_sync = (val in (ExternSyncEntry.TRUE_STRING, ExternSyncEntry.TRUE_WITH_CHILDREN_STRING))
92        self.children_extern_sync = (val == ExternSyncEntry.TRUE_WITH_CHILDREN_STRING)
93        if self.entirely_extern_sync:
94            return
95
96        self.param_ref_parts = _split_param_ref(val)
97        self.member = self.param_ref_parts[0]
98
99    def get_human_readable(self, make_param_name=None):
100        assert(not self.entirely_extern_sync)
101        return _human_readable_deref(self.full_reference, make_param_name=make_param_name)
102
103    @staticmethod
104    def parse_externsync_from_param(param):
105        """Get a list of ExternSyncEntry."""
106        sync_str = param.get('externsync')
107        if sync_str is None:
108            return None
109        return [ExternSyncEntry(elt) for elt in sync_str.split(',')]
110
111    def __repr__(self):
112        "Formats an object for repr(), debugger display, etc."
113        return 'spec_tools.attributes.ExternSyncEntry("{}")'.format(self.full_reference)
114
115