Skip to content

Commit 3f5d93b

Browse files
committed
Move configuration deeper and allow confifuring unsigned handling mode
1 parent aecd22a commit 3f5d93b

24 files changed

+726
-96
lines changed

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,16 @@ extension FFMSwift2JavaGenerator {
105105
var params: [String] = []
106106
var args: [String] = []
107107
for param in cFunc.parameters {
108-
// ! unwrapping because cdecl lowering guarantees the parameter named.
109-
params.append("\(param.type.javaType) \(param.name!)")
110-
args.append(param.name!)
108+
let name = param.name! // !-safe, because cdecl lowering guarantees the parameter named.
109+
110+
let annotationsStr =
111+
if param.type.javaType.parameterAnnotations.isEmpty {
112+
""
113+
} else {
114+
param.type.javaType.parameterAnnotations.map({$0.render()}).joined(separator: " ") + " "
115+
}
116+
params.append("\(annotationsStr)\(param.type.javaType) \(name)")
117+
args.append(name)
111118
}
112119
let paramsStr = params.joined(separator: ", ")
113120
let argsStr = args.joined(separator: ", ")
@@ -316,9 +323,12 @@ extension FFMSwift2JavaGenerator {
316323
let translatedSignature = translated.translatedSignature
317324
let returnTy = translatedSignature.result.javaResultType
318325

326+
var annotationsStr = translatedSignature.annotations.map({ $0.render() }).joined(separator: "\n")
327+
if !annotationsStr.isEmpty { annotationsStr += "\n" }
328+
319329
var paramDecls = translatedSignature.parameters
320330
.flatMap(\.javaParameters)
321-
.map { "\($0.type) \($0.name)" }
331+
.map { $0.renderParameter() }
322332
if translatedSignature.requiresSwiftArena {
323333
paramDecls.append("AllocatingSwiftArena swiftArena$")
324334
}
@@ -332,7 +342,7 @@ extension FFMSwift2JavaGenerator {
332342
* \(decl.signatureString)
333343
* }
334344
*/
335-
\(modifiers) \(returnTy) \(methodName)(\(paramDecls.joined(separator: ", ")))
345+
\(annotationsStr) \(modifiers) \(returnTy) \(methodName)(\(paramDecls.joined(separator: ", ")))
336346
"""
337347
) { printer in
338348
if case .instance(_) = decl.functionSignature.selfParameter {

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift

Lines changed: 76 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
import JavaTypes
16+
import JavaKitConfigurationShared
1617

1718
extension FFMSwift2JavaGenerator {
1819
func translatedDecl(
@@ -24,7 +25,7 @@ extension FFMSwift2JavaGenerator {
2425

2526
let translated: TranslatedFunctionDecl?
2627
do {
27-
let translation = JavaTranslation(symbolTable: self.symbolTable)
28+
let translation = JavaTranslation(config: self.config, symbolTable: self.symbolTable)
2829
translated = try translation.translate(decl)
2930
} catch {
3031
self.log.info("Failed to translate: '\(decl.swiftDecl.qualifiedNameForDebug)'; \(error)")
@@ -52,6 +53,9 @@ extension FFMSwift2JavaGenerator {
5253
/// Java type that represents the Swift result type.
5354
var javaResultType: JavaType
5455

56+
/// Java annotations that should be propagated from the result type onto the method
57+
var annotations: [JavaAnnotation] = []
58+
5559
/// Required indirect return receivers for receiving the result.
5660
///
5761
/// 'JavaParameter.name' is the suffix for the receiver variable names. For example
@@ -85,15 +89,32 @@ extension FFMSwift2JavaGenerator {
8589
/// Function signature.
8690
let translatedSignature: TranslatedFunctionSignature
8791

88-
/// Cdecl lowerd signature.
92+
/// Cdecl lowered signature.
8993
let loweredSignature: LoweredFunctionSignature
94+
95+
/// Annotations to include on the Java function declaration
96+
var annotations: [JavaAnnotation] {
97+
self.translatedSignature.annotations
98+
}
9099
}
91100

92101
/// Function signature for a Java API.
93102
struct TranslatedFunctionSignature {
94103
var selfParameter: TranslatedParameter?
104+
var annotations: [JavaAnnotation] = []
95105
var parameters: [TranslatedParameter]
96106
var result: TranslatedResult
107+
108+
init(selfParameter: TranslatedParameter?,
109+
parameters: [TranslatedParameter],
110+
result: TranslatedResult) {
111+
self.selfParameter = selfParameter
112+
// if the result type implied any annotations,
113+
// propagate them onto the function the result is returned from
114+
self.annotations = result.annotations
115+
self.parameters = parameters
116+
self.result = result
117+
}
97118
}
98119

99120
/// Represent a Swift closure type in the user facing Java API.
@@ -113,9 +134,11 @@ extension FFMSwift2JavaGenerator {
113134
}
114135

115136
struct JavaTranslation {
137+
let config: Configuration
116138
var knownTypes: SwiftKnownTypes
117139

118-
init(symbolTable: SwiftSymbolTable) {
140+
init(config: Configuration, symbolTable: SwiftSymbolTable) {
141+
self.config = config
119142
self.knownTypes = SwiftKnownTypes(symbolTable: symbolTable)
120143
}
121144

@@ -299,21 +322,27 @@ extension FFMSwift2JavaGenerator {
299322
) throws -> TranslatedParameter {
300323

301324
// If we need to handle unsigned integers "safely" do so here
302-
if let unsignedWrapperType = JavaType.unsignedWrapper(for: swiftType) /* and we're in safe wrapper mode */ {
303-
return TranslatedParameter(
304-
javaParameters: [
305-
JavaParameter(name: parameterName, type: unsignedWrapperType)
306-
], conversion: .call(.placeholder, function: "UnsignedNumbers.toPrimitive", withArena: false))
325+
if config.unsignedNumbersMode.needsConversion {
326+
if let unsignedWrapperType = JavaType.unsignedWrapper(for: swiftType) /* and we're in safe wrapper mode */ {
327+
return TranslatedParameter(
328+
javaParameters: [
329+
JavaParameter(name: parameterName, type: unsignedWrapperType)
330+
], conversion: .call(.placeholder, function: "UnsignedNumbers.toPrimitive", withArena: false))
331+
}
307332
}
308333

334+
// If the result type should cause any annotations on the method, include them here.
335+
let parameterAnnotations: [JavaAnnotation] = getTypeAnnotations(swiftType: swiftType)
336+
309337
// If there is a 1:1 mapping between this Swift type and a C type, that can
310338
// be expressed as a Java primitive type.
311339
if let cType = try? CType(cdeclType: swiftType) {
312340
let javaType = cType.javaType
313341
return TranslatedParameter(
314342
javaParameters: [
315343
JavaParameter(
316-
name: parameterName, type: javaType
344+
name: parameterName, type: javaType,
345+
annotations: parameterAnnotations
317346
)
318347
],
319348
conversion: .placeholder
@@ -326,7 +355,10 @@ extension FFMSwift2JavaGenerator {
326355
return TranslatedParameter(
327356
javaParameters: [
328357
JavaParameter(
329-
name: parameterName, type: JavaType.class(package: "org.swift.swiftkit.ffm", name: "SwiftAnyType"))
358+
name: parameterName,
359+
type: JavaType.class(package: "org.swift.swiftkit.ffm", name: "SwiftAnyType"),
360+
annotations: parameterAnnotations
361+
)
330362
],
331363
conversion: .swiftValueSelfSegment(.placeholder)
332364
)
@@ -505,7 +537,22 @@ extension FFMSwift2JavaGenerator {
505537
}
506538
}
507539

508-
func unsignedResultConversion(_ from: SwiftType, to javaType: JavaType) -> JavaConversionStep {
540+
/// Determine if the given type needs any extra annotations that should be included
541+
/// in Java sources when the corresponding Java type is rendered.
542+
func getTypeAnnotations(swiftType: SwiftType) -> [JavaAnnotation] {
543+
if swiftType.isUnsignedInteger, config.unsignedNumbersMode == .annotate {
544+
return [JavaAnnotation.unsigned]
545+
}
546+
547+
return []
548+
}
549+
550+
func unsignedResultConversion(_ from: SwiftType, to javaType: JavaType,
551+
mode: JExtractUnsignedIntegerMode) -> JavaConversionStep {
552+
guard mode == .wrap else {
553+
return .placeholder
554+
}
555+
509556
guard let className = javaType.className else {
510557
fatalError("Missing target class name for result conversion step from \(from) to \(javaType)")
511558
}
@@ -537,20 +584,28 @@ extension FFMSwift2JavaGenerator {
537584
let swiftType = swiftResult.type
538585

539586
// If we need to handle unsigned integers "safely" do so here
540-
if let unsignedWrapperType = JavaType.unsignedWrapper(for: swiftType) /* and we're in safe wrapper mode */ {
541-
return TranslatedResult(
542-
javaResultType: unsignedWrapperType,
543-
outParameters: [],
544-
conversion: unsignedResultConversion(swiftType, to: unsignedWrapperType)
545-
)
587+
if config.unsignedNumbersMode.needsConversion {
588+
if let unsignedWrapperType = JavaType.unsignedWrapper(for: swiftType) /* and we're in safe wrapper mode */ {
589+
return TranslatedResult(
590+
javaResultType: unsignedWrapperType,
591+
outParameters: [],
592+
conversion: unsignedResultConversion(
593+
swiftType, to: unsignedWrapperType,
594+
mode: self.config.unsignedNumbersMode)
595+
)
596+
}
546597
}
547598

599+
// If the result type should cause any annotations on the method, include them here.
600+
let resultAnnotations: [JavaAnnotation] = getTypeAnnotations(swiftType: swiftType)
601+
548602
// If there is a 1:1 mapping between this Swift type and a C type, that can
549603
// be expressed as a Java primitive type.
550604
if let cType = try? CType(cdeclType: swiftType) {
551605
let javaType = cType.javaType
552606
return TranslatedResult(
553607
javaResultType: javaType,
608+
annotations: resultAnnotations,
554609
outParameters: [],
555610
conversion: .placeholder
556611
)
@@ -562,6 +617,7 @@ extension FFMSwift2JavaGenerator {
562617
let javaType = JavaType.class(package: "org.swift.swiftkit.ffm", name: "SwiftAnyType")
563618
return TranslatedResult(
564619
javaResultType: javaType,
620+
annotations: resultAnnotations,
565621
outParameters: [],
566622
conversion: .construct(.placeholder, javaType)
567623
)
@@ -572,6 +628,7 @@ extension FFMSwift2JavaGenerator {
572628
case .unsafeRawBufferPointer, .unsafeMutableRawBufferPointer:
573629
return TranslatedResult(
574630
javaResultType: .javaForeignMemorySegment,
631+
annotations: resultAnnotations,
575632
outParameters: [
576633
JavaParameter(name: "pointer", type: .javaForeignMemorySegment),
577634
JavaParameter(name: "count", type: .long),
@@ -611,6 +668,7 @@ extension FFMSwift2JavaGenerator {
611668
let javaType: JavaType = .class(package: nil, name: swiftNominalType.nominalTypeDecl.name)
612669
return TranslatedResult(
613670
javaResultType: javaType,
671+
annotations: resultAnnotations,
614672
outParameters: [
615673
JavaParameter(name: "", type: javaType)
616674
],
@@ -716,7 +774,7 @@ extension CType {
716774
case .integral(.signed(bits: 32)): return .int
717775
case .integral(.signed(bits: 64)): return .long
718776
case .integral(.unsigned(bits: 8)): return .byte
719-
case .integral(.unsigned(bits: 16)): return .short
777+
case .integral(.unsigned(bits: 16)): return .char // char is Java's only unsigned primitive, we can use it!
720778
case .integral(.unsigned(bits: 32)): return .int
721779
case .integral(.unsigned(bits: 64)): return .long
722780

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
import JavaTypes
1616
import SwiftSyntax
1717
import SwiftSyntaxBuilder
18+
import JavaKitConfigurationShared
1819
import struct Foundation.URL
1920

2021
package class FFMSwift2JavaGenerator: Swift2JavaGenerator {
2122
let log: Logger
23+
let config: Configuration
2224
let analysis: AnalysisResult
2325
let swiftModuleName: String
2426
let javaPackage: String
@@ -40,12 +42,14 @@ package class FFMSwift2JavaGenerator: Swift2JavaGenerator {
4042
var expectedOutputSwiftFiles: Set<String>
4143

4244
package init(
45+
config: Configuration,
4346
translator: Swift2JavaTranslator,
4447
javaPackage: String,
4548
swiftOutputDirectory: String,
4649
javaOutputDirectory: String
4750
) {
4851
self.log = Logger(label: "ffm-generator", logLevel: translator.log.logLevel)
52+
self.config = config
4953
self.analysis = translator.result
5054
self.swiftModuleName = translator.swiftModuleName
5155
self.javaPackage = javaPackage

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ extension JNISwift2JavaGenerator {
219219
_ printer: inout CodePrinter,
220220
_ functionType: TranslatedFunctionType
221221
) {
222-
let apiParams = functionType.parameters.map(\.parameter.asParameter)
222+
let apiParams = functionType.parameters.map({ $0.parameter.renderParameter() })
223223

224224
printer.print(
225225
"""
@@ -243,7 +243,7 @@ extension JNISwift2JavaGenerator {
243243

244244
let translatedSignature = translatedDecl.translatedFunctionSignature
245245
let resultType = translatedSignature.resultType.javaType
246-
var parameters = translatedDecl.translatedFunctionSignature.parameters.map(\.parameter.asParameter)
246+
var parameters = translatedDecl.translatedFunctionSignature.parameters.map({ $0.parameter.renderParameter() })
247247
if translatedSignature.requiresSwiftArena {
248248
parameters.append("SwiftArena swiftArena$")
249249
}

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,12 +300,24 @@ extension JNISwift2JavaGenerator {
300300

301301
struct TranslatedFunctionSignature {
302302
let selfParameter: TranslatedParameter?
303+
var annotations: [JavaAnnotation] = []
303304
let parameters: [TranslatedParameter]
304305
let resultType: TranslatedResult
305306

306307
var requiresSwiftArena: Bool {
307308
return self.resultType.conversion.requiresSwiftArena
308309
}
310+
311+
init(selfParameter: TranslatedParameter?,
312+
parameters: [TranslatedParameter],
313+
resultType: TranslatedResult) {
314+
self.selfParameter = selfParameter
315+
// if the result type implied any annotations,
316+
// propagate them onto the function the result is returned from
317+
self.annotations = resultType.annotations
318+
self.parameters = parameters
319+
self.resultType = resultType
320+
}
309321
}
310322

311323
/// Represent a Swift API parameter translated to Java.
@@ -318,6 +330,9 @@ extension JNISwift2JavaGenerator {
318330
struct TranslatedResult {
319331
let javaType: JavaType
320332

333+
/// Java annotations that should be propagated from the result type onto the method
334+
var annotations: [JavaAnnotation] = []
335+
321336
/// Represents how to convert the Java native result into a user-facing result.
322337
let conversion: JavaNativeConversionStep
323338
}

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,19 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
import JavaTypes
16+
import JavaKitConfigurationShared
1617

1718
/// A table that where keys are Swift class names and the values are
1819
/// the fully qualified canoical names.
1920
package typealias JavaClassLookupTable = [String: String]
2021

2122
package class JNISwift2JavaGenerator: Swift2JavaGenerator {
23+
24+
let logger: Logger
25+
let config: Configuration
2226
let analysis: AnalysisResult
2327
let swiftModuleName: String
2428
let javaPackage: String
25-
let logger: Logger
2629
let swiftOutputDirectory: String
2730
let javaOutputDirectory: String
2831

@@ -42,12 +45,14 @@ package class JNISwift2JavaGenerator: Swift2JavaGenerator {
4245
var expectedOutputSwiftFiles: Set<String>
4346

4447
package init(
48+
config: Configuration,
4549
translator: Swift2JavaTranslator,
4650
javaPackage: String,
4751
swiftOutputDirectory: String,
4852
javaOutputDirectory: String,
4953
javaClassLookupTable: JavaClassLookupTable
5054
) {
55+
self.config = config
5156
self.logger = Logger(label: "jni-generator", logLevel: translator.log.logLevel)
5257
self.analysis = translator.result
5358
self.swiftModuleName = translator.swiftModuleName

Sources/JExtractSwiftLib/JavaParameter.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,20 @@ import JavaTypes
1818
struct JavaParameter {
1919
let name: String
2020
let type: JavaType
21+
let annotations: [JavaAnnotation]
2122

22-
var asParameter: String {
23-
"\(type) \(name)"
23+
init(name: String, type: JavaType, annotations: [JavaAnnotation] = []) {
24+
self.name = name
25+
self.type = type
26+
self.annotations = annotations
27+
}
28+
29+
func renderParameter() -> String {
30+
if annotations.isEmpty {
31+
return "\(type) \(name)"
32+
}
33+
34+
let annotationsStr = annotations.map({$0.render()}).joined(separator: "")
35+
return "\(annotationsStr) \(type) \(name)"
2436
}
2537
}

0 commit comments

Comments
 (0)