File: SwiftAPIDigester.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (143 lines) | stat: -rw-r--r-- 4,435 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import Foundation

/// A wrapper for the swift-api-digester tool.
struct SwiftAPIDigester {
    /// The path to `swift-api-digester` executable in the toolchain
    let executableURL: URL

    init(executableURL: URL) {
        self.executableURL = executableURL
    }

    struct Output: Decodable {
        let ABIRoot: SDKNode

        static func parse(_ bytes: Data) throws -> Output {
            let decoder = JSONDecoder()
            return try decoder.decode(Output.self, from: bytes)
        }
    }

    struct SDKNodeInherit<Parent: Decodable, Body: Decodable>: Decodable {
        let parent: Parent
        let body: Body

        init(from decoder: Decoder) throws {
            self.parent = try Parent(from: decoder)
            self.body = try Body(from: decoder)
        }
    }

    enum SDKNode: Decodable {
        case root(SDKNodeRoot)
        case decl(SDKNodeDecl)
        case typeDecl(SDKNodeDeclType)
        case typeNominal(SDKNodeTypeNominal)
        case unknown(SDKNodeBody)

        var body: SDKNodeBody {
            switch self {
            case .root(let node): return node.parent
            case .decl(let node): return node.parent
            case .typeDecl(let node): return node.parent.parent
            case .typeNominal(let node): return node.parent.parent
            case .unknown(let node): return node
            }
        }

        var decl: SDKNodeDecl? {
            switch self {
            case .root: return nil
            case .decl(let node): return node
            case .typeDecl(let node): return node.parent
            case .typeNominal: return nil
            case .unknown: return nil
            }
        }

        enum CodingKeys: CodingKey {
            case kind
        }

        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            switch try container.decode(String.self, forKey: .kind) {
            case "Root":
                self = try .root(SDKNodeRoot(from: decoder))
            case "TypeDecl":
                self = try .typeDecl(SDKNodeDeclType(from: decoder))
            case "TypeNominal":
                self = try .typeNominal(SDKNodeTypeNominal(from: decoder))
            case "Var", "Function":
                self = try .decl(SDKNodeDecl(from: decoder))
            default:
                self = try .unknown(SwiftAPIDigester.SDKNodeBody(from: decoder))
            }
        }
    }

    struct SDKNodeBody: Decodable {
        let kind: String
        let name: String
        let printedName: String
        let children: [SDKNode]?

        enum CodingKeys: CodingKey {
            case kind
            case name
            case printedName
            case children
        }
    }

    typealias SDKNodeRoot = SDKNodeInherit<SDKNodeBody, SDKNodeRootBody>
    struct SDKNodeRootBody: Codable {
        let json_format_version: Int
    }

    struct SDKNodeDeclBody: Codable {
        let declKind: String
        let usr: String
        let mangledName: String
        let moduleName: String
        let declAttributes: [String]?
        let spi_group_names: [String]?
        let `static`: Bool?
    }

    struct SDKNodeDeclTypeBody: Codable {}
    struct SDKNodeTypeBody: Codable {}
    struct SDKNodeTypeNominalBody: Codable {
        let usr: String?
    }

    typealias SDKNodeDecl = SDKNodeInherit<SDKNodeBody, SDKNodeDeclBody>
    typealias SDKNodeDeclType = SDKNodeInherit<SDKNodeDecl, SDKNodeDeclTypeBody>
    typealias SDKNodeType = SDKNodeInherit<SDKNodeBody, SDKNodeTypeBody>
    typealias SDKNodeTypeNominal = SDKNodeInherit<SDKNodeType, SDKNodeTypeNominalBody>

    func dumpSDK(moduleName: String, arguments: [String]) throws -> Output {
        var args = [
            "-dump-sdk",
            "-module", moduleName,
            // Emit output to stdout
            "-o", "-",
        ]
        args += arguments
        let process = Process()
        process.executableURL = executableURL
        process.arguments = args
        let stdoutPipe = Pipe()
        process.standardOutput = stdoutPipe
        try process.run()
        guard let output = try stdoutPipe.fileHandleForReading.readToEnd() else {
            throw SwiftAPIDigesterError.unexpectedEmptyOutput
        }
        process.waitUntilExit()
        return try Output.parse(output)
    }
}

enum SwiftAPIDigesterError: Error {
    case unexpectedEmptyOutput
}