1#!/usr/bin/env python
2
3from pprint import pprint
4import random, atexit, time
5from random import randrange
6import re
7
8from Enumeration import *
9from TypeGen import *
10
11####
12
13class TypePrinter:
14    def __init__(self, output, outputHeader=None,
15                 outputTests=None, outputDriver=None,
16                 headerName=None, info=None):
17        self.output = output
18        self.outputHeader = outputHeader
19        self.outputTests = outputTests
20        self.outputDriver = outputDriver
21        self.writeBody = outputHeader or outputTests or outputDriver
22        self.types = {}
23        self.testValues = {}
24        self.testReturnValues = {}
25        self.layoutTests = []
26        self.declarations = set()
27
28        if info:
29            for f in (self.output,self.outputHeader,self.outputTests,self.outputDriver):
30                if f:
31                    print >>f,info
32
33        if self.writeBody:
34            print >>self.output, '#include <stdio.h>\n'
35            if self.outputTests:
36                print >>self.outputTests, '#include <stdio.h>'
37                print >>self.outputTests, '#include <string.h>'
38                print >>self.outputTests, '#include <assert.h>\n'
39
40        if headerName:
41            for f in (self.output,self.outputTests,self.outputDriver):
42                if f is not None:
43                    print >>f, '#include "%s"\n'%(headerName,)
44
45        if self.outputDriver:
46            print >>self.outputDriver, '#include <stdio.h>'
47            print >>self.outputDriver, '#include <stdlib.h>\n'
48            print >>self.outputDriver, 'int main(int argc, char **argv) {'
49            print >>self.outputDriver, '  int index = -1;'
50            print >>self.outputDriver, '  if (argc > 1) index = atoi(argv[1]);'
51
52    def finish(self):
53        if self.layoutTests:
54            print >>self.output, 'int main(int argc, char **argv) {'
55            print >>self.output, '  int index = -1;'
56            print >>self.output, '  if (argc > 1) index = atoi(argv[1]);'
57            for i,f in self.layoutTests:
58                print >>self.output, '  if (index == -1 || index == %d)' % i
59                print >>self.output, '    %s();' % f
60            print >>self.output, '  return 0;'
61            print >>self.output, '}'
62
63        if self.outputDriver:
64            print >>self.outputDriver, '  printf("DONE\\n");'
65            print >>self.outputDriver, '  return 0;'
66            print >>self.outputDriver, '}'
67
68    def addDeclaration(self, decl):
69        if decl in self.declarations:
70            return False
71
72        self.declarations.add(decl)
73        if self.outputHeader:
74            print >>self.outputHeader, decl
75        else:
76            print >>self.output, decl
77            if self.outputTests:
78                print >>self.outputTests, decl
79        return True
80
81    def getTypeName(self, T):
82        name = self.types.get(T)
83        if name is None:
84            # Reserve slot
85            self.types[T] = None
86            self.types[T] = name = T.getTypeName(self)
87        return name
88
89    def writeLayoutTest(self, i, ty):
90        tyName = self.getTypeName(ty)
91        tyNameClean = tyName.replace(' ','_').replace('*','star')
92        fnName = 'test_%s' % tyNameClean
93
94        print >>self.output,'void %s(void) {' % fnName
95        self.printSizeOfType('    %s'%fnName, tyName, ty, self.output)
96        self.printAlignOfType('    %s'%fnName, tyName, ty, self.output)
97        self.printOffsetsOfType('    %s'%fnName, tyName, ty, self.output)
98        print >>self.output,'}'
99        print >>self.output
100
101        self.layoutTests.append((i,fnName))
102
103    def writeFunction(self, i, FT):
104        args = ', '.join(['%s arg%d'%(self.getTypeName(t),i) for i,t in enumerate(FT.argTypes)])
105        if not args:
106            args = 'void'
107
108        if FT.returnType is None:
109            retvalName = None
110            retvalTypeName = 'void'
111        else:
112            retvalTypeName = self.getTypeName(FT.returnType)
113            if self.writeBody or self.outputTests:
114                retvalName = self.getTestReturnValue(FT.returnType)
115
116        fnName = 'fn%d'%(FT.index,)
117        if self.outputHeader:
118            print >>self.outputHeader,'%s %s(%s);'%(retvalTypeName, fnName, args)
119        elif self.outputTests:
120            print >>self.outputTests,'%s %s(%s);'%(retvalTypeName, fnName, args)
121
122        print >>self.output,'%s %s(%s)'%(retvalTypeName, fnName, args),
123        if self.writeBody:
124            print >>self.output, '{'
125
126            for i,t in enumerate(FT.argTypes):
127                self.printValueOfType('    %s'%fnName, 'arg%d'%i, t)
128
129            if retvalName is not None:
130                print >>self.output, '  return %s;'%(retvalName,)
131            print >>self.output, '}'
132        else:
133            print >>self.output, '{}'
134        print >>self.output
135
136        if self.outputDriver:
137            print >>self.outputDriver, '  if (index == -1 || index == %d) {' % i
138            print >>self.outputDriver, '    extern void test_%s(void);' % fnName
139            print >>self.outputDriver, '    test_%s();' % fnName
140            print >>self.outputDriver, '   }'
141
142        if self.outputTests:
143            if self.outputHeader:
144                print >>self.outputHeader, 'void test_%s(void);'%(fnName,)
145
146            if retvalName is None:
147                retvalTests = None
148            else:
149                retvalTests = self.getTestValuesArray(FT.returnType)
150            tests = map(self.getTestValuesArray, FT.argTypes)
151            print >>self.outputTests, 'void test_%s(void) {'%(fnName,)
152
153            if retvalTests is not None:
154                print >>self.outputTests, '  printf("%s: testing return.\\n");'%(fnName,)
155                print >>self.outputTests, '  for (int i=0; i<%d; ++i) {'%(retvalTests[1],)
156                args = ', '.join(['%s[%d]'%(t,randrange(l)) for t,l in tests])
157                print >>self.outputTests, '    %s RV;'%(retvalTypeName,)
158                print >>self.outputTests, '    %s = %s[i];'%(retvalName, retvalTests[0])
159                print >>self.outputTests, '    RV = %s(%s);'%(fnName, args)
160                self.printValueOfType('  %s_RV'%fnName, 'RV', FT.returnType, output=self.outputTests, indent=4)
161                self.checkTypeValues('RV', '%s[i]' % retvalTests[0], FT.returnType, output=self.outputTests, indent=4)
162                print >>self.outputTests, '  }'
163
164            if tests:
165                print >>self.outputTests, '  printf("%s: testing arguments.\\n");'%(fnName,)
166            for i,(array,length) in enumerate(tests):
167                for j in range(length):
168                    args = ['%s[%d]'%(t,randrange(l)) for t,l in tests]
169                    args[i] = '%s[%d]'%(array,j)
170                    print >>self.outputTests, '  %s(%s);'%(fnName, ', '.join(args),)
171            print >>self.outputTests, '}'
172
173    def getTestReturnValue(self, type):
174        typeName = self.getTypeName(type)
175        info = self.testReturnValues.get(typeName)
176        if info is None:
177            name = '%s_retval'%(typeName.replace(' ','_').replace('*','star'),)
178            print >>self.output, '%s %s;'%(typeName,name)
179            if self.outputHeader:
180                print >>self.outputHeader, 'extern %s %s;'%(typeName,name)
181            elif self.outputTests:
182                print >>self.outputTests, 'extern %s %s;'%(typeName,name)
183            info = self.testReturnValues[typeName] = name
184        return info
185
186    def getTestValuesArray(self, type):
187        typeName = self.getTypeName(type)
188        info = self.testValues.get(typeName)
189        if info is None:
190            name = '%s_values'%(typeName.replace(' ','_').replace('*','star'),)
191            print >>self.outputTests, 'static %s %s[] = {'%(typeName,name)
192            length = 0
193            for item in self.getTestValues(type):
194                print >>self.outputTests, '\t%s,'%(item,)
195                length += 1
196            print >>self.outputTests,'};'
197            info = self.testValues[typeName] = (name,length)
198        return info
199
200    def getTestValues(self, t):
201        if isinstance(t, BuiltinType):
202            if t.name=='float':
203                for i in ['0.0','-1.0','1.0']:
204                    yield i+'f'
205            elif t.name=='double':
206                for i in ['0.0','-1.0','1.0']:
207                    yield i
208            elif t.name in ('void *'):
209                yield '(void*) 0'
210                yield '(void*) -1'
211            else:
212                yield '(%s) 0'%(t.name,)
213                yield '(%s) -1'%(t.name,)
214                yield '(%s) 1'%(t.name,)
215        elif isinstance(t, EnumType):
216            for i in range(0, len(t.enumerators)):
217                yield 'enum%dval%d' % (t.index, i)
218        elif isinstance(t, RecordType):
219            nonPadding = [f for f in t.fields
220                          if not f.isPaddingBitField()]
221
222            if not nonPadding:
223                yield '{ }'
224                return
225
226            # FIXME: Use designated initializers to access non-first
227            # fields of unions.
228            if t.isUnion:
229                for v in self.getTestValues(nonPadding[0]):
230                    yield '{ %s }' % v
231                return
232
233            fieldValues = map(list, map(self.getTestValues, nonPadding))
234            for i,values in enumerate(fieldValues):
235                for v in values:
236                    elements = map(random.choice,fieldValues)
237                    elements[i] = v
238                    yield '{ %s }'%(', '.join(elements))
239
240        elif isinstance(t, ComplexType):
241            for t in self.getTestValues(t.elementType):
242                yield '%s + %s * 1i'%(t,t)
243        elif isinstance(t, ArrayType):
244            values = list(self.getTestValues(t.elementType))
245            if not values:
246                yield '{ }'
247            for i in range(t.numElements):
248                for v in values:
249                    elements = [random.choice(values) for i in range(t.numElements)]
250                    elements[i] = v
251                    yield '{ %s }'%(', '.join(elements))
252        else:
253            raise NotImplementedError,'Cannot make tests values of type: "%s"'%(t,)
254
255    def printSizeOfType(self, prefix, name, t, output=None, indent=2):
256        print >>output, '%*sprintf("%s: sizeof(%s) = %%ld\\n", (long)sizeof(%s));'%(indent, '', prefix, name, name)
257    def printAlignOfType(self, prefix, name, t, output=None, indent=2):
258        print >>output, '%*sprintf("%s: __alignof__(%s) = %%ld\\n", (long)__alignof__(%s));'%(indent, '', prefix, name, name)
259    def printOffsetsOfType(self, prefix, name, t, output=None, indent=2):
260        if isinstance(t, RecordType):
261            for i,f in enumerate(t.fields):
262                if f.isBitField():
263                    continue
264                fname = 'field%d' % i
265                print >>output, '%*sprintf("%s: __builtin_offsetof(%s, %s) = %%ld\\n", (long)__builtin_offsetof(%s, %s));'%(indent, '', prefix, name, fname, name, fname)
266
267    def printValueOfType(self, prefix, name, t, output=None, indent=2):
268        if output is None:
269            output = self.output
270        if isinstance(t, BuiltinType):
271            value_expr = name
272            if t.name.split(' ')[-1] == '_Bool':
273                # Hack to work around PR5579.
274                value_expr = "%s ? 2 : 0" % name
275
276            if t.name.endswith('long long'):
277                code = 'lld'
278            elif t.name.endswith('long'):
279                code = 'ld'
280            elif t.name.split(' ')[-1] in ('_Bool','char','short',
281                                           'int','unsigned'):
282                code = 'd'
283            elif t.name in ('float','double'):
284                code = 'f'
285            elif t.name == 'long double':
286                code = 'Lf'
287            else:
288                code = 'p'
289            print >>output, '%*sprintf("%s: %s = %%%s\\n", %s);'%(
290                indent, '', prefix, name, code, value_expr)
291        elif isinstance(t, EnumType):
292            print >>output, '%*sprintf("%s: %s = %%d\\n", %s);'%(indent, '', prefix, name, name)
293        elif isinstance(t, RecordType):
294            if not t.fields:
295                print >>output, '%*sprintf("%s: %s (empty)\\n");'%(indent, '', prefix, name)
296            for i,f in enumerate(t.fields):
297                if f.isPaddingBitField():
298                    continue
299                fname = '%s.field%d'%(name,i)
300                self.printValueOfType(prefix, fname, f, output=output, indent=indent)
301        elif isinstance(t, ComplexType):
302            self.printValueOfType(prefix, '(__real %s)'%name, t.elementType, output=output,indent=indent)
303            self.printValueOfType(prefix, '(__imag %s)'%name, t.elementType, output=output,indent=indent)
304        elif isinstance(t, ArrayType):
305            for i in range(t.numElements):
306                # Access in this fashion as a hackish way to portably
307                # access vectors.
308                if t.isVector:
309                    self.printValueOfType(prefix, '((%s*) &%s)[%d]'%(t.elementType,name,i), t.elementType, output=output,indent=indent)
310                else:
311                    self.printValueOfType(prefix, '%s[%d]'%(name,i), t.elementType, output=output,indent=indent)
312        else:
313            raise NotImplementedError,'Cannot print value of type: "%s"'%(t,)
314
315    def checkTypeValues(self, nameLHS, nameRHS, t, output=None, indent=2):
316        prefix = 'foo'
317        if output is None:
318            output = self.output
319        if isinstance(t, BuiltinType):
320            print >>output, '%*sassert(%s == %s);' % (indent, '', nameLHS, nameRHS)
321        elif isinstance(t, EnumType):
322            print >>output, '%*sassert(%s == %s);' % (indent, '', nameLHS, nameRHS)
323        elif isinstance(t, RecordType):
324            for i,f in enumerate(t.fields):
325                if f.isPaddingBitField():
326                    continue
327                self.checkTypeValues('%s.field%d'%(nameLHS,i), '%s.field%d'%(nameRHS,i),
328                                     f, output=output, indent=indent)
329                if t.isUnion:
330                    break
331        elif isinstance(t, ComplexType):
332            self.checkTypeValues('(__real %s)'%nameLHS, '(__real %s)'%nameRHS, t.elementType, output=output,indent=indent)
333            self.checkTypeValues('(__imag %s)'%nameLHS, '(__imag %s)'%nameRHS, t.elementType, output=output,indent=indent)
334        elif isinstance(t, ArrayType):
335            for i in range(t.numElements):
336                # Access in this fashion as a hackish way to portably
337                # access vectors.
338                if t.isVector:
339                    self.checkTypeValues('((%s*) &%s)[%d]'%(t.elementType,nameLHS,i),
340                                         '((%s*) &%s)[%d]'%(t.elementType,nameRHS,i),
341                                         t.elementType, output=output,indent=indent)
342                else:
343                    self.checkTypeValues('%s[%d]'%(nameLHS,i), '%s[%d]'%(nameRHS,i),
344                                         t.elementType, output=output,indent=indent)
345        else:
346            raise NotImplementedError,'Cannot print value of type: "%s"'%(t,)
347
348import sys
349
350def main():
351    from optparse import OptionParser, OptionGroup
352    parser = OptionParser("%prog [options] {indices}")
353    parser.add_option("", "--mode", dest="mode",
354                      help="autogeneration mode (random or linear) [default %default]",
355                      type='choice', choices=('random','linear'), default='linear')
356    parser.add_option("", "--count", dest="count",
357                      help="autogenerate COUNT functions according to MODE",
358                      type=int, default=0)
359    parser.add_option("", "--min", dest="minIndex", metavar="N",
360                      help="start autogeneration with the Nth function type  [default %default]",
361                      type=int, default=0)
362    parser.add_option("", "--max", dest="maxIndex", metavar="N",
363                      help="maximum index for random autogeneration  [default %default]",
364                      type=int, default=10000000)
365    parser.add_option("", "--seed", dest="seed",
366                      help="random number generator seed [default %default]",
367                      type=int, default=1)
368    parser.add_option("", "--use-random-seed", dest="useRandomSeed",
369                      help="use random value for initial random number generator seed",
370                      action='store_true', default=False)
371    parser.add_option("", "--skip", dest="skipTests",
372                      help="add a test index to skip",
373                      type=int, action='append', default=[])
374    parser.add_option("-o", "--output", dest="output", metavar="FILE",
375                      help="write output to FILE  [default %default]",
376                      type=str, default='-')
377    parser.add_option("-O", "--output-header", dest="outputHeader", metavar="FILE",
378                      help="write header file for output to FILE  [default %default]",
379                      type=str, default=None)
380    parser.add_option("-T", "--output-tests", dest="outputTests", metavar="FILE",
381                      help="write function tests to FILE  [default %default]",
382                      type=str, default=None)
383    parser.add_option("-D", "--output-driver", dest="outputDriver", metavar="FILE",
384                      help="write test driver to FILE  [default %default]",
385                      type=str, default=None)
386    parser.add_option("", "--test-layout", dest="testLayout", metavar="FILE",
387                      help="test structure layout",
388                      action='store_true', default=False)
389
390    group = OptionGroup(parser, "Type Enumeration Options")
391    # Builtins - Ints
392    group.add_option("", "--no-char", dest="useChar",
393                     help="do not generate char types",
394                     action="store_false", default=True)
395    group.add_option("", "--no-short", dest="useShort",
396                     help="do not generate short types",
397                     action="store_false", default=True)
398    group.add_option("", "--no-int", dest="useInt",
399                     help="do not generate int types",
400                     action="store_false", default=True)
401    group.add_option("", "--no-long", dest="useLong",
402                     help="do not generate long types",
403                     action="store_false", default=True)
404    group.add_option("", "--no-long-long", dest="useLongLong",
405                     help="do not generate long long types",
406                     action="store_false", default=True)
407    group.add_option("", "--no-unsigned", dest="useUnsigned",
408                     help="do not generate unsigned integer types",
409                     action="store_false", default=True)
410
411    # Other builtins
412    group.add_option("", "--no-bool", dest="useBool",
413                     help="do not generate bool types",
414                     action="store_false", default=True)
415    group.add_option("", "--no-float", dest="useFloat",
416                     help="do not generate float types",
417                     action="store_false", default=True)
418    group.add_option("", "--no-double", dest="useDouble",
419                     help="do not generate double types",
420                     action="store_false", default=True)
421    group.add_option("", "--no-long-double", dest="useLongDouble",
422                     help="do not generate long double types",
423                     action="store_false", default=True)
424    group.add_option("", "--no-void-pointer", dest="useVoidPointer",
425                     help="do not generate void* types",
426                     action="store_false", default=True)
427
428    # Enumerations
429    group.add_option("", "--no-enums", dest="useEnum",
430                     help="do not generate enum types",
431                     action="store_false", default=True)
432
433    # Derived types
434    group.add_option("", "--no-array", dest="useArray",
435                     help="do not generate record types",
436                     action="store_false", default=True)
437    group.add_option("", "--no-complex", dest="useComplex",
438                     help="do not generate complex types",
439                     action="store_false", default=True)
440    group.add_option("", "--no-record", dest="useRecord",
441                     help="do not generate record types",
442                     action="store_false", default=True)
443    group.add_option("", "--no-union", dest="recordUseUnion",
444                     help="do not generate union types",
445                     action="store_false", default=True)
446    group.add_option("", "--no-vector", dest="useVector",
447                     help="do not generate vector types",
448                     action="store_false", default=True)
449    group.add_option("", "--no-bit-field", dest="useBitField",
450                     help="do not generate bit-field record members",
451                     action="store_false", default=True)
452    group.add_option("", "--no-builtins", dest="useBuiltins",
453                     help="do not use any types",
454                     action="store_false", default=True)
455
456    # Tuning
457    group.add_option("", "--no-function-return", dest="functionUseReturn",
458                     help="do not generate return types for functions",
459                     action="store_false", default=True)
460    group.add_option("", "--vector-types", dest="vectorTypes",
461                     help="comma separated list of vector types (e.g., v2i32) [default %default]",
462                     action="store", type=str, default='v2i16, v1i64, v2i32, v4i16, v8i8, v2f32, v2i64, v4i32, v8i16, v16i8, v2f64, v4f32, v16f32', metavar="N")
463    group.add_option("", "--bit-fields", dest="bitFields",
464                     help="comma separated list 'type:width' bit-field specifiers [default %default]",
465                     action="store", type=str, default=(
466            "char:0,char:4,int:0,unsigned:1,int:1,int:4,int:13,int:24"))
467    group.add_option("", "--max-args", dest="functionMaxArgs",
468                     help="maximum number of arguments per function [default %default]",
469                     action="store", type=int, default=4, metavar="N")
470    group.add_option("", "--max-array", dest="arrayMaxSize",
471                     help="maximum array size [default %default]",
472                     action="store", type=int, default=4, metavar="N")
473    group.add_option("", "--max-record", dest="recordMaxSize",
474                     help="maximum number of fields per record [default %default]",
475                     action="store", type=int, default=4, metavar="N")
476    group.add_option("", "--max-record-depth", dest="recordMaxDepth",
477                     help="maximum nested structure depth [default %default]",
478                     action="store", type=int, default=None, metavar="N")
479    parser.add_option_group(group)
480    (opts, args) = parser.parse_args()
481
482    if not opts.useRandomSeed:
483        random.seed(opts.seed)
484
485    # Construct type generator
486    builtins = []
487    if opts.useBuiltins:
488        ints = []
489        if opts.useChar: ints.append(('char',1))
490        if opts.useShort: ints.append(('short',2))
491        if opts.useInt: ints.append(('int',4))
492        # FIXME: Wrong size.
493        if opts.useLong: ints.append(('long',4))
494        if opts.useLongLong: ints.append(('long long',8))
495        if opts.useUnsigned:
496            ints = ([('unsigned %s'%i,s) for i,s in ints] +
497                    [('signed %s'%i,s) for i,s in ints])
498        builtins.extend(ints)
499
500        if opts.useBool: builtins.append(('_Bool',1))
501        if opts.useFloat: builtins.append(('float',4))
502        if opts.useDouble: builtins.append(('double',8))
503        if opts.useLongDouble: builtins.append(('long double',16))
504        # FIXME: Wrong size.
505        if opts.useVoidPointer:  builtins.append(('void*',4))
506
507    btg = FixedTypeGenerator([BuiltinType(n,s) for n,s in builtins])
508
509    bitfields = []
510    for specifier in opts.bitFields.split(','):
511        if not specifier.strip():
512            continue
513        name,width = specifier.strip().split(':', 1)
514        bitfields.append(BuiltinType(name,None,int(width)))
515    bftg = FixedTypeGenerator(bitfields)
516
517    charType = BuiltinType('char',1)
518    shortType = BuiltinType('short',2)
519    intType = BuiltinType('int',4)
520    longlongType = BuiltinType('long long',8)
521    floatType = BuiltinType('float',4)
522    doubleType = BuiltinType('double',8)
523    sbtg = FixedTypeGenerator([charType, intType, floatType, doubleType])
524
525    atg = AnyTypeGenerator()
526    artg = AnyTypeGenerator()
527    def makeGenerator(atg, subgen, subfieldgen, useRecord, useArray, useBitField):
528        atg.addGenerator(btg)
529        if useBitField and opts.useBitField:
530            atg.addGenerator(bftg)
531        if useRecord and opts.useRecord:
532            assert subgen
533            atg.addGenerator(RecordTypeGenerator(subfieldgen, opts.recordUseUnion,
534                                                 opts.recordMaxSize))
535        if opts.useComplex:
536            # FIXME: Allow overriding builtins here
537            atg.addGenerator(ComplexTypeGenerator(sbtg))
538        if useArray and opts.useArray:
539            assert subgen
540            atg.addGenerator(ArrayTypeGenerator(subgen, opts.arrayMaxSize))
541        if opts.useVector:
542            vTypes = []
543            for i,t in enumerate(opts.vectorTypes.split(',')):
544                m = re.match('v([1-9][0-9]*)([if][1-9][0-9]*)', t.strip())
545                if not m:
546                    parser.error('Invalid vector type: %r' % t)
547                count,kind = m.groups()
548                count = int(count)
549                type = { 'i8'  : charType,
550                         'i16' : shortType,
551                         'i32' : intType,
552                         'i64' : longlongType,
553                         'f32' : floatType,
554                         'f64' : doubleType,
555                         }.get(kind)
556                if not type:
557                    parser.error('Invalid vector type: %r' % t)
558                vTypes.append(ArrayType(i, True, type, count * type.size))
559
560            atg.addGenerator(FixedTypeGenerator(vTypes))
561        if opts.useEnum:
562            atg.addGenerator(EnumTypeGenerator([None, '-1', '1', '1u'], 1, 4))
563
564    if opts.recordMaxDepth is None:
565        # Fully recursive, just avoid top-level arrays.
566        subFTG = AnyTypeGenerator()
567        subTG = AnyTypeGenerator()
568        atg = AnyTypeGenerator()
569        makeGenerator(subFTG, atg, atg, True, True, True)
570        makeGenerator(subTG, atg, subFTG, True, True, False)
571        makeGenerator(atg, subTG, subFTG, True, False, False)
572    else:
573        # Make a chain of type generators, each builds smaller
574        # structures.
575        base = AnyTypeGenerator()
576        fbase = AnyTypeGenerator()
577        makeGenerator(base, None, None, False, False, False)
578        makeGenerator(fbase, None, None, False, False, True)
579        for i in range(opts.recordMaxDepth):
580            n = AnyTypeGenerator()
581            fn = AnyTypeGenerator()
582            makeGenerator(n, base, fbase, True, True, False)
583            makeGenerator(fn, base, fbase, True, True, True)
584            base = n
585            fbase = fn
586        atg = AnyTypeGenerator()
587        makeGenerator(atg, base, fbase, True, False, False)
588
589    if opts.testLayout:
590        ftg = atg
591    else:
592        ftg = FunctionTypeGenerator(atg, opts.functionUseReturn, opts.functionMaxArgs)
593
594    # Override max,min,count if finite
595    if opts.maxIndex is None:
596        if ftg.cardinality is aleph0:
597            opts.maxIndex = 10000000
598        else:
599            opts.maxIndex = ftg.cardinality
600    opts.maxIndex = min(opts.maxIndex, ftg.cardinality)
601    opts.minIndex = max(0,min(opts.maxIndex-1, opts.minIndex))
602    if not opts.mode=='random':
603        opts.count = min(opts.count, opts.maxIndex-opts.minIndex)
604
605    if opts.output=='-':
606        output = sys.stdout
607    else:
608        output = open(opts.output,'w')
609        atexit.register(lambda: output.close())
610
611    outputHeader = None
612    if opts.outputHeader:
613        outputHeader = open(opts.outputHeader,'w')
614        atexit.register(lambda: outputHeader.close())
615
616    outputTests = None
617    if opts.outputTests:
618        outputTests = open(opts.outputTests,'w')
619        atexit.register(lambda: outputTests.close())
620
621    outputDriver = None
622    if opts.outputDriver:
623        outputDriver = open(opts.outputDriver,'w')
624        atexit.register(lambda: outputDriver.close())
625
626    info = ''
627    info += '// %s\n'%(' '.join(sys.argv),)
628    info += '// Generated: %s\n'%(time.strftime('%Y-%m-%d %H:%M'),)
629    info += '// Cardinality of function generator: %s\n'%(ftg.cardinality,)
630    info += '// Cardinality of type generator: %s\n'%(atg.cardinality,)
631
632    if opts.testLayout:
633        info += '\n#include <stdio.h>'
634
635    P = TypePrinter(output,
636                    outputHeader=outputHeader,
637                    outputTests=outputTests,
638                    outputDriver=outputDriver,
639                    headerName=opts.outputHeader,
640                    info=info)
641
642    def write(N):
643        try:
644            FT = ftg.get(N)
645        except RuntimeError,e:
646            if e.args[0]=='maximum recursion depth exceeded':
647                print >>sys.stderr,'WARNING: Skipped %d, recursion limit exceeded (bad arguments?)'%(N,)
648                return
649            raise
650        if opts.testLayout:
651            P.writeLayoutTest(N, FT)
652        else:
653            P.writeFunction(N, FT)
654
655    if args:
656        [write(int(a)) for a in args]
657
658    skipTests = set(opts.skipTests)
659    for i in range(opts.count):
660        if opts.mode=='linear':
661            index = opts.minIndex + i
662        else:
663            index = opts.minIndex + int((opts.maxIndex-opts.minIndex) * random.random())
664        if index in skipTests:
665            continue
666        write(index)
667
668    P.finish()
669
670if __name__=='__main__':
671    main()
672
673