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