1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
#!/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
|