Skip to content

Commit 61659cb

Browse files
authored
BridgeJS: Fix codegen for Float/Double raw value enums in struct fields and optional context (#533)
1 parent 42fc8b3 commit 61659cb

File tree

11 files changed

+569
-4
lines changed

11 files changed

+569
-4
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,11 @@ struct StackCodegen {
784784
case .string:
785785
return
786786
"\(raw: enumName).bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32())"
787-
case .bool, .int, .int32, .int64, .uint, .uint32, .uint64, .float, .double:
787+
case .float:
788+
return "\(raw: enumName).bridgeJSLiftParameter(_swift_js_pop_param_f32())"
789+
case .double:
790+
return "\(raw: enumName).bridgeJSLiftParameter(_swift_js_pop_param_f64())"
791+
case .bool, .int, .int32, .int64, .uint, .uint32, .uint64:
788792
return "\(raw: enumName).bridgeJSLiftParameter(_swift_js_pop_param_int32())"
789793
}
790794
case .associatedValueEnum(let enumName):
@@ -825,7 +829,13 @@ struct StackCodegen {
825829
case .string:
826830
return
827831
"Optional<\(raw: enumName)>.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32(), _swift_js_pop_param_int32())"
828-
case .bool, .int, .float, .double, .int32, .int64, .uint, .uint32, .uint64:
832+
case .float:
833+
return
834+
"Optional<\(raw: enumName)>.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_f32())"
835+
case .double:
836+
return
837+
"Optional<\(raw: enumName)>.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_f64())"
838+
case .bool, .int, .int32, .int64, .uint, .uint32, .uint64:
829839
return
830840
"Optional<\(raw: enumName)>.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32())"
831841
}
@@ -880,8 +890,20 @@ struct StackCodegen {
880890
return ["_swift_js_push_int(\(raw: accessor).bridgeJSLowerParameter())"]
881891
case .caseEnum:
882892
return ["_swift_js_push_int(Int32(\(raw: accessor).bridgeJSLowerParameter()))"]
883-
case .rawValueEnum:
884-
return ["_swift_js_push_int(Int32(\(raw: accessor).bridgeJSLowerParameter()))"]
893+
case .rawValueEnum(_, let rawType):
894+
switch rawType {
895+
case .string:
896+
return [
897+
"var __bjs_\(raw: varPrefix) = \(raw: accessor).rawValue",
898+
"__bjs_\(raw: varPrefix).withUTF8 { ptr in _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) }",
899+
]
900+
case .float:
901+
return ["_swift_js_push_f32(\(raw: accessor).bridgeJSLowerParameter())"]
902+
case .double:
903+
return ["_swift_js_push_f64(\(raw: accessor).bridgeJSLowerParameter())"]
904+
default:
905+
return ["_swift_js_push_int(Int32(\(raw: accessor).bridgeJSLowerParameter()))"]
906+
}
885907
case .associatedValueEnum:
886908
return ["\(raw: accessor).bridgeJSLowerReturn()"]
887909
case .swiftStruct:
@@ -948,6 +970,10 @@ struct StackCodegen {
948970
"var __bjs_str_\(raw: varPrefix) = \(raw: unwrappedVar).rawValue",
949971
"__bjs_str_\(raw: varPrefix).withUTF8 { ptr in _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) }",
950972
]
973+
case .float:
974+
return ["_swift_js_push_f32(\(raw: unwrappedVar).bridgeJSLowerParameter())"]
975+
case .double:
976+
return ["_swift_js_push_f64(\(raw: unwrappedVar).bridgeJSLowerParameter())"]
951977
default:
952978
return ["_swift_js_push_int(\(raw: unwrappedVar).bridgeJSLowerParameter())"]
953979
}

Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2357,6 +2357,32 @@ struct IntrinsicJSFragment: Sendable {
23572357
"if(\(idVar) !== undefined) { \(JSGlueVariableScope.reservedSwift).memory.release(\(idVar)); }"
23582358
)
23592359
return [idVar]
2360+
case .float:
2361+
printer.write("if (\(isSomeVar)) {")
2362+
printer.indent {
2363+
printer.write(
2364+
"\(JSGlueVariableScope.reservedTmpParamF32s).push(Math.fround(\(value)));"
2365+
)
2366+
}
2367+
printer.write("} else {")
2368+
printer.indent {
2369+
printer.write("\(JSGlueVariableScope.reservedTmpParamF32s).push(0.0);")
2370+
}
2371+
printer.write("}")
2372+
printer.write("\(JSGlueVariableScope.reservedTmpParamInts).push(\(isSomeVar) ? 1 : 0);")
2373+
return []
2374+
case .double:
2375+
printer.write("if (\(isSomeVar)) {")
2376+
printer.indent {
2377+
printer.write("\(JSGlueVariableScope.reservedTmpParamF64s).push(\(value));")
2378+
}
2379+
printer.write("} else {")
2380+
printer.indent {
2381+
printer.write("\(JSGlueVariableScope.reservedTmpParamF64s).push(0.0);")
2382+
}
2383+
printer.write("}")
2384+
printer.write("\(JSGlueVariableScope.reservedTmpParamInts).push(\(isSomeVar) ? 1 : 0);")
2385+
return []
23602386
default:
23612387
printer.write("if (\(isSomeVar)) {")
23622388
printer.indent {
@@ -2596,6 +2622,22 @@ struct IntrinsicJSFragment: Sendable {
25962622
return [idVar]
25972623
}
25982624
)
2625+
case .float:
2626+
return IntrinsicJSFragment(
2627+
parameters: ["value"],
2628+
printCode: { arguments, scope, printer, cleanup in
2629+
printer.write("\(JSGlueVariableScope.reservedTmpParamF32s).push(Math.fround(\(arguments[0])));")
2630+
return []
2631+
}
2632+
)
2633+
case .double:
2634+
return IntrinsicJSFragment(
2635+
parameters: ["value"],
2636+
printCode: { arguments, scope, printer, cleanup in
2637+
printer.write("\(JSGlueVariableScope.reservedTmpParamF64s).push(\(arguments[0]));")
2638+
return []
2639+
}
2640+
)
25992641
default:
26002642
return IntrinsicJSFragment(
26012643
parameters: ["value"],
@@ -2795,6 +2837,24 @@ struct IntrinsicJSFragment: Sendable {
27952837
return [varName]
27962838
}
27972839
)
2840+
case .float:
2841+
return IntrinsicJSFragment(
2842+
parameters: [],
2843+
printCode: { arguments, scope, printer, cleanup in
2844+
let varName = scope.variable("value")
2845+
printer.write("const \(varName) = \(JSGlueVariableScope.reservedTmpRetF32s).pop();")
2846+
return [varName]
2847+
}
2848+
)
2849+
case .double:
2850+
return IntrinsicJSFragment(
2851+
parameters: [],
2852+
printCode: { arguments, scope, printer, cleanup in
2853+
let varName = scope.variable("value")
2854+
printer.write("const \(varName) = \(JSGlueVariableScope.reservedTmpRetF64s).pop();")
2855+
return [varName]
2856+
}
2857+
)
27982858
default:
27992859
return IntrinsicJSFragment(
28002860
parameters: [],

Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/SwiftStruct.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@
3535

3636
@JS func roundtrip(_ session: Person) -> Person
3737

38+
@JS enum Precision: Float {
39+
case rough = 0.1
40+
case fine = 0.001
41+
}
42+
43+
@JS struct Measurement {
44+
var value: Double
45+
var precision: Precision
46+
var optionalPrecision: Precision?
47+
}
48+
3849
@JS struct ConfigStruct {
3950
@JS static let maxRetries: Int = 3
4051
@JS nonisolated(unsafe) static var defaultConfig: String = "production"

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.Export.d.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
// To update this file, just rebuild your project or run
55
// `swift package bridge-js`.
66

7+
export const PrecisionValues: {
8+
readonly Rough: 0.1;
9+
readonly Fine: 0.001;
10+
};
11+
export type PrecisionTag = typeof PrecisionValues[keyof typeof PrecisionValues];
12+
713
export interface DataPoint {
814
x: number;
915
y: number;
@@ -26,8 +32,15 @@ export interface Session {
2632
id: number;
2733
owner: Greeter;
2834
}
35+
export interface Measurement {
36+
value: number;
37+
precision: PrecisionTag;
38+
optionalPrecision: PrecisionTag | null;
39+
}
2940
export interface ConfigStruct {
3041
}
42+
export type PrecisionObject = typeof PrecisionValues;
43+
3144
/// Represents a Swift heap object like a class instance or an actor instance.
3245
export interface SwiftHeapObject {
3346
/// Release the heap object.
@@ -44,6 +57,7 @@ export type Exports = {
4457
new(name: string): Greeter;
4558
}
4659
roundtrip(session: Person): Person;
60+
Precision: PrecisionObject
4761
DataPoint: {
4862
init(x: number, y: number, label: string, optCount: number | null, optFlag: boolean | null): DataPoint;
4963
}

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.Export.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
// To update this file, just rebuild your project or run
55
// `swift package bridge-js`.
66

7+
export const PrecisionValues = {
8+
Rough: 0.1,
9+
Fine: 0.001,
10+
};
11+
712
export async function createInstantiator(options, swift) {
813
let instance;
914
let memory;
@@ -184,6 +189,35 @@ export async function createInstantiator(options, swift) {
184189
}
185190
});
186191
};
192+
const __bjs_createMeasurementHelpers = () => {
193+
return (tmpParamInts, tmpParamF32s, tmpParamF64s, tmpParamPointers, tmpRetPointers, textEncoder, swift, enumHelpers) => ({
194+
lower: (value) => {
195+
tmpParamF64s.push(value.value);
196+
tmpParamF32s.push(Math.fround(value.precision));
197+
const isSome = value.optionalPrecision != null;
198+
if (isSome) {
199+
tmpParamF32s.push(Math.fround(value.optionalPrecision));
200+
} else {
201+
tmpParamF32s.push(0.0);
202+
}
203+
tmpParamInts.push(isSome ? 1 : 0);
204+
return { cleanup: undefined };
205+
},
206+
raise: (tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetPointers) => {
207+
const isSome = tmpRetInts.pop();
208+
let optional;
209+
if (isSome) {
210+
const value = tmpRetF32s.pop();
211+
optional = value;
212+
} else {
213+
optional = null;
214+
}
215+
const value1 = tmpRetF32s.pop();
216+
const f64 = tmpRetF64s.pop();
217+
return { value: f64, precision: value1, optionalPrecision: optional };
218+
}
219+
});
220+
};
187221
const __bjs_createConfigStructHelpers = () => {
188222
return (tmpParamInts, tmpParamF32s, tmpParamF64s, tmpParamPointers, tmpRetPointers, textEncoder, swift, enumHelpers) => ({
189223
lower: (value) => {
@@ -315,6 +349,17 @@ export async function createInstantiator(options, swift) {
315349
const value = structHelpers.Session.raise(tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetPointers);
316350
return swift.memory.retain(value);
317351
}
352+
bjs["swift_js_struct_lower_Measurement"] = function(objectId) {
353+
const { cleanup: cleanup } = structHelpers.Measurement.lower(swift.memory.getObject(objectId));
354+
if (cleanup) {
355+
return tmpStructCleanups.push(cleanup);
356+
}
357+
return 0;
358+
}
359+
bjs["swift_js_struct_raise_Measurement"] = function() {
360+
const value = structHelpers.Measurement.raise(tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetPointers);
361+
return swift.memory.retain(value);
362+
}
318363
bjs["swift_js_struct_lower_ConfigStruct"] = function(objectId) {
319364
const { cleanup: cleanup } = structHelpers.ConfigStruct.lower(swift.memory.getObject(objectId));
320365
if (cleanup) {
@@ -498,6 +543,9 @@ export async function createInstantiator(options, swift) {
498543
const SessionHelpers = __bjs_createSessionHelpers()(tmpParamInts, tmpParamF32s, tmpParamF64s, tmpParamPointers, tmpRetPointers, textEncoder, swift, enumHelpers);
499544
structHelpers.Session = SessionHelpers;
500545

546+
const MeasurementHelpers = __bjs_createMeasurementHelpers()(tmpParamInts, tmpParamF32s, tmpParamF64s, tmpParamPointers, tmpRetPointers, textEncoder, swift, enumHelpers);
547+
structHelpers.Measurement = MeasurementHelpers;
548+
501549
const ConfigStructHelpers = __bjs_createConfigStructHelpers()(tmpParamInts, tmpParamF32s, tmpParamF64s, tmpParamPointers, tmpRetPointers, textEncoder, swift, enumHelpers);
502550
structHelpers.ConfigStruct = ConfigStructHelpers;
503551

@@ -510,6 +558,7 @@ export async function createInstantiator(options, swift) {
510558
if (cleanup) { cleanup(); }
511559
return structValue;
512560
},
561+
Precision: PrecisionValues,
513562
DataPoint: {
514563
init: function(x, y, label, optCount, optFlag) {
515564
const labelBytes = textEncoder.encode(label);

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/SwiftStruct.json

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,35 @@
5656
}
5757
],
5858
"enums" : [
59+
{
60+
"cases" : [
61+
{
62+
"associatedValues" : [
63+
64+
],
65+
"name" : "rough",
66+
"rawValue" : "0.1"
67+
},
68+
{
69+
"associatedValues" : [
70+
71+
],
72+
"name" : "fine",
73+
"rawValue" : "0.001"
74+
}
75+
],
76+
"emitStyle" : "const",
77+
"name" : "Precision",
78+
"rawType" : "Float",
79+
"staticMethods" : [
80+
81+
],
82+
"staticProperties" : [
5983

84+
],
85+
"swiftCallName" : "Precision",
86+
"tsFullPath" : "Precision"
87+
}
6088
],
6189
"exposeToGlobal" : false,
6290
"functions" : [
@@ -345,6 +373,51 @@
345373
],
346374
"swiftCallName" : "Session"
347375
},
376+
{
377+
"methods" : [
378+
379+
],
380+
"name" : "Measurement",
381+
"properties" : [
382+
{
383+
"isReadonly" : true,
384+
"isStatic" : false,
385+
"name" : "value",
386+
"type" : {
387+
"double" : {
388+
389+
}
390+
}
391+
},
392+
{
393+
"isReadonly" : true,
394+
"isStatic" : false,
395+
"name" : "precision",
396+
"type" : {
397+
"rawValueEnum" : {
398+
"_0" : "Precision",
399+
"_1" : "Float"
400+
}
401+
}
402+
},
403+
{
404+
"isReadonly" : true,
405+
"isStatic" : false,
406+
"name" : "optionalPrecision",
407+
"type" : {
408+
"optional" : {
409+
"_0" : {
410+
"rawValueEnum" : {
411+
"_0" : "Precision",
412+
"_1" : "Float"
413+
}
414+
}
415+
}
416+
}
417+
}
418+
],
419+
"swiftCallName" : "Measurement"
420+
},
348421
{
349422
"methods" : [
350423
{

0 commit comments

Comments
 (0)