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