ABITestGen.py revision e8c55b407d8fc494d814d5fda256a47f27ace3a5
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochfrom pprint import pprint
4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochimport random, atexit, time
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochfrom random import randrange
6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochfrom Enumeration import *
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from TypeGen import *
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)####
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TypePrinter:
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def __init__(self, output, outputHeader=None,
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 outputTests=None, outputDriver=None,
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 headerName=None, info=None):
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.output = output
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.outputHeader = outputHeader
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self.outputTests = outputTests
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.outputDriver = outputDriver
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.writeBody = outputHeader or outputTests or outputDriver
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.types = {}
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.testValues = {}
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.testReturnValues = {}
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.layoutTests = []
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if info:
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            for f in (self.output,self.outputHeader,self.outputTests,self.outputDriver):
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                if f:
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    print >>f,info
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if self.writeBody:
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            print >>self.output, '#include <stdio.h>\n'
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if self.outputTests:
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                print >>self.outputTests, '#include <stdio.h>\n'
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        if headerName:
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            for f in (self.output,self.outputTests,self.outputDriver):
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if f is not None:
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    print >>f, '#include "%s"\n'%(headerName,)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if self.outputDriver:
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            print >>self.outputDriver, 'int main(int argc, char **argv) {'
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def finish(self):
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        if self.layoutTests:
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            print >>self.output, 'int main(int argc, char **argv) {'
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            for f in self.layoutTests:
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                print >>self.output, '  %s();' % f
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            print >>self.output, '  return 0;'
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            print >>self.output, '}'
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if self.outputDriver:
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            print >>self.outputDriver, '  return 0;'
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            print >>self.outputDriver, '}'
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def getTypeName(self, T):
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if isinstance(T,BuiltinType):
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return T.name
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        name = self.types.get(T)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if name is None:
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            name = 'T%d'%(len(self.types),)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # Reserve slot
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            self.types[T] = None
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if self.outputHeader:
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                print >>self.outputHeader,T.getTypedefDef(name, self)
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            else:
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                print >>self.output,T.getTypedefDef(name, self)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if self.outputTests:
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    print >>self.outputTests,T.getTypedefDef(name, self)
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            self.types[T] = name
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return name
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def writeLayoutTest(self, i, ty):
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        tyName = self.getTypeName(ty)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tyNameClean = tyName.replace(' ','_').replace('*','star')
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fnName = 'test_%s' % tyNameClean
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        print >>self.output,'void %s(void) {' % fnName
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.printSizeOfType('    %s'%fnName, tyName, ty, self.output)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.printAlignOfType('    %s'%fnName, tyName, ty, self.output)
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        self.printOffsetsOfType('    %s'%fnName, tyName, ty, self.output)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print >>self.output,'}'
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print >>self.output
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.layoutTests.append(fnName)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def writeFunction(self, i, FT):
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        args = ', '.join(['%s arg%d'%(self.getTypeName(t),i) for i,t in enumerate(FT.argTypes)])
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if not args:
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            args = 'void'
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        if FT.returnType is None:
93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            retvalName = None
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            retvalTypeName = 'void'
95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        else:
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            retvalTypeName = self.getTypeName(FT.returnType)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if self.writeBody or self.outputTests:
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                retvalName = self.getTestReturnValue(FT.returnType)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fnName = 'fn%d'%(FT.index,)
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        if self.outputHeader:
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            print >>self.outputHeader,'%s %s(%s);'%(retvalTypeName, fnName, args)
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        elif self.outputTests:
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            print >>self.outputTests,'%s %s(%s);'%(retvalTypeName, fnName, args)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        print >>self.output,'%s %s(%s)'%(retvalTypeName, fnName, args),
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if self.writeBody:
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            print >>self.output, '{'
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            for i,t in enumerate(FT.argTypes):
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                self.printValueOfType('    %s'%fnName, 'arg%d'%i, t)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if retvalName is not None:
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                print >>self.output, '  return %s;'%(retvalName,)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            print >>self.output, '}'
116        else:
117            print >>self.output, '{}'
118        print >>self.output
119
120        if self.outputDriver:
121            print >>self.outputDriver, '  { extern void test_%s(void); test_%s(); }\n'%(fnName,fnName,)
122
123        if self.outputTests:
124            if self.outputHeader:
125                print >>self.outputHeader, 'void test_%s(void);'%(fnName,)
126
127            if retvalName is None:
128                retvalTests = None
129            else:
130                retvalTests = self.getTestValuesArray(FT.returnType)
131            tests = map(self.getTestValuesArray, FT.argTypes)
132            print >>self.outputTests, 'void test_%s(void) {'%(fnName,)
133
134            if retvalTests is not None:
135                print >>self.outputTests, '  printf("%s: testing return.\\n");'%(fnName,)
136                print >>self.outputTests, '  for (int i=0; i<%d; ++i) {'%(retvalTests[1],)
137                args = ', '.join(['%s[%d]'%(t,randrange(l)) for t,l in tests])
138                print >>self.outputTests, '    %s RV;'%(retvalTypeName,)
139                print >>self.outputTests, '    %s = %s[i];'%(retvalName, retvalTests[0])
140                print >>self.outputTests, '    RV = %s(%s);'%(fnName, args)
141                self.printValueOfType('  %s_RV'%fnName, 'RV', FT.returnType, output=self.outputTests, indent=4)
142                print >>self.outputTests, '  }'
143
144            if tests:
145                print >>self.outputTests, '  printf("%s: testing arguments.\\n");'%(fnName,)
146            for i,(array,length) in enumerate(tests):
147                for j in range(length):
148                    args = ['%s[%d]'%(t,randrange(l)) for t,l in tests]
149                    args[i] = '%s[%d]'%(array,j)
150                    print >>self.outputTests, '  %s(%s);'%(fnName, ', '.join(args),)
151            print >>self.outputTests, '}'
152
153    def getTestReturnValue(self, type):
154        typeName = self.getTypeName(type)
155        info = self.testReturnValues.get(typeName)
156        if info is None:
157            name = '%s_retval'%(typeName.replace(' ','_').replace('*','star'),)
158            print >>self.output, '%s %s;'%(typeName,name)
159            if self.outputHeader:
160                print >>self.outputHeader, 'extern %s %s;'%(typeName,name)
161            elif self.outputTests:
162                print >>self.outputTests, 'extern %s %s;'%(typeName,name)
163            info = self.testReturnValues[typeName] = name
164        return info
165
166    def getTestValuesArray(self, type):
167        typeName = self.getTypeName(type)
168        info = self.testValues.get(typeName)
169        if info is None:
170            name = '%s_values'%(typeName.replace(' ','_').replace('*','star'),)
171            print >>self.outputTests, 'static %s %s[] = {'%(typeName,name)
172            length = 0
173            for item in self.getTestValues(type):
174                print >>self.outputTests, '\t%s,'%(item,)
175                length += 1
176            print >>self.outputTests,'};'
177            info = self.testValues[typeName] = (name,length)
178        return info
179
180    def getTestValues(self, t):
181        if isinstance(t, BuiltinType):
182            if t.name=='float':
183                for i in ['0.0','-1.0','1.0']:
184                    yield i+'f'
185            elif t.name=='double':
186                for i in ['0.0','-1.0','1.0']:
187                    yield i
188            elif t.name in ('void *'):
189                yield '(void*) 0'
190                yield '(void*) -1'
191            else:
192                yield '(%s) 0'%(t.name,)
193                yield '(%s) -1'%(t.name,)
194                yield '(%s) 1'%(t.name,)
195        elif isinstance(t, RecordType):
196            if not t.fields:
197                yield '{ }'
198                return
199            # FIXME: Use designated initializers to access non-first
200            # fields of unions.
201            if t.isUnion:
202                for v in self.getTestValues(t.fields[0]):
203                    yield '{ %s }' % v
204                return
205            fieldValues = [list(self.getTestValues(f)) for f in t.fields]
206            for i,values in enumerate(fieldValues):
207                for v in values:
208                    elements = map(random.choice,fieldValues)
209                    elements[i] = v
210                    yield '{ %s }'%(', '.join(elements))
211        elif isinstance(t, ComplexType):
212            for t in self.getTestValues(t.elementType):
213                yield '%s + %s * 1i'%(t,t)
214        elif isinstance(t, ArrayType):
215            values = list(self.getTestValues(t.elementType))
216            if not values:
217                yield '{ }'
218            for i in range(t.numElements):
219                for v in values:
220                    elements = [random.choice(values) for i in range(t.numElements)]
221                    elements[i] = v
222                    yield '{ %s }'%(', '.join(elements))
223        else:
224            raise NotImplementedError,'Cannot make tests values of type: "%s"'%(t,)
225
226    def printSizeOfType(self, prefix, name, t, output=None, indent=2):
227        print >>output, '%*sprintf("%s: sizeof(%s) = %%ld\\n", sizeof(%s));'%(indent, '', prefix, name, name)
228    def printAlignOfType(self, prefix, name, t, output=None, indent=2):
229        print >>output, '%*sprintf("%s: __alignof__(%s) = %%ld\\n", __alignof__(%s));'%(indent, '', prefix, name, name)
230    def printOffsetsOfType(self, prefix, name, t, output=None, indent=2):
231        if isinstance(t, RecordType):
232            for i,f in enumerate(t.fields):
233                fname = 'field%d' % i
234                print >>output, '%*sprintf("%s: __builtin_offsetof(%s, %s) = %%ld\\n", __builtin_offsetof(%s, %s));'%(indent, '', prefix, name, fname, name, fname)
235
236    def printValueOfType(self, prefix, name, t, output=None, indent=2):
237        if output is None:
238            output = self.output
239        if isinstance(t, BuiltinType):
240            if t.name.endswith('long long'):
241                code = 'lld'
242            elif t.name.endswith('long'):
243                code = 'ld'
244            elif t.name.split(' ')[-1] in ('_Bool','char','short','int'):
245                code = 'd'
246            elif t.name in ('float','double'):
247                code = 'f'
248            elif t.name == 'long double':
249                code = 'Lf'
250            else:
251                code = 'p'
252            print >>output, '%*sprintf("%s: %s = %%%s\\n", %s);'%(indent, '', prefix, name, code, name)
253        elif isinstance(t, RecordType):
254            if not t.fields:
255                print >>output, '%*sprintf("%s: %s (empty)\\n");'%(indent, '', prefix, name)
256            for i,f in enumerate(t.fields):
257                fname = '%s.field%d'%(name,i)
258                self.printValueOfType(prefix, fname, f, output=output, indent=indent)
259        elif isinstance(t, ComplexType):
260            self.printValueOfType(prefix, '(__real %s)'%name, t.elementType, output=output,indent=indent)
261            self.printValueOfType(prefix, '(__imag %s)'%name, t.elementType, output=output,indent=indent)
262        elif isinstance(t, ArrayType):
263            for i in range(t.numElements):
264                # Access in this fashion as a hackish way to portably
265                # access vectors.
266                if t.isVector:
267                    self.printValueOfType(prefix, '((%s*) &%s)[%d]'%(t.elementType,name,i), t.elementType, output=output,indent=indent)
268                else:
269                    self.printValueOfType(prefix, '%s[%d]'%(name,i), t.elementType, output=output,indent=indent)
270        else:
271            raise NotImplementedError,'Cannot print value of type: "%s"'%(t,)
272
273import sys
274
275def main():
276    from optparse import OptionParser, OptionGroup
277    parser = OptionParser("%prog [options] {indices}")
278    parser.add_option("", "--mode", dest="mode",
279                      help="autogeneration mode (random or linear) [default %default]",
280                      type='choice', choices=('random','linear'), default='linear')
281    parser.add_option("", "--count", dest="count",
282                      help="autogenerate COUNT functions according to MODE",
283                      type=int, default=0)
284    parser.add_option("", "--min", dest="minIndex", metavar="N",
285                      help="start autogeneration with the Nth function type  [default %default]",
286                      type=int, default=0)
287    parser.add_option("", "--max", dest="maxIndex", metavar="N",
288                      help="maximum index for random autogeneration  [default %default]",
289                      type=int, default=10000000)
290    parser.add_option("", "--seed", dest="seed",
291                      help="random number generator seed [default %default]",
292                      type=int, default=1)
293    parser.add_option("", "--use-random-seed", dest="useRandomSeed",
294                      help="use random value for initial random number generator seed",
295                      action='store_true', default=False)
296    parser.add_option("-o", "--output", dest="output", metavar="FILE",
297                      help="write output to FILE  [default %default]",
298                      type=str, default='-')
299    parser.add_option("-O", "--output-header", dest="outputHeader", metavar="FILE",
300                      help="write header file for output to FILE  [default %default]",
301                      type=str, default=None)
302    parser.add_option("-T", "--output-tests", dest="outputTests", metavar="FILE",
303                      help="write function tests to FILE  [default %default]",
304                      type=str, default=None)
305    parser.add_option("-D", "--output-driver", dest="outputDriver", metavar="FILE",
306                      help="write test driver to FILE  [default %default]",
307                      type=str, default=None)
308    parser.add_option("", "--test-layout", dest="testLayout", metavar="FILE",
309                      help="test structure layout",
310                      action='store_true', default=False)
311
312    group = OptionGroup(parser, "Type Enumeration Options")
313    # Builtins - Ints
314    group.add_option("", "--no-char", dest="useChar",
315                     help="do not generate char types",
316                     action="store_false", default=True)
317    group.add_option("", "--no-short", dest="useShort",
318                     help="do not generate short types",
319                     action="store_false", default=True)
320    group.add_option("", "--no-int", dest="useInt",
321                     help="do not generate int types",
322                     action="store_false", default=True)
323    group.add_option("", "--no-long", dest="useLong",
324                     help="do not generate long types",
325                     action="store_false", default=True)
326    group.add_option("", "--no-long-long", dest="useLongLong",
327                     help="do not generate long long types",
328                     action="store_false", default=True)
329    group.add_option("", "--no-unsigned", dest="useUnsigned",
330                     help="do not generate unsigned integer types",
331                     action="store_false", default=True)
332
333    # Other builtins
334    group.add_option("", "--no-bool", dest="useBool",
335                     help="do not generate bool types",
336                     action="store_false", default=True)
337    group.add_option("", "--no-float", dest="useFloat",
338                     help="do not generate float types",
339                     action="store_false", default=True)
340    group.add_option("", "--no-double", dest="useDouble",
341                     help="do not generate double types",
342                     action="store_false", default=True)
343    group.add_option("", "--no-long-double", dest="useLongDouble",
344                     help="do not generate long double types",
345                     action="store_false", default=True)
346    group.add_option("", "--no-void-pointer", dest="useVoidPointer",
347                     help="do not generate void* types",
348                     action="store_false", default=True)
349
350    # Derived types
351    group.add_option("", "--no-array", dest="useArray",
352                     help="do not generate record types",
353                     action="store_false", default=True)
354    group.add_option("", "--no-complex", dest="useComplex",
355                     help="do not generate complex types",
356                     action="store_false", default=True)
357    group.add_option("", "--no-record", dest="useRecord",
358                     help="do not generate record types",
359                     action="store_false", default=True)
360    group.add_option("", "--no-union", dest="recordUseUnion",
361                     help="do not generate union types",
362                     action="store_false", default=True)
363    group.add_option("", "--no-vector", dest="useVector",
364                     help="do not generate vector types",
365                     action="store_false", default=True)
366
367    # Tuning
368    group.add_option("", "--no-function-return", dest="functionUseReturn",
369                     help="do not generate return types for functions",
370                     action="store_false", default=True)
371    group.add_option("", "--vector-sizes", dest="vectorSizes",
372                     help="comma separated list of sizes for vectors [default %default]",
373                     action="store", type=str, default='8,16', metavar="N")
374
375    group.add_option("", "--max-args", dest="functionMaxArgs",
376                     help="maximum number of arguments per function [default %default]",
377                     action="store", type=int, default=4, metavar="N")
378    group.add_option("", "--max-array", dest="arrayMaxSize",
379                     help="maximum array size [default %default]",
380                     action="store", type=int, default=4, metavar="N")
381    group.add_option("", "--max-record", dest="recordMaxSize",
382                     help="maximum number of fields per record [default %default]",
383                     action="store", type=int, default=4, metavar="N")
384    group.add_option("", "--max-record-depth", dest="recordMaxDepth",
385                     help="maximum nested structure depth [default %default]",
386                     action="store", type=int, default=None, metavar="N")
387    parser.add_option_group(group)
388    (opts, args) = parser.parse_args()
389
390    if not opts.useRandomSeed:
391        random.seed(opts.seed)
392
393    # Contruct type generator
394    builtins = []
395    ints = []
396    if opts.useChar: ints.append(('char',1))
397    if opts.useShort: ints.append(('short',2))
398    if opts.useInt: ints.append(('int',4))
399    # FIXME: Wrong size.
400    if opts.useLong: ints.append(('long',4))
401    if opts.useLongLong: ints.append(('long long',8))
402    if opts.useUnsigned:
403        ints = ([('unsigned %s'%i,s) for i,s in ints] +
404                [('signed %s'%i,s) for i,s in ints])
405    builtins.extend(ints)
406
407    if opts.useBool: builtins.append(('_Bool',1))
408    if opts.useFloat: builtins.append(('float',4))
409    if opts.useDouble: builtins.append(('double',8))
410    if opts.useLongDouble: builtins.append(('long double',16))
411    # FIXME: Wrong size.
412    if opts.useVoidPointer:  builtins.append(('void*',4))
413
414    btg = FixedTypeGenerator([BuiltinType(n,s) for n,s in builtins])
415    sbtg = FixedTypeGenerator([BuiltinType('char',1),
416                               BuiltinType('int',4),
417                               BuiltinType('float',4),
418                               BuiltinType('double',8)])
419
420    atg = AnyTypeGenerator()
421    artg = AnyTypeGenerator()
422    def makeGenerator(atg, subgen, useRecord, useArray):
423        atg.addGenerator(btg)
424        if useRecord and opts.useRecord:
425            assert subgen
426            atg.addGenerator(RecordTypeGenerator(subgen, opts.recordUseUnion,
427                                                 opts.recordMaxSize))
428        if opts.useComplex:
429            # FIXME: Allow overriding builtins here
430            atg.addGenerator(ComplexTypeGenerator(sbtg))
431        if useArray and opts.useArray:
432            assert subgen
433            atg.addGenerator(ArrayTypeGenerator(subgen, opts.arrayMaxSize))
434        if opts.useVector:
435            atg.addGenerator(VectorTypeGenerator(sbtg,
436                                                 map(int, opts.vectorSizes.split(','))))
437
438
439    if opts.recordMaxDepth is None:
440        # Fully recursive, just avoid top-level arrays.
441        subTG = AnyTypeGenerator()
442        atg = AnyTypeGenerator()
443        makeGenerator(subTG, atg, True, True)
444        makeGenerator(atg, subTG, True, False)
445    else:
446        # Make a chain of type generators, each builds smaller
447        # structures.
448        base = AnyTypeGenerator()
449        makeGenerator(base, None, False, False)
450        for i in range(opts.recordMaxDepth):
451            n = AnyTypeGenerator()
452            makeGenerator(n, base, True, True)
453            base = n
454        atg = AnyTypeGenerator()
455        makeGenerator(atg, base, True, False)
456
457    if opts.testLayout:
458        ftg = atg
459    else:
460        ftg = FunctionTypeGenerator(atg, opts.functionUseReturn, opts.functionMaxArgs)
461
462    # Override max,min,count if finite
463    if opts.maxIndex is None:
464        if ftg.cardinality is aleph0:
465            opts.maxIndex = 10000000
466        else:
467            opts.maxIndex = ftg.cardinality
468    opts.maxIndex = min(opts.maxIndex, ftg.cardinality)
469    opts.minIndex = max(0,min(opts.maxIndex-1, opts.minIndex))
470    if not opts.mode=='random':
471        opts.count = min(opts.count, opts.maxIndex-opts.minIndex)
472
473    if opts.output=='-':
474        output = sys.stdout
475    else:
476        output = open(opts.output,'w')
477        atexit.register(lambda: output.close())
478
479    outputHeader = None
480    if opts.outputHeader:
481        outputHeader = open(opts.outputHeader,'w')
482        atexit.register(lambda: outputHeader.close())
483
484    outputTests = None
485    if opts.outputTests:
486        outputTests = open(opts.outputTests,'w')
487        atexit.register(lambda: outputTests.close())
488
489    outputDriver = None
490    if opts.outputDriver:
491        outputDriver = open(opts.outputDriver,'w')
492        atexit.register(lambda: outputDriver.close())
493
494    info = ''
495    info += '// %s\n'%(' '.join(sys.argv),)
496    info += '// Generated: %s\n'%(time.strftime('%Y-%m-%d %H:%M'),)
497    info += '// Cardinality of function generator: %s\n'%(ftg.cardinality,)
498    info += '// Cardinality of type generator: %s\n'%(atg.cardinality,)
499
500    if opts.testLayout:
501        info += '\n#include <stdio.h>'
502
503    P = TypePrinter(output,
504                    outputHeader=outputHeader,
505                    outputTests=outputTests,
506                    outputDriver=outputDriver,
507                    headerName=opts.outputHeader,
508                    info=info)
509
510    def write(N):
511        try:
512            FT = ftg.get(N)
513        except RuntimeError,e:
514            if e.args[0]=='maximum recursion depth exceeded':
515                print >>sys.stderr,'WARNING: Skipped %d, recursion limit exceeded (bad arguments?)'%(N,)
516                return
517            raise
518        if opts.testLayout:
519            P.writeLayoutTest(N, FT)
520        else:
521            P.writeFunction(N, FT)
522
523    if args:
524        [write(int(a)) for a in args]
525
526    for i in range(opts.count):
527        if opts.mode=='linear':
528            index = opts.minIndex + i
529        else:
530            index = opts.minIndex + int((opts.maxIndex-opts.minIndex) * random.random())
531        write(index)
532
533    P.finish()
534
535if __name__=='__main__':
536    main()
537
538