Announcing SwiftSyntaxBuilder

Hi Swift Community!

SwiftSyntaxBuilder a new library that makes it possible to generate Swift code in a declarative way using result builders. :tada:

The library contains everything to get started generating Swift code with a nice and convenient API, but there is space for improvements!

I would like to encourage everyone interested to give SwiftSyntaxBuilder a try, report any feedback you have or contribute to the library. Any contributions would be amazing and this is a community driven library so if you want to get involved, please do! :pray:

Based on your feedback, we will be working on finding the missing parts and implementing them.

If you find a bug or have a suggestion to improve the API, you can find the guide to report them here.

Thanks to Akio Yasui for the initial version.

Thanks!

Kim

26 Likes

I think I found an example of this new library here: swift-syntax/CodeGenerationUsingSwiftSyntaxBuilder.swift at main Β· apple/swift-syntax Β· GitHub

Looks pretty neat!

3 Likes

Congratulations on the initial take on the lib! This is awesome and really a lifesaver for source generation plugins :clap: I've been cheering on this effort from the sidelines ever since :smiley:

For better or worse, for my current work we moved away from source generation but the shape of the lib and APIs looks excellent, exactly what one would have hoped for - congrats and thanks for your work!

5 Likes

This looks great, thank you for sharing!

I wish we had more documentation for it. This is what I found apart from the link shared by Kiel:
https://speakerdeck.com/akkyie/swiftsyntaxbuilder-equals-swiftsyntax-x-function-builders?slide=25 (in Japanese)

Is there any way to manipulate SourceFile from some other part of code other than main?

In other words as per the shared example the complete structure is generated within main function:

@main
struct Main {
var source = SourceFile

  static func main() {
    let properties = [
      "firstName": "String",
      "lastName": "String",
      "age": "Int",
    ]

    source = SourceFile {
      StructDecl(identifier: "Person") {
        for (propertyName, propertyType) in properties {
          VariableDecl("var \(propertyName): \(propertyType)")

          FunctionDecl("""
            func with\(propertyName.withFirstLetterUppercased())(_ \(propertyName): \(propertyType)) -> Person {
              var result = self
              result.\(propertyName) = \(propertyName)
              return result
            }
            """
          )
        }
      }
    }

    print(source.formatted().description)
  }
}

Is it possible to modify it say on tap of button:

@IBAction func addAddressProperty() {
   // add address property to source

print(source.formatted().description) // prints updated structure
}

You can perform this kind of code generation anywhere in your application. It is not bound to a main function. The examples in the swift-syntax repository are supposed to be readily executable. That's why they perform all the generation and transformation steps right in the main function.

Speaking about transformations, you can also rewrite an existing piece of code implementing a SyntaxRewriter (available in the SwiftSyntax module). AddOneToIntegerLiterals.swift is an example for that. To get from source code to an AST you want to use the Parser provided by SwiftParser.

1 Like

You should also be able to find documentation here: SwiftSyntax – Swift Package Index

If there is any kind of specific documention you need feel free to ask here :partying_face:

2 Likes