mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
158 lines
4.1 KiB
Python
158 lines
4.1 KiB
Python
#!/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
|