Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 128f696

Browse files
committed
BridgeJS: Protocol support for enum values (all types + optionals)
BridgeJS: Final refinings to enum support and revisiting tests
1 parent d59368a commit 128f696

File tree

15 files changed

+1830
-511
lines changed

15 files changed

+1830
-511
lines changed

‎Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift‎

Lines changed: 100 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1751,13 +1751,13 @@ public class ExportSwift {
17511751
return bridgeJSRawValue
17521752
}
17531753
@_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> \(raw: typeName) {
1754-
return \(raw: typeName)(bridgeJSRawValue: value)!
1754+
return bridgeJSLiftParameter(value)
17551755
}
17561756
@_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> \(raw: typeName) {
17571757
return \(raw: typeName)(bridgeJSRawValue: value)!
17581758
}
17591759
@_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 {
1760-
return bridgeJSRawValue
1760+
return bridgeJSLowerParameter()
17611761
}
17621762
17631763
private init?(bridgeJSRawValue: Int32) {
@@ -1774,13 +1774,32 @@ public class ExportSwift {
17741774
func renderAssociatedValueEnumHelpers(_ enumDef: ExportedEnum) -> DeclSyntax {
17751775
let typeName = enumDef.swiftCallName
17761776
return """
1777-
extension \(raw: typeName): _BridgedSwiftAssociatedValueEnum {
1778-
@_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> \(raw: typeName) {
1777+
extension \(raw: typeName): _BridgedSwiftAssociatedValueEnum {
1778+
private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> \(raw: typeName) {
17791779
switch caseId {
17801780
\(raw: generateStackLiftSwitchCases(enumDef: enumDef).joined(separator: "\n"))
17811781
default: fatalError("Unknown \(raw: typeName) case ID: \\(caseId)")
17821782
}
17831783
}
1784+
1785+
// MARK: Protocol Export
1786+
1787+
@_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 {
1788+
switch self {
1789+
\(raw: generateLowerParameterSwitchCases(enumDef: enumDef).joined(separator: "\n"))
1790+
}
1791+
}
1792+
1793+
@_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> \(raw: typeName) {
1794+
let caseId = _swift_js_pop_param_int32()
1795+
return _bridgeJSLiftFromCaseId(caseId)
1796+
}
1797+
1798+
// MARK: ExportSwift
1799+
1800+
@_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> \(raw: typeName) {
1801+
return _bridgeJSLiftFromCaseId(caseId)
1802+
}
17841803
17851804
@_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() {
17861805
switch self {
@@ -1849,66 +1868,94 @@ public class ExportSwift {
18491868
return cases
18501869
}
18511870

1871+
/// Generates code to push associated value payloads to side channels
1872+
/// This helper is reused by both lowerParameter and lowerReturn to avoid duplication
1873+
private func generatePayloadPushingCode(
1874+
associatedValues: [AssociatedValue]
1875+
) -> [String] {
1876+
var bodyLines: [String] = []
1877+
for (index, associatedValue) in associatedValues.enumerated() {
1878+
let paramName = associatedValue.label ?? "param\(index)"
1879+
switch associatedValue.type {
1880+
case .string:
1881+
bodyLines.append("var __bjs_\(paramName) = \(paramName)")
1882+
bodyLines.append("__bjs_\(paramName).withUTF8 { ptr in")
1883+
bodyLines.append("_swift_js_push_string(ptr.baseAddress, Int32(ptr.count))")
1884+
bodyLines.append("}")
1885+
case .int:
1886+
bodyLines.append("_swift_js_push_int(Int32(\(paramName)))")
1887+
case .bool:
1888+
bodyLines.append("_swift_js_push_int(\(paramName) ? 1 : 0)")
1889+
case .float:
1890+
bodyLines.append("_swift_js_push_f32(\(paramName))")
1891+
case .double:
1892+
bodyLines.append("_swift_js_push_f64(\(paramName))")
1893+
case .optional(let wrappedType):
1894+
bodyLines.append("let __bjs_isSome_\(paramName) = \(paramName) != nil")
1895+
bodyLines.append("if let __bjs_unwrapped_\(paramName) = \(paramName) {")
1896+
switch wrappedType {
1897+
case .string:
1898+
bodyLines.append("var __bjs_str_\(paramName) = __bjs_unwrapped_\(paramName)")
1899+
bodyLines.append("__bjs_str_\(paramName).withUTF8 { ptr in")
1900+
bodyLines.append("_swift_js_push_string(ptr.baseAddress, Int32(ptr.count))")
1901+
bodyLines.append("}")
1902+
case .int:
1903+
bodyLines.append("_swift_js_push_int(Int32(__bjs_unwrapped_\(paramName)))")
1904+
case .bool:
1905+
bodyLines.append("_swift_js_push_int(__bjs_unwrapped_\(paramName) ? 1 : 0)")
1906+
case .float:
1907+
bodyLines.append("_swift_js_push_f32(__bjs_unwrapped_\(paramName))")
1908+
case .double:
1909+
bodyLines.append("_swift_js_push_f64(__bjs_unwrapped_\(paramName))")
1910+
default:
1911+
bodyLines.append(
1912+
"preconditionFailure(\"BridgeJS: unsupported optional wrapped type in generated code\")"
1913+
)
1914+
}
1915+
bodyLines.append("}")
1916+
bodyLines.append("_swift_js_push_int(__bjs_isSome_\(paramName) ? 1 : 0)")
1917+
default:
1918+
bodyLines.append(
1919+
"preconditionFailure(\"BridgeJS: unsupported associated value type in generated code\")"
1920+
)
1921+
}
1922+
}
1923+
return bodyLines
1924+
}
1925+
1926+
private func generateLowerParameterSwitchCases(enumDef: ExportedEnum) -> [String] {
1927+
var cases: [String] = []
1928+
for (caseIndex, enumCase) in enumDef.cases.enumerated() {
1929+
if enumCase.associatedValues.isEmpty {
1930+
cases.append("case .\(enumCase.name):")
1931+
cases.append("return Int32(\(caseIndex))")
1932+
} else {
1933+
let payloadCode = generatePayloadPushingCode(associatedValues: enumCase.associatedValues)
1934+
let pattern = enumCase.associatedValues.enumerated()
1935+
.map { index, associatedValue in "let \(associatedValue.label ?? "param\(index)")" }
1936+
.joined(separator: ", ")
1937+
cases.append("case .\(enumCase.name)(\(pattern)):")
1938+
cases.append(contentsOf: payloadCode)
1939+
cases.append("return Int32(\(caseIndex))")
1940+
}
1941+
}
1942+
return cases
1943+
}
1944+
18521945
private func generateReturnSwitchCases(enumDef: ExportedEnum) -> [String] {
18531946
var cases: [String] = []
18541947
for (caseIndex, enumCase) in enumDef.cases.enumerated() {
18551948
if enumCase.associatedValues.isEmpty {
18561949
cases.append("case .\(enumCase.name):")
18571950
cases.append("_swift_js_push_tag(Int32(\(caseIndex)))")
18581951
} else {
1859-
var bodyLines: [String] = []
1860-
bodyLines.append("_swift_js_push_tag(Int32(\(caseIndex)))")
1861-
for (index, associatedValue) in enumCase.associatedValues.enumerated() {
1862-
let paramName = associatedValue.label ?? "param\(index)"
1863-
switch associatedValue.type {
1864-
case .string:
1865-
bodyLines.append("var __bjs_\(paramName) = \(paramName)")
1866-
bodyLines.append("__bjs_\(paramName).withUTF8 { ptr in")
1867-
bodyLines.append("_swift_js_push_string(ptr.baseAddress, Int32(ptr.count))")
1868-
bodyLines.append("}")
1869-
case .int:
1870-
bodyLines.append("_swift_js_push_int(Int32(\(paramName)))")
1871-
case .bool:
1872-
bodyLines.append("_swift_js_push_int(\(paramName) ? 1 : 0)")
1873-
case .float:
1874-
bodyLines.append("_swift_js_push_f32(\(paramName))")
1875-
case .double:
1876-
bodyLines.append("_swift_js_push_f64(\(paramName))")
1877-
case .optional(let wrappedType):
1878-
bodyLines.append("let __bjs_isSome_\(paramName) = \(paramName) != nil")
1879-
bodyLines.append("if let __bjs_unwrapped_\(paramName) = \(paramName) {")
1880-
switch wrappedType {
1881-
case .string:
1882-
bodyLines.append("var __bjs_str_\(paramName) = __bjs_unwrapped_\(paramName)")
1883-
bodyLines.append("__bjs_str_\(paramName).withUTF8 { ptr in")
1884-
bodyLines.append("_swift_js_push_string(ptr.baseAddress, Int32(ptr.count))")
1885-
bodyLines.append("}")
1886-
case .int:
1887-
bodyLines.append("_swift_js_push_int(Int32(__bjs_unwrapped_\(paramName)))")
1888-
case .bool:
1889-
bodyLines.append("_swift_js_push_int(__bjs_unwrapped_\(paramName) ? 1 : 0)")
1890-
case .float:
1891-
bodyLines.append("_swift_js_push_f32(__bjs_unwrapped_\(paramName))")
1892-
case .double:
1893-
bodyLines.append("_swift_js_push_f64(__bjs_unwrapped_\(paramName))")
1894-
default:
1895-
bodyLines.append(
1896-
"preconditionFailure(\"BridgeJS: unsupported optional wrapped type in generated code\")"
1897-
)
1898-
}
1899-
bodyLines.append("}")
1900-
bodyLines.append("_swift_js_push_int(__bjs_isSome_\(paramName) ? 1 : 0)")
1901-
default:
1902-
bodyLines.append(
1903-
"preconditionFailure(\"BridgeJS: unsupported associated value type in generated code\")"
1904-
)
1905-
}
1906-
}
19071952
let pattern = enumCase.associatedValues.enumerated()
19081953
.map { index, associatedValue in "let \(associatedValue.label ?? "param\(index)")" }
19091954
.joined(separator: ", ")
19101955
cases.append("case .\(enumCase.name)(\(pattern)):")
1911-
cases.append(contentsOf: bodyLines)
1956+
cases.append("_swift_js_push_tag(Int32(\(caseIndex)))")
1957+
let payloadCode = generatePayloadPushingCode(associatedValues: enumCase.associatedValues)
1958+
cases.append(contentsOf: payloadCode)
19121959
}
19131960
}
19141961
return cases

‎Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift‎

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -447,14 +447,41 @@ extension BridgeType {
447447
}
448448
case .swiftProtocol:
449449
throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures")
450-
case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum:
451-
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
450+
case .caseEnum:
451+
switch context {
452+
case .importTS:
453+
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
454+
case .protocolExport:
455+
return LoweringParameterInfo(loweredParameters: [("value", .i32)])
456+
}
457+
case .rawValueEnum(_, let rawType):
458+
switch context {
459+
case .importTS:
460+
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
461+
case .protocolExport:
462+
let wasmType = rawType == .string ? WasmCoreType.i32 : (rawType.wasmCoreType ?? .i32)
463+
return LoweringParameterInfo(loweredParameters: [("value", wasmType)])
464+
}
465+
case .associatedValueEnum:
466+
switch context {
467+
case .importTS:
468+
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
469+
case .protocolExport:
470+
return LoweringParameterInfo(loweredParameters: [("caseId", .i32)])
471+
}
472+
case .namespaceEnum:
473+
throw BridgeJSCoreError("Namespace enums cannot be used as parameters")
452474
case .optional(let wrappedType):
453475
switch context {
454476
case .importTS:
455477
throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports")
456478
case .protocolExport:
457-
return try wrappedType.loweringParameterInfo(context: context)
479+
let wrappedInfo = try wrappedType.loweringParameterInfo(context: context)
480+
guard wrappedInfo.loweredParameters.count == 1 else {
481+
throw BridgeJSCoreError("Optional wrapped type must lower to single parameter")
482+
}
483+
let (_, wrappedWasmType) = wrappedInfo.loweredParameters[0]
484+
return LoweringParameterInfo(loweredParameters: [("value", wrappedWasmType)])
458485
}
459486
}
460487
}
@@ -494,22 +521,38 @@ extension BridgeType {
494521
}
495522
case .swiftProtocol:
496523
throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures")
497-
case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum:
498-
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
499-
case .optional:
524+
case .caseEnum:
500525
switch context {
501526
case .importTS:
502-
throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports")
527+
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
528+
case .protocolExport:
529+
return LiftingReturnInfo(valueToLift: .i32)
530+
}
531+
case .rawValueEnum(_, let rawType):
532+
switch context {
533+
case .importTS:
534+
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
535+
case .protocolExport:
536+
let wasmType = rawType == .string ? WasmCoreType.i32 : (rawType.wasmCoreType ?? .i32)
537+
return LiftingReturnInfo(valueToLift: wasmType)
538+
}
539+
case .associatedValueEnum:
540+
switch context {
541+
case .importTS:
542+
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
503543
case .protocolExport:
504-
// For Optional<String>, return the length (or -1 for null)
505-
if case .optional(.string) = self {
506-
return .string
507-
}
508-
if case .optional(.swiftHeapObject) = self {
509-
return LiftingReturnInfo(valueToLift: .pointer)
510-
}
511544
return LiftingReturnInfo(valueToLift: nil)
512545
}
546+
case .namespaceEnum:
547+
throw BridgeJSCoreError("Namespace enums cannot be used as return values")
548+
case .optional(let wrappedType):
549+
switch context {
550+
case .importTS:
551+
throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports")
552+
case .protocolExport:
553+
let wrappedInfo = try wrappedType.liftingReturnInfo(context: context)
554+
return wrappedInfo
555+
}
513556
}
514557
}
515558
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /