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.
We first define a Code variable called header. We then open a stack frame for header's components.
Header will be a struct so we need to define its body, in this case struct acts a pure POD with only variable member symbols.
The components are defined first, then the struct body is constructed. Finally the body is provided the def_struct function.
This will generate the following C code:
```cpp
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.**
## Gen's DSL
If you don't mind a low amount of macros (29 lines), a DSL may be optionally defined with:
```cpp
GEN_DEFINE_DSL
```
Using the previous example to show usage:
```cpp
make( struct, ArrayHeader )
{
Code
body = ArrayHeader.body();
body->add_var( uw, Num );
body->add_var( uw, Capacity );
body->add_var( allocaotr, Allocator );
}
```
The `__` represents the `UnusedCode` value constant, of unneeded varaibles.
The DSL purposefully has no nested macros, with the follwing exceptions:
*`__VA_ARGS__` for parameter expnasion
*`VA_NARGS( __VA_ARGS__ )` for determing number of paramters
*`txt(Value_)` and `txt_with_length(Value_)` to serialize a value type identifier.
An example of building is provided in the test directory.
There are two meson build files the one within test is the program's build specification.
The other one in the gen directory within test is the metaprogram's build specification.
Both of them build the same source file: `test.cpp`. The only differences between them is that gen need a different relative path to the include directories and defines the macro definition: `gen_time`.
This method is setup where all the metaprogram's code are the within the same files as the regular program's code.
If in your use case, decide to have exclusive separation or partial separation of the metaprogam's code from the program's code files then your build configuration would need to change to reflect that (specifically the sources).
* Macro or template generation : This library is to avoid those,
adding support for them adds unnecessary complexity. If you desire define them outside the gen_time scopes.
* Expression validation : Execution expressions are defined using the untyped string API. There is no parse API for validating expression (possibly will add in the future)
* Complete file parser DSL : This isn't like the unreal header tool. Code injection to file or based off a file contents is not supported by the api. However nothing is stopping you using the library for that purpose.
* Modern c++ (STL library) features
### There are four different of construction of Code ast's the library provides:
* Upfront construction
* Incremental construction
* Parse construction
* Untyped
### Upfront Construction:
All component ASTs must be previously constructed, and provided on creation of the code AST.
The construction will fail and return InvalidCode otherwise.
API:
* def_forward_decl
* def_class
* def_global_body
* def_proc
* def_proc_body
* def_namespace
* def_namespace_body
* def_param
* def_params
* def_operator
* def_specifier
* def_specifiers
* def_struct
* def_struct_body
* def_variable
* def_type
* def_using
* def_using_namespace
### Incremental construction:
A Code ast is provided but only completed upfront if all components are provided.
Components are then added using the AST API for adding ASTs:
* code.add( AST* ) // Adds AST with validation.
* code.add_entry( AST* ) // Adds AST entry without validation.
Templates also have a heavy cost to compile-times due to their recursive nature of expansion if complex code is getting generated, or if heavy type checking system is used (assertsion require expansion, etc).
Unfortunately most programming langauges opt the approach of internally processing the generated code immediately within the AST or not expose it to the user in a nice way to even introspect as a text file.
Stage metaprogramming doesn't have this problem, since its entire purpose is to create those generated files that the final program will reference instead.
This is technically what the macro preprocessor does in a basic form, however a proper metaprogram for generation is easier to deal with for more complex generation.
The drawback naturally is generation functions, at face value, are harder to grasp than something following a template pattern (for simple generation). This drawback becomes less valid the more complex the code generation becomes.
Thus a rule of thumb is if its a simple definition you can get away with just the preprocessor `#define`, or if the templates being used don't break the debugger or your compile times, this is most likely not neded.