Skip to content

Commit 80ec7bf

Browse files
JohelEGPDyXel
andcommitted
feat: evaluate program-defined metafunctions (based on #797)
A metafunction is normal Cpp2 code compiled as part of a library. When parsing a declaration that `@`-uses the metafunction, the library is loaded and the metafunction invoked on the declaration. The reflection API is available by default to Cpp2 code (via `cpp2util.h`). The implementation of the API is provided by the `cppfront` executable. For this to work, compiling `cppfront` should export its symbols (for an explanation, see <https://cmake.org/cmake/help/latest/prop_tgt/ENABLE_EXPORTS.html>). For `cppfront` to emit program-defined metafunctions, the environment variable `CPPFRONT_METAFUNCTION_LIBRARY` should be set to the library's path. For `cppfront` to load program-defined metafunctions, the environment variable `CPPFRONT_METAFUNCTION_LIBRARIES` should be set to the `:`-separated library paths of the used metafunctions. Here is an example of program-defined metafunctions. The commands were cleaned up from the CMake buildsystem in #797. `metafunctions.cpp2`: ```Cpp2 greeter: (inout t: cpp2::meta::type_declaration) = { t.add_member($R"(say_hi: () = std::cout << "Hello, world!\nFrom (t.name())$\n";)"); } ``` `main.cpp2`: ```Cpp2 my_class: @greeter type = { } main: () = my_class().say_hi(); ``` Build `cppfront`: ```bash g++ -std=c++20 -o cppfront.cpp.o -c cppfront.cpp g++ -Wl,--export-dynamic -rdynamic cppfront.cpp.o -o cppfront ``` Build `metafunctions`: ```bash CPPFRONT_METAFUNCTION_LIBRARY=libmetafunctions.so ./cppfront metafunctions.cpp2 g++ -std=c++20 -fPIC -o metafunctions.cpp.o -c metafunctions.cpp g++ -fPIC -shared -Wl,-soname,libmetafunctions.so -o libmetafunctions.so metafunctions.cpp.o ``` Build and run `main`: ```bash CPPFRONT_METAFUNCTION_LIBRARIES=libmetafunctions.so ./cppfront main.cpp2 g++ -std=c++20 -o main.cpp.o -c main.cpp g++ main.cpp.o -o main ./main ``` Output: ```output metafunctions.cpp2... ok (all Cpp2, passes safety checks) main.cpp2... ok (all Cpp2, passes safety checks) Hello, world! From my_class ``` @edo9300 Please, share your GitHub-provided `no-reply` email (see <https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors>). Co-authored-by: Edoardo Lolletti <> Co-authored-by: Dylam De La Torre <[email protected]>
1 parent c5feb42 commit 80ec7bf

File tree

10 files changed

+7080
-5011
lines changed

10 files changed

+7080
-5011
lines changed

include/cpp2reflect.h

Lines changed: 887 additions & 0 deletions
Large diffs are not rendered by default.

include/cpp2util.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,16 @@ constexpr auto gcc_clang_msvc_min_versions(
375375
#define CPP2_CONSTEXPR constexpr
376376
#endif
377377

378+
379+
#if defined(_WIN32)
380+
#define CPPFRONTAPI __declspec(dllexport)
381+
#else
382+
#define CPPFRONTAPI __attribute__ ((visibility ("default")))
383+
#endif
384+
385+
#define CPP2_C_API extern "C" CPPFRONTAPI
386+
387+
378388
namespace cpp2 {
379389

380390

@@ -1842,7 +1852,9 @@ constexpr auto is( auto const& x, auto&& value ) -> bool
18421852
else if constexpr (requires{ bool{x == value}; }) {
18431853
return x == value;
18441854
}
1845-
return false;
1855+
else {
1856+
return false;
1857+
}
18461858
}
18471859

18481860
//-----------------------------------------------------------------------
@@ -2883,4 +2895,15 @@ using cpp2::cpp2_new;
28832895
#pragma clang diagnostic pop
28842896
#endif
28852897

2898+
#ifdef _MSC_VER
2899+
#pragma warning(push)
2900+
#pragma warning(disable: 4251)
2901+
#endif
2902+
2903+
#include "cpp2reflect.h"
2904+
2905+
#ifdef _MSC_VER
2906+
#pragma warning(pop)
2907+
#endif
2908+
28862909
#endif // CPP2_CPP2UTIL_H

source/common.h

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// We want cppfront to build cleanly at very high warning levels, with warnings
1515
// as errors -- so disable a handful that fire incorrectly due to compiler bugs
1616
#ifdef _MSC_VER
17-
#pragma warning(disable: 4456 4706)
17+
#pragma warning(disable: 4456 4706 4996)
1818
#endif
1919
#if defined(__GNUC__) && __GNUC__ >= 13 && !defined(__clang_major__)
2020
#pragma GCC diagnostic ignored "-Wdangling-reference"
@@ -103,28 +103,11 @@ struct source_line
103103
};
104104

105105

106-
using lineno_t = int32_t;
107-
using colno_t = int32_t; // not int16_t... encountered >80,000 char line during testing
108-
using index_t = int32_t;
106+
using cpp2::meta::lineno_t;
107+
using cpp2::meta::colno_t;
108+
using cpp2::meta::index_t;
109109

110-
struct source_position
111-
{
112-
lineno_t lineno; // one-based offset into program source
113-
colno_t colno; // one-based offset into line
114-
115-
source_position(lineno_t l = 1, colno_t c = 1 )
116-
: lineno{ l }, colno{ c }
117-
{
118-
}
119-
120-
auto operator<=>(source_position const&) const = default;
121-
122-
auto to_string() const
123-
-> std::string
124-
{
125-
return "(" + std::to_string(lineno) + "," + std::to_string(colno) + ")";
126-
}
127-
};
110+
using cpp2::meta::source_position;
128111

129112
struct comment
130113
{
@@ -521,6 +504,36 @@ auto to_upper_and_underbar(std::string_view s)
521504
}
522505

523506

507+
auto to_lower_and_collapsed_underbar(
508+
std::string_view s,
509+
bool prev_was_underbar = false,
510+
bool drop_back_underbar = false
511+
)
512+
-> std::string
513+
{
514+
auto ret = std::string{};
515+
for (char c : s) {
516+
if (std::isalnum(c)) {
517+
ret.push_back(string_util::safe_tolower(c));
518+
prev_was_underbar = false;
519+
}
520+
else if (!prev_was_underbar) {
521+
ret.push_back('_');
522+
prev_was_underbar = true;
523+
}
524+
}
525+
if (
526+
drop_back_underbar
527+
&& !ret.empty()
528+
&& ret.back() == '_'
529+
)
530+
{
531+
ret.pop_back();
532+
}
533+
return ret;
534+
}
535+
536+
524537
auto is_empty_or_a_decimal_number(std::string_view s)
525538
-> bool
526539
{

0 commit comments

Comments
 (0)