@@ -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,24 @@ public class ExportSwift {
524
525
)
525
526
}
526
527
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
+
527
546
let swiftCallName = ExportSwift . computeSwiftCallName ( for: node, itemName: enumName)
528
547
let explicitAccessControl = computeExplicitAtLeastInternalAccessControl (
529
548
for: node,
@@ -753,10 +772,15 @@ public class ExportSwift {
753
772
decls. append ( Self . prelude)
754
773
755
774
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:
759
779
decls. append ( " extension \( raw: enumDef. swiftCallName) : _BridgedSwiftEnumNoPayload {} " )
780
+ case . associatedValue:
781
+ decls. append ( enumCodegen. renderAssociatedValueEnumHelpers ( enumDef) )
782
+ case . namespace:
783
+ ( )
760
784
}
761
785
}
762
786
@@ -770,45 +794,6 @@ public class ExportSwift {
770
794
return decls. map { $0. formatted ( using: format) . description } . joined ( separator: " \n \n " )
771
795
}
772
796
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
797
class ExportedThunkBuilder {
813
798
var body : [ CodeBlockItemSyntax ] = [ ]
814
799
var liftedParameterExprs : [ ExprSyntax ] = [ ]
@@ -1006,6 +991,159 @@ public class ExportSwift {
1006
991
}
1007
992
}
1008
993
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
+
1009
1147
func renderSingleExportedFunction( function: ExportedFunction ) throws -> DeclSyntax {
1010
1148
let builder = ExportedThunkBuilder ( effects: function. effects)
1011
1149
for param in function. parameters {
@@ -1264,6 +1402,9 @@ extension BridgeType {
1264
1402
static let swiftHeapObject = LiftingIntrinsicInfo ( parameters: [ ( " value " , . pointer) ] )
1265
1403
static let void = LiftingIntrinsicInfo ( parameters: [ ] )
1266
1404
static let caseEnum = LiftingIntrinsicInfo ( parameters: [ ( " value " , . i32) ] )
1405
+ static let associatedValueEnum = LiftingIntrinsicInfo ( parameters: [
1406
+ ( " caseId " , . i32) , ( " paramsId " , . i32) , ( " paramsLen " , . i32) ,
1407
+ ] )
1267
1408
}
1268
1409
1269
1410
func liftParameterInfo( ) throws -> LiftingIntrinsicInfo {
@@ -1291,7 +1432,7 @@ extension BridgeType {
1291
1432
case . uint64: return . int
1292
1433
}
1293
1434
case . associatedValueEnum:
1294
- throw BridgeJSCoreError ( " Associated value enums are not supported to pass as parameters " )
1435
+ return . associatedValueEnum
1295
1436
case . namespaceEnum:
1296
1437
throw BridgeJSCoreError ( " Namespace enums are not supported to pass as parameters " )
1297
1438
}
@@ -1310,6 +1451,7 @@ extension BridgeType {
1310
1451
static let void = LoweringIntrinsicInfo ( returnType: nil )
1311
1452
static let caseEnum = LoweringIntrinsicInfo ( returnType: . i32)
1312
1453
static let rawValueEnum = LoweringIntrinsicInfo ( returnType: . i32)
1454
+ static let associatedValueEnum = LoweringIntrinsicInfo ( returnType: nil )
1313
1455
}
1314
1456
1315
1457
func loweringReturnInfo( ) throws -> LoweringIntrinsicInfo {
@@ -1337,7 +1479,7 @@ extension BridgeType {
1337
1479
case . uint64: return . int
1338
1480
}
1339
1481
case . associatedValueEnum:
1340
- throw BridgeJSCoreError ( " Associated value enums are not supported to pass as parameters " )
1482
+ return . associatedValueEnum
1341
1483
case . namespaceEnum:
1342
1484
throw BridgeJSCoreError ( " Namespace enums are not supported to pass as parameters " )
1343
1485
}
0 commit comments