Skip to content

Commit cd20012

Browse files
committed
BridgeJS: Add BridgeTypeDescriptor and refactor ExportSwift/ImportTS to use descriptor-driven dispatch
1 parent a98e49d commit cd20012

File tree

10 files changed

+442
-285
lines changed

10 files changed

+442
-285
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 96 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,23 @@ public class ExportSwift {
147147
} else {
148148
optionalSwiftType = "JSUndefinedOr"
149149
}
150-
typeNameForIntrinsic = "\(optionalSwiftType)<\(wrappedType.swiftType)>"
150+
if case .swiftProtocol(let protocolName) = wrappedType {
151+
let wrapperName = "Any\(protocolName)"
152+
typeNameForIntrinsic = "\(optionalSwiftType)<\(wrapperName)>"
153+
liftingExpr = ExprSyntax(
154+
"\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
155+
)
156+
} else {
157+
typeNameForIntrinsic = "\(optionalSwiftType)<\(wrappedType.swiftType)>"
158+
liftingExpr = ExprSyntax(
159+
"\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
160+
)
161+
}
162+
case .swiftProtocol(let protocolName):
163+
let wrapperName = "Any\(protocolName)"
164+
typeNameForIntrinsic = wrapperName
151165
liftingExpr = ExprSyntax(
152-
"\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
166+
"\(raw: wrapperName).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
153167
)
154168
default:
155169
typeNameForIntrinsic = param.type.swiftType
@@ -164,20 +178,6 @@ public class ExportSwift {
164178
}
165179
}
166180

167-
private func protocolCastSuffix(for returnType: BridgeType) -> (prefix: String, suffix: String) {
168-
switch returnType {
169-
case .swiftProtocol:
170-
return ("", " as! \(returnType.swiftType)")
171-
case .nullable(let wrappedType, _):
172-
if case .swiftProtocol = wrappedType {
173-
return ("(", ").flatMap { $0 as? \(wrappedType.swiftType) }")
174-
}
175-
return ("", "")
176-
default:
177-
return ("", "")
178-
}
179-
}
180-
181181
private func removeFirstLiftedParameter() -> (parameter: Parameter, expr: ExprSyntax) {
182182
let parameter = parameters.removeFirst()
183183
let expr = liftedParameterExprs.removeFirst()
@@ -211,10 +211,26 @@ public class ExportSwift {
211211
if returnType == .void {
212212
return CodeBlockItemSyntax(item: .init(ExpressionStmtSyntax(expression: callExpr)))
213213
} else {
214-
let (prefix, suffix) = protocolCastSuffix(for: returnType)
215-
return CodeBlockItemSyntax(
216-
item: .init(DeclSyntax("let ret = \(raw: prefix)\(raw: callExpr)\(raw: suffix)"))
217-
)
214+
switch returnType {
215+
case .swiftProtocol(let protocolName):
216+
let wrapperName = "Any\(protocolName)"
217+
return CodeBlockItemSyntax(
218+
item: .init(DeclSyntax("let ret = \(raw: callExpr) as! \(raw: wrapperName)"))
219+
)
220+
case .nullable(let wrappedType, _):
221+
if case .swiftProtocol(let protocolName) = wrappedType {
222+
let wrapperName = "Any\(protocolName)"
223+
return CodeBlockItemSyntax(
224+
item: .init(
225+
DeclSyntax("let ret = (\(raw: callExpr)).flatMap { $0 as? \(raw: wrapperName) }")
226+
)
227+
)
228+
} else {
229+
return CodeBlockItemSyntax(item: .init(DeclSyntax("let ret = \(raw: callExpr)")))
230+
}
231+
default:
232+
return CodeBlockItemSyntax(item: .init(DeclSyntax("let ret = \(raw: callExpr)")))
233+
}
218234
}
219235
}
220236

@@ -228,8 +244,20 @@ public class ExportSwift {
228244
if returnType == .void {
229245
append("\(raw: name)")
230246
} else {
231-
let (prefix, suffix) = protocolCastSuffix(for: returnType)
232-
append("let ret = \(raw: prefix)\(raw: name)\(raw: suffix)")
247+
switch returnType {
248+
case .swiftProtocol(let protocolName):
249+
let wrapperName = "Any\(protocolName)"
250+
append("let ret = \(raw: name) as! \(raw: wrapperName)")
251+
case .nullable(let wrappedType, _):
252+
if case .swiftProtocol(let protocolName) = wrappedType {
253+
let wrapperName = "Any\(protocolName)"
254+
append("let ret = \(raw: name).flatMap { $0 as? \(raw: wrapperName) }")
255+
} else {
256+
append("let ret = \(raw: name)")
257+
}
258+
default:
259+
append("let ret = \(raw: name)")
260+
}
233261
}
234262
}
235263

@@ -273,8 +301,20 @@ public class ExportSwift {
273301
if returnType == .void {
274302
append("\(raw: selfExpr).\(raw: propertyName)")
275303
} else {
276-
let (prefix, suffix) = protocolCastSuffix(for: returnType)
277-
append("let ret = \(raw: prefix)\(raw: selfExpr).\(raw: propertyName)\(raw: suffix)")
304+
switch returnType {
305+
case .swiftProtocol(let protocolName):
306+
let wrapperName = "Any\(protocolName)"
307+
append("let ret = \(raw: selfExpr).\(raw: propertyName) as! \(raw: wrapperName)")
308+
case .nullable(let wrappedType, _):
309+
if case .swiftProtocol(let protocolName) = wrappedType {
310+
let wrapperName = "Any\(protocolName)"
311+
append("let ret = \(raw: selfExpr).\(raw: propertyName).flatMap { $0 as? \(raw: wrapperName) }")
312+
} else {
313+
append("let ret = \(raw: selfExpr).\(raw: propertyName)")
314+
}
315+
default:
316+
append("let ret = \(raw: selfExpr).\(raw: propertyName)")
317+
}
278318
}
279319
}
280320

@@ -847,24 +887,26 @@ struct StackCodegen {
847887
varPrefix: String
848888
) -> [CodeBlockItemSyntax] {
849889
switch type {
850-
case .string, .int, .uint, .bool, .float, .double, .jsValue,
851-
.jsObject(nil), .swiftHeapObject, .unsafePointer, .closure,
852-
.caseEnum, .rawValueEnum:
853-
return ["\(raw: accessor).bridgeJSLowerStackReturn()"]
854-
case .jsObject(_?):
855-
return ["\(raw: accessor).jsObject.bridgeJSLowerStackReturn()"]
856-
case .swiftProtocol:
857-
return ["(\(raw: accessor) as! \(raw: type.swiftType)).bridgeJSLowerStackReturn()"]
858-
case .associatedValueEnum, .swiftStruct:
859-
return ["\(raw: accessor).bridgeJSLowerReturn()"]
890+
860891
case .nullable(let wrappedType, _):
861892
return lowerOptionalStatements(wrappedType: wrappedType, accessor: accessor, varPrefix: varPrefix)
862-
case .void, .namespaceEnum:
863-
return []
864893
case .array(let elementType):
865894
return lowerArrayStatements(elementType: elementType, accessor: accessor, varPrefix: varPrefix)
866895
case .dictionary(let valueType):
867896
return lowerDictionaryStatements(valueType: valueType, accessor: accessor, varPrefix: varPrefix)
897+
default:
898+
break
899+
}
900+
901+
let desc = type.descriptor
902+
let transformed = desc.accessorTransform.apply(accessor)
903+
switch desc.lowerMethod {
904+
case .stackReturn:
905+
return ["\(raw: transformed).bridgeJSLowerStackReturn()"]
906+
case .fullReturn, .pushParameter:
907+
return ["\(raw: transformed).bridgeJSLowerReturn()"]
908+
case .none:
909+
return []
868910
}
869911
}
870912

@@ -873,6 +915,7 @@ struct StackCodegen {
873915
accessor: String,
874916
varPrefix: String
875917
) -> [CodeBlockItemSyntax] {
918+
// Types needing accessor transformation
876919
switch elementType {
877920
case .jsObject(let className?) where className != "JSObject":
878921
return ["\(raw: accessor).map { $0.jsObject }.bridgeJSLowerReturn()"]
@@ -977,11 +1020,8 @@ struct StackCodegen {
9771020
accessor: String,
9781021
varPrefix: String
9791022
) -> [CodeBlockItemSyntax] {
980-
switch wrappedType {
981-
case .array, .dictionary, .swiftStruct:
1023+
if wrappedType.descriptor.optionalUsesStackABI {
9821024
return ["\(raw: accessor).bridgeJSLowerReturn()"]
983-
default:
984-
break
9851025
}
9861026

9871027
var statements: [String] = []
@@ -1006,16 +1046,16 @@ struct StackCodegen {
10061046
wrappedType: BridgeType,
10071047
unwrappedVar: String
10081048
) -> [CodeBlockItemSyntax] {
1009-
switch wrappedType {
1010-
case .jsObject(_?):
1011-
return ["\(raw: unwrappedVar).jsObject.bridgeJSLowerStackReturn()"]
1012-
case .swiftProtocol:
1013-
return ["(\(raw: unwrappedVar) as! \(raw: wrappedType.swiftType)).bridgeJSLowerStackReturn()"]
1014-
case .string, .int, .uint, .bool, .float, .double, .jsValue,
1015-
.jsObject(nil), .swiftHeapObject, .unsafePointer, .closure,
1016-
.caseEnum, .rawValueEnum, .associatedValueEnum:
1017-
return ["\(raw: unwrappedVar).bridgeJSLowerStackReturn()"]
1018-
default:
1049+
let desc = wrappedType.descriptor
1050+
let transformed = desc.accessorTransform.apply(unwrappedVar)
1051+
switch desc.lowerMethod {
1052+
case .stackReturn:
1053+
return ["\(raw: transformed).bridgeJSLowerStackReturn()"]
1054+
case .fullReturn:
1055+
return ["\(raw: transformed).bridgeJSLowerReturn()"]
1056+
case .pushParameter:
1057+
return ["_swift_js_push_i32(\(raw: transformed).bridgeJSLowerParameter())"]
1058+
case .none:
10191059
return ["preconditionFailure(\"BridgeJS: unsupported optional wrapped type\")"]
10201060
}
10211061
}
@@ -1629,17 +1669,6 @@ extension BridgeType {
16291669

16301670
func liftParameterInfo() throws -> LiftingIntrinsicInfo {
16311671
switch self {
1632-
case .bool: return .bool
1633-
case .int, .uint: return .int
1634-
case .float: return .float
1635-
case .double: return .double
1636-
case .string: return .string
1637-
case .jsObject: return .jsObject
1638-
case .jsValue: return .jsValue
1639-
case .swiftHeapObject: return .swiftHeapObject
1640-
case .unsafePointer: return .unsafePointer
1641-
case .swiftProtocol: return .jsObject
1642-
case .void: return .void
16431672
case .nullable(let wrappedType, _):
16441673
let wrappedInfo = try wrappedType.liftParameterInfo()
16451674
if wrappedInfo.parameters.isEmpty {
@@ -1648,92 +1677,25 @@ extension BridgeType {
16481677
var optionalParams: [(name: String, type: WasmCoreType)] = [("isSome", .i32)]
16491678
optionalParams.append(contentsOf: wrappedInfo.parameters)
16501679
return LiftingIntrinsicInfo(parameters: optionalParams)
1651-
case .caseEnum: return .caseEnum
1652-
case .rawValueEnum(_, let rawType):
1653-
return rawType.liftingIntrinsicInfo
1654-
case .associatedValueEnum:
1655-
return .associatedValueEnum
1656-
case .swiftStruct:
1657-
return LiftingIntrinsicInfo(parameters: [])
16581680
case .namespaceEnum:
16591681
throw BridgeJSCoreError("Namespace enums are not supported to pass as parameters")
1660-
case .closure:
1661-
return LiftingIntrinsicInfo(parameters: [("callbackId", .i32)])
1662-
case .array, .dictionary:
1663-
return LiftingIntrinsicInfo(parameters: [])
1682+
default:
1683+
return LiftingIntrinsicInfo(parameters: descriptor.wasmParams)
16641684
}
16651685
}
16661686

16671687
struct LoweringIntrinsicInfo: Sendable {
16681688
let returnType: WasmCoreType?
1669-
1670-
static let bool = LoweringIntrinsicInfo(returnType: .i32)
1671-
static let int = LoweringIntrinsicInfo(returnType: .i32)
1672-
static let float = LoweringIntrinsicInfo(returnType: .f32)
1673-
static let double = LoweringIntrinsicInfo(returnType: .f64)
1674-
static let string = LoweringIntrinsicInfo(returnType: nil)
1675-
static let jsObject = LoweringIntrinsicInfo(returnType: .i32)
1676-
static let jsValue = LoweringIntrinsicInfo(returnType: nil)
1677-
static let swiftHeapObject = LoweringIntrinsicInfo(returnType: .pointer)
1678-
static let unsafePointer = LoweringIntrinsicInfo(returnType: .pointer)
1679-
static let void = LoweringIntrinsicInfo(returnType: nil)
1680-
static let caseEnum = LoweringIntrinsicInfo(returnType: .i32)
1681-
static let rawValueEnum = LoweringIntrinsicInfo(returnType: .i32)
1682-
static let associatedValueEnum = LoweringIntrinsicInfo(returnType: nil)
1683-
static let swiftStruct = LoweringIntrinsicInfo(returnType: nil)
1684-
static let optional = LoweringIntrinsicInfo(returnType: nil)
1685-
static let array = LoweringIntrinsicInfo(returnType: nil)
16861689
}
16871690

16881691
func loweringReturnInfo() throws -> LoweringIntrinsicInfo {
16891692
switch self {
1690-
case .bool: return .bool
1691-
case .int, .uint: return .int
1692-
case .float: return .float
1693-
case .double: return .double
1694-
case .string: return .string
1695-
case .jsObject: return .jsObject
1696-
case .jsValue: return .jsValue
1697-
case .swiftHeapObject: return .swiftHeapObject
1698-
case .unsafePointer: return .unsafePointer
1699-
case .swiftProtocol: return .jsObject
1700-
case .void: return .void
1701-
case .nullable: return .optional
1702-
case .caseEnum: return .caseEnum
1703-
case .rawValueEnum(_, let rawType):
1704-
return rawType.loweringIntrinsicInfo
1705-
case .associatedValueEnum:
1706-
return .associatedValueEnum
1707-
case .swiftStruct:
1708-
return .swiftStruct
1693+
case .nullable:
1694+
return LoweringIntrinsicInfo(returnType: nil)
17091695
case .namespaceEnum:
17101696
throw BridgeJSCoreError("Namespace enums are not supported to pass as parameters")
1711-
case .closure:
1712-
return .jsObject
1713-
case .array, .dictionary:
1714-
return .array
1715-
}
1716-
}
1717-
}
1718-
1719-
extension SwiftEnumRawType {
1720-
var liftingIntrinsicInfo: BridgeType.LiftingIntrinsicInfo {
1721-
switch self {
1722-
case .bool: return .bool
1723-
case .int, .int32, .int64, .uint, .uint32, .uint64: return .int
1724-
case .float: return .float
1725-
case .double: return .double
1726-
case .string: return .string
1727-
}
1728-
}
1729-
1730-
var loweringIntrinsicInfo: BridgeType.LoweringIntrinsicInfo {
1731-
switch self {
1732-
case .bool: return .bool
1733-
case .int, .int32, .int64, .uint, .uint32, .uint64: return .int
1734-
case .float: return .float
1735-
case .double: return .double
1736-
case .string: return .string
1697+
default:
1698+
return LoweringIntrinsicInfo(returnType: descriptor.wasmReturnType)
17371699
}
17381700
}
17391701
}

0 commit comments

Comments
 (0)