Skip to content

Commit 9811899

Browse files
BridgeJS: Complete protocol-based lift/lower for ImportTS and _JSBridgedClass
Add _JSBridgedClass protocol with lift/lower operations for JavaScript objects imported into Swift. Update ImportTS code generation to use new protocol-based bridgeJS* methods. Update all generated ImportTS Swift files and test snapshots to use the new bridgeJS* method calls instead of legacy functions.
1 parent e546582 commit 9811899

File tree

17 files changed

+202
-241
lines changed

17 files changed

+202
-241
lines changed

Benchmarks/Sources/Generated/BridgeJS.ImportTS.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func benchmarkHelperNoopWithNumber(_ n: Double) throws(JSException) -> Void {
3030
fatalError("Only available on WebAssembly")
3131
}
3232
#endif
33-
bjs_benchmarkHelperNoopWithNumber(n)
33+
bjs_benchmarkHelperNoopWithNumber(n.bridgeJSLowerParameter())
3434
if let error = _swift_js_take_exception() {
3535
throw error
3636
}

Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.ImportTS.swift

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,14 @@ func createTS2Skeleton() throws(JSException) -> TS2Skeleton {
1919
if let error = _swift_js_take_exception() {
2020
throw error
2121
}
22-
return TS2Skeleton(takingThis: ret)
22+
return TS2Skeleton.bridgeJSLiftReturn(ret)
2323
}
2424

25-
struct TS2Skeleton {
26-
let this: JSObject
25+
struct TS2Skeleton: _JSBridgedClass {
26+
let jsObject: JSObject
2727

28-
init(this: JSObject) {
29-
self.this = this
30-
}
31-
32-
init(takingThis this: Int32) {
33-
self.this = JSObject(id: UInt32(bitPattern: this))
28+
init(unsafelyWrapping jsObject: JSObject) {
29+
self.jsObject = jsObject
3430
}
3531

3632
func convert(_ ts: String) throws(JSException) -> String {
@@ -42,7 +38,7 @@ struct TS2Skeleton {
4238
fatalError("Only available on WebAssembly")
4339
}
4440
#endif
45-
let ret = bjs_TS2Skeleton_convert(self.this.bridgeJSLowerParameter(), ts.bridgeJSLowerParameter())
41+
let ret = bjs_TS2Skeleton_convert(self.bridgeJSLowerParameter(), ts.bridgeJSLowerParameter())
4642
if let error = _swift_js_take_exception() {
4743
throw error
4844
}

Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift

Lines changed: 81 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -68,70 +68,16 @@ public struct ImportTS {
6868
}
6969

7070
func lowerParameter(param: Parameter) throws {
71-
switch param.type {
72-
case .bool:
73-
abiParameterForwardings.append(
74-
LabeledExprSyntax(
75-
label: param.label,
76-
expression: ExprSyntax("\(raw: param.name).bridgeJSLowerParameter()")
77-
)
78-
)
79-
abiParameterSignatures.append((param.name, .i32))
80-
case .int:
81-
abiParameterForwardings.append(
82-
LabeledExprSyntax(
83-
label: param.label,
84-
expression: ExprSyntax("\(raw: param.name)")
85-
)
86-
)
87-
abiParameterSignatures.append((param.name, .i32))
88-
case .float:
89-
abiParameterForwardings.append(
90-
LabeledExprSyntax(
91-
label: param.label,
92-
expression: ExprSyntax("\(raw: param.name)")
93-
)
94-
)
95-
abiParameterSignatures.append((param.name, .f32))
96-
case .double:
97-
abiParameterForwardings.append(
98-
LabeledExprSyntax(
99-
label: param.label,
100-
expression: ExprSyntax("\(raw: param.name)")
101-
)
102-
)
103-
abiParameterSignatures.append((param.name, .f64))
104-
case .string:
105-
abiParameterForwardings.append(
106-
LabeledExprSyntax(
107-
label: param.label,
108-
expression: ExprSyntax("\(raw: param.name).bridgeJSLowerParameter()")
109-
)
71+
let loweringInfo = try param.type.loweringParameterInfo()
72+
assert(loweringInfo.loweredParameters.count == 1, "For now, we require a single parameter to be lowered to a single Wasm core type")
73+
let (_, type) = loweringInfo.loweredParameters[0]
74+
abiParameterForwardings.append(
75+
LabeledExprSyntax(
76+
label: param.label,
77+
expression: ExprSyntax("\(raw: param.name).bridgeJSLowerParameter()")
11078
)
111-
abiParameterSignatures.append((param.name, .i32))
112-
case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum:
113-
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
114-
case .jsObject(_?):
115-
abiParameterSignatures.append((param.name, .i32))
116-
abiParameterForwardings.append(
117-
LabeledExprSyntax(
118-
label: param.label,
119-
expression: ExprSyntax("\(raw: param.name).this.bridgeJSLowerParameter()")
120-
)
121-
)
122-
case .jsObject(nil):
123-
abiParameterForwardings.append(
124-
LabeledExprSyntax(
125-
label: param.label,
126-
expression: ExprSyntax("\(raw: param.name).bridgeJSLowerParameter()")
127-
)
128-
)
129-
abiParameterSignatures.append((param.name, .i32))
130-
case .swiftHeapObject(_):
131-
throw BridgeJSCoreError("swiftHeapObject is not supported in imported signatures")
132-
case .void:
133-
break
134-
}
79+
)
80+
abiParameterSignatures.append((param.name, type))
13581
}
13682

13783
func call(returnType: BridgeType) {
@@ -146,44 +92,20 @@ public struct ImportTS {
14692
}
14793

14894
func liftReturnValue(returnType: BridgeType) throws {
149-
switch returnType {
150-
case .bool:
151-
abiReturnType = .i32
152-
body.append("return \(raw: returnType.swiftType).bridgeJSLiftReturn(ret)")
153-
case .int:
154-
abiReturnType = .i32
155-
body.append("return \(raw: returnType.swiftType)(ret)")
156-
case .float:
157-
abiReturnType = .f32
158-
body.append("return \(raw: returnType.swiftType)(ret)")
159-
case .double:
160-
abiReturnType = .f64
161-
body.append("return \(raw: returnType.swiftType)(ret)")
162-
case .string:
163-
abiReturnType = .i32
164-
body.append("return \(raw: returnType.swiftType).bridgeJSLiftReturn(ret)")
165-
case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum:
166-
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
167-
case .jsObject(let name):
168-
abiReturnType = .i32
169-
if let name = name {
170-
body.append("return \(raw: name)(takingThis: ret)")
171-
} else {
172-
body.append("return JSObject.bridgeJSLiftReturn(ret)")
173-
}
174-
case .swiftHeapObject(_):
175-
throw BridgeJSCoreError("swiftHeapObject is not supported in imported signatures")
176-
case .void:
177-
break
95+
let liftingInfo = try returnType.liftingReturnInfo()
96+
abiReturnType = liftingInfo.valueToLift
97+
if returnType == .void {
98+
return
17899
}
100+
body.append("return \(raw: returnType.swiftType).bridgeJSLiftReturn(ret)")
179101
}
180102

181103
func assignThis(returnType: BridgeType) {
182104
guard case .jsObject = returnType else {
183105
preconditionFailure("assignThis can only be called with a jsObject return type")
184106
}
185107
abiReturnType = .i32
186-
body.append("self.this = JSObject(id: UInt32(bitPattern: ret))")
108+
body.append("self.jsObject = JSObject(id: UInt32(bitPattern: ret))")
187109
}
188110

189111
func renderImportDecl() -> DeclSyntax {
@@ -410,25 +332,22 @@ public struct ImportTS {
410332
let classDecl = try StructDeclSyntax(
411333
leadingTrivia: Self.renderDocumentation(documentation: type.documentation),
412334
name: .identifier(name),
335+
inheritanceClause: InheritanceClauseSyntax(
336+
inheritedTypesBuilder: {
337+
InheritedTypeSyntax(type: TypeSyntax("_JSBridgedClass"))
338+
}
339+
),
413340
memberBlockBuilder: {
414341
DeclSyntax(
415342
"""
416-
let this: JSObject
343+
let jsObject: JSObject
417344
"""
418345
).with(\.trailingTrivia, .newlines(2))
419346

420347
DeclSyntax(
421348
"""
422-
init(this: JSObject) {
423-
self.this = this
424-
}
425-
"""
426-
).with(\.trailingTrivia, .newlines(2))
427-
428-
DeclSyntax(
429-
"""
430-
init(takingThis this: Int32) {
431-
self.this = JSObject(id: UInt32(bitPattern: this))
349+
init(unsafelyWrapping jsObject: JSObject) {
350+
self.jsObject = jsObject
432351
}
433352
"""
434353
).with(\.trailingTrivia, .newlines(2))
@@ -483,3 +402,61 @@ public struct ImportTS {
483402
)
484403
}
485404
}
405+
406+
extension BridgeType {
407+
struct LoweringParameterInfo {
408+
let loweredParameters: [(name: String, type: WasmCoreType)]
409+
410+
static let bool = LoweringParameterInfo(loweredParameters: [("value", .i32)])
411+
static let int = LoweringParameterInfo(loweredParameters: [("value", .i32)])
412+
static let float = LoweringParameterInfo(loweredParameters: [("value", .f32)])
413+
static let double = LoweringParameterInfo(loweredParameters: [("value", .f64)])
414+
static let string = LoweringParameterInfo(loweredParameters: [("value", .i32)])
415+
static let jsObject = LoweringParameterInfo(loweredParameters: [("value", .i32)])
416+
static let void = LoweringParameterInfo(loweredParameters: [])
417+
}
418+
419+
func loweringParameterInfo() throws -> LoweringParameterInfo {
420+
switch self {
421+
case .bool: return .bool
422+
case .int: return .int
423+
case .float: return .float
424+
case .double: return .double
425+
case .string: return .string
426+
case .jsObject: return .jsObject
427+
case .void: return .void
428+
case .swiftHeapObject:
429+
throw BridgeJSCoreError("swiftHeapObject is not supported in imported signatures")
430+
case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum:
431+
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
432+
}
433+
}
434+
435+
struct LiftingReturnInfo {
436+
let valueToLift: WasmCoreType?
437+
438+
static let bool = LiftingReturnInfo(valueToLift: .i32)
439+
static let int = LiftingReturnInfo(valueToLift: .i32)
440+
static let float = LiftingReturnInfo(valueToLift: .f32)
441+
static let double = LiftingReturnInfo(valueToLift: .f64)
442+
static let string = LiftingReturnInfo(valueToLift: .i32)
443+
static let jsObject = LiftingReturnInfo(valueToLift: .i32)
444+
static let void = LiftingReturnInfo(valueToLift: nil)
445+
}
446+
447+
func liftingReturnInfo() throws -> LiftingReturnInfo {
448+
switch self {
449+
case .bool: return .bool
450+
case .int: return .int
451+
case .float: return .float
452+
case .double: return .double
453+
case .string: return .string
454+
case .jsObject: return .jsObject
455+
case .void: return .void
456+
case .swiftHeapObject:
457+
throw BridgeJSCoreError("swiftHeapObject is not supported in imported signatures")
458+
case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum:
459+
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
460+
}
461+
}
462+
}

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ImportTSTests/ArrayParameter.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func checkArrayWithLength(_ a: JSObject, _ b: Double) throws(JSException) -> Voi
3030
fatalError("Only available on WebAssembly")
3131
}
3232
#endif
33-
bjs_checkArrayWithLength(a.bridgeJSLowerParameter(), b)
33+
bjs_checkArrayWithLength(a.bridgeJSLowerParameter(), b.bridgeJSLowerParameter())
3434
if let error = _swift_js_take_exception() {
3535
throw error
3636
}

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ImportTSTests/Async.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func asyncReturnVoid() throws(JSException) -> JSPromise {
1919
if let error = _swift_js_take_exception() {
2020
throw error
2121
}
22-
return JSPromise(takingThis: ret)
22+
return JSPromise.bridgeJSLiftReturn(ret)
2323
}
2424

2525
func asyncRoundTripInt(_ v: Double) throws(JSException) -> JSPromise {
@@ -31,11 +31,11 @@ func asyncRoundTripInt(_ v: Double) throws(JSException) -> JSPromise {
3131
fatalError("Only available on WebAssembly")
3232
}
3333
#endif
34-
let ret = bjs_asyncRoundTripInt(v)
34+
let ret = bjs_asyncRoundTripInt(v.bridgeJSLowerParameter())
3535
if let error = _swift_js_take_exception() {
3636
throw error
3737
}
38-
return JSPromise(takingThis: ret)
38+
return JSPromise.bridgeJSLiftReturn(ret)
3939
}
4040

4141
func asyncRoundTripString(_ v: String) throws(JSException) -> JSPromise {
@@ -51,7 +51,7 @@ func asyncRoundTripString(_ v: String) throws(JSException) -> JSPromise {
5151
if let error = _swift_js_take_exception() {
5252
throw error
5353
}
54-
return JSPromise(takingThis: ret)
54+
return JSPromise.bridgeJSLiftReturn(ret)
5555
}
5656

5757
func asyncRoundTripBool(_ v: Bool) throws(JSException) -> JSPromise {
@@ -67,7 +67,7 @@ func asyncRoundTripBool(_ v: Bool) throws(JSException) -> JSPromise {
6767
if let error = _swift_js_take_exception() {
6868
throw error
6969
}
70-
return JSPromise(takingThis: ret)
70+
return JSPromise.bridgeJSLiftReturn(ret)
7171
}
7272

7373
func asyncRoundTripFloat(_ v: Double) throws(JSException) -> JSPromise {
@@ -79,11 +79,11 @@ func asyncRoundTripFloat(_ v: Double) throws(JSException) -> JSPromise {
7979
fatalError("Only available on WebAssembly")
8080
}
8181
#endif
82-
let ret = bjs_asyncRoundTripFloat(v)
82+
let ret = bjs_asyncRoundTripFloat(v.bridgeJSLowerParameter())
8383
if let error = _swift_js_take_exception() {
8484
throw error
8585
}
86-
return JSPromise(takingThis: ret)
86+
return JSPromise.bridgeJSLiftReturn(ret)
8787
}
8888

8989
func asyncRoundTripDouble(_ v: Double) throws(JSException) -> JSPromise {
@@ -95,11 +95,11 @@ func asyncRoundTripDouble(_ v: Double) throws(JSException) -> JSPromise {
9595
fatalError("Only available on WebAssembly")
9696
}
9797
#endif
98-
let ret = bjs_asyncRoundTripDouble(v)
98+
let ret = bjs_asyncRoundTripDouble(v.bridgeJSLowerParameter())
9999
if let error = _swift_js_take_exception() {
100100
throw error
101101
}
102-
return JSPromise(takingThis: ret)
102+
return JSPromise.bridgeJSLiftReturn(ret)
103103
}
104104

105105
func asyncRoundTripJSObject(_ v: JSObject) throws(JSException) -> JSPromise {
@@ -115,5 +115,5 @@ func asyncRoundTripJSObject(_ v: JSObject) throws(JSException) -> JSPromise {
115115
if let error = _swift_js_take_exception() {
116116
throw error
117117
}
118-
return JSPromise(takingThis: ret)
118+
return JSPromise.bridgeJSLiftReturn(ret)
119119
}

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ImportTSTests/Interface.swift

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,14 @@ func returnAnimatable() throws(JSException) -> Animatable {
1919
if let error = _swift_js_take_exception() {
2020
throw error
2121
}
22-
return Animatable(takingThis: ret)
22+
return Animatable.bridgeJSLiftReturn(ret)
2323
}
2424

25-
struct Animatable {
26-
let this: JSObject
25+
struct Animatable: _BridgedJSClass {
26+
let jsObject: JSObject
2727

28-
init(this: JSObject) {
29-
self.this = this
30-
}
31-
32-
init(takingThis this: Int32) {
33-
self.this = JSObject(id: UInt32(bitPattern: this))
28+
init(unsafelyWrapping jsObject: JSObject) {
29+
self.jsObject = jsObject
3430
}
3531

3632
func animate(_ keyframes: JSObject, _ options: JSObject) throws(JSException) -> JSObject {
@@ -42,7 +38,7 @@ struct Animatable {
4238
fatalError("Only available on WebAssembly")
4339
}
4440
#endif
45-
let ret = bjs_Animatable_animate(self.this.bridgeJSLowerParameter(), keyframes.bridgeJSLowerParameter(), options.bridgeJSLowerParameter())
41+
let ret = bjs_Animatable_animate(self.bridgeJSLowerParameter(), keyframes.bridgeJSLowerParameter(), options.bridgeJSLowerParameter())
4642
if let error = _swift_js_take_exception() {
4743
throw error
4844
}
@@ -58,7 +54,7 @@ struct Animatable {
5854
fatalError("Only available on WebAssembly")
5955
}
6056
#endif
61-
let ret = bjs_Animatable_getAnimations(self.this.bridgeJSLowerParameter(), options.bridgeJSLowerParameter())
57+
let ret = bjs_Animatable_getAnimations(self.bridgeJSLowerParameter(), options.bridgeJSLowerParameter())
6258
if let error = _swift_js_take_exception() {
6359
throw error
6460
}

0 commit comments

Comments
 (0)