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
38inline void emit_doc_comment(std::string& out, const char* text,
39 std::string_view indent = {}) {
40 if (!text || !*text)
41 return;
42 out += indent;
43 out += "--- ";
44 for (const char* c{text}; *c; ++c) {
45 out += *c;
46 if (*c == '\n' && c[1] != '\0') {
47 out += indent;
48 out += "--- ";
49 }
50 }
51 out += '\n';
52}
53
58inline std::string one_line(const char* text) {
59 std::string out{};
60 if (!text)
61 return out;
62 for (const char* c{text}; *c; ++c)
63 out += (*c == '\n') ? ' ' : *c;
64 return out;
65}
66
67// --- the C++ -> LuaCATS type map --------------------------------------------
68
77consteval std::string qualified_name(std::meta::info ent) {
78 std::vector<std::string> parts{};
79 if (std::meta::has_identifier(ent))
80 parts.emplace_back(std::meta::identifier_of(ent));
81 std::meta::info p{std::meta::parent_of(ent)};
82 while (p != ^^:: &&
83 (std::meta::is_namespace(p) ||
84 (std::meta::is_type(p) && std::meta::is_class_type(p)))) {
85 if (std::meta::has_identifier(p))
86 parts.emplace_back(std::meta::identifier_of(p));
87 p = std::meta::parent_of(p);
88 }
89 std::string out{};
90 for (auto it{parts.rbegin()}; it != parts.rend(); ++it) {
91 if (!out.empty())
92 out += '.';
93 out += *it;
94 }
95 return out;
96}
97
103consteval bool type_trait(std::meta::info trait_var, std::meta::info t) {
104 return std::meta::extract<bool>(std::meta::substitute(trait_var, {t}));
105}
106
112consteval bool is_wrapper(std::meta::info type, std::meta::info& tmpl_out) {
113 if (!std::meta::has_template_arguments(type))
114 return false;
115 tmpl_out = std::meta::template_of(type);
116 return true;
117}
118
128consteval std::string lua_type_string(std::meta::info type) {
129 namespace m = std::meta;
130 const m::info w{m::dealias(m::substitute(^^std::remove_cvref_t, {type}))};
131
132 // String-like (handled before the arithmetic/class buckets).
133 if (w == m::dealias(^^std::string) || w == m::dealias(^^std::string_view))
134 return "string";
135 if (type_trait(^^std::is_pointer_v, w)) {
136 const m::info pointee{m::dealias(m::substitute(
137 ^^std::remove_cv_t, {m::substitute(^^std::remove_pointer_t, {w})}))};
138 if (pointee == ^^char)
139 return "string";
140 return lua_type_string(pointee); // a pointer to a value type = that type
141 }
142
143 // Element-wise STL wrappers.
144 m::info tmpl{};
145 if (is_wrapper(w, tmpl)) {
146 const auto args{m::template_arguments_of(w)};
147 auto elem = [&](std::size_t i) { return lua_type_string(args[i]); };
148 if (tmpl == ^^std::vector || tmpl == ^^std::list || tmpl == ^^std::deque ||
149 tmpl == ^^std::set || tmpl == ^^std::multiset ||
150 tmpl == ^^std::unordered_set || tmpl == ^^std::unordered_multiset ||
151 tmpl == ^^std::array)
152 return elem(0) + "[]";
153 if (tmpl == ^^std::map || tmpl == ^^std::multimap ||
154 tmpl == ^^std::unordered_map || tmpl == ^^std::unordered_multimap)
155 return "table<" + elem(0) + ", " + elem(1) + ">";
156 if (tmpl == ^^std::optional)
157 return elem(0) + "?";
158 if (tmpl == ^^std::shared_ptr || tmpl == ^^std::unique_ptr)
159 return elem(0);
160 if (tmpl == ^^std::pair)
161 return "{ [1]: " + elem(0) + ", [2]: " + elem(1) + " }";
162 if (tmpl == ^^std::variant) {
163 std::string out{};
164 for (std::size_t i{0}; i < args.size(); ++i)
165 out += (i ? "|" : "") + lua_type_string(args[i]);
166 return out;
167 }
168 // std::tuple and any other specialization fall through to the class map.
169 }
170
171 if (w == ^^bool)
172 return "boolean";
173 if (type_trait(^^std::is_integral_v, w))
174 return "integer";
175 if (type_trait(^^std::is_floating_point_v, w))
176 return "number";
177 if (m::is_enum_type(w) || m::is_class_type(w))
178 return qualified_name(w);
179 return "any";
180}
181
186consteval const char* lua_type(std::meta::info type) {
187 return std::define_static_string(lua_type_string(type));
188}
189
194template <class U>
195inline constexpr bool is_native_lua =
196 std::is_arithmetic_v<U> ||
197 std::is_same_v<std::remove_cv_t<U>, std::string> ||
198 std::is_same_v<std::remove_cv_t<U>, std::string_view> ||
199 std::is_same_v<std::remove_cv_t<std::remove_pointer_t<std::remove_cvref_t<U>>>,
200 char>;
201
202// --- the C++ -> LuaCATS operator map ----------------------------------------
203
225consteval const char* operator_luacats(std::meta::info f) {
226 using std::meta::operators;
227 const bool unary{::welder::detail::is_unary_operator(f)};
228 switch (std::meta::operator_of(f)) {
229 case operators::op_plus: return unary ? nullptr : "add";
230 case operators::op_minus: return unary ? "unm" : "sub";
231 case operators::op_star: return unary ? nullptr : "mul";
232 case operators::op_slash: return "div";
233 case operators::op_percent: return "mod";
234 case operators::op_parentheses: return "call";
235 // Bitwise (Lua 5.3+). C++ operator^ is XOR (→ bxor), NOT power (Lua ^).
236 case operators::op_caret: return "bxor";
237 case operators::op_tilde: return unary ? "bnot" : nullptr;
238 case operators::op_ampersand: return unary ? nullptr : "band"; // unary & = address-of
239 case operators::op_pipe: return "bor";
240 case operators::op_less_less: return "shl";
241 case operators::op_greater_greater: return "shr";
242 default: return nullptr; // ==/</<=/[], !=/>/>=: not a LuaCATS @operator
243 }
244}
245
246} // 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 an operator function is unary vs binary.
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:103
constexpr bool is_native_lua
Whether the backend converts U without welder registering a type: scalars, strings and char*.
Definition type_map.hpp:195
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:186
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:77
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:58
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:112
consteval std::string lua_type_string(std::meta::info type)
The LuaCATS type name for a C++ type reflection.
Definition type_map.hpp:128
void emit_doc_comment(std::string &out, const char *text, std::string_view indent={})
Append text as --- comment lines (each source line prefixed), so a multiline summary lands as a LuaC...
Definition type_map.hpp:38
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:225