File: TypeMapping.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 (160 lines) | stat: -rw-r--r-- 5,454 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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
struct TypeMapping {
    typealias DeclScope = [SwiftAPIDigester.SDKNodeDecl]
    struct DeclSource {
        let node: SwiftAPIDigester.SDKNodeDecl
        let scope: DeclScope

        var qualifiedName: String {
            let typeContext: String
            if !scope.isEmpty {
                typeContext = scope.map(\.parent.printedName).joined(separator: ".") + "."
            } else {
                typeContext = ""
            }
            return typeContext + node.parent.printedName
        }
    }

    private var usrToWITTypeName: [String: String] = [:]
    private var witTypeNameToDecl: [String: DeclSource] = [:]
    private var declScope: DeclScope = []

    func qualifiedName(byWITName witName: String) -> String? {
        guard let source = witTypeNameToDecl[witName] else { return nil }
        return source.qualifiedName
    }

    private static let knownMapping = buildKnownMapping()

    static func buildKnownMapping() -> [String: String] {
        var mapping: [String: String] = [:]

        // This assumes platforms where this extractor is running on and
        // where the input swiftmodule is built for has the same mangled
        // type name.
        func add(_ type: Any.Type, _ witType: String) {
            guard let mangledName = _mangledTypeName(type) else {
                fatalError("mangled name should be available at runtime")
            }
            let usr = "s:" + mangledName
            mapping[usr] = witType
        }

        add(Bool.self, "bool")

        add(UInt8.self, "u8")
        add(UInt16.self, "u16")
        add(UInt32.self, "u32")
        add(UInt64.self, "u64")
        add(UInt.self, "u64")

        add(Int8.self, "s8")
        add(Int16.self, "s16")
        add(Int32.self, "s32")
        add(Int64.self, "s64")
        add(Int.self, "s64")

        add(Float.self, "f32")
        add(Double.self, "f64")

        add(String.self, "string")

        return mapping
    }

    static func lookupKnownMapping(usr: String) -> String? {
        if let known = Self.knownMapping[usr] {
            return known
        }
        return nil
    }

    func lookupWITType(
        byNode node: SwiftAPIDigester.SDKNodeTypeNominal,
        diagnostics: DiagnosticCollection
    ) -> String? {
        if let usr = node.body.usr, let found = lookupWITType(byUsr: usr) {
            return found
        }

        func genericParameters() -> some Collection<String> {
            let children = node.parent.parent.children ?? []
            return children.lazy.compactMap { child in
                guard case let .typeNominal(typeNode) = child else {
                    diagnostics.add(.warning("Missing generic parameter type node for \(node.parent.parent.printedName)"))
                    return nil
                }
                guard let found = lookupWITType(byNode: typeNode, diagnostics: diagnostics) else {
                    diagnostics.add(.warning("Missing corresponding WIT type for generic parameter type \(typeNode.parent.parent.printedName)"))
                    return nil
                }
                return found
            }
        }

        switch node.parent.parent.name {
        case "Tuple":
            let elements = genericParameters()
            if elements.count == 1 {
                return elements.first
            }
            return "tuple<\(elements.joined(separator: ", "))>"
        case "Paren":
            return genericParameters().first
        default: break
        }

        // Lookup known generic types
        switch node.body.usr {
        case "s:Sq":  // "Optional"
            guard let wrapped = genericParameters().first else { return nil }
            return "option<\(wrapped)>"
        case "s:Sa":  // "Array"
            guard let element = genericParameters().first else { return nil }
            return "list<\(element)>"
        case "s:SD":  // "Dictionary"
            var genericParams = genericParameters().makeIterator()
            guard let key = genericParams.next(), let value = genericParams.next() else { return nil }
            // NOTE: There is no key-value map representation in WIT, so lower to tuple-list
            return "list<tuple<\(key), \(value)>>"
        default: break
        }

        return nil
    }

    func lookupWITType(byUsr usr: String) -> String? {
        if let known = Self.knownMapping[usr] {
            return known
        }
        return usrToWITTypeName[usr]
    }

    mutating func collect(digest: SwiftAPIDigester.Output) {
        collect(node: digest.ABIRoot)
    }

    private mutating func collect(node: SwiftAPIDigester.SDKNode) {
        var cleanup: (inout TypeMapping) -> Void = { _ in }
        defer { cleanup(&self) }

        if case let .typeDecl(typeDecl) = node {
            collect(node: typeDecl.parent)
            declScope.append(typeDecl.parent)
            cleanup = {
                _ = $0.declScope.popLast()
            }
        }

        for child in node.body.children ?? [] {
            collect(node: child)
        }
    }

    private mutating func collect(node: SwiftAPIDigester.SDKNodeDecl) {
        let scopeNames = declScope.map { $0.parent.name }
        let witTypeName = ConvertCase.witIdentifier(identifier: scopeNames + [node.parent.name])
        self.witTypeNameToDecl[witTypeName] = DeclSource(node: node, scope: declScope)
        self.usrToWITTypeName[node.body.usr] = witTypeName
    }
}