#!/usr/bin/env python3 # This script outputs a Swift source with randomly-generated type definitions, # which can be used for ABI or layout algorithm fuzzing. # TODO: generate types with generics, existentials, compositions import random import sys maxDepth = 5 maxMembers = 5 typesDefined = [] classesDefined = [] nextToDefine = 0 objcInterop = False if len(sys.argv) >= 2: if sys.argv[1] == "--objc": objcInterop = True if sys.argv[1] == "--help": print("Usage: " + sys.argv[0] + " [--objc]", file=sys.stderr) print("", file=sys.stderr) print(" --objc Include ObjC-interop types", file=sys.stderr) sys.exit(2) random.seed() if objcInterop: print("import Foundation") print() def randomTypeList(depth): count = random.randint(0, maxMembers) result = "(" for i in range(count): if i > 0: result += ", " result += randomTypeReference(depth + 1) result += ")" return result def randomTypeReference(depth): def nominal(): global typesDefined allowNew = depth < maxDepth bound = len(classesDefined) if allowNew else len(classesDefined) - 1 which = random.randint(0, bound) if which < len(classesDefined): return classesDefined[which] newName = "T" + str(len(typesDefined)) def defineRandomRelatedType(name): defineRandomNominalType(name, depth) typesDefined.append((newName, defineRandomRelatedType)) return newName def tuple(): return randomTypeList(depth + 1) def metatype(): return "(" + randomTypeReference(depth + 1) + ").Type" def leaf(): leaves = ["Int", "String", "Int8", "Int16", "Int32", "Int64", "(() -> ())", "(@convention(c) () -> ())", "AnyObject"] if objcInterop: leaves += ["NSObject", "(@convention(block) () -> ())"] return random.choice(leaves) if depth < maxDepth: kinds = [nominal, tuple, metatype, leaf, leaf, leaf, leaf, leaf] else: kinds = [leaf] return random.choice(kinds)() def defineRandomFields(depth, basename): numMembers = random.randint(0, maxMembers) for i in range(numMembers): print(" var " + basename + str(i) + ": " + randomTypeReference(depth + 1)) def defineRandomClass(name, depth): global classesDefined classesDefined.append(name) print("class " + name, end="") def inheritNSObject(): print(": NSObject", end="") def inheritsOtherClass(): print(": ", end="") name = "T" + str(len(typesDefined)) def defineRandomBaseClass(name): defineRandomClass(name, depth) typesDefined.append((name, defineRandomBaseClass)) print(name, end="") def inheritsNothing(): pass inheritances = [inheritsNothing] if depth == 0: # The contents of classes are interesting only for top-level type inheritances += [inheritsOtherClass] if objcInterop: inheritances += [inheritNSObject] random.choice(inheritances)() print(" {") # Prevent errors about lack of initializers print(" init(" + name + ": ()) { fatalError() }") # The contents of classes are interesting only for top-level type if depth == 0: defineRandomFields(depth, "x" + name) print("}") print() def defineRandomNominalType(name, depth=0): def struct(): print("struct " + name + " {") defineRandomFields(depth, "x") print("}") print() def clazz(): defineRandomClass(name, depth) def enum(): # TODO: indirect cases print("enum " + name + " {") numCases = random.randint(0, maxMembers) for i in range(numCases): print(" case x" + str(i) + randomTypeList(depth + 1)) print("}") print() kinds = [struct, clazz, enum] return random.choice(kinds)() typesDefined.append(("Generated", defineRandomNominalType)) while nextToDefine < len(typesDefined): name, definer = typesDefined[nextToDefine] definer(name) nextToDefine += 1