Skip to content

Commit 874c625

Browse files
BridgeJS: Deduplicate closure signature collection logic
Centralize the `BridgeType` traversal logic and use it to collect closure signatures in both `BridgeJSCore` and `BridgeJSLink`, removing redundant code. This is mostly NFC but added new closure signature collection paths for `.array` and `.dictionary` element types and for enums with associated values.
1 parent 180c010 commit 874c625

File tree

3 files changed

+154
-176
lines changed

3 files changed

+154
-176
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift

Lines changed: 4 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,6 @@ import BridgeJSSkeleton
88
public struct ClosureCodegen {
99
public init() {}
1010

11-
func collectClosureSignatures(from parameters: [Parameter], into signatures: inout Set<ClosureSignature>) {
12-
for param in parameters {
13-
collectClosureSignatures(from: param.type, into: &signatures)
14-
}
15-
}
16-
17-
func collectClosureSignatures(from type: BridgeType, into signatures: inout Set<ClosureSignature>) {
18-
switch type {
19-
case .closure(let signature, _):
20-
signatures.insert(signature)
21-
for paramType in signature.parameters {
22-
collectClosureSignatures(from: paramType, into: &signatures)
23-
}
24-
collectClosureSignatures(from: signature.returnType, into: &signatures)
25-
case .nullable(let wrapped, _):
26-
collectClosureSignatures(from: wrapped, into: &signatures)
27-
default:
28-
break
29-
}
30-
}
31-
3211
func renderClosureHelpers(_ signature: ClosureSignature) throws -> [DeclSyntax] {
3312
let mangledName = signature.mangleName
3413
let helperName = "_BJS_Closure_\(mangledName)"
@@ -242,83 +221,10 @@ public struct ClosureCodegen {
242221
}
243222

244223
public func renderSupport(for skeleton: BridgeJSSkeleton) throws -> String? {
245-
var closureSignatures: Set<ClosureSignature> = []
246-
247-
if let exported = skeleton.exported {
248-
for function in exported.functions {
249-
collectClosureSignatures(from: function.parameters, into: &closureSignatures)
250-
collectClosureSignatures(from: function.returnType, into: &closureSignatures)
251-
}
252-
for klass in exported.classes {
253-
if let constructor = klass.constructor {
254-
collectClosureSignatures(from: constructor.parameters, into: &closureSignatures)
255-
}
256-
for method in klass.methods {
257-
collectClosureSignatures(from: method.parameters, into: &closureSignatures)
258-
collectClosureSignatures(from: method.returnType, into: &closureSignatures)
259-
}
260-
for property in klass.properties {
261-
collectClosureSignatures(from: property.type, into: &closureSignatures)
262-
}
263-
}
264-
for proto in exported.protocols {
265-
for method in proto.methods {
266-
collectClosureSignatures(from: method.parameters, into: &closureSignatures)
267-
collectClosureSignatures(from: method.returnType, into: &closureSignatures)
268-
}
269-
for property in proto.properties {
270-
collectClosureSignatures(from: property.type, into: &closureSignatures)
271-
}
272-
}
273-
for structDecl in exported.structs {
274-
for property in structDecl.properties {
275-
collectClosureSignatures(from: property.type, into: &closureSignatures)
276-
}
277-
if let constructor = structDecl.constructor {
278-
collectClosureSignatures(from: constructor.parameters, into: &closureSignatures)
279-
}
280-
for method in structDecl.methods {
281-
collectClosureSignatures(from: method.parameters, into: &closureSignatures)
282-
collectClosureSignatures(from: method.returnType, into: &closureSignatures)
283-
}
284-
}
285-
for enumDecl in exported.enums {
286-
for method in enumDecl.staticMethods {
287-
collectClosureSignatures(from: method.parameters, into: &closureSignatures)
288-
collectClosureSignatures(from: method.returnType, into: &closureSignatures)
289-
}
290-
for property in enumDecl.staticProperties {
291-
collectClosureSignatures(from: property.type, into: &closureSignatures)
292-
}
293-
}
294-
}
295-
296-
if let imported = skeleton.imported {
297-
for fileSkeleton in imported.children {
298-
for getter in fileSkeleton.globalGetters {
299-
collectClosureSignatures(from: getter.type, into: &closureSignatures)
300-
}
301-
for function in fileSkeleton.functions {
302-
collectClosureSignatures(from: function.parameters, into: &closureSignatures)
303-
collectClosureSignatures(from: function.returnType, into: &closureSignatures)
304-
}
305-
for type in fileSkeleton.types {
306-
if let constructor = type.constructor {
307-
collectClosureSignatures(from: constructor.parameters, into: &closureSignatures)
308-
}
309-
for getter in type.getters {
310-
collectClosureSignatures(from: getter.type, into: &closureSignatures)
311-
}
312-
for setter in type.setters {
313-
collectClosureSignatures(from: setter.type, into: &closureSignatures)
314-
}
315-
for method in type.methods + type.staticMethods {
316-
collectClosureSignatures(from: method.parameters, into: &closureSignatures)
317-
collectClosureSignatures(from: method.returnType, into: &closureSignatures)
318-
}
319-
}
320-
}
321-
}
224+
let collector = ClosureSignatureCollectorVisitor()
225+
var walker = BridgeTypeWalker(visitor: collector)
226+
walker.walk(skeleton)
227+
let closureSignatures = walker.visitor.signatures
322228

323229
guard !closureSignatures.isEmpty else { return nil }
324230

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 4 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -610,13 +610,10 @@ public struct BridgeJSLink {
610610

611611
for unified in skeletons {
612612
let moduleName = unified.moduleName
613-
var closureSignatures: Set<ClosureSignature> = []
614-
if let exported = unified.exported {
615-
collectClosureSignatures(from: exported, into: &closureSignatures)
616-
}
617-
if let imported = unified.imported {
618-
collectClosureSignatures(from: imported, into: &closureSignatures)
619-
}
613+
let collector = ClosureSignatureCollectorVisitor()
614+
var walker = BridgeTypeWalker(visitor: collector)
615+
walker.walk(unified)
616+
let closureSignatures = walker.visitor.signatures
620617

621618
guard !closureSignatures.isEmpty else { continue }
622619

@@ -714,77 +711,6 @@ public struct BridgeJSLink {
714711
return printer
715712
}
716713

717-
private func collectClosureSignatures(from skeleton: ExportedSkeleton, into signatures: inout Set<ClosureSignature>)
718-
{
719-
for function in skeleton.functions {
720-
collectClosureSignatures(from: function.parameters, into: &signatures)
721-
collectClosureSignatures(from: function.returnType, into: &signatures)
722-
}
723-
for klass in skeleton.classes {
724-
if let constructor = klass.constructor {
725-
collectClosureSignatures(from: constructor.parameters, into: &signatures)
726-
}
727-
for method in klass.methods {
728-
collectClosureSignatures(from: method.parameters, into: &signatures)
729-
collectClosureSignatures(from: method.returnType, into: &signatures)
730-
}
731-
for property in klass.properties {
732-
collectClosureSignatures(from: property.type, into: &signatures)
733-
}
734-
}
735-
}
736-
737-
private func collectClosureSignatures(
738-
from skeleton: ImportedModuleSkeleton,
739-
into signatures: inout Set<ClosureSignature>
740-
) {
741-
for fileSkeleton in skeleton.children {
742-
for getter in fileSkeleton.globalGetters {
743-
collectClosureSignatures(from: getter.type, into: &signatures)
744-
}
745-
for function in fileSkeleton.functions {
746-
collectClosureSignatures(from: function.parameters, into: &signatures)
747-
collectClosureSignatures(from: function.returnType, into: &signatures)
748-
}
749-
for type in fileSkeleton.types {
750-
if let constructor = type.constructor {
751-
collectClosureSignatures(from: constructor.parameters, into: &signatures)
752-
}
753-
for getter in type.getters {
754-
collectClosureSignatures(from: getter.type, into: &signatures)
755-
}
756-
for setter in type.setters {
757-
collectClosureSignatures(from: setter.type, into: &signatures)
758-
}
759-
for method in type.methods + type.staticMethods {
760-
collectClosureSignatures(from: method.parameters, into: &signatures)
761-
collectClosureSignatures(from: method.returnType, into: &signatures)
762-
}
763-
}
764-
}
765-
}
766-
767-
private func collectClosureSignatures(from parameters: [Parameter], into signatures: inout Set<ClosureSignature>) {
768-
for param in parameters {
769-
collectClosureSignatures(from: param.type, into: &signatures)
770-
}
771-
}
772-
773-
private func collectClosureSignatures(from type: BridgeType, into signatures: inout Set<ClosureSignature>) {
774-
switch type {
775-
case .closure(let signature, _):
776-
signatures.insert(signature)
777-
for paramType in signature.parameters {
778-
collectClosureSignatures(from: paramType, into: &signatures)
779-
}
780-
collectClosureSignatures(from: signature.returnType, into: &signatures)
781-
case .nullable(let wrapped, _):
782-
collectClosureSignatures(from: wrapped, into: &signatures)
783-
default:
784-
break
785-
}
786-
}
787-
788714
private func generateInvokeFunction(
789715
signature: ClosureSignature,
790716
functionName: String

Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,138 @@ public struct Parameter: Codable, Equatable, Sendable {
247247
}
248248
}
249249

250+
// MARK: - BridgeType Visitor
251+
252+
public protocol BridgeTypeVisitor {
253+
mutating func visitClosure(_ signature: ClosureSignature, useJSTypedClosure: Bool)
254+
}
255+
256+
public struct BridgeTypeWalker<Visitor: BridgeTypeVisitor> {
257+
public var visitor: Visitor
258+
259+
public init(visitor: Visitor) {
260+
self.visitor = visitor
261+
}
262+
263+
public mutating func walk(_ type: BridgeType) {
264+
switch type {
265+
case .closure(let signature, let useJSTypedClosure):
266+
visitor.visitClosure(signature, useJSTypedClosure: useJSTypedClosure)
267+
for paramType in signature.parameters {
268+
walk(paramType)
269+
}
270+
walk(signature.returnType)
271+
case .nullable(let wrapped, _):
272+
walk(wrapped)
273+
case .array(let element):
274+
walk(element)
275+
case .dictionary(let value):
276+
walk(value)
277+
default:
278+
break
279+
}
280+
}
281+
public mutating func walk(_ parameters: [Parameter]) {
282+
for param in parameters {
283+
walk(param.type)
284+
}
285+
}
286+
public mutating func walk(_ function: ExportedFunction) {
287+
walk(function.parameters)
288+
walk(function.returnType)
289+
}
290+
public mutating func walk(_ constructor: ExportedConstructor) {
291+
walk(constructor.parameters)
292+
}
293+
public mutating func walk(_ skeleton: ExportedSkeleton) {
294+
for function in skeleton.functions {
295+
walk(function)
296+
}
297+
for klass in skeleton.classes {
298+
if let constructor = klass.constructor {
299+
walk(constructor.parameters)
300+
}
301+
for method in klass.methods {
302+
walk(method)
303+
}
304+
for property in klass.properties {
305+
walk(property.type)
306+
}
307+
}
308+
for proto in skeleton.protocols {
309+
for method in proto.methods {
310+
walk(method)
311+
}
312+
for property in proto.properties {
313+
walk(property.type)
314+
}
315+
}
316+
for structDecl in skeleton.structs {
317+
for property in structDecl.properties {
318+
walk(property.type)
319+
}
320+
if let constructor = structDecl.constructor {
321+
walk(constructor.parameters)
322+
}
323+
for method in structDecl.methods {
324+
walk(method)
325+
}
326+
}
327+
for enumDecl in skeleton.enums {
328+
for enumCase in enumDecl.cases {
329+
for associatedValue in enumCase.associatedValues {
330+
walk(associatedValue.type)
331+
}
332+
}
333+
for method in enumDecl.staticMethods {
334+
walk(method)
335+
}
336+
for property in enumDecl.staticProperties {
337+
walk(property.type)
338+
}
339+
}
340+
}
341+
public mutating func walk(_ function: ImportedFunctionSkeleton) {
342+
walk(function.parameters)
343+
walk(function.returnType)
344+
}
345+
public mutating func walk(_ skeleton: ImportedModuleSkeleton) {
346+
for fileSkeleton in skeleton.children {
347+
for getter in fileSkeleton.globalGetters {
348+
walk(getter.type)
349+
}
350+
for setter in fileSkeleton.globalSetters {
351+
walk(setter.type)
352+
}
353+
for function in fileSkeleton.functions {
354+
walk(function)
355+
}
356+
for type in fileSkeleton.types {
357+
if let constructor = type.constructor {
358+
walk(constructor.parameters)
359+
}
360+
for getter in type.getters {
361+
walk(getter.type)
362+
}
363+
for setter in type.setters {
364+
walk(setter.type)
365+
}
366+
for method in type.methods + type.staticMethods {
367+
walk(method)
368+
}
369+
}
370+
}
371+
}
372+
public mutating func walk(_ skeleton: BridgeJSSkeleton) {
373+
if let exported = skeleton.exported {
374+
walk(exported)
375+
}
376+
if let imported = skeleton.imported {
377+
walk(imported)
378+
}
379+
}
380+
}
381+
250382
public struct Effects: Codable, Equatable, Sendable {
251383
public var isAsync: Bool
252384
public var isThrows: Bool
@@ -873,6 +1005,20 @@ public struct ImportedModuleSkeleton: Codable {
8731005
}
8741006
}
8751007

1008+
// MARK: - Closure signature collection visitor
1009+
1010+
public struct ClosureSignatureCollectorVisitor: BridgeTypeVisitor {
1011+
public var signatures: Set<ClosureSignature> = []
1012+
1013+
public init(signatures: Set<ClosureSignature> = []) {
1014+
self.signatures = signatures
1015+
}
1016+
1017+
public mutating func visitClosure(_ signature: ClosureSignature, useJSTypedClosure: Bool) {
1018+
signatures.insert(signature)
1019+
}
1020+
}
1021+
8761022
// MARK: - Unified Skeleton
8771023

8781024
/// Unified skeleton containing both exported and imported API definitions

0 commit comments

Comments
 (0)