1import re 2 3from ._regexes import ( 4 _ind, 5 STRING_LITERAL, 6 VAR_DECL as _VAR_DECL, 7) 8 9 10def log_match(group, m): 11 from . import _logger 12 _logger.debug(f'matched <{group}> ({m.group(0)})') 13 14 15############################# 16# regex utils 17 18def set_capture_group(pattern, group, *, strict=True): 19 old = f'(?: # <{group}>' 20 if strict and f'(?: # <{group}>' not in pattern: 21 raise ValueError(f'{old!r} not found in pattern') 22 return pattern.replace(old, f'( # <{group}>', 1) 23 24 25def set_capture_groups(pattern, groups, *, strict=True): 26 for group in groups: 27 pattern = set_capture_group(pattern, group, strict=strict) 28 return pattern 29 30 31############################# 32# syntax-related utils 33 34_PAREN_RE = re.compile(rf''' 35 (?: 36 (?: 37 [^'"()]* 38 {_ind(STRING_LITERAL, 3)} 39 )* 40 [^'"()]* 41 (?: 42 ( [(] ) 43 | 44 ( [)] ) 45 ) 46 ) 47 ''', re.VERBOSE) 48 49 50def match_paren(text, depth=0): 51 pos = 0 52 while (m := _PAREN_RE.match(text, pos)): 53 pos = m.end() 54 _open, _close = m.groups() 55 if _open: 56 depth += 1 57 else: # _close 58 depth -= 1 59 if depth == 0: 60 return pos 61 else: 62 raise ValueError(f'could not find matching parens for {text!r}') 63 64 65VAR_DECL = set_capture_groups(_VAR_DECL, ( 66 'STORAGE', 67 'TYPE_QUAL', 68 'TYPE_SPEC', 69 'DECLARATOR', 70 'IDENTIFIER', 71 'WRAPPED_IDENTIFIER', 72 'FUNC_IDENTIFIER', 73)) 74 75 76def parse_var_decl(decl): 77 m = re.match(VAR_DECL, decl, re.VERBOSE) 78 (storage, typequal, typespec, declarator, 79 name, 80 wrappedname, 81 funcptrname, 82 ) = m.groups() 83 if name: 84 kind = 'simple' 85 elif wrappedname: 86 kind = 'wrapped' 87 name = wrappedname 88 elif funcptrname: 89 kind = 'funcptr' 90 name = funcptrname 91 else: 92 raise NotImplementedError 93 abstract = declarator.replace(name, '') 94 vartype = { 95 'storage': storage, 96 'typequal': typequal, 97 'typespec': typespec, 98 'abstract': abstract, 99 } 100 return (kind, name, vartype) 101 102 103############################# 104# parser state utils 105 106# XXX Drop this or use it! 107def iter_results(results): 108 if not results: 109 return 110 if callable(results): 111 results = results() 112 113 for result, text in results(): 114 if result: 115 yield result, text 116