@@ -29,7 +29,45 @@ package struct Encoder {
2929 output. append ( contentsOf: contentEncoder. output)
3030 }
3131
32- package mutating func encodeVector< Source: Collection , E: Error > (
32+ /// Overload accepting any RawRepresentable<UInt8> for ergonomic use with enums.
33+ mutating func section< ID: RawRepresentable < UInt8 > , E: Error > ( id: ID , _ sectionContent: ( inout Encoder ) throws ( E ) -> Void ) throws ( E) {
34+ try section ( id: id. rawValue, sectionContent)
35+ }
36+
37+ mutating func section< E: Error > (
38+ id: UInt8 ,
39+ placement: CustomSectionDecl . SectionKind ,
40+ customSections: [ CustomSectionDecl ] ,
41+ _ body: ( inout Encoder ) throws ( E ) -> Void
42+ ) throws ( E) {
43+ for cs in customSections where cs. placement == . before( placement) {
44+ encodeCustomSection ( cs)
45+ }
46+ var contentEncoder = Encoder ( )
47+ try body ( & contentEncoder)
48+ if !contentEncoder. output. isEmpty {
49+ output. append ( id)
50+ writeUnsignedLEB128 ( UInt32 ( contentEncoder. output. count) )
51+ output. append ( contentsOf: contentEncoder. output)
52+ }
53+ for cs in customSections where cs. placement == . after( placement) {
54+ encodeCustomSection ( cs)
55+ }
56+ }
57+
58+ mutating func encodeCustomSection( _ cs: CustomSectionDecl ) {
59+ section ( id: 0 ) { encoder in
60+ cs. name. encode ( to: & encoder)
61+ encoder. output. append ( contentsOf: cs. content)
62+ }
63+ }
64+
65+ /// Append a single byte from any RawRepresentable<UInt8> value.
66+ mutating func append< T: RawRepresentable < UInt8 > > ( _ value: T ) {
67+ output. append ( value. rawValue)
68+ }
69+
70+ mutating func encodeVector< Source: Collection , E: Error > (
3371 _ values: Source , encodeElement: ( Source . Element , inout Encoder ) throws ( E ) -> Void
3472 ) throws ( E) {
3573 writeUnsignedLEB128 ( UInt32 ( values. count) )
@@ -590,55 +628,55 @@ func encode(module: inout Wat, options: EncodeOptions) throws(WatParserError) ->
590628 var functionLabelNames : [ [ ( Int , String ) ] ] = [ ]
591629
592630 if !functions. isEmpty {
593- try codeEncoder. section ( id: 0x0A ) { encoder throws ( WatParserError) in
594- try encoder. encodeVector (
595- functions,
596- encodeElement: { source, encoder throws ( WatParserError) in
597- let ( locals, function) = source
598- var exprEncoder = ExpressionEncoder ( )
599- // Encode locals
600- var localsEntries : [ ( type: ValueType , count: UInt32 ) ] = [ ]
601- for local in locals {
602- let type = try local. type. resolve ( module. types)
603- if localsEntries. last? . type == type {
604- localsEntries [ localsEntries. count - 1 ] . count += 1
605- } else {
606- localsEntries. append ( ( type: type, count: 1 ) )
607- }
608- }
609- exprEncoder. encoder. encodeVector ( localsEntries) { local, encoder in
610- encoder. writeUnsignedLEB128 ( local. count)
611- local. type. encode ( to: & encoder)
631+ try codeEncoder. encodeVector (
632+ functions,
633+ encodeElement: { source, encoder throws ( WatParserError) in
634+ let ( locals, function) = source
635+ var exprEncoder = ExpressionEncoder ( )
636+ // Encode locals
637+ var localsEntries : [ ( type: ValueType , count: UInt32 ) ] = [ ]
638+ for local in locals {
639+ let type = try local. type. resolve ( module. types)
640+ if localsEntries. last? . type == type {
641+ localsEntries [ localsEntries. count - 1 ] . count += 1
642+ } else {
643+ localsEntries. append ( ( type: type, count: 1 ) )
612644 }
613- let parseResult = try function. parse ( visitor: & exprEncoder, wat: & module, features: module. features)
614- functionSection. append ( UInt32 ( parseResult. typeIndex) )
615- functionLabelNames. append ( parseResult. labelNames)
616- // TODO?
617- try exprEncoder. visitEnd ( )
618- encoder. writeUnsignedLEB128 ( UInt ( exprEncoder. encoder. output. count) )
619- encoder. output. append ( contentsOf: exprEncoder. encoder. output)
620- hasDataSegmentInstruction = hasDataSegmentInstruction || exprEncoder. hasDataSegmentInstruction
621- } )
622- }
645+ }
646+ exprEncoder. encoder. encodeVector ( localsEntries) { local, encoder in
647+ encoder. writeUnsignedLEB128 ( local. count)
648+ local. type. encode ( to: & encoder)
649+ }
650+ let parseResult = try function. parse ( visitor: & exprEncoder, wat: & module, features: module. features)
651+ functionSection. append ( UInt32 ( parseResult. typeIndex) )
652+ functionLabelNames. append ( parseResult. labelNames)
653+ // TODO?
654+ try exprEncoder. visitEnd ( )
655+ encoder. writeUnsignedLEB128 ( UInt ( exprEncoder. encoder. output. count) )
656+ encoder. output. append ( contentsOf: exprEncoder. encoder. output)
657+ hasDataSegmentInstruction = hasDataSegmentInstruction || exprEncoder. hasDataSegmentInstruction
658+ } )
623659 }
624660
661+ let cs = module. customSections
662+
625663 // Section 1: Type section
626- if !module . types . isEmpty {
627- encoder . section ( id : 0x01 ) { encoder in
664+ encoder . section ( id : 0x01 , placement : . type , customSections : cs ) { encoder in
665+ if !module . types . isEmpty {
628666 encoder. encodeVector ( module. types, transform: \. type. signature)
629667 }
630668 }
631669
632670 // Section 2: Import section
633- if !module . imports . isEmpty {
634- encoder . section ( id : 0x02 ) { encoder in
671+ encoder . section ( id : 0x02 , placement : . import , customSections : cs ) { encoder in
672+ if !module . imports . isEmpty {
635673 encoder. encodeVector ( module. imports)
636674 }
637675 }
638676
639677 // Section 3: Function section
640- if !functionSection . isEmpty {
641- encoder . section ( id : 0x03 ) { encoder in
678+ encoder . section ( id : 0x03 , placement : . func , customSections : cs ) { encoder in
679+ if !functionSection . isEmpty {
642680 encoder. encodeVector ( functionSection) { typeIndex, encoder in
643681 encoder. writeUnsignedLEB128 ( UInt32 ( typeIndex) )
644682 }
@@ -647,8 +685,8 @@ func encode(module: inout Wat, options: EncodeOptions) throws(WatParserError) ->
647685
648686 // Section 4: Table section
649687 let tables = module. tablesMap. definitions ( )
650- if !tables . isEmpty {
651- try encoder . section ( id : 0x04 ) { encoder throws ( WatParserError ) in
688+ try encoder . section ( id : 0x04 , placement : . table , customSections : cs ) { encoder throws ( WatParserError ) in
689+ if !tables . isEmpty {
652690 try encoder. encodeVector ( tables) { table, encoder throws ( WatParserError) in
653691 try table. type. resolve ( module. types) . encode ( to: & encoder)
654692 }
@@ -657,41 +695,41 @@ func encode(module: inout Wat, options: EncodeOptions) throws(WatParserError) ->
657695
658696 // Section 5: Memory section
659697 let memories = module. memories. definitions ( )
660- if !memories . isEmpty {
661- encoder . section ( id : 0x05 ) { encoder in
698+ encoder . section ( id : 0x05 , placement : . memory , customSections : cs ) { encoder in
699+ if !memories . isEmpty {
662700 encoder. encodeVector ( memories)
663701 }
664702 }
665703
666704 // Section 6: Global section
667705 let globals = module. globals. definitions ( )
668- if !globals . isEmpty {
669- try encoder . section ( id : 0x06 ) { encoder throws ( WatParserError ) in
706+ try encoder . section ( id : 0x06 , placement : . global , customSections : cs ) { encoder throws ( WatParserError ) in
707+ if !globals . isEmpty {
670708 try encoder. encodeVector ( globals) { global, encoder throws ( WatParserError) in
671709 try global. encode ( to: & encoder, wat: & module)
672710 }
673711 }
674712 }
675713
676714 // Section 7: Export section
677- if !module . exports . isEmpty {
678- encoder . section ( id : 0x07 ) { encoder in
715+ encoder . section ( id : 0x07 , placement : . export , customSections : cs ) { encoder in
716+ if !module . exports . isEmpty {
679717 encoder. encodeVector ( module. exports) { export, encoder in
680718 export. encode ( to: & encoder)
681719 }
682720 }
683721 }
684722
685723 // Section 8: Start section
686- if let start = module . start {
687- encoder . section ( id : 0x08 ) { encoder in
724+ encoder . section ( id : 0x08 , placement : . start, customSections : cs ) { encoder in
725+ if let start = module . start {
688726 encoder. writeUnsignedLEB128 ( start)
689727 }
690728 }
691729
692730 // Section 9: Element section
693- if !module . elementsMap . isEmpty {
694- try encoder . section ( id : 0x09 ) { encoder throws ( WatParserError ) in
731+ try encoder . section ( id : 0x09 , placement : . elem , customSections : cs ) { encoder throws ( WatParserError ) in
732+ if !module . elementsMap . isEmpty {
695733 try encoder. encodeVector ( module. elementsMap) { element, encoder throws ( WatParserError) in
696734 try element. encode ( to: & encoder, wat: & module)
697735 }
@@ -706,22 +744,34 @@ func encode(module: inout Wat, options: EncodeOptions) throws(WatParserError) ->
706744 }
707745
708746 // Section 10: Code section
709- encoder. output. append ( contentsOf: codeEncoder. output)
747+ encoder. section ( id: 0x0A , placement: . code, customSections: cs) { encoder in
748+ encoder. output. append ( contentsOf: codeEncoder. output)
749+ }
710750
711751 // Section 11: Data section
712- if !module . data . isEmpty {
713- try encoder . section ( id : 0x0B ) { encoder throws ( WatParserError ) in
752+ try encoder . section ( id : 0x0B , placement : . data , customSections : cs ) { encoder throws ( WatParserError ) in
753+ if !module . data . isEmpty {
714754 try encoder. encodeVector ( module. data) { data, encoder throws ( WatParserError) in
715755 try data. encode ( to: & encoder, wat: & module)
716756 }
717757 }
718758 }
719759
760+ // Unplaced custom sections go after all standard sections
761+ for section in cs where section. placement == . unplaced {
762+ encoder. encodeCustomSection ( section)
763+ }
764+
720765 // (Optional) Name Section
721766 if options. nameSection {
722767 try encodeNameSection ( module: & module, options: options, encoder: & encoder, functions: functions, functionLabelNames: functionLabelNames)
723768 }
724769
770+ // "last" placement goes after everything including the name section
771+ for cs in cs where cs. placement == . before( . last) || cs. placement == . after( . last) {
772+ encoder. encodeCustomSection ( cs)
773+ }
774+
725775 return encoder. output
726776}
727777
@@ -848,9 +898,9 @@ private func encodeNameSection(
848898 encoder. section ( id: 0 ) { encoder in
849899 encoder. encode ( " name " )
850900
851- if let moduleId = module. id {
901+ if let moduleName = module. id {
852902 encoder. section ( id: 0 ) { encoder in
853- encoder. encode ( String ( moduleId . dropFirst ( ) ) ) // Drop "$" prefix
903+ encoder. encode ( moduleName . nameValue )
854904 }
855905 }
856906 if !functionNames. isEmpty {
0 commit comments