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