Skip to content

Commit 43f28eb

Browse files
WAT: Add support for encoding the name section
1 parent 3e510c7 commit 43f28eb

File tree

3 files changed

+77
-6
lines changed

3 files changed

+77
-6
lines changed

Sources/WAT/Encoder.swift

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ struct ExpressionEncoder: InstructionEncoder {
535535
}
536536
}
537537

538-
func encode(module: inout Wat) throws -> [UInt8] {
538+
func encode(module: inout Wat, options: EncodeOptions) throws -> [UInt8] {
539539
var encoder = Encoder()
540540
encoder.writeHeader()
541541

@@ -675,5 +675,25 @@ func encode(module: inout Wat) throws -> [UInt8] {
675675
}
676676
}
677677

678+
// (Optional) Name Section
679+
if !module.functionsMap.isEmpty, options.nameSection {
680+
encoder.section(id: 0) { encoder in
681+
encoder.encode("name")
682+
// Subsection 1: Function names
683+
encoder.section(id: 1) { encoder in
684+
let functionNames = module.functionsMap.enumerated().compactMap { i, decl -> (Int, String)? in
685+
guard let name = decl.id else { return nil }
686+
return (i, name.value)
687+
}
688+
encoder.encodeVector(functionNames) { entry, encoder in
689+
let (index, name) = entry
690+
encoder.writeUnsignedLEB128(UInt(index))
691+
// Drop initial "$"
692+
encoder.encode(String(name.dropFirst()))
693+
}
694+
}
695+
}
696+
}
697+
678698
return encoder.output
679699
}

Sources/WAT/WAT.swift

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
import WasmParser
22

3+
/// Options for encoding a WebAssembly module into a binary format.
4+
public struct EncodeOptions {
5+
/// Whether to include the name section.
6+
public var nameSection: Bool
7+
8+
/// The default encoding options.
9+
public static let `default` = EncodeOptions()
10+
11+
/// Creates a new encoding options instance.
12+
public init(nameSection: Bool = false) {
13+
self.nameSection = nameSection
14+
}
15+
}
16+
317
/// Transforms a WebAssembly text format (WAT) string into a WebAssembly binary format byte array.
418
/// - Parameter input: The WAT string to transform
519
/// - Returns: The WebAssembly binary format byte array
@@ -17,9 +31,13 @@ import WasmParser
1731
/// )
1832
/// """)
1933
/// ```
20-
public func wat2wasm(_ input: String, features: WasmFeatureSet = .default) throws -> [UInt8] {
34+
public func wat2wasm(
35+
_ input: String,
36+
features: WasmFeatureSet = .default,
37+
options: EncodeOptions = .default
38+
) throws -> [UInt8] {
2139
var wat = try parseWAT(input, features: features)
22-
return try encode(module: &wat)
40+
return try encode(module: &wat, options: options)
2341
}
2442

2543
/// A WAT module representation.
@@ -65,8 +83,8 @@ public struct Wat {
6583
/// This method effectively consumes the module value, encoding it into a
6684
/// binary format byte array. If you need to encode the module multiple times,
6785
/// you should create a copy of the module value before encoding it.
68-
public mutating func encode() throws -> [UInt8] {
69-
try WAT.encode(module: &self)
86+
public mutating func encode(options: EncodeOptions = .default) throws -> [UInt8] {
87+
try WAT.encode(module: &self, options: options)
7088
}
7189
}
7290

Tests/WATTests/EncoderTests.swift

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class EncoderTests: XCTestCase {
7878
assertEqual(watModule.id, expectedName)
7979
switch watModule.source {
8080
case .text(var watModule):
81-
moduleBytes = try encode(module: &watModule)
81+
moduleBytes = try encode(module: &watModule, options: .default)
8282
case .binary(let bytes):
8383
moduleBytes = bytes
8484
case .quote(let watText):
@@ -135,4 +135,37 @@ class EncoderTests: XCTestCase {
135135
}
136136
#endif
137137
}
138+
139+
func testEncodeNameSection() throws {
140+
let bytes = try wat2wasm(
141+
"""
142+
(module
143+
(func $foo)
144+
(func)
145+
(func $bar)
146+
)
147+
""",
148+
options: EncodeOptions(nameSection: true)
149+
)
150+
151+
var parser = WasmParser.Parser(bytes: bytes)
152+
var customSections: [CustomSection] = []
153+
while let payload = try parser.parseNext() {
154+
guard case .customSection(let section) = payload else {
155+
continue
156+
}
157+
customSections.append(section)
158+
}
159+
let nameSection = customSections.first(where: { $0.name == "name" })
160+
let nameParser = NameSectionParser(
161+
stream: StaticByteStream(bytes: nameSection?.bytes ?? [])
162+
)
163+
let names = try nameParser.parseAll()
164+
XCTAssertEqual(names.count, 1)
165+
guard case .functions(let functionNames) = try XCTUnwrap(names.first) else {
166+
XCTFail()
167+
return
168+
}
169+
XCTAssertEqual(functionNames, [0: "foo", 2: "bar"])
170+
}
138171
}

0 commit comments

Comments
 (0)