@@ -32,15 +32,14 @@ public struct ClosureCodegen {
3232 func renderClosureHelpers( _ signature: ClosureSignature ) throws -> [ DeclSyntax ] {
3333 let mangledName = signature. mangleName
3434 let helperName = " _BJS_Closure_ \( mangledName) "
35- let boxClassName = " _BJS_ClosureBox_ \( mangledName) "
3635
3736 let closureParams = signature. parameters. enumerated ( ) . map { _, type in
3837 " \( type. swiftType) "
3938 } . joined ( separator: " , " )
4039
4140 let swiftEffects = ( signature. isAsync ? " async " : " " ) + ( signature. isThrows ? " throws " : " " )
4241 let swiftReturnType = signature. returnType. swiftType
43- let closureType = " ( \( closureParams) ) \( swiftEffects) -> \( swiftReturnType) "
42+ let swiftClosureType = " ( \( closureParams) ) \( swiftEffects) -> \( swiftReturnType) "
4443
4544 let externName = " invoke_js_callback_ \( signature. moduleName) _ \( mangledName) "
4645
@@ -65,17 +64,25 @@ public struct ClosureCodegen {
6564
6665 // Get the body code
6766 let bodyCode = builder. getBody ( )
67+ let wasmBody = SwiftCodePattern . buildWasmConditionalCompilation ( wasmBody: bodyCode. statements)
68+ . formatted ( using: BasicFormat ( ) ) . description
69+ let closureParamsList = signature. parameters. enumerated ( ) . map { " param \( $0. offset) " } . joined ( separator: " , " )
70+ let wrapperParamClause = closureParamsList. isEmpty ? " " : " \( closureParamsList) "
71+ let wrapperParamIn = closureParamsList. isEmpty ? " " : " in "
72+ let wrapperCallArguments = closureParamsList. isEmpty ? " " : " \( closureParamsList) "
6873
6974 // Generate extern declaration using CallJSEmission
7075 let externDecl = builder. renderImportDecl ( )
7176
72- let boxClassDecl : DeclSyntax = """
73- private final class \( raw: boxClassName) : _BridgedSwiftClosureBox {
74- let closure: \( raw: closureType)
75- init(_ closure: @escaping \( raw: closureType) ) {
76- self.closure = closure
77- }
77+ let makeClosureExternDecl : DeclSyntax = """
78+ #if arch(wasm32)
79+ @_extern(wasm, module: " bjs " , name: " make_swift_closure_ \( raw: signature. moduleName) _ \( raw: signature. mangleName) " )
80+ fileprivate func make_swift_closure_ \( raw: signature. moduleName) _ \( raw: signature. mangleName) (_ boxPtr: UnsafeMutableRawPointer) -> Int32
81+ #else
82+ fileprivate func make_swift_closure_ \( raw: signature. moduleName) _ \( raw: signature. mangleName) (_ boxPtr: UnsafeMutableRawPointer) -> Int32 {
83+ fatalError( " Only available on WebAssembly " )
7884 }
85+ #endif
7986 """
8087
8188 let helperEnumDecl = EnumDeclSyntax (
@@ -84,33 +91,6 @@ public struct ClosureCodegen {
8491 } ,
8592 name: . identifier( helperName) ,
8693 memberBlockBuilder: {
87- DeclSyntax (
88- FunctionDeclSyntax (
89- modifiers: DeclModifierListSyntax {
90- DeclModifierSyntax ( name: . keyword( . static) )
91- } ,
92- name: . identifier( " bridgeJSLower " ) ,
93- signature: FunctionSignatureSyntax (
94- parameterClause: FunctionParameterClauseSyntax {
95- FunctionParameterSyntax (
96- firstName: . wildcardToken( ) ,
97- secondName: . identifier( " closure " ) ,
98- colon: . colonToken( ) ,
99- type: TypeSyntax ( " @escaping \( raw: closureType) " )
100- )
101- } ,
102- returnClause: ReturnClauseSyntax (
103- arrow: . arrowToken( ) ,
104- type: IdentifierTypeSyntax ( name: . identifier( " UnsafeMutableRawPointer " ) )
105- )
106- ) ,
107- body: CodeBlockSyntax {
108- " let box = \( raw: boxClassName) (closure) "
109- " return Unmanaged.passRetained(box).toOpaque() "
110- }
111- )
112- )
113-
11494 DeclSyntax (
11595 FunctionDeclSyntax (
11696 modifiers: DeclModifierListSyntax {
@@ -128,61 +108,59 @@ public struct ClosureCodegen {
128108 } ,
129109 returnClause: ReturnClauseSyntax (
130110 arrow: . arrowToken( ) ,
131- type: IdentifierTypeSyntax ( name: . identifier( closureType ) )
111+ type: IdentifierTypeSyntax ( name: . identifier( swiftClosureType ) )
132112 )
133113 ) ,
134114 body: CodeBlockSyntax {
135115 " let callback = JSObject.bridgeJSLiftParameter(callbackId) "
136- ReturnStmtSyntax (
137- expression: ClosureExprSyntax (
138- leftBrace: . leftBraceToken( ) ,
139- signature: ClosureSignatureSyntax (
140- capture: ClosureCaptureClauseSyntax (
141- leftSquare: . leftSquareToken( ) ,
142- items: ClosureCaptureListSyntax {
143- #if canImport(SwiftSyntax602)
144- ClosureCaptureSyntax (
145- name: . identifier( " " , presence: . missing) ,
146- initializer: InitializerClauseSyntax (
147- equal: . equalToken( presence: . missing) ,
148- nil ,
149- value: ExprSyntax ( " callback " )
150- ) ,
151- trailingTrivia: nil
152- )
153- #else
154- ClosureCaptureSyntax (
155- expression: ExprSyntax ( " callback " )
156- )
157- #endif
158- } ,
159- rightSquare: . rightSquareToken( )
160- ) ,
161- parameterClause: . simpleInput(
162- ClosureShorthandParameterListSyntax {
163- for (index, _) in signature. parameters. enumerated ( ) {
164- ClosureShorthandParameterSyntax ( name: . identifier( " param \( index) " ) )
165- }
166- }
167- ) ,
168- inKeyword: . keyword( . in)
169- ) ,
170- statements: CodeBlockItemListSyntax {
171- SwiftCodePattern . buildWasmConditionalCompilation ( wasmBody: bodyCode. statements)
172- } ,
173- rightBrace: . rightBraceToken( )
174- )
175- )
116+ """
117+ let callable: \( raw: swiftClosureType) = { [callback] \( raw: closureParamsList) in
118+ \( raw: wasmBody)
119+ }
120+ """
121+ " return callable "
176122 }
177123 )
178124 )
179125 }
180126 )
181- return [ externDecl, boxClassDecl, DeclSyntax ( helperEnumDecl) ]
127+ let typedClosureExtension : DeclSyntax = """
128+ extension JSTypedClosure where Signature == \( raw: swiftClosureType) {
129+ init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping \( raw: swiftClosureType) ) {
130+ self.init(
131+ makeClosure: make_swift_closure_ \( raw: signature. moduleName) _ \( raw: signature. mangleName) ,
132+ body: body,
133+ jsObject: jsObject,
134+ fileID: fileID,
135+ line: line
136+ )
137+ }
138+
139+ static func oneshot(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping \( raw: swiftClosureType) ) -> JSTypedClosure<Signature> {
140+ var typedClosure: JSTypedClosure<Signature>!
141+ let wrapper: Signature = { \( raw: wrapperParamClause) \( raw: wrapperParamIn)
142+ defer { typedClosure.release() }
143+ return body( \( raw: wrapperCallArguments) )
144+ }
145+ typedClosure = JSTypedClosure(fileID: fileID, line: line, wrapper)
146+ return typedClosure
147+ }
148+ }
149+ """
150+
151+ return [
152+ externDecl, makeClosureExternDecl, DeclSyntax ( helperEnumDecl) , typedClosureExtension,
153+ ]
182154 }
183155
184156 func renderClosureInvokeHandler( _ signature: ClosureSignature ) throws -> DeclSyntax {
185- let boxClassName = " _BJS_ClosureBox_ \( signature. mangleName) "
157+ let closureParams = signature. parameters. enumerated ( ) . map { _, type in
158+ " \( type. swiftType) "
159+ } . joined ( separator: " , " )
160+ let swiftEffects = ( signature. isAsync ? " async " : " " ) + ( signature. isThrows ? " throws " : " " )
161+ let swiftReturnType = signature. returnType. swiftType
162+ let swiftClosureType = " ( \( closureParams) ) \( swiftEffects) -> \( swiftReturnType) "
163+ let boxType = " _BridgeJSTypedClosureBox< \( swiftClosureType) > "
186164 let abiName = " invoke_swift_closure_ \( signature. moduleName) _ \( signature. mangleName) "
187165
188166 // Build ABI parameters directly with WasmCoreType (no string conversion needed)
@@ -205,7 +183,7 @@ public struct ClosureCodegen {
205183 liftedParams. append ( " \( paramType. swiftType) .bridgeJSLiftParameter( \( argNames. joined ( separator: " , " ) ) ) " )
206184 }
207185
208- let closureCallExpr = ExprSyntax ( " box. closure(\( raw: liftedParams. joined ( separator: " , " ) ) ) " )
186+ let closureCallExpr = ExprSyntax ( " closure( \( raw: liftedParams. joined ( separator: " , " ) ) ) " )
209187
210188 // Determine return type
211189 let abiReturnWasmType : WasmCoreType ?
@@ -217,6 +195,19 @@ public struct ClosureCodegen {
217195 abiReturnWasmType = nil
218196 }
219197
198+ let throwReturn : String
199+ if let abiReturnWasmType {
200+ switch abiReturnWasmType {
201+ case . i32: throwReturn = " return 0 "
202+ case . i64: throwReturn = " return 0 "
203+ case . f32: throwReturn = " return 0 "
204+ case . f64: throwReturn = " return 0 "
205+ case . pointer: throwReturn = " return UnsafeMutableRawPointer(bitPattern: 0)! "
206+ }
207+ } else {
208+ throwReturn = " return "
209+ }
210+
220211 // Build signature using SwiftSignatureBuilder
221212 let funcSignature = SwiftSignatureBuilder . buildABIFunctionSignature (
222213 abiParameters: abiParams,
@@ -225,7 +216,11 @@ public struct ClosureCodegen {
225216
226217 // Build body
227218 let body = CodeBlockItemListSyntax {
228- " let box = Unmanaged< \( raw: boxClassName) >.fromOpaque(boxPtr).takeUnretainedValue() "
219+ " let box = Unmanaged< \( raw: boxType) >.fromOpaque(boxPtr).takeUnretainedValue() "
220+ " guard let closure = box.closure else { "
221+ " box._bridgeJSThrowReleasedClosure() "
222+ " \( raw: throwReturn) "
223+ " } "
229224 if signature. returnType == . void {
230225 closureCallExpr
231226 } else {
@@ -315,7 +310,7 @@ public struct ClosureCodegen {
315310 for setter in type. setters {
316311 collectClosureSignatures ( from: setter. type, into: & closureSignatures)
317312 }
318- for method in type. methods {
313+ for method in type. methods + type . staticMethods {
319314 collectClosureSignatures ( from: method. parameters, into: & closureSignatures)
320315 collectClosureSignatures ( from: method. returnType, into: & closureSignatures)
321316 }
0 commit comments