File: NameMapping.swift

package info (click to toggle)
swiftlang 6.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,856,264 kB
  • sloc: cpp: 9,995,718; ansic: 2,234,019; asm: 1,092,167; python: 313,940; objc: 82,726; f90: 80,126; lisp: 38,373; pascal: 25,580; sh: 20,378; ml: 5,058; perl: 4,751; makefile: 4,725; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (243 lines) | stat: -rw-r--r-- 9,110 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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
import WasmParser
import WasmTypes

/// A name with its location in the source file
struct Name: Equatable {
    /// The name of the module field declaration specified in $id form
    let value: String
    /// The location of the name in the source file
    let location: Location
}

/// A module field declaration that may have its name
protocol NamedModuleFieldDecl {
    /// The name of the module field declaration specified in $id form
    var id: Name? { get }
}

/// A module field declaration that may be imported from another module
protocol ImportableModuleFieldDecl {
    /// The import names of the module field declaration
    var importNames: WatParser.ImportNames? { get }
}

/// A map of module field declarations indexed by their name
struct NameMapping<Decl: NamedModuleFieldDecl> {
    private var decls: [Decl] = []
    private var nameToIndex: [String: Int] = [:]

    /// Adds a new declaration to the mapping
    /// - Parameter newDecl: The declaration to add
    /// - Returns: The index of the added declaration
    @discardableResult
    mutating func add(_ newDecl: Decl) throws -> Int {
        let index = decls.count
        decls.append(newDecl)
        if let name = newDecl.id {
            guard nameToIndex[name.value] == nil else {
                throw WatParserError("Duplicate \(name.value) identifier", location: name.location)
            }
            nameToIndex[name.value] = index
        }
        return index
    }

    func resolveIndex(use: Parser.IndexOrId) throws -> Int {
        switch use {
        case .id(let id, _):
            guard let byName = nameToIndex[id.value] else {
                throw WatParserError("Unknown \(Decl.self) \(id)", location: use.location)
            }
            return byName
        case .index(let value, _):
            return Int(value)
        }
    }

    /// Resolves a declaration by its name or index
    /// - Parameter use: The name or index of the declaration
    /// - Returns: The declaration and its index
    func resolve(use: Parser.IndexOrId) throws -> (decl: Decl, index: Int) {
        let index = try resolveIndex(use: use)
        guard index < decls.count else {
            throw WatParserError("Invalid \(Decl.self) index \(index)", location: use.location)
        }
        return (decls[index], index)
    }
}

extension NameMapping: Collection {
    var count: Int { return decls.count }

    var isEmpty: Bool { decls.isEmpty }

    var startIndex: Int { decls.startIndex }
    var endIndex: Int { decls.endIndex }
    func index(after i: Int) -> Int {
        decls.index(after: i)
    }

    subscript(index: Int) -> Decl {
        return decls[index]
    }

    func makeIterator() -> Array<Decl>.Iterator {
        return decls.makeIterator()
    }
}

extension NameMapping where Decl: ImportableModuleFieldDecl {
    /// Returns the declarations that are defined in the module.
    /// The returned declarations are sorted by the order they were added to this mapping.
    func definitions() -> [Decl] {
        decls.filter { $0.importNames == nil }
    }
}

/// A map of unique function types indexed by their name or type signature
struct TypesMap {
    private var nameMapping = NameMapping<WatParser.FunctionTypeDecl>()
    /// Tracks the earliest index for each function type
    private var indices: [FunctionType: Int] = [:]

    /// Adds a new function type to the mapping
    @discardableResult
    mutating func add(_ decl: WatParser.FunctionTypeDecl) throws -> Int {
        try nameMapping.add(decl)
        // Normalize the function type signature without parameter names
        if let existing = indices[decl.type.signature] {
            return existing
        } else {
            let newIndex = nameMapping.count - 1
            indices[decl.type.signature] = newIndex
            return newIndex
        }
    }

    /// Adds a new function type to the mapping without parameter names
    private mutating func addAnonymousSignature(_ signature: FunctionType) throws -> Int {
        if let existing = indices[signature] {
            return existing
        }
        return try add(
            WatParser.FunctionTypeDecl(
                id: nil,
                type: WatParser.FunctionType(signature: signature, parameterNames: [])
            )
        )
    }

    private mutating func resolveBlockType(
        results: [ValueType],
        resolveSignatureIndex: (inout TypesMap) throws -> Int
    ) throws -> BlockType {
        if let result = results.first {
            guard results.count > 1 else { return .type(result) }
            return try .funcType(UInt32(resolveSignatureIndex(&self)))
        }
        return .empty
    }
    private mutating func resolveBlockType(
        signature: WasmTypes.FunctionType,
        resolveSignatureIndex: (inout TypesMap) throws -> Int
    ) throws -> BlockType {
        if signature.parameters.isEmpty {
            return try resolveBlockType(results: signature.results, resolveSignatureIndex: resolveSignatureIndex)
        }
        return try .funcType(UInt32(resolveSignatureIndex(&self)))
    }

    /// Resolves a block type from a list of result types
    mutating func resolveBlockType(results: [ValueType]) throws -> BlockType {
        return try resolveBlockType(
            results: results,
            resolveSignatureIndex: {
                let signature = FunctionType(parameters: [], results: results)
                return try $0.addAnonymousSignature(signature)
            })
    }

    /// Resolves a block type from a function type signature
    mutating func resolveBlockType(signature: WasmTypes.FunctionType) throws -> BlockType {
        return try resolveBlockType(
            signature: signature,
            resolveSignatureIndex: {
                return try $0.addAnonymousSignature(signature)
            })
    }

    /// Resolves a block type from a type use
    mutating func resolveBlockType(use: WatParser.TypeUse) throws -> BlockType {
        switch (use.index, use.inline) {
        case let (indexOrId?, inline):
            let (type, index) = try resolveAndCheck(use: indexOrId, inline: inline)
            return try resolveBlockType(signature: type.signature, resolveSignatureIndex: { _ in index })
        case (nil, let inline?):
            return try resolveBlockType(signature: inline.signature)
        case (nil, nil): return .empty
        }
    }

    mutating func resolveIndex(use: WatParser.TypeUse) throws -> Int {
        switch (use.index, use.inline) {
        case let (indexOrId?, _):
            return try nameMapping.resolveIndex(use: indexOrId)
        case (nil, let inline):
            let inline = inline?.signature ?? WasmTypes.FunctionType(parameters: [], results: [])
            return try addAnonymousSignature(inline)
        }
    }

    /// Resolves a function type from a type use
    func resolve(use: Parser.IndexOrId) throws -> (decl: WatParser.FunctionType, index: Int) {
        let (decl, index) = try nameMapping.resolve(use: use)
        return (decl.type, index)
    }

    private func resolveAndCheck(use indexOrId: Parser.IndexOrId, inline: WatParser.FunctionType?) throws -> (type: WatParser.FunctionType, index: Int) {
        let (found, index) = try resolve(use: indexOrId)
        if let inline {
            // If both index and inline type, then they must match
            guard found.signature == inline.signature else {
                throw WatParserError("Type mismatch \(found) != \(inline)", location: indexOrId.location)
            }
        }
        return (found, Int(index))
    }

    /// Resolves a function type from a type use with an optional inline type
    mutating func resolve(use: WatParser.TypeUse) throws -> (type: WatParser.FunctionType, index: Int) {
        switch (use.index, use.inline) {
        case let (indexOrId?, inline):
            return try resolveAndCheck(use: indexOrId, inline: inline)
        case (nil, let inline):
            // If no index and no inline type, then it's a function type with no parameters or results
            let inline = inline ?? WatParser.FunctionType(signature: WasmTypes.FunctionType(parameters: [], results: []), parameterNames: [])
            // Check if the inline type already exists
            if let index = indices[inline.signature] {
                return (inline, index)
            }
            // Add inline type to the index space if it doesn't already exist
            let index = try add(WatParser.FunctionTypeDecl(id: nil, type: inline))
            return (inline, index)
        }
    }
}

extension TypesMap: Collection {
    var isEmpty: Bool { return nameMapping.isEmpty }

    var startIndex: Int { return nameMapping.startIndex }
    var endIndex: Int { return nameMapping.endIndex }
    func index(after i: Int) -> Int {
        nameMapping.index(after: i)
    }

    subscript(position: Int) -> WatParser.FunctionTypeDecl {
        return nameMapping[position]
    }

    func makeIterator() -> NameMapping<WatParser.FunctionTypeDecl>.Iterator {
        return nameMapping.makeIterator()
    }
}