blob: 957ce2bb16b11d520aa6a6383d3910abec9ab6ab [file] [log] [blame]
Daniel Dunbara83fb862009-01-15 04:24:17 +00001#!/usr/bin/python
2
3from pprint import pprint
4import random, atexit, time
5from random import randrange
6
7from Enumeration import *
8from TypeGen import *
9
10####
11
12class TypePrinter:
13 def __init__(self, output, outputHeader=None,
14 outputTests=None, outputDriver=None,
15 headerName=None, info=None):
16 self.output = output
17 self.outputHeader = outputHeader
18 self.outputTests = outputTests
19 self.outputDriver = outputDriver
20 self.writeBody = outputHeader or outputTests or outputDriver
21 self.types = {}
22 self.testValues = {}
23 self.testReturnValues = {}
24
25 if info:
26 for f in (self.output,self.outputHeader,self.outputTests,self.outputDriver):
27 if f:
28 print >>f,info
29
30 if self.writeBody:
31 print >>self.output, '#include <stdio.h>\n'
32 if self.outputTests:
33 print >>self.outputTests, '#include <stdio.h>\n'
34
35 if headerName:
36 for f in (self.output,self.outputTests,self.outputDriver):
37 if f is not None:
38 print >>f, '#include "%s"\n'%(headerName,)
39
40 if self.outputDriver:
41 print >>self.outputDriver, 'int main(int argc, char **argv) {'
42
43 def finish(self):
44 if self.outputDriver:
45 print >>self.outputDriver, ' return 0;'
46 print >>self.outputDriver, '}'
47
48 def getTypeName(self, T):
49 if isinstance(T,BuiltinType):
50 return T.name
51 name = self.types.get(T)
52 if name is None:
53 name = 'T%d'%(len(self.types),)
54 # Reserve slot
55 self.types[T] = None
56 if self.outputHeader:
57 print >>self.outputHeader,T.getTypedefDef(name, self)
58 else:
59 print >>self.output,T.getTypedefDef(name, self)
60 if self.outputTests:
61 print >>self.outputTests,T.getTypedefDef(name, self)
62 self.types[T] = name
63 return name
64
65 def writeFunction(self, i, FT):
66 args = ', '.join(['%s arg%d'%(self.getTypeName(t),i) for i,t in enumerate(FT.argTypes)])
67 if not args:
68 args = 'void'
69
70 if FT.returnType is None:
71 retvalName = None
72 retvalTypeName = 'void'
73 else:
74 retvalTypeName = self.getTypeName(FT.returnType)
75 if self.writeBody or self.outputTests:
76 retvalName = self.getTestReturnValue(FT.returnType)
77
78 fnName = 'fn%d'%(FT.index,)
79 if self.outputHeader:
80 print >>self.outputHeader,'%s %s(%s);'%(retvalTypeName, fnName, args)
81 elif self.outputTests:
82 print >>self.outputTests,'%s %s(%s);'%(retvalTypeName, fnName, args)
83
84 print >>self.output,'%s %s(%s)'%(retvalTypeName, fnName, args),
85 if self.writeBody:
86 print >>self.output, '{'
87
88 for i,t in enumerate(FT.argTypes):
89 self.printValueOfType(' %s'%fnName, 'arg%d'%i, t)
90
91 if retvalName is not None:
92 print >>self.output, ' return %s;'%(retvalName,)
93 print >>self.output, '}'
94 else:
95 print >>self.output, '{}'
96 print >>self.output
97
98 if self.outputDriver:
99 print >>self.outputDriver, ' { extern void test_%s(void); test_%s(); }\n'%(fnName,fnName,)
100
101 if self.outputTests:
102 if self.outputHeader:
103 print >>self.outputHeader, 'void test_%s(void);'%(fnName,)
104
105 if retvalName is None:
106 retvalTests = None
107 else:
108 retvalTests = self.getTestValuesArray(FT.returnType)
109 tests = map(self.getTestValuesArray, FT.argTypes)
110 print >>self.outputTests, 'void test_%s(void) {'%(fnName,)
111
112 if retvalTests is not None:
113 print >>self.outputTests, ' printf("%s: testing return.\\n");'%(fnName,)
114 print >>self.outputTests, ' for (int i=0; i<%d; ++i) {'%(retvalTests[1],)
115 args = ', '.join(['%s[%d]'%(t,randrange(l)) for t,l in tests])
116 print >>self.outputTests, ' %s RV;'%(retvalTypeName,)
117 print >>self.outputTests, ' %s = %s[i];'%(retvalName, retvalTests[0])
118 print >>self.outputTests, ' RV = %s(%s);'%(fnName, args)
119 self.printValueOfType(' %s_RV'%fnName, 'RV', FT.returnType, output=self.outputTests, indent=4)
120 print >>self.outputTests, ' }'
121
122 if tests:
123 print >>self.outputTests, ' printf("%s: testing arguments.\\n");'%(fnName,)
124 for i,(array,length) in enumerate(tests):
125 for j in range(length):
126 args = ['%s[%d]'%(t,randrange(l)) for t,l in tests]
127 args[i] = '%s[%d]'%(array,j)
128 print >>self.outputTests, ' %s(%s);'%(fnName, ', '.join(args),)
129 print >>self.outputTests, '}'
130
131 def getTestReturnValue(self, type):
132 typeName = self.getTypeName(type)
133 info = self.testReturnValues.get(typeName)
134 if info is None:
135 name = '%s_retval'%(typeName.replace(' ','_').replace('*','star'),)
136 print >>self.output, '%s %s;'%(typeName,name)
137 if self.outputHeader:
138 print >>self.outputHeader, 'extern %s %s;'%(typeName,name)
139 elif self.outputTests:
140 print >>self.outputTests, 'extern %s %s;'%(typeName,name)
141 info = self.testReturnValues[typeName] = name
142 return info
143
144 def getTestValuesArray(self, type):
145 typeName = self.getTypeName(type)
146 info = self.testValues.get(typeName)
147 if info is None:
148 name = '%s_values'%(typeName.replace(' ','_').replace('*','star'),)
149 print >>self.outputTests, 'static %s %s[] = {'%(typeName,name)
150 length = 0
151 for item in self.getTestValues(type):
152 print >>self.outputTests, '\t%s,'%(item,)
153 length += 1
154 print >>self.outputTests,'};'
155 info = self.testValues[typeName] = (name,length)
156 return info
157
158 def getTestValues(self, t):
159 if isinstance(t, BuiltinType):
160 if t.name=='float':
161 for i in ['0.0','-1.0','1.0']:
162 yield i+'f'
163 elif t.name=='double':
164 for i in ['0.0','-1.0','1.0']:
165 yield i
166 elif t.name in ('void *'):
167 yield '(void*) 0'
168 yield '(void*) -1'
169 else:
170 yield '(%s) 0'%(t.name,)
171 yield '(%s) -1'%(t.name,)
172 yield '(%s) 1'%(t.name,)
173 elif isinstance(t, RecordType):
174 fieldValues = [list(self.getTestValues(f)) for f in t.fields]
175 if not t.fields:
176 yield '{ }'
177 for i,values in enumerate(fieldValues):
178 for v in values:
179 elements = map(random.choice,fieldValues)
180 elements[i] = v
181 yield '{ %s }'%(', '.join(elements))
182 elif isinstance(t, ComplexType):
183 for t in self.getTestValues(t.elementType):
Daniel Dunbar550faa32009-01-26 19:05:20 +0000184 yield '%s + %s * 1i'%(t,t)
185 elif isinstance(t, ArrayType):
Daniel Dunbara83fb862009-01-15 04:24:17 +0000186 values = list(self.getTestValues(t.elementType))
187 if not values:
188 yield '{ }'
Daniel Dunbar550faa32009-01-26 19:05:20 +0000189 for i in range(t.numElements):
Daniel Dunbara83fb862009-01-15 04:24:17 +0000190 for v in values:
Daniel Dunbar550faa32009-01-26 19:05:20 +0000191 elements = [random.choice(values) for i in range(t.numElements)]
Daniel Dunbara83fb862009-01-15 04:24:17 +0000192 elements[i] = v
193 yield '{ %s }'%(', '.join(elements))
194 else:
195 raise NotImplementedError,'Cannot make tests values of type: "%s"'%(t,)
196
197 def printValueOfType(self, prefix, name, t, output=None, indent=2):
198 if output is None:
199 output = self.output
200 if isinstance(t, BuiltinType):
201 if t.name.endswith('long long'):
202 code = 'lld'
203 elif t.name.endswith('long'):
204 code = 'ld'
205 elif t.name.split(' ')[-1] in ('_Bool','char','short','int'):
206 code = 'd'
207 elif t.name in ('float','double'):
208 code = 'f'
209 elif t.name == 'long double':
210 code = 'Lf'
211 else:
212 code = 'p'
213 print >>output, '%*sprintf("%s: %s = %%%s\\n", %s);'%(indent, '', prefix, name, code, name)
214 elif isinstance(t, RecordType):
215 if not t.fields:
216 print >>output, '%*sprintf("%s: %s (empty)\\n");'%(indent, '', prefix, name)
217 for i,f in enumerate(t.fields):
218 fname = '%s.field%d'%(name,i)
219 self.printValueOfType(prefix, fname, f, output=output, indent=indent)
220 elif isinstance(t, ComplexType):
221 self.printValueOfType(prefix, '(__real %s)'%name, t.elementType, output=output,indent=indent)
222 self.printValueOfType(prefix, '(__imag %s)'%name, t.elementType, output=output,indent=indent)
Daniel Dunbar550faa32009-01-26 19:05:20 +0000223 elif isinstance(t, ArrayType):
224 for i in range(t.numElements):
225 # Access in this fashion as a hackish way to portably
226 # access vectors.
227 self.printValueOfType(prefix, '((%s*) &%s)[%d]'%(t.elementType,name,i), t.elementType, output=output,indent=indent)
Daniel Dunbara83fb862009-01-15 04:24:17 +0000228 else:
229 raise NotImplementedError,'Cannot print value of type: "%s"'%(t,)
230
231import sys
232
233def main():
234 from optparse import OptionParser, OptionGroup
235 parser = OptionParser("%prog [options] {indices}")
236 parser.add_option("", "--mode", dest="mode",
237 help="autogeneration mode (random or linear) [default %default]",
238 type='choice', choices=('random','linear'), default='linear')
239 parser.add_option("", "--count", dest="count",
240 help="autogenerate COUNT functions according to MODE",
241 type=int, default=0)
242 parser.add_option("", "--min", dest="minIndex", metavar="N",
243 help="start autogeneration with the Nth function type [default %default]",
244 type=int, default=0)
245 parser.add_option("", "--max", dest="maxIndex", metavar="N",
246 help="maximum index for random autogeneration [default %default]",
247 type=int, default=10000000)
248 parser.add_option("", "--seed", dest="seed",
249 help="random number generator seed [default %default]",
250 type=int, default=1)
251 parser.add_option("", "--use-random-seed", dest="useRandomSeed",
252 help="use random value for initial random number generator seed",
253 action='store_true', default=False)
254 parser.add_option("-o", "--output", dest="output", metavar="FILE",
255 help="write output to FILE [default %default]",
256 type=str, default='-')
257 parser.add_option("-O", "--output-header", dest="outputHeader", metavar="FILE",
258 help="write header file for output to FILE [default %default]",
259 type=str, default=None)
260 parser.add_option("-T", "--output-tests", dest="outputTests", metavar="FILE",
261 help="write function tests to FILE [default %default]",
262 type=str, default=None)
263 parser.add_option("-D", "--output-driver", dest="outputDriver", metavar="FILE",
264 help="write test driver to FILE [default %default]",
265 type=str, default=None)
266
267 group = OptionGroup(parser, "Type Enumeration Options")
268 # Builtins - Ints
269 group.add_option("", "--no-char", dest="useChar",
270 help="do not generate char types",
271 action="store_false", default=True)
272 group.add_option("", "--no-short", dest="useShort",
273 help="do not generate short types",
274 action="store_false", default=True)
275 group.add_option("", "--no-int", dest="useInt",
276 help="do not generate int types",
277 action="store_false", default=True)
278 group.add_option("", "--no-long", dest="useLong",
279 help="do not generate long types",
280 action="store_false", default=True)
281 group.add_option("", "--no-long-long", dest="useLongLong",
282 help="do not generate long long types",
283 action="store_false", default=True)
284 group.add_option("", "--no-unsigned", dest="useUnsigned",
285 help="do not generate unsigned integer types",
286 action="store_false", default=True)
287
288 # Other builtins
289 group.add_option("", "--no-bool", dest="useBool",
290 help="do not generate bool types",
291 action="store_false", default=True)
292 group.add_option("", "--no-float", dest="useFloat",
293 help="do not generate float types",
294 action="store_false", default=True)
295 group.add_option("", "--no-double", dest="useDouble",
296 help="do not generate double types",
297 action="store_false", default=True)
298 group.add_option("", "--no-long-double", dest="useLongDouble",
299 help="do not generate long double types",
300 action="store_false", default=True)
301 group.add_option("", "--no-void-pointer", dest="useVoidPointer",
302 help="do not generate void* types",
303 action="store_false", default=True)
304
305 # Derived types
306 group.add_option("", "--no-array", dest="useArray",
307 help="do not generate record types",
308 action="store_false", default=True)
309 group.add_option("", "--no-complex", dest="useComplex",
310 help="do not generate complex types",
311 action="store_false", default=True)
312 group.add_option("", "--no-record", dest="useRecord",
313 help="do not generate record types",
314 action="store_false", default=True)
315 group.add_option("", "--no-union", dest="recordUseUnion",
316 help="do not generate union types",
317 action="store_false", default=True)
318 group.add_option("", "--no-vector", dest="useVector",
319 help="do not generate vector types",
320 action="store_false", default=True)
321
322 # Tuning
323 group.add_option("", "--no-function-return", dest="functionUseReturn",
324 help="do not generate return types for functions",
325 action="store_false", default=True)
326 group.add_option("", "--vector-sizes", dest="vectorSizes",
327 help="comma separated list of sizes for vectors [default %default]",
328 action="store", type=str, default='4,8', metavar="N")
329
330 group.add_option("", "--max-args", dest="functionMaxArgs",
331 help="maximum number of arguments per function [default %default]",
332 action="store", type=int, default=4, metavar="N")
333 group.add_option("", "--max-array", dest="arrayMaxSize",
334 help="maximum array size [default %default]",
335 action="store", type=int, default=4, metavar="N")
336 group.add_option("", "--max-record", dest="recordMaxSize",
337 help="maximum number of fields per record [default %default]",
338 action="store", type=int, default=4, metavar="N")
339 group.add_option("", "--max-record-depth", dest="recordMaxDepth",
340 help="maximum nested structure depth [default %default]",
341 action="store", type=int, default=None, metavar="N")
342 parser.add_option_group(group)
343 (opts, args) = parser.parse_args()
344
345 if not opts.useRandomSeed:
346 random.seed(opts.seed)
347
348 # Contruct type generator
349 builtins = []
350 ints = []
Daniel Dunbar550faa32009-01-26 19:05:20 +0000351 if opts.useChar: ints.append(('char',1))
352 if opts.useShort: ints.append(('short',2))
353 if opts.useInt: ints.append(('int',4))
354 # FIXME: Wrong size.
355 if opts.useLong: ints.append(('long',4))
356 if opts.useLongLong: ints.append(('long long',8))
Daniel Dunbara83fb862009-01-15 04:24:17 +0000357 if opts.useUnsigned:
Daniel Dunbar550faa32009-01-26 19:05:20 +0000358 ints = ([('unsigned %s'%i,s) for i,s in ints] +
359 [('signed %s'%i,s) for i,s in ints])
Daniel Dunbara83fb862009-01-15 04:24:17 +0000360 builtins.extend(ints)
361
Daniel Dunbar550faa32009-01-26 19:05:20 +0000362 if opts.useBool: builtins.append(('_Bool',1))
363 if opts.useFloat: builtins.append(('float',4))
364 if opts.useDouble: builtins.append(('double',8))
365 if opts.useLongDouble: builtins.append(('long double',16))
366 # FIXME: Wrong size.
367 if opts.useVoidPointer: builtins.append(('void*',4))
Daniel Dunbara83fb862009-01-15 04:24:17 +0000368
Daniel Dunbar550faa32009-01-26 19:05:20 +0000369 btg = FixedTypeGenerator([BuiltinType(n,s) for n,s in builtins])
370 sbtg = FixedTypeGenerator([BuiltinType('char',1),
371 BuiltinType('int',4),
372 BuiltinType('float',4)])
Daniel Dunbara83fb862009-01-15 04:24:17 +0000373
374 atg = AnyTypeGenerator()
375 artg = AnyTypeGenerator()
376 def makeGenerator(atg, subgen, useRecord, useArray):
377 atg.addGenerator(btg)
378 if useRecord and opts.useRecord:
379 assert subgen
380 atg.addGenerator(RecordTypeGenerator(subgen, opts.recordUseUnion,
381 opts.recordMaxSize))
382 if opts.useComplex:
383 # FIXME: Allow overriding builtins here
384 atg.addGenerator(ComplexTypeGenerator(sbtg))
385 if useArray and opts.useArray:
386 assert subgen
387 atg.addGenerator(ArrayTypeGenerator(subgen, opts.arrayMaxSize))
388 if opts.useVector:
389 atg.addGenerator(VectorTypeGenerator(sbtg,
390 map(int, opts.vectorSizes.split(','))))
391
392
393 if opts.recordMaxDepth is None:
394 # Fully recursive, just avoid top-level arrays.
395 subTG = AnyTypeGenerator()
396 atg = AnyTypeGenerator()
397 makeGenerator(subTG, atg, True, True)
398 makeGenerator(atg, subTG, True, False)
399 else:
400 # Make a chain of type generators, each builds smaller
401 # structures.
402 base = AnyTypeGenerator()
403 makeGenerator(base, None, False, False)
404 for i in range(opts.recordMaxDepth):
405 n = AnyTypeGenerator()
406 makeGenerator(n, base, True, True)
407 base = n
408 atg = AnyTypeGenerator()
409 makeGenerator(atg, base, True, False)
410
411 ftg = FunctionTypeGenerator(atg, opts.functionUseReturn, opts.functionMaxArgs)
412
413 # Override max,min,count if finite
414 if opts.maxIndex is None:
415 if ftg.cardinality is aleph0:
416 opts.maxIndex = 10000000
417 else:
418 opts.maxIndex = ftg.cardinality
419 opts.maxIndex = min(opts.maxIndex, ftg.cardinality)
420 opts.minIndex = max(0,min(opts.maxIndex-1, opts.minIndex))
421 if not opts.mode=='random':
422 opts.count = min(opts.count, opts.maxIndex-opts.minIndex)
423
424 if opts.output=='-':
425 output = sys.stdout
426 else:
427 output = open(opts.output,'w')
428 atexit.register(lambda: output.close())
429
430 outputHeader = None
431 if opts.outputHeader:
432 outputHeader = open(opts.outputHeader,'w')
433 atexit.register(lambda: outputHeader.close())
434
435 outputTests = None
436 if opts.outputTests:
437 outputTests = open(opts.outputTests,'w')
438 atexit.register(lambda: outputTests.close())
439
440 outputDriver = None
441 if opts.outputDriver:
442 outputDriver = open(opts.outputDriver,'w')
443 atexit.register(lambda: outputDriver.close())
444
445 info = ''
446 info += '// %s\n'%(' '.join(sys.argv),)
447 info += '// Generated: %s\n'%(time.strftime('%Y-%m-%d %H:%M'),)
448 info += '// Cardinality of function generator: %s\n'%(ftg.cardinality,)
449 info += '// Cardinality of type generator: %s\n'%(atg.cardinality,)
450
451 P = TypePrinter(output,
452 outputHeader=outputHeader,
453 outputTests=outputTests,
454 outputDriver=outputDriver,
455 headerName=opts.outputHeader,
456 info=info)
457
458 def write(N):
459 try:
460 FT = ftg.get(N)
461 except RuntimeError,e:
462 if e.args[0]=='maximum recursion depth exceeded':
463 print >>sys.stderr,'WARNING: Skipped %d, recursion limit exceeded (bad arguments?)'%(N,)
464 return
465 raise
466 P.writeFunction(N, FT)
467
468 if args:
469 [write(int(a)) for a in args]
470
471 for i in range(opts.count):
472 if opts.mode=='linear':
473 index = opts.minIndex + i
474 else:
475 index = opts.minIndex + int((opts.maxIndex-opts.minIndex) * random.random())
476 write(index)
477
478 P.finish()
479
480if __name__=='__main__':
481 main()
482