Skip to content

Commit 40b9e8e

Browse files
committed
BridgeJS: Generic bridging infrastructure
1 parent fba3be0 commit 40b9e8e

3 files changed

Lines changed: 201 additions & 14 deletions

File tree

Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ final class JSGlueVariableScope {
3535
static let reservedSwiftClosureRegistry = "swiftClosureRegistry"
3636
static let reservedMakeSwiftClosure = "makeClosure"
3737
static let reservedTaStack = "taStack"
38+
static let reservedCodecs = "__bjs_codecs"
39+
static let reservedCodecsById = "__bjs_codecsById"
3840

3941
private let intrinsicRegistry: JSIntrinsicRegistry
4042

@@ -65,6 +67,8 @@ final class JSGlueVariableScope {
6567
reservedSwiftClosureRegistry,
6668
reservedMakeSwiftClosure,
6769
reservedTaStack,
70+
reservedCodecs,
71+
reservedCodecsById,
6872
]
6973

7074
init(intrinsicRegistry: JSIntrinsicRegistry) {
@@ -365,11 +369,12 @@ struct IntrinsicJSFragment: Sendable {
365369
helperPrinter.write("function \(jsValueLiftHelperName)(kind, payload1, payload2) {")
366370
helperPrinter.indent {
367371
let helperScope = scope.makeChildScope()
368-
let resultVar = emitJSValueConstruction(
372+
let resultVar = helperScope.variable("jsValue")
373+
emitJSValueConstruction(
369374
kind: "kind",
370375
payload1: "payload1",
371376
payload2: "payload2",
372-
scope: helperScope,
377+
resultVar: resultVar,
373378
printer: helperPrinter
374379
)
375380
helperPrinter.write("return \(resultVar);")
@@ -465,10 +470,9 @@ struct IntrinsicJSFragment: Sendable {
465470
kind: String,
466471
payload1: String,
467472
payload2: String,
468-
scope: JSGlueVariableScope,
473+
resultVar: String,
469474
printer: CodeFragmentPrinter
470-
) -> String {
471-
let resultVar = scope.variable("jsValue")
475+
) {
472476
printer.write("let \(resultVar);")
473477
printer.write("switch (\(kind)) {")
474478
printer.indent {
@@ -526,7 +530,6 @@ struct IntrinsicJSFragment: Sendable {
526530
}
527531
}
528532
printer.write("}")
529-
return resultVar
530533
}
531534

532535
static func jsValueLowerReturn(context: BridgeContext) -> IntrinsicJSFragment {
@@ -1940,7 +1943,7 @@ struct IntrinsicJSFragment: Sendable {
19401943
)
19411944
}
19421945

1943-
private static func stackLiftFragment(elementType: BridgeType) throws -> IntrinsicJSFragment {
1946+
static func stackLiftFragment(elementType: BridgeType) throws -> IntrinsicJSFragment {
19441947
if case .nullable(let wrappedType, let kind) = elementType {
19451948
return try optionalElementRaiseFragment(wrappedType: wrappedType, kind: kind)
19461949
}
@@ -2067,7 +2070,7 @@ struct IntrinsicJSFragment: Sendable {
20672070
}
20682071
}
20692072

2070-
private static func stackLowerFragment(elementType: BridgeType) throws -> IntrinsicJSFragment {
2073+
static func stackLowerFragment(elementType: BridgeType) throws -> IntrinsicJSFragment {
20712074
if case .nullable(let wrappedType, let kind) = elementType {
20722075
return try optionalElementLowerFragment(wrappedType: wrappedType, kind: kind)
20732076
}
@@ -2676,7 +2679,7 @@ private extension BridgeType {
26762679
return .inlineFlag
26772680
case .closure:
26782681
return .inlineFlag
2679-
case .swiftStruct, .array, .dictionary, .void, .namespaceEnum:
2682+
case .swiftStruct, .array, .dictionary, .void, .namespaceEnum, .generic:
26802683
return .stackABI
26812684
case .nullable(let wrapped, _):
26822685
return wrapped.optionalConvention
@@ -2772,7 +2775,7 @@ private extension BridgeType {
27722775
return [("caseId", .i32)]
27732776
case .closure:
27742777
return [("funcRef", .i32)]
2775-
case .void, .namespaceEnum, .swiftStruct, .array, .dictionary:
2778+
case .void, .namespaceEnum, .swiftStruct, .array, .dictionary, .generic:
27762779
return []
27772780
case .nullable(let wrapped, _):
27782781
return wrapped.wasmParams
@@ -2806,10 +2809,15 @@ private extension BridgeType {
28062809
switch self {
28072810
case .bool, .rawValueEnum(_, .bool): return "$0 !== 0"
28082811
case .integer(let t) where !t.is64Bit && !t.isSigned: return "$0 >>> 0"
2812+
case .integer(let t) where t.is64Bit && !t.isSigned: return "BigInt.asUintN(64, $0)"
28092813
case .rawValueEnum(_, let rawType)
28102814
where rawType.integerType?.is64Bit == false
28112815
&& rawType.integerType?.isSigned == false:
28122816
return "$0 >>> 0"
2817+
case .rawValueEnum(_, let rawType)
2818+
where rawType.integerType?.is64Bit == true
2819+
&& rawType.integerType?.isSigned == false:
2820+
return "BigInt.asUintN(64, $0)"
28132821
default: return nil
28142822
}
28152823
}

Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,24 @@ public enum BridgeType: Codable, Equatable, Hashable, Sendable {
273273
case namespaceEnum(String)
274274
case swiftProtocol(String)
275275
case swiftStruct(String)
276+
case generic(String)
276277
indirect case closure(ClosureSignature, useJSTypedClosure: Bool)
277278
}
278279

280+
extension BridgeType {
281+
public var referencedGenericName: String? {
282+
switch self {
283+
case .generic(let name): return name
284+
case .array(.generic(let name)): return name
285+
case .nullable(.generic(let name), _): return name
286+
case .dictionary(.generic(let name)): return name
287+
default: return nil
288+
}
289+
}
290+
291+
public var usesBareGeneric: Bool { referencedGenericName != nil }
292+
}
293+
279294
public enum WasmCoreType: String, Codable, Sendable {
280295
case i32, i64, f32, f64, pointer
281296
}
@@ -854,6 +869,8 @@ public struct ExportedFunction: Codable, Equatable, Sendable {
854869
public var effects: Effects
855870
public var namespace: [String]?
856871
public var staticContext: StaticContext?
872+
public var genericParameters: [String]?
873+
public var genericParameterNames: [String] { genericParameters ?? [] }
857874

858875
public init(
859876
name: String,
@@ -862,7 +879,8 @@ public struct ExportedFunction: Codable, Equatable, Sendable {
862879
returnType: BridgeType,
863880
effects: Effects,
864881
namespace: [String]? = nil,
865-
staticContext: StaticContext? = nil
882+
staticContext: StaticContext? = nil,
883+
genericParameters: [String]? = nil
866884
) {
867885
self.name = name
868886
self.abiName = abiName
@@ -871,6 +889,7 @@ public struct ExportedFunction: Codable, Equatable, Sendable {
871889
self.effects = effects
872890
self.namespace = namespace
873891
self.staticContext = staticContext
892+
self.genericParameters = genericParameters
874893
}
875894
}
876895

@@ -883,6 +902,7 @@ public struct ExportedClass: Codable, NamespacedExportedType {
883902
public var properties: [ExportedProperty]
884903
public var namespace: [String]?
885904
public var identityMode: Bool? // nil = use config default, true/false = override
905+
public var isFinal: Bool?
886906

887907
public init(
888908
name: String,
@@ -892,7 +912,8 @@ public struct ExportedClass: Codable, NamespacedExportedType {
892912
methods: [ExportedFunction],
893913
properties: [ExportedProperty] = [],
894914
namespace: [String]? = nil,
895-
identityMode: Bool? = nil
915+
identityMode: Bool? = nil,
916+
isFinal: Bool? = nil
896917
) {
897918
self.name = name
898919
self.swiftCallName = swiftCallName
@@ -902,6 +923,7 @@ public struct ExportedClass: Codable, NamespacedExportedType {
902923
self.properties = properties
903924
self.namespace = namespace
904925
self.identityMode = identityMode
926+
self.isFinal = isFinal
905927
}
906928
}
907929

@@ -1100,6 +1122,8 @@ public struct ImportedFunctionSkeleton: Codable {
11001122
/// determine the access level of bridge-generated helpers (e.g. typed
11011123
/// closure inits) that surface through this function's signature.
11021124
public let accessLevel: BridgeJSAccessLevel
1125+
public let genericParameters: [String]?
1126+
public var genericParameterNames: [String] { genericParameters ?? [] }
11031127

11041128
public init(
11051129
name: String,
@@ -1109,7 +1133,8 @@ public struct ImportedFunctionSkeleton: Codable {
11091133
returnType: BridgeType,
11101134
effects: Effects = Effects(isAsync: false, isThrows: true),
11111135
documentation: String? = nil,
1112-
accessLevel: BridgeJSAccessLevel = .internal
1136+
accessLevel: BridgeJSAccessLevel = .internal,
1137+
genericParameters: [String]? = nil
11131138
) {
11141139
self.name = name
11151140
self.jsName = jsName
@@ -1119,10 +1144,11 @@ public struct ImportedFunctionSkeleton: Codable {
11191144
self.effects = effects
11201145
self.documentation = documentation
11211146
self.accessLevel = accessLevel
1147+
self.genericParameters = genericParameters
11221148
}
11231149

11241150
private enum CodingKeys: String, CodingKey {
1125-
case name, jsName, from, parameters, returnType, effects, documentation, accessLevel
1151+
case name, jsName, from, parameters, returnType, effects, documentation, accessLevel, genericParameters
11261152
}
11271153

11281154
public init(from decoder: any Decoder) throws {
@@ -1135,6 +1161,7 @@ public struct ImportedFunctionSkeleton: Codable {
11351161
self.effects = try container.decode(Effects.self, forKey: .effects)
11361162
self.documentation = try container.decodeIfPresent(String.self, forKey: .documentation)
11371163
self.accessLevel = try container.decodeIfPresent(BridgeJSAccessLevel.self, forKey: .accessLevel) ?? .internal
1164+
self.genericParameters = try container.decodeIfPresent([String].self, forKey: .genericParameters)
11381165
}
11391166

11401167
public func abiName(context: ImportedTypeSkeleton?) -> String {
@@ -1622,6 +1649,8 @@ extension BridgeType {
16221649
case .dictionary:
16231650
// Dictionaries use stack-based return with entry count (no direct WASM return type)
16241651
return nil
1652+
case .generic:
1653+
return nil
16251654
}
16261655
}
16271656

@@ -1709,6 +1738,8 @@ extension BridgeType {
17091738
case .dictionary(let valueType):
17101739
// Dictionary mangling: "SD" prefix followed by value type (key is always String)
17111740
return "SD\(valueType.mangleTypeName)"
1741+
case .generic(let name):
1742+
return "\(name.count)\(name)T"
17121743
}
17131744
}
17141745

0 commit comments

Comments
 (0)