diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 494351db..caecef3a 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -358,20 +358,20 @@ struct BridgeJSLink { } private func renderEnumHelperAssignments() -> [String] { - var lines: [String] = [] + let printer = CodeFragmentPrinter() for skeleton in exportedSkeletons { for enumDef in skeleton.enums where enumDef.enumType == .associatedValue { let base = enumDef.name - lines.append( + printer.write( "const \(base)Helpers = __bjs_create\(base)Helpers()(\(JSGlueVariableScope.reservedTmpParamInts), \(JSGlueVariableScope.reservedTmpParamF32s), \(JSGlueVariableScope.reservedTmpParamF64s), \(JSGlueVariableScope.reservedTextEncoder), \(JSGlueVariableScope.reservedSwift));" ) - lines.append("enumHelpers.\(base) = \(base)Helpers;") - lines.append("") + printer.write("enumHelpers.\(base) = \(base)Helpers;") + printer.nextLine() } } - return lines + return printer.lines } private func renderSwiftClassWrappers() -> [String] { @@ -408,18 +408,19 @@ struct BridgeJSLink { } private func generateImportedTypeDefinitions() -> [String] { - var typeDefinitions: [String] = [] + let printer = CodeFragmentPrinter() for skeletonSet in importedSkeletons { for fileSkeleton in skeletonSet.children { for type in fileSkeleton.types { - typeDefinitions.append("export interface \(type.name) {") + printer.write("export interface \(type.name) {") + printer.indent() // Add methods for method in type.methods { let methodSignature = "\(method.name)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: Effects(isAsync: false, isThrows: false)));" - typeDefinitions.append(methodSignature.indent(count: 4)) + printer.write(methodSignature) } // Add properties @@ -428,15 +429,16 @@ struct BridgeJSLink { property.isReadonly ? "readonly \(property.name): \(property.type.tsType);" : "\(property.name): \(property.type.tsType);" - typeDefinitions.append(propertySignature.indent(count: 4)) + printer.write(propertySignature) } - typeDefinitions.append("}") + printer.unindent() + printer.write("}") } } } - return typeDefinitions + return printer.lines } class ExportedThunkBuilder { @@ -554,327 +556,148 @@ struct BridgeJSLink { func renderExportedEnum(_ enumDefinition: ExportedEnum) throws -> (js: [String], dts: [String]) { var jsLines: [String] = [] var dtsLines: [String] = [] - let style: EnumEmitStyle = enumDefinition.emitStyle + let scope = JSGlueVariableScope() + let cleanup = CodeFragmentPrinter() + let printer = CodeFragmentPrinter() switch enumDefinition.enumType { case .simple: - jsLines.append("const \(enumDefinition.name) = {") - for (index, enumCase) in enumDefinition.cases.enumerated() { - let caseName = enumCase.name.capitalizedFirstLetter - jsLines.append("\(caseName): \(index),".indent(count: 4)) - } - jsLines.append("};") - jsLines.append("") - - if enumDefinition.namespace == nil { - switch style { - case .tsEnum: - dtsLines.append("export enum \(enumDefinition.name) {") - for (index, enumCase) in enumDefinition.cases.enumerated() { - let caseName = enumCase.name.capitalizedFirstLetter - dtsLines.append("\(caseName) = \(index),".indent(count: 4)) - } - dtsLines.append("}") - dtsLines.append("") - case .const: - dtsLines.append("export const \(enumDefinition.name): {") - for (index, enumCase) in enumDefinition.cases.enumerated() { - let caseName = enumCase.name.capitalizedFirstLetter - dtsLines.append("readonly \(caseName): \(index);".indent(count: 4)) - } - dtsLines.append("};") - dtsLines.append( - "export type \(enumDefinition.name) = typeof \(enumDefinition.name)[keyof typeof \(enumDefinition.name)];" - ) - dtsLines.append("") - } - } + let fragment = IntrinsicJSFragment.simpleEnumHelper(enumDefinition: enumDefinition) + _ = fragment.printCode([enumDefinition.name], scope, printer, cleanup) + + jsLines.append(contentsOf: printer.lines) case .rawValue: - guard let rawType = enumDefinition.rawType else { + guard enumDefinition.rawType != nil else { throw BridgeJSLinkError(message: "Raw value enum \(enumDefinition.name) is missing rawType") } - jsLines.append("const \(enumDefinition.name) = {") - for enumCase in enumDefinition.cases { - let caseName = enumCase.name.capitalizedFirstLetter - let rawValue = enumCase.rawValue ?? enumCase.name - let formattedValue: String - - if let rawTypeEnum = SwiftEnumRawType.from(rawType) { - switch rawTypeEnum { - case .string: - formattedValue = "\"\(rawValue)\"" - case .bool: - formattedValue = rawValue.lowercased() == "true" ? "true" : "false" - case .float, .double: - formattedValue = rawValue - default: - formattedValue = rawValue - } - } else { - formattedValue = rawValue - } + let fragment = IntrinsicJSFragment.rawValueEnumHelper(enumDefinition: enumDefinition) + _ = fragment.printCode([enumDefinition.name], scope, printer, cleanup) - jsLines.append("\(caseName): \(formattedValue),".indent(count: 4)) - } - jsLines.append("};") - jsLines.append("") - - if enumDefinition.namespace == nil { - switch style { - case .tsEnum: - dtsLines.append("export enum \(enumDefinition.name) {") - for enumCase in enumDefinition.cases { - let caseName = enumCase.name.capitalizedFirstLetter + jsLines.append(contentsOf: printer.lines) + case .associatedValue: + let fragment = IntrinsicJSFragment.associatedValueEnumHelper(enumDefinition: enumDefinition) + _ = fragment.printCode([enumDefinition.name], scope, printer, cleanup) + + jsLines.append(contentsOf: printer.lines) + case .namespace: + break + } + + if enumDefinition.namespace == nil { + dtsLines.append(contentsOf: generateDeclarations(enumDefinition: enumDefinition)) + } + + return (jsLines, dtsLines) + } + + private func generateDeclarations(enumDefinition: ExportedEnum) -> [String] { + let printer = CodeFragmentPrinter() + + switch enumDefinition.emitStyle { + case .tsEnum: + switch enumDefinition.enumType { + case .simple, .rawValue: + printer.write("export enum \(enumDefinition.name) {") + printer.indent() + for (index, enumCase) in enumDefinition.cases.enumerated() { + let caseName = enumCase.name.capitalizedFirstLetter + let value: String + + switch enumDefinition.enumType { + case .simple: + value = "\(index)" + case .rawValue: let rawValue = enumCase.rawValue ?? enumCase.name - let formattedValue: String - switch rawType { - case "String": formattedValue = "\"\(rawValue)\"" - case "Bool": formattedValue = rawValue.lowercased() == "true" ? "true" : "false" - case "Float", "Double": formattedValue = rawValue - default: formattedValue = rawValue - } - dtsLines.append("\(caseName) = \(formattedValue),".indent(count: 4)) + value = SwiftEnumRawType.formatValue(rawValue, rawType: enumDefinition.rawType ?? "") + case .associatedValue, .namespace: + continue } - dtsLines.append("}") - dtsLines.append("") - case .const: - dtsLines.append("export const \(enumDefinition.name): {") - for enumCase in enumDefinition.cases { - let caseName = enumCase.name.capitalizedFirstLetter - let rawValue = enumCase.rawValue ?? enumCase.name - let formattedValue: String - - switch rawType { - case "String": - formattedValue = "\"\(rawValue)\"" - case "Bool": - formattedValue = rawValue.lowercased() == "true" ? "true" : "false" - case "Float", "Double": - formattedValue = rawValue - default: - formattedValue = rawValue - } - dtsLines.append("readonly \(caseName): \(formattedValue);".indent(count: 4)) - } - dtsLines.append("};") - dtsLines.append( - "export type \(enumDefinition.name) = typeof \(enumDefinition.name)[keyof typeof \(enumDefinition.name)];" - ) - dtsLines.append("") + printer.write("\(caseName) = \(value),") } + printer.unindent() + printer.write("}") + printer.nextLine() + case .associatedValue, .namespace: + break } - case .associatedValue: - do { - jsLines.append("const \(enumDefinition.name) = {") - jsLines.append("Tag: {".indent(count: 4)) - for (caseIndex, enumCase) in enumDefinition.cases.enumerated() { + + case .const: + switch enumDefinition.enumType { + case .simple: + printer.write("export const \(enumDefinition.name): {") + printer.indent() + for (index, enumCase) in enumDefinition.cases.enumerated() { let caseName = enumCase.name.capitalizedFirstLetter - jsLines.append("\(caseName): \(caseIndex),".indent(count: 8)) + printer.write("readonly \(caseName): \(index);") } - jsLines.append("}".indent(count: 4)) - jsLines.append("};") - jsLines.append("") - jsLines.append("const __bjs_create\(enumDefinition.name)Helpers = () => {") - jsLines.append( - "return (\(JSGlueVariableScope.reservedTmpParamInts), \(JSGlueVariableScope.reservedTmpParamF32s), \(JSGlueVariableScope.reservedTmpParamF64s), textEncoder, swift) => ({" - .indent(count: 4) + printer.unindent() + printer.write("};") + printer.write( + "export type \(enumDefinition.name) = typeof \(enumDefinition.name)[keyof typeof \(enumDefinition.name)];" ) - - jsLines.append("lower: (value) => {".indent(count: 8)) - jsLines.append("const enumTag = value.tag;".indent(count: 12)) - jsLines.append("switch (enumTag) {".indent(count: 12)) - enumDefinition.cases.forEach { enumCase in + printer.nextLine() + case .rawValue: + printer.write("export const \(enumDefinition.name): {") + printer.indent() + for enumCase in enumDefinition.cases { let caseName = enumCase.name.capitalizedFirstLetter - if enumCase.associatedValues.isEmpty { - jsLines.append("case \(enumDefinition.name).Tag.\(caseName): {".indent(count: 16)) - jsLines.append("const cleanup = undefined;".indent(count: 20)) - jsLines.append( - "return { caseId: \(enumDefinition.name).Tag.\(caseName), cleanup };" - .indent(count: 20) - ) - jsLines.append("}".indent(count: 16)) - } else { - jsLines.append("case \(enumDefinition.name).Tag.\(caseName): {".indent(count: 16)) - var pushLines: [String] = [] - var releaseIds: [String] = [] - let reversedValues = enumCase.associatedValues.enumerated().reversed() - for (associatedValueIndex, associatedValue) in reversedValues { - let prop = associatedValue.label ?? "param\(associatedValueIndex)" - switch associatedValue.type { - case .string: - let bytesVar = "bytes_\(associatedValueIndex)" - let idVar = "bytesId_\(associatedValueIndex)" - pushLines.append( - "const \(bytesVar) = \(JSGlueVariableScope.reservedTextEncoder).encode(value.\(prop));" - ) - pushLines.append( - "const \(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(bytesVar));" - ) - pushLines.append( - "\(JSGlueVariableScope.reservedTmpParamInts).push(\(bytesVar).length);" - ) - pushLines.append("\(JSGlueVariableScope.reservedTmpParamInts).push(\(idVar));") - releaseIds.append(idVar) - case .bool: - pushLines.append( - "\(JSGlueVariableScope.reservedTmpParamInts).push(value.\(prop) ? 1 : 0);" - ) - case .int: - pushLines.append( - "\(JSGlueVariableScope.reservedTmpParamInts).push((value.\(prop) | 0));" - ) - case .float: - pushLines.append( - "\(JSGlueVariableScope.reservedTmpParamF32s).push(Math.fround(value.\(prop)));" - ) - case .double: - pushLines.append("\(JSGlueVariableScope.reservedTmpParamF64s).push(value.\(prop));") - default: - pushLines.append("\(JSGlueVariableScope.reservedTmpParamInts).push(0);") - } - } - jsLines.append(contentsOf: pushLines.map { $0.indent(count: 20) }) - if releaseIds.isEmpty { - jsLines.append("const cleanup = undefined;".indent(count: 20)) - } else { - jsLines.append("const cleanup = () => {".indent(count: 20)) - for id in releaseIds { - jsLines.append( - "\(JSGlueVariableScope.reservedSwift).memory.release(\(id));".indent(count: 24) - ) - } - jsLines.append("};".indent(count: 20)) - } - jsLines.append( - "return { caseId: \(enumDefinition.name).Tag.\(caseName), cleanup };" - .indent(count: 20) - ) - jsLines.append("}".indent(count: 16)) - } + let rawValue = enumCase.rawValue ?? enumCase.name + let formattedValue = SwiftEnumRawType.formatValue(rawValue, rawType: enumDefinition.rawType ?? "") + printer.write("readonly \(caseName): \(formattedValue);") } - jsLines.append( - "default: throw new Error(\"Unknown \(enumDefinition.name) tag: \" + String(enumTag));".indent( - count: 16 - ) - ) - jsLines.append("}".indent(count: 12)) - jsLines.append("},".indent(count: 8)) - - jsLines.append( - "raise: (\(JSGlueVariableScope.reservedTmpRetTag), \(JSGlueVariableScope.reservedTmpRetStrings), \(JSGlueVariableScope.reservedTmpRetInts), \(JSGlueVariableScope.reservedTmpRetF32s), \(JSGlueVariableScope.reservedTmpRetF64s)) => {" - .indent( - count: 8 - ) + printer.unindent() + printer.write("};") + printer.write( + "export type \(enumDefinition.name) = typeof \(enumDefinition.name)[keyof typeof \(enumDefinition.name)];" ) - jsLines.append("const tag = tmpRetTag | 0;".indent(count: 12)) - jsLines.append("switch (tag) {".indent(count: 12)) - enumDefinition.cases.forEach { enumCase in + printer.nextLine() + case .associatedValue: + printer.write("export const \(enumDefinition.name): {") + printer.indent() + printer.write("readonly Tag: {") + printer.indent() + for (index, enumCase) in enumDefinition.cases.enumerated() { let caseName = enumCase.name.capitalizedFirstLetter + printer.write("readonly \(caseName): \(index);") + } + printer.unindent() + printer.write("};") + printer.unindent() + printer.write("};") + printer.nextLine() + + var unionParts: [String] = [] + for enumCase in enumDefinition.cases { if enumCase.associatedValues.isEmpty { - jsLines.append( - "case \(enumDefinition.name).Tag.\(caseName): return { tag: \(enumDefinition.name).Tag.\(caseName) };" - .indent(count: 16) + unionParts.append( + "{ tag: typeof \(enumDefinition.name).Tag.\(enumCase.name.capitalizedFirstLetter) }" ) } else { - var locals: [String] = [] - var fieldPairs: [String] = [] - for (associatedValueIndex, associatedValue) in enumCase.associatedValues.enumerated().reversed() - { + var fields: [String] = [ + "tag: typeof \(enumDefinition.name).Tag.\(enumCase.name.capitalizedFirstLetter)" + ] + for (associatedValueIndex, associatedValue) in enumCase.associatedValues.enumerated() { let prop = associatedValue.label ?? "param\(associatedValueIndex)" - switch associatedValue.type { - case .string: - let strVar = "string_\(associatedValueIndex)" - locals.append("const \(strVar) = tmpRetStrings.pop();") - fieldPairs.append("\(prop): \(strVar)") - case .bool: - let bVar = "bool_\(associatedValueIndex)" - locals.append("const \(bVar) = tmpRetInts.pop();") - fieldPairs.append("\(prop): \(bVar)") - case .int: - let iVar = "int_\(associatedValueIndex)" - locals.append("const \(iVar) = tmpRetInts.pop();") - fieldPairs.append("\(prop): \(iVar)") - case .float: - let fVar = "f32_\(associatedValueIndex)" - locals.append("const \(fVar) = tmpRetF32s.pop();") - fieldPairs.append("\(prop): \(fVar)") - case .double: - let dVar = "f64_\(associatedValueIndex)" - locals.append("const \(dVar) = tmpRetF64s.pop();") - fieldPairs.append("\(prop): \(dVar)") - default: - fieldPairs.append("\(prop): undefined") - } + fields.append("\(prop): \(associatedValue.type.tsType)") } - jsLines.append("case \(enumDefinition.name).Tag.\(caseName): {".indent(count: 16)) - jsLines.append(contentsOf: locals.map { $0.indent(count: 20) }) - jsLines.append( - "return { tag: \(enumDefinition.name).Tag.\(caseName), \(fieldPairs.reversed().joined(separator: ", ")) };" - .indent(count: 20) - ) - jsLines.append("}".indent(count: 16)) + unionParts.append("{ \(fields.joined(separator: "; ")) }") } } - jsLines.append( - "default: throw new Error(\"Unknown \(enumDefinition.name) tag returned from Swift: \" + String(tag));" - .indent( - count: 16 - ) - ) - jsLines.append("}".indent(count: 12)) - jsLines.append("}".indent(count: 8)) - jsLines.append("});".indent(count: 4)) - jsLines.append("};") - - if enumDefinition.namespace == nil { - dtsLines.append("export const \(enumDefinition.name): {") - dtsLines.append("readonly Tag: {".indent(count: 4)) - for (index, enumCase) in enumDefinition.cases.enumerated() { - let caseName = enumCase.name.capitalizedFirstLetter - dtsLines.append("readonly \(caseName): \(index);".indent(count: 8)) - } - dtsLines.append("};".indent(count: 4)) - dtsLines.append("};") - dtsLines.append("") - var unionParts: [String] = [] - for enumCase in enumDefinition.cases { - if enumCase.associatedValues.isEmpty { - unionParts.append( - "{ tag: typeof \(enumDefinition.name).Tag.\(enumCase.name.capitalizedFirstLetter) }" - ) - } else { - var fields: [String] = [ - "tag: typeof \(enumDefinition.name).Tag.\(enumCase.name.capitalizedFirstLetter)" - ] - for (associatedValueIndex, associatedValue) in enumCase.associatedValues - .enumerated() - { - let prop = associatedValue.label ?? "param\(associatedValueIndex)" - let ts: String - switch associatedValue.type { - case .string: ts = "string" - case .bool: ts = "boolean" - case .int, .float, .double: ts = "number" - default: ts = "never" - } - fields.append("\(prop): \(ts)") - } - unionParts.append("{ \(fields.joined(separator: "; ")) }") - } - } - dtsLines.append("export type \(enumDefinition.name) =") - dtsLines.append(" " + unionParts.joined(separator: " | ")) - dtsLines.append("") - } + + printer.write("export type \(enumDefinition.name) =") + printer.write(" " + unionParts.joined(separator: " | ")) + printer.nextLine() + case .namespace: + break } - case .namespace: - break } - - return (jsLines, dtsLines) + return printer.lines } +} + +extension BridgeJSLink { func renderExportedFunction(function: ExportedFunction) throws -> (js: [String], dts: [String]) { let thunkBuilder = ExportedThunkBuilder(effects: function.effects) @@ -1247,7 +1070,7 @@ struct BridgeJSLink { namespacedFunctions: [ExportedFunction], namespacedClasses: [ExportedClass] ) -> [String] { - var lines: [String] = [] + let printer = CodeFragmentPrinter() var uniqueNamespaces: [String] = [] var seen = Set() @@ -1274,28 +1097,30 @@ struct BridgeJSLink { } uniqueNamespaces.sorted().forEach { namespace in - lines.append("if (typeof globalThis.\(namespace) === 'undefined') {") - lines.append("globalThis.\(namespace) = {};".indent(count: 4)) - lines.append("}") + printer.write("if (typeof globalThis.\(namespace) === 'undefined') {") + printer.indent() + printer.write("globalThis.\(namespace) = {};") + printer.unindent() + printer.write("}") } namespacedClasses.forEach { klass in let namespacePath: String = klass.namespace?.joined(separator: ".") ?? "" - lines.append("globalThis.\(namespacePath).\(klass.name) = exports.\(klass.name);") + printer.write("globalThis.\(namespacePath).\(klass.name) = exports.\(klass.name);") } namespacedFunctions.forEach { function in let namespacePath: String = function.namespace?.joined(separator: ".") ?? "" - lines.append("globalThis.\(namespacePath).\(function.name) = exports.\(function.name);") + printer.write("globalThis.\(namespacePath).\(function.name) = exports.\(function.name);") } - return lines + return printer.lines } func renderTopLevelEnumNamespaceAssignments(namespacedEnums: [ExportedEnum]) -> [String] { guard !namespacedEnums.isEmpty else { return [] } - var lines: [String] = [] + let printer = CodeFragmentPrinter() var uniqueNamespaces: [String] = [] var seen = Set() @@ -1311,21 +1136,23 @@ struct BridgeJSLink { } for namespace in uniqueNamespaces { - lines.append("if (typeof globalThis.\(namespace) === 'undefined') {") - lines.append("globalThis.\(namespace) = {};".indent(count: 4)) - lines.append("}") + printer.write("if (typeof globalThis.\(namespace) === 'undefined') {") + printer.indent() + printer.write("globalThis.\(namespace) = {};") + printer.unindent() + printer.write("}") } - if !lines.isEmpty { - lines.append("") + if !uniqueNamespaces.isEmpty { + printer.nextLine() } for enumDef in namespacedEnums { let namespacePath = enumDef.namespace?.joined(separator: ".") ?? "" - lines.append("globalThis.\(namespacePath).\(enumDef.name) = \(enumDef.name);") + printer.write("globalThis.\(namespacePath).\(enumDef.name) = \(enumDef.name);") } - return lines + return printer.lines } private struct NamespaceContent { @@ -1372,7 +1199,7 @@ struct BridgeJSLink { exportedSkeletons: [ExportedSkeleton], renderTSSignatureCallback: @escaping ([Parameter], BridgeType, Effects) -> String ) -> [String] { - var dtsLines: [String] = [] + let printer = CodeFragmentPrinter() let rootNode = NamespaceNode(name: "") @@ -1409,41 +1236,41 @@ struct BridgeJSLink { } guard !rootNode.children.isEmpty else { - return dtsLines + return printer.lines } - dtsLines.append("export {};") - dtsLines.append("") - dtsLines.append("declare global {") - - let identBaseSize = 4 + printer.write("export {};") + printer.nextLine() + printer.write("declare global {") + printer.indent() func generateNamespaceDeclarations(node: NamespaceNode, depth: Int) { let sortedChildren = node.children.sorted { $0.key < $1.key } for (childName, childNode) in sortedChildren { - dtsLines.append("namespace \(childName) {".indent(count: identBaseSize * depth)) - - let contentDepth = depth + 1 + printer.write("namespace \(childName) {") + printer.indent() let sortedClasses = childNode.content.classes.sorted { $0.name < $1.name } for klass in sortedClasses { - dtsLines.append("class \(klass.name) {".indent(count: identBaseSize * contentDepth)) + printer.write("class \(klass.name) {") + printer.indent() if let constructor = klass.constructor { let constructorSignature = "constructor(\(constructor.parameters.map { "\($0.name): \($0.type.tsType)" }.joined(separator: ", ")));" - dtsLines.append("\(constructorSignature)".indent(count: identBaseSize * (contentDepth + 1))) + printer.write(constructorSignature) } let sortedMethods = klass.methods.sorted { $0.name < $1.name } for method in sortedMethods { let methodSignature = "\(method.name)\(renderTSSignatureCallback(method.parameters, method.returnType, method.effects));" - dtsLines.append("\(methodSignature)".indent(count: identBaseSize * (contentDepth + 1))) + printer.write(methodSignature) } - dtsLines.append("}".indent(count: identBaseSize * contentDepth)) + printer.unindent() + printer.write("}") } let sortedEnums = childNode.content.enums.sorted { $0.name < $1.name } @@ -1453,41 +1280,33 @@ struct BridgeJSLink { case .simple: switch style { case .tsEnum: - dtsLines.append( - "enum \(enumDefinition.name) {".indent(count: identBaseSize * contentDepth) - ) + printer.write("enum \(enumDefinition.name) {") + printer.indent() for (index, enumCase) in enumDefinition.cases.enumerated() { let caseName = enumCase.name.capitalizedFirstLetter - dtsLines.append( - "\(caseName) = \(index),".indent(count: identBaseSize * (contentDepth + 1)) - ) + printer.write("\(caseName) = \(index),") } - dtsLines.append("}".indent(count: identBaseSize * contentDepth)) + printer.unindent() + printer.write("}") case .const: - dtsLines.append( - "const \(enumDefinition.name): {".indent(count: identBaseSize * contentDepth) - ) + printer.write("const \(enumDefinition.name): {") + printer.indent() for (index, enumCase) in enumDefinition.cases.enumerated() { let caseName = enumCase.name.capitalizedFirstLetter - dtsLines.append( - "readonly \(caseName): \(index);".indent( - count: identBaseSize * (contentDepth + 1) - ) - ) + printer.write("readonly \(caseName): \(index);") } - dtsLines.append("};".indent(count: identBaseSize * contentDepth)) - dtsLines.append( + printer.unindent() + printer.write("};") + printer.write( "type \(enumDefinition.name) = typeof \(enumDefinition.name)[keyof typeof \(enumDefinition.name)];" - .indent(count: identBaseSize * contentDepth) ) } case .rawValue: guard let rawType = enumDefinition.rawType else { continue } switch style { case .tsEnum: - dtsLines.append( - "enum \(enumDefinition.name) {".indent(count: identBaseSize * contentDepth) - ) + printer.write("enum \(enumDefinition.name) {") + printer.indent() for enumCase in enumDefinition.cases { let caseName = enumCase.name.capitalizedFirstLetter let rawValue = enumCase.rawValue ?? enumCase.name @@ -1498,17 +1317,13 @@ struct BridgeJSLink { case "Float", "Double": formattedValue = rawValue default: formattedValue = rawValue } - dtsLines.append( - "\(caseName) = \(formattedValue),".indent( - count: identBaseSize * (contentDepth + 1) - ) - ) + printer.write("\(caseName) = \(formattedValue),") } - dtsLines.append("}".indent(count: identBaseSize * contentDepth)) + printer.unindent() + printer.write("}") case .const: - dtsLines.append( - "const \(enumDefinition.name): {".indent(count: identBaseSize * contentDepth) - ) + printer.write("const \(enumDefinition.name): {") + printer.indent() for enumCase in enumDefinition.cases { let caseName = enumCase.name.capitalizedFirstLetter let rawValue = enumCase.rawValue ?? enumCase.name @@ -1519,33 +1334,27 @@ struct BridgeJSLink { case "Float", "Double": formattedValue = rawValue default: formattedValue = rawValue } - dtsLines.append( - "readonly \(caseName): \(formattedValue);".indent( - count: identBaseSize * (contentDepth + 1) - ) - ) + printer.write("readonly \(caseName): \(formattedValue);") } - dtsLines.append("};".indent(count: identBaseSize * contentDepth)) - dtsLines.append( + printer.unindent() + printer.write("};") + printer.write( "type \(enumDefinition.name) = typeof \(enumDefinition.name)[keyof typeof \(enumDefinition.name)];" - .indent(count: identBaseSize * contentDepth) ) } case .associatedValue: - dtsLines.append( - "const \(enumDefinition.name): {".indent(count: identBaseSize * contentDepth) - ) - dtsLines.append("readonly Tag: {".indent(count: identBaseSize * (contentDepth + 1))) + printer.write("const \(enumDefinition.name): {") + printer.indent() + printer.write("readonly Tag: {") + printer.indent() for (caseIndex, enumCase) in enumDefinition.cases.enumerated() { let caseName = enumCase.name.capitalizedFirstLetter - dtsLines.append( - "readonly \(caseName): \(caseIndex);".indent( - count: identBaseSize * (contentDepth + 2) - ) - ) + printer.write("readonly \(caseName): \(caseIndex);") } - dtsLines.append("};".indent(count: identBaseSize * (contentDepth + 1))) - dtsLines.append("};".indent(count: identBaseSize * contentDepth)) + printer.unindent() + printer.write("};") + printer.unindent() + printer.write("};") var unionParts: [String] = [] for enumCase in enumDefinition.cases { @@ -1561,22 +1370,13 @@ struct BridgeJSLink { .enumerated() { let prop = associatedValue.label ?? "param\(associatedValueIndex)" - let ts: String - switch associatedValue.type { - case .string: ts = "string" - case .bool: ts = "boolean" - case .int, .float, .double: ts = "number" - default: ts = "never" - } - fields.append("\(prop): \(ts)") + fields.append("\(prop): \(associatedValue.type.tsType)") } unionParts.append("{ \(fields.joined(separator: "; ")) }") } } - dtsLines.append("type \(enumDefinition.name) =".indent(count: identBaseSize * contentDepth)) - dtsLines.append( - " " + unionParts.joined(separator: " | ").indent(count: identBaseSize * contentDepth) - ) + printer.write("type \(enumDefinition.name) =") + printer.write(" " + unionParts.joined(separator: " | ")) case .namespace: continue } @@ -1586,21 +1386,23 @@ struct BridgeJSLink { for function in sortedFunctions { let signature = "\(function.name)\(renderTSSignatureCallback(function.parameters, function.returnType, function.effects));" - dtsLines.append("\(signature)".indent(count: identBaseSize * contentDepth)) + printer.write(signature) } - generateNamespaceDeclarations(node: childNode, depth: contentDepth) + generateNamespaceDeclarations(node: childNode, depth: depth + 1) - dtsLines.append("}".indent(count: identBaseSize * depth)) + printer.unindent() + printer.write("}") } } generateNamespaceDeclarations(node: rootNode, depth: 1) - dtsLines.append("}") - dtsLines.append("") + printer.unindent() + printer.write("}") + printer.nextLine() - return dtsLines + return printer.lines } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index f559e62f..36977aae 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -357,4 +357,346 @@ struct IntrinsicJSFragment: Sendable { ) } } + + // MARK: - Enums Payload Fragments + + /// Fragment for generating an entire associated value enum helper + static func associatedValueEnumHelper(enumDefinition: ExportedEnum) -> IntrinsicJSFragment { + return IntrinsicJSFragment( + parameters: ["enumName"], + printCode: { arguments, scope, printer, cleanup in + let enumName = arguments[0] + + // Generate the enum tag object + printer.write("const \(enumName) = {") + printer.indent { + printer.write("Tag: {") + printer.indent { + for (index, enumCase) in enumDefinition.cases.enumerated() { + let caseName = enumCase.name.capitalizedFirstLetter + printer.write("\(caseName): \(index),") + } + } + printer.write("}") + } + printer.write("};") + printer.nextLine() + + // Generate the helper function + printer.write("const __bjs_create\(enumName)Helpers = () => {") + printer.indent() + printer.write( + "return (\(JSGlueVariableScope.reservedTmpParamInts), \(JSGlueVariableScope.reservedTmpParamF32s), \(JSGlueVariableScope.reservedTmpParamF64s), textEncoder, \(JSGlueVariableScope.reservedSwift)) => ({" + ) + printer.indent() + + // Generate lower function + printer.write("lower: (value) => {") + printer.indent { + printer.write("const enumTag = value.tag;") + printer.write("switch (enumTag) {") + printer.indent { + let lowerPrinter = CodeFragmentPrinter() + for enumCase in enumDefinition.cases { + let caseName = enumCase.name.capitalizedFirstLetter + let caseScope = JSGlueVariableScope() + let caseCleanup = CodeFragmentPrinter() + caseCleanup.indent() + let fragment = IntrinsicJSFragment.associatedValuePushPayload(enumCase: enumCase) + _ = fragment.printCode(["value", enumName, caseName], caseScope, lowerPrinter, caseCleanup) + } + + for line in lowerPrinter.lines { + printer.write(line) + } + + printer.write("default: throw new Error(\"Unknown \(enumName) tag: \" + String(enumTag));") + } + printer.write("}") + } + printer.write("},") + + // Generate raise function + printer.write( + "raise: (\(JSGlueVariableScope.reservedTmpRetTag), \(JSGlueVariableScope.reservedTmpRetStrings), \(JSGlueVariableScope.reservedTmpRetInts), \(JSGlueVariableScope.reservedTmpRetF32s), \(JSGlueVariableScope.reservedTmpRetF64s)) => {" + ) + printer.indent { + printer.write("const tag = tmpRetTag | 0;") + printer.write("switch (tag) {") + printer.indent { + let raisePrinter = CodeFragmentPrinter() + for enumCase in enumDefinition.cases { + let caseName = enumCase.name.capitalizedFirstLetter + let caseScope = JSGlueVariableScope() + let caseCleanup = CodeFragmentPrinter() + + let fragment = IntrinsicJSFragment.associatedValuePopPayload(enumCase: enumCase) + _ = fragment.printCode([enumName, caseName], caseScope, raisePrinter, caseCleanup) + } + + for line in raisePrinter.lines { + printer.write(line) + } + + printer.write( + "default: throw new Error(\"Unknown \(enumName) tag returned from Swift: \" + String(tag));" + ) + } + 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, scope, printer, cleanup in + let enumName = arguments[0] + printer.write("const \(enumName) = {") + printer.indent { + for (index, enumCase) in enumDefinition.cases.enumerated() { + let caseName = enumCase.name.capitalizedFirstLetter + printer.write("\(caseName): \(index),") + } + } + printer.write("};") + printer.nextLine() + + return [] + } + ) + } + + static func rawValueEnumHelper(enumDefinition: ExportedEnum) -> IntrinsicJSFragment { + return IntrinsicJSFragment( + parameters: ["enumName"], + printCode: { arguments, scope, printer, cleanup in + let enumName = arguments[0] + printer.write("const \(enumName) = {") + printer.indent { + for enumCase in enumDefinition.cases { + let caseName = enumCase.name.capitalizedFirstLetter + let rawValue = enumCase.rawValue ?? enumCase.name + let formattedValue = SwiftEnumRawType.formatValue( + rawValue, + rawType: enumDefinition.rawType ?? "" + ) + + printer.write("\(caseName): \(formattedValue),") + } + } + printer.write("};") + printer.nextLine() + + return [] + } + ) + } + + private static func associatedValuePushPayload(enumCase: EnumCase) -> IntrinsicJSFragment { + return IntrinsicJSFragment( + parameters: ["value", "enumName", "caseName"], + printCode: { arguments, scope, printer, cleanup in + let enumName = arguments[1] + let caseName = arguments[2] + + printer.write("case \(enumName).Tag.\(caseName): {") + + printer.indent { + if enumCase.associatedValues.isEmpty { + printer.write("const cleanup = undefined;") + printer.write("return { caseId: \(enumName).Tag.\(caseName), cleanup };") + } 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 { + let prop = associatedValue.label ?? "param\(associatedValueIndex)" + let fragment = IntrinsicJSFragment.associatedValuePushPayload(type: associatedValue.type) + + _ = fragment.printCode(["value.\(prop)"], scope, printer, cleanup) + } + + if cleanup.lines.isEmpty { + printer.write("const cleanup = undefined;") + } else { + printer.write("const cleanup = () => {") + printer.write(contentsOf: cleanup) + printer.write("};") + } + printer.write("return { caseId: \(enumName).Tag.\(caseName), cleanup };") + } + } + + printer.write("}") + + return [] + } + ) + } + + private static func associatedValuePopPayload(enumCase: EnumCase) -> IntrinsicJSFragment { + return IntrinsicJSFragment( + parameters: ["enumName", "caseName"], + printCode: { arguments, scope, printer, cleanup in + let enumName = arguments[0] + let caseName = arguments[1] + + if enumCase.associatedValues.isEmpty { + printer.write("case \(enumName).Tag.\(caseName): return { tag: \(enumName).Tag.\(caseName) };") + } else { + var fieldPairs: [String] = [] + let casePrinter = CodeFragmentPrinter() + + // Process associated values in reverse order (to match the order they'll be popped) + for (associatedValueIndex, associatedValue) in enumCase.associatedValues.enumerated().reversed() { + let prop = associatedValue.label ?? "param\(associatedValueIndex)" + let fragment = IntrinsicJSFragment.associatedValuePopPayload(type: associatedValue.type) + + let result = fragment.printCode([], scope, casePrinter, cleanup) + let varName = result.first ?? "value_\(associatedValueIndex)" + + fieldPairs.append("\(prop): \(varName)") + } + + printer.write("case \(enumName).Tag.\(caseName): {") + printer.indent { + 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) -> IntrinsicJSFragment { + switch type { + case .string: + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, scope, printer, cleanup in + 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("\(JSGlueVariableScope.reservedTmpParamInts).push(\(bytesVar).length);") + printer.write("\(JSGlueVariableScope.reservedTmpParamInts).push(\(idVar));") + cleanup.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(idVar));") + return [] + } + ) + case .bool: + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, scope, printer, cleanup in + printer.write("\(JSGlueVariableScope.reservedTmpParamInts).push(\(arguments[0]) ? 1 : 0);") + return [] + } + ) + case .int: + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, scope, printer, cleanup in + printer.write("\(JSGlueVariableScope.reservedTmpParamInts).push((\(arguments[0]) | 0));") + return [] + } + ) + case .float: + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, scope, printer, cleanup in + printer.write("\(JSGlueVariableScope.reservedTmpParamF32s).push(Math.fround(\(arguments[0])));") + return [] + } + ) + case .double: + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, scope, printer, cleanup in + printer.write("\(JSGlueVariableScope.reservedTmpParamF64s).push(\(arguments[0]));") + return [] + } + ) + default: + return IntrinsicJSFragment( + parameters: [], + printCode: { arguments, scope, printer, cleanup in + return [] + } + ) + } + } + + private static func associatedValuePopPayload(type: BridgeType) -> IntrinsicJSFragment { + switch type { + case .string: + return IntrinsicJSFragment( + parameters: [], + printCode: { arguments, scope, printer, cleanup in + let strVar = scope.variable("string") + printer.write("const \(strVar) = \(JSGlueVariableScope.reservedTmpRetStrings).pop();") + return [strVar] + } + ) + case .bool: + return IntrinsicJSFragment( + parameters: [], + printCode: { arguments, scope, printer, cleanup in + let bVar = scope.variable("bool") + printer.write("const \(bVar) = \(JSGlueVariableScope.reservedTmpRetInts).pop();") + return [bVar] + } + ) + case .int: + return IntrinsicJSFragment( + parameters: [], + printCode: { arguments, scope, printer, cleanup in + let iVar = scope.variable("int") + printer.write("const \(iVar) = \(JSGlueVariableScope.reservedTmpRetInts).pop();") + return [iVar] + } + ) + case .float: + return IntrinsicJSFragment( + parameters: [], + printCode: { arguments, scope, printer, cleanup in + let fVar = scope.variable("f32") + printer.write("const \(fVar) = \(JSGlueVariableScope.reservedTmpRetF32s).pop();") + return [fVar] + } + ) + case .double: + return IntrinsicJSFragment( + parameters: [], + printCode: { arguments, scope, printer, cleanup in + let dVar = scope.variable("f64") + printer.write("const \(dVar) = \(JSGlueVariableScope.reservedTmpRetF64s).pop();") + return [dVar] + } + ) + default: + return IntrinsicJSFragment( + parameters: [], + printCode: { arguments, scope, printer, cleanup in + return ["undefined"] + } + ) + } + } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 5fa0acb9..a0d4bd9f 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -2,7 +2,7 @@ // MARK: - Types -public enum BridgeType: Codable, Equatable { +public enum BridgeType: Codable, Equatable, Sendable { case int, float, double, string, bool, jsObject(String?), swiftHeapObject(String), void case caseEnum(String) case rawValueEnum(String, SwiftEnumRawType) @@ -14,7 +14,7 @@ public enum WasmCoreType: String, Codable, Sendable { case i32, i64, f32, f64, pointer } -public enum SwiftEnumRawType: String, CaseIterable, Codable { +public enum SwiftEnumRawType: String, CaseIterable, Codable, Sendable { case string = "String" case bool = "Bool" case int = "Int" @@ -44,6 +44,21 @@ public enum SwiftEnumRawType: String, CaseIterable, Codable { public static func from(_ rawTypeString: String) -> SwiftEnumRawType? { return Self.allCases.first { $0.rawValue == rawTypeString } } + + public static func formatValue(_ rawValue: String, rawType: String) -> String { + if let enumType = from(rawType) { + switch enumType { + case .string: + return "\"\(rawValue)\"" + case .bool: + return rawValue.lowercased() == "true" ? "true" : "false" + case .float, .double, .int, .int32, .int64, .uint, .uint32, .uint64: + return rawValue + } + } else { + return rawValue + } + } } public struct Parameter: Codable { @@ -70,7 +85,7 @@ public struct Effects: Codable { // MARK: - Enum Skeleton -public struct AssociatedValue: Codable, Equatable { +public struct AssociatedValue: Codable, Equatable, Sendable { public let label: String? public let type: BridgeType @@ -80,7 +95,7 @@ public struct AssociatedValue: Codable, Equatable { } } -public struct EnumCase: Codable, Equatable { +public struct EnumCase: Codable, Equatable, Sendable { public let name: String public let rawValue: String? public let associatedValues: [AssociatedValue] @@ -88,20 +103,19 @@ public struct EnumCase: Codable, Equatable { public var isSimple: Bool { associatedValues.isEmpty } - - public init(name: String, rawValue: String?, associatedValues: [AssociatedValue]) { + public init(name: String, rawValue: String?, associatedValues: [AssociatedValue] = []) { self.name = name self.rawValue = rawValue self.associatedValues = associatedValues } } -public enum EnumEmitStyle: String, Codable { +public enum EnumEmitStyle: String, Codable, Sendable { case const case tsEnum } -public struct ExportedEnum: Codable, Equatable { +public struct ExportedEnum: Codable, Equatable, Sendable { public let name: String public let swiftCallName: String public let explicitAccessControl: String? @@ -138,7 +152,7 @@ public struct ExportedEnum: Codable, Equatable { } } -public enum EnumType: String, Codable { +public enum EnumType: String, Codable, Sendable { case simple // enum Direction { case north, south, east } case rawValue // enum Mode: String { case light = "light" } case associatedValue // enum Result { case success(String), failure(Int) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js index 7a189d19..3b8e1f83 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js @@ -21,12 +21,12 @@ const __bjs_createAPIResultHelpers = () => { const enumTag = value.tag; switch (enumTag) { case APIResult.Tag.Success: { - const bytes_0 = textEncoder.encode(value.param0); - const bytesId_0 = swift.memory.retain(bytes_0); - tmpParamInts.push(bytes_0.length); - tmpParamInts.push(bytesId_0); + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + tmpParamInts.push(bytes.length); + tmpParamInts.push(id); const cleanup = () => { - swift.memory.release(bytesId_0); + swift.memory.release(id); }; return { caseId: APIResult.Tag.Success, cleanup }; } @@ -61,24 +61,24 @@ const __bjs_createAPIResultHelpers = () => { const tag = tmpRetTag | 0; switch (tag) { case APIResult.Tag.Success: { - const string_0 = tmpRetStrings.pop(); - return { tag: APIResult.Tag.Success, param0: string_0 }; + const string = tmpRetStrings.pop(); + return { tag: APIResult.Tag.Success, param0: string }; } case APIResult.Tag.Failure: { - const int_0 = tmpRetInts.pop(); - return { tag: APIResult.Tag.Failure, param0: int_0 }; + const int = tmpRetInts.pop(); + return { tag: APIResult.Tag.Failure, param0: int }; } case APIResult.Tag.Flag: { - const bool_0 = tmpRetInts.pop(); - return { tag: APIResult.Tag.Flag, param0: bool_0 }; + const bool = tmpRetInts.pop(); + return { tag: APIResult.Tag.Flag, param0: bool }; } case APIResult.Tag.Rate: { - const f32_0 = tmpRetF32s.pop(); - return { tag: APIResult.Tag.Rate, param0: f32_0 }; + const f32 = tmpRetF32s.pop(); + return { tag: APIResult.Tag.Rate, param0: f32 }; } case APIResult.Tag.Precise: { - const f64_0 = tmpRetF64s.pop(); - return { tag: APIResult.Tag.Precise, param0: f64_0 }; + const f64 = tmpRetF64s.pop(); + return { tag: APIResult.Tag.Precise, param0: f64 }; } case APIResult.Tag.Info: return { tag: APIResult.Tag.Info }; default: throw new Error("Unknown APIResult tag returned from Swift: " + String(tag)); @@ -103,35 +103,35 @@ const __bjs_createComplexResultHelpers = () => { const enumTag = value.tag; switch (enumTag) { case ComplexResult.Tag.Success: { - const bytes_0 = textEncoder.encode(value.param0); - const bytesId_0 = swift.memory.retain(bytes_0); - tmpParamInts.push(bytes_0.length); - tmpParamInts.push(bytesId_0); + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + tmpParamInts.push(bytes.length); + tmpParamInts.push(id); const cleanup = () => { - swift.memory.release(bytesId_0); + swift.memory.release(id); }; return { caseId: ComplexResult.Tag.Success, cleanup }; } case ComplexResult.Tag.Error: { tmpParamInts.push((value.param1 | 0)); - const bytes_0 = textEncoder.encode(value.param0); - const bytesId_0 = swift.memory.retain(bytes_0); - tmpParamInts.push(bytes_0.length); - tmpParamInts.push(bytesId_0); + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + tmpParamInts.push(bytes.length); + tmpParamInts.push(id); const cleanup = () => { - swift.memory.release(bytesId_0); + swift.memory.release(id); }; return { caseId: ComplexResult.Tag.Error, cleanup }; } case ComplexResult.Tag.Status: { - const bytes_2 = textEncoder.encode(value.param2); - const bytesId_2 = swift.memory.retain(bytes_2); - tmpParamInts.push(bytes_2.length); - tmpParamInts.push(bytesId_2); + const bytes = textEncoder.encode(value.param2); + const id = swift.memory.retain(bytes); + tmpParamInts.push(bytes.length); + tmpParamInts.push(id); tmpParamInts.push((value.param1 | 0)); tmpParamInts.push(value.param0 ? 1 : 0); const cleanup = () => { - swift.memory.release(bytesId_2); + swift.memory.release(id); }; return { caseId: ComplexResult.Tag.Status, cleanup }; } @@ -143,18 +143,18 @@ const __bjs_createComplexResultHelpers = () => { return { caseId: ComplexResult.Tag.Coordinates, cleanup }; } case ComplexResult.Tag.Comprehensive: { - const bytes_8 = textEncoder.encode(value.param8); - const bytesId_8 = swift.memory.retain(bytes_8); - tmpParamInts.push(bytes_8.length); - tmpParamInts.push(bytesId_8); - const bytes_7 = textEncoder.encode(value.param7); - const bytesId_7 = swift.memory.retain(bytes_7); - tmpParamInts.push(bytes_7.length); - tmpParamInts.push(bytesId_7); - const bytes_6 = textEncoder.encode(value.param6); - const bytesId_6 = swift.memory.retain(bytes_6); - tmpParamInts.push(bytes_6.length); - tmpParamInts.push(bytesId_6); + const bytes = textEncoder.encode(value.param8); + const id = swift.memory.retain(bytes); + tmpParamInts.push(bytes.length); + tmpParamInts.push(id); + const bytes1 = textEncoder.encode(value.param7); + const id1 = swift.memory.retain(bytes1); + tmpParamInts.push(bytes1.length); + tmpParamInts.push(id1); + const bytes2 = textEncoder.encode(value.param6); + const id2 = swift.memory.retain(bytes2); + tmpParamInts.push(bytes2.length); + tmpParamInts.push(id2); tmpParamF64s.push(value.param5); tmpParamF64s.push(value.param4); tmpParamInts.push((value.param3 | 0)); @@ -162,9 +162,9 @@ const __bjs_createComplexResultHelpers = () => { tmpParamInts.push(value.param1 ? 1 : 0); tmpParamInts.push(value.param0 ? 1 : 0); const cleanup = () => { - swift.memory.release(bytesId_8); - swift.memory.release(bytesId_7); - swift.memory.release(bytesId_6); + swift.memory.release(id); + swift.memory.release(id1); + swift.memory.release(id2); }; return { caseId: ComplexResult.Tag.Comprehensive, cleanup }; } @@ -179,37 +179,37 @@ const __bjs_createComplexResultHelpers = () => { const tag = tmpRetTag | 0; switch (tag) { case ComplexResult.Tag.Success: { - const string_0 = tmpRetStrings.pop(); - return { tag: ComplexResult.Tag.Success, param0: string_0 }; + const string = tmpRetStrings.pop(); + return { tag: ComplexResult.Tag.Success, param0: string }; } case ComplexResult.Tag.Error: { - const int_1 = tmpRetInts.pop(); - const string_0 = tmpRetStrings.pop(); - return { tag: ComplexResult.Tag.Error, param0: string_0, param1: int_1 }; + const int = tmpRetInts.pop(); + const string = tmpRetStrings.pop(); + return { tag: ComplexResult.Tag.Error, param0: string, param1: int }; } case ComplexResult.Tag.Status: { - const string_2 = tmpRetStrings.pop(); - const int_1 = tmpRetInts.pop(); - const bool_0 = tmpRetInts.pop(); - return { tag: ComplexResult.Tag.Status, param0: bool_0, param1: int_1, param2: string_2 }; + const string = tmpRetStrings.pop(); + const int = tmpRetInts.pop(); + const bool = tmpRetInts.pop(); + return { tag: ComplexResult.Tag.Status, param0: bool, param1: int, param2: string }; } case ComplexResult.Tag.Coordinates: { - const f64_2 = tmpRetF64s.pop(); - const f64_1 = tmpRetF64s.pop(); - const f64_0 = tmpRetF64s.pop(); - return { tag: ComplexResult.Tag.Coordinates, param0: f64_0, param1: f64_1, param2: f64_2 }; + const f64 = tmpRetF64s.pop(); + const f641 = tmpRetF64s.pop(); + const f642 = tmpRetF64s.pop(); + return { tag: ComplexResult.Tag.Coordinates, param0: f642, param1: f641, param2: f64 }; } case ComplexResult.Tag.Comprehensive: { - const string_8 = tmpRetStrings.pop(); - const string_7 = tmpRetStrings.pop(); - const string_6 = tmpRetStrings.pop(); - const f64_5 = tmpRetF64s.pop(); - const f64_4 = tmpRetF64s.pop(); - const int_3 = tmpRetInts.pop(); - const int_2 = tmpRetInts.pop(); - const bool_1 = tmpRetInts.pop(); - const bool_0 = tmpRetInts.pop(); - return { tag: ComplexResult.Tag.Comprehensive, param0: bool_0, param1: bool_1, param2: int_2, param3: int_3, param4: f64_4, param5: f64_5, param6: string_6, param7: string_7, param8: string_8 }; + const string = tmpRetStrings.pop(); + const string1 = tmpRetStrings.pop(); + const string2 = tmpRetStrings.pop(); + const f64 = tmpRetF64s.pop(); + const f641 = tmpRetF64s.pop(); + const int = tmpRetInts.pop(); + const int1 = tmpRetInts.pop(); + const bool = tmpRetInts.pop(); + const bool1 = tmpRetInts.pop(); + return { tag: ComplexResult.Tag.Comprehensive, param0: bool1, param1: bool, param2: int1, param3: int, param4: f641, param5: f64, param6: string2, param7: string1, param8: string }; } case ComplexResult.Tag.Info: return { tag: ComplexResult.Tag.Info }; default: throw new Error("Unknown ComplexResult tag returned from Swift: " + String(tag)); @@ -231,35 +231,35 @@ const __bjs_createResultHelpers = () => { const enumTag = value.tag; switch (enumTag) { case Result.Tag.Success: { - const bytes_0 = textEncoder.encode(value.param0); - const bytesId_0 = swift.memory.retain(bytes_0); - tmpParamInts.push(bytes_0.length); - tmpParamInts.push(bytesId_0); + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + tmpParamInts.push(bytes.length); + tmpParamInts.push(id); const cleanup = () => { - swift.memory.release(bytesId_0); + swift.memory.release(id); }; return { caseId: Result.Tag.Success, cleanup }; } case Result.Tag.Failure: { tmpParamInts.push((value.param1 | 0)); - const bytes_0 = textEncoder.encode(value.param0); - const bytesId_0 = swift.memory.retain(bytes_0); - tmpParamInts.push(bytes_0.length); - tmpParamInts.push(bytesId_0); + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + tmpParamInts.push(bytes.length); + tmpParamInts.push(id); const cleanup = () => { - swift.memory.release(bytesId_0); + swift.memory.release(id); }; return { caseId: Result.Tag.Failure, cleanup }; } case Result.Tag.Status: { - const bytes_2 = textEncoder.encode(value.param2); - const bytesId_2 = swift.memory.retain(bytes_2); - tmpParamInts.push(bytes_2.length); - tmpParamInts.push(bytesId_2); + const bytes = textEncoder.encode(value.param2); + const id = swift.memory.retain(bytes); + tmpParamInts.push(bytes.length); + tmpParamInts.push(id); tmpParamInts.push((value.param1 | 0)); tmpParamInts.push(value.param0 ? 1 : 0); const cleanup = () => { - swift.memory.release(bytesId_2); + swift.memory.release(id); }; return { caseId: Result.Tag.Status, cleanup }; } @@ -270,19 +270,19 @@ const __bjs_createResultHelpers = () => { const tag = tmpRetTag | 0; switch (tag) { case Result.Tag.Success: { - const string_0 = tmpRetStrings.pop(); - return { tag: Result.Tag.Success, param0: string_0 }; + const string = tmpRetStrings.pop(); + return { tag: Result.Tag.Success, param0: string }; } case Result.Tag.Failure: { - const int_1 = tmpRetInts.pop(); - const string_0 = tmpRetStrings.pop(); - return { tag: Result.Tag.Failure, param0: string_0, param1: int_1 }; + const int = tmpRetInts.pop(); + const string = tmpRetStrings.pop(); + return { tag: Result.Tag.Failure, param0: string, param1: int }; } case Result.Tag.Status: { - const string_2 = tmpRetStrings.pop(); - const int_1 = tmpRetInts.pop(); - const bool_0 = tmpRetInts.pop(); - return { tag: Result.Tag.Status, param0: bool_0, param1: int_1, param2: string_2 }; + const string = tmpRetStrings.pop(); + const int = tmpRetInts.pop(); + const bool = tmpRetInts.pop(); + return { tag: Result.Tag.Status, param0: bool, param1: int, param2: string }; } default: throw new Error("Unknown Result tag returned from Swift: " + String(tag)); } @@ -302,23 +302,23 @@ const __bjs_createNetworkingResultHelpers = () => { const enumTag = value.tag; switch (enumTag) { case NetworkingResult.Tag.Success: { - const bytes_0 = textEncoder.encode(value.param0); - const bytesId_0 = swift.memory.retain(bytes_0); - tmpParamInts.push(bytes_0.length); - tmpParamInts.push(bytesId_0); + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + tmpParamInts.push(bytes.length); + tmpParamInts.push(id); const cleanup = () => { - swift.memory.release(bytesId_0); + swift.memory.release(id); }; return { caseId: NetworkingResult.Tag.Success, cleanup }; } case NetworkingResult.Tag.Failure: { tmpParamInts.push((value.param1 | 0)); - const bytes_0 = textEncoder.encode(value.param0); - const bytesId_0 = swift.memory.retain(bytes_0); - tmpParamInts.push(bytes_0.length); - tmpParamInts.push(bytesId_0); + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + tmpParamInts.push(bytes.length); + tmpParamInts.push(id); const cleanup = () => { - swift.memory.release(bytesId_0); + swift.memory.release(id); }; return { caseId: NetworkingResult.Tag.Failure, cleanup }; } @@ -329,13 +329,13 @@ const __bjs_createNetworkingResultHelpers = () => { const tag = tmpRetTag | 0; switch (tag) { case NetworkingResult.Tag.Success: { - const string_0 = tmpRetStrings.pop(); - return { tag: NetworkingResult.Tag.Success, param0: string_0 }; + const string = tmpRetStrings.pop(); + return { tag: NetworkingResult.Tag.Success, param0: string }; } case NetworkingResult.Tag.Failure: { - const int_1 = tmpRetInts.pop(); - const string_0 = tmpRetStrings.pop(); - return { tag: NetworkingResult.Tag.Failure, param0: string_0, param1: int_1 }; + const int = tmpRetInts.pop(); + const string = tmpRetStrings.pop(); + return { tag: NetworkingResult.Tag.Failure, param0: string, param1: int }; } default: throw new Error("Unknown NetworkingResult tag returned from Swift: " + String(tag)); }