welder 0.1.0
Bindings for annotated C++ types, from C++26 reflection
Loading...
Searching...
No Matches
type_map.hpp
Go to the documentation of this file.
1#pragma once
2#include <cstddef>
3#include <meta>
4#include <string>
5#include <string_view>
6#include <type_traits>
7#include <vector>
8
9#include <welder/bind_traits.hpp> // is_unary_operator
10#include <welder/bindable.hpp> // the STL-wrapper template names + reflect layer
11
26
27namespace welder::inline v0::rods::luacats {
28
29// --- small text helpers -----------------------------------------------------
30
36inline void emit_doc_comment(std::string& out, const char* text) {
37 if (!text || !*text)
38 return;
39 out += "--- ";
40 for (const char* c{text}; *c; ++c) {
41 out += *c;
42 if (*c == '\n' && c[1] != '\0')
43 out += "--- ";
44 }
45 out += '\n';
46}
47
52inline std::string one_line(const char* text) {
53 std::string out{};
54 if (!text)
55 return out;
56 for (const char* c{text}; *c; ++c)
57 out += (*c == '\n') ? ' ' : *c;
58 return out;
59}
60
61// --- the C++ -> LuaCATS type map --------------------------------------------
62
71consteval std::string qualified_name(std::meta::info ent) {
72 std::vector<std::string> parts{};
73 if (std::meta::has_identifier(ent))
74 parts.emplace_back(std::meta::identifier_of(ent));
75 std::meta::info p{std::meta::parent_of(ent)};
76 while (p != ^^:: &&
77 (std::meta::is_namespace(p) ||
78 (std::meta::is_type(p) && std::meta::is_class_type(p)))) {
79 if (std::meta::has_identifier(p))
80 parts.emplace_back(std::meta::identifier_of(p));
81 p = std::meta::parent_of(p);
82 }
83 std::string out{};
84 for (auto it{parts.rbegin()}; it != parts.rend(); ++it) {
85 if (!out.empty())
86 out += '.';
87 out += *it;
88 }
89 return out;
90}
91
97consteval bool type_trait(std::meta::info trait_var, std::meta::info t) {
98 return std::meta::extract<bool>(std::meta::substitute(trait_var, {t}));
99}
100
106consteval bool is_wrapper(std::meta::info type, std::meta::info& tmpl_out) {
107 if (!std::meta::has_template_arguments(type))
108 return false;
109 tmpl_out = std::meta::template_of(type);
110 return true;
111}
112
122consteval std::string lua_type_string(std::meta::info type) {
123 namespace m = std::meta;
124 const m::info w{m::dealias(m::substitute(^^std::remove_cvref_t, {type}))};
125
126 // String-like (handled before the arithmetic/class buckets).
127 if (w == m::dealias(^^std::string) || w == m::dealias(^^std::string_view))
128 return "string";
129 if (type_trait(^^std::is_pointer_v, w)) {
130 const m::info pointee{m::dealias(m::substitute(
131 ^^std::remove_cv_t, {m::substitute(^^std::remove_pointer_t, {w})}))};
132 if (pointee == ^^char)
133 return "string";
134 return lua_type_string(pointee); // a pointer to a value type = that type
135 }
136
137 // Element-wise STL wrappers.
138 m::info tmpl{};
139 if (is_wrapper(w, tmpl)) {
140 const auto args{m::template_arguments_of(w)};
141 auto elem = [&](std::size_t i) { return lua_type_string(args[i]); };
142 if (tmpl == ^^std::vector || tmpl == ^^std::list || tmpl == ^^std::deque ||
143 tmpl == ^^std::set || tmpl == ^^std::multiset ||
144 tmpl == ^^std::unordered_set || tmpl == ^^std::unordered_multiset ||
145 tmpl == ^^std::array)
146 return elem(0) + "[]";
147 if (tmpl == ^^std::map || tmpl == ^^std::multimap ||
148 tmpl == ^^std::unordered_map || tmpl == ^^std::unordered_multimap)
149 return "table<" + elem(0) + ", " + elem(1) + ">";
150 if (tmpl == ^^std::optional)
151 return elem(0) + "?";
152 if (tmpl == ^^std::shared_ptr || tmpl == ^^std::unique_ptr)
153 return elem(0);
154 if (tmpl == ^^std::pair)
155 return "{ [1]: " + elem(0) + ", [2]: " + elem(1) + " }";
156 if (tmpl == ^^std::variant) {
157 std::string out{};
158 for (std::size_t i{0}; i < args.size(); ++i)
159 out += (i ? "|" : "") + lua_type_string(args[i]);
160 return out;
161 }
162 // std::tuple and any other specialization fall through to the class map.
163 }
164
165 if (w == ^^bool)
166 return "boolean";
167 if (type_trait(^^std::is_integral_v, w))
168 return "integer";
169 if (type_trait(^^std::is_floating_point_v, w))
170 return "number";
171 if (m::is_enum_type(w) || m::is_class_type(w))
172 return qualified_name(w);
173 return "any";
174}
175
180consteval const char* lua_type(std::meta::info type) {
181 return std::define_static_string(lua_type_string(type));
182}
183
188template <class U>
189inline constexpr bool is_native_lua =
190 std::is_arithmetic_v<U> ||
191 std::is_same_v<std::remove_cv_t<U>, std::string> ||
192 std::is_same_v<std::remove_cv_t<U>, std::string_view> ||
193 std::is_same_v<std::remove_cv_t<std::remove_pointer_t<std::remove_cvref_t<U>>>,
194 char>;
195
196// --- the C++ -> LuaCATS operator map ----------------------------------------
197
219consteval const char* operator_luacats(std::meta::info f) {
220 using std::meta::operators;
221 const bool unary{::welder::detail::is_unary_operator(f)};
222 switch (std::meta::operator_of(f)) {
223 case operators::op_plus: return unary ? nullptr : "add";
224 case operators::op_minus: return unary ? "unm" : "sub";
225 case operators::op_star: return unary ? nullptr : "mul";
226 case operators::op_slash: return "div";
227 case operators::op_percent: return "mod";
228 case operators::op_parentheses: return "call";
229 // Bitwise (Lua 5.3+). C++ operator^ is XOR (→ bxor), NOT power (Lua ^).
230 case operators::op_caret: return "bxor";
231 case operators::op_tilde: return unary ? "bnot" : nullptr;
232 case operators::op_ampersand: return unary ? nullptr : "band"; // unary & = address-of
233 case operators::op_pipe: return "bor";
234 case operators::op_less_less: return "shl";
235 case operators::op_greater_greater: return "shr";
236 default: return nullptr; // ==/</<=/[], !=/>/>=: not a LuaCATS @operator
237 }
238}
239
240} // namespace welder::rods::luacats
Backend-agnostic selection layer: the reflection predicates and selectors that decide what participat...
Backend-agnostic bindability ("can the target language represent this type?").
consteval bool is_unary_operator(std::meta::info f)
Whether a member operator is unary (0 parameters) vs binary (1 parameter).
consteval bool type_trait(std::meta::info trait_var, std::meta::info t)
Evaluate a standard unary type-trait variable template (e.g.
Definition type_map.hpp:97
constexpr bool is_native_lua
Whether the backend converts U without welder registering a type: scalars, strings and char*.
Definition type_map.hpp:189
consteval const char * lua_type(std::meta::info type)
lua_type_string as a static-storage C string, callable on a constant type reflection.
Definition type_map.hpp:180
consteval std::string qualified_name(std::meta::info ent)
The dotted LuaCATS name of a namespace-or-type reflection: its own identifier prefixed by each enclos...
Definition type_map.hpp:71
std::string one_line(const char *text)
A one-line description for a @field/@param/@return tail: newlines in text collapse to spaces (LuaCATS...
Definition type_map.hpp:52
consteval bool is_wrapper(std::meta::info type, std::meta::info &tmpl_out)
Whether type (already a bare type) is a listed element-wise wrapper whose LuaCATS spelling this map r...
Definition type_map.hpp:106
consteval std::string lua_type_string(std::meta::info type)
The LuaCATS type name for a C++ type reflection.
Definition type_map.hpp:122
void emit_doc_comment(std::string &out, const char *text)
Append text as --- comment lines (each source line prefixed), so a multiline summary lands as a LuaC...
Definition type_map.hpp:36
consteval const char * operator_luacats(std::meta::info f)
A member operator's LuaCATS ---@operator name, or nullptr if not rendered.
Definition type_map.hpp:219