4

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.

3

Our DMS Software Reengineering Toolkit can do this.

It is actually a program transformation system that parses source text, builds ASTs, enables AST navigation, modification and construction of new ASTs, and then can prettyprint such ASTs back to compilable source code. Many transformations on the ASTs can be written in using the notation of that language, to achieve if you see this, replace it by that pattern-directed changes. DMS is parameterized by a language grammar definition allowing arbitrary languages.

DMS supports a wide variety of grammars, including recently Swift.

The following is a dump of the AST in S-expression style, produced by parsing OP's TopLevelDeclarations:

Swift Domain Parser Version 2.6.15
Copyright (C) 1996-2015 Semantic Designs, Inc; All Rights Reserved; SD Confidential
Powered by DMS (R) Software Reengineering Toolkit
(Swift@Swift=1#5240ac0^0 Line 1 Column 1 File C:/temp/test.swift
 (statement@Swift=3#5240aa0^1#5240ac0:1 Line 1 Column 1 File C:/temp/test.swift
  (struct_declaration@Swift=195#5240a40^1#5240aa0:1 Line 1 Column 1 File C:/temp/test.swift
   (attributes_opt@Swift=387#523b820^1#5240a40:1 Line 1 Column 1 File C:/temp/test.swift)attributes_opt
   (access_specifier@Swift=105#523b8a0^1#5240a40:2 Line 1 Column 1 File C:/temp/test.swift
   |('public'@Swift=501#523b800^1#523b8a0:1[Keyword:0] Line 1 Column 1 File C:/temp/test.swift)'public'
   )access_specifier#523b8a0
   ('struct'@Swift=506#523b880^1#5240a40:3[Keyword:0] Line 1 Column 8 File C:/temp/test.swift)'struct'
   (IDENTIFIER@Swift=484#523b920^1#5240a40:4[`TopLevelDeclarations'] Line 1 Column 15 File C:/temp/test.swift)IDENTIFIER
   (generic_parameter_clause_opt@Swift=385#523b960^1#5240a40:5 Line 1 Column 36 File C:/temp/test.swift)generic_parameter_clause_opt
   (type_inheritance_clause_opt@Swift=381#523b980^1#5240a40:6 Line 1 Column 36 File C:/temp/test.swift)type_inheritance_clause_opt
   ('{'@Swift=477#523b940^1#5240a40:7[Keyword:0] Line 1 Column 36 File C:/temp/test.swift)'{'
   (declarations@Swift=90#5240800^1#5240a40:8 Line 2 Column 5 File C:/temp/test.swift
   |(variable_declaration@Swift=127#523be20^1#5240800:1 Line 2 Column 5 File C:/temp/test.swift
   | (variable_declaration_head@Swift=133#523bbc0^1#523be20:1 Line 2 Column 5 File C:/temp/test.swift
   |  (attributes_opt@Swift=387#523ba00^1#523bbc0:1 Line 2 Column 5 File C:/temp/test.swift)attributes_opt
   |  (access_specifier@Swift=105#523bac0^1#523bbc0:2 Line 2 Column 5 File C:/temp/test.swift
   |   ('public'@Swift=501#523b9e0^1#523bac0:1[Keyword:0] Line 2 Column 5 File C:/temp/test.swift)'public'
   |  )access_specifier#523bac0
   |  ('var'@Swift=509#523baa0^1#523bbc0:3[Keyword:0] Line 2 Column 12 File C:/temp/test.swift)'var'
   | )variable_declaration_head#523bbc0
   | (pattern@Swift=230#523bc80^1#523be20:2 Line 2 Column 16 File C:/temp/test.swift
   |  (IDENTIFIER@Swift=484#523bba0^1#523bc80:1[`classes'] Line 2 Column 16 File C:/temp/test.swift)IDENTIFIER
   |  (type_annotation@Swift=352#523bbe0^1#523bc80:2 Line 2 Column 23 File C:/temp/test.swift
   |   (':'@Swift=480#523bc40^1#523bbe0:1[Keyword:0] Line 2 Column 23 File C:/temp/test.swift)':'
   |   (attributes_opt@Swift=387#523bda0^1#523bbe0:2 Line 2 Column 25 File C:/temp/test.swift)attributes_opt
   |   (type_identifier@Swift=353#523bca0^1#523bbe0:3 Line 2 Column 25 File C:/temp/test.swift
   |   |(IDENTIFIER@Swift=484#523bdc0^1#523bca0:1[`[ClassDeclaration]'] Line 2 Column 25 File C:/temp/test.swift)IDENTIFIER
   |   |(generic_argument_clause_opt@Swift=377#523bd40^1#523bca0:2 Line 3 Column 5 File C:/temp/test.swift)generic_argument_clause_opt
   |   )type_identifier#523bca0
   |  )type_annotation#523bbe0
   | )pattern#523bc80
   |)variable_declaration#523be20
   |(declarations@Swift=90#52407e0^1#5240800:2 Line 3 Column 5 File C:/temp/test.swift
   | (variable_declaration@Swift=127#523e040^1#52407e0:1 Line 3 Column 5 File C:/temp/test.swift
   |  (variable_declaration_head@Swift=133#523bfa0^1#523e040:1 Line 3 Column 5 File C:/temp/test.swift
   |   (attributes_opt@Swift=387#523bea0^1#523bfa0:1 Line 3 Column 5 File C:/temp/test.swift)attributes_opt
   |   (access_specifier@Swift=105#523bf60^1#523bfa0:2 Line 3 Column 5 File C:/temp/test.swift
   |   |('public'@Swift=501#523bd80^1#523bf60:1[Keyword:0] Line 3 Column 5 File C:/temp/test.swift)'public'
   |   )access_specifier#523bf60
   |   ('var'@Swift=509#523bf40^1#523bfa0:3[Keyword:0] Line 3 Column 12 File C:/temp/test.swift)'var'
   |  )variable_declaration_head#523bfa0
   |  (pattern@Swift=230#523e060^1#523e040:2 Line 3 Column 16 File C:/temp/test.swift
   |   (IDENTIFIER@Swift=484#523bf80^1#523e060:1[`structs'] Line 3 Column 16 File C:/temp/test.swift)IDENTIFIER
   |   (type_annotation@Swift=352#523bfc0^1#523e060:2 Line 3 Column 23 File C:/temp/test.swift
   |   |(':'@Swift=480#523bfe0^1#523bfc0:1[Keyword:0] Line 3 Column 23 File C:/temp/test.swift)':'
   |   |(attributes_opt@Swift=387#523bd20^1#523bfc0:2 Line 3 Column 25 File C:/temp/test.swift)attributes_opt
   |   |(type_identifier@Swift=353#523e080^1#523bfc0:3 Line 3 Column 25 File C:/temp/test.swift
   |   | (IDENTIFIER@Swift=484#523bb60^1#523e080:1[`[StructDeclaration]'] Line 3 Column 25 File C:/temp/test.swift)IDENTIFIER
   |   | (generic_argument_clause_opt@Swift=377#523e0c0^1#523e080:2 Line 4 Column 5 File C:/temp/test.swift)generic_argument_clause_opt
   |   |)type_identifier#523e080
   |   )type_annotation#523bfc0
   |  )pattern#523e060
   | )variable_declaration#523e040
   | (declarations@Swift=90#52407c0^1#52407e0:2 Line 4 Column 5 File C:/temp/test.swift
   |  (variable_declaration@Swift=127#523e2e0^1#52407c0:1 Line 4 Column 5 File C:/temp/test.swift
   |   (variable_declaration_head@Swift=133#523e1a0^1#523e2e0:1 Line 4 Column 5 File C:/temp/test.swift
   |   |(attributes_opt@Swift=387#523e0a0^1#523e1a0:1 Line 4 Column 5 File C:/temp/test.swift)attributes_opt
   |   |(access_specifier@Swift=105#523e160^1#523e1a0:2 Line 4 Column 5 File C:/temp/test.swift
   |   | ('public'@Swift=501#523bce0^1#523e160:1[Keyword:0] Line 4 Column 5 File C:/temp/test.swift)'public'
   |   |)access_specifier#523e160
   |   |('var'@Swift=509#523e140^1#523e1a0:3[Keyword:0] Line 4 Column 12 File C:/temp/test.swift)'var'
   |   )variable_declaration_head#523e1a0
   |   (pattern@Swift=230#523e2a0^1#523e2e0:2 Line 4 Column 16 File C:/temp/test.swift
   |   |(IDENTIFIER@Swift=484#523e180^1#523e2a0:1[`protocols'] Line 4 Column 16 File C:/temp/test.swift)IDENTIFIER
   |   |(type_annotation@Swift=352#523e240^1#523e2a0:2 Line 4 Column 25 File C:/temp/test.swift
   |   | (':'@Swift=480#523e1e0^1#523e240:1[Keyword:0] Line 4 Column 25 File C:/temp/test.swift)':'
   |   | (attributes_opt@Swift=387#523e2c0^1#523e240:2 Line 4 Column 27 File C:/temp/test.swift)attributes_opt
   |   | (type_identifier@Swift=353#523e260^1#523e240:3 Line 4 Column 27 File C:/temp/test.swift
   |   |  (IDENTIFIER@Swift=484#523bb20^1#523e260:1[`[ProtocolDeclaration]'] Line 4 Column 27 File C:/temp/test.swift)IDENTIFIER
   |   |  (generic_argument_clause_opt@Swift=377#523e1c0^1#523e260:2 Line 6 Column 5 File C:/temp/test.swift)generic_argument_clause_opt
   |   | )type_identifier#523e260
   |   |)type_annotation#523e240
   |   )pattern#523e2a0
   |  )variable_declaration#523e2e0
   |  (initializer_declaration@Swift=210#5240780^1#52407c0:2 Line 6 Column 5 File C:/temp/test.swift
   |   (initializer_head@Swift=212#523e580^1#5240780:1 Line 6 Column 5 File C:/temp/test.swift
   |   |(attributes_opt@Swift=387#523e200^1#523e580:1 Line 6 Column 5 File C:/temp/test.swift)attributes_opt
   |   |(access_specifier@Swift=105#523e540^1#523e580:2 Line 6 Column 5 File C:/temp/test.swift
   |   | ('public'@Swift=501#523e280^1#523e540:1[Keyword:0] Line 6 Column 5 File C:/temp/test.swift)'public'
   |   |)access_specifier#523e540
   |   |('init'@Swift=524#523e520^1#523e580:3[Keyword:0] Line 6 Column 12 File C:/temp/test.swift)'init'
   |   )initializer_head#523e580
   |   (generic_parameter_clause_opt@Swift=385#523e5a0^1#5240780:2 Line 6 Column 16 File C:/temp/test.swift)generic_parameter_clause_opt
   |   (parameter_clause@Swift=159#523f0a0^1#5240780:3 Line 6 Column 16 File C:/temp/test.swift
   |   |('('@Swift=469#523e560^1#523f0a0:1[Keyword:0] Line 6 Column 16 File C:/temp/test.swift)'('
   |   |(parameter_list@Swift=162#523f020^1#523f0a0:2 Line 6 Column 17 File C:/temp/test.swift
   |   | (parameter_list@Swift=162#523ecc0^1#523f020:1 Line 6 Column 17 File C:/temp/test.swift
   |   |  (parameter@Swift=163#523e900^1#523ecc0:1 Line 6 Column 17 File C:/temp/test.swift
   |   |   (parameter_head@Swift=166#523e680^1#523e900:1 Line 6 Column 17 File C:/temp/test.swift
   |   |   |(inout_opt@Swift=401#523e620^1#523e680:1 Line 6 Column 17 File C:/temp/test.swift)inout_opt
   |   |   |(pound_opt@Swift=399#523e660^1#523e680:2 Line 6 Column 17 File C:/temp/test.swift)pound_opt
   |   |   )parameter_head#523e680
   |   |   (parameter_body@Swift=167#523e880^1#523e900:2 Line 6 Column 17 File C:/temp/test.swift
   |   |   |(IDENTIFIER@Swift=484#523e5c0^1#523e880:1[`classes'] Line 6 Column 17 File C:/temp/test.swift)IDENTIFIER
   |   |   |(local_parameter_name_opt@Swift=449#523e740^1#523e880:2 Line 6 Column 24 File C:/temp/test.swift)local_parameter_name_opt
   |   |   |(type_annotation@Swift=352#523bee0^1#523e880:3 Line 6 Column 24 File C:/temp/test.swift
   |   |   | (':'@Swift=480#523e6a0^1#523bee0:1[Keyword:0] Line 6 Column 24 File C:/temp/test.swift)':'
   |   |   | (attributes_opt@Swift=387#523ba60^1#523bee0:2 Line 6 Column 26 File C:/temp/test.swift)attributes_opt
   |   |   | (type_identifier@Swift=353#523bec0^1#523bee0:3 Line 6 Column 26 File C:/temp/test.swift
   |   |   |  (IDENTIFIER@Swift=484#523ba20^1#523bec0:1[`[ClassDeclaration]'] Line 6 Column 26 File C:/temp/test.swift)IDENTIFIER
   |   |   |  (generic_argument_clause_opt@Swift=377#523e700^1#523bec0:2 Line 6 Column 45 File C:/temp/test.swift)generic_argument_clause_opt
   |   |   | )type_identifier#523bec0
   |   |   |)type_annotation#523bee0
   |   |   |(default_argument_clause@Swift=173#523e820^1#523e880:4 Line 6 Column 45 File C:/temp/test.swift
   |   |   | ('='@Swift=514#523e720^1#523e820:1[Keyword:0] Line 6 Column 45 File C:/temp/test.swift)'='
   |   |   | (expression@Swift=257#523e7e0^1#523e820:2 Line 6 Column 47 File C:/temp/test.swift
   |   |   |  (prefix_expression@Swift=260#523e7a0^1#523e7e0:1 Line 6 Column 47 File C:/temp/test.swift
   |   |   |   (prefix_operator_opt@Swift=407#523e760^1#523e7a0:1 Line 6 Column 47 File C:/temp/test.swift)prefix_operator_opt
   |   |   |   (primary_expression@Swift=270#523e780^1#523e7a0:2 Line 6 Column 47 File C:/temp/test.swift
   |   |   |   |(IDENTIFIER@Swift=484#523e640^1#523e780:1[`[]'] Line 6 Column 47 File C:/temp/test.swift)IDENTIFIER
   |   |   |   |(generic_argument_clause_opt@Swift=377#523e6e0^1#523e780:2 Line 6 Column 49 File C:/temp/test.swift)generic_argument_clause_opt
   |   |   |   )primary_expression#523e780
   |   |   |  )prefix_expression#523e7a0
   |   |   |  (binary_expressions_opt@Swift=443#523e7c0^1#523e7e0:2 Line 6 Column 49 File C:/temp/test.swift)binary_expressions_opt
   |   |   | )expression#523e7e0
   |   |   |)default_argument_clause#523e820
   |   |   )parameter_body#523e880
   |   |  )parameter#523e900
   |   |  (','@Swift=481#523e6c0^1#523ecc0:2[Keyword:0] Line 6 Column 49 File C:/temp/test.swift)','
   |   |  (parameter@Swift=163#523ec80^1#523ecc0:3 Line 7 Column 9 File C:/temp/test.swift
   |   |   (parameter_head@Swift=166#523ea20^1#523ec80:1 Line 7 Column 9 File C:/temp/test.swift
   |   |   |(inout_opt@Swift=401#523e9c0^1#523ea20:1 Line 7 Column 9 File C:/temp/test.swift)inout_opt
   |   |   |(pound_opt@Swift=399#523ea00^1#523ea20:2 Line 7 Column 9 File C:/temp/test.swift)pound_opt
   |   |   )parameter_head#523ea20
   |   |   (parameter_body@Swift=167#523ec00^1#523ec80:2 Line 7 Column 9 File C:/temp/test.swift
   |   |   |(IDENTIFIER@Swift=484#523e9a0^1#523ec00:1[`structs'] Line 7 Column 9 File C:/temp/test.swift)IDENTIFIER
   |   |   |(local_parameter_name_opt@Swift=449#523eae0^1#523ec00:2 Line 7 Column 16 File C:/temp/test.swift)local_parameter_name_opt
   |   |   |(type_annotation@Swift=352#523e9e0^1#523ec00:3 Line 7 Column 16 File C:/temp/test.swift
   |   |   | (':'@Swift=480#523ea80^1#523e9e0:1[Keyword:0] Line 7 Column 16 File C:/temp/test.swift)':'
   |   |   | (attributes_opt@Swift=387#523eac0^1#523e9e0:2 Line 7 Column 18 File C:/temp/test.swift)attributes_opt
   |   |   | (type_identifier@Swift=353#523e940^1#523e9e0:3 Line 7 Column 18 File C:/temp/test.swift
   |   |   |  (IDENTIFIER@Swift=484#523e800^1#523e940:1[`[StructDeclaration]'] Line 7 Column 18 File C:/temp/test.swift)IDENTIFIER
   |   |   |  (generic_argument_clause_opt@Swift=377#523e8c0^1#523e940:2 Line 7 Column 38 File C:/temp/test.swift)generic_argument_clause_opt
   |   |   | )type_identifier#523e940
   |   |   |)type_annotation#523e9e0
   |   |   |(default_argument_clause@Swift=173#523ebe0^1#523ec00:4 Line 7 Column 38 File C:/temp/test.swift
   |   |   | ('='@Swift=514#523eaa0^1#523ebe0:1[Keyword:0] Line 7 Column 38 File C:/temp/test.swift)'='
   |   |   | (expression@Swift=257#523ebc0^1#523ebe0:2 Line 7 Column 40 File C:/temp/test.swift
   |   |   |  (prefix_expression@Swift=260#523eb80^1#523ebc0:1 Line 7 Column 40 File C:/temp/test.swift
   |   |   |   (prefix_operator_opt@Swift=407#523eb00^1#523eb80:1 Line 7 Column 40 File C:/temp/test.swift)prefix_operator_opt
   |   |   |   (primary_expression@Swift=270#523eb60^1#523eb80:2 Line 7 Column 40 File C:/temp/test.swift
   |   |   |   |(IDENTIFIER@Swift=484#523ea40^1#523eb60:1[`[]'] Line 7 Column 40 File C:/temp/test.swift)IDENTIFIER
   |   |   |   |(generic_argument_clause_opt@Swift=377#523eb40^1#523eb60:2 Line 7 Column 42 File C:/temp/test.swift)generic_argument_clause_opt
   |   |   |   )primary_expression#523eb60
   |   |   |  )prefix_expression#523eb80
   |   |   |  (binary_expressions_opt@Swift=443#523eba0^1#523ebc0:2 Line 7 Column 42 File C:/temp/test.swift)binary_expressions_opt
   |   |   | )expression#523ebc0
   |   |   |)default_argument_clause#523ebe0
   |   |   )parameter_body#523ec00
   |   |  )parameter#523ec80
   |   | )parameter_list#523ecc0
   |   | (','@Swift=481#523eb20^1#523f020:2[Keyword:0] Line 7 Column 42 File C:/temp/test.swift)','
   |   | (parameter@Swift=163#523f000^1#523f020:3 Line 8 Column 9 File C:/temp/test.swift
   |   |  (parameter_head@Swift=166#523edc0^1#523f000:1 Line 8 Column 9 File C:/temp/test.swift
   |   |   (inout_opt@Swift=401#523ed60^1#523edc0:1 Line 8 Column 9 File C:/temp/test.swift)inout_opt
   |   |   (pound_opt@Swift=399#523eda0^1#523edc0:2 Line 8 Column 9 File C:/temp/test.swift)pound_opt
   |   |  )parameter_head#523edc0
   |   |  (parameter_body@Swift=167#523efc0^1#523f000:2 Line 8 Column 9 File C:/temp/test.swift
   |   |   (IDENTIFIER@Swift=484#523ed40^1#523efc0:1[`protocols'] Line 8 Column 9 File C:/temp/test.swift)IDENTIFIER
   |   |   (local_parameter_name_opt@Swift=449#523eec0^1#523efc0:2 Line 8 Column 18 File C:/temp/test.swift)local_parameter_name_opt
   |   |   (type_annotation@Swift=352#523ed80^1#523efc0:3 Line 8 Column 18 File C:/temp/test.swift
   |   |   |(':'@Swift=480#523ede0^1#523ed80:1[Keyword:0] Line 8 Column 18 File C:/temp/test.swift)':'
   |   |   |(attributes_opt@Swift=387#523e8e0^1#523ed80:2 Line 8 Column 20 File C:/temp/test.swift)attributes_opt
   |   |   |(type_identifier@Swift=353#523e980^1#523ed80:3 Line 8 Column 20 File C:/temp/test.swift
   |   |   | (IDENTIFIER@Swift=484#523e920^1#523e980:1[`[ProtocolDeclaration]'] Line 8 Column 20 File C:/temp/test.swift)IDENTIFIER
   |   |   | (generic_argument_clause_opt@Swift=377#523ee40^1#523e980:2 Line 8 Column 42 File C:/temp/test.swift)generic_argument_clause_opt
   |   |   |)type_identifier#523e980
   |   |   )type_annotation#523ed80
   |   |   (default_argument_clause@Swift=173#523efa0^1#523efc0:4 Line 8 Column 42 File C:/temp/test.swift
   |   |   |('='@Swift=514#523eea0^1#523efa0:1[Keyword:0] Line 8 Column 42 File C:/temp/test.swift)'='
   |   |   |(expression@Swift=257#523ef80^1#523efa0:2 Line 8 Column 44 File C:/temp/test.swift
   |   |   | (prefix_expression@Swift=260#523ef40^1#523ef80:1 Line 8 Column 44 File C:/temp/test.swift
   |   |   |  (prefix_operator_opt@Swift=407#523ee00^1#523ef40:1 Line 8 Column 44 File C:/temp/test.swift)prefix_operator_opt
   |   |   |  (primary_expression@Swift=270#523ef20^1#523ef40:2 Line 8 Column 44 File C:/temp/test.swift
   |   |   |   (IDENTIFIER@Swift=484#523eee0^1#523ef20:1[`[]'] Line 8 Column 44 File C:/temp/test.swift)IDENTIFIER
   |   |   |   (generic_argument_clause_opt@Swift=377#523ef00^1#523ef20:2 Line 8 Column 46 File C:/temp/test.swift)generic_argument_clause_opt
   |   |   |  )primary_expression#523ef20
   |   |   | )prefix_expression#523ef40
   |   |   | (binary_expressions_opt@Swift=443#523ef60^1#523ef80:2 Line 8 Column 46 File C:/temp/test.swift)binary_expressions_opt
   |   |   |)expression#523ef80
   |   |   )default_argument_clause#523efa0
   |   |  )parameter_body#523efc0
   |   | )parameter#523f000
   |   |)parameter_list#523f020
   |   |(')'@Swift=470#523ee20^1#523f0a0:3[Keyword:0] Line 8 Column 46 File C:/temp/test.swift)')'
   |   )parameter_clause#523f0a0
   |   (code_block@Swift=109#5240760^1#5240780:4 Line 9 Column 5 File C:/temp/test.swift
   |   |('{'@Swift=477#523f080^1#5240760:1[Keyword:0] Line 9 Column 5 File C:/temp/test.swift)'{'
   |   |(statements@Swift=9#5240680^1#5240760:2 Line 10 Column 9 File C:/temp/test.swift
   |   | (statements@Swift=9#52400a0^1#5240680:1 Line 10 Column 9 File C:/temp/test.swift
   |   |  (statements@Swift=9#523fec0^1#52400a0:1 Line 10 Column 9 File C:/temp/test.swift
   |   |   (statements@Swift=9#523f900^1#523fec0:1 Line 10 Column 9 File C:/temp/test.swift
   |   |   |(statements@Swift=9#523f720^1#523f900:1 Line 10 Column 9 File C:/temp/test.swift
   |   |   | (statement@Swift=2#523f1c0^1#523f720:1 Line 10 Column 9 File C:/temp/test.swift
   |   |   |  (expression@Swift=257#523f180^1#523f1c0:1 Line 10 Column 9 File C:/temp/test.swift
   |   |   |   (prefix_expression@Swift=260#523f140^1#523f180:1 Line 10 Column 9 File C:/temp/test.swift
   |   |   |   |(prefix_operator_opt@Swift=407#523f0e0^1#523f140:1 Line 10 Column 9 File C:/temp/test.swift)prefix_operator_opt
   |   |   |   |(self_expression@Swift=294#523f120^1#523f140:2 Line 10 Column 9 File C:/temp/test.swift
   |   |   |   | ('self'@Swift=550#523f0c0^1#523f120:1[Keyword:0] Line 10 Column 9 File C:/temp/test.swift)'self'
   |   |   |   |)self_expression#523f120
   |   |   |   )prefix_expression#523f140
   |   |   |   (binary_expressions_opt@Swift=443#523f160^1#523f180:2 Line 10 Column 13 File C:/temp/test.swift)binary_expressions_opt
   |   |   |  )expression#523f180
   |   |   |  (semicolon_opt@Swift=391#523f1a0^1#523f1c0:2 Line 10 Column 13 File C:/temp/test.swift)semicolon_opt
   |   |   | )statement#523f1c0
   |   |   | (statement@Swift=2#523f6e0^1#523f720:2 Line 10 Column 13 File C:/temp/test.swift
   |   |   |  (expression@Swift=257#523f640^1#523f6e0:1 Line 10 Column 13 File C:/temp/test.swift
   |   |   |   (prefix_expression@Swift=260#523f440^1#523f640:1 Line 10 Column 13 File C:/temp/test.swift
   |   |   |   |(prefix_operator_opt@Swift=407#523f1e0^1#523f440:1 Line 10 Column 13 File C:/temp/test.swift)prefix_operator_opt
   |   |   |   |(primary_expression@Swift=276#523f360^1#523f440:2 Line 10 Column 13 File C:/temp/test.swift
   |   |   |   | ('.'@Swift=511#523f100^1#523f360:1[Keyword:0] Line 10 Column 13 File C:/temp/test.swift)'.'
   |   |   |   | (IDENTIFIER@Swift=484#523f240^1#523f360:2[`classes'] Line 10 Column 14 File C:/temp/test.swift)IDENTIFIER
   |   |   |   |)primary_expression#523f360
   |   |   |   )prefix_expression#523f440
   |   |   |   (binary_expression@Swift=263#523f620^1#523f640:2 Line 10 Column 22 File C:/temp/test.swift
   |   |   |   |('='@Swift=514#523f2c0^1#523f620:1[Keyword:0] Line 10 Column 22 File C:/temp/test.swift)'='
   |   |   |   |(prefix_expression@Swift=260#523f600^1#523f620:2 Line 10 Column 24 File C:/temp/test.swift
   |   |   |   | (prefix_operator_opt@Swift=407#523f5c0^1#523f600:1 Line 10 Column 24 File C:/temp/test.swift)prefix_operator_opt
   |   |   |   | (primary_expression@Swift=270#523f5a0^1#523f600:2 Line 10 Column 24 File C:/temp/test.swift
   |   |   |   |  (IDENTIFIER@Swift=484#523f520^1#523f5a0:1[`classes'] Line 10 Column 24 File C:/temp/test.swift)IDENTIFIER
   |   |   |   |  (generic_argument_clause_opt@Swift=377#523f580^1#523f5a0:2 Line 11 Column 9 File C:/temp/test.swift)generic_argument_clause_opt
   |   |   |   | )primary_expression#523f5a0
   |   |   |   |)prefix_expression#523f600
   |   |   |   )binary_expression#523f620
   |   |   |  )expression#523f640
   |   |   |  (semicolon_opt@Swift=391#523f6c0^1#523f6e0:2 Line 11 Column 9 File C:/temp/test.swift)semicolon_opt
   |   |   | )statement#523f6e0
   |   |   |)statements#523f720
   |   |   |(statement@Swift=2#523f8e0^1#523f900:2 Line 11 Column 9 File C:/temp/test.swift
   |   |   | (expression@Swift=257#523f8a0^1#523f8e0:1 Line 11 Column 9 File C:/temp/test.swift
   |   |   |  (prefix_expression@Swift=260#523f820^1#523f8a0:1 Line 11 Column 9 File C:/temp/test.swift
   |   |   |   (prefix_operator_opt@Swift=407#523f7c0^1#523f820:1 Line 11 Column 9 File C:/temp/test.swift)prefix_operator_opt
   |   |   |   (self_expression@Swift=294#523f800^1#523f820:2 Line 11 Column 9 File C:/temp/test.swift
   |   |   |   |('self'@Swift=550#523f560^1#523f800:1[Keyword:0] Line 11 Column 9 File C:/temp/test.swift)'self'
   |   |   |   )self_expression#523f800
   |   |   |  )prefix_expression#523f820
   |   |   |  (binary_expressions_opt@Swift=443#523f880^1#523f8a0:2 Line 11 Column 13 File C:/temp/test.swift)binary_expressions_opt
   |   |   | )expression#523f8a0
   |   |   | (semicolon_opt@Swift=391#523f8c0^1#523f8e0:2 Line 11 Column 13 File C:/temp/test.swift)semicolon_opt
   |   |   |)statement#523f8e0
   |   |   )statements#523f900
   |   |   (statement@Swift=2#523fe40^1#523fec0:2 Line 11 Column 13 File C:/temp/test.swift
   |   |   |(expression@Swift=257#523fd00^1#523fe40:1 Line 11 Column 13 File C:/temp/test.swift
   |   |   | (prefix_expression@Swift=260#523fbc0^1#523fd00:1 Line 11 Column 13 File C:/temp/test.swift
   |   |   |  (prefix_operator_opt@Swift=407#523f920^1#523fbc0:1 Line 11 Column 13 File C:/temp/test.swift)prefix_operator_opt
   |   |   |  (primary_expression@Swift=276#523fae0^1#523fbc0:2 Line 11 Column 13 File C:/temp/test.swift
   |   |   |   ('.'@Swift=511#523f7e0^1#523fae0:1[Keyword:0] Line 11 Column 13 File C:/temp/test.swift)'.'
   |   |   |   (IDENTIFIER@Swift=484#523f9c0^1#523fae0:2[`structs'] Line 11 Column 14 File C:/temp/test.swift)IDENTIFIER
   |   |   |  )primary_expression#523fae0
   |   |   | )prefix_expression#523fbc0
   |   |   | (binary_expression@Swift=263#523fda0^1#523fd00:2 Line 11 Column 22 File C:/temp/test.swift
   |   |   |  ('='@Swift=514#523f9e0^1#523fda0:1[Keyword:0] Line 11 Column 22 File C:/temp/test.swift)'='
   |   |   |  (prefix_expression@Swift=260#523fd20^1#523fda0:2 Line 11 Column 24 File C:/temp/test.swift
   |   |   |   (prefix_operator_opt@Swift=407#523fc80^1#523fd20:1 Line 11 Column 24 File C:/temp/test.swift)prefix_operator_opt
   |   |   |   (primary_expression@Swift=270#523fc40^1#523fd20:2 Line 11 Column 24 File C:/temp/test.swift
   |   |   |   |(IDENTIFIER@Swift=484#523fce0^1#523fc40:1[`structs'] Line 11 Column 24 File C:/temp/test.swift)IDENTIFIER
   |   |   |   |(generic_argument_clause_opt@Swift=377#523fcc0^1#523fc40:2 Line 12 Column 9 File C:/temp/test.swift)generic_argument_clause_opt
   |   |   |   )primary_expression#523fc40
   |   |   |  )prefix_expression#523fd20
   |   |   | )binary_expression#523fda0
   |   |   |)expression#523fd00
   |   |   |(semicolon_opt@Swift=391#523fde0^1#523fe40:2 Line 12 Column 9 File C:/temp/test.swift)semicolon_opt
   |   |   )statement#523fe40
   |   |  )statements#523fec0
   |   |  (statement@Swift=2#5240080^1#52400a0:2 Line 12 Column 9 File C:/temp/test.swift
   |   |   (expression@Swift=257#5240040^1#5240080:1 Line 12 Column 9 File C:/temp/test.swift
   |   |   |(prefix_expression@Swift=260#523ffe0^1#5240040:1 Line 12 Column 9 File C:/temp/test.swift
   |   |   | (prefix_operator_opt@Swift=407#523ff80^1#523ffe0:1 Line 12 Column 9 File C:/temp/test.swift)prefix_operator_opt
   |   |   | (self_expression@Swift=294#523ffc0^1#523ffe0:2 Line 12 Column 9 File C:/temp/test.swift
   |   |   |  ('self'@Swift=550#523fca0^1#523ffc0:1[Keyword:0] Line 12 Column 9 File C:/temp/test.swift)'self'
   |   |   | )self_expression#523ffc0
   |   |   |)prefix_expression#523ffe0
   |   |   |(binary_expressions_opt@Swift=443#5240020^1#5240040:2 Line 12 Column 13 File C:/temp/test.swift)binary_expressions_opt
   |   |   )expression#5240040
   |   |   (semicolon_opt@Swift=391#5240060^1#5240080:2 Line 12 Column 13 File C:/temp/test.swift)semicolon_opt
   |   |  )statement#5240080
   |   | )statements#52400a0
   |   | (statement@Swift=2#52405c0^1#5240680:2 Line 12 Column 13 File C:/temp/test.swift
   |   |  (expression@Swift=257#5240460^1#52405c0:1 Line 12 Column 13 File C:/temp/test.swift
   |   |   (prefix_expression@Swift=260#5240260^1#5240460:1 Line 12 Column 13 File C:/temp/test.swift
   |   |   |(prefix_operator_opt@Swift=407#52400c0^1#5240260:1 Line 12 Column 13 File C:/temp/test.swift)prefix_operator_opt
   |   |   |(primary_expression@Swift=276#5240240^1#5240260:2 Line 12 Column 13 File C:/temp/test.swift
   |   |   | ('.'@Swift=511#523ffa0^1#5240240:1[Keyword:0] Line 12 Column 13 File C:/temp/test.swift)'.'
   |   |   | (IDENTIFIER@Swift=484#52400e0^1#5240240:2[`protocols'] Line 12 Column 14 File C:/temp/test.swift)IDENTIFIER
   |   |   |)primary_expression#5240240
   |   |   )prefix_expression#5240260
   |   |   (binary_expression@Swift=263#5240440^1#5240460:2 Line 12 Column 24 File C:/temp/test.swift
   |   |   |('='@Swift=514#5240160^1#5240440:1[Keyword:0] Line 12 Column 24 File C:/temp/test.swift)'='
   |   |   |(prefix_expression@Swift=260#5240520^1#5240440:2 Line 12 Column 26 File C:/temp/test.swift
   |   |   | (prefix_operator_opt@Swift=407#52403e0^1#5240520:1 Line 12 Column 26 File C:/temp/test.swift)prefix_operator_opt
   |   |   | (primary_expression@Swift=270#5240540^1#5240520:2 Line 12 Column 26 File C:/temp/test.swift
   |   |   |  (IDENTIFIER@Swift=484#5240400^1#5240540:1[`protocols'] Line 12 Column 26 File C:/temp/test.swift)IDENTIFIER
   |   |   |  (generic_argument_clause_opt@Swift=377#52404e0^1#5240540:2 Line 13 Column 5 File C:/temp/test.swift)generic_argument_clause_opt
   |   |   | )primary_expression#5240540
   |   |   |)prefix_expression#5240520
   |   |   )binary_expression#5240440
   |   |  )expression#5240460
   |   |  (semicolon_opt@Swift=391#52404a0^1#52405c0:2 Line 13 Column 5 File C:/temp/test.swift)semicolon_opt
   |   | )statement#52405c0
   |   |)statements#5240680
   |   |('}'@Swift=478#52404c0^1#5240760:3[Keyword:0] Line 13 Column 5 File C:/temp/test.swift)'}'
   |   )code_block#5240760
   |  )initializer_declaration#5240780
   | )declarations#52407c0
   |)declarations#52407e0
   )declarations#5240800
   ('}'@Swift=478#5240740^1#5240a40:9[Keyword:0] Line 14 Column 1 File C:/temp/test.swift)'}'
  )struct_declaration#5240a40
  (semicolon_opt@Swift=391#5240a80^1#5240aa0:2 Line 14 Column 2 File C:/temp/test.swift)semicolon_opt
 )statement#5240aa0
)Swift#5240ac0

OP's code generation problem from the DMS perspective is to manufacture ASTs representing the code he wants. He can do that by building up the AST nodes individually; more often what one does with DMS is the instantiate surface syntax patterns, giving one tree fragments, and gluing such fragments together. In fact, instantiation of a pattern can be given tree fragments constructed by other means, to construct a compound tree.

DMS has been used for a wide variety of custom code analysis and transformation tasks. This is well within scope. (Yes, building a tool like DMS is hard work; we've been building/enhancing it for over 20 years).

  • I think it is a cool software, but I need open source software. I decided to build my own tool. I already complete swift grammar... Maybe it's not an optimal choice, it's a hard way, but it seems to be an only valid option for me. – artyom.razinov Mar 12 '16 at 22:11
  • @artyom.razinov: Thanks for the compliment. Yes, that's a choice. "Not optimal" might be an understatement. Check out semdesigns.com/Products/DMS/LifeAfterParsing.html. YMMV. – Ira Baxter Mar 12 '16 at 22:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.