Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Benchmarks/Sources/Generated/JavaScript/BridgeJS.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"exported" : {
"aliases" : [

],
"classes" : [
{
"constructor" : {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"exported" : {
"aliases" : [

],
"classes" : [
{
"constructor" : {
Expand Down
6 changes: 4 additions & 2 deletions Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ public struct ClosureCodegen {
let argNames = liftInfo.parameters.map { (argName, _) in
liftInfo.parameters.count > 1 ? "\(paramName)\(argName.capitalizedFirstLetter)" : paramName
}
liftedParams.append("\(paramType.swiftType).bridgeJSLiftParameter(\(argNames.joined(separator: ", ")))")
let liftCall = "\(paramType.unaliased.swiftType).bridgeJSLiftParameter(\(argNames.joined(separator: ", ")))"
liftedParams.append(paramType.liftAliases(expression: liftCall))
}

let closureCallExpr = ExprSyntax("closure(\(raw: liftedParams.joined(separator: ", ")))")
Expand Down Expand Up @@ -184,7 +185,8 @@ public struct ClosureCodegen {
}
printer.write("}")
default:
printer.write("return result.bridgeJSLowerReturn()")
let lowered = signature.returnType.lowerAliases(expression: "result")
printer.write("return \(lowered).bridgeJSLowerReturn()")
}
}
}
Expand Down
108 changes: 89 additions & 19 deletions Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,15 @@ public class ExportSwift {
} else {
optionalSwiftType = "JSUndefinedOr"
}
typeNameForIntrinsic = "\(optionalSwiftType)<\(wrappedType.swiftType)>"
liftingExpr = ExprSyntax(
"\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
)
typeNameForIntrinsic = "\(optionalSwiftType)<\(wrappedType.unaliased.swiftType)>"
let liftCall =
"\(typeNameForIntrinsic).bridgeJSLiftParameter(\(argumentsToLift.joined(separator: ", ")))"
liftingExpr = "\(raw: param.type.liftAliases(expression: liftCall))"
default:
typeNameForIntrinsic = param.type.swiftType
liftingExpr = ExprSyntax(
"\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
)
typeNameForIntrinsic = param.type.unaliased.swiftType
let liftCall =
"\(typeNameForIntrinsic).bridgeJSLiftParameter(\(argumentsToLift.joined(separator: ", ")))"
liftingExpr = "\(raw: param.type.liftAliases(expression: liftCall))"
}

liftedParameterExprs.append(liftingExpr)
Expand Down Expand Up @@ -200,7 +200,8 @@ public class ExportSwift {
}

if effects.isAsync, returnType != .void {
return CodeBlockItemSyntax(item: .init(StmtSyntax("return \(raw: callExpr).jsValue")))
let lowered = returnType.lowerAliases(expression: callExpr.description)
return CodeBlockItemSyntax(item: .init(StmtSyntax("return \(raw: lowered).jsValue")))
}

if returnType == .void {
Expand Down Expand Up @@ -298,17 +299,18 @@ public class ExportSwift {
return
}

let returnAccessor = returnType.lowerAliases(expression: "ret")
switch returnType {
case .closure(_, useJSTypedClosure: false):
append("return JSTypedClosure(ret).bridgeJSLowerReturn()")
case .array, .nullable(.array, _):
let stackCodegen = StackCodegen()
for stmt in stackCodegen.lowerStatements(for: returnType, accessor: "ret", varPrefix: "ret") {
for stmt in stackCodegen.lowerStatements(for: returnType, accessor: returnAccessor, varPrefix: "ret") {
append(stmt)
}
case .dictionary(.swiftProtocol):
let stackCodegen = StackCodegen()
for stmt in stackCodegen.lowerStatements(for: returnType, accessor: "ret", varPrefix: "ret") {
for stmt in stackCodegen.lowerStatements(for: returnType, accessor: returnAccessor, varPrefix: "ret") {
append(stmt)
}
case .swiftProtocol:
Expand All @@ -324,7 +326,7 @@ public class ExportSwift {
"""
)
default:
append("return ret.bridgeJSLowerReturn()")
append("return \(raw: returnAccessor).bridgeJSLowerReturn()")
}
}

Expand Down Expand Up @@ -754,8 +756,8 @@ struct StackCodegen {
switch type {
case .string, .integer, .bool, .float, .double,
.jsObject(nil), .jsValue, .swiftStruct, .swiftHeapObject, .unsafePointer,
.swiftProtocol, .caseEnum, .associatedValueEnum, .rawValueEnum, .array, .dictionary:
return "\(raw: type.swiftType).bridgeJSStackPop()"
.swiftProtocol, .caseEnum, .associatedValueEnum, .rawValueEnum, .array, .dictionary, .alias:
return "\(raw: type.liftAliases(expression: "\(type.unaliased.swiftType).bridgeJSStackPop()"))"
case .jsObject(let className?):
return "\(raw: className)(unsafelyWrapping: JSObject.bridgeJSStackPop())"
case .nullable(let wrappedType, let kind):
Expand All @@ -772,8 +774,10 @@ struct StackCodegen {
switch wrappedType {
case .string, .integer, .bool, .float, .double, .jsObject(nil), .jsValue,
.swiftStruct, .swiftHeapObject, .caseEnum, .associatedValueEnum, .rawValueEnum,
.array, .dictionary:
return "\(raw: typeName)<\(raw: wrappedType.swiftType)>.bridgeJSStackPop()"
.array, .dictionary, .alias:
let popCall = "\(typeName)<\(wrappedType.unaliased.swiftType)>.bridgeJSStackPop()"
let nullableType = BridgeType.nullable(wrappedType, kind)
return "\(raw: nullableType.liftAliases(expression: popCall))"
case .jsObject(let className?):
return "\(raw: typeName)<JSObject>.bridgeJSStackPop().map { \(raw: className)(unsafelyWrapping: $0) }"
case .nullable, .void, .namespaceEnum, .closure, .unsafePointer, .swiftProtocol:
Expand All @@ -795,7 +799,7 @@ struct StackCodegen {
switch type {
case .string, .integer, .bool, .float, .double, .jsValue,
.jsObject(nil), .swiftHeapObject, .unsafePointer, .closure,
.caseEnum, .rawValueEnum, .associatedValueEnum, .swiftStruct, .nullable:
.caseEnum, .rawValueEnum, .associatedValueEnum, .swiftStruct, .nullable, .alias:
return ["\(raw: accessor).bridgeJSStackPush()"]
case .jsObject(_?):
return ["\(raw: accessor).jsObject.bridgeJSStackPush()"]
Expand Down Expand Up @@ -1081,9 +1085,10 @@ struct EnumCodegen {
) {
for (index, associatedValue) in associatedValues.enumerated() {
let paramName = associatedValue.label ?? "param\(index)"
let accessor = associatedValue.type.lowerAliases(expression: paramName)
let statements = stackCodegen.lowerStatements(
for: associatedValue.type,
accessor: paramName,
accessor: accessor,
varPrefix: paramName
)
for statement in statements {
Expand Down Expand Up @@ -1216,7 +1221,7 @@ struct StructCodegen {
let instanceProps = structDef.properties.filter { !$0.isStatic }

for property in instanceProps {
let accessor = "self.\(property.name)"
let accessor = property.type.lowerAliases(expression: "self.\(property.name)")
let statements = stackCodegen.lowerStatements(
for: property.type,
accessor: accessor,
Expand Down Expand Up @@ -1442,6 +1447,64 @@ extension UnsafePointerType {
}

extension BridgeType {
var unaliased: BridgeType {
switch self {
case .alias(_, let underlying): return underlying.unaliased
case .nullable(let wrapped, let kind): return .nullable(wrapped.unaliased, kind)
case .array(let element): return .array(element.unaliased)
case .dictionary(let value): return .dictionary(value.unaliased)
case .bool, .integer, .float, .double, .string, .jsValue, .jsObject,
.swiftHeapObject, .unsafePointer, .swiftProtocol, .void,
.caseEnum, .rawValueEnum, .associatedValueEnum, .swiftStruct,
.namespaceEnum, .closure:
return self
}
}

/// If this type contains an alias, convert the expression with a type of the alias to the underlying type.
func liftAliases(expression: String) -> String {
switch self {
case .alias(let name, _):
return "\(name).bridgeFromJS(\(expression))"
case .nullable(let wrapped, _):
let lifted = wrapped.liftAliases(expression: "$0")
return lifted == "$0" ? expression : "\(expression).map { \(lifted) }"
case .array(let element):
let lifted = element.liftAliases(expression: "$0")
return lifted == "$0" ? expression : "\(expression).map { \(lifted) }"
case .dictionary(let value):
let lifted = value.liftAliases(expression: "$0")
return lifted == "$0" ? expression : "\(expression).mapValues { \(lifted) }"
case .bool, .integer, .float, .double, .string, .jsValue, .jsObject,
.swiftHeapObject, .unsafePointer, .swiftProtocol, .void,
.caseEnum, .rawValueEnum, .associatedValueEnum, .swiftStruct,
.namespaceEnum, .closure:
return expression
}
}

/// Opposite of `liftAliases`: if this type contains an alias, convert the expression with a type of the underlying to the alias type.
func lowerAliases(expression: String) -> String {
switch self {
case .alias:
return "\(expression).bridgeToJS()"
case .nullable(let wrapped, _):
let lowered = wrapped.lowerAliases(expression: "$0")
return lowered == "$0" ? expression : "\(expression).map { \(lowered) }"
case .array(let element):
let lowered = element.lowerAliases(expression: "$0")
return lowered == "$0" ? expression : "\(expression).map { \(lowered) }"
case .dictionary(let value):
let lowered = value.lowerAliases(expression: "$0")
return lowered == "$0" ? expression : "\(expression).mapValues { \(lowered) }"
case .bool, .integer, .float, .double, .string, .jsValue, .jsObject,
.swiftHeapObject, .unsafePointer, .swiftProtocol, .void,
.caseEnum, .rawValueEnum, .associatedValueEnum, .swiftStruct,
.namespaceEnum, .closure:
return expression
}
}

var swiftType: String {
switch self {
case .bool: return "Bool"
Expand Down Expand Up @@ -1470,6 +1533,7 @@ extension BridgeType {
let effectsStr = (signature.isAsync ? " async" : "") + (signature.isThrows ? " throws" : "")
let closureType = "(\(paramTypes))\(effectsStr) -> \(signature.returnType.swiftType)"
return useJSTypedClosure ? "JSTypedClosure<\(closureType)>" : closureType
case .alias(let name, _): return name
}
}

Expand All @@ -1494,6 +1558,8 @@ extension BridgeType {
return true
case .nullable(let wrapped, _):
return wrapped.isStackUsingParameter
case .alias(_, let underlying):
return underlying.isStackUsingParameter
default:
return false
}
Expand Down Expand Up @@ -1552,6 +1618,8 @@ extension BridgeType {
return LiftingIntrinsicInfo(parameters: [("callbackId", .i32)])
case .array, .dictionary:
return LiftingIntrinsicInfo(parameters: [])
case .alias(_, let underlying):
return try underlying.liftParameterInfo()
}
}

Expand Down Expand Up @@ -1603,6 +1671,8 @@ extension BridgeType {
return .jsObject
case .array, .dictionary:
return .array
case .alias(_, let underlying):
return try underlying.loweringReturnInfo()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ public struct ExternalModuleIndex {
for proto in exported.protocols {
register(dotPath: proto.name, bridgeType: .swiftProtocol(proto.name))
}
for alias in exported.aliases {
register(
dotPath: alias.swiftCallName,
bridgeType: .alias(name: alias.swiftCallName, underlying: alias.underlying)
)
}

entriesByModule[moduleName] = moduleEntries
}
Expand Down
21 changes: 15 additions & 6 deletions Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ public struct ImportTS {
if loweringInfo.useBorrowing {
let returnVariableName = "ret\(borrowedArguments.count)"
let assign = needsReturnVariable ? "let \(returnVariableName) = " : ""
body.write("\(assign)\(param.name).bridgeJSWithLoweredParameter { \(pattern) in")
let loweredAlias = param.type.lowerAliases(expression: param.name)
body.write("\(assign)\(loweredAlias).bridgeJSWithLoweredParameter { \(pattern) in")
body.indent()
borrowedArguments.append(
BorrowedArgument(
Expand Down Expand Up @@ -203,7 +204,8 @@ public struct ImportTS {
"(\(raw: param.name) as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()"
)
} else {
initializerExpr = ExprSyntax("\(raw: param.name).bridgeJSLowerParameter()")
let loweredAlias = param.type.lowerAliases(expression: param.name)
initializerExpr = ExprSyntax("\(raw: loweredAlias).bridgeJSLowerParameter()")
}

if loweringInfo.loweredParameters.isEmpty {
Expand Down Expand Up @@ -296,18 +298,21 @@ public struct ImportTS {

if returnType.usesSideChannelForOptionalReturn() {
// Side channel returns: extern function returns Void, value is retrieved via side channel
body.write("return \(returnType.swiftType).bridgeJSLiftReturnFromSideChannel()")
let liftCall = "\(returnType.unaliased.swiftType).bridgeJSLiftReturnFromSideChannel()"
body.write("return \(returnType.liftAliases(expression: liftCall))")
} else {
let liftExpr: String
switch returnType {
case .closure(let signature, _):
liftExpr = "_BJS_Closure_\(signature.mangleName).bridgeJSLift(ret)"
default:
let liftCall: String
if liftingInfo.valueToLift != nil {
liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn(ret)"
liftCall = "\(returnType.unaliased.swiftType).bridgeJSLiftReturn(ret)"
} else {
liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn()"
liftCall = "\(returnType.unaliased.swiftType).bridgeJSLiftReturn()"
}
liftExpr = returnType.liftAliases(expression: liftCall)
}
body.write("return \(liftExpr)")
}
Expand Down Expand Up @@ -964,6 +969,8 @@ extension BridgeType {
return LoweringParameterInfo(loweredParameters: params, useBorrowing: wrappedInfo.useBorrowing)
case .array, .dictionary:
return LoweringParameterInfo(loweredParameters: [])
case .alias(_, let underlying):
return try underlying.loweringParameterInfo(context: context)
}
}

Expand Down Expand Up @@ -1035,13 +1042,15 @@ extension BridgeType {
throw BridgeJSCoreError("Namespace enums cannot be used as return values")
case .nullable(let wrappedType, _):
// jsObject uses stack ABI for optionals — returns void, value goes through stacks
if case .jsObject = wrappedType {
if case .jsObject = wrappedType.unaliased {
return LiftingReturnInfo(valueToLift: nil)
}
let wrappedInfo = try wrappedType.liftingReturnInfo(context: context)
return LiftingReturnInfo(valueToLift: wrappedInfo.valueToLift)
case .array, .dictionary:
return LiftingReturnInfo(valueToLift: nil)
case .alias(_, let underlying):
return try underlying.liftingReturnInfo(context: context)
}
}
}
Expand Down
Loading
Loading