structured editing library • Includes trivias (whitespaces & comments) • Attaches trivias to leading / trailing of token • Similar to .NET (Roslyn) / TypeScript Syntax API • Internally calls swiftc -frontend -emit-syntax and passes JSON for "C++ to Swift" bridging (in Swift 4.2)
// Simple statements, compiler control, and control flow. enum Statement { case expression(Expression, Semicolon?) case declaration(Declaration, Semicolon?) case loop(LoopStatement, Semicolon?) case branch(BranchStatement, Semicolon?) case labeled(LabeledStatement, Semicolon?) case controlTransfer(ControlTransferStatement, Semicolon?) case `defer`(DeferStatement, Semicolon?) case `do`(DoStatement, Semicolon?) case compilerControl(CompilerControlStatement) }
variables. enum Declaration { case `import`(ImportDeclaration) case constant(ConstantDeclaration) case variable(VariableDeclaration) case `typealias`(TypealiasDeclaration) case function(FunctionDeclaration) case `enum`(EnumDeclaration) case `struct`(StructDeclaration) case `class`(ClassDeclaration) case `protocol`(ProtocolDeclaration) case initializer(InitializerDeclaration) case deinitializer(DeinitializerDeclaration) case `extension`(ExtensionDeclaration) case `subscript`(SubscriptDeclaration) case `operator`(OperatorDeclaration) case precedenceGroup(PrecedenceGroupDeclaration) }
side effect. struct Expression { let tryOperator: TryOperator? let prefixExpression: PrefixExpression let binaryExpressions: [BinaryExpression] } enum PrefixExpression { case prefixOperator(PrefixOperator?, PostfixExpression) case `inout`(InoutExpression) } enum PostfixExpression { case primary(PrimaryExpression) case functionCall(FunctionCallExpression) case initializer(InitializerExpression) ... }
trailing) • Comments & whitespaces are stored in TokenSyntax • SyntaxFactory • Creates a new Syntax nodes • Diagnostic • Data types for showing diagnosed Note & FixIt
rightParen = syntax.parameters.rightParen // Modify grandchild (e.g. changing trivia). rightParen = modify(rightParen) // Set new child. let parameters = syntax.parameters .withRightParen(rightParen) // Set new `syntax` ( ❌ many more code needed if deeply nested) return syntax.withParameters(parameters)
Many incoming improvements toward Swift 5.0 or later • Swift AST Explorer: Useful AST visualizer for debugging • Formal grammar: Syntax production rules • Optics: Functional approach to traverse data structure • Let's make your own code formatter using SwiftSyntax!
Swift Tools with libSyntax • try! Swift Tokyo 2018 - AST Meta-programming • apple/swift/lib/Syntax • Speeding up SwiftSyntax by using the parser directly • About the Language Reference (Swift 4.2) • SwiftFormat (Part 1 of 3) - Schibsted Bytes • google/swift (format branch)
Brandon Williams - Lenses in Swift • Lenses and Prisms in Swift: a pragmatic approach | Fun iOS • Lenses, Folds, and Traversals - Edward Kmett • Oleg's gists - Glassery • Profunctor Optics: Modular Data Accessors