Skip to content

Commit f742aba

Browse files
committed
testkit: improve output assertion tools for jextract testing
1 parent 47aaa01 commit f742aba

File tree

16 files changed

+472
-159
lines changed

16 files changed

+472
-159
lines changed

Samples/JExtractPluginSampleApp/Sources/JExtractPluginSampleLib/MyCoolSwiftClass.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
public class MyCoolSwiftClass {
16-
public init(number: Int) {}
17-
public func exposedToJava() { }
16+
var number: Int
17+
public init(number: Int) {
18+
print("[swift] init(number: \(number))")
19+
self.number = number
20+
}
21+
22+
public func exposedToJava() {
23+
print("[swift] exposedToJava()")
24+
print("[swift] number = \(number)")
25+
}
1826
}

Samples/JExtractPluginSampleApp/build.gradle

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ def buildSwift = tasks.register("swiftBuildProject", Exec) {
5858
inputs.file(new File(rootDir, "Package.swift"))
5959
inputs.dir(new File(rootDir, "Sources"))
6060

61-
// TODO: we can use package describe --type json to figure out which targets depend on JExtractSwiftPlugin and will produce outputs
6261
inputs.file(layout.projectDirectory.file("Package.swift"))
6362
inputs.dir(layout.projectDirectory.dir("Sources"))
6463

65-
// outputs.dir(layout.buildDirectory.dir("../.build/plugins/outputs/${layout.projectDirectory.asFile.getName().toLowerCase()}/JExtractPluginSampleLib/destination/JExtractSwiftPlugin/src/generated/java"))
64+
// TODO: we can use package describe --type json to figure out which targets depend on JExtractSwiftPlugin and will produce outputs
65+
// Avoid adding this directory, but create the expected one specifically for all targets which WILL produce sources because they have the plugin
6666
outputs.dir(layout.buildDirectory.dir("../.build/plugins/outputs/${layout.projectDirectory.asFile.getName().toLowerCase()}"))
6767

6868
File baseSwiftPluginOutputsDir = layout.buildDirectory.dir("../.build/plugins/outputs/").get().asFile
@@ -72,7 +72,6 @@ def buildSwift = tasks.register("swiftBuildProject", Exec) {
7272
Files.walk(layout.buildDirectory.dir("../.build/plugins/outputs/").get().asFile.toPath()).each {
7373
if (it.endsWith("JExtractSwiftPlugin/src/generated/java")) {
7474
outputs.dir(it)
75-
println("OUTPUT = ${it}")
7675
}
7776
}
7877

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../gradlew
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../gradlew.bat

Samples/JavaSieve/Sources/JavaSieve/main.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
import JavaKit
16+
import JavaMath
1617

1718
let jvm = try JavaVirtualMachine.shared(classPath: ["QuadraticSieve-1.0.jar"])
1819
do {
1920
let sieveClass = try JavaClass<SieveOfEratosthenes>(environment: jvm.environment())
2021
for prime in sieveClass.findPrimes(100)! {
2122
print("Found prime: \(prime.intValue())")
2223
}
24+
25+
try JavaClass<RoundingMode>().HALF_UP
2326
} catch {
2427
print("Failure: \(error)")
2528
}

Sources/JExtractSwift/CodePrinter.swift

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,19 @@ public struct CodePrinter {
3434
}
3535
public var indentationText: String = ""
3636

37-
public static func toString(_ block: (inout CodePrinter) -> ()) -> String {
37+
public static func toString(_ block: (inout CodePrinter) throws -> ()) rethrows -> String {
3838
var printer = CodePrinter()
39-
block(&printer)
39+
try block(&printer)
4040
return printer.finalize()
4141
}
4242

43-
public init() {
44-
43+
var ioMode: PrintMode
44+
public enum PrintMode {
45+
case accumulateAll
46+
case flushToFileOnWrite
47+
}
48+
public init(io: PrintMode = .flushToFileOnWrite) {
49+
self.ioMode = .accumulateAll
4550
}
4651

4752
internal mutating func append(_ text: String) {
@@ -91,6 +96,16 @@ public struct CodePrinter {
9196
}
9297
}
9398

99+
/// Print a plain newline, e.g. to separate declarations.
100+
public mutating func println(
101+
_ terminator: PrinterTerminator = .newLine,
102+
function: String = #function,
103+
file: String = #fileID,
104+
line: UInt = #line
105+
) {
106+
print("")
107+
}
108+
94109
public mutating func print(
95110
_ text: Any,
96111
_ terminator: PrinterTerminator = .newLine,
@@ -159,6 +174,12 @@ public struct CodePrinter {
159174
public var isEmpty: Bool {
160175
self.contents.isEmpty
161176
}
177+
178+
public mutating func dump(file: String = #fileID, line: UInt = #line) {
179+
Swift.print("// CodePrinter.dump @ \(file):\(line)")
180+
Swift.print(contents)
181+
}
182+
162183
}
163184

164185
public enum PrinterTerminator: String {
@@ -185,3 +206,49 @@ public enum PrinterTerminator: String {
185206
}
186207
}
187208
}
209+
210+
extension CodePrinter {
211+
package mutating func writeContents(
212+
outputDirectory: String,
213+
javaPackagePath: String?,
214+
filename: String
215+
) throws {
216+
guard self.ioMode != .accumulateAll else {
217+
// if we're accumulating everything, we don't want to finalize/flush any contents
218+
// let's mark that this is where a write would have happened though:
219+
print("// ^^^^ Contents of: \(outputDirectory)/\(filename)")
220+
return
221+
}
222+
223+
let contents = finalize()
224+
if outputDirectory == "-" {
225+
print(
226+
"// ==== ---------------------------------------------------------------------------------------------------"
227+
)
228+
if let javaPackagePath {
229+
print("// \(javaPackagePath)/\(filename)")
230+
} else {
231+
print("// \(filename)")
232+
}
233+
print(contents)
234+
return
235+
}
236+
237+
let targetDirectory = [outputDirectory, javaPackagePath].compactMap { $0 }.joined(
238+
separator: PATH_SEPARATOR)
239+
log.trace("Prepare target directory: \(targetDirectory)")
240+
try FileManager.default.createDirectory(
241+
atPath: targetDirectory, withIntermediateDirectories: true)
242+
243+
let targetFilePath = [javaPackagePath, filename].compactMap { $0 }.joined(
244+
separator: PATH_SEPARATOR)
245+
Swift.print("Writing '\(targetFilePath)'...", terminator: "")
246+
try contents.write(
247+
to: Foundation.URL(fileURLWithPath: targetDirectory).appendingPathComponent(filename),
248+
atomically: true,
249+
encoding: .utf8
250+
)
251+
Swift.print(" done.".green)
252+
}
253+
254+
}

Sources/JExtractSwift/ImportedDecls.swift

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,20 @@ extension ImportedParam {
115115
}
116116

117117
// TODO: this is used in different contexts and needs a cleanup
118+
// Perhaps this is "which parameter passing style"?
118119
public enum SelfParameterVariant {
120+
// ==== Java forwarding patterns
121+
119122
/// Make a method that accepts the raw memory pointer as a MemorySegment
120123
case memorySegment
121124
/// Make a method that accepts the the Java wrapper class of the type
122125
case wrapper
123126
/// Raw SWIFT_POINTER
124127
case pointer
128+
129+
// ==== Swift forwarding patterns
130+
131+
case swiftThunkSelf
125132
}
126133

127134
public struct ImportedFunc: ImportedDecl, CustomStringConvertible {
@@ -161,14 +168,14 @@ public struct ImportedFunc: ImportedDecl, CustomStringConvertible {
161168
public var returnType: TranslatedType
162169
public var parameters: [ImportedParam]
163170

164-
public func effectiveParameters(selfVariant: SelfParameterVariant?) -> [ImportedParam] {
171+
public func effectiveParameters(paramPassingStyle: SelfParameterVariant?) -> [ImportedParam] {
165172
if let parent {
166173
var params = parameters
167174

168175
// Add `self: Self` for method calls on a member
169176
//
170177
// allocating initializer takes a Self.Type instead, but it's also a pointer
171-
switch selfVariant {
178+
switch paramPassingStyle {
172179
case nil, .wrapper:
173180
break
174181

@@ -185,6 +192,9 @@ public struct ImportedFunc: ImportedDecl, CustomStringConvertible {
185192
params.append(
186193
ImportedParam(param: selfParam, type: parentForSelf)
187194
)
195+
196+
case .swiftThunkSelf:
197+
break
188198
}
189199

190200
// TODO: add any metadata for generics and other things we may need to add here
@@ -303,24 +313,22 @@ public struct ImportedVariable: ImportedDecl, CustomStringConvertible {
303313
identifier: self.identifier,
304314
returnType: TranslatedType.void,
305315
parameters: [.init(param: newValueParam, type: self.returnType)])
306-
// FIXME: funcDecl.swiftMangledName = self.swiftMangledName + "s" // form mangled name of the getter by adding the suffix
307316
return funcDecl
308317

309318
case .get:
310-
var funcDecl = ImportedFunc(
319+
let funcDecl = ImportedFunc(
311320
module: self.module,
312321
decl: self.syntax!,
313322
parent: self.parentName,
314323
identifier: self.identifier,
315324
returnType: self.returnType,
316325
parameters: [])
317-
// FIXME: funcDecl.swiftMangledName = self.swiftMangledName + "g" // form mangled name of the getter by adding the suffix
318326
return funcDecl
319327
}
320328
}
321329

322330
public func effectiveAccessorParameters(
323-
_ kind: VariableAccessorKind, selfVariant: SelfParameterVariant?
331+
_ kind: VariableAccessorKind, paramPassingStyle: SelfParameterVariant?
324332
) -> [ImportedParam] {
325333
var params: [ImportedParam] = []
326334

@@ -338,10 +346,7 @@ public struct ImportedVariable: ImportedDecl, CustomStringConvertible {
338346
// Add `self: Self` for method calls on a member
339347
//
340348
// allocating initializer takes a Self.Type instead, but it's also a pointer
341-
switch selfVariant {
342-
case nil, .wrapper:
343-
break
344-
349+
switch paramPassingStyle {
345350
case .pointer:
346351
let selfParam: FunctionParameterSyntax = "self$: $swift_pointer"
347352
params.append(
@@ -361,6 +366,11 @@ public struct ImportedVariable: ImportedDecl, CustomStringConvertible {
361366
type: parentForSelf
362367
)
363368
)
369+
370+
case nil,
371+
.wrapper,
372+
.swiftThunkSelf:
373+
break
364374
}
365375
}
366376

Sources/JExtractSwift/Logger.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public struct Logger {
8888
}
8989

9090
let metadataString: String =
91-
metadata.isEmpty ? "\(metadata)" : ""
91+
metadata.isEmpty ? "" : "\(metadata)"
9292

9393
print("[trace][\(file):\(line)](\(function)) \(message()) \(metadataString)")
9494
}

Sources/JExtractSwift/Swift2JavaTranslator+MemoryLayouts.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,16 @@ import SwiftSyntax
2020
extension Swift2JavaTranslator {
2121
public func javaMemoryLayoutDescriptors(
2222
forParametersOf decl: ImportedFunc,
23-
selfVariant: SelfParameterVariant?
23+
paramPassingStyle: SelfParameterVariant?
2424
) -> [ForeignValueLayout] {
2525
var layouts: [ForeignValueLayout] = []
2626
layouts.reserveCapacity(decl.parameters.count + 1)
2727

2828
// // When the method is `init()` it does not accept a self (well, unless allocating init but we don't import those)
29-
// let selfVariant: SelfParameterVariant? =
29+
// let paramPassingStyle: SelfParameterVariant? =
3030
// decl.isInit ? nil : .wrapper
3131

32-
for param in decl.effectiveParameters(selfVariant: selfVariant) {
32+
for param in decl.effectiveParameters(paramPassingStyle: paramPassingStyle) {
3333
layouts.append(param.type.foreignValueLayout)
3434
}
3535

0 commit comments

Comments
 (0)