Skip to content

Commit 31f8400

Browse files
BridgeJS: Add support for exposing Swift class property accessors
1 parent fc46afd commit 31f8400

File tree

10 files changed

+1725
-53
lines changed

10 files changed

+1725
-53
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 30 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,8 @@ public class ExportSwift {
402402

403403
class ExportedThunkBuilder {
404404
var body: [CodeBlockItemSyntax] = []
405-
var abiParameterForwardings: [LabeledExprSyntax] = []
405+
var liftedParameterExprs: [ExprSyntax] = []
406+
var parameters: [Parameter] = []
406407
var abiParameterSignatures: [(name: String, type: WasmCoreType)] = []
407408
var abiReturnType: WasmCoreType?
408409
let effects: Effects
@@ -421,38 +422,19 @@ public class ExportSwift {
421422
}
422423

423424
func liftParameter(param: Parameter) {
425+
parameters.append(param)
424426
switch param.type {
425427
case .bool:
426-
abiParameterForwardings.append(
427-
LabeledExprSyntax(
428-
label: param.label,
429-
expression: ExprSyntax("\(raw: param.name) == 1")
430-
)
431-
)
428+
liftedParameterExprs.append(ExprSyntax("\(raw: param.name) == 1"))
432429
abiParameterSignatures.append((param.name, .i32))
433430
case .int:
434-
abiParameterForwardings.append(
435-
LabeledExprSyntax(
436-
label: param.label,
437-
expression: ExprSyntax("\(raw: param.type.swiftType)(\(raw: param.name))")
438-
)
439-
)
431+
liftedParameterExprs.append(ExprSyntax("\(raw: param.type.swiftType)(\(raw: param.name))"))
440432
abiParameterSignatures.append((param.name, .i32))
441433
case .float:
442-
abiParameterForwardings.append(
443-
LabeledExprSyntax(
444-
label: param.label,
445-
expression: ExprSyntax("\(raw: param.name)")
446-
)
447-
)
434+
liftedParameterExprs.append(ExprSyntax("\(raw: param.name)"))
448435
abiParameterSignatures.append((param.name, .f32))
449436
case .double:
450-
abiParameterForwardings.append(
451-
LabeledExprSyntax(
452-
label: param.label,
453-
expression: ExprSyntax("\(raw: param.name)")
454-
)
455-
)
437+
liftedParameterExprs.append(ExprSyntax("\(raw: param.name)"))
456438
abiParameterSignatures.append((param.name, .f64))
457439
case .string:
458440
let bytesLabel = "\(param.name)Bytes"
@@ -464,46 +446,40 @@ public class ExportSwift {
464446
}
465447
"""
466448
append(prepare)
467-
abiParameterForwardings.append(
468-
LabeledExprSyntax(
469-
label: param.label,
470-
expression: ExprSyntax("\(raw: param.name)")
471-
)
472-
)
449+
liftedParameterExprs.append(ExprSyntax("\(raw: param.name)"))
473450
abiParameterSignatures.append((bytesLabel, .i32))
474451
abiParameterSignatures.append((lengthLabel, .i32))
475452
case .jsObject(nil):
476-
abiParameterForwardings.append(
477-
LabeledExprSyntax(
478-
label: param.label,
479-
expression: ExprSyntax("JSObject(id: UInt32(bitPattern: \(raw: param.name)))")
480-
)
481-
)
453+
liftedParameterExprs.append(ExprSyntax("JSObject(id: UInt32(bitPattern: \(raw: param.name)))"))
482454
abiParameterSignatures.append((param.name, .i32))
483455
case .jsObject(let name):
484-
abiParameterForwardings.append(
485-
LabeledExprSyntax(
486-
label: param.label,
487-
expression: ExprSyntax("\(raw: name)(takingThis: UInt32(bitPattern: \(raw: param.name)))")
488-
)
456+
liftedParameterExprs.append(
457+
ExprSyntax("\(raw: name)(takingThis: UInt32(bitPattern: \(raw: param.name)))")
489458
)
490459
abiParameterSignatures.append((param.name, .i32))
491460
case .swiftHeapObject:
492461
// UnsafeMutableRawPointer is passed as an i32 pointer
493462
let objectExpr: ExprSyntax =
494463
"Unmanaged<\(raw: param.type.swiftType)>.fromOpaque(\(raw: param.name)).takeUnretainedValue()"
495-
abiParameterForwardings.append(
496-
LabeledExprSyntax(label: param.label, expression: objectExpr)
497-
)
464+
liftedParameterExprs.append(objectExpr)
498465
abiParameterSignatures.append((param.name, .pointer))
499466
case .void:
500467
break
501468
}
502469
}
503470

471+
private func removeFirstLiftedParameter() -> (parameter: Parameter, expr: ExprSyntax) {
472+
let parameter = parameters.removeFirst()
473+
let expr = liftedParameterExprs.removeFirst()
474+
return (parameter, expr)
475+
}
476+
504477
private func renderCallStatement(callee: ExprSyntax, returnType: BridgeType) -> CodeBlockItemSyntax {
478+
let labeledParams = zip(parameters, liftedParameterExprs).map { param, expr in
479+
LabeledExprSyntax(label: param.label, expression: expr)
480+
}
505481
var callExpr: ExprSyntax =
506-
"\(raw: callee)(\(raw: abiParameterForwardings.map { $0.description }.joined(separator: ", ")))"
482+
"\(raw: callee)(\(raw: labeledParams.map { $0.description }.joined(separator: ", ")))"
507483
if effects.isAsync {
508484
callExpr = ExprSyntax(
509485
AwaitExprSyntax(awaitKeyword: .keyword(.await).with(\.trailingTrivia, .space), expression: callExpr)
@@ -536,27 +512,28 @@ public class ExportSwift {
536512
}
537513

538514
func callMethod(klassName: String, methodName: String, returnType: BridgeType) {
539-
let _selfParam = self.abiParameterForwardings.removeFirst()
515+
let (_, selfExpr) = removeFirstLiftedParameter()
540516
let item = renderCallStatement(
541-
callee: "\(raw: _selfParam).\(raw: methodName)",
517+
callee: "\(raw: selfExpr).\(raw: methodName)",
542518
returnType: returnType
543519
)
544520
append(item)
545521
}
546522

547523
func callPropertyGetter(klassName: String, propertyName: String, returnType: BridgeType) {
548-
let _selfParam = self.abiParameterForwardings.removeFirst()
524+
let (_, selfExpr) = removeFirstLiftedParameter()
549525
let retMutability = returnType == .string ? "var" : "let"
550526
if returnType == .void {
551-
append("\(raw: _selfParam).\(raw: propertyName)")
527+
append("\(raw: selfExpr).\(raw: propertyName)")
552528
} else {
553-
append("\(raw: retMutability) ret = \(raw: _selfParam).\(raw: propertyName)")
529+
append("\(raw: retMutability) ret = \(raw: selfExpr).\(raw: propertyName)")
554530
}
555531
}
556532

557533
func callPropertySetter(klassName: String, propertyName: String) {
558-
let _selfParam = self.abiParameterForwardings.removeFirst()
559-
append("\(raw: _selfParam).\(raw: propertyName) = value")
534+
let (_, selfExpr) = removeFirstLiftedParameter()
535+
let (_, newValueExpr) = removeFirstLiftedParameter()
536+
append("\(raw: selfExpr).\(raw: propertyName) = \(raw: newValueExpr)")
560537
}
561538

562539
func lowerReturnValue(returnType: BridgeType) {
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
@JS class PropertyHolder {
2+
// Primitive properties
3+
@JS var intValue: Int
4+
@JS var floatValue: Float
5+
@JS var doubleValue: Double
6+
@JS var boolValue: Bool
7+
@JS var stringValue: String
8+
9+
// Readonly primitive properties
10+
@JS let readonlyInt: Int = 42
11+
@JS let readonlyFloat: Float = 3.14
12+
@JS let readonlyDouble: Double = 2.718281828
13+
@JS let readonlyBool: Bool = true
14+
@JS let readonlyString: String = "constant"
15+
16+
// JSObject property
17+
@JS var jsObject: JSObject
18+
19+
// SwiftHeapObject property (will be set later)
20+
@JS var sibling: PropertyHolder
21+
22+
@JS init(
23+
intValue: Int,
24+
floatValue: Float,
25+
doubleValue: Double,
26+
boolValue: Bool,
27+
stringValue: String,
28+
jsObject: JSObject
29+
) {
30+
self.intValue = intValue
31+
self.floatValue = floatValue
32+
self.doubleValue = doubleValue
33+
self.boolValue = boolValue
34+
self.stringValue = stringValue
35+
self.jsObject = jsObject
36+
self.sibling = self
37+
}
38+
39+
@JS func getAllValues() -> String {
40+
return "int:\(intValue),float:\(floatValue),double:\(doubleValue),bool:\(boolValue),string:\(stringValue)"
41+
}
42+
}
43+
44+
@JS func createPropertyHolder(
45+
intValue: Int,
46+
floatValue: Float,
47+
doubleValue: Double,
48+
boolValue: Bool,
49+
stringValue: String,
50+
jsObject: JSObject
51+
) -> PropertyHolder {
52+
return PropertyHolder(
53+
intValue: intValue,
54+
floatValue: floatValue,
55+
doubleValue: doubleValue,
56+
boolValue: boolValue,
57+
stringValue: stringValue,
58+
jsObject: jsObject
59+
)
60+
}
61+
62+
@JS func testPropertyHolder(holder: PropertyHolder) -> String {
63+
return holder.getAllValues()
64+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit,
2+
// DO NOT EDIT.
3+
//
4+
// To update this file, just rebuild your project or run
5+
// `swift package bridge-js`.
6+
7+
/// Represents a Swift heap object like a class instance or an actor instance.
8+
export interface SwiftHeapObject {
9+
/// Release the heap object.
10+
///
11+
/// Note: Calling this method will release the heap object and it will no longer be accessible.
12+
release(): void;
13+
}
14+
export interface PropertyHolder extends SwiftHeapObject {
15+
getAllValues(): string;
16+
intValue: number;
17+
floatValue: number;
18+
doubleValue: number;
19+
boolValue: boolean;
20+
stringValue: string;
21+
readonly readonlyInt: number;
22+
readonly readonlyFloat: number;
23+
readonly readonlyDouble: number;
24+
readonly readonlyBool: boolean;
25+
readonly readonlyString: string;
26+
jsObject: any;
27+
sibling: PropertyHolder;
28+
}
29+
export type Exports = {
30+
PropertyHolder: {
31+
new(intValue: number, floatValue: number, doubleValue: number, boolValue: boolean, stringValue: string, jsObject: any): PropertyHolder;
32+
}
33+
createPropertyHolder(intValue: number, floatValue: number, doubleValue: number, boolValue: boolean, stringValue: string, jsObject: any): PropertyHolder;
34+
testPropertyHolder(holder: PropertyHolder): string;
35+
}
36+
export type Imports = {
37+
}
38+
export function createInstantiator(options: {
39+
imports: Imports;
40+
}, swift: any): Promise<{
41+
addImports: (importObject: WebAssembly.Imports) => void;
42+
setInstance: (instance: WebAssembly.Instance) => void;
43+
createExports: (instance: WebAssembly.Instance) => Exports;
44+
}>;

0 commit comments

Comments
 (0)