|
22 | 22 | ) throws(WatParserError) -> [UInt8] { |
23 | 23 | writeHeader() |
24 | 24 |
|
25 | | - // Collect metadata needed for encoding |
26 | | - let fields = try groupFields(component.fields) |
| 25 | + // Compute metadata directly from component fields |
| 26 | + let coreInstances: [(ComponentWatParser.CoreInstanceDef, Location)] = component.fields.compactMap { field in |
| 27 | + if case .coreInstance(let def) = field.kind { return (def, field.location) } |
| 28 | + return nil |
| 29 | + } |
| 30 | + let canons: [(ComponentWatParser.CanonDef, Location)] = component.fields.compactMap { field in |
| 31 | + if case .canon(let def) = field.kind { return (def, field.location) } |
| 32 | + return nil |
| 33 | + } |
| 34 | + let exports: [(ComponentWatParser.ExportDef, Location)] = component.fields.compactMap { field in |
| 35 | + if case .componentExport(let def) = field.kind { return (def, field.location) } |
| 36 | + return nil |
| 37 | + } |
27 | 38 |
|
28 | 39 | // Build core instance index mapping (parser index -> binary index) |
29 | 40 | // This accounts for inline export instances that shift indices |
30 | | - let coreInstanceIndexMapping = buildCoreInstanceIndexMapping(component: component, fields: fields) |
| 41 | + let coreInstanceIndexMapping = buildCoreInstanceIndexMapping(coreInstances: coreInstances) |
31 | 42 |
|
32 | 43 | let coreFuncAliases = try collectCoreFuncAliases( |
33 | | - from: fields.canons, |
| 44 | + from: canons, |
34 | 45 | component: component, |
35 | 46 | coreInstanceIndexMapping: coreInstanceIndexMapping |
36 | 47 | ) |
37 | | - let componentFuncAliases = try collectComponentFuncAliases(from: fields.canons, component: component) |
38 | | - let exportFuncAliases = try collectExportFuncAliases(from: fields.exports, component: component) |
| 48 | + let componentFuncAliases = try collectComponentFuncAliases(from: canons, component: component) |
| 49 | + let exportFuncAliases = try collectExportFuncAliases(from: exports, component: component) |
39 | 50 |
|
40 | 51 | // Collect type indices that are exported |
41 | 52 | var exportedTypeIndices = Set<Int>() |
42 | | - for (exportDef, _) in fields.exports { |
| 53 | + for (exportDef, _) in exports { |
43 | 54 | if case .type(let indexOrId) = exportDef.descriptor { |
44 | 55 | if case .index(let idx, _) = indexOrId { |
45 | 56 | exportedTypeIndices.insert(Int(idx)) |
|
77 | 88 | } |
78 | 89 |
|
79 | 90 | // Helper to flush accumulated core types as a batched section |
80 | | - var pendingCoreTypes: [UInt32] = [] |
| 91 | + var pendingCoreTypes: [ComponentWatParser.CoreTypeDef] = [] |
81 | 92 | func flushPendingCoreTypes() throws(WatParserError) { |
82 | 93 | if !pendingCoreTypes.isEmpty { |
83 | 94 | try encodeBatchedCoreTypes( |
|
89 | 100 | } |
90 | 101 |
|
91 | 102 | // Helper to flush accumulated core instances as a batched section |
92 | | - var pendingCoreInstances: [(CoreInstanceIndex, Location)] = [] |
| 103 | + var pendingCoreInstances: [(ComponentWatParser.CoreInstanceDef, Location)] = [] |
93 | 104 | func flushPendingCoreInstances() throws(WatParserError) { |
94 | 105 | if !pendingCoreInstances.isEmpty { |
95 | 106 | try encodeCoreInstances( |
|
141 | 152 | try flushPendingSectionsExcept(field.kind.sectionKind) |
142 | 153 |
|
143 | 154 | switch field.kind { |
144 | | - case .componentType(let typeIndex): |
| 155 | + case .componentType(_, let typeIndex): |
145 | 156 | // Collect all unemitted types up to and including this type index |
146 | 157 | // This ensures anonymous dependency types (with lower indices) get batched |
147 | 158 | // with the types that reference them |
148 | | - let maxIndex = Int(typeIndex.rawValue) |
| 159 | + let maxIndex = typeIndex |
149 | 160 | for (oldIndex, _) in typeIndexMapping.sorted(by: { $0.key < $1.key }) { |
150 | 161 | if oldIndex <= maxIndex && !emittedTypes.contains(oldIndex) && !pendingComponentTypes.contains(oldIndex) { |
151 | 162 | pendingComponentTypes.append(oldIndex) |
152 | 163 | } |
153 | 164 | } |
154 | 165 |
|
155 | | - case .coreModule(let index): |
156 | | - try encodeSingleCoreModule(index, component: component, options: options) |
| 166 | + case .coreModule(let moduleDef): |
| 167 | + try encodeSingleCoreModule(moduleDef, options: options) |
157 | 168 |
|
158 | | - case .coreInstance(let index): |
159 | | - pendingCoreInstances.append((index, field.location)) |
| 169 | + case .coreInstance(let instanceDef): |
| 170 | + pendingCoreInstances.append((instanceDef, field.location)) |
160 | 171 |
|
161 | | - case .coreType(let index): |
162 | | - pendingCoreTypes.append(UInt32(index)) |
| 172 | + case .coreType(let coreTypeDef): |
| 173 | + pendingCoreTypes.append(coreTypeDef) |
163 | 174 |
|
164 | 175 | case .canon(let canonDef): |
165 | 176 | try emitRequiredTypesForCanon( |
|
208 | 219 | emittedExportFuncAliases: &emittedExportFuncAliases |
209 | 220 | ) |
210 | 221 |
|
211 | | - case .component(let index): |
212 | | - try encodeSingleComponent(index, component: component, options: options) |
| 222 | + case .component(let nestedDef): |
| 223 | + try encodeSingleComponent(nestedDef, options: options) |
213 | 224 |
|
214 | | - case .instance(let index): |
215 | | - try encodeSingleComponentInstance(index, component: component, location: field.location) |
| 225 | + case .instance(let instanceDef): |
| 226 | + try encodeSingleComponentInstance(instanceDef, component: component, location: field.location) |
216 | 227 |
|
217 | 228 | case .alias(let alias): |
218 | 229 | pendingAliases.append(alias) |
|
586 | 597 |
|
587 | 598 | // Encode a single core module as its own section |
588 | 599 | private mutating func encodeSingleCoreModule( |
589 | | - _ moduleIndex: CoreModuleIndex, |
590 | | - component: ComponentWatParser.ComponentDef, |
| 600 | + _ moduleDef: ComponentWatParser.ModuleDef, |
591 | 601 | options: EncodeOptions |
592 | 602 | ) throws(WatParserError) { |
593 | | - guard Int(moduleIndex.rawValue) < component.coreModulesMap.count else { |
594 | | - throw WatParserError("Invalid core module index \(moduleIndex.rawValue)", location: nil) |
595 | | - } |
596 | | - |
597 | | - var moduleDef = component.coreModulesMap[Int(moduleIndex.rawValue)] |
| 603 | + var moduleDef = moduleDef |
598 | 604 | var moduleBytes = try WAT.encode(module: &moduleDef.wat, options: options) |
599 | 605 |
|
600 | 606 | if options.nameSection, let moduleId = moduleDef.id { |
|
740 | 746 |
|
741 | 747 | // Encode multiple core types in a single batched section |
742 | 748 | private mutating func encodeBatchedCoreTypes( |
743 | | - _ typeIndices: [UInt32], |
| 749 | + _ typeDefs: [ComponentWatParser.CoreTypeDef], |
744 | 750 | component: ComponentWatParser.ComponentDef |
745 | 751 | ) throws(WatParserError) { |
746 | | - guard !typeIndices.isEmpty else { return } |
| 752 | + guard !typeDefs.isEmpty else { return } |
747 | 753 |
|
748 | 754 | try underlying.section(id: 0x03) { encoder throws(WatParserError) in |
749 | | - encoder.writeUnsignedLEB128(UInt32(typeIndices.count)) |
| 755 | + encoder.writeUnsignedLEB128(UInt32(typeDefs.count)) |
750 | 756 |
|
751 | | - for typeIndex in typeIndices { |
752 | | - guard Int(typeIndex) < component.coreTypesMap.count else { continue } |
753 | | - let typeDef = component.coreTypesMap[Int(typeIndex)] |
| 757 | + for typeDef in typeDefs { |
754 | 758 | try Self.encodeCoreTypeContent(typeDef, component: component, encoder: &encoder) |
755 | 759 | } |
756 | 760 | } |
|
1201 | 1205 |
|
1202 | 1206 | // Encode a single nested component as its own section |
1203 | 1207 | private mutating func encodeSingleComponent( |
1204 | | - _ componentIndex: ComponentIndex, |
1205 | | - component: ComponentWatParser.ComponentDef, |
| 1208 | + _ nestedComponent: ComponentWatParser.ComponentDef, |
1206 | 1209 | options: EncodeOptions |
1207 | 1210 | ) throws(WatParserError) { |
1208 | | - guard Int(componentIndex.rawValue) < component.componentsMap.count else { |
1209 | | - throw WatParserError("Invalid component index \(componentIndex.rawValue)", location: nil) |
1210 | | - } |
1211 | | - |
1212 | | - let nestedComponent = component.componentsMap[Int(componentIndex.rawValue)] |
1213 | 1211 | var nestedEncoder = ComponentEncoder() |
1214 | 1212 | _ = try nestedEncoder.encode(nestedComponent, options: options) |
1215 | 1213 |
|
|
1220 | 1218 |
|
1221 | 1219 | // Encode a single component instance as its own section |
1222 | 1220 | private mutating func encodeSingleComponentInstance( |
1223 | | - _ instanceIndex: ComponentInstanceIndex, |
| 1221 | + _ instanceDef: ComponentWatParser.ComponentInstanceDef, |
1224 | 1222 | component: ComponentWatParser.ComponentDef, |
1225 | 1223 | location: Location |
1226 | 1224 | ) throws(WatParserError) { |
1227 | | - guard Int(instanceIndex.rawValue) < component.componentInstancesMap.count else { |
1228 | | - throw WatParserError("Invalid component instance index \(instanceIndex.rawValue)", location: location) |
1229 | | - } |
1230 | | - |
1231 | | - let instanceDef = component.componentInstancesMap[Int(instanceIndex.rawValue)] |
1232 | | - |
1233 | 1225 | guard let componentRef = instanceDef.componentRef else { |
1234 | 1226 | throw WatParserError("Component instance has no component reference", location: location) |
1235 | 1227 | } |
|
1255 | 1247 | } |
1256 | 1248 | } |
1257 | 1249 |
|
1258 | | - private func groupFields(_ fields: [ComponentWatParser.ComponentDefField]) throws(WatParserError) -> GroupedFields { |
1259 | | - var result = GroupedFields() |
1260 | | - |
1261 | | - for field in fields { |
1262 | | - switch field.kind { |
1263 | | - case .coreModule(let index): |
1264 | | - result.coreModules.append((index, field.location)) |
1265 | | - case .coreInstance(let index): |
1266 | | - result.coreInstances.append((index, field.location)) |
1267 | | - case .coreType(let index): |
1268 | | - result.coreTypes.append((index, field.location)) |
1269 | | - case .component(let index): |
1270 | | - result.components.append((index, field.location)) |
1271 | | - case .canon(let canonDef): |
1272 | | - result.canons.append((canonDef, field.location)) |
1273 | | - case .componentExport(let exportDef): |
1274 | | - result.exports.append((exportDef, field.location)) |
1275 | | - case .componentImport(let importDef): |
1276 | | - result.imports.append((importDef, field.location)) |
1277 | | - case .instance(let index): |
1278 | | - result.instances.append((index, field.location)) |
1279 | | - case .componentType: |
1280 | | - // Component types are handled separately in the main encoding loop |
1281 | | - // They don't need to be grouped for auxiliary calculations |
1282 | | - break |
1283 | | - case .alias: |
1284 | | - // Aliases are handled in the main encoding loop with batching |
1285 | | - // They don't need to be grouped for auxiliary calculations |
1286 | | - break |
1287 | | - } |
1288 | | - } |
1289 | | - |
1290 | | - return result |
1291 | | - } |
1292 | | - |
1293 | 1250 | /// Build a mapping from parser core instance index to binary index. |
1294 | 1251 | /// This accounts for inline export instances that shift indices. |
1295 | 1252 | private func buildCoreInstanceIndexMapping( |
1296 | | - component: ComponentWatParser.ComponentDef, |
1297 | | - fields: GroupedFields |
| 1253 | + coreInstances: [(ComponentWatParser.CoreInstanceDef, Location)] |
1298 | 1254 | ) -> [Int: Int] { |
1299 | 1255 | var mapping: [Int: Int] = [:] |
1300 | 1256 | var binaryIndex = 0 |
1301 | 1257 |
|
1302 | 1258 | // Process core instances in order, counting inline export instances |
1303 | | - for (instanceIndex, _) in fields.coreInstances { |
1304 | | - let idx = Int(instanceIndex.rawValue) |
1305 | | - guard idx < component.coreInstancesMap.count else { continue } |
1306 | | - |
1307 | | - let instanceDef = component.coreInstancesMap[idx] |
1308 | | - |
| 1259 | + for (parserIndex, (instanceDef, _)) in coreInstances.enumerated() { |
1309 | 1260 | // Count inline export instances that will be emitted first |
1310 | 1261 | var inlineExportCount = 0 |
1311 | 1262 | for arg in instanceDef.arguments { |
|
1316 | 1267 |
|
1317 | 1268 | // Inline exports come first, then the main instance |
1318 | 1269 | // So the main instance index is offset by inline export count |
1319 | | - mapping[idx] = binaryIndex + inlineExportCount |
| 1270 | + mapping[parserIndex] = binaryIndex + inlineExportCount |
1320 | 1271 | binaryIndex += 1 + inlineExportCount // 1 for main instance + inline exports |
1321 | 1272 | } |
1322 | 1273 |
|
|
1372 | 1323 | } |
1373 | 1324 |
|
1374 | 1325 | private mutating func encodeCoreInstances( |
1375 | | - _ instances: [(CoreInstanceIndex, Location)], |
| 1326 | + _ instances: [(ComponentWatParser.CoreInstanceDef, Location)], |
1376 | 1327 | component: ComponentWatParser.ComponentDef |
1377 | 1328 | ) throws(WatParserError) { |
1378 | 1329 | // First pass: collect all inline export instances that need to be created |
1379 | 1330 | // and compute the mapping from original to actual instance indices |
1380 | 1331 | var inlineExportInstances: [(exports: [ComponentWatParser.CoreInstanceDef.Argument.Kind.Export], location: Location)] = [] |
1381 | | - var inlineExportInstanceMapping: [Int: Int] = [:] // Map from (instance index, arg index) hash to inline instance index |
1382 | | - |
1383 | | - for (instanceIndex, location) in instances { |
1384 | | - guard Int(instanceIndex.rawValue) < component.coreInstancesMap.count else { continue } |
1385 | | - let instanceDef = component.coreInstancesMap[Int(instanceIndex.rawValue)] |
| 1332 | + var inlineExportInstanceMapping: [Int: Int] = [:] // Map from (instance position, arg index) hash to inline instance index |
1386 | 1333 |
|
| 1334 | + for (instancePosition, (instanceDef, location)) in instances.enumerated() { |
1387 | 1335 | for (argIndex, arg) in instanceDef.arguments.enumerated() { |
1388 | 1336 | if case .exports(let exports) = arg.kind { |
1389 | | - let key = Int(instanceIndex.rawValue) * 1000 + argIndex |
| 1337 | + let key = instancePosition * 1000 + argIndex |
1390 | 1338 | inlineExportInstanceMapping[key] = inlineExportInstances.count |
1391 | 1339 | inlineExportInstances.append((exports: exports, location: location)) |
1392 | 1340 | } |
|
1414 | 1362 | // Second: encode instantiate instances (form 0x00) |
1415 | 1363 | let inlineInstanceBaseIndex = inlineExportInstances.count |
1416 | 1364 |
|
1417 | | - for (instanceIndex, location) in instances { |
1418 | | - guard Int(instanceIndex.rawValue) < component.coreInstancesMap.count else { |
1419 | | - throw WatParserError("Invalid core instance index \(instanceIndex.rawValue)", location: location) |
1420 | | - } |
1421 | | - |
1422 | | - let instanceDef = component.coreInstancesMap[Int(instanceIndex.rawValue)] |
1423 | | - |
| 1365 | + for (instancePosition, (instanceDef, location)) in instances.enumerated() { |
1424 | 1366 | encoder.output.append(0x00) // instantiate form |
1425 | 1367 |
|
1426 | 1368 | let moduleIndex = try component.coreModulesMap.resolveIndex(use: instanceDef.moduleId) |
|
1439 | 1381 | case .exports: |
1440 | 1382 | // Reference the inline export instance we created earlier |
1441 | 1383 | encoder.output.append(0x12) |
1442 | | - let key = Int(instanceIndex.rawValue) * 1000 + argIndex |
| 1384 | + let key = instancePosition * 1000 + argIndex |
1443 | 1385 | guard let inlineIndex = inlineExportInstanceMapping[key] else { |
1444 | 1386 | throw WatParserError("Internal error: inline export instance not found", location: location) |
1445 | 1387 | } |
|
1708 | 1650 | } |
1709 | 1651 | } |
1710 | 1652 |
|
1711 | | - private struct GroupedFields { |
1712 | | - var coreModules: [(CoreModuleIndex, Location)] = [] |
1713 | | - var coreInstances: [(CoreInstanceIndex, Location)] = [] |
1714 | | - var coreTypes: [(UInt32, Location)] = [] |
1715 | | - var components: [(ComponentIndex, Location)] = [] |
1716 | | - var instances: [(ComponentInstanceIndex, Location)] = [] |
1717 | | - var canons: [(ComponentWatParser.CanonDef, Location)] = [] |
1718 | | - var exports: [(ComponentWatParser.ExportDef, Location)] = [] |
1719 | | - var imports: [(ComponentWatParser.ImportDef, Location)] = [] |
1720 | | - } |
1721 | | - |
1722 | 1653 | private typealias CoreFuncAlias = (instanceIndex: Int, exportName: String) |
1723 | 1654 | private typealias ComponentFuncAlias = (instanceIndex: Int, exportName: String) |
1724 | 1655 |
|
|
0 commit comments