@@ -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,58 @@ 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+ fileID: fileID,
134+ line: line
135+ )
136+ }
137+
138+ static func oneshot(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping \( raw: swiftClosureType) ) -> JSTypedClosure<Signature> {
139+ var typedClosure: JSTypedClosure<Signature>!
140+ let wrapper: Signature = { \( raw: wrapperParamClause) \( raw: wrapperParamIn)
141+ defer { typedClosure.release() }
142+ return body( \( raw: wrapperCallArguments) )
143+ }
144+ typedClosure = JSTypedClosure(fileID: fileID, line: line, wrapper)
145+ return typedClosure
146+ }
147+ }
148+ """
149+
150+ return [
151+ externDecl, makeClosureExternDecl, DeclSyntax ( helperEnumDecl) , typedClosureExtension,
152+ ]
182153 }
183154
184155 func renderClosureInvokeHandler( _ signature: ClosureSignature ) throws -> DeclSyntax {
185- let boxClassName = " _BJS_ClosureBox_ \( signature. mangleName) "
156+ let closureParams = signature. parameters. enumerated ( ) . map { _, type in
157+ " \( type. swiftType) "
158+ } . joined ( separator: " , " )
159+ let swiftEffects = ( signature. isAsync ? " async " : " " ) + ( signature. isThrows ? " throws " : " " )
160+ let swiftReturnType = signature. returnType. swiftType
161+ let swiftClosureType = " ( \( closureParams) ) \( swiftEffects) -> \( swiftReturnType) "
162+ let boxType = " _BridgeJSTypedClosureBox< \( swiftClosureType) > "
186163 let abiName = " invoke_swift_closure_ \( signature. moduleName) _ \( signature. mangleName) "
187164
188165 // Build ABI parameters directly with WasmCoreType (no string conversion needed)
@@ -205,7 +182,7 @@ public struct ClosureCodegen {
205182 liftedParams. append ( " \( paramType. swiftType) .bridgeJSLiftParameter( \( argNames. joined ( separator: " , " ) ) ) " )
206183 }
207184
208- let closureCallExpr = ExprSyntax ( " box. closure(\( raw: liftedParams. joined ( separator: " , " ) ) ) " )
185+ let closureCallExpr = ExprSyntax ( " closure( \( raw: liftedParams. joined ( separator: " , " ) ) ) " )
209186
210187 // Determine return type
211188 let abiReturnWasmType : WasmCoreType ?
@@ -217,6 +194,8 @@ public struct ClosureCodegen {
217194 abiReturnWasmType = nil
218195 }
219196
197+ let throwReturn = abiReturnWasmType? . swiftReturnPlaceholderStmt ?? " return "
198+
220199 // Build signature using SwiftSignatureBuilder
221200 let funcSignature = SwiftSignatureBuilder . buildABIFunctionSignature (
222201 abiParameters: abiParams,
@@ -225,7 +204,13 @@ public struct ClosureCodegen {
225204
226205 // Build body
227206 let body = CodeBlockItemListSyntax {
228- " let box = Unmanaged< \( raw: boxClassName) >.fromOpaque(boxPtr).takeUnretainedValue() "
207+ " let box = Unmanaged< \( raw: boxType) >.fromOpaque(boxPtr).takeUnretainedValue() "
208+ """
209+ guard let closure = box.closure else {
210+ box._bridgeJSThrowReleasedClosure()
211+ \( raw: throwReturn)
212+ }
213+ """
229214 if signature. returnType == . void {
230215 closureCallExpr
231216 } else {
@@ -315,7 +300,7 @@ public struct ClosureCodegen {
315300 for setter in type. setters {
316301 collectClosureSignatures ( from: setter. type, into: & closureSignatures)
317302 }
318- for method in type. methods {
303+ for method in type. methods + type . staticMethods {
319304 collectClosureSignatures ( from: method. parameters, into: & closureSignatures)
320305 collectClosureSignatures ( from: method. returnType, into: & closureSignatures)
321306 }
0 commit comments