Staged metaprogramming in C++ for C/C++
Go to file
Ed_ 9b6dc3cbd8 Work on AST::is_equal.
The NumEntries checks need to be deferred until the end as a final unresolved check on valdiation. As if there really is a discrepancy of entires it should be revealed by the specific entry failing.

Right now the latest failure with the single header check involves a define directive specifically the define does omit whitespace properly and so the check interprets the different cached content to be non-equivalent.

This will happen with all unvalidated aspects of the AST ( expressions, function bodies, etc )

There are two ways to resolve, either make an AST that can tokenize all items (not realistic), or I need to strip non-syntax important whitespace and then cache the string. This would mean removing everything but a single whitespace for all content within a content string. Otherwise, I would have to somehow make sure the content of the string has the exact formatting between both files for the definitions that matter.

AST types with this issue:
* Define Directive
* Pragma Directive
* Comment
* Execution
* Platform Attributes
* Untyped

Comments can technically be left unverified as they do not matter semantically.
When the serialization is first emitted, the content these strings should for the most part be equivalent. However I do see some possible failures for that if a different style of bracket placment is used (between the serialization).

At that point what I could do is just leave those unverified and just emit the content to the user as warning that the ast and the other compared could not be verified.

Those technically can be handled on a per-eye basis, and worst case the tests with the compiler will in the determine if any critical defintions are missing for the user.
2023-08-25 18:40:13 -04:00
.vscode Formatting fixes 2023-08-22 01:51:59 -04:00
docs doc update for parampack typename 2023-08-23 13:18:32 -04:00
project Work on AST::is_equal. 2023-08-25 18:40:13 -04:00
scripts Uncomment formatting comments in build script (forgot to after completing fixes) 2023-08-22 02:17:28 -04:00
singleheader Added support for inline comments 2023-08-23 00:25:14 -04:00
test Fixes to parsing marco content, progress on validation test (single-header) 2023-08-23 21:19:31 -04:00
.editorconfig WIP Change to code types [ Broken ] 2023-07-13 23:01:20 -04:00
.gitignore Started to setup for codebase validation tests. 2023-08-22 16:01:50 -04:00
gencpp.10x Added zpl's ivrtual memory to dependencies (unused for now) 2023-08-23 11:07:43 -04:00
gencpp.sln Updated Project configuration with various editors 2023-04-10 17:55:09 -04:00
gencpp.sln.DotSettings.user Parsing constructors passed the sanity test! 2023-07-10 22:14:51 -04:00
gencpp.vcxproj Update vcproj 2023-08-21 23:09:40 -04:00
gencpp.vcxproj.filters Update vcproj 2023-08-21 23:09:40 -04:00
gencpp.vcxproj.user Started to fix some runtime bugs. 2023-05-08 20:54:24 -04:00
LICENSE Create LICENSE 2023-07-11 01:18:58 -04:00
Readme.md Fix for wrong tokens for GNU/MSVC attribute captures (parse_attributes) 2023-08-08 15:35:06 -04:00

gencpp

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

The library API is a composition of code element constructors.
These build up a code AST to then serialize with a file builder.

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

Notes

The project has reached an alpha state, all the current functionality works for the test cases but it will most likely break in many other cases.

A natvis and natstepfilter are provided in the scripts directory.

The editor and scanner have not been implemented yet. The scanner will come first, then the editor.

A C variant is hosted here; I will complete it when this library is feature complete, it should be easier to make than this...

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 will dictate everything that should be generated.

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

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(uw) );
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
    {
        uw        Num;
        uw        Capacity;
        allocator Allocator;
    };
));

Untyped

No validation, just glorified text injection.

Code header = code_str(
    struct ArrayHeader
    {
        uw        Num;
        uw        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 writting untyped_str( code( <content> ))

All three constrcuton interfaces will generate the following C code:

struct ArrayHeader
{
    uw        Num;
    uw        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, beaware its pretty slow...)

Building

See the scripts directory.