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