1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <sal/config.h>
24 #include <string_view>
28 #include <codemaker/commoncpp.hxx>
29 #include <codemaker/global.hxx>
30 #include <codemaker/typemanager.hxx>
31 #include <osl/file.hxx>
32 #include <osl/process.h>
33 #include <osl/thread.h>
34 #include <rtl/process.h>
35 #include <rtl/ref.hxx>
36 #include <rtl/string.hxx>
37 #include <rtl/textcvt.h>
38 #include <rtl/ustrbuf.hxx>
39 #include <rtl/ustring.hxx>
41 #include <sal/types.h>
42 #include <unoidl/unoidl.hxx>
50 " embindmaker <name> <cpp-output> <hpp-output> <js-output> <registries>\n\n"
51 "where each <registry> is '+' (primary) or ':' (secondary), followed by: either a\n"
52 "new- or legacy-format .rdb file, a single .idl file, or a root directory of an\n"
53 ".idl file tree. For all primary registries, Embind code is written to\n"
54 "<cpp-output>/<hpp-output> and corresponding JavaScript scaffolding code is\n"
55 "written to <js-output>. The <name> is used as part of some of the identifiers\n"
56 "in those generated files.\n";
57 std::exit(EXIT_FAILURE
);
60 std::string
getPathnameArgument(sal_uInt32 argument
)
63 rtl_getAppCommandArg(argument
, &arg
.pData
);
65 auto const enc
= osl_getThreadTextEncoding();
66 if (!arg
.convertToString(&path
, enc
,
67 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
68 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
))
70 std::cerr
<< "Cannot convert \"" << arg
<< "\" to system encoding " << enc
<< "\n";
71 std::exit(EXIT_FAILURE
);
73 return std::string(path
);
76 std::pair
<OUString
, bool> parseRegistryArgument(sal_uInt32 argument
)
79 rtl_getAppCommandArg(argument
, &arg
.pData
);
81 if (arg
.startsWith(u
"+", &arg
))
85 else if (arg
.startsWith(u
":", &arg
))
91 std::cerr
<< "Bad registry argument \"" << arg
<< "\"\n";
92 std::exit(EXIT_FAILURE
);
95 auto const e1
= osl::FileBase::getFileURLFromSystemPath(arg
, url
);
96 if (e1
!= osl::FileBase::E_None
)
98 std::cerr
<< "Cannot convert \"" << arg
<< "\" to file URL, error code " << +e1
<< "\n";
99 std::exit(EXIT_FAILURE
);
102 auto const e2
= osl_getProcessWorkingDir(&cwd
.pData
);
103 if (e2
!= osl_Process_E_None
)
105 std::cerr
<< "Cannot obtain working directory, error code " << +e2
<< "\n";
106 std::exit(EXIT_FAILURE
);
109 auto const e3
= osl::FileBase::getAbsoluteFileURL(cwd
, url
, abs
);
110 if (e3
!= osl::FileBase::E_None
)
112 std::cerr
<< "Cannot make \"" << url
<< "\" into an absolute file URL, error code " << +e3
114 std::exit(EXIT_FAILURE
);
116 return { abs
, primary
};
121 std::map
<OUString
, std::shared_ptr
<Module
>> modules
;
122 std::vector
<std::pair
<OUString
, OUString
>> mappings
;
126 getServiceConstructorName(unoidl::SingleInterfaceBasedServiceEntity::Constructor
const& constructor
)
128 return constructor
.defaultConstructor
? u
"create"_ustr
: constructor
.name
;
131 OUString
jsName(OUString
const& name
) { return name
.replace('.', '$'); }
134 jsServiceConstructor(OUString
const& service
,
135 unoidl::SingleInterfaceBasedServiceEntity::Constructor
const& constructor
)
137 return "uno_Function_" + jsName(service
) + "$$" + getServiceConstructorName(constructor
);
140 OUString
jsSingleton(OUString
const& singleton
) { return "uno_Function_" + jsName(singleton
); }
142 void scan(rtl::Reference
<unoidl::MapCursor
> const& cursor
, std::u16string_view prefix
,
143 Module
* module
, std::vector
<OUString
>& enums
, std::vector
<OUString
>& structs
,
144 std::vector
<OUString
>& exceptions
, std::vector
<OUString
>& interfaces
,
145 std::vector
<OUString
>& services
, std::vector
<OUString
>& singletons
)
148 assert(module
!= nullptr);
152 auto const ent
= cursor
->getNext(&id
);
157 OUString
name(prefix
+ id
);
158 switch (ent
->getSort())
160 case unoidl::Entity::SORT_MODULE
:
162 auto& sub
= module
->modules
[id
];
165 sub
= std::make_shared
<Module
>();
167 scan(static_cast<unoidl::ModuleEntity
*>(ent
.get())->createCursor(),
168 Concat2View(name
+ "."), sub
.get(), enums
, structs
, exceptions
, interfaces
,
169 services
, singletons
);
172 case unoidl::Entity::SORT_ENUM_TYPE
:
173 module
->mappings
.emplace_back(id
, "instance.uno_Type_" + jsName(name
));
174 enums
.emplace_back(name
);
176 case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE
:
177 module
->mappings
.emplace_back(id
, "instance.uno_Type_" + jsName(name
));
178 structs
.emplace_back(name
);
180 case unoidl::Entity::SORT_EXCEPTION_TYPE
:
181 module
->mappings
.emplace_back(id
, "instance.uno_Type_" + jsName(name
));
182 exceptions
.emplace_back(name
);
184 case unoidl::Entity::SORT_INTERFACE_TYPE
:
185 module
->mappings
.emplace_back(id
, "instance.uno_Type_" + jsName(name
));
186 interfaces
.emplace_back(name
);
188 case unoidl::Entity::SORT_CONSTANT_GROUP
:
191 = static_cast<unoidl::ConstantGroupEntity
*>(ent
.get())->getMembers();
192 if (!members
.empty())
194 auto sub
= std::make_shared
<Module
>();
195 for (auto const& member
: members
)
198 switch (member
.value
.type
)
200 case unoidl::ConstantValue::TYPE_BOOLEAN
:
201 value
= member
.value
.booleanValue
? u
"true"_ustr
: u
"false"_ustr
;
203 case unoidl::ConstantValue::TYPE_BYTE
:
204 value
= OUString::number(member
.value
.byteValue
);
206 case unoidl::ConstantValue::TYPE_SHORT
:
207 value
= OUString::number(member
.value
.shortValue
);
209 case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT
:
210 value
= OUString::number(member
.value
.unsignedShortValue
);
212 case unoidl::ConstantValue::TYPE_LONG
:
213 value
= OUString::number(member
.value
.longValue
);
215 case unoidl::ConstantValue::TYPE_UNSIGNED_LONG
:
216 value
= OUString::number(member
.value
.unsignedLongValue
);
218 case unoidl::ConstantValue::TYPE_HYPER
:
219 value
= OUString::number(member
.value
.hyperValue
) + "n";
221 case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER
:
222 value
= OUString::number(member
.value
.unsignedHyperValue
) + "n";
224 case unoidl::ConstantValue::TYPE_FLOAT
:
225 value
= OUString::number(member
.value
.floatValue
);
227 case unoidl::ConstantValue::TYPE_DOUBLE
:
228 value
= OUString::number(member
.value
.doubleValue
);
231 sub
->mappings
.emplace_back(member
.name
, value
);
233 module
->modules
[id
] = sub
;
237 case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE
:
240 = static_cast<unoidl::SingleInterfaceBasedServiceEntity
*>(ent
.get())
244 auto sub
= std::make_shared
<Module
>();
245 for (auto const& ctor
: ctors
)
247 sub
->mappings
.emplace_back(getServiceConstructorName(ctor
),
248 "instance." + jsServiceConstructor(name
, ctor
));
250 module
->modules
[id
] = sub
;
251 services
.emplace_back(name
);
255 case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON
:
256 module
->mappings
.emplace_back(id
, "instance." + jsSingleton(name
));
257 singletons
.emplace_back(name
);
265 OUString
cppName(OUString
const& name
) { return "::" + name
.replaceAll(u
".", u
"::"); }
267 OUString
resolveOuterTypedefs(rtl::Reference
<TypeManager
> const& manager
, OUString
const& name
)
269 for (OUString
n(name
);;)
271 rtl::Reference
<unoidl::Entity
> ent
;
272 if (manager
->getSort(n
, &ent
) != codemaker::UnoType::Sort::Typedef
)
276 n
= dynamic_cast<unoidl::TypedefEntity
&>(*ent
).getType();
280 OUString
resolveAllTypedefs(rtl::Reference
<TypeManager
> const& manager
, std::u16string_view name
)
283 OUString
n(b2u(codemaker::UnoType::decompose(u2b(name
), &k1
)));
286 rtl::Reference
<unoidl::Entity
> ent
;
287 if (manager
->getSort(n
, &ent
) != codemaker::UnoType::Sort::Typedef
)
292 n
= b2u(codemaker::UnoType::decompose(
293 u2b(static_cast<unoidl::TypedefEntity
*>(ent
.get())->getType()), &k2
));
294 k1
+= k2
; //TODO: overflow
297 for (sal_Int32 i
= 0; i
!= k1
; ++i
)
302 return b
.makeStringAndClear();
305 bool passByReference(rtl::Reference
<TypeManager
> const& manager
, OUString
const& name
)
307 switch (manager
->getSort(resolveOuterTypedefs(manager
, name
)))
309 case codemaker::UnoType::Sort::Boolean
:
310 case codemaker::UnoType::Sort::Byte
:
311 case codemaker::UnoType::Sort::Short
:
312 case codemaker::UnoType::Sort::UnsignedShort
:
313 case codemaker::UnoType::Sort::Long
:
314 case codemaker::UnoType::Sort::UnsignedLong
:
315 case codemaker::UnoType::Sort::Hyper
:
316 case codemaker::UnoType::Sort::UnsignedHyper
:
317 case codemaker::UnoType::Sort::Float
:
318 case codemaker::UnoType::Sort::Double
:
319 case codemaker::UnoType::Sort::Char
:
320 case codemaker::UnoType::Sort::Enum
:
322 case codemaker::UnoType::Sort::String
:
323 case codemaker::UnoType::Sort::Type
:
324 case codemaker::UnoType::Sort::Any
:
325 case codemaker::UnoType::Sort::Sequence
:
326 case codemaker::UnoType::Sort::PlainStruct
:
327 case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct
:
328 case codemaker::UnoType::Sort::Interface
:
331 throw CannotDumpException("unexpected entity \"" + name
332 + "\" in call to passByReference");
336 void dumpType(std::ostream
& out
, rtl::Reference
<TypeManager
> const& manager
,
337 std::u16string_view name
)
340 std::vector
<OString
> args
;
342 b2u(codemaker::UnoType::decompose(u2b(resolveAllTypedefs(manager
, name
)), &k
, &args
)));
343 for (sal_Int32 i
= 0; i
!= k
; ++i
)
345 out
<< "::com::sun::star::uno::Sequence<";
347 switch (manager
->getSort(n
))
349 case codemaker::UnoType::Sort::Void
:
352 case codemaker::UnoType::Sort::Boolean
:
355 case codemaker::UnoType::Sort::Byte
:
358 case codemaker::UnoType::Sort::Short
:
359 out
<< "::sal_Int16";
361 case codemaker::UnoType::Sort::UnsignedShort
:
362 out
<< "::sal_uInt16";
364 case codemaker::UnoType::Sort::Long
:
365 out
<< "::sal_Int32";
367 case codemaker::UnoType::Sort::UnsignedLong
:
368 out
<< "::sal_uInt32";
370 case codemaker::UnoType::Sort::Hyper
:
371 out
<< "::sal_Int64";
373 case codemaker::UnoType::Sort::UnsignedHyper
:
374 out
<< "::sal_uInt64";
376 case codemaker::UnoType::Sort::Float
:
379 case codemaker::UnoType::Sort::Double
:
382 case codemaker::UnoType::Sort::Char
:
383 out
<< "::sal_Unicode";
385 case codemaker::UnoType::Sort::String
:
386 out
<< "::rtl::OUString";
388 case codemaker::UnoType::Sort::Type
:
389 out
<< "::com::sun::star::uno::Type";
391 case codemaker::UnoType::Sort::Any
:
392 out
<< "::com::sun::star::uno::Any";
394 case codemaker::UnoType::Sort::Enum
:
395 case codemaker::UnoType::Sort::PlainStruct
:
396 case codemaker::UnoType::Sort::Exception
:
399 case codemaker::UnoType::Sort::PolymorphicStructTemplate
:
405 for (auto const& arg
: args
)
415 dumpType(out
, manager
, b2u(arg
));
420 case codemaker::UnoType::Sort::Interface
:
421 out
<< "::com::sun::star::uno::Reference<";
426 throw CannotDumpException(OUString::Concat("unexpected entity \"") + name
427 + "\" in call to dumpType");
429 for (sal_Int32 i
= 0; i
!= k
; ++i
)
435 void dumpStructMembers(std::ostream
& out
, rtl::Reference
<TypeManager
> const& manager
,
436 OUString
const& name
, rtl::Reference
<unoidl::PlainStructTypeEntity
> struc
)
438 auto const& base
= struc
->getDirectBase();
441 auto const ent
= manager
->getManager()->findEntity(base
);
442 if (!ent
.is() || ent
->getSort() != unoidl::Entity::SORT_PLAIN_STRUCT_TYPE
)
444 throw CannotDumpException("bad struct base \"" + base
+ "\"");
446 dumpStructMembers(out
, manager
, name
,
447 static_cast<unoidl::PlainStructTypeEntity
*>(ent
.get()));
449 for (auto const& mem
: struc
->getDirectMembers())
451 out
<< "\n .field(\"" << mem
.name
<< "\", &" << cppName(name
) << "::" << mem
.name
456 void dumpExceptionMembers(std::ostream
& out
, rtl::Reference
<TypeManager
> const& manager
,
457 OUString
const& name
,
458 rtl::Reference
<unoidl::ExceptionTypeEntity
> exception
)
460 auto const& base
= exception
->getDirectBase();
463 auto const ent
= manager
->getManager()->findEntity(base
);
464 if (!ent
.is() || ent
->getSort() != unoidl::Entity::SORT_EXCEPTION_TYPE
)
466 throw CannotDumpException("bad exception base \"" + base
+ "\"");
468 dumpExceptionMembers(out
, manager
, name
,
469 static_cast<unoidl::ExceptionTypeEntity
*>(ent
.get()));
471 for (auto const& mem
: exception
->getDirectMembers())
473 out
<< "\n .field(\"" << mem
.name
<< "\", &" << cppName(name
) << "::" << mem
.name
478 void dumpAttributes(std::ostream
& out
, rtl::Reference
<TypeManager
> const& manager
,
479 OUString
const& name
, rtl::Reference
<unoidl::InterfaceTypeEntity
> const& entity
,
480 std::list
<OUString
> const& baseTrail
)
482 for (auto const& attr
: entity
->getDirectAttributes())
484 out
<< " .function(\"get" << attr
.name
<< "\", ";
485 if (baseTrail
.empty())
487 out
<< "&" << cppName(name
) << "::get" << attr
.name
;
491 out
<< "+[](::com::sun::star::uno::Reference<" << cppName(name
)
492 << "> const & the_self) { return ";
493 for (auto const& base
: baseTrail
)
495 out
<< "static_cast<" << cppName(base
) << " *>(";
497 out
<< "the_self.get()";
498 for (std::size_t i
= 0; i
!= baseTrail
.size(); ++i
)
502 out
<< "->get" << attr
.name
<< "(); }";
504 out
<< ", ::emscripten::pure_virtual())\n";
507 out
<< " .function(\"set" << attr
.name
<< "\", ";
508 if (baseTrail
.empty())
510 out
<< "&" << cppName(name
) << "::set" << attr
.name
;
514 out
<< "+[](::com::sun::star::uno::Reference<" << cppName(name
)
515 << "> const & the_self, ";
516 dumpType(out
, manager
, attr
.type
);
517 if (passByReference(manager
, attr
.type
))
521 out
<< " the_value) { ";
522 for (auto const& base
: baseTrail
)
524 out
<< "static_cast<" << cppName(base
) << " *>(";
526 out
<< "the_self.get()";
527 for (std::size_t i
= 0; i
!= baseTrail
.size(); ++i
)
531 out
<< "->set" << attr
.name
<< "(the_value); }";
533 out
<< ", ::emscripten::pure_virtual())\n";
538 bool hasInOutParameters(unoidl::InterfaceTypeEntity::Method
const& method
)
540 return std::any_of(method
.parameters
.begin(), method
.parameters
.end(),
541 [](auto const& parameter
) {
542 return parameter
.direction
543 != unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN
;
547 void dumpParameters(std::ostream
& out
, rtl::Reference
<TypeManager
> const& manager
,
548 unoidl::InterfaceTypeEntity::Method
const& method
, bool declarations
)
551 for (auto const& param
: method
.parameters
)
562 if (param
.direction
!= unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN
)
564 switch (manager
->getSort(resolveOuterTypedefs(manager
, param
.type
)))
566 case codemaker::UnoType::Sort::Boolean
:
567 case codemaker::UnoType::Sort::Byte
:
568 case codemaker::UnoType::Sort::Short
:
569 case codemaker::UnoType::Sort::UnsignedShort
:
570 case codemaker::UnoType::Sort::Long
:
571 case codemaker::UnoType::Sort::UnsignedLong
:
572 case codemaker::UnoType::Sort::Hyper
:
573 case codemaker::UnoType::Sort::UnsignedHyper
:
574 case codemaker::UnoType::Sort::Float
:
575 case codemaker::UnoType::Sort::Double
:
576 case codemaker::UnoType::Sort::Char
:
577 case codemaker::UnoType::Sort::Enum
:
580 case codemaker::UnoType::Sort::String
:
581 case codemaker::UnoType::Sort::Type
:
582 case codemaker::UnoType::Sort::Any
:
583 case codemaker::UnoType::Sort::Sequence
:
584 case codemaker::UnoType::Sort::PlainStruct
:
585 case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct
:
586 case codemaker::UnoType::Sort::Interface
:
589 throw CannotDumpException("unexpected entity \"" + param
.type
590 + "\" as parameter type");
597 out
<< "::unoembindhelpers::UnoInOutParam<";
599 dumpType(out
, manager
, param
.type
);
604 if (param
.direction
== unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN
)
606 if (passByReference(manager
, param
.type
))
617 else if (param
.direction
!= unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN
623 if (!declarations
&& wrap
)
630 void dumpWrapper(std::ostream
& out
, rtl::Reference
<TypeManager
> const& manager
,
631 OUString
const& interfaceName
, unoidl::InterfaceTypeEntity::Method
const& method
,
632 std::list
<OUString
> const& baseTrail
)
634 out
<< " .function(\"" << method
.name
<< "\", +[](::com::sun::star::uno::Reference<"
635 << cppName(interfaceName
);
636 out
<< "> const & the_self";
637 if (!method
.parameters
.empty())
641 dumpParameters(out
, manager
, method
, true);
642 out
<< ") { return ";
643 for (auto const& base
: baseTrail
)
645 out
<< "static_cast<" << cppName(base
) << " *>(";
648 if (!baseTrail
.empty())
652 for (std::size_t i
= 0; i
!= baseTrail
.size(); ++i
)
656 out
<< "->" << method
.name
<< "(";
657 dumpParameters(out
, manager
, method
, false);
659 if (hasInOutParameters(method
))
661 out
<< ", ::emscripten::allow_raw_pointers()";
663 out
<< ", ::emscripten::pure_virtual())\n";
666 void dumpMethods(std::ostream
& out
, rtl::Reference
<TypeManager
> const& manager
,
667 OUString
const& name
, rtl::Reference
<unoidl::InterfaceTypeEntity
> const& entity
,
668 std::list
<OUString
> const& baseTrail
)
670 for (auto const& meth
: entity
->getDirectMethods())
672 if (!baseTrail
.empty() || hasInOutParameters(meth
))
674 dumpWrapper(out
, manager
, name
, meth
, baseTrail
);
678 out
<< " .function(\"" << meth
.name
<< "\", &" << cppName(name
)
679 << "::" << meth
.name
<< ", ::emscripten::pure_virtual())\n";
684 rtl::Reference
<unoidl::InterfaceTypeEntity
>
685 resolveInterface(rtl::Reference
<TypeManager
> const& manager
, OUString
const& name
)
687 auto const ent
= manager
->getManager()->findEntity(name
);
688 if (!ent
.is() || ent
->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE
)
690 throw CannotDumpException("bad interface \"" + name
+ "\"");
692 return static_cast<unoidl::InterfaceTypeEntity
*>(ent
.get());
695 void recordVisitedBases(rtl::Reference
<TypeManager
> const& manager
, OUString
const& name
,
696 std::set
<OUString
>& visitedBases
)
698 auto const ent
= resolveInterface(manager
, name
);
699 for (auto const& base
: ent
->getDirectMandatoryBases())
701 if (visitedBases
.insert(base
.name
).second
)
703 recordVisitedBases(manager
, base
.name
, visitedBases
);
708 void dumpBase(std::ostream
& out
, rtl::Reference
<TypeManager
> const& manager
,
709 OUString
const& interface
, OUString
const& name
, std::set
<OUString
>& visitedBases
,
710 std::list
<OUString
> const& baseTrail
)
712 auto const ent
= resolveInterface(manager
, name
);
713 for (auto const& base
: ent
->getDirectMandatoryBases())
715 if (visitedBases
.insert(base
.name
).second
)
717 auto trail
= baseTrail
;
718 trail
.push_front(base
.name
);
719 dumpBase(out
, manager
, interface
, base
.name
, visitedBases
, trail
);
722 dumpAttributes(out
, manager
, interface
, ent
, baseTrail
);
723 dumpMethods(out
, manager
, interface
, ent
, baseTrail
);
726 void dumpWrapperClassMembers(std::ostream
& out
, rtl::Reference
<TypeManager
> const& manager
,
727 OUString
const& interface
, OUString
const& name
,
728 std::set
<OUString
>& visitedBases
)
730 auto const ent
= resolveInterface(manager
, name
);
731 for (auto const& base
: ent
->getDirectMandatoryBases())
733 if (visitedBases
.insert(base
.name
).second
)
735 dumpWrapperClassMembers(out
, manager
, interface
, base
.name
, visitedBases
);
738 for (auto const& attr
: ent
->getDirectAttributes())
741 dumpType(out
, manager
, attr
.type
);
742 out
<< " get" << attr
.name
<< "() override { return call<";
743 dumpType(out
, manager
, attr
.type
);
744 out
<< ">(\"get" << attr
.name
<< "\"); }\n";
747 out
<< " void set" << attr
.name
<< "(";
748 dumpType(out
, manager
, attr
.type
);
749 switch (manager
->getSort(resolveOuterTypedefs(manager
, attr
.type
)))
751 case codemaker::UnoType::Sort::Boolean
:
752 case codemaker::UnoType::Sort::Byte
:
753 case codemaker::UnoType::Sort::Short
:
754 case codemaker::UnoType::Sort::UnsignedShort
:
755 case codemaker::UnoType::Sort::Long
:
756 case codemaker::UnoType::Sort::UnsignedLong
:
757 case codemaker::UnoType::Sort::Hyper
:
758 case codemaker::UnoType::Sort::UnsignedHyper
:
759 case codemaker::UnoType::Sort::Float
:
760 case codemaker::UnoType::Sort::Double
:
761 case codemaker::UnoType::Sort::Char
:
762 case codemaker::UnoType::Sort::Enum
:
764 case codemaker::UnoType::Sort::String
:
765 case codemaker::UnoType::Sort::Type
:
766 case codemaker::UnoType::Sort::Any
:
767 case codemaker::UnoType::Sort::Sequence
:
768 case codemaker::UnoType::Sort::PlainStruct
:
769 case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct
:
770 case codemaker::UnoType::Sort::Interface
:
774 throw CannotDumpException("unexpected entity \"" + attr
.type
775 + "\" as attribute type");
777 out
<< " the_value) override { return call<void>(\"set" << attr
.name
778 << "\", the_value); }\n";
781 for (auto const& meth
: ent
->getDirectMethods())
784 dumpType(out
, manager
, meth
.returnType
);
785 out
<< " " << meth
.name
<< "(";
787 for (auto const& param
: meth
.parameters
)
797 dumpType(out
, manager
, param
.type
);
798 if (param
.direction
== unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN
)
800 switch (manager
->getSort(resolveOuterTypedefs(manager
, param
.type
)))
802 case codemaker::UnoType::Sort::Boolean
:
803 case codemaker::UnoType::Sort::Byte
:
804 case codemaker::UnoType::Sort::Short
:
805 case codemaker::UnoType::Sort::UnsignedShort
:
806 case codemaker::UnoType::Sort::Long
:
807 case codemaker::UnoType::Sort::UnsignedLong
:
808 case codemaker::UnoType::Sort::Hyper
:
809 case codemaker::UnoType::Sort::UnsignedHyper
:
810 case codemaker::UnoType::Sort::Float
:
811 case codemaker::UnoType::Sort::Double
:
812 case codemaker::UnoType::Sort::Char
:
813 case codemaker::UnoType::Sort::Enum
:
815 case codemaker::UnoType::Sort::String
:
816 case codemaker::UnoType::Sort::Type
:
817 case codemaker::UnoType::Sort::Any
:
818 case codemaker::UnoType::Sort::Sequence
:
819 case codemaker::UnoType::Sort::PlainStruct
:
820 case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct
:
821 case codemaker::UnoType::Sort::Interface
:
825 throw CannotDumpException("unexpected entity \"" + param
.type
826 + "\" as parameter type");
833 out
<< " " << param
.name
;
835 out
<< ") override { return call<";
836 dumpType(out
, manager
, meth
.returnType
);
837 out
<< ">(\"" << meth
.name
<< "\"";
838 for (auto const& param
: meth
.parameters
)
840 out
<< ", " << param
.name
;
846 void dumpRegisterFunctionProlog(std::ostream
& out
, unsigned long long& counter
)
848 out
<< "static void __attribute__((noinline)) register" << counter
<< "() {\n";
851 void dumpRegisterFunctionEpilog(std::ostream
& out
, unsigned long long& counter
)
857 std::cerr
<< "Emitting too many register functions\n";
858 std::exit(EXIT_FAILURE
);
862 void recordSequenceTypes(rtl::Reference
<TypeManager
> const& manager
, OUString
const& type
,
863 std::set
<OUString
>& sequences
)
865 auto const res
= resolveAllTypedefs(manager
, type
);
866 if (manager
->getSort(res
) == codemaker::UnoType::Sort::Sequence
)
868 sequences
.insert(res
);
872 void writeJsMap(std::ostream
& out
, Module
const& module
, std::string
const& prefix
)
875 for (auto const & [ id
, to
] : module
.mappings
)
881 out
<< prefix
<< "'" << id
<< "': " << to
;
884 for (auto const & [ id
, sub
] : module
.modules
)
890 out
<< prefix
<< "'" << id
<< "': {\n";
891 writeJsMap(out
, *sub
, prefix
+ " ");
892 out
<< prefix
<< "}";
906 auto const args
= rtl_getAppCommandArgCount();
912 rtl_getAppCommandArg(0, &name
.pData
);
913 auto const cppPathname
= getPathnameArgument(1);
914 auto const hppPathname
= getPathnameArgument(2);
915 auto const jsPathname
= getPathnameArgument(3);
916 rtl::Reference
<TypeManager
> mgr(new TypeManager
);
917 for (sal_uInt32 i
= 4; i
!= args
; ++i
)
919 auto const & [ uri
, primary
] = parseRegistryArgument(i
);
922 mgr
->loadProvider(uri
, primary
);
924 catch (unoidl::NoSuchFileException
&)
926 std::cerr
<< "Input <" << uri
<< "> does not exist\n";
927 std::exit(EXIT_FAILURE
);
930 auto const module
= std::make_shared
<Module
>();
931 std::vector
<OUString
> enums
;
932 std::vector
<OUString
> structs
;
933 std::vector
<OUString
> exceptions
;
934 std::vector
<OUString
> interfaces
;
935 std::vector
<OUString
> services
;
936 std::vector
<OUString
> singletons
;
937 for (auto const& prov
: mgr
->getPrimaryProviders())
939 scan(prov
->createRootCursor(), u
"", module
.get(), enums
, structs
, exceptions
,
940 interfaces
, services
, singletons
);
942 std::ofstream
cppOut(cppPathname
, std::ios_base::out
| std::ios_base::trunc
);
945 std::cerr
<< "Cannot open \"" << cppPathname
<< "\" for writing\n";
946 std::exit(EXIT_FAILURE
);
948 cppOut
<< "#include <emscripten/bind.h>\n"
949 "#include <com/sun/star/uno/Any.hxx>\n"
950 "#include <com/sun/star/uno/Reference.hxx>\n"
951 "#include <static/unoembindhelpers/PrimaryBindings.hxx>\n";
952 for (auto const& enm
: enums
)
954 cppOut
<< "#include <" << enm
.replace('.', '/') << ".hpp>\n";
956 for (auto const& str
: structs
)
958 cppOut
<< "#include <" << str
.replace('.', '/') << ".hpp>\n";
960 for (auto const& exc
: exceptions
)
962 cppOut
<< "#include <" << exc
.replace('.', '/') << ".hpp>\n";
964 for (auto const& ifc
: interfaces
)
966 cppOut
<< "#include <" << ifc
.replace('.', '/') << ".hpp>\n";
968 for (auto const& srv
: services
)
970 cppOut
<< "#include <" << srv
.replace('.', '/') << ".hpp>\n";
972 for (auto const& sng
: singletons
)
974 cppOut
<< "#include <" << sng
.replace('.', '/') << ".hpp>\n";
977 "// TODO: This is a temporary workaround that likely causes the Embind UNO\n"
978 "// bindings to leak memory. Reference counting and cloning mechanisms of\n"
979 "// Embind should be investigated to figure out what exactly we need here:\n"
980 "namespace emscripten::internal {\n";
981 for (auto const& ifc
: interfaces
)
983 cppOut
<< " template<> void raw_destructor<" << cppName(ifc
) << ">(" << cppName(ifc
)
987 unsigned long long n
= 0;
988 for (auto const& enm
: enums
)
990 auto const ent
= mgr
->getManager()->findEntity(enm
);
992 assert(ent
->getSort() == unoidl::Entity::SORT_ENUM_TYPE
);
993 rtl::Reference
const enmEnt(static_cast<unoidl::EnumTypeEntity
*>(ent
.get()));
994 dumpRegisterFunctionProlog(cppOut
, n
);
995 cppOut
<< " ::emscripten::enum_<" << cppName(enm
) << ">(\"uno_Type_" << jsName(enm
)
997 for (auto const& mem
: enmEnt
->getMembers())
999 cppOut
<< "\n .value(\"" << mem
.name
<< "\", " << cppName(enm
) << "_"
1003 cppOut
<< " ::unoembindhelpers::registerUnoType<" << cppName(enm
) << ">();\n";
1004 dumpRegisterFunctionEpilog(cppOut
, n
);
1006 std::set
<OUString
> sequences
;
1007 for (auto const& str
: structs
)
1009 auto const ent
= mgr
->getManager()->findEntity(str
);
1011 assert(ent
->getSort() == unoidl::Entity::SORT_PLAIN_STRUCT_TYPE
);
1012 rtl::Reference
const strEnt(static_cast<unoidl::PlainStructTypeEntity
*>(ent
.get()));
1013 dumpRegisterFunctionProlog(cppOut
, n
);
1014 cppOut
<< " ::emscripten::value_object<" << cppName(str
) << ">(\"uno_Type_"
1015 << jsName(str
) << "\")";
1016 dumpStructMembers(cppOut
, mgr
, str
, strEnt
);
1018 cppOut
<< " ::unoembindhelpers::registerUnoType<" << cppName(str
) << ">();\n";
1019 dumpRegisterFunctionEpilog(cppOut
, n
);
1020 for (auto const& mem
: strEnt
->getDirectMembers())
1022 recordSequenceTypes(mgr
, mem
.type
, sequences
);
1025 for (auto const& exc
: exceptions
)
1027 auto const ent
= mgr
->getManager()->findEntity(exc
);
1029 assert(ent
->getSort() == unoidl::Entity::SORT_EXCEPTION_TYPE
);
1030 rtl::Reference
const excEnt(static_cast<unoidl::ExceptionTypeEntity
*>(ent
.get()));
1031 dumpRegisterFunctionProlog(cppOut
, n
);
1032 cppOut
<< " ::emscripten::value_object<" << cppName(exc
) << ">(\"uno_Type_"
1033 << jsName(exc
) << "\")";
1034 dumpExceptionMembers(cppOut
, mgr
, exc
, excEnt
);
1036 cppOut
<< " ::unoembindhelpers::registerUnoType<" << cppName(exc
) << ">();\n";
1037 dumpRegisterFunctionEpilog(cppOut
, n
);
1038 for (auto const& mem
: excEnt
->getDirectMembers())
1040 recordSequenceTypes(mgr
, mem
.type
, sequences
);
1043 for (auto const& ifc
: interfaces
)
1045 auto const ent
= mgr
->getManager()->findEntity(ifc
);
1047 assert(ent
->getSort() == unoidl::Entity::SORT_INTERFACE_TYPE
);
1048 rtl::Reference
const ifcEnt(static_cast<unoidl::InterfaceTypeEntity
*>(ent
.get()));
1050 auto i
= ifc
.lastIndexOf('.');
1056 cppOut
<< "namespace the_wrappers" << cppName(ifc
.copy(0, i
)) << " {\n"
1057 << "struct " << ifc
.copy(j
) << " final: public ::emscripten::wrapper<"
1058 << cppName(ifc
) << "> {\n"
1059 << " EMSCRIPTEN_WRAPPER(" << ifc
.copy(j
) << ");\n";
1060 std::set
<OUString
> visitedBases
;
1061 dumpWrapperClassMembers(cppOut
, mgr
, ifc
, ifc
, visitedBases
);
1062 cppOut
<< "};\n}\n";
1064 dumpRegisterFunctionProlog(cppOut
, n
);
1065 cppOut
<< " ::emscripten::class_<" << cppName(ifc
);
1066 //TODO: Embind only supports single inheritance, so use that support at least for a UNO
1067 // interface's first base, and explicitly spell out the attributes and methods of any
1069 auto const& bases
= ifcEnt
->getDirectMandatoryBases();
1070 if (bases
.size() != 0)
1072 cppOut
<< ", ::emscripten::base<" << cppName(bases
[0].name
) << ">";
1074 cppOut
<< ">(\"uno_Type_" << jsName(ifc
)
1076 " .allow_subclass<the_wrappers"
1077 << cppName(ifc
) << ">(\"uno_Wrapper_" << jsName(ifc
)
1079 " .smart_ptr<::com::sun::star::uno::Reference<"
1080 << cppName(ifc
) << ">>(\"uno_Reference_" << jsName(ifc
)
1082 " .class_function(\"reference\", +[]("
1084 << " * the_interface) { return ::com::sun::star::uno::Reference(the_interface); "
1085 "}, ::emscripten::allow_raw_pointers())\n"
1087 ".constructor(+[](::com::sun::star::uno::Reference<::com::sun::star::uno::"
1088 "XInterface> const & the_object) { return ::com::sun::star::uno::Reference<"
1090 << ">(the_object, ::com::sun::star::uno::UNO_QUERY); })\n"
1091 " .function(\"$is\", +[](::com::sun::star::uno::Reference<"
1093 << "> const & the_self) { return the_self.is(); })\n"
1094 " .function(\"$equals\", +[](::com::sun::star::uno::Reference<"
1096 << "> const & the_self, "
1097 "::com::sun::star::uno::Reference<::com::sun::star::uno::XInterface> const & "
1098 "the_other) { return the_self == the_other; })\n";
1099 if (bases
.size() > 1)
1101 std::set
<OUString
> visitedBases
;
1102 recordVisitedBases(mgr
, bases
[0].name
, visitedBases
);
1103 for (std::size_t i
= 1; i
!= bases
.size(); ++i
)
1105 dumpBase(cppOut
, mgr
, ifc
, bases
[i
].name
, visitedBases
, { bases
[i
].name
});
1108 dumpAttributes(cppOut
, mgr
, ifc
, ifcEnt
, {});
1109 dumpMethods(cppOut
, mgr
, ifc
, ifcEnt
, {});
1111 " ::unoembindhelpers::registerUnoType<::com::sun::star::uno::Reference<"
1112 << cppName(ifc
) << ">>();\n";
1113 dumpRegisterFunctionEpilog(cppOut
, n
);
1114 for (auto const& attr
: ifcEnt
->getDirectAttributes())
1116 recordSequenceTypes(mgr
, attr
.type
, sequences
);
1118 for (auto const& meth
: ifcEnt
->getDirectMethods())
1120 for (auto const& param
: meth
.parameters
)
1122 recordSequenceTypes(mgr
, param
.type
, sequences
);
1124 recordSequenceTypes(mgr
, meth
.returnType
, sequences
);
1127 for (auto const& srv
: services
)
1129 auto const ent
= mgr
->getManager()->findEntity(srv
);
1131 assert(ent
->getSort() == unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE
);
1132 rtl::Reference
const srvEnt(
1133 static_cast<unoidl::SingleInterfaceBasedServiceEntity
*>(ent
.get()));
1134 dumpRegisterFunctionProlog(cppOut
, n
);
1135 for (auto const& ctor
: srvEnt
->getConstructors())
1137 cppOut
<< " ::emscripten::function(\"" << jsServiceConstructor(srv
, ctor
)
1138 << "\", &" << cppName(srv
) << "::" << getServiceConstructorName(ctor
)
1141 dumpRegisterFunctionEpilog(cppOut
, n
);
1143 for (auto const& sng
: singletons
)
1145 dumpRegisterFunctionProlog(cppOut
, n
);
1146 cppOut
<< " ::emscripten::function(\"" << jsSingleton(sng
) << "\", &" << cppName(sng
)
1148 dumpRegisterFunctionEpilog(cppOut
, n
);
1150 cppOut
<< "void init_unoembind_" << name
<< "() {\n";
1151 for (unsigned long long i
= 0; i
!= n
; ++i
)
1153 cppOut
<< " register" << i
<< "();\n";
1155 for (auto const& seq
: sequences
)
1157 cppOut
<< " ::unoembindhelpers::registerSequence<";
1158 assert(seq
.startsWith("[]"));
1159 dumpType(cppOut
, mgr
, seq
.copy(2));
1160 cppOut
<< ">(\"uno_Sequence";
1162 auto const nuc
= b2u(codemaker::UnoType::decompose(u2b(seq
), &k
));
1168 cppOut
<< "_" << jsName(nuc
) << "\");\n";
1174 std::cerr
<< "Failed to write \"" << cppPathname
<< "\"\n";
1175 std::exit(EXIT_FAILURE
);
1177 std::ofstream
hppOut(hppPathname
, std::ios_base::out
| std::ios_base::trunc
);
1180 std::cerr
<< "Cannot open \"" << hppPathname
<< "\" for writing\n";
1181 std::exit(EXIT_FAILURE
);
1183 hppOut
<< "void init_unoembind_" << name
<< "();\n";
1187 std::cerr
<< "Failed to write \"" << hppPathname
<< "\"\n";
1188 std::exit(EXIT_FAILURE
);
1190 std::ofstream
jsOut(jsPathname
, std::ios_base::out
| std::ios_base::trunc
);
1193 std::cerr
<< "Cannot open \"" << jsPathname
<< "\" for writing\n";
1194 std::exit(EXIT_FAILURE
);
1196 jsOut
<< "function init_unoembind_" << name
1199 writeJsMap(jsOut
, *module
, " ");
1205 std::cerr
<< "Failed to write \"" << jsPathname
<< "\"\n";
1206 std::exit(EXIT_FAILURE
);
1208 return EXIT_SUCCESS
;
1210 catch (unoidl::FileFormatException
const& e
)
1212 std::cerr
<< "Bad input <" << e
.getUri() << ">: " << e
.getDetail() << "\n";
1213 std::exit(EXIT_FAILURE
);
1215 catch (CannotDumpException
const& e
)
1217 std::cerr
<< "Failure: " << e
.getMessage() << "\n";
1218 std::exit(EXIT_FAILURE
);
1220 catch (std::exception
const& e
)
1222 std::cerr
<< "Failure: " << e
.what() << "\n";
1223 std::exit(EXIT_FAILURE
);
1227 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */