@@ -32,15 +32,16 @@ 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) "
43+ let typedClosureType = " JSTypedClosure< \( swiftClosureType) > "
44+ let boxType = " _BridgeJSTypedClosureBox< \( swiftClosureType) > "
4445
4546 let externName = " invoke_js_callback_ \( signature. moduleName) _ \( mangledName) "
4647
@@ -65,17 +66,25 @@ public struct ClosureCodegen {
6566
6667 // Get the body code
6768 let bodyCode = builder. getBody ( )
69+ let wasmBody = SwiftCodePattern . buildWasmConditionalCompilation ( wasmBody: bodyCode. statements)
70+ . formatted ( using: BasicFormat ( ) ) . description
71+ let closureParamsList = signature. parameters. enumerated ( ) . map { " param \( $0. offset) " } . joined ( separator: " , " )
72+ let wrapperParamClause = closureParamsList. isEmpty ? " " : " \( closureParamsList) "
73+ let wrapperParamIn = closureParamsList. isEmpty ? " " : " in "
74+ let wrapperCallArguments = closureParamsList. isEmpty ? " " : " \( closureParamsList) "
6875
6976 // Generate extern declaration using CallJSEmission
7077 let externDecl = builder. renderImportDecl ( )
7178
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- }
79+ let makeClosureExternDecl : DeclSyntax = """
80+ #if arch(wasm32)
81+ @_extern(wasm, module: " bjs " , name: " make_swift_closure_ \( raw: signature. moduleName) _ \( raw: signature. mangleName) " )
82+ fileprivate func make_swift_closure_ \( raw: signature. moduleName) _ \( raw: signature. mangleName) (_ boxPtr: UnsafeMutableRawPointer) -> Int32
83+ #else
84+ fileprivate func make_swift_closure_ \( raw: signature. moduleName) _ \( raw: signature. mangleName) (_ boxPtr: UnsafeMutableRawPointer) -> Int32 {
85+ fatalError( " Only available on WebAssembly " )
7886 }
87+ #endif
7988 """
8089
8190 let helperEnumDecl = EnumDeclSyntax (
@@ -84,33 +93,6 @@ public struct ClosureCodegen {
8493 } ,
8594 name: . identifier( helperName) ,
8695 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-
11496 DeclSyntax (
11597 FunctionDeclSyntax (
11698 modifiers: DeclModifierListSyntax {
@@ -128,61 +110,60 @@ public struct ClosureCodegen {
128110 } ,
129111 returnClause: ReturnClauseSyntax (
130112 arrow: . arrowToken( ) ,
131- type: IdentifierTypeSyntax ( name: . identifier( closureType ) )
113+ type: IdentifierTypeSyntax ( name: . identifier( swiftClosureType ) )
132114 )
133115 ) ,
134116 body: CodeBlockSyntax {
135117 " 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- )
118+ """
119+ let callable: \( raw: swiftClosureType) = { [callback] \( raw: closureParamsList) in
120+ \( raw: wasmBody)
121+ }
122+ """
123+ " return callable "
176124 }
177125 )
178126 )
179127 }
180128 )
181- return [ externDecl, boxClassDecl, DeclSyntax ( helperEnumDecl) ]
129+ let typedClosureExtension : DeclSyntax = """
130+ extension JSTypedClosure where Signature == \( raw: swiftClosureType) {
131+ init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping \( raw: swiftClosureType) ) {
132+ let box = \( raw: boxType) (body, fileID: fileID, line: line)
133+ let pointer = Unmanaged.passRetained(box).toOpaque()
134+ let funcRefValue = make_swift_closure_ \( raw: signature. moduleName) _ \( raw: signature. mangleName) (pointer)
135+ let jsObject = JSObject(id: UInt32(bitPattern: funcRefValue))
136+ self.init(
137+ _boxPointer: pointer,
138+ jsObject: jsObject
139+ )
140+ }
141+
142+ static func oneshot(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping \( raw: swiftClosureType) ) -> JSTypedClosure<Signature> {
143+ var typedClosure: JSTypedClosure<Signature>!
144+ let wrapper: Signature = { \( raw: wrapperParamClause) \( raw: wrapperParamIn)
145+ defer { typedClosure.release() }
146+ return body( \( raw: wrapperCallArguments) )
147+ }
148+ typedClosure = JSTypedClosure(fileID: fileID, line: line, wrapper)
149+ return typedClosure
150+ }
151+ }
152+ """
153+
154+ return [
155+ externDecl, makeClosureExternDecl, DeclSyntax ( helperEnumDecl) , typedClosureExtension,
156+ ]
182157 }
183158
184159 func renderClosureInvokeHandler( _ signature: ClosureSignature ) throws -> DeclSyntax {
185- let boxClassName = " _BJS_ClosureBox_ \( signature. mangleName) "
160+ let closureParams = signature. parameters. enumerated ( ) . map { _, type in
161+ " \( type. swiftType) "
162+ } . joined ( separator: " , " )
163+ let swiftEffects = ( signature. isAsync ? " async " : " " ) + ( signature. isThrows ? " throws " : " " )
164+ let swiftReturnType = signature. returnType. swiftType
165+ let swiftClosureType = " ( \( closureParams) ) \( swiftEffects) -> \( swiftReturnType) "
166+ let boxType = " _BridgeJSTypedClosureBox< \( swiftClosureType) > "
186167 let abiName = " invoke_swift_closure_ \( signature. moduleName) _ \( signature. mangleName) "
187168
188169 // Build ABI parameters directly with WasmCoreType (no string conversion needed)
@@ -205,7 +186,7 @@ public struct ClosureCodegen {
205186 liftedParams. append ( " \( paramType. swiftType) .bridgeJSLiftParameter( \( argNames. joined ( separator: " , " ) ) ) " )
206187 }
207188
208- let closureCallExpr = ExprSyntax ( " box. closure(\( raw: liftedParams. joined ( separator: " , " ) ) ) " )
189+ let closureCallExpr = ExprSyntax ( " closure( \( raw: liftedParams. joined ( separator: " , " ) ) ) " )
209190
210191 // Determine return type
211192 let abiReturnWasmType : WasmCoreType ?
@@ -217,6 +198,19 @@ public struct ClosureCodegen {
217198 abiReturnWasmType = nil
218199 }
219200
201+ let throwReturn : String
202+ if let abiReturnWasmType {
203+ switch abiReturnWasmType {
204+ case . i32: throwReturn = " return 0 "
205+ case . i64: throwReturn = " return 0 "
206+ case . f32: throwReturn = " return 0 "
207+ case . f64: throwReturn = " return 0 "
208+ case . pointer: throwReturn = " return UnsafeMutableRawPointer(bitPattern: 0)! "
209+ }
210+ } else {
211+ throwReturn = " return "
212+ }
213+
220214 // Build signature using SwiftSignatureBuilder
221215 let funcSignature = SwiftSignatureBuilder . buildABIFunctionSignature (
222216 abiParameters: abiParams,
@@ -225,7 +219,11 @@ public struct ClosureCodegen {
225219
226220 // Build body
227221 let body = CodeBlockItemListSyntax {
228- " let box = Unmanaged< \( raw: boxClassName) >.fromOpaque(boxPtr).takeUnretainedValue() "
222+ " let box = Unmanaged< \( raw: boxType) >.fromOpaque(boxPtr).takeUnretainedValue() "
223+ " guard let closure = box.closure else { "
224+ " box._bridgeJSThrowReleasedClosure() "
225+ " \( raw: throwReturn) "
226+ " } "
229227 if signature. returnType == . void {
230228 closureCallExpr
231229 } else {
0 commit comments