Skip to content

Commit 788ad44

Browse files
[NFC] BridgeJS: Make JSGlueGen and IntrinsicJSFragment methods throwable
Instead of crashing on errors in JS code generation for BridgeJSLink, we should prefer propagating errors.
1 parent 3a22f4d commit 788ad44

File tree

3 files changed

+173
-165
lines changed

3 files changed

+173
-165
lines changed

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 39 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -261,19 +261,19 @@ public struct BridgeJSLink {
261261
]
262262
}
263263

264-
private func generateAddImports(needsImportsObject: Bool) -> CodeFragmentPrinter {
264+
private func generateAddImports(needsImportsObject: Bool) throws -> CodeFragmentPrinter {
265265
let printer = CodeFragmentPrinter()
266266
let allStructs = skeletons.compactMap { $0.exported?.structs }.flatMap { $0 }
267267
printer.write("return {")
268-
printer.indent {
268+
try printer.indent {
269269
printer.write(lines: [
270270
"/**",
271271
" * @param {WebAssembly.Imports} importObject",
272272
" */",
273273
"addImports: (importObject, importsContext) => {",
274274
])
275275

276-
printer.indent {
276+
try printer.indent {
277277
printer.write(lines: [
278278
"bjs = {};",
279279
"importObject[\"bjs\"] = bjs;",
@@ -687,20 +687,21 @@ public struct BridgeJSLink {
687687

688688
for signature in closureSignatures.sorted(by: { $0.mangleName < $1.mangleName }) {
689689
let invokeFuncName = "invoke_js_callback_\(moduleName)_\(signature.mangleName)"
690-
printer.write(
691-
lines: generateInvokeFunction(
692-
signature: signature,
693-
functionName: invokeFuncName
694-
)
690+
let invokeLines = try generateInvokeFunction(
691+
signature: signature,
692+
functionName: invokeFuncName
695693
)
694+
printer.write(lines: invokeLines)
696695

697696
let lowerFuncName = "lower_closure_\(moduleName)_\(signature.mangleName)"
698697
let makeFuncName = "make_swift_closure_\(moduleName)_\(signature.mangleName)"
699698
printer.write("bjs[\"\(makeFuncName)\"] = function(boxPtr, file, line) {")
700-
printer.indent {
701-
printer.write(
702-
lines: generateLowerClosureFunction(signature: signature, functionName: lowerFuncName)
699+
try printer.indent {
700+
let lowerLines = try generateLowerClosureFunction(
701+
signature: signature,
702+
functionName: lowerFuncName
703703
)
704+
printer.write(lines: lowerLines)
704705
printer.write(
705706
"return \(JSGlueVariableScope.reservedMakeSwiftClosure)(boxPtr, file, line, \(lowerFuncName));"
706707
)
@@ -788,7 +789,7 @@ public struct BridgeJSLink {
788789
private func generateInvokeFunction(
789790
signature: ClosureSignature,
790791
functionName: String
791-
) -> [String] {
792+
) throws -> [String] {
792793
let printer = CodeFragmentPrinter()
793794
let scope = JSGlueVariableScope(intrinsicRegistry: intrinsicRegistry)
794795
let cleanupCode = CodeFragmentPrinter()
@@ -806,20 +807,20 @@ public struct BridgeJSLink {
806807

807808
printer.nextLine()
808809
printer.write("bjs[\"\(functionName)\"] = function(\(invokeParams.joined(separator: ", "))) {")
809-
printer.indent {
810+
try printer.indent {
810811
printer.write("try {")
811-
printer.indent {
812+
try printer.indent {
812813
printer.write("const callback = \(JSGlueVariableScope.reservedSwift).memory.getObject(callbackId);")
813814

814815
for (index, paramType) in signature.parameters.enumerated() {
815-
let fragment = try! IntrinsicJSFragment.closureLiftParameter(type: paramType)
816+
let fragment = try IntrinsicJSFragment.closureLiftParameter(type: paramType)
816817
let args: [String]
817818
if case .nullable = paramType {
818819
args = ["param\(index)IsSome", "param\(index)Value", "param\(index)"]
819820
} else {
820821
args = ["param\(index)Id", "param\(index)"]
821822
}
822-
_ = fragment.printCode(args, scope, printer, cleanupCode)
823+
_ = try fragment.printCode(args, scope, printer, cleanupCode)
823824
}
824825

825826
let callbackParams = signature.parameters.indices.map { "param\($0)" }.joined(separator: ", ")
@@ -837,14 +838,14 @@ public struct BridgeJSLink {
837838
break
838839
}
839840

840-
let returnFragment = try! IntrinsicJSFragment.closureLowerReturn(type: signature.returnType)
841-
_ = returnFragment.printCode(["result"], scope, printer, cleanupCode)
841+
let returnFragment = try IntrinsicJSFragment.closureLowerReturn(type: signature.returnType)
842+
_ = try returnFragment.printCode(["result"], scope, printer, cleanupCode)
842843
}
843844
printer.write("} catch (error) {")
844-
printer.indent {
845+
try printer.indent {
845846
printer.write("\(JSGlueVariableScope.reservedSetException)?.(error);")
846847
let errorFragment = IntrinsicJSFragment.closureErrorReturn(type: signature.returnType)
847-
_ = errorFragment.printCode([], scope, printer, cleanupCode)
848+
_ = try errorFragment.printCode([], scope, printer, cleanupCode)
848849
}
849850
printer.write("}")
850851
}
@@ -857,21 +858,21 @@ public struct BridgeJSLink {
857858
private func generateLowerClosureFunction(
858859
signature: ClosureSignature,
859860
functionName: String
860-
) -> [String] {
861+
) throws -> [String] {
861862
let printer = CodeFragmentPrinter()
862863
let scope = JSGlueVariableScope(intrinsicRegistry: intrinsicRegistry)
863864
let cleanupCode = CodeFragmentPrinter()
864865

865866
printer.write(
866867
"const \(functionName) = function(\(signature.parameters.indices.map { "param\($0)" }.joined(separator: ", "))) {"
867868
)
868-
printer.indent {
869+
try printer.indent {
869870
var invokeArgs: [String] = ["boxPtr"]
870871

871872
for (index, paramType) in signature.parameters.enumerated() {
872873
let paramName = "param\(index)"
873-
let fragment = try! IntrinsicJSFragment.lowerParameter(type: paramType)
874-
let lowered = fragment.printCode([paramName], scope, printer, cleanupCode)
874+
let fragment = try IntrinsicJSFragment.lowerParameter(type: paramType)
875+
let lowered = try fragment.printCode([paramName], scope, printer, cleanupCode)
875876
invokeArgs.append(contentsOf: lowered)
876877
}
877878

@@ -894,8 +895,8 @@ public struct BridgeJSLink {
894895
}
895896
printer.write("}")
896897

897-
let returnFragment = try! IntrinsicJSFragment.closureLiftReturn(type: signature.returnType)
898-
_ = returnFragment.printCode([invokeResultName], scope, printer, cleanupCode)
898+
let returnFragment = try IntrinsicJSFragment.closureLiftReturn(type: signature.returnType)
899+
_ = try returnFragment.printCode([invokeResultName], scope, printer, cleanupCode)
899900
}
900901
printer.write("};")
901902

@@ -1073,7 +1074,7 @@ public struct BridgeJSLink {
10731074
// Main function declaration
10741075
printer.write("export async function createInstantiator(options, \(JSGlueVariableScope.reservedSwift)) {")
10751076

1076-
printer.indent {
1077+
try printer.indent {
10771078
printer.write(lines: generateVariableDeclarations())
10781079

10791080
let bodyPrinter = CodeFragmentPrinter()
@@ -1083,7 +1084,7 @@ public struct BridgeJSLink {
10831084
let structScope = JSGlueVariableScope(intrinsicRegistry: intrinsicRegistry)
10841085
let structCleanup = CodeFragmentPrinter()
10851086
let fragment = IntrinsicJSFragment.structHelper(structDefinition: structDef, allStructs: allStructs)
1086-
_ = fragment.printCode([structDef.name], structScope, structPrinter, structCleanup)
1087+
_ = try fragment.printCode([structDef.name], structScope, structPrinter, structCleanup)
10871088
bodyPrinter.write(lines: structPrinter.lines)
10881089
}
10891090

@@ -1095,11 +1096,11 @@ public struct BridgeJSLink {
10951096
let enumScope = JSGlueVariableScope(intrinsicRegistry: intrinsicRegistry)
10961097
let enumCleanup = CodeFragmentPrinter()
10971098
let fragment = IntrinsicJSFragment.associatedValueEnumHelperFactory(enumDefinition: enumDef)
1098-
_ = fragment.printCode([enumDef.valuesName], enumScope, enumPrinter, enumCleanup)
1099+
_ = try fragment.printCode([enumDef.valuesName], enumScope, enumPrinter, enumCleanup)
10991100
bodyPrinter.write(lines: enumPrinter.lines)
11001101
}
11011102
bodyPrinter.nextLine()
1102-
bodyPrinter.write(contentsOf: generateAddImports(needsImportsObject: data.needsImportsObject))
1103+
bodyPrinter.write(contentsOf: try generateAddImports(needsImportsObject: data.needsImportsObject))
11031104

11041105
if !intrinsicRegistry.isEmpty {
11051106
printer.write(lines: intrinsicRegistry.emitLines())
@@ -1356,7 +1357,7 @@ public struct BridgeJSLink {
13561357
loweringFragment.parameters.count == 1,
13571358
"Lowering fragment should have exactly one parameter to lower"
13581359
)
1359-
let loweredValues = loweringFragment.printCode([param.name], scope, body, cleanupCode)
1360+
let loweredValues = try loweringFragment.printCode([param.name], scope, body, cleanupCode)
13601361
parameterForwardings.append(contentsOf: loweredValues)
13611362
}
13621363

@@ -1388,7 +1389,7 @@ public struct BridgeJSLink {
13881389
body.write("const \(returnVariable) = \(call);")
13891390
fragmentArguments = [returnVariable]
13901391
}
1391-
let liftedValues = liftingFragment.printCode(fragmentArguments, scope, body, cleanupCode)
1392+
let liftedValues = try liftingFragment.printCode(fragmentArguments, scope, body, cleanupCode)
13921393
assert(liftedValues.count <= 1, "Lifting fragment should produce at most one value")
13931394
return liftedValues.first
13941395
}
@@ -1646,19 +1647,19 @@ public struct BridgeJSLink {
16461647
switch enumDefinition.enumType {
16471648
case .simple:
16481649
let fragment = IntrinsicJSFragment.simpleEnumHelper(enumDefinition: enumDefinition)
1649-
_ = fragment.printCode([enumValuesName], scope, printer, cleanup)
1650+
_ = try fragment.printCode([enumValuesName], scope, printer, cleanup)
16501651
jsTopLevelLines.append(contentsOf: printer.lines)
16511652
case .rawValue:
16521653
guard enumDefinition.rawType != nil else {
16531654
throw BridgeJSLinkError(message: "Raw value enum \(enumDefinition.name) is missing rawType")
16541655
}
16551656

16561657
let fragment = IntrinsicJSFragment.rawValueEnumHelper(enumDefinition: enumDefinition)
1657-
_ = fragment.printCode([enumValuesName], scope, printer, cleanup)
1658+
_ = try fragment.printCode([enumValuesName], scope, printer, cleanup)
16581659
jsTopLevelLines.append(contentsOf: printer.lines)
16591660
case .associatedValue:
16601661
let fragment = IntrinsicJSFragment.associatedValueEnumValues(enumDefinition: enumDefinition)
1661-
_ = fragment.printCode([enumValuesName], scope, printer, cleanup)
1662+
_ = try fragment.printCode([enumValuesName], scope, printer, cleanup)
16621663
jsTopLevelLines.append(contentsOf: printer.lines)
16631664
case .namespace:
16641665
break
@@ -2252,7 +2253,7 @@ extension BridgeJSLink {
22522253
valuesToLift = liftingFragment.parameters.map { scope.variable(param.name + $0.capitalizedFirstLetter) }
22532254
parameterNames.append(contentsOf: valuesToLift)
22542255
}
2255-
let liftedValues = liftingFragment.printCode(valuesToLift, scope, body, cleanupCode)
2256+
let liftedValues = try liftingFragment.printCode(valuesToLift, scope, body, cleanupCode)
22562257
assert(liftedValues.count == 1, "Lifting fragment should produce exactly one value")
22572258
parameterForwardings.append(contentsOf: liftedValues)
22582259
}
@@ -2362,7 +2363,7 @@ extension BridgeJSLink {
23622363
)
23632364

23642365
let fragment = try IntrinsicJSFragment.protocolPropertyOptionalToSideChannel(wrappedType: wrappedType)
2365-
_ = fragment.printCode([resultVar], scope, body, cleanupCode)
2366+
_ = try fragment.printCode([resultVar], scope, body, cleanupCode)
23662367

23672368
return nil // Side-channel types return nil (no direct return value)
23682369
}
@@ -2415,7 +2416,7 @@ extension BridgeJSLink {
24152416
loweringFragment: IntrinsicJSFragment
24162417
) throws -> String? {
24172418
assert(loweringFragment.parameters.count <= 1, "Lowering fragment should have at most one parameter")
2418-
let loweredValues = loweringFragment.printCode(returnExpr.map { [$0] } ?? [], scope, body, cleanupCode)
2419+
let loweredValues = try loweringFragment.printCode(returnExpr.map { [$0] } ?? [], scope, body, cleanupCode)
24192420
assert(loweredValues.count <= 1, "Lowering fragment should produce at most one value")
24202421
return loweredValues.first
24212422
}

Plugins/BridgeJS/Sources/BridgeJSLink/CodeFragmentPrinter.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ final class JSIntrinsicRegistry {
66
entries.isEmpty
77
}
88

9-
func register(name: String, build: (CodeFragmentPrinter) -> Void) {
9+
func register(name: String, build: (CodeFragmentPrinter) throws -> Void) rethrows {
1010
guard entries[name] == nil else { return }
1111
let printer = CodeFragmentPrinter()
12-
build(printer)
12+
try build(printer)
1313
entries[name] = printer.lines
1414
}
1515

0 commit comments

Comments
 (0)