Skip to content

Instantly share code, notes, and snippets.

@alanzeino
Last active October 26, 2018 20:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alanzeino/7570080089f11ea14a161e4d20c39cdf to your computer and use it in GitHub Desktop.
Save alanzeino/7570080089f11ea14a161e4d20c39cdf to your computer and use it in GitHub Desktop.
swiftsyntax simple class/struct gen example
struct MockGenType {
let name: String
let isOptional: Bool
init(name: String, isOptional: Bool = false) {
self.name = name
self.isOptional = isOptional
}
func libRepresentation(hasDefault: Bool = false) -> OptionalTypeSyntax {
return OptionalTypeSyntax { builder in
builder.useWrappedType(SimpleTypeIdentifierSyntax { sBuilder in
sBuilder.useName(SyntaxFactory.makeIdentifier(name, leadingTrivia: .zero, trailingTrivia: hasDefault ? .spaces(1) : .zero))
})
if isOptional {
builder.useQuestionMark(SyntaxFactory.makePostfixQuestionMarkToken())
}
}
}
}
struct MockGenFunctionArgument {
let name: String
let type: MockGenType
func libRepresentation(useTrailingComma: Bool) -> FunctionParameterSyntax {
return FunctionParameterSyntax { builder in
builder.useFirstName(SyntaxFactory.makeIdentifier(name))
builder.useType(type.libRepresentation())
builder.useColon(SyntaxFactory.makeColonToken(leadingTrivia: .zero, trailingTrivia: .spaces(1)))
if useTrailingComma {
builder.useTrailingComma(SyntaxFactory.makeCommaToken(leadingTrivia: .zero, trailingTrivia: .spaces(1)))
}
}
}
}
struct MockGenFunction {
let name: String
let arguments: [MockGenFunctionArgument]?
let returnType: MockGenType?
let hasBody: Bool
init(name: String, arguments: [MockGenFunctionArgument]?, returnType: MockGenType? = nil, hasBody: Bool = false) {
self.name = name
self.arguments = arguments
self.returnType = returnType
self.hasBody = hasBody
}
func libRepresentation() -> MemberDeclListItemSyntax {
let hasReturnType = returnType != nil
return MemberDeclListItemSyntax { builder in
builder.useDecl(FunctionDeclSyntax { fBuilder in
fBuilder.useIdentifier(SyntaxFactory.makeIdentifier(name))
fBuilder.useFuncKeyword(SyntaxFactory.makeFuncKeyword(leadingTrivia: Trivia(pieces: [.newlines(1), .tabs(1)]), trailingTrivia: .spaces(1)))
fBuilder.useSignature(FunctionSignatureSyntax { sBuilder in
sBuilder.useInput(ParameterClauseSyntax { pBuilder in
if let arguments = arguments {
let lastIndex = arguments.count - 1
for i in 0..<arguments.count {
let argument = arguments[i]
let isLastItem: Bool = i == lastIndex
pBuilder.addFunctionParameter(argument.libRepresentation(useTrailingComma: !isLastItem))
}
}
pBuilder.useLeftParen(SyntaxFactory.makeLeftParenToken())
pBuilder.useRightParen(SyntaxFactory.makeRightParenToken(leadingTrivia: .zero, trailingTrivia: hasReturnType ? .spaces(1) : .zero))
})
if let returnType = returnType {
sBuilder.useOutput(ReturnClauseSyntax { rcBuilder in
rcBuilder.useReturnType(returnType.libRepresentation())
rcBuilder.useArrow(SyntaxFactory.makeArrowToken(leadingTrivia: .zero, trailingTrivia: .spaces(1)))
})
}
})
})
}
}
}
enum MockGenVariableLetOrVar {
case letVariable
case varVariable
func libRepresentation() -> TokenSyntax {
switch (self) {
case .letVariable:
return SyntaxFactory.makeLetKeyword(leadingTrivia: Trivia(pieces: [.newlines(1), .tabs(1)]),
trailingTrivia: .spaces(1))
case .varVariable:
return SyntaxFactory.makeVarKeyword(leadingTrivia: Trivia(pieces: [.newlines(1), .tabs(1)]),
trailingTrivia: .spaces(1))
}
}
}
struct MockGenVariableType {
let type: MockGenType
let optional: Bool
init(type: MockGenType, optional: Bool = false) {
self.type = type
self.optional = optional
}
func libRepresentation(hasDefault: Bool) -> TypeAnnotationSyntax {
let colon = SyntaxFactory.makeColonToken(leadingTrivia: .zero,
trailingTrivia: .spaces(1))
var typeAnnotation: TypeSyntax?
if optional {
let questionMark = SyntaxFactory.makePostfixQuestionMarkToken(leadingTrivia: .zero, trailingTrivia: hasDefault ? .spaces(1) : .zero)
typeAnnotation = SyntaxFactory.makeOptionalType(wrappedType: type.libRepresentation(),
questionMark: questionMark)
} else {
typeAnnotation = type.libRepresentation(hasDefault: hasDefault)
}
return SyntaxFactory.makeTypeAnnotation(colon: colon,
type: typeAnnotation!)
}
}
struct MockGenVariableName {
let name: String
func libRepresentation() -> IdentifierPatternSyntax {
return SyntaxFactory.makeIdentifierPattern(identifier: SyntaxFactory.makeIdentifier(name))
}
}
struct MockGenInitializedTo {
enum MockGenInitializedToType {
case variable
case function
}
let type: MockGenInitializedToType
let stringRepresentation: String
func libRepresentation() -> InitializerClauseSyntax {
return InitializerClauseSyntax { icBuilder in
icBuilder.useEqual(SyntaxFactory.makeEqualToken(leadingTrivia: .zero, trailingTrivia: .spaces(1)))
switch type {
case .variable:
icBuilder.useValue(SyntaxFactory.makeIntegerLiteralExpr(digits: SyntaxFactory.makeUnknown(stringRepresentation)))
case .function:
icBuilder.useValue(FunctionCallExprSyntax { fceBuilder in
fceBuilder.useCalledExpression(SyntaxFactory.makeIdentifierExpr(identifier: SyntaxFactory.makeUnknown(stringRepresentation), declNameArguments: nil))
fceBuilder.addFunctionCallArgument(SyntaxFactory.makeBlankFunctionCallArgument())
fceBuilder.useLeftParen(SyntaxFactory.makeLeftParenToken())
fceBuilder.useRightParen(SyntaxFactory.makeRightParenToken())
})
}
}
}
}
struct MockGenVariable {
let variableName: MockGenVariableName
let variableType: MockGenVariableType
let letOrVar: MockGenVariableLetOrVar
var initializedToDefault: MockGenInitializedTo?
init(name: MockGenVariableName, type: MockGenVariableType, letOrVar: MockGenVariableLetOrVar, initializedToDefault: MockGenInitializedTo? = nil) {
self.variableName = name
self.variableType = type
self.letOrVar = letOrVar
self.initializedToDefault = initializedToDefault
}
func libRepresentation() -> MemberDeclListItemSyntax {
return MemberDeclListItemSyntax { builder in
builder.useDecl(VariableDeclSyntax { vBuilder in
vBuilder.useLetOrVarKeyword(letOrVar.libRepresentation())
vBuilder.addPatternBinding(PatternBindingSyntax { pbBuilder in
pbBuilder.usePattern(variableName.libRepresentation())
pbBuilder.useTypeAnnotation(variableType.libRepresentation(hasDefault: initializedToDefault != nil))
if let initializedToDefault = initializedToDefault {
pbBuilder.useInitializer(initializedToDefault.libRepresentation())
}
})
})
}
}
}
struct MockGenStruct {
let name: String
var functions: [MockGenFunction]?
var variables: [MockGenVariable]?
var conformsToProtocol: MockGenProtocolConformance?
init(name: String, functions: [MockGenFunction]?, variables: [MockGenVariable]?, conformsToProtocol: MockGenProtocolConformance? = nil) {
self.name = name
self.functions = functions
self.variables = variables
self.conformsToProtocol = conformsToProtocol
}
func isEmpty() -> Bool {
let functionsCount = functions?.count ?? 0
let variablesCount = variables?.count ?? 0
return functionsCount == 0 && variablesCount == 0
}
func libRepresentation() -> StructDeclSyntax {
return StructDeclSyntax { sBuilder in
sBuilder.useIdentifier(SyntaxFactory.makeIdentifier(name))
sBuilder.useStructKeyword(SyntaxFactory.makeStructKeyword(leadingTrivia: .zero, trailingTrivia: .spaces(1)))
sBuilder.useMembers(MemberDeclBlockSyntax { mBuilder in
if let functions = functions {
for function in functions {
mBuilder.addMemberDeclListItem(function.libRepresentation())
}
}
if let variables = variables {
for variable in variables {
mBuilder.addMemberDeclListItem(variable.libRepresentation())
}
}
mBuilder.useLeftBrace(SyntaxFactory.makeLeftBraceToken(leadingTrivia: .spaces(1), trailingTrivia: .zero))
mBuilder.useRightBrace(SyntaxFactory.makeRightBraceToken(leadingTrivia: isEmpty() ? .spaces(1) : .newlines(1), trailingTrivia: .zero))
})
if let conformsToProtocol = conformsToProtocol {
sBuilder.useInheritanceClause(conformsToProtocol.libRepresentation())
}
}
}
}
struct MockGenProtocolConformance {
let name: String
func libRepresentation() -> TypeInheritanceClauseSyntax {
return TypeInheritanceClauseSyntax { ticBuilder in
ticBuilder.addInheritedType(InheritedTypeSyntax { itBuilder in
itBuilder.useTypeName(SyntaxFactory.makeTypeIdentifier(name))
})
ticBuilder.useColon(SyntaxFactory.makeColonToken(leadingTrivia: .zero, trailingTrivia: .spaces(1)))
}
}
}
struct MockGenClass {
let name: String
var functions: [MockGenFunction]?
var variables: [MockGenVariable]?
var conformsToProtocol: MockGenProtocolConformance?
init(name: String, functions: [MockGenFunction]?, variables: [MockGenVariable]?, conformsToProtocol: MockGenProtocolConformance? = nil) {
self.name = name
self.functions = functions
self.variables = variables
self.conformsToProtocol = conformsToProtocol
}
func isEmpty() -> Bool {
let functionsCount = functions?.count ?? 0
let variablesCount = variables?.count ?? 0
return functionsCount == 0 && variablesCount == 0
}
func libRepresentation() -> ClassDeclSyntax {
return ClassDeclSyntax { cBuilder in
cBuilder.useIdentifier(SyntaxFactory.makeIdentifier(name))
cBuilder.useClassKeyword(SyntaxFactory.makeClassKeyword(leadingTrivia: .zero, trailingTrivia: .spaces(1)))
cBuilder.useMembers(MemberDeclBlockSyntax { mBuilder in
if let functions = functions {
for function in functions {
mBuilder.addMemberDeclListItem(function.libRepresentation())
}
}
if let variables = variables {
for variable in variables {
mBuilder.addMemberDeclListItem(variable.libRepresentation())
}
}
mBuilder.useLeftBrace(SyntaxFactory.makeLeftBraceToken(leadingTrivia: .spaces(1), trailingTrivia: .zero))
mBuilder.useRightBrace(SyntaxFactory.makeRightBraceToken(leadingTrivia: isEmpty() ? .spaces(1) : .newlines(1), trailingTrivia: .zero))
})
if let conformsToProtocol = conformsToProtocol {
cBuilder.useInheritanceClause(conformsToProtocol.libRepresentation())
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment