summaryrefslogtreecommitdiff
path: root/static
diff options
context:
space:
mode:
authorStephan Bergmann <stephan.bergmann@allotropia.de>2024-01-30 13:32:26 +0100
committerStephan Bergmann <stephan.bergmann@allotropia.de>2024-01-30 22:18:15 +0100
commit7e0a4322147892021f3d93fb8de23ed293d575a7 (patch)
tree5a25d7ee01205079d61cf97eb6b10884f098c641 /static
parent82e90e1b2a8873334f1fcd00dde769e45af37b5b (diff)
embindmaker: Handle interface inheritance
Change-Id: I81e66666f8a60bd34a9a3807adfb15c341303b9a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162771 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
Diffstat (limited to 'static')
-rw-r--r--static/source/embindmaker/embindmaker.cxx174
1 files changed, 148 insertions, 26 deletions
diff --git a/static/source/embindmaker/embindmaker.cxx b/static/source/embindmaker/embindmaker.cxx
index 0da6ce2ad41c..2c707f9f118a 100644
--- a/static/source/embindmaker/embindmaker.cxx
+++ b/static/source/embindmaker/embindmaker.cxx
@@ -10,13 +10,16 @@
#include <sal/config.h>
#include <cassert>
+#include <cstddef>
#include <cstdlib>
#include <fstream>
#include <ios>
#include <iostream>
+#include <list>
#include <map>
#include <memory>
#include <ostream>
+#include <set>
#include <string>
#include <string_view>
#include <utility>
@@ -159,21 +162,6 @@ OUString cppName(OUString const& name) { return "::" + name.replaceAll(u".", u":
OUString jsName(OUString const& name) { return name.replace('.', '$'); }
-void dumpAttributes(std::ostream& out, OUString const& name,
- rtl::Reference<unoidl::InterfaceTypeEntity> const& entity)
-{
- for (auto const& attr : entity->getDirectAttributes())
- {
- out << " .function(\"get" << attr.name << "\", &" << cppName(name) << "::get"
- << attr.name << ")\n";
- if (!attr.readOnly)
- {
- out << " .function(\"set" << attr.name << "\", &" << cppName(name) << "::set"
- << attr.name << ")\n";
- }
- }
-}
-
OUString resolveOuterTypedefs(rtl::Reference<TypeManager> const& manager, OUString const& name)
{
for (OUString n(name);;)
@@ -346,6 +334,66 @@ void dumpType(std::ostream& out, rtl::Reference<TypeManager> const& manager,
}
}
+void dumpAttributes(std::ostream& out, rtl::Reference<TypeManager> const& manager,
+ OUString const& name, rtl::Reference<unoidl::InterfaceTypeEntity> const& entity,
+ std::list<OUString> const& baseTrail)
+{
+ for (auto const& attr : entity->getDirectAttributes())
+ {
+ out << " .function(\"get" << attr.name << "\", ";
+ if (baseTrail.empty())
+ {
+ out << "&" << cppName(name) << "::get" << attr.name;
+ }
+ else
+ {
+ out << "+[](::com::sun::star::uno::Reference<" << cppName(name)
+ << "> const & the_self) { return ";
+ for (auto const& base : baseTrail)
+ {
+ out << "static_cast<" << cppName(base) << " *>(";
+ }
+ out << "the_self.get()";
+ for (std::size_t i = 0; i != baseTrail.size(); ++i)
+ {
+ out << ")";
+ }
+ out << "->get" << attr.name << "(); }";
+ }
+ out << ")\n";
+ if (!attr.readOnly)
+ {
+ out << " .function(\"set" << attr.name << "\", ";
+ if (baseTrail.empty())
+ {
+ out << "&" << cppName(name) << "::set" << attr.name;
+ }
+ else
+ {
+ out << "+[](::com::sun::star::uno::Reference<" << cppName(name)
+ << "> const & the_self, ";
+ dumpType(out, manager, attr.type, false);
+ if (passByReference(manager, attr.type))
+ {
+ out << " const &";
+ }
+ out << " the_value) { ";
+ for (auto const& base : baseTrail)
+ {
+ out << "static_cast<" << cppName(base) << " *>(";
+ }
+ out << "the_self.get()";
+ for (std::size_t i = 0; i != baseTrail.size(); ++i)
+ {
+ out << ")";
+ }
+ out << "->set" << attr.name << "(the_value); }";
+ }
+ out << ")\n";
+ }
+ }
+}
+
void dumpParameters(std::ostream& out, rtl::Reference<TypeManager> const& manager,
unoidl::InterfaceTypeEntity::Method const& method, bool declarations)
{
@@ -391,7 +439,8 @@ void dumpParameters(std::ostream& out, rtl::Reference<TypeManager> const& manage
}
void dumpWrapper(std::ostream& out, rtl::Reference<TypeManager> const& manager,
- OUString const& interfaceName, unoidl::InterfaceTypeEntity::Method const& method)
+ OUString const& interfaceName, unoidl::InterfaceTypeEntity::Method const& method,
+ std::list<OUString> const& baseTrail)
{
out << " .function(\"" << method.name << "\", +[](" << cppName(interfaceName);
out << " * the_self";
@@ -400,22 +449,35 @@ void dumpWrapper(std::ostream& out, rtl::Reference<TypeManager> const& manager,
out << ", ";
}
dumpParameters(out, manager, method, true);
- out << ") { return the_self->" << method.name << "(";
+ out << ") { return ";
+ for (auto const& base : baseTrail)
+ {
+ out << "static_cast<" << cppName(base) << " *>(";
+ }
+ out << "the_self";
+ for (std::size_t i = 0; i != baseTrail.size(); ++i)
+ {
+ out << ")";
+ }
+ out << "->" << method.name << "(";
dumpParameters(out, manager, method, false);
out << "); }, ::emscripten::allow_raw_pointers())\n";
}
void dumpMethods(std::ostream& out, rtl::Reference<TypeManager> const& manager,
- OUString const& name, rtl::Reference<unoidl::InterfaceTypeEntity> const& entity)
+ OUString const& name, rtl::Reference<unoidl::InterfaceTypeEntity> const& entity,
+ std::list<OUString> const& baseTrail)
{
for (auto const& meth : entity->getDirectMethods())
{
- if (std::any_of(meth.parameters.begin(), meth.parameters.end(), [](auto const& parameter) {
- return parameter.direction
- != unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN;
- }))
+ if (!baseTrail.empty()
+ || std::any_of(
+ meth.parameters.begin(), meth.parameters.end(), [](auto const& parameter) {
+ return parameter.direction
+ != unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN;
+ }))
{
- dumpWrapper(out, manager, name, meth);
+ dumpWrapper(out, manager, name, meth, baseTrail);
}
else
{
@@ -425,6 +487,48 @@ void dumpMethods(std::ostream& out, rtl::Reference<TypeManager> const& manager,
}
}
+rtl::Reference<unoidl::InterfaceTypeEntity> resolveBase(rtl::Reference<TypeManager> const& manager,
+ OUString const& name)
+{
+ auto const ent = manager->getManager()->findEntity(name);
+ if (!ent.is() || ent->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE)
+ {
+ throw CannotDumpException("bad interface base \"" + name + "\"");
+ }
+ return static_cast<unoidl::InterfaceTypeEntity*>(ent.get());
+}
+
+void recordVisitedBases(rtl::Reference<TypeManager> const& manager, OUString const& name,
+ std::set<OUString>& visitedBases)
+{
+ auto const ent = resolveBase(manager, name);
+ for (auto const& base : ent->getDirectMandatoryBases())
+ {
+ if (visitedBases.insert(base.name).second)
+ {
+ recordVisitedBases(manager, base.name, visitedBases);
+ }
+ }
+}
+
+void dumpBase(std::ostream& out, rtl::Reference<TypeManager> const& manager,
+ OUString const& interface, OUString const& name, std::set<OUString>& visitedBases,
+ std::list<OUString> const& baseTrail)
+{
+ auto const ent = resolveBase(manager, name);
+ for (auto const& base : ent->getDirectMandatoryBases())
+ {
+ if (visitedBases.insert(base.name).second)
+ {
+ auto trail = baseTrail;
+ trail.push_front(base.name);
+ dumpBase(out, manager, interface, base.name, visitedBases, trail);
+ }
+ }
+ dumpAttributes(out, manager, interface, ent, baseTrail);
+ dumpMethods(out, manager, interface, ent, baseTrail);
+}
+
void writeJsMap(std::ostream& out, Module const& module, std::string const& prefix)
{
auto comma = false;
@@ -524,7 +628,16 @@ SAL_IMPLEMENT_MAIN()
cppOut << "static void __attribute__((noinline)) register" << n
<< "() {\n"
" ::emscripten::class_<"
- << cppName(ifc) << ">(\"uno_Type_" << jsName(ifc)
+ << cppName(ifc);
+ //TODO: Embind only supports single inheritance, so use that support at least for a UNO
+ // interface's first base, and explicitly spell out the attributes and methods of any
+ // remaining bases:
+ auto const& bases = ifcEnt->getDirectMandatoryBases();
+ if (bases.size() != 0)
+ {
+ cppOut << ", ::emscripten::base<" << cppName(bases[0].name) << ">";
+ }
+ cppOut << ">(\"uno_Type_" << jsName(ifc)
<< "\")\n"
" .smart_ptr<::com::sun::star::uno::Reference<"
<< cppName(ifc) << ">>(\"uno_Reference_" << jsName(ifc)
@@ -547,8 +660,17 @@ SAL_IMPLEMENT_MAIN()
<< "> const & the_self) { return "
"::com::sun::star::uno::Reference<::com::sun::star::uno::XInterface>(the_"
"self); })\n";
- dumpAttributes(cppOut, ifc, ifcEnt);
- dumpMethods(cppOut, mgr, ifc, ifcEnt);
+ if (bases.size() > 1)
+ {
+ std::set<OUString> visitedBases;
+ recordVisitedBases(mgr, bases[0].name, visitedBases);
+ for (std::size_t i = 1; i != bases.size(); ++i)
+ {
+ dumpBase(cppOut, mgr, ifc, bases[i].name, visitedBases, { bases[i].name });
+ }
+ }
+ dumpAttributes(cppOut, mgr, ifc, ifcEnt, {});
+ dumpMethods(cppOut, mgr, ifc, ifcEnt, {});
cppOut << " ;\n"
"}\n";
++n;