welder 0.1.0
Bindings for annotated C++ types, from C++26 reflection
Loading...
Searching...
No Matches
carriage.hpp
Go to the documentation of this file.
1#pragma once
2#include <array>
3#include <cstddef>
4#include <meta>
5#include <type_traits>
6#include <utility>
7
8#include <welder/bind_traits.hpp> // what-binds selection layer
9#include <welder/bindable.hpp> // bindability gate + caster_oracle
10#include <welder/concepts.hpp> // the welder::rod contract
11#include <welder/doc.hpp> // doc_of (class / namespace docstrings)
12#include <welder/naming.hpp> // naming::none + name_of (weld_as + name styling)
13#include <welder/reflect.hpp> // welded_for / policy_of / member_bound
14
36
37namespace welder::inline v0 {
38
39namespace detail {
40
53template <class Resolution, std::meta::info Ns, std::meta::info Alias>
54consteval bool sole_alias_of_target(lang L, policy_kind pol) {
55 for (auto m :
56 std::meta::members_of(Ns, std::meta::access_context::unchecked())) {
58 continue;
59 // Self-identity by NAME, not by `==`: gcc-16 compares two alias
60 // reflections of the same underlying type as equal, which would make the
61 // duplicate invisible. Two aliases cannot share an identifier in one
62 // namespace, so the identifier is the reliable identity here.
63 if (std::meta::identifier_of(m) == std::meta::identifier_of(Alias))
64 continue;
65 if (std::meta::dealias(m) == std::meta::dealias(Alias) &&
66 Resolution::alias_participates(m, L, pol, Ns))
67 return false;
68 }
69 return true;
70}
71
87template <std::meta::info Alias, lang L, class Style,
89consteval const char* alias_bound_name() {
90 if constexpr (welder::weld_as_of<Alias, L>() != nullptr)
93 nullptr)
94 return welder::weld_as_of<std::meta::dealias(Alias), L>();
95 else
97}
98
99} // namespace detail
100
105consteval bool is_nested_type(std::meta::info type) {
106 const std::meta::info outer{std::meta::parent_of(type)};
107 return std::meta::is_type(outer) && std::meta::is_class_type(outer);
108}
109
110namespace detail {
111
130template <class Resolution>
131consteval bool nested_type_registered(std::meta::info type, lang L) {
132 const std::meta::info outer{std::meta::parent_of(type)};
133 return std::meta::has_identifier(type) && std::meta::is_complete_type(type) &&
135 member_bound(type, L, policy_of(outer)) &&
136 Resolution::counts_as_registered(outer, L);
137}
138
154template <class Resolution, std::meta::info Outer, std::meta::info Alias>
156 for (auto m : std::meta::members_of(Outer,
157 std::meta::access_context::unchecked())) {
158 if (!std::meta::is_type_alias(m) || !std::meta::has_identifier(m))
159 continue;
160 // Self-identity by NAME (== collapses alias reflections on gcc-16; two
161 // member aliases cannot share an identifier in one class).
162 if (std::meta::identifier_of(m) == std::meta::identifier_of(Alias))
163 continue;
164 if (std::meta::dealias(m) == std::meta::dealias(Alias) &&
166 Resolution::class_member_participates(m, L, pol, Outer))
167 return false;
168 }
169 return true;
170}
171
185template <class Resolution>
186consteval bool registered_by_member_alias(std::meta::info scope,
187 std::meta::info type, lang L) {
188 const policy_kind pol{policy_of(scope)};
189 for (auto m : std::meta::members_of(scope,
190 std::meta::access_context::unchecked())) {
191 if (!std::meta::is_type_alias(m) || !std::meta::has_identifier(m))
192 continue;
193 if (std::meta::dealias(m) != type)
194 continue;
195 if (member_access_admitted<Resolution>(m, L, scope) &&
196 Resolution::class_member_participates(m, L, pol, scope))
197 return true;
198 }
199 return false;
200}
201
220template <class Resolution, std::meta::info Scope>
221struct scoped_registration : Resolution {
222 static consteval bool counts_as_registered(std::meta::info type, lang L) {
223 if (Resolution::counts_as_registered(type, L))
224 return true;
225 if (!(std::meta::is_class_type(type) || std::meta::is_enum_type(type)))
226 return false;
227 // The nested chain, alias-aware: a nested type of an alias-registered
228 // target resolves through this oracle again.
229 if (welder::is_nested_type(type) &&
231 return true;
232 return registered_by_member_alias<Resolution>(Scope, type, L);
233 }
234};
235
236} // namespace detail
237
238namespace carriages {
239
240// --- resolution policies ----------------------------------------------------
241//
242// A carriage's *resolution* decides **which** entities participate — the reading of
243// welder's markers — kept separate from *how* they are emitted (the carriage body)
244// and *whether* they are representable (the bindability gate, which both share). Two
245// ship: `marker_resolution` (honor `weld`/`policy`/marks — the default) and
246// `greedy_resolution` (ignore the markers, bind everything — tack welding).
247
256 static consteval bool participates(std::meta::info entity, lang L) {
257 return welder::welded_for(entity, L);
258 }
259
262 static consteval bool is_native_base(std::meta::info base, lang L,
263 std::meta::info /*bound_into*/) {
264 return welder::welded_for(base, L);
265 }
266
267 template <std::meta::info T, lang L>
268 static consteval auto native_bases() {
270 }
271
274 static consteval bool member_participates(std::meta::info mem, lang L,
275 policy_kind pol,
276 std::meta::info /*bound_into*/) {
277 return welder::welded_for(mem, L) && member_bound(mem, L, pol);
278 }
279
283 static consteval bool alias_participates(std::meta::info mem, lang L,
284 policy_kind pol,
285 std::meta::info /*bound_into*/) {
286 return welder::alias_welded_for(mem, L) &&
287 member_bound(std::meta::dealias(mem), L, pol);
288 }
289
296 static consteval bool class_member_participates(std::meta::info mem, lang L,
297 policy_kind pol,
298 std::meta::info /*bound_into*/) {
299 return member_bound(mem, L, pol);
300 }
301
311 static consteval bool protected_participates(std::meta::info mem, lang L,
312 std::meta::info /*bound_into*/) {
313 return welder::protected_welded(std::meta::parent_of(mem), L);
314 }
315
317 static consteval bool namespace_participates(std::meta::info ns, lang L,
318 policy_kind pol,
319 std::meta::info /*bound_into*/) {
320 return member_bound(ns, L, pol) && detail::namespace_has_bound(ns, L);
321 }
322
330 static consteval bool counts_as_registered(std::meta::info type, lang L) {
331 if (welder::welded_for(type, L))
332 return true;
333 if ((std::meta::is_class_type(type) || std::meta::is_enum_type(type)) &&
336 return false;
337 }
338};
339
363template <bool WeldProtected = false>
365 static consteval bool participates(std::meta::info, lang) { return true; }
366 static consteval bool is_native_base(std::meta::info, lang,
367 std::meta::info /*bound_into*/) {
368 return false;
369 }
370 template <std::meta::info, lang>
371 static consteval auto native_bases() {
372 return std::array<std::meta::info, 0>{};
373 }
374 static consteval bool member_participates(std::meta::info mem, lang L,
375 policy_kind pol,
376 std::meta::info /*bound_into*/) {
377 return member_bound(mem, L, pol);
378 }
379
381 static consteval bool alias_participates(std::meta::info mem, lang L,
382 policy_kind pol,
383 std::meta::info /*bound_into*/) {
384 return member_bound(std::meta::dealias(mem), L, pol);
385 }
386
388 static consteval bool class_member_participates(std::meta::info mem, lang L,
389 policy_kind pol,
390 std::meta::info /*bound_into*/) {
391 return member_bound(mem, L, pol);
392 }
393
398 static consteval bool protected_participates(std::meta::info mem, lang L,
399 std::meta::info /*bound_into*/) {
400 return WeldProtected ||
401 welder::protected_welded(std::meta::parent_of(mem), L);
402 }
403 static consteval bool namespace_participates(std::meta::info ns, lang L,
404 policy_kind pol,
405 std::meta::info /*bound_into*/) {
406 return member_bound(ns, L, pol) && detail::namespace_has_bindable(ns, L);
407 }
408
432 static consteval bool counts_as_registered(std::meta::info type, lang L) {
433 if (!(std::meta::is_class_type(type) || std::meta::is_enum_type(type)))
434 return false;
435 if (!std::meta::is_complete_type(type))
436 return false;
437 if (welder::is_nested_type(type))
439 return member_bound(type, L, policy_kind::automatic);
440 }
441};
442
466template <resolution Resolution>
468 private:
488 template <rod B, std::meta::info BoundInto, std::meta::info Src, class Style,
489 class Cls>
490 static void bind_members(Cls& cls) {
491 constexpr lang L{B::language};
492 constexpr auto ctx{std::meta::access_context::unchecked()};
493
494 template for (constexpr auto base :
495 std::define_static_array(welder::public_bases(Src))) {
496 if constexpr (!Resolution::is_native_base(base, L, Src))
498 }
499
500 constexpr policy_kind pol{policy_of(Src)};
501
502 // The gate for class members runs through the SCOPE-AWARE oracle: the
503 // bound-into type's own member aliases register types the plain oracle
504 // cannot see (an alias is unrecoverable from the type it names).
506
507 template for (constexpr auto mem : std::define_static_array(
508 std::meta::nonstatic_data_members_of(Src, ctx))) {
510 BoundInto) &&
511 Resolution::class_member_participates(mem, L, pol,
512 BoundInto)) {
514 B::template add_field<mem, Style>(cls);
515 }
516 }
517
518 // Methods and operators are emitted as whole OVERLOAD GROUPS: the walk
519 // fires on each group's first participating overload (the leader),
520 // gathers the resolution-admitted set, gates every member, and hands the
521 // group to the rod in one call — so one-value-per-name frameworks (the
522 // Lua rods) register a complete set, and per-overload marks / bespoke
523 // resolutions shape the group identically on every rod.
524 template for (constexpr auto fn :
525 std::define_static_array(std::meta::members_of(Src, ctx))) {
526 if constexpr (detail::is_method_candidate(fn) &&
528 BoundInto) &&
529 Resolution::class_member_participates(fn, L, pol,
530 BoundInto)) {
531 if constexpr (detail::is_overload_leader<
533 fn, L, BoundInto)) {
534 constexpr auto grp{detail::overload_group<
536 BoundInto>()};
537 template for (constexpr auto member :
538 std::define_static_array(grp)) {
540 }
541 if constexpr (std::meta::is_static_member(fn))
542 B::template add_static_method<grp, Style>(cls);
543 else
544 B::template add_method<grp, Style>(cls);
545 }
546 } else if constexpr (detail::is_operator_candidate(fn) &&
548 fn, L, BoundInto) &&
549 Resolution::class_member_participates(fn, L, pol,
550 BoundInto) &&
551 B::special_method_name(fn) != nullptr) {
552 // A member operator group binds under the backend's special-method
553 // name (operator+ -> __add__, ...); unary/binary forms are distinct
554 // groups (distinct arity), so they never collide.
555 if constexpr (detail::is_overload_leader<
557 fn, L, BoundInto)) {
558 constexpr auto grp{detail::overload_group<
560 BoundInto>()};
561 template for (constexpr auto member :
562 std::define_static_array(grp)) {
564 }
565 B::template add_operator<grp>(cls);
566 }
567 }
568 // A member function TEMPLATE falls through every branch: not a
569 // bindable entity (welder cannot invent its template arguments) —
570 // bind an instantiation by chaining it onto the class handle
571 // weld_type returns. A participation mark on one is inert, and NOT
572 // diagnosable: P2996 refuses annotations_of on an uninstantiated
573 // template (the mark is readable only through an instantiation), so
574 // welder cannot even see it here to fail fast.
575 }
576 }
577
585 template <rod B, class E, class Style, class EnumHandle>
586 static void emit_enumerators(EnumHandle& e) {
587 constexpr lang L{B::language};
588 constexpr policy_kind pol{policy_of(^^E)};
589 template for (constexpr auto en :
590 std::define_static_array(std::meta::enumerators_of(^^E))) {
591 if constexpr (Resolution::class_member_participates(en, L, pol, ^^E))
592 B::template add_enumerator<en, Style>(e);
593 }
594 }
595
612 template <rod B, class T, class Style, class Cls>
613 static void bind_class_interior(typename B::module_type& m, Cls& cls) {
614 constexpr lang L{B::language};
615
616 // Nested member types (classes + enums declared inside T) — recursive:
617 // each one's own interior runs this walk again.
619
620 // Constructors, handed to the rod as ONE participating set (several
621 // frameworks want them all at once — sol2's sol::constructors, LuaBridge3's
622 // addConstructor). Three carriage-computed pieces:
623 // - the default constructor: constructibility is decided against the type
624 // welder actually constructs, which may be a rod-nominated substitute —
625 // a Python trampoline standing in for an abstract base — exposed as an
626 // optional `B::construction_type<T>` (fall back to T when a rod names
627 // none); a *declared* default constructor's explicit marks are honored
628 // (default_ctor_admitted);
629 // - each participating public non-copy/move constructor — resolved
630 // SYMMETRICALLY with every other member (the type's policy + the
631 // constructor's own marks, per constructor) — each gated for
632 // bindability;
633 // - for a baseless aggregate whose fields all participate, a synthesized
634 // field constructor.
635 constexpr bool has_default{
636 [] {
637 if constexpr (requires {
638 typename B::template construction_type<T>;
639 })
640 return std::is_default_constructible_v<
641 typename B::template construction_type<T>>;
642 else
643 return std::is_default_constructible_v<T>;
644 }() &&
646 constexpr auto ctors{
648 template for (constexpr auto ctor : std::define_static_array(ctors)) {
649 // Scope-aware gate: T's own member aliases may register a
650 // parameter's type (see bind_members' Reg).
653 }
654 constexpr bool aggregate{
656 // The fail-safe against SILENT uninstantiability: if the policy filtering
657 // left T with no constructor at all, but this same resolution would have
658 // admitted some under `automatic`, the emptiness came from a default (an
659 // opt_in type whose constructors nobody marked) rather than a decision —
660 // hard error. Explicit emptiness passes: mark::exclude-ing the
661 // constructors zeroes the automatic baseline too (factory-only intent),
662 // and a type automatic would also leave bare (private/deleted ctors, an
663 // abstract base) was never instantiable to begin with.
664 static_assert(
665 has_default || aggregate || ctors.size() != 0 ||
666 detail::ctor_group<Resolution, ^^T, L,
668 .size() == 0,
669 "welder: policy filtering left this type with NO constructor — it "
670 "would be silently uninstantiable from the target language. Mark a "
671 "constructor [[=welder::mark::include]] (opt_in binds only marked "
672 "members, constructors included), or mark them all "
673 "[[=welder::mark::exclude]] to make a factory-only surface explicit. "
674 "The type is the T of this bind_type<B, T, Style> instantiation.");
675 B::template add_constructors<T, ctors, has_default, aggregate>(cls);
676
677 // Data members + methods + operators (T's own, plus flattened bases).
679 }
680
707 template <rod B, std::meta::info Outer, class Style, class Cls>
708 static void bind_nested_types(typename B::module_type& m, Cls& cls) {
709 constexpr lang L{B::language};
710 constexpr auto ctx{std::meta::access_context::unchecked()};
711 constexpr policy_kind pol{policy_of(Outer)};
712 template for (constexpr auto mem : std::define_static_array(
713 std::meta::members_of(Outer, ctx))) {
714 if constexpr (std::meta::is_type(mem) &&
715 !std::meta::is_type_alias(mem) &&
716 (std::meta::is_class_type(mem) ||
717 std::meta::is_enum_type(mem)) &&
718 std::meta::has_identifier(mem) &&
719 std::meta::is_complete_type(mem)) {
721 mem, L, Outer) &&
722 Resolution::class_member_participates(mem, L, pol,
723 Outer)) {
724 if constexpr (std::meta::is_enum_type(mem))
725 bind_nested_enum<B, typename [:mem:], Style>(m, cls);
726 else
728 }
729 } else if constexpr (std::meta::is_type_alias(mem) &&
730 std::meta::has_identifier(mem) &&
731 (std::meta::is_class_type(
732 std::meta::dealias(mem)) ||
733 std::meta::is_enum_type(
734 std::meta::dealias(mem))) &&
735 std::meta::is_complete_type(
736 std::meta::dealias(mem))) {
737 // A MEMBER TYPE ALIAS: participates by the member rules (the
738 // outer's policy + the alias's own marks), with the bindability
739 // gate as the register-or-skip arbiter — a target the gate
740 // already passes (natively castable, a bindable STL wrapper,
741 // welded, otherwise registered, or trusted) converts without
742 // this registration, so registering it again would be redundant
743 // or an outright duplicate. The rule registers exactly the
744 // types that otherwise could not cross the boundary — nested
745 // under the outer, named by the alias (its weld_as → the
746 // target's → the styled identifier). Under greedy resolution
747 // every complete type passes the gate, so member aliases never
748 // participate in a tack weld, by construction.
749 static_assert(
751 "welder: only weld_as / exclude / include / only may be "
752 "attached to a member type alias; policy and doc marks "
753 "belong on the target type, and weld / trust_bindable have "
754 "no meaning here (participation follows the outer's policy "
755 "and the bindability gate)");
757 mem, L, Outer) &&
758 Resolution::class_member_participates(mem, L, pol,
759 Outer) &&
761 B, typename [:std::meta::dealias(mem):], L,
762 Resolution>()) {
763 static_assert(
764 detail::sole_member_alias_of_target<Resolution, Outer,
765 mem>(L, pol),
766 "welder: two member aliases in this class weld the SAME "
767 "target type — each target may be registered under "
768 "exactly one name; mark::exclude one of them");
769 if constexpr (std::meta::is_enum_type(
770 std::meta::dealias(mem)))
771 bind_nested_enum<B, typename [:std::meta::dealias(mem):],
772 Style>(
773 m, cls,
774 detail::alias_bound_name<mem, L, Style,
775 ent_kind::enum_>());
776 else
777 bind_nested_type<B, typename [:std::meta::dealias(mem):],
778 Style, mem>(
780 }
781 }
782 }
783 }
784
812 template <rod B, class T, class Style, std::meta::info Decl = std::meta::info{},
813 class OuterCls>
814 static void bind_nested_type(typename B::module_type& m, OuterCls& outer,
815 const char* name = nullptr) {
816 constexpr lang L{B::language};
817 // name_of_or, not `name ? name : name_of<…>`: the consteval fallback
818 // must only be compiled when T is statically nameable — an alias-welded
819 // specialization has no identifier and always arrives with an override.
820 const char* cls_name{
822 auto cls{make_nested_class_of<B, T, Decl,
823 Resolution::template native_bases<^^T, L>()>(
824 m, outer, cls_name, welder::doc_of<^^T>())};
826 // A second OPTIONAL rod hook, after the interior: a rod whose class
827 // handle re-opens the class by name/path (LuaBridge3) cannot move the
828 // class under the outer at creation time — every later add_* call would
829 // re-open a key that no longer exists — so it finalizes the placement
830 // here, once the interior (nested types included, so innermost first)
831 // is fully registered.
832 if constexpr (requires {
833 B::template finish_nested_class<T>(m, outer, cls,
834 cls_name);
835 })
836 B::template finish_nested_class<T>(m, outer, cls, cls_name);
837 }
838
850 template <rod B, class E, class Style, class OuterCls>
851 static void bind_nested_enum(typename B::module_type& m, OuterCls& outer,
852 const char* name = nullptr) {
853 constexpr lang L{B::language};
854 const char* enum_name{
856 auto e{make_nested_enum_of<B, E>(m, outer, enum_name,
859 B::template finish_enum<E>(e);
860 }
861
881 template <rod B, class T, std::meta::info Decl, auto Bases, class OuterCls>
882 static auto make_nested_class_of(typename B::module_type& m, OuterCls& outer,
883 const char* cls_name, const char* doc) {
884 constexpr std::meta::info decl{Decl == std::meta::info{} ? ^^T : Decl};
885 if constexpr (requires {
886 B::template make_nested_class<T, decl, Bases>(
887 m, outer, cls_name, doc,
888 std::make_index_sequence<Bases.size()>{});
889 })
890 return B::template make_nested_class<T, decl, Bases>(
891 m, outer, cls_name, doc,
892 std::make_index_sequence<Bases.size()>{});
893 else if constexpr (requires {
894 B::template make_nested_class<T, Bases>(
895 m, outer, cls_name, doc,
896 std::make_index_sequence<Bases.size()>{});
897 })
898 return B::template make_nested_class<T, Bases>(
899 m, outer, cls_name, doc,
900 std::make_index_sequence<Bases.size()>{});
901 else
902 return make_class_of<B, T, decl, Bases>(m, cls_name, doc);
903 }
904
914 template <rod B, class E, class OuterCls>
915 static auto make_nested_enum_of(typename B::module_type& m, OuterCls& outer,
916 const char* name, const char* doc) {
917 if constexpr (requires {
918 B::template make_nested_enum<E>(m, outer, name, doc);
919 })
920 return B::template make_nested_enum<E>(m, outer, name, doc);
921 else
922 return B::template make_enum<E>(m, name, doc);
923 }
924
925 public:
940 template <rod B, class E, class Style = naming::none>
941 static auto bind_enum(typename B::module_type& m, const char* name = nullptr) {
942 constexpr lang L{B::language};
943 static_assert(Resolution::participates(^^E, L),
944 "welder: weld_type<E>: enum E is not welded for this backend's "
945 "language; annotate it with [[=welder::weld(...)]]");
946 const char* enum_name{
948 auto e{B::template make_enum<E>(m, enum_name, welder::doc_of<^^E>())};
950 B::template finish_enum<E>(e);
951 return e;
952 }
953
970 template <rod B, class T, std::meta::info Decl, auto Bases>
971 static auto make_class_of(typename B::module_type& m, const char* cls_name,
972 const char* doc) {
973 if constexpr (requires {
974 B::template make_class<T, Decl, Bases>(
975 m, cls_name, doc,
976 std::make_index_sequence<Bases.size()>{});
977 })
978 return B::template make_class<T, Decl, Bases>(
979 m, cls_name, doc, std::make_index_sequence<Bases.size()>{});
980 else
981 return B::template make_class<T, Bases>(
982 m, cls_name, doc, std::make_index_sequence<Bases.size()>{});
983 }
984
1016 template <rod B, class T, class Style = naming::none,
1017 std::meta::info Decl = std::meta::info{}>
1018 static auto bind_type(typename B::module_type& m, const char* name = nullptr) {
1019 constexpr lang L{B::language};
1020 // Decl is the *declaring* entity when it differs from ^^T: the namespace-
1021 // scope alias through which a class-template specialization was welded
1022 // (bind_namespace's alias branch, which has already resolved participation
1023 // — the alias's own `weld` counts there, so ^^T alone can't be re-checked).
1024 static_assert(Decl != std::meta::info{} || Resolution::participates(^^T, L),
1025 "welder: weld_type<T>: T is not welded for this backend's "
1026 "language; annotate it with [[=welder::weld(...)]]");
1027 constexpr auto ctx{std::meta::access_context::unchecked()};
1028
1029 const char* cls_name{
1031
1032 // Native bases → bases of the class handle; the user binds them first.
1033 // A text-emitting rod that must *spell* the type in C++ (the trampoline
1034 // generator) declares the extended, declaring-entity-aware make_class; it
1035 // receives Decl — the alias, the one C++ name a specialization has — or
1036 // ^^T itself for a directly-declared class. Detected via requires, so the
1037 // runtime rods keep the plain form (they need only T + the bound name).
1038 constexpr auto bases{Resolution::template native_bases<^^T, L>()};
1039 auto cls{make_class_of<B, T, (Decl == std::meta::info{} ? ^^T : Decl),
1040 bases>(m, cls_name, welder::doc_of<^^T>())};
1041
1042 // Nested member types, constructors, data members / methods / operators
1043 // (shared with bind_nested_type — nesting recurses through it).
1045
1046 return cls;
1047 }
1048
1067 template <rod B, std::meta::info Fn, class Style = naming::none>
1068 static auto bind_function(typename B::module_type& m, const char* name = nullptr) {
1069 constexpr lang L{B::language};
1070 static_assert(std::meta::is_function(Fn),
1071 "welder: weld_function<Fn>: Fn must reflect a (free) function");
1072 static_assert(Resolution::participates(Fn, L),
1073 "welder: weld_function<Fn>: Fn is not welded for this backend's "
1074 "language; annotate it with [[=welder::weld(...)]]");
1076 template for (constexpr auto member : std::define_static_array(grp)) {
1078 }
1079 // Forward the rod's handle (the bound function object, where the
1080 // framework has one); a void-returning rod makes this void too.
1081 return B::template add_function<grp, Style>(m, name);
1082 }
1083
1099 template <rod B, std::meta::info Var, class Style = naming::none>
1100 static auto bind_variable(typename B::module_type& m, const char* name = nullptr) {
1101 constexpr lang L{B::language};
1102 static_assert(std::meta::is_variable(Var),
1103 "welder: weld_variable<Var>: Var must reflect a namespace "
1104 "variable");
1105 static_assert(Resolution::participates(Var, L),
1106 "welder: weld_variable<Var>: Var is not welded for this "
1107 "backend's language; annotate it with [[=welder::weld(...)]]");
1109 auto session{B::open_module(m)};
1110 // Forward the rod's handle if its add_variable yields one (the shipped
1111 // rods return void — a bound constant is a snapshot, a mutable global a
1112 // module property; neither has a framework object worth returning), but
1113 // the session must still close after the registration.
1114 if constexpr (std::is_void_v<decltype(B::template add_variable<Var, Style>(
1115 m, session, name))>) {
1116 B::template add_variable<Var, Style>(m, session, name);
1117 B::close_module(m, session);
1118 } else {
1119 auto handle{B::template add_variable<Var, Style>(m, session, name)};
1120 B::close_module(m, session);
1121 return handle;
1122 }
1123 }
1124
1137 template <rod B, std::meta::info Ns, class Style = naming::none>
1138 static void bind_namespace(typename B::module_type& m) {
1139 static_assert(std::meta::is_namespace(Ns),
1140 "welder: weld_namespace<Ns>: Ns must reflect a namespace");
1141 constexpr lang L{B::language};
1142 constexpr auto ctx{std::meta::access_context::unchecked()};
1143 constexpr policy_kind pol{policy_of(Ns)};
1144
1145 // A [[=welder::doc]] on the namespace becomes the (sub)module docstring.
1146 if (const char* nsdoc{welder::doc_of<Ns>()})
1147 B::set_module_doc(m, nsdoc);
1148
1149 // The backend's per-module session: scratch state for attributes it emits in
1150 // one batch at the end (e.g. live variable properties). Opened before the
1151 // walk, finalized by close_module after it.
1152 auto session{B::open_module(m)};
1153
1154 template for (constexpr auto mem :
1155 std::define_static_array(std::meta::members_of(Ns, ctx))) {
1156 // The alias branch must come first: type predicates (is_class_type)
1157 // look through an alias, so the class branch below would swallow it.
1158 if constexpr (std::meta::is_type_alias(mem)) {
1159 if constexpr (welder::names_template_specialization(mem)) {
1160 // The one way an *instantiation* enters a sweep (members_of
1161 // enumerates the template, never its specializations): the
1162 // alias is both the C++ spelling and the target-language name.
1163 static_assert(
1165 "welder: only weld / weld_as may be attached to a "
1166 "namespace-scope alias; every other mark belongs on the "
1167 "class template, where it applies to all instantiations");
1168 if constexpr (Resolution::alias_participates(mem, L, pol, Ns)) {
1169 static_assert(
1171 pol),
1172 "welder: two aliases in this namespace weld the SAME "
1173 "template specialization — each specialization may be "
1174 "welded under exactly one name");
1177 }
1178 } else {
1179 // An alias to a plain (non-template) type: binding it would
1180 // register the type a second time under the alias name — a
1181 // welded target makes the alias a likely mistake, diagnosed
1182 // rather than silently skipped. (Rename with weld_as instead.)
1183 static_assert(
1184 !((std::meta::is_class_type(std::meta::dealias(mem)) ||
1185 std::meta::is_enum_type(std::meta::dealias(mem))) &&
1186 welder::alias_welded_for(mem, L)),
1187 "welder: a namespace-scope alias to a welded NON-template "
1188 "type would bind the type twice (it already binds under "
1189 "its own name); remove the alias's weld, or rename the "
1190 "type with [[=welder::weld_as(...)]]");
1191 }
1192 } else if constexpr (std::meta::is_type(mem) &&
1193 std::meta::is_class_type(mem)) {
1194 if constexpr (Resolution::member_participates(mem, L, pol, Ns))
1195 bind_type<B, typename [:mem:], Style>(m, nullptr);
1196 } else if constexpr (std::meta::is_type(mem) && std::meta::is_enum_type(mem)) {
1197 if constexpr (Resolution::member_participates(mem, L, pol, Ns))
1198 bind_enum<B, typename [:mem:], Style>(m, nullptr);
1199 } else if constexpr (std::meta::is_function(mem)) {
1200 // Free functions bind as whole overload groups, emitted at the
1201 // group's first participating overload (see bind_members).
1202 if constexpr (Resolution::member_participates(mem, L, pol, Ns)) {
1203 if constexpr (detail::is_overload_leader<
1205 mem, L, Ns)) {
1206 constexpr auto grp{detail::overload_group<
1208 Ns>()};
1209 template for (constexpr auto member :
1210 std::define_static_array(grp)) {
1212 Resolution>();
1213 }
1214 B::template add_function<grp, Style>(m);
1215 }
1216 }
1217 } else if constexpr (std::meta::is_variable(mem)) {
1218 if constexpr (Resolution::member_participates(mem, L, pol, Ns)) {
1220 B::template add_variable<mem, Style>(m, session);
1221 }
1222 } else if constexpr (std::meta::is_namespace(mem)) {
1223 // A nested namespace resolves like a leaf under the parent policy (but
1224 // is never welded): it becomes a submodule when it holds participating
1225 // content (then resolved under its *own* policy).
1226 if constexpr (Resolution::namespace_participates(mem, L, pol, Ns)) {
1227 auto sub{B::add_submodule(
1230 }
1231 }
1232 }
1233
1234 B::close_module(m, session);
1235 }
1236
1246 template <rod B, std::meta::info Ns, class Style = naming::none>
1247 static typename B::module_type bind_namespace_as_submodule(
1248 typename B::module_type& m, const char* name = nullptr) {
1249 static_assert(std::meta::is_namespace(Ns),
1250 "welder: weld_namespace_as_submodule<Ns>: Ns must reflect a "
1251 "namespace");
1252 typename B::module_type sub{B::add_submodule(
1253 m,
1256 return sub;
1257 }
1258
1272 template <rod B, std::meta::info Ns, class Style = naming::none, class Pre,
1273 class Post>
1274 static void build_module(typename B::module_type& m, Pre pre, Post post) {
1275 static_assert(std::meta::is_namespace(Ns),
1276 "welder: weld_module<Ns>: Ns must reflect a namespace");
1277 static_assert(std::meta::parent_of(Ns) == ^^::,
1278 "welder: weld_module<Ns>: Ns must be a top-level namespace (its "
1279 "name is meant to be the module name)");
1280 pre(m);
1282 post(m);
1283 }
1284};
1285
1286} // namespace carriages
1287
1292
1303
1306
1307} // namespace welder
Backend-agnostic selection layer: the reflection predicates and selectors that decide what participat...
Backend-agnostic bindability ("can the target language represent this type?").
The core interface concepts welder's static polymorphism rests on, gathered in one catalogue: the cus...
The contract a rod (a welder backend, welder::rods::…::rod) must satisfy to plug into the generic dri...
Definition concepts.hpp:206
Language-agnostic documentation layer: read [[=welder::doc(...)]] annotations off reflected entities ...
The stored forms of the annotation vocabulary.
consteval bool is_overload_leader(std::meta::info fn, lang L, std::meta::info bound_into)
Whether fn is the first (declaration order) member of its Select overload set — the single visit on w...
consteval std::vector< std::meta::info > method_overload_set(std::meta::info fn, lang L, std::meta::info bound_into)
The participating method overloads sharing fn's name and static-ness, from the class where fn is decl...
consteval bool is_operator_candidate(std::meta::info f)
The shape of a bindable member operator.
consteval bool namespace_has_bound(std::meta::info ns, lang L)
Whether ns holds anything that would bind, directly or nested.
consteval bool sole_alias_of_target(lang L, policy_kind pol)
Is Alias the only participating alias in Ns welding its specialization?
Definition carriage.hpp:54
consteval auto ctor_group()
The participating constructors of Type under policy Pol: every bindable-shape constructor (see is_bin...
consteval auto manual_function_group()
The semi-manual (weld_function<Fn>) group: Fn first — the user's named entity resolves the group's ta...
consteval std::vector< std::meta::info > function_overload_set(std::meta::info fn, lang L, std::meta::info bound_into)
The participating free-function overloads sharing fn's name, from fn's declaring namespace,...
consteval bool is_method_candidate(std::meta::info f)
The shape of a bindable method: a plain non-private member function.
consteval bool sole_member_alias_of_target(lang L, policy_kind pol)
Is Alias the only member alias of Outer whose participation would register its target?
Definition carriage.hpp:155
consteval auto overload_group()
Select's overload set for Fn as a fixed-size, splice-ready static array.
consteval bool default_ctor_admitted()
Whether the resolution admits Type's DEFAULT constructor.
consteval bool namespace_has_bindable(std::meta::info ns, lang L)
The greedy twin of namespace_has_bound: whether ns holds any bindable kind (ignoring the weld marker)...
consteval const char * alias_bound_name()
The bound name of the type welded through Alias (a namespace-scope alias to a specialization,...
Definition carriage.hpp:89
consteval bool member_access_admitted(std::meta::info mem, lang L, std::meta::info bound_into)
Is mem's access level admitted for binding under Resolution?
consteval std::vector< std::meta::info > operator_overload_set(std::meta::info fn, lang L, std::meta::info bound_into)
The participating operator overloads sharing fn's target slot (same operator and arity — hence the sa...
consteval bool registered_by_member_alias(std::meta::info scope, std::meta::info type, lang L)
Does a participating member alias of scope name type — i.e.
Definition carriage.hpp:186
consteval bool aggregate_initializable()
Whether to synthesize an aggregate field constructor for T (language L, resolution Resolution).
consteval bool nested_type_registered(std::meta::info type, lang L)
The GATE side of the nested-type sweep: does class-scoped type register with its enclosing class's bi...
Definition carriage.hpp:131
consteval auto native_base_types()
The native bases of Type for L as a static array of type reflections.
consteval bool welded_for(std::meta::info type, lang L)
Is type welded for language L — i.e.
Definition reflect.hpp:26
consteval void assert_callable_bindable()
Assert a function/method/operator/constructor signature binds, unless trusted.
Definition bindable.hpp:300
stitch_welding_carriage carriage
The default carriage — an alias for welder::stitch_welding_carriage.
consteval bool bindable()
Is T bindable to language L under backend B?
Definition bindable.hpp:210
consteval detail::doc_spec< N > doc(const char(&s)[N])
Attach a docstring to a namespace, class, function, or function parameter.
policy_kind
How greedily a type's members are reflected for binding.
@ automatic
Reflect every member unless explicitly excluded (default).
consteval bool member_alias_marks_admissible(std::meta::info mem)
May the annotations on member type-alias mem appear there?
Definition reflect.hpp:109
carriages::basic_carriage< carriages::marker_resolution > stitch_welding_carriage
The stitch-welding carriage (the default): binds only where welder's weld / policy / marks direct — i...
consteval bool alias_welded_for(std::meta::info mem, lang L)
Is the specialization named by alias mem welded for language L — reading the alias's own weld first,...
Definition reflect.hpp:60
lang
The target languages welder ships rods for — but not the whole value space.
Definition lang.hpp:42
ent_kind
The nameable entity kinds welder distinguishes, one per name-style hook — picked by the driver/rod so...
Definition naming.hpp:239
@ class_
a class/struct type → transform_class.
Definition naming.hpp:240
@ enum_
an enum type → transform_enum.
Definition naming.hpp:241
consteval bool protected_welded(std::meta::info type, lang L)
Does type admit its protected members for language L — i.e.
Definition reflect.hpp:155
consteval const char * weld_as_of()
The verbatim weld_as name forced on Ent for language L, or nullptr.
Definition naming.hpp:262
consteval void assert_member_bindable()
Assert the type of a data member / namespace variable binds, unless trusted.
Definition bindable.hpp:288
carriages::basic_carriage< carriages::greedy_resolution<> > tack_welding_carriage
The tack-welding carriage: binds an unmarked library greedily — every reflectable type / function / g...
consteval policy_kind policy_of(std::meta::info type)
The reflection policy declared on type, defaulting to automatic.
Definition reflect.hpp:132
consteval bool alias_marks_admissible(std::meta::info mem)
May the annotations on alias-declaration mem appear there?
Definition reflect.hpp:78
consteval bool member_bound(std::meta::info member, lang L, policy_kind pol)
The core decision a backend asks for each member: does member bind for language L under policy pol?
Definition reflect.hpp:276
constexpr const char * name_of_or(const char *override_)
Resolve a bound name with a call-site override: override_ wins verbatim, nullptr falls back to name_o...
Definition naming.hpp:343
consteval const char * name_of()
The final bound name of Ent (a K-kind entity) for language L under name style Style.
Definition naming.hpp:294
consteval bool names_template_specialization(std::meta::info mem)
Is mem a namespace-scope alias naming a class-template specialization — the one way an instantiation ...
Definition reflect.hpp:43
consteval const char * doc_of()
The doc text on Ent (a class, namespace, function, or parameter), or nullptr.
Definition doc.hpp:138
consteval bool is_nested_type(std::meta::info type)
Is type declared at class scope — a nested (member) type?
Definition carriage.hpp:105
consteval std::vector< std::meta::info > public_bases(std::meta::info type)
The types of the public base classes of type.
Definition reflect.hpp:307
Language-agnostic name styling: reshape a C++ identifier into a target language's naming convention,...
Language-agnostic resolution: given a reflected type/member and a target language,...
A carriage: welder's reflection-driven traversal, parameterized on a Resolution (which markers it obe...
Definition carriage.hpp:467
static auto bind_function(typename B::module_type &m, const char *name=nullptr)
Register free function Fn — with its participating overload siblings — as a module-level function of ...
static B::module_type bind_namespace_as_submodule(typename B::module_type &m, const char *name=nullptr)
Define a submodule of m and bind namespace Ns into it.
static void bind_nested_types(typename B::module_type &m, Cls &cls)
Register the participating member types of Outer onto its class handle cls — the nested-class / neste...
Definition carriage.hpp:708
static void bind_members(Cls &cls)
Flatten the eligible data members, methods and operators of Src onto the class handle cls (a handle f...
Definition carriage.hpp:490
static auto bind_type(typename B::module_type &m, const char *name=nullptr)
Reflect over T and register it via rod B onto module m.
static void bind_class_interior(typename B::module_type &m, Cls &cls)
Everything a class binding contains beyond the class handle itself — shared by bind_type (a module-sc...
Definition carriage.hpp:613
static void bind_nested_enum(typename B::module_type &m, OuterCls &outer, const char *name=nullptr)
Definition carriage.hpp:851
static void bind_namespace(typename B::module_type &m)
Reflect over a whole namespace Ns and expose its members on module m.
static auto bind_enum(typename B::module_type &m, const char *name=nullptr)
Reflect over enum E and register it via rod B onto module m.
Definition carriage.hpp:941
static auto make_nested_enum_of(typename B::module_type &m, OuterCls &outer, const char *name, const char *doc)
make_nested_class_of's enum counterpart: the rod's make_nested_enum when present, else the module-sco...
Definition carriage.hpp:915
static auto make_class_of(typename B::module_type &m, const char *cls_name, const char *doc)
Call the rod's class-creation primitive, preferring the extended declaring-entity-aware form when the...
Definition carriage.hpp:971
static auto bind_variable(typename B::module_type &m, const char *name=nullptr)
Register a single namespace variable Var as an attribute of m.
static void build_module(typename B::module_type &m, Pre pre, Post post)
Fill an existing module out of top-level namespace Ns: pre hook, bind the namespace,...
static void bind_nested_type(typename B::module_type &m, OuterCls &outer, const char *name=nullptr)
Register nested class T onto the class handle of its enclosing type — bind_type's class-scope sibling...
Definition carriage.hpp:814
static auto make_nested_class_of(typename B::module_type &m, OuterCls &outer, const char *cls_name, const char *doc)
Definition carriage.hpp:882
static void emit_enumerators(EnumHandle &e)
The per-enumerator walk shared by bind_enum and bind_nested_enum: each enumerator resolves like a dat...
Definition carriage.hpp:586
Tack-welding resolution: bind an unmarked library greedily.
Definition carriage.hpp:364
static consteval bool alias_participates(std::meta::info mem, lang L, policy_kind pol, std::meta::info)
Greedy: an alias-declared specialization binds like any other type — no weld needed on alias or templ...
Definition carriage.hpp:381
static consteval bool protected_participates(std::meta::info mem, lang L, std::meta::info)
Protected members: the WeldProtected knob (the whole-pass blanket for an unannotatable third-party li...
Definition carriage.hpp:398
static consteval bool is_native_base(std::meta::info, lang, std::meta::info)
Definition carriage.hpp:366
static consteval auto native_bases()
Definition carriage.hpp:371
static consteval bool counts_as_registered(std::meta::info type, lang L)
The gate's registration oracle: a type the greedy pass itself registers — any complete class/enum who...
Definition carriage.hpp:432
static consteval bool namespace_participates(std::meta::info ns, lang L, policy_kind pol, std::meta::info)
Definition carriage.hpp:403
static consteval bool class_member_participates(std::meta::info mem, lang L, policy_kind pol, std::meta::info)
Same as stitch: greedy ignores the weld marker, not the marks — a mark on an individual overload/cons...
Definition carriage.hpp:388
static consteval bool member_participates(std::meta::info mem, lang L, policy_kind pol, std::meta::info)
Definition carriage.hpp:374
static consteval bool participates(std::meta::info, lang)
Definition carriage.hpp:365
Stitch-welding resolution: bind only where welder's markers say to.
Definition carriage.hpp:254
static consteval bool counts_as_registered(std::meta::info type, lang L)
The gate's registration oracle: welded ⇒ registered (the welder::welded_registration rule),...
Definition carriage.hpp:330
static consteval bool class_member_participates(std::meta::info mem, lang L, policy_kind pol, std::meta::info)
A class member (field / method / operator / constructor — and, loosely, an enumerator) participates: ...
Definition carriage.hpp:296
static consteval bool participates(std::meta::info entity, lang L)
A type/function/variable participates iff welded for L.
Definition carriage.hpp:256
static consteval bool is_native_base(std::meta::info base, lang L, std::meta::info)
A base is a separately-registered native base iff the user welded it.
Definition carriage.hpp:262
static consteval auto native_bases()
T's native (welded) base list, for the class handle.
Definition carriage.hpp:268
static consteval bool alias_participates(std::meta::info mem, lang L, policy_kind pol, std::meta::info)
A namespace-scope alias to a class-template specialization participates: welded via the alias's own w...
Definition carriage.hpp:283
static consteval bool namespace_participates(std::meta::info ns, lang L, policy_kind pol, std::meta::info)
A nested namespace participates (recurse + submodule).
Definition carriage.hpp:317
static consteval bool member_participates(std::meta::info mem, lang L, policy_kind pol, std::meta::info)
A namespace member (class/enum/function/variable) participates.
Definition carriage.hpp:274
static consteval bool protected_participates(std::meta::info mem, lang L, std::meta::info)
A protected member is admitted iff its declaring class says so — a policy::weld_protected annotation ...
Definition carriage.hpp:311
The scope-aware registration oracle: Resolution widened with the member-alias registrations of one cl...
Definition carriage.hpp:221
static consteval bool counts_as_registered(std::meta::info type, lang L)
Definition carriage.hpp:222
The identity style: bind every C++ identifier unchanged.
Definition naming.hpp:178