@@ -25,6 +25,7 @@ public class ExportSwift {
2525 private var exportedClasses : [ ExportedClass ] = [ ]
2626 private var exportedEnums : [ ExportedEnum ] = [ ]
2727 private var typeDeclResolver : TypeDeclResolver = TypeDeclResolver ( )
28+ private let enumCodegen : EnumCodegen = EnumCodegen ( )
2829
2930 public init ( progress: ProgressReporting , moduleName: String ) {
3031 self . progress = progress
@@ -524,6 +525,24 @@ public class ExportSwift {
524525 )
525526 }
526527
528+ if currentEnum. cases. contains ( where: { !$0. associatedValues. isEmpty } ) {
529+ for enumCase in currentEnum. cases {
530+ for associatedValue in enumCase. associatedValues {
531+ switch associatedValue. type {
532+ case . string, . int, . float, . double, . bool:
533+ break
534+ default :
535+ diagnose (
536+ node: node,
537+ message: " Unsupported associated value type: \( associatedValue. type. swiftType) " ,
538+ hint:
539+ " Only primitive types (String, Int, Float, Double, Bool) are supported in associated-value enums "
540+ )
541+ }
542+ }
543+ }
544+ }
545+
527546 let swiftCallName = ExportSwift . computeSwiftCallName ( for: node, itemName: enumName)
528547 let explicitAccessControl = computeExplicitAtLeastInternalAccessControl (
529548 for: node,
@@ -753,10 +772,15 @@ public class ExportSwift {
753772 decls. append ( Self . prelude)
754773
755774 for enumDef in exportedEnums {
756- if enumDef. enumType == . simple {
757- decls. append ( renderCaseEnumHelpers ( enumDef) )
758- } else {
775+ switch enumDef. enumType {
776+ case . simple:
777+ decls. append ( enumCodegen. renderCaseEnumHelpers ( enumDef) )
778+ case . rawValue:
759779 decls. append ( " extension \( raw: enumDef. swiftCallName) : _BridgedSwiftEnumNoPayload {} " )
780+ case . associatedValue:
781+ decls. append ( enumCodegen. renderAssociatedValueEnumHelpers ( enumDef) )
782+ case . namespace:
783+ ( )
760784 }
761785 }
762786
@@ -770,45 +794,6 @@ public class ExportSwift {
770794 return decls. map { $0. formatted ( using: format) . description } . joined ( separator: " \n \n " )
771795 }
772796
773- func renderCaseEnumHelpers( _ enumDef: ExportedEnum ) -> DeclSyntax {
774- let typeName = enumDef. swiftCallName
775- var initCases : [ String ] = [ ]
776- var valueCases : [ String ] = [ ]
777- for (index, c) in enumDef. cases. enumerated ( ) {
778- initCases. append ( " case \( index) : self = . \( c. name) " )
779- valueCases. append ( " case . \( c. name) : return \( index) " )
780- }
781- let initSwitch = ( [ " switch bridgeJSRawValue { " ] + initCases + [ " default: return nil " , " } " ] ) . joined (
782- separator: " \n "
783- )
784- let valueSwitch = ( [ " switch self { " ] + valueCases + [ " } " ] ) . joined ( separator: " \n " )
785-
786- return """
787- extension \( raw: typeName) {
788- @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 {
789- return bridgeJSRawValue
790- }
791- @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> \( raw: typeName) {
792- return \( raw: typeName) (bridgeJSRawValue: value)!
793- }
794- @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> \( raw: typeName) {
795- return \( raw: typeName) (bridgeJSRawValue: value)!
796- }
797- @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 {
798- return bridgeJSRawValue
799- }
800-
801- private init?(bridgeJSRawValue: Int32) {
802- \( raw: initSwitch)
803- }
804-
805- private var bridgeJSRawValue: Int32 {
806- \( raw: valueSwitch)
807- }
808- }
809- """
810- }
811-
812797 class ExportedThunkBuilder {
813798 var body : [ CodeBlockItemSyntax ] = [ ]
814799 var liftedParameterExprs : [ ExprSyntax ] = [ ]
@@ -1006,6 +991,159 @@ public class ExportSwift {
1006991 }
1007992 }
1008993
994+ private struct EnumCodegen {
995+ func renderCaseEnumHelpers( _ enumDef: ExportedEnum ) -> DeclSyntax {
996+ let typeName = enumDef. swiftCallName
997+ var initCases : [ String ] = [ ]
998+ var valueCases : [ String ] = [ ]
999+ for (index, enumCase) in enumDef. cases. enumerated ( ) {
1000+ initCases. append ( " case \( index) : self = . \( enumCase. name) " )
1001+ valueCases. append ( " case . \( enumCase. name) : return \( index) " )
1002+ }
1003+ let initSwitch = ( [ " switch bridgeJSRawValue { " ] + initCases + [ " default: return nil " , " } " ] ) . joined (
1004+ separator: " \n "
1005+ )
1006+ let valueSwitch = ( [ " switch self { " ] + valueCases + [ " } " ] ) . joined ( separator: " \n " )
1007+
1008+ return """
1009+ extension \( raw: typeName) {
1010+ @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 {
1011+ return bridgeJSRawValue
1012+ }
1013+ @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> \( raw: typeName) {
1014+ return \( raw: typeName) (bridgeJSRawValue: value)!
1015+ }
1016+ @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> \( raw: typeName) {
1017+ return \( raw: typeName) (bridgeJSRawValue: value)!
1018+ }
1019+ @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 {
1020+ return bridgeJSRawValue
1021+ }
1022+
1023+ private init?(bridgeJSRawValue: Int32) {
1024+ \( raw: initSwitch)
1025+ }
1026+
1027+ private var bridgeJSRawValue: Int32 {
1028+ \( raw: valueSwitch)
1029+ }
1030+ }
1031+ """
1032+ }
1033+
1034+ func renderAssociatedValueEnumHelpers( _ enumDef: ExportedEnum ) -> DeclSyntax {
1035+ let typeName = enumDef. swiftCallName
1036+ return """
1037+ private extension \( raw: typeName) {
1038+ static func bridgeJSLiftParameter(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> \( raw: typeName) {
1039+ let params: [UInt8] = .init(unsafeUninitializedCapacity: Int(paramsLen)) { buf, initializedCount in
1040+ _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped)
1041+ initializedCount = Int(paramsLen)
1042+ }
1043+ return params.withUnsafeBytes { raw in
1044+ var reader = _BJSBinaryReader(raw: raw)
1045+ switch caseId {
1046+ \( raw: generateBinaryLiftSwitchCases ( enumDef: enumDef) . joined ( separator: " \n " ) )
1047+ default: fatalError( " Unknown \( raw: typeName) case ID: \\ (caseId) " )
1048+ }
1049+ }
1050+ }
1051+
1052+ func bridgeJSLowerReturn() {
1053+ switch self {
1054+ \( raw: generateReturnSwitchCases ( enumDef: enumDef) . joined ( separator: " \n " ) )
1055+ }
1056+ }
1057+ }
1058+ """
1059+ }
1060+
1061+ private func generateBinaryLiftSwitchCases( enumDef: ExportedEnum ) -> [ String ] {
1062+ var cases : [ String ] = [ ]
1063+ for (caseIndex, enumCase) in enumDef. cases. enumerated ( ) {
1064+ if enumCase. associatedValues. isEmpty {
1065+ cases. append ( " case \( caseIndex) : return . \( enumCase. name) " )
1066+ } else {
1067+ var lines : [ String ] = [ ]
1068+ lines. append ( " case \( caseIndex) : " )
1069+ lines. append ( " reader.readParamCount(expected: \( enumCase. associatedValues. count) ) " )
1070+ var argList : [ String ] = [ ]
1071+
1072+ for (paramIndex, associatedValue) in enumCase. associatedValues. enumerated ( ) {
1073+ let paramName = associatedValue. label ?? " param \( paramIndex) "
1074+ argList. append ( paramName)
1075+
1076+ switch associatedValue. type {
1077+ case . string:
1078+ lines. append ( " reader.expectTag(.string) " )
1079+ lines. append ( " let \( paramName) = reader.readString() " )
1080+ case . int:
1081+ lines. append ( " reader.expectTag(.int32) " )
1082+ lines. append ( " let \( paramName) = Int(reader.readInt32()) " )
1083+ case . bool:
1084+ lines. append ( " reader.expectTag(.bool) " )
1085+ lines. append ( " let \( paramName) = Int32(reader.readUInt8()) != 0 " )
1086+ case . float:
1087+ lines. append ( " reader.expectTag(.float32) " )
1088+ lines. append ( " let \( paramName) = reader.readFloat32() " )
1089+ case . double:
1090+ lines. append ( " reader.expectTag(.float64) " )
1091+ lines. append ( " let \( paramName) = reader.readFloat64() " )
1092+ default :
1093+ lines. append ( " reader.expectTag(.int32) " )
1094+ lines. append ( " let \( paramName) = reader.readInt32() " )
1095+ }
1096+ }
1097+
1098+ lines. append ( " return . \( enumCase. name) ( \( argList. joined ( separator: " , " ) ) ) " )
1099+ cases. append ( lines. joined ( separator: " \n " ) )
1100+ }
1101+ }
1102+ return cases
1103+ }
1104+
1105+ private func generateReturnSwitchCases( enumDef: ExportedEnum ) -> [ String ] {
1106+ var cases : [ String ] = [ ]
1107+ for (caseIndex, enumCase) in enumDef. cases. enumerated ( ) {
1108+ if enumCase. associatedValues. isEmpty {
1109+ cases. append ( " case . \( enumCase. name) : " )
1110+ cases. append ( " _swift_js_return_tag(Int32( \( caseIndex) )) " )
1111+ } else {
1112+ var bodyLines : [ String ] = [ ]
1113+ bodyLines. append ( " _swift_js_return_tag(Int32( \( caseIndex) )) " )
1114+ for (index, associatedValue) in enumCase. associatedValues. enumerated ( ) {
1115+ let paramName = associatedValue. label ?? " param \( index) "
1116+ switch associatedValue. type {
1117+ case . string:
1118+ bodyLines. append ( " var __bjs_ \( paramName) = \( paramName) " )
1119+ bodyLines. append ( " __bjs_ \( paramName) .withUTF8 { ptr in " )
1120+ bodyLines. append ( " _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) " )
1121+ bodyLines. append ( " } " )
1122+ case . int:
1123+ bodyLines. append ( " _swift_js_return_int(Int32( \( paramName) )) " )
1124+ case . bool:
1125+ bodyLines. append ( " _swift_js_return_bool( \( paramName) ? 1 : 0) " )
1126+ case . float:
1127+ bodyLines. append ( " _swift_js_return_f32( \( paramName) ) " )
1128+ case . double:
1129+ bodyLines. append ( " _swift_js_return_f64( \( paramName) ) " )
1130+ default :
1131+ bodyLines. append (
1132+ " preconditionFailure( \" BridgeJS: unsupported associated value type in generated code \" ) "
1133+ )
1134+ }
1135+ }
1136+ let pattern = enumCase. associatedValues. enumerated ( )
1137+ . map { index, associatedValue in " let \( associatedValue. label ?? " param \( index) " ) " }
1138+ . joined ( separator: " , " )
1139+ cases. append ( " case . \( enumCase. name) ( \( pattern) ): " )
1140+ cases. append ( contentsOf: bodyLines)
1141+ }
1142+ }
1143+ return cases
1144+ }
1145+ }
1146+
10091147 func renderSingleExportedFunction( function: ExportedFunction ) throws -> DeclSyntax {
10101148 let builder = ExportedThunkBuilder ( effects: function. effects)
10111149 for param in function. parameters {
@@ -1264,6 +1402,9 @@ extension BridgeType {
12641402 static let swiftHeapObject = LiftingIntrinsicInfo ( parameters: [ ( " value " , . pointer) ] )
12651403 static let void = LiftingIntrinsicInfo ( parameters: [ ] )
12661404 static let caseEnum = LiftingIntrinsicInfo ( parameters: [ ( " value " , . i32) ] )
1405+ static let associatedValueEnum = LiftingIntrinsicInfo ( parameters: [
1406+ ( " caseId " , . i32) , ( " paramsId " , . i32) , ( " paramsLen " , . i32) ,
1407+ ] )
12671408 }
12681409
12691410 func liftParameterInfo( ) throws -> LiftingIntrinsicInfo {
@@ -1291,7 +1432,7 @@ extension BridgeType {
12911432 case . uint64: return . int
12921433 }
12931434 case . associatedValueEnum:
1294- throw BridgeJSCoreError ( " Associated value enums are not supported to pass as parameters " )
1435+ return . associatedValueEnum
12951436 case . namespaceEnum:
12961437 throw BridgeJSCoreError ( " Namespace enums are not supported to pass as parameters " )
12971438 }
@@ -1310,6 +1451,7 @@ extension BridgeType {
13101451 static let void = LoweringIntrinsicInfo ( returnType: nil )
13111452 static let caseEnum = LoweringIntrinsicInfo ( returnType: . i32)
13121453 static let rawValueEnum = LoweringIntrinsicInfo ( returnType: . i32)
1454+ static let associatedValueEnum = LoweringIntrinsicInfo ( returnType: nil )
13131455 }
13141456
13151457 func loweringReturnInfo( ) throws -> LoweringIntrinsicInfo {
@@ -1337,7 +1479,7 @@ extension BridgeType {
13371479 case . uint64: return . int
13381480 }
13391481 case . associatedValueEnum:
1340- throw BridgeJSCoreError ( " Associated value enums are not supported to pass as parameters " )
1482+ return . associatedValueEnum
13411483 case . namespaceEnum:
13421484 throw BridgeJSCoreError ( " Namespace enums are not supported to pass as parameters " )
13431485 }
0 commit comments