Skip to content

Commit 7373485

Browse files
committed
changed lowering/lifting to sentinel method
1 parent c753a1e commit 7373485

10 files changed

Lines changed: 674 additions & 1 deletion

File tree

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,6 +1457,8 @@ extension BridgeType {
14571457
case .unsafePointer: return .unsafePointer
14581458
case .swiftProtocol: return .jsObject
14591459
case .void: return .void
1460+
case .nullable(.jsString, _):
1461+
return .jsString
14601462
case .nullable(let wrappedType, _):
14611463
let wrappedInfo = try wrappedType.liftParameterInfo()
14621464
if wrappedInfo.parameters.isEmpty {
@@ -1517,6 +1519,8 @@ extension BridgeType {
15171519
case .unsafePointer: return .unsafePointer
15181520
case .swiftProtocol: return .jsObject
15191521
case .void: return .void
1522+
case .nullable(.jsString, _):
1523+
return .jsString
15201524
case .nullable: return .optional
15211525
case .caseEnum: return .caseEnum
15221526
case .rawValueEnum(_, let rawType):

Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,8 @@ extension BridgeType {
849849
}
850850
case .namespaceEnum:
851851
throw BridgeJSCoreError("Namespace enums cannot be used as parameters")
852+
case .nullable(.jsString, _):
853+
return LoweringParameterInfo(loweredParameters: [("value", .i32)], useBorrowing: true)
852854
case .nullable(let wrappedType, _):
853855
let wrappedInfo = try wrappedType.loweringParameterInfo(context: context)
854856
var params = [("isSome", WasmCoreType.i32)]

Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,15 @@ struct IntrinsicJSFragment: Sendable {
633633
kind: JSOptionalKind,
634634
context bridgeContext: BridgeContext = .importTS
635635
) throws -> IntrinsicJSFragment {
636+
if wrappedType == .jsString {
637+
let innerFragment = try liftParameter(type: wrappedType, context: bridgeContext)
638+
return sentinelOptionalLiftSingleValue(
639+
wrappedType: wrappedType,
640+
kind: kind,
641+
innerFragment: { innerFragment }
642+
)
643+
}
644+
636645
if wrappedType.isSingleParamScalar {
637646
let coerce = wrappedType.liftCoerce
638647
return IntrinsicJSFragment(
@@ -716,6 +725,15 @@ struct IntrinsicJSFragment: Sendable {
716725
wrappedType: BridgeType,
717726
kind: JSOptionalKind
718727
) throws -> IntrinsicJSFragment {
728+
if wrappedType == .jsString {
729+
let innerFragment = try lowerParameter(type: wrappedType)
730+
return sentinelOptionalLowerSingleValue(
731+
wrappedType: wrappedType,
732+
kind: kind,
733+
innerFragment: innerFragment
734+
)
735+
}
736+
719737
if wrappedType.isSingleParamScalar {
720738
let wasmType = wrappedType.wasmParams[0].type
721739
let coerce = wrappedType.lowerCoerce
@@ -807,6 +825,94 @@ struct IntrinsicJSFragment: Sendable {
807825
)
808826
}
809827

828+
private static func sentinelOptionalLiftSingleValue(
829+
wrappedType: BridgeType,
830+
kind: JSOptionalKind,
831+
innerFragment: @escaping @Sendable () throws -> IntrinsicJSFragment
832+
) -> IntrinsicJSFragment {
833+
let sentinelLiteral = wrappedType.nilSentinel.jsLiteral
834+
let absenceLiteral = kind.absenceLiteral
835+
return IntrinsicJSFragment(
836+
parameters: ["wrappedValue"],
837+
printCode: { arguments, context in
838+
let (scope, printer) = (context.scope, context.printer)
839+
let wrappedValue = arguments[0]
840+
841+
let bufferPrinter = CodeFragmentPrinter()
842+
let innerResults = try innerFragment().printCode(
843+
[wrappedValue],
844+
context.with(\.printer, bufferPrinter)
845+
)
846+
let innerExpr = innerResults.first ?? "undefined"
847+
848+
if bufferPrinter.lines.isEmpty {
849+
return ["\(wrappedValue) === \(sentinelLiteral) ? \(absenceLiteral) : \(innerExpr)"]
850+
}
851+
852+
let resultVar = scope.variable("optResult")
853+
printer.write("let \(resultVar);")
854+
printer.write("if (\(wrappedValue) === \(sentinelLiteral)) {")
855+
printer.indent {
856+
printer.write("\(resultVar) = \(absenceLiteral);")
857+
}
858+
printer.write("} else {")
859+
printer.indent {
860+
for line in bufferPrinter.lines {
861+
printer.write(line)
862+
}
863+
printer.write("\(resultVar) = \(innerExpr);")
864+
}
865+
printer.write("}")
866+
return [resultVar]
867+
}
868+
)
869+
}
870+
871+
private static func sentinelOptionalLowerSingleValue(
872+
wrappedType: BridgeType,
873+
kind: JSOptionalKind,
874+
innerFragment: IntrinsicJSFragment
875+
) -> IntrinsicJSFragment {
876+
let sentinelLiteral = wrappedType.nilSentinel.jsLiteral
877+
return IntrinsicJSFragment(
878+
parameters: ["value"],
879+
printCode: { arguments, context in
880+
let (scope, printer) = (context.scope, context.printer)
881+
let value = arguments[0]
882+
let isSomeVar = scope.variable("isSome")
883+
let presenceExpr = kind.presenceCheck(value: value)
884+
printer.write("const \(isSomeVar) = \(presenceExpr);")
885+
886+
let bufferPrinter = CodeFragmentPrinter()
887+
let innerResults = try innerFragment.printCode(
888+
[value],
889+
context.with(\.printer, bufferPrinter)
890+
)
891+
let innerExpr = innerResults.first ?? sentinelLiteral
892+
893+
if bufferPrinter.lines.isEmpty {
894+
return ["\(isSomeVar) ? \(innerExpr) : \(sentinelLiteral)"]
895+
}
896+
897+
let resultVar = scope.variable("optResult")
898+
printer.write("let \(resultVar);")
899+
printer.write("if (\(isSomeVar)) {")
900+
printer.indent {
901+
for line in bufferPrinter.lines {
902+
printer.write(line)
903+
}
904+
printer.write("\(resultVar) = \(innerExpr);")
905+
}
906+
printer.write("} else {")
907+
printer.indent {
908+
printer.write("\(resultVar) = \(sentinelLiteral);")
909+
}
910+
printer.write("}")
911+
return [resultVar]
912+
}
913+
)
914+
}
915+
810916
private static func optionalLiftReturnFromStorage(storage: String) -> IntrinsicJSFragment {
811917
IntrinsicJSFragment(
812918
parameters: [],
@@ -934,6 +1040,14 @@ struct IntrinsicJSFragment: Sendable {
9341040
wrappedType: BridgeType,
9351041
kind: JSOptionalKind
9361042
) -> IntrinsicJSFragment {
1043+
if wrappedType == .jsString {
1044+
return sentinelOptionalLiftSingleValue(
1045+
wrappedType: wrappedType,
1046+
kind: kind,
1047+
innerFragment: { try liftReturn(type: wrappedType) }
1048+
)
1049+
}
1050+
9371051
if let scalarKind = wrappedType.optionalScalarKind {
9381052
return optionalLiftReturnFromStorage(storage: scalarKind.storageName)
9391053
}
@@ -1068,6 +1182,15 @@ struct IntrinsicJSFragment: Sendable {
10681182
)
10691183
}
10701184

1185+
if wrappedType == .jsString {
1186+
let innerFragment = try lowerReturn(type: wrappedType, context: .exportSwift)
1187+
return sentinelOptionalLowerReturn(
1188+
wrappedType: wrappedType,
1189+
kind: kind,
1190+
innerFragment: innerFragment
1191+
)
1192+
}
1193+
10711194
if case .sideChannelReturn(let mode) = wrappedType.optionalConvention {
10721195
if mode == .none {
10731196
throw BridgeJSLinkError(

Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1210,7 +1210,7 @@ extension BridgeType {
12101210
}
12111211

12121212
switch wrappedType {
1213-
case .string, .int, .float, .double, .jsObject, .jsString, .swiftProtocol:
1213+
case .string, .int, .float, .double, .jsObject, .swiftProtocol:
12141214
return true
12151215
case .rawValueEnum(_, let rawType):
12161216
switch rawType {

Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/JSString.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,24 @@
77
// Export: JSString roundtrip
88
@JS func roundTripJSString(_ value: JSString) -> JSString { return value }
99

10+
// Export: Optional JSString parameter and return
11+
@JS func checkOptionalJSString(a: JSString?) {}
12+
@JS func getOptionalJSString() -> JSString? { fatalError() }
13+
@JS func roundTripOptionalJSString(_ value: JSString?) -> JSString? { return value }
14+
15+
// Export: JSUndefinedOr<JSString> parameter and return
16+
@JS func checkUndefinedOrJSString(a: JSUndefinedOr<JSString>) {}
17+
@JS func getUndefinedOrJSString() -> JSUndefinedOr<JSString> { fatalError() }
18+
@JS func roundTripUndefinedOrJSString(_ value: JSUndefinedOr<JSString>) -> JSUndefinedOr<JSString> { return value }
19+
1020
// Import: JSString parameter and return
1121
@JSFunction func jsCheckJSString(_ a: JSString) throws(JSException) -> Void
1222
@JSFunction func jsGetJSString() throws(JSException) -> JSString
23+
24+
// Import: Optional JSString parameter and return
25+
@JSFunction func jsCheckOptionalJSString(_ a: JSString?) throws(JSException) -> Void
26+
@JSFunction func jsGetOptionalJSString() throws(JSException) -> JSString?
27+
28+
// Import: JSUndefinedOr<JSString> parameter and return
29+
@JSFunction func jsCheckUndefinedOrJSString(_ a: JSUndefinedOr<JSString>) throws(JSException) -> Void
30+
@JSFunction func jsGetUndefinedOrJSString() throws(JSException) -> JSUndefinedOr<JSString>

0 commit comments

Comments
 (0)