| #!/usr/bin/env python |
| |
| from __future__ import absolute_import, division, print_function |
| from pprint import pprint |
| import random, atexit, time |
| from random import randrange |
| import re |
| |
| from Enumeration import * |
| from TypeGen import * |
| |
| #### |
| |
| |
| class TypePrinter(object): |
| def __init__( |
| self, |
| output, |
| outputHeader=None, |
| outputTests=None, |
| outputDriver=None, |
| headerName=None, |
| info=None, |
| ): |
| self.output = output |
| self.outputHeader = outputHeader |
| self.outputTests = outputTests |
| self.outputDriver = outputDriver |
| self.writeBody = outputHeader or outputTests or outputDriver |
| self.types = {} |
| self.testValues = {} |
| self.testReturnValues = {} |
| self.layoutTests = [] |
| self.declarations = set() |
| |
| if info: |
| for f in ( |
| self.output, |
| self.outputHeader, |
| self.outputTests, |
| self.outputDriver, |
| ): |
| if f: |
| print(info, file=f) |
| |
| if self.writeBody: |
| print("#include <stdio.h>\n", file=self.output) |
| if self.outputTests: |
| print("#include <stdio.h>", file=self.outputTests) |
| print("#include <string.h>", file=self.outputTests) |
| print("#include <assert.h>\n", file=self.outputTests) |
| |
| if headerName: |
| for f in (self.output, self.outputTests, self.outputDriver): |
| if f is not None: |
| print('#include "%s"\n' % (headerName,), file=f) |
| |
| if self.outputDriver: |
| print("#include <stdio.h>", file=self.outputDriver) |
| print("#include <stdlib.h>\n", file=self.outputDriver) |
| print("int main(int argc, char **argv) {", file=self.outputDriver) |
| print(" int index = -1;", file=self.outputDriver) |
| print(" if (argc > 1) index = atoi(argv[1]);", file=self.outputDriver) |
| |
| def finish(self): |
| if self.layoutTests: |
| print("int main(int argc, char **argv) {", file=self.output) |
| print(" int index = -1;", file=self.output) |
| print(" if (argc > 1) index = atoi(argv[1]);", file=self.output) |
| for i, f in self.layoutTests: |
| print(" if (index == -1 || index == %d)" % i, file=self.output) |
| print(" %s();" % f, file=self.output) |
| print(" return 0;", file=self.output) |
| print("}", file=self.output) |
| |
| if self.outputDriver: |
| print(' printf("DONE\\n");', file=self.outputDriver) |
| print(" return 0;", file=self.outputDriver) |
| print("}", file=self.outputDriver) |
| |
| def addDeclaration(self, decl): |
| if decl in self.declarations: |
| return False |
| |
| self.declarations.add(decl) |
| if self.outputHeader: |
| print(decl, file=self.outputHeader) |
| else: |
| print(decl, file=self.output) |
| if self.outputTests: |
| print(decl, file=self.outputTests) |
| return True |
| |
| def getTypeName(self, T): |
| name = self.types.get(T) |
| if name is None: |
| # Reserve slot |
| self.types[T] = None |
| self.types[T] = name = T.getTypeName(self) |
| return name |
| |
| def writeLayoutTest(self, i, ty): |
| tyName = self.getTypeName(ty) |
| tyNameClean = tyName.replace(" ", "_").replace("*", "star") |
| fnName = "test_%s" % tyNameClean |
| |
| print("void %s(void) {" % fnName, file=self.output) |
| self.printSizeOfType(" %s" % fnName, tyName, ty, self.output) |
| self.printAlignOfType(" %s" % fnName, tyName, ty, self.output) |
| self.printOffsetsOfType(" %s" % fnName, tyName, ty, self.output) |
| print("}", file=self.output) |
| print(file=self.output) |
| |
| self.layoutTests.append((i, fnName)) |
| |
| def writeFunction(self, i, FT): |
| args = ", ".join( |
| ["%s arg%d" % (self.getTypeName(t), i) for i, t in enumerate(FT.argTypes)] |
| ) |
| if not args: |
| args = "void" |
| |
| if FT.returnType is None: |
| retvalName = None |
| retvalTypeName = "void" |
| else: |
| retvalTypeName = self.getTypeName(FT.returnType) |
| if self.writeBody or self.outputTests: |
| retvalName = self.getTestReturnValue(FT.returnType) |
| |
| fnName = "fn%d" % (FT.index,) |
| if self.outputHeader: |
| print("%s %s(%s);" % (retvalTypeName, fnName, args), file=self.outputHeader) |
| elif self.outputTests: |
| print("%s %s(%s);" % (retvalTypeName, fnName, args), file=self.outputTests) |
| |
| print("%s %s(%s)" % (retvalTypeName, fnName, args), end=" ", file=self.output) |
| if self.writeBody: |
| print("{", file=self.output) |
| |
| for i, t in enumerate(FT.argTypes): |
| self.printValueOfType(" %s" % fnName, "arg%d" % i, t) |
| |
| if retvalName is not None: |
| print(" return %s;" % (retvalName,), file=self.output) |
| print("}", file=self.output) |
| else: |
| print("{}", file=self.output) |
| print(file=self.output) |
| |
| if self.outputDriver: |
| print(" if (index == -1 || index == %d) {" % i, file=self.outputDriver) |
| print(" extern void test_%s(void);" % fnName, file=self.outputDriver) |
| print(" test_%s();" % fnName, file=self.outputDriver) |
| print(" }", file=self.outputDriver) |
| |
| if self.outputTests: |
| if self.outputHeader: |
| print("void test_%s(void);" % (fnName,), file=self.outputHeader) |
| |
| if retvalName is None: |
| retvalTests = None |
| else: |
| retvalTests = self.getTestValuesArray(FT.returnType) |
| tests = [self.getTestValuesArray(ty) for ty in FT.argTypes] |
| print("void test_%s(void) {" % (fnName,), file=self.outputTests) |
| |
| if retvalTests is not None: |
| print( |
| ' printf("%s: testing return.\\n");' % (fnName,), |
| file=self.outputTests, |
| ) |
| print( |
| " for (int i=0; i<%d; ++i) {" % (retvalTests[1],), |
| file=self.outputTests, |
| ) |
| args = ", ".join(["%s[%d]" % (t, randrange(l)) for t, l in tests]) |
| print(" %s RV;" % (retvalTypeName,), file=self.outputTests) |
| print( |
| " %s = %s[i];" % (retvalName, retvalTests[0]), |
| file=self.outputTests, |
| ) |
| print(" RV = %s(%s);" % (fnName, args), file=self.outputTests) |
| self.printValueOfType( |
| " %s_RV" % fnName, |
| "RV", |
| FT.returnType, |
| output=self.outputTests, |
| indent=4, |
| ) |
| self.checkTypeValues( |
| "RV", |
| "%s[i]" % retvalTests[0], |
| FT.returnType, |
| output=self.outputTests, |
| indent=4, |
| ) |
| print(" }", file=self.outputTests) |
| |
| if tests: |
| print( |
| ' printf("%s: testing arguments.\\n");' % (fnName,), |
| file=self.outputTests, |
| ) |
| for i, (array, length) in enumerate(tests): |
| for j in range(length): |
| args = ["%s[%d]" % (t, randrange(l)) for t, l in tests] |
| args[i] = "%s[%d]" % (array, j) |
| print( |
| " %s(%s);" |
| % ( |
| fnName, |
| ", ".join(args), |
| ), |
| file=self.outputTests, |
| ) |
| print("}", file=self.outputTests) |
| |
| def getTestReturnValue(self, type): |
| typeName = self.getTypeName(type) |
| info = self.testReturnValues.get(typeName) |
| if info is None: |
| name = "%s_retval" % (typeName.replace(" ", "_").replace("*", "star"),) |
| print("%s %s;" % (typeName, name), file=self.output) |
| if self.outputHeader: |
| print("extern %s %s;" % (typeName, name), file=self.outputHeader) |
| elif self.outputTests: |
| print("extern %s %s;" % (typeName, name), file=self.outputTests) |
| info = self.testReturnValues[typeName] = name |
| return info |
| |
| def getTestValuesArray(self, type): |
| typeName = self.getTypeName(type) |
| info = self.testValues.get(typeName) |
| if info is None: |
| name = "%s_values" % (typeName.replace(" ", "_").replace("*", "star"),) |
| print("static %s %s[] = {" % (typeName, name), file=self.outputTests) |
| length = 0 |
| for item in self.getTestValues(type): |
| print("\t%s," % (item,), file=self.outputTests) |
| length += 1 |
| print("};", file=self.outputTests) |
| info = self.testValues[typeName] = (name, length) |
| return info |
| |
| def getTestValues(self, t): |
| if isinstance(t, BuiltinType): |
| if t.name == "float": |
| for i in ["0.0", "-1.0", "1.0"]: |
| yield i + "f" |
| elif t.name == "double": |
| for i in ["0.0", "-1.0", "1.0"]: |
| yield i |
| elif t.name in ("void *"): |
| yield "(void*) 0" |
| yield "(void*) -1" |
| else: |
| yield "(%s) 0" % (t.name,) |
| yield "(%s) -1" % (t.name,) |
| yield "(%s) 1" % (t.name,) |
| elif isinstance(t, EnumType): |
| for i in range(0, len(t.enumerators)): |
| yield "enum%dval%d_%d" % (t.index, i, t.unique_id) |
| elif isinstance(t, RecordType): |
| nonPadding = [f for f in t.fields if not f.isPaddingBitField()] |
| |
| if not nonPadding: |
| yield "{ }" |
| return |
| |
| # FIXME: Use designated initializers to access non-first |
| # fields of unions. |
| if t.isUnion: |
| for v in self.getTestValues(nonPadding[0]): |
| yield "{ %s }" % v |
| return |
| |
| fieldValues = [list(v) for v in map(self.getTestValues, nonPadding)] |
| for i, values in enumerate(fieldValues): |
| for v in values: |
| elements = [random.choice(fv) for fv in fieldValues] |
| elements[i] = v |
| yield "{ %s }" % (", ".join(elements)) |
| |
| elif isinstance(t, ComplexType): |
| for t in self.getTestValues(t.elementType): |
| yield "%s + %s * 1i" % (t, t) |
| elif isinstance(t, ArrayType): |
| values = list(self.getTestValues(t.elementType)) |
| if not values: |
| yield "{ }" |
| for i in range(t.numElements): |
| for v in values: |
| elements = [random.choice(values) for i in range(t.numElements)] |
| elements[i] = v |
| yield "{ %s }" % (", ".join(elements)) |
| else: |
| raise NotImplementedError('Cannot make tests values of type: "%s"' % (t,)) |
| |
| def printSizeOfType(self, prefix, name, t, output=None, indent=2): |
| print( |
| '%*sprintf("%s: sizeof(%s) = %%ld\\n", (long)sizeof(%s));' |
| % (indent, "", prefix, name, name), |
| file=output, |
| ) |
| |
| def printAlignOfType(self, prefix, name, t, output=None, indent=2): |
| print( |
| '%*sprintf("%s: __alignof__(%s) = %%ld\\n", (long)__alignof__(%s));' |
| % (indent, "", prefix, name, name), |
| file=output, |
| ) |
| |
| def printOffsetsOfType(self, prefix, name, t, output=None, indent=2): |
| if isinstance(t, RecordType): |
| for i, f in enumerate(t.fields): |
| if f.isBitField(): |
| continue |
| fname = "field%d" % i |
| print( |
| '%*sprintf("%s: __builtin_offsetof(%s, %s) = %%ld\\n", (long)__builtin_offsetof(%s, %s));' |
| % (indent, "", prefix, name, fname, name, fname), |
| file=output, |
| ) |
| |
| def printValueOfType(self, prefix, name, t, output=None, indent=2): |
| if output is None: |
| output = self.output |
| if isinstance(t, BuiltinType): |
| value_expr = name |
| if t.name.split(" ")[-1] == "_Bool": |
| # Hack to work around PR5579. |
| value_expr = "%s ? 2 : 0" % name |
| |
| if t.name.endswith("long long"): |
| code = "lld" |
| elif t.name.endswith("long"): |
| code = "ld" |
| elif t.name.split(" ")[-1] in ("_Bool", "char", "short", "int", "unsigned"): |
| code = "d" |
| elif t.name in ("float", "double"): |
| code = "f" |
| elif t.name == "long double": |
| code = "Lf" |
| else: |
| code = "p" |
| print( |
| '%*sprintf("%s: %s = %%%s\\n", %s);' |
| % (indent, "", prefix, name, code, value_expr), |
| file=output, |
| ) |
| elif isinstance(t, EnumType): |
| print( |
| '%*sprintf("%s: %s = %%d\\n", %s);' % (indent, "", prefix, name, name), |
| file=output, |
| ) |
| elif isinstance(t, RecordType): |
| if not t.fields: |
| print( |
| '%*sprintf("%s: %s (empty)\\n");' % (indent, "", prefix, name), |
| file=output, |
| ) |
| for i, f in enumerate(t.fields): |
| if f.isPaddingBitField(): |
| continue |
| fname = "%s.field%d" % (name, i) |
| self.printValueOfType(prefix, fname, f, output=output, indent=indent) |
| elif isinstance(t, ComplexType): |
| self.printValueOfType( |
| prefix, |
| "(__real %s)" % name, |
| t.elementType, |
| output=output, |
| indent=indent, |
| ) |
| self.printValueOfType( |
| prefix, |
| "(__imag %s)" % name, |
| t.elementType, |
| output=output, |
| indent=indent, |
| ) |
| elif isinstance(t, ArrayType): |
| for i in range(t.numElements): |
| # Access in this fashion as a hackish way to portably |
| # access vectors. |
| if t.isVector: |
| self.printValueOfType( |
| prefix, |
| "((%s*) &%s)[%d]" % (t.elementType, name, i), |
| t.elementType, |
| output=output, |
| indent=indent, |
| ) |
| else: |
| self.printValueOfType( |
| prefix, |
| "%s[%d]" % (name, i), |
| t.elementType, |
| output=output, |
| indent=indent, |
| ) |
| else: |
| raise NotImplementedError('Cannot print value of type: "%s"' % (t,)) |
| |
| def checkTypeValues(self, nameLHS, nameRHS, t, output=None, indent=2): |
| prefix = "foo" |
| if output is None: |
| output = self.output |
| if isinstance(t, BuiltinType): |
| print("%*sassert(%s == %s);" % (indent, "", nameLHS, nameRHS), file=output) |
| elif isinstance(t, EnumType): |
| print("%*sassert(%s == %s);" % (indent, "", nameLHS, nameRHS), file=output) |
| elif isinstance(t, RecordType): |
| for i, f in enumerate(t.fields): |
| if f.isPaddingBitField(): |
| continue |
| self.checkTypeValues( |
| "%s.field%d" % (nameLHS, i), |
| "%s.field%d" % (nameRHS, i), |
| f, |
| output=output, |
| indent=indent, |
| ) |
| if t.isUnion: |
| break |
| elif isinstance(t, ComplexType): |
| self.checkTypeValues( |
| "(__real %s)" % nameLHS, |
| "(__real %s)" % nameRHS, |
| t.elementType, |
| output=output, |
| indent=indent, |
| ) |
| self.checkTypeValues( |
| "(__imag %s)" % nameLHS, |
| "(__imag %s)" % nameRHS, |
| t.elementType, |
| output=output, |
| indent=indent, |
| ) |
| elif isinstance(t, ArrayType): |
| for i in range(t.numElements): |
| # Access in this fashion as a hackish way to portably |
| # access vectors. |
| if t.isVector: |
| self.checkTypeValues( |
| "((%s*) &%s)[%d]" % (t.elementType, nameLHS, i), |
| "((%s*) &%s)[%d]" % (t.elementType, nameRHS, i), |
| t.elementType, |
| output=output, |
| indent=indent, |
| ) |
| else: |
| self.checkTypeValues( |
| "%s[%d]" % (nameLHS, i), |
| "%s[%d]" % (nameRHS, i), |
| t.elementType, |
| output=output, |
| indent=indent, |
| ) |
| else: |
| raise NotImplementedError('Cannot print value of type: "%s"' % (t,)) |
| |
| |
| import sys |
| |
| |
| def main(): |
| from optparse import OptionParser, OptionGroup |
| |
| parser = OptionParser("%prog [options] {indices}") |
| parser.add_option( |
| "", |
| "--mode", |
| dest="mode", |
| help="autogeneration mode (random or linear) [default %default]", |
| type="choice", |
| choices=("random", "linear"), |
| default="linear", |
| ) |
| parser.add_option( |
| "", |
| "--count", |
| dest="count", |
| help="autogenerate COUNT functions according to MODE", |
| type=int, |
| default=0, |
| ) |
| parser.add_option( |
| "", |
| "--min", |
| dest="minIndex", |
| metavar="N", |
| help="start autogeneration with the Nth function type [default %default]", |
| type=int, |
| default=0, |
| ) |
| parser.add_option( |
| "", |
| "--max", |
| dest="maxIndex", |
| metavar="N", |
| help="maximum index for random autogeneration [default %default]", |
| type=int, |
| default=10000000, |
| ) |
| parser.add_option( |
| "", |
| "--seed", |
| dest="seed", |
| help="random number generator seed [default %default]", |
| type=int, |
| default=1, |
| ) |
| parser.add_option( |
| "", |
| "--use-random-seed", |
| dest="useRandomSeed", |
| help="use random value for initial random number generator seed", |
| action="store_true", |
| default=False, |
| ) |
| parser.add_option( |
| "", |
| "--skip", |
| dest="skipTests", |
| help="add a test index to skip", |
| type=int, |
| action="append", |
| default=[], |
| ) |
| parser.add_option( |
| "-o", |
| "--output", |
| dest="output", |
| metavar="FILE", |
| help="write output to FILE [default %default]", |
| type=str, |
| default="-", |
| ) |
| parser.add_option( |
| "-O", |
| "--output-header", |
| dest="outputHeader", |
| metavar="FILE", |
| help="write header file for output to FILE [default %default]", |
| type=str, |
| default=None, |
| ) |
| parser.add_option( |
| "-T", |
| "--output-tests", |
| dest="outputTests", |
| metavar="FILE", |
| help="write function tests to FILE [default %default]", |
| type=str, |
| default=None, |
| ) |
| parser.add_option( |
| "-D", |
| "--output-driver", |
| dest="outputDriver", |
| metavar="FILE", |
| help="write test driver to FILE [default %default]", |
| type=str, |
| default=None, |
| ) |
| parser.add_option( |
| "", |
| "--test-layout", |
| dest="testLayout", |
| metavar="FILE", |
| help="test structure layout", |
| action="store_true", |
| default=False, |
| ) |
| |
| group = OptionGroup(parser, "Type Enumeration Options") |
| # Builtins - Ints |
| group.add_option( |
| "", |
| "--no-char", |
| dest="useChar", |
| help="do not generate char types", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--no-short", |
| dest="useShort", |
| help="do not generate short types", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--no-int", |
| dest="useInt", |
| help="do not generate int types", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--no-long", |
| dest="useLong", |
| help="do not generate long types", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--no-long-long", |
| dest="useLongLong", |
| help="do not generate long long types", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--no-unsigned", |
| dest="useUnsigned", |
| help="do not generate unsigned integer types", |
| action="store_false", |
| default=True, |
| ) |
| |
| # Other builtins |
| group.add_option( |
| "", |
| "--no-bool", |
| dest="useBool", |
| help="do not generate bool types", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--no-float", |
| dest="useFloat", |
| help="do not generate float types", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--no-double", |
| dest="useDouble", |
| help="do not generate double types", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--no-long-double", |
| dest="useLongDouble", |
| help="do not generate long double types", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--no-void-pointer", |
| dest="useVoidPointer", |
| help="do not generate void* types", |
| action="store_false", |
| default=True, |
| ) |
| |
| # Enumerations |
| group.add_option( |
| "", |
| "--no-enums", |
| dest="useEnum", |
| help="do not generate enum types", |
| action="store_false", |
| default=True, |
| ) |
| |
| # Derived types |
| group.add_option( |
| "", |
| "--no-array", |
| dest="useArray", |
| help="do not generate record types", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--no-complex", |
| dest="useComplex", |
| help="do not generate complex types", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--no-record", |
| dest="useRecord", |
| help="do not generate record types", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--no-union", |
| dest="recordUseUnion", |
| help="do not generate union types", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--no-vector", |
| dest="useVector", |
| help="do not generate vector types", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--no-bit-field", |
| dest="useBitField", |
| help="do not generate bit-field record members", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--no-builtins", |
| dest="useBuiltins", |
| help="do not use any types", |
| action="store_false", |
| default=True, |
| ) |
| |
| # Tuning |
| group.add_option( |
| "", |
| "--no-function-return", |
| dest="functionUseReturn", |
| help="do not generate return types for functions", |
| action="store_false", |
| default=True, |
| ) |
| group.add_option( |
| "", |
| "--vector-types", |
| dest="vectorTypes", |
| help="comma separated list of vector types (e.g., v2i32) [default %default]", |
| action="store", |
| type=str, |
| default="v2i16, v1i64, v2i32, v4i16, v8i8, v2f32, v2i64, v4i32, v8i16, v16i8, v2f64, v4f32, v16f32", |
| metavar="N", |
| ) |
| group.add_option( |
| "", |
| "--bit-fields", |
| dest="bitFields", |
| help="comma separated list 'type:width' bit-field specifiers [default %default]", |
| action="store", |
| type=str, |
| default=("char:0,char:4,int:0,unsigned:1,int:1,int:4,int:13,int:24"), |
| ) |
| group.add_option( |
| "", |
| "--max-args", |
| dest="functionMaxArgs", |
| help="maximum number of arguments per function [default %default]", |
| action="store", |
| type=int, |
| default=4, |
| metavar="N", |
| ) |
| group.add_option( |
| "", |
| "--max-array", |
| dest="arrayMaxSize", |
| help="maximum array size [default %default]", |
| action="store", |
| type=int, |
| default=4, |
| metavar="N", |
| ) |
| group.add_option( |
| "", |
| "--max-record", |
| dest="recordMaxSize", |
| help="maximum number of fields per record [default %default]", |
| action="store", |
| type=int, |
| default=4, |
| metavar="N", |
| ) |
| group.add_option( |
| "", |
| "--max-record-depth", |
| dest="recordMaxDepth", |
| help="maximum nested structure depth [default %default]", |
| action="store", |
| type=int, |
| default=None, |
| metavar="N", |
| ) |
| parser.add_option_group(group) |
| (opts, args) = parser.parse_args() |
| |
| if not opts.useRandomSeed: |
| random.seed(opts.seed) |
| |
| # Construct type generator |
| builtins = [] |
| if opts.useBuiltins: |
| ints = [] |
| if opts.useChar: |
| ints.append(("char", 1)) |
| if opts.useShort: |
| ints.append(("short", 2)) |
| if opts.useInt: |
| ints.append(("int", 4)) |
| # FIXME: Wrong size. |
| if opts.useLong: |
| ints.append(("long", 4)) |
| if opts.useLongLong: |
| ints.append(("long long", 8)) |
| if opts.useUnsigned: |
| ints = [("unsigned %s" % i, s) for i, s in ints] + [ |
| ("signed %s" % i, s) for i, s in ints |
| ] |
| builtins.extend(ints) |
| |
| if opts.useBool: |
| builtins.append(("_Bool", 1)) |
| if opts.useFloat: |
| builtins.append(("float", 4)) |
| if opts.useDouble: |
| builtins.append(("double", 8)) |
| if opts.useLongDouble: |
| builtins.append(("long double", 16)) |
| # FIXME: Wrong size. |
| if opts.useVoidPointer: |
| builtins.append(("void*", 4)) |
| |
| btg = FixedTypeGenerator([BuiltinType(n, s) for n, s in builtins]) |
| |
| bitfields = [] |
| for specifier in opts.bitFields.split(","): |
| if not specifier.strip(): |
| continue |
| name, width = specifier.strip().split(":", 1) |
| bitfields.append(BuiltinType(name, None, int(width))) |
| bftg = FixedTypeGenerator(bitfields) |
| |
| charType = BuiltinType("char", 1) |
| shortType = BuiltinType("short", 2) |
| intType = BuiltinType("int", 4) |
| longlongType = BuiltinType("long long", 8) |
| floatType = BuiltinType("float", 4) |
| doubleType = BuiltinType("double", 8) |
| sbtg = FixedTypeGenerator([charType, intType, floatType, doubleType]) |
| |
| atg = AnyTypeGenerator() |
| artg = AnyTypeGenerator() |
| |
| def makeGenerator(atg, subgen, subfieldgen, useRecord, useArray, useBitField): |
| atg.addGenerator(btg) |
| if useBitField and opts.useBitField: |
| atg.addGenerator(bftg) |
| if useRecord and opts.useRecord: |
| assert subgen |
| atg.addGenerator( |
| RecordTypeGenerator( |
| subfieldgen, opts.recordUseUnion, opts.recordMaxSize |
| ) |
| ) |
| if opts.useComplex: |
| # FIXME: Allow overriding builtins here |
| atg.addGenerator(ComplexTypeGenerator(sbtg)) |
| if useArray and opts.useArray: |
| assert subgen |
| atg.addGenerator(ArrayTypeGenerator(subgen, opts.arrayMaxSize)) |
| if opts.useVector: |
| vTypes = [] |
| for i, t in enumerate(opts.vectorTypes.split(",")): |
| m = re.match("v([1-9][0-9]*)([if][1-9][0-9]*)", t.strip()) |
| if not m: |
| parser.error("Invalid vector type: %r" % t) |
| count, kind = m.groups() |
| count = int(count) |
| type = { |
| "i8": charType, |
| "i16": shortType, |
| "i32": intType, |
| "i64": longlongType, |
| "f32": floatType, |
| "f64": doubleType, |
| }.get(kind) |
| if not type: |
| parser.error("Invalid vector type: %r" % t) |
| vTypes.append(ArrayType(i, True, type, count * type.size)) |
| |
| atg.addGenerator(FixedTypeGenerator(vTypes)) |
| if opts.useEnum: |
| atg.addGenerator(EnumTypeGenerator([None, "-1", "1", "1u"], 1, 4)) |
| |
| if opts.recordMaxDepth is None: |
| # Fully recursive, just avoid top-level arrays. |
| subFTG = AnyTypeGenerator() |
| subTG = AnyTypeGenerator() |
| atg = AnyTypeGenerator() |
| makeGenerator(subFTG, atg, atg, True, True, True) |
| makeGenerator(subTG, atg, subFTG, True, True, False) |
| makeGenerator(atg, subTG, subFTG, True, False, False) |
| else: |
| # Make a chain of type generators, each builds smaller |
| # structures. |
| base = AnyTypeGenerator() |
| fbase = AnyTypeGenerator() |
| makeGenerator(base, None, None, False, False, False) |
| makeGenerator(fbase, None, None, False, False, True) |
| for i in range(opts.recordMaxDepth): |
| n = AnyTypeGenerator() |
| fn = AnyTypeGenerator() |
| makeGenerator(n, base, fbase, True, True, False) |
| makeGenerator(fn, base, fbase, True, True, True) |
| base = n |
| fbase = fn |
| atg = AnyTypeGenerator() |
| makeGenerator(atg, base, fbase, True, False, False) |
| |
| if opts.testLayout: |
| ftg = atg |
| else: |
| ftg = FunctionTypeGenerator(atg, opts.functionUseReturn, opts.functionMaxArgs) |
| |
| # Override max,min,count if finite |
| if opts.maxIndex is None: |
| if ftg.cardinality is aleph0: |
| opts.maxIndex = 10000000 |
| else: |
| opts.maxIndex = ftg.cardinality |
| opts.maxIndex = min(opts.maxIndex, ftg.cardinality) |
| opts.minIndex = max(0, min(opts.maxIndex - 1, opts.minIndex)) |
| if not opts.mode == "random": |
| opts.count = min(opts.count, opts.maxIndex - opts.minIndex) |
| |
| if opts.output == "-": |
| output = sys.stdout |
| else: |
| output = open(opts.output, "w") |
| atexit.register(lambda: output.close()) |
| |
| outputHeader = None |
| if opts.outputHeader: |
| outputHeader = open(opts.outputHeader, "w") |
| atexit.register(lambda: outputHeader.close()) |
| |
| outputTests = None |
| if opts.outputTests: |
| outputTests = open(opts.outputTests, "w") |
| atexit.register(lambda: outputTests.close()) |
| |
| outputDriver = None |
| if opts.outputDriver: |
| outputDriver = open(opts.outputDriver, "w") |
| atexit.register(lambda: outputDriver.close()) |
| |
| info = "" |
| info += "// %s\n" % (" ".join(sys.argv),) |
| info += "// Generated: %s\n" % (time.strftime("%Y-%m-%d %H:%M"),) |
| info += "// Cardinality of function generator: %s\n" % (ftg.cardinality,) |
| info += "// Cardinality of type generator: %s\n" % (atg.cardinality,) |
| |
| if opts.testLayout: |
| info += "\n#include <stdio.h>" |
| |
| P = TypePrinter( |
| output, |
| outputHeader=outputHeader, |
| outputTests=outputTests, |
| outputDriver=outputDriver, |
| headerName=opts.outputHeader, |
| info=info, |
| ) |
| |
| def write(N): |
| try: |
| FT = ftg.get(N) |
| except RuntimeError as e: |
| if e.args[0] == "maximum recursion depth exceeded": |
| print( |
| "WARNING: Skipped %d, recursion limit exceeded (bad arguments?)" |
| % (N,), |
| file=sys.stderr, |
| ) |
| return |
| raise |
| if opts.testLayout: |
| P.writeLayoutTest(N, FT) |
| else: |
| P.writeFunction(N, FT) |
| |
| if args: |
| [write(int(a)) for a in args] |
| |
| skipTests = set(opts.skipTests) |
| for i in range(opts.count): |
| if opts.mode == "linear": |
| index = opts.minIndex + i |
| else: |
| index = opts.minIndex + int( |
| (opts.maxIndex - opts.minIndex) * random.random() |
| ) |
| if index in skipTests: |
| continue |
| write(index) |
| |
| P.finish() |
| |
| |
| if __name__ == "__main__": |
| main() |