WIP: Restructuring project

This commit is contained in:
Edward R. Gonzalez 2024-12-10 16:13:14 -05:00
parent e3b3882443
commit 2c51a2f9c8
107 changed files with 417 additions and 4168 deletions

View File

@ -3,7 +3,7 @@
{
"name": "Bootstrap",
"includePath": [
"${workspaceFolder}/project/**"
"${workspaceFolder}/base/**"
],
"defines": [
"_DEBUG",

68
base/Readme.md Normal file
View File

@ -0,0 +1,68 @@
# Documentation
The library is fragmented into a series of headers and source files meant to be scanned in and then generated to a standard target format, or a user's desires.
Standard formats:
* **base**: Files are in granular pieces separated into four directories:
* **dependencies**: Originally from the c-zpl library and modified thereafter.
* **components**: The essential definitions of the library.
* **helpers**: Contains helper functionality used by base and other libraries to regenerate or generate the other library formats.
* `base_codegen.hpp`: Helps with self-hosted code generation of enums, and operator overload inlines of the code types.
* `<push/pop>.<name>.inline.<hpp>`: macros that are meant to be injected at specific locations of the library.
* `misc.hpp`:
* `undef.macros.h`: Undefines all macros from library that original were intended to leak into user code.
* **auxillary**: Non-essential tooling:
* `Builder`: Similar conceptually to Jai programming language's *builder*, just opens a file and prepares a string buffer to serialize code into (`builder_print`, `builder_print_fmt`). Then write & close the file when completed (`builder_write`).
* **`Scanner`**: Interface to load up `Code` from files two basic funcctions are currently provided.
* `scan_file`: Used mainly by the library format generators to directly scan files into untyped `Code` (raw string content, pre-formatted no AST parsed).
* `parse_file`: Used to read file and then parsed to populate a `CodeBody` AST.
* **gen_segemetned**: Dependencies go into gen.dep.{hpp/cpp} and components into gen.{hpp/cpp}
* **gen_singleheader**: Everything into a single file: gen.hpp
* **gen_unreal_engine**: Like gen_segemented but the library is modified slightly to compile as a thirdparty library within an Unreal Engine plugin or module.
* **gen_c_library**: The library is heavily modifed into C11 compliant code. A segemented and single-header set of variants are generatd.
Code not making up the core library is located in `auxiliary/<auxiliary_name>.<hpp/cpp>`. These are optional extensions or tools for the library.
Feature Macros:
* `GEN_DEFINE_ATTRIBUTE_TOKENS` : Allows user to define their own attribute macros for use in parsing.
* This is auto-generated if using the bootstrap or single-header generation
* *Note: The user will use the `AttributeTokens.csv` when the library is fully self-hosting.*
* `GEN_DEFINE_LIBRARY_CORE_CONSTANTS` : Optional typename codes as they are non-standard to C/C++ and not necessary to library usage
* `GEN_DONT_ENFORCE_GEN_TIME_GUARD` : By default, the library ( gen.hpp/ gen.cpp ) expects the macro `GEN_TIME` to be defined, this disables that.
* `GEN_ENFORCE_STRONG_CODE_TYPES` : Enforces casts to filtered code types.
* `GEN_EXPOSE_BACKEND` : Will expose symbols meant for internal use only.
* `GEN_ROLL_OWN_DEPENDENCIES` : Optional override so that user may define the dependencies themselves.
* `GEN_DONT_ALLOW_INVALID_CODE` (Not implemented yet) : Will fail when an invalid code is constructed, parsed, or serialized.
* `GEN_C_LIKE_PP` : Will prevent usage of function defnitions using references and structs with member functions.
Structs will still have user-defined operator conversions, for-range support, and other operator overloads
*Note: A variant of the C++ library could be generated where those additonal support features are removed (see gen_c_library implementation for an idea of how)*
## On multi-threading
Currently unsupported. I want the library to be *stable* and *correct*, with the addition of exhausting all basic single-threaded optimizations before I consider multi-threading.
## Extending the library
This library is relatively very small (for parsing C++), and can be extended without much hassle.
The convention you'll see used throughout the interface of the library is as follows:
1. Check name or parameters to make sure they are valid for the construction requested
2. Create a code object using `make_code`.
3. Populate immediate fields (Name, Type, ModuleFlags, etc)
4. Populate sub-entires using `add_entry`. If using the default serialization function `to_string`, follow the order at which entires are expected to appear (there is a strong ordering expected).
Names or Content fields are interned strings and thus showed be cached using `get_cached_string` if its desired to preserve that behavior.
`def_operator` is the most sophisticated upfront constructor as it has multiple permutations of definitions that could be created that are not trivial to determine if valid.
The parser is documented under `docs/Parsing.md` and `docs/Parser_Algo.md`. Extending it is more serious, but resolution of a parse for a given internal parse procedure is well documented.
## A note on compilation and runtime generation speed
The library is designed to be fast to compile and generate code at runtime as fast as resonable possible on a debug build.
Its recommended that your metaprogam be compiled using a single translation unit (unity build).

View File

@ -2,6 +2,8 @@
# include "builder.hpp"
#endif
#pragma region Builder
Builder builder_open( char const* path )
{
Builder result;
@ -54,3 +56,4 @@ void builder_write(Builder* builder)
string_free(& builder->Buffer);
}
#pragma endregion Builder

View File

@ -1,8 +1,22 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "gen.hpp"
# include "helpers/push_ignores.inline.hpp"
# include "components/header_start.hpp"
# include "components/types.hpp"
# include "components/gen/ecode.hpp"
# include "components/gen/eoperator.hpp"
# include "components/gen/especifier.hpp"
# include "components/ast.hpp"
# include "components/code_types.hpp"
# include "components/ast_types.hpp"
# include "components/interface.hpp"
# include "components/inlines.hpp"
# include "components/gen/ast_inlines.hpp"
# include "components/header_end.hpp"
#endif
#pragma region Builder
struct Builder;
typedef struct Builder Builder;
@ -51,3 +65,5 @@ void builder_print_fmt( Builder& builder, char const* fmt, ...) {
va_end( va );
}
#endif
#pragma endregion Builder

View File

@ -1,6 +1,18 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "../gen.hpp"
# include "helpers/push_ignores.inline.hpp"
# include "components/header_start.hpp"
# include "components/types.hpp"
# include "components/gen/ecode.hpp"
# include "components/gen/eoperator.hpp"
# include "components/gen/especifier.hpp"
# include "components/ast.hpp"
# include "components/code_types.hpp"
# include "components/ast_types.hpp"
# include "components/interface.hpp"
# include "components/inlines.hpp"
# include "components/gen/ast_inlines.hpp"
# include "components/header_end.hpp"
#endif
/*

View File

@ -1,8 +1,22 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "gen.hpp"
# include "helpers/push_ignores.inline.hpp"
# include "components/header_start.hpp"
# include "components/types.hpp"
# include "components/gen/ecode.hpp"
# include "components/gen/eoperator.hpp"
# include "components/gen/especifier.hpp"
# include "components/ast.hpp"
# include "components/code_types.hpp"
# include "components/ast_types.hpp"
# include "components/interface.hpp"
# include "components/inlines.hpp"
# include "components/gen/ast_inlines.hpp"
# include "components/header_end.hpp"
#endif
#pragma region Scanner
// This is a simple file reader that reads the entire file into memory.
// It has an extra option to skip the first few lines for undesired includes.
// This is done so that includes can be kept in dependency and component files so that intellisense works.
@ -119,41 +133,53 @@ Code scan_file( char const* path )
return untyped_str( string_to_strc(str) );
}
#if 0
struct CodeFile
CodeBody parse_file( const char* path )
{
using namespace Parser;
String FilePath;
TokArray Tokens;
Array<ParseFailure> ParseFailures;
Code CodeRoot;
};
namespace Parser
{
struct ParseFailure
{
String Reason;
Code Node;
};
FileContents file = file_read_contents( GlobalAllocator, true, path );
CodeBody code = parse_global_body( { file.size, (char const*)file.data } );
log_fmt("\nParsed: %s\n", path);
return code;
}
CodeFile scan_file( char const* path )
{
using namespace Parser;
// The follow is basic support for light csv parsing (use it as an example)
// Make something robust if its more serious.
CodeFile
result = {};
result.FilePath = String::make( GlobalAllocator, path );
typedef struct CSV_Column CSV_Column;
struct CSV_Column {
CSV_Object Owner;
Array<ADT_Node> Content;
};
Code code = scan_file( path );
result.CodeRoot = code;
typedef struct CSV_Columns2 CSV_Columns2;
struct CSV_Columns2 {
CSV_Object Owner;
Array<ADT_Node> Col_1;
Array<ADT_Node> Col_2;
};
ParseContext context = parser_get_last_context();
result.Tokens = context.Tokens;
result.ParseFailures = context.Failures;
CSV_Column parse_csv_one_column(AllocatorInfo allocator, char const* path) {
char scratch_mem[kilobytes(32)];
Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) );
file_read_contents( arena_allocator_info( & scratch), file_zero_terminate, path );
CSV_Column result;
csv_parse( & result.owner, scratch_mem, allocator, false );
result.Content = csv_nodes.nodes[0].nodes;
return result;
}
#endif
CSV_Columns2 parse_csv_two_columns(AllocatorInfo allocator, char const* path) {
char scratch_mem[kilobytes(32)];
Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) );
file_read_contents( arena_allocator_info( & scratch), file_zero_terminate, path );
CSV_Columns2 result;
csv_parse( & result.owner, scratch_mem, allocator, false );
result.Col_1 = csv_nodes.nodes[0].nodes;
result.Col_2 = csv_nodes.nodes[1].nodes;
return result;
}
#pragma endregion Scanner

56
base/base.cpp Normal file
View File

@ -0,0 +1,56 @@
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#define GEN_C_LIKE_CPP 1
#include "../project/gen.cpp"
#include "helpers/push_ignores.inline.hpp"
#include "helpers/helper.hpp"
GEN_NS_BEGIN
#include "helpers/push_container_defines.inline.hpp"
#include "dependencies/parsing.cpp"
#include "helpers/pop_container_defines.inline.hpp"
GEN_NS_END
#include "auxillary/builder.hpp"
#include "auxillary/builder.cpp"
#include "auxillary/scanner.hpp"
#include "auxillary/misc.hpp"
using namespace gen;
constexpr char const* path_format_style = "../scripts/.clang-format";
constexpr char const* scratch_file = "gen/scratch.hpp";
Code format( Code code ) {
return code_refactor_and_format(code, scratch_file, nullptr, path_format_style );
}
int gen_main()
{
CodeBody ecode = gen_ecode ( "enums/ECodeTypes.csv" );
CodeBody eoperator = gen_eoperator ( "enums/EOperator.csv" );
CodeBody especifier = gen_especifier( "enums/ESpecifier.csv" );
CodeBody ast_inlines = gen_ast_inlines();
Builder header_ecode = builder_open( "components/gen/ecode.hpp" );
builder_print( & header_ecode, gen_component_header );
builder_print( & header_ecode, format(ecode) );
builder_write( & header_ecode);
Builder header_eoperator = builder_open( "components/gen/eoperator.hpp" );
builder_print( & header_eoperator, gen_component_header );
builder_print( & header_eoperator, format(eoperator) );
builder_write( & header_eoperator );
Builder header_especifier = builder_open( "components/gen/especifier.hpp" );
builder_print( & header_especifier, gen_component_header );
builder_print( & header_especifier, format(especifier) );
builder_write( & header_especifier);
Builder header_ast_inlines = builder_open( "components/gen/ast_inlines.hpp" );
builder_print( & header_ast_inlines, gen_component_header );
builder_print( & header_ast_inlines, format(ast_inlines) );
builder_write( & header_ast_inlines);
}

View File

@ -31,6 +31,9 @@ GEN_NS_BEGIN
#include "components/gen/ast_inlines.hpp"
#include "components/header_end.hpp"
#include "auxillary/builder.hpp"
#include "auxillary/scanner.hpp"
GEN_NS_END
#include "helpers/pop_container_defines.inline.hpp"

View File

@ -2,50 +2,35 @@
#include "gen.hpp"
GEN_NS_BEGIN
#include "dependencies/parsing.hpp"
GEN_NS_END
using namespace gen;
#include "dependencies/parsing.hpp"
#include "misc.hpp"
CodeBody gen_ecode( char const* path, bool use_c_definition = false )
{
char scratch_mem[kilobytes(4)];
Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) );
file_read_contents( arena_allocator_info( & scratch), file_zero_terminate, path );
CSV_Object csv_nodes;
csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false );
Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes;
Array<ADT_Node> keyword_strs = csv_nodes.nodes[1].nodes;
CSV_Columns2 csv_enum = parse_csv_two_columns(GlobalAllocator, path );
String enum_entries = string_make_reserve( GlobalAllocator, kilobytes(1) );
String to_str_entries = string_make_reserve( GlobalAllocator, kilobytes(1) );
String to_keyword_str_entries = string_make_reserve( GlobalAllocator, kilobytes(1) );
for ( ssize idx = 0; idx < array_num(enum_strs); ++ idx )
{
char const* code = enum_strs [idx].string;
char const* keyword = keyword_strs[idx].string;
for ( ssize idx = 0; idx < array_num(csv_enum.Col_1); ++ idx ) {
char const* code = csv_enum.Col_1[idx].string;
char const* keyword = csv_enum.Col_2[idx].string;
// TODO(Ed): to_str_entries and the others in here didn't have proper sizing of the StrC slice.
string_append_fmt( & enum_entries, "CT_%s,\n", code );
string_append_fmt( & to_str_entries, "{ sizeof(\"%s\"), \"%s\" },\n", code, code );
string_append_fmt( & to_keyword_str_entries, "{ sizeof(\"%s\") - 1, \"%s\" },\n", keyword, keyword );
}
CodeEnum enum_code;
if (use_c_definition)
{
if (use_c_definition) {
enum_code = parse_enum(token_fmt_impl((3 + 1) / 2, "entries", string_to_strc(enum_entries),
"enum CodeType enum_underlying(u32) { <entries> CT_NumTypes, CT_UnderlyingType = GEN_U32_MAX };"
));
}
else
{
else {
enum_code = parse_enum(token_fmt_impl((3 + 1) / 2, "entries", string_to_strc(enum_entries),
"enum CodeType : u32 { <entries> CT_NumTypes, CT_UnderlyingType = GEN_U32_MAX };"
));
@ -53,7 +38,7 @@ CodeBody gen_ecode( char const* path, bool use_c_definition = false )
#pragma push_macro("local_persist")
#undef local_persist
StrC lookup_size = string_to_strc(string_fmt_buf(GlobalAllocator, "%d", array_num(enum_strs) ));
StrC lookup_size = string_to_strc(string_fmt_buf(GlobalAllocator, "%d", array_num(csv_enum.Col_1) ));
CodeBody to_str_fns = parse_global_body( token_fmt(
"entries", string_to_strc(to_str_entries)
, "keywords", string_to_strc(to_keyword_str_entries)
@ -84,16 +69,14 @@ CodeBody gen_ecode( char const* path, bool use_c_definition = false )
CodeBody result = def_body(CT_Global_Body);
body_append(result, enum_code);
if (use_c_definition)
{
if (use_c_definition) {
CodeTypedef code_t = parse_typedef(code(typedef enum CodeType CodeType; ));
body_append(result, code_t);
}
body_append(result, to_str_fns);
if (! use_c_definition)
{
if (! use_c_definition) {
#pragma push_macro("forceinline")
#undef forceinline
CodeBody alias_mappings = parse_global_body(code(
@ -108,24 +91,14 @@ CodeBody gen_ecode( char const* path, bool use_c_definition = false )
CodeBody gen_eoperator( char const* path, bool use_c_definition = false )
{
char scratch_mem[kilobytes(4)];
Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) );
file_read_contents( arena_allocator_info(& scratch), file_zero_terminate, path );
CSV_Object csv_nodes;
csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false );
Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes;
Array<ADT_Node> str_strs = csv_nodes.nodes[1].nodes;
CSV_Columns2 csv_enum = parse_csv_two_columns(GlobalAllocator, path);
String enum_entries = string_make_reserve( GlobalAllocator, kilobytes(1) );
String to_str_entries = string_make_reserve( GlobalAllocator, kilobytes(1) );
for (usize idx = 0; idx < array_num(enum_strs); idx++)
{
char const* enum_str = enum_strs[idx].string;
char const* entry_to_str = str_strs [idx].string;
for (usize idx = 0; idx < array_num(csv_enum.Col_1); idx++) {
char const* enum_str = csv_enum.Col_1[idx].string;
char const* entry_to_str = csv_enum.Col_2[idx].string;
string_append_fmt( & enum_entries, "Op_%s,\n", enum_str );
string_append_fmt( & to_str_entries, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str);
@ -160,7 +133,7 @@ CodeBody gen_eoperator( char const* path, bool use_c_definition = false )
#pragma push_macro("local_persist")
#undef local_persist
StrC lookup_size = string_to_strc(string_fmt_buf(GlobalAllocator, "%d", array_num(enum_strs) ));
StrC lookup_size = string_to_strc(string_fmt_buf(GlobalAllocator, "%d", array_num(csv_enum.Col_1) ));
CodeFn to_str = parse_function(token_fmt(
"entries", string_to_strc(to_str_entries)
, "num", lookup_size
@ -180,8 +153,7 @@ CodeBody gen_eoperator( char const* path, bool use_c_definition = false )
CodeBody result = def_body(CT_Global_Body);
body_append(result, enum_code);
if ( use_c_definition )
{
if ( use_c_definition ) {
CodeTypedef operator_t = parse_typedef(code( typedef enum Operator Operator; ));
body_append(result, operator_t);
}
@ -203,21 +175,12 @@ CodeBody gen_eoperator( char const* path, bool use_c_definition = false )
CodeBody gen_especifier( char const* path, bool use_c_definition = false )
{
char scratch_mem[kilobytes(4)];
Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) );
file_read_contents( arena_allocator_info(& scratch), file_zero_terminate, path );
CSV_Object csv_nodes;
csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false );
Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes;
Array<ADT_Node> str_strs = csv_nodes.nodes[1].nodes;
CSV_Columns2 csv_enum = parse_csv_two_columns(GlobalAllocator, path);
String enum_entries = string_make_reserve( GlobalAllocator, kilobytes(1) );
String to_str_entries = string_make_reserve( GlobalAllocator, kilobytes(1) );
for (usize idx = 0; idx < array_num(enum_strs); idx++)
for (usize idx = 0; idx < array_num(csv_enum.Col_1); idx++)
{
char const* enum_str = enum_strs[idx].string;
char const* entry_to_str = str_strs [idx].string;
@ -271,7 +234,7 @@ CodeBody gen_especifier( char const* path, bool use_c_definition = false )
#undef do_once_end
#undef forceinline
#undef neverinline
StrC lookup_size = string_to_strc(string_fmt_buf(GlobalAllocator, "%d", array_num(enum_strs) ));
StrC lookup_size = string_to_strc(string_fmt_buf(GlobalAllocator, "%d", array_num(csv_enum.Col_1) ));
CodeFn to_str = parse_function(token_fmt(
"entries", string_to_strc(to_str_entries)
, "num", lookup_size

86
base/helpers/misc.hpp Normal file
View File

@ -0,0 +1,86 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
#pragma once
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#include "../gen.cpp"
#include "helpers/push_ignores.inline.hpp"
#include "helpers/helper.hpp"
GEN_NS_BEGIN
#include "helpers/push_container_defines.inline.hpp"
#include "dependencies/parsing.cpp"
#include "helpers/pop_container_defines.inline.hpp"
GEN_NS_END
#include "auxillary/builder.hpp"
#include "auxillary/builder.cpp"
#include "auxillary/scanner.hpp"
#endif
// Will format a file with the given style at the provided path.
// Assumes clang-format is defined in an user-exposed or system enviornment PATH.
void clang_format_file( char const* path, char const* style_path )
{
GEN_ASSERT_NOT_NULL(path);
String resolved_path = string_make_strc(GlobalAllocator, to_strc_from_c_str(path));
String style_arg;
if (style_path) {
stle_arg = string_make_strc(GlobalAllocator, txt("-style=file:"));
string_append_fmt( & style_arg, "%s ", style_path );
}
StrC clang_format = txt("clang-format ")
StrC cf_format_inplace = txt("-i ")
StrC cf_verbose = txt("-verbose ")
String command = string_make_strc( GlobalAllocator, clang_format );
string_append_strc( & command, cf_format_inplace );
string_append_strc( & command, cf_verbose );
string_append_string( & command, style_arg );
string_append_string( & command, resolved_path );
log_fmt("\tRunning clang-format:\n");
system( command );
log_fmt("\tclang-format finished formatting.\n");
}
// Will refactor a file with the given script at the provided path.
// Assumes refactor is defined in an user-exposed or system enviornment PATH.
// (See: ./gencpp/scripts/build.ci.ps1 for how)
void refactor_file( char const* path, char const* refactor_script )
{
GEN_ASSERT_NOT_NULL(path, refactor_script);
#define refactor
String command = string_make_strc(GlobalAllocator, txt("refactor")));
log_fmt("\tBeginning refactor:\n");
system(command);
log_fmt("\nRefactoring complete.\n");
#undef refactor
}
Code code_refactor_and_format( Code code, char const* scratch_path, char const* refactor_script, char_const* clang_format_sytle_path )
{
GEN_ASSERT_NOT_NULL(code);
GEN_ASSERT_NOT_NULL(scratch_path);
Builder scratch_file = builder_open("gen/scratch.hpp");
builder_print( & scratch_file, code);
builder_write(& scratch_file);
if (refactor_script) {
refactor_file(scratch_path, refactor_script)
}
if ( clang_format_sytle_path ) {
clang_format_file(scratch_path, clang_format_sytle_path);
}
Code result = scan_file( scratch_path );
remove("gen/scratch.hpp");
return result;
}

View File

@ -52,7 +52,7 @@ constexpr StrC implementation_guard_end = txt(R"(
#pragma endregion GENCPP IMPLEMENTATION GUARD
)");
void format_file( char const* path )
void CHANGE_format_file( char const* path )
{
String resolved_path = String::make(GlobalAllocator, to_strc_from_c_str(path));
@ -77,7 +77,7 @@ void format_file( char const* path )
#undef cf_verbse
}
Code format_code_to_untyped( Code code )
Code CHANGE_format_code_to_untyped( Code code )
{
Builder ecode_file_temp = Builder::open("gen/scratch.hpp");
ecode_file_temp.print(code);
@ -88,18 +88,8 @@ Code format_code_to_untyped( Code code )
return result;
}
CodeBody parse_file( const char* path )
{
FileContents file = file_read_contents( GlobalAllocator, true, path );
CodeBody code = parse_global_body( { file.size, (char const*)file.data } );
log_fmt("\nParsed: %s\n", path);
return code;
}
constexpr bool helper_use_c_definition = true;
constexpr bool will_refactor_to_gen_namespace = true;
int gen_main()
{
#define project_dir "../project/"
@ -116,8 +106,8 @@ int gen_main()
PreprocessorDefines.append(txt("Using_CodeOps("));
PreprocessorDefines.append(txt("GEN_OPTIMIZE_MAPPINGS_BEGIN"));
PreprocessorDefines.append(txt("GEN_OPITMIZE_MAPPINGS_END"));
//PreprocessorDefines.append(txt("GEN_EXECUTION_EXPRESSION_SUPPORT"));
PreprocessorDefines.append(txt("GEN_PARAM_DEFAULT"));
//PreprocessorDefines.append(txt("GEN_EXECUTION_EXPRESSION_SUPPORT"));
Code push_ignores = scan_file( project_dir "helpers/push_ignores.inline.hpp" );
Code pop_ignores = scan_file( project_dir "helpers/pop_ignores.inline.hpp" );

View File

@ -1,14 +1,5 @@
__VERSION 1
// This is a example template to be used with the refactor program
// Use it to refactor the naming convention of this library to your own.
// Can be used as an aid to help use use your project's implementation if it fullfills the dependencies of this project.
// Example: Most likely have a memory and string library already, just rename the functions and make sure the args are the same.
// Program: https://github.com/Ed94/refactor
// NOTE: Due to the current limitations of the program, not every symbol in the library can be renamed.
// This is due to the program not actually parsing C/C++.
// not : Ignore
// include : #includes
// word : Alphanumeric or underscore
@ -21,6 +12,9 @@
// Gen Macro namespace
// namespace GEN_, new_namespace_
// c_library.refactor
// Used to prefix all exposed identifiers with the gen_namespace by c_library.cpp using ./gencpp/scripts/helpers/refactor.exe
// Macros
word global, gen_global

15
gen_segemented/Readme.md Normal file
View File

@ -0,0 +1,15 @@
# Generate Segemented Library
The principal (user) files are `gen.hpp` and `gen.cpp`.
They contain includes for its various components: `components/<component_name>.<hpp/cpp>`
Dependencies are bundled into `gen.dep.<hpp/cpp>`. They are included in `gen.<hpp/cpp>` before component includes.
Just like the `gen.<hpp/cpp>` they include their components: `dependencies/<dependency_name>.<hpp/cpp>`
Both libraries use *pre-generated* (self-hosting I guess) version of the library to then generate the latest version of itself.
They dedicated header and source files. Dependencies included at the top of the file and each header starting with a pragma once.
The output will be in the `project/gen` directory (if the directory does not exist, it will create it).
Use those to get a general idea of how to make your own tailored version.

View File

@ -16,6 +16,7 @@ GEN_NS_END
#include "auxillary/builder.hpp"
#include "auxillary/builder.cpp"
#include "auxillary/scanner.hpp"
#include "auxillary/misc.hpp"
using namespace gen;
@ -25,50 +26,20 @@ constexpr char const* generation_notice =
#include <cstdlib> // for system()
void format_file( char const* path )
{
String resolved_path = string_make_strc(GlobalAllocator, to_strc_from_c_str(path));
constexpr char const* path_format_style = "../scripts/.clang-format ";
constexpr char const* scratch_file = "gen/scratch.hpp";
constexpr char const* path_base = "../base/";
String style_arg = string_make_strc(GlobalAllocator, txt("-style=file:"));
string_append_strc( & style_arg, txt("../scripts/.clang-format "));
// Need to execute clang format on the generated file to get it to match the original.
#define clang_format txt("clang-format ")
#define cf_format_inplace txt("-i ")
#define cf_verbose txt("-verbose ")
String command = string_make_strc( GlobalAllocator, clang_format );
string_append_strc( & command, cf_format_inplace );
string_append_strc( & command, cf_verbose );
string_append_string( & command, style_arg );
string_append_string( & command, resolved_path );
log_fmt("\tRunning clang-format on file:\n");
system( command );
log_fmt("\tclang-format finished reformatting.\n");
#undef cf_cmd
#undef cf_format_inplace
#undef cf_style
#undef cf_verbse
}
Code dump_to_scratch_and_retireve( Code code )
{
Builder ecode_file_temp = builder_open("gen/scratch.hpp");
builder_print( & ecode_file_temp, code);
builder_write(& ecode_file_temp);
format_file("gen/scratch.hpp");
Code result = scan_file( "gen/scratch.hpp" );
remove("gen/scratch.hpp");
return result;
Code format( Code code ) {
return code_refactor_and_format(code, scratch_file, nullptr, path_format_style );
}
int gen_main()
{
gen::init();
// PreprocessorDefines.append("GEN_NS");
Code push_ignores = scan_file( "helpers/push_ignores.inline.hpp" );
Code pop_ignores = scan_file( "helpers/pop_ignores.inline.hpp" );
Code push_ignores = scan_file( path_base "helpers/push_ignores.inline.hpp" );
Code pop_ignores = scan_file( path_base "helpers/pop_ignores.inline.hpp" );
// gen_dep.hpp
{
@ -176,11 +147,11 @@ int gen_main()
builder_print_fmt(header, "#pragma region Types\n" );
builder_print( header, types );
builder_print( header, fmt_newline);
builder_print( header, dump_to_scratch_and_retireve(ecode) );
builder_print( header, format(ecode) );
builder_print( header, fmt_newline);
builder_print( header, dump_to_scratch_and_retireve(eoperator) );
builder_print( header, format(eoperator) );
builder_print( header, fmt_newline);
builder_print( header, dump_to_scratch_and_retireve(especifier) );
builder_print( header, format(especifier) );
builder_print( header, fmt_newline);
builder_print_fmt( header, "#pragma endregion Types\n\n" );
@ -195,7 +166,7 @@ int gen_main()
builder_print_fmt( header, "\n#pragma region Inlines\n" );
builder_print( header, inlines );
builder_print( header, fmt_newline );
builder_print( header, dump_to_scratch_and_retireve(ast_inlines) );
builder_print( header, format(ast_inlines) );
builder_print( header, fmt_newline );
builder_print_fmt( header, "#pragma endregion Inlines\n" );
@ -206,22 +177,22 @@ int gen_main()
Builder header_ecode = builder_open( "components/gen/ecode.hpp" );
builder_print( & header_ecode, gen_component_header );
builder_print( & header_ecode, dump_to_scratch_and_retireve(ecode) );
builder_print( & header_ecode, format(ecode) );
builder_write( & header_ecode);
Builder header_eoperator = builder_open( "components/gen/eoperator.hpp" );
builder_print( & header_eoperator, gen_component_header );
builder_print( & header_eoperator, dump_to_scratch_and_retireve(eoperator) );
builder_print( & header_eoperator, format(eoperator) );
builder_write( & header_eoperator );
Builder header_especifier = builder_open( "components/gen/especifier.hpp" );
builder_print( & header_especifier, gen_component_header );
builder_print( & header_especifier, dump_to_scratch_and_retireve(especifier) );
builder_print( & header_especifier, format(especifier) );
builder_write( & header_especifier);
Builder header_ast_inlines = builder_open( "components/gen/ast_inlines.hpp" );
builder_print( & header_ast_inlines, gen_component_header );
builder_print( & header_ast_inlines, dump_to_scratch_and_retireve(ast_inlines) );
builder_print( & header_ast_inlines, format(ast_inlines) );
builder_write( & header_ast_inlines);
}
@ -240,11 +211,10 @@ int gen_main()
Code untyped = scan_file( "components/interface.untyped.cpp" );
CodeBody etoktype = gen_etoktype( "enums/ETokType.csv", "enums/AttributeTokens.csv" );
//CodeNS nspaced_etoktype = def_namespace( name(parser), def_namespace_body( args(etoktype)) );
CodeBody nspaced_etoktype = def_global_body( args(
etoktype
));
Code formatted_toktype = dump_to_scratch_and_retireve(nspaced_etoktype);
Code formatted_toktype = format(nspaced_etoktype);
Builder _src = builder_open( "gen/gen.cpp" );
Builder* src = & _src;

View File

@ -1,66 +0,0 @@
# Documentation
The library is fragmented into a series of headers and source files meant to be scanned in and then generated to a tailored format for the target `gen` files.
The principal (user) files are `gen.hpp` and `gen.cpp`.
They contain includes for its various components: `components/<component_name>.<hpp/cpp>`
Dependencies are bundled into `gen.dep.<hpp/cpp>`.
Just like the `gen.<hpp/cpp>` they include their components: `dependencies/<dependency_name>.<hpp/cpp>`
Code not making up the core library is located in `auxiliary/<auxiliary_name>.<hpp/cpp>`. These are optional extensions or tools for the library.
Both libraries use *pre-generated* (self-hosting I guess) version of the library to then generate the latest version of itself.
The default `gen.bootstrap.cpp` located in the project folder is meant to be produce a standard segmented library, where the components of the library
have relatively dedicated header and source files. Dependencies included at the top of the file and each header starting with a pragma once.
The output will be in the `project/gen` directory (if the directory does not exist, it will create it).
Use those to get a general idea of how to make your own tailored version.
Feature Macros:
* `GEN_DEFINE_ATTRIBUTE_TOKENS` : Allows user to define their own attribute macros for use in parsing.
* This is auto-generated if using the bootstrap or single-header generation
* *Note: The user will use the `AttributeTokens.csv` when the library is fully self-hosting.*
* `GEN_DEFINE_LIBRARY_CORE_CONSTANTS` : Optional typename codes as they are non-standard to C/C++ and not necessary to library usage
* `GEN_DONT_ENFORCE_GEN_TIME_GUARD` : By default, the library ( gen.hpp/ gen.cpp ) expects the macro `GEN_TIME` to be defined, this disables that.
* `GEN_ENFORCE_STRONG_CODE_TYPES` : Enforces casts to filtered code types.
* `GEN_EXPOSE_BACKEND` : Will expose symbols meant for internal use only.
* `GEN_ROLL_OWN_DEPENDENCIES` : Optional override so that user may define the dependencies themselves.
* `GEN_DONT_ALLOW_INVALID_CODE` (Not implemented yet) : Will fail when an invalid code is constructed, parsed, or serialized.
By default the base library implementation strictly uses a C-like interface. This is to allow for the generation of a C-variant of the library using [gen_c_library](../gen_c_library/). However, the library was written in C++ and supports some of its features:
* `GEN_SUPPORT_CPP_REFERENCES` : Will enable support for reference interface on some definitions
* `GEN_SUPPORT_CPP_MEMBER_FEATURES` : Will enable support for definitions to have their interface as members.
*Note: A variant of the C++ library could be generated where those additonal support features are removed (see gen_c_library implementation for an idea of how)*
## On multi-threading
Currently unsupported. I want the library to be *stable* and *correct*, with the addition of exhausting all basic single-threaded optimizations before I consider multi-threading.
## Extending the library
This library is relatively very small, and can be extended without much hassle.
The convention you'll see used throughout the interface of the library is as follows:
1. Check name or parameters to make sure they are valid for the construction requested
2. Create a code object using `make_code`.
3. Populate immediate fields (Name, Type, ModuleFlags, etc)
4. Populate sub-entires using `add_entry`. If using the default serialization function `to_string`, follow the order at which entires are expected to appear (there is a strong ordering expected).
Names or Content fields are interned strings and thus showed be cached using `get_cached_string` if its desired to preserve that behavior.
`def_operator` is the most sophisticated constructor as it has multiple permutations of definitions that could be created that are not trivial to determine if valid.
The library has its code segmented into component files, use it to help create a derived version without needing to have to rewrite a generated file directly or build on top of the header via composition or inheritance.
The parser is documented under `docs/Parsing.md` and `docs/Parser_Algo.md`.
## A note on compilation and runtime generation speed
The library is designed to be fast to compile and generate code at runtime as fast as resonable possible on a debug build.
Its recommended that your metaprogam be compiled using a single translation unit (unity build).

View File

@ -1,10 +0,0 @@
#pragma once
#include "gen.hpp"
GEN_NS_BEGIN
#include "dependencies/parsing.hpp"
GEN_NS_END
using namespace gen;

View File

@ -40,7 +40,7 @@ Push-Location $path_root
$vendor = $null
$release = $null
$verbose = $false
[bool] $bootstrap = $false
[bool] $segemented = $false
[bool] $singleheader = $false
[bool] $c_library = $false
[bool] $unreal = $false
@ -56,7 +56,7 @@ if ( $args ) { $args | ForEach-Object {
"verbose" { $verbose = $true }
"release" { $release = $true }
"debug" { $release = $false }
"bootstrap" { $bootstrap = $true }
"segemented" { $segemented = $true }
"singleheader" { $singleheader = $true }
"c_library" { $c_library = $true }
"unreal" { $unreal = $true }
@ -88,7 +88,7 @@ else {
$optimize = $true
}
if ( $bootstrap -eq $false -and $singleheader -eq $false -and $c_library -eq $false -and $unreal -eq $false -and $test -eq $false ) {
if ( $segmented -eq $false -and $singleheader -eq $false -and $c_library -eq $false -and $unreal -eq $false -and $test -eq $false ) {
throw "No build target specified. One must be specified, this script will not assume one"
}
@ -100,25 +100,23 @@ write-host "Build Type: $(if ($release) {"Release"} else {"Debug"} )"
#region Building
$path_build = Join-Path $path_root build
$path_project = Join-Path $path_root project
$path_scripts = Join-Path $path_root scripts
$path_base = Join-Path $path_root base
$path_c_library = join-Path $path_root gen_c_library
$path_segmented = Join-Path $path_root gen_segmented
$path_singleheader = Join-Path $path_root gen_singleheader
$path_scripts = Join-Path $path_root scripts
$path_unreal = Join-Path $path_root gen_unreal_engine
$path_test = Join-Path $path_root test
if ( $bootstrap )
if ( $base )
{
$path_build = join-path $path_project build
$path_gen = join-path $path_project gen
$path_comp_gen = join-path $path_project components/gen
$path_build = join-path $path_base build
$path_comp = join-path $path_segmented 'components'
$path_comp_gen = join-path $path_comp 'gen'
if ( -not(Test-Path($path_build) )) {
New-Item -ItemType Directory -Path $path_build
}
if ( -not(Test-Path($path_gen) )) {
New-Item -ItemType Directory -Path $path_gen
}
if ( -not(Test-Path($path_comp_gen) )) {
New-Item -ItemType Directory -Path $path_comp_gen
}
@ -131,8 +129,46 @@ if ( $bootstrap )
)
$includes = @( $path_project)
$unit = join-path $path_project "bootstrap.cpp"
$executable = join-path $path_build "bootstrap.exe"
$unit = join-path $path_base "base.cpp"
$executable = join-path $path_build "base.exe"
$result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable
Push-Location $path_project
if ( Test-Path( $executable ) ) {
write-host "`nRunning bootstrap"
$time_taken = Measure-Command { & $executable
| ForEach-Object {
write-host `t $_ -ForegroundColor Green
}
}
write-host "`nBootstrap completed in $($time_taken.TotalMilliseconds) ms"
}
Pop-Location
}
if ( $segmented )
{
$path_build = join-path $path_segmented build
$path_gen = join-path $path_segmented gen
if ( -not(Test-Path($path_build) )) {
New-Item -ItemType Directory -Path $path_build
}
if ( -not(Test-Path($path_gen) )) {
New-Item -ItemType Directory -Path $path_gen
}
$compiler_args = @()
$compiler_args += ( $flag_define + 'GEN_TIME' )
$linker_args = @(
$flag_link_win_subsystem_console
)
$includes = @( $path_project)
$unit = join-path $path_segmented "segmented.cpp"
$executable = join-path $path_build "segmented.exe"
$result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable
@ -294,7 +330,8 @@ if ( $unreal )
. $refactor_unreal
}
if ( $test )
# TODO(Ed): The unit testing needs a full rewrite
if ( $test -and $false )
{
$path_gen = join-path $path_test gen
$path_gen_build = join-path $path_gen build
@ -356,55 +393,4 @@ if ( $test )
}
#endregion Building
#region Formatting
push-location $path_scripts
if ( $false -and $bootstrap -and (Test-Path (Join-Path $path_project "gen/gen.hpp")) )
{
$path_gen = join-path $path_project gen
$include = @(
'gen.hpp', 'gen.cpp',
'gen.dep.hpp', 'gen.dep.cpp',
'gen.builder.hpp', 'gen.builder.cpp'
'gen.scanner.hpp', 'gen.scanner.cpp'
)
$exclude = $null
# format-cpp $path_gen $include $exclude
format-cpp $path_comp_gen @( 'ast_inlines.hpp', 'ecode.hpp', 'especifier.hpp', 'eoperator.hpp', 'etoktype.cpp' ) $null
}
if ( $false -and $singleheader -and (Test-Path (Join-Path $path_singleheader "gen/gen.hpp")) )
{
$path_gen = join-path $path_singleheader gen
$include = @(
'gen.hpp'
)
$exclude = $null
format-cpp $path_gen $include $exclude
}
if ( $false -and $unreal -and (Test-Path( Join-Path $path_unreal "gen/gen.hpp")) )
{
$path_gen = join-path $path_unreal gen
$include = @(
'gen.hpp', 'gen.cpp',
'gen.dep.hpp', 'gen.dep.cpp',
'gen.builder.hpp', 'gen.builder.cpp'
'gen.scanner.hpp', 'gen.scanner.cpp'
)
$exclude = $null
format-cpp $path_gen $include $exclude
}
if ( $test -and $false )
{
$path_gen = join-path $path_test gen
$include = @(
'*.gen.hpp'
)
$exclude = $null
format-cpp $path_gen $include $exclude
}
pop-location
#endregion Formatting
Pop-Location # $path_root

View File

@ -1,6 +1,3 @@
# Test
The implementaiton here is not well organized and needs a rewrite..
I only do basic sanity and parsing tests for the most part.
The library is getting practical usage tests in [genc](https://github.com/Ed94/genc) and other projects.
The implementaiton here has been gutted and will be rewritten...

View File

@ -1,146 +0,0 @@
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#define GEN_BENCHMARK
#include "gen.hpp"
#include "gen.builder.hpp"
using namespace gen;
Code gen_SOA( CodeStruct struct_def, s32 num_entries = 0 )
{
StringCached name = get_cached_string( token_fmt( "name", (StrC)struct_def->Name,
stringize( SOA_<name> )
));
Code
soa_entry = { struct_def.duplicate() };
soa_entry->Name = get_cached_string( name(Entry) );
constexpr s32 Num_Vars_Cap = 128;
local_persist Code var_memory[Num_Vars_Cap];
local_persist Arena var_arena;
do_once_start
var_arena = Arena::init_from_memory( var_memory, kilobytes(Num_Vars_Cap) );
do_once_end
Array<CodeVar> vars = Array<CodeVar>::init( var_arena );;
CodeStruct soa = def_struct( name, def_struct_body( args( soa_entry ) ));
{
for ( Code struct_mem : struct_def->Body )
{
if ( struct_mem->Type == ECode::Variable )
{
CodeType var_type = struct_mem.cast<CodeVar>()->ValueType;
StrC num_entries_str = to_str( str_fmt_buf( "%d", num_entries ) );
CodeVar entry_arr = { nullptr };
if ( ! num_entries)
{
entry_arr = parse_variable( token_fmt( "type", (StrC)var_type->Name, "name", (StrC)struct_mem->Name,
stringize( Array<<type>> <name>; )
));
}
else
{
entry_arr = parse_variable( token_fmt( "type", (StrC)var_type->Name, "name", (StrC)struct_mem->Name, "num", num_entries_str,
stringize( <type> <name>[<num>]; )
));
}
vars.append( entry_arr );
soa->Body.append( entry_arr );
}
}
}
CodeFn make;
{
make = parse_function( token_fmt("SOA_Type", (StrC)name,
stringize(
static
<SOA_Type> make( AllocatorInfo allocator )
{
<SOA_Type> soa = {};
}
)
));
if ( ! num_entries )
{
for ( CodeVar member : vars )
{
Code arr_init = def_execution( token_fmt( "var_name", (StrC)member->Name, "var_type", (StrC)member->ValueType->Name,
stringize( soa.<var_name> = <var_type>::init( allocator ); )
));
make->Body.append( arr_init );
}
}
make->Body.append( def_execution( code( return soa; ) ));
}
CodeFn get;
{
get = parse_function( code(
Entry get( s32 idx )
{
}
));
String content = String::make( GlobalAllocator, "return\n{\n" );
for ( CodeVar member : vars )
{
content.append_fmt( token_fmt( "var_name", (StrC)member->Name,
"<var_name>[idx],"
));
}
content.append( "};" );
CodeExec ret = def_execution( content );
get->Body.append( ret );
}
soa->Body.append( make );
soa->Body.append( get );
soa->Body.raw()->validate_body();
vars.free();
return soa;
}
void check_SOA()
{
log_fmt("\ncheck_SOA:");
gen::init();
Builder soa_test = Builder::open( "SOA.gen.hpp" );
soa_test.print( parse_using( code(
using u16 = unsigned short;
)));
soa_test.print( def_include( txt("gen.hpp")));
soa_test.print( def_using_namespace( name(gen) ) );
soa_test.print( gen_SOA(
parse_struct( code(
struct TestStruct
{
u8 A;
u16 B;
u32 C;
u64 D;
};
))
, 100
));
soa_test.write();
gen::deinit();
log_fmt(" passed!\n");
}

View File

@ -1,25 +0,0 @@
# Unreal Header & Source reconstruction tests
***Note: This validation test has not been implemented yet.***
Will test the following modules + plugins:
* Kismet
* Slate
* RTTI Bases
* Gameframework
* Actor & Component Bases
* Lyra
In the future I could attempt to do a similar test to that of the godot engine full compilation test.
For now it just does the following:
* Download the Unreal source code
* For each module
1. Grab all header and source file paths
2. Generate an ast for each file and serialize it to a file called `<name of file>.gen.<h/c>`
3. Reconstruct the ast from the generated file
4. Compare the original ast to the reconstructed ast
This wil most likely be the most difficult test along-side godot's full compilation test.

View File

@ -1,294 +0,0 @@
#pragma once
#if GEN_TIME
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#define GEN_BENCHMARK
#include "gen.hpp"
using namespace gen;
Code gen__array_base()
{
return parse_global_body( code(
struct ArrayHeader
{
AllocatorInfo Allocator;
usize Capacity;
usize Num;
};
static inline usize array_grow_formula( usize value )
{
return 2 * value * 8;
}
));
}
Code gen__array( StrC type )
{
StrC name;
{
char const* name_str = str_fmt_buf( "Array_%s\0", type.Ptr );
s32 name_len = str_len( name_str );
name = { name_len, name_str };
};
CodeStruct array = parse_struct( token_fmt( "ArrayType", name, "type", type,
stringize(
struct <ArrayType>
{
using Header = ArrayHeader;
using Type = <type>;
static constexpr auto grow_formula = &array_grow_formula;
static
<ArrayType> init( AllocatorInfo allocator )
{
return init_reserve( allocator, grow_formula(0) );
}
static
<ArrayType> init_reserve( AllocatorInfo allocator, ssize capacity )
{
Header* header = rcast( Header*, alloc( allocator, sizeof(Header) + sizeof(Type) ));
if ( header == nullptr )
return { nullptr };
header->Allocator = allocator;
header->Capacity = capacity;
header->Num = 0;
return { rcast( Type*, header + 1) };
}
bool append( Type value )
{
Header& header = get_header();
if ( header.Num == header.Capacity )
{
if ( ! grow( header.Capacity ))
return false;
}
Data[ header.Num ] = value;
header.Num++;
return true;
}
Type& back( void )
{
Header& header = get_header();
return Data[ header.Num - 1 ];
}
void clear( void )
{
Header& header = get_header();
header.Num = 0;
}
bool fill( usize begin, usize end, Type value )
{
Header& header = get_header();
if ( begin < 0 || end >= header.Num )
return false;
for ( ssize idx = begin; idx < end; idx++ )
{
Data[ idx ] = value;
}
return true;
}
void free( void )
{
Header& header = get_header();
gen::free( header.Allocator, &header );
}
Header& get_header( void )
{
return *( reinterpret_cast< Header* >( Data ) - 1 );
}
bool grow( usize min_capacity )
{
Header& header = get_header();
usize new_capacity = grow_formula( header.Capacity );
if ( new_capacity < min_capacity )
new_capacity = 8;
return set_capacity( new_capacity );
}
usize num( void )
{
return get_header().Num;
}
bool pop( void )
{
Header& header = get_header();
GEN_ASSERT( header.Num > 0 );
header.Num--;
}
void remove_at( usize idx )
{
Header* header = &get_header();
GEN_ASSERT( idx < header->Num );
mem_move( header + idx, header + idx + 1, sizeof( Type ) * ( header->Num - idx - 1 ) );
header->Num--;
}
bool reserve( usize new_capacity )
{
Header& header = get_header();
if ( header.Capacity < new_capacity )
return set_capacity( new_capacity );
return true;
}
bool resize( usize num )
{
Header& header = get_header();
if ( num > header.Capacity )
{
if ( ! grow( header.Capacity ) )
return false;
}
header.Num = num;
return true;
}
bool set_capacity( usize new_capacity )
{
Header& header = get_header();
if ( new_capacity == header.Capacity )
return true;
if ( new_capacity < header.Num )
header.Num = new_capacity;
ssize size = sizeof( Header ) + sizeof( Type ) * new_capacity;
Header* new_header = rcast( Header*, alloc( header.Allocator, size ) );
if ( new_header == nullptr )
return false;
mem_move( new_header, &header, sizeof( Header ) + sizeof( Type ) * header.Num );
new_header->Allocator = header.Allocator;
new_header->Num = header.Num;
new_header->Capacity = new_capacity;
gen::free( header.Allocator, &header );
Data = ( Type* )new_header + 1;
return true;
}
Type* Data;
operator Type*()
{
return Data;
}
};
)
));
return array;
}
struct GenArrayRequest
{
StrC Dependency;
StrC Type;
};
Array<GenArrayRequest> GenArrayRequests;
void gen__array_request( StrC type, StrC dep = {} )
{
do_once_start
GenArrayRequests = Array<GenArrayRequest>::init( GlobalAllocator );
do_once_end
// Make sure we don't already have a request for the type.
for ( ssize idx = 0; idx < GenArrayRequests.num(); ++idx )
{
StrC const reqest_type = GenArrayRequests[ idx ].Type;
if ( reqest_type.Len != type.Len )
continue;
if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 )
return;
}
GenArrayRequest request = { dep, type };
GenArrayRequests.append( request );
}
#define gen_array( type ) gen__array_request( code(type) )
u32 gen_array_file()
{
Builder
gen_array_file;
gen_array_file.open( "array.Parsed.gen.hpp" );
Code include_gen = def_include( txt("gen.hpp") );
gen_array_file.print( include_gen );
gen_array_file.print( def_using_namespace( name(gen)));
Code array_base = gen__array_base();
gen_array_file.print( array_base );
GenArrayRequest* current = GenArrayRequests;
s32 left = GenArrayRequests.num();
while (left--)
{
GenArrayRequest const& request = * current;
Code generated_array = gen__array( request.Type );
if ( request.Dependency )
{
char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type );
s32 cmt_len = str_len( cmt_str );
Code cmt = def_comment( { cmt_len, cmt_str } );
Code include = def_include( request.Dependency );
gen_array_file.print( cmt );
gen_array_file.print( include );
}
gen_array_file.print( generated_array );
current++;
}
gen_array_file.write();
return 0;
}
#endif

View File

@ -1,205 +0,0 @@
#pragma once
#if GEN_TIME
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#define GEN_BENCHMARK
#include "gen.hpp"
using namespace gen;
Code gen__buffer_base()
{
return parse_global_body( code(
struct BufferHeader
{
AllocatorInfo Backing;
usize Capacity;
usize Num;
};
));
}
Code gen__buffer( StrC type )
{
StrC name;
{
char const* name_str = str_fmt_buf( "Buffer_%s\0", type.Ptr );
s32 name_len = str_len( name_str );
name = { name_len, name_str };
};
Code buffer = parse_struct( token_fmt( "BufferName", name, "type", type,
stringize(
struct <BufferName>
{
using Header = BufferHeader;
using Type = <type>;
static <BufferName> init( AllocatorInfo allocator, ssize capacity )
{
Header* header = rcast( Header*, alloc( allocator, sizeof( Header ) + capacity * sizeof( Type ) ) );
if ( header == nullptr )
return { nullptr };
header->Backing = allocator;
header->Capacity = capacity;
header->Num = 0;
return { rcast( Type*, header + 1 ) };
}
<BufferName> init( AllocatorInfo allocator, <BufferName> other )
{
Header& other_header = other.get_header();
Header* header = rcast( Header*, alloc( allocator, sizeof( Header ) + other_header.Capacity * sizeof( Type ) ) );
if ( header == nullptr )
return { nullptr };
header->Backing = allocator;
header->Capacity = other_header.Capacity;
header->Num = other_header.Num;
mem_copy( header + 1, other.Data, other_header.Num * sizeof( Type ) );
return { rcast( Type*, header + 1 ) };
}
void append( Type value )
{
Header& header = get_header();
Data[ header.Num ] = value;
header.Num++;
}
void append( Type* values, ssize num )
{
Header& header = get_header();
GEN_ASSERT( header.Num + num <= header.Capacity);
mem_copy( Data + header.Num, values, num * sizeof( Type ) );
header.Num += num;
}
void clear( void )
{
Header& header = get_header();
header.Num = 0;
}
Type& end( void )
{
Header& header = get_header();
return Data[ header.Num - 1 ];
}
void free( void )
{
Header& header = get_header();
gen::free( header.Backing, &header );
}
Header& get_header( void )
{
return *( rcast( Header*, Data ) - 1 );
}
ssize num( void )
{
return get_header().Num;
}
void wipe( void )
{
Header& header = get_header();
header.Num = 0;
mem_set( Data, 0, header.Capacity * sizeof( Type ) );
}
operator Type*()
{
return Data;
}
Type* Data;
};
)
));
return buffer;
}
struct GenBufferRequest
{
StrC Dependency;
StrC Type;
};
Array<GenBufferRequest> GenBufferRequests;
void gen__buffer_request( StrC type, StrC dep = {} )
{
do_once_start
GenBufferRequests = Array<GenBufferRequest>::init( GlobalAllocator );
do_once_end
// Make sure we don't already have a request for the type.
for ( ssize idx = 0; idx < GenBufferRequests.num(); ++idx )
{
StrC const reqest_type = GenBufferRequests[ idx ].Type;
if ( reqest_type.Len != type.Len )
continue;
if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 )
return;
}
GenBufferRequest request = { dep, type };
GenBufferRequests.append( request );
}
#define gen_buffer( type ) gen__buffer_request( code(type) )
u32 gen_buffer_file()
{
Builder
gen_buffer_file;
gen_buffer_file.open( "buffer.Parsed.gen.hpp" );
gen_buffer_file.print( def_include( txt("gen.hpp")) );
gen_buffer_file.print( def_using_namespace( name(gen)));
gen_buffer_file.print( gen__buffer_base() );
GenBufferRequest* current = GenBufferRequests;
s32 left = GenBufferRequests.num();
while (left--)
{
GenBufferRequest const& request = * current;
Code generated_buffer = gen__buffer( current->Type );
if ( request.Dependency )
{
char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type );
s32 cmt_len = str_len( cmt_str );
Code cmt = def_comment( { cmt_len, cmt_str } );
Code include = def_include( request.Dependency );
gen_buffer_file.print( cmt );
gen_buffer_file.print( include );
}
gen_buffer_file.print( generated_buffer );
current++;
}
gen_buffer_file.write();
return 0;
}
#endif // GEN_TIME

View File

@ -1,359 +0,0 @@
#pragma once
#if GEN_TIME
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#define GEN_BENCHMARK
#include "gen.hpp"
#include "Array.Parsed.hpp"
using namespace gen;
Code gen__hashtable_base()
{
return parse_global_body( code(
struct HashTable_FindResult
{
ssize HashIndex;
ssize PrevIndex;
ssize EntryIndex;
};
));
}
Code gen__hashtable( StrC type )
{
StringCached name;
{
char const* name_str = str_fmt_buf( "HashTable_%s", type.Ptr );
s32 len = str_len( name_str );
name = get_cached_string({ len, name_str });
}
Code ht_entry = parse_struct( token_fmt( "HashTableName", (StrC)name, "type", type,
stringize(
struct <HashTableName>_Entry
{
u64 Key;
ssize Next;
<type> Value;
};
)
));
StringCached ht_entry_name = get_cached_string( token_fmt( "HashTableName", (StrC)name, "<HashTableName>_Entry" ));
Code array_ht_entry = gen__array( ht_entry_name );
Code hashtable = parse_struct( token_fmt( "HashTableName", (StrC)name, "type", type,
stringize(
struct <HashTableName>
{
using Type = <type>;
using Entry = <HashTableName>_Entry;
using Array_Entry = Array_<HashTableName>_Entry;
using FindResult = HashTable_FindResult;
using MapProc = void ( * )( u64 key, Type value );
using MapMutProc = void ( * )( u64 key, Type* value );
static
<HashTableName> init( AllocatorInfo allocator )
{
<HashTableName>
result = { 0 };
result.Hashes = Array_sw ::init( allocator );
result.Entries = Array_Entry::init( allocator );
return result;
}
void clear( void )
{
for ( s32 idx = 0; idx < Hashes.num(); idx++ )
Hashes[ idx ] = -1;
Entries.clear();
}
void destroy( void )
{
if ( Hashes )
Hashes.free();
if ( Entries )
Entries.free();
}
Type* get( u64 key )
{
ssize idx = find( key ).EntryIndex;
if ( idx > 0 )
return &Entries[ idx ].Value;
return nullptr;
}
void grow( void )
{
ssize new_num = array_grow_formula( Entries.num() );
rehash( new_num );
}
void map( MapProc map_proc )
{
GEN_ASSERT_NOT_NULL( map_proc );
for ( ssize idx = 0; idx < Entries.num(); idx++ )
{
map_proc( Entries[ idx ].Key, Entries[ idx ].Value );
}
}
void map_mut( MapMutProc map_proc )
{
GEN_ASSERT_NOT_NULL( map_proc );
for ( ssize idx = 0; idx < Entries.num(); idx++ )
{
map_proc( Entries[ idx ].Key, &Entries[ idx ].Value );
}
}
void rehash( ssize new_num )
{
ssize idx;
ssize last_added_index;
HashTable_u32 new_ht = HashTable_u32::init( Hashes.get_header().Allocator );
new_ht.Hashes.resize( new_num );
new_ht.Entries.reserve( new_ht.Hashes.num() );
for ( idx = 0; idx < new_ht.Hashes.num(); ++idx )
new_ht.Hashes[ idx ] = -1;
for ( idx = 0; idx < Entries.num(); ++idx )
{
Entry& entry = Entries[ idx ];
FindResult find_result;
if ( new_ht.Hashes.num() == 0 )
new_ht.grow();
entry = Entries[ idx ];
find_result = new_ht.find( entry.Key );
last_added_index = new_ht.add_entry( entry.Key );
if ( find_result.PrevIndex < 0 )
new_ht.Hashes[ find_result.HashIndex ] = last_added_index;
else
new_ht.Entries[ find_result.PrevIndex ].Next = last_added_index;
new_ht.Entries[ last_added_index ].Next = find_result.EntryIndex;
new_ht.Entries[ last_added_index ].Value = entry.Value;
}
destroy();
Hashes = new_ht.Hashes;
Entries = new_ht.Entries;
}
void rehash_fast( void )
{
ssize idx;
for ( idx = 0; idx < Entries.num(); idx++ )
Entries[ idx ].Next = -1;
for ( idx = 0; idx < Hashes.num(); idx++ )
Hashes[ idx ] = -1;
for ( idx = 0; idx < Entries.num(); idx++ )
{
Entry* entry;
FindResult find_result;
}
}
void remove( u64 key )
{
FindResult find_result = find( key );
if ( find_result.EntryIndex >= 0 )
{
Entries.remove_at( find_result.EntryIndex );
rehash_fast();
}
}
void remove_entry( ssize idx )
{
Entries.remove_at( idx );
}
void set( u64 key, Type value )
{
ssize idx;
FindResult find_result;
if ( Hashes.num() == 0 )
grow();
find_result = find( key );
if ( find_result.EntryIndex >= 0 )
{
idx = find_result.EntryIndex;
}
else
{
idx = add_entry( key );
if ( find_result.PrevIndex >= 0 )
{
Entries[ find_result.PrevIndex ].Next = idx;
}
else
{
Hashes[ find_result.HashIndex ] = idx;
}
}
Entries[ idx ].Value = value;
if ( full() )
grow();
}
ssize slot( u64 key )
{
for ( ssize idx = 0; idx < Hashes.num(); ++idx )
if ( Hashes[ idx ] == key )
return idx;
return -1;
}
Array_sw Hashes;
Array_Entry Entries;
protected:
ssize add_entry( u64 key )
{
ssize idx;
Entry entry = { key, -1 };
idx = Entries.num();
Entries.append( entry );
return idx;
}
HashTable_FindResult find( u64 key )
{
FindResult result = { -1, -1, -1 };
if ( Hashes.num() > 0 )
{
result.HashIndex = key % Hashes.num();
result.EntryIndex = Hashes[ result.HashIndex ];
while ( result.EntryIndex >= 0 )
{
if ( Entries[ result.EntryIndex ].Key == key )
break;
result.PrevIndex = result.EntryIndex;
result.EntryIndex = Entries[ result.EntryIndex ].Next;
}
}
return result;
}
b32 full( void )
{
return 0.75f * Hashes.num() < Entries.num();
}
};
)
));
return def_global_body( args( ht_entry, array_ht_entry, hashtable ));
}
struct GenHashTableRequest
{
StrC Dependency;
StrC Type;
};
Array<GenHashTableRequest> GenHashTableRequests;
void gen__hashtable_request( StrC type, StrC dep = {} )
{
do_once_start
GenHashTableRequests = Array<GenHashTableRequest>::init( GlobalAllocator );
gen_array( ssize );
do_once_end
// Make sure we don't already have a request for the type.
for ( ssize idx = 0; idx < GenHashTableRequests.num(); ++idx )
{
StrC const reqest_type = GenHashTableRequests[ idx ].Type;
if ( reqest_type.Len != type.Len )
continue;
if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 )
return;
}
GenHashTableRequest request = { dep, type };
GenHashTableRequests.append( request );
}
#define gen_hashtable( type ) gen__hashtable_request( code(type) )
u32 gen_hashtable_file()
{
Builder
gen_hashtable_file;
gen_hashtable_file.open( "hashtable.Parsed.gen.hpp" );
gen_hashtable_file.print( def_include( txt("gen.hpp")) );
gen_hashtable_file.print( def_include( txt("Array.Parsed.hpp")) );
gen_hashtable_file.print( def_include( txt("array.Parsed.gen.hpp")) );
gen_hashtable_file.print( def_using_namespace( name(gen)));
gen_hashtable_file.print( gen__hashtable_base());
GenHashTableRequest* current = GenHashTableRequests;
s32 left = GenHashTableRequests.num();
while (left--)
{
GenHashTableRequest const& request = * current;
Code generated_buffer = gen__hashtable( current->Type );
if ( request.Dependency )
{
char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type );
s32 cmt_len = str_len( cmt_str );
Code cmt = def_comment( { cmt_len, cmt_str } );
Code include = def_include( request.Dependency );
gen_hashtable_file.print( cmt );
gen_hashtable_file.print( include );
}
gen_hashtable_file.print( generated_buffer );
current++;
}
gen_hashtable_file.write();
return 0;
}
#endif // GEN_TIME

View File

@ -1,175 +0,0 @@
#pragma once
#if GEN_TIME
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#define GEN_BENCHMARK
#include "gen.hpp"
#include "Buffer.Parsed.hpp"
using namespace gen;
Code gen__ring( StrC type )
{
static Code t_allocator_info = def_type( name(AllocatorInfo) );
StringCached name;
{
char const* name_str = str_fmt_buf( "Ring_%s\0", type.Ptr );
s32 name_len = str_len( name_str );
name = get_cached_string({ name_len, name_str });
};
StrC buffer_name = to_str( str_fmt_buf( "Buffer_%s", type.Ptr ));
Code ring = parse_struct( token_fmt( "RingName", (StrC)name, "type", type, "BufferName", buffer_name,
stringize(
struct <RingName>
{
using Type = <type>;
static <RingName> init( AllocatorInfo allocator, usize max_size )
{
<RingName> result = { 0 };
result.Backing = allocator;
result.Buffer = <BufferName>::init( allocator, max_size + 1 );
if ( result.Buffer == nullptr )
return { nullptr };
result.Capacity = max_size + 1;
return result;
}
void append( s16 value )
{
Buffer[ Head ] = value;
Head = ( Head + 1 ) % Capacity;
if ( Head == Tail )
Tail = ( Tail + 1 ) % Capacity;
}
inline void append( Type* values, ssize num )
{
for ( ssize idx = 0; idx < num; idx++ )
append( values[ idx ] );
}
bool empty( void )
{
return Head == Tail;
}
void free( void )
{
Buffer.free();
}
bool full( void )
{
return ( Head + 1 ) % Capacity == Tail;
}
Type& get( void )
{
Type& data = Buffer[ Tail ];
Tail = ( Tail + 1 ) % Capacity;
return data;
}
void wipe( void )
{
Head = 0;
Tail = 0;
Buffer.wipe();
}
AllocatorInfo Backing;
usize Capacity;
usize Head;
usize Tail;
<BufferName> Buffer;
};
)
));
return ring;
}
struct GenRingRequest
{
StrC Dependency;
StrC Type;
};
Array<GenRingRequest> GenRingRequests;
void gen__ring_request( StrC type, StrC dep = {} )
{
do_once_start
GenRingRequests = Array<GenRingRequest>::init( GlobalAllocator );
do_once_end
// Make sure we don't already have a request for the type.
for ( ssize idx = 0; idx < GenRingRequests.num(); ++idx )
{
StrC const reqest_type = GenRingRequests[ idx ].Type;
if ( reqest_type.Len != type.Len )
continue;
if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 )
return;
}
// Ring definition depends on a array and buffer definition.
gen__buffer_request( type, dep );
GenRingRequest request = { dep, type };
GenRingRequests.append( request );
}
#define gen_ring( type ) gen__ring_request( code(type) )
u32 gen_ring_file()
{
Builder
gen_ring_file;
gen_ring_file.open( "ring.Parsed.gen.hpp" );
gen_ring_file.print( def_include( txt("gen.hpp")) );
gen_ring_file.print( def_include( txt("buffer.Parsed.gen.hpp")) );
// gen_ring_file.print( gen__ring_base() );
gen_ring_file.print( def_using_namespace( name(gen)));
GenRingRequest* current = GenRingRequests;
s32 left = GenRingRequests.num();
while (left--)
{
GenRingRequest const& request = * current;
Code generated_ring = gen__ring( current->Type );
if ( request.Dependency )
{
char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type );
s32 cmt_len = str_len( cmt_str );
Code cmt = def_comment( { cmt_len, cmt_str } );
Code include = def_include( request.Dependency );
gen_ring_file.print( cmt );
gen_ring_file.print( include );
}
gen_ring_file.print( generated_ring );
current++;
}
gen_ring_file.write();
return 0;
}
#endif // GEN_TIME

View File

@ -1,344 +0,0 @@
#pragma once
#ifdef GEN_TIME
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#define GEN_BENCHMARK
#include "gen.hpp"
using namespace gen;
u32 gen_sanity()
{
Builder
gen_sanity_file;
gen_sanity_file.open("./sanity.Parsed.gen.hpp");
gen_sanity_file.print( def_comment( txt(
"The following will show a series of base cases for the gen parsed api.\n"
)));
// Typedef
{
CodeTypedef u8_typedef = parse_typedef( code(
typedef unsigned char u8;
));
gen_sanity_file.print(u8_typedef);
}
gen_sanity_file.print_fmt("\n");
// Class
{
CodeClass fwd = parse_class( code(
class TestEmptyClass;
));
CodeClass empty_body = parse_class( code(
class TestEmptyClass
{};
));
empty_body->Body.append( def_comment( txt("Empty class body") ) );
gen_sanity_file.print(fwd);
gen_sanity_file.print(empty_body);
}
gen_sanity_file.print_fmt("\n");
// Enum
{
CodeEnum fwd = parse_enum( code(
enum ETestEnum : u8;
));
CodeEnum def = parse_enum( code(
enum ETestEnum : u8
{
A,
B,
C
};
));
CodeEnum fwd_enum_class = parse_enum( code(
enum class ETestEnumClass : u8;
));
gen_sanity_file.print(fwd);
gen_sanity_file.print(def);
gen_sanity_file.print(fwd_enum_class);
}
gen_sanity_file.print_fmt("\n");
// External Linkage
{
CodeComment empty_comment = def_comment( txt("Empty external linkage") );
CodeExtern c_extern = parse_extern_link( code(
extern "C"
{
};
));
c_extern->Body.append( empty_comment );
gen_sanity_file.print(c_extern);
}
gen_sanity_file.print_fmt("\n");
// Friend
{
CodeClass fwd = parse_class( code(
class TestFriendClass;
));
CodeClass def = parse_class( code(
class TestFriend
{
friend class TestFriendClass;
};
));
gen_sanity_file.print(fwd);
gen_sanity_file.print(def);
}
gen_sanity_file.print_fmt("\n");
// Function
{
CodeFn fwd = parse_function( code(
void test_function();
));
CodeFn def = parse_function( code(
void test_function()
{
}
));
def->Body.append( def_comment( txt("Empty function body") ) );
gen_sanity_file.print(fwd);
gen_sanity_file.print(def);
}
gen_sanity_file.print_fmt("\n");
// Namespace
{
CodeNS def = parse_namespace( code(
namespace TestNamespace
{
}
));
def->Body.append( def_comment( txt("Empty namespace body") ) );
gen_sanity_file.print(def);
}
gen_sanity_file.print_fmt("\n");
// Operator
{
CodeEnum bitflagtest = parse_enum( code(
enum class EBitFlagTest : u8
{
A = 1 << 0,
B = 1 << 1,
C = 1 << 2
};
));
CodeOperator op_fwd = parse_operator( code(
EBitFlagTest operator | ( EBitFlagTest a, EBitFlagTest b );
));
CodeOperator op_or = parse_operator( code(
EBitFlagTest operator | ( EBitFlagTest a, EBitFlagTest b )
{
return EBitFlagTest( (u8)a | (u8)b );
}
));
gen_sanity_file.print(bitflagtest);
gen_sanity_file.print(op_fwd);
gen_sanity_file.print(op_or);
}
gen_sanity_file.print_fmt("\n");
// Operator cast
{
CodeOpCast op_ptr = parse_operator_cast( code(
operator u8* ();
));
CodeClass class_def = parse_class( code(
class TestClass
{
};
));
class_def->Body.append( op_ptr );
gen_sanity_file.print(class_def);
}
gen_sanity_file.print_fmt("\n");
// Parameters
{
CodeFn fwd = parse_function( code(
void test_function_param( int a );
));
CodeFn def = parse_function( code(
void test_function_param2( int a, int b )
{
}
));
def->Body.append( def_comment( txt("Empty function body") ) );
gen_sanity_file.print(fwd);
gen_sanity_file.print(def);
}
gen_sanity_file.print_fmt("\n");
// Specifiers
{
CodeFn fwd_fn = parse_function( code(
inline
void test_function_specifiers();
));
CodeTypedef typedef_u8_ptr = parse_typedef( code(
typedef u8* u8_ptr;
));
gen_sanity_file.print(fwd_fn);
gen_sanity_file.print(typedef_u8_ptr);
}
gen_sanity_file.print_fmt("\n");
// Struct
{
CodeStruct fwd = parse_struct( code(
struct TestEmptyStruct;
));
CodeStruct empty_body = parse_struct( code(
struct TestEmptyStruct
{};
));
empty_body->Body.append( def_comment( txt("Empty struct body") ) );
gen_sanity_file.print(fwd);
gen_sanity_file.print(empty_body);
}
gen_sanity_file.print_fmt("\n");
// Union
{
CodeUnion empty = parse_union( code(
union TestEmptyUnion
{
};
));
empty->Body.append( def_comment( txt("Empty union body") ) );
gen_sanity_file.print( parse_typedef( code( typedef unsigned short u16; )) );
gen_sanity_file.print( parse_typedef( code( typedef unsigned long u32; )) );
CodeUnion def = parse_union( code(
union TestUnion
{
u8 a;
u16 b;
u32 c;
};
));
gen_sanity_file.print(empty);
gen_sanity_file.print(def);
}
gen_sanity_file.print_fmt("\n");
// Using
{
CodeUsing reg = (CodeUsing) parse_using( code(
using TestUsing = u8;
));
CodeNS nspace = parse_namespace( code(
namespace TestNamespace
{
};
));
CodeUsing npspace_using = parse_using( code(
using namespace TestNamespace;
));
gen_sanity_file.print(reg);
gen_sanity_file.print(nspace);
gen_sanity_file.print(npspace_using);
}
gen_sanity_file.print_fmt("\n");
// Variable
{
CodeVar bss = parse_variable( code(
u8 test_variable;
));
CodeVar data = parse_variable( code(
u8 test_variable = 0x12;
));
gen_sanity_file.print(bss);
gen_sanity_file.print(data);
}
gen_sanity_file.print_fmt("\n");
// template
{
#pragma push_macro("template")
#undef template
CodeTemplate tmpl = parse_template( code(
template< typename Type >
void test_template( Type a )
{
}
));
#pragma pop_macro("template")
gen_sanity_file.print(tmpl);
}
gen_sanity_file.print_fmt("\n");
gen_sanity_file.print( def_comment( txt(
"End of base case tests\n"
)));
gen_sanity_file.write();
return 0;
}
#endif

View File

@ -1,75 +0,0 @@
#ifdef GEN_TIME
#define GEN_FEATURE_PARSING
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#define GEN_BENCHMARK
#include "Array.Parsed.hpp"
#include "Buffer.Parsed.hpp"
#include "HashTable.Parsed.hpp"
#include "Ring.Parsed.hpp"
#include "Sanity.Parsed.hpp"
#include "SOA.cpp"
#include "gen.cpp"
using namespace gen;
// TODO : Need to make a more robust test suite
int gen_main()
{
gen::init();
gen_sanity();
gen_array( u8 );
gen_array( ssize );
gen_buffer( u8 );
gen_hashtable( u32 );
gen_ring( s16 );
gen_ring( usize );
gen_array_file();
gen_buffer_file();
gen_hashtable_file();
gen_ring_file();
Builder soa_test; soa_test.open( "SOA.gen.hpp" );
soa_test.print( parse_using( code(
using u16 = unsigned short;
)));
soa_test.print( def_include( txt("gen.hpp")));
soa_test.print( def_using_namespace( name(gen) ) );
soa_test.print( gen_SOA(
parse_struct( code(
struct TestStruct
{
u8 A;
u16 B;
u32 C;
u64 D;
};
))
));
soa_test.write();
gen::deinit();
return 0;
}
#endif
#ifdef runtime
int main()
{
return 0;
}
#endif

View File

@ -1,375 +0,0 @@
#pragma once
#if GEN_TIME
#include "gen.hpp"
using namespace gen;
Code gen__array_base()
{
CodeType t_allocator_info = def_type( name(AllocatorInfo) );
CodeStruct header = def_struct( name(ArrayHeader),
def_struct_body( args(
def_variable( t_allocator_info, name(Allocator) )
, def_variable( t_uw, name(Capacity) )
, def_variable( t_uw, name(Num) )
)));
CodeFn grow_formula = def_function( name(array_grow_formula), def_param( t_uw, name(value)), t_uw
, def_execution( code( return 2 * value * 8; ) )
, def_specifiers( args( ESpecifier::Static, ESpecifier::Inline ) )
);
return def_global_body( args( header, grow_formula ) );
}
Code gen__array( StrC type )
{
static CodeType t_allocator_info = def_type( name(AllocatorInfo) );
static Code v_nullptr = code_str(nullptr);
static CodeSpecifiers spec_ct_member = def_specifiers( 2, ESpecifier::Constexpr, ESpecifier::Static );
static CodeSpecifiers spec_static_inline = def_specifiers( 2, ESpecifier::Static, ESpecifier::Inline );
static CodeSpecifiers spec_static = def_specifier( ESpecifier::Static );
static CodeUsing using_header = def_using( name(Header), def_type( name(ArrayHeader) ) );
static CodeVar ct_grow_formula = def_variable( t_auto, name(grow_formula), untyped_str( code( & array_grow_formula )), spec_ct_member );
StrC name;
{
char const* name_str = str_fmt_buf( "Array_%s\0", type.Ptr );
s32 name_len = str_len( name_str );
name = { name_len, name_str };
};
CodeType t_array_type = def_type( name );
CodeType t_type = def_type( type );
CodeType t_type_ptr = def_type( type, __, spec_ptr );
CodeType t_type_ref = def_type( type, __, spec_ref );
CodeType t_alias = def_type( name(Type) );
CodeType t_alias_ptr = def_type( name(Type), __, spec_ptr );
CodeType t_alias_ref = def_type( name(Type), __, spec_ref );
CodeType t_header = def_type( name(Header) );
CodeType t_header_ptr = def_type( name(Header), __, spec_ptr );
CodeType t_header_ref = def_type( name(Header), __, spec_ref );
CodeStruct array = {0};
{
CodeUsing using_type = def_using( name(Type), t_type );
CodeVar data = def_variable( t_alias_ptr, name(Data) );
CodeFn init = def_function( name(init), def_param( t_allocator_info, name(allocator) ), t_array_type
, def_execution( code(
return init_reserve( allocator, grow_formula(0) );
))
, spec_static
);
CodeFn init_reserve;
{
CodeParam params = def_params( args(
def_param( t_allocator_info, name(allocator) )
, def_param( t_sw, name(capacity) )
));
Code body = def_execution( code(
Header* header = rcast( Header*, alloc( allocator, sizeof(Header) + sizeof(Type) ));
if ( header == nullptr )
return { nullptr };
header->Allocator = allocator;
header->Capacity = capacity;
header->Num = 0;
return { rcast( Type*, header + 1) };
));
init_reserve = def_function( name(init_reserve), params, t_array_type, body, spec_static );
}
CodeFn append = def_function( name(append), def_param(t_alias, name(value)), t_bool
, def_execution( code(
Header* header = get_header();
if ( header->Num == header->Capacity )
{
if ( ! grow( header->Capacity ))
return false;
header = get_header();
}
Data[ header->Num ] = value;
header->Num++;
return true;
))
);
CodeFn back = def_function( name(back), __, t_alias_ref
, def_execution( code(
Header& header = * get_header();
return Data[ header.Num - 1 ];
))
);
CodeFn clear = def_function( name(clear), __, t_void
, def_execution( code(
Header& header = * get_header();
header.Num = 0;
))
);
CodeFn fill;
{
CodeParam params = def_params( args(
def_param( t_uw, name(begin) )
, def_param( t_uw, name(end) )
, def_param( t_alias, name(value) )
));
Code body = untyped_str( code(
Header& header = * get_header();
if ( begin < 0 || end >= header.Num )
return false;
for ( ssize idx = begin; idx < end; idx++ )
{
Data[ idx ] = value;
}
return true;
));
fill = def_function( name(fill), params, t_bool, body );
}
CodeFn free = def_function( name(free), __, t_void
, def_execution( code(
Header* header = get_header();
gen::free( header->Allocator, header );
))
);
CodeFn get_header = def_function( name(get_header), __, t_header_ptr
, def_execution( code(
return rcast( Header*, Data ) - 1;
))
);
CodeFn grow = def_function( name(grow), def_param( t_uw, name(min_capacity)), t_bool
, def_execution( code(
Header& header = * get_header();
usize new_capacity = grow_formula( header.Capacity );
if ( new_capacity < min_capacity )
new_capacity = 8;
return set_capacity( new_capacity );
))
);
CodeFn num = def_function( name(num), __, t_uw
, def_execution( code(
return get_header()->Num;
))
);
CodeFn pop = def_function( name(pop), __, t_bool
, def_execution( code(
Header& header = * get_header();
GEN_ASSERT( header.Num > 0 );
header.Num--;
))
);
CodeFn remove_at = def_function( name(remove_at), def_param( t_uw, name(idx)), t_void
, def_execution( code(
Header* header = get_header();
GEN_ASSERT( idx < header->Num );
mem_move( header + idx, header + idx + 1, sizeof( Type ) * ( header->Num - idx - 1 ) );
header->Num--;
))
);
CodeFn reserve = def_function( name(reserve), def_param( t_uw, name(new_capacity)), t_bool
, def_execution( code(
Header& header = * get_header();
if ( header.Capacity < new_capacity )
return set_capacity( new_capacity );
return true;
))
);
CodeFn resize = def_function( name(resize), def_param( t_uw, name(num)), t_bool
, def_execution( code(
Header* header = get_header();
if ( num > header->Capacity )
{
if ( ! grow( header->Capacity ))
return false;
header = get_header();
}
header->Num = num;
return true;
))
);
CodeFn set_capacity;
{
Code body = def_execution( code(
Header& header = * get_header();
if ( new_capacity == header.Capacity )
return true;
if ( new_capacity < header.Num )
header.Num = new_capacity;
ssize size = sizeof(Header) + sizeof(Type) * new_capacity;
Header* new_header = rcast( Header*, alloc( header.Allocator, size ));
if ( new_header == nullptr )
return false;
mem_move( new_header, & header, sizeof( Header ) + sizeof(Type) * header.Num );
new_header->Capacity = new_capacity;
gen::free( header.Allocator, & header );
Data = rcast( Type*, new_header + 1);
return true;
));
set_capacity = def_function( name(set_capacity), def_param( t_uw, name(new_capacity)), t_bool, body );
}
CodeOpCast op_ptr = def_operator_cast( t_type_ptr, def_execution( code(
return Data;
)));
CodeBody body = def_struct_body( args(
using_header
, using_type
, ct_grow_formula
, init
, init_reserve
, append
, back
, clear
, fill
, free
, get_header
, grow
, num
, pop
, remove_at
, reserve
, resize
, set_capacity
, op_ptr
, data
));
array = def_struct( name, body );
}
return array;
}
struct GenArrayRequest
{
StrC Dependency;
StrC Type;
};
Array<GenArrayRequest> GenArrayRequests;
void gen__array_request( StrC type, StrC dep = {} )
{
do_once_start
GenArrayRequests = Array<GenArrayRequest>::init( GlobalAllocator );
do_once_end
// Make sure we don't already have a request for the type.
for ( ssize idx = 0; idx < GenArrayRequests.num(); ++idx )
{
StrC const reqest_type = GenArrayRequests[ idx ].Type;
if ( reqest_type.Len != type.Len )
continue;
if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 )
return;
}
GenArrayRequest request = { dep, type };
GenArrayRequests.append( request );
}
#define gen_array( type ) gen__array_request( code(type) )
u32 gen_array_file()
{
Builder
gen_array_file;
gen_array_file.open( "array.Upfront.gen.hpp" );
CodeInclude include_gen = def_include( txt("gen.hpp") );
gen_array_file.print( include_gen );
gen_array_file.print( def_using_namespace( name(gen)));
Code array_base = gen__array_base();
gen_array_file.print( array_base );
GenArrayRequest* current = GenArrayRequests;
s32 left = GenArrayRequests.num();
while (left--)
{
GenArrayRequest const& request = * current;
Code generated_array = gen__array( request.Type );
if ( request.Dependency )
{
char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type );
s32 cmt_len = str_len( cmt_str );
CodeComment cmt = def_comment( { cmt_len, cmt_str } );
CodeInclude include = def_include( request.Dependency );
gen_array_file.print( cmt );
gen_array_file.print( include );
}
gen_array_file.print( generated_array );
current++;
}
gen_array_file.write();
return 0;
}
#endif

View File

@ -1,275 +0,0 @@
#pragma once
#if GEN_TIME
#include "gen.hpp"
using namespace gen;
Code gen__buffer_base()
{
CodeType t_allocator_info = def_type( name(AllocatorInfo) );
Code header = def_struct( name(BufferHeader),
def_struct_body( args(
def_variable( t_allocator_info, name(Backing) )
, def_variable( t_uw, name(Capacity) )
, def_variable( t_uw, name(Num) )
)));
return def_global_body( 1, header );
}
Code gen__buffer( StrC type, ssize type_size )
{
static CodeType t_allocator_info = def_type( name(AllocatorInfo));
static CodeUsing using_header = def_using( name(Header), def_type( name(BufferHeader) ) );
StrC name;
{
char const* name_str = str_fmt_buf( "Buffer_%s\0", type.Ptr );
s32 name_len = str_len( name_str );
name = { name_len, name_str };
};
CodeType t_buffer_type = def_type( name );
CodeType t_type = def_type( type );
CodeType t_type_ptr = def_type( type, __, spec_ptr );
CodeType t_type_ref = def_type( type, __, spec_ref );
CodeType t_header = def_type( name(Header) );
CodeType t_header_ptr = def_type( name(Header), __, spec_ptr );
CodeType t_header_ref = def_type( name(Header), __, spec_ref );
CodeStruct buffer = {0};
{
CodeUsing using_type = def_using( name(Type), t_type );
CodeVar data = def_variable( t_type_ptr, name(Data) );
CodeFn init;
{
CodeParam params = def_params( args(
def_param( t_allocator_info, name(allocator))
, def_param( t_sw, name(capacity))
));
Code body = def_execution( code(
Header* header = rcast( Header*, alloc( allocator, sizeof(Header) + capacity * sizeof(Type) ) );
if ( header == nullptr )
return { nullptr };
header->Backing = allocator;
header->Capacity = capacity;
header->Num = 0;
return { rcast( Type*, header + 1) };
));
init = def_function( name(init), params, t_buffer_type, body, spec_static_member );
}
CodeFn init_copy;
{
CodeParam params = def_params( args(
def_param( t_allocator_info, name(allocator))
, def_param( t_buffer_type, name(other))
));
init_copy = def_function( name(init), params, t_buffer_type
, def_execution( code(
Header& other_header = other.get_header();
Header* header = rcast( Header*, alloc( allocator, sizeof(Header) + other_header.Capacity * sizeof(Type) ) );
if ( header == nullptr )
return { nullptr };
header->Backing = allocator;
header->Capacity = other_header.Capacity;
header->Num = other_header.Num;
mem_copy( header + 1, other.Data, other_header.Num * sizeof(Type) );
return { rcast( Type*, header + 1) };
))
);
}
CodeFn append = def_function( name(append), def_param( t_type, name(value)), t_void
, def_execution( code(
Header& header = get_header();
Data[ header.Num ] = value;
header.Num++;
))
);
CodeFn appendv;
{
CodeParam params = def_params( args(
def_param( t_type_ptr, name( values))
, def_param( t_sw, name( num))
));
appendv = def_function( name(append), params, t_void
, def_execution( code(
Header& header = get_header();
GEN_ASSERT( header.Num + num <= header.Capacity);
mem_copy( Data + header.Num, values, num * sizeof( Type ) );
header.Num += num;
))
);
}
CodeFn clear = def_function( name(clear), __, t_void
, def_execution( code(
Header& header = get_header();
header.Num = 0;
))
);
CodeFn end = def_function( name(end), __, t_type_ref
, def_execution( code(
Header& header = get_header();
return Data[ header.Num - 1 ];
))
);
CodeFn free = def_function( name(free), __, t_void
, def_execution( code(
Header& header = get_header();
gen::free( header.Backing, & header );
))
);
CodeFn get_header = def_function( name(get_header), __, t_header_ref
, def_execution( code(
return * ( rcast( Header*, Data ) - 1 );
))
);
CodeFn num = def_function( name(num), __, t_sw
, def_execution( code(
return get_header().Num;
))
);
CodeFn pop = def_function( name(pop), __, t_type
, def_execution( code(
Header& header = get_header();
header.Num--;
return Data[ header.Num ];
))
);
CodeFn wipe = def_function( name(wipe), __, t_void
, def_execution( code(
Header& header = get_header();
header.Num = 0;
mem_set( Data, 0, header.Capacity * sizeof( Type ) );
))
);
CodeOpCast op_type_ptr = def_operator_cast( t_type_ptr, def_execution( code(
return Data;
)));
buffer = def_struct( name, def_struct_body( args(
using_header
, using_type
, init
, init_copy
, append
, appendv
, clear
, end
, free
, get_header
, num
, pop
, wipe
, op_type_ptr
, data
)));
}
return buffer;
}
struct GenBufferRequest
{
StrC Dependency;
StrC Type;
ssize TypeSize;
};
Array<GenBufferRequest> GenBufferRequests;
void gen__buffer_request( StrC type, StrC dep = {} )
{
do_once_start
GenBufferRequests = Array<GenBufferRequest>::init( GlobalAllocator );
do_once_end
// Make sure we don't already have a request for the type.
for ( ssize idx = 0; idx < GenBufferRequests.num(); ++idx )
{
StrC const reqest_type = GenBufferRequests[ idx ].Type;
if ( reqest_type.Len != type.Len )
continue;
if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 )
return;
}
GenBufferRequest request = { dep, type};
GenBufferRequests.append( request );
}
#define gen_buffer( type ) gen__buffer_request( code(type))
u32 gen_buffer_file()
{
Builder
gen_buffer_file;
gen_buffer_file.open( "buffer.Upfront.gen.hpp" );
gen_buffer_file.print( def_include( txt("gen.hpp")) );
gen_buffer_file.print( def_using_namespace( name(gen)) );
gen_buffer_file.print( gen__buffer_base() );
GenBufferRequest* current = GenBufferRequests;
s32 left = GenBufferRequests.num();
while (left--)
{
GenBufferRequest const& request = * current;
Code generated_buffer = gen__buffer( current->Type, current->TypeSize );
if ( request.Dependency )
{
char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type );
s32 cmt_len = str_len( cmt_str );
Code cmt = def_comment( { cmt_len, cmt_str } );
Code include = def_include( request.Dependency );
gen_buffer_file.print( cmt );
gen_buffer_file.print( include );
}
gen_buffer_file.print( generated_buffer );
current++;
}
gen_buffer_file.write();
return 0;
}
#endif // GEN_TIME

View File

@ -1,486 +0,0 @@
#pragma once
#if GEN_TIME
#include "gen.hpp"
#include "Array.Upfront.hpp"
using namespace gen;
Code gen__hashtable_base()
{
CodeVar hashIndex = def_variable( t_sw, name(HashIndex) );
CodeVar entry_prev = def_variable( t_sw, name(PrevIndex) );
CodeVar entry_index = def_variable( t_sw, name(EntryIndex) );
CodeStruct find_result = def_struct( name(HashTable_FindResult), def_struct_body( 3
, hashIndex
, entry_prev
, entry_index
));
return find_result;
}
Code gen__hashtable( StrC type )
{
static CodeType t_allocator_info = def_type( name(AllocatorInfo) );
CodeType t_find_result = def_type( name(HashTable_FindResult) );
StringCached name;
{
char const* name_str = str_fmt_buf( "HashTable_%s", type.Ptr );
s32 len = str_len( name_str );
name = get_cached_string({ len, name_str });
}
CodeType t_ht_type = def_type( name );
CodeType t_type = def_type( type );
CodeType t_type_ptr = def_type( type, __, spec_ptr );
CodeType t_type_ref = def_type( type, __, spec_ref );
// Hash table depends on array container for its entry structure.
CodeType t_ht_entry, t_array_ht_entry;
CodeStruct ht_entry, array_ht_entry;
{
char const* name_str = str_fmt_buf( "HashTable_%s_Entry", type.Ptr );
s32 len = str_len( name_str );
StringCached ht_entry_name = get_cached_string({ len, name_str });
t_ht_entry = def_type( ht_entry_name );
ht_entry = def_struct( ht_entry_name, def_struct_body( args(
def_variable( t_u64, name(Key))
, def_variable( t_sw, name(Next))
, def_variable( t_type, name(Value))
)));
array_ht_entry = gen__array( ht_entry_name );
t_array_ht_entry = def_type( array_ht_entry->Name );
}
CodeStruct hashtable = {0};
{
CodeUsing using_entry = def_using( name(Entry), t_ht_entry );
CodeUsing using_array_entry = def_using( name(Array_Entry), t_array_ht_entry );
CodeUsing using_find_result = def_using( name(FindResult), t_find_result );
CodeType t_array_sw = def_type( name(Array_sw) );
CodeType t_array_entry = def_type( name(Array_Entry) );
CodeVar hashes = def_variable( t_array_sw, name(Hashes) );
CodeVar entries = def_variable( t_array_entry, name(Entries));
CodeFn init;
{
char const* tmpl = stringize(
<type> result = { 0 };
result.Hashes = Array_sw ::init( allocator );
result.Entries = Array_Entry::init( allocator );
return result;
);
Code body = def_execution( token_fmt( "type", (StrC)name, tmpl ) );
init = def_function( name(init), def_param( t_allocator_info, name(allocator)), t_ht_type, body, spec_static_member );
}
CodeFn init_reserve;
{
char const* tmpl = stringize(
<type> result = { { nullptr }, { nullptr } };
result.Hashes = Array_sw::init_reserve( allocator, num );
result.Hashes.get_header()->Num = num;
result.Entries = Array_Entry::init_reserve( allocator, num );
return result;
);
Code body = def_execution( token_fmt( "type", (StrC)name, tmpl ) );
CodeParam params = def_params( args( def_param( t_allocator_info, name(allocator)), def_param( t_sw, name(num))));
init_reserve = def_function( name(init_reserve), params, t_ht_type, body, spec_static_member );
}
CodeFn clear = def_function( name(clear), __, t_void
, def_execution( code(
for ( s32 idx = 0; idx < Hashes.num(); idx++ )
Hashes[ idx ] = -1;
Entries.clear();
))
);
CodeFn destroy = def_function( name(destroy), __, t_void
, def_execution( code(
if ( Hashes && Hashes.get_header()->Capacity )
Hashes.free();
if ( Entries && Hashes.get_header()->Capacity )
Entries.free();
))
);
CodeFn get = def_function( name(get), def_param( t_u64, name(key)), t_type_ptr
, def_execution( code(
ssize idx = find( key ).EntryIndex;
if ( idx >= 0 )
return & Entries[ idx ].Value;
return nullptr;
))
);
CodeUsing using_map_proc;
{
char const* tmpl = stringize(
void (*) ( u64 key, <type> value )
);
CodeType value = def_type( token_fmt( "type", (StrC)t_type.to_string(), tmpl ) );
using_map_proc = def_using ( name(MapProc), value);
}
CodeFn map;
{
CodeType t_map_proc = def_type( name(MapProc) );
Code body = def_execution( code(
GEN_ASSERT_NOT_NULL( map_proc );
for ( ssize idx = 0; idx < Entries.num(); idx++ )
{
map_proc( Entries[ idx ].Key, Entries[ idx ].Value );
}
));
map = def_function( name(map), def_param( t_map_proc, name(map_proc) ), t_void, body );
}
CodeUsing using_map_mut_proc;
{
char const* tmpl = stringize(
void (*) ( u64 key, <type> value )
);
CodeType value = def_type( token_fmt( "type", (StrC)t_type_ptr.to_string(), tmpl ) );
using_map_mut_proc = def_using ( name(MapMutProc), value);
}
CodeFn map_mut;
{
CodeType t_map_mut_proc = def_type( name(MapMutProc));
Code body = def_execution( code(
GEN_ASSERT_NOT_NULL( map_proc );
for ( ssize idx = 0; idx < Entries.num(); idx++ )
{
map_proc( Entries[ idx ].Key, & Entries[ idx ].Value );
}
));
map_mut = def_function( name(map_mut), def_param( t_map_mut_proc, name(map_proc)), t_void, body );
}
CodeFn grow = def_function( name(grow), __, t_void
, def_execution( code(
ssize new_num = array_grow_formula( Entries.num() );
rehash( new_num );
))
);
CodeFn rehash;
{
char const* tmpl = stringize(
ssize idx;
ssize last_added_index;
<type> new_ht = init_reserve( Hashes.get_header()->Allocator, new_num );
Array_sw::Header* hash_header = new_ht.Hashes.get_header();
for ( idx = 0; idx < new_ht.Hashes.num(); ++idx )
new_ht.Hashes[ idx ] = -1;
for ( idx = 0; idx < Entries.num(); ++idx )
{
Entry& entry = Entries[ idx ];
FindResult find_result;
if ( new_ht.Hashes.num() == 0 )
new_ht.grow();
entry = Entries[ idx ];
find_result = new_ht.find( entry.Key );
last_added_index = new_ht.add_entry( entry.Key );
if ( find_result.PrevIndex < 0 )
new_ht.Hashes[ find_result.HashIndex ] = last_added_index;
else
new_ht.Entries[ find_result.PrevIndex ].Next = last_added_index;
new_ht.Entries[ last_added_index ].Next = find_result.EntryIndex;
new_ht.Entries[ last_added_index ].Value = entry.Value;
}
destroy();
*this = new_ht;
);
Code body = def_execution( token_fmt( "type", (StrC)name, tmpl ) );
rehash = def_function( name(rehash), def_param( t_sw, name(new_num)), t_void, body );
}
CodeFn rehash_fast;
{
char const* tmpl = stringize(
ssize idx;
for ( idx = 0; idx < Entries.num(); idx++ )
Entries[ idx ].Next = -1;
for ( idx = 0; idx < Hashes.num(); idx++ )
Hashes[ idx ] = -1;
for ( idx = 0; idx < Entries.num(); idx++ )
{
Entry* entry;
FindResult find_result;
}
);
Code body = def_execution( token_fmt( "type", name, tmpl ) );
rehash_fast = def_function( name(rehash_fast), __, t_void, body );
}
CodeFn remove = def_function( name(remove), def_param( t_u64, name(key)), t_void
, def_execution( code(
FindResult find_result = find( key);
if ( find_result.EntryIndex >= 0 )
{
Entries.remove_at( find_result.EntryIndex );
rehash_fast();
}
))
);
CodeFn remove_entry = def_function( name(remove_entry), def_param( t_sw, name(idx)), t_void
, def_execution( code(
Entries.remove_at( idx );
))
);
CodeFn set;
{
CodeParam params = def_params( args(
def_param( t_u64, name(key))
, def_param( t_type, name(value))
));
Code body = def_execution( code(
ssize idx;
FindResult find_result;
if ( Hashes.num() == 0 )
grow();
find_result = find( key );
if ( find_result.EntryIndex >= 0 )
{
idx = find_result.EntryIndex;
}
else
{
idx = add_entry( key );
if ( find_result.PrevIndex >= 0 )
{
Entries[ find_result.PrevIndex ].Next = idx;
}
else
{
Hashes[ find_result.HashIndex ] = idx;
}
}
Entries[ idx ].Value = value;
if ( full() )
grow();
));
set = def_function( name(set), params, t_void, body );
}
CodeFn slot = def_function( name(slot), def_param( t_u64, name(key)), t_sw
, def_execution( code(
for ( ssize idx = 0; idx < Hashes.num(); ++idx )
if ( Hashes[ idx ] == key )
return idx;
return -1;
))
);
CodeFn add_entry = def_function( name(add_entry), def_param( t_u64, name(key)), t_sw
, def_execution( code(
ssize idx;
Entry entry = { key, -1 };
idx = Entries.num();
Entries.append( entry );
return idx;
))
);
CodeFn find = def_function( name(find), def_param( t_u64, name(key)), t_find_result
, def_execution( code(
FindResult result = { -1, -1, -1 };
if ( Hashes.num() > 0 )
{
result.HashIndex = key % Hashes.num();
result.EntryIndex = Hashes[ result.HashIndex ];
while ( result.EntryIndex >= 0 )
{
if ( Entries[ result.EntryIndex ].Key == key )
break;
result.PrevIndex = result.EntryIndex;
result.EntryIndex = Entries[ result.EntryIndex ].Next;
}
}
return result;
))
);
CodeFn full = def_function( name(full), __, t_b32
, def_execution( code(
return 0.75f * Hashes.num() < Entries.num();
))
);
hashtable = def_struct( name, def_struct_body( args(
using_entry
, using_array_entry
, using_find_result
, using_map_proc
, using_map_mut_proc
, init
, init_reserve
, clear
, destroy
, get
, grow
, map
, map_mut
, rehash
, rehash_fast
, remove
, remove_entry
, set
, slot
, hashes
, entries
, access_protected
, add_entry
, find
, full
)));
}
return def_global_body( args( ht_entry, array_ht_entry, hashtable ));
}
struct GenHashTableRequest
{
StrC Dependency;
StrC Type;
};
Array<GenHashTableRequest> GenHashTableRequests;
void gen__hashtable_request( StrC type, StrC dep = {} )
{
do_once_start
GenHashTableRequests = Array<GenHashTableRequest>::init( GlobalAllocator );
gen_array( ssize );
do_once_end
// Make sure we don't already have a request for the type.
for ( ssize idx = 0; idx < GenHashTableRequests.num(); ++idx )
{
StrC const reqest_type = GenHashTableRequests[ idx ].Type;
if ( reqest_type.Len != type.Len )
continue;
if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 )
return;
}
GenHashTableRequest request = { dep, type };
GenHashTableRequests.append( request );
}
#define gen_hashtable( type ) gen__hashtable_request( code(type))
u32 gen_hashtable_file()
{
Builder
gen_hashtable_file;
gen_hashtable_file.open( "hashtable.Upfront.gen.hpp" );
gen_hashtable_file.print( def_include( txt("gen.hpp")) );
gen_hashtable_file.print( def_include( txt("Array.Upfront.hpp")) );
gen_hashtable_file.print( def_include( txt("array.Upfront.gen.hpp")) );
gen_hashtable_file.print( def_using_namespace( name(gen)));
gen_hashtable_file.print( gen__hashtable_base());
GenHashTableRequest* current = GenHashTableRequests;
s32 left = GenHashTableRequests.num();
while (left--)
{
GenHashTableRequest const& request = * current;
Code generated_buffer = gen__hashtable( current->Type );
if ( request.Dependency )
{
char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type );
s32 cmt_len = str_len( cmt_str );
Code cmt = def_comment( { cmt_len, cmt_str } );
Code include = def_include( request.Dependency );
gen_hashtable_file.print( cmt );
gen_hashtable_file.print( include );
}
gen_hashtable_file.print( generated_buffer );
current++;
}
gen_hashtable_file.write();
return 0;
}
#endif // GEN_TIME

View File

@ -1,228 +0,0 @@
#pragma once
#if GEN_TIME
#include "gen.hpp"
#include "Buffer.Upfront.hpp"
using namespace gen;
Code gen__ring( StrC type )
{
static CodeType t_allocator_info = def_type( name(AllocatorInfo) );
String name;
{
char const* name_str = str_fmt_buf( "Ring_%s\0", type.Ptr );
s32 name_len = str_len( name_str );
name = get_cached_string({ name_len, name_str });
};
CodeType t_ring_type = def_type( name );
CodeType t_ring_type_ptr = def_type( name, __, spec_ptr );
CodeType t_type = def_type( type );
CodeType t_type_ptr = def_type( type, __, spec_ptr );
CodeType t_type_ref = def_type( type, __, spec_ref );
CodeType t_buffer_type;
{
char const* name_str = str_fmt_buf( "Buffer_%s\0", type.Ptr );
s32 len = str_len( name_str );
t_buffer_type = def_type( { len, name_str } );
}
CodeStruct ring = {0};
{
CodeUsing using_type = def_using( name(Type), t_type );
CodeVar backing = def_variable( t_allocator_info, name(Backing) );
CodeVar capacity = def_variable( t_uw, name(Capacity) );
CodeVar head = def_variable( t_uw, name(Head) );
CodeVar tail = def_variable( t_uw, name(Tail) );
CodeVar buffer = def_variable( t_buffer_type, name(Buffer) );
CodeFn init;
{
CodeParam params = def_params( args(
def_param( t_allocator_info, name(allocator) )
, def_param( t_uw, name(max_size) )
));
char const* tmpl = stringize(
<type> result = { 0 };
result.Backing = allocator;
result.Buffer = Buffer_<data_type>::init( allocator, max_size + 1 );
if ( result.Buffer == nullptr )
return { nullptr };
result.Capacity = max_size + 1;
return result;
);
Code body = def_execution( token_fmt( "type", (StrC)name, "data_type", type, tmpl ));
init = def_function( name(init), params, t_ring_type, body, spec_static_member );
}
CodeFn append = def_function( name(append), def_param( t_type, name(value)), t_void
, def_execution( code(
Buffer[ Head ] = value;
Head = ( Head + 1 ) % Capacity;
if ( Head == Tail )
Tail = ( Tail + 1 ) % Capacity;
))
);
CodeFn appendv;
{
CodeParam params = def_params( 2
, def_param( t_type_ptr, name(values))
, def_param( t_sw, name(num))
);
Code body = def_execution( code(
for ( ssize idx = 0; idx < num; idx++ )
append( values[ idx ] );
));
appendv = def_function( name(append), params, t_void, body, spec_inline );
}
CodeFn empty = def_function( name(empty), __, t_bool
, def_execution( code(
return Head == Tail;
))
);
CodeFn free = def_function( name(free), __, t_void
, def_execution( code(
Buffer.free();
))
);
CodeFn full = def_function( name(full), __, t_bool
, def_execution( code(
return (Head + 1) % Capacity == Tail;
))
);
CodeFn get = def_function( name(get), __, t_type_ref
, def_execution( code(
Type& data = Buffer[ Tail ];
Tail = ( Tail + 1 ) % Capacity;
return data;
))
);
CodeFn wipe = def_function( name(wipe), __, t_void
, def_execution( code(
Head = 0;
Tail = 0;
Buffer.wipe();
))
);
ring = def_struct( name, def_struct_body( args(
using_type,
init,
append,
appendv,
empty,
free,
full,
get,
wipe,
backing,
capacity,
head,
tail,
buffer
)));
}
return ring;
}
struct GenRingRequest
{
StrC Dependency;
StrC Type;
};
Array<GenRingRequest> GenRingRequests;
void gen__ring_request( StrC type, StrC dep = {} )
{
do_once_start
GenRingRequests = Array<GenRingRequest>::init( GlobalAllocator );
do_once_end
// Make sure we don't already have a request for the type.
for ( ssize idx = 0; idx < GenRingRequests.num(); ++idx )
{
StrC const reqest_type = GenRingRequests[ idx ].Type;
if ( reqest_type.Len != type.Len )
continue;
if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 )
return;
}
// Ring definition depends on a array and buffer definition.
gen__buffer_request( type, dep );
GenRingRequest request = { dep, type };
GenRingRequests.append( request );
}
#define gen_ring( type ) gen__ring_request( code(type) )
u32 gen_ring_file()
{
Builder
gen_ring_file;
gen_ring_file.open( "ring.Upfront.gen.hpp" );
gen_ring_file.print( def_include( txt("gen.hpp")) );
gen_ring_file.print( def_include( txt("buffer.Upfront.gen.hpp")) );
gen_ring_file.print( def_using_namespace( name(gen)));
GenRingRequest* current = GenRingRequests;
s32 left = GenRingRequests.num();
while (left--)
{
GenRingRequest const& request = * current;
Code generated_ring = gen__ring( current->Type );
if ( request.Dependency )
{
char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type );
s32 cmt_len = str_len( cmt_str );
Code cmt = def_comment( { cmt_len, cmt_str } );
Code include = def_include( request.Dependency );
gen_ring_file.print( cmt );
gen_ring_file.print( include );
}
gen_ring_file.print( generated_ring );
current++;
}
gen_ring_file.write();
return 0;
}
#endif // GEN_TIME

View File

@ -1,331 +0,0 @@
#ifdef GEN_TIME
#include "gen.hpp"
using namespace gen;
u32 gen_sanity_upfront()
{
Builder
gen_sanity_file;
gen_sanity_file.open("./sanity.Upfront.gen.hpp");
// Comment
{
CodeComment comment_test = def_comment( txt("Sanity check: def_comment test") );
gen_sanity_file.print(comment_test);
}
gen_sanity_file.print_fmt("\n");
gen_sanity_file.print( def_comment( txt(
"The following will show a series of base cases for the gen api.\n"
)));
// Class
{
CodeClass fwd = def_class( name(TestEmptyClass) );
CodeClass empty_body;
{
CodeComment cmt = def_comment( txt("Empty class body") );
CodeBody body = def_class_body( args( cmt ) );
empty_body = def_class( name(TestEmptyClass), body );
}
gen_sanity_file.print(fwd);
gen_sanity_file.print(empty_body);
}
gen_sanity_file.print_fmt("\n");
// Typedef
{
CodeType t_unsigned_char = def_type( name(unsigned char) );
CodeTypedef u8_typedef = def_typedef( name(u8), t_unsigned_char );
gen_sanity_file.print(u8_typedef);
}
gen_sanity_file.print_fmt("\n");
// Enum
{
CodeEnum fwd = def_enum( name(ETestEnum), NullCode, t_u8 );
CodeEnum def;
{
Code body = untyped_str( code(
A,
B,
C
));
def = def_enum( name(ETestEnum), body, t_u8 );
}
CodeEnum fwd_enum_class = def_enum( name(ETestEnumClass), NullCode, t_u8, EnumClass );
gen_sanity_file.print(fwd);
gen_sanity_file.print(def);
gen_sanity_file.print(fwd_enum_class);
}
gen_sanity_file.print_fmt("\n");
// External Linkage
{
CodeBody body = def_extern_link_body( 1
, def_comment( txt("Empty extern body") )
);
CodeExtern c_extern = def_extern_link( name(C), body );
gen_sanity_file.print(c_extern);
}
gen_sanity_file.print_fmt("\n");
// Friend
{
CodeClass fwd = def_class( name(TestFriendFwd));
CodeBody body = def_class_body( args( def_friend( fwd ) ) );
gen_sanity_file.print( def_class( name(TestFriend), body ) );
}
gen_sanity_file.print_fmt("\n");
// Function
{
CodeFn fwd = def_function( name(test_function) );
CodeFn def;
{
CodeBody body = def_function_body( 1
, def_comment( txt("Empty function body") )
);
def = def_function( name(test_function), __, __, body );
}
gen_sanity_file.print(fwd);
gen_sanity_file.print(def);
}
gen_sanity_file.print_fmt("\n");
// Include
{
CodeInclude include = def_include( txt("../DummyInclude.hpp") );
gen_sanity_file.print(include);
}
gen_sanity_file.print_fmt("\n");
// Module
if (0)
{
CodeModule module_export = def_module( name(TestModule), ModuleFlag::Export );
CodeModule module_import = def_module( name(TestModule), ModuleFlag::Import );
CodeModule module_both = def_module( name(TestModule), ModuleFlag::Export | ModuleFlag::Import );
gen_sanity_file.print(module_global_fragment);
gen_sanity_file.print(module_private_fragment);
gen_sanity_file.print(module_export);
gen_sanity_file.print(module_import);
gen_sanity_file.print(module_both);
}
gen_sanity_file.print_fmt("\n");
// Namespace
{
CodeNS namespace_def;
{
CodeBody body = def_namespace_body( 1
, def_comment( txt("Empty namespace body") )
);
namespace_def = def_namespace( name(TestNamespace), body );
}
gen_sanity_file.print(namespace_def);
}
gen_sanity_file.print_fmt("\n");
// Operator
{
// Going to make a bit flag set of overloads for this.
CodeEnum bitflagtest;
{
CodeBody body = def_enum_body( 1, untyped_str( code(
A = 1 << 0,
B = 1 << 1,
C = 1 << 2
)));
bitflagtest = def_enum( name(EBitFlagtest), body, t_u8, EnumClass );
}
CodeType t_bitflag = def_type( name(EBitFlagtest) );
CodeOperator op_fwd, op_or;
{
CodeParam params = def_params( args(
def_param( t_bitflag, name(a) ),
def_param( t_bitflag, name(b) )
));
op_fwd = def_operator( EOperator::BOr, params, t_bitflag );
op_or = def_operator( EOperator::BOr, params, t_bitflag, untyped_str( code(
return EBitFlagtest( (u8)a | (u8)b );
)));
}
gen_sanity_file.print(bitflagtest);
gen_sanity_file.print(op_fwd);
gen_sanity_file.print(op_or);
}
gen_sanity_file.print_fmt("\n");
// Operator cast
{
CodeType t_u8_ptr = def_type( name(u8), __, spec_ptr );
CodeOpCast op_ptr = def_operator_cast( t_u8_ptr, __ );
CodeClass op_class = def_class( name(TestOperatorCast), def_class_body( args( op_ptr) ) );
gen_sanity_file.print(op_class);
}
gen_sanity_file.print_fmt("\n");
// Parameters
{
CodeFn fwd;
{
CodeParam params = def_param( t_u8, name(a) );
fwd = def_function( name(test_function_wparam), params );
}
CodeFn def, def2;
{
CodeBody body = def_function_body( 1
, def_comment( txt("Empty function body") )
);
CodeParam params = def_params( args(
def_param( t_u8, name(a) )
, def_param( t_u8, name(b) )
));
def = def_function( name(test_function_wparams), params, __, body );
CodeParam param_a = def_param( t_u8, name(a));
CodeParam param_b = def_param( t_u8, name(b));
CodeParam params_arr[2] = { param_a, param_b };
CodeParam params2 = def_params( 2, params_arr );
def2 = def_function( name(test_function_wparams2), params2, __, body );
}
gen_sanity_file.print(fwd);
gen_sanity_file.print(def);
gen_sanity_file.print(def2);
}
gen_sanity_file.print_fmt("\n");
// Specifiers
{
CodeFn fwd_fn = def_function( name(test_function_specifiers), __, __, __, spec_inline );
// TODO : Need an op overload here
CodeType u8_ptr = def_type( name(u8), __, spec_ptr );
CodeTypedef typedef_u8_ptr = def_typedef( name(ConstExprTest), u8_ptr );
gen_sanity_file.print(fwd_fn);
gen_sanity_file.print(typedef_u8_ptr);
}
gen_sanity_file.print_fmt("\n");
// Struct
{
CodeClass fwd = def_class( name(TestEmptyStruct) );
CodeClass empty_body;
{
CodeComment cmt = def_comment( txt("Empty struct body") );
CodeBody body = def_class_body( args( cmt ) );
empty_body = def_class( name(TestEmptyStruct), body );
}
gen_sanity_file.print(fwd);
gen_sanity_file.print(empty_body);
}
gen_sanity_file.print_fmt("\n");
// Union
{
CodeBody body = def_union_body( 1
, def_comment( txt("Empty union body") )
);
CodeUnion def = def_union( name(TestEmptyUnion), body );
gen_sanity_file.print(def);
}
gen_sanity_file.print_fmt("\n");
// Using
{
CodeUsing reg = def_using( name(TestUsing), t_u8 );
CodeUsing nspace = def_using_namespace( name(TestNamespace) );
gen_sanity_file.print(reg);
gen_sanity_file.print(nspace);
}
gen_sanity_file.print_fmt("\n");
// Variable
{
CodeVar bss = def_variable( t_u8, name(test_variable) );
CodeVar data = def_variable( t_u8, name(test_variable2), untyped_str( code( 0x12 )) );
gen_sanity_file.print(bss);
gen_sanity_file.print(data);
}
gen_sanity_file.print_fmt("\n");
// Template
{
CodeType t_Type = def_type( name(Type) );
CodeTemplate tmpl = def_template( def_param( t_class, name(Type) )
, def_function( name(test_template), def_param( t_Type, name(a) ), __
, def_function_body(1, def_comment( txt("Empty template function body")))
)
);
gen_sanity_file.print(tmpl);
}
gen_sanity_file.print_fmt("\n");
gen_sanity_file.print( def_comment( txt(
"End of base case tests.\n"
)));
gen_sanity_file.write();
return 0;
}
#endif

View File

@ -1,49 +0,0 @@
#ifdef GEN_TIME
#define GEN_FEATURE_PARSING
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#define GEN_BENCHMARK
#include "gen.cpp"
#include "Array.Upfront.hpp"
#include "Buffer.Upfront.hpp"
#include "HashTable.Upfront.hpp"
#include "Ring.Upfront.hpp"
#include "Sanity.Upfront.hpp"
using namespace gen;
int gen_main()
{
gen::init();
gen_sanity_upfront();
gen_array( u8 );
gen_array( ssize );
gen_buffer( u8 );
gen_hashtable( u32 );
gen_ring( s16 );
gen_array_file();
gen_buffer_file();
gen_hashtable_file();
gen_ring_file();
gen::deinit();
return 0;
}
#endif
#ifdef runtime
int main()
{
return 0;
}
#endif

View File

View File

@ -1,21 +0,0 @@
#ifdef GEN_TIME
#define GEN_FEATURE_PARSING
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#define GEN_BENCHMARK
#include "gen.hpp"
void check_parsing()
{
using namespace gen;
log_fmt("\nupfront: ");
gen::init();
// TODO
gen::deinit();
log_fmt("Passed!\n");
}
#endif

Some files were not shown because too many files have changed in this diff Show More