welder 0.1.0
Bindings for annotated C++ types, from C++26 reflection
Loading...
Searching...
No Matches
naming.hpp
Go to the documentation of this file.
1#pragma once
2#include <meta>
3#include <stdexcept> // name_of_or: missing-override diagnostic
4#include <string>
5#include <string_view>
6#include <vector>
7
8#include <welder/concepts.hpp> // the name_style concept (welder::naming::name_style)
9
45
46namespace welder::inline v0::naming {
47
48// --- identifier word-splitting ----------------------------------------------
49
63consteval std::vector<std::string> split_words(std::string_view id) {
64 auto is_upper = [](char c) { return c >= 'A' && c <= 'Z'; };
65 auto is_lower = [](char c) { return c >= 'a' && c <= 'z'; };
66 auto is_digit = [](char c) { return c >= '0' && c <= '9'; };
67 auto to_lower = [&](char c) { return is_upper(c) ? char(c - 'A' + 'a') : c; };
68
69 std::vector<std::string> words{};
70 std::string cur{};
71 auto flush = [&] {
72 if (!cur.empty()) {
73 words.push_back(cur);
74 cur.clear();
75 }
76 };
77 for (std::string::size_type i{0}; i < id.size(); ++i) {
78 const char c{id[i]};
79 if (c == '_' || c == '-' || c == ' ') {
80 flush();
81 continue;
82 }
83 if (!cur.empty()) {
84 const char prev{id[i - 1]};
85 const bool hump{is_upper(c) && (is_lower(prev) || is_digit(prev))};
86 const bool acronym_end{is_upper(c) && is_upper(prev) &&
87 i + 1 < id.size() && is_lower(id[i + 1])};
88 if (hump || acronym_end)
89 flush();
90 }
91 cur.push_back(to_lower(c));
92 }
93 flush();
94 return words;
95}
96
97// --- word joiners (the common conventions) ----------------------------------
98
107
112consteval std::string join_words(const std::vector<std::string>& words,
113 case_kind kind) {
114 auto upper = [](char c) { return (c >= 'a' && c <= 'z') ? char(c - 'a' + 'A') : c; };
115 auto cap = [&](std::string w) {
116 if (!w.empty())
117 w[0] = upper(w[0]);
118 return w;
119 };
120 std::string out{};
121 for (std::string::size_type i{0}; i < words.size(); ++i) {
122 switch (kind) {
123 case case_kind::snake:
124 if (i)
125 out += '_';
126 out += words[i];
127 break;
129 if (i)
130 out += '_';
131 for (char c : words[i])
132 out += upper(c);
133 break;
134 case case_kind::kebab:
135 if (i)
136 out += '-';
137 out += words[i];
138 break;
139 case case_kind::camel:
140 out += i ? cap(words[i]) : words[i];
141 break;
143 out += cap(words[i]);
144 break;
145 }
146 }
147 return out;
148}
149
157consteval std::string restyle(std::string_view id, case_kind kind) {
158 std::string::size_type lead{0};
159 while (lead < id.size() && id[lead] == '_')
160 ++lead;
161 if (lead == id.size()) // empty or all underscores: nothing to restyle
162 return std::string{id};
163 std::string::size_type trail{0};
164 while (id[id.size() - 1 - trail] == '_')
165 ++trail;
166 return std::string(lead, '_') + join_words(split_words(id), kind) +
167 std::string(trail, '_');
168}
169
170// --- the style customization point ------------------------------------------
171//
172// The `name_style` concept — the per-kind hook contract a style below implements —
173// lives in <welder/concepts.hpp> (with welder's other interface concepts).
174
178struct none {
179 static consteval std::string transform_class(std::meta::info e) { return id(e); }
180 static consteval std::string transform_enum(std::meta::info e) { return id(e); }
181 static consteval std::string transform_enumerator(std::meta::info e) { return id(e); }
182 static consteval std::string transform_method(std::meta::info e) { return id(e); }
183 static consteval std::string transform_static_method(std::meta::info e) { return id(e); }
184 static consteval std::string transform_function(std::meta::info e) { return id(e); }
185 static consteval std::string transform_field(std::meta::info e) { return id(e); }
186 static consteval std::string transform_variable(std::meta::info e) { return id(e); }
187 static consteval std::string transform_submodule(std::meta::info e) { return id(e); }
188
189 private:
190 static consteval std::string id(std::meta::info e) {
191 return std::string{std::meta::identifier_of(e)};
192 }
193};
194static_assert(name_style<none>, "welder: naming::none is not a name_style");
195
200template <case_kind Kind>
201struct uniform {
202 static consteval std::string transform_class(std::meta::info e) { return in(e); }
203 static consteval std::string transform_enum(std::meta::info e) { return in(e); }
204 static consteval std::string transform_enumerator(std::meta::info e) { return in(e); }
205 static consteval std::string transform_method(std::meta::info e) { return in(e); }
206 static consteval std::string transform_static_method(std::meta::info e) { return in(e); }
207 static consteval std::string transform_function(std::meta::info e) { return in(e); }
208 static consteval std::string transform_field(std::meta::info e) { return in(e); }
209 static consteval std::string transform_variable(std::meta::info e) { return in(e); }
210 static consteval std::string transform_submodule(std::meta::info e) { return in(e); }
211
212 private:
213 static consteval std::string in(std::meta::info e) {
214 return restyle(std::meta::identifier_of(e), Kind);
215 }
216};
217
218// Each predefined style is checked against the `name_style` concept right at its
219// definition, so a hook that drifts out of contract (a missing or wrongly-typed
220// transform_*) fails loudly here rather than at some rod's call site.
222static_assert(name_style<snake_case>, "welder: naming::snake_case is not a name_style");
225 "welder: naming::screaming_snake_case is not a name_style");
227static_assert(name_style<kebab_case>, "welder: naming::kebab_case is not a name_style");
229static_assert(name_style<camel_case>, "welder: naming::camel_case is not a name_style");
231static_assert(name_style<pascal_case>, "welder: naming::pascal_case is not a name_style");
232
233} // namespace welder::naming
234
235namespace welder::inline v0 {
236
250
261template <std::meta::info Ent, lang L>
262consteval const char* weld_as_of() {
263 template for (constexpr auto a :
264 std::define_static_array(std::meta::annotations_of(Ent))) {
265 constexpr std::meta::info t{std::meta::type_of(a)};
266 if constexpr (std::meta::has_template_arguments(t) &&
267 std::meta::template_of(t) == ^^detail::weld_as_spec) {
268 using spec_type = [:t:];
269 constexpr auto spec{std::meta::extract<spec_type>(a)};
270 if constexpr (spec.mask == 0 || (spec.mask & lang_bit(L)) != 0)
271 return std::define_static_string(spec.name.data);
272 }
273 }
274 return nullptr;
275}
276
293template <std::meta::info Ent, lang L, class Style, ent_kind K>
294consteval const char* name_of() {
295 if (const char* forced{weld_as_of<Ent, L>()})
296 return forced;
297 if constexpr (K == ent_kind::class_)
298 return std::define_static_string(Style::transform_class(Ent));
299 else if constexpr (K == ent_kind::enum_)
300 return std::define_static_string(Style::transform_enum(Ent));
301 else if constexpr (K == ent_kind::enumerator)
302 return std::define_static_string(Style::transform_enumerator(Ent));
303 else if constexpr (K == ent_kind::method)
304 return std::define_static_string(Style::transform_method(Ent));
305 else if constexpr (K == ent_kind::static_method)
306 return std::define_static_string(Style::transform_static_method(Ent));
307 else if constexpr (K == ent_kind::function)
308 return std::define_static_string(Style::transform_function(Ent));
309 else if constexpr (K == ent_kind::field)
310 return std::define_static_string(Style::transform_field(Ent));
311 else if constexpr (K == ent_kind::variable)
312 return std::define_static_string(Style::transform_variable(Ent));
313 else // ent_kind::submodule
314 return std::define_static_string(Style::transform_submodule(Ent));
315}
316
342template <std::meta::info Ent, lang L, class Style, ent_kind K>
343constexpr const char* name_of_or(const char* override_) {
344 if (override_)
345 return override_;
346 if constexpr (weld_as_of<Ent, L>() != nullptr || std::meta::has_identifier(Ent)) {
348 } else {
349 throw std::invalid_argument{
350 "welder: this entity has no identifier (a template instantiation?) and "
351 "no [[=welder::weld_as]] — pass an explicit name at the weld_* call"};
352 }
353}
354
355} // namespace welder
The core interface concepts welder's static polymorphism rests on, gathered in one catalogue: the cus...
A name style names every kind of entity welder can bind, through one hook per kind.
Definition concepts.hpp:386
consteval std::string restyle(std::string_view id, case_kind kind)
Re-spell identifier id in convention kind, preserving any leading and trailing underscore run (_priva...
Definition naming.hpp:157
uniform< case_kind::camel > camel_case
fooBar everywhere
Definition naming.hpp:228
uniform< case_kind::pascal > pascal_case
FooBar everywhere
Definition naming.hpp:230
case_kind
The naming convention a joiner emits.
Definition naming.hpp:100
consteval std::vector< std::string > split_words(std::string_view id)
Split an identifier into lower-cased words, however it was spelled.
Definition naming.hpp:63
uniform< case_kind::kebab > kebab_case
foo-bar everywhere
Definition naming.hpp:226
uniform< case_kind::screaming_snake > screaming_snake_case
FOO_BAR everywhere
Definition naming.hpp:223
consteval std::string join_words(const std::vector< std::string > &words, case_kind kind)
Join already-lower-cased words in convention kind.
Definition naming.hpp:112
uniform< case_kind::snake > snake_case
foo_bar everywhere
Definition naming.hpp:221
ent_kind
The nameable entity kinds welder distinguishes, one per name-style hook — picked by the driver/rod so...
Definition naming.hpp:239
@ field
a data member → transform_field.
Definition naming.hpp:246
@ submodule
a namespace bound as a submodule → transform_submodule.
Definition naming.hpp:248
@ static_method
a static member function → transform_static_method.
Definition naming.hpp:244
@ class_
a class/struct type → transform_class.
Definition naming.hpp:240
@ function
a free function → transform_function.
Definition naming.hpp:245
@ variable
a namespace variable → transform_variable.
Definition naming.hpp:247
@ method
a member function → transform_method.
Definition naming.hpp:243
@ enumerator
an enumerator → transform_enumerator.
Definition naming.hpp:242
@ enum_
an enum type → transform_enum.
Definition naming.hpp:241
consteval const char * weld_as_of()
The verbatim weld_as name forced on Ent for language L, or nullptr.
Definition naming.hpp:262
consteval unsigned lang_bit(lang l)
The single-language bit for l within a language mask.
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
The stored form of a weld_as annotation: a forced target-language name.
The identity style: bind every C++ identifier unchanged.
Definition naming.hpp:178
static consteval std::string transform_enumerator(std::meta::info e)
Definition naming.hpp:181
static consteval std::string transform_field(std::meta::info e)
Definition naming.hpp:185
static consteval std::string transform_variable(std::meta::info e)
Definition naming.hpp:186
static consteval std::string transform_method(std::meta::info e)
Definition naming.hpp:182
static consteval std::string transform_enum(std::meta::info e)
Definition naming.hpp:180
static consteval std::string id(std::meta::info e)
Definition naming.hpp:190
static consteval std::string transform_function(std::meta::info e)
Definition naming.hpp:184
static consteval std::string transform_submodule(std::meta::info e)
Definition naming.hpp:187
static consteval std::string transform_class(std::meta::info e)
Definition naming.hpp:179
static consteval std::string transform_static_method(std::meta::info e)
Definition naming.hpp:183
A single-convention style: reshape every kind to convention Kind, whatever the source spelling.
Definition naming.hpp:201
static consteval std::string transform_method(std::meta::info e)
Definition naming.hpp:205
static consteval std::string transform_function(std::meta::info e)
Definition naming.hpp:207
static consteval std::string transform_static_method(std::meta::info e)
Definition naming.hpp:206
static consteval std::string transform_submodule(std::meta::info e)
Definition naming.hpp:210
static consteval std::string transform_variable(std::meta::info e)
Definition naming.hpp:209
static consteval std::string in(std::meta::info e)
Definition naming.hpp:213
static consteval std::string transform_field(std::meta::info e)
Definition naming.hpp:208
static consteval std::string transform_class(std::meta::info e)
Definition naming.hpp:202
static consteval std::string transform_enumerator(std::meta::info e)
Definition naming.hpp:204
static consteval std::string transform_enum(std::meta::info e)
Definition naming.hpp:203