@@ -25,6 +25,7 @@ public class ExportSwift {
25
25
private var exportedClasses : [ ExportedClass ] = [ ]
26
26
private var exportedEnums : [ ExportedEnum ] = [ ]
27
27
private var typeDeclResolver : TypeDeclResolver = TypeDeclResolver ( )
28
+ private let enumCodegen : EnumCodegen = EnumCodegen ( )
28
29
29
30
public init ( progress: ProgressReporting , moduleName: String ) {
30
31
self . progress = progress
@@ -524,6 +525,31 @@ public class ExportSwift {
524
525
)
525
526
}
526
527
528
+ if currentEnum. cases. contains ( where: { !$0. associatedValues. isEmpty } ) {
529
+ if case . tsEnum = emitStyle {
530
+ diagnose (
531
+ node: jsAttribute,
532
+ message: " TypeScript enum style is not supported for associated value enums " ,
533
+ hint: " Use enumStyle: .const in order to map associated-value enums "
534
+ )
535
+ }
536
+ for enumCase in currentEnum. cases {
537
+ for associatedValue in enumCase. associatedValues {
538
+ switch associatedValue. type {
539
+ case . string, . int, . float, . double, . bool:
540
+ break
541
+ default :
542
+ diagnose (
543
+ node: node,
544
+ message: " Unsupported associated value type: \( associatedValue. type. swiftType) " ,
545
+ hint:
546
+ " Only primitive types (String, Int, Float, Double, Bool) are supported in associated-value enums "
547
+ )
548
+ }
549
+ }
550
+ }
551
+ }
552
+
527
553
let swiftCallName = ExportSwift . computeSwiftCallName ( for: node, itemName: enumName)
528
554
let explicitAccessControl = computeExplicitAtLeastInternalAccessControl (
529
555
for: node,
@@ -753,10 +779,15 @@ public class ExportSwift {
753
779
decls. append ( Self . prelude)
754
780
755
781
for enumDef in exportedEnums {
756
- if enumDef. enumType == . simple {
757
- decls. append ( renderCaseEnumHelpers ( enumDef) )
758
- } else {
782
+ switch enumDef. enumType {
783
+ case . simple:
784
+ decls. append ( enumCodegen. renderCaseEnumHelpers ( enumDef) )
785
+ case . rawValue:
759
786
decls. append ( " extension \( raw: enumDef. swiftCallName) : _BridgedSwiftEnumNoPayload {} " )
787
+ case . associatedValue:
788
+ decls. append ( enumCodegen. renderAssociatedValueEnumHelpers ( enumDef) )
789
+ case . namespace:
790
+ ( )
760
791
}
761
792
}
762
793
@@ -770,45 +801,6 @@ public class ExportSwift {
770
801
return decls. map { $0. formatted ( using: format) . description } . joined ( separator: " \n \n " )
771
802
}
772
803
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
-
812
804
class ExportedThunkBuilder {
813
805
var body : [ CodeBlockItemSyntax ] = [ ]
814
806
var liftedParameterExprs : [ ExprSyntax ] = [ ]
@@ -1006,6 +998,159 @@ public class ExportSwift {
1006
998
}
1007
999
}
1008
1000
1001
+ private struct EnumCodegen {
1002
+ func renderCaseEnumHelpers( _ enumDef: ExportedEnum ) -> DeclSyntax {
1003
+ let typeName = enumDef. swiftCallName
1004
+ var initCases : [ String ] = [ ]
1005
+ var valueCases : [ String ] = [ ]
1006
+ for (index, enumCase) in enumDef. cases. enumerated ( ) {
1007
+ initCases. append ( " case \( index) : self = . \( enumCase. name) " )
1008
+ valueCases. append ( " case . \( enumCase. name) : return \( index) " )
1009
+ }
1010
+ let initSwitch = ( [ " switch bridgeJSRawValue { " ] + initCases + [ " default: return nil " , " } " ] ) . joined (
1011
+ separator: " \n "
1012
+ )
1013
+ let valueSwitch = ( [ " switch self { " ] + valueCases + [ " } " ] ) . joined ( separator: " \n " )
1014
+
1015
+ return """
1016
+ extension \( raw: typeName) {
1017
+ @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 {
1018
+ return bridgeJSRawValue
1019
+ }
1020
+ @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> \( raw: typeName) {
1021
+ return \( raw: typeName) (bridgeJSRawValue: value)!
1022
+ }
1023
+ @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> \( raw: typeName) {
1024
+ return \( raw: typeName) (bridgeJSRawValue: value)!
1025
+ }
1026
+ @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 {
1027
+ return bridgeJSRawValue
1028
+ }
1029
+
1030
+ private init?(bridgeJSRawValue: Int32) {
1031
+ \( raw: initSwitch)
1032
+ }
1033
+
1034
+ private var bridgeJSRawValue: Int32 {
1035
+ \( raw: valueSwitch)
1036
+ }
1037
+ }
1038
+ """
1039
+ }
1040
+
1041
+ func renderAssociatedValueEnumHelpers( _ enumDef: ExportedEnum ) -> DeclSyntax {
1042
+ let typeName = enumDef. swiftCallName
1043
+ return """
1044
+ private extension \( raw: typeName) {
1045
+ static func bridgeJSLiftParameter(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> \( raw: typeName) {
1046
+ let params: [UInt8] = .init(unsafeUninitializedCapacity: Int(paramsLen)) { buf, initializedCount in
1047
+ _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped)
1048
+ initializedCount = Int(paramsLen)
1049
+ }
1050
+ return params.withUnsafeBytes { raw in
1051
+ var reader = _BJSBinaryReader(raw: raw)
1052
+ switch caseId {
1053
+ \( raw: generateBinaryLiftSwitchCases ( enumDef: enumDef) . joined ( separator: " \n " ) )
1054
+ default: fatalError( " Unknown \( raw: typeName) case ID: \\ (caseId) " )
1055
+ }
1056
+ }
1057
+ }
1058
+
1059
+ func bridgeJSLowerReturn() {
1060
+ switch self {
1061
+ \( raw: generateReturnSwitchCases ( enumDef: enumDef) . joined ( separator: " \n " ) )
1062
+ }
1063
+ }
1064
+ }
1065
+ """
1066
+ }
1067
+
1068
+ private func generateBinaryLiftSwitchCases( enumDef: ExportedEnum ) -> [ String ] {
1069
+ var cases : [ String ] = [ ]
1070
+ for (caseIndex, enumCase) in enumDef. cases. enumerated ( ) {
1071
+ if enumCase. associatedValues. isEmpty {
1072
+ cases. append ( " case \( caseIndex) : return . \( enumCase. name) " )
1073
+ } else {
1074
+ var lines : [ String ] = [ ]
1075
+ lines. append ( " case \( caseIndex) : " )
1076
+ lines. append ( " reader.readParamCount(expected: \( enumCase. associatedValues. count) ) " )
1077
+ var argList : [ String ] = [ ]
1078
+
1079
+ for (paramIndex, associatedValue) in enumCase. associatedValues. enumerated ( ) {
1080
+ let paramName = associatedValue. label ?? " param \( paramIndex) "
1081
+ argList. append ( paramName)
1082
+
1083
+ switch associatedValue. type {
1084
+ case . string:
1085
+ lines. append ( " reader.expectTag(.string) " )
1086
+ lines. append ( " let \( paramName) = reader.readString() " )
1087
+ case . int:
1088
+ lines. append ( " reader.expectTag(.int32) " )
1089
+ lines. append ( " let \( paramName) = Int(reader.readInt32()) " )
1090
+ case . bool:
1091
+ lines. append ( " reader.expectTag(.bool) " )
1092
+ lines. append ( " let \( paramName) = Int32(reader.readUInt8()) != 0 " )
1093
+ case . float:
1094
+ lines. append ( " reader.expectTag(.float32) " )
1095
+ lines. append ( " let \( paramName) = reader.readFloat32() " )
1096
+ case . double:
1097
+ lines. append ( " reader.expectTag(.float64) " )
1098
+ lines. append ( " let \( paramName) = reader.readFloat64() " )
1099
+ default :
1100
+ lines. append ( " reader.expectTag(.int32) " )
1101
+ lines. append ( " let \( paramName) = reader.readInt32() " )
1102
+ }
1103
+ }
1104
+
1105
+ lines. append ( " return . \( enumCase. name) ( \( argList. joined ( separator: " , " ) ) ) " )
1106
+ cases. append ( lines. joined ( separator: " \n " ) )
1107
+ }
1108
+ }
1109
+ return cases
1110
+ }
1111
+
1112
+ private func generateReturnSwitchCases( enumDef: ExportedEnum ) -> [ String ] {
1113
+ var cases : [ String ] = [ ]
1114
+ for (caseIndex, enumCase) in enumDef. cases. enumerated ( ) {
1115
+ if enumCase. associatedValues. isEmpty {
1116
+ cases. append ( " case . \( enumCase. name) : " )
1117
+ cases. append ( " _swift_js_return_tag(Int32( \( caseIndex) )) " )
1118
+ } else {
1119
+ var bodyLines : [ String ] = [ ]
1120
+ bodyLines. append ( " _swift_js_return_tag(Int32( \( caseIndex) )) " )
1121
+ for (index, associatedValue) in enumCase. associatedValues. enumerated ( ) {
1122
+ let paramName = associatedValue. label ?? " param \( index) "
1123
+ switch associatedValue. type {
1124
+ case . string:
1125
+ bodyLines. append ( " var __bjs_ \( paramName) = \( paramName) " )
1126
+ bodyLines. append ( " __bjs_ \( paramName) .withUTF8 { ptr in " )
1127
+ bodyLines. append ( " _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) " )
1128
+ bodyLines. append ( " } " )
1129
+ case . int:
1130
+ bodyLines. append ( " _swift_js_return_int(Int32( \( paramName) )) " )
1131
+ case . bool:
1132
+ bodyLines. append ( " _swift_js_return_bool( \( paramName) ? 1 : 0) " )
1133
+ case . float:
1134
+ bodyLines. append ( " _swift_js_return_f32( \( paramName) ) " )
1135
+ case . double:
1136
+ bodyLines. append ( " _swift_js_return_f64( \( paramName) ) " )
1137
+ default :
1138
+ bodyLines. append (
1139
+ " preconditionFailure( \" BridgeJS: unsupported associated value type in generated code \" ) "
1140
+ )
1141
+ }
1142
+ }
1143
+ let pattern = enumCase. associatedValues. enumerated ( )
1144
+ . map { index, associatedValue in " let \( associatedValue. label ?? " param \( index) " ) " }
1145
+ . joined ( separator: " , " )
1146
+ cases. append ( " case . \( enumCase. name) ( \( pattern) ): " )
1147
+ cases. append ( contentsOf: bodyLines)
1148
+ }
1149
+ }
1150
+ return cases
1151
+ }
1152
+ }
1153
+
1009
1154
func renderSingleExportedFunction( function: ExportedFunction ) throws -> DeclSyntax {
1010
1155
let builder = ExportedThunkBuilder ( effects: function. effects)
1011
1156
for param in function. parameters {
@@ -1264,6 +1409,9 @@ extension BridgeType {
1264
1409
static let swiftHeapObject = LiftingIntrinsicInfo ( parameters: [ ( " value " , . pointer) ] )
1265
1410
static let void = LiftingIntrinsicInfo ( parameters: [ ] )
1266
1411
static let caseEnum = LiftingIntrinsicInfo ( parameters: [ ( " value " , . i32) ] )
1412
+ static let associatedValueEnum = LiftingIntrinsicInfo ( parameters: [
1413
+ ( " caseId " , . i32) , ( " paramsId " , . i32) , ( " paramsLen " , . i32) ,
1414
+ ] )
1267
1415
}
1268
1416
1269
1417
func liftParameterInfo( ) throws -> LiftingIntrinsicInfo {
@@ -1291,7 +1439,7 @@ extension BridgeType {
1291
1439
case . uint64: return . int
1292
1440
}
1293
1441
case . associatedValueEnum:
1294
- throw BridgeJSCoreError ( " Associated value enums are not supported to pass as parameters " )
1442
+ return . associatedValueEnum
1295
1443
case . namespaceEnum:
1296
1444
throw BridgeJSCoreError ( " Namespace enums are not supported to pass as parameters " )
1297
1445
}
@@ -1310,6 +1458,7 @@ extension BridgeType {
1310
1458
static let void = LoweringIntrinsicInfo ( returnType: nil )
1311
1459
static let caseEnum = LoweringIntrinsicInfo ( returnType: . i32)
1312
1460
static let rawValueEnum = LoweringIntrinsicInfo ( returnType: . i32)
1461
+ static let associatedValueEnum = LoweringIntrinsicInfo ( returnType: nil )
1313
1462
}
1314
1463
1315
1464
func loweringReturnInfo( ) throws -> LoweringIntrinsicInfo {
@@ -1337,7 +1486,7 @@ extension BridgeType {
1337
1486
case . uint64: return . int
1338
1487
}
1339
1488
case . associatedValueEnum:
1340
- throw BridgeJSCoreError ( " Associated value enums are not supported to pass as parameters " )
1489
+ return . associatedValueEnum
1341
1490
case . namespaceEnum:
1342
1491
throw BridgeJSCoreError ( " Namespace enums are not supported to pass as parameters " )
1343
1492
}
0 commit comments