/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { [[noreturn]] void badUsage() { std::cerr << "Usage:\n\n" " wasmbridgegen \n\n" "where each is '+' (primary) or ':' (secondary), followed by: either a\n" "new- or legacy-format .rdb file, a single .idl file, or a root directory of an\n" ".idl file tree. For all primary registries, Wasm UNO bridge code is written to\n" "/, and to-be-exported exception RTTI symbols are written\n" "to .\n"; std::exit(EXIT_FAILURE); } std::string getPathnameArgument(sal_uInt32 argument) { OUString arg; rtl_getAppCommandArg(argument, &arg.pData); OString path; auto const enc = osl_getThreadTextEncoding(); if (!arg.convertToString(&path, enc, RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)) { std::cerr << "Cannot convert \"" << arg << "\" to system encoding " << enc << "\n"; std::exit(EXIT_FAILURE); } return std::string(path); } std::pair parseRegistryArgument(sal_uInt32 argument) { OUString arg; rtl_getAppCommandArg(argument, &arg.pData); bool primary; if (arg.startsWith(u"+", &arg)) { primary = true; } else if (arg.startsWith(u":", &arg)) { primary = false; } else { std::cerr << "Bad registry argument \"" << arg << "\"\n"; std::exit(EXIT_FAILURE); } OUString url; auto const e1 = osl::FileBase::getFileURLFromSystemPath(arg, url); if (e1 != osl::FileBase::E_None) { std::cerr << "Cannot convert \"" << arg << "\" to file URL, error code " << +e1 << "\n"; std::exit(EXIT_FAILURE); } OUString cwd; auto const e2 = osl_getProcessWorkingDir(&cwd.pData); if (e2 != osl_Process_E_None) { std::cerr << "Cannot obtain working directory, error code " << +e2 << "\n"; std::exit(EXIT_FAILURE); } OUString abs; auto const e3 = osl::FileBase::getAbsoluteFileURL(cwd, url, abs); if (e3 != osl::FileBase::E_None) { std::cerr << "Cannot make \"" << url << "\" into an absolute file URL, error code " << +e3 << "\n"; std::exit(EXIT_FAILURE); } return { abs, primary }; } OUString resolveAllTypedefs(rtl::Reference const& manager, std::u16string_view name) { sal_Int32 k1; OUString n(b2u(codemaker::UnoType::decompose(u2b(name), &k1))); for (;;) { rtl::Reference ent; if (manager->getSort(n, &ent) != codemaker::UnoType::Sort::Typedef) { break; } sal_Int32 k2; n = b2u(codemaker::UnoType::decompose( u2b(static_cast(ent.get())->getType()), &k2)); k1 += k2; //TODO: overflow } OUStringBuffer b; for (sal_Int32 i = 0; i != k1; ++i) { b.append("[]"); } b.append(n); return b.makeStringAndClear(); } enum class StructKind { Empty, I32, I64, F32, F64, General }; StructKind getKind(rtl::Reference const& manager, std::u16string_view type) { std::vector args; rtl::Reference ent; OUString singleMemberType; switch (manager->decompose(type, true, nullptr, nullptr, &args, &ent)) { case codemaker::UnoType::Sort::PlainStruct: { auto const strct = static_cast(ent.get()); if (strct->getDirectMembers().size() > 1) { return StructKind::General; } auto k = StructKind::Empty; if (!strct->getDirectBase().isEmpty()) { k = getKind(manager, strct->getDirectBase()); } if (strct->getDirectMembers().empty()) { return k; } if (k != StructKind::Empty) { return StructKind::General; } singleMemberType = strct->getDirectMembers()[0].type; break; } case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: { auto const strct = static_cast(ent.get()); switch (strct->getMembers().size()) { case 0: return StructKind::Empty; case 1: if (strct->getMembers()[0].parameterized) { auto const i = std::find(strct->getTypeParameters().begin(), strct->getTypeParameters().end(), strct->getMembers()[0].type); if (i == strct->getTypeParameters().end()) { throw CannotDumpException("bad type parameter \"" + strct->getMembers()[0].type + "\" in call to getKind"); } auto const n = i - strct->getTypeParameters().begin(); if (o3tl::make_unsigned(n) > args.size()) { throw CannotDumpException("bad type parameter \"" + strct->getMembers()[0].type + "\" in call to getKind"); } singleMemberType = args[n]; } else { singleMemberType = strct->getMembers()[0].type; } break; default: return StructKind::General; } break; } default: throw CannotDumpException(OUString::Concat("unexpected entity \"") + type + "\" in call to getKind"); } switch (manager->getSort(resolveAllTypedefs(manager, singleMemberType))) { case codemaker::UnoType::Sort::Boolean: case codemaker::UnoType::Sort::Byte: case codemaker::UnoType::Sort::Short: case codemaker::UnoType::Sort::UnsignedShort: case codemaker::UnoType::Sort::Long: case codemaker::UnoType::Sort::UnsignedLong: case codemaker::UnoType::Sort::Char: case codemaker::UnoType::Sort::Enum: return StructKind::I32; case codemaker::UnoType::Sort::Hyper: case codemaker::UnoType::Sort::UnsignedHyper: return StructKind::I64; case codemaker::UnoType::Sort::Float: return StructKind::F32; case codemaker::UnoType::Sort::Double: return StructKind::F64; default: return StructKind::General; } } void appendCallSignatureReturnType(OStringBuffer& buffer, rtl::Reference const& manager, OUString const& type) { switch (manager->getSort(resolveAllTypedefs(manager, type))) { case codemaker::UnoType::Sort::Void: buffer.append('v'); break; case codemaker::UnoType::Sort::Boolean: case codemaker::UnoType::Sort::Byte: case codemaker::UnoType::Sort::Short: case codemaker::UnoType::Sort::UnsignedShort: case codemaker::UnoType::Sort::Long: case codemaker::UnoType::Sort::UnsignedLong: case codemaker::UnoType::Sort::Char: case codemaker::UnoType::Sort::Enum: buffer.append('i'); break; case codemaker::UnoType::Sort::Hyper: case codemaker::UnoType::Sort::UnsignedHyper: buffer.append('j'); break; case codemaker::UnoType::Sort::Float: buffer.append('f'); break; case codemaker::UnoType::Sort::Double: buffer.append('d'); break; case codemaker::UnoType::Sort::String: case codemaker::UnoType::Sort::Type: case codemaker::UnoType::Sort::Any: case codemaker::UnoType::Sort::Sequence: case codemaker::UnoType::Sort::Interface: buffer.append("vi"); break; case codemaker::UnoType::Sort::PlainStruct: case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: { switch (getKind(manager, type)) { case StructKind::Empty: break; case StructKind::I32: buffer.append('i'); break; case StructKind::I64: buffer.append('j'); break; case StructKind::F32: buffer.append('f'); break; case StructKind::F64: buffer.append('d'); break; case StructKind::General: buffer.append("vi"); break; } break; } default: throw CannotDumpException("unexpected entity \"" + type + "\" in call to appendCallSignatureReturnType"); } } void appendCallSignatureParameter( OStringBuffer& buffer, rtl::Reference const& manager, unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction, OUString const& type) { if (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN) { switch (manager->getSort(resolveAllTypedefs(manager, type))) { case codemaker::UnoType::Sort::Boolean: case codemaker::UnoType::Sort::Byte: case codemaker::UnoType::Sort::Short: case codemaker::UnoType::Sort::UnsignedShort: case codemaker::UnoType::Sort::Long: case codemaker::UnoType::Sort::UnsignedLong: case codemaker::UnoType::Sort::Char: case codemaker::UnoType::Sort::Enum: case codemaker::UnoType::Sort::String: case codemaker::UnoType::Sort::Type: case codemaker::UnoType::Sort::Any: case codemaker::UnoType::Sort::Sequence: case codemaker::UnoType::Sort::PlainStruct: case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: case codemaker::UnoType::Sort::Interface: buffer.append('i'); break; case codemaker::UnoType::Sort::Hyper: case codemaker::UnoType::Sort::UnsignedHyper: buffer.append('j'); break; case codemaker::UnoType::Sort::Float: buffer.append('f'); break; case codemaker::UnoType::Sort::Double: buffer.append('d'); break; default: throw CannotDumpException("unexpected entity \"" + type + "\" in call to appendCallSignatureParameter"); } } else { buffer.append('i'); } } OString computeGetterCallSignature(rtl::Reference const& manager, unoidl::InterfaceTypeEntity::Attribute const& attribute) { OStringBuffer buf; appendCallSignatureReturnType(buf, manager, attribute.type); buf.append('i'); return buf.makeStringAndClear(); } OString computeSetterCallSignature(rtl::Reference const& manager, unoidl::InterfaceTypeEntity::Attribute const& attribute) { OStringBuffer buf("vi"); appendCallSignatureParameter( buf, manager, unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN, attribute.type); return buf.makeStringAndClear(); } OString computeMethodCallSignature(rtl::Reference const& manager, unoidl::InterfaceTypeEntity::Method const& method) { OStringBuffer buf; appendCallSignatureReturnType(buf, manager, method.returnType); buf.append('i'); for (auto const& param : method.parameters) { appendCallSignatureParameter(buf, manager, param.direction, param.type); } return buf.makeStringAndClear(); } void appendSlotSignatureOffsets(OStringBuffer& buffer, sal_Int32 functionOffset, sal_Int32 vtableOffset) { buffer.append(OString::number(functionOffset) + "_" + OString::number(vtableOffset)); } void appendSlotSignatureReturnType(OStringBuffer& buffer, rtl::Reference const& manager, OUString const& type) { switch (manager->getSort(resolveAllTypedefs(manager, type))) { case codemaker::UnoType::Sort::Void: buffer.append('v'); break; case codemaker::UnoType::Sort::Boolean: case codemaker::UnoType::Sort::Byte: case codemaker::UnoType::Sort::Short: case codemaker::UnoType::Sort::UnsignedShort: case codemaker::UnoType::Sort::Long: case codemaker::UnoType::Sort::UnsignedLong: case codemaker::UnoType::Sort::Char: case codemaker::UnoType::Sort::Enum: buffer.append('i'); break; case codemaker::UnoType::Sort::Hyper: case codemaker::UnoType::Sort::UnsignedHyper: buffer.append('j'); break; case codemaker::UnoType::Sort::Float: buffer.append('f'); break; case codemaker::UnoType::Sort::Double: buffer.append('d'); break; case codemaker::UnoType::Sort::String: case codemaker::UnoType::Sort::Type: case codemaker::UnoType::Sort::Any: case codemaker::UnoType::Sort::Sequence: case codemaker::UnoType::Sort::Interface: buffer.append('I'); break; case codemaker::UnoType::Sort::PlainStruct: case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: { switch (getKind(manager, type)) { case StructKind::Empty: break; case StructKind::I32: buffer.append('i'); break; case StructKind::I64: buffer.append('j'); break; case StructKind::F32: buffer.append('f'); break; case StructKind::F64: buffer.append('d'); break; case StructKind::General: buffer.append('I'); break; } break; } default: throw CannotDumpException("unexpected entity \"" + type + "\" in call to appendSlotSignatureReturnType"); } } void appendSlotSignatureParameter( OStringBuffer& buffer, rtl::Reference const& manager, unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction, OUString const& type) { if (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN) { switch (manager->getSort(resolveAllTypedefs(manager, type))) { case codemaker::UnoType::Sort::Boolean: case codemaker::UnoType::Sort::Byte: case codemaker::UnoType::Sort::Short: case codemaker::UnoType::Sort::UnsignedShort: case codemaker::UnoType::Sort::Long: case codemaker::UnoType::Sort::UnsignedLong: case codemaker::UnoType::Sort::Char: case codemaker::UnoType::Sort::Enum: case codemaker::UnoType::Sort::String: case codemaker::UnoType::Sort::Type: case codemaker::UnoType::Sort::Any: case codemaker::UnoType::Sort::Sequence: case codemaker::UnoType::Sort::PlainStruct: case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: case codemaker::UnoType::Sort::Interface: buffer.append('i'); break; case codemaker::UnoType::Sort::Hyper: case codemaker::UnoType::Sort::UnsignedHyper: buffer.append('j'); break; case codemaker::UnoType::Sort::Float: buffer.append('f'); break; case codemaker::UnoType::Sort::Double: buffer.append('d'); break; default: throw CannotDumpException("unexpected entity \"" + type + "\" in call to appendSlotSignatureParameter"); } } else { buffer.append('i'); } } OString computeGetterSlotSignature(rtl::Reference const& manager, unoidl::InterfaceTypeEntity::Attribute const& attribute, sal_Int32 functionOffset, sal_Int32 vtableOffset) { OStringBuffer buf; appendSlotSignatureOffsets(buf, functionOffset, vtableOffset); appendSlotSignatureReturnType(buf, manager, attribute.type); return buf.makeStringAndClear(); } OString computeSetterSlotSignature(rtl::Reference const& manager, unoidl::InterfaceTypeEntity::Attribute const& attribute, sal_Int32 functionOffset, sal_Int32 vtableOffset) { OStringBuffer buf; appendSlotSignatureOffsets(buf, functionOffset, vtableOffset); buf.append('v'); appendSlotSignatureParameter( buf, manager, unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN, attribute.type); return buf.makeStringAndClear(); } OString computeMethodSlotSignature(rtl::Reference const& manager, unoidl::InterfaceTypeEntity::Method const& method, sal_Int32 functionOffset, sal_Int32 vtableOffset) { OStringBuffer buf; appendSlotSignatureOffsets(buf, functionOffset, vtableOffset); appendSlotSignatureReturnType(buf, manager, method.returnType); for (auto const& param : method.parameters) { appendSlotSignatureParameter(buf, manager, param.direction, param.type); } return buf.makeStringAndClear(); } void computeSlotSignatures(rtl::Reference const& manager, unoidl::InterfaceTypeEntity const& interface, sal_Int32& functionOffset, sal_Int32& vtableOffset, std::set& slotSignatures) { auto const orgVtableOffset = vtableOffset; auto firstBase = true; for (auto const& base : interface.getDirectMandatoryBases()) { auto const ent = manager->getManager()->findEntity(base.name); if (!ent.is() || ent->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE) { throw CannotDumpException("unexpected base type \"" + base.name + "\" in call to computeSlotSignatures"); } sal_Int32 freshFunctionOffset = 0; computeSlotSignatures(manager, *static_cast(ent.get()), firstBase ? functionOffset : freshFunctionOffset, vtableOffset, slotSignatures); vtableOffset += 4; firstBase = false; } for (auto const& attr : interface.getDirectAttributes()) { slotSignatures.insert( computeGetterSlotSignature(manager, attr, functionOffset, orgVtableOffset)); ++functionOffset; if (!attr.readOnly) { slotSignatures.insert( computeSetterSlotSignature(manager, attr, functionOffset, orgVtableOffset)); ++functionOffset; } } for (auto const& meth : interface.getDirectMethods()) { slotSignatures.insert( computeMethodSlotSignature(manager, meth, functionOffset, orgVtableOffset)); ++functionOffset; } } void appendRttiSymbolSegment(OStringBuffer& buffer, OUString const& id) { OString s(OUStringToOString(id, RTL_TEXTENCODING_ASCII_US)); buffer.append(OString::number(s.getLength()) + s); } OString computeRttiSymbol(std::vector const& path, OUString const& id) { OStringBuffer buf("__ZTI"); if (!path.empty()) { buf.append('N'); for (auto const& i : path) { appendRttiSymbolSegment(buf, i); } } appendRttiSymbolSegment(buf, id); if (!path.empty()) { buf.append('E'); } return buf.makeStringAndClear(); } void scan(rtl::Reference const& manager, rtl::Reference const& cursor, std::vector& path, std::set& callSignatures, std::set& slotSignatures, std::set& rttis) { assert(cursor.is()); for (;;) { OUString id; auto const ent = cursor->getNext(&id); if (!ent.is()) { break; } switch (ent->getSort()) { case unoidl::Entity::SORT_MODULE: path.push_back(id); scan(manager, static_cast(ent.get())->createCursor(), path, callSignatures, slotSignatures, rttis); path.pop_back(); break; case unoidl::Entity::SORT_EXCEPTION_TYPE: rttis.insert(computeRttiSymbol(path, id)); break; case unoidl::Entity::SORT_INTERFACE_TYPE: { auto const ite = static_cast(ent.get()); for (auto const& attr : ite->getDirectAttributes()) { callSignatures.insert(computeGetterCallSignature(manager, attr)); if (!attr.readOnly) { callSignatures.insert(computeSetterCallSignature(manager, attr)); } } for (auto const& meth : ite->getDirectMethods()) { callSignatures.insert(computeMethodCallSignature(manager, meth)); } computeSlotSignatures(manager, *ite, o3tl::temporary(0), o3tl::temporary(0), slotSignatures); break; } default: break; } } } } SAL_IMPLEMENT_MAIN() { try { auto const args = rtl_getAppCommandArgCount(); if (args < 3) { badUsage(); } auto const cppPathname = getPathnameArgument(0); auto const asmPathname = getPathnameArgument(1); auto const expPathname = getPathnameArgument(2); rtl::Reference mgr(new TypeManager); for (sal_uInt32 i = 3; i != args; ++i) { auto const & [ uri, primary ] = parseRegistryArgument(i); try { mgr->loadProvider(uri, primary); } catch (unoidl::NoSuchFileException&) { std::cerr << "Input <" << uri << "> does not exist\n"; std::exit(EXIT_FAILURE); } } std::vector path; std::set callSignatures; std::set slotSignatures; std::set rttis; for (auto const& prov : mgr->getPrimaryProviders()) { scan(mgr, prov->createRootCursor(), path, callSignatures, slotSignatures, rttis); } std::ofstream cppOut(cppPathname, std::ios_base::out | std::ios_base::trunc); if (!cppOut) { std::cerr << "Cannot open \"" << cppPathname << "\" for writing\n"; std::exit(EXIT_FAILURE); } cppOut << "#include \n" "#include \n" "#include \n" "#include \n" "#include \n" "#include \n" "#include \n"; for (auto const& sig : callSignatures) { cppOut << "extern \"C\" void callVirtualFunction_" << sig << "(sal_uInt32 target, sal_uInt64 const * arguments, void * returnValue);\n"; } cppOut << "void callVirtualFunction(std::string_view signature, sal_uInt32 target, " "sal_uInt64 const * arguments, void * returnValue) {\n"; for (auto const& sig : callSignatures) { cppOut << " if (signature == \"" << sig << "\") {\n" << " callVirtualFunction_" << sig << "(target, arguments, returnValue);\n" << " return;\n" << " }\n"; } cppOut << " throw css::uno::RuntimeException(\"Wasm bridge cannot call virtual function " "with signature \" + OUString::fromUtf8(signature));\n" "}\n"; if (!slotSignatures.empty()) { cppOut << "namespace {\n"; } for (auto const& sig : slotSignatures) { auto const i1 = sig.indexOf('_'); assert(i1 != -1); sal_Int32 i2 = i1 + 1; for (;; ++i2) { assert(i2 < sig.getLength()); if (!rtl::isAsciiDigit(static_cast(sig[i2]))) { break; } } assert(i2 != i1); cppOut << "extern \"C\" "; switch (sig[i2]) { case 'd': cppOut << "double"; break; case 'f': cppOut << "float"; break; case 'i': cppOut << "unsigned"; break; case 'j': cppOut << "unsigned long long"; break; default: cppOut << "void"; break; } cppOut << " vtableSlotFunction_" << sig << "("; if (sig[i2] == 'I') { cppOut << "unsigned indirectRet, "; } cppOut << "unsigned thisPtr"; for (sal_Int32 i = i2 + 1; i != sig.getLength(); ++i) { cppOut << ", "; switch (sig[i]) { case 'd': cppOut << "double"; break; case 'f': cppOut << "float"; break; case 'i': cppOut << "unsigned"; break; case 'j': cppOut << "unsigned long long"; break; default: O3TL_UNREACHABLE; } cppOut << " arg" << (i - i2); } cppOut << ") { "; switch (sig[i2]) { case 'd': cppOut << "return std::bit_cast(static_cast("; break; case 'f': cppOut << "return std::bit_cast(static_cast("; break; case 'i': cppOut << "return static_cast("; break; case 'j': cppOut << "return static_cast("; break; } cppOut << "vtableCall(" << sig.subView(0, i1) << ", " << sig.subView(i1 + 1, i2 - (i1 + 1)) << ", thisPtr, {"; for (sal_Int32 i = i2 + 1; i != sig.getLength(); ++i) { if (i != i2 + 1) { cppOut << ", "; } cppOut << "sal_uInt64("; switch (sig[i]) { case 'd': cppOut << "std::bit_cast("; break; case 'f': cppOut << "std::bit_cast("; break; } cppOut << "arg" << (i - i2) << ")"; switch (sig[i]) { case 'd': case 'f': cppOut << ")"; break; } } cppOut << "}, " << (sig[i2] == 'I' ? "indirectRet" : "reinterpret_cast(nullptr)") << ")"; switch (sig[i2]) { case 'd': case 'f': cppOut << "))"; break; case 'i': case 'j': cppOut << ")"; break; } cppOut << "; }\n"; } if (!slotSignatures.empty()) { cppOut << "}\n"; } cppOut << "void const * getVtableSlotFunction(std::string_view signature) {\n"; for (auto const& sig : slotSignatures) { cppOut << " if (signature == \"" << sig << "\") {\n" << " return reinterpret_cast(vtableSlotFunction_" << sig << ");\n" << " }\n"; } cppOut << " throw css::uno::RuntimeException(\"Wasm bridge cannot fill virtual function " "slot with signature \" + OUString::fromUtf8(signature));\n" "}\n"; cppOut.close(); if (!cppOut) { std::cerr << "Failed to write \"" << cppPathname << "\"\n"; std::exit(EXIT_FAILURE); } std::ofstream asmOut(asmPathname, std::ios_base::out | std::ios_base::trunc); if (!asmOut) { std::cerr << "Cannot open \"" << asmPathname << "\" for writing\n"; std::exit(EXIT_FAILURE); } asmOut << "\t.text\n" "\t.tabletype __indirect_function_table, funcref\n"; for (auto const& sig : callSignatures) { asmOut << "\t.functype callVirtualFunction_" << sig << " (i32, i32, i32) -> ()\n"; } for (auto const& sig : callSignatures) { asmOut << "\t.section .text.callVirtualFunction_" << sig << ",\"\",@\n" "\t.globl callVirtualFunction_" << sig << "\n" "\t.type callVirtualFunction_" << sig << ",@function\n" "callVirtualFunction_" << sig << ":\n" "\t.functype callVirtualFunction_" << sig << " (i32, i32, i32) -> ()\n"; if (sig[0] != 'v') { asmOut << "\tlocal.get 2\n"; } unsigned off = 0; for (auto c : sig.subView(1)) { asmOut << "\tlocal.get 1\n" "\t"; switch (c) { case 'd': asmOut << "f64"; break; case 'f': asmOut << "f32"; break; case 'i': asmOut << "i32"; break; case 'j': asmOut << "i64"; break; default: assert(false); } asmOut << ".load " << off << "\n"; off += 8; //TODO: overflow } asmOut << "\tlocal.get 0\n" "\tcall_indirect ("; auto first = true; for (auto c : sig.subView(1)) { if (first) { first = false; } else { asmOut << ", "; } switch (c) { case 'd': asmOut << "f64"; break; case 'f': asmOut << "f32"; break; case 'i': asmOut << "i32"; break; case 'j': asmOut << "i64"; break; default: assert(false); } } asmOut << ") -> ("; switch (sig[0]) { case 'd': asmOut << "f64"; break; case 'f': asmOut << "f32"; break; case 'i': asmOut << "i32"; break; case 'j': asmOut << "i64"; break; case 'v': break; default: assert(false); } asmOut << ")\n"; if (sig[0] != 'v') { asmOut << "\t"; switch (sig[0]) { case 'd': asmOut << "f64"; break; case 'f': asmOut << "f32"; break; case 'i': asmOut << "i32"; break; case 'j': asmOut << "i64"; break; default: assert(false); } asmOut << ".store 0\n"; } asmOut << "\tend_function\n"; } asmOut.close(); if (!asmOut) { std::cerr << "Failed to write \"" << asmPathname << "\"\n"; std::exit(EXIT_FAILURE); } std::ofstream expOut(expPathname, std::ios_base::out | std::ios_base::trunc); if (!expOut) { std::cerr << "Cannot open \"" << expPathname << "\" for writing\n"; std::exit(EXIT_FAILURE); } for (auto const& rtti : rttis) { expOut << rtti.getStr() << "\n"; } expOut.close(); if (!expOut) { std::cerr << "Failed to write \"" << expPathname << "\"\n"; std::exit(EXIT_FAILURE); } return EXIT_SUCCESS; } catch (unoidl::FileFormatException const& e) { std::cerr << "Bad input <" << e.getUri() << ">: " << e.getDetail() << "\n"; std::exit(EXIT_FAILURE); } catch (CannotDumpException const& e) { std::cerr << "Failure: " << e.getMessage() << "\n"; std::exit(EXIT_FAILURE); } catch (std::exception const& e) { std::cerr << "Failure: " << e.what() << "\n"; std::exit(EXIT_FAILURE); } } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */