diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 61ffc7781..3c7b197a4 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -1048,7 +1048,7 @@ public struct BridgeJSLink { for skeleton in skeletons.compactMap(\.exported) { for enumDef in skeleton.enums where enumDef.enumType == .associatedValue { printer.write( - "const \(enumDef.name)Helpers = __bjs_create\(enumDef.valuesName)Helpers()();" + "const \(enumDef.name)Helpers = __bjs_create\(enumDef.valuesName)Helpers();" ) printer.write("\(JSGlueVariableScope.reservedEnumHelpers).\(enumDef.name) = \(enumDef.name)Helpers;") printer.nextLine() @@ -1064,7 +1064,7 @@ public struct BridgeJSLink { for skeleton in skeletons.compactMap(\.exported) { for structDef in skeleton.structs { printer.write( - "const \(structDef.name)Helpers = __bjs_create\(structDef.name)Helpers()();" + "const \(structDef.name)Helpers = __bjs_create\(structDef.name)Helpers();" ) printer.write( "\(JSGlueVariableScope.reservedStructHelpers).\(structDef.name) = \(structDef.name)Helpers;" @@ -1219,7 +1219,8 @@ public struct BridgeJSLink { loweringFragment.parameters.count == 1, "Lowering fragment should have exactly one parameter to lower" ) - let loweredValues = try loweringFragment.printCode([param.name], context) + let paramName = scope.variable(param.name) + let loweredValues = try loweringFragment.printCode([paramName], context) parameterForwardings.append(contentsOf: loweredValues) } @@ -1513,7 +1514,7 @@ public struct BridgeJSLink { switch enumDefinition.enumType { case .simple: - let fragment = IntrinsicJSFragment.simpleEnumHelper(enumDefinition: enumDefinition) + let fragment = IntrinsicJSFragment.caseEnumHelper(enumDefinition: enumDefinition) _ = try fragment.printCode([enumValuesName], context) jsTopLevelLines.append(contentsOf: printer.lines) case .rawValue: @@ -1521,7 +1522,7 @@ public struct BridgeJSLink { throw BridgeJSLinkError(message: "Raw value enum \(enumDefinition.name) is missing rawType") } - let fragment = IntrinsicJSFragment.rawValueEnumHelper(enumDefinition: enumDefinition) + let fragment = IntrinsicJSFragment.caseEnumHelper(enumDefinition: enumDefinition) _ = try fragment.printCode([enumValuesName], context) jsTopLevelLines.append(contentsOf: printer.lines) case .associatedValue: diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 20903eef8..6f848eb05 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -89,6 +89,7 @@ final class JSGlueVariableScope { func makeChildScope() -> JSGlueVariableScope { JSGlueVariableScope(intrinsicRegistry: intrinsicRegistry) } + } extension JSGlueVariableScope { @@ -107,17 +108,7 @@ extension JSGlueVariableScope { printer.write("\(JSGlueVariableScope.reservedPointerStack).push(\(value));") } - // MARK: Return - - func emitPushI32Return(_ value: String, printer: CodeFragmentPrinter) { - printer.write("\(JSGlueVariableScope.reservedI32Stack).push(\(value));") - } - func emitPushF64Return(_ value: String, printer: CodeFragmentPrinter) { - printer.write("\(JSGlueVariableScope.reservedF64Stack).push(\(value));") - } - func emitPushPointerReturn(_ value: String, printer: CodeFragmentPrinter) { - printer.write("\(JSGlueVariableScope.reservedPointerStack).push(\(value));") - } + // MARK: Pop func popString() -> String { return "\(JSGlueVariableScope.reservedStringStack).pop()" } @@ -200,29 +191,21 @@ struct IntrinsicJSFragment: Sendable { } ) - /// NOTE: JavaScript engine itself converts booleans to integers when passing them to - /// Wasm functions, so we don't need to do anything here - static let boolLowerParameter = identity + // MARK: - Scalar Coercion Fragments + static let boolLiftReturn = IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, _ in return ["\(arguments[0]) !== 0"] } ) - static let boolLiftParameter = IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, _ in - return ["\(arguments[0]) !== 0"] - } - ) + static let boolLiftParameter = boolLiftReturn static let boolLowerReturn = IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, _ in return ["\(arguments[0]) ? 1 : 0"] } ) - - /// Convert signed Int32 to unsigned for UInt values static let uintLiftReturn = IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, _ in @@ -231,6 +214,8 @@ struct IntrinsicJSFragment: Sendable { ) static let uintLiftParameter = uintLiftReturn + // MARK: - String Fragments + static let stringLowerParameter = IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in @@ -260,7 +245,9 @@ struct IntrinsicJSFragment: Sendable { let objectId = arguments[0] let objectLabel = scope.variable("\(objectId)Object") // TODO: Implement "take" operation - printer.write("const \(objectLabel) = \(JSGlueVariableScope.reservedSwift).memory.getObject(\(objectId));") + printer.write( + "const \(objectLabel) = \(JSGlueVariableScope.reservedSwift).memory.getObject(\(objectId));" + ) printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(objectId));") return [objectLabel] } @@ -268,7 +255,7 @@ struct IntrinsicJSFragment: Sendable { static let stringLowerReturn = IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) + let printer = context.printer printer.write( "\(JSGlueVariableScope.reservedStorageToReturnBytes) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(arguments[0]));" ) @@ -276,37 +263,32 @@ struct IntrinsicJSFragment: Sendable { } ) + // MARK: - JSObject Fragments + static let jsObjectLowerParameter = IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, _ in return ["swift.memory.retain(\(arguments[0]))"] } ) - static let jsObjectLiftReturn = IntrinsicJSFragment( - parameters: ["retId"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - // TODO: Implement "take" operation - let resultLabel = scope.variable("ret") - let retId = arguments[0] - printer.write("const \(resultLabel) = \(JSGlueVariableScope.reservedSwift).memory.getObject(\(retId));") - printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(retId));") - return [resultLabel] - } - ) - static let jsObjectLiftRetainedObjectId = IntrinsicJSFragment( - parameters: ["objectId"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let resultLabel = scope.variable("value") - let objectId = arguments[0] - printer.write( - "const \(resultLabel) = \(JSGlueVariableScope.reservedSwift).memory.getObject(\(objectId));" - ) - printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(objectId));") - return [resultLabel] - } - ) + private static func jsObjectTakeRetained(hint: String = "ret") -> IntrinsicJSFragment { + IntrinsicJSFragment( + parameters: ["objectId"], + printCode: { arguments, context in + let (scope, printer) = (context.scope, context.printer) + // TODO: Implement "take" operation + let resultLabel = scope.variable(hint) + let objectId = arguments[0] + printer.write( + "const \(resultLabel) = \(JSGlueVariableScope.reservedSwift).memory.getObject(\(objectId));" + ) + printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(objectId));") + return [resultLabel] + } + ) + } + static let jsObjectLiftReturn = jsObjectTakeRetained(hint: "ret") + static let jsObjectLiftRetainedObjectId = jsObjectTakeRetained(hint: "value") static let jsObjectLiftParameter = IntrinsicJSFragment( parameters: ["objectId"], printCode: { arguments, _ in @@ -320,6 +302,8 @@ struct IntrinsicJSFragment: Sendable { } ) + // MARK: - JSValue Fragments + private static let jsValueLowerHelperName = "__bjs_jsValueLower" private static let jsValueLiftHelperName = "__bjs_jsValueLift" @@ -387,13 +371,18 @@ struct IntrinsicJSFragment: Sendable { printer.write("\(payload2Var) = \(value);") printer.write("break;") } - printer.write("case \"string\":") - printer.indent { - printer.write("\(kindVar) = 1;") - printer.write("\(payload1Var) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));") - printer.write("\(payload2Var) = 0;") - printer.write("break;") + func emitRetainCase(_ caseName: String, kind: Int) { + printer.write("case \"\(caseName)\":") + printer.indent { + printer.write("\(kindVar) = \(kind);") + printer.write( + "\(payload1Var) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));" + ) + printer.write("\(payload2Var) = 0;") + printer.write("break;") + } } + emitRetainCase("string", kind: 1) printer.write("case \"undefined\":") printer.indent { printer.write("\(kindVar) = 5;") @@ -401,34 +390,10 @@ struct IntrinsicJSFragment: Sendable { printer.write("\(payload2Var) = 0;") printer.write("break;") } - printer.write("case \"object\":") - printer.indent { - printer.write("\(kindVar) = 3;") - printer.write("\(payload1Var) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));") - printer.write("\(payload2Var) = 0;") - printer.write("break;") - } - printer.write("case \"function\":") - printer.indent { - printer.write("\(kindVar) = 3;") - printer.write("\(payload1Var) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));") - printer.write("\(payload2Var) = 0;") - printer.write("break;") - } - printer.write("case \"symbol\":") - printer.indent { - printer.write("\(kindVar) = 7;") - printer.write("\(payload1Var) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));") - printer.write("\(payload2Var) = 0;") - printer.write("break;") - } - printer.write("case \"bigint\":") - printer.indent { - printer.write("\(kindVar) = 8;") - printer.write("\(payload1Var) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));") - printer.write("\(payload2Var) = 0;") - printer.write("break;") - } + emitRetainCase("object", kind: 3) + emitRetainCase("function", kind: 3) + emitRetainCase("symbol", kind: 7) + emitRetainCase("bigint", kind: 8) printer.write("default:") printer.indent { printer.write("throw new TypeError(\"Unsupported JSValue type\");") @@ -524,45 +489,20 @@ struct IntrinsicJSFragment: Sendable { } static func jsValueLowerReturn(context: BridgeContext) -> IntrinsicJSFragment { - switch context { - case .importTS: - // Return values from imported JS functions should be delivered to the Swift side - // via the parameter stacks that `_swift_js_pop_*` read from. - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let lowered = try jsValueLower.printCode(arguments, context) - let kindVar = lowered[0] - let payload1Var = lowered[1] - let payload2Var = lowered[2] - scope.emitPushI32Parameter(kindVar, printer: printer) - scope.emitPushI32Parameter(payload1Var, printer: printer) - scope.emitPushF64Parameter(payload2Var, printer: printer) - return [] - } - ) - case .exportSwift: - // Kept for symmetry, though JSValue return for export currently relies on Swift pushing - // to tmpRet stacks directly. - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let lowered = try jsValueLower.printCode( - arguments, - context - ) - let kindVar = lowered[0] - let payload1Var = lowered[1] - let payload2Var = lowered[2] - scope.emitPushI32Parameter(kindVar, printer: printer) - scope.emitPushI32Parameter(payload1Var, printer: printer) - scope.emitPushF64Parameter(payload2Var, printer: printer) - return [] - } - ) - } + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, context in + let (scope, printer) = (context.scope, context.printer) + let lowered = try jsValueLower.printCode(arguments, context) + let kindVar = lowered[0] + let payload1Var = lowered[1] + let payload2Var = lowered[2] + scope.emitPushI32Parameter(kindVar, printer: printer) + scope.emitPushI32Parameter(payload1Var, printer: printer) + scope.emitPushF64Parameter(payload2Var, printer: printer) + return [] + } + ) } static let jsValueLift = IntrinsicJSFragment( @@ -596,12 +536,21 @@ struct IntrinsicJSFragment: Sendable { } ) + // MARK: - SwiftHeapObject Fragments + static let swiftHeapObjectLowerParameter = IntrinsicJSFragment( parameters: ["value"], - printCode: { arguments, context in + printCode: { arguments, _ in + return ["\(arguments[0]).pointer"] + } + ) + static let swiftHeapObjectLowerReturn = IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, _ in return ["\(arguments[0]).pointer"] } ) + static func swiftHeapObjectLiftReturn(_ name: String) -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: ["value"], @@ -620,12 +569,8 @@ struct IntrinsicJSFragment: Sendable { } ) } - static let swiftHeapObjectLowerReturn = IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - return ["\(arguments[0]).pointer"] - } - ) + + // MARK: - Associated Enum Fragments static func associatedEnumLowerParameter(enumBase: String) -> IntrinsicJSFragment { IntrinsicJSFragment( @@ -656,407 +601,408 @@ struct IntrinsicJSFragment: Sendable { ) } - static func optionalLiftParameter(wrappedType: BridgeType, kind: JSOptionalKind) throws -> IntrinsicJSFragment { - if case .jsValue = wrappedType { + // MARK: - Optional Handling + + static func optionalLiftParameter( + wrappedType: BridgeType, + kind: JSOptionalKind, + context bridgeContext: BridgeContext = .importTS + ) throws -> IntrinsicJSFragment { + if wrappedType.isSingleParamScalar { + let coerce = wrappedType.liftCoerce return IntrinsicJSFragment( - parameters: ["isSome", "kind", "payload1", "payload2"], - printCode: { arguments, context in + parameters: ["isSome", "wrappedValue"], + printCode: { arguments, _ in let isSome = arguments[0] - let lifted = try jsValueLiftParameter.printCode( - [arguments[1], arguments[2], arguments[3]], - context - ) - let valueExpr = lifted.first ?? "undefined" - return ["\(isSome) ? \(valueExpr) : null"] + let wrappedValue = arguments[1] + let absenceLiteral = kind.absenceLiteral + if let coerce { + let coerced = coerce.replacingOccurrences(of: "$0", with: wrappedValue) + return ["\(isSome) ? \(coerced) : \(absenceLiteral)"] + } + return ["\(isSome) ? \(wrappedValue) : \(absenceLiteral)"] } ) } + let innerFragment = try liftParameter(type: wrappedType, context: bridgeContext) + return compositeOptionalLiftParameter( + wrappedType: wrappedType, + kind: kind, + innerFragment: innerFragment + ) + } + + private static func compositeOptionalLiftParameter( + wrappedType: BridgeType, + kind: JSOptionalKind, + innerFragment: IntrinsicJSFragment + ) -> IntrinsicJSFragment { + let isStackConvention = wrappedType.optionalConvention == .stackABI + let absenceLiteral = kind.absenceLiteral + + let outerParams: [String] + if isStackConvention { + outerParams = ["isSome"] + } else { + outerParams = ["isSome"] + innerFragment.parameters + } + return IntrinsicJSFragment( - parameters: ["isSome", "wrappedValue"], + parameters: outerParams, printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) let isSome = arguments[0] - let wrappedValue = arguments[1] - let resultExpr: String - let absenceLiteral = kind.absenceLiteral - - switch wrappedType { - case .int, .float, .double, .caseEnum: - resultExpr = "\(isSome) ? \(wrappedValue) : \(absenceLiteral)" - case .bool: - resultExpr = "\(isSome) ? \(wrappedValue) !== 0 : \(absenceLiteral)" - case .string: - let objectLabel = scope.variable("obj") - printer.write("let \(objectLabel);") - printer.write("if (\(isSome)) {") - printer.indent { - printer.write( - "\(objectLabel) = \(JSGlueVariableScope.reservedSwift).memory.getObject(\(wrappedValue));" - ) - printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(wrappedValue));") - } - printer.write("}") - resultExpr = "\(isSome) ? \(objectLabel) : \(absenceLiteral)" - case .closure: - resultExpr = - "\(isSome) ? \(JSGlueVariableScope.reservedSwift).memory.getObject(\(wrappedValue)) : \(absenceLiteral)" - case .swiftHeapObject(let name): - resultExpr = "\(isSome) ? _exports['\(name)'].__construct(\(wrappedValue)) : \(absenceLiteral)" - case .jsObject: - resultExpr = - "\(isSome) ? \(JSGlueVariableScope.reservedSwift).memory.getObject(\(wrappedValue)) : \(absenceLiteral)" - case .rawValueEnum(_, let rawType): - switch rawType { - case .string: - let objectLabel = scope.variable("obj") - printer.write("let \(objectLabel);") - printer.write("if (\(isSome)) {") - printer.indent { - printer.write( - "\(objectLabel) = \(JSGlueVariableScope.reservedSwift).memory.getObject(\(wrappedValue));" - ) - printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(wrappedValue));") - } - printer.write("}") - resultExpr = "\(isSome) ? \(objectLabel) : \(absenceLiteral)" - case .bool: - resultExpr = "\(isSome) ? \(wrappedValue) !== 0 : \(absenceLiteral)" - default: - resultExpr = "\(isSome) ? \(wrappedValue) : \(absenceLiteral)" - } - case .associatedValueEnum(let fullName): - let base = fullName.components(separatedBy: ".").last ?? fullName - let enumVar = scope.variable("enumValue") - printer.write("let \(enumVar);") - printer.write("if (\(isSome)) {") - printer.indent { - printer.write( - "\(enumVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lift(\(wrappedValue));" - ) - } - printer.write("}") - resultExpr = "\(isSome) ? \(enumVar) : \(absenceLiteral)" - case .swiftStruct(let fullName): - let base = fullName.components(separatedBy: ".").last ?? fullName - let structVar = scope.variable("structValue") - printer.write("let \(structVar);") + let innerArgs = isStackConvention ? [] : Array(arguments.dropFirst()) + + let bufferPrinter = CodeFragmentPrinter() + let innerResults = try innerFragment.printCode( + innerArgs, + context.with(\.printer, bufferPrinter) + ) + + let hasSideEffects = !bufferPrinter.lines.isEmpty + let innerExpr = innerResults.first ?? "undefined" + + if hasSideEffects { + let resultVar = scope.variable("optResult") + printer.write("let \(resultVar);") printer.write("if (\(isSome)) {") printer.indent { - printer.write( - "\(structVar) = \(JSGlueVariableScope.reservedStructHelpers).\(base).lift();" - ) - } - printer.write("} else {") - printer.indent { - printer.write("\(structVar) = \(absenceLiteral);") - } - printer.write("}") - resultExpr = structVar - case .array(let elementType): - let arrayVar = scope.variable("arrayValue") - printer.write("let \(arrayVar);") - printer.write("if (\(isSome)) {") - try printer.indent { - let arrayLiftFragment = try arrayLift(elementType: elementType) - let liftResults = try arrayLiftFragment.printCode([], context) - if let liftResult = liftResults.first { - printer.write("\(arrayVar) = \(liftResult);") + for line in bufferPrinter.lines { + printer.write(line) } + printer.write("\(resultVar) = \(innerExpr);") } printer.write("} else {") printer.indent { - printer.write("\(arrayVar) = \(absenceLiteral);") + printer.write("\(resultVar) = \(absenceLiteral);") } printer.write("}") - resultExpr = arrayVar - case .dictionary(let valueType): - let dictVar = scope.variable("dictValue") - printer.write("let \(dictVar);") - printer.write("if (\(isSome)) {") - try printer.indent { - let dictLiftFragment = try dictionaryLift(valueType: valueType) - let liftResults = try dictLiftFragment.printCode([], context) - if let liftResult = liftResults.first { - printer.write("\(dictVar) = \(liftResult);") - } - } - printer.write("} else {") - printer.indent { - printer.write("\(dictVar) = \(absenceLiteral);") + return [resultVar] + } else { + return ["\(isSome) ? \(innerExpr) : \(absenceLiteral)"] + } + } + ) + } + + static func optionalLowerParameter( + wrappedType: BridgeType, + kind: JSOptionalKind + ) throws -> IntrinsicJSFragment { + if wrappedType.isSingleParamScalar { + let wasmType = wrappedType.wasmParams[0].type + let coerce = wrappedType.lowerCoerce + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, context in + let (scope, printer) = (context.scope, context.printer) + let value = arguments[0] + let isSomeVar = scope.variable("isSome") + let presenceExpr = kind.presenceCheck(value: value) + printer.write("const \(isSomeVar) = \(presenceExpr);") + let coerced: String + if let coerce { + coerced = coerce.replacingOccurrences(of: "$0", with: value) + } else { + coerced = value } - printer.write("}") - resultExpr = dictVar - default: - resultExpr = "\(isSome) ? \(wrappedValue) : \(absenceLiteral)" + return ["+\(isSomeVar)", "\(isSomeVar) ? \(coerced) : \(wasmType.jsZeroLiteral)"] } + ) + } - return [resultExpr] - } + let innerFragment = try lowerParameter(type: wrappedType) + return try compositeOptionalLowerParameter( + wrappedType: wrappedType, + kind: kind, + innerFragment: innerFragment ) } - static func optionalLowerParameter(wrappedType: BridgeType) throws -> IntrinsicJSFragment { + private static func compositeOptionalLowerParameter( + wrappedType: BridgeType, + kind: JSOptionalKind, + innerFragment: IntrinsicJSFragment + ) throws -> IntrinsicJSFragment { + let isStackConvention = wrappedType.optionalConvention == .stackABI + return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) let value = arguments[0] let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(value) != null;") + printer.write("const \(isSomeVar) = \(kind.presenceCheck(value: value));") - switch wrappedType { - case .swiftStruct(let fullName): - let base = fullName.components(separatedBy: ".").last ?? fullName - printer.write("if (\(isSomeVar)) {") - printer.indent { - printer.write( - "\(JSGlueVariableScope.reservedStructHelpers).\(base).lower(\(value));" - ) - } - printer.write("}") - printer.write("\(JSGlueVariableScope.reservedI32Stack).push(+\(isSomeVar));") - return [] - case .string, .rawValueEnum(_, .string): - let bytesVar = scope.variable("\(value)Bytes") - let idVar = scope.variable("\(value)Id") + let ifBodyPrinter = CodeFragmentPrinter() + let innerResults = try innerFragment.printCode( + [value], + context.with(\.printer, ifBodyPrinter) + ) - printer.write("let \(idVar), \(bytesVar);") - printer.write("if (\(isSomeVar)) {") - printer.indent { - printer.write("\(bytesVar) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(value));") - printer.write("\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(bytesVar));") - } - printer.write("}") - return ["+\(isSomeVar)", "\(isSomeVar) ? \(idVar) : 0", "\(isSomeVar) ? \(bytesVar).length : 0"] - case .jsValue: - let lowered = try jsValueLower.printCode([value], context) - return ["+\(isSomeVar)"] + lowered - case .associatedValueEnum(let fullName): - let base = fullName.components(separatedBy: ".").last ?? fullName - let caseIdVar = scope.variable("\(value)CaseId") - - printer.write("let \(caseIdVar);") - printer.write("if (\(isSomeVar)) {") - printer.indent { - printer.write( - "\(caseIdVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lower(\(value));" - ) - } - printer.write("}") + let resultVars = innerResults.map { _ in scope.variable("result") } + assert( + isStackConvention || resultVars.count == wrappedType.wasmParams.count, + "Inner fragment result count (\(resultVars.count)) must match wasmParams count (\(wrappedType.wasmParams.count)) for \(wrappedType)" + ) + if !resultVars.isEmpty { + printer.write("let \(resultVars.joined(separator: ", "));") + } - return ["+\(isSomeVar)", "\(isSomeVar) ? \(caseIdVar) : 0"] - case .rawValueEnum: - // Raw value enums with optional - falls through to handle based on raw type - return ["+\(isSomeVar)", "\(isSomeVar) ? \(value) : 0"] - case .array(let elementType): - printer.write("if (\(isSomeVar)) {") - try printer.indent { - let arrayLowerFragment = try arrayLower(elementType: elementType) - let _ = try arrayLowerFragment.printCode( - [value], - context - ) + printer.write("if (\(isSomeVar)) {") + printer.indent { + for line in ifBodyPrinter.lines { + printer.write(line) } - printer.write("}") - printer.write("\(JSGlueVariableScope.reservedI32Stack).push(+\(isSomeVar));") - return [] - case .dictionary(let valueType): - printer.write("if (\(isSomeVar)) {") - try printer.indent { - let dictLowerFragment = try dictionaryLower(valueType: valueType) - let _ = try dictLowerFragment.printCode( - [value], - context - ) + for (resultVar, innerResult) in zip(resultVars, innerResults) { + printer.write("\(resultVar) = \(innerResult);") } - printer.write("}") - printer.write("\(JSGlueVariableScope.reservedI32Stack).push(+\(isSomeVar));") - return [] - default: - switch wrappedType { - case .swiftHeapObject: - return ["+\(isSomeVar)", "\(isSomeVar) ? \(value).pointer : 0"] - case .swiftProtocol: - return [ - "+\(isSomeVar)", - "\(isSomeVar) ? \(JSGlueVariableScope.reservedSwift).memory.retain(\(value)) : 0", - ] - case .jsObject: - let idVar = scope.variable("id") - printer.write("let \(idVar);") - printer.write("if (\(isSomeVar)) {") - printer.indent { - printer.write("\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));") + } + + let hasPlaceholders = !isStackConvention && !wrappedType.wasmParams.isEmpty + if hasPlaceholders { + printer.write("} else {") + printer.indent { + for (resultVar, param) in zip(resultVars, wrappedType.wasmParams) { + printer.write("\(resultVar) = \(param.type.jsZeroLiteral);") } - printer.write("}") - return ["+\(isSomeVar)", "\(isSomeVar) ? \(idVar) : 0"] - default: - return ["+\(isSomeVar)", "\(isSomeVar) ? \(value) : 0"] } } + printer.write("}") + + if isStackConvention { + scope.emitPushI32Parameter("+\(isSomeVar)", printer: printer) + return [] + } else { + return ["+\(isSomeVar)"] + resultVars + } } ) } - static func optionalLiftReturn( - wrappedType: BridgeType, - kind: JSOptionalKind - ) -> IntrinsicJSFragment { - let absenceLiteral = kind.absenceLiteral - return IntrinsicJSFragment( + private static func optionalLiftReturnFromStorage(storage: String) -> IntrinsicJSFragment { + IntrinsicJSFragment( parameters: [], - printCode: { arguments, context in + printCode: { _, context in let (scope, printer) = (context.scope, context.printer) let resultVar = scope.variable("optResult") - switch wrappedType { - case .bool: - printer.write("const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnOptionalBool);") - printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalBool) = undefined;") - case .int, .uint: - printer.write("const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnOptionalInt);") - printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalInt) = undefined;") - case .float: - printer.write("const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnOptionalFloat);") - printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalFloat) = undefined;") - case .double: - printer.write("const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnOptionalDouble);") - printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalDouble) = undefined;") - case .string: - printer.write("const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnString);") - printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = undefined;") - case .jsObject, .swiftProtocol: - printer.write("const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnString);") - printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = undefined;") - case .swiftHeapObject(let className): - let pointerVar = scope.variable("pointer") - printer.write( - "const \(pointerVar) = \(JSGlueVariableScope.reservedStorageToReturnOptionalHeapObject);" - ) - printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalHeapObject) = undefined;") - let constructExpr = - context.hasDirectAccessToSwiftClass - ? "\(className).__construct(\(pointerVar))" - : "_exports['\(className)'].__construct(\(pointerVar))" + printer.write("const \(resultVar) = \(storage);") + printer.write("\(storage) = undefined;") + return [resultVar] + } + ) + } + + private static func optionalLiftReturnWithPresenceFlag( + wrappedType: BridgeType, + kind: JSOptionalKind + ) -> IntrinsicJSFragment { + let absenceLiteral = kind.absenceLiteral + return IntrinsicJSFragment( + parameters: [], + printCode: { _, context in + let (scope, printer) = (context.scope, context.printer) + let isSomeVar = scope.variable("isSome") + printer.write("const \(isSomeVar) = \(scope.popI32());") + + let innerFragment = try liftReturn(type: wrappedType) + + let innerPrinter = CodeFragmentPrinter() + let innerResults = try innerFragment.printCode([], context.with(\.printer, innerPrinter)) + let innerExpr = innerResults.first ?? "undefined" + + if innerPrinter.lines.isEmpty { + return ["\(isSomeVar) ? \(innerExpr) : \(absenceLiteral)"] + } + + let resultVar = scope.variable("optResult") + printer.write("let \(resultVar);") + printer.write("if (\(isSomeVar)) {") + printer.indent { + for line in innerPrinter.lines { + printer.write(line) + } + printer.write("\(resultVar) = \(innerExpr);") + } + printer.write("} else {") + printer.indent { + printer.write("\(resultVar) = \(absenceLiteral);") + } + printer.write("}") + return [resultVar] + } + ) + } + + private static func optionalLiftReturnAssociatedEnum( + fullName: String, + kind: JSOptionalKind + ) -> IntrinsicJSFragment { + let base = fullName.components(separatedBy: ".").last ?? fullName + let absenceLiteral = kind.absenceLiteral + return IntrinsicJSFragment( + parameters: [], + printCode: { _, context in + let (scope, printer) = (context.scope, context.printer) + let resultVar = scope.variable("optResult") + let tagVar = scope.variable("tag") + printer.write("const \(tagVar) = \(scope.popI32());") + printer.write( + "const \(resultVar) = \(tagVar) === -1 ? \(absenceLiteral) : \(JSGlueVariableScope.reservedEnumHelpers).\(base).lift(\(tagVar));" + ) + return [resultVar] + } + ) + } + + private static func optionalLiftReturnHeapObject( + className: String, + kind: JSOptionalKind + ) -> IntrinsicJSFragment { + let absenceLiteral = kind.absenceLiteral + return IntrinsicJSFragment( + parameters: [], + printCode: { _, context in + let (scope, printer) = (context.scope, context.printer) + let resultVar = scope.variable("optResult") + let pointerVar = scope.variable("pointer") + printer.write( + "const \(pointerVar) = \(JSGlueVariableScope.reservedStorageToReturnOptionalHeapObject);" + ) + printer.write( + "\(JSGlueVariableScope.reservedStorageToReturnOptionalHeapObject) = undefined;" + ) + let constructExpr = + context.hasDirectAccessToSwiftClass + ? "\(className).__construct(\(pointerVar))" + : "_exports['\(className)'].__construct(\(pointerVar))" + printer.write( + "const \(resultVar) = \(pointerVar) === null ? \(absenceLiteral) : \(constructExpr);" + ) + return [resultVar] + } + ) + } + + private static func optionalLiftReturnStruct( + fullName: String, + kind: JSOptionalKind + ) -> IntrinsicJSFragment { + let base = fullName.components(separatedBy: ".").last ?? fullName + let absenceLiteral = kind.absenceLiteral + return IntrinsicJSFragment( + parameters: [], + printCode: { _, context in + let (scope, printer) = (context.scope, context.printer) + let isSomeVar = scope.variable("isSome") + let resultVar = scope.variable("optResult") + printer.write("const \(isSomeVar) = \(scope.popI32());") + printer.write( + "const \(resultVar) = \(isSomeVar) ? \(JSGlueVariableScope.reservedStructHelpers).\(base).lift() : \(absenceLiteral);" + ) + return [resultVar] + } + ) + } + + static func optionalLiftReturn( + wrappedType: BridgeType, + kind: JSOptionalKind + ) -> IntrinsicJSFragment { + if let scalarKind = wrappedType.optionalScalarKind { + return optionalLiftReturnFromStorage(storage: scalarKind.storageName) + } + if case .sideChannelReturn(let mode) = wrappedType.optionalConvention, mode != .none { + return optionalLiftReturnFromStorage(storage: JSGlueVariableScope.reservedStorageToReturnString) + } + + if case .swiftHeapObject(let className) = wrappedType { + return optionalLiftReturnHeapObject(className: className, kind: kind) + } + + if case .swiftStruct(let fullName) = wrappedType { + return optionalLiftReturnStruct(fullName: fullName, kind: kind) + } + + if wrappedType.nilSentinel.hasSentinel, case .associatedValueEnum(let fullName) = wrappedType { + return optionalLiftReturnAssociatedEnum(fullName: fullName, kind: kind) + } + + return optionalLiftReturnWithPresenceFlag(wrappedType: wrappedType, kind: kind) + } + + private static func optionalLowerReturnToSideChannel( + mode: OptionalSideChannel, + kind: JSOptionalKind + ) -> IntrinsicJSFragment { + IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, context in + let (scope, printer) = (context.scope, context.printer) + let value = arguments[0] + let isSomeVar = scope.variable("isSome") + let presenceExpr = kind.presenceCheck(value: value) + printer.write("const \(isSomeVar) = \(presenceExpr);") + + if mode == .storage { printer.write( - "const \(resultVar) = \(pointerVar) === null ? \(absenceLiteral) : \(constructExpr);" + "\(JSGlueVariableScope.reservedStorageToReturnString) = \(isSomeVar) ? \(value) : \(kind.absenceLiteral);" ) - case .caseEnum: - printer.write("const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnOptionalInt);") - printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalInt) = undefined;") - case .rawValueEnum(_, let rawType): - switch rawType { - case .string: - printer.write("const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnString);") - printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = undefined;") - case .bool: - printer.write( - "const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnOptionalBool);" - ) - printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalBool) = undefined;") - case .float: - printer.write( - "const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnOptionalFloat);" - ) - printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalFloat) = undefined;") - case .double: - printer.write( - "const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnOptionalDouble);" - ) - printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalDouble) = undefined;") - default: - printer.write("const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnOptionalInt);") - printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalInt) = undefined;") - } - case .associatedValueEnum(let fullName): - let base = fullName.components(separatedBy: ".").last ?? fullName - let tagVar = scope.variable("tag") - printer.write("const \(tagVar) = \(scope.popI32());") - let isNullVar = scope.variable("isNull") - printer.write("const \(isNullVar) = (\(tagVar) === -1);") - printer.write("let \(resultVar);") - printer.write("if (\(isNullVar)) {") - printer.indent { - printer.write("\(resultVar) = \(absenceLiteral);") - } - printer.write("} else {") - printer.indent { - printer.write( - "\(resultVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lift(\(tagVar));" - ) - } - printer.write("}") - case .swiftStruct(let fullName): - let base = fullName.components(separatedBy: ".").last ?? fullName - let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(scope.popI32());") - printer.write("let \(resultVar);") + } else { + let idVar = scope.variable("id") + printer.write("let \(idVar) = 0;") printer.write("if (\(isSomeVar)) {") printer.indent { printer.write( - "\(resultVar) = \(JSGlueVariableScope.reservedStructHelpers).\(base).lift();" + "\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));" ) } - printer.write("} else {") - printer.indent { - printer.write("\(resultVar) = \(absenceLiteral);") - } - printer.write("}") - case .array(let elementType): - let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(scope.popI32());") - printer.write("let \(resultVar);") - printer.write("if (\(isSomeVar)) {") - try printer.indent { - let arrayLiftFragment = try arrayLift(elementType: elementType) - let liftResults = try arrayLiftFragment.printCode([], context) - if let liftResult = liftResults.first { - printer.write("\(resultVar) = \(liftResult);") - } - } - printer.write("} else {") - printer.indent { - printer.write("\(resultVar) = \(absenceLiteral);") - } printer.write("}") - case .dictionary(let valueType): - let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(scope.popI32());") - printer.write("let \(resultVar);") - printer.write("if (\(isSomeVar)) {") - try printer.indent { - let dictLiftFragment = try dictionaryLift(valueType: valueType) - let liftResults = try dictLiftFragment.printCode([], context) - if let liftResult = liftResults.first { - printer.write("\(resultVar) = \(liftResult);") - } - } - printer.write("} else {") - printer.indent { - printer.write("\(resultVar) = \(absenceLiteral);") - } - printer.write("}") - case .jsValue: - let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(scope.popI32());") - printer.write("let \(resultVar);") - printer.write("if (\(isSomeVar)) {") - try printer.indent { - let lifted = try jsValueLift.printCode([], context) - if let liftedValue = lifted.first { - printer.write("\(resultVar) = \(liftedValue);") - } - } - printer.write("} else {") - printer.indent { - printer.write("\(resultVar) = null;") + printer.write("bjs[\"swift_js_return_optional_object\"](\(isSomeVar) ? 1 : 0, \(idVar));") + } + + return [] + } + ) + } + + private static func optionalLowerReturnWithPresenceFlag( + wrappedType: BridgeType, + kind: JSOptionalKind, + innerFragment: IntrinsicJSFragment + ) -> IntrinsicJSFragment { + IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, context in + let (scope, printer) = (context.scope, context.printer) + let value = arguments[0] + let isSomeVar = scope.variable("isSome") + let presenceExpr = kind.presenceCheck(value: value) + printer.write("const \(isSomeVar) = \(presenceExpr);") + + let innerPrinter = CodeFragmentPrinter() + let innerResults = try innerFragment.printCode( + [value], + context.with(\.printer, innerPrinter) + ) + if !innerResults.isEmpty { + throw BridgeJSLinkError( + message: "Unsupported wrapped type for returning from JS function: \(wrappedType)" + ) + } + + printer.write("if (\(isSomeVar)) {") + printer.indent { + for line in innerPrinter.lines { + printer.write(line) } - printer.write("}") - default: - printer.write("const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnString);") - printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = undefined;") } - return [resultVar] + printer.write("}") + + scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) + return [] } ) } @@ -1068,6 +1014,70 @@ struct IntrinsicJSFragment: Sendable { default: break } + if let scalarKind = wrappedType.optionalScalarKind, + !wrappedType.nilSentinel.hasSentinel, wrappedType.wasmParams.count == 1 + { + let wasmType = wrappedType.wasmParams[0].type + let funcName = scalarKind.funcName + let stackCoerce = wrappedType.stackLowerCoerce + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, context in + let (scope, printer) = (context.scope, context.printer) + let value = arguments[0] + let isSomeVar = scope.variable("isSome") + let presenceExpr = kind.presenceCheck(value: value) + printer.write("const \(isSomeVar) = \(presenceExpr);") + var coerced: String + if let coerce = stackCoerce { + coerced = coerce.replacingOccurrences(of: "$0", with: value) + if coerced.contains("?") && !coerced.hasPrefix("(") { + coerced = "(\(coerced))" + } + } else { + coerced = value + } + printer.write( + "bjs[\"\(funcName)\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? \(coerced) : \(wasmType.jsZeroLiteral));" + ) + return [] + } + ) + } + + if case .sideChannelReturn(let mode) = wrappedType.optionalConvention { + if mode == .none { + throw BridgeJSLinkError( + message: "Unsupported wrapped type for returning from JS function: \(wrappedType)" + ) + } + return optionalLowerReturnToSideChannel(mode: mode, kind: kind) + } + + if wrappedType.nilSentinel.hasSentinel { + let innerFragment = try lowerReturn(type: wrappedType, context: .exportSwift) + return sentinelOptionalLowerReturn( + wrappedType: wrappedType, + kind: kind, + innerFragment: innerFragment + ) + } + + let innerFragment = try lowerReturn(type: wrappedType, context: .exportSwift) + return optionalLowerReturnWithPresenceFlag( + wrappedType: wrappedType, + kind: kind, + innerFragment: innerFragment + ) + } + + private static func sentinelOptionalLowerReturn( + wrappedType: BridgeType, + kind: JSOptionalKind, + innerFragment: IntrinsicJSFragment + ) -> IntrinsicJSFragment { + let sentinelLiteral = wrappedType.nilSentinel.jsLiteral + return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in @@ -1077,197 +1087,159 @@ struct IntrinsicJSFragment: Sendable { let presenceExpr = kind.presenceCheck(value: value) printer.write("const \(isSomeVar) = \(presenceExpr);") - switch wrappedType { - case .bool: - printer.write( - "bjs[\"swift_js_return_optional_bool\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? (\(value) ? 1 : 0) : 0);" - ) - case .int, .uint: - printer.write( - "bjs[\"swift_js_return_optional_int\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? (\(value) | 0) : 0);" - ) - case .caseEnum: - printer.write("return \(isSomeVar) ? (\(value) | 0) : -1;") - case .float: - printer.write( - "bjs[\"swift_js_return_optional_float\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? Math.fround(\(value)) : 0.0);" - ) - case .double: - printer.write( - "bjs[\"swift_js_return_optional_double\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? \(value) : 0.0);" - ) - case .string: - printer.write("if (\(isSomeVar)) {") - printer.indent { - printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = \(value);") - } - printer.write("} else {") - printer.indent { - printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = null;") - } - printer.write("}") - case .jsObject, .swiftProtocol: - let idVar = scope.variable("id") - printer.write("let \(idVar) = 0;") + let bufferPrinter = CodeFragmentPrinter() + let innerResults = try innerFragment.printCode( + [value], + context.with(\.printer, bufferPrinter) + ) + + let hasSideEffects = !bufferPrinter.lines.isEmpty + let innerExpr = innerResults.first + + if hasSideEffects { printer.write("if (\(isSomeVar)) {") printer.indent { - printer.write("\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));") - } - printer.write("}") - printer.write("bjs[\"swift_js_return_optional_object\"](\(isSomeVar) ? 1 : 0, \(idVar));") - case .jsValue: - if value != "undefined" { - let lowered = try jsValueLower.printCode([value], context) - let kindVar = lowered[0] - let payload1Var = lowered[1] - let payload2Var = lowered[2] - scope.emitPushI32Parameter(kindVar, printer: printer) - scope.emitPushI32Parameter(payload1Var, printer: printer) - scope.emitPushF64Parameter(payload2Var, printer: printer) - } - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - case .swiftHeapObject: - printer.write("return \(isSomeVar) ? \(value).pointer : 0;") - case .array(let elementType): - printer.write("if (\(isSomeVar)) {") - try printer.indent { - let arrayLowerFragment = try arrayLower(elementType: elementType) - let _ = try arrayLowerFragment.printCode( - [value], - context - ) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - case .rawValueEnum(_, let rawType): - switch rawType { - case .string: - printer.write("if (\(isSomeVar)) {") - printer.indent { - printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = \(value);") + for line in bufferPrinter.lines { + printer.write(line) } - printer.write("} else {") - printer.indent { - printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = null;") + if let expr = innerExpr { + printer.write("return \(expr);") } - printer.write("}") - default: - switch rawType { - case .bool: - printer.write( - "bjs[\"swift_js_return_optional_bool\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? (\(value) ? 1 : 0) : 0);" - ) - case .float: - printer.write( - "bjs[\"swift_js_return_optional_float\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? Math.fround(\(value)) : 0.0);" - ) - case .double: - printer.write( - "bjs[\"swift_js_return_optional_double\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? \(value) : 0.0);" - ) - default: - printer.write( - "bjs[\"swift_js_return_optional_int\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? (\(value) | 0) : 0);" - ) - } - } - case .associatedValueEnum(let fullName): - let base = fullName.components(separatedBy: ".").last ?? fullName - let caseIdVar = scope.variable("caseId") - printer.write("if (\(isSomeVar)) {") - printer.indent { - printer.write( - "const \(caseIdVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lower(\(value));" - ) - printer.write("return \(caseIdVar);") } printer.write("} else {") printer.indent { - printer.write("return -1;") + printer.write("return \(sentinelLiteral);") } printer.write("}") - case .dictionary(let valueType): - printer.write("if (\(isSomeVar)) {") - try printer.indent { - let entriesVar = scope.variable("entries") - let entryVar = scope.variable("entry") - printer.write("const \(entriesVar) = Object.entries(\(value));") - printer.write("for (const \(entryVar) of \(entriesVar)) {") - try printer.indent { - let keyVar = scope.variable("key") - let valueVar = scope.variable("value") - printer.write("const [\(keyVar), \(valueVar)] = \(entryVar);") - - let keyFragment = try stackLowerFragment(elementType: .string) - let _ = try keyFragment.printCode( - [keyVar], - context - ) + } else if let expr = innerExpr { + printer.write("return \(isSomeVar) ? \(expr) : \(sentinelLiteral);") + } + + return [] + } + ) + } + + // MARK: - Protocol Support + + static func protocolPropertyOptionalToSideChannel(wrappedType: BridgeType) throws -> IntrinsicJSFragment { + if let scalarKind = wrappedType.optionalScalarKind { + let storage = scalarKind.storageName + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, context in + context.printer.write("\(storage) = \(arguments[0]);") + return [] + } + ) + } + + if case .sideChannelReturn(let mode) = wrappedType.optionalConvention, + mode != .none + { + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, context in + let printer = context.printer + let value = arguments[0] - let valueFragment = try stackLowerFragment(elementType: valueType) - let _ = try valueFragment.printCode( - [valueVar], - context - ) - } - printer.write("}") - scope.emitPushI32Parameter("\(entriesVar).length", printer: printer) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - default: - throw BridgeJSLinkError( - message: "Unsupported wrapped type for returning from JS function: \(wrappedType)" - ) + printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = \(value);") + + return [] } + ) + } - return [] - } + throw BridgeJSLinkError( + message: "Type \(wrappedType) does not use side channel for protocol property returns" ) } - // MARK: - Protocol Support + // MARK: - JS Glue Descriptor Helpers - static func protocolPropertyOptionalToSideChannel(wrappedType: BridgeType) throws -> IntrinsicJSFragment { - switch wrappedType { - case .string, .int, .float, .double, .jsObject, .swiftProtocol: - break - case .rawValueEnum(_, let rawType): - switch rawType { - case .string, .int, .float, .double: - break - default: - throw BridgeJSLinkError( - message: "Unsupported raw value enum type for protocol property side channel: \(rawType)" - ) - } - default: - throw BridgeJSLinkError( - message: "Type \(wrappedType) does not use side channel for protocol property returns" - ) + private static func popExpression(for wasmType: WasmCoreType, scope: JSGlueVariableScope) -> String { + switch wasmType { + case .i32: return scope.popI32() + case .f32: return scope.popF32() + case .f64: return scope.popF64() + case .pointer: return scope.popPointer() + case .i64: return scope.popI32() } + } - return IntrinsicJSFragment( + private static func emitPush( + for wasmType: WasmCoreType, + value: String, + scope: JSGlueVariableScope, + printer: CodeFragmentPrinter + ) { + switch wasmType { + case .i32: scope.emitPushI32Parameter(value, printer: printer) + case .f32: scope.emitPushF32Parameter(value, printer: printer) + case .f64: scope.emitPushF64Parameter(value, printer: printer) + case .pointer: scope.emitPushPointerParameter(value, printer: printer) + case .i64: scope.emitPushI32Parameter(value, printer: printer) + } + } + + @discardableResult + private static func emitOptionalPlaceholders( + for wrappedType: BridgeType, + scope: JSGlueVariableScope, + printer: CodeFragmentPrinter + ) -> Bool { + let params = wrappedType.wasmParams + if params.isEmpty { + return false + } + for param in params { + emitPush(for: param.type, value: param.type.jsZeroLiteral, scope: scope, printer: printer) + } + return true + } + + private static func stackOptionalLower( + wrappedType: BridgeType, + kind: JSOptionalKind, + innerFragment: IntrinsicJSFragment + ) -> IntrinsicJSFragment { + IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in - let printer = context.printer + let (scope, printer) = (context.scope, context.printer) let value = arguments[0] + let isSomeVar = scope.variable("isSome") + printer.write("const \(isSomeVar) = \(kind.presenceCheck(value: value));") - switch wrappedType { - case .string, .rawValueEnum(_, .string): - printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = \(value);") - case .int, .rawValueEnum(_, .int): - printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalInt) = \(value);") - case .float, .rawValueEnum(_, .float): - printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalFloat) = \(value);") - case .double, .rawValueEnum(_, .double): - printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalDouble) = \(value);") - case .jsObject, .swiftProtocol: - printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = \(value);") - default: - fatalError("Unsupported type in protocolPropertyOptionalToSideChannel: \(wrappedType)") + let ifBodyPrinter = CodeFragmentPrinter() + try ifBodyPrinter.indent { + let _ = try innerFragment.printCode( + [value], + context.with(\.printer, ifBodyPrinter) + ) } - + printer.write("if (\(isSomeVar)) {") + for line in ifBodyPrinter.lines { + printer.write(line) + } + let placeholderPrinter = CodeFragmentPrinter() + let hasPlaceholders = emitOptionalPlaceholders( + for: wrappedType, + scope: scope, + printer: placeholderPrinter + ) + if hasPlaceholders { + printer.write("} else {") + printer.indent { + for line in placeholderPrinter.lines { + printer.write(line) + } + } + printer.write("}") + } else { + printer.write("}") + } + scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) return [] } ) @@ -1278,22 +1250,19 @@ struct IntrinsicJSFragment: Sendable { /// Returns a fragment that lowers a JS value to Wasm core values for parameters static func lowerParameter(type: BridgeType) throws -> IntrinsicJSFragment { switch type { - case .int, .uint, .float, .double, .bool, .unsafePointer: return .identity + case .bool, .int, .uint, .float, .double, .unsafePointer, .caseEnum: + return .identity + case .rawValueEnum(_, let rawType) where rawType != .string: + return .identity case .string: return .stringLowerParameter case .jsObject: return .jsObjectLowerParameter case .jsValue: return .jsValueLower - case .swiftHeapObject: - return .swiftHeapObjectLowerParameter + case .swiftHeapObject: return .swiftHeapObjectLowerParameter case .swiftProtocol: return .jsObjectLowerParameter case .void: return .void - case .nullable(let wrappedType, _): - return try .optionalLowerParameter(wrappedType: wrappedType) - case .caseEnum: return .identity - case .rawValueEnum(_, let rawType): - switch rawType { - case .string: return .stringLowerParameter - default: return .identity - } + case .nullable(let wrappedType, let kind): + return try .optionalLowerParameter(wrappedType: wrappedType, kind: kind) + case .rawValueEnum(_, .string): return .stringLowerParameter case .associatedValueEnum(let fullName): let base = fullName.components(separatedBy: ".").last ?? fullName return .associatedEnumLowerParameter(enumBase: base) @@ -1319,31 +1288,31 @@ struct IntrinsicJSFragment: Sendable { return try arrayLower(elementType: elementType) case .dictionary(let valueType): return try dictionaryLower(valueType: valueType) + default: + throw BridgeJSLinkError(message: "Unhandled type in lowerParameter: \(type)") } } /// Returns a fragment that lifts a Wasm core value to a JS value for return values static func liftReturn(type: BridgeType) throws -> IntrinsicJSFragment { switch type { - case .int, .float, .double: return .identity - case .uint: return .uintLiftReturn - case .bool: return .boolLiftReturn + case .bool, .rawValueEnum(_, .bool): + return .boolLiftReturn + case .uint: + return .uintLiftReturn + case .int, .float, .double, .unsafePointer, .caseEnum: + return .identity + case .rawValueEnum(_, let rawType) where rawType != .string && rawType != .bool: + return .identity case .string: return .stringLiftReturn case .jsObject: return .jsObjectLiftReturn case .jsValue: return .jsValueLift case .swiftHeapObject(let name): return .swiftHeapObjectLiftReturn(name) - case .unsafePointer: return .identity case .swiftProtocol: return .jsObjectLiftReturn case .void: return .void case .nullable(let wrappedType, let kind): return .optionalLiftReturn(wrappedType: wrappedType, kind: kind) - case .caseEnum: return .identity - case .rawValueEnum(_, let rawType): - switch rawType { - case .string: return .stringLiftReturn - case .bool: return .boolLiftReturn - default: return .identity - } + case .rawValueEnum(_, .string): return .stringLiftReturn case .associatedValueEnum(let fullName): let base = fullName.components(separatedBy: ".").last ?? fullName return .associatedEnumLiftReturn(enumBase: base) @@ -1366,6 +1335,8 @@ struct IntrinsicJSFragment: Sendable { return try arrayLift(elementType: elementType) case .dictionary(let valueType): return try dictionaryLift(valueType: valueType) + default: + throw BridgeJSLinkError(message: "Unhandled type in liftReturn: \(type)") } } @@ -1374,13 +1345,17 @@ struct IntrinsicJSFragment: Sendable { /// Returns a fragment that lifts Wasm core values to JS values for parameters static func liftParameter(type: BridgeType, context: BridgeContext = .importTS) throws -> IntrinsicJSFragment { switch type { - case .int, .float, .double: return .identity - case .uint: return .uintLiftParameter - case .bool: return .boolLiftParameter + case .bool, .rawValueEnum(_, .bool): + return .boolLiftParameter + case .uint: + return .uintLiftParameter + case .int, .float, .double, .unsafePointer, .caseEnum: + return .identity + case .rawValueEnum(_, let rawType) where rawType != .string && rawType != .bool: + return .identity case .string: return .stringLiftParameter case .jsObject: return .jsObjectLiftParameter case .jsValue: return .jsValueLiftParameter - case .unsafePointer: return .identity case .swiftHeapObject(let name): return .swiftHeapObjectLiftParameter(name) case .swiftProtocol: return .jsObjectLiftParameter @@ -1389,14 +1364,8 @@ struct IntrinsicJSFragment: Sendable { message: "Void can't appear in parameters of imported JS functions" ) case .nullable(let wrappedType, let kind): - return try .optionalLiftParameter(wrappedType: wrappedType, kind: kind) - case .caseEnum: return .identity - case .rawValueEnum(_, let rawType): - switch rawType { - case .string: return .stringLiftParameter - case .bool: return .boolLiftParameter - default: return .identity - } + return try .optionalLiftParameter(wrappedType: wrappedType, kind: kind, context: context) + case .rawValueEnum(_, .string): return .stringLiftParameter case .associatedValueEnum(let fullName): switch context { case .importTS: @@ -1454,31 +1423,29 @@ struct IntrinsicJSFragment: Sendable { return try arrayLift(elementType: elementType) case .dictionary(let valueType): return try dictionaryLift(valueType: valueType) + default: + throw BridgeJSLinkError(message: "Unhandled type in liftParameter: \(type)") } } /// Returns a fragment that lowers a JS value to Wasm core values for return values static func lowerReturn(type: BridgeType, context: BridgeContext = .importTS) throws -> IntrinsicJSFragment { switch type { - case .int, .uint, .float, .double: return .identity - case .bool: return .boolLowerReturn + case .bool, .rawValueEnum(_, .bool): + return .boolLowerReturn + case .int, .uint, .float, .double, .unsafePointer, .caseEnum: + return .identity + case .rawValueEnum(_, let rawType) where rawType != .string && rawType != .bool: + return .identity case .string: return .stringLowerReturn case .jsObject: return .jsObjectLowerReturn case .jsValue: return .jsValueLowerReturn(context: context) - case .unsafePointer: return .identity - case .swiftHeapObject: - return .swiftHeapObjectLowerReturn + case .swiftHeapObject: return .swiftHeapObjectLowerReturn case .swiftProtocol: return .jsObjectLowerReturn case .void: return .void case .nullable(let wrappedType, let kind): return try .optionalLowerReturn(wrappedType: wrappedType, kind: kind) - case .caseEnum: return .identity - case .rawValueEnum(_, let rawType): - switch rawType { - case .string: return .stringLowerReturn - case .bool: return .boolLowerReturn - default: return .identity - } + case .rawValueEnum(_, .string): return .stringLowerReturn case .associatedValueEnum(let fullName): switch context { case .importTS: @@ -1492,7 +1459,6 @@ struct IntrinsicJSFragment: Sendable { case .swiftStruct(let fullName): switch context { case .importTS: - // ImportTS expects Swift structs to come back as a retained JS object ID. return .jsObjectLowerReturn case .exportSwift: return swiftStructLowerReturn(fullName: fullName) @@ -1519,6 +1485,8 @@ struct IntrinsicJSFragment: Sendable { return try arrayLower(elementType: elementType) case .dictionary(let valueType): return try dictionaryLower(valueType: valueType) + default: + throw BridgeJSLinkError(message: "Unhandled type in lowerReturn: \(type)") } } @@ -1578,107 +1546,77 @@ struct IntrinsicJSFragment: Sendable { let (scope, printer) = (context.scope, context.printer) let enumName = arguments[0] - printer.write("const __bjs_create\(enumName)Helpers = () => {") - printer.indent() - printer.write( - "return () => ({" - ) - printer.indent() - - // Generate lower function - printer.write("lower: (value) => {") + printer.write("const __bjs_create\(enumName)Helpers = () => ({") try printer.indent { - printer.write("const enumTag = value.tag;") - printer.write("switch (enumTag) {") + printer.write("lower: (value) => {") try printer.indent { - let lowerPrinter = CodeFragmentPrinter() - for enumCase in enumDefinition.cases { - let caseName = enumCase.name.capitalizedFirstLetter - let caseScope = scope.makeChildScope() - let fragment = IntrinsicJSFragment.associatedValuePushPayload(enumCase: enumCase) - _ = try fragment.printCode( - ["value", enumName, caseName], - context.with(\.scope, caseScope).with(\.printer, lowerPrinter) - ) - } + printer.write("const enumTag = value.tag;") + printer.write("switch (enumTag) {") + try printer.indent { + let lowerPrinter = CodeFragmentPrinter() + for enumCase in enumDefinition.cases { + let caseName = enumCase.name.capitalizedFirstLetter + let caseScope = scope.makeChildScope() + let fragment = IntrinsicJSFragment.associatedValuePushPayload( + enumCase: enumCase + ) + _ = try fragment.printCode( + ["value", enumName, caseName], + context.with(\.scope, caseScope).with(\.printer, lowerPrinter) + ) + } - for line in lowerPrinter.lines { - printer.write(line) - } + for line in lowerPrinter.lines { + printer.write(line) + } - printer.write("default: throw new Error(\"Unknown \(enumName) tag: \" + String(enumTag));") + printer.write( + "default: throw new Error(\"Unknown \(enumName) tag: \" + String(enumTag));" + ) + } + printer.write("}") } - printer.write("}") - } - printer.write("},") + printer.write("},") - // Generate lift function - printer.write( - "lift: (tag) => {" - ) - try printer.indent { - printer.write("tag = tag | 0;") - printer.write("switch (tag) {") + printer.write("lift: (tag) => {") try printer.indent { - let liftPrinter = CodeFragmentPrinter() - for enumCase in enumDefinition.cases { - let caseName = enumCase.name.capitalizedFirstLetter - let caseScope = scope.makeChildScope() + printer.write("tag = tag | 0;") + printer.write("switch (tag) {") + try printer.indent { + let liftPrinter = CodeFragmentPrinter() + for enumCase in enumDefinition.cases { + let caseName = enumCase.name.capitalizedFirstLetter + let caseScope = scope.makeChildScope() - let fragment = IntrinsicJSFragment.associatedValuePopPayload(enumCase: enumCase) - _ = try fragment.printCode( - [enumName, caseName], - context.with(\.scope, caseScope).with(\.printer, liftPrinter) - ) - } + let fragment = IntrinsicJSFragment.associatedValuePopPayload( + enumCase: enumCase + ) + _ = try fragment.printCode( + [enumName, caseName], + context.with(\.scope, caseScope).with(\.printer, liftPrinter) + ) + } - for line in liftPrinter.lines { - printer.write(line) - } + for line in liftPrinter.lines { + printer.write(line) + } - printer.write( - "default: throw new Error(\"Unknown \(enumName) tag returned from Swift: \" + String(tag));" - ) + printer.write( + "default: throw new Error(\"Unknown \(enumName) tag returned from Swift: \" + String(tag));" + ) + } + printer.write("}") } printer.write("}") } - printer.write("}") - printer.unindent() printer.write("});") - printer.unindent() - printer.write("};") - - return [] - } - ) - } - - static func simpleEnumHelper(enumDefinition: ExportedEnum) -> IntrinsicJSFragment { - return IntrinsicJSFragment( - parameters: ["enumName"], - printCode: { arguments, context in - let printer = context.printer - let enumName = arguments[0] - printer.write("const \(enumName) = {") - printer.indent { - for (index, enumCase) in enumDefinition.cases.enumerated() { - let caseName = enumCase.name.capitalizedFirstLetter - let value = enumCase.jsValue( - rawType: enumDefinition.rawType, - index: index - ) - printer.write("\(caseName): \(value),") - } - } - printer.write("};") - printer.nextLine() return [] } ) } - static func rawValueEnumHelper(enumDefinition: ExportedEnum) -> IntrinsicJSFragment { + static func caseEnumHelper(enumDefinition: ExportedEnum) -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: ["enumName"], printCode: { arguments, context in @@ -1717,7 +1655,6 @@ struct IntrinsicJSFragment: Sendable { if enumCase.associatedValues.isEmpty { printer.write("return \(enumName).Tag.\(caseName);") } else { - // Process associated values in reverse order (to match the order they'll be popped) let reversedValues = enumCase.associatedValues.enumerated().reversed() for (associatedValueIndex, associatedValue) in reversedValues { @@ -1770,175 +1707,11 @@ struct IntrinsicJSFragment: Sendable { for line in casePrinter.lines { printer.write(line) } - printer.write( - "return { tag: \(enumName).Tag.\(caseName), \(fieldPairs.reversed().joined(separator: ", ")) };" - ) - } - printer.write("}") - } - - return [] - } - ) - } - - private static func associatedValuePushPayload(type: BridgeType) throws -> IntrinsicJSFragment { - switch type { - case .nullable(let wrappedType, let kind): - return associatedValueOptionalPushPayload(wrappedType: wrappedType, kind: kind) - default: - return try stackLowerFragment(elementType: type) - } - } - - private static func associatedValueOptionalPushPayload( - wrappedType: BridgeType, - kind: JSOptionalKind - ) -> IntrinsicJSFragment { - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let value = arguments[0] - let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(kind.presenceCheck(value: value));") - - switch wrappedType { - case .string: - let idVar = scope.variable("id") - printer.write("let \(idVar);") - printer.write("if (\(isSomeVar)) {") - printer.indent { - let bytesVar = scope.variable("bytes") - printer.write( - "let \(bytesVar) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(value));" - ) - printer.write("\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(bytesVar));") - scope.emitPushI32Parameter("\(bytesVar).length", printer: printer) - scope.emitPushI32Parameter(idVar, printer: printer) - } - printer.write("} else {") - printer.indent { - scope.emitPushI32Parameter("0", printer: printer) - scope.emitPushI32Parameter("0", printer: printer) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - case .int, .uint: - scope.emitPushI32Parameter("\(isSomeVar) ? (\(value) | 0) : 0", printer: printer) - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - case .bool: - scope.emitPushI32Parameter("\(isSomeVar) ? (\(value) ? 1 : 0) : 0", printer: printer) - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - case .float: - scope.emitPushF32Parameter("\(isSomeVar) ? Math.fround(\(value)) : 0.0", printer: printer) - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - case .double: - scope.emitPushF64Parameter("\(isSomeVar) ? \(value) : 0.0", printer: printer) - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - case .caseEnum: - scope.emitPushI32Parameter("\(isSomeVar) ? (\(value) | 0) : 0", printer: printer) - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - case .rawValueEnum(_, let rawType): - switch rawType { - case .string: - let idVar = scope.variable("id") - printer.write("let \(idVar);") - printer.write("if (\(isSomeVar)) {") - printer.indent { - let bytesVar = scope.variable("bytes") - printer.write( - "let \(bytesVar) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(value));" - ) - printer.write( - "\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(bytesVar));" - ) - scope.emitPushI32Parameter("\(bytesVar).length", printer: printer) - scope.emitPushI32Parameter(idVar, printer: printer) - } - printer.write("} else {") - printer.indent { - scope.emitPushI32Parameter("0", printer: printer) - scope.emitPushI32Parameter("0", printer: printer) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - case .float: - scope.emitPushF32Parameter("\(isSomeVar) ? Math.fround(\(value)) : 0.0", printer: printer) - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - case .double: - scope.emitPushF64Parameter("\(isSomeVar) ? \(value) : 0.0", printer: printer) - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - default: - scope.emitPushI32Parameter("\(isSomeVar) ? (\(value) | 0) : 0", printer: printer) - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - } - case .swiftStruct(let structName): - let structBase = structName.components(separatedBy: ".").last ?? structName - printer.write("if (\(isSomeVar)) {") - printer.indent { - printer.write( - "\(JSGlueVariableScope.reservedStructHelpers).\(structBase).lower(\(value));" - ) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - case .swiftHeapObject: - printer.write("if (\(isSomeVar)) {") - printer.indent { - scope.emitPushPointerParameter("\(value).pointer", printer: printer) - } - printer.write("} else {") - printer.indent { - scope.emitPushPointerParameter("0", printer: printer) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - case .jsObject: - let idVar = scope.variable("id") - printer.write("let \(idVar);") - printer.write("if (\(isSomeVar)) {") - printer.indent { - printer.write("\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));") - scope.emitPushI32Parameter(idVar, printer: printer) - } - printer.write("} else {") - printer.indent { - printer.write("\(idVar) = undefined;") - scope.emitPushI32Parameter("0", printer: printer) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - case .associatedValueEnum(let enumName): - let base = enumName.components(separatedBy: ".").last ?? enumName - let caseIdVar = scope.variable("enumCaseId") - printer.write("let \(caseIdVar);") - printer.write("if (\(isSomeVar)) {") - printer.indent { - printer.write( - "\(caseIdVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lower(\(value));" - ) - scope.emitPushI32Parameter(caseIdVar, printer: printer) - } - printer.write("} else {") - printer.indent { - scope.emitPushI32Parameter("0", printer: printer) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - case .array(let elementType): - printer.write("if (\(isSomeVar)) {") - try printer.indent { - let arrFragment = try arrayLower(elementType: elementType) - _ = try arrFragment.printCode( - [value], - context + printer.write( + "return { tag: \(enumName).Tag.\(caseName), \(fieldPairs.reversed().joined(separator: ", ")) };" ) } printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - default: - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) } return [] @@ -1946,6 +1719,58 @@ struct IntrinsicJSFragment: Sendable { ) } + private static func associatedValuePushPayload(type: BridgeType) throws -> IntrinsicJSFragment { + switch type { + case .nullable(let wrappedType, let kind): + return try associatedValueOptionalPushPayload(wrappedType: wrappedType, kind: kind) + default: + return try stackLowerFragment(elementType: type) + } + } + + private static func associatedValueOptionalPushPayload( + wrappedType: BridgeType, + kind: JSOptionalKind + ) throws -> IntrinsicJSFragment { + if wrappedType.isSingleParamScalar { + let wasmType = wrappedType.wasmParams[0].type + let stackCoerce = wrappedType.stackLowerCoerce + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, context in + let (scope, printer) = (context.scope, context.printer) + let value = arguments[0] + let isSomeVar = scope.variable("isSome") + printer.write("const \(isSomeVar) = \(kind.presenceCheck(value: value));") + var coerced: String + if let coerce = stackCoerce { + coerced = coerce.replacingOccurrences(of: "$0", with: value) + if coerced.contains("?") && !coerced.hasPrefix("(") { + coerced = "(\(coerced))" + } + } else { + coerced = value + } + emitPush( + for: wasmType, + value: "\(isSomeVar) ? \(coerced) : \(wasmType.jsZeroLiteral)", + scope: scope, + printer: printer + ) + scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) + return [] + } + ) + } + + let innerFragment = try stackLowerFragment(elementType: wrappedType) + return stackOptionalLower( + wrappedType: wrappedType, + kind: kind, + innerFragment: innerFragment + ) + } + private static func associatedValuePopPayload(type: BridgeType) throws -> IntrinsicJSFragment { switch type { case .nullable(let wrappedType, let kind): @@ -2000,33 +1825,26 @@ struct IntrinsicJSFragment: Sendable { ) } - static func swiftStructLowerReturn(fullName: String) -> IntrinsicJSFragment { - let base = fullName.components(separatedBy: ".").last ?? fullName - return IntrinsicJSFragment( + private static func swiftStructLower(structBase: String) -> IntrinsicJSFragment { + IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in let printer = context.printer let value = arguments[0] printer.write( - "\(JSGlueVariableScope.reservedStructHelpers).\(base).lower(\(value));" + "\(JSGlueVariableScope.reservedStructHelpers).\(structBase).lower(\(value));" ) return [] } ) } + static func swiftStructLowerReturn(fullName: String) -> IntrinsicJSFragment { + swiftStructLower(structBase: fullName.components(separatedBy: ".").last ?? fullName) + } + static func swiftStructLowerParameter(structBase: String) -> IntrinsicJSFragment { - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let printer = context.printer - let value = arguments[0] - printer.write( - "\(JSGlueVariableScope.reservedStructHelpers).\(structBase).lower(\(value));" - ) - return [] - } - ) + swiftStructLower(structBase: structBase) } static func swiftStructLiftReturn(structBase: String) -> IntrinsicJSFragment { @@ -2161,6 +1979,29 @@ struct IntrinsicJSFragment: Sendable { } private static func stackLiftFragment(elementType: BridgeType) throws -> IntrinsicJSFragment { + if case .nullable(let wrappedType, let kind) = elementType { + return try optionalElementRaiseFragment(wrappedType: wrappedType, kind: kind) + } + if elementType.isSingleParamScalar { + let wasmType = elementType.wasmParams[0].type + let coerce = elementType.liftCoerce + let varHint = elementType.varHint + return IntrinsicJSFragment( + parameters: [], + printCode: { _, context in + let (scope, printer) = (context.scope, context.printer) + let popExpr = popExpression(for: wasmType, scope: scope) + let varName = scope.variable(varHint) + if let transform = coerce { + let inlined = transform.replacingOccurrences(of: "$0", with: popExpr) + printer.write("const \(varName) = \(inlined);") + } else { + printer.write("const \(varName) = \(popExpr);") + } + return [varName] + } + ) + } switch elementType { case .jsValue: return IntrinsicJSFragment( @@ -2191,44 +2032,14 @@ struct IntrinsicJSFragment: Sendable { return [strVar] } ) - case .bool: - return IntrinsicJSFragment( - parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let bVar = scope.variable("bool") - printer.write("const \(bVar) = \(scope.popI32()) !== 0;") - return [bVar] - } - ) - case .int, .uint: - return IntrinsicJSFragment( - parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let iVar = scope.variable("int") - printer.write("const \(iVar) = \(scope.popI32());") - return [iVar] - } - ) - case .float: - return IntrinsicJSFragment( - parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let fVar = scope.variable("f32") - printer.write("const \(fVar) = \(scope.popF32());") - return [fVar] - } - ) - case .double: + case .rawValueEnum(_, .string): return IntrinsicJSFragment( parameters: [], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) - let dVar = scope.variable("f64") - printer.write("const \(dVar) = \(scope.popF64());") - return [dVar] + let varName = scope.variable("rawValue") + printer.write("const \(varName) = \(scope.popString());") + return [varName] } ) case .swiftStruct(let fullName): @@ -2244,59 +2055,6 @@ struct IntrinsicJSFragment: Sendable { return [resultVar] } ) - case .caseEnum: - return IntrinsicJSFragment( - parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let varName = scope.variable("caseId") - printer.write("const \(varName) = \(scope.popI32());") - return [varName] - } - ) - case .rawValueEnum(_, let rawType): - switch rawType { - case .string: - return IntrinsicJSFragment( - parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let varName = scope.variable("rawValue") - printer.write("const \(varName) = \(scope.popString());") - return [varName] - } - ) - case .float: - return IntrinsicJSFragment( - parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let varName = scope.variable("rawValue") - printer.write("const \(varName) = \(scope.popF32());") - return [varName] - } - ) - case .double: - return IntrinsicJSFragment( - parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let varName = scope.variable("rawValue") - printer.write("const \(varName) = \(scope.popF64());") - return [varName] - } - ) - default: - return IntrinsicJSFragment( - parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let varName = scope.variable("rawValue") - printer.write("const \(varName) = \(scope.popI32());") - return [varName] - } - ) - } case .associatedValueEnum(let fullName): let base = fullName.components(separatedBy: ".").last ?? fullName return IntrinsicJSFragment( @@ -2305,7 +2063,7 @@ struct IntrinsicJSFragment: Sendable { let (scope, printer) = (context.scope, context.printer) let resultVar = scope.variable("enumValue") printer.write( - "const \(resultVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lift(\(scope.popI32()), );" + "const \(resultVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lift(\(scope.popI32()));" ) return [resultVar] } @@ -2330,7 +2088,9 @@ struct IntrinsicJSFragment: Sendable { let idVar = scope.variable("objId") let objVar = scope.variable("obj") printer.write("const \(idVar) = \(scope.popI32());") - printer.write("const \(objVar) = \(JSGlueVariableScope.reservedSwift).memory.getObject(\(idVar));") + printer.write( + "const \(objVar) = \(JSGlueVariableScope.reservedSwift).memory.getObject(\(idVar));" + ) printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(idVar));") return [objVar] } @@ -2339,24 +2099,34 @@ struct IntrinsicJSFragment: Sendable { return try arrayLift(elementType: innerElementType) case .dictionary(let valueType): return try dictionaryLift(valueType: valueType) - case .nullable(let wrappedType, let kind): - return try optionalElementRaiseFragment(wrappedType: wrappedType, kind: kind) - case .unsafePointer: + default: + throw BridgeJSLinkError(message: "Unsupported array element type: \(elementType)") + } + } + + private static func stackLowerFragment(elementType: BridgeType) throws -> IntrinsicJSFragment { + if case .nullable(let wrappedType, let kind) = elementType { + return try optionalElementLowerFragment(wrappedType: wrappedType, kind: kind) + } + if elementType.isSingleParamScalar { + let wasmType = elementType.wasmParams[0].type + let stackCoerce = elementType.stackLowerCoerce return IntrinsicJSFragment( - parameters: [], + parameters: ["value"], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) - let pVar = scope.variable("pointer") - printer.write("const \(pVar) = \(scope.popPointer());") - return [pVar] + let value = arguments[0] + let pushExpr: String + if let coerce = stackCoerce { + pushExpr = coerce.replacingOccurrences(of: "$0", with: value) + } else { + pushExpr = value + } + emitPush(for: wasmType, value: pushExpr, scope: scope, printer: printer) + return [] } ) - case .void, .closure, .namespaceEnum: - throw BridgeJSLinkError(message: "Unsupported array element type: \(elementType)") } - } - - private static func stackLowerFragment(elementType: BridgeType) throws -> IntrinsicJSFragment { switch elementType { case .jsValue: return IntrinsicJSFragment( @@ -2374,7 +2144,7 @@ struct IntrinsicJSFragment: Sendable { return [] } ) - case .string: + case .string, .rawValueEnum(_, .string): return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in @@ -2382,49 +2152,17 @@ struct IntrinsicJSFragment: Sendable { let value = arguments[0] let bytesVar = scope.variable("bytes") let idVar = scope.variable("id") - printer.write("const \(bytesVar) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(value));") - printer.write("const \(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(bytesVar));") + printer.write( + "const \(bytesVar) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(value));" + ) + printer.write( + "const \(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(bytesVar));" + ) scope.emitPushI32Parameter("\(bytesVar).length", printer: printer) scope.emitPushI32Parameter(idVar, printer: printer) return [] } ) - case .bool: - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - scope.emitPushI32Parameter("\(arguments[0]) ? 1 : 0", printer: printer) - return [] - } - ) - case .int, .uint: - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - scope.emitPushI32Parameter("(\(arguments[0]) | 0)", printer: printer) - return [] - } - ) - case .float: - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - scope.emitPushF32Parameter("Math.fround(\(arguments[0]))", printer: printer) - return [] - } - ) - case .double: - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - scope.emitPushF64Parameter("\(arguments[0])", printer: printer) - return [] - } - ) case .swiftStruct(let fullName): let structBase = fullName.components(separatedBy: ".").last ?? fullName return IntrinsicJSFragment( @@ -2438,64 +2176,7 @@ struct IntrinsicJSFragment: Sendable { return [] } ) - case .caseEnum: - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - scope.emitPushI32Parameter("(\(arguments[0]) | 0)", printer: printer) - return [] - } - ) - case .rawValueEnum(_, let rawType): - switch rawType { - case .string: - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let value = arguments[0] - let bytesVar = scope.variable("bytes") - let idVar = scope.variable("id") - printer.write( - "const \(bytesVar) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(value));" - ) - printer.write( - "const \(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(bytesVar));" - ) - scope.emitPushI32Parameter("\(bytesVar).length", printer: printer) - scope.emitPushI32Parameter(idVar, printer: printer) - return [] - } - ) - case .float: - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - scope.emitPushF32Parameter("Math.fround(\(arguments[0]))", printer: printer) - return [] - } - ) - case .double: - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - scope.emitPushF64Parameter("\(arguments[0])", printer: printer) - return [] - } - ) - default: - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - scope.emitPushI32Parameter("(\(arguments[0]) | 0)", printer: printer) - return [] - } - ) - } + case .associatedValueEnum(let fullName): let base = fullName.components(separatedBy: ".").last ?? fullName return IntrinsicJSFragment( @@ -2506,64 +2187,40 @@ struct IntrinsicJSFragment: Sendable { let caseIdVar = scope.variable("caseId") printer.write( "const \(caseIdVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lower(\(value));" - ) - scope.emitPushI32Parameter(caseIdVar, printer: printer) - return [] - } - ) - case .swiftHeapObject: - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - scope.emitPushPointerParameter("\(arguments[0]).pointer", printer: printer) - return [] - } - ) - case .jsObject: - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let value = arguments[0] - let idVar = scope.variable("objId") - printer.write("const \(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));") - scope.emitPushI32Parameter(idVar, printer: printer) + ) + scope.emitPushI32Parameter(caseIdVar, printer: printer) return [] } ) - case .array(let innerElementType): - return try arrayLower(elementType: innerElementType) - case .dictionary(let valueType): - return try dictionaryLower(valueType: valueType) - case .nullable(let wrappedType, let kind): - return try optionalElementLowerFragment( - wrappedType: wrappedType, - kind: kind - ) - case .swiftProtocol: - // Same as jsObject but no cleanup — Swift's AnyProtocol wrapper releases via deinit + case .swiftHeapObject: return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) let value = arguments[0] - let idVar = scope.variable("objId") - printer.write("const \(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));") - scope.emitPushI32Parameter(idVar, printer: printer) + scope.emitPushPointerParameter("\(value).pointer", printer: printer) return [] } ) - case .unsafePointer: + case .jsObject, .swiftProtocol: return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) - scope.emitPushPointerParameter("(\(arguments[0]) | 0)", printer: printer) + let value = arguments[0] + let idVar = scope.variable("objId") + printer.write( + "const \(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));" + ) + scope.emitPushI32Parameter(idVar, printer: printer) return [] } ) - case .void, .closure, .namespaceEnum: + case .array(let innerElementType): + return try arrayLower(elementType: innerElementType) + case .dictionary(let valueType): + return try dictionaryLower(valueType: valueType) + default: throw BridgeJSLinkError(message: "Unsupported array element type for lowering: \(elementType)") } } @@ -2624,27 +2281,23 @@ struct IntrinsicJSFragment: Sendable { context ) } - printer.write("} else {") - printer.indent { - // Push placeholders so Swift can unconditionally pop value slots - switch wrappedType { - case .float: - scope.emitPushF32Parameter("0.0", printer: printer) - case .double: - scope.emitPushF64Parameter("0.0", printer: printer) - case .swiftStruct: - // No placeholder — Swift only pops struct fields when isSome=1 - break - case .string, .rawValueEnum(_, .string): - scope.emitPushI32Parameter("0", printer: printer) - scope.emitPushI32Parameter("0", printer: printer) - case .swiftHeapObject: - scope.emitPushPointerParameter("0", printer: printer) - default: - scope.emitPushI32Parameter("0", printer: printer) + let placeholderPrinter = CodeFragmentPrinter() + let hasPlaceholders = emitOptionalPlaceholders( + for: wrappedType, + scope: scope, + printer: placeholderPrinter + ) + if hasPlaceholders { + printer.write("} else {") + printer.indent { + for line in placeholderPrinter.lines { + printer.write(line) + } } + printer.write("}") + } else { + printer.write("}") } - printer.write("}") scope.emitPushI32Parameter(isSomeVar, printer: printer) return [] @@ -2652,6 +2305,8 @@ struct IntrinsicJSFragment: Sendable { ) } + // MARK: - Struct Helpers + static func structHelper(structDefinition: ExportedStruct, allStructs: [ExportedStruct]) -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: ["structName"], @@ -2661,49 +2316,36 @@ struct IntrinsicJSFragment: Sendable { let capturedStructDef = structDefinition let capturedAllStructs = allStructs - printer.write("const __bjs_create\(structName)Helpers = () => {") - printer.indent() - printer.write( - "return () => ({" - ) - printer.indent() - - printer.write("lower: (value) => {") + printer.write("const __bjs_create\(structName)Helpers = () => ({") try printer.indent { - try generateStructLowerCode( - structDef: capturedStructDef, - allStructs: capturedAllStructs, - context: context - ) - } - printer.write("},") + printer.write("lower: (value) => {") + try printer.indent { + try generateStructLowerCode( + structDef: capturedStructDef, + allStructs: capturedAllStructs, + context: context + ) + } + printer.write("},") - printer.write( - "lift: () => {" - ) - try printer.indent { - try generateStructLiftCode( - structDef: capturedStructDef, - allStructs: capturedAllStructs, - context: context, - attachMethods: true - ) + printer.write("lift: () => {") + try printer.indent { + try generateStructLiftCode( + structDef: capturedStructDef, + allStructs: capturedAllStructs, + context: context, + attachMethods: true + ) + } + printer.write("}") } - printer.write("}") - printer.unindent() printer.write("});") - printer.unindent() - printer.write("};") return [] } ) } - private static func findStruct(name: String, structs: [ExportedStruct]) -> ExportedStruct? { - return structs.first(where: { $0.swiftCallName == name || $0.name == name }) - } - private static func generateStructLowerCode( structDef: ExportedStruct, allStructs: [ExportedStruct], @@ -2715,7 +2357,11 @@ struct IntrinsicJSFragment: Sendable { let instanceProps = structDef.properties.filter { !$0.isStatic } for property in instanceProps { - let fragment = try structFieldLowerFragment(field: property, allStructs: allStructs) + let fragment = try structFieldLowerFragment( + type: property.type, + fieldName: property.name, + allStructs: allStructs + ) let fieldValue = "value.\(property.name)" _ = try fragment.printCode( [fieldValue], @@ -2734,7 +2380,7 @@ struct IntrinsicJSFragment: Sendable { context: IntrinsicJSFragment.PrintCodeContext, attachMethods: Bool = false ) throws { - let (scope, printer) = (context.scope, context.printer) + let printer = context.printer let liftScope = context.scope.makeChildScope() var fieldExpressions: [(name: String, expression: String)] = [] @@ -2806,10 +2452,11 @@ struct IntrinsicJSFragment: Sendable { } private static func structFieldLowerFragment( - field: ExportedProperty, + type: BridgeType, + fieldName: String, allStructs: [ExportedStruct] ) throws -> IntrinsicJSFragment { - switch field.type { + switch type { case .jsValue: preconditionFailure("Struct field of JSValue is not supported yet") case .jsObject: @@ -2822,7 +2469,9 @@ struct IntrinsicJSFragment: Sendable { printer.write("let \(idVar);") printer.write("if (\(value) != null) {") printer.indent { - printer.write("\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));") + printer.write( + "\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));" + ) } printer.write("} else {") printer.indent { @@ -2834,251 +2483,46 @@ struct IntrinsicJSFragment: Sendable { } ) case .nullable(let wrappedType, let kind): - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let value = arguments[0] - let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(kind.presenceCheck(value: value));") - - if case .caseEnum = wrappedType { - printer.write("if (\(isSomeVar)) {") - printer.indent { - scope.emitPushI32Parameter("\(value) | 0", printer: printer) - } - printer.write("} else {") - printer.indent { - scope.emitPushI32Parameter("0", printer: printer) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - return [] - } else if case .rawValueEnum(_, let rawType) = wrappedType { - switch rawType { - case .string: - let idVar = scope.variable("id") - printer.write("let \(idVar);") - printer.write("if (\(isSomeVar)) {") - printer.indent { - let bytesVar = scope.variable("bytes") - printer.write( - "const \(bytesVar) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(value));" - ) - printer.write( - "\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(bytesVar));" - ) - scope.emitPushI32Parameter("\(bytesVar).length", printer: printer) - scope.emitPushI32Parameter(idVar, printer: printer) - } - printer.write("} else {") - printer.indent { - scope.emitPushI32Parameter("0", printer: printer) - scope.emitPushI32Parameter("0", printer: printer) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - return [idVar] - case .float: - printer.write("if (\(isSomeVar)) {") - printer.indent { - scope.emitPushF32Parameter("Math.fround(\(value))", printer: printer) - } - printer.write("} else {") - printer.indent { - scope.emitPushF32Parameter("0.0", printer: printer) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - return [] - case .double: - printer.write("if (\(isSomeVar)) {") - printer.indent { - scope.emitPushF64Parameter("\(value)", printer: printer) - } - printer.write("} else {") - printer.indent { - scope.emitPushF64Parameter("0.0", printer: printer) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - return [] - default: - printer.write("if (\(isSomeVar)) {") - printer.indent { - scope.emitPushI32Parameter("\(value) | 0", printer: printer) - } - printer.write("} else {") - printer.indent { - scope.emitPushI32Parameter("0", printer: printer) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - return [] - } - } else if case .swiftHeapObject = wrappedType { - let ptrVar = scope.variable("ptr") - printer.write("let \(ptrVar);") - printer.write("if (\(isSomeVar)) {") - printer.indent { - printer.write("\(ptrVar) = \(value).pointer;") - scope.emitPushPointerParameter("\(ptrVar)", printer: printer) - } - printer.write("} else {") - printer.indent { - scope.emitPushPointerParameter("0", printer: printer) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - return [] - } else if case .swiftStruct(let structName) = wrappedType { - printer.write("if (\(isSomeVar)) {") - printer.indent { - printer.write( - "\(JSGlueVariableScope.reservedStructHelpers).\(structName).lower(\(value));" - ) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - return [] - } else if case .string = wrappedType { - let idVar = scope.variable("id") - printer.write("let \(idVar);") - printer.write("if (\(isSomeVar)) {") - printer.indent { - let bytesVar = scope.variable("bytes") - printer.write( - "const \(bytesVar) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(value));" - ) - printer.write("\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(bytesVar));") - scope.emitPushI32Parameter("\(bytesVar).length", printer: printer) - scope.emitPushI32Parameter(idVar, printer: printer) - } - printer.write("} else {") - printer.indent { - scope.emitPushI32Parameter("0", printer: printer) - scope.emitPushI32Parameter("0", printer: printer) + if wrappedType.isSingleParamScalar { + let wasmType = wrappedType.wasmParams[0].type + let stackCoerce = wrappedType.stackLowerCoerce + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, context in + let (scope, printer) = (context.scope, context.printer) + let value = arguments[0] + let isSomeVar = scope.variable("isSome") + printer.write("const \(isSomeVar) = \(kind.presenceCheck(value: value));") + let coerced: String + if let coerce = stackCoerce { + coerced = coerce.replacingOccurrences(of: "$0", with: value) + } else { + coerced = value } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - return [idVar] - } else if case .jsObject = wrappedType { - let idVar = scope.variable("id") - printer.write("let \(idVar);") printer.write("if (\(isSomeVar)) {") printer.indent { - printer.write("\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));") - scope.emitPushI32Parameter(idVar, printer: printer) + emitPush(for: wasmType, value: coerced, scope: scope, printer: printer) } printer.write("} else {") printer.indent { - printer.write("\(idVar) = undefined;") - scope.emitPushI32Parameter("0", printer: printer) + emitPush(for: wasmType, value: wasmType.jsZeroLiteral, scope: scope, printer: printer) } printer.write("}") scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - return [idVar] - } else { - switch wrappedType { - case .int, .uint: - pushOptionalPrimitive( - value: value, - isSomeVar: isSomeVar, - stack: .i32Stack, - convert: "| 0", - zeroValue: "0", - printer: printer, - scope: scope - ) - case .bool: - pushOptionalPrimitive( - value: value, - isSomeVar: isSomeVar, - stack: .i32Stack, - convert: "? 1 : 0", - zeroValue: "0", - printer: printer, - scope: scope - ) - case .float: - pushOptionalPrimitive( - value: value, - isSomeVar: isSomeVar, - stack: .f32Stack, - convert: "Math.fround", - zeroValue: "0.0", - printer: printer, - scope: scope - ) - case .double: - pushOptionalPrimitive( - value: value, - isSomeVar: isSomeVar, - stack: .f64Stack, - convert: nil, - zeroValue: "0.0", - printer: printer, - scope: scope - ) - case .associatedValueEnum(let enumName): - let base = enumName.components(separatedBy: ".").last ?? enumName - let caseIdVar = scope.variable("enumCaseId") - printer.write("let \(caseIdVar);") - printer.write("if (\(isSomeVar)) {") - printer.indent { - printer.write( - "\(caseIdVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lower(\(value));" - ) - scope.emitPushI32Parameter(caseIdVar, printer: printer) - } - printer.write("} else {") - printer.indent { - scope.emitPushI32Parameter("0", printer: printer) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - default: - let wrappedFragment = try structFieldLowerFragment( - field: ExportedProperty( - name: field.name, - type: wrappedType, - isReadonly: true, - isStatic: false - ), - allStructs: allStructs - ) - let guardedPrinter = CodeFragmentPrinter() - _ = try wrappedFragment.printCode( - [value], - context.with(\.printer, guardedPrinter) - ) - var loweredLines = guardedPrinter.lines - var hoistedCleanupVar: String? - if let first = loweredLines.first { - let trimmed = first.trimmingCharacters(in: .whitespaces) - if trimmed.hasPrefix("const "), - let namePart = trimmed.split(separator: " ").dropFirst().first, - trimmed.contains("= []") - { - hoistedCleanupVar = String(namePart) - loweredLines[0] = "\(hoistedCleanupVar!) = [];" - } - } - if let hoistedName = hoistedCleanupVar { - printer.write("let \(hoistedName);") - } - printer.write("if (\(isSomeVar)) {") - printer.indent { - for line in loweredLines { - printer.write(line) - } - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - } return [] } - } + ) + } + + let innerFragment = try structFieldLowerFragment( + type: wrappedType, + fieldName: fieldName, + allStructs: allStructs + ) + return stackOptionalLower( + wrappedType: wrappedType, + kind: kind, + innerFragment: innerFragment ) case .swiftStruct(let nestedName): return IntrinsicJSFragment( @@ -3098,61 +2542,17 @@ struct IntrinsicJSFragment: Sendable { parameters: ["value"], printCode: { arguments, context in context.printer.write( - "throw new Error(\"Unsupported struct field type for lowering: \(field.type)\");" + "throw new Error(\"Unsupported struct field type for lowering: \(type)\");" ) return [] } ) default: - return try stackLowerFragment(elementType: field.type) + return try stackLowerFragment(elementType: type) } } /// Helper to push optional primitive values to stack-based parameters - private static func pushOptionalPrimitive( - value: String, - isSomeVar: String, - stack: StackType, - convert: String?, - zeroValue: String, - printer: CodeFragmentPrinter, - scope: JSGlueVariableScope - ) { - let stackName: String - switch stack { - case .i32Stack: stackName = JSGlueVariableScope.reservedI32Stack - case .f32Stack: stackName = JSGlueVariableScope.reservedF32Stack - case .f64Stack: stackName = JSGlueVariableScope.reservedF64Stack - } - - printer.write("if (\(isSomeVar)) {") - printer.indent { - let converted: String - if let convert = convert { - if convert.starts(with: "Math.") { - converted = "\(convert)(\(value))" - } else { - converted = "\(value) \(convert)" - } - } else { - converted = value - } - printer.write("\(stackName).push(\(converted));") - } - printer.write("} else {") - printer.indent { - printer.write("\(stackName).push(\(zeroValue));") - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - } - - private enum StackType { - case i32Stack - case f32Stack - case f64Stack - } - private static func structFieldLiftFragment( field: ExportedProperty, allStructs: [ExportedStruct] @@ -3177,7 +2577,7 @@ struct IntrinsicJSFragment: Sendable { let caseIdVar = scope.variable("enumCaseId") printer.write("const \(caseIdVar) = \(scope.popI32());") printer.write( - "\(optVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lift(\(caseIdVar), );" + "\(optVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lift(\(caseIdVar));" ) } else { let wrappedFragment = try structFieldLiftFragment( @@ -3255,3 +2655,221 @@ struct IntrinsicJSFragment: Sendable { } } } + +// MARK: - Local type helpers + +fileprivate extension WasmCoreType { + var jsZeroLiteral: String { + switch self { + case .f32, .f64: return "0.0" + case .i32, .i64, .pointer: return "0" + } + } +} + +private enum OptionalConvention: Equatable { + case stackABI + case inlineFlag + case sideChannelReturn(OptionalSideChannel) +} + +private enum OptionalSideChannel: Equatable { + case none + case storage + case retainedObject +} + +private enum NilSentinel: Equatable { + case none + case i32(Int32) + case pointer + + var jsLiteral: String { + switch self { + case .none: fatalError("No sentinel value for .none") + case .i32(let value): return "\(value)" + case .pointer: return "0" + } + } + + var hasSentinel: Bool { + self != .none + } +} + +private enum OptionalScalarKind: String { + case bool, int, float, double + + var storageName: String { "tmpRetOptional\(rawValue.prefix(1).uppercased())\(rawValue.dropFirst())" } + var funcName: String { "swift_js_return_optional_\(rawValue)" } +} + +private extension BridgeType { + var optionalConvention: OptionalConvention { + switch self { + case .bool: + return .inlineFlag + case .int, .uint: + return .sideChannelReturn(.none) + case .float: + return .sideChannelReturn(.none) + case .double: + return .sideChannelReturn(.none) + case .string: + return .sideChannelReturn(.storage) + case .jsObject: + return .sideChannelReturn(.retainedObject) + case .jsValue: + return .inlineFlag + case .swiftHeapObject: + return .inlineFlag + case .unsafePointer: + return .inlineFlag + case .swiftProtocol: + return .sideChannelReturn(.retainedObject) + case .caseEnum: + return .inlineFlag + case .rawValueEnum(_, let rawType): + switch rawType { + case .string: + return .sideChannelReturn(.storage) + case .float, .double: + return .sideChannelReturn(.none) + case .bool: + return .inlineFlag + case .int, .int32, .int64, .uint, .uint32, .uint64: + return .sideChannelReturn(.none) + } + case .associatedValueEnum: + return .inlineFlag + case .closure: + return .inlineFlag + case .swiftStruct, .array, .dictionary, .void, .namespaceEnum: + return .stackABI + case .nullable(let wrapped, _): + return wrapped.optionalConvention + } + } + + var nilSentinel: NilSentinel { + switch self { + case .jsObject, .swiftProtocol: + return .i32(0) + case .swiftHeapObject: + return .pointer + case .caseEnum, .associatedValueEnum: + return .i32(-1) + case .nullable(let wrapped, _): + return wrapped.nilSentinel + default: + return .none + } + } + + var optionalScalarKind: OptionalScalarKind? { + switch self { + case .bool, .rawValueEnum(_, .bool): return .bool + case .int, .uint, .caseEnum, + .rawValueEnum(_, .int), .rawValueEnum(_, .int32), .rawValueEnum(_, .int64), + .rawValueEnum(_, .uint), .rawValueEnum(_, .uint32), .rawValueEnum(_, .uint64): + return .int + case .float, .rawValueEnum(_, .float): return .float + case .double, .rawValueEnum(_, .double): return .double + case .nullable(let wrapped, _): return wrapped.optionalScalarKind + default: return nil + } + } + + var wasmParams: [(name: String, type: WasmCoreType)] { + switch self { + case .bool, .int, .uint: + return [("value", .i32)] + case .float: + return [("value", .f32)] + case .double: + return [("value", .f64)] + case .string: + return [("bytes", .i32), ("length", .i32)] + case .jsObject: + return [("value", .i32)] + case .jsValue: + return [("kind", .i32), ("payload1", .i32), ("payload2", .f64)] + case .swiftHeapObject: + return [("pointer", .pointer)] + case .unsafePointer: + return [("pointer", .pointer)] + case .swiftProtocol: + return [("value", .i32)] + case .caseEnum: + return [("value", .i32)] + case .rawValueEnum(_, let rawType): + switch rawType { + case .string: + return [("bytes", .i32), ("length", .i32)] + case .float: + return [("value", .f32)] + case .double: + return [("value", .f64)] + case .bool, .int, .int32, .int64, .uint, .uint32, .uint64: + return [("value", .i32)] + } + case .associatedValueEnum: + return [("caseId", .i32)] + case .closure: + return [("funcRef", .i32)] + case .void, .namespaceEnum, .swiftStruct, .array, .dictionary: + return [] + case .nullable(let wrapped, _): + return wrapped.wasmParams + } + } + + var isSingleParamScalar: Bool { + switch self { + case .bool, .int, .uint, .float, .double, .unsafePointer, .caseEnum: return true + case .rawValueEnum(_, let rawType): return rawType != .string + default: return false + } + } + + var stackLowerCoerce: String? { + switch self { + case .bool, .rawValueEnum(_, .bool): return "$0 ? 1 : 0" + case .int, .uint, .unsafePointer, .caseEnum, + .rawValueEnum(_, .int), .rawValueEnum(_, .int32), .rawValueEnum(_, .int64), + .rawValueEnum(_, .uint), .rawValueEnum(_, .uint32), .rawValueEnum(_, .uint64): + return "($0 | 0)" + case .float, .rawValueEnum(_, .float): return "Math.fround($0)" + case .double, .rawValueEnum(_, .double): return nil + default: return nil + } + } + + var liftCoerce: String? { + switch self { + case .bool, .rawValueEnum(_, .bool): return "$0 !== 0" + case .uint: return "$0 >>> 0" + default: return nil + } + } + + var lowerCoerce: String? { + switch self { + case .bool, .rawValueEnum(_, .bool): return "$0 ? 1 : 0" + default: return nil + } + } + + var varHint: String { + switch self { + case .bool: return "bool" + case .int, .uint: return "int" + case .float: return "f32" + case .double: return "f64" + case .unsafePointer: return "pointer" + case .caseEnum: return "caseId" + case .rawValueEnum: return "rawValue" + default: return "value" + } + } +} diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index ba25b6ff9..dab5fae33 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -1208,7 +1208,6 @@ extension BridgeType { } extension WasmCoreType { - /// Returns a Swift statement that returns a placeholder value for this Wasm core type. public var swiftReturnPlaceholderStmt: String { switch self { case .i32: return "return 0" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js index e7bdf975b..b206b9a9f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js @@ -41,19 +41,17 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createPointHelpers = () => { - return () => ({ - lower: (value) => { - f64Stack.push(value.x); - f64Stack.push(value.y); - }, - lift: () => { - const f64 = f64Stack.pop(); - const f641 = f64Stack.pop(); - return { x: f641, y: f64 }; - } - }); - }; + const __bjs_createPointHelpers = () => ({ + lower: (value) => { + f64Stack.push(value.x); + f64Stack.push(value.y); + }, + lift: () => { + const f64 = f64Stack.pop(); + const f641 = f64Stack.pop(); + return { x: f641, y: f64 }; + } + }); return { /** @@ -370,7 +368,7 @@ export async function createInstantiator(options, swift) { } } - const PointHelpers = __bjs_createPointHelpers()(); + const PointHelpers = __bjs_createPointHelpers(); structHelpers.Point = PointHelpers; const exports = { @@ -638,7 +636,6 @@ export async function createInstantiator(options, swift) { const isSome = elem != null ? 1 : 0; if (isSome) { structHelpers.Point.lower(elem); - } else { } i32Stack.push(isSome); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js index 0538b8078..a865882ef 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js @@ -34,46 +34,42 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createConfigHelpers = () => { - return () => ({ - lower: (value) => { - const bytes = textEncoder.encode(value.name); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - i32Stack.push((value.value | 0)); - i32Stack.push(value.enabled ? 1 : 0); - }, - lift: () => { - const bool = i32Stack.pop() !== 0; - const int = i32Stack.pop(); - const string = strStack.pop(); - return { name: string, value: int, enabled: bool }; - } - }); - }; - const __bjs_createMathOperationsHelpers = () => { - return () => ({ - lower: (value) => { - f64Stack.push(value.baseValue); - }, - lift: () => { - const f64 = f64Stack.pop(); - const instance1 = { baseValue: f64 }; - instance1.add = function(a, b = 10.0) { - structHelpers.MathOperations.lower(this); - const ret = instance.exports.bjs_MathOperations_add(a, b); - return ret; - }.bind(instance1); - instance1.multiply = function(a, b) { - structHelpers.MathOperations.lower(this); - const ret = instance.exports.bjs_MathOperations_multiply(a, b); - return ret; - }.bind(instance1); - return instance1; - } - }); - }; + const __bjs_createConfigHelpers = () => ({ + lower: (value) => { + const bytes = textEncoder.encode(value.name); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + i32Stack.push((value.value | 0)); + i32Stack.push(value.enabled ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + const int = i32Stack.pop(); + const string = strStack.pop(); + return { name: string, value: int, enabled: bool }; + } + }); + const __bjs_createMathOperationsHelpers = () => ({ + lower: (value) => { + f64Stack.push(value.baseValue); + }, + lift: () => { + const f64 = f64Stack.pop(); + const instance1 = { baseValue: f64 }; + instance1.add = function(a, b = 10.0) { + structHelpers.MathOperations.lower(this); + const ret = instance.exports.bjs_MathOperations_add(a, b); + return ret; + }.bind(instance1); + instance1.multiply = function(a, b) { + structHelpers.MathOperations.lower(this); + const ret = instance.exports.bjs_MathOperations_multiply(a, b); + return ret; + }.bind(instance1); + return instance1; + } + }); return { /** @@ -343,12 +339,17 @@ export async function createInstantiator(options, swift) { const nameBytes = textEncoder.encode(name); const nameId = swift.memory.retain(nameBytes); const isSome = tag != null; - let tagId, tagBytes; + let result, result1; if (isSome) { - tagBytes = textEncoder.encode(tag); - tagId = swift.memory.retain(tagBytes); + const tagBytes = textEncoder.encode(tag); + const tagId = swift.memory.retain(tagBytes); + result = tagId; + result1 = tagBytes.length; + } else { + result = 0; + result1 = 0; } - const ret = instance.exports.bjs_ConstructorDefaults_init(nameId, nameBytes.length, count, enabled, status, +isSome, isSome ? tagId : 0, isSome ? tagBytes.length : 0); + const ret = instance.exports.bjs_ConstructorDefaults_init(nameId, nameBytes.length, count, enabled, status, +isSome, result, result1); return ConstructorDefaults.__construct(ret); } get name() { @@ -391,18 +392,23 @@ export async function createInstantiator(options, swift) { } set tag(value) { const isSome = value != null; - let valueId, valueBytes; + let result, result1; if (isSome) { - valueBytes = textEncoder.encode(value); - valueId = swift.memory.retain(valueBytes); + const valueBytes = textEncoder.encode(value); + const valueId = swift.memory.retain(valueBytes); + result = valueId; + result1 = valueBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_ConstructorDefaults_tag_set(this.pointer, +isSome, isSome ? valueId : 0, isSome ? valueBytes.length : 0); + instance.exports.bjs_ConstructorDefaults_tag_set(this.pointer, +isSome, result, result1); } } - const ConfigHelpers = __bjs_createConfigHelpers()(); + const ConfigHelpers = __bjs_createConfigHelpers(); structHelpers.Config = ConfigHelpers; - const MathOperationsHelpers = __bjs_createMathOperationsHelpers()(); + const MathOperationsHelpers = __bjs_createMathOperationsHelpers(); structHelpers.MathOperations = MathOperationsHelpers; const exports = { @@ -435,24 +441,34 @@ export async function createInstantiator(options, swift) { }, testOptionalDefault: function bjs_testOptionalDefault(name = null) { const isSome = name != null; - let nameId, nameBytes; + let result, result1; if (isSome) { - nameBytes = textEncoder.encode(name); - nameId = swift.memory.retain(nameBytes); + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + result = nameId; + result1 = nameBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_testOptionalDefault(+isSome, isSome ? nameId : 0, isSome ? nameBytes.length : 0); + instance.exports.bjs_testOptionalDefault(+isSome, result, result1); const optResult = tmpRetString; tmpRetString = undefined; return optResult; }, testOptionalStringDefault: function bjs_testOptionalStringDefault(greeting = "Hi") { const isSome = greeting != null; - let greetingId, greetingBytes; + let result, result1; if (isSome) { - greetingBytes = textEncoder.encode(greeting); - greetingId = swift.memory.retain(greetingBytes); + const greetingBytes = textEncoder.encode(greeting); + const greetingId = swift.memory.retain(greetingBytes); + result = greetingId; + result1 = greetingBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_testOptionalStringDefault(+isSome, isSome ? greetingId : 0, isSome ? greetingBytes.length : 0); + instance.exports.bjs_testOptionalStringDefault(+isSome, result, result1); const optResult = tmpRetString; tmpRetString = undefined; return optResult; @@ -485,12 +501,7 @@ export async function createInstantiator(options, swift) { i32Stack.push(+isSome); instance.exports.bjs_testOptionalStructDefault(); const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - optResult = structHelpers.Config.lift(); - } else { - optResult = null; - } + const optResult = isSome1 ? structHelpers.Config.lift() : null; return optResult; }, testOptionalStructWithValueDefault: function bjs_testOptionalStructWithValueDefault(point = { name: "default", value: 42, enabled: true }) { @@ -501,12 +512,7 @@ export async function createInstantiator(options, swift) { i32Stack.push(+isSome); instance.exports.bjs_testOptionalStructWithValueDefault(); const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - optResult = structHelpers.Config.lift(); - } else { - optResult = null; - } + const optResult = isSome1 ? structHelpers.Config.lift() : null; return optResult; }, testIntArrayDefault: function bjs_testIntArrayDefault(values = [1, 2, 3]) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js index 43cc9f964..55967a6a3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js @@ -109,528 +109,640 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createPointHelpers = () => { - return () => ({ - lower: (value) => { - f64Stack.push(value.x); - f64Stack.push(value.y); - }, - lift: () => { - const f64 = f64Stack.pop(); - const f641 = f64Stack.pop(); - return { x: f641, y: f64 }; + const __bjs_createPointHelpers = () => ({ + lower: (value) => { + f64Stack.push(value.x); + f64Stack.push(value.y); + }, + lift: () => { + const f64 = f64Stack.pop(); + const f641 = f64Stack.pop(); + return { x: f641, y: f64 }; + } + }); + const __bjs_createAPIResultValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case APIResultValues.Tag.Success: { + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + return APIResultValues.Tag.Success; + } + case APIResultValues.Tag.Failure: { + i32Stack.push((value.param0 | 0)); + return APIResultValues.Tag.Failure; + } + case APIResultValues.Tag.Flag: { + i32Stack.push(value.param0 ? 1 : 0); + return APIResultValues.Tag.Flag; + } + case APIResultValues.Tag.Rate: { + f32Stack.push(Math.fround(value.param0)); + return APIResultValues.Tag.Rate; + } + case APIResultValues.Tag.Precise: { + f64Stack.push(value.param0); + return APIResultValues.Tag.Precise; + } + case APIResultValues.Tag.Info: { + return APIResultValues.Tag.Info; + } + default: throw new Error("Unknown APIResultValues tag: " + String(enumTag)); } - }); - }; - const __bjs_createAPIResultValuesHelpers = () => { - return () => ({ - lower: (value) => { - const enumTag = value.tag; - switch (enumTag) { - case APIResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - return APIResultValues.Tag.Success; - } - case APIResultValues.Tag.Failure: { - i32Stack.push((value.param0 | 0)); - return APIResultValues.Tag.Failure; - } - case APIResultValues.Tag.Flag: { - i32Stack.push(value.param0 ? 1 : 0); - return APIResultValues.Tag.Flag; - } - case APIResultValues.Tag.Rate: { - f32Stack.push(Math.fround(value.param0)); - return APIResultValues.Tag.Rate; - } - case APIResultValues.Tag.Precise: { - f64Stack.push(value.param0); - return APIResultValues.Tag.Precise; - } - case APIResultValues.Tag.Info: { - return APIResultValues.Tag.Info; - } - default: throw new Error("Unknown APIResultValues tag: " + String(enumTag)); + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case APIResultValues.Tag.Success: { + const string = strStack.pop(); + return { tag: APIResultValues.Tag.Success, param0: string }; } - }, - lift: (tag) => { - tag = tag | 0; - switch (tag) { - case APIResultValues.Tag.Success: { - const string = strStack.pop(); - return { tag: APIResultValues.Tag.Success, param0: string }; - } - case APIResultValues.Tag.Failure: { - const int = i32Stack.pop(); - return { tag: APIResultValues.Tag.Failure, param0: int }; - } - case APIResultValues.Tag.Flag: { - const bool = i32Stack.pop() !== 0; - return { tag: APIResultValues.Tag.Flag, param0: bool }; - } - case APIResultValues.Tag.Rate: { - const f32 = f32Stack.pop(); - return { tag: APIResultValues.Tag.Rate, param0: f32 }; - } - case APIResultValues.Tag.Precise: { - const f64 = f64Stack.pop(); - return { tag: APIResultValues.Tag.Precise, param0: f64 }; - } - case APIResultValues.Tag.Info: return { tag: APIResultValues.Tag.Info }; - default: throw new Error("Unknown APIResultValues tag returned from Swift: " + String(tag)); + case APIResultValues.Tag.Failure: { + const int = i32Stack.pop(); + return { tag: APIResultValues.Tag.Failure, param0: int }; + } + case APIResultValues.Tag.Flag: { + const bool = i32Stack.pop() !== 0; + return { tag: APIResultValues.Tag.Flag, param0: bool }; + } + case APIResultValues.Tag.Rate: { + const f32 = f32Stack.pop(); + return { tag: APIResultValues.Tag.Rate, param0: f32 }; + } + case APIResultValues.Tag.Precise: { + const f64 = f64Stack.pop(); + return { tag: APIResultValues.Tag.Precise, param0: f64 }; } + case APIResultValues.Tag.Info: return { tag: APIResultValues.Tag.Info }; + default: throw new Error("Unknown APIResultValues tag returned from Swift: " + String(tag)); } - }); - }; - const __bjs_createComplexResultValuesHelpers = () => { - return () => ({ - lower: (value) => { - const enumTag = value.tag; - switch (enumTag) { - case ComplexResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - return ComplexResultValues.Tag.Success; - } - case ComplexResultValues.Tag.Error: { - i32Stack.push((value.param1 | 0)); + } + }); + const __bjs_createComplexResultValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case ComplexResultValues.Tag.Success: { + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + return ComplexResultValues.Tag.Success; + } + case ComplexResultValues.Tag.Error: { + i32Stack.push((value.param1 | 0)); + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + return ComplexResultValues.Tag.Error; + } + case ComplexResultValues.Tag.Status: { + const bytes = textEncoder.encode(value.param2); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + i32Stack.push((value.param1 | 0)); + i32Stack.push(value.param0 ? 1 : 0); + return ComplexResultValues.Tag.Status; + } + case ComplexResultValues.Tag.Coordinates: { + f64Stack.push(value.param2); + f64Stack.push(value.param1); + f64Stack.push(value.param0); + return ComplexResultValues.Tag.Coordinates; + } + case ComplexResultValues.Tag.Comprehensive: { + const bytes = textEncoder.encode(value.param8); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + const bytes1 = textEncoder.encode(value.param7); + const id1 = swift.memory.retain(bytes1); + i32Stack.push(bytes1.length); + i32Stack.push(id1); + const bytes2 = textEncoder.encode(value.param6); + const id2 = swift.memory.retain(bytes2); + i32Stack.push(bytes2.length); + i32Stack.push(id2); + f64Stack.push(value.param5); + f64Stack.push(value.param4); + i32Stack.push((value.param3 | 0)); + i32Stack.push((value.param2 | 0)); + i32Stack.push(value.param1 ? 1 : 0); + i32Stack.push(value.param0 ? 1 : 0); + return ComplexResultValues.Tag.Comprehensive; + } + case ComplexResultValues.Tag.Info: { + return ComplexResultValues.Tag.Info; + } + default: throw new Error("Unknown ComplexResultValues tag: " + String(enumTag)); + } + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case ComplexResultValues.Tag.Success: { + const string = strStack.pop(); + return { tag: ComplexResultValues.Tag.Success, param0: string }; + } + case ComplexResultValues.Tag.Error: { + const int = i32Stack.pop(); + const string = strStack.pop(); + return { tag: ComplexResultValues.Tag.Error, param0: string, param1: int }; + } + case ComplexResultValues.Tag.Status: { + const string = strStack.pop(); + const int = i32Stack.pop(); + const bool = i32Stack.pop() !== 0; + return { tag: ComplexResultValues.Tag.Status, param0: bool, param1: int, param2: string }; + } + case ComplexResultValues.Tag.Coordinates: { + const f64 = f64Stack.pop(); + const f641 = f64Stack.pop(); + const f642 = f64Stack.pop(); + return { tag: ComplexResultValues.Tag.Coordinates, param0: f642, param1: f641, param2: f64 }; + } + case ComplexResultValues.Tag.Comprehensive: { + const string = strStack.pop(); + const string1 = strStack.pop(); + const string2 = strStack.pop(); + const f64 = f64Stack.pop(); + const f641 = f64Stack.pop(); + const int = i32Stack.pop(); + const int1 = i32Stack.pop(); + const bool = i32Stack.pop() !== 0; + const bool1 = i32Stack.pop() !== 0; + return { tag: ComplexResultValues.Tag.Comprehensive, param0: bool1, param1: bool, param2: int1, param3: int, param4: f641, param5: f64, param6: string2, param7: string1, param8: string }; + } + case ComplexResultValues.Tag.Info: return { tag: ComplexResultValues.Tag.Info }; + default: throw new Error("Unknown ComplexResultValues tag returned from Swift: " + String(tag)); + } + } + }); + const __bjs_createResultValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case ResultValues.Tag.Success: { + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + return ResultValues.Tag.Success; + } + case ResultValues.Tag.Failure: { + i32Stack.push((value.param1 | 0)); + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + return ResultValues.Tag.Failure; + } + case ResultValues.Tag.Status: { + const bytes = textEncoder.encode(value.param2); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + i32Stack.push((value.param1 | 0)); + i32Stack.push(value.param0 ? 1 : 0); + return ResultValues.Tag.Status; + } + default: throw new Error("Unknown ResultValues tag: " + String(enumTag)); + } + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case ResultValues.Tag.Success: { + const string = strStack.pop(); + return { tag: ResultValues.Tag.Success, param0: string }; + } + case ResultValues.Tag.Failure: { + const int = i32Stack.pop(); + const string = strStack.pop(); + return { tag: ResultValues.Tag.Failure, param0: string, param1: int }; + } + case ResultValues.Tag.Status: { + const string = strStack.pop(); + const int = i32Stack.pop(); + const bool = i32Stack.pop() !== 0; + return { tag: ResultValues.Tag.Status, param0: bool, param1: int, param2: string }; + } + default: throw new Error("Unknown ResultValues tag returned from Swift: " + String(tag)); + } + } + }); + const __bjs_createNetworkingResultValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case NetworkingResultValues.Tag.Success: { + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + return NetworkingResultValues.Tag.Success; + } + case NetworkingResultValues.Tag.Failure: { + i32Stack.push((value.param1 | 0)); + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + return NetworkingResultValues.Tag.Failure; + } + default: throw new Error("Unknown NetworkingResultValues tag: " + String(enumTag)); + } + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case NetworkingResultValues.Tag.Success: { + const string = strStack.pop(); + return { tag: NetworkingResultValues.Tag.Success, param0: string }; + } + case NetworkingResultValues.Tag.Failure: { + const int = i32Stack.pop(); + const string = strStack.pop(); + return { tag: NetworkingResultValues.Tag.Failure, param0: string, param1: int }; + } + default: throw new Error("Unknown NetworkingResultValues tag returned from Swift: " + String(tag)); + } + } + }); + const __bjs_createAPIOptionalResultValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case APIOptionalResultValues.Tag.Success: { + const isSome = value.param0 != null; + if (isSome) { const bytes = textEncoder.encode(value.param0); const id = swift.memory.retain(bytes); i32Stack.push(bytes.length); i32Stack.push(id); - return ComplexResultValues.Tag.Error; + } else { + i32Stack.push(0); + i32Stack.push(0); } - case ComplexResultValues.Tag.Status: { + i32Stack.push(isSome ? 1 : 0); + return APIOptionalResultValues.Tag.Success; + } + case APIOptionalResultValues.Tag.Failure: { + const isSome = value.param1 != null; + i32Stack.push(isSome ? (value.param1 ? 1 : 0) : 0); + i32Stack.push(isSome ? 1 : 0); + const isSome1 = value.param0 != null; + i32Stack.push(isSome1 ? (value.param0 | 0) : 0); + i32Stack.push(isSome1 ? 1 : 0); + return APIOptionalResultValues.Tag.Failure; + } + case APIOptionalResultValues.Tag.Status: { + const isSome = value.param2 != null; + if (isSome) { const bytes = textEncoder.encode(value.param2); const id = swift.memory.retain(bytes); i32Stack.push(bytes.length); i32Stack.push(id); - i32Stack.push((value.param1 | 0)); - i32Stack.push(value.param0 ? 1 : 0); - return ComplexResultValues.Tag.Status; - } - case ComplexResultValues.Tag.Coordinates: { - f64Stack.push(value.param2); - f64Stack.push(value.param1); - f64Stack.push(value.param0); - return ComplexResultValues.Tag.Coordinates; - } - case ComplexResultValues.Tag.Comprehensive: { - const bytes = textEncoder.encode(value.param8); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - const bytes1 = textEncoder.encode(value.param7); - const id1 = swift.memory.retain(bytes1); - i32Stack.push(bytes1.length); - i32Stack.push(id1); - const bytes2 = textEncoder.encode(value.param6); - const id2 = swift.memory.retain(bytes2); - i32Stack.push(bytes2.length); - i32Stack.push(id2); - f64Stack.push(value.param5); - f64Stack.push(value.param4); - i32Stack.push((value.param3 | 0)); - i32Stack.push((value.param2 | 0)); - i32Stack.push(value.param1 ? 1 : 0); - i32Stack.push(value.param0 ? 1 : 0); - return ComplexResultValues.Tag.Comprehensive; - } - case ComplexResultValues.Tag.Info: { - return ComplexResultValues.Tag.Info; - } - default: throw new Error("Unknown ComplexResultValues tag: " + String(enumTag)); + } else { + i32Stack.push(0); + i32Stack.push(0); + } + i32Stack.push(isSome ? 1 : 0); + const isSome1 = value.param1 != null; + i32Stack.push(isSome1 ? (value.param1 | 0) : 0); + i32Stack.push(isSome1 ? 1 : 0); + const isSome2 = value.param0 != null; + i32Stack.push(isSome2 ? (value.param0 ? 1 : 0) : 0); + i32Stack.push(isSome2 ? 1 : 0); + return APIOptionalResultValues.Tag.Status; } - }, - lift: (tag) => { - tag = tag | 0; - switch (tag) { - case ComplexResultValues.Tag.Success: { - const string = strStack.pop(); - return { tag: ComplexResultValues.Tag.Success, param0: string }; - } - case ComplexResultValues.Tag.Error: { - const int = i32Stack.pop(); + default: throw new Error("Unknown APIOptionalResultValues tag: " + String(enumTag)); + } + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case APIOptionalResultValues.Tag.Success: { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { const string = strStack.pop(); - return { tag: ComplexResultValues.Tag.Error, param0: string, param1: int }; + optional = string; + } else { + optional = null; } - case ComplexResultValues.Tag.Status: { - const string = strStack.pop(); - const int = i32Stack.pop(); + return { tag: APIOptionalResultValues.Tag.Success, param0: optional }; + } + case APIOptionalResultValues.Tag.Failure: { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { const bool = i32Stack.pop() !== 0; - return { tag: ComplexResultValues.Tag.Status, param0: bool, param1: int, param2: string }; - } - case ComplexResultValues.Tag.Coordinates: { - const f64 = f64Stack.pop(); - const f641 = f64Stack.pop(); - const f642 = f64Stack.pop(); - return { tag: ComplexResultValues.Tag.Coordinates, param0: f642, param1: f641, param2: f64 }; + optional = bool; + } else { + optional = null; } - case ComplexResultValues.Tag.Comprehensive: { - const string = strStack.pop(); - const string1 = strStack.pop(); - const string2 = strStack.pop(); - const f64 = f64Stack.pop(); - const f641 = f64Stack.pop(); + const isSome1 = i32Stack.pop(); + let optional1; + if (isSome1) { const int = i32Stack.pop(); - const int1 = i32Stack.pop(); - const bool = i32Stack.pop() !== 0; - const bool1 = i32Stack.pop() !== 0; - return { tag: ComplexResultValues.Tag.Comprehensive, param0: bool1, param1: bool, param2: int1, param3: int, param4: f641, param5: f64, param6: string2, param7: string1, param8: string }; - } - case ComplexResultValues.Tag.Info: return { tag: ComplexResultValues.Tag.Info }; - default: throw new Error("Unknown ComplexResultValues tag returned from Swift: " + String(tag)); - } - } - }); - }; - const __bjs_createResultValuesHelpers = () => { - return () => ({ - lower: (value) => { - const enumTag = value.tag; - switch (enumTag) { - case ResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - return ResultValues.Tag.Success; - } - case ResultValues.Tag.Failure: { - i32Stack.push((value.param1 | 0)); - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - return ResultValues.Tag.Failure; - } - case ResultValues.Tag.Status: { - const bytes = textEncoder.encode(value.param2); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - i32Stack.push((value.param1 | 0)); - i32Stack.push(value.param0 ? 1 : 0); - return ResultValues.Tag.Status; + optional1 = int; + } else { + optional1 = null; } - default: throw new Error("Unknown ResultValues tag: " + String(enumTag)); + return { tag: APIOptionalResultValues.Tag.Failure, param0: optional1, param1: optional }; } - }, - lift: (tag) => { - tag = tag | 0; - switch (tag) { - case ResultValues.Tag.Success: { + case APIOptionalResultValues.Tag.Status: { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { const string = strStack.pop(); - return { tag: ResultValues.Tag.Success, param0: string }; + optional = string; + } else { + optional = null; } - case ResultValues.Tag.Failure: { + const isSome1 = i32Stack.pop(); + let optional1; + if (isSome1) { const int = i32Stack.pop(); - const string = strStack.pop(); - return { tag: ResultValues.Tag.Failure, param0: string, param1: int }; + optional1 = int; + } else { + optional1 = null; } - case ResultValues.Tag.Status: { - const string = strStack.pop(); - const int = i32Stack.pop(); + const isSome2 = i32Stack.pop(); + let optional2; + if (isSome2) { const bool = i32Stack.pop() !== 0; - return { tag: ResultValues.Tag.Status, param0: bool, param1: int, param2: string }; + optional2 = bool; + } else { + optional2 = null; } - default: throw new Error("Unknown ResultValues tag returned from Swift: " + String(tag)); + return { tag: APIOptionalResultValues.Tag.Status, param0: optional2, param1: optional1, param2: optional }; } + default: throw new Error("Unknown APIOptionalResultValues tag returned from Swift: " + String(tag)); } - }); - }; - const __bjs_createNetworkingResultValuesHelpers = () => { - return () => ({ - lower: (value) => { - const enumTag = value.tag; - switch (enumTag) { - case NetworkingResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - return NetworkingResultValues.Tag.Success; - } - case NetworkingResultValues.Tag.Failure: { - i32Stack.push((value.param1 | 0)); - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - return NetworkingResultValues.Tag.Failure; - } - default: throw new Error("Unknown NetworkingResultValues tag: " + String(enumTag)); + } + }); + const __bjs_createTypedPayloadResultValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case TypedPayloadResultValues.Tag.Precision: { + f32Stack.push(Math.fround(value.param0)); + return TypedPayloadResultValues.Tag.Precision; } - }, - lift: (tag) => { - tag = tag | 0; - switch (tag) { - case NetworkingResultValues.Tag.Success: { - const string = strStack.pop(); - return { tag: NetworkingResultValues.Tag.Success, param0: string }; - } - case NetworkingResultValues.Tag.Failure: { - const int = i32Stack.pop(); - const string = strStack.pop(); - return { tag: NetworkingResultValues.Tag.Failure, param0: string, param1: int }; - } - default: throw new Error("Unknown NetworkingResultValues tag returned from Swift: " + String(tag)); + case TypedPayloadResultValues.Tag.Direction: { + i32Stack.push((value.param0 | 0)); + return TypedPayloadResultValues.Tag.Direction; } - } - }); - }; - const __bjs_createAPIOptionalResultValuesHelpers = () => { - return () => ({ - lower: (value) => { - const enumTag = value.tag; - switch (enumTag) { - case APIOptionalResultValues.Tag.Success: { - const isSome = value.param0 != null; - let id; - if (isSome) { - let bytes = textEncoder.encode(value.param0); - id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } else { - i32Stack.push(0); - i32Stack.push(0); - } - i32Stack.push(isSome ? 1 : 0); - return APIOptionalResultValues.Tag.Success; - } - case APIOptionalResultValues.Tag.Failure: { - const isSome = value.param1 != null; - i32Stack.push(isSome ? (value.param1 ? 1 : 0) : 0); - i32Stack.push(isSome ? 1 : 0); - const isSome1 = value.param0 != null; - i32Stack.push(isSome1 ? (value.param0 | 0) : 0); - i32Stack.push(isSome1 ? 1 : 0); - return APIOptionalResultValues.Tag.Failure; - } - case APIOptionalResultValues.Tag.Status: { - const isSome = value.param2 != null; - let id; - if (isSome) { - let bytes = textEncoder.encode(value.param2); - id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } else { - i32Stack.push(0); - i32Stack.push(0); - } - i32Stack.push(isSome ? 1 : 0); - const isSome1 = value.param1 != null; - i32Stack.push(isSome1 ? (value.param1 | 0) : 0); - i32Stack.push(isSome1 ? 1 : 0); - const isSome2 = value.param0 != null; - i32Stack.push(isSome2 ? (value.param0 ? 1 : 0) : 0); - i32Stack.push(isSome2 ? 1 : 0); - return APIOptionalResultValues.Tag.Status; - } - default: throw new Error("Unknown APIOptionalResultValues tag: " + String(enumTag)); - } - }, - lift: (tag) => { - tag = tag | 0; - switch (tag) { - case APIOptionalResultValues.Tag.Success: { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const string = strStack.pop(); - optional = string; - } else { - optional = null; - } - return { tag: APIOptionalResultValues.Tag.Success, param0: optional }; - } - case APIOptionalResultValues.Tag.Failure: { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const bool = i32Stack.pop() !== 0; - optional = bool; - } else { - optional = null; - } - const isSome1 = i32Stack.pop(); - let optional1; - if (isSome1) { - const int = i32Stack.pop(); - optional1 = int; - } else { - optional1 = null; - } - return { tag: APIOptionalResultValues.Tag.Failure, param0: optional1, param1: optional }; - } - case APIOptionalResultValues.Tag.Status: { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const string = strStack.pop(); - optional = string; - } else { - optional = null; - } - const isSome1 = i32Stack.pop(); - let optional1; - if (isSome1) { - const int = i32Stack.pop(); - optional1 = int; - } else { - optional1 = null; - } - const isSome2 = i32Stack.pop(); - let optional2; - if (isSome2) { - const bool = i32Stack.pop() !== 0; - optional2 = bool; - } else { - optional2 = null; - } - return { tag: APIOptionalResultValues.Tag.Status, param0: optional2, param1: optional1, param2: optional }; - } - default: throw new Error("Unknown APIOptionalResultValues tag returned from Swift: " + String(tag)); + case TypedPayloadResultValues.Tag.OptPrecision: { + const isSome = value.param0 != null; + f32Stack.push(isSome ? Math.fround(value.param0) : 0.0); + i32Stack.push(isSome ? 1 : 0); + return TypedPayloadResultValues.Tag.OptPrecision; + } + case TypedPayloadResultValues.Tag.OptDirection: { + const isSome = value.param0 != null; + i32Stack.push(isSome ? (value.param0 | 0) : 0); + i32Stack.push(isSome ? 1 : 0); + return TypedPayloadResultValues.Tag.OptDirection; + } + case TypedPayloadResultValues.Tag.Empty: { + return TypedPayloadResultValues.Tag.Empty; } + default: throw new Error("Unknown TypedPayloadResultValues tag: " + String(enumTag)); } - }); - }; - const __bjs_createTypedPayloadResultValuesHelpers = () => { - return () => ({ - lower: (value) => { - const enumTag = value.tag; - switch (enumTag) { - case TypedPayloadResultValues.Tag.Precision: { - f32Stack.push(Math.fround(value.param0)); - return TypedPayloadResultValues.Tag.Precision; - } - case TypedPayloadResultValues.Tag.Direction: { - i32Stack.push((value.param0 | 0)); - return TypedPayloadResultValues.Tag.Direction; - } - case TypedPayloadResultValues.Tag.OptPrecision: { - const isSome = value.param0 != null; - f32Stack.push(isSome ? Math.fround(value.param0) : 0.0); - i32Stack.push(isSome ? 1 : 0); - return TypedPayloadResultValues.Tag.OptPrecision; - } - case TypedPayloadResultValues.Tag.OptDirection: { - const isSome = value.param0 != null; - i32Stack.push(isSome ? (value.param0 | 0) : 0); - i32Stack.push(isSome ? 1 : 0); - return TypedPayloadResultValues.Tag.OptDirection; - } - case TypedPayloadResultValues.Tag.Empty: { - return TypedPayloadResultValues.Tag.Empty; - } - default: throw new Error("Unknown TypedPayloadResultValues tag: " + String(enumTag)); + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case TypedPayloadResultValues.Tag.Precision: { + const rawValue = f32Stack.pop(); + return { tag: TypedPayloadResultValues.Tag.Precision, param0: rawValue }; } - }, - lift: (tag) => { - tag = tag | 0; - switch (tag) { - case TypedPayloadResultValues.Tag.Precision: { + case TypedPayloadResultValues.Tag.Direction: { + const caseId = i32Stack.pop(); + return { tag: TypedPayloadResultValues.Tag.Direction, param0: caseId }; + } + case TypedPayloadResultValues.Tag.OptPrecision: { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { const rawValue = f32Stack.pop(); - return { tag: TypedPayloadResultValues.Tag.Precision, param0: rawValue }; + optional = rawValue; + } else { + optional = null; } - case TypedPayloadResultValues.Tag.Direction: { + return { tag: TypedPayloadResultValues.Tag.OptPrecision, param0: optional }; + } + case TypedPayloadResultValues.Tag.OptDirection: { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { const caseId = i32Stack.pop(); - return { tag: TypedPayloadResultValues.Tag.Direction, param0: caseId }; + optional = caseId; + } else { + optional = null; } - case TypedPayloadResultValues.Tag.OptPrecision: { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const rawValue = f32Stack.pop(); - optional = rawValue; - } else { - optional = null; - } - return { tag: TypedPayloadResultValues.Tag.OptPrecision, param0: optional }; + return { tag: TypedPayloadResultValues.Tag.OptDirection, param0: optional }; + } + case TypedPayloadResultValues.Tag.Empty: return { tag: TypedPayloadResultValues.Tag.Empty }; + default: throw new Error("Unknown TypedPayloadResultValues tag returned from Swift: " + String(tag)); + } + } + }); + const __bjs_createAllTypesResultValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case AllTypesResultValues.Tag.StructPayload: { + structHelpers.Point.lower(value.param0); + return AllTypesResultValues.Tag.StructPayload; + } + case AllTypesResultValues.Tag.ClassPayload: { + ptrStack.push(value.param0.pointer); + return AllTypesResultValues.Tag.ClassPayload; + } + case AllTypesResultValues.Tag.JsObjectPayload: { + const objId = swift.memory.retain(value.param0); + i32Stack.push(objId); + return AllTypesResultValues.Tag.JsObjectPayload; + } + case AllTypesResultValues.Tag.NestedEnum: { + const caseId = enumHelpers.APIResult.lower(value.param0); + i32Stack.push(caseId); + return AllTypesResultValues.Tag.NestedEnum; + } + case AllTypesResultValues.Tag.ArrayPayload: { + for (const elem of value.param0) { + i32Stack.push((elem | 0)); } - case TypedPayloadResultValues.Tag.OptDirection: { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const caseId = i32Stack.pop(); - optional = caseId; - } else { - optional = null; - } - return { tag: TypedPayloadResultValues.Tag.OptDirection, param0: optional }; + i32Stack.push(value.param0.length); + return AllTypesResultValues.Tag.ArrayPayload; + } + case AllTypesResultValues.Tag.Empty: { + return AllTypesResultValues.Tag.Empty; + } + default: throw new Error("Unknown AllTypesResultValues tag: " + String(enumTag)); + } + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case AllTypesResultValues.Tag.StructPayload: { + const struct = structHelpers.Point.lift(); + return { tag: AllTypesResultValues.Tag.StructPayload, param0: struct }; + } + case AllTypesResultValues.Tag.ClassPayload: { + const ptr = ptrStack.pop(); + const obj = _exports['User'].__construct(ptr); + return { tag: AllTypesResultValues.Tag.ClassPayload, param0: obj }; + } + case AllTypesResultValues.Tag.JsObjectPayload: { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return { tag: AllTypesResultValues.Tag.JsObjectPayload, param0: obj }; + } + case AllTypesResultValues.Tag.NestedEnum: { + const enumValue = enumHelpers.APIResult.lift(i32Stack.pop()); + return { tag: AllTypesResultValues.Tag.NestedEnum, param0: enumValue }; + } + case AllTypesResultValues.Tag.ArrayPayload: { + const arrayLen = i32Stack.pop(); + const arrayResult = []; + for (let i = 0; i < arrayLen; i++) { + const int = i32Stack.pop(); + arrayResult.push(int); } - case TypedPayloadResultValues.Tag.Empty: return { tag: TypedPayloadResultValues.Tag.Empty }; - default: throw new Error("Unknown TypedPayloadResultValues tag returned from Swift: " + String(tag)); + arrayResult.reverse(); + return { tag: AllTypesResultValues.Tag.ArrayPayload, param0: arrayResult }; } + case AllTypesResultValues.Tag.Empty: return { tag: AllTypesResultValues.Tag.Empty }; + default: throw new Error("Unknown AllTypesResultValues tag returned from Swift: " + String(tag)); } - }); - }; - const __bjs_createAllTypesResultValuesHelpers = () => { - return () => ({ - lower: (value) => { - const enumTag = value.tag; - switch (enumTag) { - case AllTypesResultValues.Tag.StructPayload: { + } + }); + const __bjs_createOptionalAllTypesResultValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case OptionalAllTypesResultValues.Tag.OptStruct: { + const isSome = value.param0 != null; + if (isSome) { structHelpers.Point.lower(value.param0); - return AllTypesResultValues.Tag.StructPayload; } - case AllTypesResultValues.Tag.ClassPayload: { + i32Stack.push(isSome ? 1 : 0); + return OptionalAllTypesResultValues.Tag.OptStruct; + } + case OptionalAllTypesResultValues.Tag.OptClass: { + const isSome = value.param0 != null; + if (isSome) { ptrStack.push(value.param0.pointer); - return AllTypesResultValues.Tag.ClassPayload; + } else { + ptrStack.push(0); } - case AllTypesResultValues.Tag.JsObjectPayload: { + i32Stack.push(isSome ? 1 : 0); + return OptionalAllTypesResultValues.Tag.OptClass; + } + case OptionalAllTypesResultValues.Tag.OptJSObject: { + const isSome = value.param0 != null; + if (isSome) { const objId = swift.memory.retain(value.param0); i32Stack.push(objId); - return AllTypesResultValues.Tag.JsObjectPayload; + } else { + i32Stack.push(0); } - case AllTypesResultValues.Tag.NestedEnum: { + i32Stack.push(isSome ? 1 : 0); + return OptionalAllTypesResultValues.Tag.OptJSObject; + } + case OptionalAllTypesResultValues.Tag.OptNestedEnum: { + const isSome = value.param0 != null; + if (isSome) { const caseId = enumHelpers.APIResult.lower(value.param0); i32Stack.push(caseId); - return AllTypesResultValues.Tag.NestedEnum; + } else { + i32Stack.push(0); } - case AllTypesResultValues.Tag.ArrayPayload: { + i32Stack.push(isSome ? 1 : 0); + return OptionalAllTypesResultValues.Tag.OptNestedEnum; + } + case OptionalAllTypesResultValues.Tag.OptArray: { + const isSome = value.param0 != null; + if (isSome) { for (const elem of value.param0) { i32Stack.push((elem | 0)); } i32Stack.push(value.param0.length); - return AllTypesResultValues.Tag.ArrayPayload; } - case AllTypesResultValues.Tag.Empty: { - return AllTypesResultValues.Tag.Empty; - } - default: throw new Error("Unknown AllTypesResultValues tag: " + String(enumTag)); + i32Stack.push(isSome ? 1 : 0); + return OptionalAllTypesResultValues.Tag.OptArray; + } + case OptionalAllTypesResultValues.Tag.Empty: { + return OptionalAllTypesResultValues.Tag.Empty; } - }, - lift: (tag) => { - tag = tag | 0; - switch (tag) { - case AllTypesResultValues.Tag.StructPayload: { + default: throw new Error("Unknown OptionalAllTypesResultValues tag: " + String(enumTag)); + } + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case OptionalAllTypesResultValues.Tag.OptStruct: { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { const struct = structHelpers.Point.lift(); - return { tag: AllTypesResultValues.Tag.StructPayload, param0: struct }; + optional = struct; + } else { + optional = null; } - case AllTypesResultValues.Tag.ClassPayload: { + return { tag: OptionalAllTypesResultValues.Tag.OptStruct, param0: optional }; + } + case OptionalAllTypesResultValues.Tag.OptClass: { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { const ptr = ptrStack.pop(); const obj = _exports['User'].__construct(ptr); - return { tag: AllTypesResultValues.Tag.ClassPayload, param0: obj }; + optional = obj; + } else { + optional = null; } - case AllTypesResultValues.Tag.JsObjectPayload: { + return { tag: OptionalAllTypesResultValues.Tag.OptClass, param0: optional }; + } + case OptionalAllTypesResultValues.Tag.OptJSObject: { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { const objId = i32Stack.pop(); const obj = swift.memory.getObject(objId); swift.memory.release(objId); - return { tag: AllTypesResultValues.Tag.JsObjectPayload, param0: obj }; + optional = obj; + } else { + optional = null; } - case AllTypesResultValues.Tag.NestedEnum: { - const enumValue = enumHelpers.APIResult.lift(i32Stack.pop(), ); - return { tag: AllTypesResultValues.Tag.NestedEnum, param0: enumValue }; + return { tag: OptionalAllTypesResultValues.Tag.OptJSObject, param0: optional }; + } + case OptionalAllTypesResultValues.Tag.OptNestedEnum: { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { + const caseId = i32Stack.pop(); + optional = enumHelpers.APIResult.lift(caseId); + } else { + optional = null; } - case AllTypesResultValues.Tag.ArrayPayload: { + return { tag: OptionalAllTypesResultValues.Tag.OptNestedEnum, param0: optional }; + } + case OptionalAllTypesResultValues.Tag.OptArray: { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { const arrayLen = i32Stack.pop(); const arrayResult = []; for (let i = 0; i < arrayLen; i++) { @@ -638,152 +750,17 @@ export async function createInstantiator(options, swift) { arrayResult.push(int); } arrayResult.reverse(); - return { tag: AllTypesResultValues.Tag.ArrayPayload, param0: arrayResult }; - } - case AllTypesResultValues.Tag.Empty: return { tag: AllTypesResultValues.Tag.Empty }; - default: throw new Error("Unknown AllTypesResultValues tag returned from Swift: " + String(tag)); - } - } - }); - }; - const __bjs_createOptionalAllTypesResultValuesHelpers = () => { - return () => ({ - lower: (value) => { - const enumTag = value.tag; - switch (enumTag) { - case OptionalAllTypesResultValues.Tag.OptStruct: { - const isSome = value.param0 != null; - if (isSome) { - structHelpers.Point.lower(value.param0); - } - i32Stack.push(isSome ? 1 : 0); - return OptionalAllTypesResultValues.Tag.OptStruct; - } - case OptionalAllTypesResultValues.Tag.OptClass: { - const isSome = value.param0 != null; - if (isSome) { - ptrStack.push(value.param0.pointer); - } else { - ptrStack.push(0); - } - i32Stack.push(isSome ? 1 : 0); - return OptionalAllTypesResultValues.Tag.OptClass; - } - case OptionalAllTypesResultValues.Tag.OptJSObject: { - const isSome = value.param0 != null; - let id; - if (isSome) { - id = swift.memory.retain(value.param0); - i32Stack.push(id); - } else { - id = undefined; - i32Stack.push(0); - } - i32Stack.push(isSome ? 1 : 0); - return OptionalAllTypesResultValues.Tag.OptJSObject; - } - case OptionalAllTypesResultValues.Tag.OptNestedEnum: { - const isSome = value.param0 != null; - let enumCaseId; - if (isSome) { - enumCaseId = enumHelpers.APIResult.lower(value.param0); - i32Stack.push(enumCaseId); - } else { - i32Stack.push(0); - } - i32Stack.push(isSome ? 1 : 0); - return OptionalAllTypesResultValues.Tag.OptNestedEnum; - } - case OptionalAllTypesResultValues.Tag.OptArray: { - const isSome = value.param0 != null; - if (isSome) { - for (const elem of value.param0) { - i32Stack.push((elem | 0)); - } - i32Stack.push(value.param0.length); - } - i32Stack.push(isSome ? 1 : 0); - return OptionalAllTypesResultValues.Tag.OptArray; - } - case OptionalAllTypesResultValues.Tag.Empty: { - return OptionalAllTypesResultValues.Tag.Empty; - } - default: throw new Error("Unknown OptionalAllTypesResultValues tag: " + String(enumTag)); - } - }, - lift: (tag) => { - tag = tag | 0; - switch (tag) { - case OptionalAllTypesResultValues.Tag.OptStruct: { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const struct = structHelpers.Point.lift(); - optional = struct; - } else { - optional = null; - } - return { tag: OptionalAllTypesResultValues.Tag.OptStruct, param0: optional }; - } - case OptionalAllTypesResultValues.Tag.OptClass: { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const ptr = ptrStack.pop(); - const obj = _exports['User'].__construct(ptr); - optional = obj; - } else { - optional = null; - } - return { tag: OptionalAllTypesResultValues.Tag.OptClass, param0: optional }; - } - case OptionalAllTypesResultValues.Tag.OptJSObject: { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - optional = obj; - } else { - optional = null; - } - return { tag: OptionalAllTypesResultValues.Tag.OptJSObject, param0: optional }; - } - case OptionalAllTypesResultValues.Tag.OptNestedEnum: { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const caseId = i32Stack.pop(); - optional = enumHelpers.APIResult.lift(caseId); - } else { - optional = null; - } - return { tag: OptionalAllTypesResultValues.Tag.OptNestedEnum, param0: optional }; - } - case OptionalAllTypesResultValues.Tag.OptArray: { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - optional = arrayResult; - } else { - optional = null; - } - return { tag: OptionalAllTypesResultValues.Tag.OptArray, param0: optional }; + optional = arrayResult; + } else { + optional = null; } - case OptionalAllTypesResultValues.Tag.Empty: return { tag: OptionalAllTypesResultValues.Tag.Empty }; - default: throw new Error("Unknown OptionalAllTypesResultValues tag returned from Swift: " + String(tag)); + return { tag: OptionalAllTypesResultValues.Tag.OptArray, param0: optional }; } + case OptionalAllTypesResultValues.Tag.Empty: return { tag: OptionalAllTypesResultValues.Tag.Empty }; + default: throw new Error("Unknown OptionalAllTypesResultValues tag returned from Swift: " + String(tag)); } - }); - }; + } + }); return { /** @@ -1002,31 +979,31 @@ export async function createInstantiator(options, swift) { } } - const PointHelpers = __bjs_createPointHelpers()(); + const PointHelpers = __bjs_createPointHelpers(); structHelpers.Point = PointHelpers; - const APIResultHelpers = __bjs_createAPIResultValuesHelpers()(); + const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); enumHelpers.APIResult = APIResultHelpers; - const ComplexResultHelpers = __bjs_createComplexResultValuesHelpers()(); + const ComplexResultHelpers = __bjs_createComplexResultValuesHelpers(); enumHelpers.ComplexResult = ComplexResultHelpers; - const ResultHelpers = __bjs_createResultValuesHelpers()(); + const ResultHelpers = __bjs_createResultValuesHelpers(); enumHelpers.Result = ResultHelpers; - const NetworkingResultHelpers = __bjs_createNetworkingResultValuesHelpers()(); + const NetworkingResultHelpers = __bjs_createNetworkingResultValuesHelpers(); enumHelpers.NetworkingResult = NetworkingResultHelpers; - const APIOptionalResultHelpers = __bjs_createAPIOptionalResultValuesHelpers()(); + const APIOptionalResultHelpers = __bjs_createAPIOptionalResultValuesHelpers(); enumHelpers.APIOptionalResult = APIOptionalResultHelpers; - const TypedPayloadResultHelpers = __bjs_createTypedPayloadResultValuesHelpers()(); + const TypedPayloadResultHelpers = __bjs_createTypedPayloadResultValuesHelpers(); enumHelpers.TypedPayloadResult = TypedPayloadResultHelpers; - const AllTypesResultHelpers = __bjs_createAllTypesResultValuesHelpers()(); + const AllTypesResultHelpers = __bjs_createAllTypesResultValuesHelpers(); enumHelpers.AllTypesResult = AllTypesResultHelpers; - const OptionalAllTypesResultHelpers = __bjs_createOptionalAllTypesResultValuesHelpers()(); + const OptionalAllTypesResultHelpers = __bjs_createOptionalAllTypesResultValuesHelpers(); enumHelpers.OptionalAllTypesResult = OptionalAllTypesResultHelpers; const exports = { @@ -1048,19 +1025,16 @@ export async function createInstantiator(options, swift) { }, roundTripOptionalAPIResult: function bjs_roundTripOptionalAPIResult(result) { const isSome = result != null; - let resultCaseId; + let result1; if (isSome) { - resultCaseId = enumHelpers.APIResult.lower(result); - } - instance.exports.bjs_roundTripOptionalAPIResult(+isSome, isSome ? resultCaseId : 0); - const tag = i32Stack.pop(); - const isNull = (tag === -1); - let optResult; - if (isNull) { - optResult = null; + const resultCaseId = enumHelpers.APIResult.lower(result); + result1 = resultCaseId; } else { - optResult = enumHelpers.APIResult.lift(tag); + result1 = 0; } + instance.exports.bjs_roundTripOptionalAPIResult(+isSome, result1); + const tag = i32Stack.pop(); + const optResult = tag === -1 ? null : enumHelpers.APIResult.lift(tag); return optResult; }, handleComplex: function bjs_handleComplex(result) { @@ -1080,92 +1054,80 @@ export async function createInstantiator(options, swift) { }, roundTripOptionalComplexResult: function bjs_roundTripOptionalComplexResult(result) { const isSome = result != null; - let resultCaseId; + let result1; if (isSome) { - resultCaseId = enumHelpers.ComplexResult.lower(result); - } - instance.exports.bjs_roundTripOptionalComplexResult(+isSome, isSome ? resultCaseId : 0); - const tag = i32Stack.pop(); - const isNull = (tag === -1); - let optResult; - if (isNull) { - optResult = null; + const resultCaseId = enumHelpers.ComplexResult.lower(result); + result1 = resultCaseId; } else { - optResult = enumHelpers.ComplexResult.lift(tag); + result1 = 0; } + instance.exports.bjs_roundTripOptionalComplexResult(+isSome, result1); + const tag = i32Stack.pop(); + const optResult = tag === -1 ? null : enumHelpers.ComplexResult.lift(tag); return optResult; }, roundTripOptionalUtilitiesResult: function bjs_roundTripOptionalUtilitiesResult(result) { const isSome = result != null; - let resultCaseId; + let result1; if (isSome) { - resultCaseId = enumHelpers.Result.lower(result); - } - instance.exports.bjs_roundTripOptionalUtilitiesResult(+isSome, isSome ? resultCaseId : 0); - const tag = i32Stack.pop(); - const isNull = (tag === -1); - let optResult; - if (isNull) { - optResult = null; + const resultCaseId = enumHelpers.Result.lower(result); + result1 = resultCaseId; } else { - optResult = enumHelpers.Result.lift(tag); + result1 = 0; } + instance.exports.bjs_roundTripOptionalUtilitiesResult(+isSome, result1); + const tag = i32Stack.pop(); + const optResult = tag === -1 ? null : enumHelpers.Result.lift(tag); return optResult; }, roundTripOptionalNetworkingResult: function bjs_roundTripOptionalNetworkingResult(result) { const isSome = result != null; - let resultCaseId; + let result1; if (isSome) { - resultCaseId = enumHelpers.NetworkingResult.lower(result); - } - instance.exports.bjs_roundTripOptionalNetworkingResult(+isSome, isSome ? resultCaseId : 0); - const tag = i32Stack.pop(); - const isNull = (tag === -1); - let optResult; - if (isNull) { - optResult = null; + const resultCaseId = enumHelpers.NetworkingResult.lower(result); + result1 = resultCaseId; } else { - optResult = enumHelpers.NetworkingResult.lift(tag); + result1 = 0; } + instance.exports.bjs_roundTripOptionalNetworkingResult(+isSome, result1); + const tag = i32Stack.pop(); + const optResult = tag === -1 ? null : enumHelpers.NetworkingResult.lift(tag); return optResult; }, roundTripOptionalAPIOptionalResult: function bjs_roundTripOptionalAPIOptionalResult(result) { const isSome = result != null; - let resultCaseId; + let result1; if (isSome) { - resultCaseId = enumHelpers.APIOptionalResult.lower(result); - } - instance.exports.bjs_roundTripOptionalAPIOptionalResult(+isSome, isSome ? resultCaseId : 0); - const tag = i32Stack.pop(); - const isNull = (tag === -1); - let optResult; - if (isNull) { - optResult = null; + const resultCaseId = enumHelpers.APIOptionalResult.lower(result); + result1 = resultCaseId; } else { - optResult = enumHelpers.APIOptionalResult.lift(tag); + result1 = 0; } + instance.exports.bjs_roundTripOptionalAPIOptionalResult(+isSome, result1); + const tag = i32Stack.pop(); + const optResult = tag === -1 ? null : enumHelpers.APIOptionalResult.lift(tag); return optResult; }, compareAPIResults: function bjs_compareAPIResults(result1, result2) { const isSome = result1 != null; - let result1CaseId; + let result; if (isSome) { - result1CaseId = enumHelpers.APIOptionalResult.lower(result1); + const result1CaseId = enumHelpers.APIOptionalResult.lower(result1); + result = result1CaseId; + } else { + result = 0; } const isSome1 = result2 != null; - let result2CaseId; + let result3; if (isSome1) { - result2CaseId = enumHelpers.APIOptionalResult.lower(result2); - } - instance.exports.bjs_compareAPIResults(+isSome, isSome ? result1CaseId : 0, +isSome1, isSome1 ? result2CaseId : 0); - const tag = i32Stack.pop(); - const isNull = (tag === -1); - let optResult; - if (isNull) { - optResult = null; + const result2CaseId = enumHelpers.APIOptionalResult.lower(result2); + result3 = result2CaseId; } else { - optResult = enumHelpers.APIOptionalResult.lift(tag); + result3 = 0; } + instance.exports.bjs_compareAPIResults(+isSome, result, +isSome1, result3); + const tag = i32Stack.pop(); + const optResult = tag === -1 ? null : enumHelpers.APIOptionalResult.lift(tag); return optResult; }, roundTripTypedPayloadResult: function bjs_roundTripTypedPayloadResult(result) { @@ -1176,19 +1138,16 @@ export async function createInstantiator(options, swift) { }, roundTripOptionalTypedPayloadResult: function bjs_roundTripOptionalTypedPayloadResult(result) { const isSome = result != null; - let resultCaseId; + let result1; if (isSome) { - resultCaseId = enumHelpers.TypedPayloadResult.lower(result); - } - instance.exports.bjs_roundTripOptionalTypedPayloadResult(+isSome, isSome ? resultCaseId : 0); - const tag = i32Stack.pop(); - const isNull = (tag === -1); - let optResult; - if (isNull) { - optResult = null; + const resultCaseId = enumHelpers.TypedPayloadResult.lower(result); + result1 = resultCaseId; } else { - optResult = enumHelpers.TypedPayloadResult.lift(tag); + result1 = 0; } + instance.exports.bjs_roundTripOptionalTypedPayloadResult(+isSome, result1); + const tag = i32Stack.pop(); + const optResult = tag === -1 ? null : enumHelpers.TypedPayloadResult.lift(tag); return optResult; }, roundTripAllTypesResult: function bjs_roundTripAllTypesResult(result) { @@ -1199,19 +1158,16 @@ export async function createInstantiator(options, swift) { }, roundTripOptionalAllTypesResult: function bjs_roundTripOptionalAllTypesResult(result) { const isSome = result != null; - let resultCaseId; + let result1; if (isSome) { - resultCaseId = enumHelpers.AllTypesResult.lower(result); - } - instance.exports.bjs_roundTripOptionalAllTypesResult(+isSome, isSome ? resultCaseId : 0); - const tag = i32Stack.pop(); - const isNull = (tag === -1); - let optResult; - if (isNull) { - optResult = null; + const resultCaseId = enumHelpers.AllTypesResult.lower(result); + result1 = resultCaseId; } else { - optResult = enumHelpers.AllTypesResult.lift(tag); + result1 = 0; } + instance.exports.bjs_roundTripOptionalAllTypesResult(+isSome, result1); + const tag = i32Stack.pop(); + const optResult = tag === -1 ? null : enumHelpers.AllTypesResult.lift(tag); return optResult; }, roundTripOptionalPayloadResult: function bjs_roundTripOptionalPayloadResult(result) { @@ -1222,19 +1178,16 @@ export async function createInstantiator(options, swift) { }, roundTripOptionalPayloadResultOpt: function bjs_roundTripOptionalPayloadResultOpt(result) { const isSome = result != null; - let resultCaseId; + let result1; if (isSome) { - resultCaseId = enumHelpers.OptionalAllTypesResult.lower(result); - } - instance.exports.bjs_roundTripOptionalPayloadResultOpt(+isSome, isSome ? resultCaseId : 0); - const tag = i32Stack.pop(); - const isNull = (tag === -1); - let optResult; - if (isNull) { - optResult = null; + const resultCaseId = enumHelpers.OptionalAllTypesResult.lower(result); + result1 = resultCaseId; } else { - optResult = enumHelpers.OptionalAllTypesResult.lift(tag); + result1 = 0; } + instance.exports.bjs_roundTripOptionalPayloadResultOpt(+isSome, result1); + const tag = i32Stack.pop(); + const optResult = tag === -1 ? null : enumHelpers.OptionalAllTypesResult.lift(tag); return optResult; }, APIResult: APIResultValues, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js index 77d106b57..efd75f1fa 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js @@ -305,12 +305,17 @@ export async function createInstantiator(options, swift) { }, roundTripOptionalTheme: function bjs_roundTripOptionalTheme(input) { const isSome = input != null; - let inputId, inputBytes; + let result, result1; if (isSome) { - inputBytes = textEncoder.encode(input); - inputId = swift.memory.retain(inputBytes); + const inputBytes = textEncoder.encode(input); + const inputId = swift.memory.retain(inputBytes); + result = inputId; + result1 = inputBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_roundTripOptionalTheme(+isSome, isSome ? inputId : 0, isSome ? inputBytes.length : 0); + instance.exports.bjs_roundTripOptionalTheme(+isSome, result, result1); const optResult = tmpRetString; tmpRetString = undefined; return optResult; @@ -328,12 +333,17 @@ export async function createInstantiator(options, swift) { }, roundTripOptionalTSTheme: function bjs_roundTripOptionalTSTheme(input) { const isSome = input != null; - let inputId, inputBytes; + let result, result1; if (isSome) { - inputBytes = textEncoder.encode(input); - inputId = swift.memory.retain(inputBytes); + const inputBytes = textEncoder.encode(input); + const inputId = swift.memory.retain(inputBytes); + result = inputId; + result1 = inputBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_roundTripOptionalTSTheme(+isSome, isSome ? inputId : 0, isSome ? inputBytes.length : 0); + instance.exports.bjs_roundTripOptionalTSTheme(+isSome, result, result1); const optResult = tmpRetString; tmpRetString = undefined; return optResult; @@ -351,12 +361,17 @@ export async function createInstantiator(options, swift) { }, roundTripOptionalFeatureFlag: function bjs_roundTripOptionalFeatureFlag(input) { const isSome = input != null; - let inputId, inputBytes; + let result, result1; if (isSome) { - inputBytes = textEncoder.encode(input); - inputId = swift.memory.retain(inputBytes); + const inputBytes = textEncoder.encode(input); + const inputId = swift.memory.retain(inputBytes); + result = inputId; + result1 = inputBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_roundTripOptionalFeatureFlag(+isSome, isSome ? inputId : 0, isSome ? inputBytes.length : 0); + instance.exports.bjs_roundTripOptionalFeatureFlag(+isSome, result, result1); const optResult = tmpRetString; tmpRetString = undefined; return optResult; @@ -468,7 +483,7 @@ export async function createInstantiator(options, swift) { }, roundTripOptionalPrecision: function bjs_roundTripOptionalPrecision(input) { const isSome = input != null; - instance.exports.bjs_roundTripOptionalPrecision(+isSome, isSome ? input : 0); + instance.exports.bjs_roundTripOptionalPrecision(+isSome, isSome ? input : 0.0); const optResult = tmpRetOptionalFloat; tmpRetOptionalFloat = undefined; return optResult; @@ -482,7 +497,7 @@ export async function createInstantiator(options, swift) { }, roundTripOptionalRatio: function bjs_roundTripOptionalRatio(input) { const isSome = input != null; - instance.exports.bjs_roundTripOptionalRatio(+isSome, isSome ? input : 0); + instance.exports.bjs_roundTripOptionalRatio(+isSome, isSome ? input : 0.0); const optResult = tmpRetOptionalDouble; tmpRetOptionalDouble = undefined; return optResult; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js index 92230667c..c0c9704ef 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js @@ -28,55 +28,56 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createFooContainerHelpers = () => { - return () => ({ - lower: (value) => { - let id; - if (value.foo != null) { - id = swift.memory.retain(value.foo); - } else { - id = undefined; - } - i32Stack.push(id !== undefined ? id : 0); - const isSome = value.optionalFoo != null; + const __bjs_createFooContainerHelpers = () => ({ + lower: (value) => { + let id; + if (value.foo != null) { + id = swift.memory.retain(value.foo); + } else { + id = undefined; + } + i32Stack.push(id !== undefined ? id : 0); + const isSome = value.optionalFoo != null; + if (isSome) { let id1; - if (isSome) { + if (value.optionalFoo != null) { id1 = swift.memory.retain(value.optionalFoo); - i32Stack.push(id1); } else { id1 = undefined; - i32Stack.push(0); - } - i32Stack.push(isSome ? 1 : 0); - }, - lift: () => { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const objectId = i32Stack.pop(); - let value; - if (objectId !== 0) { - value = swift.memory.getObject(objectId); - swift.memory.release(objectId); - } else { - value = null; - } - optional = value; - } else { - optional = null; } - const objectId1 = i32Stack.pop(); - let value1; - if (objectId1 !== 0) { - value1 = swift.memory.getObject(objectId1); - swift.memory.release(objectId1); + i32Stack.push(id1 !== undefined ? id1 : 0); + } else { + i32Stack.push(0); + } + i32Stack.push(isSome ? 1 : 0); + }, + lift: () => { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { + const objectId = i32Stack.pop(); + let value; + if (objectId !== 0) { + value = swift.memory.getObject(objectId); + swift.memory.release(objectId); } else { - value1 = null; + value = null; } - return { foo: value1, optionalFoo: optional }; - } - }); - }; + optional = value; + } else { + optional = null; + } + const objectId1 = i32Stack.pop(); + let value1; + if (objectId1 !== 0) { + value1 = swift.memory.getObject(objectId1); + swift.memory.release(objectId1); + } else { + value1 = null; + } + return { foo: value1, optionalFoo: optional }; + } + }); return { /** @@ -262,7 +263,7 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - const FooContainerHelpers = __bjs_createFooContainerHelpers()(); + const FooContainerHelpers = __bjs_createFooContainerHelpers(); structHelpers.FooContainer = FooContainerHelpers; const exports = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js index 0a4d37845..8571bbd6c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js @@ -368,15 +368,35 @@ export async function createInstantiator(options, swift) { constructor(value, optionalValue) { const [valueKind, valuePayload1, valuePayload2] = __bjs_jsValueLower(value); const isSome = optionalValue != null; - const [optionalValueKind, optionalValuePayload1, optionalValuePayload2] = __bjs_jsValueLower(optionalValue); - const ret = instance.exports.bjs_JSValueHolder_init(valueKind, valuePayload1, valuePayload2, +isSome, optionalValueKind, optionalValuePayload1, optionalValuePayload2); + let result, result1, result2; + if (isSome) { + const [optionalValueKind, optionalValuePayload1, optionalValuePayload2] = __bjs_jsValueLower(optionalValue); + result = optionalValueKind; + result1 = optionalValuePayload1; + result2 = optionalValuePayload2; + } else { + result = 0; + result1 = 0; + result2 = 0.0; + } + const ret = instance.exports.bjs_JSValueHolder_init(valueKind, valuePayload1, valuePayload2, +isSome, result, result1, result2); return JSValueHolder.__construct(ret); } update(value, optionalValue) { const [valueKind, valuePayload1, valuePayload2] = __bjs_jsValueLower(value); const isSome = optionalValue != null; - const [optionalValueKind, optionalValuePayload1, optionalValuePayload2] = __bjs_jsValueLower(optionalValue); - instance.exports.bjs_JSValueHolder_update(this.pointer, valueKind, valuePayload1, valuePayload2, +isSome, optionalValueKind, optionalValuePayload1, optionalValuePayload2); + let result, result1, result2; + if (isSome) { + const [optionalValueKind, optionalValuePayload1, optionalValuePayload2] = __bjs_jsValueLower(optionalValue); + result = optionalValueKind; + result1 = optionalValuePayload1; + result2 = optionalValuePayload2; + } else { + result = 0; + result1 = 0; + result2 = 0.0; + } + instance.exports.bjs_JSValueHolder_update(this.pointer, valueKind, valuePayload1, valuePayload2, +isSome, result, result1, result2); } echo(value) { const [valueKind, valuePayload1, valuePayload2] = __bjs_jsValueLower(value); @@ -389,8 +409,18 @@ export async function createInstantiator(options, swift) { } echoOptional(value) { const isSome = value != null; - const [valueKind, valuePayload1, valuePayload2] = __bjs_jsValueLower(value); - instance.exports.bjs_JSValueHolder_echoOptional(this.pointer, +isSome, valueKind, valuePayload1, valuePayload2); + let result, result1, result2; + if (isSome) { + const [valueKind, valuePayload1, valuePayload2] = __bjs_jsValueLower(value); + result = valueKind; + result1 = valuePayload1; + result2 = valuePayload2; + } else { + result = 0; + result1 = 0; + result2 = 0.0; + } + instance.exports.bjs_JSValueHolder_echoOptional(this.pointer, +isSome, result, result1, result2); const isSome1 = i32Stack.pop(); let optResult; if (isSome1) { @@ -433,8 +463,18 @@ export async function createInstantiator(options, swift) { } set optionalValue(value) { const isSome = value != null; - const [valueKind, valuePayload1, valuePayload2] = __bjs_jsValueLower(value); - instance.exports.bjs_JSValueHolder_optionalValue_set(this.pointer, +isSome, valueKind, valuePayload1, valuePayload2); + let result, result1, result2; + if (isSome) { + const [valueKind, valuePayload1, valuePayload2] = __bjs_jsValueLower(value); + result = valueKind; + result1 = valuePayload1; + result2 = valuePayload2; + } else { + result = 0; + result1 = 0; + result2 = 0.0; + } + instance.exports.bjs_JSValueHolder_optionalValue_set(this.pointer, +isSome, result, result1, result2); } } const exports = { @@ -450,8 +490,18 @@ export async function createInstantiator(options, swift) { }, roundTripOptionalJSValue: function bjs_roundTripOptionalJSValue(value) { const isSome = value != null; - const [valueKind, valuePayload1, valuePayload2] = __bjs_jsValueLower(value); - instance.exports.bjs_roundTripOptionalJSValue(+isSome, valueKind, valuePayload1, valuePayload2); + let result, result1, result2; + if (isSome) { + const [valueKind, valuePayload1, valuePayload2] = __bjs_jsValueLower(value); + result = valueKind; + result1 = valuePayload1; + result2 = valuePayload2; + } else { + result = 0; + result1 = 0; + result2 = 0.0; + } + instance.exports.bjs_roundTripOptionalJSValue(+isSome, result, result1, result2); const isSome1 = i32Stack.pop(); let optResult; if (isSome1) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index 03a3cf565..941d66ea9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -198,19 +198,25 @@ export async function createInstantiator(options, swift) { return swift.memory.retain(obj); }; const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; - TestModule["bjs_WithOptionalJSClass_init"] = function bjs_WithOptionalJSClass_init(valueOrNullIsSome, valueOrNullWrappedValue, valueOrUndefinedIsSome, valueOrUndefinedWrappedValue) { + TestModule["bjs_WithOptionalJSClass_init"] = function bjs_WithOptionalJSClass_init(valueOrNullIsSome, valueOrNullObjectId, valueOrUndefinedIsSome, valueOrUndefinedObjectId) { try { - let obj; + let optResult; if (valueOrNullIsSome) { - obj = swift.memory.getObject(valueOrNullWrappedValue); - swift.memory.release(valueOrNullWrappedValue); + const valueOrNullObjectIdObject = swift.memory.getObject(valueOrNullObjectId); + swift.memory.release(valueOrNullObjectId); + optResult = valueOrNullObjectIdObject; + } else { + optResult = null; } - let obj1; + let optResult1; if (valueOrUndefinedIsSome) { - obj1 = swift.memory.getObject(valueOrUndefinedWrappedValue); - swift.memory.release(valueOrUndefinedWrappedValue); + const valueOrUndefinedObjectIdObject = swift.memory.getObject(valueOrUndefinedObjectId); + swift.memory.release(valueOrUndefinedObjectId); + optResult1 = valueOrUndefinedObjectIdObject; + } else { + optResult1 = undefined; } - return swift.memory.retain(new imports.WithOptionalJSClass(valueOrNullIsSome ? obj : null, valueOrUndefinedIsSome ? obj1 : undefined)); + return swift.memory.retain(new imports.WithOptionalJSClass(optResult, optResult1)); } catch (error) { setException(error); return 0 @@ -220,11 +226,7 @@ export async function createInstantiator(options, swift) { try { let ret = swift.memory.getObject(self).stringOrNull; const isSome = ret != null; - if (isSome) { - tmpRetString = ret; - } else { - tmpRetString = null; - } + tmpRetString = isSome ? ret : null; } catch (error) { setException(error); } @@ -233,11 +235,7 @@ export async function createInstantiator(options, swift) { try { let ret = swift.memory.getObject(self).stringOrUndefined; const isSome = ret !== undefined; - if (isSome) { - tmpRetString = ret; - } else { - tmpRetString = null; - } + tmpRetString = isSome ? ret : undefined; } catch (error) { setException(error); } @@ -296,26 +294,32 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_WithOptionalJSClass_stringOrNull_set"] = function bjs_WithOptionalJSClass_stringOrNull_set(self, newValueIsSome, newValueWrappedValue) { + TestModule["bjs_WithOptionalJSClass_stringOrNull_set"] = function bjs_WithOptionalJSClass_stringOrNull_set(self, newValueIsSome, newValueObjectId) { try { - let obj; + let optResult; if (newValueIsSome) { - obj = swift.memory.getObject(newValueWrappedValue); - swift.memory.release(newValueWrappedValue); + const newValueObjectIdObject = swift.memory.getObject(newValueObjectId); + swift.memory.release(newValueObjectId); + optResult = newValueObjectIdObject; + } else { + optResult = null; } - swift.memory.getObject(self).stringOrNull = newValueIsSome ? obj : null; + swift.memory.getObject(self).stringOrNull = optResult; } catch (error) { setException(error); } } - TestModule["bjs_WithOptionalJSClass_stringOrUndefined_set"] = function bjs_WithOptionalJSClass_stringOrUndefined_set(self, newValueIsSome, newValueWrappedValue) { + TestModule["bjs_WithOptionalJSClass_stringOrUndefined_set"] = function bjs_WithOptionalJSClass_stringOrUndefined_set(self, newValueIsSome, newValueObjectId) { try { - let obj; + let optResult; if (newValueIsSome) { - obj = swift.memory.getObject(newValueWrappedValue); - swift.memory.release(newValueWrappedValue); + const newValueObjectIdObject = swift.memory.getObject(newValueObjectId); + swift.memory.release(newValueObjectId); + optResult = newValueObjectIdObject; + } else { + optResult = undefined; } - swift.memory.getObject(self).stringOrUndefined = newValueIsSome ? obj : undefined; + swift.memory.getObject(self).stringOrUndefined = optResult; } catch (error) { setException(error); } @@ -362,38 +366,36 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_WithOptionalJSClass_roundTripStringOrNull"] = function bjs_WithOptionalJSClass_roundTripStringOrNull(self, valueIsSome, valueWrappedValue) { + TestModule["bjs_WithOptionalJSClass_roundTripStringOrNull"] = function bjs_WithOptionalJSClass_roundTripStringOrNull(self, valueIsSome, valueObjectId) { try { - let obj; + let optResult; if (valueIsSome) { - obj = swift.memory.getObject(valueWrappedValue); - swift.memory.release(valueWrappedValue); - } - let ret = swift.memory.getObject(self).roundTripStringOrNull(valueIsSome ? obj : null); - const isSome = ret != null; - if (isSome) { - tmpRetString = ret; + const valueObjectIdObject = swift.memory.getObject(valueObjectId); + swift.memory.release(valueObjectId); + optResult = valueObjectIdObject; } else { - tmpRetString = null; + optResult = null; } + let ret = swift.memory.getObject(self).roundTripStringOrNull(optResult); + const isSome = ret != null; + tmpRetString = isSome ? ret : null; } catch (error) { setException(error); } } - TestModule["bjs_WithOptionalJSClass_roundTripStringOrUndefined"] = function bjs_WithOptionalJSClass_roundTripStringOrUndefined(self, valueIsSome, valueWrappedValue) { + TestModule["bjs_WithOptionalJSClass_roundTripStringOrUndefined"] = function bjs_WithOptionalJSClass_roundTripStringOrUndefined(self, valueIsSome, valueObjectId) { try { - let obj; + let optResult; if (valueIsSome) { - obj = swift.memory.getObject(valueWrappedValue); - swift.memory.release(valueWrappedValue); - } - let ret = swift.memory.getObject(self).roundTripStringOrUndefined(valueIsSome ? obj : undefined); - const isSome = ret !== undefined; - if (isSome) { - tmpRetString = ret; + const valueObjectIdObject = swift.memory.getObject(valueObjectId); + swift.memory.release(valueObjectId); + optResult = valueObjectIdObject; } else { - tmpRetString = null; + optResult = undefined; } + let ret = swift.memory.getObject(self).roundTripStringOrUndefined(optResult); + const isSome = ret !== undefined; + tmpRetString = isSome ? ret : undefined; } catch (error) { setException(error); } @@ -500,12 +502,17 @@ export async function createInstantiator(options, swift) { constructor(name) { const isSome = name != null; - let nameId, nameBytes; + let result, result1; if (isSome) { - nameBytes = textEncoder.encode(name); - nameId = swift.memory.retain(nameBytes); + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + result = nameId; + result1 = nameBytes.length; + } else { + result = 0; + result1 = 0; } - const ret = instance.exports.bjs_Greeter_init(+isSome, isSome ? nameId : 0, isSome ? nameBytes.length : 0); + const ret = instance.exports.bjs_Greeter_init(+isSome, result, result1); return Greeter.__construct(ret); } greet() { @@ -516,12 +523,17 @@ export async function createInstantiator(options, swift) { } changeName(name) { const isSome = name != null; - let nameId, nameBytes; + let result, result1; if (isSome) { - nameBytes = textEncoder.encode(name); - nameId = swift.memory.retain(nameBytes); + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + result = nameId; + result1 = nameBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_Greeter_changeName(this.pointer, +isSome, isSome ? nameId : 0, isSome ? nameBytes.length : 0); + instance.exports.bjs_Greeter_changeName(this.pointer, +isSome, result, result1); } get name() { instance.exports.bjs_Greeter_name_get(this.pointer); @@ -531,12 +543,17 @@ export async function createInstantiator(options, swift) { } set name(value) { const isSome = value != null; - let valueId, valueBytes; + let result, result1; if (isSome) { - valueBytes = textEncoder.encode(value); - valueId = swift.memory.retain(valueBytes); + const valueBytes = textEncoder.encode(value); + const valueId = swift.memory.retain(valueBytes); + result = valueId; + result1 = valueBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_Greeter_name_set(this.pointer, +isSome, isSome ? valueId : 0, isSome ? valueBytes.length : 0); + instance.exports.bjs_Greeter_name_set(this.pointer, +isSome, result, result1); } } class OptionalPropertyHolder extends SwiftHeapObject { @@ -556,12 +573,17 @@ export async function createInstantiator(options, swift) { } set optionalName(value) { const isSome = value != null; - let valueId, valueBytes; + let result, result1; if (isSome) { - valueBytes = textEncoder.encode(value); - valueId = swift.memory.retain(valueBytes); + const valueBytes = textEncoder.encode(value); + const valueId = swift.memory.retain(valueBytes); + result = valueId; + result1 = valueBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_OptionalPropertyHolder_optionalName_set(this.pointer, +isSome, isSome ? valueId : 0, isSome ? valueBytes.length : 0); + instance.exports.bjs_OptionalPropertyHolder_optionalName_set(this.pointer, +isSome, result, result1); } get optionalAge() { instance.exports.bjs_OptionalPropertyHolder_optionalAge_get(this.pointer); @@ -582,7 +604,13 @@ export async function createInstantiator(options, swift) { } set optionalGreeter(value) { const isSome = value != null; - instance.exports.bjs_OptionalPropertyHolder_optionalGreeter_set(this.pointer, +isSome, isSome ? value.pointer : 0); + let result; + if (isSome) { + result = value.pointer; + } else { + result = 0; + } + instance.exports.bjs_OptionalPropertyHolder_optionalGreeter_set(this.pointer, +isSome, result); } } const exports = { @@ -590,7 +618,13 @@ export async function createInstantiator(options, swift) { OptionalPropertyHolder, roundTripOptionalClass: function bjs_roundTripOptionalClass(value) { const isSome = value != null; - instance.exports.bjs_roundTripOptionalClass(+isSome, isSome ? value.pointer : 0); + let result; + if (isSome) { + result = value.pointer; + } else { + result = 0; + } + instance.exports.bjs_roundTripOptionalClass(+isSome, result); const pointer = tmpRetOptionalHeapObject; tmpRetOptionalHeapObject = undefined; const optResult = pointer === null ? null : Greeter.__construct(pointer); @@ -598,7 +632,13 @@ export async function createInstantiator(options, swift) { }, testOptionalPropertyRoundtrip: function bjs_testOptionalPropertyRoundtrip(holder) { const isSome = holder != null; - instance.exports.bjs_testOptionalPropertyRoundtrip(+isSome, isSome ? holder.pointer : 0); + let result; + if (isSome) { + result = holder.pointer; + } else { + result = 0; + } + instance.exports.bjs_testOptionalPropertyRoundtrip(+isSome, result); const pointer = tmpRetOptionalHeapObject; tmpRetOptionalHeapObject = undefined; const optResult = pointer === null ? null : OptionalPropertyHolder.__construct(pointer); @@ -606,12 +646,17 @@ export async function createInstantiator(options, swift) { }, roundTripString: function bjs_roundTripString(name) { const isSome = name != null; - let nameId, nameBytes; + let result, result1; if (isSome) { - nameBytes = textEncoder.encode(name); - nameId = swift.memory.retain(nameBytes); + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + result = nameId; + result1 = nameBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_roundTripString(+isSome, isSome ? nameId : 0, isSome ? nameBytes.length : 0); + instance.exports.bjs_roundTripString(+isSome, result, result1); const optResult = tmpRetString; tmpRetString = undefined; return optResult; @@ -625,76 +670,96 @@ export async function createInstantiator(options, swift) { }, roundTripBool: function bjs_roundTripBool(flag) { const isSome = flag != null; - instance.exports.bjs_roundTripBool(+isSome, isSome ? flag : 0); + instance.exports.bjs_roundTripBool(+isSome, isSome ? flag ? 1 : 0 : 0); const optResult = tmpRetOptionalBool; tmpRetOptionalBool = undefined; return optResult; }, roundTripFloat: function bjs_roundTripFloat(number) { const isSome = number != null; - instance.exports.bjs_roundTripFloat(+isSome, isSome ? number : 0); + instance.exports.bjs_roundTripFloat(+isSome, isSome ? number : 0.0); const optResult = tmpRetOptionalFloat; tmpRetOptionalFloat = undefined; return optResult; }, roundTripDouble: function bjs_roundTripDouble(precision) { const isSome = precision != null; - instance.exports.bjs_roundTripDouble(+isSome, isSome ? precision : 0); + instance.exports.bjs_roundTripDouble(+isSome, isSome ? precision : 0.0); const optResult = tmpRetOptionalDouble; tmpRetOptionalDouble = undefined; return optResult; }, roundTripSyntax: function bjs_roundTripSyntax(name) { const isSome = name != null; - let nameId, nameBytes; + let result, result1; if (isSome) { - nameBytes = textEncoder.encode(name); - nameId = swift.memory.retain(nameBytes); + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + result = nameId; + result1 = nameBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_roundTripSyntax(+isSome, isSome ? nameId : 0, isSome ? nameBytes.length : 0); + instance.exports.bjs_roundTripSyntax(+isSome, result, result1); const optResult = tmpRetString; tmpRetString = undefined; return optResult; }, roundTripMixSyntax: function bjs_roundTripMixSyntax(name) { const isSome = name != null; - let nameId, nameBytes; + let result, result1; if (isSome) { - nameBytes = textEncoder.encode(name); - nameId = swift.memory.retain(nameBytes); + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + result = nameId; + result1 = nameBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_roundTripMixSyntax(+isSome, isSome ? nameId : 0, isSome ? nameBytes.length : 0); + instance.exports.bjs_roundTripMixSyntax(+isSome, result, result1); const optResult = tmpRetString; tmpRetString = undefined; return optResult; }, roundTripSwiftSyntax: function bjs_roundTripSwiftSyntax(name) { const isSome = name != null; - let nameId, nameBytes; + let result, result1; if (isSome) { - nameBytes = textEncoder.encode(name); - nameId = swift.memory.retain(nameBytes); + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + result = nameId; + result1 = nameBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_roundTripSwiftSyntax(+isSome, isSome ? nameId : 0, isSome ? nameBytes.length : 0); + instance.exports.bjs_roundTripSwiftSyntax(+isSome, result, result1); const optResult = tmpRetString; tmpRetString = undefined; return optResult; }, roundTripMixedSwiftSyntax: function bjs_roundTripMixedSwiftSyntax(name) { const isSome = name != null; - let nameId, nameBytes; + let result, result1; if (isSome) { - nameBytes = textEncoder.encode(name); - nameId = swift.memory.retain(nameBytes); + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + result = nameId; + result1 = nameBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_roundTripMixedSwiftSyntax(+isSome, isSome ? nameId : 0, isSome ? nameBytes.length : 0); + instance.exports.bjs_roundTripMixedSwiftSyntax(+isSome, result, result1); const optResult = tmpRetString; tmpRetString = undefined; return optResult; }, roundTripWithSpaces: function bjs_roundTripWithSpaces(value) { const isSome = value != null; - instance.exports.bjs_roundTripWithSpaces(+isSome, isSome ? value : 0); + instance.exports.bjs_roundTripWithSpaces(+isSome, isSome ? value : 0.0); const optResult = tmpRetOptionalDouble; tmpRetOptionalDouble = undefined; return optResult; @@ -708,31 +773,46 @@ export async function createInstantiator(options, swift) { }, roundTripOptionalAlias: function bjs_roundTripOptionalAlias(name) { const isSome = name != null; - let nameId, nameBytes; + let result, result1; if (isSome) { - nameBytes = textEncoder.encode(name); - nameId = swift.memory.retain(nameBytes); + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + result = nameId; + result1 = nameBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_roundTripOptionalAlias(+isSome, isSome ? nameId : 0, isSome ? nameBytes.length : 0); + instance.exports.bjs_roundTripOptionalAlias(+isSome, result, result1); const optResult = tmpRetString; tmpRetString = undefined; return optResult; }, testMixedOptionals: function bjs_testMixedOptionals(firstName, lastName, age, active) { const isSome = firstName != null; - let firstNameId, firstNameBytes; + let result, result1; if (isSome) { - firstNameBytes = textEncoder.encode(firstName); - firstNameId = swift.memory.retain(firstNameBytes); + const firstNameBytes = textEncoder.encode(firstName); + const firstNameId = swift.memory.retain(firstNameBytes); + result = firstNameId; + result1 = firstNameBytes.length; + } else { + result = 0; + result1 = 0; } const isSome1 = lastName != null; - let lastNameId, lastNameBytes; + let result2, result3; if (isSome1) { - lastNameBytes = textEncoder.encode(lastName); - lastNameId = swift.memory.retain(lastNameBytes); + const lastNameBytes = textEncoder.encode(lastName); + const lastNameId = swift.memory.retain(lastNameBytes); + result2 = lastNameId; + result3 = lastNameBytes.length; + } else { + result2 = 0; + result3 = 0; } const isSome2 = age != null; - instance.exports.bjs_testMixedOptionals(+isSome, isSome ? firstNameId : 0, isSome ? firstNameBytes.length : 0, +isSome1, isSome1 ? lastNameId : 0, isSome1 ? lastNameBytes.length : 0, +isSome2, isSome2 ? age : 0, active); + instance.exports.bjs_testMixedOptionals(+isSome, result, result1, +isSome1, result2, result3, +isSome2, isSome2 ? age : 0, active); const optResult = tmpRetString; tmpRetString = undefined; return optResult; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index 9043d19ef..6e95d2ddf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -52,41 +52,39 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createResultValuesHelpers = () => { - return () => ({ - lower: (value) => { - const enumTag = value.tag; - switch (enumTag) { - case ResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - return ResultValues.Tag.Success; - } - case ResultValues.Tag.Failure: { - i32Stack.push((value.param0 | 0)); - return ResultValues.Tag.Failure; - } - default: throw new Error("Unknown ResultValues tag: " + String(enumTag)); - } - }, - lift: (tag) => { - tag = tag | 0; - switch (tag) { - case ResultValues.Tag.Success: { - const string = strStack.pop(); - return { tag: ResultValues.Tag.Success, param0: string }; - } - case ResultValues.Tag.Failure: { - const int = i32Stack.pop(); - return { tag: ResultValues.Tag.Failure, param0: int }; - } - default: throw new Error("Unknown ResultValues tag returned from Swift: " + String(tag)); + const __bjs_createResultValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case ResultValues.Tag.Success: { + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + return ResultValues.Tag.Success; + } + case ResultValues.Tag.Failure: { + i32Stack.push((value.param0 | 0)); + return ResultValues.Tag.Failure; + } + default: throw new Error("Unknown ResultValues tag: " + String(enumTag)); + } + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case ResultValues.Tag.Success: { + const string = strStack.pop(); + return { tag: ResultValues.Tag.Success, param0: string }; + } + case ResultValues.Tag.Failure: { + const int = i32Stack.pop(); + return { tag: ResultValues.Tag.Failure, param0: int }; } + default: throw new Error("Unknown ResultValues tag returned from Swift: " + String(tag)); } - }); - }; + } + }); return { /** @@ -293,14 +291,17 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_MyViewControllerDelegate_optionalName_set"] = function bjs_MyViewControllerDelegate_optionalName_set(self, valueIsSome, valueWrappedValue) { + TestModule["bjs_MyViewControllerDelegate_optionalName_set"] = function bjs_MyViewControllerDelegate_optionalName_set(self, valueIsSome, valueObjectId) { try { - let obj; + let optResult; if (valueIsSome) { - obj = swift.memory.getObject(valueWrappedValue); - swift.memory.release(valueWrappedValue); + const valueObjectIdObject = swift.memory.getObject(valueObjectId); + swift.memory.release(valueObjectId); + optResult = valueObjectIdObject; + } else { + optResult = null; } - swift.memory.getObject(self).optionalName = valueIsSome ? obj : null; + swift.memory.getObject(self).optionalName = optResult; } catch (error) { setException(error); } @@ -313,14 +314,17 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_MyViewControllerDelegate_optionalRawEnum_set"] = function bjs_MyViewControllerDelegate_optionalRawEnum_set(self, valueIsSome, valueWrappedValue) { + TestModule["bjs_MyViewControllerDelegate_optionalRawEnum_set"] = function bjs_MyViewControllerDelegate_optionalRawEnum_set(self, valueIsSome, valueObjectId) { try { - let obj; + let optResult; if (valueIsSome) { - obj = swift.memory.getObject(valueWrappedValue); - swift.memory.release(valueWrappedValue); + const valueObjectIdObject = swift.memory.getObject(valueObjectId); + swift.memory.release(valueObjectId); + optResult = valueObjectIdObject; + } else { + optResult = null; } - swift.memory.getObject(self).optionalRawEnum = valueIsSome ? obj : null; + swift.memory.getObject(self).optionalRawEnum = optResult; } catch (error) { setException(error); } @@ -374,13 +378,16 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_MyViewControllerDelegate_optionalResult_set"] = function bjs_MyViewControllerDelegate_optionalResult_set(self, valueIsSome, valueWrappedValue) { + TestModule["bjs_MyViewControllerDelegate_optionalResult_set"] = function bjs_MyViewControllerDelegate_optionalResult_set(self, valueIsSome, valueCaseId) { try { - let enumValue; + let optResult; if (valueIsSome) { - enumValue = enumHelpers.Result.lift(valueWrappedValue); + const enumValue = enumHelpers.Result.lift(valueCaseId); + optResult = enumValue; + } else { + optResult = null; } - swift.memory.getObject(self).optionalResult = valueIsSome ? enumValue : null; + swift.memory.getObject(self).optionalResult = optResult; } catch (error) { setException(error); } @@ -405,7 +412,7 @@ export async function createInstantiator(options, swift) { try { let ret = swift.memory.getObject(self).directionOptional; const isSome = ret != null; - return isSome ? (ret | 0) : -1; + return isSome ? ret : -1; } catch (error) { setException(error); } @@ -509,9 +516,9 @@ export async function createInstantiator(options, swift) { return 0 } } - TestModule["bjs_MyViewControllerDelegate_onOptionalHelperUpdated"] = function bjs_MyViewControllerDelegate_onOptionalHelperUpdated(self, helperIsSome, helperWrappedValue) { + TestModule["bjs_MyViewControllerDelegate_onOptionalHelperUpdated"] = function bjs_MyViewControllerDelegate_onOptionalHelperUpdated(self, helperIsSome, helperPointer) { try { - swift.memory.getObject(self).onOptionalHelperUpdated(helperIsSome ? _exports['Helper'].__construct(helperWrappedValue) : null); + swift.memory.getObject(self).onOptionalHelperUpdated(helperIsSome ? _exports['Helper'].__construct(helperPointer) : null); } catch (error) { setException(error); } @@ -664,7 +671,13 @@ export async function createInstantiator(options, swift) { } set secondDelegate(value) { const isSome = value != null; - instance.exports.bjs_MyViewController_secondDelegate_set(this.pointer, +isSome, isSome ? swift.memory.retain(value) : 0); + let result; + if (isSome) { + result = swift.memory.retain(value); + } else { + result = 0; + } + instance.exports.bjs_MyViewController_secondDelegate_set(this.pointer, +isSome, result); } } class DelegateManager extends SwiftHeapObject { @@ -706,7 +719,7 @@ export async function createInstantiator(options, swift) { instance.exports.bjs_DelegateManager_delegates_set(this.pointer); } } - const ResultHelpers = __bjs_createResultValuesHelpers()(); + const ResultHelpers = __bjs_createResultValuesHelpers(); enumHelpers.Result = ResultHelpers; const exports = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index 109a403b4..0e8a5a7bb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -39,41 +39,39 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createAPIResultValuesHelpers = () => { - return () => ({ - lower: (value) => { - const enumTag = value.tag; - switch (enumTag) { - case APIResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - return APIResultValues.Tag.Success; - } - case APIResultValues.Tag.Failure: { - i32Stack.push((value.param0 | 0)); - return APIResultValues.Tag.Failure; - } - default: throw new Error("Unknown APIResultValues tag: " + String(enumTag)); + const __bjs_createAPIResultValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case APIResultValues.Tag.Success: { + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + return APIResultValues.Tag.Success; } - }, - lift: (tag) => { - tag = tag | 0; - switch (tag) { - case APIResultValues.Tag.Success: { - const string = strStack.pop(); - return { tag: APIResultValues.Tag.Success, param0: string }; - } - case APIResultValues.Tag.Failure: { - const int = i32Stack.pop(); - return { tag: APIResultValues.Tag.Failure, param0: int }; - } - default: throw new Error("Unknown APIResultValues tag returned from Swift: " + String(tag)); + case APIResultValues.Tag.Failure: { + i32Stack.push((value.param0 | 0)); + return APIResultValues.Tag.Failure; + } + default: throw new Error("Unknown APIResultValues tag: " + String(enumTag)); + } + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case APIResultValues.Tag.Success: { + const string = strStack.pop(); + return { tag: APIResultValues.Tag.Success, param0: string }; + } + case APIResultValues.Tag.Failure: { + const int = i32Stack.pop(); + return { tag: APIResultValues.Tag.Failure, param0: int }; } + default: throw new Error("Unknown APIResultValues tag returned from Swift: " + String(tag)); } - }); - }; + } + }); return { /** @@ -301,7 +299,7 @@ export async function createInstantiator(options, swift) { return ret; } } - const APIResultHelpers = __bjs_createAPIResultValuesHelpers()(); + const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); enumHelpers.APIResult = APIResultHelpers; if (typeof globalThis.Utils === 'undefined') { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index 1be36c28e..2eea1f12f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -39,41 +39,39 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createAPIResultValuesHelpers = () => { - return () => ({ - lower: (value) => { - const enumTag = value.tag; - switch (enumTag) { - case APIResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - return APIResultValues.Tag.Success; - } - case APIResultValues.Tag.Failure: { - i32Stack.push((value.param0 | 0)); - return APIResultValues.Tag.Failure; - } - default: throw new Error("Unknown APIResultValues tag: " + String(enumTag)); + const __bjs_createAPIResultValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case APIResultValues.Tag.Success: { + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + return APIResultValues.Tag.Success; } - }, - lift: (tag) => { - tag = tag | 0; - switch (tag) { - case APIResultValues.Tag.Success: { - const string = strStack.pop(); - return { tag: APIResultValues.Tag.Success, param0: string }; - } - case APIResultValues.Tag.Failure: { - const int = i32Stack.pop(); - return { tag: APIResultValues.Tag.Failure, param0: int }; - } - default: throw new Error("Unknown APIResultValues tag returned from Swift: " + String(tag)); + case APIResultValues.Tag.Failure: { + i32Stack.push((value.param0 | 0)); + return APIResultValues.Tag.Failure; + } + default: throw new Error("Unknown APIResultValues tag: " + String(enumTag)); + } + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case APIResultValues.Tag.Success: { + const string = strStack.pop(); + return { tag: APIResultValues.Tag.Success, param0: string }; + } + case APIResultValues.Tag.Failure: { + const int = i32Stack.pop(); + return { tag: APIResultValues.Tag.Failure, param0: int }; } + default: throw new Error("Unknown APIResultValues tag returned from Swift: " + String(tag)); } - }); - }; + } + }); return { /** @@ -301,7 +299,7 @@ export async function createInstantiator(options, swift) { return ret; } } - const APIResultHelpers = __bjs_createAPIResultValuesHelpers()(); + const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); enumHelpers.APIResult = APIResultHelpers; const exports = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js index 12afbb82c..16bf8ba0c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js @@ -303,12 +303,17 @@ export async function createInstantiator(options, swift) { } static set optionalProperty(value) { const isSome = value != null; - let valueId, valueBytes; + let result, result1; if (isSome) { - valueBytes = textEncoder.encode(value); - valueId = swift.memory.retain(valueBytes); + const valueBytes = textEncoder.encode(value); + const valueId = swift.memory.retain(valueBytes); + result = valueId; + result1 = valueBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_PropertyClass_static_optionalProperty_set(+isSome, isSome ? valueId : 0, isSome ? valueBytes.length : 0); + instance.exports.bjs_PropertyClass_static_optionalProperty_set(+isSome, result, result1); } } if (typeof globalThis.PropertyNamespace === 'undefined') { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js index e9c5d105c..ea6c448ed 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js @@ -303,12 +303,17 @@ export async function createInstantiator(options, swift) { } static set optionalProperty(value) { const isSome = value != null; - let valueId, valueBytes; + let result, result1; if (isSome) { - valueBytes = textEncoder.encode(value); - valueId = swift.memory.retain(valueBytes); + const valueBytes = textEncoder.encode(value); + const valueId = swift.memory.retain(valueBytes); + result = valueId; + result1 = valueBytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.bjs_PropertyClass_static_optionalProperty_set(+isSome, isSome ? valueId : 0, isSome ? valueBytes.length : 0); + instance.exports.bjs_PropertyClass_static_optionalProperty_set(+isSome, result, result1); } } const exports = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index cd6c9062b..a74d49327 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -211,9 +211,9 @@ export async function createInstantiator(options, swift) { return 0 } } - TestModule["bjs_jsRoundTripOptionalGreeter"] = function bjs_jsRoundTripOptionalGreeter(greeterIsSome, greeterWrappedValue) { + TestModule["bjs_jsRoundTripOptionalGreeter"] = function bjs_jsRoundTripOptionalGreeter(greeterIsSome, greeterPointer) { try { - let ret = imports.jsRoundTripOptionalGreeter(greeterIsSome ? _exports['Greeter'].__construct(greeterWrappedValue) : null); + let ret = imports.jsRoundTripOptionalGreeter(greeterIsSome ? _exports['Greeter'].__construct(greeterPointer) : null); const isSome = ret != null; return isSome ? ret.pointer : 0; } catch (error) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index 68bcfbe93..023a2fab0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -83,69 +83,67 @@ export async function createInstantiator(options, swift) { return swift.memory.retain(real); }; - const __bjs_createAPIResultValuesHelpers = () => { - return () => ({ - lower: (value) => { - const enumTag = value.tag; - switch (enumTag) { - case APIResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - return APIResultValues.Tag.Success; - } - case APIResultValues.Tag.Failure: { - i32Stack.push((value.param0 | 0)); - return APIResultValues.Tag.Failure; - } - case APIResultValues.Tag.Flag: { - i32Stack.push(value.param0 ? 1 : 0); - return APIResultValues.Tag.Flag; - } - case APIResultValues.Tag.Rate: { - f32Stack.push(Math.fround(value.param0)); - return APIResultValues.Tag.Rate; - } - case APIResultValues.Tag.Precise: { - f64Stack.push(value.param0); - return APIResultValues.Tag.Precise; - } - case APIResultValues.Tag.Info: { - return APIResultValues.Tag.Info; - } - default: throw new Error("Unknown APIResultValues tag: " + String(enumTag)); + const __bjs_createAPIResultValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case APIResultValues.Tag.Success: { + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + return APIResultValues.Tag.Success; } - }, - lift: (tag) => { - tag = tag | 0; - switch (tag) { - case APIResultValues.Tag.Success: { - const string = strStack.pop(); - return { tag: APIResultValues.Tag.Success, param0: string }; - } - case APIResultValues.Tag.Failure: { - const int = i32Stack.pop(); - return { tag: APIResultValues.Tag.Failure, param0: int }; - } - case APIResultValues.Tag.Flag: { - const bool = i32Stack.pop() !== 0; - return { tag: APIResultValues.Tag.Flag, param0: bool }; - } - case APIResultValues.Tag.Rate: { - const f32 = f32Stack.pop(); - return { tag: APIResultValues.Tag.Rate, param0: f32 }; - } - case APIResultValues.Tag.Precise: { - const f64 = f64Stack.pop(); - return { tag: APIResultValues.Tag.Precise, param0: f64 }; - } - case APIResultValues.Tag.Info: return { tag: APIResultValues.Tag.Info }; - default: throw new Error("Unknown APIResultValues tag returned from Swift: " + String(tag)); + case APIResultValues.Tag.Failure: { + i32Stack.push((value.param0 | 0)); + return APIResultValues.Tag.Failure; + } + case APIResultValues.Tag.Flag: { + i32Stack.push(value.param0 ? 1 : 0); + return APIResultValues.Tag.Flag; + } + case APIResultValues.Tag.Rate: { + f32Stack.push(Math.fround(value.param0)); + return APIResultValues.Tag.Rate; } + case APIResultValues.Tag.Precise: { + f64Stack.push(value.param0); + return APIResultValues.Tag.Precise; + } + case APIResultValues.Tag.Info: { + return APIResultValues.Tag.Info; + } + default: throw new Error("Unknown APIResultValues tag: " + String(enumTag)); } - }); - }; + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case APIResultValues.Tag.Success: { + const string = strStack.pop(); + return { tag: APIResultValues.Tag.Success, param0: string }; + } + case APIResultValues.Tag.Failure: { + const int = i32Stack.pop(); + return { tag: APIResultValues.Tag.Failure, param0: int }; + } + case APIResultValues.Tag.Flag: { + const bool = i32Stack.pop() !== 0; + return { tag: APIResultValues.Tag.Flag, param0: bool }; + } + case APIResultValues.Tag.Rate: { + const f32 = f32Stack.pop(); + return { tag: APIResultValues.Tag.Rate, param0: f32 }; + } + case APIResultValues.Tag.Precise: { + const f64 = f64Stack.pop(); + return { tag: APIResultValues.Tag.Precise, param0: f64 }; + } + case APIResultValues.Tag.Info: return { tag: APIResultValues.Tag.Info }; + default: throw new Error("Unknown APIResultValues tag returned from Swift: " + String(tag)); + } + } + }); return { /** @@ -577,21 +575,20 @@ export async function createInstantiator(options, swift) { }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq10HttpStatusO_Sq10HttpStatusO); } - bjs["invoke_js_callback_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO"] = function(callbackId, param0IsSome, param0WrappedValue) { + bjs["invoke_js_callback_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO"] = function(callbackId, param0IsSome, param0ObjectId) { try { const callback = swift.memory.getObject(callbackId); - let obj; + let optResult; if (param0IsSome) { - obj = swift.memory.getObject(param0WrappedValue); - swift.memory.release(param0WrappedValue); - } - let ret = callback(param0IsSome ? obj : null); - const isSome = ret != null; - if (isSome) { - tmpRetString = ret; + const param0ObjectIdObject = swift.memory.getObject(param0ObjectId); + swift.memory.release(param0ObjectId); + optResult = param0ObjectIdObject; } else { - tmpRetString = null; + optResult = null; } + let ret = callback(optResult); + const isSome = ret != null; + tmpRetString = isSome ? ret : null; } catch (error) { setException(error); } @@ -599,12 +596,17 @@ export async function createInstantiator(options, swift) { bjs["make_swift_closure_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO = function(param0) { const isSome = param0 != null; - let param0Id, param0Bytes; + let result, result1; if (isSome) { - param0Bytes = textEncoder.encode(param0); - param0Id = swift.memory.retain(param0Bytes); + const param0Bytes = textEncoder.encode(param0); + const param0Id = swift.memory.retain(param0Bytes); + result = param0Id; + result1 = param0Bytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.invoke_swift_closure_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO(boxPtr, +isSome, isSome ? param0Id : 0, isSome ? param0Bytes.length : 0); + instance.exports.invoke_swift_closure_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO(boxPtr, +isSome, result, result1); const optResult = tmpRetString; tmpRetString = undefined; if (tmpRetException) { @@ -617,10 +619,10 @@ export async function createInstantiator(options, swift) { }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO); } - bjs["invoke_js_callback_TestModule_10TestModuleSq6PersonC_Sq6PersonC"] = function(callbackId, param0IsSome, param0WrappedValue) { + bjs["invoke_js_callback_TestModule_10TestModuleSq6PersonC_Sq6PersonC"] = function(callbackId, param0IsSome, param0Pointer) { try { const callback = swift.memory.getObject(callbackId); - let ret = callback(param0IsSome ? _exports['Person'].__construct(param0WrappedValue) : null); + let ret = callback(param0IsSome ? _exports['Person'].__construct(param0Pointer) : null); const isSome = ret != null; return isSome ? ret.pointer : 0; } catch (error) { @@ -630,7 +632,13 @@ export async function createInstantiator(options, swift) { bjs["make_swift_closure_TestModule_10TestModuleSq6PersonC_Sq6PersonC"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModuleSq6PersonC_Sq6PersonC = function(param0) { const isSome = param0 != null; - instance.exports.invoke_swift_closure_TestModule_10TestModuleSq6PersonC_Sq6PersonC(boxPtr, +isSome, isSome ? param0.pointer : 0); + let result; + if (isSome) { + result = param0.pointer; + } else { + result = 0; + } + instance.exports.invoke_swift_closure_TestModule_10TestModuleSq6PersonC_Sq6PersonC(boxPtr, +isSome, result); const pointer = tmpRetOptionalHeapObject; tmpRetOptionalHeapObject = undefined; const optResult = pointer === null ? null : _exports['Person'].__construct(pointer); @@ -644,14 +652,17 @@ export async function createInstantiator(options, swift) { }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq6PersonC_Sq6PersonC); } - bjs["invoke_js_callback_TestModule_10TestModuleSq9APIResultO_Sq9APIResultO"] = function(callbackId, param0IsSome, param0WrappedValue) { + bjs["invoke_js_callback_TestModule_10TestModuleSq9APIResultO_Sq9APIResultO"] = function(callbackId, param0IsSome, param0CaseId) { try { const callback = swift.memory.getObject(callbackId); - let enumValue; + let optResult; if (param0IsSome) { - enumValue = enumHelpers.APIResult.lift(param0WrappedValue); + const enumValue = enumHelpers.APIResult.lift(param0CaseId); + optResult = enumValue; + } else { + optResult = null; } - let ret = callback(param0IsSome ? enumValue : null); + let ret = callback(optResult); const isSome = ret != null; if (isSome) { const caseId = enumHelpers.APIResult.lower(ret); @@ -666,19 +677,16 @@ export async function createInstantiator(options, swift) { bjs["make_swift_closure_TestModule_10TestModuleSq9APIResultO_Sq9APIResultO"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModuleSq9APIResultO_Sq9APIResultO = function(param0) { const isSome = param0 != null; - let param0CaseId; + let result; if (isSome) { - param0CaseId = enumHelpers.APIResult.lower(param0); - } - instance.exports.invoke_swift_closure_TestModule_10TestModuleSq9APIResultO_Sq9APIResultO(boxPtr, +isSome, isSome ? param0CaseId : 0); - const tag = i32Stack.pop(); - const isNull = (tag === -1); - let optResult; - if (isNull) { - optResult = null; + const param0CaseId = enumHelpers.APIResult.lower(param0); + result = param0CaseId; } else { - optResult = enumHelpers.APIResult.lift(tag); + result = 0; } + instance.exports.invoke_swift_closure_TestModule_10TestModuleSq9APIResultO_Sq9APIResultO(boxPtr, +isSome, result); + const tag = i32Stack.pop(); + const optResult = tag === -1 ? null : enumHelpers.APIResult.lift(tag); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); @@ -694,7 +702,7 @@ export async function createInstantiator(options, swift) { const callback = swift.memory.getObject(callbackId); let ret = callback(param0IsSome ? param0WrappedValue : null); const isSome = ret != null; - return isSome ? (ret | 0) : -1; + return isSome ? ret : -1; } catch (error) { setException(error); } @@ -715,21 +723,20 @@ export async function createInstantiator(options, swift) { }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq9DirectionO_Sq9DirectionO); } - bjs["invoke_js_callback_TestModule_10TestModuleSqSS_SqSS"] = function(callbackId, param0IsSome, param0WrappedValue) { + bjs["invoke_js_callback_TestModule_10TestModuleSqSS_SqSS"] = function(callbackId, param0IsSome, param0ObjectId) { try { const callback = swift.memory.getObject(callbackId); - let obj; + let optResult; if (param0IsSome) { - obj = swift.memory.getObject(param0WrappedValue); - swift.memory.release(param0WrappedValue); - } - let ret = callback(param0IsSome ? obj : null); - const isSome = ret != null; - if (isSome) { - tmpRetString = ret; + const param0ObjectIdObject = swift.memory.getObject(param0ObjectId); + swift.memory.release(param0ObjectId); + optResult = param0ObjectIdObject; } else { - tmpRetString = null; + optResult = null; } + let ret = callback(optResult); + const isSome = ret != null; + tmpRetString = isSome ? ret : null; } catch (error) { setException(error); } @@ -737,12 +744,17 @@ export async function createInstantiator(options, swift) { bjs["make_swift_closure_TestModule_10TestModuleSqSS_SqSS"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModuleSqSS_SqSS = function(param0) { const isSome = param0 != null; - let param0Id, param0Bytes; + let result, result1; if (isSome) { - param0Bytes = textEncoder.encode(param0); - param0Id = swift.memory.retain(param0Bytes); + const param0Bytes = textEncoder.encode(param0); + const param0Id = swift.memory.retain(param0Bytes); + result = param0Id; + result1 = param0Bytes.length; + } else { + result = 0; + result1 = 0; } - instance.exports.invoke_swift_closure_TestModule_10TestModuleSqSS_SqSS(boxPtr, +isSome, isSome ? param0Id : 0, isSome ? param0Bytes.length : 0); + instance.exports.invoke_swift_closure_TestModule_10TestModuleSqSS_SqSS(boxPtr, +isSome, result, result1); const optResult = tmpRetString; tmpRetString = undefined; if (tmpRetException) { @@ -768,7 +780,7 @@ export async function createInstantiator(options, swift) { bjs["make_swift_closure_TestModule_10TestModuleSqSb_SqSb"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModuleSqSb_SqSb = function(param0) { const isSome = param0 != null; - instance.exports.invoke_swift_closure_TestModule_10TestModuleSqSb_SqSb(boxPtr, +isSome, isSome ? param0 : 0); + instance.exports.invoke_swift_closure_TestModule_10TestModuleSqSb_SqSb(boxPtr, +isSome, isSome ? param0 ? 1 : 0 : 0); const optResult = tmpRetOptionalBool; tmpRetOptionalBool = undefined; if (tmpRetException) { @@ -794,7 +806,7 @@ export async function createInstantiator(options, swift) { bjs["make_swift_closure_TestModule_10TestModuleSqSd_SqSd"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModuleSqSd_SqSd = function(param0) { const isSome = param0 != null; - instance.exports.invoke_swift_closure_TestModule_10TestModuleSqSd_SqSd(boxPtr, +isSome, isSome ? param0 : 0); + instance.exports.invoke_swift_closure_TestModule_10TestModuleSqSd_SqSd(boxPtr, +isSome, isSome ? param0 : 0.0); const optResult = tmpRetOptionalDouble; tmpRetOptionalDouble = undefined; if (tmpRetException) { @@ -820,7 +832,7 @@ export async function createInstantiator(options, swift) { bjs["make_swift_closure_TestModule_10TestModuleSqSf_SqSf"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModuleSqSf_SqSf = function(param0) { const isSome = param0 != null; - instance.exports.invoke_swift_closure_TestModule_10TestModuleSqSf_SqSf(boxPtr, +isSome, isSome ? param0 : 0); + instance.exports.invoke_swift_closure_TestModule_10TestModuleSqSf_SqSf(boxPtr, +isSome, isSome ? param0 : 0.0); const optResult = tmpRetOptionalFloat; tmpRetOptionalFloat = undefined; if (tmpRetException) { @@ -935,7 +947,7 @@ export async function createInstantiator(options, swift) { return TestProcessor.__construct(ret); } } - const APIResultHelpers = __bjs_createAPIResultValuesHelpers()(); + const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); enumHelpers.APIResult = APIResultHelpers; const exports = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index dbbbd6bc9..cc973e379 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -33,226 +33,214 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createDataPointHelpers = () => { - return () => ({ - lower: (value) => { - f64Stack.push(value.x); - f64Stack.push(value.y); - const bytes = textEncoder.encode(value.label); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - const isSome = value.optCount != null; - if (isSome) { - i32Stack.push(value.optCount | 0); - } else { - i32Stack.push(0); - } - i32Stack.push(isSome ? 1 : 0); - const isSome1 = value.optFlag != null; - if (isSome1) { - i32Stack.push(value.optFlag ? 1 : 0); - } else { - i32Stack.push(0); - } - i32Stack.push(isSome1 ? 1 : 0); - }, - lift: () => { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const bool = i32Stack.pop() !== 0; - optional = bool; - } else { - optional = null; - } - const isSome1 = i32Stack.pop(); - let optional1; - if (isSome1) { - const int = i32Stack.pop(); - optional1 = int; - } else { - optional1 = null; - } - const string = strStack.pop(); - const f64 = f64Stack.pop(); - const f641 = f64Stack.pop(); - return { x: f641, y: f64, label: string, optCount: optional1, optFlag: optional }; - } - }); - }; - const __bjs_createAddressHelpers = () => { - return () => ({ - lower: (value) => { - const bytes = textEncoder.encode(value.street); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - const bytes1 = textEncoder.encode(value.city); + const __bjs_createDataPointHelpers = () => ({ + lower: (value) => { + f64Stack.push(value.x); + f64Stack.push(value.y); + const bytes = textEncoder.encode(value.label); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + const isSome = value.optCount != null; + if (isSome) { + i32Stack.push((value.optCount | 0)); + } else { + i32Stack.push(0); + } + i32Stack.push(isSome ? 1 : 0); + const isSome1 = value.optFlag != null; + if (isSome1) { + i32Stack.push(value.optFlag ? 1 : 0); + } else { + i32Stack.push(0); + } + i32Stack.push(isSome1 ? 1 : 0); + }, + lift: () => { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { + const bool = i32Stack.pop() !== 0; + optional = bool; + } else { + optional = null; + } + const isSome1 = i32Stack.pop(); + let optional1; + if (isSome1) { + const int = i32Stack.pop(); + optional1 = int; + } else { + optional1 = null; + } + const string = strStack.pop(); + const f64 = f64Stack.pop(); + const f641 = f64Stack.pop(); + return { x: f641, y: f64, label: string, optCount: optional1, optFlag: optional }; + } + }); + const __bjs_createAddressHelpers = () => ({ + lower: (value) => { + const bytes = textEncoder.encode(value.street); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + const bytes1 = textEncoder.encode(value.city); + const id1 = swift.memory.retain(bytes1); + i32Stack.push(bytes1.length); + i32Stack.push(id1); + const isSome = value.zipCode != null; + if (isSome) { + i32Stack.push((value.zipCode | 0)); + } else { + i32Stack.push(0); + } + i32Stack.push(isSome ? 1 : 0); + }, + lift: () => { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { + const int = i32Stack.pop(); + optional = int; + } else { + optional = null; + } + const string = strStack.pop(); + const string1 = strStack.pop(); + return { street: string1, city: string, zipCode: optional }; + } + }); + const __bjs_createPersonHelpers = () => ({ + lower: (value) => { + const bytes = textEncoder.encode(value.name); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + i32Stack.push((value.age | 0)); + structHelpers.Address.lower(value.address); + const isSome = value.email != null; + if (isSome) { + const bytes1 = textEncoder.encode(value.email); const id1 = swift.memory.retain(bytes1); i32Stack.push(bytes1.length); i32Stack.push(id1); - const isSome = value.zipCode != null; - if (isSome) { - i32Stack.push(value.zipCode | 0); - } else { - i32Stack.push(0); - } - i32Stack.push(isSome ? 1 : 0); - }, - lift: () => { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const int = i32Stack.pop(); - optional = int; - } else { - optional = null; - } + } else { + i32Stack.push(0); + i32Stack.push(0); + } + i32Stack.push(isSome ? 1 : 0); + }, + lift: () => { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { const string = strStack.pop(); - const string1 = strStack.pop(); - return { street: string1, city: string, zipCode: optional }; - } - }); - }; - const __bjs_createPersonHelpers = () => { - return () => ({ - lower: (value) => { - const bytes = textEncoder.encode(value.name); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - i32Stack.push((value.age | 0)); - structHelpers.Address.lower(value.address); - const isSome = value.email != null; - let id1; - if (isSome) { - const bytes1 = textEncoder.encode(value.email); - id1 = swift.memory.retain(bytes1); - i32Stack.push(bytes1.length); - i32Stack.push(id1); - } else { - i32Stack.push(0); - i32Stack.push(0); - } - i32Stack.push(isSome ? 1 : 0); - }, - lift: () => { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const string = strStack.pop(); - optional = string; - } else { - optional = null; - } - const struct = structHelpers.Address.lift(); - const int = i32Stack.pop(); - const string1 = strStack.pop(); - return { name: string1, age: int, address: struct, email: optional }; - } - }); - }; - const __bjs_createSessionHelpers = () => { - return () => ({ - lower: (value) => { - i32Stack.push((value.id | 0)); - ptrStack.push(value.owner.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = _exports['Greeter'].__construct(ptr); - const int = i32Stack.pop(); - return { id: int, owner: obj }; - } - }); - }; - const __bjs_createMeasurementHelpers = () => { - return () => ({ - lower: (value) => { - f64Stack.push(value.value); - f32Stack.push(Math.fround(value.precision)); - const isSome = value.optionalPrecision != null; - if (isSome) { - f32Stack.push(Math.fround(value.optionalPrecision)); - } else { - f32Stack.push(0.0); - } - i32Stack.push(isSome ? 1 : 0); - }, - lift: () => { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const rawValue = f32Stack.pop(); - optional = rawValue; - } else { - optional = null; - } - const rawValue1 = f32Stack.pop(); - const f64 = f64Stack.pop(); - return { value: f64, precision: rawValue1, optionalPrecision: optional }; - } - }); - }; - const __bjs_createConfigStructHelpers = () => { - return () => ({ - lower: (value) => { - }, - lift: () => { - return { }; - } - }); - }; - const __bjs_createContainerHelpers = () => { - return () => ({ - lower: (value) => { - let id; - if (value.object != null) { - id = swift.memory.retain(value.object); - } else { - id = undefined; - } - i32Stack.push(id !== undefined ? id : 0); - const isSome = value.optionalObject != null; + optional = string; + } else { + optional = null; + } + const struct = structHelpers.Address.lift(); + const int = i32Stack.pop(); + const string1 = strStack.pop(); + return { name: string1, age: int, address: struct, email: optional }; + } + }); + const __bjs_createSessionHelpers = () => ({ + lower: (value) => { + i32Stack.push((value.id | 0)); + ptrStack.push(value.owner.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = _exports['Greeter'].__construct(ptr); + const int = i32Stack.pop(); + return { id: int, owner: obj }; + } + }); + const __bjs_createMeasurementHelpers = () => ({ + lower: (value) => { + f64Stack.push(value.value); + f32Stack.push(Math.fround(value.precision)); + const isSome = value.optionalPrecision != null; + if (isSome) { + f32Stack.push(Math.fround(value.optionalPrecision)); + } else { + f32Stack.push(0.0); + } + i32Stack.push(isSome ? 1 : 0); + }, + lift: () => { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { + const rawValue = f32Stack.pop(); + optional = rawValue; + } else { + optional = null; + } + const rawValue1 = f32Stack.pop(); + const f64 = f64Stack.pop(); + return { value: f64, precision: rawValue1, optionalPrecision: optional }; + } + }); + const __bjs_createConfigStructHelpers = () => ({ + lower: (value) => { + }, + lift: () => { + return { }; + } + }); + const __bjs_createContainerHelpers = () => ({ + lower: (value) => { + let id; + if (value.object != null) { + id = swift.memory.retain(value.object); + } else { + id = undefined; + } + i32Stack.push(id !== undefined ? id : 0); + const isSome = value.optionalObject != null; + if (isSome) { let id1; - if (isSome) { + if (value.optionalObject != null) { id1 = swift.memory.retain(value.optionalObject); - i32Stack.push(id1); } else { id1 = undefined; - i32Stack.push(0); - } - i32Stack.push(isSome ? 1 : 0); - }, - lift: () => { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const objectId = i32Stack.pop(); - let value; - if (objectId !== 0) { - value = swift.memory.getObject(objectId); - swift.memory.release(objectId); - } else { - value = null; - } - optional = value; - } else { - optional = null; } - const objectId1 = i32Stack.pop(); - let value1; - if (objectId1 !== 0) { - value1 = swift.memory.getObject(objectId1); - swift.memory.release(objectId1); + i32Stack.push(id1 !== undefined ? id1 : 0); + } else { + i32Stack.push(0); + } + i32Stack.push(isSome ? 1 : 0); + }, + lift: () => { + const isSome = i32Stack.pop(); + let optional; + if (isSome) { + const objectId = i32Stack.pop(); + let value; + if (objectId !== 0) { + value = swift.memory.getObject(objectId); + swift.memory.release(objectId); } else { - value1 = null; + value = null; } - return { object: value1, optionalObject: optional }; - } - }); - }; + optional = value; + } else { + optional = null; + } + const objectId1 = i32Stack.pop(); + let value1; + if (objectId1 !== 0) { + value1 = swift.memory.getObject(objectId1); + swift.memory.release(objectId1); + } else { + value1 = null; + } + return { object: value1, optionalObject: optional }; + } + }); return { /** @@ -536,25 +524,25 @@ export async function createInstantiator(options, swift) { instance.exports.bjs_Greeter_name_set(this.pointer, valueId, valueBytes.length); } } - const DataPointHelpers = __bjs_createDataPointHelpers()(); + const DataPointHelpers = __bjs_createDataPointHelpers(); structHelpers.DataPoint = DataPointHelpers; - const AddressHelpers = __bjs_createAddressHelpers()(); + const AddressHelpers = __bjs_createAddressHelpers(); structHelpers.Address = AddressHelpers; - const PersonHelpers = __bjs_createPersonHelpers()(); + const PersonHelpers = __bjs_createPersonHelpers(); structHelpers.Person = PersonHelpers; - const SessionHelpers = __bjs_createSessionHelpers()(); + const SessionHelpers = __bjs_createSessionHelpers(); structHelpers.Session = SessionHelpers; - const MeasurementHelpers = __bjs_createMeasurementHelpers()(); + const MeasurementHelpers = __bjs_createMeasurementHelpers(); structHelpers.Measurement = MeasurementHelpers; - const ConfigStructHelpers = __bjs_createConfigStructHelpers()(); + const ConfigStructHelpers = __bjs_createConfigStructHelpers(); structHelpers.ConfigStruct = ConfigStructHelpers; - const ContainerHelpers = __bjs_createContainerHelpers()(); + const ContainerHelpers = __bjs_createContainerHelpers(); structHelpers.Container = ContainerHelpers; const exports = { @@ -578,7 +566,7 @@ export async function createInstantiator(options, swift) { const labelId = swift.memory.retain(labelBytes); const isSome = optCount != null; const isSome1 = optFlag != null; - instance.exports.bjs_DataPoint_init(x, y, labelId, labelBytes.length, +isSome, isSome ? optCount : 0, +isSome1, isSome1 ? optFlag : 0); + instance.exports.bjs_DataPoint_init(x, y, labelId, labelBytes.length, +isSome, isSome ? optCount : 0, +isSome1, isSome1 ? optFlag ? 1 : 0 : 0); const structValue = structHelpers.DataPoint.lift(); return structValue; }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js index cf64ab587..d00b7450d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js @@ -28,19 +28,17 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createPointHelpers = () => { - return () => ({ - lower: (value) => { - i32Stack.push((value.x | 0)); - i32Stack.push((value.y | 0)); - }, - lift: () => { - const int = i32Stack.pop(); - const int1 = i32Stack.pop(); - return { x: int1, y: int }; - } - }); - }; + const __bjs_createPointHelpers = () => ({ + lower: (value) => { + i32Stack.push((value.x | 0)); + i32Stack.push((value.y | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + const int1 = i32Stack.pop(); + return { x: int1, y: int }; + } + }); return { /** @@ -228,7 +226,7 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - const PointHelpers = __bjs_createPointHelpers()(); + const PointHelpers = __bjs_createPointHelpers(); structHelpers.Point = PointHelpers; const exports = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js index 30c40a18c..c141a7926 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js @@ -28,25 +28,23 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createPointerFieldsHelpers = () => { - return () => ({ - lower: (value) => { - ptrStack.push((value.raw | 0)); - ptrStack.push((value.mutRaw | 0)); - ptrStack.push((value.opaque | 0)); - ptrStack.push((value.ptr | 0)); - ptrStack.push((value.mutPtr | 0)); - }, - lift: () => { - const pointer = ptrStack.pop(); - const pointer1 = ptrStack.pop(); - const pointer2 = ptrStack.pop(); - const pointer3 = ptrStack.pop(); - const pointer4 = ptrStack.pop(); - return { raw: pointer4, mutRaw: pointer3, opaque: pointer2, ptr: pointer1, mutPtr: pointer }; - } - }); - }; + const __bjs_createPointerFieldsHelpers = () => ({ + lower: (value) => { + ptrStack.push((value.raw | 0)); + ptrStack.push((value.mutRaw | 0)); + ptrStack.push((value.opaque | 0)); + ptrStack.push((value.ptr | 0)); + ptrStack.push((value.mutPtr | 0)); + }, + lift: () => { + const pointer = ptrStack.pop(); + const pointer1 = ptrStack.pop(); + const pointer2 = ptrStack.pop(); + const pointer3 = ptrStack.pop(); + const pointer4 = ptrStack.pop(); + return { raw: pointer4, mutRaw: pointer3, opaque: pointer2, ptr: pointer1, mutPtr: pointer }; + } + }); return { /** @@ -222,7 +220,7 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - const PointerFieldsHelpers = __bjs_createPointerFieldsHelpers()(); + const PointerFieldsHelpers = __bjs_createPointerFieldsHelpers(); structHelpers.PointerFields = PointerFieldsHelpers; const exports = {