welder 0.1.0
Bindings for annotated C++ types, from C++26 reflection
Loading...
Searching...
No Matches
document.hpp
Go to the documentation of this file.
1#pragma once
2#include <cstddef>
3#include <meta>
4#include <string>
5
6#include <welder/rods/python/trampoline.hpp> // overridable_virtuals / bound_flat
7
32
33namespace welder::inline v0::rods::trampolines {
34
35// --- small consteval text helpers -------------------------------------------
36
39consteval std::string int_string(std::size_t n) {
40 if (n == 0)
41 return "0";
42 std::string s{};
43 for (; n; n /= 10)
44 s.insert(s.begin(), char('0' + n % 10));
45 return s;
46}
47
51consteval std::string cpp_qualified_name(std::meta::info ent) {
52 std::string tail{};
53 if (std::meta::has_identifier(ent))
54 tail = std::meta::identifier_of(ent);
55 for (std::meta::info p{std::meta::parent_of(ent)};
56 p != std::meta::info{} && p != ^^:: && std::meta::has_identifier(p);
57 p = std::meta::parent_of(p))
58 tail = std::string{std::meta::identifier_of(p)} + "::" + tail;
59 return "::" + tail;
60}
61
64consteval std::string trampoline_ident(std::meta::info type) {
65 std::string s{};
66 if (std::meta::has_identifier(type))
67 s = std::meta::identifier_of(type);
68 for (std::meta::info p{std::meta::parent_of(type)};
69 p != std::meta::info{} && p != ^^:: && std::meta::has_identifier(p);
70 p = std::meta::parent_of(p))
71 s = std::string{std::meta::identifier_of(p)} + "_" + s;
72 return s + "_trampoline";
73}
74
82consteval bool is_c_variadic(std::meta::info fn) {
83 std::string s{std::meta::display_string_of(std::meta::type_of(fn))};
84 return s.find("...") != std::string::npos;
85}
86
89consteval std::string qualifier_tokens(std::meta::info fn) {
90 std::string q{};
91 if (std::meta::is_const(fn))
92 q += " const";
93 if (std::meta::is_volatile(fn))
94 q += " volatile";
95 if (std::meta::is_lvalue_reference_qualified(fn))
96 q += " &";
97 if (std::meta::is_rvalue_reference_qualified(fn))
98 q += " &&";
99 if (std::meta::is_noexcept(fn))
100 q += " noexcept";
101 return q;
102}
103
105inline constexpr const char* generated_namespace{
106 "::welder::rods::trampolines::generated"};
107
115consteval std::string render_trampoline(std::meta::info type) {
116 const std::string base{cpp_qualified_name(type)};
117 const std::string ident{trampoline_ident(type)};
118 std::string s{};
119 s += "struct " + ident + " : " + base + " {\n";
120 s += " WELDER_PY_TRAMPOLINE(" + base + ");\n";
121
122 std::size_t k{0};
123 for (auto slot : ::welder::rods::python::overridable_virtuals(type)) {
124 const std::string name{std::meta::identifier_of(slot)};
125 if (is_c_variadic(slot)) {
126 s += " static_assert(false, \"welder: '" + base + "::" + name +
127 "' is a C-variadic virtual; C++26 reflection cannot reproduce its "
128 "'...' parameter. Mark it "
129 "[[=welder::rods::python::bind_flat]] to bind it non-overridably.\");\n";
130 ++k; // keep k aligned with the overridable_virtuals index for later slots
131 continue;
132 }
133 // The reflected slot, re-derived in the generated TU (same order as here).
134 const std::string idx{"::welder::rods::python::overridable_virtuals(^^" + base +
135 ")[" + int_string(k) + "]"};
136 s += " [: ::std::meta::return_type_of(" + idx + ") :] " + name + "(";
137 std::string args{};
138 std::size_t j{0};
139 for (auto p : std::meta::parameters_of(slot)) {
140 (void)p;
141 if (j) {
142 s += ", ";
143 args += ", ";
144 }
145 const std::string js{int_string(j)};
146 s += "[: ::std::meta::type_of(::std::meta::parameters_of(" + idx + ")[" +
147 js + "]) :] a" + js;
148 args += "a" + js;
149 ++j;
150 }
151 // The slot-taking macro form: dispatch keys on the slot's reflection (never
152 // `^^Base::name`, which is ill-formed for an overloaded virtual), while the
153 // textual name spells the qualified base fallback, where overload resolution
154 // picks the right overload from the forwarded parameters.
155 s += ")" + qualifier_tokens(slot) + " override { WELDER_PY_OVERRIDE_AS((" +
156 idx + "), " + name + (args.empty() ? "" : ", " + args) + "); }\n";
157 ++k;
158 }
159 s += "};\n";
160 return s;
161}
162
164consteval std::string render_registration(std::meta::info type) {
165 return "template <> constexpr ::std::meta::info\n"
166 " ::welder::rods::python::trampoline_for<" +
167 cpp_qualified_name(type) + "> = ^^" + generated_namespace +
168 "::" + trampoline_ident(type) + ";\n";
169}
170
174struct document {
175 std::string structs{};
176 std::string registrations{};
177
184 template <std::meta::info Type>
185 void add() {
186 // The generated text must SPELL the type in C++ (base clause, the
187 // trampoline_for key, the slot re-derivations) — impossible for a bare
188 // class-template specialization, which has no identifier and whose
189 // template-id cannot be respelled faithfully from reflection. The alias
190 // is that spelling: welding `using IntRing = Ring<int>;` in the swept
191 // namespace routes the carriage here with the alias as @a Type.
192 static_assert(std::meta::has_identifier(Type),
193 "welder: cannot generate a trampoline for a class-template "
194 "specialization spelled directly (it has no identifier); "
195 "declare a namespace-scope alias — using IntRing = "
196 "Ring<int>; — and weld that instead");
197 structs += std::define_static_string(render_trampoline(Type));
198 registrations += std::define_static_string(render_registration(Type));
199 }
200
202 std::string render() const {
203 std::string out{};
204 out += "#pragma once\n";
205 out += "// AUTO-GENERATED by welder (welder::rods::trampolines). Do not edit.\n";
206 out += "//\n";
207 out += "// Include AFTER your welded type headers and the active backend's\n";
208 out += "// <welder/rods/python/{pybind11,nanobind}/trampoline.hpp>.\n";
209 out += "#include <meta>\n";
210 out += "#include <welder/rods/python/trampoline.hpp>\n\n";
211 out += "namespace welder::rods::trampolines::generated {\n\n";
212 out += structs;
213 out += "\n} // namespace welder::rods::trampolines::generated\n\n";
214 out += registrations;
215 return out;
216 }
217};
218
219} // namespace welder::rods::trampolines
consteval std::vector< std::meta::info > overridable_virtuals(std::meta::info type)
Every overridable virtual slot of type — the ones welder routes through a trampoline — folding in vir...
consteval std::string cpp_qualified_name(std::meta::info ent)
The fully ::-qualified name of a namespace-scope entity, leading :: included (geometry::Point → "geom...
Definition document.hpp:51
consteval std::string render_trampoline(std::meta::info type)
Render the trampoline struct for welded virtual type type — one override per overridable virtual,...
Definition document.hpp:115
consteval bool is_c_variadic(std::meta::info fn)
Is fn a C-style variadic function (R(…, ...))?
Definition document.hpp:82
consteval std::string int_string(std::size_t n)
Render a non-negative integer as decimal (constexpr std::to_string is not available on gcc-16 in a co...
Definition document.hpp:39
constexpr const char * generated_namespace
The namespace the generated trampoline structs are emitted into (fully qualified).
Definition document.hpp:105
consteval std::string render_registration(std::meta::info type)
The trampoline_for<type> specialization pointing at type's generated struct.
Definition document.hpp:164
consteval std::string trampoline_ident(std::meta::info type)
A collision-free identifier for type's generated trampoline: its qualified name with :: folded to _ (...
Definition document.hpp:64
consteval std::string qualifier_tokens(std::meta::info fn)
The trailing cv / ref-qualifier / noexcept tokens of a member function fn, in grammatical order (" co...
Definition document.hpp:89
The growing generated header: the trampoline struct bodies and their trampoline_for registrations,...
Definition document.hpp:174
std::string structs
Accumulated trampoline struct definitions.
Definition document.hpp:175
std::string render() const
The finished, self-contained header text.
Definition document.hpp:202
void add()
Append the generated trampoline + registration for welded virtual Type.
Definition document.hpp:185
std::string registrations
Accumulated trampoline_for specializations.
Definition document.hpp:176
Virtual-function overriding support shared by welder's Python backends.