"""Flexible enumeration of C types.""" from Enumeration import * # TODO: # - struct improvements (flexible arrays, packed & # unpacked, alignment) # - objective-c qualified id # - anonymous / transparent unions # - VLAs # - block types # - K&R functions # - pass arguments of different types (test extension, transparent union) # - varargs ### # Actual type types class Type: def isBitField(self): return False def isPaddingBitField(self): return False def getTypeName(self, printer): name = 'T%d' % len(printer.types) typedef = self.getTypedefDef(name, printer) printer.addDeclaration(typedef) return name class BuiltinType(Type): def __init__(self, name, size, bitFieldSize=None): self.name = name self.size = size self.bitFieldSize = bitFieldSize def isBitField(self): return self.bitFieldSize is not None def isPaddingBitField(self): return self.bitFieldSize is 0 def getBitFieldSize(self): assert self.isBitField() return self.bitFieldSize def getTypeName(self, printer): return self.name def sizeof(self): return self.size def __str__(self): return self.name class EnumType(Type): unique_id = 0 def __init__(self, index, enumerators): self.index = index self.enumerators = enumerators self.unique_id = self.__class__.unique_id self.__class__.unique_id += 1 def getEnumerators(self): result = '' for i, init in enumerate(self.enumerators): if i > 0: result = result + ', ' result = result + 'enum%dval%d_%d' % (self.index, i, self.unique_id) if init: result = result + ' = %s' % (init) return result def __str__(self): return 'enum { %s }' % (self.getEnumerators()) def getTypedefDef(self, name, printer): return 'typedef enum %s { %s } %s;'%(name, self.getEnumerators(), name) class RecordType(Type): def __init__(self, index, isUnion, fields): self.index = index self.isUnion = isUnion self.fields = fields self.name = None def __str__(self): def getField(t): if t.isBitField(): return "%s : %d;" % (t, t.getBitFieldSize()) else: return "%s;" % t return '%s { %s }'%(('struct','union')[self.isUnion], ' '.join(map(getField, self.fields))) def getTypedefDef(self, name, printer): def getField((i, t)): if t.isBitField(): if t.isPaddingBitField(): return '%s : 0;'%(printer.getTypeName(t),) else: return '%s field%d : %d;'%(printer.getTypeName(t),i, t.getBitFieldSize()) else: return '%s field%d;'%(printer.getTypeName(t),i) fields = map(getField, enumerate(self.fields)) # Name the struct for more readable LLVM IR. return 'typedef %s %s { %s } %s;'%(('struct','union')[self.isUnion], name, ' '.join(fields), name) class ArrayType(Type): def __init__(self, index, isVector, elementType, size): if isVector: # Note that for vectors, this is the size in bytes. assert size > 0 else: assert size is None or size >= 0 self.index = index self.isVector = isVector self.elementType = elementType self.size = size if isVector: eltSize = self.elementType.sizeof() assert not (self.size % eltSize) self.numElements = self.size // eltSize else: self.numElements = self.size def __str__(self): if self.isVector: return 'vector (%s)[%d]'%(self.elementType,self.size) elif self.size is not None: return '(%s)[%d]'%(self.elementType,self.size) else: return '(%s)[]'%(self.elementType,) def getTypedefDef(self, name, printer): elementName = printer.getTypeName(self.elementType) if self.isVector: return 'typedef %s %s __attribute__ ((vector_size (%d)));'%(elementName, name, self.size) else: if self.size is None: sizeStr = '' else: sizeStr = str(self.size) return 'typedef %s %s[%s];'%(elementName, name, sizeStr) class ComplexType(Type): def __init__(self, index, elementType): self.index = index self.elementType = elementType def __str__(self): return '_Complex (%s)'%(self.elementType) def getTypedefDef(self, name, printer): return 'typedef _Complex %s %s;'%(printer.getTypeName(self.elementType), name) class FunctionType(Type): def __init__(self, index, returnType, argTypes): self.index = index self.returnType = returnType self.argTypes = argTypes def __str__(self): if self.returnType is None: rt = 'void' else: rt = str(self.returnType) if not self.argTypes: at = 'void' else: at = ', '.join(map(str, self.argTypes)) return '%s (*)(%s)'%(rt, at) def getTypedefDef(self, name, printer): if self.returnType is None: rt = 'void' else: rt = str(self.returnType) if not self.argTypes: at = 'void' else: at = ', '.join(map(str, self.argTypes)) return 'typedef %s (*%s)(%s);'%(rt, name, at) ### # Type enumerators class TypeGenerator(object): def __init__(self): self.cache = {} def setCardinality(self): abstract def get(self, N): T = self.cache.get(N) if T is None: assert 0 <= N < self.cardinality T = self.cache[N] = self.generateType(N) return T def generateType(self, N): abstract class FixedTypeGenerator(TypeGenerator): def __init__(self, types): TypeGenerator.__init__(self) self.types = types self.setCardinality() def setCardinality(self): self.cardinality = len(self.types) def generateType(self, N): return self.types[N] # Factorial def fact(n): result = 1 while n > 0: result = result * n n = n - 1 return result # Compute the number of combinations (n choose k) def num_combinations(n, k): return fact(n) / (fact(k) * fact(n - k)) # Enumerate the combinations choosing k elements from the list of values def combinations(values, k): # From ActiveState Recipe 190465: Generator for permutations, # combinations, selections of a sequence if k==0: yield [] else: for i in xrange(len(values)-k+1): for cc in combinations(values[i+1:],k-1): yield [values[i]]+cc class EnumTypeGenerator(TypeGenerator): def __init__(self, values, minEnumerators, maxEnumerators): TypeGenerator.__init__(self) self.values = values self.minEnumerators = minEnumerators self.maxEnumerators = maxEnumerators self.setCardinality() def setCardinality(self): self.cardinality = 0 for num in range(self.minEnumerators, self.maxEnumerators + 1): self.cardinality += num_combinations(len(self.values), num) def generateType(self, n): # Figure out the number of enumerators in this type numEnumerators = self.minEnumerators valuesCovered = 0 while numEnumerators < self.maxEnumerators: comb = num_combinations(len(self.values), numEnumerators) if valuesCovered + comb > n: break numEnumerators = numEnumerators + 1 valuesCovered += comb # Find the requested combination of enumerators and build a # type from it. i = 0 for enumerators in combinations(self.values, numEnumerators): if i == n - valuesCovered: return EnumType(n, enumerators) i = i + 1 assert False class ComplexTypeGenerator(TypeGenerator): def __init__(self, typeGen): TypeGenerator.__init__(self) self.typeGen = typeGen self.setCardinality() def setCardinality(self): self.cardinality = self.typeGen.cardinality def generateType(self, N): return ComplexType(N, self.typeGen.get(N)) class VectorTypeGenerator(TypeGenerator): def __init__(self, typeGen, sizes): TypeGenerator.__init__(self) self.typeGen = typeGen self.sizes = tuple(map(int,sizes)) self.setCardinality() def setCardinality(self): self.cardinality = len(self.sizes)*self.typeGen.cardinality def generateType(self, N): S,T = getNthPairBounded(N, len(self.sizes), self.typeGen.cardinality) return ArrayType(N, True, self.typeGen.get(T), self.sizes[S]) class FixedArrayTypeGenerator(TypeGenerator): def __init__(self, typeGen, sizes): TypeGenerator.__init__(self) self.typeGen = typeGen self.sizes = tuple(size) self.setCardinality() def setCardinality(self): self.cardinality = len(self.sizes)*self.typeGen.cardinality def generateType(self, N): S,T = getNthPairBounded(N, len(self.sizes), self.typeGen.cardinality) return ArrayType(N, false, self.typeGen.get(T), self.sizes[S]) class ArrayTypeGenerator(TypeGenerator): def __init__(self, typeGen, maxSize, useIncomplete=False, useZero=False): TypeGenerator.__init__(self) self.typeGen = typeGen self.useIncomplete = useIncomplete self.useZero = useZero self.maxSize = int(maxSize) self.W = useIncomplete + useZero + self.maxSize self.setCardinality() def setCardinality(self): self.cardinality = self.W * self.typeGen.cardinality def generateType(self, N): S,T = getNthPairBounded(N, self.W, self.typeGen.cardinality) if self.useIncomplete: if S==0: size = None S = None else: S = S - 1 if S is not None: if self.useZero: size = S else: size = S + 1 return ArrayType(N, False, self.typeGen.get(T), size) class RecordTypeGenerator(TypeGenerator): def __init__(self, typeGen, useUnion, maxSize): TypeGenerator.__init__(self) self.typeGen = typeGen self.useUnion = bool(useUnion) self.maxSize = int(maxSize) self.setCardinality() def setCardinality(self): M = 1 + self.useUnion if self.maxSize is aleph0: S = aleph0 * self.typeGen.cardinality else: S = 0 for i in range(self.maxSize+1): S += M * (self.typeGen.cardinality ** i) self.cardinality = S def generateType(self, N): isUnion,I = False,N if self.useUnion: isUnion,I = (I&1),I>>1 fields = map(self.typeGen.get,getNthTuple(I,self.maxSize,self.typeGen.cardinality)) return RecordType(N, isUnion, fields) class FunctionTypeGenerator(TypeGenerator): def __init__(self, typeGen, useReturn, maxSize): TypeGenerator.__init__(self) self.typeGen = typeGen self.useReturn = useReturn self.maxSize = maxSize self.setCardinality() def setCardinality(self): if self.maxSize is aleph0: S = aleph0 * self.typeGen.cardinality() elif self.useReturn: S = 0 for i in range(1,self.maxSize+1+1): S += self.typeGen.cardinality ** i else: S = 0 for i in range(self.maxSize+1): S += self.typeGen.cardinality ** i self.cardinality = S def generateType(self, N): if self.useReturn: # Skip the empty tuple argIndices = getNthTuple(N+1, self.maxSize+1, self.typeGen.cardinality) retIndex,argIndices = argIndices[0],argIndices[1:] retTy = self.typeGen.get(retIndex) else: retTy = None argIndices = getNthTuple(N, self.maxSize, self.typeGen.cardinality) args = map(self.typeGen.get, argIndices) return FunctionType(N, retTy, args) class AnyTypeGenerator(TypeGenerator): def __init__(self): TypeGenerator.__init__(self) self.generators = [] self.bounds = [] self.setCardinality() self._cardinality = None def getCardinality(self): if self._cardinality is None: return aleph0 else: return self._cardinality def setCardinality(self): self.bounds = [g.cardinality for g in self.generators] self._cardinality = sum(self.bounds) cardinality = property(getCardinality, None) def addGenerator(self, g): self.generators.append(g) for i in range(100): prev = self._cardinality self._cardinality = None for g in self.generators: g.setCardinality() self.setCardinality() if (self._cardinality is aleph0) or prev==self._cardinality: break else: raise RuntimeError,"Infinite loop in setting cardinality" def generateType(self, N): index,M = getNthPairVariableBounds(N, self.bounds) return self.generators[index].get(M) def test(): fbtg = FixedTypeGenerator([BuiltinType('char', 4), BuiltinType('char', 4, 0), BuiltinType('int', 4, 5)]) fields1 = AnyTypeGenerator() fields1.addGenerator( fbtg ) fields0 = AnyTypeGenerator() fields0.addGenerator( fbtg ) # fields0.addGenerator( RecordTypeGenerator(fields1, False, 4) ) btg = FixedTypeGenerator([BuiltinType('char', 4), BuiltinType('int', 4)]) etg = EnumTypeGenerator([None, '-1', '1', '1u'], 0, 3) atg = AnyTypeGenerator() atg.addGenerator( btg ) atg.addGenerator( RecordTypeGenerator(fields0, False, 4) ) atg.addGenerator( etg ) print 'Cardinality:',atg.cardinality for i in range(100): if i == atg.cardinality: try: atg.get(i) raise RuntimeError,"Cardinality was wrong" except AssertionError: break print '%4d: %s'%(i, atg.get(i)) if __name__ == '__main__': test()