I am writing a utility for code generation for Swift. It will use several libraries, for parsing command line arguments, for parsing xcodeproj, and for parsing Swift code. The latter I'm writing myself. Because I can't find any alternative.
Is there a framework that is designed for reading, modifying and generating Swift code? More complicated than SourceKitten.
Story:
I found that many projects use SourceKitten framework, that connects to SourceKit daemon, reads XML from it and returns a dictionary of objects. But all these projects have their own implementation of parsing those dictionaries.
So I thought that there's no universal and supported library for getting type safe Swift code structure. For example, that's what SourceKitten outputs:
{
"key.substructure" : [
{
"key.kind" : "source.lang.swift.decl.class",
"key.offset" : 128,
"key.attributes" : [
{
"key.attribute" : "source.decl.attribute.__raw_doc_comment"
}
],
"key.nameoffset" : 134,
"key.namelength" : 13,
"key.bodyoffset" : 149,
"key.bodylength" : 36,
"key.accessibility" : "source.lang.swift.accessibility.internal",
"key.substructure" : [
{
"key.kind" : "source.lang.swift.decl.var.static",
"key.offset" : 154,
"key.nameoffset" : 165,
"key.namelength" : 8,
"key.length" : 30,
"key.accessibility" : "source.lang.swift.accessibility.internal",
"key.typename" : "filename",
"key.name" : "filename"
}
],
"key.name" : "TestSwiftFile",
"key.runtime_name" : "_TtC8__main__13TestSwiftFile",
"key.length" : 58
},
{
"key.kind" : "source.lang.swift.decl.protocol",
"key.offset" : 195,
"key.nameoffset" : 204,
"key.namelength" : 12,
"key.bodyoffset" : 218,
"key.bodylength" : 83,
"key.accessibility" : "source.lang.swift.accessibility.public",
"key.substructure" : [
{
"key.kind" : "source.lang.swift.decl.var.instance",
"key.offset" : 223,
"key.nameoffset" : 227,
"key.namelength" : 12,
"key.bodyoffset" : 249,
"key.bodylength" : 9,
"key.accessibility" : "source.lang.swift.accessibility.public",
"key.setter_accessibility" : "source.lang.swift.accessibility.public",
"key.typename" : "String",
"key.name" : "getSetString",
"key.length" : 24
},
...etc...
I want something like this:
public struct TopLevelDeclarations {
public var classes: [ClassDeclaration]
public var structs: [StructDeclaration]
public var protocols: [ProtocolDeclaration]
public init(classes: [ClassDeclaration] = [],
structs: [StructDeclaration] = [],
protocols: [ProtocolDeclaration] = [])
{
self.classes = classes
self.structs = structs
self.protocols = protocols
}
}
With classes described like this:
public struct ClassDeclaration {
public var name: String
public var runtimeName: String
public var accessibility: Accessibility
// Construction
public var inits: [FunctionConstructorDeclaration]
public var deinits: [FunctionDestructorDeclaration]
// Methods
public var instanceMethods: [FunctionMethodInstanceDeclaration]
public var classMethods: [FunctionMethodClassDeclaration]
public var staticMethods: [FunctionMethodStaticDeclaration]
// Types
public var nestedClasses: [ClassDeclaration]
public var nestedStructs: [StructDeclaration]
public var nestedTypealiases: [TypealiasDeclaration]
// Vars
public var staticVars: [VarStaticDeclaration]
public var instanceVars: [VarInstanceDeclaration]
public init(name: String,
runtimeName: String,
accessibility: Accessibility,
// Construction
inits: [FunctionConstructorDeclaration] = [],
deinits: [FunctionDestructorDeclaration] = [],
// Methods
instanceMethods: [FunctionMethodInstanceDeclaration] = [],
classMethods: [FunctionMethodClassDeclaration] = [],
staticMethods: [FunctionMethodStaticDeclaration] = [],
// Types
nestedClasses: [ClassDeclaration] = [],
nestedStructs: [StructDeclaration] = [],
nestedTypealiases: [TypealiasDeclaration] = [],
// Vars
staticVars: [VarStaticDeclaration] = [],
instanceVars: [VarInstanceDeclaration] = [])
{
self.name = name
self.runtimeName = runtimeName
self.accessibility = accessibility
// Construction
self.inits = inits
self.deinits = deinits
// Methods
self.instanceMethods = instanceMethods
self.classMethods = classMethods
self.staticMethods = staticMethods
// Types
self.nestedClasses = nestedClasses
self.nestedStructs = nestedStructs
self.nestedTypealiases = nestedTypealiases
// Vars
self.staticVars = staticVars
self.instanceVars = instanceVars
}
}
So, these structures are easy to read, modify, they don't contain unused properties. It's easy to generate code from those structures.
Code examples are from my project called Switt (https://github.com/SwiftTools/Switt, project with little history). It is that framework that I want to have for my main goal - various code generation utils.
It turned out that it is really a hard work. I need to describe each declaration, fix the erroneous output of SourceKit (such as a variables with type "{"), and do many other things. And I have to support it.
But I still don't know if I do excess work. Because I want to use such tool and not write it. If there's already a thing like I'm writing, I will use it.