1from collections import namedtuple 2 3from ..common.info import ID, UNKNOWN 4from ..common.util import classonly, _NTBase 5 6 7def normalize_vartype(vartype): 8 """Return the canonical form for a variable type (or func signature).""" 9 # We allow empty strring through for semantic reasons. 10 if vartype is None: 11 return None 12 13 # XXX finish! 14 # XXX Return (modifiers, type, pointer)? 15 return str(vartype) 16 17 18# XXX Variable.vartype -> decl (Declaration). 19 20class Variable(_NTBase, 21 namedtuple('Variable', 'id storage vartype')): 22 """Information about a single variable declaration.""" 23 24 __slots__ = () 25 26 STORAGE = ( 27 'static', 28 'extern', 29 'implicit', 30 'local', 31 ) 32 33 @classonly 34 def from_parts(cls, filename, funcname, name, decl, storage=None): 35 varid = ID(filename, funcname, name) 36 if storage is None: 37 self = cls.from_id(varid, decl) 38 else: 39 self = cls(varid, storage, decl) 40 return self 41 42 @classonly 43 def from_id(cls, varid, decl): 44 from ..parser.declarations import extract_storage 45 storage = extract_storage(decl, infunc=varid.funcname) 46 return cls(varid, storage, decl) 47 48 def __new__(cls, id, storage, vartype): 49 self = super().__new__( 50 cls, 51 id=ID.from_raw(id), 52 storage=str(storage) if storage else None, 53 vartype=normalize_vartype(vartype) if vartype else None, 54 ) 55 return self 56 57 def __hash__(self): 58 return hash(self.id) 59 60 def __getattr__(self, name): 61 return getattr(self.id, name) 62 63 def _validate_id(self): 64 if not self.id: 65 raise TypeError('missing id') 66 67 if not self.filename or self.filename == UNKNOWN: 68 raise TypeError(f'id missing filename ({self.id})') 69 70 if self.funcname and self.funcname == UNKNOWN: 71 raise TypeError(f'id missing funcname ({self.id})') 72 73 self.id.validate() 74 75 def validate(self): 76 """Fail if the object is invalid (i.e. init with bad data).""" 77 self._validate_id() 78 79 if self.storage is None or self.storage == UNKNOWN: 80 raise TypeError('missing storage') 81 elif self.storage not in self.STORAGE: 82 raise ValueError(f'unsupported storage {self.storage:r}') 83 84 if self.vartype is None or self.vartype == UNKNOWN: 85 raise TypeError('missing vartype') 86 87 @property 88 def isglobal(self): 89 return self.storage != 'local' 90 91 @property 92 def isconst(self): 93 return 'const' in self.vartype.split() 94