diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift index 12e4a413c..08a61321c 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift @@ -8,27 +8,6 @@ import BridgeJSSkeleton public struct ClosureCodegen { public init() {} - func collectClosureSignatures(from parameters: [Parameter], into signatures: inout Set) { - for param in parameters { - collectClosureSignatures(from: param.type, into: &signatures) - } - } - - func collectClosureSignatures(from type: BridgeType, into signatures: inout Set) { - switch type { - case .closure(let signature, _): - signatures.insert(signature) - for paramType in signature.parameters { - collectClosureSignatures(from: paramType, into: &signatures) - } - collectClosureSignatures(from: signature.returnType, into: &signatures) - case .nullable(let wrapped, _): - collectClosureSignatures(from: wrapped, into: &signatures) - default: - break - } - } - func renderClosureHelpers(_ signature: ClosureSignature) throws -> [DeclSyntax] { let mangledName = signature.mangleName let helperName = "_BJS_Closure_\(mangledName)" @@ -242,83 +221,10 @@ public struct ClosureCodegen { } public func renderSupport(for skeleton: BridgeJSSkeleton) throws -> String? { - var closureSignatures: Set = [] - - if let exported = skeleton.exported { - for function in exported.functions { - collectClosureSignatures(from: function.parameters, into: &closureSignatures) - collectClosureSignatures(from: function.returnType, into: &closureSignatures) - } - for klass in exported.classes { - if let constructor = klass.constructor { - collectClosureSignatures(from: constructor.parameters, into: &closureSignatures) - } - for method in klass.methods { - collectClosureSignatures(from: method.parameters, into: &closureSignatures) - collectClosureSignatures(from: method.returnType, into: &closureSignatures) - } - for property in klass.properties { - collectClosureSignatures(from: property.type, into: &closureSignatures) - } - } - for proto in exported.protocols { - for method in proto.methods { - collectClosureSignatures(from: method.parameters, into: &closureSignatures) - collectClosureSignatures(from: method.returnType, into: &closureSignatures) - } - for property in proto.properties { - collectClosureSignatures(from: property.type, into: &closureSignatures) - } - } - for structDecl in exported.structs { - for property in structDecl.properties { - collectClosureSignatures(from: property.type, into: &closureSignatures) - } - if let constructor = structDecl.constructor { - collectClosureSignatures(from: constructor.parameters, into: &closureSignatures) - } - for method in structDecl.methods { - collectClosureSignatures(from: method.parameters, into: &closureSignatures) - collectClosureSignatures(from: method.returnType, into: &closureSignatures) - } - } - for enumDecl in exported.enums { - for method in enumDecl.staticMethods { - collectClosureSignatures(from: method.parameters, into: &closureSignatures) - collectClosureSignatures(from: method.returnType, into: &closureSignatures) - } - for property in enumDecl.staticProperties { - collectClosureSignatures(from: property.type, into: &closureSignatures) - } - } - } - - if let imported = skeleton.imported { - for fileSkeleton in imported.children { - for getter in fileSkeleton.globalGetters { - collectClosureSignatures(from: getter.type, into: &closureSignatures) - } - for function in fileSkeleton.functions { - collectClosureSignatures(from: function.parameters, into: &closureSignatures) - collectClosureSignatures(from: function.returnType, into: &closureSignatures) - } - for type in fileSkeleton.types { - if let constructor = type.constructor { - collectClosureSignatures(from: constructor.parameters, into: &closureSignatures) - } - for getter in type.getters { - collectClosureSignatures(from: getter.type, into: &closureSignatures) - } - for setter in type.setters { - collectClosureSignatures(from: setter.type, into: &closureSignatures) - } - for method in type.methods + type.staticMethods { - collectClosureSignatures(from: method.parameters, into: &closureSignatures) - collectClosureSignatures(from: method.returnType, into: &closureSignatures) - } - } - } - } + let collector = ClosureSignatureCollectorVisitor() + var walker = BridgeTypeWalker(visitor: collector) + walker.walk(skeleton) + let closureSignatures = walker.visitor.signatures guard !closureSignatures.isEmpty else { return nil } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 13ea4e910..621e9c98b 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -610,13 +610,10 @@ public struct BridgeJSLink { for unified in skeletons { let moduleName = unified.moduleName - var closureSignatures: Set = [] - if let exported = unified.exported { - collectClosureSignatures(from: exported, into: &closureSignatures) - } - if let imported = unified.imported { - collectClosureSignatures(from: imported, into: &closureSignatures) - } + let collector = ClosureSignatureCollectorVisitor() + var walker = BridgeTypeWalker(visitor: collector) + walker.walk(unified) + let closureSignatures = walker.visitor.signatures guard !closureSignatures.isEmpty else { continue } @@ -714,77 +711,6 @@ public struct BridgeJSLink { return printer } - private func collectClosureSignatures(from skeleton: ExportedSkeleton, into signatures: inout Set) - { - for function in skeleton.functions { - collectClosureSignatures(from: function.parameters, into: &signatures) - collectClosureSignatures(from: function.returnType, into: &signatures) - } - for klass in skeleton.classes { - if let constructor = klass.constructor { - collectClosureSignatures(from: constructor.parameters, into: &signatures) - } - for method in klass.methods { - collectClosureSignatures(from: method.parameters, into: &signatures) - collectClosureSignatures(from: method.returnType, into: &signatures) - } - for property in klass.properties { - collectClosureSignatures(from: property.type, into: &signatures) - } - } - } - - private func collectClosureSignatures( - from skeleton: ImportedModuleSkeleton, - into signatures: inout Set - ) { - for fileSkeleton in skeleton.children { - for getter in fileSkeleton.globalGetters { - collectClosureSignatures(from: getter.type, into: &signatures) - } - for function in fileSkeleton.functions { - collectClosureSignatures(from: function.parameters, into: &signatures) - collectClosureSignatures(from: function.returnType, into: &signatures) - } - for type in fileSkeleton.types { - if let constructor = type.constructor { - collectClosureSignatures(from: constructor.parameters, into: &signatures) - } - for getter in type.getters { - collectClosureSignatures(from: getter.type, into: &signatures) - } - for setter in type.setters { - collectClosureSignatures(from: setter.type, into: &signatures) - } - for method in type.methods + type.staticMethods { - collectClosureSignatures(from: method.parameters, into: &signatures) - collectClosureSignatures(from: method.returnType, into: &signatures) - } - } - } - } - - private func collectClosureSignatures(from parameters: [Parameter], into signatures: inout Set) { - for param in parameters { - collectClosureSignatures(from: param.type, into: &signatures) - } - } - - private func collectClosureSignatures(from type: BridgeType, into signatures: inout Set) { - switch type { - case .closure(let signature, _): - signatures.insert(signature) - for paramType in signature.parameters { - collectClosureSignatures(from: paramType, into: &signatures) - } - collectClosureSignatures(from: signature.returnType, into: &signatures) - case .nullable(let wrapped, _): - collectClosureSignatures(from: wrapped, into: &signatures) - default: - break - } - } - private func generateInvokeFunction( signature: ClosureSignature, functionName: String diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 3ebc91306..ba25b6ff9 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -247,6 +247,138 @@ public struct Parameter: Codable, Equatable, Sendable { } } +// MARK: - BridgeType Visitor + +public protocol BridgeTypeVisitor { + mutating func visitClosure(_ signature: ClosureSignature, useJSTypedClosure: Bool) +} + +public struct BridgeTypeWalker { + public var visitor: Visitor + + public init(visitor: Visitor) { + self.visitor = visitor + } + + public mutating func walk(_ type: BridgeType) { + switch type { + case .closure(let signature, let useJSTypedClosure): + visitor.visitClosure(signature, useJSTypedClosure: useJSTypedClosure) + for paramType in signature.parameters { + walk(paramType) + } + walk(signature.returnType) + case .nullable(let wrapped, _): + walk(wrapped) + case .array(let element): + walk(element) + case .dictionary(let value): + walk(value) + default: + break + } + } + public mutating func walk(_ parameters: [Parameter]) { + for param in parameters { + walk(param.type) + } + } + public mutating func walk(_ function: ExportedFunction) { + walk(function.parameters) + walk(function.returnType) + } + public mutating func walk(_ constructor: ExportedConstructor) { + walk(constructor.parameters) + } + public mutating func walk(_ skeleton: ExportedSkeleton) { + for function in skeleton.functions { + walk(function) + } + for klass in skeleton.classes { + if let constructor = klass.constructor { + walk(constructor.parameters) + } + for method in klass.methods { + walk(method) + } + for property in klass.properties { + walk(property.type) + } + } + for proto in skeleton.protocols { + for method in proto.methods { + walk(method) + } + for property in proto.properties { + walk(property.type) + } + } + for structDecl in skeleton.structs { + for property in structDecl.properties { + walk(property.type) + } + if let constructor = structDecl.constructor { + walk(constructor.parameters) + } + for method in structDecl.methods { + walk(method) + } + } + for enumDecl in skeleton.enums { + for enumCase in enumDecl.cases { + for associatedValue in enumCase.associatedValues { + walk(associatedValue.type) + } + } + for method in enumDecl.staticMethods { + walk(method) + } + for property in enumDecl.staticProperties { + walk(property.type) + } + } + } + public mutating func walk(_ function: ImportedFunctionSkeleton) { + walk(function.parameters) + walk(function.returnType) + } + public mutating func walk(_ skeleton: ImportedModuleSkeleton) { + for fileSkeleton in skeleton.children { + for getter in fileSkeleton.globalGetters { + walk(getter.type) + } + for setter in fileSkeleton.globalSetters { + walk(setter.type) + } + for function in fileSkeleton.functions { + walk(function) + } + for type in fileSkeleton.types { + if let constructor = type.constructor { + walk(constructor.parameters) + } + for getter in type.getters { + walk(getter.type) + } + for setter in type.setters { + walk(setter.type) + } + for method in type.methods + type.staticMethods { + walk(method) + } + } + } + } + public mutating func walk(_ skeleton: BridgeJSSkeleton) { + if let exported = skeleton.exported { + walk(exported) + } + if let imported = skeleton.imported { + walk(imported) + } + } +} + public struct Effects: Codable, Equatable, Sendable { public var isAsync: Bool public var isThrows: Bool @@ -873,6 +1005,20 @@ public struct ImportedModuleSkeleton: Codable { } } +// MARK: - Closure signature collection visitor + +public struct ClosureSignatureCollectorVisitor: BridgeTypeVisitor { + public var signatures: Set = [] + + public init(signatures: Set = []) { + self.signatures = signatures + } + + public mutating func visitClosure(_ signature: ClosureSignature, useJSTypedClosure: Bool) { + signatures.insert(signature) + } +} + // MARK: - Unified Skeleton /// Unified skeleton containing both exported and imported API definitions