Staged metaprogramming in C++ for C/C++
Go to file
2024-12-13 15:56:57 -05:00
.vscode working to towards https://github.com/Ed94/gencpp/issues/56 2024-12-12 12:55:15 -05:00
base correct formatting in singleheader.cpp 2024-12-13 15:42:13 -05:00
docs Corrected enum serialization of ecodetypes, eoperator, especifier, and etoktype, some more naming refactors for strbuilder... formatting 2024-12-13 14:38:27 -05:00
gen_c_library formatting fixes to C library generator 2024-12-13 15:56:57 -05:00
gen_segmented corrected formatting for gen_segmented 2024-12-13 15:44:29 -05:00
gen_singleheader correct formatting in singleheader.cpp 2024-12-13 15:42:13 -05:00
gen_unreal_engine formatting fixes to C library generator 2024-12-13 15:56:57 -05:00
scripts Corrected enum serialization of ecodetypes, eoperator, especifier, and etoktype, some more naming refactors for strbuilder... formatting 2024-12-13 14:38:27 -05:00
test Updates to docs and various changes to project from working on them. 2024-12-11 13:33:35 -05:00
.editorconfig WIP Change to code types [ Broken ] 2023-07-13 23:01:20 -04:00
.gitignore Finished first pass reviewing memory.hpp for C lib generation 2024-11-30 23:38:27 -05:00
gencpp.10x c_library refacotring works, and compiles with all content from the base project. 2024-12-10 13:56:56 -05:00
gencpp.sln WIP : better AST::debug_str() 2023-09-12 02:32:44 -04:00
gencpp.sln.DotSettings.user working to towards https://github.com/Ed94/gencpp/issues/56 2024-12-12 12:55:15 -05:00
gencpp.vcxproj WIP: code_types.hpp c_library.cpp conversion (issue with C struct padding on asts) 2024-12-07 19:46:19 -05:00
gencpp.vcxproj.filters Fixed some compilation errors 2023-11-22 15:41:41 -05:00
gencpp.vcxproj.user WIP : better AST::debug_str() 2023-09-12 02:32:44 -04:00
LICENSE Create LICENSE 2023-07-11 01:18:58 -04:00
Readme.md more typo correction 2024-12-12 10:42:01 -05:00

gencpp

An attempt at simple staged metaprogramming for C/C++.

The library API is a composition of code element constructors, and a non-standards-compliant single-pass C/C++ parser.
These build up a code AST to then serialize with a file builder, or can be traversed for staged-reflection of C/C++ code.

This code base attempts follow the handmade philosophy.
Its not meant to be a black box metaprogramming utility, it should be easy to integrate into a user's project domain.

Documentation

Notes

This project is still in development (very much an alpha state), so expect bugs and missing features.
See issues for a list of known bugs or todos.

The library can already be used to generate code just fine, but the parser is where the most work is needed. If your C++ isn't "down to earth" expect issues.

A natvis and natstepfilter are provided in the scripts directory (its outdated, I'll update this readme when its not).
Minor update: I've been using RAD Debugger with this and the code structures should be easy to debug even without natvis.

Usage

A metaprogram is built to generate files before the main program is built. We'll term runtime for this program as GEN_TIME. The metaprogram's core implementation are within gen.hpp and gen.cpp in the project directory.

gen.cpp `s main() is defined as gen_main() which the user will have to define once for their program. There they may reflect and/or generate code.

In order to keep the locality of this code within the same files the following pattern may be used (although this pattern isn't the best to use):

Within program.cpp :

#ifdef GEN_TIME
#include "gen.hpp"

...

u32 gen_main()
{
    ...
}
#endif

// "Stage" agnostic code.

#ifndef GEN_TIME
#include "program.gen.cpp"

    // Regular runtime dependent on the generated code here.
#endif

The design uses a constructive builder API for the code to generate.
The user is provided Code objects that are used to build up the AST.

Example using each construction interface:

Upfront

Validation and construction through a functional interface.

Code t_uw           = def_type( name(usize) );
Code t_allocator    = def_type( name(allocator) );
Code t_string_const = def_type( name(char), def_specifiers( args( ESpecifier::Const, ESpecifier::Ptr ) ));

Code header;
{
    Code num       = def_variable( t_uw,        name(Num) );
    Code cap       = def_variable( t_uw,        name(Capacity) );
    Code mem_alloc = def_variable( t_allocator, name(Allocator) );
    Code body      = def_struct_body( args( num, cap, mem_alloc ) );

    header = def_struct( name(ArrayHeader), __, __, body );
}

Parse

Validation through ast construction.

Code header = parse_struct( code(
    struct ArrayHeader
    {
        usize     Num;
        usize     Capacity;
        allocator Allocator;
    };
));

Untyped

No validation, just glorified text injection.

Code header = code_str(
    struct ArrayHeader
    {
        usize     Num;
        usize     Capacity;
        allocator Allocator;
    };
);

name is a helper macro for providing a string literal with its size, intended for the name parameter of functions.
code is a helper macro for providing a string literal with its size, but intended for code string parameters.
args is a helper macro for providing the number of arguments to varadic constructors.
code_str is a helper macro for writing untyped_str( code( <content> ))

All three construction interfaces will generate the following C code:

struct ArrayHeader
{
    usize     Num;
    usize     Capacity;
    allocator Allocator;
};

Note: The formatting shown here is not how it will look. For your desired formatting its recommended to run a pass through the files with an auto-formatter.
(The library currently uses clang-format for formatting, beware its pretty slow...)

Building

See the scripts directory.